alive: add parsing for assume & add a couple of tests
ADD
tests/unit/call-error5.opt
+%c1 = call i8 @f(i8 poison) nowrite noread
+%c2 = call i8 @f(i8 poison) nowrite noread
+%d = add i8 %c1, %c2
+ret i8 %d
+ =>
+ret i8 1
+
+; FIXME: this test should fail!

ADD
tests/unit/call-error6.opt
+%f3 = call i8 @f(i8 3) nowrite noread
+%f4 = call i8 @f(i8 4) nowrite noread
+%eq1 = icmp eq i8 %f3, 3
+%eq2 = icmp eq i8 %f4, 4
+assume(%eq1)
+assume(%eq2)
+%c1 = call i8 @f(i8 poison) nowrite noread
+%c2 = call i8 @f(i8 poison) nowrite noread
+
+%eq3 = icmp ule i8 %c1, 9
+%eq4 = icmp ule i8 %c2, 9
+assume_non_poison(%eq3)
+assume_non_poison(%eq4)
+
+%d = add i8 %c1, %c2
+ret i8 %d
+ =>
+assume(false)
+ret i8 0
+
+; FIXME: this test should fail!

MODIFY
tools/alive_lexer.h
tools/alive_lexer.h
@@ -39,6 +39,6 @@ struct LexException {
};
-constexpr unsigned LEXER_READ_AHEAD = 16;
+constexpr unsigned LEXER_READ_AHEAD = 20;
}

MODIFY
tools/alive_lexer.re
tools/alive_lexer.re
@@ -228,6 +228,8 @@ space+ {
"uge" { return UGE; }
"ugt" { return UGT; }
"call" { return CALL; }
+"noread" { return NOREAD; }
+"nowrite" { return NOWRITE; }
"freeze" { return FREEZE; }
"malloc" { return MALLOC; }
"free" { return FREE; }
@@ -283,6 +285,8 @@ space+ {
"nnan" { return NNAN; }
"ninf" { return NINF; }
"nsz" { return NSZ; }
+"assume" { return ASSUME; }
+"assume_non_poison" { return ASSUME_NON_POISON; }
"unreachable" { return UNREACH; }
[a-zA-Z][a-zA-Z0-9]* {

MODIFY
tools/alive_parser.cpp
tools/alive_parser.cpp
@@ -937,7 +937,7 @@ static unique_ptr<Instr> parse_call(string_view name) {
auto fn_name = parse_global_name();
tokenizer.ensure(LPAREN);
- auto call = make_unique<FnCall>(ret_ty, string(name), move(fn_name));
+ vector<Value*> args;
bool first = true;
while (tokenizer.peek() != RPAREN) {
@@ -945,9 +945,27 @@ static unique_ptr<Instr> parse_call(string_view name) {
tokenizer.ensure(COMMA);
first = false;
auto &ty = parse_type();
- call->addArg(parse_operand(ty), ParamAttrs::None);
+ args.emplace_back(&parse_operand(ty));
}
tokenizer.ensure(RPAREN);
+
+ FnAttrs attrs;
+ while (true) {
+ switch (auto t = *tokenizer) {
+ case NOREAD: attrs.set(FnAttrs::NoRead); break;
+ case NOWRITE: attrs.set(FnAttrs::NoWrite); break;
+ default:
+ tokenizer.unget(t);
+ goto exit;
+ }
+ }
+exit:
+ auto call = make_unique<FnCall>(ret_ty, string(name), move(fn_name),
+ move(attrs));
+
+ for (auto arg : args) {
+ call->addArg(*arg, ParamAttrs::None);
+ }
return call;
}
@@ -1107,6 +1125,13 @@ static unique_ptr<Instr> parse_instr(string_view name) {
UNREACHABLE();
}
+static unique_ptr<Instr> parse_assume(bool if_non_poison) {
+ tokenizer.ensure(LPAREN);
+ auto &val = parse_operand(*int_types[1].get());
+ tokenizer.ensure(RPAREN);
+ return make_unique<Assume>(val, if_non_poison);
+}
+
static unique_ptr<Instr> parse_return() {
auto &type = parse_type();
auto &val = parse_operand(type);
@@ -1120,6 +1145,12 @@ static void parse_fn(Function &f) {
while (true) {
switch (auto t = *tokenizer) {
+ case ASSUME:
+ bb->addInstr(parse_assume(true));
+ break;
+ case ASSUME_NON_POISON:
+ bb->addInstr(parse_assume(false));
+ break;
case LABEL:
bb = &f.getBB(yylval.str);
break;

MODIFY
tools/alive_parser.h
tools/alive_parser.h
@@ -28,6 +28,6 @@ struct ParseException {
: str(std::move(str)), lineno(lineno) {}
};
-constexpr unsigned PARSER_READ_AHEAD = 16;
+constexpr unsigned PARSER_READ_AHEAD = 20;
}

MODIFY
tools/tokens.h
tools/tokens.h
@@ -7,6 +7,8 @@ TOKEN(AND)
TOKEN(ARRAY_TYPE_PREFIX)
TOKEN(ARROW)
TOKEN(ASHR)
+TOKEN(ASSUME)
+TOKEN(ASSUME_NON_POISON)
TOKEN(BAND)
TOKEN(BITCAST)
TOKEN(BITREVERSE)
@@ -68,6 +70,8 @@ TOKEN(NAME)
TOKEN(NE)
TOKEN(NINF)
TOKEN(NNAN)
+TOKEN(NOREAD)
+TOKEN(NOWRITE)
TOKEN(NSZ)
TOKEN(NSW)
TOKEN(NULLTOKEN)

alive: add parsing for assume & add a couple of tests