Skip to content

Commit 1f66435

Browse files
committed
support cmpxchg at comptime
1 parent 64e60d8 commit 1f66435

File tree

2 files changed

+39
-35
lines changed

2 files changed

+39
-35
lines changed

src/ir.cpp

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -25212,7 +25212,20 @@ static IrInstGen *ir_analyze_instruction_cmpxchg(IrAnalyze *ira, IrInstSrcCmpxch
2521225212

2521325213
if (instr_is_comptime(casted_ptr) && casted_ptr->value->data.x_ptr.mut != ConstPtrMutRuntimeVar &&
2521425214
instr_is_comptime(casted_cmp_value) && instr_is_comptime(casted_new_value)) {
25215-
zig_panic("TODO compile-time execution of cmpxchg");
25215+
IrInstGen *result = ir_get_deref(ira, &instruction->base.base, casted_ptr, nullptr);
25216+
ZigValue *op1_val = ir_resolve_const(ira, result, UndefBad);
25217+
ZigValue *op2_val = ir_resolve_const(ira, casted_cmp_value, UndefBad);
25218+
bool eql = const_values_equal(ira->codegen, op1_val, op2_val);
25219+
ZigValue *val = ira->codegen->pass1_arena->allocate<ZigValue>(1);
25220+
val->special = ConstValSpecialStatic;
25221+
val->type = result_type;
25222+
if (eql) {
25223+
ir_analyze_store_ptr(ira, &instruction->base.base, casted_ptr, casted_new_value, false);
25224+
set_optional_value_to_null(val);
25225+
} else {
25226+
set_optional_payload(val, op1_val);
25227+
}
25228+
return ir_const_move(ira, &instruction->base.base, val);
2521625229
}
2521725230

2521825231
IrInstGen *result_loc;
@@ -28334,7 +28347,6 @@ static ZigType *ir_resolve_atomic_operand_type(IrAnalyze *ira, IrInstGen *op, Zi
2833428347
int_type = operand_type;
2833528348
}
2833628349
auto bit_count = int_type->data.integral.bit_count;
28337-
bool is_signed = int_type->data.integral.is_signed;
2833828350
uint32_t max_atomic_bits = target_arch_largest_atomic_bits(ira->codegen->zig_target->arch);
2833928351

2834028352
if (bit_count > max_atomic_bits) {
@@ -28344,20 +28356,8 @@ static ZigType *ir_resolve_atomic_operand_type(IrAnalyze *ira, IrInstGen *op, Zi
2834428356
return ira->codegen->builtin_types.entry_invalid;
2834528357
}
2834628358

28347-
if (bit_count < 2 || !is_power_of_2(bit_count)) {
28348-
if (bit_count < 8) {
28349-
*actual_type = get_int_type(ira->codegen, is_signed, 8);
28350-
} else if (bit_count < 16) {
28351-
*actual_type = get_int_type(ira->codegen, is_signed, 16);
28352-
} else if (bit_count < 32) {
28353-
*actual_type = get_int_type(ira->codegen, is_signed, 32);
28354-
} else if (bit_count < 64) {
28355-
*actual_type = get_int_type(ira->codegen, is_signed, 64);
28356-
} else if (bit_count < 128) {
28357-
*actual_type = get_int_type(ira->codegen, is_signed, 128);
28358-
} else {
28359-
zig_unreachable();
28360-
}
28359+
if (bit_count == 1 || !is_power_of_2(bit_count)) {
28360+
*actual_type = get_int_type(ira->codegen, int_type->data.integral.is_signed, int_type->abi_size * 8);
2836128361
}
2836228362
} else if (operand_type->id == ZigTypeIdFloat) {
2836328363
uint32_t max_atomic_bits = target_arch_largest_atomic_bits(ira->codegen->zig_target->arch);

test/stage1/behavior/atomics.zig

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,29 +2,32 @@ const std = @import("std");
22
const expect = std.testing.expect;
33
const expectEqual = std.testing.expectEqual;
44
const builtin = @import("builtin");
5-
const AtomicRmwOp = builtin.AtomicRmwOp;
6-
const AtomicOrder = builtin.AtomicOrder;
75

86
test "cmpxchg" {
7+
testCmpxchg();
8+
comptime testCmpxchg();
9+
}
10+
11+
fn testCmpxchg() void {
912
var x: i32 = 1234;
10-
if (@cmpxchgWeak(i32, &x, 99, 5678, AtomicOrder.SeqCst, AtomicOrder.SeqCst)) |x1| {
13+
if (@cmpxchgWeak(i32, &x, 99, 5678, .SeqCst, .SeqCst)) |x1| {
1114
expect(x1 == 1234);
1215
} else {
1316
@panic("cmpxchg should have failed");
1417
}
1518

16-
while (@cmpxchgWeak(i32, &x, 1234, 5678, AtomicOrder.SeqCst, AtomicOrder.SeqCst)) |x1| {
19+
while (@cmpxchgWeak(i32, &x, 1234, 5678, .SeqCst, .SeqCst)) |x1| {
1720
expect(x1 == 1234);
1821
}
1922
expect(x == 5678);
2023

21-
expect(@cmpxchgStrong(i32, &x, 5678, 42, AtomicOrder.SeqCst, AtomicOrder.SeqCst) == null);
24+
expect(@cmpxchgStrong(i32, &x, 5678, 42, .SeqCst, .SeqCst) == null);
2225
expect(x == 42);
2326
}
2427

2528
test "fence" {
2629
var x: i32 = 1234;
27-
@fence(AtomicOrder.SeqCst);
30+
@fence(.SeqCst);
2831
x = 5678;
2932
}
3033

@@ -36,18 +39,18 @@ test "atomicrmw and atomicload" {
3639
}
3740

3841
fn testAtomicRmw(ptr: *u8) void {
39-
const prev_value = @atomicRmw(u8, ptr, AtomicRmwOp.Xchg, 42, AtomicOrder.SeqCst);
42+
const prev_value = @atomicRmw(u8, ptr, .Xchg, 42, .SeqCst);
4043
expect(prev_value == 200);
4144
comptime {
4245
var x: i32 = 1234;
4346
const y: i32 = 12345;
44-
expect(@atomicLoad(i32, &x, AtomicOrder.SeqCst) == 1234);
45-
expect(@atomicLoad(i32, &y, AtomicOrder.SeqCst) == 12345);
47+
expect(@atomicLoad(i32, &x, .SeqCst) == 1234);
48+
expect(@atomicLoad(i32, &y, .SeqCst) == 12345);
4649
}
4750
}
4851

4952
fn testAtomicLoad(ptr: *u8) void {
50-
const x = @atomicLoad(u8, ptr, AtomicOrder.SeqCst);
53+
const x = @atomicLoad(u8, ptr, .SeqCst);
5154
expect(x == 42);
5255
}
5356

@@ -56,18 +59,18 @@ test "cmpxchg with ptr" {
5659
var data2: i32 = 5678;
5760
var data3: i32 = 9101;
5861
var x: *i32 = &data1;
59-
if (@cmpxchgWeak(*i32, &x, &data2, &data3, AtomicOrder.SeqCst, AtomicOrder.SeqCst)) |x1| {
62+
if (@cmpxchgWeak(*i32, &x, &data2, &data3, .SeqCst, .SeqCst)) |x1| {
6063
expect(x1 == &data1);
6164
} else {
6265
@panic("cmpxchg should have failed");
6366
}
6467

65-
while (@cmpxchgWeak(*i32, &x, &data1, &data3, AtomicOrder.SeqCst, AtomicOrder.SeqCst)) |x1| {
68+
while (@cmpxchgWeak(*i32, &x, &data1, &data3, .SeqCst, .SeqCst)) |x1| {
6669
expect(x1 == &data1);
6770
}
6871
expect(x == &data3);
6972

70-
expect(@cmpxchgStrong(*i32, &x, &data3, &data2, AtomicOrder.SeqCst, AtomicOrder.SeqCst) == null);
73+
expect(@cmpxchgStrong(*i32, &x, &data3, &data2, .SeqCst, .SeqCst) == null);
7174
expect(x == &data2);
7275
}
7376

@@ -163,16 +166,17 @@ fn testAtomicRmwFloat() void {
163166
}
164167

165168
test "atomics with different types" {
166-
// testAtomicsWithType(bool, true, false);
167-
// inline for (.{ u1, i5, u33 }) |T| {
168-
// var x: T = 0;
169-
// testAtomicsWithType(T, 0, 1);
170-
// }
169+
testAtomicsWithType(bool, true, false);
170+
inline for (.{ u1, i5, u33 }) |T| {
171+
var x: T = 0;
172+
testAtomicsWithType(T, 0, 1);
173+
}
171174
testAtomicsWithType(u0, 0, 0);
172175
testAtomicsWithType(i0, 0, 0);
173176
}
174177

175-
fn testAtomicsWithType(comptime T: type, a: T, b: T) void {
178+
// a and b souldn't need to be comptime
179+
fn testAtomicsWithType(comptime T: type, comptime a: T, comptime b: T) void {
176180
var x: T = b;
177181
@atomicStore(T, &x, a, .SeqCst);
178182
expect(x == a);

0 commit comments

Comments
 (0)