Advertisement
metalim

Go min/max implementation

Jun 16th, 2025
225
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Go 3.03 KB | None | 0 0
  1. // minMax converts an OMIN/OMAX builtin call into SSA.
  2. func (s *state) minMax(n *ir.CallExpr) *ssa.Value {
  3.     // The OMIN/OMAX builtin is variadic, but its semantics are
  4.     // equivalent to left-folding a binary min/max operation across the
  5.     // arguments list.
  6.     fold := func(op func(x, a *ssa.Value) *ssa.Value) *ssa.Value {
  7.         x := s.expr(n.Args[0])
  8.         for _, arg := range n.Args[1:] {
  9.             x = op(x, s.expr(arg))
  10.         }
  11.         return x
  12.     }
  13.  
  14.     typ := n.Type()
  15.  
  16.     if typ.IsFloat() || typ.IsString() {
  17.         // min/max semantics for floats are tricky because of NaNs and
  18.         // negative zero. Some architectures have instructions which
  19.         // we can use to generate the right result. For others we must
  20.         // call into the runtime instead.
  21.         //
  22.         // Strings are conceptually simpler, but we currently desugar
  23.         // string comparisons during walk, not ssagen.
  24.  
  25.         if typ.IsFloat() {
  26.             hasIntrinsic := false
  27.             switch Arch.LinkArch.Family {
  28.             case sys.AMD64, sys.ARM64, sys.Loong64, sys.RISCV64:
  29.                 hasIntrinsic = true
  30.             case sys.PPC64:
  31.                 hasIntrinsic = buildcfg.GOPPC64 >= 9
  32.             }
  33.  
  34.             if hasIntrinsic {
  35.                 var op ssa.Op
  36.                 switch {
  37.                 case typ.Kind() == types.TFLOAT64 && n.Op() == ir.OMIN:
  38.                     op = ssa.OpMin64F
  39.                 case typ.Kind() == types.TFLOAT64 && n.Op() == ir.OMAX:
  40.                     op = ssa.OpMax64F
  41.                 case typ.Kind() == types.TFLOAT32 && n.Op() == ir.OMIN:
  42.                     op = ssa.OpMin32F
  43.                 case typ.Kind() == types.TFLOAT32 && n.Op() == ir.OMAX:
  44.                     op = ssa.OpMax32F
  45.                 }
  46.                 return fold(func(x, a *ssa.Value) *ssa.Value {
  47.                     return s.newValue2(op, typ, x, a)
  48.                 })
  49.             }
  50.         }
  51.         var name string
  52.         switch typ.Kind() {
  53.         case types.TFLOAT32:
  54.             switch n.Op() {
  55.             case ir.OMIN:
  56.                 name = "fmin32"
  57.             case ir.OMAX:
  58.                 name = "fmax32"
  59.             }
  60.         case types.TFLOAT64:
  61.             switch n.Op() {
  62.             case ir.OMIN:
  63.                 name = "fmin64"
  64.             case ir.OMAX:
  65.                 name = "fmax64"
  66.             }
  67.         case types.TSTRING:
  68.             switch n.Op() {
  69.             case ir.OMIN:
  70.                 name = "strmin"
  71.             case ir.OMAX:
  72.                 name = "strmax"
  73.             }
  74.         }
  75.         fn := typecheck.LookupRuntimeFunc(name)
  76.  
  77.         return fold(func(x, a *ssa.Value) *ssa.Value {
  78.             return s.rtcall(fn, true, []*types.Type{typ}, x, a)[0]
  79.         })
  80.     }
  81.  
  82.     if typ.IsInteger() {
  83.         if Arch.LinkArch.Family == sys.RISCV64 && buildcfg.GORISCV64 >= 22 && typ.Size() == 8 {
  84.             var op ssa.Op
  85.             switch {
  86.             case typ.IsSigned() && n.Op() == ir.OMIN:
  87.                 op = ssa.OpMin64
  88.             case typ.IsSigned() && n.Op() == ir.OMAX:
  89.                 op = ssa.OpMax64
  90.             case typ.IsUnsigned() && n.Op() == ir.OMIN:
  91.                 op = ssa.OpMin64u
  92.             case typ.IsUnsigned() && n.Op() == ir.OMAX:
  93.                 op = ssa.OpMax64u
  94.             }
  95.             return fold(func(x, a *ssa.Value) *ssa.Value {
  96.                 return s.newValue2(op, typ, x, a)
  97.             })
  98.         }
  99.     }
  100.  
  101.     lt := s.ssaOp(ir.OLT, typ)
  102.  
  103.     return fold(func(x, a *ssa.Value) *ssa.Value {
  104.         switch n.Op() {
  105.         case ir.OMIN:
  106.             // a < x ? a : x
  107.             return s.ternary(s.newValue2(lt, types.Types[types.TBOOL], a, x), a, x)
  108.         case ir.OMAX:
  109.             // x < a ? a : x
  110.             return s.ternary(s.newValue2(lt, types.Types[types.TBOOL], x, a), a, x)
  111.         }
  112.         panic("unreachable")
  113.     })
  114. }
  115.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement