Skip to content

Commit

Permalink
[CUDA][HIP] Support CUID in new driver
Browse files Browse the repository at this point in the history
CUID is needed by CUDA/HIP for supporting accessing static device variables
in host function.

Currently CUID is only supported by the old driver for CUDA/HIP.
The new clang driver does not support it, which causes CUDA/HIP programs
using static device variables in host functions to fail with
the new driver for CUDA/HIP.

This patch refactors the CUID support in the old driver so that CUID
is supported by both the old and the new drivers for CUDA/HIP.
  • Loading branch information
yxsamliu committed Jan 14, 2025
1 parent ac604b2 commit ae31bf1
Show file tree
Hide file tree
Showing 3 changed files with 125 additions and 60 deletions.
32 changes: 31 additions & 1 deletion clang/include/clang/Driver/Driver.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,29 @@ enum ModuleHeaderMode {
HeaderMode_System
};

/// Options for specifying CUID used by CUDA/HIP for uniquely identifying
/// compilation units.
class CUIDOptions {
public:
enum class Kind { Hash, Random, Fixed, None, Invalid };

CUIDOptions() = default;
CUIDOptions(const CUIDOptions &) = default;
CUIDOptions(llvm::opt::DerivedArgList &Args, const Driver &D);

// Get the CUID for an input string
std::string getCUID(StringRef InputFile,
llvm::opt::DerivedArgList &Args) const;

bool isEnabled() const {
return UseCUID != Kind::None && UseCUID != Kind::Invalid;
}

private:
Kind UseCUID = Kind::None;
StringRef FixedCUID;
};

/// Driver - Encapsulate logic for constructing compilation processes
/// from a set of gcc-driver-like command line arguments.
class Driver {
Expand Down Expand Up @@ -119,6 +142,9 @@ class Driver {
/// LTO mode selected via -f(no-offload-)?lto(=.*)? options.
LTOKind OffloadLTOMode;

/// Options for CUID
CUIDOptions CUIDOpts;

public:
enum OpenMPRuntimeKind {
/// An unknown OpenMP runtime. We can't generate effective OpenMP code
Expand Down Expand Up @@ -501,10 +527,11 @@ class Driver {
/// \param C - The compilation that is being built.
/// \param Args - The input arguments.
/// \param Input - The input type and arguments
/// \param CUID - The CUID for \p Input
/// \param HostAction - The host action used in the offloading toolchain.
Action *BuildOffloadingActions(Compilation &C,
llvm::opt::DerivedArgList &Args,
const InputTy &Input,
const InputTy &Input, StringRef CUID,
Action *HostAction) const;

/// Returns the set of bound architectures active for this offload kind.
Expand Down Expand Up @@ -728,6 +755,9 @@ class Driver {
/// Get the specific kind of offload LTO being performed.
LTOKind getOffloadLTOMode() const { return OffloadLTOMode; }

/// Get the CUID option.
const CUIDOptions &getCUIDOpts() const { return CUIDOpts; }

private:

/// Tries to load options from configuration files.
Expand Down
116 changes: 65 additions & 51 deletions clang/lib/Driver/Driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,50 @@ std::string Driver::GetResourcesPath(StringRef BinaryPath) {
return std::string(P);
}

CUIDOptions::CUIDOptions(llvm::opt::DerivedArgList &Args, const Driver &D)
: UseCUID(Kind::Hash) {
if (Arg *A = Args.getLastArg(options::OPT_fuse_cuid_EQ)) {
StringRef UseCUIDStr = A->getValue();
UseCUID = llvm::StringSwitch<Kind>(UseCUIDStr)
.Case("hash", Kind::Hash)
.Case("random", Kind::Random)
.Case("none", Kind::None)
.Default(Kind::Invalid);
if (UseCUID == Kind::Invalid)
D.Diag(clang::diag::err_drv_invalid_value)
<< A->getAsString(Args) << UseCUIDStr;
}

FixedCUID = Args.getLastArgValue(options::OPT_cuid_EQ);
if (!FixedCUID.empty())
UseCUID = Kind::Fixed;
}

std::string CUIDOptions::getCUID(StringRef InputFile,
llvm::opt::DerivedArgList &Args) const {
std::string CUID = FixedCUID.str();
if (CUID.empty()) {
if (UseCUID == Kind::Random)
CUID = llvm::utohexstr(llvm::sys::Process::GetRandomNumber(),
/*LowerCase=*/true);
else if (UseCUID == Kind::Hash) {
llvm::MD5 Hasher;
llvm::MD5::MD5Result Hash;
SmallString<256> RealPath;
llvm::sys::fs::real_path(InputFile, RealPath,
/*expand_tilde=*/true);
Hasher.update(RealPath);
for (auto *A : Args) {
if (A->getOption().matches(options::OPT_INPUT))
continue;
Hasher.update(A->getAsString(Args));
}
Hasher.final(Hash);
CUID = llvm::utohexstr(Hash.low(), /*LowerCase=*/true);
}
}
return CUID;
}
Driver::Driver(StringRef ClangExecutable, StringRef TargetTriple,
DiagnosticsEngine &Diags, std::string Title,
IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS)
Expand Down Expand Up @@ -875,6 +919,9 @@ void Driver::CreateOffloadingDeviceToolChains(Compilation &C,
C.addOffloadDeviceToolChain(HIPTC, OFK);
}

if (IsCuda || IsHIP)
CUIDOpts = CUIDOptions(C.getArgs(), *this);

//
// OpenMP
//
Expand Down Expand Up @@ -3156,19 +3203,15 @@ class OffloadingActionBuilder final {
/// Default GPU architecture if there's no one specified.
OffloadArch DefaultOffloadArch = OffloadArch::UNKNOWN;

/// Method to generate compilation unit ID specified by option
/// '-fuse-cuid='.
enum UseCUIDKind { CUID_Hash, CUID_Random, CUID_None, CUID_Invalid };
UseCUIDKind UseCUID = CUID_Hash;

/// Compilation unit ID specified by option '-cuid='.
StringRef FixedCUID;
/// Compilation unit ID specified by option '-fuse-cuid=' or'-cuid='.
const CUIDOptions &CUIDOpts;

public:
CudaActionBuilderBase(Compilation &C, DerivedArgList &Args,
const Driver::InputList &Inputs,
Action::OffloadKind OFKind)
: DeviceActionBuilder(C, Args, Inputs, OFKind) {
: DeviceActionBuilder(C, Args, Inputs, OFKind),
CUIDOpts(C.getDriver().getCUIDOpts()) {

CompileDeviceOnly = C.getDriver().offloadDeviceOnly();
Relocatable = Args.hasFlag(options::OPT_fgpu_rdc,
Expand Down Expand Up @@ -3199,28 +3242,8 @@ class OffloadingActionBuilder final {
// Set the flag to true, so that the builder acts on the current input.
IsActive = true;

std::string CUID = FixedCUID.str();
if (CUID.empty()) {
if (UseCUID == CUID_Random)
CUID = llvm::utohexstr(llvm::sys::Process::GetRandomNumber(),
/*LowerCase=*/true);
else if (UseCUID == CUID_Hash) {
llvm::MD5 Hasher;
llvm::MD5::MD5Result Hash;
SmallString<256> RealPath;
llvm::sys::fs::real_path(IA->getInputArg().getValue(), RealPath,
/*expand_tilde=*/true);
Hasher.update(RealPath);
for (auto *A : Args) {
if (A->getOption().matches(options::OPT_INPUT))
continue;
Hasher.update(A->getAsString(Args));
}
Hasher.final(Hash);
CUID = llvm::utohexstr(Hash.low(), /*LowerCase=*/true);
}
}
IA->setId(CUID);
if (CUIDOpts.isEnabled())
IA->setId(CUIDOpts.getCUID(IA->getInputArg().getValue(), Args));

if (CompileHostOnly)
return ABRT_Success;
Expand Down Expand Up @@ -3346,21 +3369,6 @@ class OffloadingActionBuilder final {
CompileHostOnly = C.getDriver().offloadHostOnly();
EmitLLVM = Args.getLastArg(options::OPT_emit_llvm);
EmitAsm = Args.getLastArg(options::OPT_S);
FixedCUID = Args.getLastArgValue(options::OPT_cuid_EQ);
if (Arg *A = Args.getLastArg(options::OPT_fuse_cuid_EQ)) {
StringRef UseCUIDStr = A->getValue();
UseCUID = llvm::StringSwitch<UseCUIDKind>(UseCUIDStr)
.Case("hash", CUID_Hash)
.Case("random", CUID_Random)
.Case("none", CUID_None)
.Default(CUID_Invalid);
if (UseCUID == CUID_Invalid) {
C.getDriver().Diag(diag::err_drv_invalid_value)
<< A->getAsString(Args) << UseCUIDStr;
C.setContainsError();
return true;
}
}

// --offload and --offload-arch options are mutually exclusive.
if (Args.hasArgNoClaim(options::OPT_offload_EQ) &&
Expand Down Expand Up @@ -4360,6 +4368,12 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args,
// Build the pipeline for this file.
Action *Current = C.MakeAction<InputAction>(*InputArg, InputType);

std::string CUID;
if (CUIDOpts.isEnabled() && types::isSrcFile(InputType)) {
CUID = CUIDOpts.getCUID(InputArg->getValue(), Args);
cast<InputAction>(Current)->setId(CUID);
}

// Use the current host action in any of the offloading actions, if
// required.
if (!UseNewOffloadingDriver)
Expand Down Expand Up @@ -4423,7 +4437,7 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args,
// Try to build the offloading actions and add the result as a dependency
// to the host.
if (UseNewOffloadingDriver)
Current = BuildOffloadingActions(C, Args, I, Current);
Current = BuildOffloadingActions(C, Args, I, CUID, Current);
// Use the current host action in any of the offloading actions, if
// required.
else if (OffloadBuilder->addHostDependenceToDeviceActions(Current,
Expand Down Expand Up @@ -4760,7 +4774,7 @@ Driver::getOffloadArchs(Compilation &C, const llvm::opt::DerivedArgList &Args,

Action *Driver::BuildOffloadingActions(Compilation &C,
llvm::opt::DerivedArgList &Args,
const InputTy &Input,
const InputTy &Input, StringRef CUID,
Action *HostAction) const {
// Don't build offloading actions if explicitly disabled or we do not have a
// valid source input and compile action to embed it in. If preprocessing only
Expand Down Expand Up @@ -4801,13 +4815,13 @@ Action *Driver::BuildOffloadingActions(Compilation &C,
llvm::DenseSet<StringRef> Arches = getOffloadArchs(C, Args, Kind, TC);
SmallVector<StringRef, 0> Sorted(Arches.begin(), Arches.end());
llvm::sort(Sorted);
for (StringRef Arch : Sorted)
for (StringRef Arch : Sorted) {
TCAndArchs.push_back(std::make_pair(TC, Arch));
DeviceActions.push_back(
C.MakeAction<InputAction>(*InputArg, InputType, CUID));
}
}

for (unsigned I = 0, E = TCAndArchs.size(); I != E; ++I)
DeviceActions.push_back(C.MakeAction<InputAction>(*InputArg, InputType));

if (DeviceActions.empty())
return HostAction;

Expand Down
37 changes: 29 additions & 8 deletions clang/test/Driver/hip-cuid.hip
Original file line number Diff line number Diff line change
Expand Up @@ -80,32 +80,53 @@
// RUN: %S/Inputs/hip_multiple_inputs/b.hip \
// RUN: 2>&1 | FileCheck -check-prefixes=DEVICE %s

// Check cuid is supported by the new driver.
// RUN: %clang -### -x hip \
// RUN: --target=x86_64-unknown-linux-gnu \
// RUN: --no-offload-new-driver \
// RUN: --offload-arch=gfx900 \
// RUN: --offload-arch=gfx906 \
// RUN: -c -nogpuinc -nogpulib --offload-new-driver \
// RUN: %S/Inputs/hip_multiple_inputs/a.cu \
// RUN: %S/Inputs/hip_multiple_inputs/b.hip \
// RUN: 2>&1 | FileCheck -check-prefixes=COMMON,HEX %s

// Check cuid is supported by CUDA by the default new driver.
// RUN: %clang -### -x cu \
// RUN: --target=x86_64-unknown-linux-gnu \
// RUN: --offload-arch=sm_60 \
// RUN: --offload-arch=sm_70 \
// RUN: -c -nogpuinc -nogpulib \
// RUN: %S/Inputs/hip_multiple_inputs/a.cu \
// RUN: %S/Inputs/hip_multiple_inputs/b.hip \
// RUN: 2>&1 | FileCheck -check-prefixes=COMMON,HEX %s

// INVALID: invalid value 'invalid' in '-fuse-cuid=invalid'

// COMMON: "-cc1"{{.*}} "-triple" "amdgcn-amd-amdhsa"
// COMMON-SAME: "-target-cpu" "gfx900"
// COMMON: "-cc1"{{.*}} "-triple" "[[TRIP:(amdgcn-amd-amdhsa|nvptx64-nvidia-cuda)]]"
// COMMON-SAME: "-target-cpu" "[[G1:(gfx900|sm_60)]]"
// HEX-SAME: "-cuid=[[CUID:[0-9a-f]+]]"
// FIXED-SAME: "-cuid=[[CUID:xyz_123]]"
// COMMON-SAME: "{{.*}}a.cu"

// COMMON: "-cc1"{{.*}} "-triple" "amdgcn-amd-amdhsa"
// COMMON-SAME: "-target-cpu" "gfx906"
// COMMON: "-cc1"{{.*}} "-triple" "[[TRIP]]"
// COMMON-SAME: "-target-cpu" "[[G2:(gfx906|sm_70)]]"
// COMMON-SAME: "-cuid=[[CUID]]"
// COMMON-SAME: "{{.*}}a.cu"

// COMMON: "-cc1"{{.*}} "-triple" "x86_64-unknown-linux-gnu"
// COMMON-SAME: "-cuid=[[CUID]]"
// COMMON-SAME: "{{.*}}a.cu"

// COMMON: "-cc1"{{.*}} "-triple" "amdgcn-amd-amdhsa"
// COMMON-SAME: "-target-cpu" "gfx900"
// COMMON: "-cc1"{{.*}} "-triple" "[[TRIP]]"
// COMMON-SAME: "-target-cpu" "[[G1]]"
// HEX-NOT: "-cuid=[[CUID]]"
// HEX-SAME: "-cuid=[[CUID2:[0-9a-f]+]]"
// FIXED-SAME: "-cuid=[[CUID2:xyz_123]]"
// COMMON-SAME: "{{.*}}b.hip"

// COMMON: "-cc1"{{.*}} "-triple" "amdgcn-amd-amdhsa"
// COMMON-SAME: "-target-cpu" "gfx906"
// COMMON: "-cc1"{{.*}} "-triple" "[[TRIP]]"
// COMMON-SAME: "-target-cpu" "[[G2]]"
// HEX-NOT: "-cuid=[[CUID]]"
// COMMON-SAME: "-cuid=[[CUID2]]"
// COMMON-SAME: "{{.*}}b.hip"
Expand Down

0 comments on commit ae31bf1

Please sign in to comment.