add parse & sema support for select, and, x?or, [su]rem, trunc, [sz]ext
MODIFY
ir/instr.cpp
ir/instr.cpp
@@ -10,27 +10,31 @@ using namespace std;
namespace IR {
-void Instr::printType(ostream &os) const {
- auto t = getType().toString();
- if (!t.empty())
- os << t << ' ';
-}
-
-
BinOp::BinOp(unique_ptr<Type> &&type, string &&name, Value &lhs, Value &rhs,
Op op, Flags flags)
: Instr(move(type), move(name)), lhs(lhs), rhs(rhs), op(op), flags(flags) {
getWType().enforceIntOrPtrOrVectorType();
switch (op) {
- case Add: assert((flags & NSWNUW) == flags); break;
- case Sub: assert((flags & NSWNUW) == flags); break;
- case Mul: assert((flags & NSWNUW) == flags); break;
- case SDiv: assert((flags & Exact) == flags); break;
- case UDiv: assert((flags & Exact) == flags); break;
- case Shl: assert((flags & NSWNUW) == flags); break;
- case AShr: assert((flags & Exact) == flags); break;
- case LShr: assert((flags & Exact) == flags); break;
+ case Add:
+ case Sub:
+ case Mul:
+ case Shl:
+ assert((flags & NSWNUW) == flags);
+ break;
+ case SDiv:
+ case UDiv:
+ case AShr:
+ case LShr:
+ assert((flags & Exact) == flags);
+ break;
+ case SRem:
+ case URem:
+ case And:
+ case Or:
+ case Xor:
+ assert(flags == 0);
+ break;
}
}
@@ -42,9 +46,14 @@ void BinOp::print(ostream &os) const {
case Mul: str = "mul"; break;
case SDiv: str = "sdiv"; break;
case UDiv: str = "udiv"; break;
+ case SRem: str = "srem"; break;
+ case URem: str = "urem"; break;
case Shl: str = "shl"; break;
case AShr: str = "ashr"; break;
case LShr: str = "lshr"; break;
+ case And: str = "and"; break;
+ case Or: str = "or"; break;
+ case Xor: str = "xor"; break;
}
const char *flag = nullptr;
@@ -56,9 +65,16 @@ void BinOp::print(ostream &os) const {
case Exact: flag = " exact "; break;
}
- os << getName() << " = " << str << flag;
- printType(os);
- os << lhs.getName() << ", " << rhs.getName();
+ os << getName() << " = " << str << flag << lhs << ", " << rhs.getName();
+}
+
+static void div_ub(State &s, const expr &a, const expr &b, const expr &ap,
+ const expr &bp, bool sign) {
+ auto bits = b.bits();
+ s.addUB(bp);
+ s.addUB(b != expr::mkUInt(0, bits));
+ if (sign)
+ s.addUB((ap && a != expr::IntMin(bits)) || b != expr::mkInt(-1, bits));
}
StateValue BinOp::toSMT(State &s) const {
@@ -93,24 +109,29 @@ StateValue BinOp::toSMT(State &s) const {
break;
case SDiv:
- {
val = a.sdiv(b);
+ div_ub(s, a, b, ap, bp, true);
+
if (flags & Exact)
not_poison &= a.sdiv_exact(b);
-
- auto bits = b.bits();
- s.addUB(bp);
- s.addUB(b != expr::mkUInt(0, bits));
- s.addUB((ap && a != expr::IntMin(bits)) || b != expr::mkInt(-1, bits));
break;
- }
+
case UDiv:
val = a.udiv(b);
+ div_ub(s, a, b, ap, bp, false);
+
if (flags & Exact)
not_poison &= a.udiv_exact(b);
+ break;
- s.addUB(bp);
- s.addUB(b != expr::mkUInt(0, b.bits()));
+ case SRem:
+ val = a.srem(b);
+ div_ub(s, a, b, ap, bp, true);
+ break;
+
+ case URem:
+ val = a.urem(b);
+ div_ub(s, a, b, ap, bp, false);
break;
case Shl:
@@ -146,6 +167,17 @@ StateValue BinOp::toSMT(State &s) const {
not_poison &= a.lshr_exact(b);
break;
}
+ case And:
+ val = a & b;
+ break;
+
+ case Or:
+ val = a | b;
+ break;
+
+ case Xor:
+ val = a ^ b;
+ break;
}
return { move(val), move(not_poison) };
}
@@ -157,10 +189,98 @@ expr BinOp::getTypeConstraints() const {
}
+ConversionOp::ConversionOp(unique_ptr<Type> &&type, string &&name, Value &val,
+ Op op) :
+ Instr(move(type), move(name)), val(val), op(op) {
+ getWType().enforceIntOrPtrOrVectorType();
+ val.getWType().enforceIntOrPtrOrVectorType();
+}
+
+void ConversionOp::print(std::ostream &os) const {
+ const char *str = nullptr;
+ switch (op) {
+ case SExt: str = "sext "; break;
+ case ZExt: str = "zext "; break;
+ case Trunc: str = "trunc "; break;
+ }
+
+ os << getName() << " = " << str << val;
+
+ if (auto ty = getType().toString();
+ !ty.empty())
+ os << " to " << ty;
+}
+
+StateValue ConversionOp::toSMT(State &s) const {
+ auto &[v, vp] = s[val];
+ expr newval;
+ auto to_bw = getType().bits();
+
+ switch (op) {
+ case SExt:
+ newval = v.sext(to_bw - val.bits());
+ break;
+ case ZExt:
+ newval = v.zext(to_bw - val.bits());
+ break;
+ case Trunc:
+ newval = v.trunc(to_bw);
+ break;
+ }
+ return { move(newval), expr(vp) };
+}
+
+expr ConversionOp::getTypeConstraints() const {
+ expr sizeconstr;
+ switch (op) {
+ case SExt:
+ case ZExt:
+ sizeconstr = val.getType().sizeVar().ult(getType().sizeVar());
+ break;
+ case Trunc:
+ sizeconstr = getType().sizeVar().ult(val.getType().sizeVar());
+ break;
+ }
+ // TODO: missing constraint comparing ty and to_ty (e.g. both ints)
+ return getType().getTypeConstraints() &&
+ val.getTypeConstraints() &&
+ move(sizeconstr);
+}
+
+
+Select::Select(unique_ptr<Type> &&type, string &&name, Value &cond, Value &a,
+ Value &b)
+ : Instr(move(type), move(name)), cond(cond), a(a), b(b) {
+ getWType().enforceIntOrPtrOrVectorType();
+ cond.getWType().enforceIntType();
+ a.getWType().enforceIntOrPtrOrVectorType();
+ b.getWType().enforceIntOrPtrOrVectorType();
+}
+
+void Select::print(std::ostream &os) const {
+ os << getName() << " = select " << cond << ", " << a << ", " << b;
+}
+
+StateValue Select::toSMT(State &s) const {
+ auto &[c, cp] = s[cond];
+ auto &[av, ap] = s[a];
+ auto &[bv, bp] = s[b];
+ auto cond = c == 1u;
+ return { expr::mkIf(cond, av, bv),
+ cp && expr::mkIf(cond, ap, bp) };
+}
+
+expr Select::getTypeConstraints() const {
+ return cond.getTypeConstraints() &&
+ cond.getType().sizeVar() == 1u &&
+ getType().getTypeConstraints() &&
+ getType() == a.getType() &&
+ getType() == b.getType();
+}
+
+
void Return::print(ostream &os) const {
- os << "ret ";
- printType(os);
- os << val.getName();
+ os << "ret " << val;
}
StateValue Return::toSMT(State &s) const {

MODIFY
ir/instr.h
ir/instr.h
@@ -12,13 +12,13 @@ protected:
Instr(std::unique_ptr<Type> &&type, std::string &&name,
bool mk_unique_name = false)
: Value(std::move(type), std::move(name), mk_unique_name) {}
- void printType(std::ostream &os) const;
};
class BinOp final : public Instr {
public:
- enum Op { Add, Sub, Mul, SDiv, UDiv, Shl, AShr, LShr };
+ enum Op { Add, Sub, Mul, SDiv, UDiv, SRem, URem, Shl, AShr, LShr,
+ And, Or, Xor };
enum Flags { None = 0, NSW = 1, NUW = 2, NSWNUW = 3, Exact = 4 };
private:
@@ -36,6 +36,34 @@ public:
};
+class ConversionOp final : public Instr {
+public:
+ enum Op { SExt, ZExt, Trunc };
+
+private:
+ Value &val;
+ Op op;
+
+public:
+ ConversionOp(std::unique_ptr<Type> &&type, std::string &&name, Value &val,
+ Op op);
+ void print(std::ostream &os) const override;
+ StateValue toSMT(State &s) const override;
+ smt::expr getTypeConstraints() const override;
+};
+
+
+class Select final : public Instr {
+ Value &cond, &a, &b;
+public:
+ Select(std::unique_ptr<Type> &&type, std::string &&name, Value &cond,
+ Value &a, Value &b);
+ void print(std::ostream &os) const override;
+ StateValue toSMT(State &s) const override;
+ smt::expr getTypeConstraints() const override;
+};
+
+
class Return final : public Instr {
Value &val;
public:

MODIFY
ir/type.cpp
ir/type.cpp
@@ -26,6 +26,10 @@ expr Type::typeVar() const {
return var("type", var_type_bits);
}
+expr Type::sizeVar() const {
+ return var("bw", var_bw_bits);
+}
+
expr Type::is(unsigned t) const {
return typeVar() == expr::mkUInt(t, var_type_bits);
}
@@ -90,10 +94,6 @@ expr VoidType::getTypeConstraints() const {
return true;
}
-expr VoidType::atLeastBits(unsigned bits) const {
- UNREACHABLE();
-}
-
void VoidType::fixup(const Model &m) {
// do nothing
}
@@ -114,7 +114,7 @@ unsigned IntType::bits() const {
expr IntType::getTypeConstraints() const {
auto c = isInt();
- auto bw = var("bw", var_bw_bits);
+ auto bw = sizeVar();
if (defined) {
c &= bw == expr::mkUInt(bitwidth, var_bw_bits);
}
@@ -126,17 +126,13 @@ expr IntType::getTypeConstraints() const {
return c;
}
-expr IntType::atLeastBits(unsigned bits) const {
- return var("bw", var_bw_bits).uge(expr::mkUInt(bits, var_bw_bits));
-}
-
expr IntType::operator==(const IntType &rhs) const {
- return var("bw", var_bw_bits) == rhs.var("bw", var_bw_bits);
+ return sizeVar() == rhs.sizeVar();
}
void IntType::fixup(const Model &m) {
assert(m.getUInt(typeVar()) == SymbolicType::Int);
- bitwidth = m.getUInt(var("bw", var_bw_bits));
+ bitwidth = m.getUInt(sizeVar());
defined = true;
}
@@ -163,11 +159,6 @@ expr FloatType::getTypeConstraints() const {
return isFloat() && false;
}
-expr FloatType::atLeastBits(unsigned bits) const {
- // TODO
- return true;
-}
-
expr FloatType::operator==(const FloatType &rhs) const {
// TODO
return true;
@@ -192,13 +183,9 @@ expr PtrType::getTypeConstraints() const {
return isPtr() && false;
}
-expr PtrType::atLeastBits(unsigned bits) const {
- return var("bw", var_bw_bits).uge(expr::mkUInt(bits, var_bw_bits));
-}
-
expr PtrType::operator==(const PtrType &rhs) const {
// TODO
- return var("bw", var_bw_bits) == rhs.var("bw", var_bw_bits);
+ return sizeVar() == rhs.sizeVar();
}
void PtrType::fixup(const Model &m) {
@@ -224,11 +211,6 @@ expr ArrayType::getTypeConstraints() const {
return isArray() && false;
}
-expr ArrayType::atLeastBits(unsigned bits) const {
- // FIXME
- return true;
-}
-
expr ArrayType::operator==(const ArrayType &rhs) const {
// TODO
return true;
@@ -253,11 +235,6 @@ expr VectorType::getTypeConstraints() const {
return isVector() && false;
}
-expr VectorType::atLeastBits(unsigned bits) const {
- // FIXME
- return true;
-}
-
expr VectorType::operator==(const VectorType &rhs) const {
// TODO
return true;
@@ -334,16 +311,6 @@ expr SymbolicType::getTypeConstraints() const {
return c;
}
-expr SymbolicType::atLeastBits(unsigned bits) const {
- expr c(false);
- c |= isInt() && i.atLeastBits(bits);
- c |= isFloat() && f.atLeastBits(bits);
- c |= isPtr() && p.atLeastBits(bits);
- c |= isArray() && a.atLeastBits(bits);
- c |= isVector() && v.atLeastBits(bits);
- return c;
-}
-
expr SymbolicType::operator==(const Type &b) const {
if (auto rhs = dynamic_cast<const IntType*>(&b))
return isInt() && i == *rhs;

MODIFY
ir/type.h
ir/type.h
@@ -31,7 +31,7 @@ public:
virtual unsigned bits() const;
virtual smt::expr getTypeConstraints() const = 0;
- virtual smt::expr atLeastBits(unsigned bits) const = 0;
+ smt::expr sizeVar() const;
smt::expr operator==(const Type &rhs) const;
virtual void fixup(const smt::Model &m) = 0;
@@ -50,7 +50,6 @@ class VoidType final : public Type {
public:
VoidType() {}
smt::expr getTypeConstraints() const override;
- smt::expr atLeastBits(unsigned bits) const override;
void fixup(const smt::Model &m) override;
std::unique_ptr<Type> dup() const override;
void print(std::ostream &os) const override;
@@ -66,7 +65,6 @@ public:
IntType(unsigned bitwidth) : bitwidth(bitwidth), defined(true) {}
unsigned bits() const override;
smt::expr getTypeConstraints() const override;
- smt::expr atLeastBits(unsigned bits) const override;
smt::expr operator==(const IntType &rhs) const;
void fixup(const smt::Model &m) override;
void enforceIntType() override;
@@ -80,7 +78,6 @@ class FloatType final : public Type {
public:
FloatType() {}
smt::expr getTypeConstraints() const override;
- smt::expr atLeastBits(unsigned bits) const override;
smt::expr operator==(const FloatType &rhs) const;
void fixup(const smt::Model &m) override;
std::unique_ptr<Type> dup() const override;
@@ -92,7 +89,6 @@ class PtrType final : public Type {
public:
PtrType() {}
smt::expr getTypeConstraints() const override;
- smt::expr atLeastBits(unsigned bits) const override;
smt::expr operator==(const PtrType &rhs) const;
void fixup(const smt::Model &m) override;
void enforceIntOrPtrOrVectorType() override;
@@ -105,7 +101,6 @@ class ArrayType final : public Type {
public:
ArrayType() {}
smt::expr getTypeConstraints() const override;
- smt::expr atLeastBits(unsigned bits) const override;
smt::expr operator==(const ArrayType &rhs) const;
void fixup(const smt::Model &m) override;
std::unique_ptr<Type> dup() const override;
@@ -117,7 +112,6 @@ class VectorType final : public Type {
public:
VectorType() {}
smt::expr getTypeConstraints() const override;
- smt::expr atLeastBits(unsigned bits) const override;
smt::expr operator==(const VectorType &rhs) const;
void fixup(const smt::Model &m) override;
void enforceIntOrPtrOrVectorType() override;
@@ -153,7 +147,6 @@ public:
void setName(const std::string &name) override;
unsigned bits() const override;
smt::expr getTypeConstraints() const override;
- smt::expr atLeastBits(unsigned bits) const override;
smt::expr operator==(const Type &rhs) const;
void fixup(const smt::Model &m) override;
void enforceIntType() override;

MODIFY
ir/value.cpp
ir/value.cpp
@@ -54,7 +54,7 @@ StateValue IntConst::toSMT(State &s) const {
expr IntConst::getTypeConstraints() const {
unsigned min_bits = (val >= 0 ? 63 : 64) - num_sign_bits(val);
return getType().getTypeConstraints() &&
- getType().atLeastBits(min_bits);
+ getType().sizeVar().uge(min_bits);
}

MODIFY
ir/value.h
ir/value.h
@@ -21,12 +21,12 @@ class Value {
protected:
Value(std::unique_ptr<Type> &&type, std::string &&name,
bool mk_unique_name = false);
- Type& getWType() { return *type.get(); }
public:
unsigned bits() const { return type->bits(); }
const std::string& getName() const { return name; }
const Type& getType() const { return *type.get(); }
+ Type& getWType() { return *type.get(); }
virtual void print(std::ostream &os) const = 0;
virtual StateValue toSMT(State &s) const = 0;

MODIFY
smt/expr.cpp
smt/expr.cpp
@@ -250,7 +250,11 @@ bool expr::isNot(expr &neg) const {
return false;
auto decl = Z3_get_app_decl(ctx(), app);
- return Z3_get_decl_kind(ctx(), decl) == Z3_OP_NOT;
+ if (Z3_get_decl_kind(ctx(), decl) != Z3_OP_NOT)
+ return false;
+
+ neg = Z3_get_app_arg(ctx(), app, 0);
+ return true;
}
expr expr::binop_commutative(const expr &rhs,
@@ -353,6 +357,41 @@ expr expr::udiv(const expr &rhs) const {
return Z3_mk_bvudiv(ctx(), ast(), rhs());
}
+expr expr::srem(const expr &rhs) const {
+ C(rhs);
+
+ if (eq(rhs))
+ return mkUInt(1, sort());
+
+ if (rhs.isZero())
+ return rhs;
+
+ if (isSMin() && rhs.isAllOnes())
+ return mkUInt(0, sort());
+
+ expr r;
+ if (binop_sfold(rhs, [](auto a, auto b) { return a % b; }, r))
+ return r;
+
+ return Z3_mk_bvsrem(ctx(), ast(), rhs());
+}
+
+expr expr::urem(const expr &rhs) const {
+ C(rhs);
+
+ if (eq(rhs))
+ return mkUInt(1, sort());
+
+ if (rhs.isZero())
+ return rhs;
+
+ expr r;
+ if (binop_ufold(rhs, [](auto a, auto b) { return a % b; }, r))
+ return r;
+
+ return Z3_mk_bvurem(ctx(), ast(), rhs());
+}
+
expr expr::add_no_soverflow(const expr &rhs) const {
return sext(1) + rhs.sext(1) == (*this + rhs).sext(1);
}
@@ -616,6 +655,10 @@ expr expr::zext(unsigned amount) const {
return mkUInt(0, amount).concat(*this);
}
+expr expr::trunc(unsigned tobw) const {
+ return extract(tobw-1, 0);
+}
+
expr expr::concat(const expr &rhs) const {
C(rhs);
return Z3_mk_concat(ctx(), ast(), rhs());
@@ -633,7 +676,16 @@ expr expr::mkIf(const expr &cond, const expr &then, const expr &els) {
return then;
if (cond.isFalse())
return els;
- return Z3_mk_ite(ctx(), cond(), then(), els());
+
+ expr notcond;
+ Z3_ast c, t = then(), e = els();
+ if (cond.isNot(notcond)) {
+ c = notcond();
+ swap(t, e);
+ } else {
+ c = cond();
+ }
+ return Z3_mk_ite(ctx(), c, t, e);
}
ostream& operator<<(ostream &os, const expr &e) {

MODIFY
smt/expr.h
smt/expr.h
@@ -98,6 +98,8 @@ public:
expr operator*(const expr &rhs) const;
expr sdiv(const expr &rhs) const;
expr udiv(const expr &rhs) const;
+ expr srem(const expr &rhs) const;
+ expr urem(const expr &rhs) const;
expr add_no_soverflow(const expr &rhs) const;
expr add_no_uoverflow(const expr &rhs) const;
@@ -145,8 +147,15 @@ public:
expr sge(const expr &rhs) const;
expr sgt(const expr &rhs) const;
+ expr ule(uint64_t rhs) const { return ule(mkUInt(rhs, bits())); }
+ expr ult(uint64_t rhs) const { return ult(mkUInt(rhs, bits())); }
+ expr uge(uint64_t rhs) const { return uge(mkUInt(rhs, bits())); }
+ expr ugt(uint64_t rhs) const { return ugt(mkUInt(rhs, bits())); }
+ expr operator==(uint64_t rhs) const { return *this == mkUInt(rhs, bits()); }
+
expr sext(unsigned amount) const;
expr zext(unsigned amount) const;
+ expr trunc(unsigned tobw) const;
expr concat(const expr &rhs) const;
expr extract(unsigned high, unsigned low) const;

MODIFY
tools/alive_lexer.re
tools/alive_lexer.re
@@ -124,17 +124,29 @@ re2c:yyfill:check = 0;
return LABEL;
}
+"true" { return TRUE; }
+"false" { return FALSE; }
"add" { return ADD; }
"mul" { return MUL; }
"sub" { return SUB; }
"sdiv" { return SDIV; }
"udiv" { return UDIV; }
+"srem" { return SREM; }
+"urem" { return UREM; }
"shl" { return SHL; }
"ashr" { return ASHR; }
"lshr" { return LSHR; }
+"and" { return AND; }
+"or" { return OR; }
+"xor" { return XOR; }
"nsw" { return NSW; }
"nuw" { return NUW; }
"exact" { return EXACT; }
+"sext" { return SEXT; }
+"zext" { return ZEXT; }
+"trunc" { return TRUNC; }
+"to" { return TO; }
+"select" { return SELECT; }
"ret" { return RETURN; }
"unreachable" { return UNREACH; }

MODIFY
tools/alive_parser.cpp
tools/alive_parser.cpp
@@ -113,7 +113,7 @@ static void parse_comma() {
tokenizer.ensure(COMMA);
}
-static unique_ptr<Type> parse_type(bool optional) {
+static unique_ptr<Type> parse_type(bool optional = true) {
switch (auto t = *tokenizer) {
case INT_TYPE:
return make_unique<IntType>(yylval.num);
@@ -131,7 +131,13 @@ static unique_ptr<Type> parse_type(bool optional) {
static Value& parse_operand(Type *type) {
switch (auto t = *tokenizer) {
case NUM:
+ // FIXME: constraint type to int
return get_constant(yylval.num, type);
+ case TRUE:
+ // FIXME: constrain types below to boolean
+ return get_constant(1, type);
+ case FALSE:
+ return get_constant(0, type);
case IDENTIFIER: {
string id(yylval.str);
if (auto I = identifiers.find(id);
@@ -172,14 +178,22 @@ static BinOp::Flags parse_exact() {
static BinOp::Flags parse_binop_flags(token op_token) {
switch (op_token) {
- case ADD: return parse_nsw_nuw();
- case SUB: return parse_nsw_nuw();
- case MUL: return parse_nsw_nuw();
- case SDIV: return parse_exact();
- case UDIV: return parse_exact();
- case SHL: return parse_nsw_nuw();
- case LSHR: return parse_exact();
- case ASHR: return parse_exact();
+ case ADD:
+ case SUB:
+ case MUL:
+ case SHL:
+ return parse_nsw_nuw();
+ case SDIV:
+ case UDIV:
+ case LSHR:
+ case ASHR:
+ return parse_exact();
+ case SREM:
+ case UREM:
+ case AND:
+ case OR:
+ case XOR:
+ return BinOp::None;
default:
UNREACHABLE();
}
@@ -187,7 +201,7 @@ static BinOp::Flags parse_binop_flags(token op_token) {
static unique_ptr<Instr> parse_binop(string_view name, token op_token) {
BinOp::Flags flags = parse_binop_flags(op_token);
- auto type = parse_type(/*optional=*/true);
+ auto type = parse_type();
auto &a = parse_operand(type.get());
parse_comma();
auto &b = parse_operand(type.get());
@@ -199,15 +213,53 @@ static unique_ptr<Instr> parse_binop(string_view name, token op_token) {
case MUL: op = BinOp::Mul; break;
case SDIV: op = BinOp::SDiv; break;
case UDIV: op = BinOp::UDiv; break;
+ case SREM: op = BinOp::SRem; break;
+ case UREM: op = BinOp::URem; break;
case SHL: op = BinOp::Shl; break;
case LSHR: op = BinOp::LShr; break;
case ASHR: op = BinOp::AShr; break;
+ case AND: op = BinOp::And; break;
+ case OR: op = BinOp::Or; break;
+ case XOR: op = BinOp::Xor; break;
default:
UNREACHABLE();
}
return make_unique<BinOp>(move(type), string(name), a, b, op, flags);
}
+static unique_ptr<Instr> parse_conversionop(string_view name, token op_token) {
+ // op ty %op to ty2
+ auto opty = parse_type();
+ auto &val = parse_operand(opty.get());
+ unique_ptr<Type> ty2;
+ if (tokenizer.consumeIf(TO)) {
+ ty2 = parse_type(/*optional=*/false);
+ }
+
+ ConversionOp::Op op;
+ switch (op_token) {
+ case SEXT: op = ConversionOp::SExt; break;
+ case ZEXT: op = ConversionOp::ZExt; break;
+ case TRUNC: op = ConversionOp::Trunc; break;
+ default:
+ UNREACHABLE();
+ }
+ return make_unique<ConversionOp>(move(ty2), string(name), val, op);
+}
+
+static unique_ptr<Instr> parse_select(string_view name) {
+ // select condty %cond, ty %a, ty %b
+ auto condty = parse_type();
+ auto &cond = parse_operand(condty.get());
+ parse_comma();
+ auto aty = parse_type();
+ auto &a = parse_operand(aty.get());
+ parse_comma();
+ auto bty = parse_type();
+ auto &b = parse_operand(bty.get());
+ return make_unique<Select>(move(aty), string(name), cond, a, b);
+}
+
static unique_ptr<Instr> parse_instr(string_view name) {
// %name = instr arg1, arg2, ...
tokenizer.ensure(EQUALS);
@@ -217,10 +269,21 @@ static unique_ptr<Instr> parse_instr(string_view name) {
case MUL:
case SDIV:
case UDIV:
+ case SREM:
+ case UREM:
case SHL:
case ASHR:
case LSHR:
+ case AND:
+ case OR:
+ case XOR:
return parse_binop(name, t);
+ case SEXT:
+ case ZEXT:
+ case TRUNC:
+ return parse_conversionop(name, t);
+ case SELECT:
+ return parse_select(name);
default:
error(string("Expected instruction name; got: ") + token_name[t]);
}
@@ -228,7 +291,7 @@ static unique_ptr<Instr> parse_instr(string_view name) {
}
static unique_ptr<Instr> parse_return() {
- auto type = parse_type(/*optional=*/true);
+ auto type = parse_type();
auto &val = parse_operand(type.get());
return make_unique<Return>(move(type), val);
}

MODIFY
tools/tokens.h
tools/tokens.h
TOKEN(END)
TOKEN(ADD)
+TOKEN(AND)
TOKEN(ARROW)
TOKEN(ASHR)
TOKEN(COMMA)
TOKEN(EQUALS)
TOKEN(EXACT)
+TOKEN(FALSE)
TOKEN(IDENTIFIER)
TOKEN(INT_TYPE)
TOKEN(LABEL)
@@ -17,10 +19,20 @@ TOKEN(NAME)
TOKEN(NSW)
TOKEN(NUM)
TOKEN(NUW)
+TOKEN(OR)
TOKEN(PRE)
TOKEN(RETURN)
TOKEN(SDIV)
+TOKEN(SELECT)
+TOKEN(SEXT)
TOKEN(SHL)
+TOKEN(SREM)
TOKEN(SUB)
+TOKEN(TO)
+TOKEN(TRUE)
+TOKEN(TRUNC)
TOKEN(UDIV)
TOKEN(UNREACH)
+TOKEN(UREM)
+TOKEN(XOR)
+TOKEN(ZEXT)

add parse & sema support for select, and, x?or, [su]rem, trunc, [sz]ext