diff --git a/c/c.go b/c/c.go index 7e8e34b0..bf856138 100644 --- a/c/c.go +++ b/c/c.go @@ -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 diff --git a/cl/_testdata/utf8/out.ll b/cl/_testdata/utf8/out.ll index 28780d33..eac45eb9 100644 --- a/cl/_testdata/utf8/out.ll +++ b/cl/_testdata/utf8/out.ll @@ -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") diff --git a/cl/_testgo/reader/out.ll b/cl/_testgo/reader/out.ll index 59ee281c..e6dde2b4 100644 --- a/cl/_testgo/reader/out.ll +++ b/cl/_testgo/reader/out.ll @@ -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) diff --git a/cl/_testrt/builtin/out.ll b/cl/_testrt/builtin/out.ll index cbcc1a53..78acbf57 100644 --- a/cl/_testrt/builtin/out.ll +++ b/cl/_testrt/builtin/out.ll @@ -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") diff --git a/cl/import.go b/cl/import.go index 9244c90e..1d28858e 100644 --- a/cl/import.go +++ b/cl/import.go @@ -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 diff --git a/cl/instr.go b/cl/instr.go index 9edc144e..7c19a9e0 100644 --- a/cl/instr.go +++ b/cl/instr.go @@ -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: diff --git a/internal/lib/os/os.go b/internal/lib/os/os.go index d250a7e6..2377b589 100644 --- a/internal/lib/os/os.go +++ b/internal/lib/os/os.go @@ -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 { diff --git a/internal/runtime/z_string.go b/internal/runtime/z_string.go index da56b161..e38f3495 100644 --- a/internal/runtime/z_string.go +++ b/internal/runtime/z_string.go @@ -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 } diff --git a/ssa/datastruct.go b/ssa/datastruct.go index 15bc90af..aed82763 100644 --- a/ssa/datastruct.go +++ b/ssa/datastruct.go @@ -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))