Skip to content

Commit 0ee2fac

Browse files
committed
refactor code; support errors for explicit -Xarch_device; improve testing
1 parent da9e715 commit 0ee2fac

File tree

7 files changed

+161
-79
lines changed

7 files changed

+161
-79
lines changed

clang/include/clang/Basic/DiagnosticDriverKinds.td

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,16 +126,23 @@ def err_drv_bad_offload_arch_combo : Error<
126126
"invalid offload arch combinations: '%0' and '%1' (for a specific processor, "
127127
"a feature should either exist in all offload archs, or not exist in any "
128128
"offload archs)">;
129+
def err_drv_unsupported_option_for_offload_arch_req_feature : Error<
130+
"'%0' option for offload arch '%1' is not currently supported "
131+
"there. Use it with an offload arch containing '%2' instead">;
129132
def warn_drv_unsupported_option_for_offload_arch_req_feature : Warning<
130133
"ignoring '%0' option for offload arch '%1' as it is not currently supported "
131134
"there. Use it with an offload arch containing '%2' instead">,
132135
InGroup<OptionIgnored>;
133136
def warn_drv_unsupported_option_for_target : Warning<
134137
"ignoring '%0' option as it is not currently supported for target '%1'">,
135138
InGroup<OptionIgnored>;
139+
def err_drv_unsupported_option_for_target : Error<
140+
"'%0' option is not currently supported for target '%1'">;
136141
def warn_drv_unsupported_option_part_for_target : Warning<
137142
"ignoring '%0' in '%1' option as it is not currently supported for target '%2'">,
138143
InGroup<OptionIgnored>;
144+
def err_drv_unsupported_option_part_for_target : Error<
145+
"'%0' in '%1' option is not currently supported for target '%2'">;
139146
def warn_drv_invalid_argument_for_flang : Warning<
140147
"'%0' is not valid for Fortran">,
141148
InGroup<OptionIgnored>;

clang/lib/Driver/ToolChains/AMDGPU.cpp

Lines changed: 15 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1074,32 +1074,12 @@ ROCMToolChain::getCommonDeviceLibNames(
10741074
getSanitizerArgs(DriverArgs).needsAsanRt());
10751075
}
10761076

1077-
std::optional<std::string> AMDGPUToolChain::filterSanitizeOption(
1077+
bool AMDGPUToolChain::shouldSkipSanitizeOption(
10781078
const ToolChain &TC, const llvm::opt::ArgList &DriverArgs,
10791079
StringRef TargetID, const llvm::opt::Arg *A) const {
1080-
// For actions without targetID, do nothing.
1081-
if (TargetID.empty())
1082-
return std::nullopt;
1083-
Option O = A->getOption();
1084-
1085-
if (!O.matches(options::OPT_fsanitize_EQ))
1086-
return std::nullopt;
1087-
1088-
if (!DriverArgs.hasFlag(options::OPT_fgpu_sanitize,
1089-
options::OPT_fno_gpu_sanitize, true))
1090-
return "";
1091-
10921080
auto &Diags = TC.getDriver().getDiags();
1093-
1094-
// We only allow the address sanitizer and ignore all other sanitizers.
1095-
SmallVector<std::string, 4> SupportedSanitizers;
1096-
for (const char *Value : A->getValues()) {
1097-
SanitizerMask K = parseSanitizerValue(Value, /*AllowGroups=*/false);
1098-
if (K == SanitizerKind::Address)
1099-
SupportedSanitizers.push_back(std::string(Value));
1100-
}
1101-
if (SupportedSanitizers.empty())
1102-
return "";
1081+
bool IsExplicitDevice =
1082+
A->getBaseArg().getOption().matches(options::OPT_Xarch_device);
11031083

11041084
// Check 'xnack+' availability by default
11051085
llvm::StringRef Processor =
@@ -1111,7 +1091,7 @@ std::optional<std::string> AMDGPUToolChain::filterSanitizeOption(
11111091
? llvm::AMDGPU::getArchAttrAMDGCN(ProcKind)
11121092
: llvm::AMDGPU::getArchAttrR600(ProcKind);
11131093
if (Features & llvm::AMDGPU::FEATURE_XNACK_ALWAYS)
1114-
return std::nullopt;
1094+
return false;
11151095

11161096
// Look for the xnack feature in TargetID
11171097
llvm::StringMap<bool> FeatureMap;
@@ -1120,11 +1100,17 @@ std::optional<std::string> AMDGPUToolChain::filterSanitizeOption(
11201100
(void)OptionalGpuArch;
11211101
auto Loc = FeatureMap.find("xnack");
11221102
if (Loc == FeatureMap.end() || !Loc->second) {
1123-
Diags.Report(
1124-
clang::diag::warn_drv_unsupported_option_for_offload_arch_req_feature)
1125-
<< A->getAsString(DriverArgs) << TargetID << "xnack+";
1126-
return "";
1103+
if (IsExplicitDevice) {
1104+
Diags.Report(
1105+
clang::diag::err_drv_unsupported_option_for_offload_arch_req_feature)
1106+
<< A->getAsString(DriverArgs) << TargetID << "xnack+";
1107+
} else {
1108+
Diags.Report(
1109+
clang::diag::warn_drv_unsupported_option_for_offload_arch_req_feature)
1110+
<< A->getAsString(DriverArgs) << TargetID << "xnack+";
1111+
}
1112+
return true;
11271113
}
11281114

1129-
return llvm::join(SupportedSanitizers, ",");
1115+
return false;
11301116
}

clang/lib/Driver/ToolChains/AMDGPU.h

Lines changed: 59 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -101,13 +101,11 @@ class LLVM_LIBRARY_VISIBILITY AMDGPUToolChain : public Generic_ELF {
101101
/// Needed for translating LTO options.
102102
const char *getDefaultLinker() const override { return "ld.lld"; }
103103

104-
/// Filter supported sanitizers from the sanitize option and return them. If
105-
/// there should be no filtering and Arg should be kept as-is, return
106-
/// std::nullopt. If no sanitizers are supported, return an empty string.
107-
std::optional<std::string>
108-
filterSanitizeOption(const ToolChain &TC,
109-
const llvm::opt::ArgList &DriverArgs, StringRef TargetID,
110-
const llvm::opt::Arg *A) const;
104+
/// Should skip sanitize option.
105+
bool shouldSkipSanitizeOption(const ToolChain &TC,
106+
const llvm::opt::ArgList &DriverArgs,
107+
StringRef TargetID,
108+
const llvm::opt::Arg *A) const;
111109

112110
/// Uses amdgpu-arch tool to get arch of the system GPU. Will return error
113111
/// if unable to find one.
@@ -157,19 +155,64 @@ class LLVM_LIBRARY_VISIBILITY ROCMToolChain : public AMDGPUToolChain {
157155
return SanitizerKind::Address;
158156
}
159157

160-
void diagnoseUnsupportedSanitizers(const llvm::opt::ArgList &Args) const {
161-
if (!Args.hasFlag(options::OPT_fgpu_sanitize, options::OPT_fno_gpu_sanitize,
162-
true))
163-
return;
158+
bool handleSanitizeOption(const ToolChain &TC, llvm::opt::DerivedArgList &DAL,
159+
const llvm::opt::ArgList &DriverArgs,
160+
StringRef TargetID, const llvm::opt::Arg *A) const {
161+
if (TargetID.empty())
162+
return false;
163+
// If this isn't a sanitizer option, don't handle it.
164+
if (!A->getOption().matches(options::OPT_fsanitize_EQ))
165+
return false;
166+
// If we shouldn't do sanitizing, skip it.
167+
if (!DriverArgs.hasFlag(options::OPT_fgpu_sanitize,
168+
options::OPT_fno_gpu_sanitize, true))
169+
return true;
170+
164171
auto &Diags = getDriver().getDiags();
165-
for (auto *A : Args.filtered(options::OPT_fsanitize_EQ)) {
166-
for (const char *Value : A->getValues()) {
167-
SanitizerMask K = parseSanitizerValue(Value, /*Allow Groups*/ false);
168-
if (K != SanitizerKind::Address)
172+
bool IsExplicitDevice =
173+
A->getBaseArg().getOption().matches(options::OPT_Xarch_device);
174+
175+
SmallVector<const char *, 4> SupportedSanitizers;
176+
SmallVector<const char *, 4> UnSupportedSanitizers;
177+
178+
for (const char *Value : A->getValues()) {
179+
SanitizerMask K = parseSanitizerValue(Value, /*Allow Groups*/ false);
180+
if (K & ROCMToolChain::getSupportedSanitizers())
181+
SupportedSanitizers.push_back(Value);
182+
else
183+
UnSupportedSanitizers.push_back(Value);
184+
}
185+
186+
// If there are no supported sanitizers, drop the whole argument.
187+
if (SupportedSanitizers.empty()) {
188+
if (IsExplicitDevice) {
189+
Diags.Report(clang::diag::err_drv_unsupported_option_for_target)
190+
<< A->getAsString(DAL) << getTriple().str();
191+
} else {
192+
Diags.Report(clang::diag::warn_drv_unsupported_option_for_target)
193+
<< A->getAsString(DAL) << getTriple().str();
194+
}
195+
return true;
196+
}
197+
// If only some sanitizers are unsupported, report each one individually.
198+
if (!UnSupportedSanitizers.empty()) {
199+
for (const char *Value : UnSupportedSanitizers) {
200+
if (IsExplicitDevice) {
201+
Diags.Report(clang::diag::err_drv_unsupported_option_part_for_target)
202+
<< Value << A->getAsString(DriverArgs) << getTriple().str();
203+
} else {
169204
Diags.Report(clang::diag::warn_drv_unsupported_option_part_for_target)
170-
<< Value << A->getAsString(Args) << getTriple().str();
205+
<< Value << A->getAsString(DriverArgs) << getTriple().str();
206+
}
171207
}
172208
}
209+
// If we know the target arch, check if the sanitizer is supported for it.
210+
if (shouldSkipSanitizeOption(TC, DriverArgs, TargetID, A))
211+
return true;
212+
213+
// Add a new argument with only the supported sanitizers.
214+
DAL.AddJoinedArg(A, A->getOption(), llvm::join(SupportedSanitizers, ","));
215+
return true;
173216
}
174217
};
175218

clang/lib/Driver/ToolChains/AMDGPUOpenMP.cpp

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,6 @@ AMDGPUOpenMPToolChain::AMDGPUOpenMPToolChain(const Driver &D,
2828
// Lookup binaries into the driver directory, this is used to
2929
// discover the 'amdgpu-arch' executable.
3030
getProgramPaths().push_back(getDriver().Dir);
31-
// Diagnose unsupported sanitizer options only once.
32-
diagnoseUnsupportedSanitizers(Args);
3331
}
3432

3533
void AMDGPUOpenMPToolChain::addClangTargetOptions(
@@ -66,19 +64,10 @@ llvm::opt::DerivedArgList *AMDGPUOpenMPToolChain::TranslateArgs(
6664

6765
const OptTable &Opts = getDriver().getOpts();
6866

69-
// Skip sanitize options passed from the HostTC. Remove them early.
70-
// The decision to sanitize device code is computed only by
71-
// 'shouldSkipSanitizeOption'.
72-
if (DAL->hasArg(options::OPT_fsanitize_EQ))
73-
DAL->eraseArg(options::OPT_fsanitize_EQ);
74-
7567
for (Arg *A : Args) {
76-
std::optional<std::string> SupportedSanitizers =
77-
filterSanitizeOption(*this, Args, BoundArch, A);
78-
if (!SupportedSanitizers)
68+
// Filter unsupported sanitizers passed from the HostTC.
69+
if (!handleSanitizeOption(*this, *DAL, Args, BoundArch, A))
7970
DAL->append(A);
80-
else if (!SupportedSanitizers->empty())
81-
DAL->AddJoinedArg(A, A->getOption(), *SupportedSanitizers);
8271
}
8372

8473
if (!BoundArch.empty()) {
@@ -119,9 +108,8 @@ void AMDGPUOpenMPToolChain::AddIAMCUIncludeArgs(const ArgList &Args,
119108
SanitizerMask AMDGPUOpenMPToolChain::getSupportedSanitizers() const {
120109
// The AMDGPUOpenMPToolChain only supports sanitizers in the sense that it
121110
// allows sanitizer arguments on the command line if they are supported by the
122-
// host toolchain. The AMDGPUOpenMPToolChain will actually ignore any command
123-
// line arguments for any of these "supported" sanitizers. That means that no
124-
// sanitization of device code is actually supported at this time.
111+
// host toolchain. The AMDGPUOpenMPToolChain will later filter unsupported
112+
// sanitizers from the command line arguments.
125113
//
126114
// This behavior is necessary because the host and device toolchains
127115
// invocations often share the command line, so the device toolchain must

clang/lib/Driver/ToolChains/HIPAMD.cpp

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -219,8 +219,6 @@ HIPAMDToolChain::HIPAMDToolChain(const Driver &D, const llvm::Triple &Triple,
219219
// Lookup binaries into the driver directory, this is used to
220220
// discover the clang-offload-bundler executable.
221221
getProgramPaths().push_back(getDriver().Dir);
222-
// Diagnose unsupported sanitizer options only once.
223-
diagnoseUnsupportedSanitizers(Args);
224222
}
225223

226224
void HIPAMDToolChain::addClangTargetOptions(
@@ -291,19 +289,10 @@ HIPAMDToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args,
291289

292290
const OptTable &Opts = getDriver().getOpts();
293291

294-
// Skip sanitize options passed from the HostTC. Remove them early.
295-
// The decision to sanitize device code is computed only by
296-
// 'shouldSkipSanitizeOption'.
297-
if (DAL->hasArg(options::OPT_fsanitize_EQ))
298-
DAL->eraseArg(options::OPT_fsanitize_EQ);
299-
300292
for (Arg *A : Args) {
301-
std::optional<std::string> SupportedSanitizers =
302-
filterSanitizeOption(*this, Args, BoundArch, A);
303-
if (!SupportedSanitizers)
293+
// Filter unsupported sanitizers passed from the HostTC.
294+
if (!handleSanitizeOption(*this, *DAL, Args, BoundArch, A))
304295
DAL->append(A);
305-
else if (!SupportedSanitizers->empty())
306-
DAL->AddJoinedArg(A, A->getOption(), *SupportedSanitizers);
307296
}
308297

309298
if (!BoundArch.empty()) {
@@ -358,9 +347,8 @@ void HIPAMDToolChain::AddHIPIncludeArgs(const ArgList &DriverArgs,
358347
SanitizerMask HIPAMDToolChain::getSupportedSanitizers() const {
359348
// The HIPAMDToolChain only supports sanitizers in the sense that it allows
360349
// sanitizer arguments on the command line if they are supported by the host
361-
// toolchain. The HIPAMDToolChain will actually ignore any command line
362-
// arguments for any of these "supported" sanitizers. That means that no
363-
// sanitization of device code is actually supported at this time.
350+
// toolchain. The HIPAMDToolChain will later filter unsupported sanitizers
351+
// from the command line arguments.
364352
//
365353
// This behavior is necessary because the host and device toolchains
366354
// invocations often share the command line, so the device toolchain must

clang/test/Driver/amdgpu-openmp-sanitize-options.c

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,26 +57,52 @@
5757
// (The address sanitizer enables the device sanitizer pipeline. The fuzzer
5858
// implicitly turns on LLVMs SanitizerCoverage, which the driver then forwards
5959
// to the device cc1. SanitizerCoverage is not supported on amdgcn.)
60+
6061
// RUN: %clang -no-canonical-prefixes -### --target=x86_64-unknown-linux-gnu -fopenmp=libomp --offload-arch=gfx908:xnack+ -fsanitize=address,fuzzer --rocm-path=%S/Inputs/rocm %s 2>&1 \
6162
// RUN: | FileCheck -check-prefixes=HOSTSANCOMBINATION,INVALIDCOMBINATION1 %s
6263
// RUN: %clang -no-canonical-prefixes -### --target=x86_64-unknown-linux-gnu -fopenmp=libomp --offload-arch=gfx908:xnack+ -fsanitize=fuzzer,address --rocm-path=%S/Inputs/rocm %s 2>&1 \
6364
// RUN: | FileCheck -check-prefixes=HOSTSANCOMBINATION,INVALIDCOMBINATION2 %s
6465

66+
// Do the same for multiple -fsanitize arguments and multi-arch scenarios.
67+
68+
// RUN: %clang -no-canonical-prefixes -### --target=x86_64-unknown-linux-gnu -fopenmp=libomp --offload-arch=gfx908:xnack+ --offload-arch=gfx900:xnack- -fsanitize=address,fuzzer --rocm-path=%S/Inputs/rocm %s 2>&1 \
69+
// RUN: | FileCheck -check-prefixes=HOSTSANCOMBINATION,INVALIDCOMBINATION1 %s
70+
// RUN: %clang -no-canonical-prefixes -### --target=x86_64-unknown-linux-gnu -fopenmp=libomp --offload-arch=gfx908:xnack+,gfx900:xnack- -fsanitize=address,fuzzer --rocm-path=%S/Inputs/rocm %s 2>&1 \
71+
// RUN: | FileCheck -check-prefixes=HOSTSANCOMBINATION,INVALIDCOMBINATION1 %s
72+
// RUN: %clang -no-canonical-prefixes -### --target=x86_64-unknown-linux-gnu -fopenmp=libomp --offload-arch=gfx908:xnack+,gfx900:xnack- -fsanitize=fuzzer,address -fsanitize=leak --rocm-path=%S/Inputs/rocm %s 2>&1 \
73+
// RUN: | FileCheck -check-prefixes=HOSTSANCOMBINATION2,NOTSUPPORTED-DAG,INVALIDCOMBINATION2 %s
74+
75+
// Test -Xarch_device error scenario
76+
77+
// RUN: not %clang -no-canonical-prefixes -### --target=x86_64-unknown-linux-gnu -fopenmp=libomp --offload-arch=gfx908:xnack+ -Xarch_device -fsanitize=leak --rocm-path=%S/Inputs/rocm %s 2>&1 \
78+
// RUN: | FileCheck -check-prefixes=UNSUPPORTEDERROR %s
79+
80+
// RUN: not %clang -no-canonical-prefixes -### --target=x86_64-unknown-linux-gnu -fopenmp=libomp --offload-arch=gfx908:xnack- -Xarch_device -fsanitize=address --rocm-path=%S/Inputs/rocm %s 2>&1 \
81+
// RUN: | FileCheck -check-prefixes=XNACKERROR %s
82+
83+
// RUN: not %clang -no-canonical-prefixes -### --target=x86_64-unknown-linux-gnu -fopenmp=libomp --offload-arch=gfx908:xnack+ -Xarch_device -fsanitize=fuzzer,address --rocm-path=%S/Inputs/rocm %s 2>&1 \
84+
// RUN: | FileCheck -check-prefixes=INVALIDCOMBINATIONERROR %s
85+
6586
// INVALIDCOMBINATION1: warning: ignoring 'fuzzer' in '-fsanitize=address,fuzzer' option as it is not currently supported for target 'amdgcn-amd-amdhsa' [-Woption-ignored]
6687
// INVALIDCOMBINATION2: warning: ignoring 'fuzzer' in '-fsanitize=fuzzer,address' option as it is not currently supported for target 'amdgcn-amd-amdhsa' [-Woption-ignored]
6788

6889
// FAIL-DAG: error: cannot find ROCm device library for ABI version 5; provide its path via '--rocm-path' or '--rocm-device-lib-path', or pass '-nogpulib' to build without ROCm device library
69-
// NOTSUPPORTED-DAG: warning: ignoring 'leak' in '-fsanitize=leak' option as it is not currently supported for target 'amdgcn-amd-amdhsa'
90+
// NOTSUPPORTED-DAG: warning: ignoring '-fsanitize=leak' option as it is not currently supported for target 'amdgcn-amd-amdhsa'
7091

7192
// NOXNACK: warning: ignoring '-fsanitize=address' option for offload arch 'gfx908' as it is not currently supported there. Use it with an offload arch containing 'xnack+' instead
7293
// XNACKNEG: warning: ignoring '-fsanitize=address' option for offload arch 'gfx908:xnack-' as it is not currently supported there. Use it with an offload arch containing 'xnack+' instead
7394

7495
// HOSTSAN: {{"[^"]*clang[^"]*" "-cc1" "-triple" "x86_64-unknown-linux-gnu".* "-fopenmp".* "-fsanitize=address".* "--offload-targets=amdgcn-amd-amdhsa".* "-x" "c".*}}
7596
// HOSTSANCOMBINATION: {{"[^"]*clang[^"]*" "-cc1" "-triple" "x86_64-unknown-linux-gnu".* "-fopenmp".* "-fsanitize=address,fuzzer,fuzzer-no-link".* "--offload-targets=amdgcn-amd-amdhsa".* "-x" "c".*}}
97+
// HOSTSANCOMBINATION2: {{"[^"]*clang[^"]*" "-cc1" "-triple" "x86_64-unknown-linux-gnu".* "-fopenmp".* "-fsanitize=address,fuzzer,fuzzer-no-link,leak".* "--offload-targets=amdgcn-amd-amdhsa".* "-x" "c".*}}
7698

7799
// GPUSAN: {{"[^"]*clang[^"]*" "-cc1" "-triple" "amdgcn-amd-amdhsa" "-aux-triple" "x86_64-unknown-linux-gnu".* "-emit-llvm-bc".* "-mlink-bitcode-file" "[^"]*asanrtl.bc".* "-mlink-bitcode-file" "[^"]*ockl.bc".* "-target-cpu" "(gfx908|gfx900|gfx1250|gfx1251)".* "-fopenmp".* "-fsanitize=address".* "-x" "c".*}}
78100
// NOGPUSAN: {{"[^"]*clang[^"]*" "-cc1" "-triple" "amdgcn-amd-amdhsa" "-aux-triple" "x86_64-unknown-linux-gnu".* "-emit-llvm-bc".* "-target-cpu" "(gfx908|gfx900)".* "-fopenmp".* "-x" "c".*}}
79101

80102
// SAN: {{"[^"]*llvm-offload-binary[^"]*" "-o".* "--image=file=.*.bc,triple=amdgcn-amd-amdhsa,arch=(gfx908|gfx1250|gfx1251)(:xnack\-|:xnack\+)?,kind=openmp(,feature=(\-xnack|\+xnack))?"}}
81103
// SAN: {{"[^"]*clang[^"]*" "-cc1" "-triple" "x86_64-unknown-linux-gnu".* "-fopenmp".* "-fsanitize=address".* "--offload-targets=amdgcn-amd-amdhsa".* "-x" "ir".*}}
82104
// SAN: {{"[^"]*clang-linker-wrapper[^"]*".* "--host-triple=x86_64-unknown-linux-gnu".* "--linker-path=[^"]*".* "--whole-archive" "[^"]*(libclang_rt.asan_static.a|libclang_rt.asan_static-x86_64.a)".* "--whole-archive" "[^"]*(libclang_rt.asan.a|libclang_rt.asan-x86_64.a)".*}}
105+
106+
// UNSUPPORTEDERROR: error: '-fsanitize=leak' option is not currently supported for target 'amdgcn-amd-amdhsa'
107+
// XNACKERROR: error: '-fsanitize=address' option for offload arch 'gfx908:xnack-' is not currently supported there. Use it with an offload arch containing 'xnack+' instead
108+
// INVALIDCOMBINATIONERROR: error: 'fuzzer' in '-fsanitize=fuzzer,address' option is not currently supported for target 'amdgcn-amd-amdhsa'

0 commit comments

Comments
 (0)