llgo.string; c string library

This commit is contained in:
xushiwei
2024-06-19 23:40:05 +08:00
parent 3c0e321538
commit 3ead4b4d4b
9 changed files with 125 additions and 26 deletions

58
c/c.go
View File

@@ -77,8 +77,64 @@ func Memset(s Pointer, c Int, n uintptr) Pointer
// -----------------------------------------------------------------------------
//go:linkname Strlen C.strlen
func Strlen(s *Char) uintptr
//go:linkname Strcpy C.strcpy
func Strcpy(dst, src *Char) *Char
//go:linkname Strncpy C.strncpy
func Strncpy(dst, src *Char, n uintptr) *Char
//go:linkname Strcat C.strcat
func Strcat(dst, src *Char) *Char
//go:linkname Strncat C.strncat
func Strncat(dst, src *Char, n uintptr) *Char
//go:linkname Strcmp C.strcmp
func Strcmp(s1, s2 *Char) Int
//go:linkname Strncmp C.strncmp
func Strncmp(s1, s2 *Char, n uintptr) Int
//go:linkname Strchr C.strchr
func Strchr(s *Char, c Int) *Char
//go:linkname Strrchr C.strrchr
func Strrchr(s *Char, c Int) *Char
//go:linkname Strstr C.strstr
func Strstr(s1, s2 *Char) *Char
//go:linkname Strdup C.strdup
func Strdup(s *Char) *Char
//go:linkname Strndup C.strndup
func Strndup(s *Char, n uintptr) *Char
//go:linkname Strtok C.strtok
func Strtok(s, delim *Char) *Char
//go:linkname Strerror C.strerror
func Strerror(errnum Int) *Char
//go:linkname Sprintf C.sprintf
func Sprintf(s *Char, format *Char, __llgo_va_list ...any) Int
//go:linkname Snprintf C.snprintf
func Snprintf(s *Char, n uintptr, format *Char, __llgo_va_list ...any) Int
//go:linkname Vsnprintf C.vsnprintf
func Vsnprintf(s *Char, n uintptr, format *Char, ap Pointer) Int
// -----------------------------------------------------------------------------
// GoString converts a C string to a Go string.
// TODO(xsw): any => int
//
//go:linkname GoString llgo.string
func GoString(cstr *Char, n ...int) string
func GoString(cstr *Char, __llgo_va_list /* n */ ...any) string
//go:linkname GoStringData llgo.stringData
func GoStringData(string) *Char

View File

@@ -59,7 +59,7 @@ _llgo_1: ; preds = %_llgo_3
store i64 7, ptr %4, align 4
%5 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %2, align 8
%6 = extractvalue %"github.com/goplus/llgo/internal/runtime.String" %5, 1
%7 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewStringSlice"(%"github.com/goplus/llgo/internal/runtime.String" %5, i64 %15, i64 %6)
%7 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.StringSlice"(%"github.com/goplus/llgo/internal/runtime.String" %5, i64 %15, i64 %6)
%8 = call { i32, i64 } @"unicode/utf8.DecodeRuneInString"(%"github.com/goplus/llgo/internal/runtime.String" %7)
%9 = extractvalue { i32, i64 } %8, 0
%10 = extractvalue { i32, i64 } %8, 1
@@ -95,7 +95,7 @@ declare void @"unicode/utf8.init"()
declare void @"github.com/goplus/llgo/internal/runtime.init"()
declare %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewStringSlice"(%"github.com/goplus/llgo/internal/runtime.String", i64, i64)
declare %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.StringSlice"(%"github.com/goplus/llgo/internal/runtime.String", i64, i64)
declare { i32, i64 } @"unicode/utf8.DecodeRuneInString"(%"github.com/goplus/llgo/internal/runtime.String")

View File

@@ -700,7 +700,7 @@ _llgo_2: ; preds = %_llgo_0
%12 = getelementptr inbounds %main.stringReader, ptr %0, i32 0, i32 1
%13 = load i64, ptr %12, align 4
%14 = extractvalue %"github.com/goplus/llgo/internal/runtime.String" %11, 1
%15 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewStringSlice"(%"github.com/goplus/llgo/internal/runtime.String" %11, i64 %13, i64 %14)
%15 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.StringSlice"(%"github.com/goplus/llgo/internal/runtime.String" %11, i64 %13, i64 %14)
%16 = extractvalue %"github.com/goplus/llgo/internal/runtime.String" %15, 0
%17 = extractvalue %"github.com/goplus/llgo/internal/runtime.String" %15, 1
%18 = call i64 @"github.com/goplus/llgo/internal/runtime.SliceCopy"(%"github.com/goplus/llgo/internal/runtime.Slice" %1, ptr %16, i64 %17, i64 1)
@@ -746,7 +746,7 @@ _llgo_4: ; preds = %_llgo_2
%14 = getelementptr inbounds %main.stringReader, ptr %0, i32 0, i32 0
%15 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %14, align 8
%16 = extractvalue %"github.com/goplus/llgo/internal/runtime.String" %15, 1
%17 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewStringSlice"(%"github.com/goplus/llgo/internal/runtime.String" %15, i64 %2, i64 %16)
%17 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.StringSlice"(%"github.com/goplus/llgo/internal/runtime.String" %15, i64 %2, i64 %16)
%18 = extractvalue %"github.com/goplus/llgo/internal/runtime.String" %17, 0
%19 = extractvalue %"github.com/goplus/llgo/internal/runtime.String" %17, 1
%20 = call i64 @"github.com/goplus/llgo/internal/runtime.SliceCopy"(%"github.com/goplus/llgo/internal/runtime.Slice" %1, ptr %18, i64 %19, i64 1)
@@ -860,7 +860,7 @@ _llgo_4: ; preds = %_llgo_2
%31 = getelementptr inbounds %main.stringReader, ptr %0, i32 0, i32 1
%32 = load i64, ptr %31, align 4
%33 = extractvalue %"github.com/goplus/llgo/internal/runtime.String" %30, 1
%34 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewStringSlice"(%"github.com/goplus/llgo/internal/runtime.String" %30, i64 %32, i64 %33)
%34 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.StringSlice"(%"github.com/goplus/llgo/internal/runtime.String" %30, i64 %32, i64 %33)
%35 = call { i32, i64 } @"unicode/utf8.DecodeRuneInString"(%"github.com/goplus/llgo/internal/runtime.String" %34)
%36 = extractvalue { i32, i64 } %35, 0
%37 = extractvalue { i32, i64 } %35, 1
@@ -1041,7 +1041,7 @@ _llgo_2: ; preds = %_llgo_0
%11 = getelementptr inbounds %main.stringReader, ptr %0, i32 0, i32 1
%12 = load i64, ptr %11, align 4
%13 = extractvalue %"github.com/goplus/llgo/internal/runtime.String" %10, 1
%14 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewStringSlice"(%"github.com/goplus/llgo/internal/runtime.String" %10, i64 %12, i64 %13)
%14 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.StringSlice"(%"github.com/goplus/llgo/internal/runtime.String" %10, i64 %12, i64 %13)
%15 = call { i64, %"github.com/goplus/llgo/internal/runtime.iface" } @main.WriteString(%"github.com/goplus/llgo/internal/runtime.iface" %1, %"github.com/goplus/llgo/internal/runtime.String" %14)
%16 = extractvalue { i64, %"github.com/goplus/llgo/internal/runtime.iface" } %15, 0
%17 = extractvalue { i64, %"github.com/goplus/llgo/internal/runtime.iface" } %15, 1
@@ -2724,7 +2724,7 @@ declare void @"github.com/goplus/llgo/internal/runtime.PrintIface"(%"github.com/
declare void @"github.com/goplus/llgo/internal/runtime.Panic"(%"github.com/goplus/llgo/internal/runtime.eface")
declare %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewStringSlice"(%"github.com/goplus/llgo/internal/runtime.String", i64, i64)
declare %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.StringSlice"(%"github.com/goplus/llgo/internal/runtime.String", i64, i64)
declare i64 @"github.com/goplus/llgo/internal/runtime.SliceCopy"(%"github.com/goplus/llgo/internal/runtime.Slice", ptr, i64, i64)

View File

@@ -229,14 +229,14 @@ _llgo_0:
store i64 5, ptr %74, align 4
%75 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %72, align 8
%76 = extractvalue %"github.com/goplus/llgo/internal/runtime.String" %75, 1
%77 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewStringSlice"(%"github.com/goplus/llgo/internal/runtime.String" %75, i64 1, i64 %76)
%77 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.StringSlice"(%"github.com/goplus/llgo/internal/runtime.String" %75, i64 1, i64 %76)
%78 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8
%79 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %78, i32 0, i32 0
store ptr @0, ptr %79, align 8
%80 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %78, i32 0, i32 1
store i64 5, ptr %80, align 4
%81 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %78, align 8
%82 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewStringSlice"(%"github.com/goplus/llgo/internal/runtime.String" %81, i64 1, i64 2)
%82 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.StringSlice"(%"github.com/goplus/llgo/internal/runtime.String" %81, i64 1, i64 2)
%83 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8
%84 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %83, i32 0, i32 0
store ptr @0, ptr %84, align 8
@@ -244,7 +244,7 @@ _llgo_0:
store i64 5, ptr %85, align 4
%86 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %83, align 8
%87 = extractvalue %"github.com/goplus/llgo/internal/runtime.String" %86, 1
%88 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewStringSlice"(%"github.com/goplus/llgo/internal/runtime.String" %86, i64 5, i64 %87)
%88 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.StringSlice"(%"github.com/goplus/llgo/internal/runtime.String" %86, i64 5, i64 %87)
%89 = extractvalue %"github.com/goplus/llgo/internal/runtime.String" %88, 1
%90 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8
%91 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %90, i32 0, i32 0
@@ -654,7 +654,7 @@ declare void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8)
declare void @"github.com/goplus/llgo/internal/runtime.PrintInt"(i64)
declare %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewStringSlice"(%"github.com/goplus/llgo/internal/runtime.String", i64, i64)
declare %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.StringSlice"(%"github.com/goplus/llgo/internal/runtime.String", i64, i64)
declare void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String")

View File

@@ -381,8 +381,9 @@ const (
llgoAllocaCStr = llgoInstrBase + 3
llgoAdvance = llgoInstrBase + 4
llgoIndex = llgoInstrBase + 5
llgoStringData = llgoInstrBase + 6
llgoDeferData = llgoInstrBase + 7
llgoDeferData = llgoInstrBase + 6
llgoStringData = llgoInstrBase + 7
llgoString = llgoInstrBase + 8
llgoSigjmpbuf = llgoInstrBase + 0xa
llgoSigsetjmp = llgoInstrBase + 0xb

View File

@@ -74,6 +74,17 @@ func (p *context) allocaCStr(b llssa.Builder, args []ssa.Value) (ret llssa.Expr)
panic("allocaCStr(s string): invalid arguments")
}
// func string(cstr *int8, n ...int) *int8
func (p *context) string(b llssa.Builder, args []ssa.Value) (ret llssa.Expr) {
if len(args) == 2 {
cstr := p.compileValue(b, args[0])
n := make([]llssa.Expr, 0, 1)
n = p.compileVArg(n, b, args[1])
return b.MakeString(cstr, n...)
}
panic("string(cstr *int8, n ...int): invalid arguments")
}
// func stringData(s string) *int8
func (p *context) stringData(b llssa.Builder, args []ssa.Value) (ret llssa.Expr) {
if len(args) == 1 {
@@ -147,6 +158,7 @@ var llgoInstrs = map[string]int{
"index": llgoIndex,
"alloca": llgoAlloca,
"allocaCStr": llgoAllocaCStr,
"string": llgoString,
"stringData": llgoStringData,
"pyList": llgoPyList,
"sigjmpbuf": llgoSigjmpbuf,
@@ -297,6 +309,8 @@ func (p *context) call(b llssa.Builder, act llssa.DoAction, call *ssa.CallCommon
ret = p.alloca(b, args)
case llgoAllocaCStr:
ret = p.allocaCStr(b, args)
case llgoString:
ret = p.string(b, args)
case llgoStringData:
ret = p.stringData(b, args)
case llgoAtomicLoad:

View File

@@ -86,12 +86,12 @@ func toMode(mode FileMode) os.ModeT {
panic("todo")
}
func toPathErr(op, path string, errno c.Int) error {
func toSyscallErr(errno c.Int) error {
panic("todo")
}
func toSyscallErr(errno c.Int) error {
panic("todo")
func toPathErr(op, path string, errno c.Int) error {
return &PathError{Op: op, Path: path, Err: toSyscallErr(errno)}
}
func Chdir(dir string) error {
@@ -255,7 +255,7 @@ func Setenv(key, value string) error {
if ret == 0 {
return nil
}
return &SyscallError{Syscall: "setenv", Err: toSyscallErr(ret)}
return &SyscallError{"setenv", toSyscallErr(ret)}
}
func Symlink(oldname, newname string) error {

View File

@@ -50,8 +50,7 @@ func StringCat(a, b String) String {
func CStrCopy(dest unsafe.Pointer, s String) *int8 {
n := s.len
c.Memcpy(dest, s.data, uintptr(n))
arr := (*[1 << 30]int8)(dest)
arr[n] = 0
*(*int8)(c.Advance(dest, n)) = 0
return (*int8)(dest)
}
@@ -60,7 +59,7 @@ func CStrDup(s String) *int8 {
return CStrCopy(dest, s)
}
func NewStringSlice(base String, i, j int) String {
func StringSlice(base String, i, j int) String {
if i < 0 || j < i || j > base.len {
panic("string slice index out of bounds")
}
@@ -121,13 +120,21 @@ func StringToRunes(s string) []rune {
return data[:index:index]
}
func StringFromCStr(cstr *int8) (s String) {
return StringFrom(unsafe.Pointer(cstr), int(c.Strlen(cstr)))
}
func StringFromBytes(b Slice) (s String) {
if b.len == 0 {
return StringFrom(b.data, b.len)
}
func StringFrom(data unsafe.Pointer, n int) (s String) {
if n == 0 {
return
}
s.len = b.len
s.data = AllocU(uintptr(s.len))
c.Memcpy(s.data, b.data, uintptr(b.len))
s.len = n
s.data = AllocU(uintptr(n))
c.Memcpy(s.data, data, uintptr(n))
return
}

View File

@@ -64,6 +64,21 @@ func (b Builder) getField(x Expr, idx int) Expr {
return Expr{fld, tfld}
}
// -----------------------------------------------------------------------------
// MakeString creates a new string from a C string pointer and length.
func (b Builder) MakeString(cstr Expr, n ...Expr) Expr {
if debugInstr {
log.Printf("MakeString %v\n", cstr.impl)
}
pkg := b.Pkg
if len(n) == 0 {
return b.Call(pkg.rtFunc("StringFromCStr"), cstr)
}
// TODO(xsw): remove Convert
return b.Call(pkg.rtFunc("StringFrom"), cstr, b.Convert(b.Prog.Int(), n[0]))
}
// StringData returns the data pointer of a string.
func (b Builder) StringData(x Expr) Expr {
if debugInstr {
@@ -82,6 +97,8 @@ func (b Builder) StringLen(x Expr) Expr {
return Expr{ptr, b.Prog.Int()}
}
// -----------------------------------------------------------------------------
// SliceData returns the data pointer of a slice.
func (b Builder) SliceData(x Expr) Expr {
if debugInstr {
@@ -109,6 +126,8 @@ func (b Builder) SliceCap(x Expr) Expr {
return Expr{ptr, b.Prog.Int()}
}
// -----------------------------------------------------------------------------
// The IndexAddr instruction yields the address of the element at
// index `idx` of collection `x`. `idx` is an integer expression.
//
@@ -277,6 +296,8 @@ func (b Builder) Index(x, idx Expr, addr func(Expr) (Expr, bool)) Expr {
return b.Load(buf)
}
// -----------------------------------------------------------------------------
// The Slice instruction yields a slice of an existing string, slice
// or *array X between optional integer bounds Low and High.
//
@@ -310,7 +331,7 @@ func (b Builder) Slice(x, low, high, max Expr) (ret Expr) {
high = b.StringLen(x)
}
ret.Type = x.Type
ret.impl = b.InlineCall(b.Pkg.rtFunc("NewStringSlice"), x, low, high).impl
ret.impl = b.InlineCall(b.Pkg.rtFunc("StringSlice"), x, low, high).impl
return
case *types.Slice:
nEltSize = SizeOf(prog, prog.Index(x.Type))