Imagine we have the following code:
```c++
void foo() {}
void bar() {
void *ptr = reinterpret_cast<void*>(foo);
}
```
Usually clang would treat this as a simple `bitcast`, but in the case
that the target has a non-default program address space, this needs to
be an `addrspacecast`.
Today, if we try to codegen this, we get an assert due to the two types
not being valid for a `bitcast`.
```
clang-23: /tmp/llvm/clang/lib/CodeGen/CGExprScalar.cpp:2661: llvm::Value* {anonymous}::ScalarExprEmitter::VisitCastExpr(clang::CastExpr*): Assertion `(!SrcTy->isPtrOrPtrVectorTy() || !DstTy->isPtrOrPtrVectorTy() || SrcTy->getPointerAddressSpace() == DstTy->getPointerAddressSpace()) && "Address-space cast must be used to convert address spaces"' failed.
```
The complicating issue is that Sema has no idea about the target's
default program AS, that's part of the LLVM target data layout which is
only known to CodeGen, so there I don't see a way we could represent
this as a `AddressSpaceConversion` -type `CastExpr` in Sema, the only
place we have the required info is during codegen for the `CastExpr`.
Modify the codegen of `BitCast`-type `CastExpr` to generate an LLVM
`addrspacecast` if necessary.
---------
Signed-off-by: Nick Sarnie <nick.sarnie@intel.com>
35 lines
1.3 KiB
C++
35 lines
1.3 KiB
C++
// RUN: %clang_cc1 -triple spirv64-intel %s -emit-llvm -o - | FileCheck %s
|
|
|
|
// Test that function pointer casts properly handle address space conversions
|
|
// on targets like spirv64-intel that use a non-default program address space.
|
|
|
|
void foo() {}
|
|
|
|
// CHECK-LABEL: define spir_func void @_Z21test_func_to_void_ptrv() addrspace(9)
|
|
void test_func_to_void_ptr() {
|
|
void *ptr = (void*)foo;
|
|
// CHECK: store ptr addrspace(4) addrspacecast (ptr addrspace(9) @_Z3foov to ptr addrspace(4))
|
|
}
|
|
|
|
// CHECK-LABEL: define spir_func void @_Z21test_void_ptr_to_funcv() addrspace(9)
|
|
void test_void_ptr_to_func() {
|
|
void *ptr = (void*)foo;
|
|
void (*fptr)() = (void (*)())ptr;
|
|
// CHECK: addrspacecast ptr addrspace(4) %{{.*}} to ptr addrspace(9)
|
|
fptr();
|
|
}
|
|
|
|
// CHECK-LABEL: define spir_func void @_Z25cxx_test_func_to_void_ptrv() addrspace(9)
|
|
void cxx_test_func_to_void_ptr() {
|
|
void *ptr = reinterpret_cast<void*>(foo);
|
|
// CHECK: store ptr addrspace(4) addrspacecast (ptr addrspace(9) @_Z3foov to ptr addrspace(4))
|
|
}
|
|
|
|
// CHECK-LABEL: define spir_func void @_Z25cxx_test_void_ptr_to_funcv() addrspace(9)
|
|
void cxx_test_void_ptr_to_func() {
|
|
void *ptr = reinterpret_cast<void*>(foo);
|
|
void (*fptr)() = reinterpret_cast<void (*)()>(ptr);
|
|
// CHECK: addrspacecast ptr addrspace(4) %{{.*}} to ptr addrspace(9)
|
|
fptr();
|
|
}
|