Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // minMax converts an OMIN/OMAX builtin call into SSA.
- func (s *state) minMax(n *ir.CallExpr) *ssa.Value {
- // The OMIN/OMAX builtin is variadic, but its semantics are
- // equivalent to left-folding a binary min/max operation across the
- // arguments list.
- fold := func(op func(x, a *ssa.Value) *ssa.Value) *ssa.Value {
- x := s.expr(n.Args[0])
- for _, arg := range n.Args[1:] {
- x = op(x, s.expr(arg))
- }
- return x
- }
- typ := n.Type()
- if typ.IsFloat() || typ.IsString() {
- // min/max semantics for floats are tricky because of NaNs and
- // negative zero. Some architectures have instructions which
- // we can use to generate the right result. For others we must
- // call into the runtime instead.
- //
- // Strings are conceptually simpler, but we currently desugar
- // string comparisons during walk, not ssagen.
- if typ.IsFloat() {
- hasIntrinsic := false
- switch Arch.LinkArch.Family {
- case sys.AMD64, sys.ARM64, sys.Loong64, sys.RISCV64:
- hasIntrinsic = true
- case sys.PPC64:
- hasIntrinsic = buildcfg.GOPPC64 >= 9
- }
- if hasIntrinsic {
- var op ssa.Op
- switch {
- case typ.Kind() == types.TFLOAT64 && n.Op() == ir.OMIN:
- op = ssa.OpMin64F
- case typ.Kind() == types.TFLOAT64 && n.Op() == ir.OMAX:
- op = ssa.OpMax64F
- case typ.Kind() == types.TFLOAT32 && n.Op() == ir.OMIN:
- op = ssa.OpMin32F
- case typ.Kind() == types.TFLOAT32 && n.Op() == ir.OMAX:
- op = ssa.OpMax32F
- }
- return fold(func(x, a *ssa.Value) *ssa.Value {
- return s.newValue2(op, typ, x, a)
- })
- }
- }
- var name string
- switch typ.Kind() {
- case types.TFLOAT32:
- switch n.Op() {
- case ir.OMIN:
- name = "fmin32"
- case ir.OMAX:
- name = "fmax32"
- }
- case types.TFLOAT64:
- switch n.Op() {
- case ir.OMIN:
- name = "fmin64"
- case ir.OMAX:
- name = "fmax64"
- }
- case types.TSTRING:
- switch n.Op() {
- case ir.OMIN:
- name = "strmin"
- case ir.OMAX:
- name = "strmax"
- }
- }
- fn := typecheck.LookupRuntimeFunc(name)
- return fold(func(x, a *ssa.Value) *ssa.Value {
- return s.rtcall(fn, true, []*types.Type{typ}, x, a)[0]
- })
- }
- if typ.IsInteger() {
- if Arch.LinkArch.Family == sys.RISCV64 && buildcfg.GORISCV64 >= 22 && typ.Size() == 8 {
- var op ssa.Op
- switch {
- case typ.IsSigned() && n.Op() == ir.OMIN:
- op = ssa.OpMin64
- case typ.IsSigned() && n.Op() == ir.OMAX:
- op = ssa.OpMax64
- case typ.IsUnsigned() && n.Op() == ir.OMIN:
- op = ssa.OpMin64u
- case typ.IsUnsigned() && n.Op() == ir.OMAX:
- op = ssa.OpMax64u
- }
- return fold(func(x, a *ssa.Value) *ssa.Value {
- return s.newValue2(op, typ, x, a)
- })
- }
- }
- lt := s.ssaOp(ir.OLT, typ)
- return fold(func(x, a *ssa.Value) *ssa.Value {
- switch n.Op() {
- case ir.OMIN:
- // a < x ? a : x
- return s.ternary(s.newValue2(lt, types.Types[types.TBOOL], a, x), a, x)
- case ir.OMAX:
- // x < a ? a : x
- return s.ternary(s.newValue2(lt, types.Types[types.TBOOL], x, a), a, x)
- }
- panic("unreachable")
- })
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement