func buildIncStmt(b *builder, stmt *tast.IncStmt) { expr := b.buildExpr(stmt.Expr) switch stmt.Op.Lit { case "++": b.b.Arith(expr.IR(), expr.IR(), "+", codegen.Num(1)) case "--": b.b.Arith(expr.IR(), expr.IR(), "-", codegen.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 codegen.Ref if expr.Index == nil { indexStart = codegen.Num(0) addr = baseAddr } else { indexStart = buildArrayIndex(b, expr.Index) checkInRange(b, indexStart, n, "u<=") offset = b.newPtr() b.b.Arith(offset, indexStart, "*", codegen.Snum(arrayElementSize(et))) addr = b.newPtr() b.b.Arith(addr, baseAddr, "+", offset) } var indexEnd codegen.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 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(), codegen.NewAddrRef(addr, 4, 4, false, true)) return ret case *types.Array: b.b.Assign(ret.IR(), codegen.Num(uint32(t.N))) return ret } panic("bug") }
func constNumIr(v int64, t types.T) codegen.Ref { b, ok := t.(types.Basic) if ok { switch b { case types.Int: return codegen.Snum(int32(v)) case types.Uint: return codegen.Num(uint32(v)) case types.Int8: return codegen.Byt(uint8(v), false) case types.Uint8: return codegen.Byt(uint8(v), true) } } panic("expect an integer type") }
func buildBasicArith(b *builder, ret, A, B *ref, op string) { switch op { case "/", "%", "u/", "u%": isZero := b.newCond() b.b.Arith(isZero, B.IR(), "==", codegen.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 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, codegen.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") }