@@ -5491,9 +5491,11 @@ static enum ZigLLVM_AtomicRMWBinOp to_ZigLLVMAtomicRMWBinOp(AtomicRmwOp op, bool
5491
5491
zig_unreachable ();
5492
5492
}
5493
5493
5494
- static LLVMTypeRef get_atomic_abi_type (CodeGen *g, IrInstGen *instruction) {
5494
+ static LLVMTypeRef get_atomic_abi_type (CodeGen *g, IrInstGen *instruction, bool RMWXchg ) {
5495
5495
// If the operand type of an atomic operation is not byte sized we need to
5496
5496
// 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.
5497
5499
5498
5500
ir_assert (instruction->value ->type ->id == ZigTypeIdPointer, instruction);
5499
5501
ZigType *operand_type = instruction->value ->type ->data .pointer .child_type ;
@@ -5511,7 +5513,7 @@ static LLVMTypeRef get_atomic_abi_type(CodeGen *g, IrInstGen *instruction) {
5511
5513
return nullptr ;
5512
5514
}
5513
5515
} else if (operand_type->id == ZigTypeIdFloat) {
5514
- return nullptr ;
5516
+ return RMWXchg ? LLVMIntType (operand_type-> abi_size * 8 ) : nullptr ;
5515
5517
} else if (operand_type->id == ZigTypeIdBool) {
5516
5518
return g->builtin_types .entry_u8 ->llvm_type ;
5517
5519
} else {
@@ -5526,7 +5528,7 @@ static LLVMValueRef ir_render_cmpxchg(CodeGen *g, IrExecutableGen *executable, I
5526
5528
LLVMValueRef new_val = ir_llvm_value (g, instruction->new_value );
5527
5529
5528
5530
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 );
5530
5532
if (actual_abi_type != nullptr ) {
5531
5533
// operand needs widening and truncating
5532
5534
ptr_val = LLVMBuildBitCast (g->builder , ptr_val,
@@ -6315,20 +6317,27 @@ static LLVMValueRef ir_render_atomic_rmw(CodeGen *g, IrExecutableGen *executable
6315
6317
LLVMValueRef ptr = ir_llvm_value (g, instruction->ptr );
6316
6318
LLVMValueRef operand = ir_llvm_value (g, instruction->operand );
6317
6319
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);
6319
6322
if (actual_abi_type != nullptr ) {
6320
- // operand needs widening and truncating
6323
+ // operand needs widening and truncating or bitcasting.
6321
6324
LLVMValueRef casted_ptr = LLVMBuildBitCast (g->builder , ptr,
6322
6325
LLVMPointerType (actual_abi_type, 0 ), " " );
6323
6326
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 ) {
6325
6330
casted_operand = LLVMBuildSExt (g->builder , operand, actual_abi_type, " " );
6326
6331
} else {
6327
6332
casted_operand = LLVMBuildZExt (g->builder , operand, actual_abi_type, " " );
6328
6333
}
6329
6334
LLVMValueRef uncasted_result = ZigLLVMBuildAtomicRMW (g->builder , op, casted_ptr, casted_operand, ordering,
6330
6335
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
+ }
6332
6341
}
6333
6342
6334
6343
if (get_codegen_ptr_type_bail (g, operand_type) == nullptr ) {
@@ -6351,7 +6360,7 @@ static LLVMValueRef ir_render_atomic_load(CodeGen *g, IrExecutableGen *executabl
6351
6360
LLVMValueRef ptr = ir_llvm_value (g, instruction->ptr );
6352
6361
6353
6362
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 );
6355
6364
if (actual_abi_type != nullptr ) {
6356
6365
// operand needs widening and truncating
6357
6366
ptr = LLVMBuildBitCast (g->builder , ptr,
@@ -6372,7 +6381,7 @@ static LLVMValueRef ir_render_atomic_store(CodeGen *g, IrExecutableGen *executab
6372
6381
LLVMValueRef ptr = ir_llvm_value (g, instruction->ptr );
6373
6382
LLVMValueRef value = ir_llvm_value (g, instruction->value );
6374
6383
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 );
6376
6385
if (actual_abi_type != nullptr ) {
6377
6386
// operand needs widening
6378
6387
ptr = LLVMBuildBitCast (g->builder , ptr,
0 commit comments