Skip to content

Commit d3fb9f9

Browse files
LemonBoyandrewrk
authored andcommitted
stage1: Fix for atomicrmw xchg on fp types
Bitcast the pointer and operands to integer types having the same size, working around LLVM inability to lower a LL/SC operation when the operands have floating-point types (and are reasonably sized). Closes #4457
1 parent 3483931 commit d3fb9f9

File tree

2 files changed

+18
-14
lines changed

2 files changed

+18
-14
lines changed

src/stage1/codegen.cpp

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5491,9 +5491,11 @@ static enum ZigLLVM_AtomicRMWBinOp to_ZigLLVMAtomicRMWBinOp(AtomicRmwOp op, bool
54915491
zig_unreachable();
54925492
}
54935493

5494-
static LLVMTypeRef get_atomic_abi_type(CodeGen *g, IrInstGen *instruction) {
5494+
static LLVMTypeRef get_atomic_abi_type(CodeGen *g, IrInstGen *instruction, bool RMWXchg) {
54955495
// If the operand type of an atomic operation is not byte sized we need to
54965496
// widen it before using it and then truncate the result.
5497+
// RMW exchange of floating-point values is bitcasted to same-sized integer
5498+
// types to work around a LLVM deficiency when targeting ARM/AArch64.
54975499

54985500
ir_assert(instruction->value->type->id == ZigTypeIdPointer, instruction);
54995501
ZigType *operand_type = instruction->value->type->data.pointer.child_type;
@@ -5511,7 +5513,7 @@ static LLVMTypeRef get_atomic_abi_type(CodeGen *g, IrInstGen *instruction) {
55115513
return nullptr;
55125514
}
55135515
} else if (operand_type->id == ZigTypeIdFloat) {
5514-
return nullptr;
5516+
return RMWXchg ? LLVMIntType(operand_type->abi_size * 8) : nullptr;
55155517
} else if (operand_type->id == ZigTypeIdBool) {
55165518
return g->builtin_types.entry_u8->llvm_type;
55175519
} else {
@@ -5526,7 +5528,7 @@ static LLVMValueRef ir_render_cmpxchg(CodeGen *g, IrExecutableGen *executable, I
55265528
LLVMValueRef new_val = ir_llvm_value(g, instruction->new_value);
55275529

55285530
ZigType *operand_type = instruction->new_value->value->type;
5529-
LLVMTypeRef actual_abi_type = get_atomic_abi_type(g, instruction->ptr);
5531+
LLVMTypeRef actual_abi_type = get_atomic_abi_type(g, instruction->ptr, false);
55305532
if (actual_abi_type != nullptr) {
55315533
// operand needs widening and truncating
55325534
ptr_val = LLVMBuildBitCast(g->builder, ptr_val,
@@ -6315,20 +6317,27 @@ static LLVMValueRef ir_render_atomic_rmw(CodeGen *g, IrExecutableGen *executable
63156317
LLVMValueRef ptr = ir_llvm_value(g, instruction->ptr);
63166318
LLVMValueRef operand = ir_llvm_value(g, instruction->operand);
63176319

6318-
LLVMTypeRef actual_abi_type = get_atomic_abi_type(g, instruction->ptr);
6320+
LLVMTypeRef actual_abi_type = get_atomic_abi_type(g, instruction->ptr,
6321+
op == ZigLLVMAtomicRMWBinOpXchg);
63196322
if (actual_abi_type != nullptr) {
6320-
// operand needs widening and truncating
6323+
// operand needs widening and truncating or bitcasting.
63216324
LLVMValueRef casted_ptr = LLVMBuildBitCast(g->builder, ptr,
63226325
LLVMPointerType(actual_abi_type, 0), "");
63236326
LLVMValueRef casted_operand;
6324-
if (operand_type->data.integral.is_signed) {
6327+
if (is_float) {
6328+
casted_operand = LLVMBuildBitCast(g->builder, operand, actual_abi_type, "");
6329+
} else if (operand_type->data.integral.is_signed) {
63256330
casted_operand = LLVMBuildSExt(g->builder, operand, actual_abi_type, "");
63266331
} else {
63276332
casted_operand = LLVMBuildZExt(g->builder, operand, actual_abi_type, "");
63286333
}
63296334
LLVMValueRef uncasted_result = ZigLLVMBuildAtomicRMW(g->builder, op, casted_ptr, casted_operand, ordering,
63306335
g->is_single_threaded);
6331-
return LLVMBuildTrunc(g->builder, uncasted_result, get_llvm_type(g, operand_type), "");
6336+
if (is_float) {
6337+
return LLVMBuildBitCast(g->builder, uncasted_result, get_llvm_type(g, operand_type), "");
6338+
} else {
6339+
return LLVMBuildTrunc(g->builder, uncasted_result, get_llvm_type(g, operand_type), "");
6340+
}
63326341
}
63336342

63346343
if (get_codegen_ptr_type_bail(g, operand_type) == nullptr) {
@@ -6351,7 +6360,7 @@ static LLVMValueRef ir_render_atomic_load(CodeGen *g, IrExecutableGen *executabl
63516360
LLVMValueRef ptr = ir_llvm_value(g, instruction->ptr);
63526361

63536362
ZigType *operand_type = instruction->ptr->value->type->data.pointer.child_type;
6354-
LLVMTypeRef actual_abi_type = get_atomic_abi_type(g, instruction->ptr);
6363+
LLVMTypeRef actual_abi_type = get_atomic_abi_type(g, instruction->ptr, false);
63556364
if (actual_abi_type != nullptr) {
63566365
// operand needs widening and truncating
63576366
ptr = LLVMBuildBitCast(g->builder, ptr,
@@ -6372,7 +6381,7 @@ static LLVMValueRef ir_render_atomic_store(CodeGen *g, IrExecutableGen *executab
63726381
LLVMValueRef ptr = ir_llvm_value(g, instruction->ptr);
63736382
LLVMValueRef value = ir_llvm_value(g, instruction->value);
63746383

6375-
LLVMTypeRef actual_abi_type = get_atomic_abi_type(g, instruction->ptr);
6384+
LLVMTypeRef actual_abi_type = get_atomic_abi_type(g, instruction->ptr, false);
63766385
if (actual_abi_type != nullptr) {
63776386
// operand needs widening
63786387
ptr = LLVMBuildBitCast(g->builder, ptr,

test/behavior/atomics.zig

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -149,11 +149,6 @@ fn testAtomicStore() !void {
149149
}
150150

151151
test "atomicrmw with floats" {
152-
switch (builtin.target.cpu.arch) {
153-
// https://github.com/ziglang/zig/issues/4457
154-
.aarch64, .arm, .thumb, .riscv64 => return error.SkipZigTest,
155-
else => {},
156-
}
157152
try testAtomicRmwFloat();
158153
comptime try testAtomicRmwFloat();
159154
}

0 commit comments

Comments
 (0)