From 93b20e7d1f1d72c19c450a81ef5d84376e474b77 Mon Sep 17 00:00:00 2001 From: Guy David Date: Sun, 23 Nov 2025 14:32:03 +0200 Subject: [PATCH 01/10] [AArch64] Extend int-to-fp load optimization to support f16 (#168076) --- .../Target/AArch64/AArch64ISelLowering.cpp | 4 +- llvm/lib/Target/AArch64/AArch64InstrInfo.td | 13 +++++ .../test/CodeGen/AArch64/int-to-fp-no-neon.ll | 48 +++++++++++++------ llvm/test/CodeGen/AArch64/itofp.ll | 36 +++++++++----- 4 files changed, 73 insertions(+), 28 deletions(-) diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp index ac3745ea5c274..0bbe117ecf51f 100644 --- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp +++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp @@ -20146,7 +20146,9 @@ static SDValue performIntToFpCombine(SDNode *N, SelectionDAG &DAG, return Res; EVT VT = N->getValueType(0); - if (VT != MVT::f32 && VT != MVT::f64) + if (VT != MVT::f16 && VT != MVT::f32 && VT != MVT::f64) + return SDValue(); + if (VT == MVT::f16 && !Subtarget->hasFullFP16()) return SDValue(); // Only optimize when the source and destination types have the same width. diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td index 50a3a4ab8d8b6..881f7707f0eb7 100644 --- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td +++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td @@ -7014,6 +7014,19 @@ multiclass UIntToFPROLoadPat; } +let Predicates = [HasNEONandIsSME2p2StreamingSafe, HasFullFP16] in { +defm : UIntToFPROLoadPat; +def : Pat <(f16 (uint_to_fp (i32 + (zextloadi8 (am_indexed8 GPR64sp:$Rn, uimm12s1:$offset))))), + (UCVTFv1i16 (INSERT_SUBREG (f16 (IMPLICIT_DEF)), + (LDRBui GPR64sp:$Rn, uimm12s1:$offset), bsub))>; +def : Pat <(f16 (uint_to_fp (i32 + (zextloadi8 (am_unscaled8 GPR64sp:$Rn, simm9:$offset))))), + (UCVTFv1i16 (INSERT_SUBREG (f16 (IMPLICIT_DEF)), + (LDURBi GPR64sp:$Rn, simm9:$offset), bsub))>; +} + defm : UIntToFPROLoadPat; def : Pat <(f32 (uint_to_fp (i32 diff --git a/llvm/test/CodeGen/AArch64/int-to-fp-no-neon.ll b/llvm/test/CodeGen/AArch64/int-to-fp-no-neon.ll index 478ccf58f32c5..56e4b1988b8d1 100644 --- a/llvm/test/CodeGen/AArch64/int-to-fp-no-neon.ll +++ b/llvm/test/CodeGen/AArch64/int-to-fp-no-neon.ll @@ -43,11 +43,17 @@ entry: } define half @ui8_to_half(ptr %i, ptr %f) { -; CHECK-LABEL: ui8_to_half: -; CHECK: // %bb.0: // %entry -; CHECK-NEXT: ldrb w8, [x0] -; CHECK-NEXT: ucvtf h0, w8 -; CHECK-NEXT: ret +; NEON-ENABLED-LABEL: ui8_to_half: +; NEON-ENABLED: // %bb.0: // %entry +; NEON-ENABLED-NEXT: ldr b0, [x0] +; NEON-ENABLED-NEXT: ucvtf h0, h0 +; NEON-ENABLED-NEXT: ret +; +; NEON-DISABLED-LABEL: ui8_to_half: +; NEON-DISABLED: // %bb.0: // %entry +; NEON-DISABLED-NEXT: ldrb w8, [x0] +; NEON-DISABLED-NEXT: ucvtf h0, w8 +; NEON-DISABLED-NEXT: ret entry: %ld = load i8, ptr %i, align 1 %conv = uitofp i8 %ld to half @@ -91,11 +97,17 @@ entry: } define half @ui16_to_half(ptr %i, ptr %f) { -; CHECK-LABEL: ui16_to_half: -; CHECK: // %bb.0: // %entry -; CHECK-NEXT: ldrh w8, [x0] -; CHECK-NEXT: ucvtf h0, w8 -; CHECK-NEXT: ret +; NEON-ENABLED-LABEL: ui16_to_half: +; NEON-ENABLED: // %bb.0: // %entry +; NEON-ENABLED-NEXT: ldr h0, [x0] +; NEON-ENABLED-NEXT: ucvtf h0, h0 +; NEON-ENABLED-NEXT: ret +; +; NEON-DISABLED-LABEL: ui16_to_half: +; NEON-DISABLED: // %bb.0: // %entry +; NEON-DISABLED-NEXT: ldrh w8, [x0] +; NEON-DISABLED-NEXT: ucvtf h0, w8 +; NEON-DISABLED-NEXT: ret entry: %ld = load i16, ptr %i, align 1 %conv = uitofp i16 %ld to half @@ -277,11 +289,17 @@ entry: } define half @si16_to_half(ptr %i, ptr %f) { -; CHECK-LABEL: si16_to_half: -; CHECK: // %bb.0: // %entry -; CHECK-NEXT: ldrsh w8, [x0] -; CHECK-NEXT: scvtf h0, w8 -; CHECK-NEXT: ret +; NEON-ENABLED-LABEL: si16_to_half: +; NEON-ENABLED: // %bb.0: // %entry +; NEON-ENABLED-NEXT: ldr h0, [x0] +; NEON-ENABLED-NEXT: scvtf h0, h0 +; NEON-ENABLED-NEXT: ret +; +; NEON-DISABLED-LABEL: si16_to_half: +; NEON-DISABLED: // %bb.0: // %entry +; NEON-DISABLED-NEXT: ldrsh w8, [x0] +; NEON-DISABLED-NEXT: scvtf h0, w8 +; NEON-DISABLED-NEXT: ret entry: %ld = load i16, ptr %i, align 1 %conv = sitofp i16 %ld to half diff --git a/llvm/test/CodeGen/AArch64/itofp.ll b/llvm/test/CodeGen/AArch64/itofp.ll index e526a9f7bc0f6..26a933d400f29 100644 --- a/llvm/test/CodeGen/AArch64/itofp.ll +++ b/llvm/test/CodeGen/AArch64/itofp.ll @@ -1090,11 +1090,17 @@ define half @stofp_load_i16_f16(ptr %p) { ; CHECK-NOFP16-NEXT: fcvt h0, s0 ; CHECK-NOFP16-NEXT: ret ; -; CHECK-FP16-LABEL: stofp_load_i16_f16: -; CHECK-FP16: // %bb.0: // %entry -; CHECK-FP16-NEXT: ldrsh w8, [x0] -; CHECK-FP16-NEXT: scvtf h0, w8 -; CHECK-FP16-NEXT: ret +; CHECK-FP16-SD-LABEL: stofp_load_i16_f16: +; CHECK-FP16-SD: // %bb.0: // %entry +; CHECK-FP16-SD-NEXT: ldr h0, [x0] +; CHECK-FP16-SD-NEXT: scvtf h0, h0 +; CHECK-FP16-SD-NEXT: ret +; +; CHECK-FP16-GI-LABEL: stofp_load_i16_f16: +; CHECK-FP16-GI: // %bb.0: // %entry +; CHECK-FP16-GI-NEXT: ldrsh w8, [x0] +; CHECK-FP16-GI-NEXT: scvtf h0, w8 +; CHECK-FP16-GI-NEXT: ret entry: %a = load i16, ptr %p %c = sitofp i16 %a to half @@ -1109,11 +1115,17 @@ define half @utofp_load_i16_f16(ptr %p) { ; CHECK-NOFP16-NEXT: fcvt h0, s0 ; CHECK-NOFP16-NEXT: ret ; -; CHECK-FP16-LABEL: utofp_load_i16_f16: -; CHECK-FP16: // %bb.0: // %entry -; CHECK-FP16-NEXT: ldrh w8, [x0] -; CHECK-FP16-NEXT: ucvtf h0, w8 -; CHECK-FP16-NEXT: ret +; CHECK-FP16-SD-LABEL: utofp_load_i16_f16: +; CHECK-FP16-SD: // %bb.0: // %entry +; CHECK-FP16-SD-NEXT: ldr h0, [x0] +; CHECK-FP16-SD-NEXT: ucvtf h0, h0 +; CHECK-FP16-SD-NEXT: ret +; +; CHECK-FP16-GI-LABEL: utofp_load_i16_f16: +; CHECK-FP16-GI: // %bb.0: // %entry +; CHECK-FP16-GI-NEXT: ldrh w8, [x0] +; CHECK-FP16-GI-NEXT: ucvtf h0, w8 +; CHECK-FP16-GI-NEXT: ret entry: %a = load i16, ptr %p %c = uitofp i16 %a to half @@ -1149,8 +1161,8 @@ define half @utofp_load_i8_f16(ptr %p) { ; ; CHECK-FP16-LABEL: utofp_load_i8_f16: ; CHECK-FP16: // %bb.0: // %entry -; CHECK-FP16-NEXT: ldrb w8, [x0] -; CHECK-FP16-NEXT: ucvtf h0, w8 +; CHECK-FP16-NEXT: ldr b0, [x0] +; CHECK-FP16-NEXT: ucvtf h0, h0 ; CHECK-FP16-NEXT: ret entry: %a = load i8, ptr %p From 06fc87bcd3d61a08f8c035e60949631f61bccee7 Mon Sep 17 00:00:00 2001 From: Krzysztof Parzyszek Date: Sun, 23 Nov 2025 07:55:10 -0600 Subject: [PATCH 02/10] [flang][OpenMP] Better diagnostics for invalid or misplaced directives (#168885) Add two more AST nodes, one for a misplaced end-directive, and one for an invalid string following the OpenMP sentinel (e.g. "!$OMP XYZ"). Emit error messages when either node is encountered in semantic analysis. --- flang/include/flang/Parser/dump-parse-tree.h | 2 + flang/include/flang/Parser/parse-tree.h | 20 ++++++- flang/lib/Parser/executable-parsers.cpp | 2 + flang/lib/Parser/openmp-parsers.cpp | 53 ++++++++++++------- flang/lib/Parser/program-parsers.cpp | 3 ++ flang/lib/Parser/type-parsers.h | 3 +- flang/lib/Parser/unparse.cpp | 10 ++++ flang/lib/Semantics/check-omp-structure.cpp | 19 +++++++ flang/lib/Semantics/check-omp-structure.h | 5 ++ flang/lib/Semantics/resolve-directives.cpp | 3 ++ flang/test/Parser/OpenMP/fail-construct2.f90 | 2 +- flang/test/Parser/OpenMP/tile-fail.f90 | 4 +- .../Semantics/OpenMP/clause-validity01.f90 | 5 +- .../Semantics/OpenMP/loop-association.f90 | 16 ++++++ .../loop-transformation-construct02.f90 | 12 ++--- .../loop-transformation-construct03.f90 | 5 +- 16 files changed, 129 insertions(+), 35 deletions(-) diff --git a/flang/include/flang/Parser/dump-parse-tree.h b/flang/include/flang/Parser/dump-parse-tree.h index 5ca9deeb9b7f6..32fcd4182bed7 100644 --- a/flang/include/flang/Parser/dump-parse-tree.h +++ b/flang/include/flang/Parser/dump-parse-tree.h @@ -755,7 +755,9 @@ class ParseTreeDumper { NODE(parser, OpenMPDispatchConstruct) NODE(parser, OpenMPFlushConstruct) NODE(parser, OpenMPGroupprivate) + NODE(parser, OpenMPInvalidDirective) NODE(parser, OpenMPLoopConstruct) + NODE(parser, OpenMPMisplacedEndDirective) NODE(parser, OpenMPRequiresConstruct) NODE(parser, OpenMPSectionConstruct) NODE(parser, OpenMPSectionsConstruct) diff --git a/flang/include/flang/Parser/parse-tree.h b/flang/include/flang/Parser/parse-tree.h index 9795a0d2ae25e..003d11721908e 100644 --- a/flang/include/flang/Parser/parse-tree.h +++ b/flang/include/flang/Parser/parse-tree.h @@ -269,8 +269,9 @@ struct AccEndCombinedDirective; struct OpenACCDeclarativeConstruct; struct OpenACCRoutineConstruct; struct OpenMPConstruct; -struct OpenMPLoopConstruct; struct OpenMPDeclarativeConstruct; +struct OpenMPInvalidDirective; +struct OpenMPMisplacedEndDirective; struct CUFKernelDoConstruct; // Cooked character stream locations @@ -406,6 +407,8 @@ struct SpecificationConstruct { common::Indirection, common::Indirection, common::Indirection, + common::Indirection, + common::Indirection, common::Indirection> u; }; @@ -538,6 +541,8 @@ struct ExecutableConstruct { common::Indirection, common::Indirection, common::Indirection, + common::Indirection, + common::Indirection, common::Indirection> u; }; @@ -5379,6 +5384,19 @@ struct OpenMPConstruct { u; }; +// Orphaned !$OMP END , i.e. not being a part of a valid OpenMP +// construct. +struct OpenMPMisplacedEndDirective : public OmpEndDirective { + INHERITED_TUPLE_CLASS_BOILERPLATE( + OpenMPMisplacedEndDirective, OmpEndDirective); +}; + +// Unrecognized string after the !$OMP sentinel. +struct OpenMPInvalidDirective { + using EmptyTrait = std::true_type; + CharBlock source; +}; + // Parse tree nodes for OpenACC 3.3 directives and clauses struct AccObject { diff --git a/flang/lib/Parser/executable-parsers.cpp b/flang/lib/Parser/executable-parsers.cpp index 8d777a6671495..2241c04f5d26d 100644 --- a/flang/lib/Parser/executable-parsers.cpp +++ b/flang/lib/Parser/executable-parsers.cpp @@ -50,6 +50,8 @@ constexpr auto executableConstruct{first( construct(indirect(whereConstruct)), construct(indirect(forallConstruct)), construct(indirect(openmpConstruct)), + construct(indirect(openmpMisplacedEndDirective)), + construct(indirect(openmpInvalidDirective)), construct(indirect(Parser{})), construct(indirect(compilerDirective)), construct(indirect(Parser{})))}; diff --git a/flang/lib/Parser/openmp-parsers.cpp b/flang/lib/Parser/openmp-parsers.cpp index b7f23348328b4..b033206d90c41 100644 --- a/flang/lib/Parser/openmp-parsers.cpp +++ b/flang/lib/Parser/openmp-parsers.cpp @@ -1602,6 +1602,14 @@ static inline constexpr auto IsMemberOf(const DirectiveSet &dirs) { }; } +constexpr auto validEPC{// + predicated(executionPartConstruct, [](auto &epc) { + return !Unwrap(epc) && + !Unwrap(epc); + })}; + +constexpr auto validBlock{many(validEPC)}; + TYPE_PARSER(sourced(construct(OmpDirectiveNameParser{}))) OmpDirectiveSpecification static makeFlushFromOldSyntax(Verbatim &&text, @@ -1659,7 +1667,7 @@ struct StrictlyStructuredBlockParser { std::optional Parse(ParseState &state) const { // Detect BLOCK construct without parsing the entire thing. if (lookAhead(skipStuffBeforeStatement >> "BLOCK"_tok).Parse(state)) { - if (auto epc{Parser{}.Parse(state)}) { + if (auto &&epc{executionPartConstruct.Parse(state)}) { if (GetFortranBlockConstruct(*epc) != nullptr) { Block body; body.emplace_back(std::move(*epc)); @@ -1679,7 +1687,7 @@ struct LooselyStructuredBlockParser { if (lookAhead(skipStuffBeforeStatement >> "BLOCK"_tok).Parse(state)) { return std::nullopt; } - if (auto &&body{block.Parse(state)}) { + if (auto &&body{validBlock.Parse(state)}) { // Empty body is ok. return std::move(body); } @@ -1718,7 +1726,7 @@ struct NonBlockDoConstructParser { if (auto &&nbd{nonBlockDo.Parse(state)}) { processEpc(std::move(*nbd)); - while (auto &&epc{attempt(executionPartConstruct).Parse(state)}) { + while (auto &&epc{attempt(validEPC).Parse(state)}) { processEpc(std::move(*epc)); if (labels.empty()) { break; @@ -1840,7 +1848,7 @@ struct OmpStatementConstructParser { std::optional Parse(ParseState &state) const { if (auto begin{OmpBeginDirectiveParser(dir_).Parse(state)}) { Block body; - if (auto stmt{attempt(Parser{}).Parse(state)}) { + if (auto stmt{attempt(validEPC).Parse(state)}) { body.emplace_back(std::move(*stmt)); } // Allow empty block. Check for this in semantics. @@ -1924,7 +1932,7 @@ struct OmpLoopConstructParser { } } else if (assoc == llvm::omp::Association::LoopSeq) { // Parse loop sequence as a block. - if (auto &&body{block.Parse(state)}) { + if (auto &&body{validBlock.Parse(state)}) { auto end{maybe(OmpEndDirectiveParser{loopDir}).Parse(state)}; return OpenMPLoopConstruct{OmpBeginLoopDirective(std::move(*begin)), std::move(*body), @@ -2021,11 +2029,9 @@ struct OmpAtomicConstructParser { return std::nullopt; } - auto exec{Parser{}}; - auto end{OmpEndDirectiveParser{llvm::omp::Directive::OMPD_atomic}}; TailType tail; - if (ParseOne(exec, end, tail, state)) { + if (ParseOne(tail, state)) { if (!tail.first.empty()) { if (auto &&rest{attempt(LimitedTailParser(BodyLimit)).Parse(state)}) { for (auto &&s : rest->first) { @@ -2052,13 +2058,12 @@ struct OmpAtomicConstructParser { // Parse either an ExecutionPartConstruct, or atomic end-directive. When // successful, record the result in the "tail" provided, otherwise fail. - static std::optional ParseOne( // - Parser &exec, OmpEndDirectiveParser &end, - TailType &tail, ParseState &state) { - auto isRecovery{[](const ExecutionPartConstruct &e) { - return std::holds_alternative(e.u); + static std::optional ParseOne(TailType &tail, ParseState &state) { + auto isUsable{[](const std::optional &e) { + return e && !std::holds_alternative(e->u); }}; - if (auto &&stmt{attempt(exec).Parse(state)}; stmt && !isRecovery(*stmt)) { + auto end{OmpEndDirectiveParser{llvm::omp::Directive::OMPD_atomic}}; + if (auto &&stmt{attempt(validEPC).Parse(state)}; isUsable(stmt)) { tail.first.emplace_back(std::move(*stmt)); } else if (auto &&dir{attempt(end).Parse(state)}) { tail.second = std::move(*dir); @@ -2074,12 +2079,10 @@ struct OmpAtomicConstructParser { constexpr LimitedTailParser(size_t count) : count_(count) {} std::optional Parse(ParseState &state) const { - auto exec{Parser{}}; - auto end{OmpEndDirectiveParser{llvm::omp::Directive::OMPD_atomic}}; TailType tail; for (size_t i{0}; i != count_; ++i) { - if (ParseOne(exec, end, tail, state)) { + if (ParseOne(tail, state)) { if (tail.second) { // Return when the end-directive was parsed. return std::move(tail); @@ -2351,9 +2354,9 @@ TYPE_PARSER(sourced(construct( Parser{} / endOmpLine, cons( // construct(sourced( - construct(maybe(sectionDir), block))), - many(construct( - sourced(construct(sectionDir, block))))), + construct(maybe(sectionDir), validBlock))), + many(construct(sourced( + construct(sectionDir, validBlock))))), maybe(Parser{} / endOmpLine)))) static bool IsExecutionPart(const OmpDirectiveName &name) { @@ -2429,4 +2432,14 @@ static constexpr DirectiveSet GetLoopDirectives() { TYPE_PARSER(sourced(construct( OmpLoopConstructParser(GetLoopDirectives())))) +static constexpr DirectiveSet GetAllDirectives() { // + return ~DirectiveSet{}; +} + +TYPE_PARSER(construct( + OmpEndDirectiveParser{GetAllDirectives()})) + +TYPE_PARSER( // + startOmpLine >> sourced(construct( + !OmpDirectiveNameParser{} >> SkipTo<'\n'>{}))) } // namespace Fortran::parser diff --git a/flang/lib/Parser/program-parsers.cpp b/flang/lib/Parser/program-parsers.cpp index 740dbbfab9db7..303335934a37a 100644 --- a/flang/lib/Parser/program-parsers.cpp +++ b/flang/lib/Parser/program-parsers.cpp @@ -201,6 +201,9 @@ TYPE_CONTEXT_PARSER("specification construct"_en_US, construct( indirect(openaccDeclarativeConstruct)), construct(indirect(openmpDeclarativeConstruct)), + construct( + indirect(openmpMisplacedEndDirective)), + construct(indirect(openmpInvalidDirective)), construct(indirect(compilerDirective)))) // R513 other-specification-stmt -> diff --git a/flang/lib/Parser/type-parsers.h b/flang/lib/Parser/type-parsers.h index 3900c5a86c874..142aa226893b6 100644 --- a/flang/lib/Parser/type-parsers.h +++ b/flang/lib/Parser/type-parsers.h @@ -139,7 +139,8 @@ constexpr Parser openaccDeclarativeConstruct; constexpr Parser openmpConstruct; constexpr Parser openmpExecDirective; constexpr Parser openmpDeclarativeConstruct; -constexpr Parser ompEndLoopDirective; +constexpr Parser openmpMisplacedEndDirective; +constexpr Parser openmpInvalidDirective; constexpr Parser intrinsicVectorTypeSpec; // Extension constexpr Parser vectorTypeSpec; // Extension constexpr Parser unsignedTypeSpec; // Extension diff --git a/flang/lib/Parser/unparse.cpp b/flang/lib/Parser/unparse.cpp index f81200d092b11..3854d33d46d48 100644 --- a/flang/lib/Parser/unparse.cpp +++ b/flang/lib/Parser/unparse.cpp @@ -2706,6 +2706,16 @@ class UnparseVisitor { Put("\n"); EndOpenMP(); } + void Unparse(const OpenMPMisplacedEndDirective &x) { + Unparse(static_cast(x)); + } + void Unparse(const OpenMPInvalidDirective &x) { + BeginOpenMP(); + Word("!$OMP "); + Put(parser::ToUpperCaseLetters(x.source.ToString())); + Put("\n"); + EndOpenMP(); + } void Unparse(const BasedPointer &x) { Put('('), Walk(std::get<0>(x.t)), Put(","), Walk(std::get<1>(x.t)); Walk("(", std::get>(x.t), ")"), Put(')'); diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp index 63751fd0c8abd..b2cc86a5260b4 100644 --- a/flang/lib/Semantics/check-omp-structure.cpp +++ b/flang/lib/Semantics/check-omp-structure.cpp @@ -5476,6 +5476,25 @@ void OmpStructureChecker::CheckAllowedRequiresClause(llvmOmpClause clause) { } } +void OmpStructureChecker::Enter(const parser::OpenMPMisplacedEndDirective &x) { + context_.Say(x.DirName().source, "Misplaced OpenMP end-directive"_err_en_US); + PushContextAndClauseSets( + x.DirName().source, llvm::omp::Directive::OMPD_unknown); +} + +void OmpStructureChecker::Leave(const parser::OpenMPMisplacedEndDirective &x) { + dirContext_.pop_back(); +} + +void OmpStructureChecker::Enter(const parser::OpenMPInvalidDirective &x) { + context_.Say(x.source, "Invalid OpenMP directive"_err_en_US); + PushContextAndClauseSets(x.source, llvm::omp::Directive::OMPD_unknown); +} + +void OmpStructureChecker::Leave(const parser::OpenMPInvalidDirective &x) { + dirContext_.pop_back(); +} + // Use when clause falls under 'struct OmpClause' in 'parse-tree.h'. #define CHECK_SIMPLE_CLAUSE(X, Y) \ void OmpStructureChecker::Enter(const parser::OmpClause::X &) { \ diff --git a/flang/lib/Semantics/check-omp-structure.h b/flang/lib/Semantics/check-omp-structure.h index 3e5de0071aca7..a99d7c32a3f2b 100644 --- a/flang/lib/Semantics/check-omp-structure.h +++ b/flang/lib/Semantics/check-omp-structure.h @@ -94,6 +94,11 @@ class OmpStructureChecker : public OmpStructureCheckerBase { void Enter(const parser::OpenMPDeclarativeConstruct &); void Leave(const parser::OpenMPDeclarativeConstruct &); + void Enter(const parser::OpenMPMisplacedEndDirective &); + void Leave(const parser::OpenMPMisplacedEndDirective &); + void Enter(const parser::OpenMPInvalidDirective &); + void Leave(const parser::OpenMPInvalidDirective &); + void Enter(const parser::OpenMPLoopConstruct &); void Leave(const parser::OpenMPLoopConstruct &); void Enter(const parser::OmpEndLoopDirective &); diff --git a/flang/lib/Semantics/resolve-directives.cpp b/flang/lib/Semantics/resolve-directives.cpp index bd6c1f8e4c776..673ea4ef10e08 100644 --- a/flang/lib/Semantics/resolve-directives.cpp +++ b/flang/lib/Semantics/resolve-directives.cpp @@ -532,6 +532,9 @@ class OmpAttributeVisitor : DirectiveAttributeVisitor { void Post(const parser::OmpBeginLoopDirective &) { GetContext().withinConstruct = true; } + bool Pre(const parser::OpenMPMisplacedEndDirective &x) { return false; } + bool Pre(const parser::OpenMPInvalidDirective &x) { return false; } + bool Pre(const parser::DoConstruct &); bool Pre(const parser::OpenMPSectionsConstruct &); diff --git a/flang/test/Parser/OpenMP/fail-construct2.f90 b/flang/test/Parser/OpenMP/fail-construct2.f90 index b7f5736d1329b..3798c3dae3f0d 100644 --- a/flang/test/Parser/OpenMP/fail-construct2.f90 +++ b/flang/test/Parser/OpenMP/fail-construct2.f90 @@ -1,5 +1,5 @@ ! RUN: not %flang_fc1 -fsyntax-only -fopenmp %s 2>&1 | FileCheck %s -! CHECK: error: expected OpenMP construct +! CHECK: error: Invalid OpenMP directive !$omp dummy end diff --git a/flang/test/Parser/OpenMP/tile-fail.f90 b/flang/test/Parser/OpenMP/tile-fail.f90 index 3cb0ea96975c8..a69261a927961 100644 --- a/flang/test/Parser/OpenMP/tile-fail.f90 +++ b/flang/test/Parser/OpenMP/tile-fail.f90 @@ -8,7 +8,7 @@ ! Parser error subroutine stray_end1 - !CHECK: error: expected OpenMP construct + !CHECK: error: Misplaced OpenMP end-directive !$omp end tile end subroutine @@ -17,7 +17,7 @@ subroutine stray_end1 subroutine stray_end2 print * - !CHECK: error: expected 'END' + !CHECK: error: Misplaced OpenMP end-directive !$omp end tile end subroutine diff --git a/flang/test/Semantics/OpenMP/clause-validity01.f90 b/flang/test/Semantics/OpenMP/clause-validity01.f90 index fda15eb9876ef..ad0b764b2cc28 100644 --- a/flang/test/Semantics/OpenMP/clause-validity01.f90 +++ b/flang/test/Semantics/OpenMP/clause-validity01.f90 @@ -252,6 +252,8 @@ !$omp parallel do if(target:a>1.) do i = 1, N enddo + !ERROR: Misplaced OpenMP end-directive + !$omp end simd ! 2.7.2 sections-clause -> private-clause | ! firstprivate-clause | @@ -572,7 +574,8 @@ do i = 1, N a = a + 3.14 enddo - !$omp end taskloop simd + !ERROR: Misplaced OpenMP end-directive + !$omp end taskloop !ERROR: GRAINSIZE and NUM_TASKS clauses are mutually exclusive and may not appear on the same TASKLOOP SIMD directive !$omp taskloop simd num_tasks(3) grainsize(2) diff --git a/flang/test/Semantics/OpenMP/loop-association.f90 b/flang/test/Semantics/OpenMP/loop-association.f90 index b2898d3967a25..9c79a91429fdf 100644 --- a/flang/test/Semantics/OpenMP/loop-association.f90 +++ b/flang/test/Semantics/OpenMP/loop-association.f90 @@ -82,6 +82,8 @@ do i = 1, N enddo !$omp end parallel do + !ERROR: Misplaced OpenMP end-directive + !$omp end parallel do !$omp parallel a = 3.0 @@ -97,6 +99,8 @@ !$omp end parallel a = 0.0 + !ERROR: Misplaced OpenMP end-directive + !$omp end parallel do !$omp parallel do private(c) do i = 1, N do j = 1, N @@ -104,8 +108,12 @@ !$omp parallel do shared(b) a = 3.14 enddo + !ERROR: Misplaced OpenMP end-directive + !$omp end parallel do enddo a = 1.414 + !ERROR: Misplaced OpenMP end-directive + !$omp end parallel do do i = 1, N !$omp parallel do @@ -113,6 +121,8 @@ a = 3.14 enddo enddo + !ERROR: Misplaced OpenMP end-directive + !$omp end parallel do !ERROR: OpenMP loop construct should contain a DO-loop or a loop-nest-generating OpenMP construct !$omp parallel do private(c) @@ -120,15 +130,21 @@ do i=1, N a = 3.14 enddo + !ERROR: Misplaced OpenMP end-directive + !$omp end parallel do !$omp parallel do simd do i = 1, N a = 3.14 enddo !$omp end parallel do simd + !ERROR: Misplaced OpenMP end-directive + !$omp end parallel do simd !ERROR: OpenMP loop construct should contain a DO-loop or a loop-nest-generating OpenMP construct !$omp simd + a = i + 1 + !ERROR: Misplaced OpenMP end-directive !$omp end simd a = i + 1 end diff --git a/flang/test/Semantics/OpenMP/loop-transformation-construct02.f90 b/flang/test/Semantics/OpenMP/loop-transformation-construct02.f90 index 3c07d6d08508a..1b15c938915cd 100644 --- a/flang/test/Semantics/OpenMP/loop-transformation-construct02.f90 +++ b/flang/test/Semantics/OpenMP/loop-transformation-construct02.f90 @@ -2,13 +2,12 @@ ! nested Loop Transformation Constructs !RUN: %python %S/../test_errors.py %s %flang -fopenmp -fopenmp-version=60 -!XFAIL: * subroutine loop_transformation_construct1 implicit none !$omp do - !ERROR: The FUSE construct requires the END FUSE directive + !ERROR: OpenMP loop construct should contain a DO-loop or a loop-nest-generating OpenMP construct !$omp fuse end subroutine @@ -16,7 +15,7 @@ subroutine loop_transformation_construct2 implicit none !$omp do - !ERROR: A DO loop must follow the FUSE directive + !ERROR: OpenMP loop construct should contain a DO-loop or a loop-nest-generating OpenMP construct !$omp fuse !$omp end fuse end subroutine @@ -37,7 +36,7 @@ subroutine loop_transformation_construct3 end do !$omp end fuse !$omp end do - !ERROR: The END FUSE directive must follow the DO loop associated with the loop construct + !ERROR: Misplaced OpenMP end-directive !$omp end fuse end subroutine @@ -51,7 +50,7 @@ subroutine loop_transformation_construct4 do x = 1, i v(x) = v(x) * 2 end do - !ERROR: A DO loop must follow the FUSE directive + !ERROR: OpenMP loop construct should contain a DO-loop or a loop-nest-generating OpenMP construct !$omp fuse !$omp end fuse end subroutine @@ -63,7 +62,7 @@ subroutine loop_transformation_construct5 integer :: v(i) !$omp do - !ERROR: If a loop construct has been fully unrolled, it cannot then be further transformed + !ERROR: OpenMP loop construct cannot apply to a fully unrolled loop !$omp fuse !$omp unroll full do x = 1, i @@ -81,6 +80,7 @@ subroutine loop_transformation_construct6 integer :: x integer :: v(i) + !ERROR: The loop sequence following the DO construct must be fully fused first. !$omp do !$omp fuse looprange(1,1) !$omp unroll partial(2) diff --git a/flang/test/Semantics/OpenMP/loop-transformation-construct03.f90 b/flang/test/Semantics/OpenMP/loop-transformation-construct03.f90 index ab6b1bd7d67f9..578c55b3c0aff 100644 --- a/flang/test/Semantics/OpenMP/loop-transformation-construct03.f90 +++ b/flang/test/Semantics/OpenMP/loop-transformation-construct03.f90 @@ -1,7 +1,6 @@ ! Testing the Semantic failure of forming loop sequences under regular OpenMP directives !RUN: %python %S/../test_errors.py %s %flang -fopenmp -fopenmp-version=60 -!XFAIL: * subroutine loop_transformation_construct1 implicit none @@ -17,7 +16,7 @@ subroutine loop_transformation_construct1 do x = 1, i v(x) = v(x) * 2 end do - !ERROR: The END DO directive must follow the DO loop associated with the loop construct + !ERROR: Misplaced OpenMP end-directive !$omp end do end subroutine @@ -35,6 +34,6 @@ subroutine loop_transformation_construct2 do x = 1, i v(x) = v(x) * 2 end do - !ERROR: The END TILE directive must follow the DO loop associated with the loop construct + !ERROR: Misplaced OpenMP end-directive !$omp end tile end subroutine From 7485f34802f0ea1e00ac69499050e79692609b85 Mon Sep 17 00:00:00 2001 From: Simon Pilgrim Date: Sun, 23 Nov 2025 15:04:05 +0000 Subject: [PATCH 03/10] [X86] X86ISelDAGToDAG - don't let ADD/SUB(X,1) -> SUB/ADD(X,-1) constant fold (#169217) Extension to #168726 - ensure we peek through bitcasts to look for constants (as constant folding will) DAG should have constant folded this, but we're still fighting the lack of proper topological sorting. Fixes #169205 --- llvm/lib/Target/X86/X86ISelDAGToDAG.cpp | 3 ++- llvm/test/CodeGen/X86/pr169205.ll | 23 +++++++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 llvm/test/CodeGen/X86/pr169205.ll diff --git a/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp b/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp index 2b5a63aa66926..e7903a72d85bb 100644 --- a/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp +++ b/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp @@ -1004,7 +1004,8 @@ void X86DAGToDAGISel::PreprocessISelDAG() { if ((N->getOpcode() == ISD::ADD || N->getOpcode() == ISD::SUB) && N->getSimpleValueType(0).isVector() && !mayPreventLoadFold()) { APInt SplatVal; - if (!ISD::isBuildVectorOfConstantSDNodes(N->getOperand(0).getNode()) && + if (!ISD::isBuildVectorOfConstantSDNodes( + peekThroughBitcasts(N->getOperand(0)).getNode()) && X86::isConstantSplat(N->getOperand(1), SplatVal) && SplatVal.isOne()) { SDLoc DL(N); diff --git a/llvm/test/CodeGen/X86/pr169205.ll b/llvm/test/CodeGen/X86/pr169205.ll new file mode 100644 index 0000000000000..1416102d6ba77 --- /dev/null +++ b/llvm/test/CodeGen/X86/pr169205.ll @@ -0,0 +1,23 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc < %s -mtriple=x86_64-- -mcpu=x86-64 | FileCheck %s --check-prefixes=SSE +; RUN: llc < %s -mtriple=x86_64-- -mcpu=x86-64-v2 | FileCheck %s --check-prefixes=SSE +; RUN: llc < %s -mtriple=x86_64-- -mcpu=x86-64-v3 | FileCheck %s --check-prefixes=AVX +; RUN: llc < %s -mtriple=x86_64-- -mcpu=x86-64-v4 | FileCheck %s --check-prefixes=AVX + +define <4 x i16> @PR169205() { +; SSE-LABEL: PR169205: +; SSE: # %bb.0: +; SSE-NEXT: movaps {{.*#+}} xmm0 = [1,1,1,1,u,u,u,u] +; SSE-NEXT: retq +; +; AVX-LABEL: PR169205: +; AVX: # %bb.0: +; AVX-NEXT: vpxor %xmm0, %xmm0, %xmm0 +; AVX-NEXT: vpaddw {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm0, %xmm0 +; AVX-NEXT: retq + %avg = tail call <16 x i8> @llvm.x86.sse2.pavg.b(<16 x i8> zeroinitializer, <16 x i8> zeroinitializer) + %shuffle24 = shufflevector <16 x i8> %avg, <16 x i8> zeroinitializer, <4 x i32> + %conv25 = zext <4 x i8> %shuffle24 to <4 x i16> + %not.neg = add <4 x i16> %conv25, splat (i16 1) + ret <4 x i16> %not.neg +} From 21378fb75a6e4df1525067d408ebbf241aa63c75 Mon Sep 17 00:00:00 2001 From: Florian Hahn Date: Sun, 23 Nov 2025 15:52:19 +0000 Subject: [PATCH 04/10] [VPlan] Merge `fcmp uno` feeding AnyOf. (#166823) Fold any-of (fcmp uno %A, %A), (fcmp uno %B, %B), ... -> any-of (fcmp uno %A, %B), ... This pattern is generated to check if any vector lane is NaN, and combining multiple compares is beneficial on architectures that have dedicated instructions. Alive2 Proof: https://alive2.llvm.org/ce/z/vA_aoM Combine suggested as part of https://github.com/llvm/llvm-project/pull/161735 PR: https://github.com/llvm/llvm-project/pull/166823 --- .../Transforms/Vectorize/VPlanPatternMatch.h | 4 +++ .../lib/Transforms/Vectorize/VPlanRecipes.cpp | 2 +- .../Transforms/Vectorize/VPlanTransforms.cpp | 29 +++++++++++++++++ .../AArch64/fmax-without-fast-math-flags.ll | 7 ++--- .../AArch64/fmin-without-fast-math-flags.ll | 7 ++--- .../LoopVectorize/fcmp-uno-fold-interleave.ll | 31 +++++-------------- ...fmax-without-fast-math-flags-interleave.ll | 7 ++--- 7 files changed, 48 insertions(+), 39 deletions(-) diff --git a/llvm/lib/Transforms/Vectorize/VPlanPatternMatch.h b/llvm/lib/Transforms/Vectorize/VPlanPatternMatch.h index 5d65d9bf34bcc..91a392cccc1e3 100644 --- a/llvm/lib/Transforms/Vectorize/VPlanPatternMatch.h +++ b/llvm/lib/Transforms/Vectorize/VPlanPatternMatch.h @@ -420,6 +420,10 @@ m_BranchOnCount(const Op0_t &Op0, const Op1_t &Op1) { return m_VPInstruction(Op0, Op1); } +inline VPInstruction_match m_AnyOf() { + return m_VPInstruction(); +} + template inline VPInstruction_match m_AnyOf(const Op0_t &Op0) { diff --git a/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp b/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp index 535c77b048a7b..7ca1dbe51d68f 100644 --- a/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp +++ b/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp @@ -554,7 +554,6 @@ unsigned VPInstruction::getNumOperandsForOpcode(unsigned Opcode) { case Instruction::ExtractValue: case Instruction::Freeze: case Instruction::Load: - case VPInstruction::AnyOf: case VPInstruction::BranchOnCond: case VPInstruction::Broadcast: case VPInstruction::BuildStructVector: @@ -594,6 +593,7 @@ unsigned VPInstruction::getNumOperandsForOpcode(unsigned Opcode) { case Instruction::GetElementPtr: case Instruction::PHI: case Instruction::Switch: + case VPInstruction::AnyOf: case VPInstruction::SLPLoad: case VPInstruction::SLPStore: // Cannot determine the number of operands from the opcode. diff --git a/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp b/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp index dc2d013a24029..003a049da91e4 100644 --- a/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp +++ b/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp @@ -1241,6 +1241,35 @@ static void simplifyRecipe(VPSingleDefRecipe *Def, VPTypeAnalysis &TypeInfo) { } } + // Fold any-of (fcmp uno %A, %A), (fcmp uno %B, %B), ... -> + // any-of (fcmp uno %A, %B), ... + if (match(Def, m_AnyOf())) { + SmallVector NewOps; + VPRecipeBase *UnpairedCmp = nullptr; + for (VPValue *Op : Def->operands()) { + VPValue *X; + if (Op->getNumUsers() > 1 || + !match(Op, m_SpecificCmp(CmpInst::FCMP_UNO, m_VPValue(X), + m_Deferred(X)))) { + NewOps.push_back(Op); + } else if (!UnpairedCmp) { + UnpairedCmp = Op->getDefiningRecipe(); + } else { + NewOps.push_back(Builder.createFCmp(CmpInst::FCMP_UNO, + UnpairedCmp->getOperand(0), X)); + UnpairedCmp = nullptr; + } + } + + if (UnpairedCmp) + NewOps.push_back(UnpairedCmp->getVPSingleValue()); + + if (NewOps.size() < Def->getNumOperands()) { + VPValue *NewAnyOf = Builder.createNaryOp(VPInstruction::AnyOf, NewOps); + return Def->replaceAllUsesWith(NewAnyOf); + } + } + // Fold (fcmp uno %X, %X) or (fcmp uno %Y, %Y) -> fcmp uno %X, %Y // This is useful for fmax/fmin without fast-math flags, where we need to // check if any operand is NaN. diff --git a/llvm/test/Transforms/LoopVectorize/AArch64/fmax-without-fast-math-flags.ll b/llvm/test/Transforms/LoopVectorize/AArch64/fmax-without-fast-math-flags.ll index f3d649b899686..6902dd990509e 100644 --- a/llvm/test/Transforms/LoopVectorize/AArch64/fmax-without-fast-math-flags.ll +++ b/llvm/test/Transforms/LoopVectorize/AArch64/fmax-without-fast-math-flags.ll @@ -59,11 +59,8 @@ define float @fmaxnum(ptr %src, i64 %n) { ; CHECK-NEXT: [[TMP7]] = call <4 x float> @llvm.maxnum.v4f32(<4 x float> [[VEC_PHI]], <4 x float> [[WIDE_LOAD]]) ; CHECK-NEXT: [[TMP8]] = call <4 x float> @llvm.maxnum.v4f32(<4 x float> [[VEC_PHI1]], <4 x float> [[WIDE_LOAD2]]) ; CHECK-NEXT: [[INDEX_NEXT]] = add nuw i64 [[IV]], 8 -; CHECK-NEXT: [[TMP3:%.*]] = fcmp uno <4 x float> [[WIDE_LOAD]], [[WIDE_LOAD]] -; CHECK-NEXT: [[TMP4:%.*]] = fcmp uno <4 x float> [[WIDE_LOAD2]], [[WIDE_LOAD2]] -; CHECK-NEXT: [[TMP18:%.*]] = freeze <4 x i1> [[TMP3]] -; CHECK-NEXT: [[TMP15:%.*]] = freeze <4 x i1> [[TMP4]] -; CHECK-NEXT: [[TMP5:%.*]] = or <4 x i1> [[TMP18]], [[TMP15]] +; CHECK-NEXT: [[TMP4:%.*]] = fcmp uno <4 x float> [[WIDE_LOAD]], [[WIDE_LOAD2]] +; CHECK-NEXT: [[TMP5:%.*]] = freeze <4 x i1> [[TMP4]] ; CHECK-NEXT: [[TMP6:%.*]] = call i1 @llvm.vector.reduce.or.v4i1(<4 x i1> [[TMP5]]) ; CHECK-NEXT: [[TMP9:%.*]] = icmp eq i64 [[INDEX_NEXT]], [[N_VEC]] ; CHECK-NEXT: [[TMP10:%.*]] = or i1 [[TMP6]], [[TMP9]] diff --git a/llvm/test/Transforms/LoopVectorize/AArch64/fmin-without-fast-math-flags.ll b/llvm/test/Transforms/LoopVectorize/AArch64/fmin-without-fast-math-flags.ll index 1cc4c152649b4..193424d3eb70a 100644 --- a/llvm/test/Transforms/LoopVectorize/AArch64/fmin-without-fast-math-flags.ll +++ b/llvm/test/Transforms/LoopVectorize/AArch64/fmin-without-fast-math-flags.ll @@ -59,11 +59,8 @@ define float @fminnum(ptr %src, i64 %n) { ; CHECK-NEXT: [[TMP7]] = call <4 x float> @llvm.minnum.v4f32(<4 x float> [[VEC_PHI]], <4 x float> [[WIDE_LOAD]]) ; CHECK-NEXT: [[TMP8]] = call <4 x float> @llvm.minnum.v4f32(<4 x float> [[VEC_PHI1]], <4 x float> [[WIDE_LOAD2]]) ; CHECK-NEXT: [[INDEX_NEXT]] = add nuw i64 [[IV]], 8 -; CHECK-NEXT: [[TMP3:%.*]] = fcmp uno <4 x float> [[WIDE_LOAD]], [[WIDE_LOAD]] -; CHECK-NEXT: [[TMP4:%.*]] = fcmp uno <4 x float> [[WIDE_LOAD2]], [[WIDE_LOAD2]] -; CHECK-NEXT: [[TMP15:%.*]] = freeze <4 x i1> [[TMP3]] -; CHECK-NEXT: [[TMP18:%.*]] = freeze <4 x i1> [[TMP4]] -; CHECK-NEXT: [[TMP5:%.*]] = or <4 x i1> [[TMP15]], [[TMP18]] +; CHECK-NEXT: [[TMP4:%.*]] = fcmp uno <4 x float> [[WIDE_LOAD]], [[WIDE_LOAD2]] +; CHECK-NEXT: [[TMP5:%.*]] = freeze <4 x i1> [[TMP4]] ; CHECK-NEXT: [[TMP6:%.*]] = call i1 @llvm.vector.reduce.or.v4i1(<4 x i1> [[TMP5]]) ; CHECK-NEXT: [[TMP9:%.*]] = icmp eq i64 [[INDEX_NEXT]], [[N_VEC]] ; CHECK-NEXT: [[TMP10:%.*]] = or i1 [[TMP6]], [[TMP9]] diff --git a/llvm/test/Transforms/LoopVectorize/fcmp-uno-fold-interleave.ll b/llvm/test/Transforms/LoopVectorize/fcmp-uno-fold-interleave.ll index 7b8e1997a5011..22226a711bcf0 100644 --- a/llvm/test/Transforms/LoopVectorize/fcmp-uno-fold-interleave.ll +++ b/llvm/test/Transforms/LoopVectorize/fcmp-uno-fold-interleave.ll @@ -28,14 +28,11 @@ define float @fmaxnum(ptr %src, i64 %n) { ; IC3-NEXT: [[TMP4]] = call <4 x float> @llvm.maxnum.v4f32(<4 x float> [[VEC_PHI1]], <4 x float> [[WIDE_LOAD3]]) ; IC3-NEXT: [[TMP5]] = call <4 x float> @llvm.maxnum.v4f32(<4 x float> [[VEC_PHI2]], <4 x float> [[WIDE_LOAD4]]) ; IC3-NEXT: [[INDEX_NEXT]] = add nuw i64 [[INDEX]], 12 -; IC3-NEXT: [[TMP6:%.*]] = fcmp uno <4 x float> [[WIDE_LOAD]], [[WIDE_LOAD]] -; IC3-NEXT: [[TMP7:%.*]] = fcmp uno <4 x float> [[WIDE_LOAD3]], [[WIDE_LOAD3]] ; IC3-NEXT: [[TMP8:%.*]] = fcmp uno <4 x float> [[WIDE_LOAD4]], [[WIDE_LOAD4]] -; IC3-NEXT: [[TMP9:%.*]] = freeze <4 x i1> [[TMP6]] +; IC3-NEXT: [[TMP7:%.*]] = fcmp uno <4 x float> [[WIDE_LOAD]], [[WIDE_LOAD3]] ; IC3-NEXT: [[TMP10:%.*]] = freeze <4 x i1> [[TMP7]] -; IC3-NEXT: [[TMP11:%.*]] = or <4 x i1> [[TMP9]], [[TMP10]] ; IC3-NEXT: [[TMP12:%.*]] = freeze <4 x i1> [[TMP8]] -; IC3-NEXT: [[TMP13:%.*]] = or <4 x i1> [[TMP11]], [[TMP12]] +; IC3-NEXT: [[TMP13:%.*]] = or <4 x i1> [[TMP10]], [[TMP12]] ; IC3-NEXT: [[TMP14:%.*]] = call i1 @llvm.vector.reduce.or.v4i1(<4 x i1> [[TMP13]]) ; IC3-NEXT: [[TMP15:%.*]] = icmp eq i64 [[INDEX_NEXT]], [[N_VEC]] ; IC3-NEXT: [[TMP16:%.*]] = or i1 [[TMP14]], [[TMP15]] @@ -86,17 +83,11 @@ define float @fmaxnum(ptr %src, i64 %n) { ; IC4-NEXT: [[TMP6]] = call <4 x float> @llvm.maxnum.v4f32(<4 x float> [[VEC_PHI2]], <4 x float> [[WIDE_LOAD5]]) ; IC4-NEXT: [[TMP7]] = call <4 x float> @llvm.maxnum.v4f32(<4 x float> [[VEC_PHI3]], <4 x float> [[WIDE_LOAD6]]) ; IC4-NEXT: [[INDEX_NEXT]] = add nuw i64 [[INDEX]], 16 -; IC4-NEXT: [[TMP8:%.*]] = fcmp uno <4 x float> [[WIDE_LOAD]], [[WIDE_LOAD]] -; IC4-NEXT: [[TMP9:%.*]] = fcmp uno <4 x float> [[WIDE_LOAD4]], [[WIDE_LOAD4]] -; IC4-NEXT: [[TMP24:%.*]] = fcmp uno <4 x float> [[WIDE_LOAD5]], [[WIDE_LOAD5]] -; IC4-NEXT: [[TMP25:%.*]] = fcmp uno <4 x float> [[WIDE_LOAD6]], [[WIDE_LOAD6]] -; IC4-NEXT: [[TMP10:%.*]] = freeze <4 x i1> [[TMP8]] -; IC4-NEXT: [[TMP11:%.*]] = freeze <4 x i1> [[TMP9]] -; IC4-NEXT: [[TMP12:%.*]] = or <4 x i1> [[TMP10]], [[TMP11]] +; IC4-NEXT: [[TMP24:%.*]] = fcmp uno <4 x float> [[WIDE_LOAD]], [[WIDE_LOAD4]] +; IC4-NEXT: [[TMP25:%.*]] = fcmp uno <4 x float> [[WIDE_LOAD5]], [[WIDE_LOAD6]] ; IC4-NEXT: [[TMP26:%.*]] = freeze <4 x i1> [[TMP24]] -; IC4-NEXT: [[TMP27:%.*]] = or <4 x i1> [[TMP12]], [[TMP26]] ; IC4-NEXT: [[TMP28:%.*]] = freeze <4 x i1> [[TMP25]] -; IC4-NEXT: [[TMP29:%.*]] = or <4 x i1> [[TMP27]], [[TMP28]] +; IC4-NEXT: [[TMP29:%.*]] = or <4 x i1> [[TMP26]], [[TMP28]] ; IC4-NEXT: [[TMP13:%.*]] = call i1 @llvm.vector.reduce.or.v4i1(<4 x i1> [[TMP29]]) ; IC4-NEXT: [[TMP14:%.*]] = icmp eq i64 [[INDEX_NEXT]], [[N_VEC]] ; IC4-NEXT: [[TMP15:%.*]] = or i1 [[TMP13]], [[TMP14]] @@ -153,18 +144,12 @@ define float @fmaxnum(ptr %src, i64 %n) { ; IC5-NEXT: [[TMP8]] = call <4 x float> @llvm.maxnum.v4f32(<4 x float> [[VEC_PHI3]], <4 x float> [[WIDE_LOAD7]]) ; IC5-NEXT: [[TMP9]] = call <4 x float> @llvm.maxnum.v4f32(<4 x float> [[VEC_PHI4]], <4 x float> [[WIDE_LOAD8]]) ; IC5-NEXT: [[INDEX_NEXT]] = add nuw i64 [[INDEX]], 20 -; IC5-NEXT: [[TMP10:%.*]] = fcmp uno <4 x float> [[WIDE_LOAD]], [[WIDE_LOAD]] -; IC5-NEXT: [[TMP11:%.*]] = fcmp uno <4 x float> [[WIDE_LOAD5]], [[WIDE_LOAD5]] -; IC5-NEXT: [[TMP12:%.*]] = fcmp uno <4 x float> [[WIDE_LOAD6]], [[WIDE_LOAD6]] -; IC5-NEXT: [[TMP13:%.*]] = fcmp uno <4 x float> [[WIDE_LOAD7]], [[WIDE_LOAD7]] ; IC5-NEXT: [[TMP14:%.*]] = fcmp uno <4 x float> [[WIDE_LOAD8]], [[WIDE_LOAD8]] -; IC5-NEXT: [[TMP15:%.*]] = freeze <4 x i1> [[TMP10]] -; IC5-NEXT: [[TMP16:%.*]] = freeze <4 x i1> [[TMP11]] -; IC5-NEXT: [[TMP17:%.*]] = or <4 x i1> [[TMP15]], [[TMP16]] +; IC5-NEXT: [[TMP12:%.*]] = fcmp uno <4 x float> [[WIDE_LOAD]], [[WIDE_LOAD5]] +; IC5-NEXT: [[TMP13:%.*]] = fcmp uno <4 x float> [[WIDE_LOAD6]], [[WIDE_LOAD7]] ; IC5-NEXT: [[TMP18:%.*]] = freeze <4 x i1> [[TMP12]] -; IC5-NEXT: [[TMP19:%.*]] = or <4 x i1> [[TMP17]], [[TMP18]] ; IC5-NEXT: [[TMP20:%.*]] = freeze <4 x i1> [[TMP13]] -; IC5-NEXT: [[TMP21:%.*]] = or <4 x i1> [[TMP19]], [[TMP20]] +; IC5-NEXT: [[TMP21:%.*]] = or <4 x i1> [[TMP18]], [[TMP20]] ; IC5-NEXT: [[TMP22:%.*]] = freeze <4 x i1> [[TMP14]] ; IC5-NEXT: [[TMP23:%.*]] = or <4 x i1> [[TMP21]], [[TMP22]] ; IC5-NEXT: [[TMP24:%.*]] = call i1 @llvm.vector.reduce.or.v4i1(<4 x i1> [[TMP23]]) diff --git a/llvm/test/Transforms/LoopVectorize/fmax-without-fast-math-flags-interleave.ll b/llvm/test/Transforms/LoopVectorize/fmax-without-fast-math-flags-interleave.ll index ca6e5bc2d0dcb..0745f286b2608 100644 --- a/llvm/test/Transforms/LoopVectorize/fmax-without-fast-math-flags-interleave.ll +++ b/llvm/test/Transforms/LoopVectorize/fmax-without-fast-math-flags-interleave.ll @@ -59,11 +59,8 @@ define float @fmaxnum(ptr %src, i64 %n) { ; CHECK-NEXT: [[TMP7]] = call <4 x float> @llvm.maxnum.v4f32(<4 x float> [[VEC_PHI]], <4 x float> [[WIDE_LOAD]]) ; CHECK-NEXT: [[TMP8]] = call <4 x float> @llvm.maxnum.v4f32(<4 x float> [[VEC_PHI1]], <4 x float> [[WIDE_LOAD2]]) ; CHECK-NEXT: [[INDEX_NEXT]] = add nuw i64 [[IV]], 8 -; CHECK-NEXT: [[TMP3:%.*]] = fcmp uno <4 x float> [[WIDE_LOAD]], [[WIDE_LOAD]] -; CHECK-NEXT: [[TMP4:%.*]] = fcmp uno <4 x float> [[WIDE_LOAD2]], [[WIDE_LOAD2]] -; CHECK-NEXT: [[TMP15:%.*]] = freeze <4 x i1> [[TMP3]] -; CHECK-NEXT: [[TMP18:%.*]] = freeze <4 x i1> [[TMP4]] -; CHECK-NEXT: [[TMP5:%.*]] = or <4 x i1> [[TMP15]], [[TMP18]] +; CHECK-NEXT: [[TMP4:%.*]] = fcmp uno <4 x float> [[WIDE_LOAD]], [[WIDE_LOAD2]] +; CHECK-NEXT: [[TMP5:%.*]] = freeze <4 x i1> [[TMP4]] ; CHECK-NEXT: [[TMP6:%.*]] = call i1 @llvm.vector.reduce.or.v4i1(<4 x i1> [[TMP5]]) ; CHECK-NEXT: [[TMP9:%.*]] = icmp eq i64 [[INDEX_NEXT]], [[N_VEC]] ; CHECK-NEXT: [[TMP10:%.*]] = or i1 [[TMP6]], [[TMP9]] From 0332af25b9e33dad9b4d4ba4bef1400bbfe9383d Mon Sep 17 00:00:00 2001 From: Simon Pilgrim Date: Sun, 23 Nov 2025 16:35:31 +0000 Subject: [PATCH 05/10] [X86] BuiltinsX86.td - merge avx512 cmp/ucmp builtins into common Features/Attributes blocks. NFC. (#169223) --- clang/include/clang/Basic/BuiltinsX86.td | 96 ++++++------------------ 1 file changed, 22 insertions(+), 74 deletions(-) diff --git a/clang/include/clang/Basic/BuiltinsX86.td b/clang/include/clang/Basic/BuiltinsX86.td index f6069fdc5707a..4aa3d51931980 100644 --- a/clang/include/clang/Basic/BuiltinsX86.td +++ b/clang/include/clang/Basic/BuiltinsX86.td @@ -1246,102 +1246,46 @@ let Features = "avx512bw", Attributes = [NoThrow, Const, Constexpr] in { def knotdi : X86Builtin<"unsigned long long int(unsigned long long int)">; } -let Features = "avx512vl,avx512bw", - Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<128>] in { - def cmpb128_mask : X86Builtin<"unsigned short(_Vector<16, char>, _Vector<16, char>, _Constant int, unsigned short)">; -} - -let Features = "avx512vl", - Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<128>] in { +let Features = "avx512vl", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<128>] in { def cmpd128_mask : X86Builtin<"unsigned char(_Vector<4, int>, _Vector<4, int>, _Constant int, unsigned char)">; def cmpq128_mask : X86Builtin<"unsigned char(_Vector<2, long long int>, _Vector<2, long long int>, _Constant int, unsigned char)">; -} - -let Features = "avx512vl,avx512bw", - Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<128>] in { - def cmpw128_mask : X86Builtin<"unsigned char(_Vector<8, short>, _Vector<8, short>, _Constant int, unsigned char)">; -} - -let Features = "avx512vl,avx512bw", - Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<256>] in { - def cmpb256_mask : X86Builtin<"unsigned int(_Vector<32, char>, _Vector<32, char>, _Constant int, unsigned int)">; -} - -let Features = "avx512vl", - Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<256>] in { - def cmpd256_mask : X86Builtin<"unsigned char(_Vector<8, int>, _Vector<8, int>, _Constant int, unsigned char)">; - def cmpq256_mask : X86Builtin<"unsigned char(_Vector<4, long long int>, _Vector<4, long long int>, _Constant int, unsigned char)">; -} - -let Features = "avx512vl,avx512bw", - Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<256>] in { - def cmpw256_mask : X86Builtin<"unsigned short(_Vector<16, short>, _Vector<16, short>, _Constant int, unsigned short)">; -} - -let Features = "avx512bw", - Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<512>] in { - def cmpb512_mask : X86Builtin<"unsigned long long int(_Vector<64, char>, _Vector<64, char>, _Constant int, unsigned long long int)">; -} - -let Features = "avx512f", - Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<512>] in { - def cmpd512_mask : X86Builtin<"unsigned short(_Vector<16, int>, _Vector<16, int>, _Constant int, unsigned short)">; - def cmpq512_mask : X86Builtin<"unsigned char(_Vector<8, long long int>, _Vector<8, long long int>, _Constant int, unsigned char)">; -} - -let Features = "avx512bw", - Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<512>] in { - def cmpw512_mask : X86Builtin<"unsigned int(_Vector<32, short>, _Vector<32, short>, _Constant int, unsigned int)">; -} - -let Features = "avx512vl,avx512bw", - Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<128>] in { - def ucmpb128_mask : X86Builtin<"unsigned short(_Vector<16, char>, _Vector<16, char>, _Constant int, unsigned short)">; -} -let Features = "avx512vl", - Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<128>] in { def ucmpd128_mask : X86Builtin<"unsigned char(_Vector<4, int>, _Vector<4, int>, _Constant int, unsigned char)">; def ucmpq128_mask : X86Builtin<"unsigned char(_Vector<2, long long int>, _Vector<2, long long int>, _Constant int, unsigned char)">; } -let Features = "avx512vl,avx512bw", - Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<128>] in { +let Features = "avx512vl,avx512bw", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<128>] in { + def cmpb128_mask : X86Builtin<"unsigned short(_Vector<16, char>, _Vector<16, char>, _Constant int, unsigned short)">; + def cmpw128_mask : X86Builtin<"unsigned char(_Vector<8, short>, _Vector<8, short>, _Constant int, unsigned char)">; + + def ucmpb128_mask : X86Builtin<"unsigned short(_Vector<16, char>, _Vector<16, char>, _Constant int, unsigned short)">; def ucmpw128_mask : X86Builtin<"unsigned char(_Vector<8, short>, _Vector<8, short>, _Constant int, unsigned char)">; } -let Features = "avx512vl,avx512bw", - Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<256>] in { - def ucmpb256_mask : X86Builtin<"unsigned int(_Vector<32, char>, _Vector<32, char>, _Constant int, unsigned int)">; -} +let Features = "avx512vl", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<256>] in { + def cmpd256_mask : X86Builtin<"unsigned char(_Vector<8, int>, _Vector<8, int>, _Constant int, unsigned char)">; + def cmpq256_mask : X86Builtin<"unsigned char(_Vector<4, long long int>, _Vector<4, long long int>, _Constant int, unsigned char)">; -let Features = "avx512vl", - Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<256>] in { def ucmpd256_mask : X86Builtin<"unsigned char(_Vector<8, int>, _Vector<8, int>, _Constant int, unsigned char)">; def ucmpq256_mask : X86Builtin<"unsigned char(_Vector<4, long long int>, _Vector<4, long long int>, _Constant int, unsigned char)">; } -let Features = "avx512vl,avx512bw", - Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<256>] in { +let Features = "avx512vl,avx512bw", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<256>] in { + def cmpb256_mask : X86Builtin<"unsigned int(_Vector<32, char>, _Vector<32, char>, _Constant int, unsigned int)">; + def cmpw256_mask : X86Builtin<"unsigned short(_Vector<16, short>, _Vector<16, short>, _Constant int, unsigned short)">; + + def ucmpb256_mask : X86Builtin<"unsigned int(_Vector<32, char>, _Vector<32, char>, _Constant int, unsigned int)">; def ucmpw256_mask : X86Builtin<"unsigned short(_Vector<16, short>, _Vector<16, short>, _Constant int, unsigned short)">; } -let Features = "avx512bw", - Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<512>] in { - def ucmpb512_mask : X86Builtin<"unsigned long long int(_Vector<64, char>, _Vector<64, char>, _Constant int, unsigned long long int)">; -} +let Features = "avx512f", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<512>] in { + def cmpd512_mask : X86Builtin<"unsigned short(_Vector<16, int>, _Vector<16, int>, _Constant int, unsigned short)">; + def cmpq512_mask : X86Builtin<"unsigned char(_Vector<8, long long int>, _Vector<8, long long int>, _Constant int, unsigned char)">; -let Features = "avx512f", - Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<512>] in { def ucmpd512_mask : X86Builtin<"unsigned short(_Vector<16, int>, _Vector<16, int>, _Constant int, unsigned short)">; def ucmpq512_mask : X86Builtin<"unsigned char(_Vector<8, long long int>, _Vector<8, long long int>, _Constant int, unsigned char)">; } -let Features = "avx512bw", - Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<512>] in { - def ucmpw512_mask : X86Builtin<"unsigned int(_Vector<32, short>, _Vector<32, short>, _Constant int, unsigned int)">; -} - let Features = "avx512bw", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<512>] in { def packsswb512 : X86Builtin<"_Vector<64, char>(_Vector<32, short>, _Vector<32, short>)">; def packssdw512 : X86Builtin<"_Vector<32, short>(_Vector<16, int>, _Vector<16, int>)">; @@ -1349,6 +1293,11 @@ let Features = "avx512bw", Attributes = [NoThrow, Const, Constexpr, RequiredVect def packusdw512 : X86Builtin<"_Vector<32, short>(_Vector<16, int>, _Vector<16, int>)">; def pshufb512 : X86Builtin<"_Vector<64, char>(_Vector<64, char>, _Vector<64, char>)">; + + def cmpb512_mask : X86Builtin<"unsigned long long int(_Vector<64, char>, _Vector<64, char>, _Constant int, unsigned long long int)">; + def cmpw512_mask : X86Builtin<"unsigned int(_Vector<32, short>, _Vector<32, short>, _Constant int, unsigned int)">; + def ucmpb512_mask : X86Builtin<"unsigned long long int(_Vector<64, char>, _Vector<64, char>, _Constant int, unsigned long long int)">; + def ucmpw512_mask : X86Builtin<"unsigned int(_Vector<32, short>, _Vector<32, short>, _Constant int, unsigned int)">; } let Features = "avx512cd,avx512vl", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<128>] in { @@ -1397,7 +1346,6 @@ let Features = "avx512f", Attributes = [NoThrow, Const, RequiredVectorWidth<512> def subps512 : X86Builtin<"_Vector<16, float>(_Vector<16, float>, _Vector<16, float>, _Constant int)">; } - let Features = "avx512f", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in { def addss_round_mask : X86Builtin<"_Vector<4, float>(_Vector<4, float>, _Vector<4, float>, _Vector<4, float>, unsigned char, _Constant int)">; def divss_round_mask : X86Builtin<"_Vector<4, float>(_Vector<4, float>, _Vector<4, float>, _Vector<4, float>, unsigned char, _Constant int)">; From a54edafa02bb4c11c1e4425c7da1e34864c9fde2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolai=20H=C3=A4hnle?= Date: Sun, 23 Nov 2025 08:46:14 -0800 Subject: [PATCH 06/10] ADT: Complete the at() methods for DenseMap and MapVector (#169147) Make it easier to use these containers as drop-in replacements for std::map. --- llvm/include/llvm/ADT/DenseMap.h | 8 ++++++++ llvm/include/llvm/ADT/MapVector.h | 22 ++++++++++++++++++---- llvm/unittests/ADT/DenseMapTest.cpp | 8 ++++++++ llvm/unittests/ADT/MapVectorTest.cpp | 15 +++++++++++++++ 4 files changed, 49 insertions(+), 4 deletions(-) diff --git a/llvm/include/llvm/ADT/DenseMap.h b/llvm/include/llvm/ADT/DenseMap.h index a706f68fab81b..fe8868619730e 100644 --- a/llvm/include/llvm/ADT/DenseMap.h +++ b/llvm/include/llvm/ADT/DenseMap.h @@ -219,6 +219,14 @@ class DenseMapBase : public DebugEpochBase { return Default; } + /// at - Return the entry for the specified key, or abort if no such + /// entry exists. + [[nodiscard]] ValueT &at(const_arg_type_t Val) { + auto Iter = this->find(std::move(Val)); + assert(Iter != this->end() && "DenseMap::at failed due to a missing key"); + return Iter->second; + } + /// at - Return the entry for the specified key, or abort if no such /// entry exists. [[nodiscard]] const ValueT &at(const_arg_type_t Val) const { diff --git a/llvm/include/llvm/ADT/MapVector.h b/llvm/include/llvm/ADT/MapVector.h index 82f2c4977e01d..80bcb7e0b7ba4 100644 --- a/llvm/include/llvm/ADT/MapVector.h +++ b/llvm/include/llvm/ADT/MapVector.h @@ -148,14 +148,28 @@ class MapVector { [[nodiscard]] iterator find(const KeyT &Key) { typename MapType::const_iterator Pos = Map.find(Key); - return Pos == Map.end()? Vector.end() : - (Vector.begin() + Pos->second); + return Pos == Map.end() ? Vector.end() : (Vector.begin() + Pos->second); } [[nodiscard]] const_iterator find(const KeyT &Key) const { typename MapType::const_iterator Pos = Map.find(Key); - return Pos == Map.end()? Vector.end() : - (Vector.begin() + Pos->second); + return Pos == Map.end() ? Vector.end() : (Vector.begin() + Pos->second); + } + + /// at - Return the entry for the specified key, or abort if no such + /// entry exists. + [[nodiscard]] ValueT &at(const KeyT &Key) { + auto Pos = Map.find(Key); + assert(Pos != Map.end() && "MapVector::at failed due to a missing key"); + return Vector[Pos->second].second; + } + + /// at - Return the entry for the specified key, or abort if no such + /// entry exists. + [[nodiscard]] const ValueT &at(const KeyT &Key) const { + auto Pos = Map.find(Key); + assert(Pos != Map.end() && "MapVector::at failed due to a missing key"); + return Vector[Pos->second].second; } /// Remove the last element from the vector. diff --git a/llvm/unittests/ADT/DenseMapTest.cpp b/llvm/unittests/ADT/DenseMapTest.cpp index 273ee09fc1e28..553d159d33b1a 100644 --- a/llvm/unittests/ADT/DenseMapTest.cpp +++ b/llvm/unittests/ADT/DenseMapTest.cpp @@ -200,6 +200,14 @@ TYPED_TEST(DenseMapTest, AtTest) { EXPECT_EQ(this->getValue(0), this->Map.at(this->getKey(0))); EXPECT_EQ(this->getValue(1), this->Map.at(this->getKey(1))); EXPECT_EQ(this->getValue(2), this->Map.at(this->getKey(2))); + + this->Map.at(this->getKey(0)) = this->getValue(1); + EXPECT_EQ(this->getValue(1), this->Map.at(this->getKey(0))); + + const auto &ConstMap = this->Map; + EXPECT_EQ(this->getValue(1), ConstMap.at(this->getKey(0))); + EXPECT_EQ(this->getValue(1), ConstMap.at(this->getKey(1))); + EXPECT_EQ(this->getValue(2), ConstMap.at(this->getKey(2))); } // Test clear() method diff --git a/llvm/unittests/ADT/MapVectorTest.cpp b/llvm/unittests/ADT/MapVectorTest.cpp index 639e1a14e8178..e0589445e3271 100644 --- a/llvm/unittests/ADT/MapVectorTest.cpp +++ b/llvm/unittests/ADT/MapVectorTest.cpp @@ -292,6 +292,21 @@ TEST(MapVectorTest, GetArrayRef) { EXPECT_TRUE(MV.getArrayRef().equals({std::pair(100, 99), std::pair(99, 98)})); } +TEST(MapVectorTest, AtTest) { + MapVector MV; + MV[0] = 10; + MV[1] = 11; + EXPECT_EQ(MV.at(0), 10); + EXPECT_EQ(MV.at(1), 11); + + MV.at(1) = 12; + EXPECT_EQ(MV.at(1), 12); + + const auto &ConstMV = MV; + EXPECT_EQ(ConstMV.at(0), 10); + EXPECT_EQ(ConstMV.at(1), 12); +} + template struct MapVectorMappedTypeTest : ::testing::Test { using int_type = IntType; }; From 8b7401f13d89fe7e1815a7ab95209afe49493d72 Mon Sep 17 00:00:00 2001 From: Simon Pilgrim Date: Sun, 23 Nov 2025 16:46:23 +0000 Subject: [PATCH 07/10] Fix MSVC "not all control paths return a value" warning. NFC. (#169222) --- llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.cpp b/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.cpp index d6d63f3b6198d..baeab6a33ff6a 100644 --- a/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.cpp +++ b/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.cpp @@ -183,6 +183,7 @@ bool AArch64FunctionInfo::shouldSignReturnAddress(SignReturnAddress Condition, case SignReturnAddress::All: return true; } + llvm_unreachable("Unknown SignReturnAddress enum"); } bool AArch64FunctionInfo::shouldSignReturnAddress( From 3773bbe9e7916ec89fb3e3cd02e29c54cabac82b Mon Sep 17 00:00:00 2001 From: Naveen Seth Hanig Date: Sun, 23 Nov 2025 17:55:36 +0100 Subject: [PATCH 08/10] [clang] Refactor to remove clangDriver dependency from clangFrontend and flangFrontend (#165277) This removes the dependency on clangDriver from clangFrontend and flangFrontend. This refactoring is part of a broader effort to support driver-managed builds for compilations using C++ named modules and/or Clang modules. It is required for linking the dependency scanning tooling against the driver without introducing cyclic dependencies, which would otherwise cause build failures when dynamic linking is enabled. In particular, clangFrontend must no longer depend on clangDriver for this to be possible. This change was discussed in the following RFC: https://discourse.llvm.org/t/rfc-new-clangoptions-library-remove-dependency-on-clangdriver-from-clangfrontend-and-flangfrontend/88773 --- clang-tools-extra/clangd/CompileCommands.cpp | 3 +- clang-tools-extra/clangd/Compiler.cpp | 1 + clang/docs/ReleaseNotes.rst | 2 + clang/include/clang/Driver/CommonArgs.h | 10 - .../clang/Driver/CreateASTUnitFromArgs.h | 80 ++++ .../clang/Driver/CreateInvocationFromArgs.h | 76 ++++ clang/include/clang/Driver/Driver.h | 5 - clang/include/clang/Frontend/ASTUnit.h | 146 ++++---- .../Frontend/ChainedDiagnosticConsumer.h | 2 +- .../clang/Frontend/CompilerInvocation.h | 10 - .../clang/Frontend/StandaloneDiagnostic.h | 82 +++++ clang/include/clang/Frontend/Utils.h | 45 --- clang/include/clang/Options/OptionUtils.h | 24 ++ clang/lib/CrossTU/CMakeLists.txt | 1 + clang/lib/CrossTU/CrossTranslationUnit.cpp | 3 +- clang/lib/Driver/CMakeLists.txt | 4 + clang/lib/Driver/CreateASTUnitFromArgs.cpp | 166 +++++++++ .../CreateInvocationFromArgs.cpp} | 15 +- clang/lib/Driver/Driver.cpp | 35 +- clang/lib/Driver/ToolChains/Clang.cpp | 1 + clang/lib/Driver/ToolChains/CommonArgs.cpp | 163 --------- clang/lib/Driver/ToolChains/Flang.cpp | 1 + clang/lib/Frontend/ASTUnit.cpp | 346 +++--------------- clang/lib/Frontend/CMakeLists.txt | 3 +- clang/lib/Frontend/CompilerInvocation.cpp | 7 - clang/lib/Frontend/StandaloneDiagnostic.cpp | 117 ++++++ clang/lib/Interpreter/CMakeLists.txt | 1 + clang/lib/Interpreter/Interpreter.cpp | 3 +- clang/lib/Options/OptionUtils.cpp | 215 ++++++++++- clang/lib/Tooling/Tooling.cpp | 4 +- clang/tools/c-index-test/CMakeLists.txt | 1 + clang/tools/c-index-test/core_main.cpp | 1 + clang/tools/diagtool/CMakeLists.txt | 1 + clang/tools/diagtool/ShowEnabledWarnings.cpp | 1 + clang/tools/driver/cc1_main.cpp | 3 +- clang/tools/libclang/CIndex.cpp | 3 +- clang/tools/libclang/CIndexer.cpp | 3 +- clang/tools/libclang/CMakeLists.txt | 1 + clang/tools/libclang/Indexing.cpp | 1 + clang/unittests/Driver/DXCModeTest.cpp | 1 + clang/unittests/Driver/ToolChainTest.cpp | 1 + clang/unittests/Frontend/ASTUnitTest.cpp | 6 +- .../Frontend/CompilerInstanceTest.cpp | 1 + clang/unittests/Frontend/UtilsTest.cpp | 1 + clang/unittests/Sema/CMakeLists.txt | 1 + clang/unittests/Sema/SemaNoloadLookupTest.cpp | 1 + .../Serialization/ForceCheckFileInputTest.cpp | 1 + .../Serialization/LoadSpecLazilyTest.cpp | 1 + .../Serialization/ModuleCacheTest.cpp | 1 + .../Serialization/NoCommentsTest.cpp | 1 + .../PreambleInNamedModulesTest.cpp | 1 + .../Serialization/VarDeclConstantInitTest.cpp | 1 + clang/unittests/Tooling/Syntax/TokensTest.cpp | 1 + .../unittests/Tooling/Syntax/TreeTestBase.cpp | 1 + flang/lib/Frontend/CMakeLists.txt | 1 - flang/lib/Frontend/CompilerInvocation.cpp | 5 +- lldb/source/Commands/CommandObjectTarget.cpp | 1 + .../ExpressionParser/Clang/CMakeLists.txt | 2 +- .../ExpressionParser/Clang/ClangHost.cpp | 4 +- .../Clang/ClangModulesDeclVendor.cpp | 1 + lldb/unittests/Expression/ClangParserTest.cpp | 4 +- 61 files changed, 937 insertions(+), 687 deletions(-) create mode 100644 clang/include/clang/Driver/CreateASTUnitFromArgs.h create mode 100644 clang/include/clang/Driver/CreateInvocationFromArgs.h create mode 100644 clang/include/clang/Frontend/StandaloneDiagnostic.h create mode 100644 clang/lib/Driver/CreateASTUnitFromArgs.cpp rename clang/lib/{Frontend/CreateInvocationFromCommandLine.cpp => Driver/CreateInvocationFromArgs.cpp} (93%) create mode 100644 clang/lib/Frontend/StandaloneDiagnostic.cpp diff --git a/clang-tools-extra/clangd/CompileCommands.cpp b/clang-tools-extra/clangd/CompileCommands.cpp index 7990f2719e9a0..4eda330716f21 100644 --- a/clang-tools-extra/clangd/CompileCommands.cpp +++ b/clang-tools-extra/clangd/CompileCommands.cpp @@ -132,8 +132,7 @@ std::optional detectSysroot() { std::string detectStandardResourceDir() { static int StaticForMainAddr; // Just an address in this process. - return CompilerInvocation::GetResourcesPath("clangd", - (void *)&StaticForMainAddr); + return GetResourcesPath("clangd", (void *)&StaticForMainAddr); } // The path passed to argv[0] is important: diff --git a/clang-tools-extra/clangd/Compiler.cpp b/clang-tools-extra/clangd/Compiler.cpp index 6ebc2eac25745..9ea7df139382a 100644 --- a/clang-tools-extra/clangd/Compiler.cpp +++ b/clang-tools-extra/clangd/Compiler.cpp @@ -9,6 +9,7 @@ #include "Compiler.h" #include "support/Logger.h" #include "clang/Basic/TargetInfo.h" +#include "clang/Driver/CreateInvocationFromArgs.h" #include "clang/Frontend/CompilerInvocation.h" #include "clang/Lex/PreprocessorOptions.h" #include "clang/Serialization/PCHContainerOperations.h" diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 8161ccdffca82..439e47b209b2f 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -84,6 +84,8 @@ Potentially Breaking Changes - Downstream projects that previously linked only against ``clangDriver`` may now (also) need to link against the new ``clangOptions`` library, since options-related code has been moved out of the Driver into a separate library. +- The ``clangFrontend`` library no longer depends on ``clangDriver``, which may + break downstream projects that relied on this transitive dependency. C/C++ Language Potentially Breaking Changes ------------------------------------------- diff --git a/clang/include/clang/Driver/CommonArgs.h b/clang/include/clang/Driver/CommonArgs.h index ac17d6211d882..264bd4965f9ad 100644 --- a/clang/include/clang/Driver/CommonArgs.h +++ b/clang/include/clang/Driver/CommonArgs.h @@ -291,16 +291,6 @@ void handleVectorizeLoopsArgs(const llvm::opt::ArgList &Args, void handleVectorizeSLPArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs); -// Parse -mprefer-vector-width=. Return the Value string if well-formed. -// Otherwise, return an empty string and issue a diagnosic message if needed. -StringRef parseMPreferVectorWidthOption(clang::DiagnosticsEngine &Diags, - const llvm::opt::ArgList &Args); - -// Parse -mrecip. Return the Value string if well-formed. -// Otherwise, return an empty string and issue a diagnosic message if needed. -StringRef parseMRecipOption(clang::DiagnosticsEngine &Diags, - const llvm::opt::ArgList &Args); - // Convert ComplexRangeKind to a string that can be passed as a frontend option. std::string complexRangeKindToStr(LangOptions::ComplexRangeKind Range); diff --git a/clang/include/clang/Driver/CreateASTUnitFromArgs.h b/clang/include/clang/Driver/CreateASTUnitFromArgs.h new file mode 100644 index 0000000000000..30575cc04ca7c --- /dev/null +++ b/clang/include/clang/Driver/CreateASTUnitFromArgs.h @@ -0,0 +1,80 @@ +//===-- CreateInvocationFromArgs.h - Create an ASTUnit from Args-*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Utility for creating an ASTUnit from a vector of command line arguments. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_DRIVER_CREATEASTUNITFROMARGS_H +#define LLVM_CLANG_DRIVER_CREATEASTUNITFROMARGS_H + +#include "clang/Frontend/ASTUnit.h" + +namespace clang { + +/// Create an ASTUnit from a vector of command line arguments, which must +/// specify exactly one source file. +/// +/// \param ArgBegin - The beginning of the argument vector. +/// +/// \param ArgEnd - The end of the argument vector. +/// +/// \param PCHContainerOps - The PCHContainerOperations to use for loading and +/// creating modules. +/// +/// \param Diags - The diagnostics engine to use for reporting errors; its +/// lifetime is expected to extend past that of the returned ASTUnit. +/// +/// \param ResourceFilesPath - The path to the compiler resource files. +/// +/// \param StorePreamblesInMemory - Whether to store PCH in memory. If false, +/// PCH are stored in temporary files. +/// +/// \param PreambleStoragePath - The path to a directory, in which to create +/// temporary PCH files. If empty, the default system temporary directory is +/// used. This parameter is ignored if \p StorePreamblesInMemory is true. +/// +/// \param ModuleFormat - If provided, uses the specific module format. +/// +/// \param ErrAST - If non-null and parsing failed without any AST to return +/// (e.g. because the PCH could not be loaded), this accepts the ASTUnit +/// mainly to allow the caller to see the diagnostics. +/// +/// \param VFS - A llvm::vfs::FileSystem to be used for all file accesses. +/// Note that preamble is saved to a temporary directory on a RealFileSystem, +/// so in order for it to be loaded correctly, VFS should have access to +/// it(i.e., be an overlay over RealFileSystem). RealFileSystem will be used +/// if \p VFS is nullptr. +/// +// FIXME: Move OnlyLocalDecls, UseBumpAllocator to setters on the ASTUnit, we +// shouldn't need to specify them at construction time. +std::unique_ptr CreateASTUnitFromCommandLine( + const char **ArgBegin, const char **ArgEnd, + std::shared_ptr PCHContainerOps, + std::shared_ptr DiagOpts, + IntrusiveRefCntPtr Diags, StringRef ResourceFilesPath, + bool StorePreamblesInMemory = false, + StringRef PreambleStoragePath = StringRef(), bool OnlyLocalDecls = false, + CaptureDiagsKind CaptureDiagnostics = CaptureDiagsKind::None, + ArrayRef RemappedFiles = {}, + bool RemappedFilesKeepOriginalName = true, + unsigned PrecompilePreambleAfterNParses = 0, + TranslationUnitKind TUKind = TU_Complete, + bool CacheCodeCompletionResults = false, + bool IncludeBriefCommentsInCodeCompletion = false, + bool AllowPCHWithCompilerErrors = false, + SkipFunctionBodiesScope SkipFunctionBodies = SkipFunctionBodiesScope::None, + bool SingleFileParse = false, bool UserFilesAreVolatile = false, + bool ForSerialization = false, bool RetainExcludedConditionalBlocks = false, + std::optional ModuleFormat = std::nullopt, + std::unique_ptr *ErrAST = nullptr, + IntrusiveRefCntPtr VFS = nullptr); + +} // namespace clang + +#endif // LLVM_CLANG_DRIVER_CREATEASTUNITFROMARGS_H diff --git a/clang/include/clang/Driver/CreateInvocationFromArgs.h b/clang/include/clang/Driver/CreateInvocationFromArgs.h new file mode 100644 index 0000000000000..0e0f67373ce87 --- /dev/null +++ b/clang/include/clang/Driver/CreateInvocationFromArgs.h @@ -0,0 +1,76 @@ +//===--- CreateInvocationFromArgs.h - CompilerInvocation from Args --------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Utility for creating a CompilerInvocation from command-line arguments, for +// tools to use in preparation to parse a file. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_DRIVER_CREATEINVOCATIONFROMARGS_H +#define LLVM_CLANG_DRIVER_CREATEINVOCATIONFROMARGS_H + +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/LLVM.h" +#include "llvm/Support/VirtualFileSystem.h" +#include +#include +#include + +namespace clang { + +class CompilerInvocation; +class DiagnosticsEngine; + +/// Optional inputs to createInvocation. +struct CreateInvocationOptions { + /// Receives diagnostics encountered while parsing command-line flags. + /// If not provided, these are printed to stderr. + IntrusiveRefCntPtr Diags = nullptr; + /// Used e.g. to probe for system headers locations. + /// If not provided, the real filesystem is used. + /// FIXME: the driver does perform some non-virtualized IO. + IntrusiveRefCntPtr VFS = nullptr; + /// Whether to attempt to produce a non-null (possibly incorrect) invocation + /// if any errors were encountered. + /// By default, always return null on errors. + bool RecoverOnError = false; + /// Allow the driver to probe the filesystem for PCH files. + /// This is used to replace -include with -include-pch in the cc1 args. + /// FIXME: ProbePrecompiled=true is a poor, historical default. + /// It misbehaves if the PCH file is from GCC, has the wrong version, etc. + bool ProbePrecompiled = false; + /// If set, the target is populated with the cc1 args produced by the driver. + /// This may be populated even if createInvocation returns nullptr. + std::vector *CC1Args = nullptr; +}; + +/// Interpret clang arguments in preparation to parse a file. +/// +/// This simulates a number of steps Clang takes when its driver is invoked: +/// - choosing actions (e.g compile + link) to run +/// - probing the system for settings like standard library locations +/// - spawning a cc1 subprocess to compile code, with more explicit arguments +/// - in the cc1 process, assembling those arguments into a CompilerInvocation +/// which is used to configure the parser +/// +/// This simulation is lossy, e.g. in some situations one driver run would +/// result in multiple parses. (Multi-arch, CUDA, ...). +/// This function tries to select a reasonable invocation that tools should use. +/// +/// Args[0] should be the driver name, such as "clang" or "/usr/bin/g++". +/// Absolute path is preferred - this affects searching for system headers. +/// +/// May return nullptr if an invocation could not be determined. +/// See CreateInvocationOptions::RecoverOnError to try harder! +std::unique_ptr +createInvocation(ArrayRef Args, + CreateInvocationOptions Opts = {}); + +} // namespace clang + +#endif // LLVM_CLANG_DRIVER_CREATEINVOCATIONFROMARGS_H diff --git a/clang/include/clang/Driver/Driver.h b/clang/include/clang/Driver/Driver.h index aa86bffb802a4..76a6c5a128efb 100644 --- a/clang/include/clang/Driver/Driver.h +++ b/clang/include/clang/Driver/Driver.h @@ -406,11 +406,6 @@ class Driver { SmallString<128> &CrashDiagDir); public: - - /// Takes the path to a binary that's either in bin/ or lib/ and returns - /// the path to clang's resource directory. - static std::string GetResourcesPath(StringRef BinaryPath); - Driver(StringRef ClangExecutable, StringRef TargetTriple, DiagnosticsEngine &Diags, std::string Title = "clang LLVM compiler", IntrusiveRefCntPtr VFS = nullptr); diff --git a/clang/include/clang/Frontend/ASTUnit.h b/clang/include/clang/Frontend/ASTUnit.h index 3cea159afa33c..341460e1962cb 100644 --- a/clang/include/clang/Frontend/ASTUnit.h +++ b/clang/include/clang/Frontend/ASTUnit.h @@ -22,12 +22,14 @@ #include "clang/Basic/SourceLocation.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetOptions.h" +#include "clang/Frontend/PrecompiledPreamble.h" +#include "clang/Frontend/StandaloneDiagnostic.h" #include "clang/Lex/HeaderSearchOptions.h" #include "clang/Lex/ModuleLoader.h" #include "clang/Lex/PreprocessingRecord.h" #include "clang/Sema/CodeCompleteConsumer.h" #include "clang/Serialization/ASTBitCodes.h" -#include "clang/Frontend/PrecompiledPreamble.h" +#include "clang/Serialization/ASTWriter.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/IntrusiveRefCntPtr.h" @@ -36,6 +38,7 @@ #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/iterator_range.h" +#include "llvm/Bitstream/BitstreamWriter.h" #include #include #include @@ -88,25 +91,6 @@ enum class CaptureDiagsKind { None, All, AllWithoutNonErrorsFromIncludes }; /// Utility class for loading a ASTContext from an AST file. class ASTUnit { -public: - struct StandaloneFixIt { - std::pair RemoveRange; - std::pair InsertFromRange; - std::string CodeToInsert; - bool BeforePreviousInsertions; - }; - - struct StandaloneDiagnostic { - unsigned ID; - DiagnosticsEngine::Level Level; - std::string Message; - std::string Filename; - unsigned LocOffset; - std::vector> Ranges; - std::vector FixIts; - }; - -private: std::unique_ptr LangOpts; std::unique_ptr CodeGenOpts; // FIXME: The documentation on \c LoadFrom* member functions states that the @@ -129,7 +113,15 @@ class ASTUnit { bool HadModuleLoaderFatalFailure = false; bool StorePreamblesInMemory = false; - struct ASTWriterData; + /// Utility struct for managing ASTWriter and its associated data streams. + struct ASTWriterData { + SmallString<128> Buffer; + llvm::BitstreamWriter Stream; + ASTWriter Writer; + + ASTWriterData(ModuleCache &ModCache, const CodeGenOptions &CGOpts) + : Stream(Buffer), Writer(Stream, Buffer, ModCache, CGOpts, {}) {} + }; std::unique_ptr WriterData; FileSystemOptions FileSystemOpts; @@ -271,11 +263,6 @@ class ASTUnit { static void ConfigureDiags(IntrusiveRefCntPtr Diags, ASTUnit &AST, CaptureDiagsKind CaptureDiagnostics); - void TranslateStoredDiagnostics(FileManager &FileMgr, - SourceManager &SrcMan, - const SmallVectorImpl &Diags, - SmallVectorImpl &Out); - void clearFileLevelDecls(); public: @@ -834,65 +821,24 @@ class ASTUnit { bool IncludeBriefCommentsInCodeCompletion = false, bool UserFilesAreVolatile = false); - /// LoadFromCommandLine - Create an ASTUnit from a vector of command line - /// arguments, which must specify exactly one source file. - /// - /// \param ArgBegin - The beginning of the argument vector. - /// - /// \param ArgEnd - The end of the argument vector. - /// - /// \param PCHContainerOps - The PCHContainerOperations to use for loading and - /// creating modules. - /// - /// \param Diags - The diagnostics engine to use for reporting errors; its - /// lifetime is expected to extend past that of the returned ASTUnit. - /// - /// \param ResourceFilesPath - The path to the compiler resource files. - /// - /// \param StorePreamblesInMemory - Whether to store PCH in memory. If false, - /// PCH are stored in temporary files. - /// - /// \param PreambleStoragePath - The path to a directory, in which to create - /// temporary PCH files. If empty, the default system temporary directory is - /// used. This parameter is ignored if \p StorePreamblesInMemory is true. - /// - /// \param ModuleFormat - If provided, uses the specific module format. - /// - /// \param ErrAST - If non-null and parsing failed without any AST to return - /// (e.g. because the PCH could not be loaded), this accepts the ASTUnit - /// mainly to allow the caller to see the diagnostics. - /// - /// \param VFS - A llvm::vfs::FileSystem to be used for all file accesses. - /// Note that preamble is saved to a temporary directory on a RealFileSystem, - /// so in order for it to be loaded correctly, VFS should have access to - /// it(i.e., be an overlay over RealFileSystem). RealFileSystem will be used - /// if \p VFS is nullptr. - /// - // FIXME: Move OnlyLocalDecls, UseBumpAllocator to setters on the ASTUnit, we - // shouldn't need to specify them at construction time. - static std::unique_ptr LoadFromCommandLine( + friend std::unique_ptr CreateASTUnitFromCommandLine( const char **ArgBegin, const char **ArgEnd, std::shared_ptr PCHContainerOps, std::shared_ptr DiagOpts, IntrusiveRefCntPtr Diags, StringRef ResourceFilesPath, - bool StorePreamblesInMemory = false, - StringRef PreambleStoragePath = StringRef(), bool OnlyLocalDecls = false, - CaptureDiagsKind CaptureDiagnostics = CaptureDiagsKind::None, - ArrayRef RemappedFiles = {}, - bool RemappedFilesKeepOriginalName = true, - unsigned PrecompilePreambleAfterNParses = 0, - TranslationUnitKind TUKind = TU_Complete, - bool CacheCodeCompletionResults = false, - bool IncludeBriefCommentsInCodeCompletion = false, - bool AllowPCHWithCompilerErrors = false, - SkipFunctionBodiesScope SkipFunctionBodies = - SkipFunctionBodiesScope::None, - bool SingleFileParse = false, bool UserFilesAreVolatile = false, - bool ForSerialization = false, - bool RetainExcludedConditionalBlocks = false, - std::optional ModuleFormat = std::nullopt, - std::unique_ptr *ErrAST = nullptr, - IntrusiveRefCntPtr VFS = nullptr); + bool StorePreamblesInMemory, StringRef PreambleStoragePath, + bool OnlyLocalDecls, CaptureDiagsKind CaptureDiagnostics, + ArrayRef RemappedFiles, + bool RemappedFilesKeepOriginalName, + unsigned PrecompilePreambleAfterNParses, TranslationUnitKind TUKind, + bool CacheCodeCompletionResults, + bool IncludeBriefCommentsInCodeCompletion, + bool AllowPCHWithCompilerErrors, + SkipFunctionBodiesScope SkipFunctionBodies, bool SingleFileParse, + bool UserFilesAreVolatile, bool ForSerialization, + bool RetainExcludedConditionalBlocks, + std::optional ModuleFormat, std::unique_ptr *ErrAST, + IntrusiveRefCntPtr VFS); /// Reparse the source files using the same command-line options that /// were originally used to produce this translation unit. @@ -963,6 +909,44 @@ class ASTUnit { bool serialize(raw_ostream &OS); }; +/// Diagnostic consumer that saves each diagnostic it is given. +class FilterAndStoreDiagnosticConsumer : public DiagnosticConsumer { + SmallVectorImpl *StoredDiags; + SmallVectorImpl *StandaloneDiags; + bool CaptureNonErrorsFromIncludes = true; + const LangOptions *LangOpts = nullptr; + SourceManager *SourceMgr = nullptr; + +public: + FilterAndStoreDiagnosticConsumer( + SmallVectorImpl *StoredDiags, + SmallVectorImpl *StandaloneDiags, + bool CaptureNonErrorsFromIncludes); + + void BeginSourceFile(const LangOptions &LangOpts, + const Preprocessor *PP = nullptr) override; + + void HandleDiagnostic(DiagnosticsEngine::Level Level, + const Diagnostic &Info) override; +}; + +/// RAII object that optionally captures and filters diagnostics, if +/// there is no diagnostic client to capture them already. +class CaptureDroppedDiagnostics { + DiagnosticsEngine &Diags; + FilterAndStoreDiagnosticConsumer Client; + DiagnosticConsumer *PreviousClient = nullptr; + std::unique_ptr OwningPreviousClient; + +public: + CaptureDroppedDiagnostics( + CaptureDiagsKind CaptureDiagnostics, DiagnosticsEngine &Diags, + SmallVectorImpl *StoredDiags, + SmallVectorImpl *StandaloneDiags); + + ~CaptureDroppedDiagnostics(); +}; + } // namespace clang #endif // LLVM_CLANG_FRONTEND_ASTUNIT_H diff --git a/clang/include/clang/Frontend/ChainedDiagnosticConsumer.h b/clang/include/clang/Frontend/ChainedDiagnosticConsumer.h index ca284560754fd..839b5e7fa0a3e 100644 --- a/clang/include/clang/Frontend/ChainedDiagnosticConsumer.h +++ b/clang/include/clang/Frontend/ChainedDiagnosticConsumer.h @@ -66,6 +66,6 @@ class ChainedDiagnosticConsumer : public DiagnosticConsumer { } }; -} // end namspace clang +} // namespace clang #endif diff --git a/clang/include/clang/Frontend/CompilerInvocation.h b/clang/include/clang/Frontend/CompilerInvocation.h index b19a6e1a8acc3..4977ddb307d21 100644 --- a/clang/include/clang/Frontend/CompilerInvocation.h +++ b/clang/include/clang/Frontend/CompilerInvocation.h @@ -299,16 +299,6 @@ class CompilerInvocation : public CompilerInvocationBase { DiagnosticsEngine &Diags, const char *Argv0 = nullptr); - /// Get the directory where the compiler headers - /// reside, relative to the compiler binary (found by the passed in - /// arguments). - /// - /// \param Argv0 - The program path (from argv[0]), for finding the builtin - /// compiler path. - /// \param MainAddr - The address of main (or some other function in the main - /// executable), for finding the builtin compiler path. - static std::string GetResourcesPath(const char *Argv0, void *MainAddr); - /// Populate \p Opts with the default set of pointer authentication-related /// options given \p LangOpts and \p Triple. /// diff --git a/clang/include/clang/Frontend/StandaloneDiagnostic.h b/clang/include/clang/Frontend/StandaloneDiagnostic.h new file mode 100644 index 0000000000000..c23d5f95e0c2f --- /dev/null +++ b/clang/include/clang/Frontend/StandaloneDiagnostic.h @@ -0,0 +1,82 @@ +//===--- StandaloneDiagnostic.h - Serializable Diagnostic -------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// A serializable diagnostic representation to retain diagnostics after their +// SourceManager has been destroyed. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_FRONTEND_STANDALONEDIAGNOSTICS_H +#define LLVM_CLANG_FRONTEND_STANDALONEDIAGNOSTICS_H + +#include "clang/Basic/DiagnosticIDs.h" +#include "clang/Basic/DiagnosticOptions.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/Specifiers.h" +#include "llvm/ADT/StringExtras.h" +#include +#include +#include + +namespace clang { + +/// Represents a StoredDiagnostic in a form that can be retained until after its +/// SourceManager has been destroyed. +/// +/// Source locations are stored as a combination of filename and offsets into +/// that file. +/// To report the diagnostic, it must first be translated back into a +/// StoredDiagnostic with a new associated SourceManager. +struct StandaloneDiagnostic { + /// Represents a CharSourceRange within a StandaloneDiagnostic. + struct SourceOffsetRange { + SourceOffsetRange(CharSourceRange Range, const SourceManager &SrcMgr, + const LangOptions &LangOpts); + + unsigned Begin = 0; + unsigned End = 0; + }; + + /// Represents a FixItHint within a StandaloneDiagnostic. + struct StandaloneFixIt { + StandaloneFixIt(const SourceManager &SrcMgr, const LangOptions &LangOpts, + const FixItHint &FixIt); + + SourceOffsetRange RemoveRange; + SourceOffsetRange InsertFromRange; + std::string CodeToInsert; + bool BeforePreviousInsertions; + }; + + StandaloneDiagnostic(const LangOptions &LangOpts, + const StoredDiagnostic &InDiag); + + DiagnosticsEngine::Level Level; + SrcMgr::CharacteristicKind FileKind; + unsigned ID = 0; + unsigned FileOffset = 0; + std::string Message; + std::string Filename; + std::vector Ranges; + std::vector FixIts; +}; + +/// Translates \c StandaloneDiag into a StoredDiagnostic, associating it with +/// the provided FileManager and SourceManager. +/// +/// This allows the diagnostic to be emitted using the diagnostics engine, since +/// StandaloneDiagnostics themselfs cannot be emitted directly. +StoredDiagnostic +translateStandaloneDiag(FileManager &FileMgr, SourceManager &SrcMgr, + const StandaloneDiagnostic &StandaloneDiag, + llvm::StringMap &SrcLocCache); + +} // namespace clang + +#endif // STANDALONEDIAGNOSTICS diff --git a/clang/include/clang/Frontend/Utils.h b/clang/include/clang/Frontend/Utils.h index ed2703c76f18d..1c561b47b5c47 100644 --- a/clang/include/clang/Frontend/Utils.h +++ b/clang/include/clang/Frontend/Utils.h @@ -192,51 +192,6 @@ IntrusiveRefCntPtr createChainedIncludesSource(CompilerInstance &CI, IntrusiveRefCntPtr &OutReader); -/// Optional inputs to createInvocation. -struct CreateInvocationOptions { - /// Receives diagnostics encountered while parsing command-line flags. - /// If not provided, these are printed to stderr. - IntrusiveRefCntPtr Diags = nullptr; - /// Used e.g. to probe for system headers locations. - /// If not provided, the real filesystem is used. - /// FIXME: the driver does perform some non-virtualized IO. - IntrusiveRefCntPtr VFS = nullptr; - /// Whether to attempt to produce a non-null (possibly incorrect) invocation - /// if any errors were encountered. - /// By default, always return null on errors. - bool RecoverOnError = false; - /// Allow the driver to probe the filesystem for PCH files. - /// This is used to replace -include with -include-pch in the cc1 args. - /// FIXME: ProbePrecompiled=true is a poor, historical default. - /// It misbehaves if the PCH file is from GCC, has the wrong version, etc. - bool ProbePrecompiled = false; - /// If set, the target is populated with the cc1 args produced by the driver. - /// This may be populated even if createInvocation returns nullptr. - std::vector *CC1Args = nullptr; -}; - -/// Interpret clang arguments in preparation to parse a file. -/// -/// This simulates a number of steps Clang takes when its driver is invoked: -/// - choosing actions (e.g compile + link) to run -/// - probing the system for settings like standard library locations -/// - spawning a cc1 subprocess to compile code, with more explicit arguments -/// - in the cc1 process, assembling those arguments into a CompilerInvocation -/// which is used to configure the parser -/// -/// This simulation is lossy, e.g. in some situations one driver run would -/// result in multiple parses. (Multi-arch, CUDA, ...). -/// This function tries to select a reasonable invocation that tools should use. -/// -/// Args[0] should be the driver name, such as "clang" or "/usr/bin/g++". -/// Absolute path is preferred - this affects searching for system headers. -/// -/// May return nullptr if an invocation could not be determined. -/// See CreateInvocationOptions::ShouldRecoverOnErrors to try harder! -std::unique_ptr -createInvocation(ArrayRef Args, - CreateInvocationOptions Opts = {}); - } // namespace clang #endif // LLVM_CLANG_FRONTEND_UTILS_H diff --git a/clang/include/clang/Options/OptionUtils.h b/clang/include/clang/Options/OptionUtils.h index 83c48bd7d6843..02c9c27554db1 100644 --- a/clang/include/clang/Options/OptionUtils.h +++ b/clang/include/clang/Options/OptionUtils.h @@ -28,6 +28,7 @@ class ArgList; } // namespace llvm namespace clang { + /// Return the value of the last argument as an integer, or a default. If Diags /// is non-null, emits an error if the argument is given, but non-integral. int getLastArgIntValue(const llvm::opt::ArgList &Args, @@ -53,6 +54,29 @@ inline uint64_t getLastArgUInt64Value(const llvm::opt::ArgList &Args, return getLastArgUInt64Value(Args, Id, Default, &Diags, Base); } +// Parse -mprefer-vector-width=. Return the Value string if well-formed. +// Otherwise, return an empty string and issue a diagnosic message if needed. +StringRef parseMPreferVectorWidthOption(clang::DiagnosticsEngine &Diags, + const llvm::opt::ArgList &Args); + +// Parse -mrecip. Return the Value string if well-formed. +// Otherwise, return an empty string and issue a diagnosic message if needed. +StringRef parseMRecipOption(clang::DiagnosticsEngine &Diags, + const llvm::opt::ArgList &Args); + +/// Get the directory where the compiler headers reside, relative to the +/// compiler binary path \p BinaryPath. +std::string GetResourcesPath(StringRef BinaryPath); + +/// Get the directory where the compiler headers reside, relative to the +/// compiler binary path (found by the passed in arguments). +/// +/// \param Argv0 The program path (from argv[0]), for finding the builtin +/// compiler path. +/// \param MainAddr The address of main (or some other function in the main +/// executable), for finding the builtin compiler path. +std::string GetResourcesPath(const char *Argv0, void *MainAddr); + } // namespace clang #endif // LLVM_CLANG_OPTIONS_OPTIONUTILS_H diff --git a/clang/lib/CrossTU/CMakeLists.txt b/clang/lib/CrossTU/CMakeLists.txt index 3349fc283925d..eef7a892701fb 100644 --- a/clang/lib/CrossTU/CMakeLists.txt +++ b/clang/lib/CrossTU/CMakeLists.txt @@ -9,6 +9,7 @@ add_clang_library(clangCrossTU LINK_LIBS clangAST clangBasic + clangDriver clangFrontend clangIndex ) diff --git a/clang/lib/CrossTU/CrossTranslationUnit.cpp b/clang/lib/CrossTU/CrossTranslationUnit.cpp index 0287845a741ed..a3fc2cf6bfb3c 100644 --- a/clang/lib/CrossTU/CrossTranslationUnit.cpp +++ b/clang/lib/CrossTU/CrossTranslationUnit.cpp @@ -16,6 +16,7 @@ #include "clang/Basic/DiagnosticDriver.h" #include "clang/Basic/TargetInfo.h" #include "clang/CrossTU/CrossTUDiagnostic.h" +#include "clang/Driver/CreateASTUnitFromArgs.h" #include "clang/Frontend/ASTUnit.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/TextDiagnosticPrinter.h" @@ -619,7 +620,7 @@ CrossTranslationUnitContext::ASTLoader::loadFromSource( auto Diags = llvm::makeIntrusiveRefCnt(DiagID, *DiagOpts, DiagClient); - return ASTUnit::LoadFromCommandLine( + return CreateASTUnitFromCommandLine( CommandLineArgs.begin(), (CommandLineArgs.end()), CI.getPCHContainerOperations(), DiagOpts, Diags, CI.getHeaderSearchOpts().ResourceDir); diff --git a/clang/lib/Driver/CMakeLists.txt b/clang/lib/Driver/CMakeLists.txt index 8052659e9836b..d987111827597 100644 --- a/clang/lib/Driver/CMakeLists.txt +++ b/clang/lib/Driver/CMakeLists.txt @@ -17,6 +17,8 @@ endif() add_clang_library(clangDriver Action.cpp Compilation.cpp + CreateASTUnitFromArgs.cpp + CreateInvocationFromArgs.cpp Distro.cpp Driver.cpp Job.cpp @@ -96,6 +98,8 @@ add_clang_library(clangDriver LINK_LIBS clangBasic + clangFrontend + clangSerialization clangLex clangOptions ${system_libs} diff --git a/clang/lib/Driver/CreateASTUnitFromArgs.cpp b/clang/lib/Driver/CreateASTUnitFromArgs.cpp new file mode 100644 index 0000000000000..ea31a8ed07c5f --- /dev/null +++ b/clang/lib/Driver/CreateASTUnitFromArgs.cpp @@ -0,0 +1,166 @@ +//===--- CreateASTUnitFromArgs.h - Create an ASTUnit from Args ------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Utility for creating an ASTUnit from a vector of command line arguments. +// +//===----------------------------------------------------------------------===// + +#include "clang/Driver/CreateASTUnitFromArgs.h" +#include "clang/Driver/CreateInvocationFromArgs.h" +#include "clang/Frontend/CompilerInvocation.h" +#include "clang/Lex/PreprocessorOptions.h" +#include "clang/Serialization/ModuleCache.h" +#include "llvm/Support/CrashRecoveryContext.h" + +using namespace clang; + +/// Create an ASTUnit from a vector of command line arguments, which must +/// specify exactly one source file. +/// +/// \param ArgBegin - The beginning of the argument vector. +/// +/// \param ArgEnd - The end of the argument vector. +/// +/// \param PCHContainerOps - The PCHContainerOperations to use for loading and +/// creating modules. +/// +/// \param Diags - The diagnostics engine to use for reporting errors; its +/// lifetime is expected to extend past that of the returned ASTUnit. +/// +/// \param ResourceFilesPath - The path to the compiler resource files. +/// +/// \param StorePreamblesInMemory - Whether to store PCH in memory. If false, +/// PCH are stored in temporary files. +/// +/// \param PreambleStoragePath - The path to a directory, in which to create +/// temporary PCH files. If empty, the default system temporary directory is +/// used. This parameter is ignored if \p StorePreamblesInMemory is true. +/// +/// \param ModuleFormat - If provided, uses the specific module format. +/// +/// \param ErrAST - If non-null and parsing failed without any AST to return +/// (e.g. because the PCH could not be loaded), this accepts the ASTUnit +/// mainly to allow the caller to see the diagnostics. +/// +/// \param VFS - A llvm::vfs::FileSystem to be used for all file accesses. +/// Note that preamble is saved to a temporary directory on a RealFileSystem, +/// so in order for it to be loaded correctly, VFS should have access to +/// it(i.e., be an overlay over RealFileSystem). RealFileSystem will be used +/// if \p VFS is nullptr. +/// +// FIXME: Move OnlyLocalDecls, UseBumpAllocator to setters on the ASTUnit, we +// shouldn't need to specify them at construction time. +std::unique_ptr clang::CreateASTUnitFromCommandLine( + const char **ArgBegin, const char **ArgEnd, + std::shared_ptr PCHContainerOps, + std::shared_ptr DiagOpts, + IntrusiveRefCntPtr Diags, StringRef ResourceFilesPath, + bool StorePreamblesInMemory, StringRef PreambleStoragePath, + bool OnlyLocalDecls, CaptureDiagsKind CaptureDiagnostics, + ArrayRef RemappedFiles, + bool RemappedFilesKeepOriginalName, unsigned PrecompilePreambleAfterNParses, + TranslationUnitKind TUKind, bool CacheCodeCompletionResults, + bool IncludeBriefCommentsInCodeCompletion, bool AllowPCHWithCompilerErrors, + SkipFunctionBodiesScope SkipFunctionBodies, bool SingleFileParse, + bool UserFilesAreVolatile, bool ForSerialization, + bool RetainExcludedConditionalBlocks, std::optional ModuleFormat, + std::unique_ptr *ErrAST, + IntrusiveRefCntPtr VFS) { + assert(Diags.get() && "no DiagnosticsEngine was provided"); + + // If no VFS was provided, create one that tracks the physical file system. + // If '-working-directory' was passed as an argument, 'createInvocation' will + // set this as the current working directory of the VFS. + if (!VFS) + VFS = llvm::vfs::createPhysicalFileSystem(); + + SmallVector StoredDiagnostics; + + std::shared_ptr CI; + + { + CaptureDroppedDiagnostics Capture(CaptureDiagnostics, *Diags, + &StoredDiagnostics, nullptr); + + CreateInvocationOptions CIOpts; + CIOpts.VFS = VFS; + CIOpts.Diags = Diags; + CIOpts.ProbePrecompiled = true; // FIXME: historical default. Needed? + CI = createInvocation(llvm::ArrayRef(ArgBegin, ArgEnd), std::move(CIOpts)); + if (!CI) + return nullptr; + } + + // Override any files that need remapping + for (const auto &RemappedFile : RemappedFiles) { + CI->getPreprocessorOpts().addRemappedFile(RemappedFile.first, + RemappedFile.second); + } + PreprocessorOptions &PPOpts = CI->getPreprocessorOpts(); + PPOpts.RemappedFilesKeepOriginalName = RemappedFilesKeepOriginalName; + PPOpts.AllowPCHWithCompilerErrors = AllowPCHWithCompilerErrors; + PPOpts.SingleFileParseMode = SingleFileParse; + PPOpts.RetainExcludedConditionalBlocks = RetainExcludedConditionalBlocks; + + // Override the resources path. + CI->getHeaderSearchOpts().ResourceDir = std::string(ResourceFilesPath); + + CI->getFrontendOpts().SkipFunctionBodies = + SkipFunctionBodies == SkipFunctionBodiesScope::PreambleAndMainFile; + + if (ModuleFormat) + CI->getHeaderSearchOpts().ModuleFormat = std::string(*ModuleFormat); + + // Create the AST unit. + std::unique_ptr AST; + AST.reset(new ASTUnit(false)); + AST->NumStoredDiagnosticsFromDriver = StoredDiagnostics.size(); + AST->StoredDiagnostics.swap(StoredDiagnostics); + ASTUnit::ConfigureDiags(Diags, *AST, CaptureDiagnostics); + AST->DiagOpts = DiagOpts; + AST->Diagnostics = Diags; + AST->FileSystemOpts = CI->getFileSystemOpts(); + AST->CodeGenOpts = std::make_unique(CI->getCodeGenOpts()); + VFS = createVFSFromCompilerInvocation(*CI, *Diags, VFS); + AST->FileMgr = + llvm::makeIntrusiveRefCnt(AST->FileSystemOpts, VFS); + AST->StorePreamblesInMemory = StorePreamblesInMemory; + AST->PreambleStoragePath = PreambleStoragePath; + AST->ModCache = createCrossProcessModuleCache(); + AST->OnlyLocalDecls = OnlyLocalDecls; + AST->CaptureDiagnostics = CaptureDiagnostics; + AST->TUKind = TUKind; + AST->ShouldCacheCodeCompletionResults = CacheCodeCompletionResults; + AST->IncludeBriefCommentsInCodeCompletion = + IncludeBriefCommentsInCodeCompletion; + AST->UserFilesAreVolatile = UserFilesAreVolatile; + AST->Invocation = CI; + AST->SkipFunctionBodies = SkipFunctionBodies; + if (ForSerialization) + AST->WriterData.reset( + new ASTUnit::ASTWriterData(*AST->ModCache, *AST->CodeGenOpts)); + // Zero out now to ease cleanup during crash recovery. + CI = nullptr; + Diags = nullptr; + + // Recover resources if we crash before exiting this method. + llvm::CrashRecoveryContextCleanupRegistrar ASTUnitCleanup(AST.get()); + + if (AST->LoadFromCompilerInvocation(std::move(PCHContainerOps), + PrecompilePreambleAfterNParses, VFS)) { + // Some error occurred, if caller wants to examine diagnostics, pass it the + // ASTUnit. + if (ErrAST) { + AST->StoredDiagnostics.swap(AST->FailedParseDiagnostics); + ErrAST->swap(AST); + } + return nullptr; + } + + return AST; +} diff --git a/clang/lib/Frontend/CreateInvocationFromCommandLine.cpp b/clang/lib/Driver/CreateInvocationFromArgs.cpp similarity index 93% rename from clang/lib/Frontend/CreateInvocationFromCommandLine.cpp rename to clang/lib/Driver/CreateInvocationFromArgs.cpp index 9db594bed1538..516d61f1a1159 100644 --- a/clang/lib/Frontend/CreateInvocationFromCommandLine.cpp +++ b/clang/lib/Driver/CreateInvocationFromArgs.cpp @@ -1,4 +1,4 @@ -//===--- CreateInvocationFromCommandLine.cpp - CompilerInvocation from Args ==// +//===--- CreateInvocationFromArgs.h - CompilerInvocation from Args --------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -10,9 +10,9 @@ // //===----------------------------------------------------------------------===// +#include "clang/Driver/CreateInvocationFromArgs.h" #include "clang/Basic/DiagnosticFrontend.h" #include "clang/Basic/DiagnosticOptions.h" -#include "clang/Driver/Action.h" #include "clang/Driver/Compilation.h" #include "clang/Driver/Driver.h" #include "clang/Driver/Tool.h" @@ -24,12 +24,13 @@ #include "llvm/Option/ArgList.h" #include "llvm/Support/VirtualFileSystem.h" #include "llvm/TargetParser/Host.h" -using namespace clang; + using namespace llvm::opt; +namespace clang { + std::unique_ptr -clang::createInvocation(ArrayRef ArgList, - CreateInvocationOptions Opts) { +createInvocation(ArrayRef ArgList, CreateInvocationOptions Opts) { assert(!ArgList.empty()); std::optional LocalDiagOpts; IntrusiveRefCntPtr Diags; @@ -78,7 +79,7 @@ clang::createInvocation(ArrayRef ArgList, const driver::JobList &Jobs = C->getJobs(); bool OffloadCompilation = false; if (Jobs.size() > 1) { - for (auto &A : C->getActions()){ + for (auto &A : C->getActions()) { // On MacOSX real actions may end up being wrapped in BindArchAction if (isa(A)) A = *A->input_begin(); @@ -114,3 +115,5 @@ clang::createInvocation(ArrayRef ArgList, return nullptr; return CI; } + +} // namespace clang diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp index de8d4601210ae..c6dd66d9efef3 100644 --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -66,6 +66,7 @@ #include "clang/Driver/ToolChain.h" #include "clang/Driver/Types.h" #include "clang/Lex/DependencyDirectivesScanner.h" +#include "clang/Options/OptionUtils.h" #include "clang/Options/Options.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/STLExtras.h" @@ -125,40 +126,6 @@ template static bool usesInput(const ArgList &Args, F &&Fn) { }); } -// static -std::string Driver::GetResourcesPath(StringRef BinaryPath) { - // Since the resource directory is embedded in the module hash, it's important - // that all places that need it call this function, so that they get the - // exact same string ("a/../b/" and "b/" get different hashes, for example). - - // Dir is bin/ or lib/, depending on where BinaryPath is. - StringRef Dir = llvm::sys::path::parent_path(BinaryPath); - SmallString<128> P(Dir); - - StringRef ConfiguredResourceDir(CLANG_RESOURCE_DIR); - if (!ConfiguredResourceDir.empty()) { - // FIXME: We should fix the behavior of llvm::sys::path::append so we don't - // need to check for absolute paths here. - if (llvm::sys::path::is_absolute(ConfiguredResourceDir)) - P = ConfiguredResourceDir; - else - llvm::sys::path::append(P, ConfiguredResourceDir); - } else { - // On Windows, libclang.dll is in bin/. - // On non-Windows, libclang.so/.dylib is in lib/. - // With a static-library build of libclang, LibClangPath will contain the - // path of the embedding binary, which for LLVM binaries will be in bin/. - // ../lib gets us to lib/ in both cases. - P = llvm::sys::path::parent_path(Dir); - // This search path is also created in the COFF driver of lld, so any - // changes here also needs to happen in lld/COFF/Driver.cpp - llvm::sys::path::append(P, CLANG_INSTALL_LIBDIR_BASENAME, "clang", - CLANG_VERSION_MAJOR_STRING); - } - - 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)) { diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index c5d40c9825fab..2f0aec3ec3c37 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -32,6 +32,7 @@ #include "clang/Driver/SanitizerArgs.h" #include "clang/Driver/Types.h" #include "clang/Driver/XRayArgs.h" +#include "clang/Options/OptionUtils.h" #include "clang/Options/Options.h" #include "llvm/ADT/ScopeExit.h" #include "llvm/ADT/SmallSet.h" diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp index 4c036f0f8dee3..d3539a594df11 100644 --- a/clang/lib/Driver/ToolChains/CommonArgs.cpp +++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp @@ -3398,169 +3398,6 @@ void tools::handleInterchangeLoopsArgs(const ArgList &Args, CmdArgs.push_back("-floop-interchange"); } -// Parse -mprefer-vector-width=. Return the Value string if well-formed. -// Otherwise, return an empty string and issue a diagnosic message if needed. -StringRef tools::parseMPreferVectorWidthOption(clang::DiagnosticsEngine &Diags, - const llvm::opt::ArgList &Args) { - Arg *A = Args.getLastArg(options::OPT_mprefer_vector_width_EQ); - if (!A) - return ""; - - StringRef Value = A->getValue(); - unsigned Width LLVM_ATTRIBUTE_UNINITIALIZED; - - // Only "none" and Integer values are accepted by - // -mprefer-vector-width=. - if (Value != "none" && Value.getAsInteger(10, Width)) { - Diags.Report(clang::diag::err_drv_invalid_value) - << A->getOption().getName() << Value; - return ""; - } - - return Value; -} - -// This is a helper function for validating the optional refinement step -// parameter in reciprocal argument strings. Return false if there is an error -// parsing the refinement step. Otherwise, return true and set the Position -// of the refinement step in the input string. -static bool getRefinementStep(StringRef In, clang::DiagnosticsEngine &Diags, - const Arg &A, size_t &Position) { - const char RefinementStepToken = ':'; - Position = In.find(RefinementStepToken); - if (Position != StringRef::npos) { - StringRef Option = A.getOption().getName(); - StringRef RefStep = In.substr(Position + 1); - // Allow exactly one numeric character for the additional refinement - // step parameter. This is reasonable for all currently-supported - // operations and architectures because we would expect that a larger value - // of refinement steps would cause the estimate "optimization" to - // under-perform the native operation. Also, if the estimate does not - // converge quickly, it probably will not ever converge, so further - // refinement steps will not produce a better answer. - if (RefStep.size() != 1) { - Diags.Report(diag::err_drv_invalid_value) << Option << RefStep; - return false; - } - char RefStepChar = RefStep[0]; - if (RefStepChar < '0' || RefStepChar > '9') { - Diags.Report(diag::err_drv_invalid_value) << Option << RefStep; - return false; - } - } - return true; -} - -// Parse -mrecip. Return the Value string if well-formed. -// Otherwise, return an empty string and issue a diagnosic message if needed. -StringRef tools::parseMRecipOption(clang::DiagnosticsEngine &Diags, - const ArgList &Args) { - StringRef DisabledPrefixIn = "!"; - StringRef DisabledPrefixOut = "!"; - StringRef EnabledPrefixOut = ""; - StringRef Out = ""; - - Arg *A = Args.getLastArg(options::OPT_mrecip, options::OPT_mrecip_EQ); - if (!A) - return ""; - - unsigned NumOptions = A->getNumValues(); - if (NumOptions == 0) { - // No option is the same as "all". - return "all"; - } - - // Pass through "all", "none", or "default" with an optional refinement step. - if (NumOptions == 1) { - StringRef Val = A->getValue(0); - size_t RefStepLoc; - if (!getRefinementStep(Val, Diags, *A, RefStepLoc)) - return ""; - StringRef ValBase = Val.slice(0, RefStepLoc); - if (ValBase == "all" || ValBase == "none" || ValBase == "default") { - return Val; - } - } - - // Each reciprocal type may be enabled or disabled individually. - // Check each input value for validity, concatenate them all back together, - // and pass through. - - llvm::StringMap OptionStrings; - OptionStrings.insert(std::make_pair("divd", false)); - OptionStrings.insert(std::make_pair("divf", false)); - OptionStrings.insert(std::make_pair("divh", false)); - OptionStrings.insert(std::make_pair("vec-divd", false)); - OptionStrings.insert(std::make_pair("vec-divf", false)); - OptionStrings.insert(std::make_pair("vec-divh", false)); - OptionStrings.insert(std::make_pair("sqrtd", false)); - OptionStrings.insert(std::make_pair("sqrtf", false)); - OptionStrings.insert(std::make_pair("sqrth", false)); - OptionStrings.insert(std::make_pair("vec-sqrtd", false)); - OptionStrings.insert(std::make_pair("vec-sqrtf", false)); - OptionStrings.insert(std::make_pair("vec-sqrth", false)); - - for (unsigned i = 0; i != NumOptions; ++i) { - StringRef Val = A->getValue(i); - - bool IsDisabled = Val.starts_with(DisabledPrefixIn); - // Ignore the disablement token for string matching. - if (IsDisabled) - Val = Val.substr(1); - - size_t RefStep; - if (!getRefinementStep(Val, Diags, *A, RefStep)) - return ""; - - StringRef ValBase = Val.slice(0, RefStep); - llvm::StringMap::iterator OptionIter = OptionStrings.find(ValBase); - if (OptionIter == OptionStrings.end()) { - // Try again specifying float suffix. - OptionIter = OptionStrings.find(ValBase.str() + 'f'); - if (OptionIter == OptionStrings.end()) { - // The input name did not match any known option string. - Diags.Report(diag::err_drv_unknown_argument) << Val; - return ""; - } - // The option was specified without a half or float or double suffix. - // Make sure that the double or half entry was not already specified. - // The float entry will be checked below. - if (OptionStrings[ValBase.str() + 'd'] || - OptionStrings[ValBase.str() + 'h']) { - Diags.Report(diag::err_drv_invalid_value) - << A->getOption().getName() << Val; - return ""; - } - } - - if (OptionIter->second == true) { - // Duplicate option specified. - Diags.Report(diag::err_drv_invalid_value) - << A->getOption().getName() << Val; - return ""; - } - - // Mark the matched option as found. Do not allow duplicate specifiers. - OptionIter->second = true; - - // If the precision was not specified, also mark the double and half entry - // as found. - if (ValBase.back() != 'f' && ValBase.back() != 'd' && - ValBase.back() != 'h') { - OptionStrings[ValBase.str() + 'd'] = true; - OptionStrings[ValBase.str() + 'h'] = true; - } - - // Build the output string. - StringRef Prefix = IsDisabled ? DisabledPrefixOut : EnabledPrefixOut; - Out = Args.MakeArgString(Out + Prefix + Val); - if (i != NumOptions - 1) - Out = Args.MakeArgString(Out + ","); - } - - return Out; -} - std::string tools::complexRangeKindToStr(LangOptions::ComplexRangeKind Range) { switch (Range) { case LangOptions::ComplexRangeKind::CX_Full: diff --git a/clang/lib/Driver/ToolChains/Flang.cpp b/clang/lib/Driver/ToolChains/Flang.cpp index cc4755cd6a9b0..438de23be0103 100644 --- a/clang/lib/Driver/ToolChains/Flang.cpp +++ b/clang/lib/Driver/ToolChains/Flang.cpp @@ -11,6 +11,7 @@ #include "clang/Basic/CodeGenOptions.h" #include "clang/Driver/CommonArgs.h" +#include "clang/Options/OptionUtils.h" #include "clang/Options/Options.h" #include "llvm/Frontend/Debug/Options.h" #include "llvm/Support/Path.h" diff --git a/clang/lib/Frontend/ASTUnit.cpp b/clang/lib/Frontend/ASTUnit.cpp index db13086bcb470..e72317da64596 100644 --- a/clang/lib/Frontend/ASTUnit.cpp +++ b/clang/lib/Frontend/ASTUnit.cpp @@ -44,6 +44,7 @@ #include "clang/Frontend/FrontendOptions.h" #include "clang/Frontend/MultiplexConsumer.h" #include "clang/Frontend/PrecompiledPreamble.h" +#include "clang/Frontend/StandaloneDiagnostic.h" #include "clang/Frontend/Utils.h" #include "clang/Lex/HeaderSearch.h" #include "clang/Lex/HeaderSearchOptions.h" @@ -210,15 +211,6 @@ getBufferForFileHandlingRemapping(const CompilerInvocation &Invocation, return llvm::MemoryBuffer::getMemBufferCopy(Buffer->getBuffer(), FilePath); } -struct ASTUnit::ASTWriterData { - SmallString<128> Buffer; - llvm::BitstreamWriter Stream; - ASTWriter Writer; - - ASTWriterData(ModuleCache &ModCache, const CodeGenOptions &CGOpts) - : Stream(Buffer), Writer(Stream, Buffer, ModCache, CGOpts, {}) {} -}; - void ASTUnit::clearFileLevelDecls() { FileDecls.clear(); } @@ -581,73 +573,24 @@ class ASTInfoCollector : public ASTReaderListener { Counter = NewCounter; } }; +} // anonymous namespace -/// Diagnostic consumer that saves each diagnostic it is given. -class FilterAndStoreDiagnosticConsumer : public DiagnosticConsumer { - SmallVectorImpl *StoredDiags; - SmallVectorImpl *StandaloneDiags; - bool CaptureNonErrorsFromIncludes = true; - const LangOptions *LangOpts = nullptr; - SourceManager *SourceMgr = nullptr; - -public: - FilterAndStoreDiagnosticConsumer( - SmallVectorImpl *StoredDiags, - SmallVectorImpl *StandaloneDiags, - bool CaptureNonErrorsFromIncludes) - : StoredDiags(StoredDiags), StandaloneDiags(StandaloneDiags), - CaptureNonErrorsFromIncludes(CaptureNonErrorsFromIncludes) { - assert((StoredDiags || StandaloneDiags) && - "No output collections were passed to StoredDiagnosticConsumer."); - } - - void BeginSourceFile(const LangOptions &LangOpts, - const Preprocessor *PP = nullptr) override { - this->LangOpts = &LangOpts; - if (PP) - SourceMgr = &PP->getSourceManager(); - } - - void HandleDiagnostic(DiagnosticsEngine::Level Level, - const Diagnostic &Info) override; -}; - -/// RAII object that optionally captures and filters diagnostics, if -/// there is no diagnostic client to capture them already. -class CaptureDroppedDiagnostics { - DiagnosticsEngine &Diags; - FilterAndStoreDiagnosticConsumer Client; - DiagnosticConsumer *PreviousClient = nullptr; - std::unique_ptr OwningPreviousClient; - -public: - CaptureDroppedDiagnostics( - CaptureDiagsKind CaptureDiagnostics, DiagnosticsEngine &Diags, - SmallVectorImpl *StoredDiags, - SmallVectorImpl *StandaloneDiags) - : Diags(Diags), - Client(StoredDiags, StandaloneDiags, - CaptureDiagnostics != - CaptureDiagsKind::AllWithoutNonErrorsFromIncludes) { - if (CaptureDiagnostics != CaptureDiagsKind::None || - Diags.getClient() == nullptr) { - OwningPreviousClient = Diags.takeClient(); - PreviousClient = Diags.getClient(); - Diags.setClient(&Client, false); - } - } - - ~CaptureDroppedDiagnostics() { - if (Diags.getClient() == &Client) - Diags.setClient(PreviousClient, !!OwningPreviousClient.release()); - } -}; - -} // namespace +FilterAndStoreDiagnosticConsumer::FilterAndStoreDiagnosticConsumer( + SmallVectorImpl *StoredDiags, + SmallVectorImpl *StandaloneDiags, + bool CaptureNonErrorsFromIncludes) + : StoredDiags(StoredDiags), StandaloneDiags(StandaloneDiags), + CaptureNonErrorsFromIncludes(CaptureNonErrorsFromIncludes) { + assert((StoredDiags || StandaloneDiags) && + "No output collections were passed to StoredDiagnosticConsumer."); +} -static ASTUnit::StandaloneDiagnostic -makeStandaloneDiagnostic(const LangOptions &LangOpts, - const StoredDiagnostic &InDiag); +void FilterAndStoreDiagnosticConsumer::BeginSourceFile( + const LangOptions &LangOpts, const Preprocessor *PP) { + this->LangOpts = &LangOpts; + if (PP) + SourceMgr = &PP->getSourceManager(); +} static bool isInMainFile(const clang::Diagnostic &D) { if (!D.hasSourceManager() || !D.getLocation().isValid()) @@ -683,12 +626,32 @@ void FilterAndStoreDiagnosticConsumer::HandleDiagnostic( StoredDiag.emplace(Level, Info); ResultDiag = &*StoredDiag; } - StandaloneDiags->push_back( - makeStandaloneDiagnostic(*LangOpts, *ResultDiag)); + StandaloneDiags->emplace_back(*LangOpts, *ResultDiag); } } } +CaptureDroppedDiagnostics::CaptureDroppedDiagnostics( + CaptureDiagsKind CaptureDiagnostics, DiagnosticsEngine &Diags, + SmallVectorImpl *StoredDiags, + SmallVectorImpl *StandaloneDiags) + : Diags(Diags), + Client(StoredDiags, StandaloneDiags, + CaptureDiagnostics != + CaptureDiagsKind::AllWithoutNonErrorsFromIncludes) { + if (CaptureDiagnostics != CaptureDiagsKind::None || + Diags.getClient() == nullptr) { + OwningPreviousClient = Diags.takeClient(); + PreviousClient = Diags.getClient(); + Diags.setClient(&Client, false); + } +} + +CaptureDroppedDiagnostics::~CaptureDroppedDiagnostics() { + if (Diags.getClient() == &Client) + Diags.setClient(PreviousClient, !!OwningPreviousClient.release()); +} + IntrusiveRefCntPtr ASTUnit::getASTReader() const { return Reader; } @@ -1110,7 +1073,7 @@ class ASTUnitPreambleCallbacks : public PreambleCallbacks { unsigned Hash = 0; std::vector TopLevelDecls; std::vector TopLevelDeclIDs; - llvm::SmallVector PreambleDiags; + llvm::SmallVector PreambleDiags; }; } // namespace @@ -1259,10 +1222,17 @@ bool ASTUnit::Parse(std::shared_ptr PCHContainerOps, if (!Act->BeginSourceFile(*Clang, Clang->getFrontendOpts().Inputs[0])) return true; - if (SavedMainFileBuffer) - TranslateStoredDiagnostics(getFileManager(), getSourceManager(), - PreambleDiagnostics, StoredDiagnostics); - else + if (SavedMainFileBuffer) { + StoredDiagnostics.clear(); + StoredDiagnostics.reserve(PreambleDiagnostics.size()); + llvm::transform(std::move(PreambleDiagnostics), + std::back_inserter(StoredDiagnostics), + [&](auto &&StandaloneDiag) { + return translateStandaloneDiag( + getFileManager(), getSourceManager(), + std::move(StandaloneDiag), PreambleSrcLocCache); + }); + } else PreambleSrcLocCache.clear(); if (llvm::Error Err = Act->Execute()) { @@ -1281,51 +1251,6 @@ bool ASTUnit::Parse(std::shared_ptr PCHContainerOps, return false; } -static std::pair -makeStandaloneRange(CharSourceRange Range, const SourceManager &SM, - const LangOptions &LangOpts) { - CharSourceRange FileRange = Lexer::makeFileCharRange(Range, SM, LangOpts); - unsigned Offset = SM.getFileOffset(FileRange.getBegin()); - unsigned EndOffset = SM.getFileOffset(FileRange.getEnd()); - return std::make_pair(Offset, EndOffset); -} - -static ASTUnit::StandaloneFixIt makeStandaloneFixIt(const SourceManager &SM, - const LangOptions &LangOpts, - const FixItHint &InFix) { - ASTUnit::StandaloneFixIt OutFix; - OutFix.RemoveRange = makeStandaloneRange(InFix.RemoveRange, SM, LangOpts); - OutFix.InsertFromRange = makeStandaloneRange(InFix.InsertFromRange, SM, - LangOpts); - OutFix.CodeToInsert = InFix.CodeToInsert; - OutFix.BeforePreviousInsertions = InFix.BeforePreviousInsertions; - return OutFix; -} - -static ASTUnit::StandaloneDiagnostic -makeStandaloneDiagnostic(const LangOptions &LangOpts, - const StoredDiagnostic &InDiag) { - ASTUnit::StandaloneDiagnostic OutDiag; - OutDiag.ID = InDiag.getID(); - OutDiag.Level = InDiag.getLevel(); - OutDiag.Message = std::string(InDiag.getMessage()); - OutDiag.LocOffset = 0; - if (InDiag.getLocation().isInvalid()) - return OutDiag; - const SourceManager &SM = InDiag.getLocation().getManager(); - SourceLocation FileLoc = SM.getFileLoc(InDiag.getLocation()); - OutDiag.Filename = std::string(SM.getFilename(FileLoc)); - if (OutDiag.Filename.empty()) - return OutDiag; - OutDiag.LocOffset = SM.getFileOffset(FileLoc); - for (const auto &Range : InDiag.getRanges()) - OutDiag.Ranges.push_back(makeStandaloneRange(Range, SM, LangOpts)); - for (const auto &FixIt : InDiag.getFixIts()) - OutDiag.FixIts.push_back(makeStandaloneFixIt(SM, LangOpts, FixIt)); - - return OutDiag; -} - /// Attempt to build or re-use a precompiled preamble when (re-)parsing /// the source file. /// @@ -1780,116 +1705,6 @@ std::unique_ptr ASTUnit::LoadFromCompilerInvocation( return AST; } -std::unique_ptr ASTUnit::LoadFromCommandLine( - const char **ArgBegin, const char **ArgEnd, - std::shared_ptr PCHContainerOps, - std::shared_ptr DiagOpts, - IntrusiveRefCntPtr Diags, StringRef ResourceFilesPath, - bool StorePreamblesInMemory, StringRef PreambleStoragePath, - bool OnlyLocalDecls, CaptureDiagsKind CaptureDiagnostics, - ArrayRef RemappedFiles, bool RemappedFilesKeepOriginalName, - unsigned PrecompilePreambleAfterNParses, TranslationUnitKind TUKind, - bool CacheCodeCompletionResults, bool IncludeBriefCommentsInCodeCompletion, - bool AllowPCHWithCompilerErrors, SkipFunctionBodiesScope SkipFunctionBodies, - bool SingleFileParse, bool UserFilesAreVolatile, bool ForSerialization, - bool RetainExcludedConditionalBlocks, std::optional ModuleFormat, - std::unique_ptr *ErrAST, - IntrusiveRefCntPtr VFS) { - assert(Diags.get() && "no DiagnosticsEngine was provided"); - - // If no VFS was provided, create one that tracks the physical file system. - // If '-working-directory' was passed as an argument, 'createInvocation' will - // set this as the current working directory of the VFS. - if (!VFS) - VFS = llvm::vfs::createPhysicalFileSystem(); - - SmallVector StoredDiagnostics; - - std::shared_ptr CI; - - { - CaptureDroppedDiagnostics Capture(CaptureDiagnostics, *Diags, - &StoredDiagnostics, nullptr); - - CreateInvocationOptions CIOpts; - CIOpts.VFS = VFS; - CIOpts.Diags = Diags; - CIOpts.ProbePrecompiled = true; // FIXME: historical default. Needed? - CI = createInvocation(llvm::ArrayRef(ArgBegin, ArgEnd), std::move(CIOpts)); - if (!CI) - return nullptr; - } - - // Override any files that need remapping - for (const auto &RemappedFile : RemappedFiles) { - CI->getPreprocessorOpts().addRemappedFile(RemappedFile.first, - RemappedFile.second); - } - PreprocessorOptions &PPOpts = CI->getPreprocessorOpts(); - PPOpts.RemappedFilesKeepOriginalName = RemappedFilesKeepOriginalName; - PPOpts.AllowPCHWithCompilerErrors = AllowPCHWithCompilerErrors; - PPOpts.SingleFileParseMode = SingleFileParse; - PPOpts.RetainExcludedConditionalBlocks = RetainExcludedConditionalBlocks; - - // Override the resources path. - CI->getHeaderSearchOpts().ResourceDir = std::string(ResourceFilesPath); - - CI->getFrontendOpts().SkipFunctionBodies = - SkipFunctionBodies == SkipFunctionBodiesScope::PreambleAndMainFile; - - if (ModuleFormat) - CI->getHeaderSearchOpts().ModuleFormat = std::string(*ModuleFormat); - - // Create the AST unit. - std::unique_ptr AST; - AST.reset(new ASTUnit(false)); - AST->NumStoredDiagnosticsFromDriver = StoredDiagnostics.size(); - AST->StoredDiagnostics.swap(StoredDiagnostics); - ConfigureDiags(Diags, *AST, CaptureDiagnostics); - AST->DiagOpts = DiagOpts; - AST->Diagnostics = Diags; - AST->FileSystemOpts = CI->getFileSystemOpts(); - AST->CodeGenOpts = std::make_unique(CI->getCodeGenOpts()); - VFS = createVFSFromCompilerInvocation(*CI, *Diags, VFS); - AST->FileMgr = - llvm::makeIntrusiveRefCnt(AST->FileSystemOpts, VFS); - AST->StorePreamblesInMemory = StorePreamblesInMemory; - AST->PreambleStoragePath = PreambleStoragePath; - AST->ModCache = createCrossProcessModuleCache(); - AST->OnlyLocalDecls = OnlyLocalDecls; - AST->CaptureDiagnostics = CaptureDiagnostics; - AST->TUKind = TUKind; - AST->ShouldCacheCodeCompletionResults = CacheCodeCompletionResults; - AST->IncludeBriefCommentsInCodeCompletion - = IncludeBriefCommentsInCodeCompletion; - AST->UserFilesAreVolatile = UserFilesAreVolatile; - AST->Invocation = CI; - AST->SkipFunctionBodies = SkipFunctionBodies; - if (ForSerialization) - AST->WriterData.reset(new ASTWriterData(*AST->ModCache, *AST->CodeGenOpts)); - // Zero out now to ease cleanup during crash recovery. - CI = nullptr; - Diags = nullptr; - - // Recover resources if we crash before exiting this method. - llvm::CrashRecoveryContextCleanupRegistrar - ASTUnitCleanup(AST.get()); - - if (AST->LoadFromCompilerInvocation(std::move(PCHContainerOps), - PrecompilePreambleAfterNParses, - VFS)) { - // Some error occurred, if caller wants to examine diagnostics, pass it the - // ASTUnit. - if (ErrAST) { - AST->StoredDiagnostics.swap(AST->FailedParseDiagnostics); - ErrAST->swap(AST); - } - return nullptr; - } - - return AST; -} - bool ASTUnit::Reparse(std::shared_ptr PCHContainerOps, ArrayRef RemappedFiles, IntrusiveRefCntPtr VFS) { @@ -2408,65 +2223,6 @@ bool ASTUnit::serialize(raw_ostream &OS) { return serializeUnit(Writer, Buffer, getSema(), OS); } -void ASTUnit::TranslateStoredDiagnostics( - FileManager &FileMgr, - SourceManager &SrcMgr, - const SmallVectorImpl &Diags, - SmallVectorImpl &Out) { - // Map the standalone diagnostic into the new source manager. We also need to - // remap all the locations to the new view. This includes the diag location, - // any associated source ranges, and the source ranges of associated fix-its. - // FIXME: There should be a cleaner way to do this. - SmallVector Result; - Result.reserve(Diags.size()); - - for (const auto &SD : Diags) { - // Rebuild the StoredDiagnostic. - if (SD.Filename.empty()) - continue; - auto FE = FileMgr.getOptionalFileRef(SD.Filename); - if (!FE) - continue; - SourceLocation FileLoc; - auto ItFileID = PreambleSrcLocCache.find(SD.Filename); - if (ItFileID == PreambleSrcLocCache.end()) { - FileID FID = SrcMgr.translateFile(*FE); - FileLoc = SrcMgr.getLocForStartOfFile(FID); - PreambleSrcLocCache[SD.Filename] = FileLoc; - } else { - FileLoc = ItFileID->getValue(); - } - - if (FileLoc.isInvalid()) - continue; - SourceLocation L = FileLoc.getLocWithOffset(SD.LocOffset); - FullSourceLoc Loc(L, SrcMgr); - - SmallVector Ranges; - Ranges.reserve(SD.Ranges.size()); - for (const auto &Range : SD.Ranges) { - SourceLocation BL = FileLoc.getLocWithOffset(Range.first); - SourceLocation EL = FileLoc.getLocWithOffset(Range.second); - Ranges.push_back(CharSourceRange::getCharRange(BL, EL)); - } - - SmallVector FixIts; - FixIts.reserve(SD.FixIts.size()); - for (const auto &FixIt : SD.FixIts) { - FixIts.push_back(FixItHint()); - FixItHint &FH = FixIts.back(); - FH.CodeToInsert = FixIt.CodeToInsert; - SourceLocation BL = FileLoc.getLocWithOffset(FixIt.RemoveRange.first); - SourceLocation EL = FileLoc.getLocWithOffset(FixIt.RemoveRange.second); - FH.RemoveRange = CharSourceRange::getCharRange(BL, EL); - } - - Result.push_back(StoredDiagnostic(SD.Level, SD.ID, - SD.Message, Loc, Ranges, FixIts)); - } - Result.swap(Out); -} - void ASTUnit::addFileLevelDecl(Decl *D) { assert(D); diff --git a/clang/lib/Frontend/CMakeLists.txt b/clang/lib/Frontend/CMakeLists.txt index dac9e0d26f393..634f239933605 100644 --- a/clang/lib/Frontend/CMakeLists.txt +++ b/clang/lib/Frontend/CMakeLists.txt @@ -17,7 +17,6 @@ add_clang_library(clangFrontend ChainedIncludesSource.cpp CompilerInstance.cpp CompilerInvocation.cpp - CreateInvocationFromCommandLine.cpp DependencyFile.cpp DependencyGraph.cpp DiagnosticRenderer.cpp @@ -36,6 +35,7 @@ add_clang_library(clangFrontend SARIFDiagnosticPrinter.cpp SerializedDiagnosticPrinter.cpp SerializedDiagnosticReader.cpp + StandaloneDiagnostic.cpp TestModuleFileExtension.cpp TextDiagnostic.cpp TextDiagnosticBuffer.cpp @@ -51,7 +51,6 @@ add_clang_library(clangFrontend clangAPINotes clangAST clangBasic - clangDriver clangOptions clangEdit clangLex diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index be7239da55cce..c081ed7215b54 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -3274,13 +3274,6 @@ static bool ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, return Diags.getNumErrors() == NumErrorsBefore; } -std::string CompilerInvocation::GetResourcesPath(const char *Argv0, - void *MainAddr) { - std::string ClangExecutable = - llvm::sys::fs::getMainExecutable(Argv0, MainAddr); - return Driver::GetResourcesPath(ClangExecutable); -} - static void GenerateHeaderSearchArgs(const HeaderSearchOptions &Opts, ArgumentConsumer Consumer) { const HeaderSearchOptions *HeaderSearchOpts = &Opts; diff --git a/clang/lib/Frontend/StandaloneDiagnostic.cpp b/clang/lib/Frontend/StandaloneDiagnostic.cpp new file mode 100644 index 0000000000000..4f19c91b7d266 --- /dev/null +++ b/clang/lib/Frontend/StandaloneDiagnostic.cpp @@ -0,0 +1,117 @@ +//===--- StandaloneDiagnostic.h - Serializable Diagnostic ------------- ---===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "clang/Frontend/StandaloneDiagnostic.h" +#include "clang/Lex/Lexer.h" + +namespace clang { + +StandaloneDiagnostic::SourceOffsetRange::SourceOffsetRange( + CharSourceRange Range, const SourceManager &SrcMgr, + const LangOptions &LangOpts) { + const auto FileRange = Lexer::makeFileCharRange(Range, SrcMgr, LangOpts); + Begin = SrcMgr.getFileOffset(FileRange.getBegin()); + End = SrcMgr.getFileOffset(FileRange.getEnd()); +} + +StandaloneDiagnostic::StandaloneFixIt::StandaloneFixIt( + const SourceManager &SrcMgr, const LangOptions &LangOpts, + const FixItHint &FixIt) + : RemoveRange(FixIt.RemoveRange, SrcMgr, LangOpts), + InsertFromRange(FixIt.InsertFromRange, SrcMgr, LangOpts), + CodeToInsert(FixIt.CodeToInsert), + BeforePreviousInsertions(FixIt.BeforePreviousInsertions) {} + +StandaloneDiagnostic::StandaloneDiagnostic(const LangOptions &LangOpts, + const StoredDiagnostic &InDiag) + : Level(InDiag.getLevel()), ID(InDiag.getID()), + Message(InDiag.getMessage()) { + const FullSourceLoc &FullLoc = InDiag.getLocation(); + // This is not an invalid diagnostic; invalid SourceLocations are used to + // represent diagnostics without a specific SourceLocation. + if (FullLoc.isInvalid()) + return; + + const auto &SrcMgr = FullLoc.getManager(); + FileKind = SrcMgr.getFileCharacteristic(static_cast(FullLoc)); + const auto FileLoc = SrcMgr.getFileLoc(static_cast(FullLoc)); + FileOffset = SrcMgr.getFileOffset(FileLoc); + Filename = SrcMgr.getFilename(FileLoc); + assert(!Filename.empty() && "diagnostic with location has no source file?"); + + Ranges.reserve(InDiag.getRanges().size()); + for (const auto &Range : InDiag.getRanges()) + Ranges.emplace_back(Range, SrcMgr, LangOpts); + + FixIts.reserve(InDiag.getFixIts().size()); + for (const auto &FixIt : InDiag.getFixIts()) + FixIts.emplace_back(SrcMgr, LangOpts, FixIt); +} + +StoredDiagnostic +translateStandaloneDiag(FileManager &FileMgr, SourceManager &SrcMgr, + const StandaloneDiagnostic &StandaloneDiag, + llvm::StringMap &SrcLocCache) { + const auto FileRef = FileMgr.getOptionalFileRef(StandaloneDiag.Filename); + if (!FileRef) + return StoredDiagnostic(StandaloneDiag.Level, StandaloneDiag.ID, + StandaloneDiag.Message); + + // Try to get FileLoc from cache first + SourceLocation FileLoc; + auto It = SrcLocCache.find(StandaloneDiag.Filename); + if (It != SrcLocCache.end()) { + FileLoc = It->getValue(); + } + + // Cache miss - compute and cache the location + if (FileLoc.isInvalid()) { + const auto FileID = + SrcMgr.getOrCreateFileID(*FileRef, StandaloneDiag.FileKind); + FileLoc = SrcMgr.getLocForStartOfFile(FileID); + + if (FileLoc.isInvalid()) + return StoredDiagnostic(StandaloneDiag.Level, StandaloneDiag.ID, + StandaloneDiag.Message); + + SrcLocCache[StandaloneDiag.Filename] = FileLoc; + } + + const auto DiagLoc = FileLoc.getLocWithOffset(StandaloneDiag.FileOffset); + const FullSourceLoc Loc(DiagLoc, SrcMgr); + + auto ConvertOffsetRange = + [&](const StandaloneDiagnostic::SourceOffsetRange &Range) { + return CharSourceRange( + SourceRange(FileLoc.getLocWithOffset(Range.Begin), + FileLoc.getLocWithOffset(Range.End)), + /*IsTokenRange*/ false); + }; + + SmallVector TranslatedRanges; + TranslatedRanges.reserve(StandaloneDiag.Ranges.size()); + transform(StandaloneDiag.Ranges, std::back_inserter(TranslatedRanges), + ConvertOffsetRange); + + SmallVector TranslatedFixIts; + TranslatedFixIts.reserve(StandaloneDiag.FixIts.size()); + for (const auto &FixIt : StandaloneDiag.FixIts) { + FixItHint TranslatedFixIt; + TranslatedFixIt.CodeToInsert = FixIt.CodeToInsert; + TranslatedFixIt.RemoveRange = ConvertOffsetRange(FixIt.RemoveRange); + TranslatedFixIt.InsertFromRange = ConvertOffsetRange(FixIt.InsertFromRange); + TranslatedFixIt.BeforePreviousInsertions = FixIt.BeforePreviousInsertions; + TranslatedFixIts.push_back(std::move(TranslatedFixIt)); + } + + return StoredDiagnostic(StandaloneDiag.Level, StandaloneDiag.ID, + StandaloneDiag.Message, Loc, TranslatedRanges, + TranslatedFixIts); +} + +} // namespace clang diff --git a/clang/lib/Interpreter/CMakeLists.txt b/clang/lib/Interpreter/CMakeLists.txt index 37faa0302caaa..9a597146b2fc4 100644 --- a/clang/lib/Interpreter/CMakeLists.txt +++ b/clang/lib/Interpreter/CMakeLists.txt @@ -46,6 +46,7 @@ add_clang_library(clangInterpreter clangFrontend clangFrontendTool clangLex + clangOptions clangParse clangSema clangSerialization diff --git a/clang/lib/Interpreter/Interpreter.cpp b/clang/lib/Interpreter/Interpreter.cpp index 7764fa7dc92b9..6cbc5e9910bcc 100644 --- a/clang/lib/Interpreter/Interpreter.cpp +++ b/clang/lib/Interpreter/Interpreter.cpp @@ -42,6 +42,7 @@ #include "clang/Interpreter/Interpreter.h" #include "clang/Interpreter/Value.h" #include "clang/Lex/PreprocessorOptions.h" +#include "clang/Options/OptionUtils.h" #include "clang/Options/Options.h" #include "clang/Sema/Lookup.h" #include "clang/Serialization/ObjectFilePCHContainerReader.h" @@ -105,7 +106,7 @@ CreateCI(const llvm::opt::ArgStringList &Argv) { if (Clang->getHeaderSearchOpts().UseBuiltinIncludes && Clang->getHeaderSearchOpts().ResourceDir.empty()) Clang->getHeaderSearchOpts().ResourceDir = - CompilerInvocation::GetResourcesPath(Argv[0], nullptr); + GetResourcesPath(Argv[0], nullptr); Clang->createVirtualFileSystem(); diff --git a/clang/lib/Options/OptionUtils.cpp b/clang/lib/Options/OptionUtils.cpp index fcafd3c83c6b3..e5aefa012f679 100644 --- a/clang/lib/Options/OptionUtils.cpp +++ b/clang/lib/Options/OptionUtils.cpp @@ -9,7 +9,12 @@ #include "clang/Options/OptionUtils.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/DiagnosticDriver.h" +#include "clang/Basic/Version.h" +#include "clang/Config/config.h" +#include "clang/Options/Options.h" #include "llvm/Option/ArgList.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" using namespace clang; using namespace llvm::opt; @@ -31,17 +36,211 @@ IntTy getLastArgIntValueImpl(const ArgList &Args, OptSpecifier Id, } } // namespace -namespace clang { - -int getLastArgIntValue(const ArgList &Args, OptSpecifier Id, int Default, - DiagnosticsEngine *Diags, unsigned Base) { +int clang::getLastArgIntValue(const ArgList &Args, OptSpecifier Id, int Default, + DiagnosticsEngine *Diags, unsigned Base) { return getLastArgIntValueImpl(Args, Id, Default, Diags, Base); } -uint64_t getLastArgUInt64Value(const ArgList &Args, OptSpecifier Id, - uint64_t Default, DiagnosticsEngine *Diags, - unsigned Base) { +uint64_t clang::getLastArgUInt64Value(const ArgList &Args, OptSpecifier Id, + uint64_t Default, + DiagnosticsEngine *Diags, unsigned Base) { return getLastArgIntValueImpl(Args, Id, Default, Diags, Base); } -} // namespace clang +StringRef clang::parseMPreferVectorWidthOption(clang::DiagnosticsEngine &Diags, + const llvm::opt::ArgList &Args) { + const Arg *A = Args.getLastArg(options::OPT_mprefer_vector_width_EQ); + if (!A) + return ""; + + StringRef Value = A->getValue(); + unsigned Width LLVM_ATTRIBUTE_UNINITIALIZED; + + // Only "none" and Integer values are accepted by + // -mprefer-vector-width=. + if (Value != "none" && Value.getAsInteger(10, Width)) { + Diags.Report(clang::diag::err_drv_invalid_value) + << A->getOption().getName() << Value; + return ""; + } + + return Value; +} + +// This is a helper function for validating the optional refinement step +// parameter in reciprocal argument strings. Return false if there is an error +// parsing the refinement step. Otherwise, return true and set the Position +// of the refinement step in the input string. +static bool getRefinementStep(StringRef In, clang::DiagnosticsEngine &Diags, + const Arg &A, size_t &Position) { + const char RefinementStepToken = ':'; + Position = In.find(RefinementStepToken); + if (Position != StringRef::npos) { + StringRef Option = A.getOption().getName(); + StringRef RefStep = In.substr(Position + 1); + // Allow exactly one numeric character for the additional refinement + // step parameter. This is reasonable for all currently-supported + // operations and architectures because we would expect that a larger value + // of refinement steps would cause the estimate "optimization" to + // under-perform the native operation. Also, if the estimate does not + // converge quickly, it probably will not ever converge, so further + // refinement steps will not produce a better answer. + if (RefStep.size() != 1) { + Diags.Report(diag::err_drv_invalid_value) << Option << RefStep; + return false; + } + char RefStepChar = RefStep[0]; + if (RefStepChar < '0' || RefStepChar > '9') { + Diags.Report(diag::err_drv_invalid_value) << Option << RefStep; + return false; + } + } + return true; +} + +StringRef clang::parseMRecipOption(clang::DiagnosticsEngine &Diags, + const ArgList &Args) { + StringRef DisabledPrefixIn = "!"; + StringRef DisabledPrefixOut = "!"; + StringRef EnabledPrefixOut = ""; + StringRef Out = ""; + + const Arg *A = Args.getLastArg(options::OPT_mrecip, options::OPT_mrecip_EQ); + if (!A) + return ""; + + const unsigned NumOptions = A->getNumValues(); + if (NumOptions == 0) { + // No option is the same as "all". + return "all"; + } + + // Pass through "all", "none", or "default" with an optional refinement step. + if (NumOptions == 1) { + StringRef Val = A->getValue(0); + size_t RefStepLoc; + if (!getRefinementStep(Val, Diags, *A, RefStepLoc)) + return ""; + StringRef ValBase = Val.slice(0, RefStepLoc); + if (ValBase == "all" || ValBase == "none" || ValBase == "default") { + return Val; + } + } + + // Each reciprocal type may be enabled or disabled individually. + // Check each input value for validity, concatenate them all back together, + // and pass through. + + llvm::StringMap OptionStrings; + OptionStrings.insert(std::make_pair("divd", false)); + OptionStrings.insert(std::make_pair("divf", false)); + OptionStrings.insert(std::make_pair("divh", false)); + OptionStrings.insert(std::make_pair("vec-divd", false)); + OptionStrings.insert(std::make_pair("vec-divf", false)); + OptionStrings.insert(std::make_pair("vec-divh", false)); + OptionStrings.insert(std::make_pair("sqrtd", false)); + OptionStrings.insert(std::make_pair("sqrtf", false)); + OptionStrings.insert(std::make_pair("sqrth", false)); + OptionStrings.insert(std::make_pair("vec-sqrtd", false)); + OptionStrings.insert(std::make_pair("vec-sqrtf", false)); + OptionStrings.insert(std::make_pair("vec-sqrth", false)); + + for (unsigned i = 0; i != NumOptions; ++i) { + StringRef Val = A->getValue(i); + + bool IsDisabled = Val.starts_with(DisabledPrefixIn); + // Ignore the disablement token for string matching. + if (IsDisabled) + Val = Val.substr(1); + + size_t RefStep; + if (!getRefinementStep(Val, Diags, *A, RefStep)) + return ""; + + StringRef ValBase = Val.slice(0, RefStep); + llvm::StringMap::iterator OptionIter = OptionStrings.find(ValBase); + if (OptionIter == OptionStrings.end()) { + // Try again specifying float suffix. + OptionIter = OptionStrings.find(ValBase.str() + 'f'); + if (OptionIter == OptionStrings.end()) { + // The input name did not match any known option string. + Diags.Report(diag::err_drv_unknown_argument) << Val; + return ""; + } + // The option was specified without a half or float or double suffix. + // Make sure that the double or half entry was not already specified. + // The float entry will be checked below. + if (OptionStrings[ValBase.str() + 'd'] || + OptionStrings[ValBase.str() + 'h']) { + Diags.Report(diag::err_drv_invalid_value) + << A->getOption().getName() << Val; + return ""; + } + } + + if (OptionIter->second == true) { + // Duplicate option specified. + Diags.Report(diag::err_drv_invalid_value) + << A->getOption().getName() << Val; + return ""; + } + + // Mark the matched option as found. Do not allow duplicate specifiers. + OptionIter->second = true; + + // If the precision was not specified, also mark the double and half entry + // as found. + if (ValBase.back() != 'f' && ValBase.back() != 'd' && + ValBase.back() != 'h') { + OptionStrings[ValBase.str() + 'd'] = true; + OptionStrings[ValBase.str() + 'h'] = true; + } + + // Build the output string. + StringRef Prefix = IsDisabled ? DisabledPrefixOut : EnabledPrefixOut; + Out = Args.MakeArgString(Out + Prefix + Val); + if (i != NumOptions - 1) + Out = Args.MakeArgString(Out + ","); + } + + return Out; +} + +std::string clang::GetResourcesPath(StringRef BinaryPath) { + // Since the resource directory is embedded in the module hash, it's important + // that all places that need it call this function, so that they get the + // exact same string ("a/../b/" and "b/" get different hashes, for example). + + // Dir is bin/ or lib/, depending on where BinaryPath is. + StringRef Dir = llvm::sys::path::parent_path(BinaryPath); + SmallString<128> P(Dir); + + StringRef ConfiguredResourceDir(CLANG_RESOURCE_DIR); + if (!ConfiguredResourceDir.empty()) { + // FIXME: We should fix the behavior of llvm::sys::path::append so we don't + // need to check for absolute paths here. + if (llvm::sys::path::is_absolute(ConfiguredResourceDir)) + P = ConfiguredResourceDir; + else + llvm::sys::path::append(P, ConfiguredResourceDir); + } else { + // On Windows, libclang.dll is in bin/. + // On non-Windows, libclang.so/.dylib is in lib/. + // With a static-library build of libclang, LibClangPath will contain the + // path of the embedding binary, which for LLVM binaries will be in bin/. + // ../lib gets us to lib/ in both cases. + P = llvm::sys::path::parent_path(Dir); + // This search path is also created in the COFF driver of lld, so any + // changes here also needs to happen in lld/COFF/Driver.cpp + llvm::sys::path::append(P, CLANG_INSTALL_LIBDIR_BASENAME, "clang", + CLANG_VERSION_MAJOR_STRING); + } + + return std::string(P); +} + +std::string clang::GetResourcesPath(const char *Argv0, void *MainAddr) { + const std::string ClangExecutable = + llvm::sys::fs::getMainExecutable(Argv0, MainAddr); + return GetResourcesPath(ClangExecutable); +} diff --git a/clang/lib/Tooling/Tooling.cpp b/clang/lib/Tooling/Tooling.cpp index 9bae12454d2dc..1d55f615de8a9 100644 --- a/clang/lib/Tooling/Tooling.cpp +++ b/clang/lib/Tooling/Tooling.cpp @@ -31,6 +31,7 @@ #include "clang/Frontend/TextDiagnosticPrinter.h" #include "clang/Lex/HeaderSearchOptions.h" #include "clang/Lex/PreprocessorOptions.h" +#include "clang/Options/OptionUtils.h" #include "clang/Options/Options.h" #include "clang/Tooling/ArgumentsAdjusters.h" #include "clang/Tooling/CompilationDatabase.h" @@ -510,8 +511,7 @@ static void injectResourceDir(CommandLineArguments &Args, const char *Argv0, // If there's no override in place add our resource dir. Args = getInsertArgumentAdjuster( - ("-resource-dir=" + CompilerInvocation::GetResourcesPath(Argv0, MainAddr)) - .c_str())(Args, ""); + ("-resource-dir=" + GetResourcesPath(Argv0, MainAddr)).c_str())(Args, ""); } int ClangTool::run(ToolAction *Action) { diff --git a/clang/tools/c-index-test/CMakeLists.txt b/clang/tools/c-index-test/CMakeLists.txt index 24e7c9692ca56..41e80e66ffa7a 100644 --- a/clang/tools/c-index-test/CMakeLists.txt +++ b/clang/tools/c-index-test/CMakeLists.txt @@ -27,6 +27,7 @@ else() libclang clangAST clangBasic + clangDriver clangFrontend clangIndex clangSerialization diff --git a/clang/tools/c-index-test/core_main.cpp b/clang/tools/c-index-test/core_main.cpp index 5a3086a7fc08f..c67479fd130ca 100644 --- a/clang/tools/c-index-test/core_main.cpp +++ b/clang/tools/c-index-test/core_main.cpp @@ -8,6 +8,7 @@ #include "clang/AST/Mangle.h" #include "clang/Basic/LangOptions.h" +#include "clang/Driver/CreateInvocationFromArgs.h" #include "clang/Frontend/ASTUnit.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/CompilerInvocation.h" diff --git a/clang/tools/diagtool/CMakeLists.txt b/clang/tools/diagtool/CMakeLists.txt index b49619c075c73..09b2a81790f87 100644 --- a/clang/tools/diagtool/CMakeLists.txt +++ b/clang/tools/diagtool/CMakeLists.txt @@ -15,5 +15,6 @@ add_clang_tool(diagtool clang_target_link_libraries(diagtool PRIVATE clangBasic + clangDriver clangFrontend ) diff --git a/clang/tools/diagtool/ShowEnabledWarnings.cpp b/clang/tools/diagtool/ShowEnabledWarnings.cpp index bea0288c09358..5b25e656dafa4 100644 --- a/clang/tools/diagtool/ShowEnabledWarnings.cpp +++ b/clang/tools/diagtool/ShowEnabledWarnings.cpp @@ -9,6 +9,7 @@ #include "DiagTool.h" #include "DiagnosticNames.h" #include "clang/Basic/LLVM.h" +#include "clang/Driver/CreateInvocationFromArgs.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/TextDiagnosticBuffer.h" #include "clang/Frontend/TextDiagnosticPrinter.h" diff --git a/clang/tools/driver/cc1_main.cpp b/clang/tools/driver/cc1_main.cpp index 92357487865ce..cc757039cafd0 100644 --- a/clang/tools/driver/cc1_main.cpp +++ b/clang/tools/driver/cc1_main.cpp @@ -17,6 +17,7 @@ #include "clang/Basic/TargetOptions.h" #include "clang/CodeGen/ObjectFilePCHContainerWriter.h" #include "clang/Config/config.h" +#include "clang/Driver/Driver.h" #include "clang/Driver/DriverDiagnostic.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/CompilerInvocation.h" @@ -269,7 +270,7 @@ int cc1_main(ArrayRef Argv, const char *Argv0, void *MainAddr) { if (Clang->getHeaderSearchOpts().UseBuiltinIncludes && Clang->getHeaderSearchOpts().ResourceDir.empty()) Clang->getHeaderSearchOpts().ResourceDir = - CompilerInvocation::GetResourcesPath(Argv0, MainAddr); + GetResourcesPath(Argv0, MainAddr); /// Create the actual file system. Clang->createVirtualFileSystem(llvm::vfs::getRealFileSystem(), DiagsBuffer); diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp index f4d6fa72a1dfe..32e84248c1b27 100644 --- a/clang/tools/libclang/CIndex.cpp +++ b/clang/tools/libclang/CIndex.cpp @@ -38,6 +38,7 @@ #include "clang/Basic/Stack.h" #include "clang/Basic/TargetInfo.h" #include "clang/Basic/Version.h" +#include "clang/Driver/CreateASTUnitFromArgs.h" #include "clang/Frontend/ASTUnit.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Index/CommentToXML.h" @@ -4361,7 +4362,7 @@ clang_parseTranslationUnit_Impl(CXIndex CIdx, const char *source_filename, LibclangInvocationReporter InvocationReporter( *CXXIdx, LibclangInvocationReporter::OperationKind::ParseOperation, options, llvm::ArrayRef(*Args), /*InvocationArgs=*/{}, unsaved_files); - std::unique_ptr Unit = ASTUnit::LoadFromCommandLine( + std::unique_ptr Unit = CreateASTUnitFromCommandLine( Args->data(), Args->data() + Args->size(), CXXIdx->getPCHContainerOperations(), DiagOpts, Diags, CXXIdx->getClangResourcesPath(), CXXIdx->getStorePreamblesInMemory(), diff --git a/clang/tools/libclang/CIndexer.cpp b/clang/tools/libclang/CIndexer.cpp index 11d9312b64849..853a936b43e37 100644 --- a/clang/tools/libclang/CIndexer.cpp +++ b/clang/tools/libclang/CIndexer.cpp @@ -16,6 +16,7 @@ #include "clang/Basic/Version.h" #include "clang/Config/config.h" #include "clang/Driver/Driver.h" +#include "clang/Options/OptionUtils.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" #include "llvm/Support/FileSystem.h" @@ -137,7 +138,7 @@ const std::string &CIndexer::getClangResourcesPath() { #endif // Cache our result. - ResourcesPath = driver::Driver::GetResourcesPath(LibClangPath); + ResourcesPath = GetResourcesPath(LibClangPath); return ResourcesPath; } diff --git a/clang/tools/libclang/CMakeLists.txt b/clang/tools/libclang/CMakeLists.txt index e0ff7605b68b8..b0105f5a5f79f 100644 --- a/clang/tools/libclang/CMakeLists.txt +++ b/clang/tools/libclang/CMakeLists.txt @@ -65,6 +65,7 @@ set(LIBS clangFrontend clangIndex clangLex + clangOptions clangRewrite clangSema clangSerialization diff --git a/clang/tools/libclang/Indexing.cpp b/clang/tools/libclang/Indexing.cpp index c142f142d5071..75323d70afcfe 100644 --- a/clang/tools/libclang/Indexing.cpp +++ b/clang/tools/libclang/Indexing.cpp @@ -15,6 +15,7 @@ #include "CXString.h" #include "CXTranslationUnit.h" #include "clang/AST/ASTConsumer.h" +#include "clang/Driver/CreateInvocationFromArgs.h" #include "clang/Frontend/ASTUnit.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/CompilerInvocation.h" diff --git a/clang/unittests/Driver/DXCModeTest.cpp b/clang/unittests/Driver/DXCModeTest.cpp index e0454f190b35a..130da620b40b5 100644 --- a/clang/unittests/Driver/DXCModeTest.cpp +++ b/clang/unittests/Driver/DXCModeTest.cpp @@ -15,6 +15,7 @@ #include "clang/Basic/LLVM.h" #include "clang/Basic/TargetOptions.h" #include "clang/Driver/Compilation.h" +#include "clang/Driver/CreateInvocationFromArgs.h" #include "clang/Driver/Driver.h" #include "clang/Driver/ToolChain.h" #include "clang/Frontend/CompilerInstance.h" diff --git a/clang/unittests/Driver/ToolChainTest.cpp b/clang/unittests/Driver/ToolChainTest.cpp index afa17ff219be2..8f533790ec501 100644 --- a/clang/unittests/Driver/ToolChainTest.cpp +++ b/clang/unittests/Driver/ToolChainTest.cpp @@ -17,6 +17,7 @@ #include "clang/Basic/TargetInfo.h" #include "clang/Basic/TargetOptions.h" #include "clang/Driver/Compilation.h" +#include "clang/Driver/CreateInvocationFromArgs.h" #include "clang/Driver/Driver.h" #include "clang/Frontend/CompilerInstance.h" #include "llvm/ADT/ArrayRef.h" diff --git a/clang/unittests/Frontend/ASTUnitTest.cpp b/clang/unittests/Frontend/ASTUnitTest.cpp index dfdbe90e72f1f..bf9e4e184b5db 100644 --- a/clang/unittests/Frontend/ASTUnitTest.cpp +++ b/clang/unittests/Frontend/ASTUnitTest.cpp @@ -9,6 +9,8 @@ #include #include "clang/Basic/FileManager.h" +#include "clang/Driver/CreateASTUnitFromArgs.h" +#include "clang/Driver/CreateInvocationFromArgs.h" #include "clang/Frontend/ASTUnit.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/CompilerInvocation.h" @@ -173,7 +175,7 @@ TEST_F(ASTUnitTest, LoadFromCommandLineEarlyError) { auto PCHContainerOps = std::make_shared(); std::unique_ptr ErrUnit; - std::unique_ptr AST = ASTUnit::LoadFromCommandLine( + std::unique_ptr AST = CreateASTUnitFromCommandLine( &Args[0], &Args[4], PCHContainerOps, DiagOpts, Diags, "", false, "", false, CaptureDiagsKind::All, {}, true, 0, TU_Complete, false, false, false, SkipFunctionBodiesScope::None, false, true, false, false, @@ -201,7 +203,7 @@ TEST_F(ASTUnitTest, LoadFromCommandLineWorkingDirectory) { auto PCHContainerOps = std::make_shared(); std::unique_ptr ErrUnit; - std::unique_ptr AST = ASTUnit::LoadFromCommandLine( + std::unique_ptr AST = CreateASTUnitFromCommandLine( &Args[0], &Args[4], PCHContainerOps, DiagOpts, Diags, "", false, "", false, CaptureDiagsKind::All, {}, true, 0, TU_Complete, false, false, false, SkipFunctionBodiesScope::None, false, true, false, false, diff --git a/clang/unittests/Frontend/CompilerInstanceTest.cpp b/clang/unittests/Frontend/CompilerInstanceTest.cpp index cd3fefa1ea994..39d35b48f394a 100644 --- a/clang/unittests/Frontend/CompilerInstanceTest.cpp +++ b/clang/unittests/Frontend/CompilerInstanceTest.cpp @@ -8,6 +8,7 @@ #include "clang/Frontend/CompilerInstance.h" #include "clang/Basic/FileManager.h" +#include "clang/Driver/CreateInvocationFromArgs.h" #include "clang/Frontend/CompilerInvocation.h" #include "clang/Frontend/FrontendActions.h" #include "clang/Frontend/TextDiagnosticPrinter.h" diff --git a/clang/unittests/Frontend/UtilsTest.cpp b/clang/unittests/Frontend/UtilsTest.cpp index fc411e4af705f..a82733d57714a 100644 --- a/clang/unittests/Frontend/UtilsTest.cpp +++ b/clang/unittests/Frontend/UtilsTest.cpp @@ -9,6 +9,7 @@ #include "clang/Frontend/Utils.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/TargetOptions.h" +#include "clang/Driver/CreateInvocationFromArgs.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/CompilerInvocation.h" #include "clang/Lex/PreprocessorOptions.h" diff --git a/clang/unittests/Sema/CMakeLists.txt b/clang/unittests/Sema/CMakeLists.txt index b61ed8c457635..188f6135a60ac 100644 --- a/clang/unittests/Sema/CMakeLists.txt +++ b/clang/unittests/Sema/CMakeLists.txt @@ -13,6 +13,7 @@ add_distinct_clang_unittest(SemaTests clangAST clangASTMatchers clangBasic + clangDriver clangFrontend clangParse clangSema diff --git a/clang/unittests/Sema/SemaNoloadLookupTest.cpp b/clang/unittests/Sema/SemaNoloadLookupTest.cpp index e565372698e5e..3944269eff502 100644 --- a/clang/unittests/Sema/SemaNoloadLookupTest.cpp +++ b/clang/unittests/Sema/SemaNoloadLookupTest.cpp @@ -10,6 +10,7 @@ #include "clang/AST/DeclarationName.h" #include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/ASTMatchers/ASTMatchers.h" +#include "clang/Driver/CreateInvocationFromArgs.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendAction.h" #include "clang/Frontend/FrontendActions.h" diff --git a/clang/unittests/Serialization/ForceCheckFileInputTest.cpp b/clang/unittests/Serialization/ForceCheckFileInputTest.cpp index edf33ae04230b..b76dcfec96063 100644 --- a/clang/unittests/Serialization/ForceCheckFileInputTest.cpp +++ b/clang/unittests/Serialization/ForceCheckFileInputTest.cpp @@ -9,6 +9,7 @@ #include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/ASTMatchers/ASTMatchers.h" #include "clang/Basic/FileManager.h" +#include "clang/Driver/CreateInvocationFromArgs.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/CompilerInvocation.h" #include "clang/Frontend/FrontendActions.h" diff --git a/clang/unittests/Serialization/LoadSpecLazilyTest.cpp b/clang/unittests/Serialization/LoadSpecLazilyTest.cpp index d7b55491fddac..f55925aeae1f2 100644 --- a/clang/unittests/Serialization/LoadSpecLazilyTest.cpp +++ b/clang/unittests/Serialization/LoadSpecLazilyTest.cpp @@ -6,6 +6,7 @@ // //===----------------------------------------------------------------------===// +#include "clang/Driver/CreateInvocationFromArgs.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendAction.h" #include "clang/Frontend/FrontendActions.h" diff --git a/clang/unittests/Serialization/ModuleCacheTest.cpp b/clang/unittests/Serialization/ModuleCacheTest.cpp index e9b8da3dba6af..df26e54588b9e 100644 --- a/clang/unittests/Serialization/ModuleCacheTest.cpp +++ b/clang/unittests/Serialization/ModuleCacheTest.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "clang/Basic/FileManager.h" +#include "clang/Driver/CreateInvocationFromArgs.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/CompilerInvocation.h" #include "clang/Frontend/FrontendActions.h" diff --git a/clang/unittests/Serialization/NoCommentsTest.cpp b/clang/unittests/Serialization/NoCommentsTest.cpp index 01bb6999a7c90..444a082bba907 100644 --- a/clang/unittests/Serialization/NoCommentsTest.cpp +++ b/clang/unittests/Serialization/NoCommentsTest.cpp @@ -9,6 +9,7 @@ #include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/ASTMatchers/ASTMatchers.h" #include "clang/Basic/FileManager.h" +#include "clang/Driver/CreateInvocationFromArgs.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/CompilerInvocation.h" #include "clang/Frontend/FrontendActions.h" diff --git a/clang/unittests/Serialization/PreambleInNamedModulesTest.cpp b/clang/unittests/Serialization/PreambleInNamedModulesTest.cpp index 55ee72875ead2..b826f20ce4d70 100644 --- a/clang/unittests/Serialization/PreambleInNamedModulesTest.cpp +++ b/clang/unittests/Serialization/PreambleInNamedModulesTest.cpp @@ -6,6 +6,7 @@ // //===----------------------------------------------------------------------===// +#include "clang/Driver/CreateInvocationFromArgs.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/CompilerInvocation.h" #include "clang/Frontend/FrontendActions.h" diff --git a/clang/unittests/Serialization/VarDeclConstantInitTest.cpp b/clang/unittests/Serialization/VarDeclConstantInitTest.cpp index 743f851fc5fe1..2be01def49809 100644 --- a/clang/unittests/Serialization/VarDeclConstantInitTest.cpp +++ b/clang/unittests/Serialization/VarDeclConstantInitTest.cpp @@ -9,6 +9,7 @@ #include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/ASTMatchers/ASTMatchers.h" #include "clang/Basic/FileManager.h" +#include "clang/Driver/CreateInvocationFromArgs.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/CompilerInvocation.h" #include "clang/Frontend/FrontendActions.h" diff --git a/clang/unittests/Tooling/Syntax/TokensTest.cpp b/clang/unittests/Tooling/Syntax/TokensTest.cpp index 47184cbf5d768..468ca5ddd2c75 100644 --- a/clang/unittests/Tooling/Syntax/TokensTest.cpp +++ b/clang/unittests/Tooling/Syntax/TokensTest.cpp @@ -20,6 +20,7 @@ #include "clang/Basic/SourceManager.h" #include "clang/Basic/TokenKinds.def" #include "clang/Basic/TokenKinds.h" +#include "clang/Driver/CreateInvocationFromArgs.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendAction.h" #include "clang/Frontend/Utils.h" diff --git a/clang/unittests/Tooling/Syntax/TreeTestBase.cpp b/clang/unittests/Tooling/Syntax/TreeTestBase.cpp index b2be64fc08f3d..dad75854240ef 100644 --- a/clang/unittests/Tooling/Syntax/TreeTestBase.cpp +++ b/clang/unittests/Tooling/Syntax/TreeTestBase.cpp @@ -13,6 +13,7 @@ #include "TreeTestBase.h" #include "clang/AST/ASTConsumer.h" #include "clang/Basic/LLVM.h" +#include "clang/Driver/CreateInvocationFromArgs.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/CompilerInvocation.h" #include "clang/Frontend/FrontendAction.h" diff --git a/flang/lib/Frontend/CMakeLists.txt b/flang/lib/Frontend/CMakeLists.txt index bb0b4a39cec9b..fb74b3dcb280e 100644 --- a/flang/lib/Frontend/CMakeLists.txt +++ b/flang/lib/Frontend/CMakeLists.txt @@ -75,7 +75,6 @@ add_flang_library(flangFrontend CLANG_LIBS clangBasic - clangDriver clangOptions ) diff --git a/flang/lib/Frontend/CompilerInvocation.cpp b/flang/lib/Frontend/CompilerInvocation.cpp index 0c32f3914e04b..b6c4e6303cdac 100644 --- a/flang/lib/Frontend/CompilerInvocation.cpp +++ b/flang/lib/Frontend/CompilerInvocation.cpp @@ -325,10 +325,9 @@ static void parseCodeGenArgs(Fortran::frontend::CodeGenOptions &opts, for (auto *a : args.filtered(clang::options::OPT_fpass_plugin_EQ)) opts.LLVMPassPlugins.push_back(a->getValue()); - opts.Reciprocals = clang::driver::tools::parseMRecipOption(diags, args); + opts.Reciprocals = clang::parseMRecipOption(diags, args); - opts.PreferVectorWidth = - clang::driver::tools::parseMPreferVectorWidthOption(diags, args); + opts.PreferVectorWidth = clang::parseMPreferVectorWidthOption(diags, args); // -fembed-offload-object option for (auto *a : args.filtered(clang::options::OPT_fembed_offload_object_EQ)) diff --git a/lldb/source/Commands/CommandObjectTarget.cpp b/lldb/source/Commands/CommandObjectTarget.cpp index 30bca639060e6..7f880d223d6c3 100644 --- a/lldb/source/Commands/CommandObjectTarget.cpp +++ b/lldb/source/Commands/CommandObjectTarget.cpp @@ -60,6 +60,7 @@ #include "lldb/lldb-forward.h" #include "lldb/lldb-private-enumerations.h" +#include "clang/Driver/CreateInvocationFromArgs.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/CompilerInvocation.h" #include "clang/Frontend/FrontendActions.h" diff --git a/lldb/source/Plugins/ExpressionParser/Clang/CMakeLists.txt b/lldb/source/Plugins/ExpressionParser/Clang/CMakeLists.txt index 01d588ff6a78b..759a7c4dd14fb 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/CMakeLists.txt +++ b/lldb/source/Plugins/ExpressionParser/Clang/CMakeLists.txt @@ -51,10 +51,10 @@ add_lldb_library(lldbPluginExpressionParserClang CLANG_LIBS clangAST clangCodeGen - clangDriver clangEdit clangFrontend clangLex + clangOptions clangParse clangRewrite clangRewriteFrontend diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangHost.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangHost.cpp index 6de851081598f..660a21e3c6a8d 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangHost.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangHost.cpp @@ -10,7 +10,7 @@ #include "clang/Basic/Version.h" #include "clang/Config/config.h" -#include "clang/Driver/Driver.h" +#include "clang/Options/OptionUtils.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" @@ -53,7 +53,7 @@ static bool DefaultComputeClangResourceDirectory(FileSpec &lldb_shlib_spec, std::string raw_path = lldb_shlib_spec.GetPath(); llvm::StringRef parent_dir = llvm::sys::path::parent_path(raw_path); static const std::string clang_resource_path = - clang::driver::Driver::GetResourcesPath("bin/lldb"); + clang::GetResourcesPath("bin/lldb"); static const llvm::StringRef kResourceDirSuffixes[] = { // LLVM.org's build of LLDB uses the clang resource directory placed diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp index e37c84efefdc9..ce8dc50b84a31 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp @@ -10,6 +10,7 @@ #include "clang/Basic/DiagnosticFrontend.h" #include "clang/Basic/IdentifierTable.h" #include "clang/Basic/TargetInfo.h" +#include "clang/Driver/CreateInvocationFromArgs.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendActions.h" #include "clang/Frontend/TextDiagnosticPrinter.h" diff --git a/lldb/unittests/Expression/ClangParserTest.cpp b/lldb/unittests/Expression/ClangParserTest.cpp index fab4487c73719..c949026e87cd8 100644 --- a/lldb/unittests/Expression/ClangParserTest.cpp +++ b/lldb/unittests/Expression/ClangParserTest.cpp @@ -8,7 +8,7 @@ #include "clang/Basic/Version.h" #include "clang/Config/config.h" -#include "clang/Driver/Driver.h" +#include "clang/Options/OptionUtils.h" #include "Plugins/ExpressionParser/Clang/ClangHost.h" #include "TestingSupport/SubsystemRAII.h" @@ -43,7 +43,7 @@ TEST_F(ClangHostTest, ComputeClangResourceDirectory) { std::string path_to_liblldb = "C:\\foo\\bar\\lib\\"; #endif std::string path_to_clang_dir = - clang::driver::Driver::GetResourcesPath(path_to_liblldb + "liblldb"); + clang::GetResourcesPath(path_to_liblldb + "liblldb"); llvm::SmallString<256> path_to_clang_lib_dir_real; llvm::sys::fs::real_path(path_to_clang_dir, path_to_clang_lib_dir_real); From 8e2f5442f8a5caaa968b6215bd416ece8ed694c7 Mon Sep 17 00:00:00 2001 From: Craig Topper Date: Sun, 23 Nov 2025 09:22:34 -0800 Subject: [PATCH 09/10] [TableGen] Use std::array::fill instead of std::memset. NFC (#169204) --- llvm/utils/TableGen/Common/CodeGenDAGPatterns.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/utils/TableGen/Common/CodeGenDAGPatterns.h b/llvm/utils/TableGen/Common/CodeGenDAGPatterns.h index 2cd7ec1521feb..8146f54cd3db5 100644 --- a/llvm/utils/TableGen/Common/CodeGenDAGPatterns.h +++ b/llvm/utils/TableGen/Common/CodeGenDAGPatterns.h @@ -71,7 +71,7 @@ struct MachineValueTypeSet { return Count; } LLVM_ATTRIBUTE_ALWAYS_INLINE - void clear() { std::memset(Words.data(), 0, NumWords * sizeof(WordType)); } + void clear() { Words.fill(0); } LLVM_ATTRIBUTE_ALWAYS_INLINE bool empty() const { for (WordType W : Words) From 0b9b0b44b6eb544441411b01fb981d292cf5e33d Mon Sep 17 00:00:00 2001 From: Ron Lieberman Date: Sun, 23 Nov 2025 12:40:35 -0600 Subject: [PATCH 10/10] [comgr] GetResourcesPath changes --- amd/comgr/src/comgr-compiler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/amd/comgr/src/comgr-compiler.cpp b/amd/comgr/src/comgr-compiler.cpp index 822e4b3ce512f..358e8af87f4c8 100644 --- a/amd/comgr/src/comgr-compiler.cpp +++ b/amd/comgr/src/comgr-compiler.cpp @@ -1129,7 +1129,7 @@ amd_comgr_status_t AMDGPUCompiler::addDeviceLibraries() { SmallString<256> ClangBinaryPath(env::getLLVMPath()); sys::path::append(ClangBinaryPath, "bin", "clang"); - std::string ClangResourceDir = Driver::GetResourcesPath(ClangBinaryPath); + std::string ClangResourceDir = GetResourcesPath(ClangBinaryPath); SmallString<256> DeviceLibPath(ClangResourceDir); sys::path::append(DeviceLibPath, "lib");