To remove logical or arithmetic operations which do nothing.


§1. Pipeline stage. This stage removes redundant operations, replacing each of the following with just x. This is useful mainly because the Compile Conditions (in imperative) has a tendency to make redundant OR_BIP operations like these; the other cases occur much more rarely.

    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);
        }
    }
}

§2. 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 candidate2.1;
    }
}

§2.1. An elimination candidate2.1 =

    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;
                }
            }
        }
    }