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 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 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 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) }