refactor fp bin ops in preparation for adding support for rounding modes
MODIFY
ir/instr.cpp
ir/instr.cpp
@@ -108,61 +108,23 @@ expr Instr::getTypeConstraints() const {
BinOp::BinOp(Type &type, string &&name, Value &lhs, Value &rhs, Op op,
- unsigned flags, FastMathFlags fmath)
- : Instr(type, move(name)), lhs(&lhs), rhs(&rhs), op(op), flags(flags),
- fmath(fmath) {
+ unsigned flags)
+ : Instr(type, move(name)), lhs(&lhs), rhs(&rhs), op(op), flags(flags) {
switch (op) {
case Add:
case Sub:
case Mul:
case Shl:
assert((flags & (NSW | NUW)) == flags);
- assert(fmath.isNone());
break;
case SDiv:
case UDiv:
case AShr:
case LShr:
assert((flags & Exact) == flags);
- assert(fmath.isNone());
break;
- case FAdd:
- case FSub:
- case FMul:
- case FDiv:
- case FRem:
- case FMin:
- case FMax:
- case FMinimum:
- case FMaximum:
- assert(flags == None);
- break;
- case SRem:
- case URem:
- case SAdd_Sat:
- case UAdd_Sat:
- case SSub_Sat:
- case USub_Sat:
- case SShl_Sat:
- case UShl_Sat:
- case And:
- case Or:
- case Xor:
- case Cttz:
- case Ctlz:
- case SAdd_Overflow:
- case UAdd_Overflow:
- case SSub_Overflow:
- case USub_Overflow:
- case SMul_Overflow:
- case UMul_Overflow:
- case UMin:
- case UMax:
- case SMin:
- case SMax:
- case Abs:
+ default:
assert(flags == None);
- assert(fmath.isNone());
break;
}
}
@@ -210,22 +172,11 @@ void BinOp::print(ostream &os) const {
case USub_Overflow: str = "usub_overflow "; break;
case SMul_Overflow: str = "smul_overflow "; break;
case UMul_Overflow: str = "umul_overflow "; break;
- case FAdd: str = "fadd "; break;
- case FSub: str = "fsub "; break;
- case FMul: str = "fmul "; break;
- case FDiv: str = "fdiv "; break;
- 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;
case SMax: str = "smax "; break;
- case Abs:
- str = "abs ";
- break;
+ case Abs: str = "abs "; break;
}
os << getName() << " = " << str;
@@ -236,7 +187,7 @@ void BinOp::print(ostream &os) const {
os << "nuw ";
if (flags & Exact)
os << "exact ";
- os << fmath << *lhs << ", " << rhs->getName();
+ os << *lhs << ", " << rhs->getName();
}
static void div_ub(State &s, const expr &a, const expr &b, const expr &ap,
@@ -247,100 +198,6 @@ static void div_ub(State &s, const expr &a, const expr &b, const expr &ap,
s.addUB((ap && a != expr::IntSMin(b.bits())) || b != expr::mkInt(-1, b));
}
-static expr any_fp_zero(State &s, const expr &v) {
- expr is_zero = v.isFPZero();
- if (is_zero.isFalse())
- return v;
-
- expr var = expr::mkFreshVar("anyzero", true);
- s.addQuantVar(var);
- return expr::mkIf(var && is_zero, v.fneg(), v);
-}
-
-static StateValue fm_poison(State &s, const expr &a, const expr &ap,
- const expr &b, const expr &bp, const expr &c,
- function<expr(expr&,expr&,expr&)> fn,
- FastMathFlags fmath, bool only_input,
- int nary = 3) {
- expr new_a, new_b, new_c;
- if (fmath.flags & FastMathFlags::NSZ) {
- new_a = any_fp_zero(s, a);
- if (nary >= 2) {
- new_b = any_fp_zero(s, b);
- if (nary == 3)
- new_c = any_fp_zero(s, c);
- }
- } else {
- new_a = a;
- new_b = b;
- new_c = c;
- }
-
- expr val = fn(new_a, new_b, new_c);
- AndExpr non_poison;
- non_poison.add(ap);
- if (nary >= 2)
- non_poison.add(bp);
-
- if (fmath.flags & FastMathFlags::NNaN) {
- non_poison.add(!a.isNaN());
- if (nary >= 2) {
- non_poison.add(!b.isNaN());
- if (nary == 3)
- non_poison.add(!c.isNaN());
- }
- if (!only_input)
- non_poison.add(!val.isNaN());
- }
- if (fmath.flags & FastMathFlags::NInf) {
- non_poison.add(!a.isInf());
- if (nary >= 2) {
- non_poison.add(!b.isInf());
- if (nary == 3)
- non_poison.add(!c.isInf());
- }
- if (!only_input)
- non_poison.add(!val.isInf());
- }
- if (fmath.flags & FastMathFlags::ARCP) {
- val = expr::mkUF("arcp", { val }, val);
- s.doesApproximation("arcp", val);
- }
- if (fmath.flags & FastMathFlags::Contract) {
- val = expr::mkUF("contract", { val }, val);
- s.doesApproximation("contract", val);
- }
- if (fmath.flags & FastMathFlags::Reassoc) {
- val = expr::mkUF("reassoc", { val }, val);
- s.doesApproximation("reassoc", val);
- }
- if (fmath.flags & FastMathFlags::AFN) {
- val = expr::mkUF("afn", { val }, val);
- s.doesApproximation("afn", val);
- }
- if (fmath.flags & FastMathFlags::NSZ && !only_input)
- val = any_fp_zero(s, move(val));
-
- return { move(val), non_poison() };
-}
-
-static StateValue fm_poison(State &s, const expr &a, const expr &ap,
- const expr &b, const expr &bp,
- function<expr(expr&,expr&)> fn,
- FastMathFlags fmath, bool only_input) {
- return fm_poison(s, move(a), ap, move(b), bp, expr(),
- [&](expr &a, expr &b, expr &c) { return fn(a, b); },
- fmath, only_input, 2);
-}
-
-static StateValue fm_poison(State &s, const expr &a, const expr &ap,
- function<expr(expr&)> fn,
- FastMathFlags fmath, bool only_input) {
- return fm_poison(s, move(a), ap, expr(), expr(), expr(),
- [&](expr &a, expr &b, expr &c) { return fn(a); },
- fmath, only_input, 1);
-}
-
StateValue BinOp::toSMT(State &s) const {
bool vertical_zip = false;
function<StateValue(const expr&, const expr&, const expr&, const expr&)>
@@ -554,89 +411,6 @@ StateValue BinOp::toSMT(State &s) const {
};
break;
- case FAdd:
- fn = [&](auto a, auto ap, auto b, auto bp) -> StateValue {
- return fm_poison(s, a, ap, b, bp,
- [](expr &a, expr &b) { return a.fadd(b); },
- fmath, false);
- };
- break;
-
- case FSub:
- fn = [&](auto a, auto ap, auto b, auto bp) -> StateValue {
- return fm_poison(s, a, ap, b, bp,
- [](expr &a, expr &b) { return a.fsub(b); },
- fmath, false);
- };
- break;
-
- case FMul:
- fn = [&](auto a, auto ap, auto b, auto bp) -> StateValue {
- return fm_poison(s, a, ap, b, bp,
- [](expr &a, expr &b) { return a.fmul(b); },
- fmath, false);
- };
- break;
-
- case FDiv:
- fn = [&](auto a, auto ap, auto b, auto bp) -> StateValue {
- return fm_poison(s, a, ap, b, bp,
- [](expr &a, expr &b) { return a.fdiv(b); },
- fmath, false);
- };
- break;
-
- case FRem:
- fn = [&](auto a, auto ap, auto b, auto bp) -> StateValue {
- // TODO; Z3 has no support for LLVM's frem which is actually an fmod
- return fm_poison(s, a, ap, b, bp,
- [&](expr &a, expr &b) {
- auto val = expr::mkUF("fmod", {a, b}, a);
- s.doesApproximation("frem", val);
- return val;
- },
- fmath, false);
- };
- break;
-
- case FMin:
- case FMax:
- fn = [&](auto a, auto ap, auto b, auto bp) -> StateValue {
- expr ndet = expr::mkFreshVar("maxminnondet", true);
- s.addQuantVar(ndet);
- auto ndz = expr::mkIf(ndet, expr::mkNumber("0", a),
- expr::mkNumber("-0", a));
-
- auto v = [&](expr &a, expr &b) {
- expr z = a.isFPZero() && b.isFPZero();
- expr cmp = (op == FMin) ? a.fole(b) : a.foge(b);
- return expr::mkIf(a.isNaN(), b,
- expr::mkIf(b.isNaN(), a,
- expr::mkIf(z, ndz,
- expr::mkIf(cmp, a, b))));
- };
- return fm_poison(s, a, ap, b, bp, v, fmath, false);
- };
- 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.isFPNegative() || b.isFPNegative())
- : (a.isFPNegative() && b.isFPNegative());
- 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, ap, b, bp, v, fmath, false);
- };
- break;
-
case UMin:
case UMax:
case SMin:
@@ -771,19 +545,6 @@ expr BinOp::getTypeConstraints(const Function &f) const {
getType() == lhs->getType() &&
rhs->getType().enforceIntType(1);
break;
- case FAdd:
- case FSub:
- case FMul:
- case FDiv:
- case FRem:
- case FMax:
- case FMin:
- case FMaximum:
- case FMinimum:
- instrconstr = getType().enforceFloatOrVectorType() &&
- getType() == lhs->getType() &&
- getType() == rhs->getType();
- break;
default:
instrconstr = getType().enforceIntOrVectorType() &&
getType() == lhs->getType() &&
@@ -794,8 +555,7 @@ expr BinOp::getTypeConstraints(const Function &f) const {
}
unique_ptr<Instr> BinOp::dup(const string &suffix) const {
- return make_unique<BinOp>(getType(), getName()+suffix, *lhs, *rhs, op, flags,
- fmath);
+ return make_unique<BinOp>(getType(), getName()+suffix, *lhs, *rhs, op, flags);
}
bool BinOp::isDivOrRem() const {
@@ -811,6 +571,246 @@ bool BinOp::isDivOrRem() const {
}
+vector<Value*> FpBinOp::operands() const {
+ return { lhs, rhs };
+}
+
+bool FpBinOp::propagatesPoison() const {
+ return true;
+}
+
+void FpBinOp::rauw(const Value &what, Value &with) {
+ RAUW(lhs);
+ RAUW(rhs);
+}
+
+void FpBinOp::print(ostream &os) const {
+ const char *str = nullptr;
+ switch (op) {
+ case FAdd: str = "fadd "; break;
+ case FSub: str = "fsub "; break;
+ case FMul: str = "fmul "; break;
+ case FDiv: str = "fdiv "; break;
+ 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;
+ }
+ os << getName() << " = " << str << fmath << *lhs << ", " << rhs->getName();
+}
+
+static expr any_fp_zero(State &s, const expr &v) {
+ expr is_zero = v.isFPZero();
+ if (is_zero.isFalse())
+ return v;
+
+ expr var = expr::mkFreshVar("anyzero", true);
+ s.addQuantVar(var);
+ return expr::mkIf(var && is_zero, v.fneg(), v);
+}
+
+static StateValue fm_poison(State &s, const expr &a, const expr &ap,
+ const expr &b, const expr &bp, const expr &c,
+ function<expr(expr&,expr&,expr&)> fn,
+ FastMathFlags fmath, bool only_input,
+ int nary = 3) {
+ expr new_a, new_b, new_c;
+ if (fmath.flags & FastMathFlags::NSZ) {
+ new_a = any_fp_zero(s, a);
+ if (nary >= 2) {
+ new_b = any_fp_zero(s, b);
+ if (nary == 3)
+ new_c = any_fp_zero(s, c);
+ }
+ } else {
+ new_a = a;
+ new_b = b;
+ new_c = c;
+ }
+
+ expr val = fn(new_a, new_b, new_c);
+ AndExpr non_poison;
+ non_poison.add(ap);
+ if (nary >= 2)
+ non_poison.add(bp);
+
+ if (fmath.flags & FastMathFlags::NNaN) {
+ non_poison.add(!a.isNaN());
+ if (nary >= 2) {
+ non_poison.add(!b.isNaN());
+ if (nary == 3)
+ non_poison.add(!c.isNaN());
+ }
+ if (!only_input)
+ non_poison.add(!val.isNaN());
+ }
+ if (fmath.flags & FastMathFlags::NInf) {
+ non_poison.add(!a.isInf());
+ if (nary >= 2) {
+ non_poison.add(!b.isInf());
+ if (nary == 3)
+ non_poison.add(!c.isInf());
+ }
+ if (!only_input)
+ non_poison.add(!val.isInf());
+ }
+ if (fmath.flags & FastMathFlags::ARCP) {
+ val = expr::mkUF("arcp", { val }, val);
+ s.doesApproximation("arcp", val);
+ }
+ if (fmath.flags & FastMathFlags::Contract) {
+ val = expr::mkUF("contract", { val }, val);
+ s.doesApproximation("contract", val);
+ }
+ if (fmath.flags & FastMathFlags::Reassoc) {
+ val = expr::mkUF("reassoc", { val }, val);
+ s.doesApproximation("reassoc", val);
+ }
+ if (fmath.flags & FastMathFlags::AFN) {
+ val = expr::mkUF("afn", { val }, val);
+ s.doesApproximation("afn", val);
+ }
+ if (fmath.flags & FastMathFlags::NSZ && !only_input)
+ val = any_fp_zero(s, move(val));
+
+ return { move(val), non_poison() };
+}
+
+static StateValue fm_poison(State &s, const expr &a, const expr &ap,
+ const expr &b, const expr &bp,
+ function<expr(expr&,expr&)> fn,
+ FastMathFlags fmath, bool only_input) {
+ return fm_poison(s, move(a), ap, move(b), bp, expr(),
+ [&](expr &a, expr &b, expr &c) { return fn(a, b); },
+ fmath, only_input, 2);
+}
+
+static StateValue fm_poison(State &s, const expr &a, const expr &ap,
+ function<expr(expr&)> fn,
+ FastMathFlags fmath, bool only_input) {
+ return fm_poison(s, move(a), ap, expr(), expr(), expr(),
+ [&](expr &a, expr &b, expr &c) { return fn(a); },
+ fmath, only_input, 1);
+}
+
+StateValue FpBinOp::toSMT(State &s) const {
+ function<StateValue(const expr&, const expr&, const expr&, const expr&)> fn;
+
+ switch (op) {
+ case FAdd:
+ fn = [&](auto a, auto ap, auto b, auto bp) -> StateValue {
+ return fm_poison(s, a, ap, b, bp,
+ [](expr &a, expr &b) { return a.fadd(b); },
+ fmath, false);
+ };
+ break;
+
+ case FSub:
+ fn = [&](auto a, auto ap, auto b, auto bp) -> StateValue {
+ return fm_poison(s, a, ap, b, bp,
+ [](expr &a, expr &b) { return a.fsub(b); },
+ fmath, false);
+ };
+ break;
+
+ case FMul:
+ fn = [&](auto a, auto ap, auto b, auto bp) -> StateValue {
+ return fm_poison(s, a, ap, b, bp,
+ [](expr &a, expr &b) { return a.fmul(b); },
+ fmath, false);
+ };
+ break;
+
+ case FDiv:
+ fn = [&](auto a, auto ap, auto b, auto bp) -> StateValue {
+ return fm_poison(s, a, ap, b, bp,
+ [](expr &a, expr &b) { return a.fdiv(b); },
+ fmath, false);
+ };
+ break;
+
+ case FRem:
+ fn = [&](auto a, auto ap, auto b, auto bp) -> StateValue {
+ // TODO; Z3 has no support for LLVM's frem which is actually an fmod
+ return fm_poison(s, a, ap, b, bp,
+ [&](expr &a, expr &b) {
+ auto val = expr::mkUF("fmod", {a, b}, a);
+ s.doesApproximation("frem", val);
+ return val;
+ },
+ fmath, false);
+ };
+ break;
+
+ case FMin:
+ case FMax:
+ fn = [&](auto a, auto ap, auto b, auto bp) -> StateValue {
+ expr ndet = expr::mkFreshVar("maxminnondet", true);
+ s.addQuantVar(ndet);
+ auto ndz = expr::mkIf(ndet, expr::mkNumber("0", a),
+ expr::mkNumber("-0", a));
+
+ auto v = [&](expr &a, expr &b) {
+ expr z = a.isFPZero() && b.isFPZero();
+ expr cmp = op == FMin ? a.fole(b) : a.foge(b);
+ return expr::mkIf(a.isNaN(), b,
+ expr::mkIf(b.isNaN(), a,
+ expr::mkIf(z, ndz,
+ expr::mkIf(cmp, a, b))));
+ };
+ return fm_poison(s, a, ap, b, bp, v, fmath, false);
+ };
+ 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.isFPNegative() || b.isFPNegative())
+ : (a.isFPNegative() && b.isFPNegative());
+ 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, ap, b, bp, v, fmath, false);
+ };
+ break;
+ }
+
+ auto &a = s[*lhs];
+ auto &b = s[*rhs];
+
+ if (lhs->getType().isVectorType()) {
+ auto retty = getType().getAsAggregateType();
+ vector<StateValue> vals;
+ for (unsigned i = 0, e = retty->numElementsConst(); i != e; ++i) {
+ auto ai = retty->extract(a, i);
+ auto bi = retty->extract(b, i);
+ vals.emplace_back(fn(ai.value, ai.non_poison, bi.value, bi.non_poison));
+ }
+ return retty->aggregateVals(vals);
+ }
+ return fn(a.value, a.non_poison, b.value, b.non_poison);
+}
+
+expr FpBinOp::getTypeConstraints(const Function &f) const {
+ return Value::getTypeConstraints() &&
+ getType().enforceFloatOrVectorType() &&
+ getType() == lhs->getType() &&
+ getType() == rhs->getType();
+}
+
+unique_ptr<Instr> FpBinOp::dup(const string &suffix) const {
+ return make_unique<FpBinOp>(getType(), getName()+suffix, *lhs, *rhs, op,
+ fmath);
+}
+
+
vector<Value*> UnaryOp::operands() const {
return { val };
}

MODIFY
ir/instr.h
ir/instr.h
@@ -33,7 +33,6 @@ 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, 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 };
@@ -41,12 +40,35 @@ private:
Value *lhs, *rhs;
Op op;
unsigned flags;
- FastMathFlags fmath;
bool isDivOrRem() const;
public:
BinOp(Type &type, std::string &&name, Value &lhs, Value &rhs, Op op,
- unsigned flags = 0, FastMathFlags fmath = {});
+ unsigned flags = None);
+
+ std::vector<Value*> operands() const override;
+ bool propagatesPoison() const override;
+ void rauw(const Value &what, Value &with) override;
+ void print(std::ostream &os) const override;
+ StateValue toSMT(State &s) const override;
+ smt::expr getTypeConstraints(const Function &f) const override;
+ std::unique_ptr<Instr> dup(const std::string &suffix) const override;
+};
+
+
+class FpBinOp final : public Instr {
+public:
+ enum Op { FAdd, FSub, FMul, FDiv, FRem, FMax, FMin, FMaximum, FMinimum };
+
+private:
+ Value *lhs, *rhs;
+ Op op;
+ FastMathFlags fmath;
+
+public:
+ FpBinOp(Type &type, std::string &&name, Value &lhs, Value &rhs, Op op,
+ FastMathFlags fmath)
+ : Instr(type, std::move(name)), lhs(&lhs), rhs(&rhs), op(op), fmath(fmath) {}
std::vector<Value*> operands() const override;
bool propagatesPoison() const override;

MODIFY
llvm_util/llvm2alive.cpp
llvm_util/llvm2alive.cpp
@@ -159,6 +159,8 @@ public:
RetTy visitBinaryOperator(llvm::BinaryOperator &i) {
PARSE_BINOP();
BinOp::Op alive_op;
+ FpBinOp::Op fp_op;
+ bool is_fp = false;
switch (i.getOpcode()) {
case llvm::Instruction::Add: alive_op = BinOp::Add; break;
case llvm::Instruction::Sub: alive_op = BinOp::Sub; break;
@@ -173,15 +175,19 @@ public:
case llvm::Instruction::And: alive_op = BinOp::And; break;
case llvm::Instruction::Or: alive_op = BinOp::Or; break;
case llvm::Instruction::Xor: alive_op = BinOp::Xor; break;
- case llvm::Instruction::FAdd: alive_op = BinOp::FAdd; break;
- case llvm::Instruction::FSub: alive_op = BinOp::FSub; break;
- case llvm::Instruction::FMul: alive_op = BinOp::FMul; break;
- case llvm::Instruction::FDiv: alive_op = BinOp::FDiv; break;
- case llvm::Instruction::FRem: alive_op = BinOp::FRem; break;
+ case llvm::Instruction::FAdd: fp_op = FpBinOp::FAdd; is_fp = true; break;
+ case llvm::Instruction::FSub: fp_op = FpBinOp::FSub; is_fp = true; break;
+ case llvm::Instruction::FMul: fp_op = FpBinOp::FMul; is_fp = true; break;
+ case llvm::Instruction::FDiv: fp_op = FpBinOp::FDiv; is_fp = true; break;
+ case llvm::Instruction::FRem: fp_op = FpBinOp::FRem; is_fp = true; break;
default:
return error(i);
}
+ if (is_fp)
+ RETURN_IDENTIFIER(make_unique<FpBinOp>(*ty, value_name(i), *a, *b, fp_op,
+ parse_fmath(i)));
+
unsigned flags = BinOp::None;
if (isa<llvm::OverflowingBinaryOperator>(i) && i.hasNoSignedWrap())
flags |= BinOp::NSW;
@@ -190,7 +196,7 @@ public:
if (isa<llvm::PossiblyExactOperator>(i) && i.isExact())
flags = BinOp::Exact;
RETURN_IDENTIFIER(make_unique<BinOp>(*ty, value_name(i), *a, *b, alive_op,
- flags, parse_fmath(i)));
+ flags));
}
RetTy visitCastInst(llvm::CastInst &i) {
@@ -894,16 +900,16 @@ public:
case llvm::Intrinsic::maximum:
{
PARSE_BINOP();
- BinOp::Op op;
+ FpBinOp::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;
+ case llvm::Intrinsic::minnum: op = FpBinOp::FMin; break;
+ case llvm::Intrinsic::maxnum: op = FpBinOp::FMax; break;
+ case llvm::Intrinsic::minimum: op = FpBinOp::FMinimum; break;
+ case llvm::Intrinsic::maximum: op = FpBinOp::FMaximum; break;
default: UNREACHABLE();
}
- RETURN_IDENTIFIER(make_unique<BinOp>(*ty, value_name(i), *a, *b,
- op, BinOp::None, parse_fmath(i)));
+ RETURN_IDENTIFIER(make_unique<FpBinOp>(*ty, value_name(i), *a, *b, op,
+ parse_fmath(i)));
}
case llvm::Intrinsic::lifetime_start:
case llvm::Intrinsic::lifetime_end:

MODIFY
tools/alive_parser.cpp
tools/alive_parser.cpp
@@ -638,25 +638,6 @@ static FastMathFlags parse_fast_math(token op_token) {
break;
}
}
-
- switch (op_token) {
- case FABS:
- case FADD:
- case FSUB:
- case FMUL:
- case FDIV:
- case FREM:
- case FCMP:
- case FMA:
- case FMAX:
- case FMIN:
- case FMAXIMUM:
- case FMINIMUM:
- break;
- default:
- if (!fmath.isNone())
- error("Unexpected fast-math tokens");
- }
return fmath;
}
@@ -714,7 +695,6 @@ static unsigned parse_binop_flags(token op_token) {
static unique_ptr<Instr> parse_binop(string_view name, token op_token) {
auto flags = parse_binop_flags(op_token);
- auto fmath = parse_fast_math(op_token);
auto &type = parse_type();
auto &a = parse_operand(type);
parse_comma();
@@ -769,26 +749,41 @@ static unique_ptr<Instr> parse_binop(string_view name, token op_token) {
op = BinOp::UMul_Overflow;
rettype = &get_overflow_type(type);
break;
- case FADD: op = BinOp::FAdd; break;
- case FSUB: op = BinOp::FSub; break;
- case FMUL: op = BinOp::FMul; break;
- case FDIV: op = BinOp::FDiv; break;
- 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;
case SMAX: op = BinOp::SMax; break;
- case ABS:
- op = BinOp::Abs;
- break;
+ case ABS: op = BinOp::Abs; break;
+ default:
+ UNREACHABLE();
+ }
+ return make_unique<BinOp>(*rettype, string(name), a, b, op, flags);
+}
+
+static unique_ptr<Instr> parse_fp_binop(string_view name, token op_token) {
+ auto fmath = parse_fast_math(op_token);
+ auto &type = parse_type();
+ auto &a = parse_operand(type);
+ parse_comma();
+ Type &type_rhs = try_parse_type(type);
+ auto &b = parse_operand(type_rhs);
+ Type *rettype = &type;
+
+ FpBinOp::Op op;
+ switch (op_token) {
+ case FADD: op = FpBinOp::FAdd; break;
+ case FSUB: op = FpBinOp::FSub; break;
+ case FMUL: op = FpBinOp::FMul; break;
+ case FDIV: op = FpBinOp::FDiv; break;
+ case FREM: op = FpBinOp::FRem; break;
+ case FMAX: op = FpBinOp::FMax; break;
+ case FMIN: op = FpBinOp::FMin; break;
+ case FMAXIMUM: op = FpBinOp::FMaximum; break;
+ case FMINIMUM: op = FpBinOp::FMinimum; break;
default:
UNREACHABLE();
}
- return make_unique<BinOp>(*rettype, string(name), a, b, op, flags, fmath);
+ return make_unique<FpBinOp>(*rettype, string(name), a, b, op, fmath);
}
static unique_ptr<Instr> parse_unaryop(string_view name, token op_token) {
@@ -1137,6 +1132,12 @@ static unique_ptr<Instr> parse_instr(string_view name) {
case USUB_OVERFLOW:
case SMUL_OVERFLOW:
case UMUL_OVERFLOW:
+ case UMIN:
+ case UMAX:
+ case SMIN:
+ case SMAX:
+ case ABS:
+ return parse_binop(name, t);
case FADD:
case FSUB:
case FMUL:
@@ -1146,12 +1147,7 @@ static unique_ptr<Instr> parse_instr(string_view name) {
case FMIN:
case FMAXIMUM:
case FMINIMUM:
- case UMIN:
- case UMAX:
- case SMIN:
- case SMAX:
- case ABS:
- return parse_binop(name, t);
+ return parse_fp_binop(name, t);
case BITREVERSE:
case BSWAP:
case CTPOP:

refactor fp bin ops in preparation for adding support for rounding modes