typVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "typ"}}
idataVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "idata"}}
okVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "ok"}}
+ deltaVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "delta"}}
)
// startBlock sets the current block we're generating code in to b.
// Generate the following code assuming that indexes are in bounds.
// The conditional is to make sure that we don't generate a slice
// that points to the next object in memory.
- // rlen = (Sub64 j i)
- // rcap = (Sub64 k i)
- // p = ptr
- // if rcap != 0 {
- // p = (AddPtr ptr (Mul64 low (Const64 size)))
+ // rlen = j-i
+ // rcap = k-i
+ // delta = i*elemsize
+ // if rcap == 0 {
+ // delta = 0
// }
- // result = (SliceMake p size)
+ // rptr = p+delta
+ // result = (SliceMake rptr rlen rcap)
subOp := s.ssaOp(OSUB, Types[TINT])
- neqOp := s.ssaOp(ONE, Types[TINT])
+ eqOp := s.ssaOp(OEQ, Types[TINT])
mulOp := s.ssaOp(OMUL, Types[TINT])
rlen := s.newValue2(subOp, Types[TINT], j, i)
var rcap *ssa.Value
rcap = s.newValue2(subOp, Types[TINT], k, i)
}
- s.vars[&ptrVar] = ptr
+ // delta = # of elements to offset pointer by.
+ s.vars[&deltaVar] = i
- // Generate code to test the resulting slice length.
- cmp := s.newValue2(neqOp, Types[TBOOL], rcap, s.constInt(Types[TINT], 0))
+ // Generate code to set delta=0 if the resulting capacity is zero.
+ if !((i.Op == ssa.OpConst64 && i.AuxInt == 0) ||
+ (i.Op == ssa.OpConst32 && int32(i.AuxInt) == 0)) {
+ cmp := s.newValue2(eqOp, Types[TBOOL], rcap, zero)
- b := s.endBlock()
- b.Kind = ssa.BlockIf
- b.Likely = ssa.BranchLikely
- b.SetControl(cmp)
+ b := s.endBlock()
+ b.Kind = ssa.BlockIf
+ b.Likely = ssa.BranchUnlikely
+ b.SetControl(cmp)
- // Generate code for non-zero length slice case.
- nz := s.f.NewBlock(ssa.BlockPlain)
- b.AddEdgeTo(nz)
- s.startBlock(nz)
- var inc *ssa.Value
- if elemtype.Width == 1 {
- inc = i
- } else {
- inc = s.newValue2(mulOp, Types[TINT], i, s.constInt(Types[TINT], elemtype.Width))
+ // Generate block which zeros the delta variable.
+ nz := s.f.NewBlock(ssa.BlockPlain)
+ b.AddEdgeTo(nz)
+ s.startBlock(nz)
+ s.vars[&deltaVar] = zero
+ s.endBlock()
+
+ // All done.
+ merge := s.f.NewBlock(ssa.BlockPlain)
+ b.AddEdgeTo(merge)
+ nz.AddEdgeTo(merge)
+ s.startBlock(merge)
+
+ // TODO: use conditional moves somehow?
}
- s.vars[&ptrVar] = s.newValue2(ssa.OpAddPtr, ptrtype, ptr, inc)
- s.endBlock()
- // All done.
- merge := s.f.NewBlock(ssa.BlockPlain)
- b.AddEdgeTo(merge)
- nz.AddEdgeTo(merge)
- s.startBlock(merge)
- rptr := s.variable(&ptrVar, ptrtype)
- delete(s.vars, &ptrVar)
+ // Compute rptr = ptr + delta * elemsize
+ rptr := s.newValue2(ssa.OpAddPtr, ptrtype, ptr, s.newValue2(mulOp, Types[TINT], s.variable(&deltaVar, Types[TINT]), s.constInt(Types[TINT], elemtype.Width)))
+ delete(s.vars, &deltaVar)
return rptr, rlen, rcap
}