Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions clang/lib/CodeGen/CodeGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1255,6 +1255,17 @@ void CodeGenModule::Release() {
: "buffered");
getModule().addModuleFlag(llvm::Module::Error, "amdgpu_printf_kind",
MDStr);
} else if (LangOpts.SYCLIsDevice) {
// SYCL device code on AMDGPU always uses the buffered printf scheme: the
// hostcall scheme relies on ROCm's hostcall runtime service (and PCIe
// atomics), which the SYCL/UR HIP runtime does not set up. The buffered
// scheme only needs the printf buffer implicit kernarg, which the HIP
// runtime allocates and parses automatically from the code object's
// printf metadata. This flag tells AMDGPUPrintfRuntimeBinding to lower
// printf using the buffered layout expected by the runtime.
getModule().addModuleFlag(llvm::Module::Error, "amdgpu_printf_kind",
llvm::MDString::get(getLLVMContext(),
"buffered"));
}
}

Expand Down
9 changes: 9 additions & 0 deletions libclc/libspirv/lib/amdgpu/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -65,3 +65,12 @@ libclc_add_sources(${LIBCLC_LIBSPIRV_TARGET} FILES
async/wait_group_events.cl
assert/__assert_fail.cl
)

# Provide the AMDGPU buffered-printf allocator helper. The AMDGPUPrintfRuntimeBinding
# backend pass lowers printf calls to __printf_alloc + a device print buffer; the
# definition is shared with the OpenCL libclc build.
libclc_add_sources(${LIBCLC_LIBSPIRV_TARGET}
BASE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../../opencl/lib/amdgpu
FILES
printf/__printf_alloc.cl
)
9 changes: 7 additions & 2 deletions libclc/opencl/lib/amdgpu/printf/__printf_alloc.cl
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,13 @@
#define OFFSET 8

// Atomically reserves space to the printf data buffer and returns a pointer to
// it
__global char *__printf_alloc(uint bytes) {
// it.
//
// This helper is referenced by the AMDGPUPrintfRuntimeBinding backend pass,
// which only introduces the reference late in the pipeline (after the device
// bitcode libraries have already been internalized and dead-stripped). Mark it
// as used so the definition is retained and available when the pass runs.
__attribute__((used)) __global char *__printf_alloc(uint bytes) {
__constant amdhsa_implicit_kernarg_v5 *args =
(__constant amdhsa_implicit_kernarg_v5 *)
__builtin_amdgcn_implicitarg_ptr();
Expand Down
6 changes: 5 additions & 1 deletion llvm/lib/SYCLPostLink/ModuleSplitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,11 @@ void collectFunctionsAndGlobalVariablesToExtract(

static bool isIntrinsicOrBuiltin(const Function &F) {
return F.isIntrinsic() || F.getName().starts_with("__") ||
isSpirvSyclBuiltin(F.getName()) || isESIMDBuiltin(F.getName());
// printf is a standard C library builtin. On AMDGPU it is left as an
// undefined declaration until the AMDGPUPrintfRuntimeBinding backend
// pass lowers it, so it is not an undefined *user* function.
F.getName() == "printf" || isSpirvSyclBuiltin(F.getName()) ||
isESIMDBuiltin(F.getName());
}

// Checks for use of undefined user functions and emits a warning message.
Expand Down
49 changes: 49 additions & 0 deletions llvm/lib/Target/AMDGPU/AMDGPUPrintfRuntimeBinding.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include "llvm/InitializePasses.h"
#include "llvm/Support/DataExtractor.h"
#include "llvm/TargetParser/Triple.h"
#include "llvm/Transforms/Utils/AMDGPUEmitPrintf.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"

using namespace llvm;
Expand Down Expand Up @@ -59,6 +60,14 @@ class AMDGPUPrintfRuntimeBindingImpl {

bool lowerPrintfForGpu(Module &M);

// Lowers printf calls using the buffered scheme shared with clang's HIP
// -mprintf-kind=buffered lowering (llvm::emitAMDGPUPrintfCall). This produces
// a device print buffer layout that the HIP/OpenCL runtime parses. Unlike
// lowerPrintfForGpu(), it can be run after inlining, which is required for
// SYCL where printf calls are wrapped in a helper and the format string is
// only a resolvable constant once the wrapper has been inlined.
bool lowerPrintfForGpuBuffered(Module &M);

const DataLayout *TD;
SmallVector<CallInst *, 32> Printfs;
};
Expand Down Expand Up @@ -423,6 +432,36 @@ bool AMDGPUPrintfRuntimeBindingImpl::lowerPrintfForGpu(Module &M) {
return true;
}

bool AMDGPUPrintfRuntimeBindingImpl::lowerPrintfForGpuBuffered(Module &M) {
for (auto *CI : Printfs) {
// Collect the printf call arguments (format string followed by the
// C-vararg-promoted arguments) and hand them off to the shared buffered
// printf emitter.
SmallVector<Value *, 8> Args(CI->args());

// Split the call's basic block so the hammock created by
// emitAMDGPUPrintfCall has a well-defined continuation.
BasicBlock *Tail = CI->getParent()->splitBasicBlock(CI, "printf.split");
BasicBlock *Head = Tail->getSinglePredecessor();
assert(Head && "expected split to create a single predecessor");
Head->getTerminator()->eraseFromParent();

IRBuilder<> Builder(Head);
Builder.SetCurrentDebugLocation(CI->getDebugLoc());
Value *Result = emitAMDGPUPrintfCall(Builder, Args, /*IsBuffered=*/true);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please feel free to modify the codes. Thank you for your review.

Builder.CreateBr(Tail);

if (!CI->use_empty())
CI->replaceAllUsesWith(Result);
}

for (auto *CI : Printfs)
CI->eraseFromParent();

Printfs.clear();
return true;
}

bool AMDGPUPrintfRuntimeBindingImpl::run(Module &M) {
auto *PrintfFunction = M.getFunction("printf");
if (!PrintfFunction || !PrintfFunction->isDeclaration() ||
Expand Down Expand Up @@ -452,6 +491,16 @@ bool AMDGPUPrintfRuntimeBindingImpl::run(Module &M) {

TD = &M.getDataLayout();

// When the module requests the buffered printf scheme (e.g. SYCL device code
// targeting the HIP runtime), use the buffered emitter which produces the
// print buffer layout expected by the HIP/OpenCL runtime and correctly
// handles %s once the format string is a resolvable constant.
if (auto *MD = M.getModuleFlag("amdgpu_printf_kind")) {
if (auto *MDS = dyn_cast<MDString>(MD))
if (MDS->getString() == "buffered")
return lowerPrintfForGpuBuffered(M);
}

return lowerPrintfForGpu(M);
}

Expand Down
3 changes: 0 additions & 3 deletions sycl/test-e2e/DeviceLib/built-ins/printf.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
// UNSUPPORTED: target-amd
// UNSUPPORTED-TRACKER: https://github.com/intel/llvm/issues/22300
// HIP doesn't support printf.
// CUDA doesn't support vector format specifiers ("%v").
// XFAIL: run-mode && spirv-backend
// XFAIL-TRACKER: https://github.com/intel/llvm/issues/21618
Expand Down
2 changes: 0 additions & 2 deletions sycl/test-e2e/Printf/char.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@
// The test is written using conversion specifiers table from cppreference [1]
// [1]: https://en.cppreference.com/w/cpp/io/c/fprintf
//
// UNSUPPORTED: target-amd
// UNSUPPORTED-TRACKER: https://github.com/intel/llvm/issues/22300
//
// RUN: %{build} -o %t.out
// RUN: %{run} %t.out | FileCheck %s
Expand Down
2 changes: 0 additions & 2 deletions sycl/test-e2e/Printf/double.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@
// [1]: https://en.cppreference.com/w/cpp/io/c/fprintf
//
// REQUIRES: aspect-fp64
// UNSUPPORTED: target-amd
// UNSUPPORTED-TRACKER: https://github.com/intel/llvm/issues/22300
//
// RUN: %{build} -o %t.out
// RUN: %{run} %t.out | FileCheck %s
Expand Down
2 changes: 0 additions & 2 deletions sycl/test-e2e/Printf/float.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@
// The test is written using conversion specifiers table from cppreference [1]
// [1]: https://en.cppreference.com/w/cpp/io/c/fprintf
//
// UNSUPPORTED: target-amd
// UNSUPPORTED-TRACKER: https://github.com/intel/llvm/issues/22300
//
// RUN: %{build} -o %t.out
// RUN: %{run} %t.out | FileCheck %s
Expand Down
2 changes: 0 additions & 2 deletions sycl/test-e2e/Printf/int.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@
// The test is written using conversion specifiers table from cppreference [1]
// [1]: https://en.cppreference.com/w/cpp/io/c/fprintf
//
// UNSUPPORTED: target-amd
// UNSUPPORTED-TRACKER: https://github.com/intel/llvm/issues/22300
// XFAIL: spirv-backend && gpu && run-mode
// XFAIL-TRACKER: https://github.com/intel/llvm/issues/21314
// RUN: %{build} -o %t.out
Expand Down
1 change: 0 additions & 1 deletion sycl/test-e2e/Printf/mixed-address-space.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// This test is written with an aim to check that experimental::printf versions
// for constant and generic address space can be used in the same module.
//
// UNSUPPORTED: target-amd
// XFAIL: cuda && windows
// XFAIL-TRACKER: https://github.com/intel/llvm/issues/14733
// FIXME: Drop the test once generic AS support is considered stable and the
Expand Down
2 changes: 0 additions & 2 deletions sycl/test-e2e/Printf/percent-symbol.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@
// The test is written using conversion specifiers table from cppreference [1]
// [1]: https://en.cppreference.com/w/cpp/io/c/fprintf
//
// UNSUPPORTED: target-amd
// UNSUPPORTED-TRACKER: https://github.com/intel/llvm/issues/22300
// XFAIL: cuda && windows
// XFAIL-TRACKER: https://github.com/intel/llvm/issues/14733
// RUN: %{build} -o %t.out
Expand Down
Loading