commit 4d0e68ae8339813f94cb46ed56140ae72031ae51
parent ef5ac4a6e8831874b370529cd530e2207a750a61
Author: Nihal Jere <nihal@nihaljere.xyz>
Date: Thu, 27 Jan 2022 20:08:52 -0600
add not operator
Diffstat:
8 files changed, 61 insertions(+), 0 deletions(-)
diff --git a/ir.c b/ir.c
@@ -88,6 +88,7 @@ putins(struct iproc *out, int op, uint64_t val, int valtype)
case IR_LOAD:
case IR_ADD:
case IR_CEQ:
+ case IR_NOT:
case IR_ZEXT:
case IR_ASSIGN:
case IR_CALLARG:
@@ -276,6 +277,14 @@ genexpr(struct iproc *out, size_t expri, uint64_t *val)
}
break;
}
+ case UOP_NOT: {
+ uint64_t arg;
+ int type = genexpr(out, expr->d.uop.expr, &arg);
+ assert(type == VT_TEMP);
+ *val = assign(out, 4); // FIXME: how big should bools be?
+ putins(out, IR_NOT, arg, VT_TEMP);
+ break;
+ }
default:
die("genexpr: EXPR_UNARY: unhandled unop kind");
}
diff --git a/ir.h b/ir.h
@@ -14,6 +14,9 @@ struct instr {
IR_CONDJUMP,
IR_JUMP,
+ // unary ops
+ IR_NOT,
+
// binary ops
IR_ADD,
diff --git a/lex.c b/lex.c
@@ -57,6 +57,9 @@ lex(struct slice start)
} else if (*start.data == '>') {
cur->type = TOK_GREATER;
ADVANCE(1);
+ } else if (*start.data == '!') {
+ cur->type = TOK_NOT;
+ ADVANCE(1);
} else if (*start.data == '$') {
cur->type = TOK_DOLLAR;
ADVANCE(1);
diff --git a/nooc.h b/nooc.h
@@ -17,6 +17,7 @@ enum tokentype {
TOK_PLUS,
TOK_MINUS,
TOK_GREATER,
+ TOK_NOT,
TOK_DOLLAR,
@@ -197,6 +198,7 @@ struct binop {
struct unop {
enum {
UOP_REF,
+ UOP_NOT,
} kind;
size_t expr;
};
diff --git a/parse.c b/parse.c
@@ -237,6 +237,16 @@ parseexpr(struct block *block)
case TOK_NUM:
parsenum(&expr);
break;
+ case TOK_NOT:
+ expr.start = tok;
+ tok = tok->next;
+ expr.kind = EXPR_UNARY;
+ expr.d.uop.kind = UOP_NOT;
+ expr.d.uop.expr = parseexpr(block);
+ if (exprs.data[expr.d.uop.expr].class != C_BOOL)
+ error(tok->line, tok->col, "expected boolean expression as not operand");
+ expr.class = C_BOOL;
+ break;
case TOK_EQUAL:
expr.kind = EXPR_BINARY;
expr.d.bop.kind = BOP_EQUAL;
diff --git a/test/not.pass.nooc b/test/not.pass.nooc
@@ -0,0 +1,9 @@
+let main proc() = proc() {
+ let a i64 = 10
+ let b i64 = 20
+ if != a b {
+ syscall2(60, 0)
+ } else {
+ syscall2(60, 1)
+ }
+}+
\ No newline at end of file
diff --git a/util.c b/util.c
@@ -184,6 +184,9 @@ dumpir(struct iproc *instrs)
case IR_CEQ:
fprintf(stderr, "ceq %c%lu", sig, instr->val);
break;
+ case IR_NOT:
+ fprintf(stderr, "not %c%lu\n", sig, instr->val);
+ break;
case IR_ZEXT:
fprintf(stderr, "zext %c%lu\n", sig, instr->val);
break;
diff --git a/x64.c b/x64.c
@@ -692,6 +692,20 @@ sete_reg(struct data *text, enum reg reg)
}
static size_t
+setne_reg(struct data *text, enum reg reg)
+{
+ uint8_t temp;
+ if (text) {
+ if (reg >= 8) array_addlit(text, REX_B);
+ array_addlit(text, 0x0F);
+ array_addlit(text, 0x95);
+ array_addlit(text, (MOD_DIRECT << 6) | (reg & 7));
+ }
+
+ return 3 + !(reg < 8);
+}
+
+static size_t
jmp(struct data *text, int64_t offset)
{
uint8_t temp;
@@ -879,6 +893,13 @@ emitblock(struct data *text, struct iproc *proc, struct instr *start, struct ins
NEXT;
switch (ins->op) {
+ case IR_NOT:
+ assert(ins->valtype == VT_TEMP);
+ assert(size == 4);
+ total += cmp_r32_r32(text, src, proc->temps.data[ins->val].reg);
+ total += setne_reg(text, dest);
+ NEXT;
+ break;
case IR_CEQ:
assert(ins->valtype == VT_TEMP);
src = proc->temps.data[ins->val].reg;