diff --git a/cl/_testdata/print/in.go b/cl/_testdata/print/in.go new file mode 100644 index 00000000..8ab1f11c --- /dev/null +++ b/cl/_testdata/print/in.go @@ -0,0 +1,174 @@ +package main + +import ( + "unsafe" + + "github.com/goplus/llgo/internal/runtime/c" +) + +func gwrite(b []byte) { + if len(b) == 0 { + return + } + for _, v := range b { + c.Printf(c.Str("%c"), v) + } +} + +// func printfloat(v float64) { +// switch { +// case v != v: +// printstring("NaN") +// return +// case v+v == v && v > 0: +// printstring("+Inf") +// return +// case v+v == v && v < 0: +// printstring("-Inf") +// return +// } + +// const n = 7 // digits printed +// var buf [n + 7]byte +// buf[0] = '+' +// e := 0 // exp +// if v == 0 { +// if 1/v < 0 { +// buf[0] = '-' +// } +// } else { +// if v < 0 { +// v = -v +// buf[0] = '-' +// } + +// // normalize +// for v >= 10 { +// e++ +// v /= 10 +// } +// for v < 1 { +// e-- +// v *= 10 +// } + +// // round +// h := 5.0 +// for i := 0; i < n; i++ { +// h /= 10 +// } +// v += h +// if v >= 10 { +// e++ +// v /= 10 +// } +// } + +// // format +d.dddd+edd +// for i := 0; i < n; i++ { +// s := int(v) +// buf[i+2] = byte(s + '0') +// v -= float64(s) +// v *= 10 +// } +// buf[1] = buf[2] +// buf[2] = '.' + +// buf[n+2] = 'e' +// buf[n+3] = '+' +// if e < 0 { +// e = -e +// buf[n+3] = '-' +// } + +// buf[n+4] = byte(e/100) + '0' +// buf[n+5] = byte(e/10)%10 + '0' +// buf[n+6] = byte(e%10) + '0' +// gwrite(buf[:]) +// } + +func printuint(v uint64) { + var buf [100]byte + i := len(buf) + for i--; i > 0; i-- { + buf[i] = byte(v%10 + '0') + if v < 10 { + break + } + v /= 10 + } + gwrite(buf[i:]) +} + +// func printint(v int64) { +// if v < 0 { +// printstring("-") +// v = -v +// } +// printuint(uint64(v)) +// } + +var minhexdigits = 0 + +func printhex(v uint64) { + const dig = "0123456789abcdef" + var buf [100]byte + i := len(buf) + for i--; i > 0; i-- { + buf[i] = dig[v%16] + if v < 16 && len(buf)-i >= minhexdigits { + break + } + v /= 16 + } + i-- + buf[i] = 'x' + i-- + buf[i] = '0' + gwrite(buf[i:]) +} + +func printsp() { + printstring(" ") +} + +func printnl() { + printstring("\n") +} + +func printstring(s string) { + gwrite(bytes(s)) +} + +type slice struct { + array unsafe.Pointer + len int + cap int +} + +type stringStruct struct { + str unsafe.Pointer + len int +} + +func stringStructOf(sp *string) *stringStruct { + return (*stringStruct)(unsafe.Pointer(sp)) +} + +func bytes(s string) (ret []byte) { + rp := (*slice)(unsafe.Pointer(&ret)) + sp := stringStructOf(&s) + rp.array = sp.str + rp.len = sp.len + rp.cap = sp.len + return +} + +func main() { + printstring("llgo") + printnl() + printuint(1024) + printnl() + printhex(0x1234abcf) + printnl() +} diff --git a/cl/_testdata/print/out.ll b/cl/_testdata/print/out.ll new file mode 100644 index 00000000..b8256d6e --- /dev/null +++ b/cl/_testdata/print/out.ll @@ -0,0 +1,213 @@ +; ModuleID = 'main' +source_filename = "main" + +%"github.com/goplus/llgo/internal/runtime.Slice" = type { ptr, i64, i64 } +%"github.com/goplus/llgo/internal/runtime.String" = type { ptr, i64 } +%main.stringStruct = type { ptr, i64 } +%main.slice = type { ptr, i64, i64 } + +@"main.init$guard" = global ptr null +@main.minhexdigits = global ptr null +@0 = private unnamed_addr constant [3 x i8] c"%c\00", align 1 +@1 = private unnamed_addr constant [5 x i8] c"llgo\00", align 1 +@2 = private unnamed_addr constant [17 x i8] c"0123456789abcdef\00", align 1 +@3 = private unnamed_addr constant [2 x i8] c"\0A\00", align 1 +@4 = private unnamed_addr constant [2 x i8] c" \00", align 1 + +define %"github.com/goplus/llgo/internal/runtime.Slice" @main.bytes(%"github.com/goplus/llgo/internal/runtime.String" %0) { +_llgo_0: + %1 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocZ"(i64 16) + store %"github.com/goplus/llgo/internal/runtime.String" %0, ptr %1, align 8 + %2 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocZ"(i64 24) + %3 = call ptr @main.stringStructOf(ptr %1) + %4 = getelementptr inbounds %main.stringStruct, ptr %3, i32 0, i32 0 + %5 = load ptr, ptr %4, align 8 + %6 = getelementptr inbounds %main.slice, ptr %2, i32 0, i32 0 + store ptr %5, ptr %6, align 8 + %7 = getelementptr inbounds %main.stringStruct, ptr %3, i32 0, i32 1 + %8 = load i64, ptr %7, align 4 + %9 = getelementptr inbounds %main.slice, ptr %2, i32 0, i32 1 + store i64 %8, ptr %9, align 4 + %10 = getelementptr inbounds %main.stringStruct, ptr %3, i32 0, i32 1 + %11 = load i64, ptr %10, align 4 + %12 = getelementptr inbounds %main.slice, ptr %2, i32 0, i32 2 + store i64 %11, ptr %12, align 4 + %13 = load %"github.com/goplus/llgo/internal/runtime.Slice", ptr %2, align 8 + ret %"github.com/goplus/llgo/internal/runtime.Slice" %13 +} + +define void @main.gwrite(%"github.com/goplus/llgo/internal/runtime.Slice" %0) { +_llgo_0: + %1 = call i64 @"github.com/goplus/llgo/internal/runtime.SliceLen"(%"github.com/goplus/llgo/internal/runtime.Slice" %0) + %2 = icmp eq i64 %1, 0 + br i1 %2, label %_llgo_1, label %_llgo_2 + +_llgo_1: ; preds = %_llgo_0 + ret void + +_llgo_2: ; preds = %_llgo_0 + %3 = call i64 @"github.com/goplus/llgo/internal/runtime.SliceLen"(%"github.com/goplus/llgo/internal/runtime.Slice" %0) + br label %_llgo_3 + +_llgo_3: ; preds = %_llgo_4, %_llgo_2 + %4 = phi i64 [ -1, %_llgo_2 ], [ %5, %_llgo_4 ] + %5 = add i64 %4, 1 + %6 = icmp slt i64 %5, %3 + br i1 %6, label %_llgo_4, label %_llgo_5 + +_llgo_4: ; preds = %_llgo_3 + %7 = call ptr @"github.com/goplus/llgo/internal/runtime.SliceData"(%"github.com/goplus/llgo/internal/runtime.Slice" %0) + %8 = getelementptr inbounds i8, ptr %7, i64 %5 + %9 = load i8, ptr %8, align 1 + %10 = call i32 (ptr, ...) @printf(ptr @0, i8 %9) + br label %_llgo_3 + +_llgo_5: ; preds = %_llgo_3 + ret void +} + +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 + store i64 0, ptr @main.minhexdigits, align 4 + br label %_llgo_2 + +_llgo_2: ; preds = %_llgo_1, %_llgo_0 + ret void +} + +define void @main() { +_llgo_0: + call void @"github.com/goplus/llgo/internal/runtime.init"() + call void @main.init() + %0 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr @1, i64 4) + call void @main.printstring(%"github.com/goplus/llgo/internal/runtime.String" %0) + call void @main.printnl() + call void @main.printuint(i64 1024) + call void @main.printnl() + call void @main.printhex(i64 305441743) + call void @main.printnl() + ret void +} + +define void @main.printhex(i64 %0) { +_llgo_0: + %1 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocZ"(i64 100) + br label %_llgo_3 + +_llgo_1: ; preds = %_llgo_3 + %2 = urem i64 %14, 16 + %3 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr @2, i64 16) + %4 = call ptr @"github.com/goplus/llgo/internal/runtime.StringData"(%"github.com/goplus/llgo/internal/runtime.String" %3) + %5 = getelementptr inbounds i8, ptr %4, i64 %2 + %6 = load i8, ptr %5, align 1 + %7 = getelementptr inbounds i8, ptr %1, i64 %15 + store i8 %6, ptr %7, align 1 + %8 = icmp ult i64 %14, 16 + br i1 %8, label %_llgo_5, label %_llgo_4 + +_llgo_2: ; preds = %_llgo_5, %_llgo_3 + %9 = sub i64 %15, 1 + %10 = getelementptr inbounds i8, ptr %1, i64 %9 + store i8 120, ptr %10, align 1 + %11 = sub i64 %9, 1 + %12 = getelementptr inbounds i8, ptr %1, i64 %11 + store i8 48, ptr %12, align 1 + %13 = call %"github.com/goplus/llgo/internal/runtime.Slice" @"github.com/goplus/llgo/internal/runtime.NewSlice3"(ptr %1, i64 1, i64 100, i64 %11, i64 100, i64 100) + call void @main.gwrite(%"github.com/goplus/llgo/internal/runtime.Slice" %13) + ret void + +_llgo_3: ; preds = %_llgo_4, %_llgo_0 + %14 = phi i64 [ %0, %_llgo_0 ], [ %17, %_llgo_4 ] + %15 = phi i64 [ 99, %_llgo_0 ], [ %18, %_llgo_4 ] + %16 = icmp sgt i64 %15, 0 + br i1 %16, label %_llgo_1, label %_llgo_2 + +_llgo_4: ; preds = %_llgo_5, %_llgo_1 + %17 = udiv i64 %14, 16 + %18 = sub i64 %15, 1 + br label %_llgo_3 + +_llgo_5: ; preds = %_llgo_1 + %19 = sub i64 100, %15 + %20 = load i64, ptr @main.minhexdigits, align 4 + %21 = icmp sge i64 %19, %20 + br i1 %21, label %_llgo_2, label %_llgo_4 +} + +define void @main.printnl() { +_llgo_0: + %0 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr @3, i64 1) + call void @main.printstring(%"github.com/goplus/llgo/internal/runtime.String" %0) + ret void +} + +define void @main.printsp() { +_llgo_0: + %0 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr @4, i64 1) + call void @main.printstring(%"github.com/goplus/llgo/internal/runtime.String" %0) + ret void +} + +define void @main.printstring(%"github.com/goplus/llgo/internal/runtime.String" %0) { +_llgo_0: + %1 = call %"github.com/goplus/llgo/internal/runtime.Slice" @main.bytes(%"github.com/goplus/llgo/internal/runtime.String" %0) + call void @main.gwrite(%"github.com/goplus/llgo/internal/runtime.Slice" %1) + ret void +} + +define void @main.printuint(i64 %0) { +_llgo_0: + %1 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocZ"(i64 100) + br label %_llgo_3 + +_llgo_1: ; preds = %_llgo_3 + %2 = urem i64 %8, 10 + %3 = add i64 %2, 48 + %4 = trunc i64 %3 to i8 + %5 = getelementptr inbounds i8, ptr %1, i64 %9 + store i8 %4, ptr %5, align 1 + %6 = icmp ult i64 %8, 10 + br i1 %6, label %_llgo_2, label %_llgo_4 + +_llgo_2: ; preds = %_llgo_3, %_llgo_1 + %7 = call %"github.com/goplus/llgo/internal/runtime.Slice" @"github.com/goplus/llgo/internal/runtime.NewSlice3"(ptr %1, i64 1, i64 100, i64 %9, i64 100, i64 100) + call void @main.gwrite(%"github.com/goplus/llgo/internal/runtime.Slice" %7) + ret void + +_llgo_3: ; preds = %_llgo_4, %_llgo_0 + %8 = phi i64 [ %0, %_llgo_0 ], [ %11, %_llgo_4 ] + %9 = phi i64 [ 99, %_llgo_0 ], [ %12, %_llgo_4 ] + %10 = icmp sgt i64 %9, 0 + br i1 %10, label %_llgo_1, label %_llgo_2 + +_llgo_4: ; preds = %_llgo_1 + %11 = udiv i64 %8, 10 + %12 = sub i64 %9, 1 + br label %_llgo_3 +} + +define ptr @main.stringStructOf(ptr %0) { +_llgo_0: + ret ptr %0 +} + +declare ptr @"github.com/goplus/llgo/internal/runtime.AllocZ"(i64) + +declare i64 @"github.com/goplus/llgo/internal/runtime.SliceLen"(%"github.com/goplus/llgo/internal/runtime.Slice") + +declare ptr @"github.com/goplus/llgo/internal/runtime.SliceData"(%"github.com/goplus/llgo/internal/runtime.Slice") + +declare i32 @printf(ptr, ...) + +declare void @"github.com/goplus/llgo/internal/runtime.init"() + +declare %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr, i64) + +declare ptr @"github.com/goplus/llgo/internal/runtime.StringData"(%"github.com/goplus/llgo/internal/runtime.String") + +declare %"github.com/goplus/llgo/internal/runtime.Slice" @"github.com/goplus/llgo/internal/runtime.NewSlice3"(ptr, i64, i64, i64, i64, i64) diff --git a/cl/compile.go b/cl/compile.go index bee1a4f4..954412c9 100644 --- a/cl/compile.go +++ b/cl/compile.go @@ -242,8 +242,12 @@ func (p *context) compileFuncDecl(pkg llssa.Package, pkgTypes *types.Package, f } b := fn.NewBuilder() p.bvals = make(map[ssa.Value]llssa.Expr) + off := make([]int, len(f.Blocks)) for i, block := range f.Blocks { - p.compileBlock(b, block, i == 0 && name == "main") + off[i] = p.compilePhis(b, block) + } + for i, block := range f.Blocks { + p.compileBlock(b, block, off[i], i == 0 && name == "main") } for _, phi := range p.phis { phi() @@ -281,7 +285,7 @@ func (p *context) funcOf(fn *ssa.Function) (ret llssa.Function, ftype int) { return } -func (p *context) compileBlock(b llssa.Builder, block *ssa.BasicBlock, doInit bool) llssa.BasicBlock { +func (p *context) compileBlock(b llssa.Builder, block *ssa.BasicBlock, n int, doInit bool) llssa.BasicBlock { ret := p.fn.Block(block.Index) b.SetBlock(ret) if doInit { @@ -289,8 +293,7 @@ func (p *context) compileBlock(b llssa.Builder, block *ssa.BasicBlock, doInit bo callRuntimeInit(b, pkg) b.Call(pkg.FuncOf("main.init").Expr) } - instrs := p.compilePhis(b, block.Instrs) - for _, instr := range instrs { + for _, instr := range block.Instrs[n:] { p.compileInstr(b, instr) } return ret @@ -386,26 +389,28 @@ func isPhi(i ssa.Instruction) bool { return ok } -func (p *context) compilePhis(b llssa.Builder, instrs []ssa.Instruction) []ssa.Instruction { - if ninstr := len(instrs); ninstr > 0 { - if isPhi(instrs[0]) { +func (p *context) compilePhis(b llssa.Builder, block *ssa.BasicBlock) int { + ret := p.fn.Block(block.Index) + b.SetBlock(ret) + if ninstr := len(block.Instrs); ninstr > 0 { + if isPhi(block.Instrs[0]) { n := 1 - for n < ninstr && isPhi(instrs[n]) { + for n < ninstr && isPhi(block.Instrs[n]) { n++ } rets := make([]llssa.Expr, n) for i := 0; i < n; i++ { - iv := instrs[i].(*ssa.Phi) + iv := block.Instrs[i].(*ssa.Phi) rets[i] = p.compilePhi(b, iv) } for i := 0; i < n; i++ { - iv := instrs[i].(*ssa.Phi) + iv := block.Instrs[i].(*ssa.Phi) p.bvals[iv] = rets[i].Do(b) } - return instrs[n:] + return n } } - return instrs + return 0 } func (p *context) compilePhi(b llssa.Builder, v *ssa.Phi) (ret llssa.Expr) {