func addTestStart(b *builder, testList ir.Ref, n int) { b.f = b.p.NewFunc(testStartName, nil, ir.VoidFuncSig) b.b = b.f.NewBlock(nil) argAddr := ir.Num(arch8.AddrBootArg) // the arg index := b.newTempIR(types.Uint) // to save the index b.b.Assign(index, ir.NewAddrRef(argAddr, arch8.RegSize, 0, false, true)) size := ir.Num(uint32(n)) checkInRange(b, index, size, "u<") base := b.newPtr() b.b.Arith(base, nil, "&", testList) addr := b.newPtr() b.b.Arith(addr, index, "*", ir.Num(arch8.RegSize)) b.b.Arith(addr, base, "+", addr) f := ir.NewFuncPtr( ir.VoidFuncSig, ir.NewAddrRef(addr, arch8.RegSize, 0, false, true), ) testMain := findFunc(b, "testMain", testMainFuncType) if testMain == nil { b.b.Call(nil, f) } else { b.b.Call(nil, testMain.ref.IR(), f) } }
func newSlice(b *builder, t types.T, addr, size ir.Ref) *ref { ret := b.newTemp(&types.Slice{T: t}) retAddr := b.newPtr() b.b.Arith(retAddr, nil, "&", ret.IR()) b.b.Assign(ir.NewAddrRef(retAddr, 4, 0, false, true), addr) b.b.Assign(ir.NewAddrRef(retAddr, 4, 4, false, true), size) return ret }
func loadArray(b *builder, array *ref) (addr, n ir.Ref, et types.T) { base := b.newPtr() t := array.Type() switch t := t.(type) { case *types.Array: b.b.Arith(base, nil, "&", array.IR()) return base, ir.Snum(t.N), t.T case *types.Slice: b.b.Arith(base, nil, "&", array.IR()) addr = ir.NewAddrRef(base, 4, 0, false, true) n = ir.NewAddrRef(base, 4, 4, false, true) return addr, n, t.T } panic("bug") }
func testNilSlice(b *builder, r *ref, neg bool) *ref { addr := b.newPtr() isNil := b.newCond() b.b.Arith(addr, nil, "&", r.IR()) b.b.Arith(isNil, nil, "?", ir.NewAddrRef(addr, 4, 0, false, true)) if neg { b.b.Arith(isNil, nil, "!", isNil) } return newRef(types.Bool, isNil) }
func buildField(b *builder, this ir.Ref, field *types.Field) *ref { retIR := ir.NewAddrRef( this, field.T.Size(), field.Offset(), types.IsByte(field.T), true, ) return newAddressableRef(field.T, retIR) }
func buildStarExpr(b *builder, expr *tast.StarExpr) *ref { addr := b.buildExpr(expr.Expr) nilPointerPanic(b, addr.IR()) t := addr.Type().(*types.Pointer).T retIR := ir.NewAddrRef( addr.IR(), // base t.Size(), // size 0, // offset types.IsBasic(t, types.Uint8), // is byte? t.RegSizeAlign(), // is aligned? ) return newAddressableRef(t, retIR) }
func binaryOpSlice(b *builder, op string, A, B *ref) *ref { atyp := A.Type() btyp := B.Type() switch op { case "==", "!=": if types.IsNil(atyp) { return testNilSlice(b, B, op == "==") } else if types.IsNil(btyp) { return testNilSlice(b, A, op == "==") } addrA := b.newPtr() addrB := b.newPtr() b.b.Arith(addrA, nil, "&", A.IR()) b.b.Arith(addrB, nil, "&", B.IR()) baseA := ir.NewAddrRef(addrA, 4, 0, false, true) sizeA := ir.NewAddrRef(addrA, 4, 4, false, true) baseB := ir.NewAddrRef(addrB, 4, 0, false, true) sizeB := ir.NewAddrRef(addrB, 4, 4, false, true) ptrEq := b.newCond() sizeEq := b.newCond() b.b.Arith(ptrEq, baseA, "==", baseB) b.b.Arith(sizeEq, sizeA, "==", sizeB) ret := b.newCond() b.b.Arith(ret, ptrEq, "&", sizeEq) if op == "!=" { b.b.Arith(ret, nil, "!", ret) } return newRef(types.Bool, ret) } panic("bug") }
func buildCallLen(b *builder, expr *tast.CallExpr) *ref { args := b.buildExpr(expr.Args) t := args.Type() ret := b.newTemp(types.Int) switch t := t.(type) { case *types.Slice: addr := b.newPtr() b.b.Arith(addr, nil, "&", args.IR()) b.b.Assign(ret.IR(), ir.NewAddrRef(addr, 4, 4, false, true)) return ret case *types.Array: b.b.Assign(ret.IR(), ir.Num(uint32(t.N))) return ret } panic("bug") }
func buildArrayGet(b *builder, expr *tast.IndexExpr, array *ref) *ref { index := buildArrayIndex(b, expr.Index) base, n, et := loadArray(b, array) checkInRange(b, index, n, "u<") addr := b.newPtr() b.b.Arith(addr, index, "*", ir.Snum(arrayElementSize(et))) b.b.Arith(addr, base, "+", addr) size := et.Size() retIR := ir.NewAddrRef( addr, // base address size, // size 0, // dynamic offset; precalculated types.IsByte(et), // isByte true, // isAlign ) return newAddressableRef(et, retIR) }