Skip to content

Commit ba71a63

Browse files
authored
Rollup merge of #105578 - erikdesjardins:addrspacecast, r=bjorn3
Fix transmutes between pointers in different address spaces (e.g. fn ptrs on AVR) Currently, this causes a verifier error (https://godbolt.org/z/YYohed4bj), since it uses `bitcast`, which can't convert between address spaces. Uncovered due to #105545 (comment) r? `@bjorn3`
2 parents 35ff2cf + 6085d33 commit ba71a63

File tree

2 files changed

+32
-5
lines changed

2 files changed

+32
-5
lines changed

compiler/rustc_codegen_ssa/src/mir/block.rs

+9-4
Original file line numberDiff line numberDiff line change
@@ -1802,15 +1802,20 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
18021802
match (src.layout.abi, dst.layout.abi) {
18031803
(abi::Abi::Scalar(src_scalar), abi::Abi::Scalar(dst_scalar)) => {
18041804
// HACK(eddyb) LLVM doesn't like `bitcast`s between pointers and non-pointers.
1805-
if (src_scalar.primitive() == abi::Pointer)
1806-
== (dst_scalar.primitive() == abi::Pointer)
1807-
{
1805+
let src_is_ptr = src_scalar.primitive() == abi::Pointer;
1806+
let dst_is_ptr = dst_scalar.primitive() == abi::Pointer;
1807+
if src_is_ptr == dst_is_ptr {
18081808
assert_eq!(src.layout.size, dst.layout.size);
18091809

18101810
// NOTE(eddyb) the `from_immediate` and `to_immediate_scalar`
18111811
// conversions allow handling `bool`s the same as `u8`s.
18121812
let src = bx.from_immediate(src.immediate());
1813-
let src_as_dst = bx.bitcast(src, bx.backend_type(dst.layout));
1813+
// LLVM also doesn't like `bitcast`s between pointers in different address spaces.
1814+
let src_as_dst = if src_is_ptr {
1815+
bx.pointercast(src, bx.backend_type(dst.layout))
1816+
} else {
1817+
bx.bitcast(src, bx.backend_type(dst.layout))
1818+
};
18141819
Immediate(bx.to_immediate_scalar(src_as_dst, dst_scalar)).store(bx, dst);
18151820
return;
18161821
}

src/test/codegen/avr/avr-func-addrspace.rs

+23-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
// It also validates that functions can be called through function pointers
1010
// through traits.
1111

12-
#![feature(no_core, lang_items, unboxed_closures, arbitrary_self_types)]
12+
#![feature(no_core, lang_items, intrinsics, unboxed_closures, arbitrary_self_types)]
1313
#![crate_type = "lib"]
1414
#![no_core]
1515

@@ -49,6 +49,10 @@ pub trait Fn<Args: Tuple>: FnOnce<Args> {
4949
extern "rust-call" fn call(&self, args: Args) -> Self::Output;
5050
}
5151

52+
extern "rust-intrinsic" {
53+
pub fn transmute<Src, Dst>(src: Src) -> Dst;
54+
}
55+
5256
pub static mut STORAGE_FOO: fn(&usize, &mut u32) -> Result<(), ()> = arbitrary_black_box;
5357
pub static mut STORAGE_BAR: u32 = 12;
5458

@@ -87,3 +91,21 @@ pub extern "C" fn test() {
8791
STORAGE_FOO(&1, &mut buf);
8892
}
8993
}
94+
95+
// Validate that we can codegen transmutes between data ptrs and fn ptrs.
96+
97+
// CHECK: define{{.+}}{{void \(\) addrspace\(1\)\*|ptr addrspace\(1\)}} @transmute_data_ptr_to_fn({{\{\}\*|ptr}}{{.*}} %x)
98+
#[no_mangle]
99+
pub unsafe fn transmute_data_ptr_to_fn(x: *const ()) -> fn() {
100+
// It doesn't matter precisely how this is codegenned (through memory or an addrspacecast),
101+
// as long as it doesn't cause a verifier error by using `bitcast`.
102+
transmute(x)
103+
}
104+
105+
// CHECK: define{{.+}}{{\{\}\*|ptr}} @transmute_fn_ptr_to_data({{void \(\) addrspace\(1\)\*|ptr addrspace\(1\)}}{{.*}} %x)
106+
#[no_mangle]
107+
pub unsafe fn transmute_fn_ptr_to_data(x: fn()) -> *const () {
108+
// It doesn't matter precisely how this is codegenned (through memory or an addrspacecast),
109+
// as long as it doesn't cause a verifier error by using `bitcast`.
110+
transmute(x)
111+
}

0 commit comments

Comments
 (0)