Skip to content

Commit f5acae8

Browse files
authored
Merge pull request llvm#623 from AMD-Lightning-Internal/amd/merge/upstream_merge_20250212205251
merge main into amd-staging
2 parents ba1efac + a82f6b6 commit f5acae8

File tree

191 files changed

+11484
-1703
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

191 files changed

+11484
-1703
lines changed

bolt/tools/driver/llvm-bolt.cpp

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -173,24 +173,14 @@ void boltMode(int argc, char **argv) {
173173
}
174174
}
175175

176-
static std::string GetExecutablePath(const char *Argv0) {
177-
SmallString<256> ExecutablePath(Argv0);
178-
// Do a PATH lookup if Argv0 isn't a valid path.
179-
if (!llvm::sys::fs::exists(ExecutablePath))
180-
if (llvm::ErrorOr<std::string> P =
181-
llvm::sys::findProgramByName(ExecutablePath))
182-
ExecutablePath = *P;
183-
return std::string(ExecutablePath);
184-
}
185-
186176
int main(int argc, char **argv) {
187177
// Print a stack trace if we signal out.
188178
sys::PrintStackTraceOnErrorSignal(argv[0]);
189179
PrettyStackTraceProgram X(argc, argv);
190180

191181
llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
192182

193-
std::string ToolPath = GetExecutablePath(argv[0]);
183+
std::string ToolPath = llvm::sys::fs::getMainExecutable(argv[0], nullptr);
194184

195185
// Initialize targets and assembly printers/parsers.
196186
llvm::InitializeAllTargetInfos();

clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.def

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,16 @@ ANALYZER_OPTION(
294294
bool, ShouldUnrollLoops, "unroll-loops",
295295
"Whether the analysis should try to unroll loops with known bounds.", false)
296296

297+
ANALYZER_OPTION(
298+
bool, ShouldAssumeAtLeastOneIteration, "assume-at-least-one-iteration",
299+
"Whether the analyzer should always assume at least one iteration in "
300+
"loops where the loop condition is opaque (i.e. the analyzer cannot "
301+
"determine if it's true or false). Setting this to true eliminates some "
302+
"false positives (where e.g. a structure is nonempty, but the analyzer "
303+
"does not notice this); but it also eliminates some true positives (e.g. "
304+
"cases where a structure can be empty and this causes buggy behavior).",
305+
false)
306+
297307
ANALYZER_OPTION(
298308
bool, ShouldDisplayNotesAsEvents, "notes-as-events",
299309
"Whether the bug reporter should transparently treat extra note diagnostic "

clang/lib/AST/ByteCode/InterpBuiltin.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1683,7 +1683,7 @@ static bool interp__builtin_operator_new(InterpState &S, CodePtr OpPC,
16831683
assert(!ElemT);
16841684
// Structs etc.
16851685
const Descriptor *Desc = S.P.createDescriptor(
1686-
Call, ElemType.getTypePtr(), Descriptor::InlineDescMD,
1686+
NewCall, ElemType.getTypePtr(), Descriptor::InlineDescMD,
16871687
/*IsConst=*/false, /*IsTemporary=*/false, /*IsMutable=*/false,
16881688
/*Init=*/nullptr);
16891689

clang/lib/CodeGen/CGStmtOpenMP.cpp

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2922,10 +2922,86 @@ static void emitSimdlenSafelenClause(CodeGenFunction &CGF,
29222922
}
29232923
}
29242924

2925+
// Check for the presence of an `OMPOrderedDirective`,
2926+
// i.e., `ordered` in `#pragma omp ordered simd`.
2927+
//
2928+
// Consider the following source code:
2929+
// ```
2930+
// __attribute__((noinline)) void omp_simd_loop(float X[ARRAY_SIZE][ARRAY_SIZE])
2931+
// {
2932+
// for (int r = 1; r < ARRAY_SIZE; ++r) {
2933+
// for (int c = 1; c < ARRAY_SIZE; ++c) {
2934+
// #pragma omp simd
2935+
// for (int k = 2; k < ARRAY_SIZE; ++k) {
2936+
// #pragma omp ordered simd
2937+
// X[r][k] = X[r][k - 2] + sinf((float)(r / c));
2938+
// }
2939+
// }
2940+
// }
2941+
// }
2942+
// ```
2943+
//
2944+
// Suppose we are in `CodeGenFunction::EmitOMPSimdInit(const OMPLoopDirective
2945+
// &D)`. By examining `D.dump()` we have the following AST containing
2946+
// `OMPOrderedDirective`:
2947+
//
2948+
// ```
2949+
// OMPSimdDirective 0x1c32950
2950+
// `-CapturedStmt 0x1c32028
2951+
// |-CapturedDecl 0x1c310e8
2952+
// | |-ForStmt 0x1c31e30
2953+
// | | |-DeclStmt 0x1c31298
2954+
// | | | `-VarDecl 0x1c31208 used k 'int' cinit
2955+
// | | | `-IntegerLiteral 0x1c31278 'int' 2
2956+
// | | |-<<<NULL>>>
2957+
// | | |-BinaryOperator 0x1c31308 'int' '<'
2958+
// | | | |-ImplicitCastExpr 0x1c312f0 'int' <LValueToRValue>
2959+
// | | | | `-DeclRefExpr 0x1c312b0 'int' lvalue Var 0x1c31208 'k' 'int'
2960+
// | | | `-IntegerLiteral 0x1c312d0 'int' 256
2961+
// | | |-UnaryOperator 0x1c31348 'int' prefix '++'
2962+
// | | | `-DeclRefExpr 0x1c31328 'int' lvalue Var 0x1c31208 'k' 'int'
2963+
// | | `-CompoundStmt 0x1c31e18
2964+
// | | `-OMPOrderedDirective 0x1c31dd8
2965+
// | | |-OMPSimdClause 0x1c31380
2966+
// | | `-CapturedStmt 0x1c31cd0
2967+
// ```
2968+
//
2969+
// Note the presence of `OMPOrderedDirective` above:
2970+
// It's (transitively) nested in a `CapturedStmt` representing the pragma
2971+
// annotated compound statement. Thus, we need to consider this nesting and
2972+
// include checking the `getCapturedStmt` in this case.
2973+
static bool hasOrderedDirective(const Stmt *S) {
2974+
if (isa<OMPOrderedDirective>(S))
2975+
return true;
2976+
2977+
if (const auto *CS = dyn_cast<CapturedStmt>(S))
2978+
return hasOrderedDirective(CS->getCapturedStmt());
2979+
2980+
for (const Stmt *Child : S->children()) {
2981+
if (Child && hasOrderedDirective(Child))
2982+
return true;
2983+
}
2984+
2985+
return false;
2986+
}
2987+
2988+
static void applyConservativeSimdOrderedDirective(const Stmt &AssociatedStmt,
2989+
LoopInfoStack &LoopStack) {
2990+
// Check for the presence of an `OMPOrderedDirective`
2991+
// i.e., `ordered` in `#pragma omp ordered simd`
2992+
bool HasOrderedDirective = hasOrderedDirective(&AssociatedStmt);
2993+
// If present then conservatively disable loop vectorization
2994+
// analogously to how `emitSimdlenSafelenClause` does.
2995+
if (HasOrderedDirective)
2996+
LoopStack.setParallel(/*Enable=*/false);
2997+
}
2998+
29252999
void CodeGenFunction::EmitOMPSimdInit(const OMPLoopDirective &D) {
29263000
// Walk clauses and process safelen/lastprivate.
29273001
LoopStack.setParallel(/*Enable=*/true);
29283002
LoopStack.setVectorizeEnable();
3003+
const Stmt *AssociatedStmt = D.getAssociatedStmt();
3004+
applyConservativeSimdOrderedDirective(*AssociatedStmt, LoopStack);
29293005
emitSimdlenSafelenClause(*this, D);
29303006
if (const auto *C = D.getSingleClause<OMPOrderClause>())
29313007
if (C->getKind() == OMPC_ORDER_concurrent)

clang/lib/Driver/ToolChains/AMDGPU.cpp

Lines changed: 17 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -740,10 +740,6 @@ amdgpu::dlr::getCommonDeviceLibNames(
740740
// If --hip-device-lib is not set, add the default bitcode libraries.
741741
// TODO: There are way too many flags that change this. Do we need to check
742742
// them all?
743-
std::tuple<bool, const SanitizerArgs> GPUSan(
744-
DriverArgs.hasFlag(options::OPT_fgpu_sanitize,
745-
options::OPT_fno_gpu_sanitize, true),
746-
SanArgs);
747743
bool DAZ = DriverArgs.hasFlag(
748744
options::OPT_fgpu_flush_denormals_to_zero,
749745
options::OPT_fno_gpu_flush_denormals_to_zero,
@@ -760,6 +756,12 @@ amdgpu::dlr::getCommonDeviceLibNames(
760756
options::OPT_fno_hip_fp32_correctly_rounded_divide_sqrt, true);
761757
bool Wave64 = toolchains::AMDGPUToolChain::isWave64(DriverArgs, Kind);
762758

759+
// GPU Sanitizer currently only supports ASan and is enabled through host
760+
// ASan.
761+
bool GPUSan = DriverArgs.hasFlag(options::OPT_fgpu_sanitize,
762+
options::OPT_fno_gpu_sanitize, true) &&
763+
SanArgs.needsAsanRt();
764+
763765
return RocmInstallation.getCommonBitcodeLibs(
764766
DriverArgs, LibDeviceFile, Wave64, DAZ, FiniteOnly, UnsafeMathOpt,
765767
FastRelaxedMath, CorrectSqrt, ABIVer, GPUSan, isOpenMP);
@@ -1008,13 +1010,7 @@ void ROCMToolChain::addClangTargetOptions(
10081010
ABIVer, noGPULib))
10091011
return;
10101012

1011-
std::tuple<bool, const SanitizerArgs> GPUSan(
1012-
DriverArgs.hasFlag(options::OPT_fgpu_sanitize,
1013-
options::OPT_fno_gpu_sanitize, true),
1014-
getSanitizerArgs((DriverArgs)));
1015-
10161013
bool Wave64 = isWave64(DriverArgs, Kind);
1017-
10181014
// TODO: There are way too many flags that change this. Do we need to check
10191015
// them all?
10201016
bool DAZ = DriverArgs.hasArg(options::OPT_cl_denorms_are_zero) ||
@@ -1027,6 +1023,12 @@ void ROCMToolChain::addClangTargetOptions(
10271023
bool CorrectSqrt =
10281024
DriverArgs.hasArg(options::OPT_cl_fp32_correctly_rounded_divide_sqrt);
10291025

1026+
// GPU Sanitizer currently only supports ASan and is enabled through host
1027+
// ASan.
1028+
bool GPUSan = DriverArgs.hasFlag(options::OPT_fgpu_sanitize,
1029+
options::OPT_fno_gpu_sanitize, true) &&
1030+
getSanitizerArgs(DriverArgs).needsAsanRt();
1031+
10301032
// Add the OpenCL specific bitcode library.
10311033
llvm::SmallVector<BitCodeLibraryInfo, 12> BCLibs;
10321034
BCLibs.emplace_back(RocmInstallation->getOpenCLPath().str());
@@ -1070,24 +1072,18 @@ llvm::SmallVector<ToolChain::BitCodeLibraryInfo, 12>
10701072
RocmInstallationDetector::getCommonBitcodeLibs(
10711073
const llvm::opt::ArgList &DriverArgs, StringRef LibDeviceFile, bool Wave64,
10721074
bool DAZ, bool FiniteOnly, bool UnsafeMathOpt, bool FastRelaxedMath,
1073-
bool CorrectSqrt, DeviceLibABIVersion ABIVer,
1074-
const std::tuple<bool, const SanitizerArgs> &GPUSan,
1075-
bool isOpenMP = false) const {
1075+
bool CorrectSqrt, DeviceLibABIVersion ABIVer, bool GPUSan,
1076+
bool isOpenMP) const {
10761077
llvm::SmallVector<ToolChain::BitCodeLibraryInfo, 12> BCLibs;
10771078

1078-
auto GPUSanEnabled = [GPUSan]() {
1079-
return std::get<bool>(GPUSan) &&
1080-
std::get<const SanitizerArgs>(GPUSan).needsAsanRt();
1081-
};
10821079
auto AddBCLib = [&](ToolChain::BitCodeLibraryInfo BCLib,
10831080
bool Internalize = true) {
10841081
BCLib.ShouldInternalize = Internalize;
10851082
BCLibs.push_back(BCLib);
10861083
};
10871084
auto AddSanBCLibs = [&]() {
1088-
if (GPUSanEnabled()) {
1085+
if (GPUSan)
10891086
AddBCLib(getAsanRTLPath(), false);
1090-
}
10911087
};
10921088

10931089
AddSanBCLibs();
@@ -1100,7 +1096,7 @@ RocmInstallationDetector::getCommonBitcodeLibs(
11001096
// __BUILD_MATH_BUILTINS_LIB__ turning static libm functions to extern.
11011097
if (!isOpenMP)
11021098
AddBCLib(getOCKLPath());
1103-
else if (GPUSanEnabled() && isOpenMP)
1099+
else if (GPUSan && isOpenMP)
11041100
AddBCLib(getOCKLPath(), false);
11051101
AddBCLib(getDenormalsAreZeroPath(DAZ));
11061102
AddBCLib(getUnsafeMathPath(UnsafeMathOpt || FastRelaxedMath));
@@ -1140,6 +1136,7 @@ bool AMDGPUToolChain::shouldSkipSanitizeOption(
11401136
if (TargetID.empty())
11411137
return false;
11421138
Option O = A->getOption();
1139+
11431140
if (!O.matches(options::OPT_fsanitize_EQ))
11441141
return false;
11451142

clang/lib/Driver/ToolChains/AMDGPUOpenMP.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -458,11 +458,18 @@ llvm::opt::DerivedArgList *AMDGPUOpenMPToolChain::TranslateArgs(
458458

459459
DerivedArgList *DAL =
460460
HostTC.TranslateArgs(Args, BoundArch, DeviceOffloadKind);
461-
if (!DAL || Args.hasArg(options::OPT_fsanitize_EQ))
461+
462+
if (!DAL)
462463
DAL = new DerivedArgList(Args.getBaseArgs());
463464

464465
const OptTable &Opts = getDriver().getOpts();
465466

467+
// Skip sanitize options passed from the HostTC. Claim them early.
468+
// The decision to sanitize device code is computed only by
469+
// 'shouldSkipSanitizeOption'.
470+
if (DAL->hasArg(options::OPT_fsanitize_EQ))
471+
DAL->claimAllArgs(options::OPT_fsanitize_EQ);
472+
466473
for (Arg *A : Args)
467474
if (!shouldSkipSanitizeOption(*this, Args, BoundArch, A) &&
468475
!llvm::is_contained(*DAL, A))

clang/lib/Driver/ToolChains/ROCm.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ class RocmInstallationDetector {
178178
const llvm::opt::ArgList &DriverArgs, StringRef LibDeviceFile,
179179
bool Wave64, bool DAZ, bool FiniteOnly, bool UnsafeMathOpt,
180180
bool FastRelaxedMath, bool CorrectSqrt, DeviceLibABIVersion ABIVer,
181-
const std::tuple<bool, const SanitizerArgs> &GPUSan, bool isOpenMP) const;
181+
bool GPUSan, bool isOpenMP) const;
182182

183183
/// Check file paths of default bitcode libraries common to AMDGPU based
184184
/// toolchains. \returns false if there are invalid or missing files.

clang/lib/StaticAnalyzer/Core/ExprEngine.cpp

Lines changed: 37 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2813,13 +2813,24 @@ void ExprEngine::processBranch(
28132813
if (StTrue && StFalse)
28142814
assert(!isa<ObjCForCollectionStmt>(Condition));
28152815

2816+
// We want to ensure consistent behavior between `eagerly-assume=false`,
2817+
// when the state split is always performed by the `assumeCondition()`
2818+
// call within this function and `eagerly-assume=true` (the default), when
2819+
// some conditions (comparison operators, unary negation) can trigger a
2820+
// state split before this callback. There are some contrived corner cases
2821+
// that behave differently with and without `eagerly-assume`, but I don't
2822+
// know about an example that could plausibly appear in "real" code.
2823+
bool BothFeasible =
2824+
(StTrue && StFalse) ||
2825+
didEagerlyAssumeBifurcateAt(PrevState, dyn_cast<Expr>(Condition));
2826+
28162827
if (StTrue) {
2817-
// If we are processing a loop condition where two iterations have
2818-
// already been completed and the false branch is also feasible, then
2819-
// don't assume a third iteration because it is a redundant execution
2820-
// path (unlikely to be different from earlier loop exits) and can cause
2821-
// false positives if e.g. the loop iterates over a two-element structure
2822-
// with an opaque condition.
2828+
// In a loop, if both branches are feasible (i.e. the analyzer doesn't
2829+
// understand the loop condition) and two iterations have already been
2830+
// completed, then don't assume a third iteration because it is a
2831+
// redundant execution path (unlikely to be different from earlier loop
2832+
// exits) and can cause false positives if e.g. the loop iterates over a
2833+
// two-element structure with an opaque condition.
28232834
//
28242835
// The iteration count "2" is hardcoded because it's the natural limit:
28252836
// * the fact that the programmer wrote a loop (and not just an `if`)
@@ -2830,10 +2841,7 @@ void ExprEngine::processBranch(
28302841
// two iterations". (This pattern is common in FFMPEG and appears in
28312842
// many other projects as well.)
28322843
bool CompletedTwoIterations = IterationsCompletedInLoop.value_or(0) >= 2;
2833-
bool FalseAlsoFeasible =
2834-
StFalse ||
2835-
didEagerlyAssumeBifurcateAt(PrevState, dyn_cast<Expr>(Condition));
2836-
bool SkipTrueBranch = CompletedTwoIterations && FalseAlsoFeasible;
2844+
bool SkipTrueBranch = BothFeasible && CompletedTwoIterations;
28372845

28382846
// FIXME: This "don't assume third iteration" heuristic partially
28392847
// conflicts with the widen-loop analysis option (which is off by
@@ -2843,8 +2851,25 @@ void ExprEngine::processBranch(
28432851
Builder.generateNode(StTrue, true, PredN);
28442852
}
28452853

2846-
if (StFalse)
2847-
Builder.generateNode(StFalse, false, PredN);
2854+
if (StFalse) {
2855+
// In a loop, if both branches are feasible (i.e. the analyzer doesn't
2856+
// understand the loop condition), we are before the first iteration and
2857+
// the analyzer option `assume-at-least-one-iteration` is set to `true`,
2858+
// then avoid creating the execution path where the loop is skipped.
2859+
//
2860+
// In some situations this "loop is skipped" execution path is an
2861+
// important corner case that may evade the notice of the developer and
2862+
// hide significant bugs -- however, there are also many situations where
2863+
// it's guaranteed that at least one iteration will happen (e.g. some
2864+
// data structure is always nonempty), but the analyzer cannot realize
2865+
// this and will produce false positives when it assumes that the loop is
2866+
// skipped.
2867+
bool BeforeFirstIteration = IterationsCompletedInLoop == std::optional{0};
2868+
bool SkipFalseBranch = BothFeasible && BeforeFirstIteration &&
2869+
AMgr.options.ShouldAssumeAtLeastOneIteration;
2870+
if (!SkipFalseBranch)
2871+
Builder.generateNode(StFalse, false, PredN);
2872+
}
28482873
}
28492874
currBldrCtx = nullptr;
28502875
}

clang/test/AST/ByteCode/new-delete.cpp

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -840,10 +840,17 @@ template <typename T>
840840
struct SS {
841841
constexpr SS(unsigned long long N)
842842
: data(nullptr){
843-
data = alloc.allocate(N); // #call
843+
data = alloc.allocate(N);
844844
for(std::size_t i = 0; i < N; i ++)
845-
std::construct_at<T>(data + i, i); // #construct_call
845+
std::construct_at<T>(data + i, i);
846846
}
847+
848+
constexpr SS()
849+
: data(nullptr){
850+
data = alloc.allocate(1);
851+
std::construct_at<T>(data);
852+
}
853+
847854
constexpr T operator[](std::size_t i) const {
848855
return data[i];
849856
}
@@ -855,6 +862,7 @@ struct SS {
855862
T* data;
856863
};
857864
constexpr unsigned short ssmall = SS<unsigned short>(100)[42];
865+
constexpr auto Ss = SS<S>()[0];
858866

859867

860868

clang/test/Analysis/analyzer-config.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
// CHECK-NEXT: alpha.cplusplus.STLAlgorithmModeling:AggressiveStdFindModeling = false
1111
// CHECK-NEXT: alpha.osx.cocoa.DirectIvarAssignment:AnnotatedFunctions = false
1212
// CHECK-NEXT: apply-fixits = false
13+
// CHECK-NEXT: assume-at-least-one-iteration = false
1314
// CHECK-NEXT: assume-controlled-environment = false
1415
// CHECK-NEXT: avoid-suppressing-null-argument-paths = false
1516
// CHECK-NEXT: c++-allocator-inlining = true

0 commit comments

Comments
 (0)