add support for llvm.bswap
MODIFY
ir/instr.cpp
ir/instr.cpp
@@ -254,6 +254,7 @@ void UnaryOp::print(ostream &os) const {
const char *str = nullptr;
switch (op) {
case BitReverse: str = "bitreverse "; break;
+ case BSwap: str = "bswap "; break;
case Ctpop: str = "ctpop "; break;
}
@@ -268,6 +269,9 @@ StateValue UnaryOp::toSMT(State &s) const {
case BitReverse:
newval = v.bitreverse();
break;
+ case BSwap:
+ newval = v.bswap();;
+ break;
case Ctpop:
newval = v.ctpop();
break;
@@ -276,9 +280,19 @@ StateValue UnaryOp::toSMT(State &s) const {
}
expr UnaryOp::getTypeConstraints(const Function &f) const {
+ expr instrconstr;
+ switch(op) {
+ case BSwap:
+ instrconstr = val.getType().sizeVar().urem(expr::mkUInt(16, 8)) == 0;
+ break;
+ default:
+ instrconstr = true;
+ }
+
return Value::getTypeConstraints() &&
getType().enforceIntOrPtrOrVectorType() &&
- getType() == val.getType();
+ getType() == val.getType() &&
+ move(instrconstr);
}

MODIFY
ir/instr.h
ir/instr.h
@@ -44,7 +44,7 @@ public:
class UnaryOp final : public Instr {
public:
- enum Op { BitReverse, Ctpop };
+ enum Op { BitReverse, BSwap, Ctpop };
private:
Value &val;

MODIFY
smt/expr.cpp
smt/expr.cpp
@@ -523,6 +523,20 @@ expr expr::lshr_exact(const expr &rhs) const {
return (lshr(rhs) << rhs) == *this;
}
+expr expr::bswap() const {
+ C();
+ auto nbits = bits();
+ constexpr unsigned bytelen = 8;
+
+ assert(nbits > 0 && nbits % (bytelen * 2) == 0);
+ expr res = extract(bytelen - 1, 0);
+ for (unsigned i = 1; i < nbits / bytelen; i++) {
+ res = res.concat(extract((i + 1) * bytelen - 1, i * bytelen));
+ }
+
+ return res;
+}
+
expr expr::bitreverse() const {
C();
auto nbits = bits();

MODIFY
smt/expr.h
smt/expr.h
@@ -129,6 +129,7 @@ public:
expr ashr_exact(const expr &rhs) const;
expr lshr_exact(const expr &rhs) const;
+ expr bswap() const;
expr bitreverse() const;
expr cttz() const;
expr ctlz() const;

ADD
tests/unit/bswap.opt
+Name: bswap constant16
+%a = bswap i16 52275
+ =>
+%a = 13260
+
+Name: bswap constant32
+%a = bswap i32 32896
+ =>
+%a = 2155872256

MODIFY
tools/alive_lexer.re
tools/alive_lexer.re
@@ -189,6 +189,7 @@ re2c:yyfill:check = 0;
"ugt" { return UGT; }
"freeze" { return FREEZE; }
"ret" { return RETURN; }
+"bswap" { return BSWAP; }
"bitreverse" { return BITREVERSE; }
"cttz" { return CTTZ; }
"ctlz" { return CTLZ; }

MODIFY
tools/alive_parser.cpp
tools/alive_parser.cpp
@@ -411,6 +411,7 @@ static unique_ptr<Instr> parse_unaryop(string_view name, token op_token) {
UnaryOp::Op op;
switch (op_token) {
case BITREVERSE: op = UnaryOp::BitReverse; break;
+ case BSWAP: op = UnaryOp::BSwap; break;
case CTPOP: op = UnaryOp::Ctpop; break;
default:
UNREACHABLE();
@@ -518,6 +519,7 @@ static unique_ptr<Instr> parse_instr(string_view name) {
case CTLZ:
return parse_binop(name, t);
case BITREVERSE:
+ case BSWAP:
case CTPOP:
return parse_unaryop(name, t);
case SEXT:

MODIFY
tools/tokens.h
tools/tokens.h
@@ -8,6 +8,7 @@ TOKEN(ARROW)
TOKEN(ASHR)
TOKEN(BAND)
TOKEN(BITREVERSE)
+TOKEN(BSWAP)
TOKEN(BOR)
TOKEN(COMMA)
TOKEN(CONSTANT)

MODIFY
tv/tv.cpp
tv/tv.cpp
@@ -294,6 +294,11 @@ public:
PARSE_UNOP();
RETURN_IDENTIFIER(make_unique<UnaryOp>(*ty, value_name(i), *val, UnaryOp::BitReverse));
}
+ case llvm::Intrinsic::bswap:
+ {
+ PARSE_UNOP();
+ RETURN_IDENTIFIER(make_unique<UnaryOp>(*ty, value_name(i), *val, UnaryOp::BSwap));
+ }
case llvm::Intrinsic::ctpop:
{
PARSE_UNOP();

add support for llvm.bswap

https://llvm.org/docs/LangRef.html#llvm-bswap-intrinsics