authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-04-18 12:16:42-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-04-18 12:16:42-04:00
logf1f998e07124f141312289ff82e0ad8d99af1cf7
tree3c01eb14a0bd8e4cdd83f376097264f45efae2ff
parent96ebd8b23b39e2d4019a8019a6774d7c3d20149d

improve cmpxchg

* remove @cmpxchg, add @cmpxchgWeak and @cmpxchgStrong - See explanations in the langref. * add operand type as first parameter * return type is ?T where T is the operand type closes #461

8 files changed, 148 insertions(+), 63 deletions(-)

doc/langref.html.in+49-5
......@@ -4065,16 +4065,60 @@ comptime {
40654065 </p>
40664066
40674067 {#header_close#}
4068 {#header_open|@cmpxchg#}
4069 <pre><code class="zig">@cmpxchg(ptr: &T, cmp: T, new: T, success_order: AtomicOrder, fail_order: AtomicOrder) -&gt; bool</code></pre>
4068 {#header_open|@cmpxchgStrong#}
4069 <pre><code class="zig">@cmpxchgStrong(comptime T: type, ptr: &T, expected_value: T, new_value: T, success_order: AtomicOrder, fail_order: AtomicOrder) -&gt; ?T</code></pre>
40704070 <p>
4071 This function performs an atomic compare exchange operation.
4071 This function performs a strong atomic compare exchange operation. It's the equivalent of this code,
4072 except atomic:
4073 </p>
4074 {#code_begin|syntax#}
4075fn cmpxchgStrongButNotAtomic(comptime T: type, ptr: &T, expected_value: T, new_value: T) ?T {
4076 const old_value = *ptr;
4077 if (old_value == expected_value) {
4078 *ptr = new_value;
4079 return null;
4080 } else {
4081 return old_value;
4082 }
4083}
4084 {#code_end#}
4085 <p>
4086 If you are using cmpxchg in a loop, {#link|@cmpxchgWeak#} is the better choice, because it can be implemented
4087 more efficiently in machine instructions.
40724088 </p>
40734089 <p>
40744090 <code>AtomicOrder</code> can be found with <code>@import("builtin").AtomicOrder</code>.
40754091 </p>
40764092 <p><code>@typeOf(ptr).alignment</code> must be <code>&gt;= @sizeOf(T).</code></p>
4077 {#see_also|Compile Variables#}
4093 {#see_also|Compile Variables|cmpxchgWeak#}
4094 {#header_close#}
4095 {#header_open|@cmpxchgWeak#}
4096 <pre><code class="zig">@cmpxchgWeak(comptime T: type, ptr: &T, expected_value: T, new_value: T, success_order: AtomicOrder, fail_order: AtomicOrder) -&gt; ?T</code></pre>
4097 <p>
4098 This function performs a weak atomic compare exchange operation. It's the equivalent of this code,
4099 except atomic:
4100 </p>
4101 {#code_begin|syntax#}
4102fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: &T, expected_value: T, new_value: T) ?T {
4103 const old_value = *ptr;
4104 if (old_value == expected_value and usuallyTrueButSometimesFalse()) {
4105 *ptr = new_value;
4106 return null;
4107 } else {
4108 return old_value;
4109 }
4110}
4111 {#code_end#}
4112 <p>
4113 If you are using cmpxchg in a loop, the sporadic failure will be no problem, and <code>cmpxchgWeak</code>
4114 is the better choice, because it can be implemented more efficiently in machine instructions.
4115 However if you need a stronger guarantee, use {#link|@cmpxchgStrong#}.
4116 </p>
4117 <p>
4118 <code>AtomicOrder</code> can be found with <code>@import("builtin").AtomicOrder</code>.
4119 </p>
4120 <p><code>@typeOf(ptr).alignment</code> must be <code>&gt;= @sizeOf(T).</code></p>
4121 {#see_also|Compile Variables|cmpxchgStrong#}
40784122 {#header_close#}
40794123 {#header_open|@compileError#}
40804124 <pre><code class="zig">@compileError(comptime msg: []u8)</code></pre>
......@@ -6020,7 +6064,7 @@ hljs.registerLanguage("zig", function(t) {
60206064 a = t.IR + "\\s*\\(",
60216065 c = {
60226066 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",
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",
6067 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 cmpxchgStrong cmpxchgWeak fence divExact truncate atomicRmw sqrt",
60246068 literal: "true false null undefined"
60256069 },
60266070 n = [e, t.CLCM, t.CBCM, s, r];
src/all_types.hpp+8-1
......@@ -1310,7 +1310,8 @@ enum BuiltinFnId {
13101310 BuiltinFnIdReturnAddress,
13111311 BuiltinFnIdFrameAddress,
13121312 BuiltinFnIdEmbedFile,
1313 BuiltinFnIdCmpExchange,
1313 BuiltinFnIdCmpxchgWeak,
1314 BuiltinFnIdCmpxchgStrong,
13141315 BuiltinFnIdFence,
13151316 BuiltinFnIdDivExact,
13161317 BuiltinFnIdDivTrunc,
......@@ -2528,6 +2529,7 @@ struct IrInstructionEmbedFile {
25282529struct IrInstructionCmpxchg {
25292530 IrInstruction base;
25302531
2532 IrInstruction *type_value;
25312533 IrInstruction *ptr;
25322534 IrInstruction *cmp_value;
25332535 IrInstruction *new_value;
......@@ -2535,8 +2537,13 @@ struct IrInstructionCmpxchg {
25352537 IrInstruction *failure_order_value;
25362538
25372539 // if this instruction gets to runtime then we know these values:
2540 TypeTableEntry *type;
25382541 AtomicOrder success_order;
25392542 AtomicOrder failure_order;
2543
2544 bool is_weak;
2545
2546 LLVMValueRef tmp_ptr;
25402547};
25412548
25422549struct IrInstructionFence {
src/codegen.cpp+18-3
......@@ -3558,9 +3558,20 @@ static LLVMValueRef ir_render_cmpxchg(CodeGen *g, IrExecutable *executable, IrIn
35583558 LLVMAtomicOrdering failure_order = to_LLVMAtomicOrdering(instruction->failure_order);
35593559
35603560 LLVMValueRef result_val = ZigLLVMBuildCmpXchg(g->builder, ptr_val, cmp_val, new_val,
3561 success_order, failure_order);
3561 success_order, failure_order, instruction->is_weak);
35623562
3563 return LLVMBuildExtractValue(g->builder, result_val, 1, "");
3563 assert(instruction->tmp_ptr != nullptr);
3564 assert(type_has_bits(instruction->type));
3565
3566 LLVMValueRef payload_val = LLVMBuildExtractValue(g->builder, result_val, 0, "");
3567 LLVMValueRef val_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, maybe_child_index, "");
3568 gen_assign_raw(g, val_ptr, get_pointer_to_type(g, instruction->type, false), payload_val);
3569
3570 LLVMValueRef success_bit = LLVMBuildExtractValue(g->builder, result_val, 1, "");
3571 LLVMValueRef nonnull_bit = LLVMBuildNot(g->builder, success_bit, "");
3572 LLVMValueRef maybe_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, maybe_null_index, "");
3573 gen_store_untyped(g, nonnull_bit, maybe_ptr, 0, false);
3574 return instruction->tmp_ptr;
35643575}
35653576
35663577static LLVMValueRef ir_render_fence(CodeGen *g, IrExecutable *executable, IrInstructionFence *instruction) {
......@@ -5588,6 +5599,9 @@ static void do_code_gen(CodeGen *g) {
55885599 } else if (instruction->id == IrInstructionIdErrWrapCode) {
55895600 IrInstructionErrWrapCode *err_wrap_code_instruction = (IrInstructionErrWrapCode *)instruction;
55905601 slot = &err_wrap_code_instruction->tmp_ptr;
5602 } else if (instruction->id == IrInstructionIdCmpxchg) {
5603 IrInstructionCmpxchg *cmpxchg_instruction = (IrInstructionCmpxchg *)instruction;
5604 slot = &cmpxchg_instruction->tmp_ptr;
55915605 } else {
55925606 zig_unreachable();
55935607 }
......@@ -6115,7 +6129,8 @@ static void define_builtin_fns(CodeGen *g) {
61156129 create_builtin_fn(g, BuiltinFnIdTypeName, "typeName", 1);
61166130 create_builtin_fn(g, BuiltinFnIdCanImplicitCast, "canImplicitCast", 2);
61176131 create_builtin_fn(g, BuiltinFnIdEmbedFile, "embedFile", 1);
6118 create_builtin_fn(g, BuiltinFnIdCmpExchange, "cmpxchg", 5);
6132 create_builtin_fn(g, BuiltinFnIdCmpxchgWeak, "cmpxchgWeak", 6);
6133 create_builtin_fn(g, BuiltinFnIdCmpxchgStrong, "cmpxchgStrong", 6);
61196134 create_builtin_fn(g, BuiltinFnIdFence, "fence", 1);
61206135 create_builtin_fn(g, BuiltinFnIdTruncate, "truncate", 2);
61216136 create_builtin_fn(g, BuiltinFnIdCompileErr, "compileError", 1);
src/ir.cpp+45-40
......@@ -110,6 +110,7 @@ static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_
110110 IrInstruction *source_instr, IrInstruction *container_ptr, TypeTableEntry *container_type);
111111static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction,
112112 VariableTableEntry *var, bool is_const_ptr, bool is_volatile_ptr);
113static TypeTableEntry *ir_resolve_atomic_operand_type(IrAnalyze *ira, IrInstruction *op);
113114
114115ConstExprValue *const_ptr_pointee(CodeGen *g, ConstExprValue *const_val) {
115116 assert(const_val->type->id == TypeTableEntryIdPointer);
......@@ -1832,38 +1833,34 @@ static IrInstruction *ir_build_embed_file(IrBuilder *irb, Scope *scope, AstNode
18321833 return &instruction->base;
18331834}
18341835
1835static IrInstruction *ir_build_cmpxchg(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *ptr,
1836 IrInstruction *cmp_value, IrInstruction *new_value, IrInstruction *success_order_value, IrInstruction *failure_order_value,
1837 AtomicOrder success_order, AtomicOrder failure_order)
1836static IrInstruction *ir_build_cmpxchg(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *type_value,
1837 IrInstruction *ptr, IrInstruction *cmp_value, IrInstruction *new_value,
1838 IrInstruction *success_order_value, IrInstruction *failure_order_value,
1839 bool is_weak,
1840 TypeTableEntry *type, AtomicOrder success_order, AtomicOrder failure_order)
18381841{
18391842 IrInstructionCmpxchg *instruction = ir_build_instruction<IrInstructionCmpxchg>(irb, scope, source_node);
1843 instruction->type_value = type_value;
18401844 instruction->ptr = ptr;
18411845 instruction->cmp_value = cmp_value;
18421846 instruction->new_value = new_value;
18431847 instruction->success_order_value = success_order_value;
18441848 instruction->failure_order_value = failure_order_value;
1849 instruction->is_weak = is_weak;
1850 instruction->type = type;
18451851 instruction->success_order = success_order;
18461852 instruction->failure_order = failure_order;
18471853
1854 if (type_value != nullptr) ir_ref_instruction(type_value, irb->current_basic_block);
18481855 ir_ref_instruction(ptr, irb->current_basic_block);
18491856 ir_ref_instruction(cmp_value, irb->current_basic_block);
18501857 ir_ref_instruction(new_value, irb->current_basic_block);
1851 ir_ref_instruction(success_order_value, irb->current_basic_block);
1852 ir_ref_instruction(failure_order_value, irb->current_basic_block);
1858 if (type_value != nullptr) ir_ref_instruction(success_order_value, irb->current_basic_block);
1859 if (type_value != nullptr) ir_ref_instruction(failure_order_value, irb->current_basic_block);
18531860
18541861 return &instruction->base;
18551862}
18561863
1857static IrInstruction *ir_build_cmpxchg_from(IrBuilder *irb, IrInstruction *old_instruction, IrInstruction *ptr,
1858 IrInstruction *cmp_value, IrInstruction *new_value, IrInstruction *success_order_value, IrInstruction *failure_order_value,
1859 AtomicOrder success_order, AtomicOrder failure_order)
1860{
1861 IrInstruction *new_instruction = ir_build_cmpxchg(irb, old_instruction->scope, old_instruction->source_node,
1862 ptr, cmp_value, new_value, success_order_value, failure_order_value, success_order, failure_order);
1863 ir_link_new_instruction(new_instruction, old_instruction);
1864 return new_instruction;
1865}
1866
18671864static IrInstruction *ir_build_fence(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *order_value, AtomicOrder order) {
18681865 IrInstructionFence *instruction = ir_build_instruction<IrInstructionFence>(irb, scope, source_node);
18691866 instruction->order_value = order_value;
......@@ -3771,7 +3768,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
37713768
37723769 return ir_build_embed_file(irb, scope, node, arg0_value);
37733770 }
3774 case BuiltinFnIdCmpExchange:
3771 case BuiltinFnIdCmpxchgWeak:
3772 case BuiltinFnIdCmpxchgStrong:
37753773 {
37763774 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
37773775 IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
......@@ -3798,9 +3796,14 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
37983796 if (arg4_value == irb->codegen->invalid_instruction)
37993797 return arg4_value;
38003798
3799 AstNode *arg5_node = node->data.fn_call_expr.params.at(5);
3800 IrInstruction *arg5_value = ir_gen_node(irb, arg5_node, scope);
3801 if (arg5_value == irb->codegen->invalid_instruction)
3802 return arg5_value;
3803
38013804 return ir_build_cmpxchg(irb, scope, node, arg0_value, arg1_value,
3802 arg2_value, arg3_value, arg4_value,
3803 AtomicOrderUnordered, AtomicOrderUnordered);
3805 arg2_value, arg3_value, arg4_value, arg5_value, (builtin_fn->id == BuiltinFnIdCmpxchgWeak),
3806 nullptr, AtomicOrderUnordered, AtomicOrderUnordered);
38043807 }
38053808 case BuiltinFnIdFence:
38063809 {
......@@ -15730,10 +15733,20 @@ static TypeTableEntry *ir_analyze_instruction_embed_file(IrAnalyze *ira, IrInstr
1573015733}
1573115734
1573215735static TypeTableEntry *ir_analyze_instruction_cmpxchg(IrAnalyze *ira, IrInstructionCmpxchg *instruction) {
15736 TypeTableEntry *operand_type = ir_resolve_atomic_operand_type(ira, instruction->type_value->other);
15737 if (type_is_invalid(operand_type))
15738 return ira->codegen->builtin_types.entry_invalid;
15739
1573315740 IrInstruction *ptr = instruction->ptr->other;
1573415741 if (type_is_invalid(ptr->value.type))
1573515742 return ira->codegen->builtin_types.entry_invalid;
1573615743
15744 // TODO let this be volatile
15745 TypeTableEntry *ptr_type = get_pointer_to_type(ira->codegen, operand_type, false);
15746 IrInstruction *casted_ptr = ir_implicit_cast(ira, ptr, ptr_type);
15747 if (type_is_invalid(casted_ptr->value.type))
15748 return ira->codegen->builtin_types.entry_invalid;
15749
1573715750 IrInstruction *cmp_value = instruction->cmp_value->other;
1573815751 if (type_is_invalid(cmp_value->value.type))
1573915752 return ira->codegen->builtin_types.entry_invalid;
......@@ -15758,28 +15771,11 @@ static TypeTableEntry *ir_analyze_instruction_cmpxchg(IrAnalyze *ira, IrInstruct
1575815771 if (!ir_resolve_atomic_order(ira, failure_order_value, &failure_order))
1575915772 return ira->codegen->builtin_types.entry_invalid;
1576015773
15761 if (ptr->value.type->id != TypeTableEntryIdPointer) {
15762 ir_add_error(ira, instruction->ptr,
15763 buf_sprintf("expected pointer argument, found '%s'", buf_ptr(&ptr->value.type->name)));
15764 return ira->codegen->builtin_types.entry_invalid;
15765 }
15766
15767 TypeTableEntry *child_type = ptr->value.type->data.pointer.child_type;
15768
15769 uint32_t align_bytes = ptr->value.type->data.pointer.alignment;
15770 uint64_t size_bytes = type_size(ira->codegen, child_type);
15771 if (align_bytes < size_bytes) {
15772 ir_add_error(ira, instruction->ptr,
15773 buf_sprintf("expected pointer alignment of at least %" ZIG_PRI_u64 ", found %" PRIu32,
15774 size_bytes, align_bytes));
15775 return ira->codegen->builtin_types.entry_invalid;
15776 }
15777
15778 IrInstruction *casted_cmp_value = ir_implicit_cast(ira, cmp_value, child_type);
15774 IrInstruction *casted_cmp_value = ir_implicit_cast(ira, cmp_value, operand_type);
1577915775 if (type_is_invalid(casted_cmp_value->value.type))
1578015776 return ira->codegen->builtin_types.entry_invalid;
1578115777
15782 IrInstruction *casted_new_value = ir_implicit_cast(ira, new_value, child_type);
15778 IrInstruction *casted_new_value = ir_implicit_cast(ira, new_value, operand_type);
1578315779 if (type_is_invalid(casted_new_value->value.type))
1578415780 return ira->codegen->builtin_types.entry_invalid;
1578515781
......@@ -15804,9 +15800,17 @@ static TypeTableEntry *ir_analyze_instruction_cmpxchg(IrAnalyze *ira, IrInstruct
1580415800 return ira->codegen->builtin_types.entry_invalid;
1580515801 }
1580615802
15807 ir_build_cmpxchg_from(&ira->new_irb, &instruction->base, ptr, casted_cmp_value, casted_new_value,
15808 success_order_value, failure_order_value, success_order, failure_order);
15809 return ira->codegen->builtin_types.entry_bool;
15803 if (instr_is_comptime(casted_ptr) && instr_is_comptime(casted_cmp_value) && instr_is_comptime(casted_new_value)) {
15804 zig_panic("TODO compile-time execution of cmpxchg");
15805 }
15806
15807 IrInstruction *result = ir_build_cmpxchg(&ira->new_irb, instruction->base.scope, instruction->base.source_node,
15808 nullptr, casted_ptr, casted_cmp_value, casted_new_value, nullptr, nullptr, instruction->is_weak,
15809 operand_type, success_order, failure_order);
15810 result->value.type = get_maybe_type(ira->codegen, operand_type);
15811 ir_link_new_instruction(result, &instruction->base);
15812 ir_add_alloca(ira, result, result->value.type);
15813 return result->value.type;
1581015814}
1581115815
1581215816static TypeTableEntry *ir_analyze_instruction_fence(IrAnalyze *ira, IrInstructionFence *instruction) {
......@@ -17981,6 +17985,7 @@ static TypeTableEntry *ir_analyze_instruction_atomic_rmw(IrAnalyze *ira, IrInstr
1798117985 if (type_is_invalid(ptr_inst->value.type))
1798217986 return ira->codegen->builtin_types.entry_invalid;
1798317987
17988 // TODO let this be volatile
1798417989 TypeTableEntry *ptr_type = get_pointer_to_type(ira->codegen, operand_type, false);
1798517990 IrInstruction *casted_ptr = ir_implicit_cast(ira, ptr_inst, ptr_type);
1798617991 if (type_is_invalid(casted_ptr->value.type))
src/zig_llvm.cpp+5-3
......@@ -765,10 +765,12 @@ static AtomicOrdering mapFromLLVMOrdering(LLVMAtomicOrdering Ordering) {
765765
766766LLVMValueRef ZigLLVMBuildCmpXchg(LLVMBuilderRef builder, LLVMValueRef ptr, LLVMValueRef cmp,
767767 LLVMValueRef new_val, LLVMAtomicOrdering success_ordering,
768 LLVMAtomicOrdering failure_ordering)
768 LLVMAtomicOrdering failure_ordering, bool is_weak)
769769{
770 return wrap(unwrap(builder)->CreateAtomicCmpXchg(unwrap(ptr), unwrap(cmp), unwrap(new_val),
771 mapFromLLVMOrdering(success_ordering), mapFromLLVMOrdering(failure_ordering)));
770 AtomicCmpXchgInst *inst = unwrap(builder)->CreateAtomicCmpXchg(unwrap(ptr), unwrap(cmp),
771 unwrap(new_val), mapFromLLVMOrdering(success_ordering), mapFromLLVMOrdering(failure_ordering));
772 inst->setWeak(is_weak);
773 return wrap(inst);
772774}
773775
774776LLVMValueRef ZigLLVMBuildNSWShl(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMValueRef RHS,
src/zig_llvm.h+1-1
......@@ -66,7 +66,7 @@ ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildCall(LLVMBuilderRef B, LLVMValueRef Fn, LL
6666
6767ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildCmpXchg(LLVMBuilderRef builder, LLVMValueRef ptr, LLVMValueRef cmp,
6868 LLVMValueRef new_val, LLVMAtomicOrdering success_ordering,
69 LLVMAtomicOrdering failure_ordering);
69 LLVMAtomicOrdering failure_ordering, bool is_weak);
7070
7171ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildNSWShl(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMValueRef RHS,
7272 const char *name);
test/cases/atomics.zig+14-2
......@@ -1,12 +1,24 @@
1const assert = @import("std").debug.assert;
1const std = @import("std");
2const assert = std.debug.assert;
23const builtin = @import("builtin");
34const AtomicRmwOp = builtin.AtomicRmwOp;
45const AtomicOrder = builtin.AtomicOrder;
56
67test "cmpxchg" {
78 var x: i32 = 1234;
8 while (!@cmpxchg(&x, 1234, 5678, AtomicOrder.SeqCst, AtomicOrder.SeqCst)) {}
9 if (@cmpxchgWeak(i32, &x, 99, 5678, AtomicOrder.SeqCst, AtomicOrder.SeqCst)) |x1| {
10 assert(x1 == 1234);
11 } else {
12 @panic("cmpxchg should have failed");
13 }
14
15 while (@cmpxchgWeak(i32, &x, 1234, 5678, AtomicOrder.SeqCst, AtomicOrder.SeqCst)) |x1| {
16 assert(x1 == 1234);
17 }
918 assert(x == 5678);
19
20 assert(@cmpxchgStrong(i32, &x, 5678, 42, AtomicOrder.SeqCst, AtomicOrder.SeqCst) == null);
21 assert(x == 42);
1022}
1123
1224test "fence" {
test/compile_errors.zig+8-8
......@@ -1394,17 +1394,17 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
13941394 \\const AtomicOrder = @import("builtin").AtomicOrder;
13951395 \\export fn f() void {
13961396 \\ var x: i32 = 1234;
1397 \\ while (!@cmpxchg(&x, 1234, 5678, AtomicOrder.Monotonic, AtomicOrder.SeqCst)) {}
1397 \\ while (!@cmpxchgWeak(i32, &x, 1234, 5678, AtomicOrder.Monotonic, AtomicOrder.SeqCst)) {}
13981398 \\}
1399 , ".tmp_source.zig:4:72: error: failure atomic ordering must be no stricter than success");
1399 , ".tmp_source.zig:4:81: error: failure atomic ordering must be no stricter than success");
14001400
14011401 cases.add("atomic orderings of cmpxchg - success Monotonic or stricter",
14021402 \\const AtomicOrder = @import("builtin").AtomicOrder;
14031403 \\export fn f() void {
14041404 \\ var x: i32 = 1234;
1405 \\ while (!@cmpxchg(&x, 1234, 5678, AtomicOrder.Unordered, AtomicOrder.Unordered)) {}
1405 \\ while (!@cmpxchgWeak(i32, &x, 1234, 5678, AtomicOrder.Unordered, AtomicOrder.Unordered)) {}
14061406 \\}
1407 , ".tmp_source.zig:4:49: error: success atomic ordering must be Monotonic or stricter");
1407 , ".tmp_source.zig:4:58: error: success atomic ordering must be Monotonic or stricter");
14081408
14091409 cases.add("negation overflow in function evaluation",
14101410 \\const y = neg(-128);
......@@ -2460,11 +2460,11 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
24602460 \\const AtomicOrder = @import("builtin").AtomicOrder;
24612461 \\export fn entry() bool {
24622462 \\ var x: i32 align(1) = 1234;
2463 \\ while (!@cmpxchg(&x, 1234, 5678, AtomicOrder.SeqCst, AtomicOrder.SeqCst)) {}
2463 \\ while (!@cmpxchgWeak(i32, &x, 1234, 5678, AtomicOrder.SeqCst, AtomicOrder.SeqCst)) {}
24642464 \\ return x == 5678;
24652465 \\}
24662466 ,
2467 ".tmp_source.zig:4:23: error: expected pointer alignment of at least 4, found 1");
2467 ".tmp_source.zig:4:32: error: expected type '&i32', found '&align(1) i32'");
24682468
24692469 cases.add("wrong size to an array literal",
24702470 \\comptime {
......@@ -2534,10 +2534,10 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
25342534 cases.add("wrong types given to atomic order args in cmpxchg",
25352535 \\export fn entry() void {
25362536 \\ var x: i32 = 1234;
2537 \\ while (!@cmpxchg(&x, 1234, 5678, u32(1234), u32(1234))) {}
2537 \\ while (!@cmpxchgWeak(i32, &x, 1234, 5678, u32(1234), u32(1234))) {}
25382538 \\}
25392539 ,
2540 ".tmp_source.zig:3:41: error: expected type 'AtomicOrder', found 'u32'");
2540 ".tmp_source.zig:3:50: error: expected type 'AtomicOrder', found 'u32'");
25412541
25422542 cases.add("wrong types given to @export",
25432543 \\extern fn entry() void { }