authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-12-11 19:43:06-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-12-11 19:43:06-05:00
logfb2157063060682a314cb8f2e34efc7989646455
tree2fb7f3c638d82a6816720d1e0cf04f6373fc9191
parenta963fba246819e8b71777db157ad9578086ea16e

IR: implement alloca builtin


5 files changed, 166 insertions(+), 115 deletions(-)

doc/langref.md+13
...@@ -370,6 +370,19 @@ TODO...@@ -370,6 +370,19 @@ TODO
370Built-in functions are prefixed with `@`. Remember that the `inline` keyword on370Built-in functions are prefixed with `@`. Remember that the `inline` keyword on
371a parameter means that the parameter must be known at compile time.371a parameter means that the parameter must be known at compile time.
372372
373### @alloca(inline T: type, count: usize) -> []T
374
375Allocates memory in the stack frame of the caller. This temporary space is
376automatically freed when the function that called alloca returns to its caller,
377just like other stack variables.
378
379When using this function to allocate memory, you should know the upper bound
380of `count`. Consider putting a constant array on the stack with the upper bound
381instead of using alloca. If you do use alloca it is to save a few bytes off
382the memory size given that you didn't actually hit your upper bound.
383
384The allocated memory contents are undefined.
385
373### @typeof(expression) -> type386### @typeof(expression) -> type
374387
375This function returns a compile-time constant, which is the type of the388This function returns a compile-time constant, which is the type of the
src/all_types.hpp+10
...@@ -1044,6 +1044,7 @@ enum BuiltinFnId {...@@ -1044,6 +1044,7 @@ enum BuiltinFnId {
1044 BuiltinFnIdSetFnTest,1044 BuiltinFnIdSetFnTest,
1045 BuiltinFnIdSetFnVisible,1045 BuiltinFnIdSetFnVisible,
1046 BuiltinFnIdSetDebugSafety,1046 BuiltinFnIdSetDebugSafety,
1047 BuiltinFnIdAlloca,
1047};1048};
10481049
1049struct BuiltinFnEntry {1050struct BuiltinFnEntry {
...@@ -1413,6 +1414,7 @@ enum IrInstructionId {...@@ -1413,6 +1414,7 @@ enum IrInstructionId {
1413 IrInstructionIdTruncate,1414 IrInstructionIdTruncate,
1414 IrInstructionIdIntType,1415 IrInstructionIdIntType,
1415 IrInstructionIdBoolNot,1416 IrInstructionIdBoolNot,
1417 IrInstructionIdAlloca,
1416};1418};
14171419
1418struct IrInstruction {1420struct IrInstruction {
...@@ -1914,6 +1916,14 @@ struct IrInstructionBoolNot {...@@ -1914,6 +1916,14 @@ struct IrInstructionBoolNot {
1914 IrInstruction *value;1916 IrInstruction *value;
1915};1917};
19161918
1919struct IrInstructionAlloca {
1920 IrInstruction base;
1921
1922 IrInstruction *type_value;
1923 IrInstruction *count;
1924 LLVMValueRef tmp_ptr;
1925};
1926
1917enum LValPurpose {1927enum LValPurpose {
1918 LValPurposeNone,1928 LValPurposeNone,
1919 LValPurposeAssign,1929 LValPurposeAssign,
src/codegen.cpp+27-3
...@@ -1881,13 +1881,31 @@ static LLVMValueRef ir_render_div_exact(CodeGen *g, IrExecutable *executable, Ir...@@ -1881,13 +1881,31 @@ static LLVMValueRef ir_render_div_exact(CodeGen *g, IrExecutable *executable, Ir
1881}1881}
18821882
1883static LLVMValueRef ir_render_truncate(CodeGen *g, IrExecutable *executable, IrInstructionTruncate *instruction) {1883static LLVMValueRef ir_render_truncate(CodeGen *g, IrExecutable *executable, IrInstructionTruncate *instruction) {
1884 assert(instruction->dest_type->type_entry->id == TypeTableEntryIdMetaType);1884 TypeTableEntry *dest_type = get_underlying_type(instruction->base.type_entry);
1885 TypeTableEntry *dest_type = get_underlying_type(instruction->dest_type->static_value.data.x_type);
1886 assert(dest_type->id == TypeTableEntryIdInt);
1887 LLVMValueRef target_val = ir_llvm_value(g, instruction->target);1885 LLVMValueRef target_val = ir_llvm_value(g, instruction->target);
1888 return LLVMBuildTrunc(g->builder, target_val, dest_type->type_ref, "");1886 return LLVMBuildTrunc(g->builder, target_val, dest_type->type_ref, "");
1889}1887}
18901888
1889static LLVMValueRef ir_render_alloca(CodeGen *g, IrExecutable *executable, IrInstructionAlloca *instruction) {
1890 TypeTableEntry *slice_type = get_underlying_type(instruction->base.type_entry);
1891 TypeTableEntry *ptr_type = slice_type->data.structure.fields[slice_ptr_index].type_entry;
1892 TypeTableEntry *child_type = ptr_type->data.pointer.child_type;
1893 LLVMValueRef size_val = ir_llvm_value(g, instruction->count);
1894 LLVMValueRef ptr_val = LLVMBuildArrayAlloca(g->builder, child_type->type_ref, size_val, "");
1895
1896 // TODO in debug mode, initialize all the bytes to 0xaa
1897
1898 // store the freshly allocated pointer in the slice
1899 LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, slice_ptr_index, "");
1900 LLVMBuildStore(g->builder, ptr_val, ptr_field_ptr);
1901
1902 // store the size in the len field
1903 LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, slice_len_index, "");
1904 LLVMBuildStore(g->builder, size_val, len_field_ptr);
1905
1906 return instruction->tmp_ptr;
1907}
1908
1891static void set_debug_location(CodeGen *g, IrInstruction *instruction) {1909static void set_debug_location(CodeGen *g, IrInstruction *instruction) {
1892 AstNode *source_node = instruction->source_node;1910 AstNode *source_node = instruction->source_node;
1893 Scope *scope = instruction->scope;1911 Scope *scope = instruction->scope;
...@@ -1988,6 +2006,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,...@@ -1988,6 +2006,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
1988 return ir_render_truncate(g, executable, (IrInstructionTruncate *)instruction);2006 return ir_render_truncate(g, executable, (IrInstructionTruncate *)instruction);
1989 case IrInstructionIdBoolNot:2007 case IrInstructionIdBoolNot:
1990 return ir_render_bool_not(g, executable, (IrInstructionBoolNot *)instruction);2008 return ir_render_bool_not(g, executable, (IrInstructionBoolNot *)instruction);
2009 case IrInstructionIdAlloca:
2010 return ir_render_alloca(g, executable, (IrInstructionAlloca *)instruction);
1991 case IrInstructionIdSwitchVar:2011 case IrInstructionIdSwitchVar:
1992 case IrInstructionIdContainerInitList:2012 case IrInstructionIdContainerInitList:
1993 case IrInstructionIdStructInit:2013 case IrInstructionIdStructInit:
...@@ -2567,6 +2587,9 @@ static void do_code_gen(CodeGen *g) {...@@ -2567,6 +2587,9 @@ static void do_code_gen(CodeGen *g) {
2567 } else if (instruction->id == IrInstructionIdCall) {2587 } else if (instruction->id == IrInstructionIdCall) {
2568 IrInstructionCall *call_instruction = (IrInstructionCall *)instruction;2588 IrInstructionCall *call_instruction = (IrInstructionCall *)instruction;
2569 slot = &call_instruction->tmp_ptr;2589 slot = &call_instruction->tmp_ptr;
2590 } else if (instruction->id == IrInstructionIdAlloca) {
2591 IrInstructionAlloca *alloca_instruction = (IrInstructionAlloca *)instruction;
2592 slot = &alloca_instruction->tmp_ptr;
2570 } else {2593 } else {
2571 zig_unreachable();2594 zig_unreachable();
2572 }2595 }
...@@ -3191,6 +3214,7 @@ static void define_builtin_fns(CodeGen *g) {...@@ -3191,6 +3214,7 @@ static void define_builtin_fns(CodeGen *g) {
3191 create_builtin_fn(g, BuiltinFnIdSetFnTest, "setFnTest", 1);3214 create_builtin_fn(g, BuiltinFnIdSetFnTest, "setFnTest", 1);
3192 create_builtin_fn(g, BuiltinFnIdSetFnVisible, "setFnVisible", 2);3215 create_builtin_fn(g, BuiltinFnIdSetFnVisible, "setFnVisible", 2);
3193 create_builtin_fn(g, BuiltinFnIdSetDebugSafety, "setDebugSafety", 2);3216 create_builtin_fn(g, BuiltinFnIdSetDebugSafety, "setDebugSafety", 2);
3217 create_builtin_fn(g, BuiltinFnIdAlloca, "alloca", 2);
3194}3218}
31953219
3196static void init(CodeGen *g, Buf *source_path) {3220static void init(CodeGen *g, Buf *source_path) {
src/ir.cpp+105-112
...@@ -371,6 +371,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionBoolNot *) {...@@ -371,6 +371,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionBoolNot *) {
371 return IrInstructionIdBoolNot;371 return IrInstructionIdBoolNot;
372}372}
373373
374static constexpr IrInstructionId ir_instruction_id(IrInstructionAlloca *) {
375 return IrInstructionIdAlloca;
376}
377
374template<typename T>378template<typename T>
375static T *ir_create_instruction(IrExecutable *exec, Scope *scope, AstNode *source_node) {379static T *ir_create_instruction(IrExecutable *exec, Scope *scope, AstNode *source_node) {
376 T *special_instruction = allocate<T>(1);380 T *special_instruction = allocate<T>(1);
...@@ -1489,6 +1493,27 @@ static IrInstruction *ir_build_bool_not_from(IrBuilder *irb, IrInstruction *old_...@@ -1489,6 +1493,27 @@ static IrInstruction *ir_build_bool_not_from(IrBuilder *irb, IrInstruction *old_
1489 return new_instruction;1493 return new_instruction;
1490}1494}
14911495
1496static IrInstruction *ir_build_alloca(IrBuilder *irb, Scope *scope, AstNode *source_node,
1497 IrInstruction *type_value, IrInstruction *count)
1498{
1499 IrInstructionAlloca *instruction = ir_build_instruction<IrInstructionAlloca>(irb, scope, source_node);
1500 instruction->type_value = type_value;
1501 instruction->count = count;
1502
1503 ir_ref_instruction(type_value);
1504 ir_ref_instruction(count);
1505
1506 return &instruction->base;
1507}
1508
1509static IrInstruction *ir_build_alloca_from(IrBuilder *irb, IrInstruction *old_instruction,
1510 IrInstruction *type_value, IrInstruction *count)
1511{
1512 IrInstruction *new_instruction = ir_build_alloca(irb, old_instruction->scope, old_instruction->source_node, type_value, count);
1513 ir_link_new_instruction(new_instruction, old_instruction);
1514 return new_instruction;
1515}
1516
1492static void ir_gen_defers_for_block(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope,1517static void ir_gen_defers_for_block(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope,
1493 bool gen_error_defers, bool gen_maybe_defers)1518 bool gen_error_defers, bool gen_maybe_defers)
1494{1519{
...@@ -2310,6 +2335,20 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo...@@ -2310,6 +2335,20 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
23102335
2311 return ir_build_int_type(irb, scope, node, arg0_value, arg1_value);2336 return ir_build_int_type(irb, scope, node, arg0_value, arg1_value);
2312 }2337 }
2338 case BuiltinFnIdAlloca:
2339 {
2340 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
2341 IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
2342 if (arg0_value == irb->codegen->invalid_instruction)
2343 return arg0_value;
2344
2345 AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
2346 IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
2347 if (arg1_value == irb->codegen->invalid_instruction)
2348 return arg1_value;
2349
2350 return ir_build_alloca(irb, scope, node, arg0_value, arg1_value);
2351 }
2313 case BuiltinFnIdMemcpy:2352 case BuiltinFnIdMemcpy:
2314 case BuiltinFnIdMemset:2353 case BuiltinFnIdMemset:
2315 case BuiltinFnIdAlignof:2354 case BuiltinFnIdAlignof:
...@@ -7876,6 +7915,69 @@ static TypeTableEntry *ir_analyze_instruction_bool_not(IrAnalyze *ira, IrInstruc...@@ -7876,6 +7915,69 @@ static TypeTableEntry *ir_analyze_instruction_bool_not(IrAnalyze *ira, IrInstruc
7876 return bool_type;7915 return bool_type;
7877}7916}
78787917
7918static TypeTableEntry *ir_analyze_instruction_alloca(IrAnalyze *ira, IrInstructionAlloca *instruction) {
7919 IrInstruction *type_value = instruction->type_value->other;
7920 if (type_value->type_entry->id == TypeTableEntryIdInvalid)
7921 return ira->codegen->builtin_types.entry_invalid;
7922
7923 IrInstruction *count_value = instruction->count->other;
7924 if (count_value->type_entry->id == TypeTableEntryIdInvalid)
7925 return ira->codegen->builtin_types.entry_invalid;
7926
7927 TypeTableEntry *child_type = ir_resolve_type(ira, type_value);
7928 TypeTableEntry *canon_type = get_underlying_type(child_type);
7929
7930 if (count_value->static_value.special == ConstValSpecialStatic) {
7931 // this should be the same as an array declaration
7932
7933 uint64_t count;
7934 if (!ir_resolve_usize(ira, count_value, &count))
7935 return ira->codegen->builtin_types.entry_invalid;
7936
7937 zig_panic("TODO alloca with compile time known count");
7938 }
7939
7940 switch (canon_type->id) {
7941 case TypeTableEntryIdInvalid:
7942 case TypeTableEntryIdTypeDecl:
7943 zig_unreachable();
7944 case TypeTableEntryIdBool:
7945 case TypeTableEntryIdVoid:
7946 case TypeTableEntryIdInt:
7947 case TypeTableEntryIdFloat:
7948 case TypeTableEntryIdPointer:
7949 case TypeTableEntryIdArray:
7950 case TypeTableEntryIdStruct:
7951 case TypeTableEntryIdMaybe:
7952 case TypeTableEntryIdErrorUnion:
7953 case TypeTableEntryIdPureError:
7954 case TypeTableEntryIdEnum:
7955 case TypeTableEntryIdUnion:
7956 case TypeTableEntryIdFn:
7957 {
7958 TypeTableEntry *slice_type = get_slice_type(ira->codegen, child_type, false);
7959 IrInstruction *new_instruction = ir_build_alloca_from(&ira->new_irb, &instruction->base, type_value, count_value);
7960 ir_add_alloca(ira, new_instruction, slice_type);
7961 return slice_type;
7962 }
7963 case TypeTableEntryIdVar:
7964 case TypeTableEntryIdMetaType:
7965 case TypeTableEntryIdUnreachable:
7966 case TypeTableEntryIdNumLitFloat:
7967 case TypeTableEntryIdNumLitInt:
7968 case TypeTableEntryIdUndefLit:
7969 case TypeTableEntryIdNullLit:
7970 case TypeTableEntryIdNamespace:
7971 case TypeTableEntryIdBlock:
7972 case TypeTableEntryIdBoundFn:
7973 ir_add_error(ira, type_value,
7974 buf_sprintf("invalid alloca type '%s'", buf_ptr(&child_type->name)));
7975 // TODO if this is a typedecl, add error note showing the declaration of the type decl
7976 return ira->codegen->builtin_types.entry_invalid;
7977 }
7978 zig_unreachable();
7979}
7980
7879static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {7981static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {
7880 switch (instruction->id) {7982 switch (instruction->id) {
7881 case IrInstructionIdInvalid:7983 case IrInstructionIdInvalid:
...@@ -7990,6 +8092,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi...@@ -7990,6 +8092,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
7990 return ir_analyze_instruction_int_type(ira, (IrInstructionIntType *)instruction);8092 return ir_analyze_instruction_int_type(ira, (IrInstructionIntType *)instruction);
7991 case IrInstructionIdBoolNot:8093 case IrInstructionIdBoolNot:
7992 return ir_analyze_instruction_bool_not(ira, (IrInstructionBoolNot *)instruction);8094 return ir_analyze_instruction_bool_not(ira, (IrInstructionBoolNot *)instruction);
8095 case IrInstructionIdAlloca:
8096 return ir_analyze_instruction_alloca(ira, (IrInstructionAlloca *)instruction);
7993 case IrInstructionIdCast:8097 case IrInstructionIdCast:
7994 case IrInstructionIdStructFieldPtr:8098 case IrInstructionIdStructFieldPtr:
7995 case IrInstructionIdEnumFieldPtr:8099 case IrInstructionIdEnumFieldPtr:
...@@ -8131,6 +8235,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {...@@ -8131,6 +8235,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
8131 case IrInstructionIdTruncate:8235 case IrInstructionIdTruncate:
8132 case IrInstructionIdIntType:8236 case IrInstructionIdIntType:
8133 case IrInstructionIdBoolNot:8237 case IrInstructionIdBoolNot:
8238 case IrInstructionIdAlloca:
8134 return false;8239 return false;
8135 case IrInstructionIdAsm:8240 case IrInstructionIdAsm:
8136 {8241 {
...@@ -8998,115 +9103,3 @@ bool ir_has_side_effects(IrInstruction *instruction) {...@@ -8998,115 +9103,3 @@ bool ir_has_side_effects(IrInstruction *instruction) {
8998// }9103// }
8999// zig_unreachable();9104// zig_unreachable();
9000//}9105//}
9001//
9002//static LLVMValueRef gen_var_decl_raw(CodeGen *g, AstNode *source_node, AstNodeVariableDeclaration *var_decl,
9003// bool unwrap_maybe, LLVMValueRef *init_value, TypeTableEntry **expr_type, bool var_is_ptr)
9004//{
9005// VariableTableEntry *variable = var_decl->variable;
9006//
9007// assert(variable);
9008//
9009// if (var_decl->expr) {
9010// *init_value = gen_expr(g, var_decl->expr);
9011// *expr_type = get_expr_type(var_decl->expr);
9012// }
9013// if (!type_has_bits(variable->type)) {
9014// return nullptr;
9015// }
9016//
9017// bool have_init_expr = false;
9018// bool want_zeroes = false;
9019// if (var_decl->expr) {
9020// ConstExprValue *const_val = &get_resolved_expr(var_decl->expr)->const_val;
9021// if (!const_val->ok || const_val->special == ConstValSpecialOther) {
9022// have_init_expr = true;
9023// }
9024// if (const_val->ok && const_val->special == ConstValSpecialZeroes) {
9025// want_zeroes = true;
9026// }
9027// }
9028// if (have_init_expr) {
9029// TypeTableEntry *expr_type = get_expr_type(var_decl->expr);
9030// LLVMValueRef value;
9031// if (unwrap_maybe) {
9032// assert(var_decl->expr);
9033// assert(expr_type->id == TypeTableEntryIdMaybe);
9034// value = gen_unwrap_maybe(g, var_decl->expr, *init_value);
9035// expr_type = expr_type->data.maybe.child_type;
9036// } else {
9037// value = *init_value;
9038// }
9039// gen_assign_raw(g, var_decl->expr, BinOpTypeAssign, variable->value_ref,
9040// value, variable->type, expr_type);
9041// } else {
9042// bool ignore_uninit = false;
9043// // handle runtime stack allocation
9044// if (var_decl->type) {
9045// TypeTableEntry *var_type = get_type_for_type_node(var_decl->type);
9046// if (var_type->id == TypeTableEntryIdStruct &&
9047// var_type->data.structure.is_slice)
9048// {
9049// assert(var_decl->type->type == NodeTypeArrayType);
9050// AstNode *size_node = var_decl->type->data.array_type.size;
9051// if (size_node) {
9052// ConstExprValue *const_val = &get_resolved_expr(size_node)->const_val;
9053// if (!const_val->ok) {
9054// TypeTableEntry *ptr_type = var_type->data.structure.fields[0].type_entry;
9055// assert(ptr_type->id == TypeTableEntryIdPointer);
9056// TypeTableEntry *child_type = ptr_type->data.pointer.child_type;
9057//
9058// LLVMValueRef size_val = gen_expr(g, size_node);
9059//
9060// set_debug_source_node(g, source_node);
9061// LLVMValueRef ptr_val = LLVMBuildArrayAlloca(g->builder, child_type->type_ref,
9062// size_val, "");
9063//
9064// size_t ptr_index = var_type->data.structure.fields[0].gen_index;
9065// assert(ptr_index != SIZE_MAX);
9066// size_t len_index = var_type->data.structure.fields[1].gen_index;
9067// assert(len_index != SIZE_MAX);
9068//
9069// // store the freshly allocated pointer in the unknown size array struct
9070// LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder,
9071// variable->value_ref, ptr_index, "");
9072// LLVMBuildStore(g->builder, ptr_val, ptr_field_ptr);
9073//
9074// // store the size in the len field
9075// LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder,
9076// variable->value_ref, len_index, "");
9077// LLVMBuildStore(g->builder, size_val, len_field_ptr);
9078//
9079// // don't clobber what we just did with debug initialization
9080// ignore_uninit = true;
9081// }
9082// }
9083// }
9084// }
9085// bool want_safe = want_debug_safety(g, source_node);
9086// if (!ignore_uninit && (want_safe || want_zeroes)) {
9087// TypeTableEntry *usize = g->builtin_types.entry_usize;
9088// uint64_t size_bytes = LLVMStoreSizeOfType(g->target_data_ref, variable->type->type_ref);
9089// uint64_t align_bytes = get_memcpy_align(g, variable->type);
9090//
9091// // memset uninitialized memory to 0xa
9092// set_debug_source_node(g, source_node);
9093// LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0);
9094// LLVMValueRef fill_char = LLVMConstInt(LLVMInt8Type(), want_zeroes ? 0x00 : 0xaa, false);
9095// LLVMValueRef dest_ptr = LLVMBuildBitCast(g->builder, variable->value_ref, ptr_u8, "");
9096// LLVMValueRef byte_count = LLVMConstInt(usize->type_ref, size_bytes, false);
9097// LLVMValueRef align_in_bytes = LLVMConstInt(LLVMInt32Type(), align_bytes, false);
9098// LLVMValueRef params[] = {
9099// dest_ptr,
9100// fill_char,
9101// byte_count,
9102// align_in_bytes,
9103// LLVMConstNull(LLVMInt1Type()), // is volatile
9104// };
9105//
9106// LLVMBuildCall(g->builder, g->memset_fn_val, params, 5, "");
9107// }
9108// }
9109//
9110// gen_var_debug_decl(g, variable);
9111// return nullptr;
9112//}
src/ir_print.cpp+11
...@@ -753,6 +753,14 @@ static void ir_print_truncate(IrPrint *irp, IrInstructionTruncate *instruction)...@@ -753,6 +753,14 @@ static void ir_print_truncate(IrPrint *irp, IrInstructionTruncate *instruction)
753 fprintf(irp->f, ")");753 fprintf(irp->f, ")");
754}754}
755755
756static void ir_print_alloca(IrPrint *irp, IrInstructionAlloca *instruction) {
757 fprintf(irp->f, "@alloca(");
758 ir_print_other_instruction(irp, instruction->type_value);
759 fprintf(irp->f, ", ");
760 ir_print_other_instruction(irp, instruction->count);
761 fprintf(irp->f, ")");
762}
763
756static void ir_print_int_type(IrPrint *irp, IrInstructionIntType *instruction) {764static void ir_print_int_type(IrPrint *irp, IrInstructionIntType *instruction) {
757 fprintf(irp->f, "@intType(");765 fprintf(irp->f, "@intType(");
758 ir_print_other_instruction(irp, instruction->is_signed);766 ir_print_other_instruction(irp, instruction->is_signed);
...@@ -942,6 +950,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {...@@ -942,6 +950,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
942 case IrInstructionIdTruncate:950 case IrInstructionIdTruncate:
943 ir_print_truncate(irp, (IrInstructionTruncate *)instruction);951 ir_print_truncate(irp, (IrInstructionTruncate *)instruction);
944 break;952 break;
953 case IrInstructionIdAlloca:
954 ir_print_alloca(irp, (IrInstructionAlloca *)instruction);
955 break;
945 case IrInstructionIdIntType:956 case IrInstructionIdIntType:
946 ir_print_int_type(irp, (IrInstructionIntType *)instruction);957 ir_print_int_type(irp, (IrInstructionIntType *)instruction);
947 break;958 break;