Skip to content

Commit 6e28764

Browse files
committed
Merge main into fix-556: resolve CMakeLists.txt conflict
2 parents 99eb65d + 9a7a8a0 commit 6e28764

13 files changed

Lines changed: 277 additions & 30 deletions

File tree

CMakeLists.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -710,12 +710,12 @@ message(STATUS "Generated HIP_OFFLOAD_LINK_OPTIONS: ${HIP_OFFLOAD_LINK_OPTIONS_I
710710
# TODO: Is there a better way to do this?
711711
add_library(deviceInternal INTERFACE)
712712
target_compile_options(deviceInternal INTERFACE
713-
-x hip ${HIP_OFFLOAD_COMPILE_OPTIONS_BUILD_})
713+
$<$<COMPILE_LANGUAGE:CXX>:-xhip> ${HIP_OFFLOAD_COMPILE_OPTIONS_BUILD_})
714714
target_link_libraries(deviceInternal INTERFACE CHIP)
715715

716716
add_library(device INTERFACE)
717717
target_compile_options(device INTERFACE
718-
-x hip ${HIP_OFFLOAD_COMPILE_OPTIONS_INSTALL_})
718+
$<$<COMPILE_LANGUAGE:CXX>:-xhip> ${HIP_OFFLOAD_COMPILE_OPTIONS_INSTALL_})
719719
target_link_libraries(device INTERFACE CHIP)
720720

721721
# same as device on chipStar but provides compatibility with AMD

bitcode/_cl_print_str.cl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
* DEALINGS IN THE SOFTWARE.
2121
*/
2222

23-
static void __attribute__((used)) _cl_print_str(__generic const char *S) {
23+
void _cl_print_str(__generic const char *S) {
2424
if (S == 0) {
2525
return; /* Match AMD/nvidia: null %s prints nothing, format provides newline */
2626
}

bitcode/texture.cl

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -43,47 +43,47 @@ uint4 _chip_tex2du(hipTextureObject_t TextureObject, float2 Pos);
4343

4444
// ^^^ DECLARATIONS INTENTIONALLY WITHOUT DEFINITION ^^^
4545

46-
static int4 __attribute__((used))
46+
int4
4747
_chip_tex1dfetchi_impl(image1d_t I, sampler_t S, int Pos) {
4848
return read_imagei(I, S, Pos);
4949
}
5050

51-
static uint4 __attribute__((used))
51+
uint4
5252
_chip_tex1dfetchu_impl(image1d_t I, sampler_t S, int Pos) {
5353
return read_imageui(I, S, Pos);
5454
}
5555

56-
static float4 __attribute__((used))
56+
float4
5757
_chip_tex1dfetchf_impl(image1d_t I, sampler_t S, int Pos) {
5858
return read_imagef(I, S, Pos);
5959
}
6060

61-
static int4 __attribute__((used))
61+
int4
6262
_chip_tex1di_impl(image1d_t I, sampler_t S, float Pos) {
6363
return read_imagei(I, S, Pos);
6464
}
6565

66-
static uint4 __attribute__((used))
66+
uint4
6767
_chip_tex1du_impl(image1d_t I, sampler_t S, float Pos) {
6868
return read_imageui(I, S, Pos);
6969
}
7070

71-
static float4 __attribute__((used))
71+
float4
7272
_chip_tex1df_impl(image1d_t I, sampler_t S, float Pos) {
7373
return read_imagef(I, S, Pos);
7474
}
7575

76-
static float4 __attribute__((used))
76+
float4
7777
_chip_tex2df_impl(image2d_t I, sampler_t S, float2 Pos) {
7878
return read_imagef(I, S, Pos);
7979
}
8080

81-
static int4 __attribute__((used))
81+
int4
8282
_chip_tex2di_impl(image2d_t I, sampler_t S, float2 Pos) {
8383
return read_imagei(I, S, Pos);
8484
}
8585

86-
static uint4 __attribute__((used))
86+
uint4
8787
_chip_tex2du_impl(image2d_t I, sampler_t S, float2 Pos) {
8888
return read_imageui(I, S, Pos);
8989
}

llvm_passes/HipPrintf.cpp

Lines changed: 71 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -314,21 +314,81 @@ HipPrintfToOpenCLPrintfPass::getOrCreateStrLiteralArg(const std::string &Str,
314314
Function *HipPrintfToOpenCLPrintfPass::getOrCreatePrintStringF() {
315315

316316
if (GlobalValue *OldPrintStrF =
317-
M_->getNamedValue(ORIG_PRINT_STRING_FUNC_NAME))
318-
return cast<Function>(OldPrintStrF);
317+
M_->getNamedValue(ORIG_PRINT_STRING_FUNC_NAME)) {
318+
auto *Existing = cast<Function>(OldPrintStrF);
319+
if (!Existing->isDeclaration())
320+
return Existing;
321+
// Declaration exists (e.g. inserted on a prior call before we got
322+
// to define a body); fall through and define the body now.
323+
}
319324

320-
auto *Int8Ty = IntegerType::get(M_->getContext(), 8);
325+
auto &Ctx = M_->getContext();
326+
auto *Int8Ty = IntegerType::get(Ctx, 8);
327+
auto *Int32Ty = IntegerType::get(Ctx, 32);
328+
auto *VoidTy = Type::getVoidTy(Ctx);
321329
PointerType *GenericCStrArgT =
322330
PointerType::get(Int8Ty, SPIRV_OPENCL_GENERIC_AS);
331+
PointerType *ConstStrPtrT =
332+
PointerType::get(Int8Ty, SPIRV_OPENCL_CONSTANT_AS);
323333

324-
FunctionType *PrintStrFTy = FunctionType::get(
325-
Type::getVoidTy(M_->getContext()), {GenericCStrArgT}, false);
326-
327-
FunctionCallee PrintStrF =
328-
M_->getOrInsertFunction(ORIG_PRINT_STRING_FUNC_NAME, PrintStrFTy);
329-
cast<Function>(PrintStrF.getCallee())
330-
->setCallingConv(llvm::CallingConv::SPIR_FUNC);
331-
return cast<Function>(PrintStrF.getCallee());
334+
FunctionType *PrintStrFTy =
335+
FunctionType::get(VoidTy, {GenericCStrArgT}, false);
336+
Function *F = cast<Function>(
337+
M_->getOrInsertFunction(ORIG_PRINT_STRING_FUNC_NAME, PrintStrFTy)
338+
.getCallee());
339+
F->setCallingConv(llvm::CallingConv::SPIR_FUNC);
340+
F->setLinkage(llvm::GlobalValue::InternalLinkage);
341+
342+
// Define the body inline so the kernel module is self-contained for %s
343+
// printf support. The historical implementation in bitcode/_cl_print_str.cl
344+
// required `static __attribute__((used))`, which forced an `@llvm.used`
345+
// entry into hipspv.bc. That collided with `@llvm.used` from HIP TUs
346+
// (different element address space) at `-mlink-builtin-bitcode` time and
347+
// broke any HIP code that also uses `__attribute__((used))` (rocThrust).
348+
//
349+
// Equivalent C:
350+
// void _cl_print_str(__generic const char *S) {
351+
// if (S == 0) return;
352+
// unsigned Pos = 0;
353+
// char C;
354+
// while ((C = S[Pos]) != 0) { printf("%c", C); ++Pos; }
355+
// }
356+
BasicBlock *Entry = BasicBlock::Create(Ctx, "entry", F);
357+
BasicBlock *Loop = BasicBlock::Create(Ctx, "loop", F);
358+
BasicBlock *Body = BasicBlock::Create(Ctx, "body", F);
359+
BasicBlock *Exit = BasicBlock::Create(Ctx, "exit", F);
360+
361+
Argument *S = F->getArg(0);
362+
363+
FunctionType *PrintfTy =
364+
FunctionType::get(Int32Ty, {ConstStrPtrT}, /*isVarArg=*/true);
365+
Function *Printf = cast<Function>(
366+
M_->getOrInsertFunction("printf", PrintfTy).getCallee());
367+
368+
IRBuilder<> B(Entry);
369+
Value *IsNull = B.CreateICmpEQ(S, ConstantPointerNull::get(GenericCStrArgT));
370+
B.CreateCondBr(IsNull, Exit, Loop);
371+
372+
B.SetInsertPoint(Loop);
373+
PHINode *Pos = B.CreatePHI(Int32Ty, 2);
374+
Pos->addIncoming(ConstantInt::get(Int32Ty, 0), Entry);
375+
Value *CharPtr = B.CreateGEP(Int8Ty, S, Pos);
376+
Value *C = B.CreateLoad(Int8Ty, CharPtr);
377+
Value *IsZero = B.CreateICmpEQ(C, ConstantInt::get(Int8Ty, 0));
378+
B.CreateCondBr(IsZero, Exit, Body);
379+
380+
B.SetInsertPoint(Body);
381+
Constant *PercentC = getOrCreateStrLiteralArg("%c", B);
382+
CallInst *PrintfCall = B.CreateCall(Printf, {PercentC, C});
383+
PrintfCall->setCallingConv(llvm::CallingConv::SPIR_FUNC);
384+
Value *PosNext = B.CreateAdd(Pos, ConstantInt::get(Int32Ty, 1));
385+
Pos->addIncoming(PosNext, Body);
386+
B.CreateBr(Loop);
387+
388+
B.SetInsertPoint(Exit);
389+
B.CreateRetVoid();
390+
391+
return F;
332392
}
333393

334394
// Get called function from 'CI' call or return nullptr the call is indirect.

src/CHIPBackend.cc

Lines changed: 53 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1419,14 +1419,28 @@ hipError_t chipstar::Context::free(void *Ptr) {
14191419
// test suite excepts hipErrorInvalidValue. Go with the latter.
14201420
return hipErrorInvalidValue;
14211421

1422-
if (AllocInfo->DevPtr)
1423-
ChipDev->AllocTracker->releaseMemReservation(AllocInfo->Size);
1424-
if (AllocInfo->MemoryType == hipMemoryTypeHost && AllocInfo->HostPtr &&
1425-
AllocInfo->HostPtr != AllocInfo->DevPtr)
1426-
std::free(AllocInfo->HostPtr);
1422+
// Save the fields we need before eraseRecord() deletes AllocInfo.
1423+
bool HasDevPtr = AllocInfo->DevPtr != nullptr;
1424+
size_t AllocSize = AllocInfo->Size;
1425+
bool IsHostNonMapped = (AllocInfo->MemoryType == hipMemoryTypeHost &&
1426+
AllocInfo->HostPtr &&
1427+
AllocInfo->HostPtr != AllocInfo->DevPtr);
1428+
void *HostPtrToFree = AllocInfo->HostPtr;
1429+
1430+
if (HasDevPtr)
1431+
ChipDev->AllocTracker->releaseMemReservation(AllocSize);
1432+
1433+
// Erase the record BEFORE freeing the underlying memory. Freeing first
1434+
// returns the address to the allocator pool, so a concurrent allocation
1435+
// could obtain the same address and call recordAllocation() while the old
1436+
// entry is still in the tracker, causing a "Device pointer already
1437+
// recorded" abort (issue #1133).
1438+
ChipDev->AllocTracker->eraseRecord(AllocInfo); // AllocInfo deleted here.
1439+
1440+
if (IsHostNonMapped)
1441+
std::free(HostPtrToFree);
14271442
else
14281443
freeImpl(Ptr);
1429-
ChipDev->AllocTracker->eraseRecord(AllocInfo);
14301444

14311445
return hipSuccess;
14321446
}
@@ -1778,13 +1792,36 @@ static void mapHostAlloc(const void *Ptr,
17781792
}
17791793

17801794
///////// Enqueue Operations //////////
1795+
1796+
// Validate that a pointer expected to be a device allocation is actually
1797+
// a known allocation in the tracker. Throws hipErrorInvalidValue if not.
1798+
static void validateDevicePtr(chipstar::AllocationTracker *AT, void *Ptr,
1799+
bool IsDevice, const char *Role) {
1800+
if (!IsDevice)
1801+
return;
1802+
if (!AT->getAllocInfoCheckPtrRanges(Ptr))
1803+
CHIPERR_LOG_AND_THROW(std::string("hipMemcpy: invalid ") + Role +
1804+
" device pointer.",
1805+
hipErrorInvalidValue);
1806+
}
1807+
17811808
hipError_t chipstar::Queue::memCopy(void *Dst, const void *Src, size_t Size,
17821809
hipMemcpyKind Kind) {
17831810

17841811
std::shared_ptr<chipstar::Event> ChipEvent;
17851812
unmapHostAlloc(Src);
17861813
unmapHostAlloc(Dst);
17871814

1815+
auto *AT = getDevice()->AllocTracker;
1816+
bool DstDev = (Kind == hipMemcpyHostToDevice || Kind == hipMemcpyDeviceToDevice);
1817+
bool SrcDev = (Kind == hipMemcpyDeviceToHost || Kind == hipMemcpyDeviceToDevice);
1818+
if (Kind == hipMemcpyDefault) {
1819+
DstDev = AT->getAllocInfo(Dst) != nullptr;
1820+
SrcDev = AT->getAllocInfo(Src) != nullptr;
1821+
}
1822+
validateDevicePtr(AT, Dst, DstDev, "destination");
1823+
validateDevicePtr(AT, const_cast<void *>(Src), SrcDev, "source");
1824+
17881825
ChipEvent = memCopyAsyncImpl(Dst, Src, Size, Kind);
17891826

17901827
mapHostAlloc(Src);
@@ -1801,6 +1838,16 @@ void chipstar::Queue::memCopyAsync(void *Dst, const void *Src, size_t Size,
18011838
unmapHostAlloc(Src);
18021839
unmapHostAlloc(Dst);
18031840

1841+
auto *AT = getDevice()->AllocTracker;
1842+
bool DstDev = (Kind == hipMemcpyHostToDevice || Kind == hipMemcpyDeviceToDevice);
1843+
bool SrcDev = (Kind == hipMemcpyDeviceToHost || Kind == hipMemcpyDeviceToDevice);
1844+
if (Kind == hipMemcpyDefault) {
1845+
DstDev = AT->getAllocInfo(Dst) != nullptr;
1846+
SrcDev = AT->getAllocInfo(Src) != nullptr;
1847+
}
1848+
validateDevicePtr(AT, Dst, DstDev, "destination");
1849+
validateDevicePtr(AT, const_cast<void *>(Src), SrcDev, "source");
1850+
18041851
ChipEvent = memCopyAsyncImpl(Dst, Src, Size, Kind);
18051852

18061853
mapHostAlloc(Src);
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Regression test for #1001: C source files in a CMake target that links
2+
# against hip::device must not receive -x hip / -xhip compilation flags.
3+
# With the bug, helper.c (which uses 'class' as a C identifier) fails to
4+
# compile because it is treated as C++ / HIP source.
5+
cmake_minimum_required(VERSION 3.20 FATAL_ERROR)
6+
project(HipDeviceCSourceTrial
7+
DESCRIPTION "Checking C sources are not compiled as HIP when using hip::device."
8+
LANGUAGES C CXX)
9+
find_package(HIP CONFIG REQUIRED)
10+
11+
# A mixed C+HIP executable that links against hip::device.
12+
add_executable(hip_c_source main.cpp helper.c)
13+
target_link_libraries(hip_c_source PRIVATE hip::device)
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
/* Pure C helper used by the regression test for issue #1001.
2+
'class' is a reserved keyword in C++ / HIP but a valid identifier in C.
3+
If this file is compiled with -x hip the compiler will reject it. */
4+
int get_value(void) {
5+
int class = 42;
6+
return class;
7+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#include <hip/hip_runtime.h>
2+
#include <iostream>
3+
4+
// Declared in helper.c (pure C, uses 'class' as a C identifier).
5+
// If -xhip/-x hip is applied to helper.c the compiler rejects it.
6+
extern "C" int get_value(void);
7+
8+
int main() {
9+
// Verify chipStar runtime is reachable.
10+
int deviceCount = 0;
11+
if (hipGetDeviceCount(&deviceCount) != hipSuccess)
12+
return 1;
13+
14+
// Call the pure-C helper to confirm it compiled correctly.
15+
int v = get_value();
16+
std::cout << "get_value() = " << v << "\n";
17+
return v != 42;
18+
}

tests/post-install/cmake-tests.bash

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,15 @@ else
3232
echo "Skip: clang++ or g++ is required"
3333
fi
3434
echo
35+
echo "### Check hip::device with mixed C/C++ sources (#1001)"
36+
setup-test-dir
37+
cmake @CMAKE_CURRENT_SOURCE_DIR@/HipDeviceCSource \
38+
-DCMAKE_PREFIX_PATH=@CMAKE_INSTALL_PREFIX@ \
39+
-DCMAKE_CXX_COMPILER=${CXX}
40+
make VERBOSE=1
41+
echo "Success"
42+
echo
43+
3544
echo "### check CMake-CUDA"
3645
setup-test-dir
3746

0 commit comments

Comments
 (0)