diff --git a/cl/_testgo/strucintf/out.ll b/cl/_testgo/strucintf/out.ll index e69de29b..de0f7f58 100644 --- a/cl/_testgo/strucintf/out.ll +++ b/cl/_testgo/strucintf/out.ll @@ -0,0 +1,150 @@ +; ModuleID = 'main' +source_filename = "main" + +%"github.com/goplus/llgo/internal/runtime.eface" = type { ptr, ptr } +%"github.com/goplus/llgo/internal/runtime.String" = type { ptr, i64 } + +@"main.init$guard" = global ptr null +@__llgo_argc = global ptr null +@__llgo_argv = global ptr null +@"_llgo_struct$K-dZ9QotZfVPz2a0YdRa9vmZUuDXPTqZOlMShKEDJtk" = global ptr null +@"main.struct$MYpsoM99ZwFY087IpUOkIw1zjBA_sgFXVodmn1m-G88" = global ptr null +@0 = private unnamed_addr constant [12 x i8] c"Bar: not ok\00", align 1 +@1 = private unnamed_addr constant [10 x i8] c"F: not ok\00", align 1 + +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 + call void @"github.com/goplus/llgo/_demo/interf/foo.init"() + br label %_llgo_2 + +_llgo_2: ; preds = %_llgo_1, %_llgo_0 + ret void +} + +define i32 @main(i32 %0, ptr %1) { +_llgo_0: + store i32 %0, ptr @__llgo_argc, align 4 + store ptr %1, ptr @__llgo_argv, align 8 + call void @"github.com/goplus/llgo/internal/runtime.init"() + call void @main.init() + %2 = alloca { i64 }, align 8 + %3 = call ptr @"github.com/goplus/llgo/internal/runtime.Zeroinit"(ptr %2, i64 8) + %4 = call %"github.com/goplus/llgo/internal/runtime.eface" @"github.com/goplus/llgo/_demo/interf/foo.Bar"() + %5 = extractvalue %"github.com/goplus/llgo/internal/runtime.eface" %4, 0 + %6 = load ptr, ptr @"_llgo_struct$K-dZ9QotZfVPz2a0YdRa9vmZUuDXPTqZOlMShKEDJtk", align 8 + %7 = icmp eq ptr %5, %6 + %8 = extractvalue %"github.com/goplus/llgo/internal/runtime.eface" %4, 1 + %9 = ptrtoint ptr %8 to i64 + %10 = alloca { i64 }, align 8 + %11 = getelementptr inbounds { i64 }, ptr %10, i32 0, i32 0 + store i64 %9, ptr %11, align 4 + %12 = load { i64 }, ptr %10, align 4 + %13 = alloca { { i64 }, i1 }, align 8 + %14 = getelementptr inbounds { { i64 }, i1 }, ptr %13, i32 0, i32 0 + store { i64 } %12, ptr %14, align 4 + %15 = getelementptr inbounds { { i64 }, i1 }, ptr %13, i32 0, i32 1 + store i1 true, ptr %15, align 1 + %16 = load { { i64 }, i1 }, ptr %13, align 4 + %17 = alloca { { i64 }, i1 }, align 8 + %18 = getelementptr inbounds { { i64 }, i1 }, ptr %17, i32 0, i32 0 + store { i64 } zeroinitializer, ptr %18, align 4 + %19 = getelementptr inbounds { { i64 }, i1 }, ptr %17, i32 0, i32 1 + store i1 false, ptr %19, align 1 + %20 = load { { i64 }, i1 }, ptr %17, align 4 + %21 = select i1 %7, { { i64 }, i1 } %16, { { i64 }, i1 } %20 + %22 = extractvalue { { i64 }, i1 } %21, 0 + store { i64 } %22, ptr %3, align 4 + %23 = extractvalue { { i64 }, i1 } %21, 1 + br i1 %23, label %_llgo_1, label %_llgo_3 + +_llgo_1: ; preds = %_llgo_0 + %24 = getelementptr inbounds { i64 }, ptr %3, i32 0, i32 0 + %25 = load i64, ptr %24, align 4 + call void @"github.com/goplus/llgo/internal/runtime.PrintInt"(i64 %25) + call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 10) + br label %_llgo_2 + +_llgo_2: ; preds = %_llgo_3, %_llgo_1 + %26 = alloca { i64 }, align 8 + %27 = call ptr @"github.com/goplus/llgo/internal/runtime.Zeroinit"(ptr %26, i64 8) + %28 = call %"github.com/goplus/llgo/internal/runtime.eface" @"github.com/goplus/llgo/_demo/interf/foo.F"() + %29 = extractvalue %"github.com/goplus/llgo/internal/runtime.eface" %28, 0 + %30 = load ptr, ptr @"main.struct$MYpsoM99ZwFY087IpUOkIw1zjBA_sgFXVodmn1m-G88", align 8 + %31 = icmp eq ptr %29, %30 + %32 = extractvalue %"github.com/goplus/llgo/internal/runtime.eface" %28, 1 + %33 = ptrtoint ptr %32 to i64 + %34 = alloca { i64 }, align 8 + %35 = getelementptr inbounds { i64 }, ptr %34, i32 0, i32 0 + store i64 %33, ptr %35, align 4 + %36 = load { i64 }, ptr %34, align 4 + %37 = alloca { { i64 }, i1 }, align 8 + %38 = getelementptr inbounds { { i64 }, i1 }, ptr %37, i32 0, i32 0 + store { i64 } %36, ptr %38, align 4 + %39 = getelementptr inbounds { { i64 }, i1 }, ptr %37, i32 0, i32 1 + store i1 true, ptr %39, align 1 + %40 = load { { i64 }, i1 }, ptr %37, align 4 + %41 = alloca { { i64 }, i1 }, align 8 + %42 = getelementptr inbounds { { i64 }, i1 }, ptr %41, i32 0, i32 0 + store { i64 } zeroinitializer, ptr %42, align 4 + %43 = getelementptr inbounds { { i64 }, i1 }, ptr %41, i32 0, i32 1 + store i1 false, ptr %43, align 1 + %44 = load { { i64 }, i1 }, ptr %41, align 4 + %45 = select i1 %31, { { i64 }, i1 } %40, { { i64 }, i1 } %44 + %46 = extractvalue { { i64 }, i1 } %45, 0 + store { i64 } %46, ptr %27, align 4 + %47 = extractvalue { { i64 }, i1 } %45, 1 + br i1 %47, label %_llgo_4, label %_llgo_6 + +_llgo_3: ; preds = %_llgo_0 + %48 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8 + %49 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %48, i32 0, i32 0 + store ptr @0, ptr %49, align 8 + %50 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %48, i32 0, i32 1 + store i64 11, ptr %50, align 4 + %51 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %48, align 8 + call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %51) + call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 10) + br label %_llgo_2 + +_llgo_4: ; preds = %_llgo_2 + %52 = getelementptr inbounds { i64 }, ptr %27, i32 0, i32 0 + %53 = load i64, ptr %52, align 4 + call void @"github.com/goplus/llgo/internal/runtime.PrintInt"(i64 %53) + call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 10) + br label %_llgo_5 + +_llgo_5: ; preds = %_llgo_6, %_llgo_4 + ret i32 0 + +_llgo_6: ; preds = %_llgo_2 + %54 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8 + %55 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %54, i32 0, i32 0 + store ptr @1, ptr %55, align 8 + %56 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %54, i32 0, i32 1 + store i64 9, ptr %56, align 4 + %57 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %54, align 8 + call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %57) + call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 10) + br label %_llgo_5 +} + +declare void @"github.com/goplus/llgo/_demo/interf/foo.init"() + +declare void @"github.com/goplus/llgo/internal/runtime.init"() + +declare ptr @"github.com/goplus/llgo/internal/runtime.Zeroinit"(ptr, i64) + +declare %"github.com/goplus/llgo/internal/runtime.eface" @"github.com/goplus/llgo/_demo/interf/foo.Bar"() + +declare void @"github.com/goplus/llgo/internal/runtime.PrintInt"(i64) + +declare void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8) + +declare %"github.com/goplus/llgo/internal/runtime.eface" @"github.com/goplus/llgo/_demo/interf/foo.F"() + +declare void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String") diff --git a/ssa/abi/abi.go b/ssa/abi/abi.go index 14775932..05b09df6 100644 --- a/ssa/abi/abi.go +++ b/ssa/abi/abi.go @@ -36,41 +36,41 @@ const ( BitCast // store other value (need bitcast) directly in the interface value ) -func KindOf(raw types.Type, is32Bits bool) (ret Kind) { +func KindOf(raw types.Type, lvl int, is32Bits bool) (Kind, types.Type, int) { switch t := raw.Underlying().(type) { case *types.Basic: kind := t.Kind() switch { case types.Bool <= kind && kind <= types.Uintptr: if is32Bits && (kind == types.Int64 || kind == types.Uint64) { - return Indirect + return Indirect, raw, lvl } - return Integer + return Integer, raw, lvl case kind == types.Float32: - return BitCast + return BitCast, raw, lvl case kind == types.Float64 || kind == types.Complex64: if is32Bits { - return Indirect + return Indirect, raw, lvl } - return BitCast + return BitCast, raw, lvl case kind == types.UnsafePointer: - return Pointer + return Pointer, raw, lvl } case *types.Pointer, *types.Signature, *types.Map, *types.Chan: - return Pointer + return Pointer, raw, lvl case *types.Struct: if t.NumFields() == 1 { - return KindOf(t.Field(0).Type(), is32Bits) + return KindOf(t.Field(0).Type(), lvl+1, is32Bits) } case *types.Interface, *types.Slice: case *types.Array: if t.Len() == 1 { - return KindOf(t.Elem(), is32Bits) + return KindOf(t.Elem(), lvl+1, is32Bits) } default: panic("unkown type") } - return Indirect + return Indirect, raw, lvl } // ----------------------------------------------------------------------------- diff --git a/ssa/interface.go b/ssa/interface.go index 51a7900b..ea06e88f 100644 --- a/ssa/interface.go +++ b/ssa/interface.go @@ -178,23 +178,43 @@ func (b Builder) makeIntfByIntptr(tinter Type, rawIntf *types.Interface, typ Typ panic("todo") } -func (b Builder) valFromData(t Type, data Expr) Expr { - kind := abi.KindOf(t.raw.Type, b.Prog.is32Bits) +func (b Builder) valFromData(typ Type, data llvm.Value) Expr { + prog := b.Prog + kind, real, lvl := abi.KindOf(typ.raw.Type, 0, prog.is32Bits) switch kind { case abi.Indirect: impl := b.impl - tll := t.ll + tll := typ.ll tptr := llvm.PointerType(tll, 0) - ptr := llvm.CreatePointerCast(impl, data.impl, tptr) - return Expr{llvm.CreateLoad(impl, tll, ptr), t} + ptr := llvm.CreatePointerCast(impl, data, tptr) + return Expr{llvm.CreateLoad(impl, tll, ptr), typ} case abi.Pointer: - return Expr{data.impl, t} + return Expr{data, typ} + } + t := typ + if lvl > 0 { + t = prog.rawType(real) + } + switch kind { case abi.Integer: - x := castUintptr(b, data.impl, b.Prog.Uintptr()) - return Expr{castInt(b, x, t), t} + x := castUintptr(b, data, prog.Uintptr()) + return b.buildVal(typ, castInt(b, x, t), lvl) case abi.BitCast: - x := castUintptr(b, data.impl, b.Prog.Uintptr()) - return Expr{llvm.CreateBitCast(b.impl, x, t.ll), t} + x := castUintptr(b, data, prog.Uintptr()) + return b.buildVal(typ, llvm.CreateBitCast(b.impl, x, t.ll), lvl) + } + panic("todo") +} + +func (b Builder) buildVal(typ Type, val llvm.Value, lvl int) Expr { + if lvl == 0 { + return Expr{val, typ} + } + switch t := typ.raw.Type.Underlying().(type) { + case *types.Struct: + telem := b.Prog.rawType(t.Field(0).Type()) + elem := b.buildVal(telem, val, lvl-1) + return Expr{aggregateValue(b.impl, typ.ll, elem.impl), typ} } panic("todo") } @@ -248,7 +268,7 @@ func (b Builder) TypeAssert(x Expr, assertedTyp Type, commaOk bool) Expr { if commaOk { prog := b.Prog t := prog.Tuple(assertedTyp, prog.Bool()) - val := b.valFromData(assertedTyp, b.InterfaceData(x)) + val := b.valFromData(assertedTyp, b.faceData(x.impl)) zero := prog.Zero(assertedTyp) valTrue := aggregateValue(b.impl, t.ll, val.impl, prog.BoolVal(true).impl) valFalse := aggregateValue(b.impl, t.ll, zero.impl, prog.BoolVal(false).impl) @@ -259,7 +279,7 @@ func (b Builder) TypeAssert(x Expr, assertedTyp Type, commaOk bool) Expr { b.SetBlock(blks[1]) b.Panic(b.Str("type assertion failed")) b.SetBlock(blks[0]) - return b.valFromData(assertedTyp, b.InterfaceData(x)) + return b.valFromData(assertedTyp, b.faceData(x.impl)) } /* @@ -337,8 +357,11 @@ func (b Builder) InterfaceData(x Expr) Expr { if debugInstr { log.Printf("InterfaceData %v\n", x.impl) } - ptr := llvm.CreateExtractValue(b.impl, x.impl, 1) - return Expr{ptr, b.Prog.VoidPtr()} + return Expr{b.faceData(x.impl), b.Prog.VoidPtr()} +} + +func (b Builder) faceData(x llvm.Value) llvm.Value { + return llvm.CreateExtractValue(b.impl, x, 1) } func (b Builder) faceAbiType(x Expr) Expr {