}
}
-// simdLoadSliceMethod does intrinsic for method form of Load-from-slice
-func simdLoadSliceMethod(nElts int64) func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
- return func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
- // args[0] is unused except for its type.
- t := args[0].Type
- slice := args[1]
- arrlen := s.constInt(types.Types[types.TINT], nElts)
- cap := s.newValue1(ssa.OpSliceLen, types.Types[types.TINT], slice)
- s.boundsCheck(arrlen, cap, ssa.BoundsConvert, false)
- ptr := s.newValue1(ssa.OpSlicePtr, t.PtrTo(), slice) // is this the right type? Does it need a convert?
- return s.newValue2(ssa.OpLoad, t, ptr, s.mem())
- }
-}
-
-// simdLoadSlice does intrinsic for function form of Load-from-slice
-func simdLoadSlice(nElts int64) func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
- return func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
- // args[0] is unused except for its type.
- t := n.Type()
- slice := args[0]
- arrlen := s.constInt(types.Types[types.TINT], nElts)
- cap := s.newValue1(ssa.OpSliceLen, types.Types[types.TINT], slice)
- s.boundsCheck(arrlen, cap, ssa.BoundsConvert, false)
- ptr := s.newValue1(ssa.OpSlicePtr, t.PtrTo(), slice) // is this the right type? Does it need a convert?
- return s.newValue2(ssa.OpLoad, t, ptr, s.mem())
- }
-}
-
-func simdStoreSlice(nElts int64) func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
- return func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
- x := args[0]
- t := x.Type
- slice := args[1]
- arrlen := s.constInt(types.Types[types.TINT], nElts)
- cap := s.newValue1(ssa.OpSliceLen, types.Types[types.TINT], slice)
- s.boundsCheck(arrlen, cap, ssa.BoundsConvert, false)
- ptr := s.newValue1(ssa.OpSlicePtr, t.PtrTo(), slice) // is this the right type? Does it need a convert?
- s.store(t, ptr, x)
- return nil
- }
-}
-
-func simdLoadSliceMethodPart(nElts int64) func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
- return func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
- // args[0] is unused except for its type.
- t := args[0].Type
- slice := args[1]
- arrLen := s.constInt(types.Types[types.TINT], nElts)
- cap := s.newValue1(ssa.OpSliceLen, types.Types[types.TINT], slice)
-
- /*
- if off := vec.Len() - len(slice) ; off <= 0 {
- plain load
- } else {
- load mask[off] into a scratch vector
- masked load/store
- }
- */
-
- // TODO SIMD support on a 32-bit processor
-
- off := s.newValue2(ssa.OpSub64, types.Types[types.TINT], arrLen, cap)
- cond := s.newValue2(ssa.OpLeq64, types.Types[types.TBOOL], off, s.zeroVal(types.Types[types.TINT]))
- b := s.endBlock()
- b.Kind = ssa.BlockIf
- b.SetControl(cond)
- bTrue := s.f.NewBlock(ssa.BlockPlain)
- bFalse := s.f.NewBlock(ssa.BlockPlain)
- bEnd := s.f.NewBlock(ssa.BlockPlain)
- b.AddEdgeTo(bTrue)
- b.AddEdgeTo(bFalse)
-
- simdRes := ssaMarker("simdload")
-
- // We have atomic instructions - use it directly.
- s.startBlock(bTrue)
- ptr := s.newValue1(ssa.OpSlicePtr, t.PtrTo(), slice)
- s.vars[simdRes] = s.newValue2(ssa.OpLoad, t, ptr, s.mem())
- s.endBlock().AddEdgeTo(bEnd)
-
- // Use original instruction sequence.
- s.startBlock(bFalse)
- // NOT IMPLEMENTED, NEED TO ADD GENERIC PARTIAL LOAD/STORE
- // MASK REGISTER DEPENDS ON ARCH AND ITS SIMD VERSION.
- s.endBlock().AddEdgeTo(bEnd)
-
- // Merge results.
- s.startBlock(bEnd)
- return s.variable(simdRes, t)
-
- }
-}
-
// findIntrinsic returns a function which builds the SSA equivalent of the
// function identified by the symbol sym. If sym is not an intrinsic call, returns nil.
func findIntrinsic(sym *types.Sym) intrinsicBuilder {