Skip to content

Commit

Permalink
logical or
Browse files Browse the repository at this point in the history
  • Loading branch information
LesleyLai committed Jan 10, 2025
1 parent 001ec83 commit ca2ea99
Show file tree
Hide file tree
Showing 12 changed files with 138 additions and 42 deletions.
1 change: 1 addition & 0 deletions include/mcc/ir.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ typedef enum IRInstructionType {
IR_JMP,
// conditional jump
// br <cond> <if_label> <else_label>
// jump to <if_label> if <cond> is not zero, otherwise jump to <else_label>
IR_BR,

IR_LABEL,
Expand Down
129 changes: 90 additions & 39 deletions src/ir/ir_generator.c
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,92 @@ static IRValue emit_ir_instructions_from_binary_expr(const Expr* expr,
return dst;
}

static IRValue emit_ir_instructions_from_logical_and(const Expr* expr,
IRGenContext* context)
{
const IRValue lhs =
emit_ir_instructions_from_expr(expr->binary_op.lhs, context);
const StringView lhs_true_label =
create_fresh_label_name(context, "and_lhs_true");
const StringView rhs_true_label =
create_fresh_label_name(context, "and_rhs_true");
const StringView false_label = create_fresh_label_name(context, "and_false");
const StringView end_label = create_fresh_label_name(context, "and_end");

const IRValue result = ir_variable(string_view_from_c_str("result"));

// br lhs .and_lhs_true .and_false
push_instruction(context, ir_br(lhs, lhs_true_label, false_label));
// .and_lhs_true:
push_instruction(context, ir_label(lhs_true_label));

const IRValue rhs =
emit_ir_instructions_from_expr(expr->binary_op.rhs, context);

// br rhs .and_rhs_true .and_false
push_instruction(context, ir_br(rhs, rhs_true_label, false_label));

// .and_rhs_true:
// result = 1
// jmp .and_end
push_instruction(context, ir_label(rhs_true_label));
push_instruction(context, ir_unary_instr(IR_COPY, result, ir_constant(1)));
push_instruction(context, ir_jmp(end_label));

// .and_false:
// result = 0
push_instruction(context, ir_label(false_label));
push_instruction(context, ir_unary_instr(IR_COPY, result, ir_constant(0)));

// .and_end
push_instruction(context, ir_label(end_label));

return result;
}

static IRValue emit_ir_instructions_from_logical_or(const Expr* expr,
IRGenContext* context)
{
const IRValue lhs =
emit_ir_instructions_from_expr(expr->binary_op.lhs, context);
const StringView lhs_false_label =
create_fresh_label_name(context, "or_lhs_false");
const StringView rhs_false_label =
create_fresh_label_name(context, "or_rhs_false");
const StringView true_label = create_fresh_label_name(context, "or_true");
const StringView end_label = create_fresh_label_name(context, "or_end");

const IRValue result = ir_variable(string_view_from_c_str("result"));

// br lhs .or_true .or_lhs_false
push_instruction(context, ir_br(lhs, true_label, lhs_false_label));
// .or_lhs_false:
push_instruction(context, ir_label(lhs_false_label));

const IRValue rhs =
emit_ir_instructions_from_expr(expr->binary_op.rhs, context);

// br rhs .or_true .or_rhs_false
push_instruction(context, ir_br(rhs, true_label, rhs_false_label));

// .or_rhs_false:
// result = 0
// jmp .or_end
push_instruction(context, ir_label(rhs_false_label));
push_instruction(context, ir_unary_instr(IR_COPY, result, ir_constant(0)));
push_instruction(context, ir_jmp(end_label));

// .or_true:
// result = 1
push_instruction(context, ir_label(true_label));
push_instruction(context, ir_unary_instr(IR_COPY, result, ir_constant(1)));

// .or_end:
push_instruction(context, ir_label(end_label));

return result;
}

static IRValue emit_ir_instructions_from_expr(const Expr* expr,
IRGenContext* context)
{
Expand All @@ -177,45 +263,10 @@ static IRValue emit_ir_instructions_from_expr(const Expr* expr,
}
case EXPR_BINARY: {
switch (expr->binary_op.binary_op_type) {
case BINARY_OP_AND: {
const IRValue lhs =
emit_ir_instructions_from_expr(expr->binary_op.lhs, context);
const StringView lhs_true_label =
create_fresh_label_name(context, "and_lhs_true");
const StringView rhs_true_label =
create_fresh_label_name(context, "and_rhs_true");
const StringView false_label =
create_fresh_label_name(context, "and_false");
const StringView end_label = create_fresh_label_name(context, "and_end");

const IRValue result = ir_variable(string_view_from_c_str("result"));

push_instruction(context, ir_br(lhs, lhs_true_label, false_label));
push_instruction(context, ir_label(lhs_true_label));

const IRValue rhs =
emit_ir_instructions_from_expr(expr->binary_op.rhs, context);

push_instruction(context, ir_br(rhs, rhs_true_label, false_label));

// .if2:
// result = 1
push_instruction(context, ir_label(rhs_true_label));
push_instruction(context,
ir_unary_instr(IR_COPY, result, ir_constant(1)));
push_instruction(context, ir_jmp(end_label));

// .false
push_instruction(context, ir_label(false_label));
// result = 0
push_instruction(context,
ir_unary_instr(IR_COPY, result, ir_constant(0)));

push_instruction(context, ir_label(end_label));

return result;
}
case BINARY_OP_OR: MCC_UNIMPLEMENTED();
case BINARY_OP_AND:
return emit_ir_instructions_from_logical_and(expr, context);
case BINARY_OP_OR:
return emit_ir_instructions_from_logical_or(expr, context);
default: return emit_ir_instructions_from_binary_expr(expr, context);
}
}
Expand Down
15 changes: 14 additions & 1 deletion src/x86/x86_from_ir.c
Original file line number Diff line number Diff line change
Expand Up @@ -222,8 +222,21 @@ X86FunctionDef x86_function_from_ir(const IRFunctionDef* ir_function,
}});

break;
// If the else_label is directly follow this instruction
} else if (string_view_eq(next_instruction->label, else_label)) {
MCC_UNIMPLEMENTED();
// cmp cond, 0
push_instruction(&instructions,
binary_instruction(X86_INST_CMP, X86_SZ_4, cond,
immediate_operand(0)));
// jne .if_label
push_instruction(&instructions,
(X86Instruction){.typ = X86_INST_JMPCC,
.jmpcc = {
.cond = X86_COND_NE,
.label = if_label,
}});

break;
}
}

Expand Down
2 changes: 1 addition & 1 deletion test/test_data/basics/logical/and_false.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// RETURN: 0
int main(void)
{
return (-1 && 0) + (0 && 42);
return (-1 && 0) + (0 && 42) + (0 && 0);
}
File renamed without changes.
5 changes: 5 additions & 0 deletions test/test_data/basics/logical/multi_short_circuit.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// RETURN: 0
int main(void)
{
return 0 || 0 && (1 / 0);
}
5 changes: 5 additions & 0 deletions test/test_data/basics/logical/or_false.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// RETURN: 0
int main(void)
{
return 0 || 0;
}
5 changes: 5 additions & 0 deletions test/test_data/basics/logical/or_short_circuit.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// RETURN: 1
int main(void)
{
return 1 || (1 / 0);
}
5 changes: 5 additions & 0 deletions test/test_data/basics/logical/or_true.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// RETURN: 3
int main(void)
{
return (1 || 0) + (2 || 3) + (0 || 4);
}
5 changes: 5 additions & 0 deletions test/test_data/basics/logical/precedence.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// RETURN: 1
int main(void)
{
return 1 || 0 && 2;
}
5 changes: 5 additions & 0 deletions test/test_data/basics/logical/precedence2.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// RETURN: 1
int main(void)
{
return 2 == 2 || 0;
}
3 changes: 2 additions & 1 deletion test/unit_tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ add_executable(mcc_unit_tests
string_test.cpp
formatting_test.cpp
lexer_test.cpp
dynarray_test.cpp)
dynarray_test.cpp
)
target_link_libraries(mcc_unit_tests PUBLIC mcc_lib mcc::compiler_warnings Catch2::Catch2WithMain fmt::fmt)

add_test(NAME mcc COMMAND mcc_unit_tests)

0 comments on commit ca2ea99

Please sign in to comment.