authorgravatar for thatlemon@gmail.comLemonBoy <thatlemon@gmail.com> 2021-05-28 10:26:14+02:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-05-28 19:18:42-04:00
logd3fb9f95323eb09b1f1f52e31363401115bfdae9
treee113fe0475d8f5d3e9289c4802b5e867fa860f0f
parent3483931d2a8e9cd565e2c03ee34ac9a7db538a7e

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

2 files changed, 18 insertions(+), 14 deletions(-)

src/stage1/codegen.cpp+18-9
......@@ -5491,9 +5491,11 @@ static enum ZigLLVM_AtomicRMWBinOp to_ZigLLVMAtomicRMWBinOp(AtomicRmwOp op, bool
54915491 zig_unreachable();
54925492}
54935493
5494static LLVMTypeRef get_atomic_abi_type(CodeGen *g, IrInstGen *instruction) {
5494static 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-5
......@@ -149,11 +149,6 @@ fn testAtomicStore() !void {
149149}
150150
151151test "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}