Skip to content

Commit

Permalink
all existing tests pass now
Browse files Browse the repository at this point in the history
  • Loading branch information
alex-s168 committed Feb 4, 2025
1 parent 07a1462 commit 71f3e52
Show file tree
Hide file tree
Showing 17 changed files with 178 additions and 41 deletions.
3 changes: 3 additions & 0 deletions .github/workflows/compile.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,6 @@ jobs:
chmod +x build.sh
./build.sh build
shell: bash
- name: Run tests
run: |
cd tests && ./run.sh
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ build.slowdb
venv/
*.plist
tests/*.asm
tests/*.o
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ please do not currently change anything related to:

| id | task | money | dependencies |
| --- | -------------------------------------------------------------------------------------------------------- | ---------------- | ------------------- |
| 1. | floats on amd64 using scalar sse ops | 100€ (~103$) | |
| 1. | | | |
| 2. | refactor number data types to allow non-power-of-2 bit widths, and also add different float types | 50€ (~ 51$) | |
| 3. | lower ints pass. asks backend for supported types. lower arbitary-width integers | 100€ (~103$) | depends on 2 |
| 4. | identify passes by names and use S-expr KV maps for config. describe pass pipeline using S-exprs instead | 100€ (~103$) | |
Expand Down
21 changes: 11 additions & 10 deletions ir/eval.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,18 +24,19 @@ bool vx_IrBlock_eval_var(vx_IrBlock *block, vx_IrVar var, vx_IrValue *dest) {
return false;
}

bool vx_Irblock_mightbeVar(vx_IrBlock *block, vx_IrVar var, vx_IrValue v) {
vx_IrValue is;
if (vx_IrBlock_eval_var(block, var, &is)) {
return memcmp(&is, &v, sizeof(vx_IrValue)) == 0;
}
return true;
bool vx_Irblock_mightbe(vx_IrBlock *block, vx_IrValue val, vx_IrValue v) {
vx_IrValue is = val;
if (val.type == VX_IR_VAL_VAR)
vx_IrBlock_eval_var(block, val.var, &is);
return memcmp(&is, &v, sizeof(vx_IrValue)) == 0;
}

bool vx_Irblock_alwaysIsVar(vx_IrBlock *block, vx_IrVar var, vx_IrValue v) {
vx_IrValue is;
if (!vx_IrBlock_eval_var(block, var, &is))
return false;
bool vx_Irblock_alwaysIs(vx_IrBlock *block, vx_IrValue val, vx_IrValue v) {
vx_IrValue is = val;
if (val.type == VX_IR_VAL_VAR) {
if (!vx_IrBlock_eval_var(block, val.var, &is))
return false;
}
return memcmp(&is, &v, sizeof(vx_IrValue)) == 0;
}

Expand Down
4 changes: 2 additions & 2 deletions ir/ir.h
Original file line number Diff line number Diff line change
Expand Up @@ -365,8 +365,8 @@ bool vx_IrBlock_varUsed(vx_IrBlock *block, vx_IrVar var);
void vx_IrBlock_dump(vx_IrBlock *block, FILE *out, size_t indent);
/** returns true if static eval ok; only touches dest if true */
bool vx_IrBlock_evalVar(vx_IrBlock *block, vx_IrVar var, vx_IrValue *dest);
bool vx_Irblock_mightbeVar(vx_IrBlock *block, vx_IrVar var, vx_IrValue v);
bool vx_Irblock_alwaysIsVar(vx_IrBlock *block, vx_IrVar var, vx_IrValue v);
bool vx_Irblock_mightbe(vx_IrBlock *block, vx_IrValue val, vx_IrValue v);
bool vx_Irblock_alwaysIs(vx_IrBlock *block, vx_IrValue val, vx_IrValue v);
void vx_Irblock_eval(vx_IrBlock *block, vx_IrValue *v);

/** can be ored together */
Expand Down
18 changes: 15 additions & 3 deletions ir/ops.cdef
Original file line number Diff line number Diff line change
Expand Up @@ -252,9 +252,21 @@ enum_entry_prefix "VX_IR_OP_"
x86_affect_flags true
;

entry MOD args "a: value, b: value"
debug "mod"
descr "modulus a % b ; both values have to have the same type as the output type"
entry UMOD args "a: value, b: value"
debug "umod"
descr "(unsigned) modulus a % b ; both values have to have the same type as the output type"
inlineCost 1
execCost 2
endsFlow false
hasEffect true
volatile false
sideEffect false
x86_affect_flags true
;

entry SMOD args "a: value, b: value"
debug "smod"
descr "(signed) modulus a % b ; both values have to have the same type as the output type"
inlineCost 1
execCost 2
endsFlow false
Expand Down
7 changes: 6 additions & 1 deletion ir/opt/constant_eval.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

void vx_opt_constant_eval(vx_CU* cu, vx_IrBlock *block)
{
// TODO: only if arg type sizes < sizeof(long long)
for (vx_IrOp *op = block->first; op; op = op->next) {
#define BINARY(typedest, what) { \
vx_IrValue *a = vx_IrOp_param(op, VX_IR_NAME_OPERAND_A); \
Expand Down Expand Up @@ -66,7 +67,11 @@ void vx_opt_constant_eval(vx_CU* cu, vx_IrBlock *block)
BINARY(unsigned long long, /);
break;

case VX_IR_OP_MOD:
case VX_IR_OP_UMOD:
BINARY(unsigned long long, %);
break;

case VX_IR_OP_SMOD:
BINARY(signed long long, %);
break;

Expand Down
4 changes: 2 additions & 2 deletions ir/opt/loop_simplify.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@ void vx_opt_loop_simplify(vx_CU* cu, vx_IrBlock *block)
const vx_IrVar condVar = cond->outs[0];

// if it will always we 0, we optimize it out
if (vx_Irblock_alwaysIsVar(cond, condVar, (vx_IrValue) { .type = VX_IR_VAL_IMM_INT, .imm_int = 0 })) {
if (vx_Irblock_alwaysIs(cond, VX_IR_VALUE_VAR(condVar), (vx_IrValue) { .type = VX_IR_VAL_IMM_INT, .imm_int = 0 })) {
vx_IrOp_remove(op);
continue;
}

// if it will never be 0 (not might be 0), it is always true => infinite loop
if (!vx_Irblock_mightbeVar(cond, condVar, (vx_IrValue) { .type = VX_IR_VAL_IMM_INT, .imm_int = 0 })) {
if (!vx_Irblock_mightbe(cond, VX_IR_VALUE_VAR(condVar), (vx_IrValue) { .type = VX_IR_VAL_IMM_INT, .imm_int = 0 })) {
op->id = VX_IR_OP_INFINITE;
vx_IrOp_removeParam(op, VX_IR_NAME_COND);
continue;
Expand Down
8 changes: 4 additions & 4 deletions ir/opt/reduce_if.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ void vx_opt_reduce_if(vx_CU* cu, vx_IrBlock *block)
if (op->id != VX_IR_OP_IF)
continue;

vx_IrBlock *cond = vx_IrOp_param(op, VX_IR_NAME_COND)->block;
const vx_IrVar condVar = cond->outs[0];
vx_IrValue cond = *vx_IrOp_param(op, VX_IR_NAME_COND);
assert(cond.type != VX_IR_VAL_BLOCK);

vx_IrValue *pthen = vx_IrOp_param(op, VX_IR_NAME_COND_THEN);
vx_IrBlock *then = pthen ? pthen->block : NULL;
Expand All @@ -26,7 +26,7 @@ void vx_opt_reduce_if(vx_CU* cu, vx_IrBlock *block)

if (then) {
// if it will never be 0 (not might be 0), it is always true => only execute then block
if (!vx_Irblock_mightbeVar(cond, condVar, VX_IR_VALUE_IMM_INT(0))) {
if (!vx_Irblock_mightbe(block, cond, VX_IR_VALUE_IMM_INT(0))) {
for (size_t i = 0; i < op->outs_len; i ++) {
const vx_IrVar out = op->outs[i].var;
vx_IrBlock_renameVar(block, out, then->outs[i], VX_RENAME_VAR_BOTH); // does all the bookkeeping for us
Expand All @@ -41,7 +41,7 @@ void vx_opt_reduce_if(vx_CU* cu, vx_IrBlock *block)

if (els) {
// if it will always we 0, only the else block will ever be executed
if (vx_Irblock_alwaysIsVar(cond, condVar, VX_IR_VALUE_IMM_INT(0))) {
if (vx_Irblock_alwaysIs(block, cond, VX_IR_VALUE_IMM_INT(0))) {
for (size_t i = 0; i < op->outs_len; i ++) {
const vx_IrVar out = op->outs[i].var;
vx_IrBlock_renameVar(block, out, els->outs[i], VX_RENAME_VAR_BOTH); // does all the bookkeeping for us
Expand Down
125 changes: 111 additions & 14 deletions targets/x86/cg.c
Original file line number Diff line number Diff line change
Expand Up @@ -836,6 +836,79 @@ static void emiti_bittest(Location* val, Location* idx, FILE* file) {
end_as_primitive(idxv, idx, file);
}

static void emiti_push(Location* l, FILE* file) {
fputs("push ", file);
emit(l, file);
fputc('\n', file);
}

static void emiti_pop(Location* l, FILE* file) {
fputs("pop ", file);
emit(l, file);
fputc('\n', file);
}

static void emiti_moddiv(Location* o, Location* a, Location* b, bool sign, bool ismod, FILE* file) {
Location* need_pop_rax = NULL;
if (REG_RAX.stored && REG_RAX.stored != a) {
need_pop_rax = REG_RAX.stored;
emiti_push(REG_RAX.stored, file);
}
Location arax = LocReg(a->bytesWidth, REG_RAX.id);
emiti_move(a, &arax, false, file);

Location* need_pop_rdx = NULL;
if (REG_RDX.stored && REG_RDX.stored != o) {
need_pop_rdx = REG_RDX.stored;
emiti_push(REG_RDX.stored, file);
}

if (sign) {
if (a->bytesWidth == 4) {
fputs("cdq\n", file);
} else if (a->bytesWidth == 8) {
fputs("cqo\n", file);
} else {
assert(false && "x86 backend: unsupported operand a int width for mod/div");
}
}

fputs(sign ? "idiv " : "div ", file);
emit(b, file);
fputc('\n', file);

if (ismod) {
Location oo = LocReg(o->bytesWidth, REG_RDX.id);
emiti_move(&oo, o, false, file);
}

if (need_pop_rdx) {
emiti_pop(need_pop_rdx, file);
}

if (need_pop_rax) {
emiti_pop(need_pop_rax, file);
}
}

static void emiti_shift(Location* o, Location* a, Location* b, char const* op, FILE* file) {
Location* need_pop_rcx = NULL;
if (REG_RCX.stored && REG_RCX.stored != b) {
need_pop_rcx = REG_RCX.stored;
emiti_push(REG_RCX.stored, file);
}
Location cl = LocReg(1, REG_RCX.id);
emiti_move(b, &cl, false, file);

fprintf(file, "%s ", op);
emit(a, file);
fputs(", cl\n", file);

if (need_pop_rcx) {
emiti_pop(need_pop_rcx, file);
}
}

static void emiti_ret(vx_IrBlock* block, vx_IrValue* values, FILE* out) {
if (block->ll_out_types_len >= 1) {
VarData vd = varData[values[0].var];
Expand Down Expand Up @@ -1129,6 +1202,42 @@ static vx_IrOp* emiti(vx_IrOp *prev, vx_IrOp* op, FILE* file) {
}
} break;

case VX_IR_OP_UDIV: // "a", "b"
case VX_IR_OP_SDIV: // "a", "b"
case VX_IR_OP_UMOD: // "a", "b"
case VX_IR_OP_SMOD: // "a", "b"
{
Location* o = varData[op->outs[0].var].location;
assert(o);
Location* a = as_loc(o->bytesWidth, *vx_IrOp_param(op, VX_IR_NAME_OPERAND_A));
Location* b = as_loc(o->bytesWidth, *vx_IrOp_param(op, VX_IR_NAME_OPERAND_B));

bool sign = op->id == VX_IR_OP_SDIV || op->id == VX_IR_OP_SMOD;
bool mod = op->id == VX_IR_OP_SMOD || op->id == VX_IR_OP_UMOD;
emiti_moddiv(o, a, b, sign, mod, file);
} break;

case VX_IR_OP_SHL: // "a", "b"
case VX_IR_OP_SHR: // "a", "b"
case VX_IR_OP_ASHR: // "a", "b"
{
Location* o = varData[op->outs[0].var].location;
assert(o);
Location* a = as_loc(o->bytesWidth, *vx_IrOp_param(op, VX_IR_NAME_OPERAND_A));
Location* b = as_loc(o->bytesWidth, *vx_IrOp_param(op, VX_IR_NAME_OPERAND_B));

const char * bin;
switch (op->id) {
case VX_IR_OP_SHL: bin = "shl"; break;
case VX_IR_OP_SHR: bin = "shr"; break;
case VX_IR_OP_ASHR: bin = "sar"; break;

default: assert(false); break;
}

emiti_shift(o, a, b, bin, file);
} break;

case VX_IR_OP_ADD: // "a", "b"
case VX_IR_OP_SUB: // "a", "b"
{
Expand All @@ -1137,7 +1246,7 @@ static vx_IrOp* emiti(vx_IrOp *prev, vx_IrOp* op, FILE* file) {
Location* a = as_loc(o->bytesWidth, *vx_IrOp_param(op, VX_IR_NAME_OPERAND_A));
Location* b = as_loc(o->bytesWidth, *vx_IrOp_param(op, VX_IR_NAME_OPERAND_B));

if (!equal(o, a) && a->type == LOC_REG) {
if (!equal(o, a) && a->type == LOC_REG && (op->id == VX_IR_OP_ADD || b->type != LOC_REG)) {
int sign = op->id == VX_IR_OP_ADD ? 1 : -1;

Location* ea = fastalloc(sizeof(Location));
Expand All @@ -1148,17 +1257,11 @@ static vx_IrOp* emiti(vx_IrOp *prev, vx_IrOp* op, FILE* file) {
}
} // no break

case VX_IR_OP_MOD: // "a", "b"
case VX_IR_OP_MUL: // "a", "b"
case VX_IR_OP_UDIV: // "a", "b"
case VX_IR_OP_SDIV: // "a", "b"
case VX_IR_OP_AND: // "a", "b"
case VX_IR_OP_BITWISE_AND: // "a", "b"
case VX_IR_OP_OR: // "a", "b"
case VX_IR_OP_BITIWSE_OR: // "a", "b"
case VX_IR_OP_SHL: // "a", "b"
case VX_IR_OP_SHR: // "a", "b"
case VX_IR_OP_ASHR: // "a", "b"
{
Location* o = varData[op->outs[0].var].location;
assert(o);
Expand All @@ -1169,17 +1272,11 @@ static vx_IrOp* emiti(vx_IrOp *prev, vx_IrOp* op, FILE* file) {
switch (op->id) {
case VX_IR_OP_ADD: bin = "add"; break;
case VX_IR_OP_SUB: bin = "sub"; break;
case VX_IR_OP_MOD: bin = "mod"; break;
case VX_IR_OP_MUL: bin = "imul"; break;
case VX_IR_OP_UDIV: bin = "div"; break;
case VX_IR_OP_SDIV: bin = "idiv"; break;
case VX_IR_OP_AND:
case VX_IR_OP_BITWISE_AND: bin = "and"; break;
case VX_IR_OP_OR:
case VX_IR_OP_BITIWSE_OR: bin = "orr"; break;
case VX_IR_OP_SHL: bin = "shl"; break;
case VX_IR_OP_SHR: bin = "shr"; break;
case VX_IR_OP_ASHR: bin = "sar"; break;
case VX_IR_OP_BITIWSE_OR: bin = "or"; break;

default: assert(false); break;
}
Expand Down
1 change: 1 addition & 0 deletions tests/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
core
3 changes: 3 additions & 0 deletions tests/asm_to_obj.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
for f in *.asm; do
nasm $f -o $f.o
done
2 changes: 1 addition & 1 deletion tests/assignments.c3.s
Original file line number Diff line number Diff line change
@@ -1 +1 @@
("amd64:cmov" (opt ((max_total_cmov_inline_cost 4) (consteval_iterations 6) (loop_simplify 1) (if_eval 1))) (type ("int" simple ((float 0) (size 4) (align 4)))) (cu-block (((name "assignments") (export 1)) (block ((args (("int" 1))) (ops (((outs (("int" 0))) (name "imm") (params (("val" (uninit)))) (args ())) ((outs (("int" 3))) (name "imm") (params (("val" (int 0)))) (args ())) ((outs (("int" 2))) (name "imm") (params (("val" (var 3)))) (args ())) ((outs (("int" 4))) (name "add") (params (("a" (var 1)) ("b" (var 2)))) (args ())) ((outs (("int" 2))) (name "imm") (params (("val" (var 4)))) (args ())) ((outs (("int" 5))) (name "sub") (params (("a" (var 1)) ("b" (var 2)))) (args ())) ((outs (("int" 2))) (name "imm") (params (("val" (var 5)))) (args ())) ((outs (("int" 6))) (name "mod") (params (("a" (var 1)) ("b" (var 2)))) (args ())) ((outs (("int" 2))) (name "imm") (params (("val" (var 6)))) (args ())) ((outs (("int" 7))) (name "sdiv") (params (("a" (var 1)) ("b" (var 2)))) (args ())) ((outs (("int" 2))) (name "imm") (params (("val" (var 7)))) (args ())) ((outs (("int" 8))) (name "mul") (params (("a" (var 1)) ("b" (var 2)))) (args ())) ((outs (("int" 2))) (name "imm") (params (("val" (var 8)))) (args ())) ((outs (("int" 9))) (name "shl") (params (("a" (var 1)) ("b" (var 2)))) (args ())) ((outs (("int" 2))) (name "imm") (params (("val" (var 9)))) (args ())) ((outs (("int" 10))) (name "ashr") (params (("a" (var 1)) ("b" (var 2)))) (args ())) ((outs (("int" 2))) (name "imm") (params (("val" (var 10)))) (args ())) ((outs (("int" 11))) (name "or") (params (("a" (var 1)) ("b" (var 2)))) (args ())) ((outs (("int" 2))) (name "imm") (params (("val" (var 11)))) (args ())) ((outs (("int" 12))) (name "bwand") (params (("a" (var 1)) ("b" (var 2)))) (args ())) ((outs (("int" 2))) (name "imm") (params (("val" (var 12)))) (args ())) ((outs ()) (name "ret") (params ()) (args ((var 2)))))) (rets (0)))))))
("amd64:cmov" (opt ((max_total_cmov_inline_cost 4) (consteval_iterations 6) (loop_simplify 1) (if_eval 1))) (type ("int" simple ((float 0) (size 4) (align 4)))) (cu-block (((name "assignments") (export 1)) (block ((args (("int" 1))) (ops (((outs (("int" 0))) (name "imm") (params (("val" (uninit)))) (args ())) ((outs (("int" 3))) (name "imm") (params (("val" (int 0)))) (args ())) ((outs (("int" 2))) (name "imm") (params (("val" (var 3)))) (args ())) ((outs (("int" 4))) (name "add") (params (("a" (var 1)) ("b" (var 2)))) (args ())) ((outs (("int" 2))) (name "imm") (params (("val" (var 4)))) (args ())) ((outs (("int" 5))) (name "sub") (params (("a" (var 1)) ("b" (var 2)))) (args ())) ((outs (("int" 2))) (name "imm") (params (("val" (var 5)))) (args ())) ((outs (("int" 6))) (name "smod") (params (("a" (var 1)) ("b" (var 2)))) (args ())) ((outs (("int" 2))) (name "imm") (params (("val" (var 6)))) (args ())) ((outs (("int" 7))) (name "sdiv") (params (("a" (var 1)) ("b" (var 2)))) (args ())) ((outs (("int" 2))) (name "imm") (params (("val" (var 7)))) (args ())) ((outs (("int" 8))) (name "mul") (params (("a" (var 1)) ("b" (var 2)))) (args ())) ((outs (("int" 2))) (name "imm") (params (("val" (var 8)))) (args ())) ((outs (("int" 9))) (name "shl") (params (("a" (var 1)) ("b" (var 2)))) (args ())) ((outs (("int" 2))) (name "imm") (params (("val" (var 9)))) (args ())) ((outs (("int" 10))) (name "ashr") (params (("a" (var 1)) ("b" (var 2)))) (args ())) ((outs (("int" 2))) (name "imm") (params (("val" (var 10)))) (args ())) ((outs (("int" 11))) (name "or") (params (("a" (var 1)) ("b" (var 2)))) (args ())) ((outs (("int" 2))) (name "imm") (params (("val" (var 11)))) (args ())) ((outs (("int" 12))) (name "bwand") (params (("a" (var 1)) ("b" (var 2)))) (args ())) ((outs (("int" 2))) (name "imm") (params (("val" (var 12)))) (args ())) ((outs ()) (name "ret") (params ()) (args ((var 2)))))) (rets (0)))))))
2 changes: 1 addition & 1 deletion tests/max1.c3.s
Original file line number Diff line number Diff line change
@@ -1 +1 @@
("amd64:cmov" (opt ((max_total_cmov_inline_cost 4) (consteval_iterations 6) (loop_simplify 1) (if_eval 1))) (type ("int" simple ((float 0) (size 4) (align 4)))) (type ("bool" simple ((float 0) (size 1) (align 1)))) (cu-block (((name "max") (export 1)) (block ((args (("int" 1) ("int" 2))) (ops (((outs (("int" 0))) (name "imm") (params (("val" (uninit)))) (args ())) ((outs (("int" 3))) (name "imm") (params (("val" (uninit)))) (args ())) ((outs ()) (name "if") (params (("cond" (var 4)) ("then" (block ((args ()) (ops (((outs (("int" 3))) (name "imm") (params (("val" (var 1)))) (args ())))) (rets ())))) ("else" (block ((args ()) (ops (((outs (("int" 3))) (name "imm") (params (("val" (var 2)))) (args ())))) (rets ())))))) (args ())) ((outs (("bool" 4))) (name "sgt") (params (("a" (var 1)) ("b" (var 2)))) (args ())) ((outs ()) (name "ret") (params ()) (args ((var 3)))))) (rets (0)))))))
("amd64:cmov" (opt ((max_total_cmov_inline_cost 4) (consteval_iterations 6) (loop_simplify 1) (if_eval 1))) (type ("int" simple ((float 0) (size 4) (align 4)))) (type ("bool" simple ((float 0) (size 1) (align 1)))) (cu-block (((name "max") (export 1)) (block ((args (("int" 1) ("int" 2))) (ops (((outs (("int" 0))) (name "imm") (params (("val" (uninit)))) (args ())) ((outs (("int" 3))) (name "imm") (params (("val" (uninit)))) (args ())) ((outs (("bool" 4))) (name "sgt") (params (("a" (var 1)) ("b" (var 2)))) (args ())) ((outs ()) (name "if") (params (("cond" (var 4)) ("then" (block ((args ()) (ops (((outs (("int" 3))) (name "imm") (params (("val" (var 1)))) (args ())))) (rets ())))) ("else" (block ((args ()) (ops (((outs (("int" 3))) (name "imm") (params (("val" (var 2)))) (args ())))) (rets ())))))) (args ())) ((outs ()) (name "ret") (params ()) (args ((var 3)))))) (rets (0)))))))
Loading

0 comments on commit 71f3e52

Please sign in to comment.