| ... | ... | @@ -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, |