authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-02-04 21:49:27-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-02-04 21:49:27-05:00
log419e75eb2313b4910921185211201317cbbb400c
tree3ad2166c30e84a6d7ce075fb48741e336eb87027
parent0d7abc6368a826490f8985634882300b50d81cba

remove volatileStore builtin; add volatile pointers

closes #238

10 files changed, 213 insertions(+), 172 deletions(-)

doc/langref.md+1-1
......@@ -143,7 +143,7 @@ ContainerInitBody = list(StructLiteralField, ",") | list(Expression, ",")
143143
144144StructLiteralField = "." Symbol "=" Expression
145145
146PrefixOp = "!" | "-" | "~" | "*" | ("&" option("const")) | "?" | "%" | "%%" | "??" | "-%"
146PrefixOp = "!" | "-" | "~" | "*" | ("&" option("const") option("volatile")) | "?" | "%" | "%%" | "??" | "-%"
147147
148148PrimaryExpression = Number | String | CharLiteral | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression | Symbol | ("@" Symbol FnCallExpression) | ArrayType | (option("extern") FnProto) | AsmExpression | ("error" "." Symbol) | ContainerDecl
149149
src/all_types.hpp+7-10
......@@ -490,6 +490,8 @@ enum PrefixOp {
490490 PrefixOpNegationWrap,
491491 PrefixOpAddressOf,
492492 PrefixOpConstAddressOf,
493 PrefixOpVolatileAddressOf,
494 PrefixOpConstVolatileAddressOf,
493495 PrefixOpDereference,
494496 PrefixOpMaybe,
495497 PrefixOpError,
......@@ -806,6 +808,7 @@ bool fn_type_id_eql(FnTypeId *a, FnTypeId *b);
806808struct TypeTableEntryPointer {
807809 TypeTableEntry *child_type;
808810 bool is_const;
811 bool is_volatile;
809812};
810813
811814struct TypeTableEntryInt {
......@@ -991,7 +994,7 @@ struct TypeTableEntry {
991994 } data;
992995
993996 // use these fields to make sure we don't duplicate type table entries for the same type
994 TypeTableEntry *pointer_parent[2];
997 TypeTableEntry *pointer_parent[2][2]; // [0 - mut, 1 - const][0 - normal, 1 - volatile]
995998 TypeTableEntry *unknown_size_array_parent[2];
996999 HashMap<uint64_t, TypeTableEntry *, uint64_hash, uint64_eq> arrays_by_size;
9971000 TypeTableEntry *maybe_parent;
......@@ -1113,7 +1116,6 @@ enum BuiltinFnId {
11131116 BuiltinFnIdCanImplicitCast,
11141117 BuiltinFnIdSetGlobalAlign,
11151118 BuiltinFnIdSetGlobalSection,
1116 BuiltinFnIdVolatileStore,
11171119};
11181120
11191121struct BuiltinFnEntry {
......@@ -1692,7 +1694,6 @@ struct IrInstructionStorePtr {
16921694
16931695 IrInstruction *ptr;
16941696 IrInstruction *value;
1695 bool is_volatile;
16961697};
16971698
16981699struct IrInstructionFieldPtr {
......@@ -1943,6 +1944,7 @@ struct IrInstructionRef {
19431944 IrInstruction *value;
19441945 LLVMValueRef tmp_ptr;
19451946 bool is_const;
1947 bool is_volatile;
19461948};
19471949
19481950struct IrInstructionMinValue {
......@@ -2062,6 +2064,7 @@ struct IrInstructionMemset {
20622064 IrInstruction *dest_ptr;
20632065 IrInstruction *byte;
20642066 IrInstruction *count;
2067 bool is_volatile;
20652068};
20662069
20672070struct IrInstructionMemcpy {
......@@ -2070,6 +2073,7 @@ struct IrInstructionMemcpy {
20702073 IrInstruction *dest_ptr;
20712074 IrInstruction *src_ptr;
20722075 IrInstruction *count;
2076 bool is_volatile;
20732077};
20742078
20752079struct IrInstructionSlice {
......@@ -2267,13 +2271,6 @@ struct IrInstructionSetGlobalSection {
22672271 IrInstruction *value;
22682272};
22692273
2270enum LValPurpose {
2271 LValPurposeNone,
2272 LValPurposeAssign,
2273 LValPurposeAddressOf,
2274 LValPurposeAddressOfConst,
2275};
2276
22772274static const size_t slice_ptr_index = 0;
22782275static const size_t slice_len_index = 1;
22792276
src/analyze.cpp+32-27
......@@ -269,43 +269,48 @@ TypeTableEntry *get_smallest_unsigned_int_type(CodeGen *g, uint64_t x) {
269269 return get_int_type(g, false, bits_needed_for_unsigned(x));
270270}
271271
272TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool is_const) {
272TypeTableEntry *get_pointer_to_type_volatile(CodeGen *g, TypeTableEntry *child_type, bool is_const, bool is_volatile) {
273273 assert(child_type->id != TypeTableEntryIdInvalid);
274 TypeTableEntry **parent_pointer = &child_type->pointer_parent[(is_const ? 1 : 0)];
275 if (*parent_pointer) {
274 TypeTableEntry **parent_pointer = &child_type->pointer_parent[(is_const ? 1 : 0)][(is_volatile ? 1 : 0)];
275 if (*parent_pointer)
276276 return *parent_pointer;
277 } else {
278 type_ensure_zero_bits_known(g, child_type);
279277
280 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdPointer);
278 type_ensure_zero_bits_known(g, child_type);
281279
282 const char *const_str = is_const ? "const " : "";
283 buf_resize(&entry->name, 0);
284 buf_appendf(&entry->name, "&%s%s", const_str, buf_ptr(&child_type->name));
285
286 TypeTableEntry *canon_child_type = get_underlying_type(child_type);
287 assert(canon_child_type->id != TypeTableEntryIdInvalid);
280 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdPointer);
288281
289 entry->zero_bits = !type_has_bits(canon_child_type);
282 const char *const_str = is_const ? "const " : "";
283 const char *volatile_str = is_volatile ? "volatile " : "";
284 buf_resize(&entry->name, 0);
285 buf_appendf(&entry->name, "&%s%s%s", const_str, volatile_str, buf_ptr(&child_type->name));
290286
291 if (!entry->zero_bits) {
292 entry->type_ref = LLVMPointerType(child_type->type_ref, 0);
287 TypeTableEntry *canon_child_type = get_underlying_type(child_type);
288 assert(canon_child_type->id != TypeTableEntryIdInvalid);
293289
294 uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, entry->type_ref);
295 uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, entry->type_ref);
296 assert(child_type->di_type);
297 entry->di_type = ZigLLVMCreateDebugPointerType(g->dbuilder, child_type->di_type,
298 debug_size_in_bits, debug_align_in_bits, buf_ptr(&entry->name));
299 } else {
300 entry->di_type = g->builtin_types.entry_void->di_type;
301 }
290 entry->zero_bits = !type_has_bits(canon_child_type);
302291
303 entry->data.pointer.child_type = child_type;
304 entry->data.pointer.is_const = is_const;
292 if (!entry->zero_bits) {
293 entry->type_ref = LLVMPointerType(child_type->type_ref, 0);
305294
306 *parent_pointer = entry;
307 return entry;
295 uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, entry->type_ref);
296 uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, entry->type_ref);
297 assert(child_type->di_type);
298 entry->di_type = ZigLLVMCreateDebugPointerType(g->dbuilder, child_type->di_type,
299 debug_size_in_bits, debug_align_in_bits, buf_ptr(&entry->name));
300 } else {
301 entry->di_type = g->builtin_types.entry_void->di_type;
308302 }
303
304 entry->data.pointer.child_type = child_type;
305 entry->data.pointer.is_const = is_const;
306 entry->data.pointer.is_volatile = is_volatile;
307
308 *parent_pointer = entry;
309 return entry;
310}
311
312TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool is_const) {
313 return get_pointer_to_type_volatile(g, child_type, is_const, false);
309314}
310315
311316TypeTableEntry *get_maybe_type(CodeGen *g, TypeTableEntry *child_type) {
src/analyze.hpp+1
......@@ -15,6 +15,7 @@ ErrorMsg *add_node_error(CodeGen *g, AstNode *node, Buf *msg);
1515ErrorMsg *add_error_note(CodeGen *g, ErrorMsg *parent_msg, AstNode *node, Buf *msg);
1616TypeTableEntry *new_type_table_entry(TypeTableEntryId id);
1717TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool is_const);
18TypeTableEntry *get_pointer_to_type_volatile(CodeGen *g, TypeTableEntry *child_type, bool is_const, bool is_volatile);
1819bool is_node_void_expr(AstNode *node);
1920uint64_t type_size(CodeGen *g, TypeTableEntry *type_entry);
2021TypeTableEntry **get_int_type_ptr(CodeGen *g, bool is_signed, size_t size_in_bits);
src/ast_render.cpp+2
......@@ -68,6 +68,8 @@ static const char *prefix_op_str(PrefixOp prefix_op) {
6868 case PrefixOpBinNot: return "~";
6969 case PrefixOpAddressOf: return "&";
7070 case PrefixOpConstAddressOf: return "&const ";
71 case PrefixOpVolatileAddressOf: return "&volatile ";
72 case PrefixOpConstVolatileAddressOf: return "&const volatile ";
7173 case PrefixOpDereference: return "*";
7274 case PrefixOpMaybe: return "?";
7375 case PrefixOpError: return "%";
src/codegen.cpp+14-8
......@@ -1294,18 +1294,19 @@ static LLVMValueRef ir_render_store_ptr(CodeGen *g, IrExecutable *executable, Ir
12941294 LLVMValueRef value = ir_llvm_value(g, instruction->value);
12951295
12961296 assert(instruction->ptr->value.type->id == TypeTableEntryIdPointer);
1297 TypeTableEntry *op1_type = instruction->ptr->value.type->data.pointer.child_type;
1297 TypeTableEntry *ptr_type = get_underlying_type(instruction->ptr->value.type);
1298 TypeTableEntry *child_type = get_underlying_type(ptr_type->data.pointer.child_type);
12981299
1299 if (!type_has_bits(op1_type)) {
1300 if (!type_has_bits(child_type)) {
13001301 return nullptr;
13011302 }
1302 if (handle_is_ptr(op1_type)) {
1303 return gen_struct_memcpy(g, value, ptr, op1_type);
1303 if (handle_is_ptr(child_type)) {
1304 return gen_struct_memcpy(g, value, ptr, child_type);
13041305 }
13051306
13061307 LLVMValueRef llvm_instruction = LLVMBuildStore(g->builder, value, ptr);
13071308
1308 LLVMSetVolatile(llvm_instruction, instruction->is_volatile);
1309 LLVMSetVolatile(llvm_instruction, ptr_type->data.pointer.is_volatile);
13091310
13101311 return nullptr;
13111312}
......@@ -1803,12 +1804,15 @@ static LLVMValueRef ir_render_memset(CodeGen *g, IrExecutable *executable, IrIns
18031804
18041805 LLVMValueRef dest_ptr_casted = LLVMBuildBitCast(g->builder, dest_ptr, ptr_u8, "");
18051806
1807 LLVMValueRef is_volatile = instruction->is_volatile ?
1808 LLVMConstAllOnes(LLVMInt1Type()) : LLVMConstNull(LLVMInt1Type());
1809
18061810 LLVMValueRef params[] = {
18071811 dest_ptr_casted, // dest pointer
18081812 char_val, // source pointer
18091813 len_val, // byte count
18101814 LLVMConstInt(LLVMInt32Type(), 1, false), // align in bytes
1811 LLVMConstNull(LLVMInt1Type()), // is volatile
1815 is_volatile,
18121816 };
18131817
18141818 LLVMBuildCall(g->builder, g->memset_fn_val, params, 5, "");
......@@ -1825,12 +1829,15 @@ static LLVMValueRef ir_render_memcpy(CodeGen *g, IrExecutable *executable, IrIns
18251829 LLVMValueRef dest_ptr_casted = LLVMBuildBitCast(g->builder, dest_ptr, ptr_u8, "");
18261830 LLVMValueRef src_ptr_casted = LLVMBuildBitCast(g->builder, src_ptr, ptr_u8, "");
18271831
1832 LLVMValueRef is_volatile = instruction->is_volatile ?
1833 LLVMConstAllOnes(LLVMInt1Type()) : LLVMConstNull(LLVMInt1Type());
1834
18281835 LLVMValueRef params[] = {
18291836 dest_ptr_casted, // dest pointer
18301837 src_ptr_casted, // source pointer
18311838 len_val, // byte count
18321839 LLVMConstInt(LLVMInt32Type(), 1, false), // align in bytes
1833 LLVMConstNull(LLVMInt1Type()), // is volatile
1840 is_volatile,
18341841 };
18351842
18361843 LLVMBuildCall(g->builder, g->memcpy_fn_val, params, 5, "");
......@@ -3690,7 +3697,6 @@ static void define_builtin_fns(CodeGen *g) {
36903697 create_builtin_fn(g, BuiltinFnIdAlloca, "alloca", 2);
36913698 create_builtin_fn(g, BuiltinFnIdSetGlobalAlign, "setGlobalAlign", 2);
36923699 create_builtin_fn(g, BuiltinFnIdSetGlobalSection, "setGlobalSection", 2);
3693 create_builtin_fn(g, BuiltinFnIdVolatileStore, "volatileStore", 2);
36943700}
36953701
36963702static void init(CodeGen *g, Buf *source_path) {
src/ir.cpp+132-118
......@@ -44,9 +44,21 @@ struct IrAnalyze {
4444 IrBasicBlock *const_predecessor_bb;
4545};
4646
47struct LVal {
48 bool is_ptr;
49 bool is_const;
50 bool is_volatile;
51};
52
53static const LVal LVAL_NONE = { false, false, false };
54static const LVal LVAL_PTR = { true, false, false };
55
56static LVal make_lval_addr(bool is_const, bool is_volatile) {
57 return { true, is_const, is_volatile };
58}
59
4760static IrInstruction *ir_gen_node(IrBuilder *irb, AstNode *node, Scope *scope);
48static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, Scope *scope,
49 LValPurpose lval);
61static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, Scope *scope, LVal lval);
5062static TypeTableEntry *ir_analyze_instruction(IrAnalyze *ira, IrInstruction *instruction);
5163static IrInstruction *ir_implicit_cast(IrAnalyze *ira, IrInstruction *value, TypeTableEntry *expected_type);
5264
......@@ -1042,14 +1054,13 @@ static IrInstruction *ir_build_unreachable_from(IrBuilder *irb, IrInstruction *o
10421054}
10431055
10441056static IrInstruction *ir_build_store_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node,
1045 IrInstruction *ptr, IrInstruction *value, bool is_volatile)
1057 IrInstruction *ptr, IrInstruction *value)
10461058{
10471059 IrInstructionStorePtr *instruction = ir_build_instruction<IrInstructionStorePtr>(irb, scope, source_node);
10481060 instruction->base.value.special = ConstValSpecialStatic;
10491061 instruction->base.value.type = irb->codegen->builtin_types.entry_void;
10501062 instruction->ptr = ptr;
10511063 instruction->value = value;
1052 instruction->is_volatile = is_volatile;
10531064
10541065 ir_ref_instruction(ptr, irb->current_basic_block);
10551066 ir_ref_instruction(value, irb->current_basic_block);
......@@ -1058,10 +1069,10 @@ static IrInstruction *ir_build_store_ptr(IrBuilder *irb, Scope *scope, AstNode *
10581069}
10591070
10601071static IrInstruction *ir_build_store_ptr_from(IrBuilder *irb, IrInstruction *old_instruction,
1061 IrInstruction *ptr, IrInstruction *value, bool is_volatile)
1072 IrInstruction *ptr, IrInstruction *value)
10621073{
10631074 IrInstruction *new_instruction = ir_build_store_ptr(irb, old_instruction->scope,
1064 old_instruction->source_node, ptr, value, is_volatile);
1075 old_instruction->source_node, ptr, value);
10651076 ir_link_new_instruction(new_instruction, old_instruction);
10661077 return new_instruction;
10671078}
......@@ -1450,11 +1461,12 @@ static IrInstruction *ir_build_array_len(IrBuilder *irb, Scope *scope, AstNode *
14501461}
14511462
14521463static IrInstruction *ir_build_ref(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *value,
1453 bool is_const)
1464 bool is_const, bool is_volatile)
14541465{
14551466 IrInstructionRef *instruction = ir_build_instruction<IrInstructionRef>(irb, scope, source_node);
14561467 instruction->value = value;
14571468 instruction->is_const = is_const;
1469 instruction->is_volatile = is_volatile;
14581470
14591471 ir_ref_instruction(value, irb->current_basic_block);
14601472
......@@ -1462,10 +1474,10 @@ static IrInstruction *ir_build_ref(IrBuilder *irb, Scope *scope, AstNode *source
14621474}
14631475
14641476static IrInstruction *ir_build_ref_from(IrBuilder *irb, IrInstruction *old_instruction, IrInstruction *value,
1465 bool is_const)
1477 bool is_const, bool is_volatile)
14661478{
14671479 IrInstruction *new_instruction = ir_build_ref(irb, old_instruction->scope, old_instruction->source_node,
1468 value, is_const);
1480 value, is_const, is_volatile);
14691481 ir_link_new_instruction(new_instruction, old_instruction);
14701482 return new_instruction;
14711483}
......@@ -2980,7 +2992,7 @@ static ScopeDeferExpr *get_scope_defer_expr(Scope *scope) {
29802992 return nullptr;
29812993}
29822994
2983static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, LValPurpose lval) {
2995static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval) {
29842996 assert(node->type == NodeTypeReturnExpr);
29852997
29862998 FnTableEntry *fn_entry = exec_fn_entry(irb->exec);
......@@ -3068,7 +3080,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
30683080 case ReturnKindError:
30693081 {
30703082 assert(expr_node);
3071 IrInstruction *err_union_ptr = ir_gen_node_extra(irb, expr_node, scope, LValPurposeAddressOf);
3083 IrInstruction *err_union_ptr = ir_gen_node_extra(irb, expr_node, scope, LVAL_PTR);
30723084 if (err_union_ptr == irb->codegen->invalid_instruction)
30733085 return irb->codegen->invalid_instruction;
30743086 IrInstruction *err_union_val = ir_build_load_ptr(irb, scope, node, err_union_ptr);
......@@ -3086,7 +3098,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
30863098
30873099 ir_set_cursor_at_end(irb, continue_block);
30883100 IrInstruction *unwrapped_ptr = ir_build_unwrap_err_payload(irb, scope, node, err_union_ptr, false);
3089 if (lval != LValPurposeNone)
3101 if (lval.is_ptr)
30903102 return unwrapped_ptr;
30913103 else
30923104 return ir_build_load_ptr(irb, scope, node, unwrapped_ptr);
......@@ -3094,7 +3106,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
30943106 case ReturnKindMaybe:
30953107 {
30963108 assert(expr_node);
3097 IrInstruction *maybe_val_ptr = ir_gen_node_extra(irb, expr_node, scope, LValPurposeAddressOf);
3109 IrInstruction *maybe_val_ptr = ir_gen_node_extra(irb, expr_node, scope, LVAL_PTR);
30983110 if (maybe_val_ptr == irb->codegen->invalid_instruction)
30993111 return irb->codegen->invalid_instruction;
31003112 IrInstruction *maybe_val = ir_build_load_ptr(irb, scope, node, maybe_val_ptr);
......@@ -3112,7 +3124,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
31123124
31133125 ir_set_cursor_at_end(irb, continue_block);
31143126 IrInstruction *unwrapped_ptr = ir_build_unwrap_maybe(irb, scope, node, maybe_val_ptr, false);
3115 if (lval != LValPurposeNone)
3127 if (lval.is_ptr)
31163128 return unwrapped_ptr;
31173129 else
31183130 return ir_build_load_ptr(irb, scope, node, unwrapped_ptr);
......@@ -3293,18 +3305,18 @@ static IrInstruction *ir_gen_bin_op_id(IrBuilder *irb, Scope *scope, AstNode *no
32933305}
32943306
32953307static IrInstruction *ir_gen_assign(IrBuilder *irb, Scope *scope, AstNode *node) {
3296 IrInstruction *lvalue = ir_gen_node_extra(irb, node->data.bin_op_expr.op1, scope, LValPurposeAssign);
3308 IrInstruction *lvalue = ir_gen_node_extra(irb, node->data.bin_op_expr.op1, scope, LVAL_PTR);
32973309 IrInstruction *rvalue = ir_gen_node(irb, node->data.bin_op_expr.op2, scope);
32983310
32993311 if (lvalue == irb->codegen->invalid_instruction || rvalue == irb->codegen->invalid_instruction)
33003312 return irb->codegen->invalid_instruction;
33013313
3302 ir_build_store_ptr(irb, scope, node, lvalue, rvalue, false);
3314 ir_build_store_ptr(irb, scope, node, lvalue, rvalue);
33033315 return ir_build_const_void(irb, scope, node);
33043316}
33053317
33063318static IrInstruction *ir_gen_assign_op(IrBuilder *irb, Scope *scope, AstNode *node, IrBinOp op_id) {
3307 IrInstruction *lvalue = ir_gen_node_extra(irb, node->data.bin_op_expr.op1, scope, LValPurposeAssign);
3319 IrInstruction *lvalue = ir_gen_node_extra(irb, node->data.bin_op_expr.op1, scope, LVAL_PTR);
33083320 if (lvalue == irb->codegen->invalid_instruction)
33093321 return lvalue;
33103322 IrInstruction *op1 = ir_build_load_ptr(irb, scope, node->data.bin_op_expr.op1, lvalue);
......@@ -3312,7 +3324,7 @@ static IrInstruction *ir_gen_assign_op(IrBuilder *irb, Scope *scope, AstNode *no
33123324 if (op2 == irb->codegen->invalid_instruction)
33133325 return op2;
33143326 IrInstruction *result = ir_build_bin_op(irb, scope, node, op_id, op1, op2, true);
3315 ir_build_store_ptr(irb, scope, node, lvalue, result, false);
3327 ir_build_store_ptr(irb, scope, node, lvalue, result);
33163328 return ir_build_const_void(irb, scope, node);
33173329}
33183330
......@@ -3406,7 +3418,7 @@ static IrInstruction *ir_gen_maybe_ok_or(IrBuilder *irb, Scope *parent_scope, As
34063418 AstNode *op1_node = node->data.bin_op_expr.op1;
34073419 AstNode *op2_node = node->data.bin_op_expr.op2;
34083420
3409 IrInstruction *maybe_ptr = ir_gen_node_extra(irb, op1_node, parent_scope, LValPurposeAddressOf);
3421 IrInstruction *maybe_ptr = ir_gen_node_extra(irb, op1_node, parent_scope, LVAL_PTR);
34103422 if (maybe_ptr == irb->codegen->invalid_instruction)
34113423 return irb->codegen->invalid_instruction;
34123424
......@@ -3574,9 +3586,9 @@ static IrInstruction *ir_gen_var_literal(IrBuilder *irb, Scope *scope, AstNode *
35743586}
35753587
35763588static IrInstruction *ir_gen_decl_ref(IrBuilder *irb, AstNode *source_node, Tld *tld,
3577 LValPurpose lval, Scope *scope)
3589 LVal lval, Scope *scope)
35783590{
3579 resolve_top_level_decl(irb->codegen, tld, lval != LValPurposeNone);
3591 resolve_top_level_decl(irb->codegen, tld, lval.is_ptr);
35803592 if (tld->resolution == TldResolutionInvalid)
35813593 return irb->codegen->invalid_instruction;
35823594
......@@ -3587,8 +3599,8 @@ static IrInstruction *ir_gen_decl_ref(IrBuilder *irb, AstNode *source_node, Tld
35873599 {
35883600 TldVar *tld_var = (TldVar *)tld;
35893601 VariableTableEntry *var = tld_var->var;
3590 IrInstruction *var_ptr = ir_build_var_ptr(irb, scope, source_node, var, lval == LValPurposeAddressOfConst);
3591 if (lval != LValPurposeNone)
3602 IrInstruction *var_ptr = ir_build_var_ptr(irb, scope, source_node, var, !lval.is_ptr || lval.is_const);
3603 if (lval.is_ptr)
35923604 return var_ptr;
35933605 else
35943606 return ir_build_load_ptr(irb, scope, source_node, var_ptr);
......@@ -3599,8 +3611,8 @@ static IrInstruction *ir_gen_decl_ref(IrBuilder *irb, AstNode *source_node, Tld
35993611 FnTableEntry *fn_entry = tld_fn->fn_entry;
36003612 assert(fn_entry->type_entry);
36013613 IrInstruction *ref_instruction = ir_build_const_fn(irb, scope, source_node, fn_entry);
3602 if (lval != LValPurposeNone)
3603 return ir_build_ref(irb, scope, source_node, ref_instruction, true);
3614 if (lval.is_ptr)
3615 return ir_build_ref(irb, scope, source_node, ref_instruction, true, false);
36043616 else
36053617 return ref_instruction;
36063618 }
......@@ -3609,8 +3621,8 @@ static IrInstruction *ir_gen_decl_ref(IrBuilder *irb, AstNode *source_node, Tld
36093621 TldTypeDef *tld_typedef = (TldTypeDef *)tld;
36103622 TypeTableEntry *typedef_type = tld_typedef->type_entry;
36113623 IrInstruction *ref_instruction = ir_build_const_type(irb, scope, source_node, typedef_type, false);
3612 if (lval != LValPurposeNone)
3613 return ir_build_ref(irb, scope, source_node, ref_instruction, true);
3624 if (lval.is_ptr)
3625 return ir_build_ref(irb, scope, source_node, ref_instruction, true, false);
36143626 else
36153627 return ref_instruction;
36163628 }
......@@ -3618,7 +3630,7 @@ static IrInstruction *ir_gen_decl_ref(IrBuilder *irb, AstNode *source_node, Tld
36183630 zig_unreachable();
36193631}
36203632
3621static IrInstruction *ir_gen_symbol(IrBuilder *irb, Scope *scope, AstNode *node, LValPurpose lval) {
3633static IrInstruction *ir_gen_symbol(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval) {
36223634 assert(node->type == NodeTypeSymbol);
36233635
36243636 Buf *variable_name = node->data.symbol_expr.symbol;
......@@ -3626,8 +3638,8 @@ static IrInstruction *ir_gen_symbol(IrBuilder *irb, Scope *scope, AstNode *node,
36263638 auto primitive_table_entry = irb->codegen->primitive_type_table.maybe_get(variable_name);
36273639 if (primitive_table_entry) {
36283640 IrInstruction *value = ir_build_const_type(irb, scope, node, primitive_table_entry->value, false);
3629 if (lval != LValPurposeNone) {
3630 return ir_build_ref(irb, scope, node, value, lval == LValPurposeAddressOfConst);
3641 if (lval.is_ptr) {
3642 return ir_build_ref(irb, scope, node, value, lval.is_const, lval.is_volatile);
36313643 } else {
36323644 return value;
36333645 }
......@@ -3635,8 +3647,9 @@ static IrInstruction *ir_gen_symbol(IrBuilder *irb, Scope *scope, AstNode *node,
36353647
36363648 VariableTableEntry *var = find_variable(irb->codegen, scope, variable_name);
36373649 if (var) {
3638 IrInstruction *var_ptr = ir_build_var_ptr(irb, scope, node, var, lval == LValPurposeAddressOfConst);
3639 if (lval != LValPurposeNone)
3650 IrInstruction *var_ptr = ir_build_var_ptr(irb, scope, node, var,
3651 !lval.is_ptr || lval.is_const);
3652 if (lval.is_ptr)
36403653 return var_ptr;
36413654 else
36423655 return ir_build_load_ptr(irb, scope, node, var_ptr);
......@@ -3658,12 +3671,11 @@ static IrInstruction *ir_gen_symbol(IrBuilder *irb, Scope *scope, AstNode *node,
36583671 return irb->codegen->invalid_instruction;
36593672}
36603673
3661static IrInstruction *ir_gen_array_access(IrBuilder *irb, Scope *scope, AstNode *node, LValPurpose lval) {
3674static IrInstruction *ir_gen_array_access(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval) {
36623675 assert(node->type == NodeTypeArrayAccessExpr);
36633676
36643677 AstNode *array_ref_node = node->data.array_access_expr.array_ref_expr;
3665 IrInstruction *array_ref_instruction = ir_gen_node_extra(irb, array_ref_node, scope,
3666 LValPurposeAddressOf);
3678 IrInstruction *array_ref_instruction = ir_gen_node_extra(irb, array_ref_node, scope, LVAL_PTR);
36673679 if (array_ref_instruction == irb->codegen->invalid_instruction)
36683680 return array_ref_instruction;
36693681
......@@ -3674,25 +3686,24 @@ static IrInstruction *ir_gen_array_access(IrBuilder *irb, Scope *scope, AstNode
36743686
36753687 IrInstruction *ptr_instruction = ir_build_elem_ptr(irb, scope, node, array_ref_instruction,
36763688 subscript_instruction, true);
3677 if (lval != LValPurposeNone)
3689 if (lval.is_ptr)
36783690 return ptr_instruction;
36793691
36803692 return ir_build_load_ptr(irb, scope, node, ptr_instruction);
36813693}
36823694
3683static IrInstruction *ir_gen_field_access(IrBuilder *irb, Scope *scope, AstNode *node, LValPurpose lval) {
3695static IrInstruction *ir_gen_field_access(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval) {
36843696 assert(node->type == NodeTypeFieldAccessExpr);
36853697
36863698 AstNode *container_ref_node = node->data.field_access_expr.struct_expr;
36873699 Buf *field_name = node->data.field_access_expr.field_name;
36883700
3689 IrInstruction *container_ref_instruction = ir_gen_node_extra(irb, container_ref_node, scope,
3690 LValPurposeAddressOf);
3701 IrInstruction *container_ref_instruction = ir_gen_node_extra(irb, container_ref_node, scope, LVAL_PTR);
36913702 if (container_ref_instruction == irb->codegen->invalid_instruction)
36923703 return container_ref_instruction;
36933704
36943705 IrInstruction *ptr_instruction = ir_build_field_ptr(irb, scope, node, container_ref_instruction, field_name);
3695 if (lval != LValPurposeNone)
3706 if (lval.is_ptr)
36963707 return ptr_instruction;
36973708
36983709 return ir_build_load_ptr(irb, scope, node, ptr_instruction);
......@@ -4199,20 +4210,6 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
41994210 return ir_build_set_global_section(irb, scope, node, tld_var, arg1_value);
42004211 }
42014212 }
4202 case BuiltinFnIdVolatileStore:
4203 {
4204 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
4205 IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
4206 if (arg0_value == irb->codegen->invalid_instruction)
4207 return arg0_value;
4208
4209 AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
4210 IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
4211 if (arg1_value == irb->codegen->invalid_instruction)
4212 return arg1_value;
4213
4214 return ir_build_store_ptr(irb, scope, node, arg0_value, arg1_value, true);
4215 }
42164213 }
42174214 zig_unreachable();
42184215}
......@@ -4295,7 +4292,7 @@ static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, Scope *scope, AstNode
42954292 return ir_build_phi(irb, scope, node, 2, incoming_blocks, incoming_values);
42964293}
42974294
4298static IrInstruction *ir_gen_prefix_op_id_lval(IrBuilder *irb, Scope *scope, AstNode *node, IrUnOp op_id, LValPurpose lval) {
4295static IrInstruction *ir_gen_prefix_op_id_lval(IrBuilder *irb, Scope *scope, AstNode *node, IrUnOp op_id, LVal lval) {
42994296 assert(node->type == NodeTypePrefixOpExpr);
43004297 AstNode *expr_node = node->data.prefix_op_expr.primary_expr;
43014298
......@@ -4307,38 +4304,38 @@ static IrInstruction *ir_gen_prefix_op_id_lval(IrBuilder *irb, Scope *scope, Ast
43074304}
43084305
43094306static IrInstruction *ir_gen_prefix_op_id(IrBuilder *irb, Scope *scope, AstNode *node, IrUnOp op_id) {
4310 return ir_gen_prefix_op_id_lval(irb, scope, node, op_id, LValPurposeNone);
4307 return ir_gen_prefix_op_id_lval(irb, scope, node, op_id, LVAL_NONE);
43114308}
43124309
4313static IrInstruction *ir_lval_wrap(IrBuilder *irb, Scope *scope, IrInstruction *value, LValPurpose lval) {
4314 if (lval == LValPurposeNone)
4310static IrInstruction *ir_lval_wrap(IrBuilder *irb, Scope *scope, IrInstruction *value, LVal lval) {
4311 if (!lval.is_ptr)
43154312 return value;
43164313 if (value == irb->codegen->invalid_instruction)
43174314 return value;
43184315
43194316 // We needed a pointer to a value, but we got a value. So we create
43204317 // an instruction which just makes a const pointer of it.
4321 return ir_build_ref(irb, scope, value->source_node, value, true);
4318 return ir_build_ref(irb, scope, value->source_node, value, true, false);
43224319}
43234320
4324static IrInstruction *ir_gen_address_of(IrBuilder *irb, Scope *scope, AstNode *node, bool is_const, LValPurpose lval) {
4321static IrInstruction *ir_gen_address_of(IrBuilder *irb, Scope *scope, AstNode *node,
4322 bool is_const, bool is_volatile, LVal lval)
4323{
43254324 assert(node->type == NodeTypePrefixOpExpr);
43264325 AstNode *expr_node = node->data.prefix_op_expr.primary_expr;
43274326
4328 IrInstruction *value = ir_gen_node_extra(irb, expr_node, scope,
4329 is_const ? LValPurposeAddressOfConst : LValPurposeAddressOf);
4327 IrInstruction *value = ir_gen_node_extra(irb, expr_node, scope, make_lval_addr(is_const, is_volatile));
43304328 if (value == irb->codegen->invalid_instruction)
43314329 return value;
43324330
4333
43344331 return ir_lval_wrap(irb, scope, value, lval);
43354332}
43364333
4337static IrInstruction *ir_gen_err_assert_ok(IrBuilder *irb, Scope *scope, AstNode *node, LValPurpose lval) {
4334static IrInstruction *ir_gen_err_assert_ok(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval) {
43384335 assert(node->type == NodeTypePrefixOpExpr);
43394336 AstNode *expr_node = node->data.prefix_op_expr.primary_expr;
43404337
4341 IrInstruction *err_union_ptr = ir_gen_node_extra(irb, expr_node, scope, LValPurposeAddressOf);
4338 IrInstruction *err_union_ptr = ir_gen_node_extra(irb, expr_node, scope, LVAL_PTR);
43424339 if (err_union_ptr == irb->codegen->invalid_instruction)
43434340 return irb->codegen->invalid_instruction;
43444341
......@@ -4346,25 +4343,25 @@ static IrInstruction *ir_gen_err_assert_ok(IrBuilder *irb, Scope *scope, AstNode
43464343 if (payload_ptr == irb->codegen->invalid_instruction)
43474344 return irb->codegen->invalid_instruction;
43484345
4349 if (lval == LValPurposeNone)
4350 return ir_build_load_ptr(irb, scope, node, payload_ptr);
4351 else
4346 if (lval.is_ptr)
43524347 return payload_ptr;
4348
4349 return ir_build_load_ptr(irb, scope, node, payload_ptr);
43534350}
43544351
4355static IrInstruction *ir_gen_maybe_assert_ok(IrBuilder *irb, Scope *scope, AstNode *node, LValPurpose lval) {
4352static IrInstruction *ir_gen_maybe_assert_ok(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval) {
43564353 assert(node->type == NodeTypePrefixOpExpr);
43574354 AstNode *expr_node = node->data.prefix_op_expr.primary_expr;
43584355
4359 IrInstruction *maybe_ptr = ir_gen_node_extra(irb, expr_node, scope, LValPurposeAddressOf);
4356 IrInstruction *maybe_ptr = ir_gen_node_extra(irb, expr_node, scope, LVAL_PTR);
43604357 if (maybe_ptr == irb->codegen->invalid_instruction)
43614358 return irb->codegen->invalid_instruction;
43624359
43634360 IrInstruction *unwrapped_ptr = ir_build_unwrap_maybe(irb, scope, node, maybe_ptr, true);
4364 if (lval == LValPurposeNone)
4365 return ir_build_load_ptr(irb, scope, node, unwrapped_ptr);
4366 else
4361 if (lval.is_ptr)
43674362 return unwrapped_ptr;
4363
4364 return ir_build_load_ptr(irb, scope, node, unwrapped_ptr);
43684365}
43694366
43704367static IrInstruction *ir_gen_bool_not(IrBuilder *irb, Scope *scope, AstNode *node) {
......@@ -4378,7 +4375,7 @@ static IrInstruction *ir_gen_bool_not(IrBuilder *irb, Scope *scope, AstNode *nod
43784375 return ir_build_bool_not(irb, scope, node, value);
43794376}
43804377
4381static IrInstruction *ir_gen_prefix_op_expr(IrBuilder *irb, Scope *scope, AstNode *node, LValPurpose lval) {
4378static IrInstruction *ir_gen_prefix_op_expr(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval) {
43824379 assert(node->type == NodeTypePrefixOpExpr);
43834380
43844381 PrefixOp prefix_op = node->data.prefix_op_expr.prefix_op;
......@@ -4395,9 +4392,13 @@ static IrInstruction *ir_gen_prefix_op_expr(IrBuilder *irb, Scope *scope, AstNod
43954392 case PrefixOpNegationWrap:
43964393 return ir_lval_wrap(irb, scope, ir_gen_prefix_op_id(irb, scope, node, IrUnOpNegationWrap), lval);
43974394 case PrefixOpAddressOf:
4398 return ir_gen_address_of(irb, scope, node, false, lval);
4395 return ir_gen_address_of(irb, scope, node, false, false, lval);
43994396 case PrefixOpConstAddressOf:
4400 return ir_gen_address_of(irb, scope, node, true, lval);
4397 return ir_gen_address_of(irb, scope, node, true, false, lval);
4398 case PrefixOpVolatileAddressOf:
4399 return ir_gen_address_of(irb, scope, node, false, true, lval);
4400 case PrefixOpConstVolatileAddressOf:
4401 return ir_gen_address_of(irb, scope, node, true, true, lval);
44014402 case PrefixOpDereference:
44024403 return ir_gen_prefix_op_id_lval(irb, scope, node, IrUnOpDereference, lval);
44034404 case PrefixOpMaybe:
......@@ -4559,7 +4560,7 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo
45594560 }
45604561 assert(elem_node->type == NodeTypeSymbol);
45614562
4562 IrInstruction *array_val_ptr = ir_gen_node_extra(irb, array_node, parent_scope, LValPurposeAddressOf);
4563 IrInstruction *array_val_ptr = ir_gen_node_extra(irb, array_node, parent_scope, LVAL_PTR);
45634564 if (array_val_ptr == irb->codegen->invalid_instruction)
45644565 return array_val_ptr;
45654566
......@@ -4627,7 +4628,7 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo
46274628 } else {
46284629 elem_val = ir_build_load_ptr(irb, child_scope, node, elem_ptr);
46294630 }
4630 ir_mark_gen(ir_build_store_ptr(irb, child_scope, node, elem_var_ptr, elem_val, false));
4631 ir_mark_gen(ir_build_store_ptr(irb, child_scope, node, elem_var_ptr, elem_val));
46314632
46324633 LoopStackItem *loop_stack_item = irb->loop_stack.add_one();
46334634 loop_stack_item->break_block = end_block;
......@@ -4641,7 +4642,7 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo
46414642
46424643 ir_set_cursor_at_end(irb, continue_block);
46434644 IrInstruction *new_index_val = ir_build_bin_op(irb, child_scope, node, IrBinOpAdd, index_val, one, false);
4644 ir_mark_gen(ir_build_store_ptr(irb, child_scope, node, index_ptr, new_index_val, false));
4645 ir_mark_gen(ir_build_store_ptr(irb, child_scope, node, index_ptr, new_index_val));
46454646 ir_build_br(irb, child_scope, node, cond_block, is_comptime);
46464647
46474648 ir_set_cursor_at_end(irb, end_block);
......@@ -4783,7 +4784,7 @@ static IrInstruction *ir_gen_if_var_expr(IrBuilder *irb, Scope *scope, AstNode *
47834784 AstNode *else_node = node->data.if_var_expr.else_node;
47844785 bool var_is_ptr = node->data.if_var_expr.var_is_ptr;
47854786
4786 IrInstruction *maybe_val_ptr = ir_gen_node_extra(irb, expr_node, scope, LValPurposeAddressOf);
4787 IrInstruction *maybe_val_ptr = ir_gen_node_extra(irb, expr_node, scope, LVAL_PTR);
47874788 if (maybe_val_ptr == irb->codegen->invalid_instruction)
47884789 return maybe_val_ptr;
47894790
......@@ -4859,7 +4860,7 @@ static IrInstruction *ir_gen_try_expr(IrBuilder *irb, Scope *scope, AstNode *nod
48594860 Buf *var_symbol = node->data.try_expr.var_symbol;
48604861 Buf *err_symbol = node->data.try_expr.err_symbol;
48614862
4862 IrInstruction *err_val_ptr = ir_gen_node_extra(irb, target_node, scope, LValPurposeAddressOf);
4863 IrInstruction *err_val_ptr = ir_gen_node_extra(irb, target_node, scope, LVAL_PTR);
48634864 if (err_val_ptr == irb->codegen->invalid_instruction)
48644865 return err_val_ptr;
48654866
......@@ -4987,7 +4988,7 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode *
49874988 assert(node->type == NodeTypeSwitchExpr);
49884989
49894990 AstNode *target_node = node->data.switch_expr.expr;
4990 IrInstruction *target_value_ptr = ir_gen_node_extra(irb, target_node, scope, LValPurposeAddressOf);
4991 IrInstruction *target_value_ptr = ir_gen_node_extra(irb, target_node, scope, LVAL_PTR);
49914992 if (target_value_ptr == irb->codegen->invalid_instruction)
49924993 return target_value_ptr;
49934994 IrInstruction *target_value = ir_build_switch_target(irb, scope, node, target_value_ptr);
......@@ -5175,7 +5176,7 @@ static IrInstruction *ir_gen_goto(IrBuilder *irb, Scope *scope, AstNode *node) {
51755176 return ir_build_unreachable(irb, scope, node);
51765177}
51775178
5178static IrInstruction *ir_gen_comptime(IrBuilder *irb, Scope *parent_scope, AstNode *node, LValPurpose lval) {
5179static IrInstruction *ir_gen_comptime(IrBuilder *irb, Scope *parent_scope, AstNode *node, LVal lval) {
51795180 assert(node->type == NodeTypeCompTime);
51805181
51815182 Scope *child_scope = create_comptime_scope(node, parent_scope);
......@@ -5285,7 +5286,7 @@ static IrInstruction *ir_gen_err_ok_or(IrBuilder *irb, Scope *parent_scope, AstN
52855286 AstNode *op2_node = node->data.unwrap_err_expr.op2;
52865287 AstNode *var_node = node->data.unwrap_err_expr.symbol;
52875288
5288 IrInstruction *err_union_ptr = ir_gen_node_extra(irb, op1_node, parent_scope, LValPurposeAddressOf);
5289 IrInstruction *err_union_ptr = ir_gen_node_extra(irb, op1_node, parent_scope, LVAL_PTR);
52895290 if (err_union_ptr == irb->codegen->invalid_instruction)
52905291 return irb->codegen->invalid_instruction;
52915292
......@@ -5423,7 +5424,7 @@ static IrInstruction *ir_gen_fn_proto(IrBuilder *irb, Scope *parent_scope, AstNo
54235424}
54245425
54255426static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scope,
5426 LValPurpose lval)
5427 LVal lval)
54275428{
54285429 assert(scope);
54295430 switch (node->type) {
......@@ -5522,16 +5523,14 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
55225523 zig_unreachable();
55235524}
55245525
5525static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, Scope *scope,
5526 LValPurpose lval)
5527{
5526static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, Scope *scope, LVal lval) {
55285527 IrInstruction *result = ir_gen_node_raw(irb, node, scope, lval);
55295528 irb->exec->invalid = irb->exec->invalid || (result == irb->codegen->invalid_instruction);
55305529 return result;
55315530}
55325531
55335532static IrInstruction *ir_gen_node(IrBuilder *irb, AstNode *node, Scope *scope) {
5534 return ir_gen_node_extra(irb, node, scope, LValPurposeNone);
5533 return ir_gen_node_extra(irb, node, scope, LVAL_NONE);
55355534}
55365535
55375536static bool ir_goto_pass2(IrBuilder *irb) {
......@@ -5589,7 +5588,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
55895588 // Entry block gets a reference because we enter it to begin.
55905589 ir_ref_bb(irb->current_basic_block);
55915590
5592 IrInstruction *result = ir_gen_node_extra(irb, node, scope, LValPurposeNone);
5591 IrInstruction *result = ir_gen_node_extra(irb, node, scope, LVAL_NONE);
55935592 assert(result);
55945593 if (irb->exec->invalid)
55955594 return false;
......@@ -6178,7 +6177,7 @@ static TypeTableEntry *ir_analyze_void(IrAnalyze *ira, IrInstruction *instructio
61786177
61796178static TypeTableEntry *ir_analyze_const_ptr(IrAnalyze *ira, IrInstruction *instruction,
61806179 ConstExprValue *pointee, TypeTableEntry *pointee_type, bool depends_on_compile_var,
6181 ConstPtrSpecial special, bool ptr_is_const)
6180 ConstPtrSpecial special, bool ptr_is_const, bool ptr_is_volatile)
61826181{
61836182 if (pointee_type->id == TypeTableEntryIdMetaType) {
61846183 TypeTableEntry *type_entry = pointee->data.x_type;
......@@ -6190,10 +6189,12 @@ static TypeTableEntry *ir_analyze_const_ptr(IrAnalyze *ira, IrInstruction *instr
61906189 ConstExprValue *const_val = ir_build_const_from(ira, instruction,
61916190 depends_on_compile_var || pointee->depends_on_compile_var);
61926191 type_ensure_zero_bits_known(ira->codegen, type_entry);
6193 const_val->data.x_type = get_pointer_to_type(ira->codegen, type_entry, ptr_is_const);
6192 const_val->data.x_type = get_pointer_to_type_volatile(ira->codegen, type_entry,
6193 ptr_is_const, ptr_is_volatile);
61946194 return pointee_type;
61956195 } else {
6196 TypeTableEntry *ptr_type = get_pointer_to_type(ira->codegen, pointee_type, ptr_is_const);
6196 TypeTableEntry *ptr_type = get_pointer_to_type_volatile(ira->codegen, pointee_type,
6197 ptr_is_const, ptr_is_volatile);
61976198 ConstExprValue *const_val = ir_build_const_from(ira, instruction,
61986199 depends_on_compile_var || pointee->depends_on_compile_var);
61996200 const_val->data.x_ptr.base_ptr = pointee;
......@@ -6433,7 +6434,9 @@ static IrInstruction *ir_analyze_err_wrap_code(IrAnalyze *ira, IrInstruction *so
64336434 return result;
64346435}
64356436
6436static IrInstruction *ir_analyze_cast_ref(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value, TypeTableEntry *wanted_type) {
6437static IrInstruction *ir_analyze_cast_ref(IrAnalyze *ira, IrInstruction *source_instr,
6438 IrInstruction *value, TypeTableEntry *wanted_type)
6439{
64376440 if (instr_is_comptime(value)) {
64386441 ConstExprValue *val = ir_resolve_const(ira, value, UndefBad);
64396442 if (!val)
......@@ -6454,7 +6457,7 @@ static IrInstruction *ir_analyze_cast_ref(IrAnalyze *ira, IrInstruction *source_
64546457 return load_ptr_inst->ptr;
64556458 } else {
64566459 IrInstruction *new_instruction = ir_build_ref(&ira->new_irb, source_instr->scope,
6457 source_instr->source_node, value, true);
6460 source_instr->source_node, value, true, false);
64586461 new_instruction->value.type = wanted_type;
64596462
64606463 TypeTableEntry *child_type = wanted_type->data.pointer.child_type;
......@@ -6997,7 +7000,7 @@ static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruc
69977000}
69987001
69997002static TypeTableEntry *ir_analyze_ref(IrAnalyze *ira, IrInstruction *source_instruction, IrInstruction *value,
7000 bool is_const)
7003 bool is_const, bool is_volatile)
70017004{
70027005 if (value->value.type->id == TypeTableEntryIdInvalid)
70037006 return ira->codegen->builtin_types.entry_invalid;
......@@ -7007,13 +7010,14 @@ static TypeTableEntry *ir_analyze_ref(IrAnalyze *ira, IrInstruction *source_inst
70077010 if (!val)
70087011 return ira->codegen->builtin_types.entry_invalid;
70097012 return ir_analyze_const_ptr(ira, source_instruction, val, value->value.type,
7010 value->value.depends_on_compile_var, ConstPtrSpecialNone, is_const);
7013 value->value.depends_on_compile_var, ConstPtrSpecialNone, is_const, is_volatile);
70117014 }
70127015
7013 TypeTableEntry *ptr_type = get_pointer_to_type(ira->codegen, value->value.type, true);
7016 TypeTableEntry *ptr_type = get_pointer_to_type_volatile(ira->codegen, value->value.type, is_const, is_volatile);
70147017 FnTableEntry *fn_entry = exec_fn_entry(ira->new_irb.exec);
70157018 assert(fn_entry);
7016 IrInstruction *new_instruction = ir_build_ref_from(&ira->new_irb, source_instruction, value, is_const);
7019 IrInstruction *new_instruction = ir_build_ref_from(&ira->new_irb, source_instruction,
7020 value, is_const, is_volatile);
70177021 fn_entry->alloca_list.append(new_instruction);
70187022 return ptr_type;
70197023}
......@@ -8700,7 +8704,7 @@ static TypeTableEntry *ir_analyze_var_ptr(IrAnalyze *ira, IrInstruction *instruc
87008704 bool is_const = (var->value.type->id == TypeTableEntryIdMetaType) ? is_const_ptr : var->src_is_const;
87018705 depends_on_compile_var = mem_slot->depends_on_compile_var || depends_on_compile_var || is_comptime;
87028706 return ir_analyze_const_ptr(ira, instruction, mem_slot, var->value.type,
8703 depends_on_compile_var, ptr_special, is_const);
8707 depends_on_compile_var, ptr_special, is_const, false);
87048708 } else {
87058709 ir_build_var_ptr_from(&ira->new_irb, instruction, var, false);
87068710 type_ensure_zero_bits_known(ira->codegen, var->value.type);
......@@ -8786,7 +8790,8 @@ static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruc
87868790 return ir_analyze_var_ptr(ira, &elem_ptr_instruction->base, var, true, depends_on_compile_var);
87878791 } else {
87888792 return ir_analyze_const_ptr(ira, &elem_ptr_instruction->base, &ira->codegen->const_void_val,
8789 ira->codegen->builtin_types.entry_void, depends_on_compile_var, ConstPtrSpecialNone, true);
8793 ira->codegen->builtin_types.entry_void, depends_on_compile_var, ConstPtrSpecialNone,
8794 true, false);
87908795 }
87918796 } else {
87928797 ir_add_error_node(ira, elem_ptr_instruction->base.source_node,
......@@ -8894,7 +8899,7 @@ static TypeTableEntry *ir_analyze_container_member_access_inner(IrAnalyze *ira,
88948899 bool depends_on_compile_var = container_ptr->value.depends_on_compile_var;
88958900 IrInstruction *bound_fn_value = ir_build_const_bound_fn(&ira->new_irb, field_ptr_instruction->base.scope,
88968901 field_ptr_instruction->base.source_node, fn_entry, container_ptr, depends_on_compile_var);
8897 return ir_analyze_ref(ira, &field_ptr_instruction->base, bound_fn_value, true);
8902 return ir_analyze_ref(ira, &field_ptr_instruction->base, bound_fn_value, true, false);
88988903 }
88998904 }
89008905 ir_add_error_node(ira, field_ptr_instruction->base.source_node,
......@@ -8911,6 +8916,7 @@ static TypeTableEntry *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field
89118916
89128917 assert(container_ptr->value.type->id == TypeTableEntryIdPointer);
89138918 bool is_const = container_ptr->value.type->data.pointer.is_const;
8919 bool is_volatile = container_ptr->value.type->data.pointer.is_volatile;
89148920 if (bare_type->id == TypeTableEntryIdStruct) {
89158921 if (bare_type->data.structure.is_invalid)
89168922 return ira->codegen->builtin_types.entry_invalid;
......@@ -8929,12 +8935,12 @@ static TypeTableEntry *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field
89298935 bool depends_on_compile_var = field_val->depends_on_compile_var ||
89308936 struct_val->depends_on_compile_var || ptr_val->depends_on_compile_var;
89318937 return ir_analyze_const_ptr(ira, &field_ptr_instruction->base, field_val,
8932 field_val->type, depends_on_compile_var, ConstPtrSpecialNone, is_const);
8938 field_val->type, depends_on_compile_var, ConstPtrSpecialNone, is_const, is_volatile);
89338939 }
89348940 }
89358941 }
89368942 ir_build_struct_field_ptr_from(&ira->new_irb, &field_ptr_instruction->base, container_ptr, field);
8937 return get_pointer_to_type(ira->codegen, field->type_entry, is_const);
8943 return get_pointer_to_type_volatile(ira->codegen, field->type_entry, is_const, is_volatile);
89388944 } else {
89398945 return ir_analyze_container_member_access_inner(ira, bare_type, field_name,
89408946 field_ptr_instruction, container_ptr, container_type);
......@@ -8946,7 +8952,7 @@ static TypeTableEntry *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field
89468952 TypeEnumField *field = find_enum_type_field(bare_type, field_name);
89478953 if (field) {
89488954 ir_build_enum_field_ptr_from(&ira->new_irb, &field_ptr_instruction->base, container_ptr, field);
8949 return get_pointer_to_type(ira->codegen, field->type_entry, is_const);
8955 return get_pointer_to_type_volatile(ira->codegen, field->type_entry, is_const, is_volatile);
89508956 } else {
89518957 return ir_analyze_container_member_access_inner(ira, bare_type, field_name,
89528958 field_ptr_instruction, container_ptr, container_type);
......@@ -8992,8 +8998,9 @@ static TypeTableEntry *ir_analyze_decl_ref(IrAnalyze *ira, IrInstruction *source
89928998 const_val->data.x_fn = fn_entry;
89938999
89949000 bool ptr_is_const = true;
9001 bool ptr_is_volatile = false;
89959002 return ir_analyze_const_ptr(ira, source_instruction, const_val, fn_entry->type_entry,
8996 depends_on_compile_var, ConstPtrSpecialNone, ptr_is_const);
9003 depends_on_compile_var, ConstPtrSpecialNone, ptr_is_const, ptr_is_volatile);
89979004 }
89989005 case TldIdTypeDef:
89999006 {
......@@ -9008,8 +9015,9 @@ static TypeTableEntry *ir_analyze_decl_ref(IrAnalyze *ira, IrInstruction *source
90089015 const_val->data.x_type = tld_typedef->type_entry;
90099016
90109017 bool ptr_is_const = true;
9018 bool ptr_is_volatile = false;
90119019 return ir_analyze_const_ptr(ira, source_instruction, const_val, ira->codegen->builtin_types.entry_type,
9012 depends_on_compile_var, ConstPtrSpecialNone, ptr_is_const);
9020 depends_on_compile_var, ConstPtrSpecialNone, ptr_is_const, ptr_is_volatile);
90139021 }
90149022 }
90159023 zig_unreachable();
......@@ -9051,8 +9059,9 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru
90519059
90529060 TypeTableEntry *usize = ira->codegen->builtin_types.entry_usize;
90539061 bool ptr_is_const = true;
9062 bool ptr_is_volatile = false;
90549063 return ir_analyze_const_ptr(ira, &field_ptr_instruction->base, len_val,
9055 usize, false, ConstPtrSpecialNone, ptr_is_const);
9064 usize, false, ConstPtrSpecialNone, ptr_is_const, ptr_is_volatile);
90569065 } else {
90579066 ir_add_error_node(ira, source_node,
90589067 buf_sprintf("no member named '%s' in '%s'", buf_ptr(field_name),
......@@ -9074,8 +9083,9 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru
90749083
90759084 TypeTableEntry *usize = ira->codegen->builtin_types.entry_usize;
90769085 bool ptr_is_const = true;
9086 bool ptr_is_volatile = false;
90779087 return ir_analyze_const_ptr(ira, &field_ptr_instruction->base, len_val,
9078 usize, false, ConstPtrSpecialNone, ptr_is_const);
9088 usize, false, ConstPtrSpecialNone, ptr_is_const, ptr_is_volatile);
90799089 } else {
90809090 ir_add_error_node(ira, source_node,
90819091 buf_sprintf("no member named '%s' in '%s'", buf_ptr(field_name),
......@@ -9111,15 +9121,17 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru
91119121 if (field) {
91129122 if (field->type_entry->id == TypeTableEntryIdVoid) {
91139123 bool ptr_is_const = true;
9124 bool ptr_is_volatile = false;
91149125 return ir_analyze_const_ptr(ira, &field_ptr_instruction->base,
91159126 create_const_enum_tag(child_type, field->value), child_type, depends_on_compile_var,
9116 ConstPtrSpecialNone, ptr_is_const);
9127 ConstPtrSpecialNone, ptr_is_const, ptr_is_volatile);
91179128 } else {
91189129 bool ptr_is_const = true;
9130 bool ptr_is_volatile = false;
91199131 return ir_analyze_const_ptr(ira, &field_ptr_instruction->base,
91209132 create_const_unsigned_negative(child_type->data.enumeration.tag_type, field->value, false),
91219133 child_type->data.enumeration.tag_type, depends_on_compile_var,
9122 ConstPtrSpecialNone, ptr_is_const);
9134 ConstPtrSpecialNone, ptr_is_const, ptr_is_volatile);
91239135 }
91249136 }
91259137 }
......@@ -9142,8 +9154,9 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru
91429154 const_val->data.x_pure_err = err_table_entry->value;
91439155
91449156 bool ptr_is_const = true;
9157 bool ptr_is_volatile = false;
91459158 return ir_analyze_const_ptr(ira, &field_ptr_instruction->base, const_val,
9146 child_type, depends_on_compile_var, ConstPtrSpecialNone, ptr_is_const);
9159 child_type, depends_on_compile_var, ConstPtrSpecialNone, ptr_is_const, ptr_is_volatile);
91479160 }
91489161
91499162 ir_add_error(ira, &field_ptr_instruction->base,
......@@ -9152,17 +9165,19 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru
91529165 } else if (child_type->id == TypeTableEntryIdInt) {
91539166 if (buf_eql_str(field_name, "bit_count")) {
91549167 bool ptr_is_const = true;
9168 bool ptr_is_volatile = false;
91559169 return ir_analyze_const_ptr(ira, &field_ptr_instruction->base,
91569170 create_const_unsigned_negative(ira->codegen->builtin_types.entry_num_lit_int,
91579171 child_type->data.integral.bit_count, false),
91589172 ira->codegen->builtin_types.entry_num_lit_int, depends_on_compile_var,
9159 ConstPtrSpecialNone, ptr_is_const);
9173 ConstPtrSpecialNone, ptr_is_const, ptr_is_volatile);
91609174 } else if (buf_eql_str(field_name, "is_signed")) {
91619175 bool ptr_is_const = true;
9176 bool ptr_is_volatile = false;
91629177 return ir_analyze_const_ptr(ira, &field_ptr_instruction->base,
91639178 create_const_bool(ira->codegen, child_type->data.integral.is_signed),
91649179 ira->codegen->builtin_types.entry_bool, depends_on_compile_var,
9165 ConstPtrSpecialNone, ptr_is_const);
9180 ConstPtrSpecialNone, ptr_is_const, ptr_is_volatile);
91669181 } else {
91679182 ir_add_error(ira, &field_ptr_instruction->base,
91689183 buf_sprintf("type '%s' has no member called '%s'",
......@@ -9288,12 +9303,11 @@ static TypeTableEntry *ir_analyze_instruction_store_ptr(IrAnalyze *ira, IrInstru
92889303 }
92899304 new_ptr_inst->value.type = ptr->value.type;
92909305 ir_build_store_ptr(&ira->new_irb, store_ptr_instruction->base.scope,
9291 store_ptr_instruction->base.source_node, new_ptr_inst, casted_value, false);
9306 store_ptr_instruction->base.source_node, new_ptr_inst, casted_value);
92929307 return ir_analyze_void(ira, &store_ptr_instruction->base);
92939308 }
92949309
9295 ir_build_store_ptr_from(&ira->new_irb, &store_ptr_instruction->base, ptr, casted_value,
9296 store_ptr_instruction->is_volatile);
9310 ir_build_store_ptr_from(&ira->new_irb, &store_ptr_instruction->base, ptr, casted_value);
92979311 return ira->codegen->builtin_types.entry_void;
92989312}
92999313
......@@ -10337,7 +10351,7 @@ static TypeTableEntry *ir_analyze_instruction_array_len(IrAnalyze *ira,
1033710351
1033810352static TypeTableEntry *ir_analyze_instruction_ref(IrAnalyze *ira, IrInstructionRef *ref_instruction) {
1033910353 IrInstruction *value = ref_instruction->value->other;
10340 return ir_analyze_ref(ira, &ref_instruction->base, value, ref_instruction->is_const);
10354 return ir_analyze_ref(ira, &ref_instruction->base, value, ref_instruction->is_const, ref_instruction->is_volatile);
1034110355}
1034210356
1034310357static TypeTableEntry *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruction *instruction,
src/ir_print.cpp+2-4
......@@ -299,9 +299,6 @@ static void ir_print_store_ptr(IrPrint *irp, IrInstructionStorePtr *instruction)
299299 ir_print_var_instruction(irp, instruction->ptr);
300300 fprintf(irp->f, " = ");
301301 ir_print_other_instruction(irp, instruction->value);
302 if (instruction->is_volatile) {
303 fprintf(irp->f, " // volatile");
304 }
305302}
306303
307304static void ir_print_typeof(IrPrint *irp, IrInstructionTypeOf *instruction) {
......@@ -512,7 +509,8 @@ static void ir_print_array_len(IrPrint *irp, IrInstructionArrayLen *instruction)
512509
513510static void ir_print_ref(IrPrint *irp, IrInstructionRef *instruction) {
514511 const char *const_str = instruction->is_const ? "const " : "";
515 fprintf(irp->f, "%sref ", const_str);
512 const char *volatile_str = instruction->is_volatile ? "volatile " : "";
513 fprintf(irp->f, "%s%sref ", const_str, volatile_str);
516514 ir_print_other_instruction(irp, instruction->value);
517515}
518516
src/parser.cpp+13-4
......@@ -996,7 +996,7 @@ static PrefixOp tok_to_prefix_op(Token *token) {
996996
997997/*
998998PrefixOpExpression : PrefixOp PrefixOpExpression | SuffixOpExpression
999PrefixOp = "!" | "-" | "~" | "*" | ("&" option("const")) | "?" | "%" | "%%" | "??" | "-%"
999PrefixOp = "!" | "-" | "~" | "*" | ("&" option("const") option("volatile")) | "?" | "%" | "%%" | "??" | "-%"
10001000*/
10011001static AstNode *ast_parse_prefix_op_expr(ParseContext *pc, size_t *token_index, bool mandatory) {
10021002 Token *token = &pc->tokens->at(*token_index);
......@@ -1036,10 +1036,19 @@ static AstNode *ast_parse_prefix_op_expr(ParseContext *pc, size_t *token_index,
10361036 }
10371037
10381038 if (prefix_op == PrefixOpAddressOf) {
1039 Token *token = &pc->tokens->at(*token_index);
1040 if (token->id == TokenIdKeywordConst) {
1039 Token *const_or_volatile_tok = &pc->tokens->at(*token_index);
1040 if (const_or_volatile_tok->id == TokenIdKeywordConst) {
1041 *token_index += 1;
1042 Token *volatile_token = &pc->tokens->at(*token_index);
1043 if (volatile_token->id == TokenIdKeywordVolatile) {
1044 *token_index += 1;
1045 prefix_op = PrefixOpConstVolatileAddressOf;
1046 } else {
1047 prefix_op = PrefixOpConstAddressOf;
1048 }
1049 } else if (const_or_volatile_tok->id == TokenIdKeywordVolatile) {
1050 prefix_op = PrefixOpVolatileAddressOf;
10411051 *token_index += 1;
1042 prefix_op = PrefixOpConstAddressOf;
10431052 }
10441053 }
10451054
test/cases/misc.zig+9
......@@ -566,3 +566,12 @@ fn typeName() {
566566 assert(str.eql(@typeName(&usize), "&usize"));
567567 }
568568}
569
570fn volatileLoadAndStore() {
571 @setFnTest(this);
572
573 var number: i32 = 1234;
574 const ptr = &volatile number;
575 *ptr += 1;
576 assert(*ptr == 1235);
577}