| ... | ... | @@ -371,6 +371,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionBoolNot *) { |
| 371 | 371 | return IrInstructionIdBoolNot; |
| 372 | 372 | } |
| 373 | 373 | |
| 374 | static constexpr IrInstructionId ir_instruction_id(IrInstructionAlloca *) { |
| 375 | return IrInstructionIdAlloca; |
| 376 | } |
| 377 | |
| 374 | 378 | template<typename T> |
| 375 | 379 | static T *ir_create_instruction(IrExecutable *exec, Scope *scope, AstNode *source_node) { |
| 376 | 380 | T *special_instruction = allocate<T>(1); |
| ... | ... | @@ -1489,6 +1493,27 @@ static IrInstruction *ir_build_bool_not_from(IrBuilder *irb, IrInstruction *old_ |
| 1489 | 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 | 1517 | static void ir_gen_defers_for_block(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, |
| 1493 | 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 | 2335 | |
| 2311 | 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 | 2352 | case BuiltinFnIdMemcpy: |
| 2314 | 2353 | case BuiltinFnIdMemset: |
| 2315 | 2354 | case BuiltinFnIdAlignof: |
| ... | ... | @@ -7876,6 +7915,69 @@ static TypeTableEntry *ir_analyze_instruction_bool_not(IrAnalyze *ira, IrInstruc |
| 7876 | 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 | 7981 | static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) { |
| 7880 | 7982 | switch (instruction->id) { |
| 7881 | 7983 | case IrInstructionIdInvalid: |
| ... | ... | @@ -7990,6 +8092,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi |
| 7990 | 8092 | return ir_analyze_instruction_int_type(ira, (IrInstructionIntType *)instruction); |
| 7991 | 8093 | case IrInstructionIdBoolNot: |
| 7992 | 8094 | return ir_analyze_instruction_bool_not(ira, (IrInstructionBoolNot *)instruction); |
| 8095 | case IrInstructionIdAlloca: |
| 8096 | return ir_analyze_instruction_alloca(ira, (IrInstructionAlloca *)instruction); |
| 7993 | 8097 | case IrInstructionIdCast: |
| 7994 | 8098 | case IrInstructionIdStructFieldPtr: |
| 7995 | 8099 | case IrInstructionIdEnumFieldPtr: |
| ... | ... | @@ -8131,6 +8235,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 8131 | 8235 | case IrInstructionIdTruncate: |
| 8132 | 8236 | case IrInstructionIdIntType: |
| 8133 | 8237 | case IrInstructionIdBoolNot: |
| 8238 | case IrInstructionIdAlloca: |
| 8134 | 8239 | return false; |
| 8135 | 8240 | case IrInstructionIdAsm: |
| 8136 | 8241 | { |
| ... | ... | @@ -8998,115 +9103,3 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 8998 | 9103 | // } |
| 8999 | 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 | | //} |