mirror of
https://github.com/ziglang/zig.git
synced 2026-02-12 20:37:54 +00:00
IR: switch expression works with numbers
This commit is contained in:
parent
0c22358cc1
commit
bbf785bc1d
@ -1455,6 +1455,7 @@ enum IrInstructionId {
|
||||
IrInstructionIdSizeOf,
|
||||
IrInstructionIdTestNull,
|
||||
IrInstructionIdUnwrapMaybe,
|
||||
IrInstructionIdEnumTag,
|
||||
IrInstructionIdClz,
|
||||
IrInstructionIdCtz,
|
||||
};
|
||||
@ -1801,6 +1802,12 @@ struct IrInstructionClz {
|
||||
IrInstruction *value;
|
||||
};
|
||||
|
||||
struct IrInstructionEnumTag {
|
||||
IrInstruction base;
|
||||
|
||||
IrInstruction *value;
|
||||
};
|
||||
|
||||
enum LValPurpose {
|
||||
LValPurposeNone,
|
||||
LValPurposeAssign,
|
||||
|
||||
126
src/analyze.cpp
126
src/analyze.cpp
@ -2108,44 +2108,6 @@ static bool type_has_codegen_value(TypeTableEntry *type_entry) {
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
static bool num_lit_fits_in_other_type(CodeGen *g, AstNode *literal_node, TypeTableEntry *other_type) {
|
||||
TypeTableEntry *other_type_underlying = get_underlying_type(other_type);
|
||||
|
||||
if (other_type_underlying->id == TypeTableEntryIdInvalid) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Expr *expr = get_resolved_expr(literal_node);
|
||||
ConstExprValue *const_val = &expr->instruction->static_value;
|
||||
assert(const_val->special != ConstValSpecialRuntime);
|
||||
if (other_type_underlying->id == TypeTableEntryIdFloat) {
|
||||
return true;
|
||||
} else if (other_type_underlying->id == TypeTableEntryIdInt &&
|
||||
const_val->data.x_bignum.kind == BigNumKindInt)
|
||||
{
|
||||
if (bignum_fits_in_bits(&const_val->data.x_bignum, other_type_underlying->data.integral.bit_count,
|
||||
other_type_underlying->data.integral.is_signed))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
} else if ((other_type_underlying->id == TypeTableEntryIdNumLitFloat &&
|
||||
const_val->data.x_bignum.kind == BigNumKindFloat) ||
|
||||
(other_type_underlying->id == TypeTableEntryIdNumLitInt &&
|
||||
const_val->data.x_bignum.kind == BigNumKindInt))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
const char *num_lit_str = (const_val->data.x_bignum.kind == BigNumKindFloat) ? "float" : "integer";
|
||||
|
||||
add_node_error(g, literal_node,
|
||||
buf_sprintf("%s value %s cannot be implicitly casted to type '%s'",
|
||||
num_lit_str,
|
||||
buf_ptr(bignum_to_buf(&const_val->data.x_bignum)),
|
||||
buf_ptr(&other_type->name)));
|
||||
return false;
|
||||
}
|
||||
|
||||
bool types_match_const_cast_only(TypeTableEntry *expected_type, TypeTableEntry *actual_type) {
|
||||
if (expected_type == actual_type)
|
||||
return true;
|
||||
@ -2233,94 +2195,6 @@ bool types_match_const_cast_only(TypeTableEntry *expected_type, TypeTableEntry *
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool types_match_with_implicit_cast(CodeGen *g, TypeTableEntry *expected_type,
|
||||
TypeTableEntry *actual_type, AstNode *literal_node, bool *reported_err)
|
||||
{
|
||||
if (types_match_const_cast_only(expected_type, actual_type)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// implicit conversion from non maybe type to maybe type
|
||||
if (expected_type->id == TypeTableEntryIdMaybe &&
|
||||
types_match_with_implicit_cast(g, expected_type->data.maybe.child_type, actual_type,
|
||||
literal_node, reported_err))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// implicit conversion from null literal to maybe type
|
||||
if (expected_type->id == TypeTableEntryIdMaybe &&
|
||||
actual_type->id == TypeTableEntryIdNullLit)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// implicit conversion from error child type to error type
|
||||
if (expected_type->id == TypeTableEntryIdErrorUnion &&
|
||||
types_match_with_implicit_cast(g, expected_type->data.error.child_type, actual_type,
|
||||
literal_node, reported_err))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// implicit conversion from pure error to error union type
|
||||
if (expected_type->id == TypeTableEntryIdErrorUnion &&
|
||||
actual_type->id == TypeTableEntryIdPureError)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// implicit widening conversion
|
||||
if (expected_type->id == TypeTableEntryIdInt &&
|
||||
actual_type->id == TypeTableEntryIdInt &&
|
||||
expected_type->data.integral.is_signed == actual_type->data.integral.is_signed &&
|
||||
expected_type->data.integral.bit_count >= actual_type->data.integral.bit_count)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// small enough unsigned ints can get casted to large enough signed ints
|
||||
if (expected_type->id == TypeTableEntryIdInt && expected_type->data.integral.is_signed &&
|
||||
actual_type->id == TypeTableEntryIdInt && !actual_type->data.integral.is_signed &&
|
||||
expected_type->data.integral.bit_count > actual_type->data.integral.bit_count)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// implicit float widening conversion
|
||||
if (expected_type->id == TypeTableEntryIdFloat &&
|
||||
actual_type->id == TypeTableEntryIdFloat &&
|
||||
expected_type->data.floating.bit_count >= actual_type->data.floating.bit_count)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// implicit array to slice conversion
|
||||
if (expected_type->id == TypeTableEntryIdStruct &&
|
||||
expected_type->data.structure.is_slice &&
|
||||
actual_type->id == TypeTableEntryIdArray &&
|
||||
types_match_const_cast_only(
|
||||
expected_type->data.structure.fields[0].type_entry->data.pointer.child_type,
|
||||
actual_type->data.array.child_type))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// implicit number literal to typed number
|
||||
if ((actual_type->id == TypeTableEntryIdNumLitFloat ||
|
||||
actual_type->id == TypeTableEntryIdNumLitInt))
|
||||
{
|
||||
if (num_lit_fits_in_other_type(g, literal_node, expected_type)) {
|
||||
return true;
|
||||
} else {
|
||||
*reported_err = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
BlockContext *new_block_context(AstNode *node, BlockContext *parent) {
|
||||
BlockContext *context = allocate<BlockContext>(1);
|
||||
context->node = node;
|
||||
|
||||
@ -354,6 +354,9 @@ static void render_node_ungrouped(AstRender *ar, AstNode *node) {
|
||||
|
||||
static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
|
||||
switch (node->type) {
|
||||
case NodeTypeSwitchProng:
|
||||
case NodeTypeSwitchRange:
|
||||
zig_unreachable();
|
||||
case NodeTypeRoot:
|
||||
for (size_t i = 0; i < node->data.root.top_level_decls.length; i += 1) {
|
||||
AstNode *child = node->data.root.top_level_decls.at(i);
|
||||
@ -728,6 +731,47 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
|
||||
break;
|
||||
}
|
||||
case NodeTypeSwitchExpr:
|
||||
{
|
||||
AstNodeSwitchExpr *switch_expr = &node->data.switch_expr;
|
||||
fprintf(ar->f, "switch (");
|
||||
render_node_grouped(ar, switch_expr->expr);
|
||||
fprintf(ar->f, ") {\n");
|
||||
ar->indent += ar->indent_size;
|
||||
|
||||
for (size_t prong_i = 0; prong_i < switch_expr->prongs.length; prong_i += 1) {
|
||||
AstNode *prong_node = switch_expr->prongs.at(prong_i);
|
||||
AstNodeSwitchProng *switch_prong = &prong_node->data.switch_prong;
|
||||
print_indent(ar);
|
||||
for (size_t item_i = 0; item_i < switch_prong->items.length; item_i += 1) {
|
||||
AstNode *item_node = switch_prong->items.at(item_i);
|
||||
if (item_i != 0)
|
||||
fprintf(ar->f, ", ");
|
||||
if (item_node->type == NodeTypeSwitchRange) {
|
||||
AstNode *start_node = item_node->data.switch_range.start;
|
||||
AstNode *end_node = item_node->data.switch_range.end;
|
||||
render_node_grouped(ar, start_node);
|
||||
fprintf(ar->f, "...");
|
||||
render_node_grouped(ar, end_node);
|
||||
} else {
|
||||
render_node_grouped(ar, item_node);
|
||||
}
|
||||
}
|
||||
const char *else_str = (switch_prong->items.length == 0) ? "else" : "";
|
||||
fprintf(ar->f, "%s => ", else_str);
|
||||
if (switch_prong->var_symbol) {
|
||||
const char *star_str = switch_prong->var_is_ptr ? "*" : "";
|
||||
Buf *var_name = switch_prong->var_symbol->data.symbol_expr.symbol;
|
||||
fprintf(ar->f, "|%s%s| ", star_str, buf_ptr(var_name));
|
||||
}
|
||||
render_node_grouped(ar, switch_prong->expr);
|
||||
fprintf(ar->f, ",\n");
|
||||
}
|
||||
|
||||
ar->indent -= ar->indent_size;
|
||||
print_indent(ar);
|
||||
fprintf(ar->f, "}");
|
||||
break;
|
||||
}
|
||||
case NodeTypeFnDecl:
|
||||
case NodeTypeParamDecl:
|
||||
case NodeTypeErrorValueDecl:
|
||||
@ -738,8 +782,6 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
|
||||
case NodeTypeUse:
|
||||
case NodeTypeZeroesLiteral:
|
||||
case NodeTypeForExpr:
|
||||
case NodeTypeSwitchProng:
|
||||
case NodeTypeSwitchRange:
|
||||
case NodeTypeLabel:
|
||||
case NodeTypeGoto:
|
||||
case NodeTypeBreak:
|
||||
|
||||
@ -1638,6 +1638,31 @@ static LLVMValueRef ir_render_ctz(CodeGen *g, IrExecutable *executable, IrInstru
|
||||
return LLVMBuildCall(g->builder, fn_val, params, 2, "");
|
||||
}
|
||||
|
||||
static LLVMValueRef ir_render_switch_br(CodeGen *g, IrExecutable *executable, IrInstructionSwitchBr *instruction) {
|
||||
assert(!instruction->is_inline);
|
||||
|
||||
LLVMValueRef target_value = ir_llvm_value(g, instruction->target_value);
|
||||
LLVMBasicBlockRef else_block = instruction->else_block->llvm_block;
|
||||
LLVMValueRef switch_instr = LLVMBuildSwitch(g->builder, target_value, else_block, instruction->case_count);
|
||||
for (size_t i = 0; i < instruction->case_count; i += 1) {
|
||||
IrInstructionSwitchBrCase *this_case = &instruction->cases[i];
|
||||
LLVMAddCase(switch_instr, ir_llvm_value(g, this_case->value), this_case->block->llvm_block);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static LLVMValueRef ir_render_phi(CodeGen *g, IrExecutable *executable, IrInstructionPhi *instruction) {
|
||||
LLVMValueRef phi = LLVMBuildPhi(g->builder, instruction->base.type_entry->type_ref, "");
|
||||
LLVMValueRef *incoming_values = allocate<LLVMValueRef>(instruction->incoming_count);
|
||||
LLVMBasicBlockRef *incoming_blocks = allocate<LLVMBasicBlockRef>(instruction->incoming_count);
|
||||
for (size_t i = 0; i < instruction->incoming_count; i += 1) {
|
||||
incoming_values[i] = ir_llvm_value(g, instruction->incoming_values[i]);
|
||||
incoming_blocks[i] = instruction->incoming_blocks[i]->llvm_block;
|
||||
}
|
||||
LLVMAddIncoming(phi, incoming_values, incoming_blocks, instruction->incoming_count);
|
||||
return phi;
|
||||
}
|
||||
|
||||
static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, IrInstruction *instruction) {
|
||||
set_debug_source_node(g, instruction->source_node);
|
||||
|
||||
@ -1655,6 +1680,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
|
||||
case IrInstructionIdSliceType:
|
||||
case IrInstructionIdCompileVar:
|
||||
case IrInstructionIdSizeOf:
|
||||
case IrInstructionIdSwitchTarget:
|
||||
zig_unreachable();
|
||||
case IrInstructionIdReturn:
|
||||
return ir_render_return(g, executable, (IrInstructionReturn *)instruction);
|
||||
@ -1695,12 +1721,14 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
|
||||
case IrInstructionIdCtz:
|
||||
return ir_render_ctz(g, executable, (IrInstructionCtz *)instruction);
|
||||
case IrInstructionIdSwitchBr:
|
||||
case IrInstructionIdSwitchTarget:
|
||||
case IrInstructionIdSwitchVar:
|
||||
return ir_render_switch_br(g, executable, (IrInstructionSwitchBr *)instruction);
|
||||
case IrInstructionIdPhi:
|
||||
return ir_render_phi(g, executable, (IrInstructionPhi *)instruction);
|
||||
case IrInstructionIdSwitchVar:
|
||||
case IrInstructionIdContainerInitList:
|
||||
case IrInstructionIdContainerInitFields:
|
||||
case IrInstructionIdReadField:
|
||||
case IrInstructionIdEnumTag:
|
||||
zig_panic("TODO render more IR instructions to LLVM");
|
||||
}
|
||||
zig_unreachable();
|
||||
|
||||
281
src/ir.cpp
281
src/ir.cpp
@ -88,16 +88,21 @@ static void ir_ref_var(VariableTableEntry *var) {
|
||||
var->ref_count += 1;
|
||||
}
|
||||
|
||||
static IrBasicBlock *ir_build_basic_block(IrBuilder *irb, const char *name_hint) {
|
||||
static IrBasicBlock *ir_build_basic_block_raw(IrBuilder *irb, const char *name_hint) {
|
||||
IrBasicBlock *result = allocate<IrBasicBlock>(1);
|
||||
result->name_hint = name_hint;
|
||||
result->debug_id = exec_next_debug_id(irb->exec);
|
||||
return result;
|
||||
}
|
||||
|
||||
static IrBasicBlock *ir_build_basic_block(IrBuilder *irb, const char *name_hint) {
|
||||
IrBasicBlock *result = ir_build_basic_block_raw(irb, name_hint);
|
||||
irb->exec->basic_block_list.append(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
static IrBasicBlock *ir_build_bb_from(IrBuilder *irb, IrBasicBlock *other_bb) {
|
||||
IrBasicBlock *new_bb = ir_build_basic_block(irb, other_bb->name_hint);
|
||||
IrBasicBlock *new_bb = ir_build_basic_block_raw(irb, other_bb->name_hint);
|
||||
ir_link_new_bb(new_bb, other_bb);
|
||||
return new_bb;
|
||||
}
|
||||
@ -254,6 +259,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionCtz *) {
|
||||
return IrInstructionIdCtz;
|
||||
}
|
||||
|
||||
static constexpr IrInstructionId ir_instruction_id(IrInstructionEnumTag *) {
|
||||
return IrInstructionIdEnumTag;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static T *ir_create_instruction(IrExecutable *exec, AstNode *source_node) {
|
||||
T *special_instruction = allocate<T>(1);
|
||||
@ -612,6 +621,9 @@ static IrInstruction *ir_build_call_from(IrBuilder *irb, IrInstruction *old_inst
|
||||
static IrInstruction *ir_build_phi(IrBuilder *irb, AstNode *source_node,
|
||||
size_t incoming_count, IrBasicBlock **incoming_blocks, IrInstruction **incoming_values)
|
||||
{
|
||||
assert(incoming_count != 0);
|
||||
assert(incoming_count != SIZE_MAX);
|
||||
|
||||
IrInstructionPhi *phi_instruction = ir_build_instruction<IrInstructionPhi>(irb, source_node);
|
||||
phi_instruction->incoming_count = incoming_count;
|
||||
phi_instruction->incoming_blocks = incoming_blocks;
|
||||
@ -993,6 +1005,8 @@ static IrInstruction *ir_build_switch_br(IrBuilder *irb, AstNode *source_node, I
|
||||
IrBasicBlock *else_block, size_t case_count, IrInstructionSwitchBrCase *cases, bool is_inline)
|
||||
{
|
||||
IrInstructionSwitchBr *instruction = ir_build_instruction<IrInstructionSwitchBr>(irb, source_node);
|
||||
instruction->base.type_entry = irb->codegen->builtin_types.entry_unreachable;
|
||||
instruction->base.static_value.special = ConstValSpecialStatic;
|
||||
instruction->target_value = target_value;
|
||||
instruction->else_block = else_block;
|
||||
instruction->case_count = case_count;
|
||||
@ -1010,6 +1024,16 @@ static IrInstruction *ir_build_switch_br(IrBuilder *irb, AstNode *source_node, I
|
||||
return &instruction->base;
|
||||
}
|
||||
|
||||
static IrInstruction *ir_build_switch_br_from(IrBuilder *irb, IrInstruction *old_instruction,
|
||||
IrInstruction *target_value, IrBasicBlock *else_block, size_t case_count,
|
||||
IrInstructionSwitchBrCase *cases, bool is_inline)
|
||||
{
|
||||
IrInstruction *new_instruction = ir_build_switch_br(irb, old_instruction->source_node,
|
||||
target_value, else_block, case_count, cases, is_inline);
|
||||
ir_link_new_instruction(new_instruction, old_instruction);
|
||||
return new_instruction;
|
||||
}
|
||||
|
||||
static IrInstruction *ir_build_switch_target(IrBuilder *irb, AstNode *source_node,
|
||||
IrInstruction *target_value_ptr)
|
||||
{
|
||||
@ -1034,6 +1058,21 @@ static IrInstruction *ir_build_switch_var(IrBuilder *irb, AstNode *source_node,
|
||||
return &instruction->base;
|
||||
}
|
||||
|
||||
static IrInstruction *ir_build_enum_tag(IrBuilder *irb, AstNode *source_node, IrInstruction *value) {
|
||||
IrInstructionEnumTag *instruction = ir_build_instruction<IrInstructionEnumTag>(irb, source_node);
|
||||
instruction->value = value;
|
||||
|
||||
ir_ref_instruction(value);
|
||||
|
||||
return &instruction->base;
|
||||
}
|
||||
|
||||
static IrInstruction *ir_build_enum_tag_from(IrBuilder *irb, IrInstruction *old_instruction, IrInstruction *value) {
|
||||
IrInstruction *new_instruction = ir_build_enum_tag(irb, old_instruction->source_node, value);
|
||||
ir_link_new_instruction(new_instruction, old_instruction);
|
||||
return new_instruction;
|
||||
}
|
||||
|
||||
static void ir_gen_defers_for_block(IrBuilder *irb, BlockContext *inner_block, BlockContext *outer_block,
|
||||
bool gen_error_defers, bool gen_maybe_defers)
|
||||
{
|
||||
@ -2149,7 +2188,7 @@ static IrInstruction *ir_gen_if_var_expr(IrBuilder *irb, AstNode *node) {
|
||||
|
||||
static bool ir_gen_switch_prong_expr(IrBuilder *irb, AstNode *switch_node, AstNode *prong_node,
|
||||
IrBasicBlock *end_block, bool is_inline, IrInstruction *target_value_ptr, IrInstruction *prong_value,
|
||||
ZigList<IrBasicBlock *> incoming_blocks, ZigList<IrInstruction *> incoming_values)
|
||||
ZigList<IrBasicBlock *> *incoming_blocks, ZigList<IrInstruction *> *incoming_values)
|
||||
{
|
||||
assert(switch_node->type == NodeTypeSwitchExpr);
|
||||
assert(prong_node->type == NodeTypeSwitchProng);
|
||||
@ -2184,8 +2223,8 @@ static bool ir_gen_switch_prong_expr(IrBuilder *irb, AstNode *switch_node, AstNo
|
||||
if (expr_result == irb->codegen->invalid_instruction)
|
||||
return false;
|
||||
ir_build_br(irb, switch_node, end_block, is_inline);
|
||||
incoming_blocks.append(irb->current_basic_block);
|
||||
incoming_values.append(expr_result);
|
||||
incoming_blocks->append(irb->current_basic_block);
|
||||
incoming_values->append(expr_result);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -2222,11 +2261,14 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, AstNode *node) {
|
||||
}
|
||||
else_prong = prong_node;
|
||||
|
||||
IrBasicBlock *prev_block = irb->current_basic_block;
|
||||
ir_set_cursor_at_end(irb, else_block);
|
||||
if (!ir_gen_switch_prong_expr(irb, node, prong_node, end_block,
|
||||
is_inline, target_value_ptr, nullptr, incoming_blocks, incoming_values))
|
||||
is_inline, target_value_ptr, nullptr, &incoming_blocks, &incoming_values))
|
||||
{
|
||||
return irb->codegen->invalid_instruction;
|
||||
}
|
||||
ir_set_cursor_at_end(irb, prev_block);
|
||||
} else {
|
||||
if (prong_node->data.switch_prong.any_items_are_range) {
|
||||
IrInstruction *ok_bit = nullptr;
|
||||
@ -2235,6 +2277,7 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, AstNode *node) {
|
||||
AstNode *item_node = prong_node->data.switch_prong.items.at(item_i);
|
||||
last_item_node = item_node;
|
||||
if (item_node->type == NodeTypeSwitchRange) {
|
||||
item_node->block_context = node->block_context;
|
||||
AstNode *start_node = item_node->data.switch_range.start;
|
||||
AstNode *end_node = item_node->data.switch_range.end;
|
||||
|
||||
@ -2252,7 +2295,7 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, AstNode *node) {
|
||||
IrInstruction *both_ok = ir_build_bin_op(irb, item_node, IrBinOpBoolAnd,
|
||||
lower_range_ok, upper_range_ok);
|
||||
if (ok_bit) {
|
||||
ok_bit = ir_build_bin_op(irb, item_node, IrBinOpBoolAnd, both_ok, ok_bit);
|
||||
ok_bit = ir_build_bin_op(irb, item_node, IrBinOpBoolOr, both_ok, ok_bit);
|
||||
} else {
|
||||
ok_bit = both_ok;
|
||||
}
|
||||
@ -2264,7 +2307,7 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, AstNode *node) {
|
||||
IrInstruction *cmp_ok = ir_build_bin_op(irb, item_node, IrBinOpCmpEq,
|
||||
item_value, target_value);
|
||||
if (ok_bit) {
|
||||
ok_bit = ir_build_bin_op(irb, item_node, IrBinOpBoolAnd, cmp_ok, ok_bit);
|
||||
ok_bit = ir_build_bin_op(irb, item_node, IrBinOpBoolOr, cmp_ok, ok_bit);
|
||||
} else {
|
||||
ok_bit = cmp_ok;
|
||||
}
|
||||
@ -2280,13 +2323,16 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, AstNode *node) {
|
||||
|
||||
ir_set_cursor_at_end(irb, range_block_yes);
|
||||
if (!ir_gen_switch_prong_expr(irb, node, prong_node, end_block,
|
||||
is_inline, target_value_ptr, nullptr, incoming_blocks, incoming_values))
|
||||
is_inline, target_value_ptr, nullptr, &incoming_blocks, &incoming_values))
|
||||
{
|
||||
return irb->codegen->invalid_instruction;
|
||||
}
|
||||
|
||||
ir_set_cursor_at_end(irb, range_block_no);
|
||||
} else {
|
||||
IrBasicBlock *prong_block = ir_build_basic_block(irb, "SwitchProng");
|
||||
IrInstruction *last_item_value = nullptr;
|
||||
|
||||
for (size_t item_i = 0; item_i < prong_item_count; item_i += 1) {
|
||||
AstNode *item_node = prong_node->data.switch_prong.items.at(item_i);
|
||||
assert(item_node->type != NodeTypeSwitchRange);
|
||||
@ -2295,22 +2341,24 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, AstNode *node) {
|
||||
if (item_value == irb->codegen->invalid_instruction)
|
||||
return irb->codegen->invalid_instruction;
|
||||
|
||||
IrBasicBlock *prong_block = ir_build_basic_block(irb, "SwitchProng");
|
||||
IrBasicBlock *prev_block = irb->current_basic_block;
|
||||
ir_set_cursor_at_end(irb, prong_block);
|
||||
|
||||
if (!ir_gen_switch_prong_expr(irb, node, prong_node, end_block,
|
||||
is_inline, target_value_ptr, item_value, incoming_blocks, incoming_values))
|
||||
{
|
||||
return irb->codegen->invalid_instruction;
|
||||
}
|
||||
|
||||
IrInstructionSwitchBrCase *this_case = cases.add_one();
|
||||
this_case->value = item_value;
|
||||
this_case->block = prong_block;
|
||||
|
||||
ir_set_cursor_at_end(irb, prev_block);
|
||||
last_item_value = item_value;
|
||||
}
|
||||
IrInstruction *only_item_value = (prong_item_count == 1) ? last_item_value : nullptr;
|
||||
|
||||
IrBasicBlock *prev_block = irb->current_basic_block;
|
||||
ir_set_cursor_at_end(irb, prong_block);
|
||||
if (!ir_gen_switch_prong_expr(irb, node, prong_node, end_block,
|
||||
is_inline, target_value_ptr, only_item_value, &incoming_blocks, &incoming_values))
|
||||
{
|
||||
return irb->codegen->invalid_instruction;
|
||||
}
|
||||
|
||||
ir_set_cursor_at_end(irb, prev_block);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2712,26 +2760,47 @@ static IrBasicBlock *ir_get_new_bb(IrAnalyze *ira, IrBasicBlock *old_bb) {
|
||||
if (old_bb->other)
|
||||
return old_bb->other;
|
||||
IrBasicBlock *new_bb = ir_build_bb_from(&ira->new_irb, old_bb);
|
||||
|
||||
// We are about to enqueue old_bb for analysis. Before we do so, check old_bb
|
||||
// for phi instructions. Any incoming blocks in the phi instructions need to be
|
||||
// queued first.
|
||||
for (size_t instr_i = 0; instr_i < old_bb->instruction_list.length; instr_i += 1) {
|
||||
IrInstruction *instruction = old_bb->instruction_list.at(instr_i);
|
||||
if (instruction->id != IrInstructionIdPhi)
|
||||
break;
|
||||
IrInstructionPhi *phi_instruction = (IrInstructionPhi *)instruction;
|
||||
for (size_t incoming_i = 0; incoming_i < phi_instruction->incoming_count; incoming_i += 1) {
|
||||
IrBasicBlock *predecessor = phi_instruction->incoming_blocks[incoming_i];
|
||||
ir_get_new_bb(ira, predecessor);
|
||||
}
|
||||
}
|
||||
ira->old_bb_queue.append(old_bb);
|
||||
|
||||
return new_bb;
|
||||
}
|
||||
|
||||
static void ir_start_bb(IrAnalyze *ira, IrBasicBlock *old_bb, IrBasicBlock *const_predecessor_bb) {
|
||||
ira->instruction_index = 0;
|
||||
ira->old_irb.current_basic_block = old_bb;
|
||||
ira->const_predecessor_bb = const_predecessor_bb;
|
||||
|
||||
assert(old_bb->other);
|
||||
ira->new_irb.exec->basic_block_list.append(old_bb->other);
|
||||
}
|
||||
|
||||
static void ir_finish_bb(IrAnalyze *ira) {
|
||||
ira->block_queue_index += 1;
|
||||
|
||||
if (ira->block_queue_index < ira->old_bb_queue.length) {
|
||||
IrBasicBlock *old_bb = ira->old_bb_queue.at(ira->block_queue_index);
|
||||
ira->instruction_index = 0;
|
||||
ira->new_irb.current_basic_block = ir_get_new_bb(ira, old_bb);
|
||||
ira->old_irb.current_basic_block = old_bb;
|
||||
ira->const_predecessor_bb = nullptr;
|
||||
|
||||
ir_start_bb(ira, old_bb, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
static void ir_inline_bb(IrAnalyze *ira, IrBasicBlock *old_bb) {
|
||||
ira->instruction_index = 0;
|
||||
ira->const_predecessor_bb = ira->old_irb.current_basic_block;
|
||||
ira->old_irb.current_basic_block = old_bb;
|
||||
ir_start_bb(ira, old_bb, ira->old_irb.current_basic_block);
|
||||
}
|
||||
|
||||
static TypeTableEntry *ir_finish_anal(IrAnalyze *ira, TypeTableEntry *result_type) {
|
||||
@ -3603,6 +3672,8 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc
|
||||
return explicit_type;
|
||||
}
|
||||
|
||||
AstNode *source_node = decl_var_instruction->base.source_node;
|
||||
|
||||
IrInstruction *casted_init_value = ir_get_casted_value(ira, init_value, explicit_type);
|
||||
TypeTableEntry *result_type = get_underlying_type(casted_init_value->type_entry);
|
||||
switch (result_type->id) {
|
||||
@ -3614,7 +3685,7 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc
|
||||
case TypeTableEntryIdNumLitFloat:
|
||||
case TypeTableEntryIdNumLitInt:
|
||||
if (is_export || is_extern || casted_init_value->static_value.special == ConstValSpecialRuntime) {
|
||||
add_node_error(ira->codegen, var_type->source_node, buf_sprintf("unable to infer variable type"));
|
||||
add_node_error(ira->codegen, source_node, buf_sprintf("unable to infer variable type"));
|
||||
result_type = ira->codegen->builtin_types.entry_invalid;
|
||||
}
|
||||
break;
|
||||
@ -3622,14 +3693,14 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc
|
||||
case TypeTableEntryIdVar:
|
||||
case TypeTableEntryIdBlock:
|
||||
case TypeTableEntryIdNullLit:
|
||||
add_node_error(ira->codegen, var_type->source_node,
|
||||
add_node_error(ira->codegen, source_node,
|
||||
buf_sprintf("variable of type '%s' not allowed", buf_ptr(&result_type->name)));
|
||||
result_type = ira->codegen->builtin_types.entry_invalid;
|
||||
break;
|
||||
case TypeTableEntryIdMetaType:
|
||||
case TypeTableEntryIdNamespace:
|
||||
if (casted_init_value->static_value.special == ConstValSpecialRuntime) {
|
||||
add_node_error(ira->codegen, var_type->source_node,
|
||||
add_node_error(ira->codegen, source_node,
|
||||
buf_sprintf("variable of type '%s' must be constant", buf_ptr(&result_type->name)));
|
||||
result_type = ira->codegen->builtin_types.entry_invalid;
|
||||
}
|
||||
@ -4072,6 +4143,8 @@ static TypeTableEntry *ir_analyze_instruction_br(IrAnalyze *ira, IrInstructionBr
|
||||
|
||||
static TypeTableEntry *ir_analyze_instruction_cond_br(IrAnalyze *ira, IrInstructionCondBr *cond_br_instruction) {
|
||||
IrInstruction *condition = cond_br_instruction->condition->other;
|
||||
if (condition->type_entry->id == TypeTableEntryIdInvalid)
|
||||
return ir_finish_anal(ira, ira->codegen->builtin_types.entry_unreachable);
|
||||
|
||||
// TODO detect backward jumps
|
||||
|
||||
@ -4116,6 +4189,9 @@ static TypeTableEntry *ir_analyze_instruction_phi(IrAnalyze *ira, IrInstructionP
|
||||
continue;
|
||||
IrInstruction *value = phi_instruction->incoming_values[i]->other;
|
||||
assert(value->type_entry);
|
||||
if (value->type_entry->id == TypeTableEntryIdInvalid)
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
|
||||
if (value->static_value.special != ConstValSpecialRuntime) {
|
||||
ConstExprValue *out_val = ir_build_const_from(ira, &phi_instruction->base,
|
||||
value->static_value.depends_on_compile_var);
|
||||
@ -4141,7 +4217,10 @@ static TypeTableEntry *ir_analyze_instruction_phi(IrAnalyze *ira, IrInstructionP
|
||||
|
||||
IrInstruction *old_value = phi_instruction->incoming_values[i];
|
||||
assert(old_value);
|
||||
new_incoming_values.append(old_value->other);
|
||||
IrInstruction *new_value = old_value->other;
|
||||
if (new_value->type_entry->id == TypeTableEntryIdInvalid)
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
new_incoming_values.append(new_value);
|
||||
}
|
||||
assert(new_incoming_blocks.length != 0);
|
||||
|
||||
@ -4156,6 +4235,21 @@ static TypeTableEntry *ir_analyze_instruction_phi(IrAnalyze *ira, IrInstructionP
|
||||
if (resolved_type->id == TypeTableEntryIdInvalid)
|
||||
return resolved_type;
|
||||
|
||||
if (resolved_type->id == TypeTableEntryIdNumLitFloat ||
|
||||
resolved_type->id == TypeTableEntryIdNumLitInt)
|
||||
{
|
||||
add_node_error(ira->codegen, phi_instruction->base.source_node,
|
||||
buf_sprintf("unable to infer expression type"));
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
}
|
||||
|
||||
// cast all literal values to the resolved type
|
||||
for (size_t i = 0; i < new_incoming_values.length; i += 1) {
|
||||
IrInstruction *new_value = new_incoming_values.at(i);
|
||||
IrInstruction *casted_value = ir_get_casted_value(ira, new_value, resolved_type);
|
||||
new_incoming_values.items[i] = casted_value;
|
||||
}
|
||||
|
||||
ir_build_phi_from(&ira->new_irb, &phi_instruction->base, new_incoming_blocks.length,
|
||||
new_incoming_blocks.items, new_incoming_values.items);
|
||||
return resolved_type;
|
||||
@ -5114,13 +5208,123 @@ static TypeTableEntry *ir_analyze_instruction_clz(IrAnalyze *ira, IrInstructionC
|
||||
static TypeTableEntry *ir_analyze_instruction_switch_br(IrAnalyze *ira,
|
||||
IrInstructionSwitchBr *switch_br_instruction)
|
||||
{
|
||||
zig_panic("TODO switch br analyze");
|
||||
IrInstruction *target_value = switch_br_instruction->target_value->other;
|
||||
if (target_value->type_entry->id == TypeTableEntryIdInvalid)
|
||||
return ir_finish_anal(ira, ira->codegen->builtin_types.entry_unreachable);
|
||||
|
||||
// TODO detect backward jumps
|
||||
|
||||
size_t case_count = switch_br_instruction->case_count;
|
||||
bool is_inline = switch_br_instruction->is_inline;
|
||||
|
||||
if (is_inline || target_value->static_value.special != ConstValSpecialRuntime) {
|
||||
zig_panic("TODO compile time switch br");
|
||||
}
|
||||
|
||||
IrInstructionSwitchBrCase *cases = allocate<IrInstructionSwitchBrCase>(case_count);
|
||||
for (size_t i = 0; i < case_count; i += 1) {
|
||||
IrInstructionSwitchBrCase *old_case = &switch_br_instruction->cases[i];
|
||||
IrInstructionSwitchBrCase *new_case = &cases[i];
|
||||
new_case->block = ir_get_new_bb(ira, old_case->block);
|
||||
new_case->value = ira->codegen->invalid_instruction;
|
||||
|
||||
IrInstruction *old_value = old_case->value;
|
||||
IrInstruction *new_value = old_value->other;
|
||||
if (new_value->type_entry->id == TypeTableEntryIdInvalid)
|
||||
continue;
|
||||
|
||||
IrInstruction *casted_new_value = ir_get_casted_value(ira, new_value, target_value->type_entry);
|
||||
if (casted_new_value->type_entry->id == TypeTableEntryIdInvalid)
|
||||
continue;
|
||||
|
||||
if (casted_new_value->static_value.special != ConstValSpecialStatic) {
|
||||
add_node_error(ira->codegen, casted_new_value->source_node,
|
||||
buf_sprintf("unable to evaluate constant expression"));
|
||||
continue;
|
||||
}
|
||||
|
||||
new_case->value = casted_new_value;
|
||||
}
|
||||
|
||||
IrBasicBlock *new_else_block = ir_get_new_bb(ira, switch_br_instruction->else_block);
|
||||
ir_build_switch_br_from(&ira->new_irb, &switch_br_instruction->base,
|
||||
target_value, new_else_block, case_count, cases, is_inline);
|
||||
return ir_finish_anal(ira, ira->codegen->builtin_types.entry_unreachable);
|
||||
}
|
||||
|
||||
static TypeTableEntry *ir_analyze_instruction_switch_target(IrAnalyze *ira,
|
||||
IrInstructionSwitchTarget *switch_target_instruction)
|
||||
{
|
||||
zig_panic("TODO switch target analyze");
|
||||
IrInstruction *target_value_ptr = switch_target_instruction->target_value_ptr->other;
|
||||
if (target_value_ptr->type_entry->id == TypeTableEntryIdInvalid)
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
|
||||
assert(target_value_ptr->type_entry->id == TypeTableEntryIdPointer);
|
||||
TypeTableEntry *target_type = target_value_ptr->type_entry->data.pointer.child_type;
|
||||
bool depends_on_compile_var = target_value_ptr->static_value.depends_on_compile_var;
|
||||
ConstExprValue *pointee_val = nullptr;
|
||||
if (target_value_ptr->static_value.special != ConstValSpecialRuntime) {
|
||||
pointee_val = const_ptr_pointee(&target_value_ptr->static_value);
|
||||
if (pointee_val->special == ConstValSpecialRuntime)
|
||||
pointee_val = nullptr;
|
||||
}
|
||||
TypeTableEntry *canon_target_type = get_underlying_type(target_type);
|
||||
switch (canon_target_type->id) {
|
||||
case TypeTableEntryIdInvalid:
|
||||
case TypeTableEntryIdVar:
|
||||
case TypeTableEntryIdTypeDecl:
|
||||
zig_unreachable();
|
||||
case TypeTableEntryIdMetaType:
|
||||
case TypeTableEntryIdVoid:
|
||||
case TypeTableEntryIdBool:
|
||||
case TypeTableEntryIdInt:
|
||||
case TypeTableEntryIdFloat:
|
||||
case TypeTableEntryIdNumLitFloat:
|
||||
case TypeTableEntryIdNumLitInt:
|
||||
case TypeTableEntryIdPointer:
|
||||
case TypeTableEntryIdFn:
|
||||
case TypeTableEntryIdNamespace:
|
||||
case TypeTableEntryIdPureError:
|
||||
if (pointee_val) {
|
||||
ConstExprValue *out_val = ir_build_const_from(ira, &switch_target_instruction->base,
|
||||
depends_on_compile_var);
|
||||
*out_val = *pointee_val;
|
||||
return target_type;
|
||||
}
|
||||
|
||||
ir_build_load_ptr_from(&ira->new_irb, &switch_target_instruction->base, target_value_ptr);
|
||||
return target_type;
|
||||
case TypeTableEntryIdEnum:
|
||||
{
|
||||
TypeTableEntry *tag_type = target_type->data.enumeration.tag_type;
|
||||
if (pointee_val) {
|
||||
ConstExprValue *out_val = ir_build_const_from(ira, &switch_target_instruction->base,
|
||||
depends_on_compile_var);
|
||||
bignum_init_unsigned(&out_val->data.x_bignum, pointee_val->data.x_enum.tag);
|
||||
return tag_type;
|
||||
}
|
||||
|
||||
ir_build_enum_tag_from(&ira->new_irb, &switch_target_instruction->base, target_value_ptr);
|
||||
return tag_type;
|
||||
}
|
||||
case TypeTableEntryIdErrorUnion:
|
||||
// see https://github.com/andrewrk/zig/issues/83
|
||||
zig_panic("TODO switch on error union");
|
||||
case TypeTableEntryIdUnreachable:
|
||||
case TypeTableEntryIdArray:
|
||||
case TypeTableEntryIdStruct:
|
||||
case TypeTableEntryIdUndefLit:
|
||||
case TypeTableEntryIdNullLit:
|
||||
case TypeTableEntryIdMaybe:
|
||||
case TypeTableEntryIdUnion:
|
||||
case TypeTableEntryIdBlock:
|
||||
case TypeTableEntryIdGenericFn:
|
||||
add_node_error(ira->codegen, switch_target_instruction->base.source_node,
|
||||
buf_sprintf("invalid switch target type '%s'", buf_ptr(&target_type->name)));
|
||||
// TODO if this is a typedecl, add error note showing the declaration of the type decl
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
static TypeTableEntry *ir_analyze_instruction_switch_var(IrAnalyze *ira,
|
||||
@ -5129,6 +5333,12 @@ static TypeTableEntry *ir_analyze_instruction_switch_var(IrAnalyze *ira,
|
||||
zig_panic("TODO switch var analyze");
|
||||
}
|
||||
|
||||
static TypeTableEntry *ir_analyze_instruction_enum_tag(IrAnalyze *ira,
|
||||
IrInstructionEnumTag *enum_tag_instruction)
|
||||
{
|
||||
zig_panic("TODO ir_analyze_instruction_enum_tag");
|
||||
}
|
||||
|
||||
static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {
|
||||
switch (instruction->id) {
|
||||
case IrInstructionIdInvalid:
|
||||
@ -5201,6 +5411,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
|
||||
return ir_analyze_instruction_switch_target(ira, (IrInstructionSwitchTarget *)instruction);
|
||||
case IrInstructionIdSwitchVar:
|
||||
return ir_analyze_instruction_switch_var(ira, (IrInstructionSwitchVar *)instruction);
|
||||
case IrInstructionIdEnumTag:
|
||||
return ir_analyze_instruction_enum_tag(ira, (IrInstructionEnumTag *)instruction);
|
||||
case IrInstructionIdCast:
|
||||
case IrInstructionIdContainerInitList:
|
||||
case IrInstructionIdContainerInitFields:
|
||||
@ -5247,10 +5459,10 @@ TypeTableEntry *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutabl
|
||||
IrBasicBlock *old_entry_bb = ira->old_irb.exec->basic_block_list.at(0);
|
||||
IrBasicBlock *new_entry_bb = ir_get_new_bb(ira, old_entry_bb);
|
||||
ir_ref_bb(new_entry_bb);
|
||||
ira->old_irb.current_basic_block = old_entry_bb;
|
||||
ira->new_irb.current_basic_block = new_entry_bb;
|
||||
ira->block_queue_index = 0;
|
||||
ira->instruction_index = 0;
|
||||
|
||||
ir_start_bb(ira, old_entry_bb, nullptr);
|
||||
|
||||
while (ira->block_queue_index < ira->old_bb_queue.length) {
|
||||
IrInstruction *old_instruction = ira->old_irb.current_basic_block->instruction_list.at(ira->instruction_index);
|
||||
@ -5319,6 +5531,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
|
||||
case IrInstructionIdCtz:
|
||||
case IrInstructionIdSwitchVar:
|
||||
case IrInstructionIdSwitchTarget:
|
||||
case IrInstructionIdEnumTag:
|
||||
return false;
|
||||
case IrInstructionIdAsm:
|
||||
{
|
||||
|
||||
@ -313,6 +313,8 @@ static void ir_print_br(IrPrint *irp, IrInstructionBr *br_instruction) {
|
||||
}
|
||||
|
||||
static void ir_print_phi(IrPrint *irp, IrInstructionPhi *phi_instruction) {
|
||||
assert(phi_instruction->incoming_count != 0);
|
||||
assert(phi_instruction->incoming_count != SIZE_MAX);
|
||||
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];
|
||||
@ -534,6 +536,39 @@ static void ir_print_ctz(IrPrint *irp, IrInstructionCtz *instruction) {
|
||||
fprintf(irp->f, ")");
|
||||
}
|
||||
|
||||
static void ir_print_switch_br(IrPrint *irp, IrInstructionSwitchBr *instruction) {
|
||||
const char *inline_kw = instruction->is_inline ? "inline " : "";
|
||||
fprintf(irp->f, "%sswitch (", inline_kw);
|
||||
ir_print_other_instruction(irp, instruction->target_value);
|
||||
fprintf(irp->f, ") ");
|
||||
for (size_t i = 0; i < instruction->case_count; i += 1) {
|
||||
IrInstructionSwitchBrCase *this_case = &instruction->cases[i];
|
||||
ir_print_other_instruction(irp, this_case->value);
|
||||
fprintf(irp->f, " => ");
|
||||
ir_print_other_block(irp, this_case->block);
|
||||
fprintf(irp->f, ", ");
|
||||
}
|
||||
fprintf(irp->f, "else => ");
|
||||
ir_print_other_block(irp, instruction->else_block);
|
||||
}
|
||||
|
||||
static void ir_print_switch_var(IrPrint *irp, IrInstructionSwitchVar *instruction) {
|
||||
fprintf(irp->f, "switchvar ");
|
||||
ir_print_other_instruction(irp, instruction->target_value_ptr);
|
||||
fprintf(irp->f, ", ");
|
||||
ir_print_other_instruction(irp, instruction->prong_value);
|
||||
}
|
||||
|
||||
static void ir_print_switch_target(IrPrint *irp, IrInstructionSwitchTarget *instruction) {
|
||||
fprintf(irp->f, "switchtarget ");
|
||||
ir_print_other_instruction(irp, instruction->target_value_ptr);
|
||||
}
|
||||
|
||||
static void ir_print_enum_tag(IrPrint *irp, IrInstructionEnumTag *instruction) {
|
||||
fprintf(irp->f, "enumtag ");
|
||||
ir_print_other_instruction(irp, instruction->value);
|
||||
}
|
||||
|
||||
static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
|
||||
ir_print_prefix(irp, instruction);
|
||||
switch (instruction->id) {
|
||||
@ -645,9 +680,17 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
|
||||
ir_print_clz(irp, (IrInstructionClz *)instruction);
|
||||
break;
|
||||
case IrInstructionIdSwitchBr:
|
||||
ir_print_switch_br(irp, (IrInstructionSwitchBr *)instruction);
|
||||
break;
|
||||
case IrInstructionIdSwitchVar:
|
||||
ir_print_switch_var(irp, (IrInstructionSwitchVar *)instruction);
|
||||
break;
|
||||
case IrInstructionIdSwitchTarget:
|
||||
zig_panic("TODO print more IR instructions");
|
||||
ir_print_switch_target(irp, (IrInstructionSwitchTarget *)instruction);
|
||||
break;
|
||||
case IrInstructionIdEnumTag:
|
||||
ir_print_enum_tag(irp, (IrInstructionEnumTag *)instruction);
|
||||
break;
|
||||
}
|
||||
fprintf(irp->f, "\n");
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user