1
0
Fork 0
mirror of https://github.com/ganelson/inform.git synced 2024-07-08 18:14:21 +03:00
inform7/inter/codegen-module/Chapter 2/Eliminate Redundant Operations.w
2021-04-15 22:42:28 +01:00

96 lines
3.4 KiB
OpenEdge ABL

[CodeGen::Operations::] Eliminate Redundant Operations.
To remove logical or arithmetic operations which do nothing.
@h Pipeline stage.
This stage removes redundant operations, replacing each of the following
with just |x|. This is useful mainly because the //imperative: Compile Conditions//
has a tendency to make redundant |OR_BIP| operations like these; the other
cases occur much more rarely.
= (text)
x || false
x && true
x + 0
0 + x
x - 0
x * 1
1 * x
x / 1
=
We could also perform constant-folding here (e.g., replacing |2+3| with |5|),
but we would need to be careful about word size on the VM, and there's not much
gain because the next compiler after us (e.g. Inform 6) will perform its own
constant-folding anyway.
We do not replace |x * 0| with |0|, nor |x && false| with |false|, because then
any intended side-effects of evaluating |x| would be lost.
=
void CodeGen::Operations::create_pipeline_stage(void) {
CodeGen::Stage::new(I"eliminate-redundant-operations",
CodeGen::Operations::run_pipeline_stage, NO_STAGE_ARG, FALSE);
}
int redundant_operations_removed = 0;
int CodeGen::Operations::run_pipeline_stage(pipeline_step *step) {
redundant_operations_removed = 0;
InterTree::traverse(step->repository, CodeGen::Operations::visitor, NULL, NULL, 0);
if (redundant_operations_removed > 0)
LOG("%d redundant operation(s) removed\n", redundant_operations_removed);
return TRUE;
}
void CodeGen::Operations::visitor(inter_tree *I, inter_tree_node *P, void *state) {
if (P->W.data[ID_IFLD] == PACKAGE_IST) {
inter_package *pack = Inter::Package::defined_by_frame(P);
if (Inter::Packages::is_codelike(pack)) {
inter_tree_node *D = Inter::Packages::definition(pack);
CodeGen::Operations::traverse_code_tree(D);
}
}
}
@ |iden[0]| and |iden[1]| hold left and right identity elements for these binary
operations:
=
void CodeGen::Operations::traverse_code_tree(inter_tree_node *P) {
PROTECTED_LOOP_THROUGH_INTER_CHILDREN(F, P) {
CodeGen::Operations::traverse_code_tree(F);
}
PROTECTED_LOOP_THROUGH_INTER_CHILDREN(F, P) {
int iden[2] = { -1, -1 };
if ((F->W.data[ID_IFLD] == INV_IST) &&
(F->W.data[METHOD_INV_IFLD] == INVOKED_PRIMITIVE)) {
inter_symbol *prim = Inter::Inv::invokee(F);
if (Primitives::to_bip(P->tree, prim) == OR_BIP) { iden[1] = 0; }
if (Primitives::to_bip(P->tree, prim) == AND_BIP) { iden[1] = 1; }
if (Primitives::to_bip(P->tree, prim) == PLUS_BIP) { iden[0] = 0; iden[1] = 0; }
if (Primitives::to_bip(P->tree, prim) == MINUS_BIP) { iden[1] = 0; }
if (Primitives::to_bip(P->tree, prim) == TIMES_BIP) { iden[0] = 1; iden[1] = 1; }
if (Primitives::to_bip(P->tree, prim) == DIVIDE_BIP) { iden[1] = 1; }
}
if ((iden[0] >= 0) || (iden[1] >= 0)) @<An elimination candidate@>;
}
}
@<An elimination candidate@> =
inter_tree_node *operands[2];
operands[0] = InterTree::first_child(F);
operands[1] = InterTree::second_child(F);
if ((operands[0]) && (operands[1])) {
for (int i = 0; i < 2; i++) {
if ((iden[i] >= 0) && (operands[i]->W.data[ID_IFLD] == VAL_IST)) {
inter_ti val1 = operands[i]->W.data[VAL1_VAL_IFLD];
inter_ti val2 = operands[i]->W.data[VAL2_VAL_IFLD];
if ((val1 == LITERAL_IVAL) && (val2 == (inter_ti) iden[i])) {
redundant_operations_removed++;
InterTree::remove_node(operands[i]);
InterTree::place(operands[1-i], IMMEDIATELY_AFTER_ICPLACEMENT, F);
InterTree::remove_node(F);
break;
}
}
}
}