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 buildIncStmt(b *builder, stmt *tast.IncStmt) { expr := b.buildExpr(stmt.Expr) switch stmt.Op.Lit { case "++": b.b.Arith(expr.IR(), expr.IR(), "+", ir.Num(1)) case "--": b.b.Arith(expr.IR(), expr.IR(), "-", ir.Num(1)) default: panic("bug") } }
func buildSlicing(b *builder, expr *tast.IndexExpr, array *ref) *ref { baseAddr, n, et := loadArray(b, array) var addr, indexStart, offset ir.Ref if expr.Index == nil { indexStart = ir.Num(0) addr = baseAddr } else { indexStart = buildArrayIndex(b, expr.Index) checkInRange(b, indexStart, n, "u<=") offset = b.newPtr() b.b.Arith(offset, indexStart, "*", ir.Snum(arrayElementSize(et))) addr = b.newPtr() b.b.Arith(addr, baseAddr, "+", offset) } var indexEnd ir.Ref if expr.IndexEnd == nil { indexEnd = n } else { indexEnd = buildArrayIndex(b, expr.IndexEnd) checkInRange(b, indexEnd, n, "u<=") checkInRange(b, indexStart, indexEnd, "u<=") } size := b.newPtr() b.b.Arith(size, indexEnd, "-", indexStart) return newSlice(b, et, addr, size) }
func buildConst(b *builder, c *tast.Const) *ref { if _, ok := types.NumConst(c.T); ok { // untyped consts are just types. return newRef(c.T, nil) } if t, ok := c.T.(types.Basic); ok { v := c.ConstValue.(int64) switch t { case types.Int, types.Uint: return newRef(c.T, ir.Num(uint32(v))) case types.Int8, types.Uint8, types.Bool: return newRef(c.T, ir.Byt(uint8(v))) default: panic("other basic types not supported yet") } } if c.T == types.String { s := c.ConstValue.(string) ret := b.newTemp(c.T) b.b.Arith(ret.IR(), nil, "makeStr", b.p.NewString(s)) return ret } panic("other const types not supported") }
func binaryOpPtr(b *builder, op string, A, B *ref) *ref { atyp := A.Type() btyp := B.Type() switch op { case "==", "!=": // replace nil with a typed zero if types.IsNil(atyp) { A = newRef(btyp, ir.Num(0)) } else if types.IsNil(btyp) { B = newRef(atyp, ir.Num(0)) } ret := b.newTemp(types.Bool) b.b.Arith(ret.IR(), A.IR(), op, B.IR()) return ret } panic("bug") }
func constNumIr(v int64, t types.T) ir.Ref { b, ok := t.(types.Basic) if ok { switch b { case types.Int: return ir.Snum(int32(v)) case types.Uint: return ir.Num(uint32(v)) case types.Int8, types.Uint8: return ir.Byt(uint8(v)) } } panic("expect an integer type") }
func buildBasicArith(b *builder, ret, A, B *ref, op string) { if op == "%" || op == "/" { isZero := b.newCond() b.b.Arith(isZero, B.IR(), "==", ir.Num(0)) zeroPanic := b.f.NewBlock(b.b) after := b.f.NewBlock(zeroPanic) b.b.JumpIfNot(isZero, after) b.b = zeroPanic callPanic(b, "divided by zero") b.b = after } b.b.Arith(ret.IR(), A.IR(), op, B.IR()) }
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 buildCast(b *builder, from *ref, t types.T) *ref { srcType := from.Type() ret := b.newTemp(t) if types.IsNil(srcType) { size := t.Size() if size == arch8.RegSize { return newRef(t, ir.Num(0)) } if _, ok := t.(*types.Slice); !ok { panic("bug") } ret := b.newTemp(t) b.b.Zero(ret.IR()) return ret } if c, ok := srcType.(*types.Const); ok { if v, ok := types.NumConst(srcType); ok && types.IsInteger(t) { return newRef(t, constNumIr(v, t)) } // TODO: we do not support typed const right? // so why need this line? srcType = c.Type // using the underlying type } if types.IsInteger(t) && types.IsInteger(srcType) { b.b.Arith(ret.IR(), nil, "cast", from.IR()) return ret } if regSizeCastable(t, srcType) { b.b.Arith(ret.IR(), nil, "", from.IR()) return ret } panic("bug") }