Skip to content

Commit

Permalink
Logical and && jmp
Browse files Browse the repository at this point in the history
  • Loading branch information
LesleyLai committed Jan 10, 2025
1 parent 4bcd60f commit 001ec83
Show file tree
Hide file tree
Showing 13 changed files with 278 additions and 31 deletions.
1 change: 1 addition & 0 deletions .clang-tidy
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ readability-simplify-*,
-*-no-recursion,
-*-use-nullptr,
-*-use-anonymous-namespace,
-*-include-cleaner,
'
HeaderFilterRegex: 'catch.hpp'
FormatStyle: 'file'
Expand Down
30 changes: 27 additions & 3 deletions include/mcc/ir.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ typedef enum IRInstructionType {
IR_RETURN, // return val

// unary
IR_COPY, // dest = src
IR_NEG, // dest = -src
IR_COMPLEMENT, // dest = ~src
IR_NOT, // dest = !src
Expand All @@ -63,13 +64,36 @@ typedef enum IRInstructionType {
IR_LESS_EQUAL, // dest = src1 <= src2
IR_GREATER, // dest = src1 > src2
IR_GREATER_EQUAL, // dest = src1 >= src2

// unconditional jump
// jmp <label>
IR_JMP,
// conditional jump
// br <cond> <if_label> <else_label>
IR_BR,

IR_LABEL,
} IRInstructionType;

typedef struct IRInstruction {
IRInstructionType typ;
IRValue operand1; // often dest
IRValue operand2;
IRValue operand3;
union {
struct {
IRValue operand1; // often dest
IRValue operand2;
IRValue operand3;
};
// Label or JMP
struct {
StringView label;
};
// Br
struct {
IRValue cond;
StringView if_label;
StringView else_label;
};
};
} IRInstruction;

#endif // MCC_IR_H
9 changes: 9 additions & 0 deletions include/mcc/x86.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,11 @@ typedef enum X86InstructionType {
X86_INST_SAR, // Arithmetic Right Shift
X86_INST_CMP, // Compare

X86_INST_JMP, // unconditional jump
X86_INST_JMPCC, // conditional jump
X86_INST_SETCC,
X86_INST_LABEL,

} X86InstructionType;

typedef enum X86CondCode {
Expand All @@ -111,10 +115,15 @@ struct X86Instruction {
X86Operand dest;
X86Operand src;
} binary;
struct {
X86CondCode cond;
StringView label;
} jmpcc;
struct {
X86CondCode cond;
X86Operand op;
} setcc;
StringView label; // label or jmp
};
};

Expand Down
122 changes: 103 additions & 19 deletions src/ir/ir_generator.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,16 @@
* Convenient "constructors"
* =============================================================================
*/
static IRValue ir_constant(int32_t constant)
{
return (IRValue){.typ = IR_VALUE_TYPE_CONSTANT, .constant = constant};
}

static IRValue ir_variable(StringView name)
{
return (IRValue){.typ = IR_VALUE_TYPE_VARIABLE, .variable = name};
}

static IRInstruction ir_single_operand_instr(IRInstructionType typ,
IRValue operand)
{
Expand All @@ -22,9 +32,23 @@ static IRInstruction ir_unary_instr(IRInstructionType typ, IRValue dst,
return (IRInstruction){.typ = typ, .operand1 = dst, .operand2 = src};
}

static IRValue ir_variable(StringView name)
static IRInstruction ir_label(StringView label)
{
return (IRValue){.typ = IR_VALUE_TYPE_VARIABLE, .variable = name};
return (IRInstruction){.typ = IR_LABEL, .label = label};
}

static IRInstruction ir_jmp(StringView label)
{
return (IRInstruction){.typ = IR_JMP, .label = label};
}

static IRInstruction ir_br(IRValue cond, StringView if_label,
StringView else_label)
{
return (IRInstruction){.typ = IR_BR,
.cond = cond,
.if_label = if_label,
.else_label = else_label};
}

static IRInstructionType instruction_typ_from_unary_op(UnaryOpType op_type)
Expand Down Expand Up @@ -52,8 +76,8 @@ static IRInstructionType instruction_typ_from_binary_op(BinaryOpType op_type)
case BINARY_OP_BITWISE_XOR: return IR_BITWISE_XOR;
case BINARY_OP_SHIFT_LEFT: return IR_SHIFT_LEFT;
case BINARY_OP_SHIFT_RIGHT: return IR_SHIFT_RIGHT_ARITHMETIC;
case BINARY_OP_AND: MCC_UNIMPLEMENTED();
case BINARY_OP_OR: MCC_UNIMPLEMENTED();
case BINARY_OP_AND: MCC_UNREACHABLE();
case BINARY_OP_OR: MCC_UNREACHABLE();
case BINARY_OP_EQUAL: return IR_EQUAL;
case BINARY_OP_NOT_EQUAL: return IR_NOT_EQUAL;
case BINARY_OP_LESS: return IR_LESS;
Expand All @@ -75,6 +99,7 @@ typedef struct IRGenContext {
Arena* scratch_arena;
IRInstructions instructions;
int fresh_variable_counter;
int fresh_label_counter;
} IRGenContext;

static void push_instruction(IRGenContext* context, IRInstruction instruction)
Expand All @@ -91,6 +116,43 @@ static StringView create_fresh_variable_name(IRGenContext* context)
return string_view_from_c_str(variable_name_buffer);
}

static StringView create_fresh_label_name(IRGenContext* context,
const char* name)
{
char* variable_name_buffer = allocate_printf(
context->permanent_arena, "%s_%d", name, context->fresh_label_counter);
++context->fresh_label_counter;
return string_view_from_c_str(variable_name_buffer);
}

static IRValue emit_ir_instructions_from_expr(const Expr* expr,
IRGenContext* context);

static IRValue emit_ir_instructions_from_binary_expr(const Expr* expr,
IRGenContext* context)
{
const IRInstructionType instruction_type =
instruction_typ_from_binary_op(expr->binary_op.binary_op_type);

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

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

const StringView dst_name = create_fresh_variable_name(context);
const IRValue dst = ir_variable(dst_name);

push_instruction(context, (IRInstruction){
.typ = instruction_type,
.operand1 = dst,
.operand2 = lhs,
.operand3 = rhs,
});

return dst;
}

static IRValue emit_ir_instructions_from_expr(const Expr* expr,
IRGenContext* context)
{
Expand All @@ -114,26 +176,48 @@ static IRValue emit_ir_instructions_from_expr(const Expr* expr,
return dst;
}
case EXPR_BINARY: {
const IRInstructionType instruction_type =
instruction_typ_from_binary_op(expr->binary_op.binary_op_type);
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 lhs =
emit_ir_instructions_from_expr(expr->binary_op.lhs, context);
const IRValue result = ir_variable(string_view_from_c_str("result"));

const IRValue rhs =
emit_ir_instructions_from_expr(expr->binary_op.rhs, context);
push_instruction(context, ir_br(lhs, lhs_true_label, false_label));
push_instruction(context, ir_label(lhs_true_label));

const StringView dst_name = create_fresh_variable_name(context);
const IRValue dst = ir_variable(dst_name);
const IRValue rhs =
emit_ir_instructions_from_expr(expr->binary_op.rhs, context);

push_instruction(context, (IRInstruction){
.typ = instruction_type,
.operand1 = dst,
.operand2 = lhs,
.operand3 = rhs,
});
push_instruction(context, ir_br(rhs, rhs_true_label, false_label));

return dst;
// .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();
default: return emit_ir_instructions_from_binary_expr(expr, context);
}
}
}

Expand Down
16 changes: 16 additions & 0 deletions src/ir/ir_printer.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ void print_ir(const IRProgram* ir)
print_ir_value(instruction.operand1);
printf("\n");
} break;
case IR_COPY: print_unary_op(instruction, "copy"); break;
case IR_NEG: print_unary_op(instruction, "neg"); break;
case IR_COMPLEMENT: print_unary_op(instruction, "complement"); break;
case IR_NOT: print_unary_op(instruction, "not"); break;
Expand All @@ -67,6 +68,21 @@ void print_ir(const IRProgram* ir)
case IR_LESS_EQUAL: print_binary_op(instruction, "le"); break;
case IR_GREATER: print_binary_op(instruction, "gt"); break;
case IR_GREATER_EQUAL: print_binary_op(instruction, "ge"); break;
case IR_JMP: {
printf(" jmp ");
printf(".%.*s\n", (int)instruction.label.size, instruction.label.start);
} break;
case IR_BR: {
printf(" br ");
print_ir_value(instruction.cond);
printf(" .%.*s .%.*s\n", //
(int)instruction.if_label.size, instruction.if_label.start, //
(int)instruction.else_label.size, instruction.else_label.start);
} break;
case IR_LABEL: {
printf(".%.*s:\n", (int)instruction.label.size,
instruction.label.start);
} break;
}
}
}
Expand Down
64 changes: 60 additions & 4 deletions src/x86/x86_from_ir.c
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#include "mcc/prelude.h"
#include "x86_passes.h"
#include <mcc/ir.h>

Expand Down Expand Up @@ -98,14 +99,20 @@ static void generate_comparison_instruction(X86InstructionVector* instructions,
.setcc = {.cond = cond_code, .op = dest}});
}

static const IRInstruction* get_instruction(const IRFunctionDef* function,
size_t i)
{
return i < function->instruction_count ? &function->instructions[i] : nullptr;
}

// First pass to generate assembly. Still need fixing later
X86FunctionDef x86_function_from_ir(const IRFunctionDef* ir_function,
Arena* scratch_arena)
Arena* scratch_arena)
{
X86InstructionVector instructions = {.arena = scratch_arena};

for (size_t j = 0; j < ir_function->instruction_count; ++j) {
const IRInstruction* ir_instruction = &ir_function->instructions[j];
for (size_t i = 0; i < ir_function->instruction_count; ++i) {
const IRInstruction* ir_instruction = get_instruction(ir_function, i);
switch (ir_instruction->typ) {
case IR_INVALID: MCC_UNREACHABLE(); break;
case IR_RETURN: {
Expand All @@ -118,7 +125,13 @@ X86FunctionDef x86_function_from_ir(const IRFunctionDef* ir_function,
push_instruction(&instructions, (X86Instruction){.typ = X86_INST_RET});
break;
}

case IR_COPY: {
X86Operand dest = x86_operand_from_ir(ir_instruction->operand1);
X86Operand src = x86_operand_from_ir(ir_instruction->operand2);
// mov dest src
push_instruction(&instructions,
binary_instruction(X86_INST_MOV, X86_SZ_4, dest, src));
} break;
case IR_NEG:
push_unary_instruction(&instructions, X86_INST_NEG, ir_instruction);
break;
Expand Down Expand Up @@ -179,6 +192,49 @@ X86FunctionDef x86_function_from_ir(const IRFunctionDef* ir_function,
case IR_GREATER_EQUAL:
generate_comparison_instruction(&instructions, ir_instruction);
break;
case IR_JMP:
push_instruction(&instructions, (X86Instruction){
.typ = X86_INST_JMP,
.label = ir_instruction->label,
});
break;
case IR_BR: {
const X86Operand cond = x86_operand_from_ir(ir_instruction->cond);
const StringView if_label = ir_instruction->if_label;
const StringView else_label = ir_instruction->else_label;

const IRInstruction* next_instruction =
get_instruction(ir_function, i + 1);

if (next_instruction != nullptr && next_instruction->typ == IR_LABEL) {
// If the if_label is directly follow this instruction
if (string_view_eq(next_instruction->label, if_label)) {
// cmp cond, 0
push_instruction(&instructions,
binary_instruction(X86_INST_CMP, X86_SZ_4, cond,
immediate_operand(0)));
// je .else_label
push_instruction(&instructions,
(X86Instruction){.typ = X86_INST_JMPCC,
.jmpcc = {
.cond = X86_COND_E,
.label = else_label,
}});

break;
} else if (string_view_eq(next_instruction->label, else_label)) {
MCC_UNIMPLEMENTED();
}
}

MCC_UNIMPLEMENTED();
} break;
case IR_LABEL:
push_instruction(&instructions, (X86Instruction){
.typ = X86_INST_LABEL,
.label = ir_instruction->label,
});
break;
}
}

Expand Down
5 changes: 4 additions & 1 deletion src/x86/x86_helpers.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,10 @@ static bool is_binary(X86InstructionType typ)
case X86_INST_RET:
case X86_INST_CDQ:
X86_UNARY_INSTRUCTION_CASES:
case X86_INST_SETCC: return false;
case X86_INST_JMP:
case X86_INST_JMPCC:
case X86_INST_SETCC:
case X86_INST_LABEL: return false;
}
MCC_UNREACHABLE();
}
Expand Down
Loading

0 comments on commit 001ec83

Please sign in to comment.