authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2020-03-12 16:46:16+02:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2020-03-12 16:46:16+02:00
log710b05b15302f05f98a31635af6d654858215f34
tree9714ad94ff090312e7df8d0ccc4d1e516e4b0668
parent9262f065f50db3ea72454b6c1b9b66fd911aa6ba
signaturelock-open Commit is signed but in an unrecognized format.

support `@atomicRmw` at comptime


3 files changed, 114 insertions(+), 15 deletions(-)

src/ir.cpp+76-6
...@@ -28436,14 +28436,84 @@ static IrInstGen *ir_analyze_instruction_atomic_rmw(IrAnalyze *ira, IrInstSrcAto...@@ -28436,14 +28436,84 @@ static IrInstGen *ir_analyze_instruction_atomic_rmw(IrAnalyze *ira, IrInstSrcAto
28436 return ir_const_move(ira, &instruction->base.base, get_the_one_possible_value(ira->codegen, operand_type));28436 return ir_const_move(ira, &instruction->base.base, get_the_one_possible_value(ira->codegen, operand_type));
28437 }28437 }
2843828438
28439 if (instr_is_comptime(casted_operand) && instr_is_comptime(casted_ptr) && casted_ptr->value->data.x_ptr.mut == ConstPtrMutComptimeVar)28439 IrInst *source_inst = &instruction->base.base;
28440 {28440 if (instr_is_comptime(casted_operand) && instr_is_comptime(casted_ptr) && casted_ptr->value->data.x_ptr.mut == ConstPtrMutComptimeVar) {
28441 ir_add_error(ira, &instruction->base.base,28441 ZigValue *ptr_val = ir_resolve_const(ira, casted_ptr, UndefBad);
28442 buf_sprintf("compiler bug: TODO compile-time execution of @atomicRmw"));28442 if (ptr_val == nullptr)
28443 return ira->codegen->invalid_inst_gen;28443 return ira->codegen->invalid_inst_gen;
28444
28445 ZigValue *op1_val = const_ptr_pointee(ira, ira->codegen, ptr_val, instruction->base.base.source_node);
28446 if (op1_val == nullptr)
28447 return ira->codegen->invalid_inst_gen;
28448
28449 ZigValue *op2_val = ir_resolve_const(ira, casted_operand, UndefBad);
28450 if (op2_val == nullptr)
28451 return ira->codegen->invalid_inst_gen;
28452
28453 if (op == AtomicRmwOp_xchg) {
28454 ir_analyze_store_ptr(ira, source_inst, casted_ptr, casted_operand, false);
28455 return ir_const_move(ira, source_inst, op1_val);
28456 }
28457
28458 if (operand_type->id == ZigTypeIdPointer || operand_type->id == ZigTypeIdOptional) {
28459 ir_add_error(ira, &instruction->ordering->base,
28460 buf_sprintf("TODO comptime @atomicRmw with pointers other than .Xchg"));
28461 return ira->codegen->invalid_inst_gen;
28462 }
28463
28464 if (op == AtomicRmwOp_min || op == AtomicRmwOp_max) {
28465 IrBinOp bin_op;
28466 if (op == AtomicRmwOp_min)
28467 // store op2 if op2 < op1
28468 bin_op = IrBinOpCmpGreaterThan;
28469 else
28470 // store op2 if op2 > op1
28471 bin_op = IrBinOpCmpLessThan;
28472
28473 IrInstGen *dummy_value = ir_const(ira, source_inst, operand_type);
28474 ir_eval_bin_op_cmp_scalar(ira, source_inst, op1_val, bin_op, op2_val, dummy_value->value);
28475 if (dummy_value->value->data.x_bool)
28476 ir_analyze_store_ptr(ira, source_inst, casted_ptr, casted_operand, false);
28477 } else {
28478 IrBinOp bin_op;
28479 switch (op) {
28480 case AtomicRmwOp_xchg:
28481 case AtomicRmwOp_max:
28482 case AtomicRmwOp_min:
28483 zig_unreachable();
28484 case AtomicRmwOp_add:
28485 if (operand_type->id == ZigTypeIdFloat)
28486 bin_op = IrBinOpAdd;
28487 else
28488 bin_op = IrBinOpAddWrap;
28489 break;
28490 case AtomicRmwOp_sub:
28491 if (operand_type->id == ZigTypeIdFloat)
28492 bin_op = IrBinOpSub;
28493 else
28494 bin_op = IrBinOpSubWrap;
28495 break;
28496 case AtomicRmwOp_and:
28497 case AtomicRmwOp_nand:
28498 bin_op = IrBinOpBinAnd;
28499 break;
28500 case AtomicRmwOp_or:
28501 bin_op = IrBinOpBinOr;
28502 break;
28503 case AtomicRmwOp_xor:
28504 bin_op = IrBinOpBinXor;
28505 break;
28506 }
28507 ir_eval_math_op_scalar(ira, source_inst, operand_type, op1_val, bin_op, op2_val, op1_val);
28508 if (op == AtomicRmwOp_nand) {
28509 bigint_not(&op1_val->data.x_bigint, &op1_val->data.x_bigint,
28510 operand_type->data.integral.bit_count, operand_type->data.integral.is_signed);
28511 }
28512 }
28513 return ir_const_move(ira, source_inst, op1_val);
28444 }28514 }
2844528515
28446 return ir_build_atomic_rmw_gen(ira, &instruction->base.base, casted_ptr, casted_operand, op,28516 return ir_build_atomic_rmw_gen(ira, source_inst, casted_ptr, casted_operand, op,
28447 ordering, operand_type);28517 ordering, operand_type);
28448}28518}
2844928519
test/compile_errors.zig+9-9
...@@ -2,15 +2,6 @@ const tests = @import("tests.zig");...@@ -2,15 +2,6 @@ const tests = @import("tests.zig");
2const std = @import("std");2const std = @import("std");
33
4pub fn addCases(cases: *tests.CompileErrorContext) void {4pub fn addCases(cases: *tests.CompileErrorContext) void {
5 cases.add("atomicrmw with bool op not .Xchg",
6 \\export fn entry() void {
7 \\ var x = false;
8 \\ _ = @atomicRmw(bool, &x, .Add, true, .SeqCst);
9 \\}
10 , &[_][]const u8{
11 "tmp.zig:3:30: error: @atomicRmw with bool only allowed with .Xchg",
12 });
13
14 cases.addTest("combination of noasync and async",5 cases.addTest("combination of noasync and async",
15 \\export fn entry() void {6 \\export fn entry() void {
16 \\ noasync {7 \\ noasync {
...@@ -26,6 +17,15 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -26,6 +17,15 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
26 "tmp.zig:5:9: error: resume in noasync scope",17 "tmp.zig:5:9: error: resume in noasync scope",
27 });18 });
2819
20 cases.add("atomicrmw with bool op not .Xchg",
21 \\export fn entry() void {
22 \\ var x = false;
23 \\ _ = @atomicRmw(bool, &x, .Add, true, .SeqCst);
24 \\}
25 , &[_][]const u8{
26 "tmp.zig:3:30: error: @atomicRmw with bool only allowed with .Xchg",
27 });
28
29 cases.addTest("@TypeOf with no arguments",29 cases.addTest("@TypeOf with no arguments",
30 \\export fn entry() void {30 \\export fn entry() void {
31 \\ _ = @TypeOf();31 \\ _ = @TypeOf();
test/stage1/behavior/atomics.zig+29
...@@ -149,6 +149,7 @@ fn testAtomicStore() void {...@@ -149,6 +149,7 @@ fn testAtomicStore() void {
149}149}
150150
151test "atomicrmw with floats" {151test "atomicrmw with floats" {
152 comptime testAtomicRmwFloat();
152 if (builtin.arch == .aarch64 or builtin.arch == .arm or builtin.arch == .riscv64)153 if (builtin.arch == .aarch64 or builtin.arch == .arm or builtin.arch == .riscv64)
153 return error.SkipZigTest;154 return error.SkipZigTest;
154 testAtomicRmwFloat();155 testAtomicRmwFloat();
...@@ -165,6 +166,34 @@ fn testAtomicRmwFloat() void {...@@ -165,6 +166,34 @@ fn testAtomicRmwFloat() void {
165 expect(x == 4);166 expect(x == 4);
166}167}
167168
169test "atomicrmw with ints" {
170 testAtomicRmwFloat();
171 comptime testAtomicRmwFloat();
172}
173
174fn testAtomicRmwInt() void {
175 var x: u8 = 1;
176 _ = @atomicRmw(u8, &x, .Xchg, 3, .SeqCst);
177 expect(x == 3);
178 _ = @atomicRmw(u8, &x, .Add, 3, .SeqCst);
179 expect(x == 6);
180 _ = @atomicRmw(u8, &x, .Sub, 1, .SeqCst);
181 expect(x == 5);
182 _ = @atomicRmw(u8, &x, .And, 4, .SeqCst);
183 expect(x == 4);
184 _ = @atomicRmw(u8, &x, .Nand, 4, .SeqCst);
185 expect(x == 0xfb);
186 _ = @atomicRmw(u8, &x, .Or, 6, .SeqCst);
187 expect(x == 0xff);
188 _ = @atomicRmw(u8, &x, .Xor, 2, .SeqCst);
189 expect(x == 0xfd);
190 _ = @atomicRmw(u8, &x, .Max, 1, .SeqCst);
191 expect(x == 0xfd);
192 _ = @atomicRmw(u8, &x, .Min, 1, .SeqCst);
193 expect(x == 1);
194}
195
196
168test "atomics with different types" {197test "atomics with different types" {
169 testAtomicsWithType(bool, true, false);198 testAtomicsWithType(bool, true, false);
170 inline for (.{ u1, i5, u15 }) |T| {199 inline for (.{ u1, i5, u15 }) |T| {