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 loadArray(b *builder, array *ref) (addr, n codegen.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, codegen.Snum(t.N), t.T case *types.Slice: b.b.Arith(base, nil, "&", array.IR()) addr = codegen.NewAddrRef(base, 4, 0, false, true) n = codegen.NewAddrRef(base, 4, 4, false, true) return addr, n, t.T } 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 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, "*", codegen.Snum(arrayElementSize(et))) b.b.Arith(addr, base, "+", addr) size := et.Size() retIR := codegen.NewAddrRef( addr, // base address size, // size 0, // dynamic offset; precalculated types.IsByte(et), // isByte true, // isAlign ) return newAddressableRef(et, retIR) }