2016-10-16 14:19:01 +08:00
|
|
|
#include "ir.hpp"
|
2016-10-01 08:12:00 +08:00
|
|
|
#include "ir_print.hpp"
|
|
|
|
|
|
|
|
struct IrPrint {
|
|
|
|
FILE *f;
|
|
|
|
int indent;
|
|
|
|
int indent_size;
|
|
|
|
};
|
|
|
|
|
|
|
|
static void ir_print_indent(IrPrint *irp) {
|
|
|
|
for (int i = 0; i < irp->indent; i += 1) {
|
|
|
|
fprintf(irp->f, " ");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void ir_print_prefix(IrPrint *irp, IrInstruction *instruction) {
|
|
|
|
ir_print_indent(irp);
|
2016-10-16 14:19:01 +08:00
|
|
|
const char *type_name = instruction->type_entry ? buf_ptr(&instruction->type_entry->name) : "(unknown)";
|
|
|
|
const char *ref_count = ir_has_side_effects(instruction) ?
|
|
|
|
"-" : buf_ptr(buf_sprintf("%zu", instruction->ref_count));
|
|
|
|
fprintf(irp->f, "#%-3zu| %-12s| %-2s| ", instruction->debug_id, type_name, ref_count);
|
2016-10-01 08:12:00 +08:00
|
|
|
}
|
|
|
|
|
2016-10-16 14:19:01 +08:00
|
|
|
static void ir_print_const_instruction(IrPrint *irp, IrInstruction *instruction) {
|
|
|
|
TypeTableEntry *type_entry = instruction->type_entry;
|
2016-10-03 11:48:48 +08:00
|
|
|
switch (type_entry->id) {
|
2016-10-01 08:12:00 +08:00
|
|
|
case TypeTableEntryIdInvalid:
|
|
|
|
zig_unreachable();
|
|
|
|
case TypeTableEntryIdVoid:
|
2016-10-16 14:19:01 +08:00
|
|
|
fprintf(irp->f, "{}");
|
2016-10-01 08:12:00 +08:00
|
|
|
break;
|
2016-10-03 11:48:48 +08:00
|
|
|
case TypeTableEntryIdNumLitFloat:
|
2016-10-16 14:19:01 +08:00
|
|
|
fprintf(irp->f, "%f", instruction->static_value.data.x_bignum.data.x_float);
|
2016-10-03 11:48:48 +08:00
|
|
|
break;
|
|
|
|
case TypeTableEntryIdNumLitInt:
|
|
|
|
{
|
2016-10-16 14:19:01 +08:00
|
|
|
BigNum *bignum = &instruction->static_value.data.x_bignum;
|
2016-10-03 11:48:48 +08:00
|
|
|
const char *negative_str = bignum->is_negative ? "-" : "";
|
2016-10-16 14:19:01 +08:00
|
|
|
fprintf(irp->f, "%s%llu", negative_str, bignum->data.x_uint);
|
2016-10-03 11:48:48 +08:00
|
|
|
break;
|
|
|
|
}
|
2016-10-01 08:12:00 +08:00
|
|
|
case TypeTableEntryIdMetaType:
|
2016-10-16 14:19:01 +08:00
|
|
|
fprintf(irp->f, "%s", buf_ptr(&instruction->static_value.data.x_type->name));
|
2016-10-09 14:20:01 +08:00
|
|
|
break;
|
2016-10-12 11:45:33 +08:00
|
|
|
case TypeTableEntryIdInt:
|
|
|
|
{
|
2016-10-16 14:19:01 +08:00
|
|
|
BigNum *bignum = &instruction->static_value.data.x_bignum;
|
2016-10-12 11:45:33 +08:00
|
|
|
assert(bignum->kind == BigNumKindInt);
|
|
|
|
const char *negative_str = bignum->is_negative ? "-" : "";
|
2016-10-16 14:19:01 +08:00
|
|
|
fprintf(irp->f, "%s%llu", negative_str, bignum->data.x_uint);
|
2016-10-12 11:45:33 +08:00
|
|
|
}
|
|
|
|
break;
|
2016-10-16 14:19:01 +08:00
|
|
|
case TypeTableEntryIdUnreachable:
|
|
|
|
fprintf(irp->f, "@unreachable()");
|
|
|
|
break;
|
2016-10-09 14:20:01 +08:00
|
|
|
case TypeTableEntryIdVar:
|
2016-10-01 08:12:00 +08:00
|
|
|
case TypeTableEntryIdBool:
|
|
|
|
case TypeTableEntryIdFloat:
|
|
|
|
case TypeTableEntryIdPointer:
|
|
|
|
case TypeTableEntryIdArray:
|
|
|
|
case TypeTableEntryIdStruct:
|
|
|
|
case TypeTableEntryIdUndefLit:
|
|
|
|
case TypeTableEntryIdNullLit:
|
|
|
|
case TypeTableEntryIdMaybe:
|
|
|
|
case TypeTableEntryIdErrorUnion:
|
|
|
|
case TypeTableEntryIdPureError:
|
|
|
|
case TypeTableEntryIdEnum:
|
|
|
|
case TypeTableEntryIdUnion:
|
|
|
|
case TypeTableEntryIdFn:
|
|
|
|
case TypeTableEntryIdTypeDecl:
|
|
|
|
case TypeTableEntryIdNamespace:
|
|
|
|
case TypeTableEntryIdBlock:
|
|
|
|
case TypeTableEntryIdGenericFn:
|
|
|
|
zig_panic("TODO render more constant types in IR printer");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-16 14:19:01 +08:00
|
|
|
static void ir_print_other_instruction(IrPrint *irp, IrInstruction *instruction) {
|
|
|
|
if (instruction->static_value.ok) {
|
|
|
|
ir_print_const_instruction(irp, instruction);
|
|
|
|
} else {
|
|
|
|
fprintf(irp->f, "#%zu", instruction->debug_id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void ir_print_other_block(IrPrint *irp, IrBasicBlock *bb) {
|
|
|
|
fprintf(irp->f, "$%s_%zu", bb->name_hint, bb->debug_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void ir_print_return(IrPrint *irp, IrInstructionReturn *return_instruction) {
|
|
|
|
assert(return_instruction->value);
|
|
|
|
fprintf(irp->f, "return ");
|
|
|
|
ir_print_other_instruction(irp, return_instruction->value);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void ir_print_const(IrPrint *irp, IrInstructionConst *const_instruction) {
|
|
|
|
ir_print_const_instruction(irp, &const_instruction->base);
|
|
|
|
}
|
2016-10-03 11:48:48 +08:00
|
|
|
|
|
|
|
static const char *ir_bin_op_id_str(IrBinOp op_id) {
|
|
|
|
switch (op_id) {
|
|
|
|
case IrBinOpInvalid:
|
|
|
|
zig_unreachable();
|
|
|
|
case IrBinOpBoolOr:
|
|
|
|
return "BoolOr";
|
|
|
|
case IrBinOpBoolAnd:
|
|
|
|
return "BoolAnd";
|
|
|
|
case IrBinOpCmpEq:
|
|
|
|
return "==";
|
|
|
|
case IrBinOpCmpNotEq:
|
|
|
|
return "!=";
|
|
|
|
case IrBinOpCmpLessThan:
|
|
|
|
return "<";
|
|
|
|
case IrBinOpCmpGreaterThan:
|
|
|
|
return ">";
|
|
|
|
case IrBinOpCmpLessOrEq:
|
|
|
|
return "<=";
|
|
|
|
case IrBinOpCmpGreaterOrEq:
|
|
|
|
return ">=";
|
|
|
|
case IrBinOpBinOr:
|
|
|
|
return "|";
|
|
|
|
case IrBinOpBinXor:
|
|
|
|
return "^";
|
|
|
|
case IrBinOpBinAnd:
|
|
|
|
return "&";
|
|
|
|
case IrBinOpBitShiftLeft:
|
|
|
|
return "<<";
|
|
|
|
case IrBinOpBitShiftLeftWrap:
|
|
|
|
return "<<%";
|
|
|
|
case IrBinOpBitShiftRight:
|
|
|
|
return ">>";
|
|
|
|
case IrBinOpAdd:
|
|
|
|
return "+";
|
|
|
|
case IrBinOpAddWrap:
|
|
|
|
return "+%";
|
|
|
|
case IrBinOpSub:
|
|
|
|
return "-";
|
|
|
|
case IrBinOpSubWrap:
|
|
|
|
return "-%";
|
|
|
|
case IrBinOpMult:
|
|
|
|
return "*";
|
|
|
|
case IrBinOpMultWrap:
|
|
|
|
return "*%";
|
|
|
|
case IrBinOpDiv:
|
|
|
|
return "/";
|
|
|
|
case IrBinOpMod:
|
|
|
|
return "%";
|
|
|
|
case IrBinOpArrayCat:
|
|
|
|
return "++";
|
|
|
|
case IrBinOpArrayMult:
|
|
|
|
return "**";
|
|
|
|
}
|
|
|
|
zig_unreachable();
|
|
|
|
}
|
|
|
|
|
2016-10-12 11:45:33 +08:00
|
|
|
static const char *ir_un_op_id_str(IrUnOp op_id) {
|
|
|
|
switch (op_id) {
|
|
|
|
case IrUnOpInvalid:
|
|
|
|
zig_unreachable();
|
|
|
|
case IrUnOpBoolNot:
|
|
|
|
return "!";
|
|
|
|
case IrUnOpBinNot:
|
|
|
|
return "~";
|
|
|
|
case IrUnOpNegation:
|
|
|
|
return "-";
|
|
|
|
case IrUnOpNegationWrap:
|
|
|
|
return "-%";
|
|
|
|
case IrUnOpAddressOf:
|
|
|
|
return "&";
|
|
|
|
case IrUnOpConstAddressOf:
|
|
|
|
return "&const";
|
|
|
|
case IrUnOpDereference:
|
|
|
|
return "*";
|
|
|
|
case IrUnOpMaybe:
|
|
|
|
return "?";
|
|
|
|
case IrUnOpError:
|
|
|
|
return "%";
|
|
|
|
case IrUnOpUnwrapError:
|
|
|
|
return "%%";
|
|
|
|
case IrUnOpUnwrapMaybe:
|
|
|
|
return "??";
|
|
|
|
case IrUnOpMaybeReturn:
|
|
|
|
return "?return";
|
|
|
|
case IrUnOpErrorReturn:
|
|
|
|
return "%return";
|
|
|
|
}
|
|
|
|
zig_unreachable();
|
|
|
|
}
|
|
|
|
|
|
|
|
static void ir_print_un_op(IrPrint *irp, IrInstructionUnOp *un_op_instruction) {
|
2016-10-16 14:19:01 +08:00
|
|
|
fprintf(irp->f, "%s ", ir_un_op_id_str(un_op_instruction->op_id));
|
|
|
|
ir_print_other_instruction(irp, un_op_instruction->value);
|
2016-10-12 11:45:33 +08:00
|
|
|
}
|
|
|
|
|
2016-10-03 11:48:48 +08:00
|
|
|
static void ir_print_bin_op(IrPrint *irp, IrInstructionBinOp *bin_op_instruction) {
|
2016-10-16 14:19:01 +08:00
|
|
|
ir_print_other_instruction(irp, bin_op_instruction->op1);
|
|
|
|
fprintf(irp->f, " %s ", ir_bin_op_id_str(bin_op_instruction->op_id));
|
|
|
|
ir_print_other_instruction(irp, bin_op_instruction->op2);
|
2016-10-03 11:48:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void ir_print_load_var(IrPrint *irp, IrInstructionLoadVar *load_var_instruction) {
|
2016-10-16 14:19:01 +08:00
|
|
|
fprintf(irp->f, "%s", buf_ptr(&load_var_instruction->var->name));
|
2016-10-03 11:48:48 +08:00
|
|
|
}
|
|
|
|
|
2016-10-09 14:20:01 +08:00
|
|
|
static void ir_print_cast(IrPrint *irp, IrInstructionCast *cast_instruction) {
|
2016-10-16 14:19:01 +08:00
|
|
|
fprintf(irp->f, "cast ");
|
|
|
|
ir_print_other_instruction(irp, cast_instruction->value);
|
|
|
|
fprintf(irp->f, " to ");
|
|
|
|
ir_print_other_instruction(irp, cast_instruction->dest_type);
|
2016-10-09 14:20:01 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void ir_print_call(IrPrint *irp, IrInstructionCall *call_instruction) {
|
2016-10-16 14:19:01 +08:00
|
|
|
ir_print_other_instruction(irp, call_instruction->fn);
|
|
|
|
fprintf(irp->f, "(");
|
2016-10-09 14:20:01 +08:00
|
|
|
for (size_t i = 0; i < call_instruction->arg_count; i += 1) {
|
|
|
|
IrInstruction *arg = call_instruction->args[i];
|
|
|
|
if (i != 0)
|
|
|
|
fprintf(irp->f, ", ");
|
2016-10-16 14:19:01 +08:00
|
|
|
ir_print_other_instruction(irp, arg);
|
2016-10-09 14:20:01 +08:00
|
|
|
}
|
2016-10-16 14:19:01 +08:00
|
|
|
fprintf(irp->f, ")");
|
2016-10-09 14:20:01 +08:00
|
|
|
}
|
|
|
|
|
2016-10-12 11:45:33 +08:00
|
|
|
static void ir_print_builtin_call(IrPrint *irp, IrInstructionBuiltinCall *call_instruction) {
|
|
|
|
fprintf(irp->f, "@%s(", buf_ptr(&call_instruction->fn->name));
|
|
|
|
for (size_t i = 0; i < call_instruction->fn->param_count; i += 1) {
|
|
|
|
IrInstruction *arg = call_instruction->args[i];
|
|
|
|
if (i != 0)
|
|
|
|
fprintf(irp->f, ", ");
|
2016-10-16 14:19:01 +08:00
|
|
|
ir_print_other_instruction(irp, arg);
|
2016-10-12 11:45:33 +08:00
|
|
|
}
|
2016-10-16 14:19:01 +08:00
|
|
|
fprintf(irp->f, ")");
|
2016-10-12 11:45:33 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void ir_print_cond_br(IrPrint *irp, IrInstructionCondBr *cond_br_instruction) {
|
2016-10-16 14:19:01 +08:00
|
|
|
fprintf(irp->f, "if (");
|
|
|
|
ir_print_other_instruction(irp, cond_br_instruction->condition);
|
|
|
|
fprintf(irp->f, ") ");
|
|
|
|
ir_print_other_block(irp, cond_br_instruction->then_block);
|
|
|
|
fprintf(irp->f, " else ");
|
|
|
|
ir_print_other_block(irp, cond_br_instruction->else_block);
|
2016-10-12 11:45:33 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void ir_print_br(IrPrint *irp, IrInstructionBr *br_instruction) {
|
2016-10-16 14:19:01 +08:00
|
|
|
fprintf(irp->f, "goto ");
|
|
|
|
ir_print_other_block(irp, br_instruction->dest_block);
|
2016-10-12 11:45:33 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void ir_print_phi(IrPrint *irp, IrInstructionPhi *phi_instruction) {
|
|
|
|
for (size_t i = 0; i < phi_instruction->incoming_count; i += 1) {
|
|
|
|
IrBasicBlock *incoming_block = phi_instruction->incoming_blocks[i];
|
|
|
|
IrInstruction *incoming_value = phi_instruction->incoming_values[i];
|
|
|
|
if (i != 0)
|
|
|
|
fprintf(irp->f, " ");
|
2016-10-16 14:19:01 +08:00
|
|
|
ir_print_other_block(irp, incoming_block);
|
|
|
|
fprintf(irp->f, ":");
|
|
|
|
ir_print_other_instruction(irp, incoming_value);
|
2016-10-12 11:45:33 +08:00
|
|
|
}
|
2016-10-16 14:19:01 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void ir_print_container_init_list(IrPrint *irp, IrInstructionContainerInitList *instruction) {
|
|
|
|
ir_print_other_instruction(irp, instruction->container_type);
|
|
|
|
fprintf(irp->f, "{");
|
|
|
|
for (size_t i = 0; i < instruction->item_count; i += 1) {
|
|
|
|
IrInstruction *item = instruction->items[i];
|
|
|
|
if (i != 0)
|
|
|
|
fprintf(irp->f, ", ");
|
|
|
|
ir_print_other_instruction(irp, item);
|
|
|
|
}
|
|
|
|
fprintf(irp->f, "}");
|
|
|
|
}
|
|
|
|
|
|
|
|
static void ir_print_container_init_fields(IrPrint *irp, IrInstructionContainerInitFields *instruction) {
|
|
|
|
ir_print_other_instruction(irp, instruction->container_type);
|
|
|
|
fprintf(irp->f, "{");
|
|
|
|
for (size_t i = 0; i < instruction->field_count; i += 1) {
|
|
|
|
Buf *name = instruction->field_names[i];
|
|
|
|
IrInstruction *field_value = instruction->field_values[i];
|
|
|
|
const char *comma = (i == 0) ? "" : ", ";
|
|
|
|
fprintf(irp->f, "%s.%s = ", comma, buf_ptr(name));
|
|
|
|
ir_print_other_instruction(irp, field_value);
|
|
|
|
}
|
|
|
|
fprintf(irp->f, "}");
|
|
|
|
}
|
|
|
|
|
|
|
|
static void ir_print_unreachable(IrPrint *irp, IrInstructionUnreachable *instruction) {
|
|
|
|
fprintf(irp->f, "unreachable");
|
2016-10-12 11:45:33 +08:00
|
|
|
}
|
|
|
|
|
2016-10-03 11:48:48 +08:00
|
|
|
static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
|
2016-10-16 14:19:01 +08:00
|
|
|
ir_print_prefix(irp, instruction);
|
2016-10-03 11:48:48 +08:00
|
|
|
switch (instruction->id) {
|
|
|
|
case IrInstructionIdInvalid:
|
|
|
|
zig_unreachable();
|
|
|
|
case IrInstructionIdReturn:
|
|
|
|
ir_print_return(irp, (IrInstructionReturn *)instruction);
|
|
|
|
break;
|
|
|
|
case IrInstructionIdConst:
|
|
|
|
ir_print_const(irp, (IrInstructionConst *)instruction);
|
|
|
|
break;
|
|
|
|
case IrInstructionIdBinOp:
|
|
|
|
ir_print_bin_op(irp, (IrInstructionBinOp *)instruction);
|
|
|
|
break;
|
|
|
|
case IrInstructionIdLoadVar:
|
|
|
|
ir_print_load_var(irp, (IrInstructionLoadVar *)instruction);
|
|
|
|
break;
|
2016-10-09 14:20:01 +08:00
|
|
|
case IrInstructionIdCast:
|
|
|
|
ir_print_cast(irp, (IrInstructionCast *)instruction);
|
|
|
|
break;
|
|
|
|
case IrInstructionIdCall:
|
|
|
|
ir_print_call(irp, (IrInstructionCall *)instruction);
|
|
|
|
break;
|
2016-10-12 11:45:33 +08:00
|
|
|
case IrInstructionIdUnOp:
|
|
|
|
ir_print_un_op(irp, (IrInstructionUnOp *)instruction);
|
|
|
|
break;
|
2016-10-03 11:48:48 +08:00
|
|
|
case IrInstructionIdCondBr:
|
2016-10-12 11:45:33 +08:00
|
|
|
ir_print_cond_br(irp, (IrInstructionCondBr *)instruction);
|
|
|
|
break;
|
|
|
|
case IrInstructionIdBr:
|
|
|
|
ir_print_br(irp, (IrInstructionBr *)instruction);
|
|
|
|
break;
|
|
|
|
case IrInstructionIdBuiltinCall:
|
|
|
|
ir_print_builtin_call(irp, (IrInstructionBuiltinCall *)instruction);
|
|
|
|
break;
|
2016-10-03 11:48:48 +08:00
|
|
|
case IrInstructionIdPhi:
|
2016-10-12 11:45:33 +08:00
|
|
|
ir_print_phi(irp, (IrInstructionPhi *)instruction);
|
|
|
|
break;
|
2016-10-16 14:19:01 +08:00
|
|
|
case IrInstructionIdContainerInitList:
|
|
|
|
ir_print_container_init_list(irp, (IrInstructionContainerInitList *)instruction);
|
|
|
|
break;
|
|
|
|
case IrInstructionIdContainerInitFields:
|
|
|
|
ir_print_container_init_fields(irp, (IrInstructionContainerInitFields *)instruction);
|
|
|
|
break;
|
|
|
|
case IrInstructionIdUnreachable:
|
|
|
|
ir_print_unreachable(irp, (IrInstructionUnreachable *)instruction);
|
|
|
|
break;
|
2016-10-12 11:45:33 +08:00
|
|
|
case IrInstructionIdSwitchBr:
|
2016-10-03 11:48:48 +08:00
|
|
|
case IrInstructionIdStoreVar:
|
|
|
|
zig_panic("TODO print more IR instructions");
|
|
|
|
}
|
2016-10-16 14:19:01 +08:00
|
|
|
fprintf(irp->f, "\n");
|
2016-10-03 11:48:48 +08:00
|
|
|
}
|
|
|
|
|
2016-10-01 08:12:00 +08:00
|
|
|
void ir_print(FILE *f, IrExecutable *executable, int indent_size) {
|
|
|
|
IrPrint ir_print = {};
|
|
|
|
IrPrint *irp = &ir_print;
|
|
|
|
irp->f = f;
|
|
|
|
irp->indent = indent_size;
|
|
|
|
irp->indent_size = indent_size;
|
|
|
|
|
2016-10-06 13:09:01 +08:00
|
|
|
for (size_t bb_i = 0; bb_i < executable->basic_block_list.length; bb_i += 1) {
|
|
|
|
IrBasicBlock *current_block = executable->basic_block_list.at(bb_i);
|
2016-10-12 11:45:33 +08:00
|
|
|
fprintf(irp->f, "%s_%zu:\n", current_block->name_hint, current_block->debug_id);
|
2016-10-06 13:09:01 +08:00
|
|
|
for (size_t instr_i = 0; instr_i < current_block->instruction_list.length; instr_i += 1) {
|
|
|
|
IrInstruction *instruction = current_block->instruction_list.at(instr_i);
|
2016-10-03 11:48:48 +08:00
|
|
|
ir_print_instruction(irp, instruction);
|
2016-10-01 08:12:00 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|