diff --git a/cl/_testcgo/alloca/in.go b/cl/_testcgo/alloca/in.go new file mode 100644 index 00000000..83452977 --- /dev/null +++ b/cl/_testcgo/alloca/in.go @@ -0,0 +1,14 @@ +package main + +import ( + "unsafe" + + "github.com/goplus/llgo/internal/runtime/c" +) + +func main() { + s := c.String("Hi\n") + s2 := c.Alloca(4) + c.Memcpy(s2, unsafe.Pointer(s), 4) + c.Printf(c.String("%s"), s) +} diff --git a/cl/_testcgo/alloca/out.ll b/cl/_testcgo/alloca/out.ll new file mode 100644 index 00000000..44cd672d --- /dev/null +++ b/cl/_testcgo/alloca/out.ll @@ -0,0 +1,36 @@ +; ModuleID = 'main' +source_filename = "main" + +%"github.com/goplus/llgo/internal/runtime.String" = type { ptr, i64 } + +@"main.init$guard" = global ptr null + +define void @main.init() { +_llgo_0: + %0 = load i1, ptr @"main.init$guard", align 1 + br i1 %0, label %_llgo_2, label %_llgo_1 + +_llgo_1: ; preds = %_llgo_0 + store i1 true, ptr @"main.init$guard", align 1 + br label %_llgo_2 + +_llgo_2: ; preds = %_llgo_1, %_llgo_0 + ret void +} + +define void @main() { +_llgo_0: + call void @main.init() + %0 = call ptr @"github.com/goplus/llgo/internal/runtime/c.String"([4 x i8] c"Hi\0A\00") + %1 = alloca i8, i64 4, align 1 + %2 = call ptr @memcpy(ptr %1, ptr %0, i64 4) + %3 = call ptr @"github.com/goplus/llgo/internal/runtime/c.String"([3 x i8] c"%s\00") + %4 = call i32 (ptr, ...) @printf(ptr %3, ptr %0) + ret void +} + +declare ptr @"github.com/goplus/llgo/internal/runtime/c.String"(%"github.com/goplus/llgo/internal/runtime.String") + +declare ptr @memcpy(ptr, ptr, i64) + +declare i32 @printf(ptr, ...) diff --git a/cl/_testdata/cstr/in.go b/cl/_testcgo/cstr/in.go similarity index 100% rename from cl/_testdata/cstr/in.go rename to cl/_testcgo/cstr/in.go diff --git a/cl/_testdata/cstr/out.ll b/cl/_testcgo/cstr/out.ll similarity index 100% rename from cl/_testdata/cstr/out.ll rename to cl/_testcgo/cstr/out.ll diff --git a/cl/compile.go b/cl/compile.go index 1c10d564..4782e8b1 100644 --- a/cl/compile.go +++ b/cl/compile.go @@ -282,6 +282,14 @@ func cstr(b llssa.Builder, args []ssa.Value) (ret llssa.Expr) { panic("cstr(): invalid arguments") } +func (p *context) alloca(b llssa.Builder, args []ssa.Value) (ret llssa.Expr) { + if len(args) == 1 { + n := p.compileValue(b, args[0]) + return b.Alloca(n) + } + panic("alloca(size uintptr): invalid arguments") +} + func (p *context) compileInstrOrValue(b llssa.Builder, iv instrOrValue, asValue bool) (ret llssa.Expr) { if asValue { if v, ok := p.bvals[iv]; ok { @@ -319,6 +327,8 @@ func (p *context) compileInstrOrValue(b llssa.Builder, iv instrOrValue, asValue ret = b.Call(fn.Expr, args...) case llgoCstr: ret = cstr(b, call.Args) + case llgoAlloca: + ret = p.alloca(b, call.Args) default: panic("todo") } diff --git a/internal/runtime/c/c.go b/internal/runtime/c/c.go index d3914551..7c11ea9a 100644 --- a/internal/runtime/c/c.go +++ b/internal/runtime/c/c.go @@ -16,6 +16,7 @@ package c +import "C" import "unsafe" const ( @@ -38,4 +39,4 @@ func Malloc(size uintptr) unsafe.Pointer func Memcpy(dst, src unsafe.Pointer, n uintptr) unsafe.Pointer //go:linkname Printf C.printf -func Printf(format *int8, __llgo_va_list ...any) +func Printf(format *int8, __llgo_va_list ...any) C.int diff --git a/ssa/expr.go b/ssa/expr.go index e38961eb..817bb55c 100644 --- a/ssa/expr.go +++ b/ssa/expr.go @@ -420,6 +420,28 @@ func (b Builder) Alloc(t *types.Pointer, heap bool) (ret Expr) { return } +// Alloca allocates space for n bytes. +func (b Builder) Alloca(n Expr) (ret Expr) { + if debugInstr { + log.Printf("Alloca %v\n", n.impl) + } + prog := b.Prog + telem := prog.tyInt8() + ret.impl = llvm.CreateArrayAlloca(b.impl, telem, n.impl) + ret.Type = &aType{prog.tyVoidPtr(), types.Typ[types.UnsafePointer], vkPtr} + return +} + +// ArrayAlloca reserves space for an array of n elements of type telem. +func (b Builder) ArrayAlloca(telem Type, n Expr) (ret Expr) { + if debugInstr { + log.Printf("ArrayAlloca %v, %v\n", telem.t, n.impl) + } + ret.impl = llvm.CreateArrayAlloca(b.impl, telem.ll, n.impl) + ret.Type = b.Prog.Pointer(telem) + return +} + // The ChangeType instruction applies to X a value-preserving type // change to Type(). //