| ... | @@ -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 | } |
| 373 | | 373 | |
| | 374 | static constexpr IrInstructionId ir_instruction_id(IrInstructionAlloca *) { |
| | 375 | return IrInstructionIdAlloca; |
| | 376 | } |
| | 377 | |
| 374 | template<typename T> | 378 | template<typename T> |
| 375 | static T *ir_create_instruction(IrExecutable *exec, Scope *scope, AstNode *source_node) { | 379 | static 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 | } |
| 1491 | | 1495 | |
| | 1496 | static 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 | |
| | 1509 | static 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 | |
| 1492 | static void ir_gen_defers_for_block(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, | 1517 | static 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 |
| 2310 | | 2335 | |
| 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 | } |
| 7878 | | 7917 | |
| | 7918 | static 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 | |
| 7879 | static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) { | 7981 | static 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 | //} | | |