authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-02-28 21:19:51-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-02-28 21:19:51-05:00
log807a5e94e976f03058426e04dceef449a5bf7ed8
tree3717696ae449bcc5c5a83ca4e1da965a63de864d
parent36eadb569a31a87b610b9b70e225a981dc181df4

add atomicrmw builtin function


7 files changed, 297 insertions(+), 12 deletions(-)

doc/langref.html.in+20-1
......@@ -3775,6 +3775,25 @@ pub fn main() void {
37753775 {#header_open|@ArgType#}
37763776 <p>TODO</p>
37773777 {#header_close#}
3778 {#header_open|@atomicRmw#}
3779 <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>
3780 <p>
3781 This builtin function atomically modifies memory and then returns the previous value.
3782 </p>
3783 <p>
3784 <code>T</code> must be a pointer type, a <code>bool</code>,
3785 or an integer whose bit count meets these requirements:
3786 </p>
3787 <ul>
3788 <li>At least 8</li>
3789 <li>At most the same as usize</li>
3790 <li>Power of 2</li>
3791 </ul>
3792 <p>
3793 TODO right now bool is not accepted. Also I think we could make non powers of 2 work fine, maybe
3794 we can remove this restriction
3795 </p>
3796 {#header_close#}
37783797 {#header_open|@bitCast#}
37793798 <pre><code class="zig">@bitCast(comptime DestType: type, value: var) -&gt; DestType</code></pre>
37803799 <p>
......@@ -5859,7 +5878,7 @@ hljs.registerLanguage("zig", function(t) {
58595878 a = t.IR + "\\s*\\(",
58605879 c = {
58615880 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",
5862 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",
5881 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",
58635882 literal: "true false null undefined"
58645883 },
58655884 n = [e, t.CLCM, t.CBCM, s, r];
src/all_types.hpp+27
......@@ -1338,6 +1338,7 @@ enum BuiltinFnId {
13381338 BuiltinFnIdArgType,
13391339 BuiltinFnIdExport,
13401340 BuiltinFnIdErrorReturnTrace,
1341 BuiltinFnIdAtomicRmw,
13411342};
13421343
13431344struct BuiltinFnEntry {
......@@ -1857,6 +1858,19 @@ enum AtomicOrder {
18571858 AtomicOrderSeqCst,
18581859};
18591860
1861// synchronized with the code in define_builtin_compile_vars
1862enum AtomicRmwOp {
1863 AtomicRmwOp_xchg,
1864 AtomicRmwOp_add,
1865 AtomicRmwOp_sub,
1866 AtomicRmwOp_and,
1867 AtomicRmwOp_nand,
1868 AtomicRmwOp_or,
1869 AtomicRmwOp_xor,
1870 AtomicRmwOp_max,
1871 AtomicRmwOp_min,
1872};
1873
18601874// A basic block contains no branching. Branches send control flow
18611875// to another basic block.
18621876// Phi instructions must be first in a basic block.
......@@ -2006,6 +2020,7 @@ enum IrInstructionId {
20062020 IrInstructionIdCoroResume,
20072021 IrInstructionIdCoroSave,
20082022 IrInstructionIdCoroAllocHelper,
2023 IrInstructionIdAtomicRmw,
20092024};
20102025
20112026struct IrInstruction {
......@@ -2929,6 +2944,18 @@ struct IrInstructionCoroAllocHelper {
29292944 IrInstruction *coro_size;
29302945};
29312946
2947struct IrInstructionAtomicRmw {
2948 IrInstruction base;
2949
2950 IrInstruction *operand_type;
2951 IrInstruction *ptr;
2952 IrInstruction *op;
2953 AtomicRmwOp resolved_op;
2954 IrInstruction *operand;
2955 IrInstruction *ordering;
2956 AtomicOrder resolved_ordering;
2957};
2958
29322959static const size_t slice_ptr_index = 0;
29332960static const size_t slice_len_index = 1;
29342961
src/codegen.cpp+50
......@@ -3311,6 +3311,23 @@ static LLVMAtomicOrdering to_LLVMAtomicOrdering(AtomicOrder atomic_order) {
33113311 zig_unreachable();
33123312}
33133313
3314static LLVMAtomicRMWBinOp to_LLVMAtomicRMWBinOp(AtomicRmwOp op, bool is_signed) {
3315 switch (op) {
3316 case AtomicRmwOp_xchg: return LLVMAtomicRMWBinOpXchg;
3317 case AtomicRmwOp_add: return LLVMAtomicRMWBinOpAdd;
3318 case AtomicRmwOp_sub: return LLVMAtomicRMWBinOpSub;
3319 case AtomicRmwOp_and: return LLVMAtomicRMWBinOpAnd;
3320 case AtomicRmwOp_nand: return LLVMAtomicRMWBinOpNand;
3321 case AtomicRmwOp_or: return LLVMAtomicRMWBinOpOr;
3322 case AtomicRmwOp_xor: return LLVMAtomicRMWBinOpXor;
3323 case AtomicRmwOp_max:
3324 return is_signed ? LLVMAtomicRMWBinOpMax : LLVMAtomicRMWBinOpUMax;
3325 case AtomicRmwOp_min:
3326 return is_signed ? LLVMAtomicRMWBinOpMin : LLVMAtomicRMWBinOpUMin;
3327 }
3328 zig_unreachable();
3329}
3330
33143331static LLVMValueRef ir_render_cmpxchg(CodeGen *g, IrExecutable *executable, IrInstructionCmpxchg *instruction) {
33153332 LLVMValueRef ptr_val = ir_llvm_value(g, instruction->ptr);
33163333 LLVMValueRef cmp_val = ir_llvm_value(g, instruction->cmp_value);
......@@ -4111,6 +4128,22 @@ static LLVMValueRef ir_render_coro_alloc_helper(CodeGen *g, IrExecutable *execut
41114128 get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, "");
41124129}
41134130
4131static LLVMValueRef ir_render_atomic_rmw(CodeGen *g, IrExecutable *executable,
4132 IrInstructionAtomicRmw *instruction)
4133{
4134 bool is_signed;
4135 if (instruction->operand->value.type->id == TypeTableEntryIdInt) {
4136 is_signed = instruction->operand->value.type->data.integral.is_signed;
4137 } else {
4138 is_signed = false;
4139 }
4140 LLVMAtomicRMWBinOp op = to_LLVMAtomicRMWBinOp(instruction->resolved_op, is_signed);
4141 LLVMAtomicOrdering ordering = to_LLVMAtomicOrdering(instruction->resolved_ordering);
4142 LLVMValueRef ptr = ir_llvm_value(g, instruction->ptr);
4143 LLVMValueRef operand = ir_llvm_value(g, instruction->operand);
4144 return LLVMBuildAtomicRMW(g->builder, op, ptr, operand, ordering, false);
4145}
4146
41144147static void set_debug_location(CodeGen *g, IrInstruction *instruction) {
41154148 AstNode *source_node = instruction->source_node;
41164149 Scope *scope = instruction->scope;
......@@ -4318,6 +4351,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
43184351 return ir_render_coro_save(g, executable, (IrInstructionCoroSave *)instruction);
43194352 case IrInstructionIdCoroAllocHelper:
43204353 return ir_render_coro_alloc_helper(g, executable, (IrInstructionCoroAllocHelper *)instruction);
4354 case IrInstructionIdAtomicRmw:
4355 return ir_render_atomic_rmw(g, executable, (IrInstructionAtomicRmw *)instruction);
43214356 }
43224357 zig_unreachable();
43234358}
......@@ -5810,6 +5845,7 @@ static void define_builtin_fns(CodeGen *g) {
58105845 create_builtin_fn(g, BuiltinFnIdArgType, "ArgType", 2);
58115846 create_builtin_fn(g, BuiltinFnIdExport, "export", 3);
58125847 create_builtin_fn(g, BuiltinFnIdErrorReturnTrace, "errorReturnTrace", 0);
5848 create_builtin_fn(g, BuiltinFnIdAtomicRmw, "atomicRmw", 5);
58135849}
58145850
58155851static const char *bool_to_str(bool b) {
......@@ -5939,6 +5975,20 @@ static void define_builtin_compile_vars(CodeGen *g) {
59395975 " SeqCst,\n"
59405976 "};\n\n");
59415977 }
5978 {
5979 buf_appendf(contents,
5980 "pub const AtomicRmwOp = enum {\n"
5981 " Xchg,\n"
5982 " Add,\n"
5983 " Sub,\n"
5984 " And,\n"
5985 " Nand,\n"
5986 " Or,\n"
5987 " Xor,\n"
5988 " Max,\n"
5989 " Min,\n"
5990 "};\n\n");
5991 }
59425992 {
59435993 buf_appendf(contents,
59445994 "pub const Mode = enum {\n"
src/ir.cpp+149
......@@ -701,6 +701,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionCoroAllocHelper
701701 return IrInstructionIdCoroAllocHelper;
702702}
703703
704static constexpr IrInstructionId ir_instruction_id(IrInstructionAtomicRmw *) {
705 return IrInstructionIdAtomicRmw;
706}
707
704708template<typename T>
705709static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {
706710 T *special_instruction = allocate<T>(1);
......@@ -2614,6 +2618,28 @@ static IrInstruction *ir_build_coro_alloc_helper(IrBuilder *irb, Scope *scope, A
26142618 return &instruction->base;
26152619}
26162620
2621static IrInstruction *ir_build_atomic_rmw(IrBuilder *irb, Scope *scope, AstNode *source_node,
2622 IrInstruction *operand_type, IrInstruction *ptr, IrInstruction *op, IrInstruction *operand,
2623 IrInstruction *ordering, AtomicRmwOp resolved_op, AtomicOrder resolved_ordering)
2624{
2625 IrInstructionAtomicRmw *instruction = ir_build_instruction<IrInstructionAtomicRmw>(irb, scope, source_node);
2626 instruction->operand_type = operand_type;
2627 instruction->ptr = ptr;
2628 instruction->op = op;
2629 instruction->operand = operand;
2630 instruction->ordering = ordering;
2631 instruction->resolved_op = resolved_op;
2632 instruction->resolved_ordering = resolved_ordering;
2633
2634 if (operand_type != nullptr) ir_ref_instruction(operand_type, irb->current_basic_block);
2635 ir_ref_instruction(ptr, irb->current_basic_block);
2636 if (op != nullptr) ir_ref_instruction(op, irb->current_basic_block);
2637 ir_ref_instruction(operand, irb->current_basic_block);
2638 if (ordering != nullptr) ir_ref_instruction(ordering, irb->current_basic_block);
2639
2640 return &instruction->base;
2641}
2642
26172643static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) {
26182644 results[ReturnKindUnconditional] = 0;
26192645 results[ReturnKindError] = 0;
......@@ -4094,6 +4120,38 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
40944120 {
40954121 return ir_build_error_return_trace(irb, scope, node);
40964122 }
4123 case BuiltinFnIdAtomicRmw:
4124 {
4125 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
4126 IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
4127 if (arg0_value == irb->codegen->invalid_instruction)
4128 return arg0_value;
4129
4130 AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
4131 IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
4132 if (arg1_value == irb->codegen->invalid_instruction)
4133 return arg1_value;
4134
4135 AstNode *arg2_node = node->data.fn_call_expr.params.at(2);
4136 IrInstruction *arg2_value = ir_gen_node(irb, arg2_node, scope);
4137 if (arg2_value == irb->codegen->invalid_instruction)
4138 return arg2_value;
4139
4140 AstNode *arg3_node = node->data.fn_call_expr.params.at(3);
4141 IrInstruction *arg3_value = ir_gen_node(irb, arg3_node, scope);
4142 if (arg3_value == irb->codegen->invalid_instruction)
4143 return arg3_value;
4144
4145 AstNode *arg4_node = node->data.fn_call_expr.params.at(4);
4146 IrInstruction *arg4_value = ir_gen_node(irb, arg4_node, scope);
4147 if (arg4_value == irb->codegen->invalid_instruction)
4148 return arg4_value;
4149
4150 return ir_build_atomic_rmw(irb, scope, node, arg0_value, arg1_value, arg2_value, arg3_value,
4151 arg4_value,
4152 // these 2 values don't mean anything since we passed non-null values for other args
4153 AtomicRmwOp_xchg, AtomicOrderMonotonic);
4154 }
40974155 }
40984156 zig_unreachable();
40994157}
......@@ -9730,6 +9788,26 @@ static bool ir_resolve_atomic_order(IrAnalyze *ira, IrInstruction *value, Atomic
97309788 return true;
97319789}
97329790
9791static bool ir_resolve_atomic_rmw_op(IrAnalyze *ira, IrInstruction *value, AtomicRmwOp *out) {
9792 if (type_is_invalid(value->value.type))
9793 return false;
9794
9795 ConstExprValue *atomic_rmw_op_val = get_builtin_value(ira->codegen, "AtomicRmwOp");
9796 assert(atomic_rmw_op_val->type->id == TypeTableEntryIdMetaType);
9797 TypeTableEntry *atomic_rmw_op_type = atomic_rmw_op_val->data.x_type;
9798
9799 IrInstruction *casted_value = ir_implicit_cast(ira, value, atomic_rmw_op_type);
9800 if (type_is_invalid(casted_value->value.type))
9801 return false;
9802
9803 ConstExprValue *const_val = ir_resolve_const(ira, casted_value, UndefBad);
9804 if (!const_val)
9805 return false;
9806
9807 *out = (AtomicRmwOp)bigint_as_unsigned(&const_val->data.x_enum_tag);
9808 return true;
9809}
9810
97339811static bool ir_resolve_global_linkage(IrAnalyze *ira, IrInstruction *value, GlobalLinkageId *out) {
97349812 if (type_is_invalid(value->value.type))
97359813 return false;
......@@ -17316,6 +17394,74 @@ static TypeTableEntry *ir_analyze_instruction_coro_alloc_helper(IrAnalyze *ira,
1731617394 return result->value.type;
1731717395}
1731817396
17397static TypeTableEntry *ir_analyze_instruction_atomic_rmw(IrAnalyze *ira, IrInstructionAtomicRmw *instruction) {
17398 TypeTableEntry *operand_type = ir_resolve_type(ira, instruction->operand_type->other);
17399 if (type_is_invalid(operand_type)) {
17400 return ira->codegen->builtin_types.entry_invalid;
17401 }
17402 if (operand_type->id == TypeTableEntryIdInt) {
17403 if (operand_type->data.integral.bit_count < 8) {
17404 ir_add_error(ira, &instruction->base,
17405 buf_sprintf("expected integer type 8 bits or larger, found %" PRIu32 "-bit integer type",
17406 operand_type->data.integral.bit_count));
17407 return ira->codegen->builtin_types.entry_invalid;
17408 }
17409 if (operand_type->data.integral.bit_count > ira->codegen->pointer_size_bytes * 8) {
17410 ir_add_error(ira, &instruction->base,
17411 buf_sprintf("expected integer type pointer size or smaller, found %" PRIu32 "-bit integer type",
17412 operand_type->data.integral.bit_count));
17413 return ira->codegen->builtin_types.entry_invalid;
17414 }
17415 if (!is_power_of_2(operand_type->data.integral.bit_count)) {
17416 ir_add_error(ira, &instruction->base,
17417 buf_sprintf("%" PRIu32 "-bit integer type is not a power of 2", operand_type->data.integral.bit_count));
17418 return ira->codegen->builtin_types.entry_invalid;
17419 }
17420 } else if (get_codegen_ptr_type(operand_type) == nullptr) {
17421 ir_add_error(ira, &instruction->base,
17422 buf_sprintf("expected integer or pointer type, found '%s'", buf_ptr(&operand_type->name)));
17423 return ira->codegen->builtin_types.entry_invalid;
17424 }
17425
17426 IrInstruction *ptr_inst = instruction->ptr->other;
17427 if (type_is_invalid(ptr_inst->value.type))
17428 return ira->codegen->builtin_types.entry_invalid;
17429
17430 TypeTableEntry *ptr_type = get_pointer_to_type(ira->codegen, operand_type, false);
17431 IrInstruction *casted_ptr = ir_implicit_cast(ira, ptr_inst, ptr_type);
17432 if (type_is_invalid(casted_ptr->value.type))
17433 return ira->codegen->builtin_types.entry_invalid;
17434
17435 AtomicRmwOp op;
17436 if (!ir_resolve_atomic_rmw_op(ira, instruction->op->other, &op)) {
17437 return ira->codegen->builtin_types.entry_invalid;
17438 }
17439
17440 IrInstruction *operand = instruction->operand->other;
17441 if (type_is_invalid(operand->value.type))
17442 return ira->codegen->builtin_types.entry_invalid;
17443
17444 IrInstruction *casted_operand = ir_implicit_cast(ira, operand, operand_type);
17445 if (type_is_invalid(casted_ptr->value.type))
17446 return ira->codegen->builtin_types.entry_invalid;
17447
17448 AtomicOrder ordering;
17449 if (!ir_resolve_atomic_order(ira, instruction->ordering->other, &ordering))
17450 return ira->codegen->builtin_types.entry_invalid;
17451
17452 if (instr_is_comptime(casted_operand) && instr_is_comptime(casted_ptr) && casted_ptr->value.data.x_ptr.mut == ConstPtrMutComptimeVar)
17453 {
17454 zig_panic("TODO compile-time execution of atomicRmw");
17455 }
17456
17457 IrInstruction *result = ir_build_atomic_rmw(&ira->new_irb, instruction->base.scope,
17458 instruction->base.source_node, nullptr, casted_ptr, nullptr, casted_operand, nullptr,
17459 op, ordering);
17460 ir_link_new_instruction(result, &instruction->base);
17461 result->value.type = operand_type;
17462 return result->value.type;
17463}
17464
1731917465
1732017466static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {
1732117467 switch (instruction->id) {
......@@ -17545,6 +17691,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
1754517691 return ir_analyze_instruction_coro_save(ira, (IrInstructionCoroSave *)instruction);
1754617692 case IrInstructionIdCoroAllocHelper:
1754717693 return ir_analyze_instruction_coro_alloc_helper(ira, (IrInstructionCoroAllocHelper *)instruction);
17694 case IrInstructionIdAtomicRmw:
17695 return ir_analyze_instruction_atomic_rmw(ira, (IrInstructionAtomicRmw *)instruction);
1754817696 }
1754917697 zig_unreachable();
1755017698}
......@@ -17748,6 +17896,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
1774817896 case IrInstructionIdCoroSize:
1774917897 case IrInstructionIdCoroSuspend:
1775017898 case IrInstructionIdCoroFree:
17899 case IrInstructionIdAtomicRmw:
1775117900 return false;
1775217901
1775317902 case IrInstructionIdAsm:
src/ir_print.cpp+29
......@@ -1113,6 +1113,32 @@ static void ir_print_coro_alloc_helper(IrPrint *irp, IrInstructionCoroAllocHelpe
11131113 fprintf(irp->f, ")");
11141114}
11151115
1116static void ir_print_atomic_rmw(IrPrint *irp, IrInstructionAtomicRmw *instruction) {
1117 fprintf(irp->f, "@atomicRmw(");
1118 if (instruction->operand_type != nullptr) {
1119 ir_print_other_instruction(irp, instruction->operand_type);
1120 } else {
1121 fprintf(irp->f, "[TODO print]");
1122 }
1123 fprintf(irp->f, ",");
1124 ir_print_other_instruction(irp, instruction->ptr);
1125 fprintf(irp->f, ",");
1126 if (instruction->op != nullptr) {
1127 ir_print_other_instruction(irp, instruction->op);
1128 } else {
1129 fprintf(irp->f, "[TODO print]");
1130 }
1131 fprintf(irp->f, ",");
1132 ir_print_other_instruction(irp, instruction->operand);
1133 fprintf(irp->f, ",");
1134 if (instruction->ordering != nullptr) {
1135 ir_print_other_instruction(irp, instruction->ordering);
1136 } else {
1137 fprintf(irp->f, "[TODO print]");
1138 }
1139 fprintf(irp->f, ")");
1140}
1141
11161142static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
11171143 ir_print_prefix(irp, instruction);
11181144 switch (instruction->id) {
......@@ -1472,6 +1498,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
14721498 case IrInstructionIdCoroAllocHelper:
14731499 ir_print_coro_alloc_helper(irp, (IrInstructionCoroAllocHelper *)instruction);
14741500 break;
1501 case IrInstructionIdAtomicRmw:
1502 ir_print_atomic_rmw(irp, (IrInstructionAtomicRmw *)instruction);
1503 break;
14751504 }
14761505 fprintf(irp->f, "\n");
14771506}
std/debug/index.zig+8-10
......@@ -97,21 +97,18 @@ pub fn assertOrPanic(ok: bool) void {
9797 }
9898}
9999
100var panicking = false;
100var panicking: u8 = 0; // TODO make this a bool
101101/// This is the default panic implementation.
102102pub fn panic(comptime format: []const u8, args: ...) noreturn {
103 // TODO an intrinsic that labels this as unlikely to be reached
103 @setCold(true);
104104
105 // TODO
106 // if (@atomicRmw(AtomicOp.XChg, &panicking, true, AtomicOrder.SeqCst)) { }
107 if (panicking) {
105 if (@atomicRmw(u8, &panicking, builtin.AtomicRmwOp.Xchg, 1, builtin.AtomicOrder.SeqCst) == 1) {
108106 // Panicked during a panic.
107
109108 // TODO detect if a different thread caused the panic, because in that case
110109 // we would want to return here instead of calling abort, so that the thread
111110 // which first called panic can finish printing a stack trace.
112111 os.abort();
113 } else {
114 panicking = true;
115112 }
116113
117114 const stderr = getStderrStream() catch os.abort();
......@@ -122,10 +119,11 @@ pub fn panic(comptime format: []const u8, args: ...) noreturn {
122119}
123120
124121pub fn panicWithTrace(trace: &const builtin.StackTrace, comptime format: []const u8, args: ...) noreturn {
125 if (panicking) {
122 @setCold(true);
123
124 if (@atomicRmw(u8, &panicking, builtin.AtomicRmwOp.Xchg, 1, builtin.AtomicOrder.SeqCst) == 1) {
125 // See TODO in above function
126126 os.abort();
127 } else {
128 panicking = true;
129127 }
130128 const stderr = getStderrStream() catch os.abort();
131129 stderr.print(format ++ "\n", args) catch os.abort();
test/cases/atomics.zig+14-1
......@@ -1,5 +1,7 @@
11const assert = @import("std").debug.assert;
2const AtomicOrder = @import("builtin").AtomicOrder;
2const builtin = @import("builtin");
3const AtomicRmwOp = builtin.AtomicRmwOp;
4const AtomicOrder = builtin.AtomicOrder;
35
46test "cmpxchg" {
57 var x: i32 = 1234;
......@@ -12,3 +14,14 @@ test "fence" {
1214 @fence(AtomicOrder.SeqCst);
1315 x = 5678;
1416}
17
18test "atomicrmw" {
19 var data: u8 = 200;
20 testAtomicRmw(&data);
21 assert(data == 42);
22}
23
24fn testAtomicRmw(ptr: &u8) void {
25 const prev_value = @atomicRmw(u8, ptr, AtomicRmwOp.Xchg, 42, AtomicOrder.SeqCst);
26 assert(prev_value == 200);
27}