support cmpxchg at comptime

This commit is contained in:
Vexu 2020-03-11 12:02:05 +02:00
parent 64e60d8ae2
commit 1f66435a6b
No known key found for this signature in database
GPG Key ID: 59AEB8936E16A6AC
2 changed files with 39 additions and 35 deletions

View File

@ -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 && 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)) { 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; IrInstGen *result_loc;
@ -28334,7 +28347,6 @@ static ZigType *ir_resolve_atomic_operand_type(IrAnalyze *ira, IrInstGen *op, Zi
int_type = operand_type; int_type = operand_type;
} }
auto bit_count = int_type->data.integral.bit_count; 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); uint32_t max_atomic_bits = target_arch_largest_atomic_bits(ira->codegen->zig_target->arch);
if (bit_count > max_atomic_bits) { 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; return ira->codegen->builtin_types.entry_invalid;
} }
if (bit_count < 2 || !is_power_of_2(bit_count)) { if (bit_count == 1 || !is_power_of_2(bit_count)) {
if (bit_count < 8) { *actual_type = get_int_type(ira->codegen, int_type->data.integral.is_signed, int_type->abi_size * 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();
}
} }
} else if (operand_type->id == ZigTypeIdFloat) { } else if (operand_type->id == ZigTypeIdFloat) {
uint32_t max_atomic_bits = target_arch_largest_atomic_bits(ira->codegen->zig_target->arch); uint32_t max_atomic_bits = target_arch_largest_atomic_bits(ira->codegen->zig_target->arch);

View File

@ -2,29 +2,32 @@ const std = @import("std");
const expect = std.testing.expect; const expect = std.testing.expect;
const expectEqual = std.testing.expectEqual; const expectEqual = std.testing.expectEqual;
const builtin = @import("builtin"); const builtin = @import("builtin");
const AtomicRmwOp = builtin.AtomicRmwOp;
const AtomicOrder = builtin.AtomicOrder;
test "cmpxchg" { test "cmpxchg" {
testCmpxchg();
comptime testCmpxchg();
}
fn testCmpxchg() void {
var x: i32 = 1234; 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); expect(x1 == 1234);
} else { } else {
@panic("cmpxchg should have failed"); @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(x1 == 1234);
} }
expect(x == 5678); 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); expect(x == 42);
} }
test "fence" { test "fence" {
var x: i32 = 1234; var x: i32 = 1234;
@fence(AtomicOrder.SeqCst); @fence(.SeqCst);
x = 5678; x = 5678;
} }
@ -36,18 +39,18 @@ test "atomicrmw and atomicload" {
} }
fn testAtomicRmw(ptr: *u8) void { 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); expect(prev_value == 200);
comptime { comptime {
var x: i32 = 1234; var x: i32 = 1234;
const y: i32 = 12345; const y: i32 = 12345;
expect(@atomicLoad(i32, &x, AtomicOrder.SeqCst) == 1234); expect(@atomicLoad(i32, &x, .SeqCst) == 1234);
expect(@atomicLoad(i32, &y, AtomicOrder.SeqCst) == 12345); expect(@atomicLoad(i32, &y, .SeqCst) == 12345);
} }
} }
fn testAtomicLoad(ptr: *u8) void { fn testAtomicLoad(ptr: *u8) void {
const x = @atomicLoad(u8, ptr, AtomicOrder.SeqCst); const x = @atomicLoad(u8, ptr, .SeqCst);
expect(x == 42); expect(x == 42);
} }
@ -56,18 +59,18 @@ test "cmpxchg with ptr" {
var data2: i32 = 5678; var data2: i32 = 5678;
var data3: i32 = 9101; var data3: i32 = 9101;
var x: *i32 = &data1; 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); expect(x1 == &data1);
} else { } else {
@panic("cmpxchg should have failed"); @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(x1 == &data1);
} }
expect(x == &data3); 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); expect(x == &data2);
} }
@ -163,16 +166,17 @@ fn testAtomicRmwFloat() void {
} }
test "atomics with different types" { test "atomics with different types" {
// testAtomicsWithType(bool, true, false); testAtomicsWithType(bool, true, false);
// inline for (.{ u1, i5, u33 }) |T| { inline for (.{ u1, i5, u33 }) |T| {
// var x: T = 0; var x: T = 0;
// testAtomicsWithType(T, 0, 1); testAtomicsWithType(T, 0, 1);
// } }
testAtomicsWithType(u0, 0, 0); testAtomicsWithType(u0, 0, 0);
testAtomicsWithType(i0, 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; var x: T = b;
@atomicStore(T, &x, a, .SeqCst); @atomicStore(T, &x, a, .SeqCst);
expect(x == a); expect(x == a);