-
Notifications
You must be signed in to change notification settings - Fork 24
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement e-SSA PI nodes #81
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -296,11 +296,14 @@ typedef enum _ir_type { | |
\ | ||
/* data-flow and miscellaneous ops */ \ | ||
_(PHI, pN, reg, def, def) /* SSA Phi function */ \ | ||
_(PI, d2, def, def, ___) /* e-SSA Pi constraint */ \ | ||
_(COPY, d1X1, def, opt, ___) /* COPY (last foldable op) */ \ | ||
_(PI, p2, reg, def, ___) /* e-SSA Pi constraint ??? */ \ | ||
_(FRAME_ADDR, d0, ___, ___, ___) /* function frame address */ \ | ||
/* (USE, RENAME) */ \ | ||
\ | ||
/* PI range */ \ | ||
_(RANGE, d2, def, def, ___) /* [min, max] */ \ | ||
\ | ||
Comment on lines
+304
to
+306
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would prefer to make RANGE a "constant" (similar to FUNC/SYM/STR). |
||
/* data ops */ \ | ||
_(PARAM, p1X2, reg, str, num) /* incoming parameter proj. */ \ | ||
_(VAR, p1X1, reg, str, ___) /* local variable */ \ | ||
|
@@ -749,6 +752,7 @@ void ir_build_prev_refs(ir_ctx *ctx); | |
|
||
/* SCCP - Sparse Conditional Constant Propagation (implementation in ir_sccp.c) */ | ||
int ir_sccp(ir_ctx *ctx); | ||
bool ir_remove_pis(ir_ctx *ctx); | ||
|
||
/* GCM - Global Code Motion and scheduling (implementation in ir_gcm.c) */ | ||
int ir_gcm(ir_ctx *ctx); | ||
|
@@ -908,7 +912,8 @@ IR_ALWAYS_INLINE void *ir_jit_compile(ir_ctx *ctx, int opt_level, size_t *size) | |
|
||
ir_build_def_use_lists(ctx); | ||
|
||
if (!ir_build_cfg(ctx) | ||
if (!ir_remove_pis(ctx) | ||
|| !ir_build_cfg(ctx) | ||
|| !ir_match(ctx) | ||
|| !ir_assign_virtual_registers(ctx) | ||
|| !ir_compute_dessa_moves(ctx)) { | ||
|
@@ -930,7 +935,8 @@ IR_ALWAYS_INLINE void *ir_jit_compile(ir_ctx *ctx, int opt_level, size_t *size) | |
return NULL; | ||
} | ||
|
||
if (!ir_build_cfg(ctx) | ||
if (!ir_remove_pis(ctx) | ||
|| !ir_build_cfg(ctx) | ||
|| !ir_build_dominators_tree(ctx) | ||
|| !ir_find_loops(ctx) | ||
|| !ir_gcm(ctx) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -407,7 +407,7 @@ static void ir_emit_bitcast(ir_ctx *ctx, FILE *f, int def, ir_insn *insn) | |
fprintf(f, " = _u.d;}\n"); | ||
} else { | ||
IR_ASSERT(insn->type == IR_FLOAT); | ||
fprintf(f, "\t{union {float f; uint32_t bits;} _u; _u.buts = "); | ||
fprintf(f, "\t{union {float f; uint32_t bits;} _u; _u.bits = "); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've merged this typo fix. |
||
ir_emit_ref(ctx, f, insn->op1); | ||
fprintf(f, "; "); | ||
ir_emit_ref(ctx, f, def); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1352,6 +1352,23 @@ IR_FOLD(FP2FP(C_DOUBLE)) | |
} | ||
} | ||
|
||
IR_FOLD(PI(C_BOOL, _)) | ||
IR_FOLD(PI(C_U8, _)) | ||
IR_FOLD(PI(C_U16, _)) | ||
IR_FOLD(PI(C_U32, _)) | ||
IR_FOLD(PI(C_U64, _)) | ||
IR_FOLD(PI(C_ADDR, _)) | ||
IR_FOLD(PI(C_CHAR, _)) | ||
IR_FOLD(PI(C_I8, _)) | ||
IR_FOLD(PI(C_I16, _)) | ||
IR_FOLD(PI(C_I32, _)) | ||
IR_FOLD(PI(C_I64, _)) | ||
IR_FOLD(PI(C_DOUBLE, _)) | ||
IR_FOLD(PI(C_FLOAT, _)) | ||
{ | ||
IR_FOLD_COPY(op1); | ||
} | ||
|
||
// TODO: constant functions (e.g. sin, cos) | ||
|
||
/* Copy Propagation */ | ||
|
@@ -1426,6 +1443,103 @@ IR_FOLD(BSWAP(BSWAP)) | |
IR_FOLD_COPY(op1_insn->op1); | ||
} | ||
|
||
IR_FOLD(EQ(PI, C_BOOL)) | ||
IR_FOLD(EQ(PI, C_U8)) | ||
IR_FOLD(EQ(PI, C_U16)) | ||
IR_FOLD(EQ(PI, C_U32)) | ||
IR_FOLD(EQ(PI, C_U64)) | ||
IR_FOLD(EQ(PI, C_ADDR)) | ||
{ | ||
ir_insn *range_insn = &ctx->ir_base[op1_insn->op2]; | ||
IR_ASSERT(range_insn->op == IR_RANGE); | ||
if (IR_IS_CONST_REF(range_insn->op1)) { | ||
if (op2_insn->val.u64 < ctx->ir_base[range_insn->op1].val.u64) { | ||
IR_FOLD_COPY(IR_FALSE); | ||
} | ||
} | ||
if (IR_IS_CONST_REF(range_insn->op2)) { | ||
if (op2_insn->val.u64 > ctx->ir_base[range_insn->op2].val.u64) { | ||
IR_FOLD_COPY(IR_FALSE); | ||
} | ||
} | ||
if (IR_IS_CONST_REF(range_insn->op1) && IR_IS_CONST_REF(range_insn->op2)) { | ||
if (ctx->ir_base[range_insn->op1].val.u64 == ctx->ir_base[range_insn->op2].val.u64) { | ||
IR_FOLD_COPY(IR_TRUE); | ||
} | ||
} | ||
IR_FOLD_NEXT; | ||
} | ||
|
||
IR_FOLD(EQ(PI, C_CHAR)) | ||
IR_FOLD(EQ(PI, C_I8)) | ||
IR_FOLD(EQ(PI, C_I16)) | ||
IR_FOLD(EQ(PI, C_I32)) | ||
IR_FOLD(EQ(PI, C_I64)) | ||
{ | ||
ir_insn *range_insn = &ctx->ir_base[op1_insn->op2]; | ||
IR_ASSERT(range_insn->op == IR_RANGE); | ||
if (IR_IS_CONST_REF(range_insn->op1)) { | ||
if (op2_insn->val.i64 < ctx->ir_base[range_insn->op1].val.i64) { | ||
IR_FOLD_COPY(IR_FALSE); | ||
} | ||
} | ||
if (IR_IS_CONST_REF(range_insn->op2)) { | ||
if (op2_insn->val.i64 > ctx->ir_base[range_insn->op2].val.i64) { | ||
IR_FOLD_COPY(IR_FALSE); | ||
} | ||
} | ||
if (IR_IS_CONST_REF(range_insn->op1) && IR_IS_CONST_REF(range_insn->op2)) { | ||
if (ctx->ir_base[range_insn->op1].val.i64 == ctx->ir_base[range_insn->op2].val.i64) { | ||
IR_FOLD_COPY(IR_TRUE); | ||
} | ||
} | ||
IR_FOLD_NEXT; | ||
} | ||
|
||
IR_FOLD(EQ(PI, C_DOUBLE)) | ||
{ | ||
Comment on lines
+1499
to
+1500
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Floating point numbers might need additional checks for NAN (and may be for negative zero and INF). |
||
ir_insn *range_insn = &ctx->ir_base[op1_insn->op2]; | ||
IR_ASSERT(range_insn->op == IR_RANGE); | ||
if (IR_IS_CONST_REF(range_insn->op1)) { | ||
if (op2_insn->val.d < ctx->ir_base[range_insn->op1].val.d) { | ||
IR_FOLD_COPY(IR_FALSE); | ||
} | ||
} | ||
if (IR_IS_CONST_REF(range_insn->op2)) { | ||
if (op2_insn->val.d > ctx->ir_base[range_insn->op2].val.d) { | ||
IR_FOLD_COPY(IR_FALSE); | ||
} | ||
} | ||
if (IR_IS_CONST_REF(range_insn->op1) && IR_IS_CONST_REF(range_insn->op2)) { | ||
if (ctx->ir_base[range_insn->op1].val.d == ctx->ir_base[range_insn->op2].val.d) { | ||
IR_FOLD_COPY(IR_TRUE); | ||
} | ||
} | ||
IR_FOLD_NEXT; | ||
} | ||
|
||
IR_FOLD(EQ(PI, C_FLOAT)) | ||
{ | ||
ir_insn *range_insn = &ctx->ir_base[op1_insn->op2]; | ||
IR_ASSERT(range_insn->op == IR_RANGE); | ||
if (IR_IS_CONST_REF(range_insn->op1)) { | ||
if (op2_insn->val.f < ctx->ir_base[range_insn->op1].val.f) { | ||
IR_FOLD_COPY(IR_FALSE); | ||
} | ||
} | ||
if (IR_IS_CONST_REF(range_insn->op2)) { | ||
if (op2_insn->val.f > ctx->ir_base[range_insn->op2].val.f) { | ||
IR_FOLD_COPY(IR_FALSE); | ||
} | ||
} | ||
if (IR_IS_CONST_REF(range_insn->op1) && IR_IS_CONST_REF(range_insn->op2)) { | ||
if (ctx->ir_base[range_insn->op1].val.f == ctx->ir_base[range_insn->op2].val.f) { | ||
IR_FOLD_COPY(IR_TRUE); | ||
} | ||
} | ||
IR_FOLD_NEXT; | ||
} | ||
|
||
IR_FOLD(EQ(_, C_BOOL)) | ||
{ | ||
if (op2 == IR_TRUE) { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -550,6 +550,24 @@ static void ir_sccp_remove_if(ir_ctx *ctx, ir_insn *_values, ir_ref ref, ir_ref | |
} | ||
} | ||
|
||
static void ir_sccp_remove_guard(ir_ctx *ctx, ir_ref ref, ir_ref dst) | ||
{ | ||
ir_ref use; | ||
ir_insn *insn, *use_insn; | ||
ir_use_list *use_list = &ctx->use_lists[ref]; | ||
|
||
insn = &ctx->ir_base[ref]; | ||
IR_ASSERT(use_list->count == 1); | ||
use = ctx->use_edges[use_list->refs]; | ||
if (use == dst) { | ||
use_insn = &ctx->ir_base[use]; | ||
use_insn->op1 = insn->op1; | ||
ir_use_list_replace_one(ctx, insn->op1, ref, use); | ||
/* remove GUARD/GUARD_NOT instruction */ | ||
ir_sccp_make_nop(ctx, ref); | ||
} | ||
} | ||
|
||
static void ir_sccp_remove_unfeasible_merge_inputs(ir_ctx *ctx, ir_insn *_values, ir_ref ref, ir_ref unfeasible_inputs) | ||
{ | ||
ir_ref i, j, n, k, *p, use; | ||
|
@@ -1069,6 +1087,41 @@ int ir_sccp(ir_ctx *ctx) | |
continue; | ||
} | ||
IR_MAKE_BOTTOM(i); | ||
} else if (insn->op == IR_GUARD || insn->op == IR_GUARD_NOT) { | ||
if (IR_IS_TOP(insn->op2)) { | ||
/* do backward propagaton only once */ | ||
if (!_values[insn->op2].op1) { | ||
_values[insn->op2].op1 = 1; | ||
ir_bitqueue_add(&worklist, insn->op2); | ||
} | ||
continue; | ||
} | ||
if (!IR_IS_BOTTOM(insn->op2) | ||
#if IR_COMBO_COPY_PROPAGATION | ||
&& (IR_IS_CONST_REF(insn->op2) || _values[insn->op2].op != IR_COPY) | ||
#endif | ||
) { | ||
bool b = ir_sccp_is_true(ctx, _values, insn->op2); | ||
use_list = &ctx->use_lists[i]; | ||
IR_ASSERT(use_list->count == 1); | ||
p = &ctx->use_edges[use_list->refs]; | ||
use = *p; | ||
use_insn = &ctx->ir_base[use]; | ||
if ((insn->op == IR_GUARD) != b) { | ||
use = IR_UNUSED; | ||
} | ||
if (_values[i].optx == IR_TOP) { | ||
_values[i].optx = IR_GUARD; | ||
_values[i].op1 = use; | ||
} else if (_values[i].optx != IR_GUARD || _values[i].op1 != use) { | ||
IR_MAKE_BOTTOM(i); | ||
} | ||
if (use > 0 && !IR_IS_BOTTOM(use)) { | ||
ir_bitqueue_add(&worklist, use); | ||
} | ||
continue; | ||
} | ||
IR_MAKE_BOTTOM(i); | ||
Comment on lines
+1090
to
+1124
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It may be better not to add a special handling for Actually, this may be profitable even without ranges and PI. Can you try this in a separate PR? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. On the other hand, handling GUARDs at first stage allows not only eliminate the "false" GUARDs, but also allows eliminate all the code after the "true" GUARDs. I didn't get if your code does this or not. |
||
} else if (insn->op == IR_SWITCH) { | ||
if (IR_IS_TOP(insn->op2)) { | ||
/* do backward propagaton only once */ | ||
|
@@ -1232,6 +1285,9 @@ int ir_sccp(ir_ctx *ctx) | |
} else if (value->op == IR_IF) { | ||
/* remove one way IF/SWITCH */ | ||
ir_sccp_remove_if(ctx, _values, i, value->op1); | ||
} else if (value->op == IR_GUARD) { | ||
/* remove one way GUARD/GUARD_NOT */ | ||
ir_sccp_remove_guard(ctx, i, value->op1); | ||
} else if (value->op == IR_MERGE) { | ||
/* schedule merge to remove unfeasible MERGE inputs */ | ||
ir_bitqueue_add(&worklist, i); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
--TEST-- | ||
001: Dead guard | ||
--CODE-- | ||
{ | ||
int32_t d_1 = 0; | ||
uintptr_t d_2 = 0; | ||
uintptr_t d_3 = 1; | ||
l_1 = START(l_12); | ||
int32_t d_4 = PARAM(l_1, "x", 0); | ||
bool d_5 = EQ(d_4, d_2); | ||
l_4 = GUARD(l_1, d_4, d_1); | ||
int32_t d_6 = RANGE(d_2, d_2); | ||
int32_t d_7 = PI(d_4, d_6); | ||
bool d_8 = EQ(d_7, d_2); | ||
l_5 = GUARD(l_4, d_8, d_1); | ||
l_12 = RETURN(l_5); | ||
} | ||
--EXPECT-- | ||
{ | ||
uintptr_t c_1 = 0; | ||
bool c_2 = 0; | ||
bool c_3 = 1; | ||
int32_t c_4 = 0; | ||
l_1 = START(l_4); | ||
int32_t d_2 = PARAM(l_1, "x", 0); | ||
l_3 = GUARD(l_1, d_2, c_4); | ||
l_4 = RETURN(l_3, null); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
--TEST-- | ||
014: FOLD: PI(A, CONST) => CONST | ||
--CODE-- | ||
{ | ||
l_1 = START(l_6); | ||
int32_t d_1 = 2; | ||
int32_t d_2 = 1; | ||
int32_t d_3 = ADD(d_2, d_2); | ||
int32_t d_4 = RANGE(d_2, d_1); | ||
int32_t d_5 = PI(d_3, d_4); | ||
l_6 = RETURN(l_1, d_5); | ||
} | ||
--EXPECT-- | ||
{ | ||
uintptr_t c_1 = 0; | ||
bool c_2 = 0; | ||
bool c_3 = 1; | ||
int32_t c_4 = 2; | ||
l_1 = START(l_2); | ||
l_2 = RETURN(l_1, c_4); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From the first look, I don't see a big reason in converting
PI
toCOPY
.COPY
is not going to be removed, and have to be handled by all the following passes. Actually, we may handlePI
in the same way asCOPY
and keep the range info. On the other hand this will may additional overhead for all the following passes.It's also possible to remove
PI
completely (turning it into NOP and re-connecting) input/def/use chains. TThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This may be done at the second phase of SCCP, that removes constant calculations and redundant copies.
I don't know what approach is better yet.