From eb31bedc20dc14ded337a04e57030d0619311d11 Mon Sep 17 00:00:00 2001 From: alex_s168 <63254202+alex-s168@users.noreply.github.com> Date: Tue, 22 Oct 2024 19:50:50 +0200 Subject: [PATCH] improve join compute pass -> better strcpy code gen --- build.sh | 2 +- ir/builder.c | 7 +++ ir/ir.c | 42 ++++++++++++++++++ ir/ir.h | 4 ++ ir/ops.cdef | 4 +- ir/opt.c | 23 ++++++---- ir/opt/join_compute.c | 79 +++++++++++++++++++++++++++++---- ir/transform/lower_loops.c | 4 +- ir/transform/ssair_llir_lower.c | 3 ++ ir/verify_common.c | 23 +++------- 10 files changed, 154 insertions(+), 37 deletions(-) diff --git a/build.sh b/build.sh index 81b08f7..e510d43 100755 --- a/build.sh +++ b/build.sh @@ -2,7 +2,7 @@ set -e -: ${CFLAGS:="-Wall -Wextra -Wno-unused -Wno-unused-parameter -Wno-comment -Wno-format -Wno-sign-compare -Wno-char-subscripts -Wno-implicit-fallthrough -Wno-missing-braces -Werror"} +: ${CFLAGS:="-Wall -Wextra -Wno-unused -Wno-unused-parameter -Wno-comment -Wno-format -Wno-sign-compare -Wno-char-subscripts -Wno-implicit-fallthrough -Wno-missing-braces -Werror -g -glldb"} if [ -z $EMPATH ]; then : ${CC:=clang} diff --git a/ir/builder.c b/ir/builder.c index 44e6856..a417ddf 100644 --- a/ir/builder.c +++ b/ir/builder.c @@ -155,6 +155,13 @@ void vx_IrBlock_addOp(vx_IrBlock *block, vx_IrBlock_deepTraverse(new->parent, add_op__trav, &data); } +vx_IrOp *vx_IrBlock_addOpAtBeginBuilding(vx_IrBlock *block) { + vx_IrOp *new = fastalloc(sizeof(vx_IrOp)); + new->next = block->first; + block->first = new; + return new; +} + /** WARNING: DON'T REF VARS IN OP THAT ARE NOT ALREADY INDEXED ROOT */ vx_IrOp *vx_IrBlock_addOpBuilding(vx_IrBlock *block) { vx_IrOp *new = fastalloc(sizeof(vx_IrOp)); diff --git a/ir/ir.c b/ir/ir.c index b4846a7..44c6db3 100644 --- a/ir/ir.c +++ b/ir/ir.c @@ -7,6 +7,39 @@ #include +bool vx_IrValue_eq(vx_IrValue a, vx_IrValue b) +{ + if (a.type != b.type) + return false; + + switch (a.type) + { + case VX_IR_VAL_IMM_INT: + return a.imm_int == b.imm_int; + + case VX_IR_VAL_IMM_FLT: + return a.imm_flt == b.imm_flt; + + case VX_IR_VAL_VAR: + return a.var == b.var; + + case VX_IR_VAL_UNINIT: + return true; + + case VX_IR_VAL_BLOCKREF: + return a.block == b.block; + + case VX_IR_VAL_BLOCK: + return a.block == b.block; + + case VX_IR_VAL_TYPE: + return a.ty == b.ty; + + case VX_IR_VAL_ID: + return a.id == b.id; + } +} + vx_IrOp *vx_IrBlock_tail(vx_IrBlock *block) { vx_IrOp *op = block->first; while (op && op->next) { @@ -278,6 +311,15 @@ vx_IrTypeRef vx_IrBlock_type(vx_IrBlock* block) { return (vx_IrTypeRef) { .ptr = type, .shouldFree = true }; } +void vx_IrOp_updateParent(vx_IrOp* op, vx_IrBlock* to) +{ + op->parent = to; + FOR_INPUTS(op, inp, ({ + if (inp.type == VX_IR_VAL_BLOCK) + inp.block->parent = to; + })); +} + #include "opt.h" #include "../cg/x86_stupid/cg.h" diff --git a/ir/ir.h b/ir/ir.h index 743e247..e74b746 100644 --- a/ir/ir.h +++ b/ir/ir.h @@ -252,6 +252,8 @@ typedef struct { }; } vx_IrValue; +bool vx_IrValue_eq(vx_IrValue a, vx_IrValue b); + #define VX_IR_VALUE_IMM_INT(varin) ((vx_IrValue) { .type = VX_IR_VAL_IMM_INT, .imm_int = varin }) #define VX_IR_VALUE_IMM_FLT(varin) ((vx_IrValue) { .type = VX_IR_VAL_IMM_FLT, .imm_flt = varin }) #define VX_IR_VALUE_VAR(varin) ((vx_IrValue) { .type = VX_IR_VAL_VAR, .var = varin }) @@ -286,6 +288,7 @@ void vx_IrBlock_addIn(vx_IrBlock *block, vx_IrVar var, vx_IrType *type); void vx_IrBlock_addOp(vx_IrBlock *block, const vx_IrOp *op); /** WARNING: DON'T REF VARS IN OP THAT ARE NOT ALREADY INDEXED ROOT */ vx_IrOp *vx_IrBlock_addOpBuilding(vx_IrBlock *block); +vx_IrOp *vx_IrBlock_addOpAtBeginBuilding(vx_IrBlock *block); vx_IrOp *vx_IrBlock_insertOpBuildingAfter(vx_IrOp *after); void vx_IrBlock_addAllOp(vx_IrBlock *dest, const vx_IrBlock *src); void vx_IrBlock_addOut(vx_IrBlock *block, vx_IrVar out); @@ -472,6 +475,7 @@ bool vx_IrOp_isTail(vx_IrOp *op); bool vx_IrOp_after(vx_IrOp *op, vx_IrOp *after); bool vx_IrOp_followingNoEffect(vx_IrOp* op); vx_IrOp* vx_IrOp_nextWithEffect(vx_IrOp* op); +void vx_IrOp_updateParent(vx_IrOp* op, vx_IrBlock* to); typedef bool (*vx_IrOpFilter)(vx_IrOp* op, void* userdata); diff --git a/ir/ops.cdef b/ir/ops.cdef index a45dba0..1ba8dbb 100644 --- a/ir/ops.cdef +++ b/ir/ops.cdef @@ -571,7 +571,7 @@ enum_entry_prefix "VX_IR_OP_" endsFlow true hasEffect true volatile false - sideEffect false + sideEffect true ; entry BREAK args "states.." @@ -582,7 +582,7 @@ enum_entry_prefix "VX_IR_OP_" endsFlow true hasEffect true volatile false - sideEffect false + sideEffect true ; entry RETURN args "returns.." diff --git a/ir/opt.c b/ir/opt.c index a778dcf..1bdede0 100644 --- a/ir/opt.c +++ b/ir/opt.c @@ -9,6 +9,18 @@ vx_OptConfig vx_g_optconfig = { .if_eval = true, }; +static void RecCallInOut(void (*fn)(vx_IrBlock*), vx_IrBlock* block) +{ + for (vx_IrOp *op = block->first; op; op = op->next) { + FOR_INPUTS(op, input, ({ + if (input.type == VX_IR_VAL_BLOCK) + RecCallInOut(fn, input.block); + })); + } + + fn(block); +} + static void opt_pre(vx_IrBlock *block) { // place immediates into params vx_opt_inline_vars(block); @@ -53,14 +65,9 @@ void opt(vx_IrBlock *block) { void opt_preLower(vx_IrBlock *block) { - for (vx_IrOp *op = block->first; op; op = op->next) { - FOR_INPUTS(op, input, ({ - if (input.type == VX_IR_VAL_BLOCK) - opt_preLower(input.block); - })); - } - - opt_pre(block); + RecCallInOut(opt_pre, block); + RecCallInOut(vx_opt_join_compute, block); + RecCallInOut(opt_pre, block); } void opt_ll(vx_IrBlock *block) { diff --git a/ir/opt/join_compute.c b/ir/opt/join_compute.c index be17e13..00543c8 100644 --- a/ir/opt/join_compute.c +++ b/ir/opt/join_compute.c @@ -2,24 +2,85 @@ #include #include +static bool eq(vx_IrOp* a, vx_IrOp* b) +{ + if (!( a->id == b->id + && a->args_len == b->args_len + && a->params_len == b->params_len + && a->outs_len == b->outs_len + )) + return false; + + for (size_t i = 0; i < a->params_len; i ++) { + if (a->params[i].name != b->params[i].name) + return false; + if (!vx_IrValue_eq(a->params[i].val, b->params[i].val)) + return false; + } + + for (size_t i = 0; i < a->args_len; i ++) + if (!vx_IrValue_eq(a->args[i], b->args[i])) + return false; + + return true; +} + +static vx_IrOp* findMatchingOutBefore(vx_IrBlock* block, vx_IrOp* before, vx_IrOp* cmp, bool stepIn, bool stepOut) +{ + for (vx_IrOp* op = block->first; op && op != before; op = op->next) + { + if (eq(op, cmp)) + return op; + + if (stepIn) { + FOR_INPUTS(op, inp, ({ + if (inp.type == VX_IR_VAL_BLOCK) { + vx_IrOp* m = findMatchingOutBefore(inp.block, NULL, cmp, /*stepIn=*/true, /*stepOut=*/false); + if (m) + return m; + } + })); + } + } + + if (stepOut && block->parent) + { + vx_IrOp* m = findMatchingOutBefore(block->parent, block->parent_op, cmp, /*stepIn=*/false, /*stepOut=*/true); + if (m) + return m; + } + + return NULL; +} + /** * Find identical computations and join them */ void vx_opt_join_compute(vx_IrBlock *block) { for (vx_IrOp *op = block->first; op; op = op->next) { - for (vx_IrOp *prev = block->first; prev != op; prev = prev->next) { - if (prev->id != op->id || vx_IrOp_isVolatile(op) || prev->params_len != op->params_len || prev->outs_len == 0) - continue; + if (vx_IrOp_isVolatile(op) || vx_IrOp_hasSideEffect(op)) + continue; - if (memcmp(prev->params, op->params, sizeof(vx_IrNamedValue) * op->params_len) != 0) - continue; + vx_IrOp* m = findMatchingOutBefore(block, op, op, true, true); + assert(m != op); + if (m == NULL) + continue; - op->id = VX_IR_OP_IMM; - vx_IrOp_removeParams(op); - vx_IrOp_addParam_s(op, VX_IR_NAME_VALUE, (vx_IrValue) { .type = VX_IR_VAL_VAR, .var = prev->outs[0].var }); + vx_IrOp* pred = vx_IrOp_predecessor(op); - break; + vx_IrOp* last = pred; + for (size_t i = 0; i < op->outs_len; i ++) { + vx_IrOp* new = (pred == NULL) + ? vx_IrBlock_addOpAtBeginBuilding(block) + : vx_IrBlock_insertOpBuildingAfter(pred); + + vx_IrOp_init(new, VX_IR_OP_IMM, block); + vx_IrOp_addParam_s(new, VX_IR_NAME_VALUE, VX_IR_VALUE_VAR(m->outs[i].var)); + vx_IrOp_addOut(new, op->outs[i].var, op->outs[i].type); + last = new; } + + last->next = op->next; } } diff --git a/ir/transform/lower_loops.c b/ir/transform/lower_loops.c index 73e412b..a9f0e24 100644 --- a/ir/transform/lower_loops.c +++ b/ir/transform/lower_loops.c @@ -41,12 +41,14 @@ void vx_IrBlock_llir_preLower_loops(vx_IrBlock *block) vx_IrOp* ifOp = vx_IrBlock_addOpBuilding(newBody); vx_IrOp_init(ifOp, VX_IR_OP_IF, newBody); + body->parent = ifOp->parent; vx_IrOp_addParam_s(ifOp, VX_IR_NAME_COND, VX_IR_VALUE_BLK(cond)); + body->parent = ifOp->parent; vx_IrOp_addParam_s(ifOp, VX_IR_NAME_COND_THEN, VX_IR_VALUE_BLK(body)); { - vx_IrBlock* els = vx_IrBlock_initHeap(newBody, ifOp); + vx_IrBlock* els = vx_IrBlock_initHeap(ifOp->parent, ifOp); vx_IrOp* brk = vx_IrBlock_addOpBuilding(els); vx_IrOp_init(brk, VX_IR_OP_BREAK, els); diff --git a/ir/transform/ssair_llir_lower.c b/ir/transform/ssair_llir_lower.c index 68fbe25..67b51aa 100644 --- a/ir/transform/ssair_llir_lower.c +++ b/ir/transform/ssair_llir_lower.c @@ -20,6 +20,9 @@ void vx_IrBlock_llir_preLower_ifs(vx_IrBlock *block) *cond = VX_IR_VALUE_VAR(condbl->outs[0]); if (condbl->first) { + for (vx_IrOp* i = condbl->first; i; i = i->next) + vx_IrOp_updateParent(i, block); + vx_IrOp* pred = vx_IrOp_predecessor(op); if (pred) pred->next = condbl->first; diff --git a/ir/verify_common.c b/ir/verify_common.c index 607badc..0d0604b 100644 --- a/ir/verify_common.c +++ b/ir/verify_common.c @@ -1,3 +1,4 @@ +#include #include #include "ir.h" @@ -32,9 +33,6 @@ static bool analyze_if(vx_Errors *dest, if (vcond == NULL) { vx_error_param_missing(dest, "cond"); err = true; - } else if (vcond->type != VX_IR_VAL_BLOCK) { - vx_error_param_type(dest, "block"); - err = true; } const vx_IrValue *vthen = vx_IrOp_param(op, VX_IR_NAME_COND_THEN); @@ -56,18 +54,9 @@ static bool analyze_if(vx_Errors *dest, } if (!err) { - vx_IrBlock *bcond = vcond->block; vx_IrBlock *bthen = vthen->block; vx_IrBlock *belse = velse->block; - if (bcond->outs_len != 1) { - vx_Error error = { - .error = "If block is missing a condition", - .additional = "If block is missing a condition! Example: `cond=(){ ^ 1 }`" - }; - vx_Errors_add(dest, &error); - } - if (!(bthen->outs_len == belse->outs_len && bthen->outs_len == op->outs_len)) { vx_Error error = { .error = "If block invalid outputs", @@ -122,9 +111,11 @@ void vx_IrBlock_verify_ssa_based(vx_Errors *dest, vx_IrBlock *block) { for (vx_IrOp *op = block->first; op; op = op->next) { if (op->parent != block) { + char buf[256]; + sprintf(buf, "OP (%s) has different parent", vx_IrOpType__entries[op->id].debug.a); const vx_Error error = { .error = "Invalid parent", - .additional = "OP has different parent" + .additional = strdup(buf) }; vx_Errors_add(dest, &error); } @@ -159,11 +150,11 @@ void vx_IrBlock_verify_ssa_based(vx_Errors *dest, vx_IrBlock *block) { case VX_IR_OP_COND: { size_t label = vx_IrOp_param(op, VX_IR_NAME_ID)->id; if (label >= root->as_root.labels_len || root->as_root.labels[label].decl == NULL) { - static char buf[256]; + char buf[256]; sprintf(buf, "Label %%%zu is never declared!", label); vx_Error error = { .error = "Undeclared label", - .additional = buf + .additional = strdup(buf) }; vx_Errors_add(dest, &error); } @@ -202,7 +193,7 @@ void vx_IrBlock_verify_ssa_based(vx_Errors *dest, vx_IrBlock *block) { sprintf(buf, "Variable %%%zu is never declared!", var); vx_Error error = { .error = "Undeclared variable", - .additional = buf + .additional = strdup(buf) }; vx_Errors_add(dest, &error); }