| ... | ... | @@ -2368,8 +2368,8 @@ static IrInstruction *ir_gen_symbol(IrBuilder *irb, Scope *scope, AstNode *node, |
| 2368 | 2368 | auto primitive_table_entry = irb->codegen->primitive_type_table.maybe_get(variable_name); |
| 2369 | 2369 | if (primitive_table_entry) { |
| 2370 | 2370 | IrInstruction *value = ir_build_const_type(irb, scope, node, primitive_table_entry->value); |
| 2371 | | if (lval == LValPurposeAddressOf) { |
| 2372 | | return ir_build_un_op(irb, scope, node, IrUnOpAddressOf, value); |
| 2371 | if (lval != LValPurposeNone) { |
| 2372 | return ir_build_ref(irb, scope, node, value); |
| 2373 | 2373 | } else { |
| 2374 | 2374 | return value; |
| 2375 | 2375 | } |
| ... | ... | @@ -2947,10 +2947,6 @@ static IrInstruction *ir_gen_prefix_op_id_lval(IrBuilder *irb, Scope *scope, Ast |
| 2947 | 2947 | if (value == irb->codegen->invalid_instruction) |
| 2948 | 2948 | return value; |
| 2949 | 2949 | |
| 2950 | | if (lval == LValPurposeAddressOf && (op_id == IrUnOpAddressOf || op_id == IrUnOpConstAddressOf)) { |
| 2951 | | return value; |
| 2952 | | } |
| 2953 | | |
| 2954 | 2950 | return ir_build_un_op(irb, scope, node, op_id, value); |
| 2955 | 2951 | } |
| 2956 | 2952 | |
| ... | ... | @@ -2958,6 +2954,29 @@ static IrInstruction *ir_gen_prefix_op_id(IrBuilder *irb, Scope *scope, AstNode |
| 2958 | 2954 | return ir_gen_prefix_op_id_lval(irb, scope, node, op_id, LValPurposeNone); |
| 2959 | 2955 | } |
| 2960 | 2956 | |
| 2957 | static IrInstruction *ir_lval_wrap(IrBuilder *irb, Scope *scope, IrInstruction *value, LValPurpose lval) { |
| 2958 | if (lval == LValPurposeNone) |
| 2959 | return value; |
| 2960 | if (value == irb->codegen->invalid_instruction) |
| 2961 | return value; |
| 2962 | |
| 2963 | // We needed a pointer to a value, but we got a value. So we create |
| 2964 | // an instruction which just makes a const pointer of it. |
| 2965 | return ir_build_ref(irb, scope, value->source_node, value); |
| 2966 | } |
| 2967 | |
| 2968 | static IrInstruction *ir_gen_address_of(IrBuilder *irb, Scope *scope, AstNode *node, bool is_const, LValPurpose lval) { |
| 2969 | assert(node->type == NodeTypePrefixOpExpr); |
| 2970 | AstNode *expr_node = node->data.prefix_op_expr.primary_expr; |
| 2971 | |
| 2972 | IrInstruction *value = ir_gen_node_extra(irb, expr_node, scope, LValPurposeAddressOf); |
| 2973 | if (value == irb->codegen->invalid_instruction) |
| 2974 | return value; |
| 2975 | |
| 2976 | |
| 2977 | return ir_lval_wrap(irb, scope, value, lval); |
| 2978 | } |
| 2979 | |
| 2961 | 2980 | static IrInstruction *ir_gen_err_assert_ok(IrBuilder *irb, Scope *scope, AstNode *node, LValPurpose lval) { |
| 2962 | 2981 | assert(node->type == NodeTypePrefixOpExpr); |
| 2963 | 2982 | AstNode *expr_node = node->data.prefix_op_expr.primary_expr; |
| ... | ... | @@ -3002,17 +3021,6 @@ static IrInstruction *ir_gen_bool_not(IrBuilder *irb, Scope *scope, AstNode *nod |
| 3002 | 3021 | return ir_build_bool_not(irb, scope, node, value); |
| 3003 | 3022 | } |
| 3004 | 3023 | |
| 3005 | | static IrInstruction *ir_lval_wrap(IrBuilder *irb, Scope *scope, IrInstruction *value, LValPurpose lval) { |
| 3006 | | if (lval == LValPurposeNone) |
| 3007 | | return value; |
| 3008 | | if (value == irb->codegen->invalid_instruction) |
| 3009 | | return value; |
| 3010 | | |
| 3011 | | // We needed a pointer to a value, but we got a value. So we create |
| 3012 | | // an instruction which just makes a const pointer of it. |
| 3013 | | return ir_build_ref(irb, scope, value->source_node, value); |
| 3014 | | } |
| 3015 | | |
| 3016 | 3024 | static IrInstruction *ir_gen_prefix_op_expr(IrBuilder *irb, Scope *scope, AstNode *node, LValPurpose lval) { |
| 3017 | 3025 | assert(node->type == NodeTypePrefixOpExpr); |
| 3018 | 3026 | |
| ... | ... | @@ -3024,21 +3032,21 @@ static IrInstruction *ir_gen_prefix_op_expr(IrBuilder *irb, Scope *scope, AstNod |
| 3024 | 3032 | case PrefixOpBoolNot: |
| 3025 | 3033 | return ir_lval_wrap(irb, scope, ir_gen_bool_not(irb, scope, node), lval); |
| 3026 | 3034 | case PrefixOpBinNot: |
| 3027 | | return ir_gen_prefix_op_id(irb, scope, node, IrUnOpBinNot); |
| 3035 | return ir_lval_wrap(irb, scope, ir_gen_prefix_op_id(irb, scope, node, IrUnOpBinNot), lval); |
| 3028 | 3036 | case PrefixOpNegation: |
| 3029 | | return ir_gen_prefix_op_id(irb, scope, node, IrUnOpNegation); |
| 3037 | return ir_lval_wrap(irb, scope, ir_gen_prefix_op_id(irb, scope, node, IrUnOpNegation), lval); |
| 3030 | 3038 | case PrefixOpNegationWrap: |
| 3031 | | return ir_gen_prefix_op_id(irb, scope, node, IrUnOpNegationWrap); |
| 3039 | return ir_lval_wrap(irb, scope, ir_gen_prefix_op_id(irb, scope, node, IrUnOpNegationWrap), lval); |
| 3032 | 3040 | case PrefixOpAddressOf: |
| 3033 | | return ir_gen_prefix_op_id_lval(irb, scope, node, IrUnOpAddressOf, LValPurposeAddressOf); |
| 3041 | return ir_gen_address_of(irb, scope, node, false, lval); |
| 3034 | 3042 | case PrefixOpConstAddressOf: |
| 3035 | | return ir_gen_prefix_op_id_lval(irb, scope, node, IrUnOpConstAddressOf, LValPurposeAddressOf); |
| 3043 | return ir_gen_address_of(irb, scope, node, true, lval); |
| 3036 | 3044 | case PrefixOpDereference: |
| 3037 | 3045 | return ir_gen_prefix_op_id_lval(irb, scope, node, IrUnOpDereference, lval); |
| 3038 | 3046 | case PrefixOpMaybe: |
| 3039 | | return ir_gen_prefix_op_id(irb, scope, node, IrUnOpMaybe); |
| 3047 | return ir_lval_wrap(irb, scope, ir_gen_prefix_op_id(irb, scope, node, IrUnOpMaybe), lval); |
| 3040 | 3048 | case PrefixOpError: |
| 3041 | | return ir_gen_prefix_op_id(irb, scope, node, IrUnOpError); |
| 3049 | return ir_lval_wrap(irb, scope, ir_gen_prefix_op_id(irb, scope, node, IrUnOpError), lval); |
| 3042 | 3050 | case PrefixOpUnwrapError: |
| 3043 | 3051 | return ir_gen_err_assert_ok(irb, scope, node, lval); |
| 3044 | 3052 | case PrefixOpUnwrapMaybe: |
| ... | ... | @@ -4501,13 +4509,20 @@ static TypeTableEntry *ir_analyze_const_ptr(IrAnalyze *ira, IrInstruction *instr |
| 4501 | 4509 | ConstExprValue *pointee, TypeTableEntry *pointee_type, bool depends_on_compile_var, |
| 4502 | 4510 | ConstPtrSpecial special, bool ptr_is_const) |
| 4503 | 4511 | { |
| 4504 | | TypeTableEntry *ptr_type = get_pointer_to_type(ira->codegen, pointee_type, ptr_is_const); |
| 4505 | | ConstExprValue *const_val = ir_build_const_from(ira, instruction, |
| 4506 | | depends_on_compile_var || pointee->depends_on_compile_var); |
| 4507 | | const_val->data.x_ptr.base_ptr = pointee; |
| 4508 | | const_val->data.x_ptr.index = SIZE_MAX; |
| 4509 | | const_val->data.x_ptr.special = special; |
| 4510 | | return ptr_type; |
| 4512 | if (pointee_type->id == TypeTableEntryIdMetaType) { |
| 4513 | TypeTableEntry *type_entry = pointee->data.x_type; |
| 4514 | ConstExprValue *const_val = ir_build_const_from(ira, instruction, depends_on_compile_var || pointee->depends_on_compile_var); |
| 4515 | const_val->data.x_type = get_pointer_to_type(ira->codegen, type_entry, ptr_is_const); |
| 4516 | return pointee_type; |
| 4517 | } else { |
| 4518 | TypeTableEntry *ptr_type = get_pointer_to_type(ira->codegen, pointee_type, ptr_is_const); |
| 4519 | ConstExprValue *const_val = ir_build_const_from(ira, instruction, |
| 4520 | depends_on_compile_var || pointee->depends_on_compile_var); |
| 4521 | const_val->data.x_ptr.base_ptr = pointee; |
| 4522 | const_val->data.x_ptr.index = SIZE_MAX; |
| 4523 | const_val->data.x_ptr.special = special; |
| 4524 | return ptr_type; |
| 4525 | } |
| 4511 | 4526 | } |
| 4512 | 4527 | |
| 4513 | 4528 | static TypeTableEntry *ir_analyze_const_usize(IrAnalyze *ira, IrInstruction *instruction, uint64_t value, |
| ... | ... | @@ -5004,6 +5019,20 @@ static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruc |
| 5004 | 5019 | IrInstruction *load_ptr_instruction = ir_build_load_ptr(&ira->new_irb, source_instruction->scope, source_instruction->source_node, ptr); |
| 5005 | 5020 | load_ptr_instruction->type_entry = child_type; |
| 5006 | 5021 | return load_ptr_instruction; |
| 5022 | } else if (type_entry->id == TypeTableEntryIdMetaType) { |
| 5023 | ConstExprValue *ptr_val = ir_resolve_const(ira, ptr); |
| 5024 | if (!ptr_val) |
| 5025 | return ira->codegen->invalid_instruction; |
| 5026 | |
| 5027 | TypeTableEntry *ptr_type = ptr_val->data.x_type; |
| 5028 | if (ptr_type->id == TypeTableEntryIdPointer) { |
| 5029 | TypeTableEntry *child_type = ptr_type->data.pointer.child_type; |
| 5030 | return ir_create_const_type(&ira->new_irb, source_instruction->scope, source_instruction->source_node, child_type); |
| 5031 | } else { |
| 5032 | ir_add_error(ira, source_instruction, |
| 5033 | buf_sprintf("attempt to dereference non pointer type '%s'", buf_ptr(&ptr_type->name))); |
| 5034 | return ira->codegen->invalid_instruction; |
| 5035 | } |
| 5007 | 5036 | } else { |
| 5008 | 5037 | add_node_error(ira->codegen, source_instruction->source_node, |
| 5009 | 5038 | buf_sprintf("attempt to dereference non pointer type '%s'", |
| ... | ... | @@ -5034,7 +5063,6 @@ static TypeTableEntry *ir_analyze_ref(IrAnalyze *ira, IrInstruction *source_inst |
| 5034 | 5063 | return ptr_type; |
| 5035 | 5064 | } |
| 5036 | 5065 | |
| 5037 | | |
| 5038 | 5066 | static bool ir_resolve_usize(IrAnalyze *ira, IrInstruction *value, uint64_t *out) { |
| 5039 | 5067 | if (value->type_entry->id == TypeTableEntryIdInvalid) |
| 5040 | 5068 | return false; |
| ... | ... | @@ -6182,66 +6210,6 @@ static TypeTableEntry *ir_analyze_unary_prefix_op_err(IrAnalyze *ira, IrInstruct |
| 6182 | 6210 | zig_unreachable(); |
| 6183 | 6211 | } |
| 6184 | 6212 | |
| 6185 | | static TypeTableEntry *ir_analyze_unary_address_of(IrAnalyze *ira, IrInstructionUnOp *un_op_instruction, |
| 6186 | | bool is_const) |
| 6187 | | { |
| 6188 | | IrInstruction *value = un_op_instruction->value->other; |
| 6189 | | if (value->type_entry->id == TypeTableEntryIdInvalid) |
| 6190 | | return ira->codegen->builtin_types.entry_invalid; |
| 6191 | | |
| 6192 | | TypeTableEntry *target_type = value->type_entry; |
| 6193 | | TypeTableEntry *canon_target_type = get_underlying_type(target_type); |
| 6194 | | switch (canon_target_type->id) { |
| 6195 | | case TypeTableEntryIdTypeDecl: |
| 6196 | | // impossible because we look at the canonicalized type |
| 6197 | | zig_unreachable(); |
| 6198 | | case TypeTableEntryIdInvalid: |
| 6199 | | return ira->codegen->builtin_types.entry_invalid; |
| 6200 | | case TypeTableEntryIdNumLitFloat: |
| 6201 | | case TypeTableEntryIdNumLitInt: |
| 6202 | | case TypeTableEntryIdUndefLit: |
| 6203 | | case TypeTableEntryIdNullLit: |
| 6204 | | case TypeTableEntryIdNamespace: |
| 6205 | | case TypeTableEntryIdBlock: |
| 6206 | | case TypeTableEntryIdUnreachable: |
| 6207 | | case TypeTableEntryIdVar: |
| 6208 | | case TypeTableEntryIdBoundFn: |
| 6209 | | add_node_error(ira->codegen, un_op_instruction->base.source_node, |
| 6210 | | buf_sprintf("unable to get address of type '%s'", buf_ptr(&target_type->name))); |
| 6211 | | // TODO if type decl, add note pointing to type decl declaration |
| 6212 | | return ira->codegen->builtin_types.entry_invalid; |
| 6213 | | case TypeTableEntryIdMetaType: |
| 6214 | | { |
| 6215 | | ConstExprValue *out_val = ir_build_const_from(ira, &un_op_instruction->base, |
| 6216 | | value->static_value.depends_on_compile_var); |
| 6217 | | assert(value->static_value.special != ConstValSpecialRuntime); |
| 6218 | | TypeTableEntry *child_type = value->static_value.data.x_type; |
| 6219 | | out_val->data.x_type = get_pointer_to_type(ira->codegen, child_type, is_const); |
| 6220 | | return ira->codegen->builtin_types.entry_type; |
| 6221 | | } |
| 6222 | | case TypeTableEntryIdPointer: |
| 6223 | | { |
| 6224 | | // this instruction is a noop - we solved this in IR gen by passing |
| 6225 | | // LValPurposeAddressOf which caused the loadptr to not do the load. |
| 6226 | | ir_link_new_instruction(value, &un_op_instruction->base); |
| 6227 | | return ir_finish_anal(ira, target_type); |
| 6228 | | } |
| 6229 | | case TypeTableEntryIdVoid: |
| 6230 | | case TypeTableEntryIdBool: |
| 6231 | | case TypeTableEntryIdInt: |
| 6232 | | case TypeTableEntryIdFloat: |
| 6233 | | case TypeTableEntryIdArray: |
| 6234 | | case TypeTableEntryIdStruct: |
| 6235 | | case TypeTableEntryIdMaybe: |
| 6236 | | case TypeTableEntryIdErrorUnion: |
| 6237 | | case TypeTableEntryIdPureError: |
| 6238 | | case TypeTableEntryIdEnum: |
| 6239 | | case TypeTableEntryIdUnion: |
| 6240 | | case TypeTableEntryIdFn: |
| 6241 | | zig_unreachable(); |
| 6242 | | } |
| 6243 | | zig_unreachable(); |
| 6244 | | } |
| 6245 | 6213 | |
| 6246 | 6214 | static TypeTableEntry *ir_analyze_dereference(IrAnalyze *ira, IrInstructionUnOp *un_op_instruction) { |
| 6247 | 6215 | IrInstruction *value = un_op_instruction->value->other; |
| ... | ... | @@ -6385,9 +6353,6 @@ static TypeTableEntry *ir_analyze_instruction_un_op(IrAnalyze *ira, IrInstructio |
| 6385 | 6353 | case IrUnOpNegation: |
| 6386 | 6354 | case IrUnOpNegationWrap: |
| 6387 | 6355 | return ir_analyze_negation(ira, un_op_instruction); |
| 6388 | | case IrUnOpAddressOf: |
| 6389 | | case IrUnOpConstAddressOf: |
| 6390 | | return ir_analyze_unary_address_of(ira, un_op_instruction, op_id == IrUnOpConstAddressOf); |
| 6391 | 6356 | case IrUnOpDereference: |
| 6392 | 6357 | return ir_analyze_dereference(ira, un_op_instruction); |
| 6393 | 6358 | case IrUnOpMaybe: |