Commit 1f66435a6b

Vexu <git@vexu.eu>
2020-03-11 11:02:05
support cmpxchg at comptime
1 parent 64e60d8
Changed files (2)
src
test
stage1
behavior
src/ir.cpp
@@ -25212,7 +25212,20 @@ static IrInstGen *ir_analyze_instruction_cmpxchg(IrAnalyze *ira, IrInstSrcCmpxch
 
     if (instr_is_comptime(casted_ptr) && casted_ptr->value->data.x_ptr.mut != ConstPtrMutRuntimeVar &&
         instr_is_comptime(casted_cmp_value) && instr_is_comptime(casted_new_value)) {
-        zig_panic("TODO compile-time execution of cmpxchg");
+        IrInstGen *result = ir_get_deref(ira, &instruction->base.base, casted_ptr, nullptr);
+        ZigValue *op1_val = ir_resolve_const(ira, result, UndefBad);
+        ZigValue *op2_val = ir_resolve_const(ira, casted_cmp_value, UndefBad);
+        bool eql = const_values_equal(ira->codegen, op1_val, op2_val);
+        ZigValue *val = ira->codegen->pass1_arena->allocate<ZigValue>(1);
+        val->special = ConstValSpecialStatic;
+        val->type = result_type;
+        if (eql) {
+            ir_analyze_store_ptr(ira, &instruction->base.base, casted_ptr, casted_new_value, false);
+            set_optional_value_to_null(val);
+        } else {
+            set_optional_payload(val, op1_val);
+        }
+        return ir_const_move(ira, &instruction->base.base, val);
     }
 
     IrInstGen *result_loc;
@@ -28334,7 +28347,6 @@ static ZigType *ir_resolve_atomic_operand_type(IrAnalyze *ira, IrInstGen *op, Zi
             int_type = operand_type;
         }
         auto bit_count = int_type->data.integral.bit_count;
-        bool is_signed = int_type->data.integral.is_signed;
         uint32_t max_atomic_bits = target_arch_largest_atomic_bits(ira->codegen->zig_target->arch);
 
         if (bit_count > max_atomic_bits) {
@@ -28344,20 +28356,8 @@ static ZigType *ir_resolve_atomic_operand_type(IrAnalyze *ira, IrInstGen *op, Zi
             return ira->codegen->builtin_types.entry_invalid;
         }
 
-        if (bit_count < 2 || !is_power_of_2(bit_count)) {
-            if (bit_count < 8) {
-                *actual_type = get_int_type(ira->codegen, is_signed, 8);
-            } else if (bit_count < 16) {
-                *actual_type = get_int_type(ira->codegen, is_signed, 16);
-            } else if (bit_count < 32) {
-                *actual_type = get_int_type(ira->codegen, is_signed, 32);
-            } else if (bit_count < 64) {
-                *actual_type = get_int_type(ira->codegen, is_signed, 64);
-            } else if (bit_count < 128) {
-                *actual_type = get_int_type(ira->codegen, is_signed, 128);
-            } else {
-                zig_unreachable();
-            }
+        if (bit_count == 1 || !is_power_of_2(bit_count)) {
+            *actual_type = get_int_type(ira->codegen, int_type->data.integral.is_signed, int_type->abi_size * 8);
         }
     } else if (operand_type->id == ZigTypeIdFloat) {
         uint32_t max_atomic_bits = target_arch_largest_atomic_bits(ira->codegen->zig_target->arch);
test/stage1/behavior/atomics.zig
@@ -2,29 +2,32 @@ const std = @import("std");
 const expect = std.testing.expect;
 const expectEqual = std.testing.expectEqual;
 const builtin = @import("builtin");
-const AtomicRmwOp = builtin.AtomicRmwOp;
-const AtomicOrder = builtin.AtomicOrder;
 
 test "cmpxchg" {
+    testCmpxchg();
+    comptime testCmpxchg();
+}
+
+fn testCmpxchg() void {
     var x: i32 = 1234;
-    if (@cmpxchgWeak(i32, &x, 99, 5678, AtomicOrder.SeqCst, AtomicOrder.SeqCst)) |x1| {
+    if (@cmpxchgWeak(i32, &x, 99, 5678, .SeqCst, .SeqCst)) |x1| {
         expect(x1 == 1234);
     } else {
         @panic("cmpxchg should have failed");
     }
 
-    while (@cmpxchgWeak(i32, &x, 1234, 5678, AtomicOrder.SeqCst, AtomicOrder.SeqCst)) |x1| {
+    while (@cmpxchgWeak(i32, &x, 1234, 5678, .SeqCst, .SeqCst)) |x1| {
         expect(x1 == 1234);
     }
     expect(x == 5678);
 
-    expect(@cmpxchgStrong(i32, &x, 5678, 42, AtomicOrder.SeqCst, AtomicOrder.SeqCst) == null);
+    expect(@cmpxchgStrong(i32, &x, 5678, 42, .SeqCst, .SeqCst) == null);
     expect(x == 42);
 }
 
 test "fence" {
     var x: i32 = 1234;
-    @fence(AtomicOrder.SeqCst);
+    @fence(.SeqCst);
     x = 5678;
 }
 
@@ -36,18 +39,18 @@ test "atomicrmw and atomicload" {
 }
 
 fn testAtomicRmw(ptr: *u8) void {
-    const prev_value = @atomicRmw(u8, ptr, AtomicRmwOp.Xchg, 42, AtomicOrder.SeqCst);
+    const prev_value = @atomicRmw(u8, ptr, .Xchg, 42, .SeqCst);
     expect(prev_value == 200);
     comptime {
         var x: i32 = 1234;
         const y: i32 = 12345;
-        expect(@atomicLoad(i32, &x, AtomicOrder.SeqCst) == 1234);
-        expect(@atomicLoad(i32, &y, AtomicOrder.SeqCst) == 12345);
+        expect(@atomicLoad(i32, &x, .SeqCst) == 1234);
+        expect(@atomicLoad(i32, &y, .SeqCst) == 12345);
     }
 }
 
 fn testAtomicLoad(ptr: *u8) void {
-    const x = @atomicLoad(u8, ptr, AtomicOrder.SeqCst);
+    const x = @atomicLoad(u8, ptr, .SeqCst);
     expect(x == 42);
 }
 
@@ -56,18 +59,18 @@ test "cmpxchg with ptr" {
     var data2: i32 = 5678;
     var data3: i32 = 9101;
     var x: *i32 = &data1;
-    if (@cmpxchgWeak(*i32, &x, &data2, &data3, AtomicOrder.SeqCst, AtomicOrder.SeqCst)) |x1| {
+    if (@cmpxchgWeak(*i32, &x, &data2, &data3, .SeqCst, .SeqCst)) |x1| {
         expect(x1 == &data1);
     } else {
         @panic("cmpxchg should have failed");
     }
 
-    while (@cmpxchgWeak(*i32, &x, &data1, &data3, AtomicOrder.SeqCst, AtomicOrder.SeqCst)) |x1| {
+    while (@cmpxchgWeak(*i32, &x, &data1, &data3, .SeqCst, .SeqCst)) |x1| {
         expect(x1 == &data1);
     }
     expect(x == &data3);
 
-    expect(@cmpxchgStrong(*i32, &x, &data3, &data2, AtomicOrder.SeqCst, AtomicOrder.SeqCst) == null);
+    expect(@cmpxchgStrong(*i32, &x, &data3, &data2, .SeqCst, .SeqCst) == null);
     expect(x == &data2);
 }
 
@@ -163,16 +166,17 @@ fn testAtomicRmwFloat() void {
 }
 
 test "atomics with different types" {
-    // testAtomicsWithType(bool, true, false);
-    // inline for (.{ u1, i5, u33 }) |T| {
-    //     var x: T = 0;
-    //     testAtomicsWithType(T, 0, 1);
-    // }
+    testAtomicsWithType(bool, true, false);
+    inline for (.{ u1, i5, u33 }) |T| {
+        var x: T = 0;
+        testAtomicsWithType(T, 0, 1);
+    }
     testAtomicsWithType(u0, 0, 0);
     testAtomicsWithType(i0, 0, 0);
 }
 
-fn testAtomicsWithType(comptime T: type, a: T, b: T) void {
+// a and b souldn't need to be comptime
+fn testAtomicsWithType(comptime T: type, comptime a: T, comptime b: T) void {
     var x: T = b;
     @atomicStore(T, &x, a, .SeqCst);
     expect(x == a);