authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2019-12-17 00:28:17+02:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2019-12-23 11:54:47+02:00
log8bb1e0444951b7b83254277c52534c7ab58fd135
treec334c30c388ba0920b92c06e1ca939582a9cd1d7
parent25e71216c4640a3d88c8f63912ea574ad6fa004c
signature Commit is signed but in an unrecognized format.

support some atomic operations with floats


5 files changed, 64 insertions(+), 9 deletions(-)

doc/langref.html.in+3-3
...@@ -6695,7 +6695,7 @@ async fn func(y: *i32) void {...@@ -6695,7 +6695,7 @@ async fn func(y: *i32) void {
6695 This builtin function atomically dereferences a pointer and returns the value.6695 This builtin function atomically dereferences a pointer and returns the value.
6696 </p>6696 </p>
6697 <p>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 an integer whose bit count meets these requirements:6699 an integer whose bit count meets these requirements:
6700 </p>6700 </p>
6701 <ul>6701 <ul>
...@@ -6730,7 +6730,7 @@ async fn func(y: *i32) void {...@@ -6730,7 +6730,7 @@ async fn func(y: *i32) void {
6730 Supported operations:6730 Supported operations:
6731 </p>6731 </p>
6732 <ul>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 <li>{#syntax#}.Add{#endsyntax#} - for integers, twos complement wraparound addition.6734 <li>{#syntax#}.Add{#endsyntax#} - for integers, twos complement wraparound addition.
6735 Also supports {#link|Floats#}.</li>6735 Also supports {#link|Floats#}.</li>
6736 <li>{#syntax#}.Sub{#endsyntax#} - for integers, twos complement wraparound subtraction.6736 <li>{#syntax#}.Sub{#endsyntax#} - for integers, twos complement wraparound subtraction.
...@@ -6749,7 +6749,7 @@ async fn func(y: *i32) void {...@@ -6749,7 +6749,7 @@ async fn func(y: *i32) void {
6749 This builtin function atomically stores a value.6749 This builtin function atomically stores a value.
6750 </p>6750 </p>
6751 <p>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 an integer whose bit count meets these requirements:6753 an integer whose bit count meets these requirements:
6754 </p>6754 </p>
6755 <ul>6755 <ul>
src/codegen.cpp+7-5
...@@ -5129,11 +5129,13 @@ static LLVMAtomicOrdering to_LLVMAtomicOrdering(AtomicOrder atomic_order) {...@@ -5129,11 +5129,13 @@ static LLVMAtomicOrdering to_LLVMAtomicOrdering(AtomicOrder atomic_order) {
5129 zig_unreachable();5129 zig_unreachable();
5130}5130}
51315131
5132static LLVMAtomicRMWBinOp to_LLVMAtomicRMWBinOp(AtomicRmwOp op, bool is_signed) {5132static LLVMAtomicRMWBinOp to_LLVMAtomicRMWBinOp(AtomicRmwOp op, bool is_signed, bool is_float) {
5133 switch (op) {5133 switch (op) {
5134 case AtomicRmwOp_xchg: return LLVMAtomicRMWBinOpXchg;5134 case AtomicRmwOp_xchg: return LLVMAtomicRMWBinOpXchg;
5135 case AtomicRmwOp_add: return LLVMAtomicRMWBinOpAdd;5135 case AtomicRmwOp_add:
5136 case AtomicRmwOp_sub: return LLVMAtomicRMWBinOpSub;5136 return is_float ? LLVMAtomicRMWBinOpFAdd: LLVMAtomicRMWBinOpAdd;
5137 case AtomicRmwOp_sub:
5138 return is_float ? LLVMAtomicRMWBinOpFSub: LLVMAtomicRMWBinOpSub;
5137 case AtomicRmwOp_and: return LLVMAtomicRMWBinOpAnd;5139 case AtomicRmwOp_and: return LLVMAtomicRMWBinOpAnd;
5138 case AtomicRmwOp_nand: return LLVMAtomicRMWBinOpNand;5140 case AtomicRmwOp_nand: return LLVMAtomicRMWBinOpNand;
5139 case AtomicRmwOp_or: return LLVMAtomicRMWBinOpOr;5141 case AtomicRmwOp_or: return LLVMAtomicRMWBinOpOr;
...@@ -5725,14 +5727,14 @@ static LLVMValueRef ir_render_panic(CodeGen *g, IrExecutable *executable, IrInst...@@ -5725,14 +5727,14 @@ static LLVMValueRef ir_render_panic(CodeGen *g, IrExecutable *executable, IrInst
5725static LLVMValueRef ir_render_atomic_rmw(CodeGen *g, IrExecutable *executable,5727static LLVMValueRef ir_render_atomic_rmw(CodeGen *g, IrExecutable *executable,
5726 IrInstructionAtomicRmw *instruction)5728 IrInstructionAtomicRmw *instruction)
5727{5729{
5728 bool is_signed;
5729 ZigType *operand_type = instruction->operand->value->type;5730 ZigType *operand_type = instruction->operand->value->type;
5731 bool is_float = operand_type->id == ZigTypeIdFloat;
5730 if (operand_type->id == ZigTypeIdInt) {5732 if (operand_type->id == ZigTypeIdInt) {
5731 is_signed = operand_type->data.integral.is_signed;5733 is_signed = operand_type->data.integral.is_signed;
5732 } else {5734 } else {
5733 is_signed = false;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 LLVMAtomicOrdering ordering = to_LLVMAtomicOrdering(instruction->resolved_ordering);5738 LLVMAtomicOrdering ordering = to_LLVMAtomicOrdering(instruction->resolved_ordering);
5737 LLVMValueRef ptr = ir_llvm_value(g, instruction->ptr);5739 LLVMValueRef ptr = ir_llvm_value(g, instruction->ptr);
5738 LLVMValueRef operand = ir_llvm_value(g, instruction->operand);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,6 +23956,12 @@ static IrInstruction *ir_analyze_instruction_cmpxchg(IrAnalyze *ira, IrInstructi
23956 if (type_is_invalid(operand_type))23956 if (type_is_invalid(operand_type))
23957 return ira->codegen->invalid_instruction;23957 return ira->codegen->invalid_instruction;
2395823958
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 IrInstruction *ptr = instruction->ptr->child;23965 IrInstruction *ptr = instruction->ptr->child;
23960 if (type_is_invalid(ptr->value->type))23966 if (type_is_invalid(ptr->value->type))
23961 return ira->codegen->invalid_instruction;23967 return ira->codegen->invalid_instruction;
...@@ -27433,9 +27439,17 @@ static ZigType *ir_resolve_atomic_operand_type(IrAnalyze *ira, IrInstruction *op...@@ -27433,9 +27439,17 @@ static ZigType *ir_resolve_atomic_operand_type(IrAnalyze *ira, IrInstruction *op
27433 buf_sprintf("%" PRIu32 "-bit enum tag type is not a power of 2", int_type->data.integral.bit_count));27439 buf_sprintf("%" PRIu32 "-bit enum tag type is not a power of 2", int_type->data.integral.bit_count));
27434 return ira->codegen->builtin_types.entry_invalid;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 } else if (get_codegen_ptr_type(operand_type) == nullptr) {27450 } else if (get_codegen_ptr_type(operand_type) == nullptr) {
27437 ir_add_error(ira, op,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 return ira->codegen->builtin_types.entry_invalid;27453 return ira->codegen->builtin_types.entry_invalid;
27440 }27454 }
2744127455
...@@ -27470,6 +27484,10 @@ static IrInstruction *ir_analyze_instruction_atomic_rmw(IrAnalyze *ira, IrInstru...@@ -27470,6 +27484,10 @@ static IrInstruction *ir_analyze_instruction_atomic_rmw(IrAnalyze *ira, IrInstru
27470 ir_add_error(ira, instruction->op,27484 ir_add_error(ira, instruction->op,
27471 buf_sprintf("@atomicRmw on enum only works with .Xchg"));27485 buf_sprintf("@atomicRmw on enum only works with .Xchg"));
27472 return ira->codegen->invalid_instruction;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 }
2747427492
27475 IrInstruction *operand = instruction->operand->child;27493 IrInstruction *operand = instruction->operand->child;
test/compile_errors.zig+20
...@@ -13,6 +13,26 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -13,6 +13,26 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
13 "tmp.zig:3:12: note: destination pointer requires a terminating '0' sentinel",13 "tmp.zig:3:12: note: destination pointer requires a terminating '0' sentinel",
14 });14 });
1515
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 cases.add("intToPtr with misaligned address",36 cases.add("intToPtr with misaligned address",
17 \\pub fn main() void {37 \\pub fn main() void {
18 \\ var y = @intToPtr([*]align(4) u8, 5);38 \\ var y = @intToPtr([*]align(4) u8, 5);
test/stage1/behavior/atomics.zig+15
...@@ -144,3 +144,18 @@ fn testAtomicStore() void {...@@ -144,3 +144,18 @@ fn testAtomicStore() void {
144 @atomicStore(u32, &x, 12345678, .SeqCst);144 @atomicStore(u32, &x, 12345678, .SeqCst);
145 expect(@atomicLoad(u32, &x, .SeqCst) == 12345678);145 expect(@atomicLoad(u32, &x, .SeqCst) == 12345678);
146}146}
147
148test "atomicrmw with floats" {
149 testAtomicRmwFloat();
150}
151
152fn 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}