Add support for fminimum, fmaximum
MODIFY
ir/instr.cpp
ir/instr.cpp
@@ -151,6 +151,8 @@ BinOp::BinOp(Type &type, string &&name, Value &lhs, Value &rhs, Op op,
case FRem:
case FMin:
case FMax:
+ case FMinimum:
+ case FMaximum:
assert(flags == None);
break;
case SRem:
@@ -233,6 +235,8 @@ void BinOp::print(ostream &os) const {
case FRem: str = "frem "; break;
case FMax: str = "fmax "; break;
case FMin: str = "fmin "; break;
+ case FMaximum: str = "fmaximum "; break;
+ case FMinimum: str = "fminimum "; break;
case UMin: str = "umin "; break;
case UMax: str = "umax "; break;
case SMin: str = "smin "; break;
@@ -594,6 +598,24 @@ StateValue BinOp::toSMT(State &s) const {
};
break;
+ case FMinimum:
+ case FMaximum:
+ fn = [&](auto a, auto ap, auto b, auto bp) -> StateValue {
+ auto v = [&](expr &a, expr &b) {
+ expr zpos = expr::mkNumber("0", a), zneg = expr::mkNumber("-0", a);
+ expr cmp = (op == FMinimum) ? a.fole(b) : a.foge(b);
+ expr neg_cond = (op == FMinimum) ? a.isFPNeg() || b.isFPNeg()
+ : a.isFPNeg() && b.isFPNeg();
+ expr e = expr::mkIf(a.isFPZero() && b.isFPZero(),
+ expr::mkIf(neg_cond, zneg, zpos),
+ expr::mkIf(cmp, a, b));
+
+ return expr::mkIf(a.isNaN(), a, expr::mkIf(b.isNaN(), b, e));
+ };
+ return fm_poison(s, a, b, v, fmath, false);
+ };
+ break;
+
case UMin:
case UMax:
case SMin:
@@ -735,6 +757,8 @@ expr BinOp::getTypeConstraints(const Function &f) const {
case FRem:
case FMax:
case FMin:
+ case FMaximum:
+ case FMinimum:
instrconstr = getType().enforceFloatOrVectorType() &&
getType() == lhs->getType() &&
getType() == rhs->getType();

MODIFY
ir/instr.h
ir/instr.h
@@ -46,7 +46,7 @@ public:
SAdd_Sat, UAdd_Sat, SSub_Sat, USub_Sat, SShl_Sat, UShl_Sat,
SAdd_Overflow, UAdd_Overflow, SSub_Overflow, USub_Overflow,
SMul_Overflow, UMul_Overflow,
- FAdd, FSub, FMul, FDiv, FRem, FMax, FMin,
+ FAdd, FSub, FMul, FDiv, FRem, FMax, FMin, FMaximum, FMinimum,
And, Or, Xor, Cttz, Ctlz, UMin, UMax, SMin, SMax, Abs };
enum Flags { None = 0, NSW = 1 << 0, NUW = 1 << 1, Exact = 1 << 2 };

MODIFY
llvm_util/llvm2alive.cpp
llvm_util/llvm2alive.cpp
@@ -798,12 +798,16 @@ end:
}
case llvm::Intrinsic::minnum:
case llvm::Intrinsic::maxnum:
+ case llvm::Intrinsic::minimum:
+ case llvm::Intrinsic::maximum:
{
PARSE_BINOP();
BinOp::Op op;
switch (i.getIntrinsicID()) {
case llvm::Intrinsic::minnum: op = BinOp::FMin; break;
case llvm::Intrinsic::maxnum: op = BinOp::FMax; break;
+ case llvm::Intrinsic::minimum: op = BinOp::FMinimum; break;
+ case llvm::Intrinsic::maximum: op = BinOp::FMaximum; break;
default: UNREACHABLE();
}
RETURN_IDENTIFIER(make_unique<BinOp>(*ty, value_name(i), *a, *b,

MODIFY
tests/unit/fp/fmaxmin.opt
tests/unit/fp/fmaxmin.opt
@@ -86,3 +86,72 @@ Name: fmin, nondet
%t = fmin float -0.0, float +0.0
=>
%t = float -0.0
+
+
+Name: fmaximum, constant prop.
+%t = fmaximum float 1.0, float 3.0
+ =>
+%t = float 3.0
+
+Name: fminimum, constant prop.
+%t = fminimum float 1.0, float 3.0
+ =>
+%t = float 1.0
+
+Name: fmaximum, LHS NaN
+%v = fdiv float 0.0, 0.0
+%t = fmaximum float %v, float 3.0
+ =>
+%t = fdiv float 0.0, 0.0
+
+Name: fmaximum, RHS NaN
+%v = fdiv float 0.0, 0.0
+%t = fmaximum float 3.0, float %v
+ =>
+%t = fdiv float 0.0, 0.0
+
+Name: fmaximum, BOTH NaN
+%v = fdiv float 0.0, 0.0
+%t = fmaximum float %v, float %v
+ =>
+%v = fdiv float 0.0, 0.0
+%t = float %v
+
+Name: fminimum, LHS NaN
+%v = fdiv float 0.0, 0.0
+%t = fminimum float %v, float 3.0
+ =>
+%t = fdiv float 0.0, 0.0
+
+Name: fminimum, RHS NaN
+%v = fdiv float 0.0, 0.0
+%t = fminimum float 3.0, float %v
+ =>
+%t = fdiv float 0.0, 0.0
+
+Name: fminimum, BOTH NaN
+%v = fdiv float 0.0, 0.0
+%t = fminimum float %v, float %v
+ =>
+%v = fdiv float 0.0, 0.0
+%t = float %v
+
+Name: fmaximum, +0, -0
+%t = fmaximum float +0.0, float -0.0
+ =>
+%t = float +0.0
+
+Name: fmaximum, -0, +0
+%t = fmaximum float -0.0, float +0.0
+ =>
+%t = float +0.0
+
+Name: fminimum, +0, -0
+%t = fminimum float +0.0, float -0.0
+ =>
+%t = float -0.0
+
+Name: fminimum, -0, +0
+%t = fminimum float -0.0, float +0.0
+ =>
+%t = float -0.0

MODIFY
tools/alive_lexer.re
tools/alive_lexer.re
@@ -240,6 +240,8 @@ space+ {
"fma" { return FMA; }
"fmax" { return FMAX; }
"fmin" { return FMIN; }
+"fmaximum" { return FMAXIMUM; }
+"fminimum" { return FMINIMUM; }
"extractelement" { return EXTRACTELEMENT; }
"insertelement" { return INSERTELEMENT; }
"shufflevector" { return SHUFFLEVECTOR; }

MODIFY
tools/alive_parser.cpp
tools/alive_parser.cpp
@@ -618,6 +618,8 @@ static FastMathFlags parse_fast_math(token op_token) {
case FMA:
case FMAX:
case FMIN:
+ case FMAXIMUM:
+ case FMINIMUM:
break;
default:
if (!fmath.isNone())
@@ -646,6 +648,8 @@ static unsigned parse_binop_flags(token op_token) {
case FREM:
case FMAX:
case FMIN:
+ case FMAXIMUM:
+ case FMINIMUM:
case SREM:
case UREM:
case UADD_SAT:
@@ -740,6 +744,8 @@ static unique_ptr<Instr> parse_binop(string_view name, token op_token) {
case FREM: op = BinOp::FRem; break;
case FMAX: op = BinOp::FMax; break;
case FMIN: op = BinOp::FMin; break;
+ case FMAXIMUM: op = BinOp::FMaximum; break;
+ case FMINIMUM: op = BinOp::FMinimum; break;
case UMIN: op = BinOp::UMin; break;
case UMAX: op = BinOp::UMax; break;
case SMIN: op = BinOp::SMin; break;
@@ -1100,6 +1106,8 @@ static unique_ptr<Instr> parse_instr(string_view name) {
case FREM:
case FMAX:
case FMIN:
+ case FMAXIMUM:
+ case FMINIMUM:
case UMIN:
case UMAX:
case SMIN:

MODIFY
tools/tokens.h
tools/tokens.h
@@ -61,7 +61,9 @@ TOKEN(FSHL)
TOKEN(FSHR)
TOKEN(FMA)
TOKEN(FMAX)
+TOKEN(FMAXIMUM)
TOKEN(FMIN)
+TOKEN(FMINIMUM)
TOKEN(FSUB)
TOKEN(GLOBAL_NAME)
TOKEN(HALF)

Add support for fminimum, fmaximum (#483)