| author | |
| committer | |
| log | 8bb1e0444951b7b83254277c52534c7ab58fd135 |
| tree | c334c30c388ba0920b92c06e1ca939582a9cd1d7 |
| parent | 25e71216c4640a3d88c8f63912ea574ad6fa004c |
| signature | Commit is signed but in an unrecognized format. |
5 files changed, 64 insertions(+), 9 deletions(-)
doc/langref.html.in+3-3| ... | ... | @@ -6695,7 +6695,7 @@ async fn func(y: *i32) void { |
| 6695 | 6695 | This builtin function atomically dereferences a pointer and returns the value. |
| 6696 | 6696 | </p> |
| 6697 | 6697 | <p> |
| 6698 | {#syntax#}T{#endsyntax#} must be a pointer type, a {#syntax#}bool{#endsyntax#} | |
| 6698 | {#syntax#}T{#endsyntax#} must be a pointer type, a {#syntax#}bool{#endsyntax#}, a float, | |
| 6699 | 6699 | an integer whose bit count meets these requirements: |
| 6700 | 6700 | </p> |
| 6701 | 6701 | <ul> |
| ... | ... | @@ -6730,7 +6730,7 @@ async fn func(y: *i32) void { |
| 6730 | 6730 | Supported operations: |
| 6731 | 6731 | </p> |
| 6732 | 6732 | <ul> |
| 6733 | <li>{#syntax#}.Xchg{#endsyntax#} - stores the operand unmodified.</li> | |
| 6733 | <li>{#syntax#}.Xchg{#endsyntax#} - stores the operand unmodified. Supports enums, integers and floats.</li> | |
| 6734 | 6734 | <li>{#syntax#}.Add{#endsyntax#} - for integers, twos complement wraparound addition. |
| 6735 | 6735 | Also supports {#link|Floats#}.</li> |
| 6736 | 6736 | <li>{#syntax#}.Sub{#endsyntax#} - for integers, twos complement wraparound subtraction. |
| ... | ... | @@ -6749,7 +6749,7 @@ async fn func(y: *i32) void { |
| 6749 | 6749 | This builtin function atomically stores a value. |
| 6750 | 6750 | </p> |
| 6751 | 6751 | <p> |
| 6752 | {#syntax#}T{#endsyntax#} must be a pointer type, a {#syntax#}bool{#endsyntax#} | |
| 6752 | {#syntax#}T{#endsyntax#} must be a pointer type, a {#syntax#}bool{#endsyntax#}, a float, | |
| 6753 | 6753 | an integer whose bit count meets these requirements: |
| 6754 | 6754 | </p> |
| 6755 | 6755 | <ul> |
src/codegen.cpp+7-5| ... | ... | @@ -5129,11 +5129,13 @@ static LLVMAtomicOrdering to_LLVMAtomicOrdering(AtomicOrder atomic_order) { |
| 5129 | 5129 | zig_unreachable(); |
| 5130 | 5130 | } |
| 5131 | 5131 | |
| 5132 | static LLVMAtomicRMWBinOp to_LLVMAtomicRMWBinOp(AtomicRmwOp op, bool is_signed) { | |
| 5132 | static LLVMAtomicRMWBinOp to_LLVMAtomicRMWBinOp(AtomicRmwOp op, bool is_signed, bool is_float) { | |
| 5133 | 5133 | switch (op) { |
| 5134 | 5134 | case AtomicRmwOp_xchg: return LLVMAtomicRMWBinOpXchg; |
| 5135 | case AtomicRmwOp_add: return LLVMAtomicRMWBinOpAdd; | |
| 5136 | case AtomicRmwOp_sub: return LLVMAtomicRMWBinOpSub; | |
| 5135 | case AtomicRmwOp_add: | |
| 5136 | return is_float ? LLVMAtomicRMWBinOpFAdd: LLVMAtomicRMWBinOpAdd; | |
| 5137 | case AtomicRmwOp_sub: | |
| 5138 | return is_float ? LLVMAtomicRMWBinOpFSub: LLVMAtomicRMWBinOpSub; | |
| 5137 | 5139 | case AtomicRmwOp_and: return LLVMAtomicRMWBinOpAnd; |
| 5138 | 5140 | case AtomicRmwOp_nand: return LLVMAtomicRMWBinOpNand; |
| 5139 | 5141 | case AtomicRmwOp_or: return LLVMAtomicRMWBinOpOr; |
| ... | ... | @@ -5725,14 +5727,14 @@ static LLVMValueRef ir_render_panic(CodeGen *g, IrExecutable *executable, IrInst |
| 5725 | 5727 | static LLVMValueRef ir_render_atomic_rmw(CodeGen *g, IrExecutable *executable, |
| 5726 | 5728 | IrInstructionAtomicRmw *instruction) |
| 5727 | 5729 | { |
| 5728 | bool is_signed; | |
| 5729 | 5730 | ZigType *operand_type = instruction->operand->value->type; |
| 5731 | bool is_float = operand_type->id == ZigTypeIdFloat; | |
| 5730 | 5732 | if (operand_type->id == ZigTypeIdInt) { |
| 5731 | 5733 | is_signed = operand_type->data.integral.is_signed; |
| 5732 | 5734 | } else { |
| 5733 | 5735 | is_signed = false; |
| 5734 | 5736 | } |
| 5735 | LLVMAtomicRMWBinOp op = to_LLVMAtomicRMWBinOp(instruction->resolved_op, is_signed); | |
| 5737 | LLVMAtomicRMWBinOp op = to_LLVMAtomicRMWBinOp(instruction->resolved_op, is_signed, is_float); | |
| 5736 | 5738 | LLVMAtomicOrdering ordering = to_LLVMAtomicOrdering(instruction->resolved_ordering); |
| 5737 | 5739 | LLVMValueRef ptr = ir_llvm_value(g, instruction->ptr); |
| 5738 | 5740 | LLVMValueRef operand = ir_llvm_value(g, instruction->operand); |
src/ir.cpp+19-1| ... | ... | @@ -23956,6 +23956,12 @@ static IrInstruction *ir_analyze_instruction_cmpxchg(IrAnalyze *ira, IrInstructi |
| 23956 | 23956 | if (type_is_invalid(operand_type)) |
| 23957 | 23957 | return ira->codegen->invalid_instruction; |
| 23958 | 23958 | |
| 23959 | if (operand_type->id == ZigTypeIdFloat) { | |
| 23960 | ir_add_error(ira, instruction->type_value->child, | |
| 23961 | buf_sprintf("expected integer, enum or pointer type, found '%s'", buf_ptr(&operand_type->name))); | |
| 23962 | return ira->codegen->invalid_instruction; | |
| 23963 | } | |
| 23964 | ||
| 23959 | 23965 | IrInstruction *ptr = instruction->ptr->child; |
| 23960 | 23966 | if (type_is_invalid(ptr->value->type)) |
| 23961 | 23967 | return ira->codegen->invalid_instruction; |
| ... | ... | @@ -27433,9 +27439,17 @@ static ZigType *ir_resolve_atomic_operand_type(IrAnalyze *ira, IrInstruction *op |
| 27433 | 27439 | buf_sprintf("%" PRIu32 "-bit enum tag type is not a power of 2", int_type->data.integral.bit_count)); |
| 27434 | 27440 | return ira->codegen->builtin_types.entry_invalid; |
| 27435 | 27441 | } |
| 27442 | } else if (operand_type->id == ZigTypeIdFloat) { | |
| 27443 | uint32_t max_atomic_bits = target_arch_largest_atomic_bits(ira->codegen->zig_target->arch); | |
| 27444 | if (operand_type->data.floating.bit_count > max_atomic_bits) { | |
| 27445 | ir_add_error(ira, op, | |
| 27446 | buf_sprintf("expected %" PRIu32 "-bit float or smaller, found %" PRIu32 "-bit float", | |
| 27447 | max_atomic_bits, (uint32_t) operand_type->data.floating.bit_count)); | |
| 27448 | return ira->codegen->builtin_types.entry_invalid; | |
| 27449 | } | |
| 27436 | 27450 | } else if (get_codegen_ptr_type(operand_type) == nullptr) { |
| 27437 | 27451 | ir_add_error(ira, op, |
| 27438 | buf_sprintf("expected integer, enum or pointer type, found '%s'", buf_ptr(&operand_type->name))); | |
| 27452 | buf_sprintf("expected integer, float, enum or pointer type, found '%s'", buf_ptr(&operand_type->name))); | |
| 27439 | 27453 | return ira->codegen->builtin_types.entry_invalid; |
| 27440 | 27454 | } |
| 27441 | 27455 | |
| ... | ... | @@ -27470,6 +27484,10 @@ static IrInstruction *ir_analyze_instruction_atomic_rmw(IrAnalyze *ira, IrInstru |
| 27470 | 27484 | ir_add_error(ira, instruction->op, |
| 27471 | 27485 | buf_sprintf("@atomicRmw on enum only works with .Xchg")); |
| 27472 | 27486 | return ira->codegen->invalid_instruction; |
| 27487 | } else if (operand_type->id == ZigTypeIdFloat && op > AtomicRmwOp_sub) { | |
| 27488 | ir_add_error(ira, instruction->op, | |
| 27489 | buf_sprintf("@atomicRmw with float only works with .Xchg, .Add and .Sub")); | |
| 27490 | return ira->codegen->invalid_instruction; | |
| 27473 | 27491 | } |
| 27474 | 27492 | |
| 27475 | 27493 | IrInstruction *operand = instruction->operand->child; |
test/compile_errors.zig+20| ... | ... | @@ -13,6 +13,26 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 13 | 13 | "tmp.zig:3:12: note: destination pointer requires a terminating '0' sentinel", |
| 14 | 14 | }); |
| 15 | 15 | |
| 16 | cases.add( | |
| 17 | "cmpxchg with float", | |
| 18 | \\export fn entry() void { | |
| 19 | \\ var x: f32 = 0; | |
| 20 | \\ _ = @cmpxchgWeak(f32, &x, 1, 2, .SeqCst, .SeqCst); | |
| 21 | \\} | |
| 22 | , | |
| 23 | "tmp.zig:3:22: error: expected integer, enum or pointer type, found 'f32'", | |
| 24 | ); | |
| 25 | ||
| 26 | cases.add( | |
| 27 | "atomicrmw with float op not .Xchg, .Add or .Sub", | |
| 28 | \\export fn entry() void { | |
| 29 | \\ var x: f32 = 0; | |
| 30 | \\ _ = @atomicRmw(f32, &x, .And, 2, .SeqCst); | |
| 31 | \\} | |
| 32 | , | |
| 33 | "tmp.zig:3:29: error: @atomicRmw with float only works with .Xchg, .Add and .Sub", | |
| 34 | ); | |
| 35 | ||
| 16 | 36 | cases.add("intToPtr with misaligned address", |
| 17 | 37 | \\pub fn main() void { |
| 18 | 38 | \\ var y = @intToPtr([*]align(4) u8, 5); |
test/stage1/behavior/atomics.zig+15| ... | ... | @@ -144,3 +144,18 @@ fn testAtomicStore() void { |
| 144 | 144 | @atomicStore(u32, &x, 12345678, .SeqCst); |
| 145 | 145 | expect(@atomicLoad(u32, &x, .SeqCst) == 12345678); |
| 146 | 146 | } |
| 147 | ||
| 148 | test "atomicrmw with floats" { | |
| 149 | testAtomicRmwFloat(); | |
| 150 | } | |
| 151 | ||
| 152 | fn testAtomicRmwFloat() void { | |
| 153 | var x: f32 = 0; | |
| 154 | expect(x == 0); | |
| 155 | _ = @atomicRmw(f32, &x, .Xchg, 1, .SeqCst); | |
| 156 | expect(x == 1); | |
| 157 | _ = @atomicRmw(f32, &x, .Add, 5, .SeqCst); | |
| 158 | expect(x == 6); | |
| 159 | _ = @atomicRmw(f32, &x, .Sub, 2, .SeqCst); | |
| 160 | expect(x == 4); | |
| 161 | } |