| author | |
| committer | |
| log | b9360640cefd1aa30dedf71a0c6b7bddc51a6ae3 |
| tree | 89c751d93d98bee02e77fd7ac015845f398d8afd |
| parent | 859b10d8bfcca3c4a30798b4522fd88ec6c66de6 |
See #1747 files changed, 183 insertions(+), 11 deletions(-)
doc/langref.html.in+20-1| ... | @@ -3880,6 +3880,25 @@ pub fn main() void { | ... | @@ -3880,6 +3880,25 @@ pub fn main() void { |
| 3880 | {#header_open|@ArgType#} | 3880 | {#header_open|@ArgType#} |
| 3881 | <p>TODO</p> | 3881 | <p>TODO</p> |
| 3882 | {#header_close#} | 3882 | {#header_close#} |
| 3883 | {#header_open|@atomicLoad#} | ||
| 3884 | <pre><code class="zig">@atomicLoad(comptime T: type, ptr: &amp;const T, comptime ordering: builtin.AtomicOrder) -&gt; T</code></pre> | ||
| 3885 | <p> | ||
| 3886 | This builtin function atomically dereferences a pointer and returns the value. | ||
| 3887 | </p> | ||
| 3888 | <p> | ||
| 3889 | <code>T</code> must be a pointer type, a <code>bool</code>, | ||
| 3890 | or an integer whose bit count meets these requirements: | ||
| 3891 | </p> | ||
| 3892 | <ul> | ||
| 3893 | <li>At least 8</li> | ||
| 3894 | <li>At most the same as usize</li> | ||
| 3895 | <li>Power of 2</li> | ||
| 3896 | </ul> | ||
| 3897 | <p> | ||
| 3898 | TODO right now bool is not accepted. Also I think we could make non powers of 2 work fine, maybe | ||
| 3899 | we can remove this restriction | ||
| 3900 | </p> | ||
| 3901 | {#header_close#} | ||
| 3883 | {#header_open|@atomicRmw#} | 3902 | {#header_open|@atomicRmw#} |
| 3884 | <pre><code class="zig">@atomicRmw(comptime T: type, ptr: &amp;T, comptime op: builtin.AtomicRmwOp, operand: T, comptime ordering: builtin.AtomicOrder) -&gt; T</code></pre> | 3903 | <pre><code class="zig">@atomicRmw(comptime T: type, ptr: &amp;T, comptime op: builtin.AtomicRmwOp, operand: T, comptime ordering: builtin.AtomicOrder) -&gt; T</code></pre> |
| 3885 | <p> | 3904 | <p> |
| ... | @@ -6001,7 +6020,7 @@ hljs.registerLanguage("zig", function(t) { | ... | @@ -6001,7 +6020,7 @@ hljs.registerLanguage("zig", function(t) { |
| 6001 | a = t.IR + "\\s*\\(", | 6020 | a = t.IR + "\\s*\\(", |
| 6002 | c = { | 6021 | c = { |
| 6003 | keyword: "const align var extern stdcallcc nakedcc volatile export pub noalias inline struct packed enum union break return try catch test continue unreachable comptime and or asm defer errdefer if else switch while for fn use bool f32 f64 void type noreturn error i8 u8 i16 u16 i32 u32 i64 u64 isize usize i8w u8w i16w i32w u32w i64w u64w isizew usizew c_short c_ushort c_int c_uint c_long c_ulong c_longlong c_ulonglong", | 6022 | keyword: "const align var extern stdcallcc nakedcc volatile export pub noalias inline struct packed enum union break return try catch test continue unreachable comptime and or asm defer errdefer if else switch while for fn use bool f32 f64 void type noreturn error i8 u8 i16 u16 i32 u32 i64 u64 isize usize i8w u8w i16w i32w u32w i64w u64w isizew usizew c_short c_ushort c_int c_uint c_long c_ulong c_longlong c_ulonglong", |
| 6004 | built_in: "breakpoint returnAddress frameAddress fieldParentPtr setFloatMode IntType OpaqueType compileError compileLog setCold setRuntimeSafety setEvalBranchQuota offsetOf memcpy inlineCall setGlobalLinkage setGlobalSection divTrunc divFloor enumTagName intToPtr ptrToInt panic canImplicitCast ptrCast bitCast rem mod memset sizeOf alignOf alignCast maxValue minValue memberCount memberName memberType typeOf addWithOverflow subWithOverflow mulWithOverflow shlWithOverflow shlExact shrExact cInclude cDefine cUndef ctz clz import cImport errorName embedFile cmpxchg fence divExact truncate atomicRmw sqrt", | 6023 | built_in: "atomicLoad breakpoint returnAddress frameAddress fieldParentPtr setFloatMode IntType OpaqueType compileError compileLog setCold setRuntimeSafety setEvalBranchQuota offsetOf memcpy inlineCall setGlobalLinkage setGlobalSection divTrunc divFloor enumTagName intToPtr ptrToInt panic canImplicitCast ptrCast bitCast rem mod memset sizeOf alignOf alignCast maxValue minValue memberCount memberName memberType typeOf addWithOverflow subWithOverflow mulWithOverflow shlWithOverflow shlExact shrExact cInclude cDefine cUndef ctz clz import cImport errorName embedFile cmpxchg fence divExact truncate atomicRmw sqrt", |
| 6005 | literal: "true false null undefined" | 6024 | literal: "true false null undefined" |
| 6006 | }, | 6025 | }, |
| 6007 | n = [e, t.CLCM, t.CBCM, s, r]; | 6026 | n = [e, t.CLCM, t.CBCM, s, r]; |
src/all_types.hpp+11| ... | @@ -1347,6 +1347,7 @@ enum BuiltinFnId { | ... | @@ -1347,6 +1347,7 @@ enum BuiltinFnId { |
| 1347 | BuiltinFnIdExport, | 1347 | BuiltinFnIdExport, |
| 1348 | BuiltinFnIdErrorReturnTrace, | 1348 | BuiltinFnIdErrorReturnTrace, |
| 1349 | BuiltinFnIdAtomicRmw, | 1349 | BuiltinFnIdAtomicRmw, |
| 1350 | BuiltinFnIdAtomicLoad, | ||
| 1350 | }; | 1351 | }; |
| 1351 | 1352 | ||
| 1352 | struct BuiltinFnEntry { | 1353 | struct BuiltinFnEntry { |
| ... | @@ -2043,6 +2044,7 @@ enum IrInstructionId { | ... | @@ -2043,6 +2044,7 @@ enum IrInstructionId { |
| 2043 | IrInstructionIdCoroPromise, | 2044 | IrInstructionIdCoroPromise, |
| 2044 | IrInstructionIdCoroAllocHelper, | 2045 | IrInstructionIdCoroAllocHelper, |
| 2045 | IrInstructionIdAtomicRmw, | 2046 | IrInstructionIdAtomicRmw, |
| 2047 | IrInstructionIdAtomicLoad, | ||
| 2046 | IrInstructionIdPromiseResultType, | 2048 | IrInstructionIdPromiseResultType, |
| 2047 | IrInstructionIdAwaitBookkeeping, | 2049 | IrInstructionIdAwaitBookkeeping, |
| 2048 | IrInstructionIdSaveErrRetAddr, | 2050 | IrInstructionIdSaveErrRetAddr, |
| ... | @@ -3003,6 +3005,15 @@ struct IrInstructionAtomicRmw { | ... | @@ -3003,6 +3005,15 @@ struct IrInstructionAtomicRmw { |
| 3003 | AtomicOrder resolved_ordering; | 3005 | AtomicOrder resolved_ordering; |
| 3004 | }; | 3006 | }; |
| 3005 | 3007 | ||
| 3008 | struct IrInstructionAtomicLoad { | ||
| 3009 | IrInstruction base; | ||
| 3010 | |||
| 3011 | IrInstruction *operand_type; | ||
| 3012 | IrInstruction *ptr; | ||
| 3013 | IrInstruction *ordering; | ||
| 3014 | AtomicOrder resolved_ordering; | ||
| 3015 | }; | ||
| 3016 | |||
| 3006 | struct IrInstructionPromiseResultType { | 3017 | struct IrInstructionPromiseResultType { |
| 3007 | IrInstruction base; | 3018 | IrInstruction base; |
| 3008 | 3019 |
src/codegen.cpp+13| ... | @@ -4385,6 +4385,16 @@ static LLVMValueRef ir_render_atomic_rmw(CodeGen *g, IrExecutable *executable, | ... | @@ -4385,6 +4385,16 @@ static LLVMValueRef ir_render_atomic_rmw(CodeGen *g, IrExecutable *executable, |
| 4385 | return LLVMBuildIntToPtr(g->builder, uncasted_result, operand_type->type_ref, ""); | 4385 | return LLVMBuildIntToPtr(g->builder, uncasted_result, operand_type->type_ref, ""); |
| 4386 | } | 4386 | } |
| 4387 | 4387 | ||
| 4388 | static LLVMValueRef ir_render_atomic_load(CodeGen *g, IrExecutable *executable, | ||
| 4389 | IrInstructionAtomicLoad *instruction) | ||
| 4390 | { | ||
| 4391 | LLVMAtomicOrdering ordering = to_LLVMAtomicOrdering(instruction->resolved_ordering); | ||
| 4392 | LLVMValueRef ptr = ir_llvm_value(g, instruction->ptr); | ||
| 4393 | LLVMValueRef load_inst = gen_load(g, ptr, instruction->ptr->value.type, ""); | ||
| 4394 | LLVMSetOrdering(load_inst, ordering); | ||
| 4395 | return load_inst; | ||
| 4396 | } | ||
| 4397 | |||
| 4388 | static LLVMValueRef ir_render_merge_err_ret_traces(CodeGen *g, IrExecutable *executable, | 4398 | static LLVMValueRef ir_render_merge_err_ret_traces(CodeGen *g, IrExecutable *executable, |
| 4389 | IrInstructionMergeErrRetTraces *instruction) | 4399 | IrInstructionMergeErrRetTraces *instruction) |
| 4390 | { | 4400 | { |
| ... | @@ -4628,6 +4638,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, | ... | @@ -4628,6 +4638,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, |
| 4628 | return ir_render_coro_alloc_helper(g, executable, (IrInstructionCoroAllocHelper *)instruction); | 4638 | return ir_render_coro_alloc_helper(g, executable, (IrInstructionCoroAllocHelper *)instruction); |
| 4629 | case IrInstructionIdAtomicRmw: | 4639 | case IrInstructionIdAtomicRmw: |
| 4630 | return ir_render_atomic_rmw(g, executable, (IrInstructionAtomicRmw *)instruction); | 4640 | return ir_render_atomic_rmw(g, executable, (IrInstructionAtomicRmw *)instruction); |
| 4641 | case IrInstructionIdAtomicLoad: | ||
| 4642 | return ir_render_atomic_load(g, executable, (IrInstructionAtomicLoad *)instruction); | ||
| 4631 | case IrInstructionIdSaveErrRetAddr: | 4643 | case IrInstructionIdSaveErrRetAddr: |
| 4632 | return ir_render_save_err_ret_addr(g, executable, (IrInstructionSaveErrRetAddr *)instruction); | 4644 | return ir_render_save_err_ret_addr(g, executable, (IrInstructionSaveErrRetAddr *)instruction); |
| 4633 | case IrInstructionIdMergeErrRetTraces: | 4645 | case IrInstructionIdMergeErrRetTraces: |
| ... | @@ -6136,6 +6148,7 @@ static void define_builtin_fns(CodeGen *g) { | ... | @@ -6136,6 +6148,7 @@ static void define_builtin_fns(CodeGen *g) { |
| 6136 | create_builtin_fn(g, BuiltinFnIdExport, "export", 3); | 6148 | create_builtin_fn(g, BuiltinFnIdExport, "export", 3); |
| 6137 | create_builtin_fn(g, BuiltinFnIdErrorReturnTrace, "errorReturnTrace", 0); | 6149 | create_builtin_fn(g, BuiltinFnIdErrorReturnTrace, "errorReturnTrace", 0); |
| 6138 | create_builtin_fn(g, BuiltinFnIdAtomicRmw, "atomicRmw", 5); | 6150 | create_builtin_fn(g, BuiltinFnIdAtomicRmw, "atomicRmw", 5); |
| 6151 | create_builtin_fn(g, BuiltinFnIdAtomicLoad, "atomicLoad", 3); | ||
| 6139 | } | 6152 | } |
| 6140 | 6153 | ||
| 6141 | static const char *bool_to_str(bool b) { | 6154 | static const char *bool_to_str(bool b) { |
src/ir.cpp+104-8| ... | @@ -709,6 +709,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionAtomicRmw *) { | ... | @@ -709,6 +709,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionAtomicRmw *) { |
| 709 | return IrInstructionIdAtomicRmw; | 709 | return IrInstructionIdAtomicRmw; |
| 710 | } | 710 | } |
| 711 | 711 | ||
| 712 | static constexpr IrInstructionId ir_instruction_id(IrInstructionAtomicLoad *) { | ||
| 713 | return IrInstructionIdAtomicLoad; | ||
| 714 | } | ||
| 715 | |||
| 712 | static constexpr IrInstructionId ir_instruction_id(IrInstructionPromiseResultType *) { | 716 | static constexpr IrInstructionId ir_instruction_id(IrInstructionPromiseResultType *) { |
| 713 | return IrInstructionIdPromiseResultType; | 717 | return IrInstructionIdPromiseResultType; |
| 714 | } | 718 | } |
| ... | @@ -2673,6 +2677,23 @@ static IrInstruction *ir_build_atomic_rmw(IrBuilder *irb, Scope *scope, AstNode | ... | @@ -2673,6 +2677,23 @@ static IrInstruction *ir_build_atomic_rmw(IrBuilder *irb, Scope *scope, AstNode |
| 2673 | return &instruction->base; | 2677 | return &instruction->base; |
| 2674 | } | 2678 | } |
| 2675 | 2679 | ||
| 2680 | static IrInstruction *ir_build_atomic_load(IrBuilder *irb, Scope *scope, AstNode *source_node, | ||
| 2681 | IrInstruction *operand_type, IrInstruction *ptr, | ||
| 2682 | IrInstruction *ordering, AtomicOrder resolved_ordering) | ||
| 2683 | { | ||
| 2684 | IrInstructionAtomicLoad *instruction = ir_build_instruction<IrInstructionAtomicLoad>(irb, scope, source_node); | ||
| 2685 | instruction->operand_type = operand_type; | ||
| 2686 | instruction->ptr = ptr; | ||
| 2687 | instruction->ordering = ordering; | ||
| 2688 | instruction->resolved_ordering = resolved_ordering; | ||
| 2689 | |||
| 2690 | if (operand_type != nullptr) ir_ref_instruction(operand_type, irb->current_basic_block); | ||
| 2691 | ir_ref_instruction(ptr, irb->current_basic_block); | ||
| 2692 | if (ordering != nullptr) ir_ref_instruction(ordering, irb->current_basic_block); | ||
| 2693 | |||
| 2694 | return &instruction->base; | ||
| 2695 | } | ||
| 2696 | |||
| 2676 | static IrInstruction *ir_build_promise_result_type(IrBuilder *irb, Scope *scope, AstNode *source_node, | 2697 | static IrInstruction *ir_build_promise_result_type(IrBuilder *irb, Scope *scope, AstNode *source_node, |
| 2677 | IrInstruction *promise_type) | 2698 | IrInstruction *promise_type) |
| 2678 | { | 2699 | { |
| ... | @@ -4303,6 +4324,27 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo | ... | @@ -4303,6 +4324,27 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo |
| 4303 | // these 2 values don't mean anything since we passed non-null values for other args | 4324 | // these 2 values don't mean anything since we passed non-null values for other args |
| 4304 | AtomicRmwOp_xchg, AtomicOrderMonotonic); | 4325 | AtomicRmwOp_xchg, AtomicOrderMonotonic); |
| 4305 | } | 4326 | } |
| 4327 | case BuiltinFnIdAtomicLoad: | ||
| 4328 | { | ||
| 4329 | AstNode *arg0_node = node->data.fn_call_expr.params.at(0); | ||
| 4330 | IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope); | ||
| 4331 | if (arg0_value == irb->codegen->invalid_instruction) | ||
| 4332 | return arg0_value; | ||
| 4333 | |||
| 4334 | AstNode *arg1_node = node->data.fn_call_expr.params.at(1); | ||
| 4335 | IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope); | ||
| 4336 | if (arg1_value == irb->codegen->invalid_instruction) | ||
| 4337 | return arg1_value; | ||
| 4338 | |||
| 4339 | AstNode *arg2_node = node->data.fn_call_expr.params.at(2); | ||
| 4340 | IrInstruction *arg2_value = ir_gen_node(irb, arg2_node, scope); | ||
| 4341 | if (arg2_value == irb->codegen->invalid_instruction) | ||
| 4342 | return arg2_value; | ||
| 4343 | |||
| 4344 | return ir_build_atomic_load(irb, scope, node, arg0_value, arg1_value, arg2_value, | ||
| 4345 | // this value does not mean anything since we passed non-null values for other arg | ||
| 4346 | AtomicOrderMonotonic); | ||
| 4347 | } | ||
| 4306 | } | 4348 | } |
| 4307 | zig_unreachable(); | 4349 | zig_unreachable(); |
| 4308 | } | 4350 | } |
| ... | @@ -17898,35 +17940,43 @@ static TypeTableEntry *ir_analyze_instruction_coro_alloc_helper(IrAnalyze *ira, | ... | @@ -17898,35 +17940,43 @@ static TypeTableEntry *ir_analyze_instruction_coro_alloc_helper(IrAnalyze *ira, |
| 17898 | return result->value.type; | 17940 | return result->value.type; |
| 17899 | } | 17941 | } |
| 17900 | 17942 | ||
| 17901 | static TypeTableEntry *ir_analyze_instruction_atomic_rmw(IrAnalyze *ira, IrInstructionAtomicRmw *instruction) { | 17943 | static TypeTableEntry *ir_resolve_atomic_operand_type(IrAnalyze *ira, IrInstruction *op) { |
| 17902 | TypeTableEntry *operand_type = ir_resolve_type(ira, instruction->operand_type->other); | 17944 | TypeTableEntry *operand_type = ir_resolve_type(ira, op); |
| 17903 | if (type_is_invalid(operand_type)) { | 17945 | if (type_is_invalid(operand_type)) |
| 17904 | return ira->codegen->builtin_types.entry_invalid; | 17946 | return ira->codegen->builtin_types.entry_invalid; |
| 17905 | } | 17947 | |
| 17906 | if (operand_type->id == TypeTableEntryIdInt) { | 17948 | if (operand_type->id == TypeTableEntryIdInt) { |
| 17907 | if (operand_type->data.integral.bit_count < 8) { | 17949 | if (operand_type->data.integral.bit_count < 8) { |
| 17908 | ir_add_error(ira, &instruction->base, | 17950 | ir_add_error(ira, op, |
| 17909 | buf_sprintf("expected integer type 8 bits or larger, found %" PRIu32 "-bit integer type", | 17951 | buf_sprintf("expected integer type 8 bits or larger, found %" PRIu32 "-bit integer type", |
| 17910 | operand_type->data.integral.bit_count)); | 17952 | operand_type->data.integral.bit_count)); |
| 17911 | return ira->codegen->builtin_types.entry_invalid; | 17953 | return ira->codegen->builtin_types.entry_invalid; |
| 17912 | } | 17954 | } |
| 17913 | if (operand_type->data.integral.bit_count > ira->codegen->pointer_size_bytes * 8) { | 17955 | if (operand_type->data.integral.bit_count > ira->codegen->pointer_size_bytes * 8) { |
| 17914 | ir_add_error(ira, &instruction->base, | 17956 | ir_add_error(ira, op, |
| 17915 | buf_sprintf("expected integer type pointer size or smaller, found %" PRIu32 "-bit integer type", | 17957 | buf_sprintf("expected integer type pointer size or smaller, found %" PRIu32 "-bit integer type", |
| 17916 | operand_type->data.integral.bit_count)); | 17958 | operand_type->data.integral.bit_count)); |
| 17917 | return ira->codegen->builtin_types.entry_invalid; | 17959 | return ira->codegen->builtin_types.entry_invalid; |
| 17918 | } | 17960 | } |
| 17919 | if (!is_power_of_2(operand_type->data.integral.bit_count)) { | 17961 | if (!is_power_of_2(operand_type->data.integral.bit_count)) { |
| 17920 | ir_add_error(ira, &instruction->base, | 17962 | ir_add_error(ira, op, |
| 17921 | buf_sprintf("%" PRIu32 "-bit integer type is not a power of 2", operand_type->data.integral.bit_count)); | 17963 | buf_sprintf("%" PRIu32 "-bit integer type is not a power of 2", operand_type->data.integral.bit_count)); |
| 17922 | return ira->codegen->builtin_types.entry_invalid; | 17964 | return ira->codegen->builtin_types.entry_invalid; |
| 17923 | } | 17965 | } |
| 17924 | } else if (get_codegen_ptr_type(operand_type) == nullptr) { | 17966 | } else if (get_codegen_ptr_type(operand_type) == nullptr) { |
| 17925 | ir_add_error(ira, &instruction->base, | 17967 | ir_add_error(ira, op, |
| 17926 | buf_sprintf("expected integer or pointer type, found '%s'", buf_ptr(&operand_type->name))); | 17968 | buf_sprintf("expected integer or pointer type, found '%s'", buf_ptr(&operand_type->name))); |
| 17927 | return ira->codegen->builtin_types.entry_invalid; | 17969 | return ira->codegen->builtin_types.entry_invalid; |
| 17928 | } | 17970 | } |
| 17929 | 17971 | ||
| 17972 | return operand_type; | ||
| 17973 | } | ||
| 17974 | |||
| 17975 | static TypeTableEntry *ir_analyze_instruction_atomic_rmw(IrAnalyze *ira, IrInstructionAtomicRmw *instruction) { | ||
| 17976 | TypeTableEntry *operand_type = ir_resolve_atomic_operand_type(ira, instruction->operand_type->other); | ||
| 17977 | if (type_is_invalid(operand_type)) | ||
| 17978 | return ira->codegen->builtin_types.entry_invalid; | ||
| 17979 | |||
| 17930 | IrInstruction *ptr_inst = instruction->ptr->other; | 17980 | IrInstruction *ptr_inst = instruction->ptr->other; |
| 17931 | if (type_is_invalid(ptr_inst->value.type)) | 17981 | if (type_is_invalid(ptr_inst->value.type)) |
| 17932 | return ira->codegen->builtin_types.entry_invalid; | 17982 | return ira->codegen->builtin_types.entry_invalid; |
| ... | @@ -17974,6 +18024,49 @@ static TypeTableEntry *ir_analyze_instruction_atomic_rmw(IrAnalyze *ira, IrInstr | ... | @@ -17974,6 +18024,49 @@ static TypeTableEntry *ir_analyze_instruction_atomic_rmw(IrAnalyze *ira, IrInstr |
| 17974 | return result->value.type; | 18024 | return result->value.type; |
| 17975 | } | 18025 | } |
| 17976 | 18026 | ||
| 18027 | static TypeTableEntry *ir_analyze_instruction_atomic_load(IrAnalyze *ira, IrInstructionAtomicLoad *instruction) { | ||
| 18028 | TypeTableEntry *operand_type = ir_resolve_atomic_operand_type(ira, instruction->operand_type->other); | ||
| 18029 | if (type_is_invalid(operand_type)) | ||
| 18030 | return ira->codegen->builtin_types.entry_invalid; | ||
| 18031 | |||
| 18032 | IrInstruction *ptr_inst = instruction->ptr->other; | ||
| 18033 | if (type_is_invalid(ptr_inst->value.type)) | ||
| 18034 | return ira->codegen->builtin_types.entry_invalid; | ||
| 18035 | |||
| 18036 | TypeTableEntry *ptr_type = get_pointer_to_type(ira->codegen, operand_type, true); | ||
| 18037 | IrInstruction *casted_ptr = ir_implicit_cast(ira, ptr_inst, ptr_type); | ||
| 18038 | if (type_is_invalid(casted_ptr->value.type)) | ||
| 18039 | return ira->codegen->builtin_types.entry_invalid; | ||
| 18040 | |||
| 18041 | AtomicOrder ordering; | ||
| 18042 | if (instruction->ordering == nullptr) { | ||
| 18043 | ordering = instruction->resolved_ordering; | ||
| 18044 | } else { | ||
| 18045 | if (!ir_resolve_atomic_order(ira, instruction->ordering->other, &ordering)) | ||
| 18046 | return ira->codegen->builtin_types.entry_invalid; | ||
| 18047 | } | ||
| 18048 | |||
| 18049 | if (ordering == AtomicOrderRelease || ordering == AtomicOrderAcqRel) { | ||
| 18050 | assert(instruction->ordering != nullptr); | ||
| 18051 | ir_add_error(ira, instruction->ordering, | ||
| 18052 | buf_sprintf("@atomicLoad atomic ordering must not be Release or AcqRel")); | ||
| 18053 | return ira->codegen->builtin_types.entry_invalid; | ||
| 18054 | } | ||
| 18055 | |||
| 18056 | if (instr_is_comptime(casted_ptr)) { | ||
| 18057 | IrInstruction *result = ir_get_deref(ira, &instruction->base, casted_ptr); | ||
| 18058 | ir_link_new_instruction(result, &instruction->base); | ||
| 18059 | assert(result->value.type != nullptr); | ||
| 18060 | return result->value.type; | ||
| 18061 | } | ||
| 18062 | |||
| 18063 | IrInstruction *result = ir_build_atomic_load(&ira->new_irb, instruction->base.scope, | ||
| 18064 | instruction->base.source_node, nullptr, casted_ptr, nullptr, ordering); | ||
| 18065 | ir_link_new_instruction(result, &instruction->base); | ||
| 18066 | result->value.type = operand_type; | ||
| 18067 | return result->value.type; | ||
| 18068 | } | ||
| 18069 | |||
| 17977 | static TypeTableEntry *ir_analyze_instruction_promise_result_type(IrAnalyze *ira, IrInstructionPromiseResultType *instruction) { | 18070 | static TypeTableEntry *ir_analyze_instruction_promise_result_type(IrAnalyze *ira, IrInstructionPromiseResultType *instruction) { |
| 17978 | TypeTableEntry *promise_type = ir_resolve_type(ira, instruction->promise_type->other); | 18071 | TypeTableEntry *promise_type = ir_resolve_type(ira, instruction->promise_type->other); |
| 17979 | if (type_is_invalid(promise_type)) | 18072 | if (type_is_invalid(promise_type)) |
| ... | @@ -18357,6 +18450,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi | ... | @@ -18357,6 +18450,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi |
| 18357 | return ir_analyze_instruction_coro_alloc_helper(ira, (IrInstructionCoroAllocHelper *)instruction); | 18450 | return ir_analyze_instruction_coro_alloc_helper(ira, (IrInstructionCoroAllocHelper *)instruction); |
| 18358 | case IrInstructionIdAtomicRmw: | 18451 | case IrInstructionIdAtomicRmw: |
| 18359 | return ir_analyze_instruction_atomic_rmw(ira, (IrInstructionAtomicRmw *)instruction); | 18452 | return ir_analyze_instruction_atomic_rmw(ira, (IrInstructionAtomicRmw *)instruction); |
| 18453 | case IrInstructionIdAtomicLoad: | ||
| 18454 | return ir_analyze_instruction_atomic_load(ira, (IrInstructionAtomicLoad *)instruction); | ||
| 18360 | case IrInstructionIdPromiseResultType: | 18455 | case IrInstructionIdPromiseResultType: |
| 18361 | return ir_analyze_instruction_promise_result_type(ira, (IrInstructionPromiseResultType *)instruction); | 18456 | return ir_analyze_instruction_promise_result_type(ira, (IrInstructionPromiseResultType *)instruction); |
| 18362 | case IrInstructionIdAwaitBookkeeping: | 18457 | case IrInstructionIdAwaitBookkeeping: |
| ... | @@ -18584,6 +18679,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { | ... | @@ -18584,6 +18679,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 18584 | case IrInstructionIdCoroPromise: | 18679 | case IrInstructionIdCoroPromise: |
| 18585 | case IrInstructionIdPromiseResultType: | 18680 | case IrInstructionIdPromiseResultType: |
| 18586 | case IrInstructionIdSqrt: | 18681 | case IrInstructionIdSqrt: |
| 18682 | case IrInstructionIdAtomicLoad: | ||
| 18587 | return false; | 18683 | return false; |
| 18588 | 18684 | ||
| 18589 | case IrInstructionIdAsm: | 18685 | case IrInstructionIdAsm: |
src/ir_print.cpp+21| ... | @@ -1172,6 +1172,24 @@ static void ir_print_atomic_rmw(IrPrint *irp, IrInstructionAtomicRmw *instructio | ... | @@ -1172,6 +1172,24 @@ static void ir_print_atomic_rmw(IrPrint *irp, IrInstructionAtomicRmw *instructio |
| 1172 | fprintf(irp->f, ")"); | 1172 | fprintf(irp->f, ")"); |
| 1173 | } | 1173 | } |
| 1174 | 1174 | ||
| 1175 | static void ir_print_atomic_load(IrPrint *irp, IrInstructionAtomicLoad *instruction) { | ||
| 1176 | fprintf(irp->f, "@atomicLoad("); | ||
| 1177 | if (instruction->operand_type != nullptr) { | ||
| 1178 | ir_print_other_instruction(irp, instruction->operand_type); | ||
| 1179 | } else { | ||
| 1180 | fprintf(irp->f, "[TODO print]"); | ||
| 1181 | } | ||
| 1182 | fprintf(irp->f, ","); | ||
| 1183 | ir_print_other_instruction(irp, instruction->ptr); | ||
| 1184 | fprintf(irp->f, ","); | ||
| 1185 | if (instruction->ordering != nullptr) { | ||
| 1186 | ir_print_other_instruction(irp, instruction->ordering); | ||
| 1187 | } else { | ||
| 1188 | fprintf(irp->f, "[TODO print]"); | ||
| 1189 | } | ||
| 1190 | fprintf(irp->f, ")"); | ||
| 1191 | } | ||
| 1192 | |||
| 1175 | static void ir_print_await_bookkeeping(IrPrint *irp, IrInstructionAwaitBookkeeping *instruction) { | 1193 | static void ir_print_await_bookkeeping(IrPrint *irp, IrInstructionAwaitBookkeeping *instruction) { |
| 1176 | fprintf(irp->f, "@awaitBookkeeping("); | 1194 | fprintf(irp->f, "@awaitBookkeeping("); |
| 1177 | ir_print_other_instruction(irp, instruction->promise_result_type); | 1195 | ir_print_other_instruction(irp, instruction->promise_result_type); |
| ... | @@ -1605,6 +1623,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { | ... | @@ -1605,6 +1623,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { |
| 1605 | case IrInstructionIdSqrt: | 1623 | case IrInstructionIdSqrt: |
| 1606 | ir_print_sqrt(irp, (IrInstructionSqrt *)instruction); | 1624 | ir_print_sqrt(irp, (IrInstructionSqrt *)instruction); |
| 1607 | break; | 1625 | break; |
| 1626 | case IrInstructionIdAtomicLoad: | ||
| 1627 | ir_print_atomic_load(irp, (IrInstructionAtomicLoad *)instruction); | ||
| 1628 | break; | ||
| 1608 | } | 1629 | } |
| 1609 | fprintf(irp->f, "\n"); | 1630 | fprintf(irp->f, "\n"); |
| 1610 | } | 1631 | } |
std/os/index.zig+1-1| ... | @@ -2392,7 +2392,7 @@ pub const Thread = struct { | ... | @@ -2392,7 +2392,7 @@ pub const Thread = struct { |
| 2392 | 2392 | ||
| 2393 | pub fn wait(self: &const Thread) void { | 2393 | pub fn wait(self: &const Thread) void { |
| 2394 | while (true) { | 2394 | while (true) { |
| 2395 | const pid_value = self.pid; // TODO atomic load | 2395 | const pid_value = @atomicLoad(i32, &self.pid, builtin.AtomicOrder.SeqCst); |
| 2396 | if (pid_value == 0) break; | 2396 | if (pid_value == 0) break; |
| 2397 | const rc = linux.futex_wait(@ptrToInt(&self.pid), linux.FUTEX_WAIT, pid_value, null); | 2397 | const rc = linux.futex_wait(@ptrToInt(&self.pid), linux.FUTEX_WAIT, pid_value, null); |
| 2398 | switch (linux.getErrno(rc)) { | 2398 | switch (linux.getErrno(rc)) { |
test/cases/atomics.zig+13-1| ... | @@ -15,13 +15,25 @@ test "fence" { | ... | @@ -15,13 +15,25 @@ test "fence" { |
| 15 | x = 5678; | 15 | x = 5678; |
| 16 | } | 16 | } |
| 17 | 17 | ||
| 18 | test "atomicrmw" { | 18 | test "atomicrmw and atomicload" { |
| 19 | var data: u8 = 200; | 19 | var data: u8 = 200; |
| 20 | testAtomicRmw(&data); | 20 | testAtomicRmw(&data); |
| 21 | assert(data == 42); | 21 | assert(data == 42); |
| 22 | testAtomicLoad(&data); | ||
| 22 | } | 23 | } |
| 23 | 24 | ||
| 24 | fn testAtomicRmw(ptr: &u8) void { | 25 | fn testAtomicRmw(ptr: &u8) void { |
| 25 | const prev_value = @atomicRmw(u8, ptr, AtomicRmwOp.Xchg, 42, AtomicOrder.SeqCst); | 26 | const prev_value = @atomicRmw(u8, ptr, AtomicRmwOp.Xchg, 42, AtomicOrder.SeqCst); |
| 26 | assert(prev_value == 200); | 27 | assert(prev_value == 200); |
| 28 | comptime { | ||
| 29 | var x: i32 = 1234; | ||
| 30 | const y: i32 = 12345; | ||
| 31 | assert(@atomicLoad(i32, &x, AtomicOrder.SeqCst) == 1234); | ||
| 32 | assert(@atomicLoad(i32, &y, AtomicOrder.SeqCst) == 12345); | ||
| 33 | } | ||
| 34 | } | ||
| 35 | |||
| 36 | fn testAtomicLoad(ptr: &u8) void { | ||
| 37 | const x = @atomicLoad(u8, ptr, AtomicOrder.SeqCst); | ||
| 38 | assert(x == 42); | ||
| 27 | } | 39 | } |