From e177dd6fbbfa998751fafdeb445b83d1b0c04fbc Mon Sep 17 00:00:00 2001 From: Youngsuk Kim Date: Thu, 26 Sep 2024 16:38:50 -0400 Subject: [PATCH 001/469] [llvm] Replace uses of Type::getPointerTo() (NFC) (#110163) Replace uses of `Type::getPointerTo()` which is to be removed. --------- Co-authored-by: Nikita Popov --- llvm/lib/CodeGen/GlobalISel/CallLowering.cpp | 2 +- llvm/lib/Target/BPF/BPFCheckAndAdjustIR.cpp | 5 ++--- llvm/lib/Transforms/IPO/LowerTypeTests.cpp | 4 ++-- llvm/lib/Transforms/IPO/OpenMPOpt.cpp | 4 ++-- llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp | 2 +- 5 files changed, 8 insertions(+), 9 deletions(-) diff --git a/llvm/lib/CodeGen/GlobalISel/CallLowering.cpp b/llvm/lib/CodeGen/GlobalISel/CallLowering.cpp index 513914d3218fb..08ee6169ecee8 100644 --- a/llvm/lib/CodeGen/GlobalISel/CallLowering.cpp +++ b/llvm/lib/CodeGen/GlobalISel/CallLowering.cpp @@ -1034,7 +1034,7 @@ void CallLowering::insertSRetStores(MachineIRBuilder &MIRBuilder, Type *RetTy, unsigned NumValues = SplitVTs.size(); Align BaseAlign = DL.getPrefTypeAlign(RetTy); unsigned AS = DL.getAllocaAddrSpace(); - LLT OffsetLLTy = getLLTForType(*DL.getIndexType(RetTy->getPointerTo(AS)), DL); + LLT OffsetLLTy = getLLTForType(*DL.getIndexType(RetTy->getContext(), AS), DL); MachinePointerInfo PtrInfo(AS); diff --git a/llvm/lib/Target/BPF/BPFCheckAndAdjustIR.cpp b/llvm/lib/Target/BPF/BPFCheckAndAdjustIR.cpp index 2b78ed7134c92..660e00b893c88 100644 --- a/llvm/lib/Target/BPF/BPFCheckAndAdjustIR.cpp +++ b/llvm/lib/Target/BPF/BPFCheckAndAdjustIR.cpp @@ -440,7 +440,7 @@ static Value *aspaceWrapValue(DenseMap &Cache, Function *F, auto *GEPTy = cast(GEP->getType()); auto *NewGEP = GEP->clone(); NewGEP->insertAfter(GEP); - NewGEP->mutateType(GEPTy->getPointerTo(0)); + NewGEP->mutateType(PointerType::getUnqual(GEPTy->getContext())); NewGEP->setOperand(GEP->getPointerOperandIndex(), WrappedPtr); NewGEP->setName(GEP->getName()); Cache[ToWrap] = NewGEP; @@ -452,8 +452,7 @@ static Value *aspaceWrapValue(DenseMap &Cache, Function *F, IB.SetInsertPoint(*InsnPtr->getInsertionPointAfterDef()); else IB.SetInsertPoint(F->getEntryBlock().getFirstInsertionPt()); - auto *PtrTy = cast(ToWrap->getType()); - auto *ASZeroPtrTy = PtrTy->getPointerTo(0); + auto *ASZeroPtrTy = IB.getPtrTy(0); auto *ACast = IB.CreateAddrSpaceCast(ToWrap, ASZeroPtrTy, ToWrap->getName()); Cache[ToWrap] = ACast; return ACast; diff --git a/llvm/lib/Transforms/IPO/LowerTypeTests.cpp b/llvm/lib/Transforms/IPO/LowerTypeTests.cpp index 0742b259c489c..519a4e9314a26 100644 --- a/llvm/lib/Transforms/IPO/LowerTypeTests.cpp +++ b/llvm/lib/Transforms/IPO/LowerTypeTests.cpp @@ -1658,8 +1658,8 @@ void LowerTypeTestsModule::buildBitSetsFromFunctionsNative( ".cfi.jumptable", &M); ArrayType *JumpTableType = ArrayType::get(getJumpTableEntryType(), Functions.size()); - auto JumpTable = - ConstantExpr::getPointerCast(JumpTableFn, JumpTableType->getPointerTo(0)); + auto JumpTable = ConstantExpr::getPointerCast( + JumpTableFn, PointerType::getUnqual(M.getContext())); lowerTypeTestCalls(TypeIds, JumpTable, GlobalLayout); diff --git a/llvm/lib/Transforms/IPO/OpenMPOpt.cpp b/llvm/lib/Transforms/IPO/OpenMPOpt.cpp index 28da864cad0ff..35664a5c7a2ac 100644 --- a/llvm/lib/Transforms/IPO/OpenMPOpt.cpp +++ b/llvm/lib/Transforms/IPO/OpenMPOpt.cpp @@ -3536,8 +3536,8 @@ struct AAHeapToSharedFunction : public AAHeapToShared { PoisonValue::get(Int8ArrTy), CB->getName() + "_shared", nullptr, GlobalValue::NotThreadLocal, static_cast(AddressSpace::Shared)); - auto *NewBuffer = - ConstantExpr::getPointerCast(SharedMem, Int8Ty->getPointerTo()); + auto *NewBuffer = ConstantExpr::getPointerCast( + SharedMem, PointerType::getUnqual(M->getContext())); auto Remark = [&](OptimizationRemark OR) { return OR << "Replaced globalized variable with " diff --git a/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp b/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp index 18116b5701fe1..2f0ba5510b8f3 100644 --- a/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp +++ b/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp @@ -1743,7 +1743,7 @@ void VPVectorPointerRecipe ::execute(VPTransformState &State) { // or query DataLayout for a more suitable index type otherwise. const DataLayout &DL = Builder.GetInsertBlock()->getDataLayout(); Type *IndexTy = State.VF.isScalable() && (IsReverse || CurrentPart > 0) - ? DL.getIndexType(IndexedTy->getPointerTo()) + ? DL.getIndexType(Builder.getPtrTy(0)) : Builder.getInt32Ty(); Value *Ptr = State.get(getOperand(0), VPLane(0)); bool InBounds = isInBounds(); From bfe29945603e2040cc56d9e30f05da0627c819cd Mon Sep 17 00:00:00 2001 From: Dave Lee Date: Thu, 26 Sep 2024 13:39:54 -0700 Subject: [PATCH 002/469] [lldb] Fix minor runCmd error message formatting (#110150) This tweaks the construction of the error message when using `expect`/`runCmd`. With this change, the stdout/stderr is placed after the message "Command '' did not return successfully". Before: ``` AssertionError: False is not True : Command 'p whatever Error output: error: ' did not return successfully ``` After: ``` AssertionError: False is not True : Command 'p whatever' did not return successfully Error output: error: ``` --- lldb/packages/Python/lldbsuite/test/lldbtest.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/lldb/packages/Python/lldbsuite/test/lldbtest.py b/lldb/packages/Python/lldbsuite/test/lldbtest.py index c6b7ce84109c0..8884ef5933ada 100644 --- a/lldb/packages/Python/lldbsuite/test/lldbtest.py +++ b/lldb/packages/Python/lldbsuite/test/lldbtest.py @@ -172,9 +172,9 @@ WATCHPOINT_CREATED = "Watchpoint created successfully" -def CMD_MSG(str): +def CMD_MSG(command): """A generic "Command '%s' did not return successfully" message generator.""" - return "Command '%s' did not return successfully" % str + return f"Command '{command}' did not return successfully" def COMPLETION_MSG(str_before, str_after, completions): @@ -990,16 +990,14 @@ def runCmd(self, cmd, msg=None, check=True, trace=False, inHistory=False): print("Command '" + cmd + "' failed!", file=sbuf) if check: + if not msg: + msg = CMD_MSG(cmd) output = "" if self.res.GetOutput(): output += "\nCommand output:\n" + self.res.GetOutput() if self.res.GetError(): output += "\nError output:\n" + self.res.GetError() - if msg: - msg += output - if cmd: - cmd += output - self.assertTrue(self.res.Succeeded(), msg if (msg) else CMD_MSG(cmd)) + self.assertTrue(self.res.Succeeded(), msg + output) def HideStdout(self): """Hide output to stdout from the user. From 9483ff9f09e5c3d2c4b01fbb8272d0d5c7bcc042 Mon Sep 17 00:00:00 2001 From: Teresa Johnson Date: Thu, 26 Sep 2024 13:41:56 -0700 Subject: [PATCH 003/469] Reapply "[MemProf] Streamline and avoid unnecessary context id duplication (#107918)" (#110036) This reverts commit 12d4769cb84b2b2e60f9776fa043c6ea16f08ebb, reapplying 524a028f69cdf25503912c396ebda7ebf0065ed2 but with fixes for failures seen in broader testing. --- .../IPO/MemProfContextDisambiguation.cpp | 106 ++++++++++++------ .../MemProfContextDisambiguation/inlined4.ll | 102 +++++++++++++++++ 2 files changed, 173 insertions(+), 35 deletions(-) create mode 100644 llvm/test/Transforms/MemProfContextDisambiguation/inlined4.ll diff --git a/llvm/lib/Transforms/IPO/MemProfContextDisambiguation.cpp b/llvm/lib/Transforms/IPO/MemProfContextDisambiguation.cpp index 576a31f8b86ae..27049d547f6e3 100644 --- a/llvm/lib/Transforms/IPO/MemProfContextDisambiguation.cpp +++ b/llvm/lib/Transforms/IPO/MemProfContextDisambiguation.cpp @@ -1377,9 +1377,12 @@ void CallsiteContextGraph:: // Compute the last node's context ids once, as it is shared by all calls in // this entry. DenseSet LastNodeContextIds = LastNode->getContextIds(); - assert(!LastNodeContextIds.empty()); - for (unsigned I = 0; I < Calls.size(); I++) { + bool PrevIterCreatedNode = false; + bool CreatedNode = false; + for (unsigned I = 0; I < Calls.size(); + I++, PrevIterCreatedNode = CreatedNode) { + CreatedNode = false; auto &[Call, Ids, Func, SavedContextIds] = Calls[I]; // Skip any for which we didn't assign any ids, these don't get a node in // the graph. @@ -1391,7 +1394,13 @@ void CallsiteContextGraph:: if (!CallToMatchingCall.contains(Call)) continue; auto MatchingCall = CallToMatchingCall[Call]; - assert(NonAllocationCallToContextNodeMap.contains(MatchingCall)); + if (!NonAllocationCallToContextNodeMap.contains(MatchingCall)) { + // This should only happen if we had a prior iteration, and it didn't + // create a node because of the below recomputation of context ids + // finding none remaining and continuing early. + assert(I > 0 && !PrevIterCreatedNode); + continue; + } NonAllocationCallToContextNodeMap[MatchingCall]->MatchingCalls.push_back( Call); continue; @@ -1444,6 +1453,7 @@ void CallsiteContextGraph:: ContextNode *NewNode = NodeOwner.back().get(); NodeToCallingFunc[NewNode] = Func; NonAllocationCallToContextNodeMap[Call] = NewNode; + CreatedNode = true; NewNode->AllocTypes = computeAllocType(SavedContextIds); ContextNode *FirstNode = getNodeForStackId(Ids[0]); @@ -1548,13 +1558,23 @@ void CallsiteContextGraph::updateStackNodes() { // of length, and within each length, lexicographically by stack id. The // latter is so that we can specially handle calls that have identical stack // id sequences (either due to cloning or artificially because of the MIB - // context pruning). - std::stable_sort(Calls.begin(), Calls.end(), - [](const CallContextInfo &A, const CallContextInfo &B) { - return A.StackIds.size() > B.StackIds.size() || - (A.StackIds.size() == B.StackIds.size() && - A.StackIds < B.StackIds); - }); + // context pruning). Those with the same Ids are then sorted by function to + // facilitate efficiently mapping them to the same context node. + // Because the functions are pointers, to ensure a stable sort first assign + // each function pointer to its first index in the Calls array, and then use + // that to sort by. + DenseMap FuncToIndex; + for (const auto &[Idx, CallCtxInfo] : enumerate(Calls)) + FuncToIndex.insert({CallCtxInfo.Func, Idx}); + std::stable_sort( + Calls.begin(), Calls.end(), + [&FuncToIndex](const CallContextInfo &A, const CallContextInfo &B) { + return A.StackIds.size() > B.StackIds.size() || + (A.StackIds.size() == B.StackIds.size() && + (A.StackIds < B.StackIds || + (A.StackIds == B.StackIds && + FuncToIndex[A.Func] < FuncToIndex[B.Func]))); + }); // Find the node for the last stack id, which should be the same // across all calls recorded for this id, and is the id for this @@ -1572,18 +1592,26 @@ void CallsiteContextGraph::updateStackNodes() { DenseSet LastNodeContextIds = LastNode->getContextIds(); assert(!LastNodeContextIds.empty()); - // Map from function to the first call from the below list (with matching - // stack ids) found in that function. Note that calls from different - // functions can have the same stack ids because this is the list of stack - // ids that had (possibly pruned) nodes after building the graph from the - // allocation MIBs. - DenseMap FuncToCallMap; +#ifndef NDEBUG + // Save the set of functions seen for a particular set of the same stack + // ids. This is used to ensure that they have been correctly sorted to be + // adjacent in the Calls list, since we rely on that to efficiently place + // all such matching calls onto the same context node. + DenseSet MatchingIdsFuncSet; +#endif for (unsigned I = 0; I < Calls.size(); I++) { auto &[Call, Ids, Func, SavedContextIds] = Calls[I]; assert(SavedContextIds.empty()); assert(LastId == Ids.back()); +#ifndef NDEBUG + // If this call has a different set of ids than the last one, clear the + // set used to ensure they are sorted properly. + if (I > 0 && Ids != Calls[I - 1].StackIds) + MatchingIdsFuncSet.clear(); +#endif + // First compute the context ids for this stack id sequence (the // intersection of the context ids of the corresponding nodes). // Start with the remaining saved ids for the last node. @@ -1652,23 +1680,38 @@ void CallsiteContextGraph::updateStackNodes() { continue; } - // If the prior call had the same stack ids this map would not be empty. +#ifndef NDEBUG + // If the prior call had the same stack ids this set would not be empty. // Check if we already have a call that "matches" because it is located - // in the same function. - if (FuncToCallMap.contains(Func)) { - // Record the matching call found for this call, and skip it. We - // will subsequently combine it into the same node. - CallToMatchingCall[Call] = FuncToCallMap[Func]; - continue; - } + // in the same function. If the Calls list was sorted properly we should + // not encounter this situation as all such entries should be adjacent + // and processed in bulk further below. + assert(!MatchingIdsFuncSet.contains(Func)); + + MatchingIdsFuncSet.insert(Func); +#endif // Check if the next set of stack ids is the same (since the Calls vector // of tuples is sorted by the stack ids we can just look at the next one). + // If so, save them in the CallToMatchingCall map so that they get + // assigned to the same context node, and skip them. bool DuplicateContextIds = false; - if (I + 1 < Calls.size()) { - auto &CallCtxInfo = Calls[I + 1]; + for (unsigned J = I + 1; J < Calls.size(); J++) { + auto &CallCtxInfo = Calls[J]; auto &NextIds = CallCtxInfo.StackIds; - DuplicateContextIds = Ids == NextIds; + if (NextIds != Ids) + break; + auto *NextFunc = CallCtxInfo.Func; + if (NextFunc != Func) { + // We have another Call with the same ids but that cannot share this + // node, must duplicate ids for it. + DuplicateContextIds = true; + break; + } + auto &NextCall = CallCtxInfo.Call; + CallToMatchingCall[NextCall] = Call; + // Update I so that it gets incremented correctly to skip this call. + I = J; } // If we don't have duplicate context ids, then we can assign all the @@ -1692,14 +1735,7 @@ void CallsiteContextGraph::updateStackNodes() { set_subtract(LastNodeContextIds, StackSequenceContextIds); if (LastNodeContextIds.empty()) break; - // No longer possibly in a sequence of calls with duplicate stack ids, - // clear the map. - FuncToCallMap.clear(); - } else - // Record the call with its function, so we can locate it the next time - // we find a call from this function when processing the calls with the - // same stack ids. - FuncToCallMap[Func] = Call; + } } } diff --git a/llvm/test/Transforms/MemProfContextDisambiguation/inlined4.ll b/llvm/test/Transforms/MemProfContextDisambiguation/inlined4.ll new file mode 100644 index 0000000000000..bf419ea987bd0 --- /dev/null +++ b/llvm/test/Transforms/MemProfContextDisambiguation/inlined4.ll @@ -0,0 +1,102 @@ +;; This test ensures that the logic which assigns calls to stack nodes +;; correctly handles a case where multiple nodes have stack ids that +;; overlap with each other but have different last nodes (can happen with +;; inlining into various levels of a call chain). Specifically, when we +;; have one that is duplicated (e.g. unrolling), we need to correctly +;; handle the case where the context id has already been assigned to +;; a different call with a different last node. + +;; -stats requires asserts +; REQUIRES: asserts + +; RUN: opt -passes=memprof-context-disambiguation -supports-hot-cold-new \ +; RUN: -memprof-verify-ccg -memprof-verify-nodes \ +; RUN: -stats -pass-remarks=memprof-context-disambiguation \ +; RUN: %s -S 2>&1 | FileCheck %s --check-prefix=IR \ +; RUN: --check-prefix=STATS --check-prefix=REMARKS + +; REMARKS: created clone _Z1Ab.memprof.1 +; REMARKS: created clone _Z3XZNv.memprof.1 +; REMARKS: call in clone main assigned to call function clone _Z3XZNv.memprof.1 +;; Make sure the inlined context in _Z3XZNv, which partially overlaps the stack +;; ids in the shorter inlined context of Z2XZv, correctly calls a cloned +;; version of Z1Ab, which will call the cold annotated allocation. +; REMARKS: call in clone _Z3XZNv.memprof.1 assigned to call function clone _Z1Ab.memprof.1 +; REMARKS: call in clone _Z1Ab.memprof.1 marked with memprof allocation attribute cold +; REMARKS: call in clone main assigned to call function clone _Z3XZNv +; REMARKS: call in clone _Z3XZNv assigned to call function clone _Z1Ab +; REMARKS: call in clone _Z1Ab marked with memprof allocation attribute notcold + + +target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +define dso_local void @_Z1Ab() { +entry: + %call = call noalias noundef nonnull ptr @_Znam(i64 noundef 10) #1, !memprof !0, !callsite !5 + ret void +} + +; Function Attrs: nobuiltin +declare ptr @_Znam(i64) #0 + +;; Inlining of stack id 2 into 3. Assume this is called from somewhere else. +define dso_local void @_Z2XZv() local_unnamed_addr #0 { +entry: + ;; Simulate duplication of the callsite (e.g. unrolling). + call void @_Z1Ab(), !callsite !6 + call void @_Z1Ab(), !callsite !6 + ret void +} + +;; Inlining of stack id 2 into 3 into 4. Called by main below. +define dso_local void @_Z3XZNv() local_unnamed_addr { +entry: + call void @_Z1Ab(), !callsite !7 + ret void +} + +define dso_local noundef i32 @main() local_unnamed_addr { +entry: + call void @_Z3XZNv(), !callsite !8 ;; Not cold context + call void @_Z3XZNv(), !callsite !9 ;; Cold context + ret i32 0 +} + +attributes #0 = { nobuiltin } +attributes #7 = { builtin } + +!0 = !{!1, !3} +;; Not cold context via first call to _Z3XZNv in main +!1 = !{!2, !"notcold"} +!2 = !{i64 1, i64 2, i64 3, i64 4, i64 5} +;; Cold context via second call to _Z3XZNv in main +!3 = !{!4, !"cold"} +!4 = !{i64 1, i64 2, i64 3, i64 4, i64 6} +!5 = !{i64 1} +!6 = !{i64 2, i64 3} +!7 = !{i64 2, i64 3, i64 4} +!8 = !{i64 5} +!9 = !{i64 6} + +; IR: define {{.*}} @_Z1Ab() +; IR: call {{.*}} @_Znam(i64 noundef 10) #[[NOTCOLD:[0-9]+]] +; IR: define {{.*}} @_Z2XZv() +; IR: call {{.*}} @_Z1Ab() +; IR: call {{.*}} @_Z1Ab() +; IR: define {{.*}} @_Z3XZNv() +; IR: call {{.*}} @_Z1Ab() +; IR: define {{.*}} @main() +; IR: call {{.*}} @_Z3XZNv() +; IR: call {{.*}} @_Z3XZNv.memprof.1() +; IR: define {{.*}} @_Z1Ab.memprof.1() +; IR: call {{.*}} @_Znam(i64 noundef 10) #[[COLD:[0-9]+]] +; IR: define {{.*}} @_Z3XZNv.memprof.1() +; IR: call {{.*}} @_Z1Ab.memprof.1() + +; IR: attributes #[[NOTCOLD]] = { "memprof"="notcold" } +; IR: attributes #[[COLD]] = { "memprof"="cold" } + +; STATS: 1 memprof-context-disambiguation - Number of cold static allocations (possibly cloned) +; STATS: 1 memprof-context-disambiguation - Number of not cold static allocations (possibly cloned) +; STATS: 2 memprof-context-disambiguation - Number of function clones created during whole program analysis From 0950078ba07116f52402c22b173ae113432d2b83 Mon Sep 17 00:00:00 2001 From: Rahul Joshi Date: Thu, 26 Sep 2024 13:51:43 -0700 Subject: [PATCH 004/469] [LLVM][TableGen] Change DXILEmitter to use const Record pointers (#110111) Change DXILEmitter to use const Record pointers. This is a part of effort to have better const correctness in TableGen backends: https://discourse.llvm.org/t/psa-planned-changes-to-tablegen-getallderiveddefinitions-api-potential-downstream-breakages/81089 --- llvm/utils/TableGen/DXILEmitter.cpp | 39 ++++++++++++++--------------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/llvm/utils/TableGen/DXILEmitter.cpp b/llvm/utils/TableGen/DXILEmitter.cpp index a4b5495092867..bab53adbaefe3 100644 --- a/llvm/utils/TableGen/DXILEmitter.cpp +++ b/llvm/utils/TableGen/DXILEmitter.cpp @@ -39,10 +39,10 @@ struct DXILOperationDesc { StringRef OpClass; // name of the opcode class StringRef Doc; // the documentation description of this instruction // Vector of operand type records - return type is at index 0 - SmallVector OpTypes; - SmallVector OverloadRecs; - SmallVector StageRecs; - SmallVector AttrRecs; + SmallVector OpTypes; + SmallVector OverloadRecs; + SmallVector StageRecs; + SmallVector AttrRecs; StringRef Intrinsic; // The llvm intrinsic map to OpName. Default is "" which // means no map exists SmallVector @@ -57,8 +57,8 @@ struct DXILOperationDesc { /// In-place sort TableGen records of class with a field /// Version dxil_version /// in the ascending version order. -static void AscendingSortByVersion(std::vector &Recs) { - std::sort(Recs.begin(), Recs.end(), [](Record *RecA, Record *RecB) { +static void AscendingSortByVersion(std::vector &Recs) { + sort(Recs, [](const Record *RecA, const Record *RecB) { unsigned RecAMaj = RecA->getValueAsDef("dxil_version")->getValueAsInt("Major"); unsigned RecAMin = @@ -82,13 +82,12 @@ DXILOperationDesc::DXILOperationDesc(const Record *R) { OpCode = R->getValueAsInt("OpCode"); Doc = R->getValueAsString("Doc"); - SmallVector ParamTypeRecs; + SmallVector ParamTypeRecs; ParamTypeRecs.push_back(R->getValueAsDef("result")); - std::vector ArgTys = R->getValueAsListOfDefs("arguments"); - for (auto Ty : ArgTys) { - ParamTypeRecs.push_back(Ty); + for (const Record *ArgTy : R->getValueAsListOfDefs("arguments")) { + ParamTypeRecs.push_back(ArgTy); } size_t ParamTypeRecsSize = ParamTypeRecs.size(); // Populate OpTypes with return type and parameter types @@ -100,7 +99,7 @@ DXILOperationDesc::DXILOperationDesc(const Record *R) { // llvm/IR/Intrinsics.td OverloadParamIndex = -1; // A sigil meaning none. for (unsigned i = 0; i < ParamTypeRecsSize; i++) { - Record *TR = ParamTypeRecs[i]; + const Record *TR = ParamTypeRecs[i]; // Track operation parameter indices of any overload types if (TR->getValueAsInt("isOverload")) { if (OverloadParamIndex != -1) { @@ -117,17 +116,17 @@ DXILOperationDesc::DXILOperationDesc(const Record *R) { } // Get overload records - std::vector Recs = R->getValueAsListOfDefs("overloads"); + std::vector Recs = R->getValueAsListOfConstDefs("overloads"); // Sort records in ascending order of DXIL version AscendingSortByVersion(Recs); - for (Record *CR : Recs) { + for (const Record *CR : Recs) { OverloadRecs.push_back(CR); } // Get stage records - Recs = R->getValueAsListOfDefs("stages"); + Recs = R->getValueAsListOfConstDefs("stages"); if (Recs.empty()) { PrintFatalError(R, Twine("Atleast one specification of valid stage for ") + @@ -137,17 +136,17 @@ DXILOperationDesc::DXILOperationDesc(const Record *R) { // Sort records in ascending order of DXIL version AscendingSortByVersion(Recs); - for (Record *CR : Recs) { + for (const Record *CR : Recs) { StageRecs.push_back(CR); } // Get attribute records - Recs = R->getValueAsListOfDefs("attributes"); + Recs = R->getValueAsListOfConstDefs("attributes"); // Sort records in ascending order of DXIL version AscendingSortByVersion(Recs); - for (Record *CR : Recs) { + for (const Record *CR : Recs) { AttrRecs.push_back(CR); } @@ -201,7 +200,7 @@ static StringRef getOverloadKindStr(const Record *R) { /// \return std::string string representation of overload mask string /// predicated by DXIL Version. E.g., // {{{1, 0}, Mask1}, {{1, 2}, Mask2}, ...} -static std::string getOverloadMaskString(const SmallVector Recs) { +static std::string getOverloadMaskString(ArrayRef Recs) { std::string MaskString = ""; std::string Prefix = ""; MaskString.append("{"); @@ -247,7 +246,7 @@ static std::string getOverloadMaskString(const SmallVector Recs) { /// \return std::string string representation of stages mask string /// predicated by DXIL Version. E.g., // {{{1, 0}, Mask1}, {{1, 2}, Mask2}, ...} -static std::string getStageMaskString(const SmallVector Recs) { +static std::string getStageMaskString(ArrayRef Recs) { std::string MaskString = ""; std::string Prefix = ""; MaskString.append("{"); @@ -290,7 +289,7 @@ static std::string getStageMaskString(const SmallVector Recs) { /// \return std::string string representation of stages mask string /// predicated by DXIL Version. E.g., // {{{1, 0}, Mask1}, {{1, 2}, Mask2}, ...} -static std::string getAttributeMaskString(const SmallVector Recs) { +static std::string getAttributeMaskString(ArrayRef Recs) { std::string MaskString = ""; std::string Prefix = ""; MaskString.append("{"); From 90b7fe42d8e6f8647ce9279d6d026c36ccfcbb8f Mon Sep 17 00:00:00 2001 From: Helena Kotas Date: Thu, 26 Sep 2024 13:56:49 -0700 Subject: [PATCH 005/469] [HLSL] Remove `__builtin_hlsl_create_handle` (#109910) The `__builtin_hlsl_create_handle` called from the constructor of resource buffer class was supposed to initialize the resource handle based on resource type and registry binding information. It is not possible to do though that because the registry binding information is not accessible from the constructor during codegen. Instead, the handle should be initialized to an empty or null handle with something like `__builtin_hlsl_create_null_handle`. This PR is removing `__builtin_hlsl_create_handle` first and the `__builtin_hlsl_create_null_handle` will be added to the constructor once the handle type changes to `__hlsl_resource_t` and HLSLAttributeResourceType is updated to be a canonical type, which will allow the initialization assignment. The actual handle initialization based on the registry binding will be implemented part 2/2 of llvm/llvm-project#105076 once the dependent tasks are completed. Part 1/2 of llvm/llvm-project#105076. --- clang/include/clang/Basic/Builtins.td | 6 ---- clang/lib/Sema/HLSLExternalSemaSource.cpp | 32 ++----------------- clang/test/AST/HLSL/RWBuffer-AST.hlsl | 2 +- clang/test/AST/HLSL/StructuredBuffer-AST.hlsl | 2 +- .../builtins/RWBuffer-constructor.hlsl | 8 ++++- .../StructuredBuffer-constructor.hlsl | 7 ++++ .../CodeGenHLSL/builtins/create_handle.hlsl | 7 ---- .../hlsl_resource_handle_attrs.hlsl | 4 +-- llvm/include/llvm/IR/IntrinsicsDirectX.td | 3 -- llvm/include/llvm/IR/IntrinsicsSPIRV.td | 2 -- llvm/unittests/IR/IntrinsicsTest.cpp | 1 - 11 files changed, 20 insertions(+), 54 deletions(-) delete mode 100644 clang/test/CodeGenHLSL/builtins/create_handle.hlsl diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td index 8c5d7ad763bf9..33791270800c9 100644 --- a/clang/include/clang/Basic/Builtins.td +++ b/clang/include/clang/Basic/Builtins.td @@ -4703,12 +4703,6 @@ def HLSLClamp : LangBuiltin<"HLSL_LANG"> { let Prototype = "void(...)"; } -def HLSLCreateHandle : LangBuiltin<"HLSL_LANG"> { - let Spellings = ["__builtin_hlsl_create_handle"]; - let Attributes = [NoThrow, Const]; - let Prototype = "void*(unsigned char)"; -} - def HLSLDotProduct : LangBuiltin<"HLSL_LANG"> { let Spellings = ["__builtin_hlsl_dot"]; let Attributes = [NoThrow, Const]; diff --git a/clang/lib/Sema/HLSLExternalSemaSource.cpp b/clang/lib/Sema/HLSLExternalSemaSource.cpp index d19f79b6ddefc..ca521dc0bcd26 100644 --- a/clang/lib/Sema/HLSLExternalSemaSource.cpp +++ b/clang/lib/Sema/HLSLExternalSemaSource.cpp @@ -193,36 +193,8 @@ struct BuiltinTypeDeclBuilder { ExplicitSpecifier(), false, true, false, ConstexprSpecKind::Unspecified); - DeclRefExpr *Fn = - lookupBuiltinFunction(AST, S, "__builtin_hlsl_create_handle"); - Expr *RCExpr = emitResourceClassExpr(AST, RC); - Expr *Call = CallExpr::Create(AST, Fn, {RCExpr}, AST.VoidPtrTy, VK_PRValue, - SourceLocation(), FPOptionsOverride()); - - CXXThisExpr *This = CXXThisExpr::Create( - AST, SourceLocation(), Constructor->getFunctionObjectParameterType(), - true); - Expr *Handle = MemberExpr::CreateImplicit(AST, This, false, Fields["h"], - Fields["h"]->getType(), VK_LValue, - OK_Ordinary); - - // If the handle isn't a void pointer, cast the builtin result to the - // correct type. - if (Handle->getType().getCanonicalType() != AST.VoidPtrTy) { - Call = CXXStaticCastExpr::Create( - AST, Handle->getType(), VK_PRValue, CK_Dependent, Call, nullptr, - AST.getTrivialTypeSourceInfo(Handle->getType(), SourceLocation()), - FPOptionsOverride(), SourceLocation(), SourceLocation(), - SourceRange()); - } - - BinaryOperator *Assign = BinaryOperator::Create( - AST, Handle, Call, BO_Assign, Handle->getType(), VK_LValue, OK_Ordinary, - SourceLocation(), FPOptionsOverride()); - - Constructor->setBody( - CompoundStmt::Create(AST, {Assign}, FPOptionsOverride(), - SourceLocation(), SourceLocation())); + Constructor->setBody(CompoundStmt::Create( + AST, {}, FPOptionsOverride(), SourceLocation(), SourceLocation())); Constructor->setAccess(AccessSpecifier::AS_public); Record->addDecl(Constructor); return *this; diff --git a/clang/test/AST/HLSL/RWBuffer-AST.hlsl b/clang/test/AST/HLSL/RWBuffer-AST.hlsl index c3ba520e0f68e..a95be63da5dc1 100644 --- a/clang/test/AST/HLSL/RWBuffer-AST.hlsl +++ b/clang/test/AST/HLSL/RWBuffer-AST.hlsl @@ -66,7 +66,7 @@ RWBuffer Buffer; // CHECK: TemplateArgument type 'float' // CHECK-NEXT: BuiltinType 0x{{[0-9A-Fa-f]+}} 'float' // CHECK-NEXT: FinalAttr 0x{{[0-9A-Fa-f]+}} <> Implicit final -// CHECK-NEXT: FieldDecl 0x{{[0-9A-Fa-f]+}} <> implicit referenced h 'float * +// CHECK-NEXT: FieldDecl 0x{{[0-9A-Fa-f]+}} <> implicit h 'float * // CHECK-SAME{LITERAL}: [[hlsl::resource_class(UAV)]] // CHECK-SAME{LITERAL}: [[hlsl::contained_type(float)]] // CHECK-SAME: ':'float *' diff --git a/clang/test/AST/HLSL/StructuredBuffer-AST.hlsl b/clang/test/AST/HLSL/StructuredBuffer-AST.hlsl index 1a3deba5830fa..a186779870c26 100644 --- a/clang/test/AST/HLSL/StructuredBuffer-AST.hlsl +++ b/clang/test/AST/HLSL/StructuredBuffer-AST.hlsl @@ -70,7 +70,7 @@ StructuredBuffer Buffer; // CHECK: TemplateArgument type 'float' // CHECK-NEXT: BuiltinType 0x{{[0-9A-Fa-f]+}} 'float' // CHECK-NEXT: FinalAttr 0x{{[0-9A-Fa-f]+}} <> Implicit final -// CHECK-NEXT: FieldDecl 0x{{[0-9A-Fa-f]+}} <> implicit referenced h 'float * +// CHECK-NEXT: FieldDecl 0x{{[0-9A-Fa-f]+}} <> implicit h 'float * // CHECK-SAME{LITERAL}: [[hlsl::resource_class(UAV)]] // CHECK-SAME{LITERAL}: [[hlsl::raw_buffer]] // CHECK-SAME{LITERAL}: [[hlsl::contained_type(float)]] diff --git a/clang/test/CodeGenHLSL/builtins/RWBuffer-constructor.hlsl b/clang/test/CodeGenHLSL/builtins/RWBuffer-constructor.hlsl index 174f4c3eaaad2..19699dcf14d9f 100644 --- a/clang/test/CodeGenHLSL/builtins/RWBuffer-constructor.hlsl +++ b/clang/test/CodeGenHLSL/builtins/RWBuffer-constructor.hlsl @@ -1,6 +1,12 @@ // RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s // RUN: %clang_cc1 -triple spirv-vulkan-library -x hlsl -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s --check-prefix=CHECK-SPIRV +// XFAIL: * +// This expectedly fails because create.handle is no longer called +// from RWBuffer constructor and the replacement has not been +// implemented yet. This test should be updated to expect +// dx.create.handleFromBinding as part of issue #105076. + RWBuffer Buf; // CHECK: define linkonce_odr noundef ptr @"??0?$RWBuffer@M@hlsl@@QAA@XZ" @@ -10,4 +16,4 @@ RWBuffer Buf; // CHECK: store ptr %[[HandleRes]], ptr %h, align 4 // CHECK-SPIRV: %[[HandleRes:[0-9]+]] = call ptr @llvm.spv.create.handle(i8 1) -// CHECK-SPIRV: store ptr %[[HandleRes]], ptr %h, align 8 \ No newline at end of file +// CHECK-SPIRV: store ptr %[[HandleRes]], ptr %h, align 8 diff --git a/clang/test/CodeGenHLSL/builtins/StructuredBuffer-constructor.hlsl b/clang/test/CodeGenHLSL/builtins/StructuredBuffer-constructor.hlsl index 34019e5b18693..178332d03e640 100644 --- a/clang/test/CodeGenHLSL/builtins/StructuredBuffer-constructor.hlsl +++ b/clang/test/CodeGenHLSL/builtins/StructuredBuffer-constructor.hlsl @@ -1,5 +1,12 @@ +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s // RUN: %clang_cc1 -triple spirv-vulkan-library -x hlsl -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s --check-prefix=CHECK-SPIRV +// XFAIL: * +// This expectedly fails because create.handle is no longer invoked +// from StructuredBuffer constructor and the replacement has not been +// implemented yet. This test should be updated to expect +// dx.create.handleFromBinding as part of issue #105076. + StructuredBuffer Buf; // CHECK: define linkonce_odr noundef ptr @"??0?$StructuredBuffer@M@hlsl@@QAA@XZ" diff --git a/clang/test/CodeGenHLSL/builtins/create_handle.hlsl b/clang/test/CodeGenHLSL/builtins/create_handle.hlsl deleted file mode 100644 index 61226c2b54e72..0000000000000 --- a/clang/test/CodeGenHLSL/builtins/create_handle.hlsl +++ /dev/null @@ -1,7 +0,0 @@ -// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s - -void fn() { - (void)__builtin_hlsl_create_handle(0); -} - -// CHECK: call ptr @llvm.dx.create.handle(i8 0) diff --git a/clang/test/ParserHLSL/hlsl_resource_handle_attrs.hlsl b/clang/test/ParserHLSL/hlsl_resource_handle_attrs.hlsl index 301d61c0e906e..5e4ed96561a30 100644 --- a/clang/test/ParserHLSL/hlsl_resource_handle_attrs.hlsl +++ b/clang/test/ParserHLSL/hlsl_resource_handle_attrs.hlsl @@ -3,7 +3,7 @@ // CHECK: -ClassTemplateSpecializationDecl 0x{{[0-9a-f]+}} <> class RWBuffer definition implicit_instantiation // CHECK: -TemplateArgument type 'float' // CHECK: `-BuiltinType 0x{{[0-9a-f]+}} 'float' -// CHECK: -FieldDecl 0x{{[0-9a-f]+}} <> implicit referenced h 'float * +// CHECK: -FieldDecl 0x{{[0-9a-f]+}} <> implicit h 'float * // CHECK-SAME{LITERAL}: [[hlsl::resource_class(UAV)]] // CHECK-SAME{LITERAL}: [[hlsl::contained_type(float)]] // CHECK-SAME: ':'float *' @@ -14,7 +14,7 @@ RWBuffer Buffer1; // CHECK: -TemplateArgument type 'vector' // CHECK: `-ExtVectorType 0x{{[0-9a-f]+}} 'vector' 4 // CHECK: `-BuiltinType 0x{{[0-9a-f]+}} 'float' -// CHECK: -FieldDecl 0x{{[0-9a-f]+}} <> implicit referenced h 'vector +// CHECK: -FieldDecl 0x{{[0-9a-f]+}} <> implicit h 'vector // CHECK-SAME{LITERAL}: [[hlsl::resource_class(UAV)] // CHECK-SAME{LITERAL}: [[hlsl::is_rov]] // CHECK-SAME{LITERAL}: [[hlsl::contained_type(vector)]] diff --git a/llvm/include/llvm/IR/IntrinsicsDirectX.td b/llvm/include/llvm/IR/IntrinsicsDirectX.td index 3ce7b8b987ef8..555877e7aaf0e 100644 --- a/llvm/include/llvm/IR/IntrinsicsDirectX.td +++ b/llvm/include/llvm/IR/IntrinsicsDirectX.td @@ -17,9 +17,6 @@ def int_dx_group_id : Intrinsic<[llvm_i32_ty], [llvm_i32_ty], [IntrNoMem, IntrWi def int_dx_thread_id_in_group : Intrinsic<[llvm_i32_ty], [llvm_i32_ty], [IntrNoMem, IntrWillReturn]>; def int_dx_flattened_thread_id_in_group : Intrinsic<[llvm_i32_ty], [], [IntrNoMem, IntrWillReturn]>; -def int_dx_create_handle : ClangBuiltin<"__builtin_hlsl_create_handle">, - Intrinsic<[ llvm_ptr_ty ], [llvm_i8_ty], [IntrWillReturn]>; - // Create resource handle given binding information. Returns a `target("dx.")` // type appropriate for the kind of resource given a register space ID, lower // bound and range size of the binding, as well as an index and an indicator diff --git a/llvm/include/llvm/IR/IntrinsicsSPIRV.td b/llvm/include/llvm/IR/IntrinsicsSPIRV.td index c5c60963ed6fd..7ff3d58690ba7 100644 --- a/llvm/include/llvm/IR/IntrinsicsSPIRV.td +++ b/llvm/include/llvm/IR/IntrinsicsSPIRV.td @@ -59,8 +59,6 @@ let TargetPrefix = "spv" in { // The following intrinsic(s) are mirrored from IntrinsicsDirectX.td for HLSL support. def int_spv_thread_id : Intrinsic<[llvm_i32_ty], [llvm_i32_ty], [IntrNoMem, IntrWillReturn]>; - def int_spv_create_handle : ClangBuiltin<"__builtin_hlsl_create_handle">, - Intrinsic<[ llvm_ptr_ty ], [llvm_i8_ty], [IntrWillReturn]>; def int_spv_all : DefaultAttrsIntrinsic<[llvm_i1_ty], [llvm_any_ty]>; def int_spv_any : DefaultAttrsIntrinsic<[llvm_i1_ty], [llvm_any_ty]>; def int_spv_frac : DefaultAttrsIntrinsic<[LLVMMatchType<0>], [llvm_anyfloat_ty]>; diff --git a/llvm/unittests/IR/IntrinsicsTest.cpp b/llvm/unittests/IR/IntrinsicsTest.cpp index a92ffe3cdeb7e..0c4af28a2ab57 100644 --- a/llvm/unittests/IR/IntrinsicsTest.cpp +++ b/llvm/unittests/IR/IntrinsicsTest.cpp @@ -94,7 +94,6 @@ TEST(IntrinsicNameLookup, ClangBuiltinLookup) { {"__builtin_amdgcn_workgroup_id_z", "amdgcn", amdgcn_workgroup_id_z}, {"__builtin_arm_cdp", "arm", arm_cdp}, {"__builtin_bpf_preserve_type_info", "bpf", bpf_preserve_type_info}, - {"__builtin_hlsl_create_handle", "dx", dx_create_handle}, {"__builtin_HEXAGON_A2_tfr", "hexagon", hexagon_A2_tfr}, {"__builtin_lasx_xbz_w", "loongarch", loongarch_lasx_xbz_w}, {"__builtin_mips_bitrev", "mips", mips_bitrev}, From d1297638a381c4c7da93af4cd48173f4cef4252d Mon Sep 17 00:00:00 2001 From: norx1991 Date: Thu, 26 Sep 2024 16:09:36 -0500 Subject: [PATCH 006/469] Update BUILD.bazel (#110170) It was broken by https://github.com/llvm/llvm-project/pull/100667 --- .../llvm-project-overlay/mlir/BUILD.bazel | 70 +++++++++++++++---- 1 file changed, 56 insertions(+), 14 deletions(-) diff --git a/utils/bazel/llvm-project-overlay/mlir/BUILD.bazel b/utils/bazel/llvm-project-overlay/mlir/BUILD.bazel index f5437245e8e13..dada2b6ecca38 100644 --- a/utils/bazel/llvm-project-overlay/mlir/BUILD.bazel +++ b/utils/bazel/llvm-project-overlay/mlir/BUILD.bazel @@ -9615,6 +9615,7 @@ cc_library( ":PolynomialDialect", ":PtrDialect", ":QuantOps", + ":QuantTransforms", ":ROCDLDialect", ":ROCDLTarget", ":ReconcileUnrealizedCasts", @@ -10662,8 +10663,8 @@ cc_library( td_library( name = "QuantizationOpsTdFiles", srcs = [ - "include/mlir/Dialect/Quant/QuantOps.td", - "include/mlir/Dialect/Quant/QuantOpsBase.td", + "include/mlir/Dialect/Quant/IR/QuantOps.td", + "include/mlir/Dialect/Quant/IR/QuantBase.td", ], includes = ["include"], deps = [ @@ -10678,19 +10679,19 @@ gentbl_cc_library( tbl_outs = [ ( ["-gen-op-decls"], - "include/mlir/Dialect/Quant/QuantOps.h.inc", + "include/mlir/Dialect/Quant/IR/QuantOps.h.inc", ), ( ["-gen-op-defs"], - "include/mlir/Dialect/Quant/QuantOps.cpp.inc", + "include/mlir/Dialect/Quant/IR/QuantOps.cpp.inc", ), ( ["-gen-dialect-decls"], - "include/mlir/Dialect/Quant/QuantOpsDialect.h.inc", + "include/mlir/Dialect/Quant/IR/QuantOpsDialect.h.inc", ), ( ["-gen-dialect-defs"], - "include/mlir/Dialect/Quant/QuantOpsDialect.cpp.inc", + "include/mlir/Dialect/Quant/IR/QuantOpsDialect.cpp.inc", ), ( ["-gen-op-doc"], @@ -10698,7 +10699,7 @@ gentbl_cc_library( ), ], tblgen = ":mlir-tblgen", - td_file = "include/mlir/Dialect/Quant/QuantOps.td", + td_file = "include/mlir/Dialect/Quant/IR/QuantOps.td", deps = [":QuantizationOpsTdFiles"], ) @@ -10710,11 +10711,11 @@ gentbl_cc_library( "-gen-bytecode", "-bytecode-dialect=Quant", ], - "include/mlir/Dialect/Quant/QuantDialectBytecode.cpp.inc", + "include/mlir/Dialect/Quant/IR/QuantDialectBytecode.cpp.inc", ), ], tblgen = ":mlir-tblgen", - td_file = "include/mlir/Dialect/Quant/QuantDialectBytecode.td", + td_file = "include/mlir/Dialect/Quant/IR/QuantDialectBytecode.td", deps = [ ":BytecodeTdFiles", ], @@ -10733,10 +10734,10 @@ cc_library( "lib/Dialect/Quant/Utils/UniformSupport.cpp", ], hdrs = [ - "include/mlir/Dialect/Quant/FakeQuantSupport.h", - "include/mlir/Dialect/Quant/QuantOps.h", - "include/mlir/Dialect/Quant/QuantTypes.h", - "include/mlir/Dialect/Quant/UniformSupport.h", + "include/mlir/Dialect/Quant/IR/Quant.h", + "include/mlir/Dialect/Quant/IR/QuantTypes.h", + "include/mlir/Dialect/Quant/Utils/FakeQuantSupport.h", + "include/mlir/Dialect/Quant/Utils/UniformSupport.h", ], includes = ["include"], deps = [ @@ -10747,7 +10748,7 @@ cc_library( ":QuantOpsIncGen", ":SideEffectInterfaces", ":Support", - "//llvm:Support", + "//third_party/llvm/llvm-project/llvm:Support", ], ) @@ -14563,3 +14564,44 @@ gentbl_cc_library( td_file = "include/mlir/Dialect/LLVMIR/VCIXOps.td", deps = [":VCIXTdFiles"], ) + +gentbl_cc_library( + name = "QuantPassIncGen", + tbl_outs = [ + ( + [ + "-gen-pass-decls", + "-name=Quant", + ], + "include/mlir/Dialect/Quant/Transforms/Passes.h.inc", + ), + ], + tblgen = ":mlir-tblgen", + td_file = "include/mlir/Dialect/Quant/Transforms/Passes.td", + deps = [":PassBaseTdFiles"], +) + +cc_library( + name = "QuantTransforms", + srcs = glob([ + "lib/Dialect/Quant/Transforms/*.cpp", + ]), + hdrs = glob([ + "include/mlir/Dialect/Quant/Transforms/*.h", + ]), + includes = ["include"], + deps = [ + ":ArithDialect", + ":FuncDialect", + ":FuncTransforms", + ":IR", + ":LinalgDialect", + ":Pass", + ":QuantOps", + ":QuantPassIncGen", + ":ShapeDialect", + ":TensorDialect", + ":TransformUtils", + "//third_party/llvm/llvm-project/llvm:Support", + ], +) From 324bdd662dedfd03b884e082f577a8ad6dc1f8a6 Mon Sep 17 00:00:00 2001 From: Farzon Lotfi <1802579+farzonl@users.noreply.github.com> Date: Thu, 26 Sep 2024 17:16:29 -0400 Subject: [PATCH 007/469] [DirectX] Data Scalarization of Vectors in Global Scope (#110029) This change adds a pass to scalarize vectors in global scope into arrays. There are three distinct parts 1. find the globals that need to be updated and define what the new type should be 2. initialize that new type and copy over all the right attributes over from the old type. 3. Use the instruction visitor pattern to update the loads, stores, and geps for the layout of the new data structure. resolves https://github.com/llvm/llvm-project/issues/107920 --- llvm/lib/Target/DirectX/CMakeLists.txt | 1 + .../Target/DirectX/DXILDataScalarization.cpp | 300 ++++++++++++++++++ .../Target/DirectX/DXILDataScalarization.h | 25 ++ llvm/lib/Target/DirectX/DirectX.h | 6 + .../Target/DirectX/DirectXTargetMachine.cpp | 2 + llvm/test/CodeGen/DirectX/llc-pipeline.ll | 1 + llvm/test/CodeGen/DirectX/scalar-data.ll | 12 + llvm/test/CodeGen/DirectX/scalar-load.ll | 58 ++++ llvm/test/CodeGen/DirectX/scalar-store.ll | 36 ++- 9 files changed, 429 insertions(+), 12 deletions(-) create mode 100644 llvm/lib/Target/DirectX/DXILDataScalarization.cpp create mode 100644 llvm/lib/Target/DirectX/DXILDataScalarization.h create mode 100644 llvm/test/CodeGen/DirectX/scalar-data.ll create mode 100644 llvm/test/CodeGen/DirectX/scalar-load.ll diff --git a/llvm/lib/Target/DirectX/CMakeLists.txt b/llvm/lib/Target/DirectX/CMakeLists.txt index 7e0f8a145505e..c8ef0ef6f7e70 100644 --- a/llvm/lib/Target/DirectX/CMakeLists.txt +++ b/llvm/lib/Target/DirectX/CMakeLists.txt @@ -20,6 +20,7 @@ add_llvm_target(DirectXCodeGen DirectXTargetMachine.cpp DirectXTargetTransformInfo.cpp DXContainerGlobals.cpp + DXILDataScalarization.cpp DXILFinalizeLinkage.cpp DXILIntrinsicExpansion.cpp DXILOpBuilder.cpp diff --git a/llvm/lib/Target/DirectX/DXILDataScalarization.cpp b/llvm/lib/Target/DirectX/DXILDataScalarization.cpp new file mode 100644 index 0000000000000..0e6cf59e25750 --- /dev/null +++ b/llvm/lib/Target/DirectX/DXILDataScalarization.cpp @@ -0,0 +1,300 @@ +//===- DXILDataScalarization.cpp - Perform DXIL Data Legalization ---------===// +// +// 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 "DXILDataScalarization.h" +#include "DirectX.h" +#include "llvm/ADT/PostOrderIterator.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/Analysis/DXILResource.h" +#include "llvm/IR/GlobalVariable.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/InstVisitor.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/Operator.h" +#include "llvm/IR/PassManager.h" +#include "llvm/IR/ReplaceConstant.h" +#include "llvm/IR/Type.h" +#include "llvm/Transforms/Utils/Cloning.h" +#include "llvm/Transforms/Utils/Local.h" + +#define DEBUG_TYPE "dxil-data-scalarization" +static const int MaxVecSize = 4; + +using namespace llvm; + +class DXILDataScalarizationLegacy : public ModulePass { + +public: + bool runOnModule(Module &M) override; + DXILDataScalarizationLegacy() : ModulePass(ID) {} + + void getAnalysisUsage(AnalysisUsage &AU) const override; + static char ID; // Pass identification. +}; + +static bool findAndReplaceVectors(Module &M); + +class DataScalarizerVisitor : public InstVisitor { +public: + DataScalarizerVisitor() : GlobalMap() {} + bool visit(Function &F); + // InstVisitor methods. They return true if the instruction was scalarized, + // false if nothing changed. + bool visitInstruction(Instruction &I) { return false; } + bool visitSelectInst(SelectInst &SI) { return false; } + bool visitICmpInst(ICmpInst &ICI) { return false; } + bool visitFCmpInst(FCmpInst &FCI) { return false; } + bool visitUnaryOperator(UnaryOperator &UO) { return false; } + bool visitBinaryOperator(BinaryOperator &BO) { return false; } + bool visitGetElementPtrInst(GetElementPtrInst &GEPI); + bool visitCastInst(CastInst &CI) { return false; } + bool visitBitCastInst(BitCastInst &BCI) { return false; } + bool visitInsertElementInst(InsertElementInst &IEI) { return false; } + bool visitExtractElementInst(ExtractElementInst &EEI) { return false; } + bool visitShuffleVectorInst(ShuffleVectorInst &SVI) { return false; } + bool visitPHINode(PHINode &PHI) { return false; } + bool visitLoadInst(LoadInst &LI); + bool visitStoreInst(StoreInst &SI); + bool visitCallInst(CallInst &ICI) { return false; } + bool visitFreezeInst(FreezeInst &FI) { return false; } + friend bool findAndReplaceVectors(llvm::Module &M); + +private: + GlobalVariable *lookupReplacementGlobal(Value *CurrOperand); + DenseMap GlobalMap; + SmallVector PotentiallyDeadInstrs; + bool finish(); +}; + +bool DataScalarizerVisitor::visit(Function &F) { + assert(!GlobalMap.empty()); + ReversePostOrderTraversal RPOT(&F.getEntryBlock()); + for (BasicBlock *BB : RPOT) { + for (BasicBlock::iterator II = BB->begin(), IE = BB->end(); II != IE;) { + Instruction *I = &*II; + bool Done = InstVisitor::visit(I); + ++II; + if (Done && I->getType()->isVoidTy()) + I->eraseFromParent(); + } + } + return finish(); +} + +bool DataScalarizerVisitor::finish() { + RecursivelyDeleteTriviallyDeadInstructionsPermissive(PotentiallyDeadInstrs); + return true; +} + +GlobalVariable * +DataScalarizerVisitor::lookupReplacementGlobal(Value *CurrOperand) { + if (GlobalVariable *OldGlobal = dyn_cast(CurrOperand)) { + auto It = GlobalMap.find(OldGlobal); + if (It != GlobalMap.end()) { + return It->second; // Found, return the new global + } + } + return nullptr; // Not found +} + +bool DataScalarizerVisitor::visitLoadInst(LoadInst &LI) { + unsigned NumOperands = LI.getNumOperands(); + for (unsigned I = 0; I < NumOperands; ++I) { + Value *CurrOpperand = LI.getOperand(I); + if (GlobalVariable *NewGlobal = lookupReplacementGlobal(CurrOpperand)) + LI.setOperand(I, NewGlobal); + } + return false; +} + +bool DataScalarizerVisitor::visitStoreInst(StoreInst &SI) { + unsigned NumOperands = SI.getNumOperands(); + for (unsigned I = 0; I < NumOperands; ++I) { + Value *CurrOpperand = SI.getOperand(I); + if (GlobalVariable *NewGlobal = lookupReplacementGlobal(CurrOpperand)) { + SI.setOperand(I, NewGlobal); + } + } + return false; +} + +bool DataScalarizerVisitor::visitGetElementPtrInst(GetElementPtrInst &GEPI) { + unsigned NumOperands = GEPI.getNumOperands(); + for (unsigned I = 0; I < NumOperands; ++I) { + Value *CurrOpperand = GEPI.getOperand(I); + GlobalVariable *NewGlobal = lookupReplacementGlobal(CurrOpperand); + if (!NewGlobal) + continue; + IRBuilder<> Builder(&GEPI); + + SmallVector Indices; + for (auto &Index : GEPI.indices()) + Indices.push_back(Index); + + Value *NewGEP = + Builder.CreateGEP(NewGlobal->getValueType(), NewGlobal, Indices); + + GEPI.replaceAllUsesWith(NewGEP); + PotentiallyDeadInstrs.emplace_back(&GEPI); + } + return true; +} + +// Recursively Creates and Array like version of the given vector like type. +static Type *replaceVectorWithArray(Type *T, LLVMContext &Ctx) { + if (auto *VecTy = dyn_cast(T)) + return ArrayType::get(VecTy->getElementType(), + dyn_cast(VecTy)->getNumElements()); + if (auto *ArrayTy = dyn_cast(T)) { + Type *NewElementType = + replaceVectorWithArray(ArrayTy->getElementType(), Ctx); + return ArrayType::get(NewElementType, ArrayTy->getNumElements()); + } + // If it's not a vector or array, return the original type. + return T; +} + +Constant *transformInitializer(Constant *Init, Type *OrigType, Type *NewType, + LLVMContext &Ctx) { + // Handle ConstantAggregateZero (zero-initialized constants) + if (isa(Init)) { + return ConstantAggregateZero::get(NewType); + } + + // Handle UndefValue (undefined constants) + if (isa(Init)) { + return UndefValue::get(NewType); + } + + // Handle vector to array transformation + if (isa(OrigType) && isa(NewType)) { + // Convert vector initializer to array initializer + SmallVector ArrayElements; + if (ConstantVector *ConstVecInit = dyn_cast(Init)) { + for (unsigned I = 0; I < ConstVecInit->getNumOperands(); ++I) + ArrayElements.push_back(ConstVecInit->getOperand(I)); + } else if (ConstantDataVector *ConstDataVecInit = + llvm::dyn_cast(Init)) { + for (unsigned I = 0; I < ConstDataVecInit->getNumElements(); ++I) + ArrayElements.push_back(ConstDataVecInit->getElementAsConstant(I)); + } else { + assert(false && "Expected a ConstantVector or ConstantDataVector for " + "vector initializer!"); + } + + return ConstantArray::get(cast(NewType), ArrayElements); + } + + // Handle array of vectors transformation + if (auto *ArrayTy = dyn_cast(OrigType)) { + auto *ArrayInit = dyn_cast(Init); + assert(ArrayInit && "Expected a ConstantArray for array initializer!"); + + SmallVector NewArrayElements; + for (unsigned I = 0; I < ArrayTy->getNumElements(); ++I) { + // Recursively transform array elements + Constant *NewElemInit = transformInitializer( + ArrayInit->getOperand(I), ArrayTy->getElementType(), + cast(NewType)->getElementType(), Ctx); + NewArrayElements.push_back(NewElemInit); + } + + return ConstantArray::get(cast(NewType), NewArrayElements); + } + + // If not a vector or array, return the original initializer + return Init; +} + +static bool findAndReplaceVectors(Module &M) { + bool MadeChange = false; + LLVMContext &Ctx = M.getContext(); + IRBuilder<> Builder(Ctx); + DataScalarizerVisitor Impl; + for (GlobalVariable &G : M.globals()) { + Type *OrigType = G.getValueType(); + + Type *NewType = replaceVectorWithArray(OrigType, Ctx); + if (OrigType != NewType) { + // Create a new global variable with the updated type + // Note: Initializer is set via transformInitializer + GlobalVariable *NewGlobal = new GlobalVariable( + M, NewType, G.isConstant(), G.getLinkage(), + /*Initializer=*/nullptr, G.getName() + ".scalarized", &G, + G.getThreadLocalMode(), G.getAddressSpace(), + G.isExternallyInitialized()); + + // Copy relevant attributes + NewGlobal->setUnnamedAddr(G.getUnnamedAddr()); + if (G.getAlignment() > 0) { + NewGlobal->setAlignment(G.getAlign()); + } + + if (G.hasInitializer()) { + Constant *Init = G.getInitializer(); + Constant *NewInit = transformInitializer(Init, OrigType, NewType, Ctx); + NewGlobal->setInitializer(NewInit); + } + + // Note: we want to do G.replaceAllUsesWith(NewGlobal);, but it assumes + // type equality. Instead we will use the visitor pattern. + Impl.GlobalMap[&G] = NewGlobal; + for (User *U : make_early_inc_range(G.users())) { + if (isa(U) && isa(U)) { + ConstantExpr *CE = cast(U); + convertUsersOfConstantsToInstructions(CE, + /*RestrictToFunc=*/nullptr, + /*RemoveDeadConstants=*/false, + /*IncludeSelf=*/true); + } + if (isa(U)) { + Instruction *Inst = cast(U); + Function *F = Inst->getFunction(); + if (F) + Impl.visit(*F); + } + } + } + } + + // Remove the old globals after the iteration + for (auto &[Old, New] : Impl.GlobalMap) { + Old->eraseFromParent(); + MadeChange = true; + } + return MadeChange; +} + +PreservedAnalyses DXILDataScalarization::run(Module &M, + ModuleAnalysisManager &) { + bool MadeChanges = findAndReplaceVectors(M); + if (!MadeChanges) + return PreservedAnalyses::all(); + PreservedAnalyses PA; + PA.preserve(); + return PA; +} + +bool DXILDataScalarizationLegacy::runOnModule(Module &M) { + return findAndReplaceVectors(M); +} + +void DXILDataScalarizationLegacy::getAnalysisUsage(AnalysisUsage &AU) const { + AU.addPreserved(); +} + +char DXILDataScalarizationLegacy::ID = 0; + +INITIALIZE_PASS_BEGIN(DXILDataScalarizationLegacy, DEBUG_TYPE, + "DXIL Data Scalarization", false, false) +INITIALIZE_PASS_END(DXILDataScalarizationLegacy, DEBUG_TYPE, + "DXIL Data Scalarization", false, false) + +ModulePass *llvm::createDXILDataScalarizationLegacyPass() { + return new DXILDataScalarizationLegacy(); +} diff --git a/llvm/lib/Target/DirectX/DXILDataScalarization.h b/llvm/lib/Target/DirectX/DXILDataScalarization.h new file mode 100644 index 0000000000000..560e061db96d0 --- /dev/null +++ b/llvm/lib/Target/DirectX/DXILDataScalarization.h @@ -0,0 +1,25 @@ +//===- DXILDataScalarization.h - Perform DXIL Data Legalization -*- 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 +// +//===---------------------------------------------------------------------===// + +#ifndef LLVM_TARGET_DIRECTX_DXILDATASCALARIZATION_H +#define LLVM_TARGET_DIRECTX_DXILDATASCALARIZATION_H + +#include "DXILResource.h" +#include "llvm/IR/PassManager.h" +#include "llvm/Pass.h" + +namespace llvm { + +/// A pass that transforms Vectors to Arrays +class DXILDataScalarization : public PassInfoMixin { +public: + PreservedAnalyses run(Module &M, ModuleAnalysisManager &); +}; +} // namespace llvm + +#endif // LLVM_TARGET_DIRECTX_DXILDATASCALARIZATION_H diff --git a/llvm/lib/Target/DirectX/DirectX.h b/llvm/lib/Target/DirectX/DirectX.h index 60fc5094542b3..3221779be2f31 100644 --- a/llvm/lib/Target/DirectX/DirectX.h +++ b/llvm/lib/Target/DirectX/DirectX.h @@ -34,6 +34,12 @@ void initializeDXILIntrinsicExpansionLegacyPass(PassRegistry &); /// Pass to expand intrinsic operations that lack DXIL opCodes ModulePass *createDXILIntrinsicExpansionLegacyPass(); +/// Initializer for DXIL Data Scalarization Pass +void initializeDXILDataScalarizationLegacyPass(PassRegistry &); + +/// Pass to scalarize llvm global data into a DXIL legal form +ModulePass *createDXILDataScalarizationLegacyPass(); + /// Initializer for DXILOpLowering void initializeDXILOpLoweringLegacyPass(PassRegistry &); diff --git a/llvm/lib/Target/DirectX/DirectXTargetMachine.cpp b/llvm/lib/Target/DirectX/DirectXTargetMachine.cpp index 606022a9835f0..f358215ecf373 100644 --- a/llvm/lib/Target/DirectX/DirectXTargetMachine.cpp +++ b/llvm/lib/Target/DirectX/DirectXTargetMachine.cpp @@ -46,6 +46,7 @@ extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeDirectXTarget() { RegisterTargetMachine X(getTheDirectXTarget()); auto *PR = PassRegistry::getPassRegistry(); initializeDXILIntrinsicExpansionLegacyPass(*PR); + initializeDXILDataScalarizationLegacyPass(*PR); initializeScalarizerLegacyPassPass(*PR); initializeDXILPrepareModulePass(*PR); initializeEmbedDXILPassPass(*PR); @@ -86,6 +87,7 @@ class DirectXPassConfig : public TargetPassConfig { FunctionPass *createTargetRegisterAllocator(bool) override { return nullptr; } void addCodeGenPrepare() override { addPass(createDXILIntrinsicExpansionLegacyPass()); + addPass(createDXILDataScalarizationLegacyPass()); ScalarizerPassOptions DxilScalarOptions; DxilScalarOptions.ScalarizeLoadStore = true; addPass(createScalarizerPass(DxilScalarOptions)); diff --git a/llvm/test/CodeGen/DirectX/llc-pipeline.ll b/llvm/test/CodeGen/DirectX/llc-pipeline.ll index 46326d6917587..102748508b4ad 100644 --- a/llvm/test/CodeGen/DirectX/llc-pipeline.ll +++ b/llvm/test/CodeGen/DirectX/llc-pipeline.ll @@ -8,6 +8,7 @@ ; CHECK-NEXT: Target Transform Information ; CHECK-NEXT: ModulePass Manager ; CHECK-NEXT: DXIL Intrinsic Expansion +; CHECK-NEXT: DXIL Data Scalarization ; CHECK-NEXT: FunctionPass Manager ; CHECK-NEXT: Dominator Tree Construction ; CHECK-NEXT: Scalarize vector operations diff --git a/llvm/test/CodeGen/DirectX/scalar-data.ll b/llvm/test/CodeGen/DirectX/scalar-data.ll new file mode 100644 index 0000000000000..4438604a3a879 --- /dev/null +++ b/llvm/test/CodeGen/DirectX/scalar-data.ll @@ -0,0 +1,12 @@ +; RUN: opt -S -dxil-data-scalarization -scalarizer -scalarize-load-store -dxil-op-lower -mtriple=dxil-pc-shadermodel6.3-library %s | FileCheck %s +; RUN: llc %s -mtriple=dxil-pc-shadermodel6.3-library --filetype=asm -o - | FileCheck %s + +; Make sure we don't touch arrays without vectors and that can recurse multiple-dimension arrays of vectors + +@staticArray = internal global [4 x i32] [i32 1, i32 2, i32 3, i32 4], align 4 +@"groushared3dArrayofVectors" = local_unnamed_addr addrspace(3) global [3 x [3 x [3 x <4 x i32>]]] zeroinitializer, align 16 + +; CHECK @staticArray +; CHECK-NOT: @staticArray.scalarized +; CHECK: @groushared3dArrayofVectors.scalarized = local_unnamed_addr addrspace(3) global [3 x [3 x [3 x [4 x i32]]]] zeroinitializer, align 16 +; CHECK-NOT: @groushared3dArrayofVectors diff --git a/llvm/test/CodeGen/DirectX/scalar-load.ll b/llvm/test/CodeGen/DirectX/scalar-load.ll new file mode 100644 index 0000000000000..11678f48a5e01 --- /dev/null +++ b/llvm/test/CodeGen/DirectX/scalar-load.ll @@ -0,0 +1,58 @@ +; RUN: opt -S -dxil-data-scalarization -scalarizer -scalarize-load-store -dxil-op-lower -mtriple=dxil-pc-shadermodel6.3-library %s | FileCheck %s +; RUN: llc %s -mtriple=dxil-pc-shadermodel6.3-library --filetype=asm -o - | FileCheck %s + +; Make sure we can load groupshared, static vectors and arrays of vectors + +@"arrayofVecData" = local_unnamed_addr addrspace(3) global [2 x <3 x float>] zeroinitializer, align 16 +@"vecData" = external addrspace(3) global <4 x i32>, align 4 +@staticArrayOfVecData = internal global [3 x <4 x i32>] [<4 x i32> , <4 x i32> , <4 x i32> ], align 4 +@"groushared2dArrayofVectors" = local_unnamed_addr addrspace(3) global [3 x [ 3 x <4 x i32>]] zeroinitializer, align 16 + +; CHECK: @arrayofVecData.scalarized = local_unnamed_addr addrspace(3) global [2 x [3 x float]] zeroinitializer, align 16 +; CHECK: @vecData.scalarized = external addrspace(3) global [4 x i32], align 4 +; CHECK: @staticArrayOfVecData.scalarized = internal global [3 x [4 x i32]] {{\[}}[4 x i32] [i32 1, i32 2, i32 3, i32 4], [4 x i32] [i32 5, i32 6, i32 7, i32 8], [4 x i32] [i32 9, i32 10, i32 11, i32 12]], align 4 +; CHECK: @groushared2dArrayofVectors.scalarized = local_unnamed_addr addrspace(3) global [3 x [3 x [4 x i32]]] zeroinitializer, align 16 + +; CHECK-NOT: @arrayofVecData +; CHECK-NOT: @vecData +; CHECK-NOT: @staticArrayOfVecData +; CHECK-NOT: @groushared2dArrayofVectors + + +; CHECK-LABEL: load_array_vec_test +define <4 x i32> @load_array_vec_test() { + ; CHECK-COUNT-8: load i32, ptr addrspace(3) {{(.*@arrayofVecData.scalarized.*|%.*)}}, align 4 + ; CHECK-NOT: load i32, ptr addrspace(3) {{.*}}, align 4 + %1 = load <4 x i32>, <4 x i32> addrspace(3)* getelementptr inbounds ([2 x <4 x i32>], [2 x <4 x i32>] addrspace(3)* @"arrayofVecData", i32 0, i32 0), align 4 + %2 = load <4 x i32>, <4 x i32> addrspace(3)* getelementptr inbounds ([2 x <4 x i32>], [2 x <4 x i32>] addrspace(3)* @"arrayofVecData", i32 0, i32 1), align 4 + %3 = add <4 x i32> %1, %2 + ret <4 x i32> %3 +} + +; CHECK-LABEL: load_vec_test +define <4 x i32> @load_vec_test() { + ; CHECK-COUNT-4: load i32, ptr addrspace(3) {{(@vecData.scalarized|getelementptr \(i32, ptr addrspace\(3\) @vecData.scalarized, i32 .*\)|%.*)}}, align {{.*}} + ; CHECK-NOT: load i32, ptr addrspace(3) {{.*}}, align 4 + %1 = load <4 x i32>, <4 x i32> addrspace(3)* @"vecData", align 4 + ret <4 x i32> %1 +} + +; CHECK-LABEL: load_static_array_of_vec_test +define <4 x i32> @load_static_array_of_vec_test(i32 %index) { + ; CHECK: getelementptr [3 x [4 x i32]], ptr @staticArrayOfVecData.scalarized, i32 0, i32 %index + ; CHECK-COUNT-4: load i32, ptr {{.*}}, align 4 + ; CHECK-NOT: load i32, ptr {{.*}}, align 4 + %3 = getelementptr inbounds [3 x <4 x i32>], [3 x <4 x i32>]* @staticArrayOfVecData, i32 0, i32 %index + %4 = load <4 x i32>, <4 x i32>* %3, align 4 + ret <4 x i32> %4 +} + +; CHECK-LABEL: multid_load_test +define <4 x i32> @multid_load_test() { + ; CHECK-COUNT-8: load i32, ptr addrspace(3) {{(.*@groushared2dArrayofVectors.scalarized.*|%.*)}}, align 4 + ; CHECK-NOT: load i32, ptr addrspace(3) {{.*}}, align 4 + %1 = load <4 x i32>, <4 x i32> addrspace(3)* getelementptr inbounds ([3 x [3 x <4 x i32>]], [3 x [3 x <4 x i32>]] addrspace(3)* @"groushared2dArrayofVectors", i32 0, i32 0, i32 0), align 4 + %2 = load <4 x i32>, <4 x i32> addrspace(3)* getelementptr inbounds ([3 x [3 x <4 x i32>]], [3 x [3 x <4 x i32>]] addrspace(3)* @"groushared2dArrayofVectors", i32 0, i32 1, i32 1), align 4 + %3 = add <4 x i32> %1, %2 + ret <4 x i32> %3 +} diff --git a/llvm/test/CodeGen/DirectX/scalar-store.ll b/llvm/test/CodeGen/DirectX/scalar-store.ll index b970a2842e5a8..08d8a2c57c6c3 100644 --- a/llvm/test/CodeGen/DirectX/scalar-store.ll +++ b/llvm/test/CodeGen/DirectX/scalar-store.ll @@ -1,17 +1,29 @@ -; RUN: opt -S -scalarizer -scalarize-load-store -dxil-op-lower -mtriple=dxil-pc-shadermodel6.3-library %s | FileCheck %s +; RUN: opt -S -dxil-data-scalarization -scalarizer -scalarize-load-store -dxil-op-lower -mtriple=dxil-pc-shadermodel6.3-library %s | FileCheck %s ; RUN: llc %s -mtriple=dxil-pc-shadermodel6.3-library --filetype=asm -o - | FileCheck %s -@"sharedData" = local_unnamed_addr addrspace(3) global [2 x <3 x float>] zeroinitializer, align 16 -; CHECK-LABEL: store_test -define void @store_test () local_unnamed_addr { - ; CHECK: store float 1.000000e+00, ptr addrspace(3) {{.*}}, align {{.*}} - ; CHECK: store float 2.000000e+00, ptr addrspace(3) {{.*}}, align {{.*}} - ; CHECK: store float 3.000000e+00, ptr addrspace(3) {{.*}}, align {{.*}} - ; CHECK: store float 2.000000e+00, ptr addrspace(3) {{.*}}, align {{.*}} - ; CHECK: store float 4.000000e+00, ptr addrspace(3) {{.*}}, align {{.*}} - ; CHECK: store float 6.000000e+00, ptr addrspace(3) {{.*}}, align {{.*}} +; Make sure we can store groupshared, static vectors and arrays of vectors - store <3 x float> , ptr addrspace(3) @"sharedData", align 16 - store <3 x float> , ptr addrspace(3) getelementptr inbounds (i8, ptr addrspace(3) @"sharedData", i32 16), align 16 +@"arrayofVecData" = local_unnamed_addr addrspace(3) global [2 x <3 x float>] zeroinitializer, align 16 +@"vecData" = external addrspace(3) global <4 x i32>, align 4 + +; CHECK: @arrayofVecData.scalarized = local_unnamed_addr addrspace(3) global [2 x [3 x float]] zeroinitializer, align 16 +; CHECK: @vecData.scalarized = external addrspace(3) global [4 x i32], align 4 +; CHECK-NOT: @arrayofVecData +; CHECK-NOT: @vecData + +; CHECK-LABEL: store_array_vec_test +define void @store_array_vec_test () local_unnamed_addr { + ; CHECK-COUNT-6: store float {{1|2|3|4|6}}.000000e+00, ptr addrspace(3) {{(.*@arrayofVecData.scalarized.*|%.*)}}, align {{4|8|16}} + ; CHECK-NOT: store float {{1|2|3|4|6}}.000000e+00, ptr addrspace(3) {{(.*@arrayofVecData.scalarized.*|%.*)}}, align {{4|8|16}} + store <3 x float> , ptr addrspace(3) @"arrayofVecData", align 16 + store <3 x float> , ptr addrspace(3) getelementptr inbounds (i8, ptr addrspace(3) @"arrayofVecData", i32 16), align 16 ret void } + +; CHECK-LABEL: store_vec_test +define void @store_vec_test(<4 x i32> %inputVec) { + ; CHECK-COUNT-4: store i32 %inputVec.{{.*}}, ptr addrspace(3) {{(@vecData.scalarized|getelementptr \(i32, ptr addrspace\(3\) @vecData.scalarized, i32 .*\)|%.*)}}, align 4 + ; CHECK-NOT: store i32 %inputVec.{{.*}}, ptr addrspace(3) + store <4 x i32> %inputVec, <4 x i32> addrspace(3)* @"vecData", align 4 + ret void +} From ac2a2816e3fe934998e5f950c9426fca0796929d Mon Sep 17 00:00:00 2001 From: norx1991 Date: Thu, 26 Sep 2024 16:24:59 -0500 Subject: [PATCH 008/469] Fix BUILD.bazel error (#110172) --- utils/bazel/llvm-project-overlay/mlir/BUILD.bazel | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/utils/bazel/llvm-project-overlay/mlir/BUILD.bazel b/utils/bazel/llvm-project-overlay/mlir/BUILD.bazel index dada2b6ecca38..1f47d603e9576 100644 --- a/utils/bazel/llvm-project-overlay/mlir/BUILD.bazel +++ b/utils/bazel/llvm-project-overlay/mlir/BUILD.bazel @@ -10748,7 +10748,7 @@ cc_library( ":QuantOpsIncGen", ":SideEffectInterfaces", ":Support", - "//third_party/llvm/llvm-project/llvm:Support", + "//llvm:Support", ], ) @@ -14602,6 +14602,6 @@ cc_library( ":ShapeDialect", ":TensorDialect", ":TransformUtils", - "//third_party/llvm/llvm-project/llvm:Support", + "//llvm:Support", ], ) From 7a2c5c69ce01cacb18b7838826e442bb981bf9c8 Mon Sep 17 00:00:00 2001 From: vporpo Date: Thu, 26 Sep 2024 14:25:59 -0700 Subject: [PATCH 009/469] [SandboxIR][NFC] Move User into a separate file (#110157) --- llvm/include/llvm/SandboxIR/Context.h | 10 +- llvm/include/llvm/SandboxIR/SandboxIR.h | 128 +------------------- llvm/include/llvm/SandboxIR/User.h | 150 ++++++++++++++++++++++++ llvm/lib/SandboxIR/CMakeLists.txt | 1 + llvm/lib/SandboxIR/Context.cpp | 8 ++ llvm/lib/SandboxIR/SandboxIR.cpp | 60 ---------- llvm/lib/SandboxIR/User.cpp | 74 ++++++++++++ 7 files changed, 238 insertions(+), 193 deletions(-) create mode 100644 llvm/include/llvm/SandboxIR/User.h create mode 100644 llvm/lib/SandboxIR/User.cpp diff --git a/llvm/include/llvm/SandboxIR/Context.h b/llvm/include/llvm/SandboxIR/Context.h index dfba3085c66ac..092b791bc2acb 100644 --- a/llvm/include/llvm/SandboxIR/Context.h +++ b/llvm/include/llvm/SandboxIR/Context.h @@ -18,6 +18,7 @@ namespace llvm::sandboxir { class Module; class Value; class Argument; +class Constant; class Context { protected: @@ -69,9 +70,8 @@ class Context { return getOrCreateValueInternal(LLVMV, 0); } /// Get or create a sandboxir::Constant from an existing LLVM IR \p LLVMC. - Constant *getOrCreateConstant(llvm::Constant *LLVMC) { - return cast(getOrCreateValueInternal(LLVMC, 0)); - } + Constant *getOrCreateConstant(llvm::Constant *LLVMC); + // Friends for getOrCreateConstant(). #define DEF_CONST(ID, CLASS) friend class CLASS; #include "llvm/SandboxIR/SandboxIRValues.def" @@ -158,9 +158,7 @@ class Context { friend FCmpInst; // For createFCmpInst() public: - Context(LLVMContext &LLVMCtx) - : LLVMCtx(LLVMCtx), IRTracker(*this), - LLVMIRBuilder(LLVMCtx, ConstantFolder()) {} + Context(LLVMContext &LLVMCtx); Tracker &getTracker() { return IRTracker; } /// Convenience function for `getTracker().save()` diff --git a/llvm/include/llvm/SandboxIR/SandboxIR.h b/llvm/include/llvm/SandboxIR/SandboxIR.h index b32333263c03b..3d206bca9eae6 100644 --- a/llvm/include/llvm/SandboxIR/SandboxIR.h +++ b/llvm/include/llvm/SandboxIR/SandboxIR.h @@ -114,6 +114,7 @@ #include "llvm/SandboxIR/Tracker.h" #include "llvm/SandboxIR/Type.h" #include "llvm/SandboxIR/Use.h" +#include "llvm/SandboxIR/User.h" #include "llvm/SandboxIR/Value.h" #include "llvm/Support/raw_ostream.h" #include @@ -188,42 +189,6 @@ class CmpInst; class ICmpInst; class FCmpInst; -/// Iterator for the `Use` edges of a User's operands. -/// \Returns the operand `Use` when dereferenced. -class OperandUseIterator { - sandboxir::Use Use; - /// Don't let the user create a non-empty OperandUseIterator. - OperandUseIterator(const class Use &Use) : Use(Use) {} - friend class User; // For constructor -#define DEF_INSTR(ID, OPC, CLASS) friend class CLASS; // For constructor -#include "llvm/SandboxIR/SandboxIRValues.def" - -public: - using difference_type = std::ptrdiff_t; - using value_type = sandboxir::Use; - using pointer = value_type *; - using reference = value_type &; - using iterator_category = std::input_iterator_tag; - - OperandUseIterator() = default; - value_type operator*() const; - OperandUseIterator &operator++(); - OperandUseIterator operator++(int) { - auto Copy = *this; - this->operator++(); - return Copy; - } - bool operator==(const OperandUseIterator &Other) const { - return Use == Other.Use; - } - bool operator!=(const OperandUseIterator &Other) const { - return !(*this == Other); - } - OperandUseIterator operator+(unsigned Num) const; - OperandUseIterator operator-(unsigned Num) const; - int operator-(const OperandUseIterator &Other) const; -}; - /// Argument of a sandboxir::Function. class Argument : public sandboxir::Value { Argument(llvm::Argument *Arg, sandboxir::Context &Ctx) @@ -243,97 +208,6 @@ class Argument : public sandboxir::Value { #endif }; -/// A sandboxir::User has operands. -class User : public Value { -protected: - User(ClassID ID, llvm::Value *V, Context &Ctx) : Value(ID, V, Ctx) {} - - /// \Returns the Use edge that corresponds to \p OpIdx. - /// Note: This is the default implementation that works for instructions that - /// match the underlying LLVM instruction. All others should use a different - /// implementation. - Use getOperandUseDefault(unsigned OpIdx, bool Verify) const; - /// \Returns the Use for the \p OpIdx'th operand. This is virtual to allow - /// instructions to deviate from the LLVM IR operands, which is a requirement - /// for sandboxir Instructions that consist of more than one LLVM Instruction. - virtual Use getOperandUseInternal(unsigned OpIdx, bool Verify) const = 0; - friend class OperandUseIterator; // for getOperandUseInternal() - - /// The default implementation works only for single-LLVMIR-instruction - /// Users and only if they match exactly the LLVM instruction. - unsigned getUseOperandNoDefault(const Use &Use) const { - return Use.LLVMUse->getOperandNo(); - } - /// \Returns the operand index of \p Use. - virtual unsigned getUseOperandNo(const Use &Use) const = 0; - friend unsigned Use::getOperandNo() const; // For getUseOperandNo() - - void swapOperandsInternal(unsigned OpIdxA, unsigned OpIdxB) { - assert(OpIdxA < getNumOperands() && "OpIdxA out of bounds!"); - assert(OpIdxB < getNumOperands() && "OpIdxB out of bounds!"); - auto UseA = getOperandUse(OpIdxA); - auto UseB = getOperandUse(OpIdxB); - UseA.swap(UseB); - } - -#ifndef NDEBUG - void verifyUserOfLLVMUse(const llvm::Use &Use) const; -#endif // NDEBUG - -public: - /// For isa/dyn_cast. - static bool classof(const Value *From); - using op_iterator = OperandUseIterator; - using const_op_iterator = OperandUseIterator; - using op_range = iterator_range; - using const_op_range = iterator_range; - - virtual op_iterator op_begin() { - assert(isa(Val) && "Expect User value!"); - return op_iterator(getOperandUseInternal(0, /*Verify=*/false)); - } - virtual op_iterator op_end() { - assert(isa(Val) && "Expect User value!"); - return op_iterator( - getOperandUseInternal(getNumOperands(), /*Verify=*/false)); - } - virtual const_op_iterator op_begin() const { - return const_cast(this)->op_begin(); - } - virtual const_op_iterator op_end() const { - return const_cast(this)->op_end(); - } - - op_range operands() { return make_range(op_begin(), op_end()); } - const_op_range operands() const { - return make_range(op_begin(), op_end()); - } - Value *getOperand(unsigned OpIdx) const { return getOperandUse(OpIdx).get(); } - /// \Returns the operand edge for \p OpIdx. NOTE: This should also work for - /// OpIdx == getNumOperands(), which is used for op_end(). - Use getOperandUse(unsigned OpIdx) const { - return getOperandUseInternal(OpIdx, /*Verify=*/true); - } - virtual unsigned getNumOperands() const { - return isa(Val) ? cast(Val)->getNumOperands() : 0; - } - - virtual void setOperand(unsigned OperandIdx, Value *Operand); - /// Replaces any operands that match \p FromV with \p ToV. Returns whether any - /// operands were replaced. - bool replaceUsesOfWith(Value *FromV, Value *ToV); - -#ifndef NDEBUG - void verify() const override { - assert(isa(Val) && "Expected User!"); - } - void dumpCommonHeader(raw_ostream &OS) const final; - void dumpOS(raw_ostream &OS) const override { - // TODO: Remove this tmp implementation once we get the Instruction classes. - } -#endif -}; - class Constant : public sandboxir::User { protected: Constant(llvm::Constant *C, sandboxir::Context &SBCtx) diff --git a/llvm/include/llvm/SandboxIR/User.h b/llvm/include/llvm/SandboxIR/User.h new file mode 100644 index 0000000000000..5e47ba5e727f4 --- /dev/null +++ b/llvm/include/llvm/SandboxIR/User.h @@ -0,0 +1,150 @@ +//===- User.h ---------------------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SANDBOXIR_USER_H +#define LLVM_SANDBOXIR_USER_H + +#include "llvm/IR/User.h" +#include "llvm/IR/Value.h" +#include "llvm/SandboxIR/Use.h" +#include "llvm/SandboxIR/Value.h" + +namespace llvm::sandboxir { + +class Context; + +/// Iterator for the `Use` edges of a User's operands. +/// \Returns the operand `Use` when dereferenced. +class OperandUseIterator { + sandboxir::Use Use; + /// Don't let the user create a non-empty OperandUseIterator. + OperandUseIterator(const class Use &Use) : Use(Use) {} + friend class User; // For constructor +#define DEF_INSTR(ID, OPC, CLASS) friend class CLASS; // For constructor +#include "llvm/SandboxIR/SandboxIRValues.def" + +public: + using difference_type = std::ptrdiff_t; + using value_type = sandboxir::Use; + using pointer = value_type *; + using reference = value_type &; + using iterator_category = std::input_iterator_tag; + + OperandUseIterator() = default; + value_type operator*() const; + OperandUseIterator &operator++(); + OperandUseIterator operator++(int) { + auto Copy = *this; + this->operator++(); + return Copy; + } + bool operator==(const OperandUseIterator &Other) const { + return Use == Other.Use; + } + bool operator!=(const OperandUseIterator &Other) const { + return !(*this == Other); + } + OperandUseIterator operator+(unsigned Num) const; + OperandUseIterator operator-(unsigned Num) const; + int operator-(const OperandUseIterator &Other) const; +}; + +/// A sandboxir::User has operands. +class User : public Value { +protected: + User(ClassID ID, llvm::Value *V, Context &Ctx) : Value(ID, V, Ctx) {} + + /// \Returns the Use edge that corresponds to \p OpIdx. + /// Note: This is the default implementation that works for instructions that + /// match the underlying LLVM instruction. All others should use a different + /// implementation. + Use getOperandUseDefault(unsigned OpIdx, bool Verify) const; + /// \Returns the Use for the \p OpIdx'th operand. This is virtual to allow + /// instructions to deviate from the LLVM IR operands, which is a requirement + /// for sandboxir Instructions that consist of more than one LLVM Instruction. + virtual Use getOperandUseInternal(unsigned OpIdx, bool Verify) const = 0; + friend class OperandUseIterator; // for getOperandUseInternal() + + /// The default implementation works only for single-LLVMIR-instruction + /// Users and only if they match exactly the LLVM instruction. + unsigned getUseOperandNoDefault(const Use &Use) const { + return Use.LLVMUse->getOperandNo(); + } + /// \Returns the operand index of \p Use. + virtual unsigned getUseOperandNo(const Use &Use) const = 0; + friend unsigned Use::getOperandNo() const; // For getUseOperandNo() + + void swapOperandsInternal(unsigned OpIdxA, unsigned OpIdxB) { + assert(OpIdxA < getNumOperands() && "OpIdxA out of bounds!"); + assert(OpIdxB < getNumOperands() && "OpIdxB out of bounds!"); + auto UseA = getOperandUse(OpIdxA); + auto UseB = getOperandUse(OpIdxB); + UseA.swap(UseB); + } + +#ifndef NDEBUG + void verifyUserOfLLVMUse(const llvm::Use &Use) const; +#endif // NDEBUG + +public: + /// For isa/dyn_cast. + static bool classof(const Value *From); + using op_iterator = OperandUseIterator; + using const_op_iterator = OperandUseIterator; + using op_range = iterator_range; + using const_op_range = iterator_range; + + virtual op_iterator op_begin() { + assert(isa(Val) && "Expect User value!"); + return op_iterator(getOperandUseInternal(0, /*Verify=*/false)); + } + virtual op_iterator op_end() { + assert(isa(Val) && "Expect User value!"); + return op_iterator( + getOperandUseInternal(getNumOperands(), /*Verify=*/false)); + } + virtual const_op_iterator op_begin() const { + return const_cast(this)->op_begin(); + } + virtual const_op_iterator op_end() const { + return const_cast(this)->op_end(); + } + + op_range operands() { return make_range(op_begin(), op_end()); } + const_op_range operands() const { + return make_range(op_begin(), op_end()); + } + Value *getOperand(unsigned OpIdx) const { return getOperandUse(OpIdx).get(); } + /// \Returns the operand edge for \p OpIdx. NOTE: This should also work for + /// OpIdx == getNumOperands(), which is used for op_end(). + Use getOperandUse(unsigned OpIdx) const { + return getOperandUseInternal(OpIdx, /*Verify=*/true); + } + virtual unsigned getNumOperands() const { + return isa(Val) ? cast(Val)->getNumOperands() : 0; + } + + virtual void setOperand(unsigned OperandIdx, Value *Operand); + /// Replaces any operands that match \p FromV with \p ToV. Returns whether any + /// operands were replaced. + bool replaceUsesOfWith(Value *FromV, Value *ToV); + +#ifndef NDEBUG + void verify() const override { + assert(isa(Val) && "Expected User!"); + } + void dumpCommonHeader(raw_ostream &OS) const final; + void dumpOS(raw_ostream &OS) const override { + // TODO: Remove this tmp implementation once we get the Instruction classes. + } +#endif +}; + +} // namespace llvm::sandboxir + +#endif // LLVM_SANDBOXIR_USER_H diff --git a/llvm/lib/SandboxIR/CMakeLists.txt b/llvm/lib/SandboxIR/CMakeLists.txt index bd91e8dff8a8e..6386fc908388a 100644 --- a/llvm/lib/SandboxIR/CMakeLists.txt +++ b/llvm/lib/SandboxIR/CMakeLists.txt @@ -6,6 +6,7 @@ add_llvm_component_library(LLVMSandboxIR SandboxIR.cpp Tracker.cpp Type.cpp + User.cpp Value.cpp ADDITIONAL_HEADER_DIRS diff --git a/llvm/lib/SandboxIR/Context.cpp b/llvm/lib/SandboxIR/Context.cpp index 1dc239ba48288..d10cb18e6d368 100644 --- a/llvm/lib/SandboxIR/Context.cpp +++ b/llvm/lib/SandboxIR/Context.cpp @@ -409,6 +409,10 @@ Argument *Context::getOrCreateArgument(llvm::Argument *LLVMArg) { return cast(It->second.get()); } +Constant *Context::getOrCreateConstant(llvm::Constant *LLVMC) { + return cast(getOrCreateValueInternal(LLVMC, 0)); +} + BasicBlock *Context::createBasicBlock(llvm::BasicBlock *LLVMBB) { assert(getValue(LLVMBB) == nullptr && "Already exists!"); auto NewBBPtr = std::unique_ptr(new BasicBlock(LLVMBB, *this)); @@ -662,6 +666,10 @@ Value *Context::getValue(llvm::Value *V) const { return nullptr; } +Context::Context(LLVMContext &LLVMCtx) + : LLVMCtx(LLVMCtx), IRTracker(*this), + LLVMIRBuilder(LLVMCtx, ConstantFolder()) {} + Module *Context::getModule(llvm::Module *LLVMM) const { auto It = LLVMModuleToModuleMap.find(LLVMM); if (It != LLVMModuleToModuleMap.end()) diff --git a/llvm/lib/SandboxIR/SandboxIR.cpp b/llvm/lib/SandboxIR/SandboxIR.cpp index 17c77f470549e..92b1ebeedc55b 100644 --- a/llvm/lib/SandboxIR/SandboxIR.cpp +++ b/llvm/lib/SandboxIR/SandboxIR.cpp @@ -115,66 +115,6 @@ void Argument::dumpOS(raw_ostream &OS) const { } #endif // NDEBUG -Use User::getOperandUseDefault(unsigned OpIdx, bool Verify) const { - assert((!Verify || OpIdx < getNumOperands()) && "Out of bounds!"); - assert(isa(Val) && "Non-users have no operands!"); - llvm::Use *LLVMUse; - if (OpIdx != getNumOperands()) - LLVMUse = &cast(Val)->getOperandUse(OpIdx); - else - LLVMUse = cast(Val)->op_end(); - return Use(LLVMUse, const_cast(this), Ctx); -} - -#ifndef NDEBUG -void User::verifyUserOfLLVMUse(const llvm::Use &Use) const { - assert(Ctx.getValue(Use.getUser()) == this && - "Use not found in this SBUser's operands!"); -} -#endif - -bool User::classof(const Value *From) { - switch (From->getSubclassID()) { -#define DEF_VALUE(ID, CLASS) -#define DEF_USER(ID, CLASS) \ - case ClassID::ID: \ - return true; -#define DEF_INSTR(ID, OPC, CLASS) \ - case ClassID::ID: \ - return true; -#include "llvm/SandboxIR/SandboxIRValues.def" - default: - return false; - } -} - -void User::setOperand(unsigned OperandIdx, Value *Operand) { - assert(isa(Val) && "No operands!"); - Ctx.getTracker().emplaceIfTracking(getOperandUse(OperandIdx)); - // We are delegating to llvm::User::setOperand(). - cast(Val)->setOperand(OperandIdx, Operand->Val); -} - -bool User::replaceUsesOfWith(Value *FromV, Value *ToV) { - auto &Tracker = Ctx.getTracker(); - if (Tracker.isTracking()) { - for (auto OpIdx : seq(0, getNumOperands())) { - auto Use = getOperandUse(OpIdx); - if (Use.get() == FromV) - Tracker.emplaceIfTracking(Use); - } - } - // We are delegating RUOW to LLVM IR's RUOW. - return cast(Val)->replaceUsesOfWith(FromV->Val, ToV->Val); -} - -#ifndef NDEBUG -void User::dumpCommonHeader(raw_ostream &OS) const { - Value::dumpCommonHeader(OS); - // TODO: This is incomplete -} -#endif // NDEBUG - BBIterator &BBIterator::operator++() { auto ItE = BB->end(); assert(It != ItE && "Already at end!"); diff --git a/llvm/lib/SandboxIR/User.cpp b/llvm/lib/SandboxIR/User.cpp new file mode 100644 index 0000000000000..8afa52e32b762 --- /dev/null +++ b/llvm/lib/SandboxIR/User.cpp @@ -0,0 +1,74 @@ +//===- User.cpp - The User class of Sandbox IR ----------------------------===// +// +// 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 "llvm/SandboxIR/User.h" +#include "llvm/SandboxIR/Context.h" + +namespace llvm::sandboxir { + +Use User::getOperandUseDefault(unsigned OpIdx, bool Verify) const { + assert((!Verify || OpIdx < getNumOperands()) && "Out of bounds!"); + assert(isa(Val) && "Non-users have no operands!"); + llvm::Use *LLVMUse; + if (OpIdx != getNumOperands()) + LLVMUse = &cast(Val)->getOperandUse(OpIdx); + else + LLVMUse = cast(Val)->op_end(); + return Use(LLVMUse, const_cast(this), Ctx); +} + +#ifndef NDEBUG +void User::verifyUserOfLLVMUse(const llvm::Use &Use) const { + assert(Ctx.getValue(Use.getUser()) == this && + "Use not found in this SBUser's operands!"); +} +#endif + +bool User::classof(const Value *From) { + switch (From->getSubclassID()) { +#define DEF_VALUE(ID, CLASS) +#define DEF_USER(ID, CLASS) \ + case ClassID::ID: \ + return true; +#define DEF_INSTR(ID, OPC, CLASS) \ + case ClassID::ID: \ + return true; +#include "llvm/SandboxIR/SandboxIRValues.def" + default: + return false; + } +} + +void User::setOperand(unsigned OperandIdx, Value *Operand) { + assert(isa(Val) && "No operands!"); + Ctx.getTracker().emplaceIfTracking(getOperandUse(OperandIdx)); + // We are delegating to llvm::User::setOperand(). + cast(Val)->setOperand(OperandIdx, Operand->Val); +} + +bool User::replaceUsesOfWith(Value *FromV, Value *ToV) { + auto &Tracker = Ctx.getTracker(); + if (Tracker.isTracking()) { + for (auto OpIdx : seq(0, getNumOperands())) { + auto Use = getOperandUse(OpIdx); + if (Use.get() == FromV) + Tracker.emplaceIfTracking(Use); + } + } + // We are delegating RUOW to LLVM IR's RUOW. + return cast(Val)->replaceUsesOfWith(FromV->Val, ToV->Val); +} + +#ifndef NDEBUG +void User::dumpCommonHeader(raw_ostream &OS) const { + Value::dumpCommonHeader(OS); + // TODO: This is incomplete +} +#endif // NDEBUG + +} // namespace llvm::sandboxir From 35eaed7ec7dd7f02ed2f6893bfdd349e19fc3c79 Mon Sep 17 00:00:00 2001 From: LLVM GN Syncbot Date: Thu, 26 Sep 2024 21:26:31 +0000 Subject: [PATCH 010/469] [gn build] Port 7a2c5c69ce01 --- llvm/utils/gn/secondary/llvm/lib/SandboxIR/BUILD.gn | 1 + 1 file changed, 1 insertion(+) diff --git a/llvm/utils/gn/secondary/llvm/lib/SandboxIR/BUILD.gn b/llvm/utils/gn/secondary/llvm/lib/SandboxIR/BUILD.gn index 5f15e9ff1d9e5..c6fbddb4bf13a 100644 --- a/llvm/utils/gn/secondary/llvm/lib/SandboxIR/BUILD.gn +++ b/llvm/utils/gn/secondary/llvm/lib/SandboxIR/BUILD.gn @@ -13,6 +13,7 @@ static_library("SandboxIR") { "SandboxIR.cpp", "Tracker.cpp", "Type.cpp", + "User.cpp", "Value.cpp", ] } From c11722223bacf604e60414542743d021a9f13aee Mon Sep 17 00:00:00 2001 From: Jacob Lalonde Date: Thu, 26 Sep 2024 14:33:12 -0700 Subject: [PATCH 011/469] [LLDB][Minidump] Add Multiplatform test to ensure determinism (#108602) Adds a test that ensures two minidumps produced from the same target are the same bytes. Covers the three primary core flavors. --- .../TestProcessSaveCoreMinidump.py | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/lldb/test/API/functionalities/process_save_core_minidump/TestProcessSaveCoreMinidump.py b/lldb/test/API/functionalities/process_save_core_minidump/TestProcessSaveCoreMinidump.py index ccdb6653cf16f..03cc415924e0b 100644 --- a/lldb/test/API/functionalities/process_save_core_minidump/TestProcessSaveCoreMinidump.py +++ b/lldb/test/API/functionalities/process_save_core_minidump/TestProcessSaveCoreMinidump.py @@ -522,3 +522,46 @@ def minidump_deleted_on_save_failure(self): finally: self.assertTrue(self.dbg.DeleteTarget(target)) + + def minidump_deterministic_difference(self): + """Test that verifies that two minidumps produced are identical.""" + + self.build() + exe = self.getBuildArtifact("a.out") + try: + target = self.dbg.CreateTarget(exe) + process = target.LaunchSimple( + None, None, self.get_process_working_directory() + ) + self.assertState(process.GetState(), lldb.eStateStopped) + + core_styles = [ + lldb.eSaveCoreStackOnly, + lldb.eSaveCoreDirtyOnly, + lldb.eSaveCoreFull, + ] + for style in core_styles: + spec_one = lldb.SBFileSpec(self.getBuildArtifact("core.one.dmp")) + spec_two = lldb.SBFileSpec(self.getBuildArtifact("core.two.dmp")) + options = lldb.SBSaveCoreOptions() + options.SetOutputFile(spec_one) + options.SetPluginName("minidump") + options.SetStyle(style) + error = process.SaveCore(options) + self.assertTrue(error.Success()) + options.SetOutputFile(spec_two) + error = process.SaveCore(options) + self.assertTrue(error.Success()) + + file_one = None + file_two = None + with open(spec_one.GetFileName(), mode="rb") as file: + file_one = file.read() + with open(spec_two.GetFileName(), mode="rb") as file: + file_two = file.read() + self.assertEqual(file_one, file_two) + self.assertTrue(os.unlink(spec_one.GetFileName())) + self.assertTrue(os.unlink(spec_two.GetFileName())) + + finally: + self.assertTrue(self.dbg.DeleteTarget(target)) From 1d8fad9fef4b2f1637498a017c44f0e8ebac20f8 Mon Sep 17 00:00:00 2001 From: Helena Kotas Date: Thu, 26 Sep 2024 14:45:50 -0700 Subject: [PATCH 012/469] [HLSL] Allow resource type attributes only on `__hlsl_resource_t` (#110143) Resource type attributes should only ever be used on the intangible type `__hlsl_resource_t`. --- clang/include/clang/Basic/DiagnosticSemaKinds.td | 1 + clang/include/clang/Sema/SemaHLSL.h | 2 +- clang/lib/Sema/SemaHLSL.cpp | 10 ++++++++-- clang/lib/Sema/SemaType.cpp | 2 +- .../ParserHLSL/hlsl_contained_type_attr_error.hlsl | 4 ++++ clang/test/ParserHLSL/hlsl_is_rov_attr_error.hlsl | 4 ++++ clang/test/ParserHLSL/hlsl_raw_buffer_attr_error.hlsl | 4 ++++ .../ParserHLSL/hlsl_resource_class_attr_error.hlsl | 3 +++ 8 files changed, 26 insertions(+), 4 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 5ce637f349259..f3d5d4c56606c 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -12388,6 +12388,7 @@ def err_hlsl_packoffset_alignment_mismatch : Error<"packoffset at 'y' not match def err_hlsl_pointers_unsupported : Error< "%select{pointers|references}0 are unsupported in HLSL">; def err_hlsl_missing_resource_class : Error<"HLSL resource needs to have [[hlsl::resource_class()]] attribute">; +def err_hlsl_attribute_needs_intangible_type: Error<"attribute %0 can be used only on HLSL intangible type %1">; def err_hlsl_operator_unsupported : Error< "the '%select{&|*|->}0' operator is unsupported in HLSL">; diff --git a/clang/include/clang/Sema/SemaHLSL.h b/clang/include/clang/Sema/SemaHLSL.h index e088254c566d3..311cd58bbcac2 100644 --- a/clang/include/clang/Sema/SemaHLSL.h +++ b/clang/include/clang/Sema/SemaHLSL.h @@ -70,7 +70,7 @@ class SemaHLSL : public SemaBase { void handleShaderAttr(Decl *D, const ParsedAttr &AL); void handleResourceBindingAttr(Decl *D, const ParsedAttr &AL); void handleParamModifierAttr(Decl *D, const ParsedAttr &AL); - bool handleResourceTypeAttr(const ParsedAttr &AL); + bool handleResourceTypeAttr(QualType T, const ParsedAttr &AL); bool CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); QualType ProcessResourceTypeAttributes(QualType Wrapped); diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp index ebe76185cbb2d..1d8ccdda45573 100644 --- a/clang/lib/Sema/SemaHLSL.cpp +++ b/clang/lib/Sema/SemaHLSL.cpp @@ -693,13 +693,19 @@ bool clang::CreateHLSLAttributedResourceType( // HLSL resource. The attributes are collected in HLSLResourcesTypeAttrs and at // the end of the declaration they are applied to the declaration type by // wrapping it in HLSLAttributedResourceType. -bool SemaHLSL::handleResourceTypeAttr(const ParsedAttr &AL) { - Attr *A = nullptr; +bool SemaHLSL::handleResourceTypeAttr(QualType T, const ParsedAttr &AL) { + // only allow resource type attributes on intangible types + if (!T->isHLSLResourceType()) { + Diag(AL.getLoc(), diag::err_hlsl_attribute_needs_intangible_type) + << AL << getASTContext().HLSLResourceTy; + return false; + } // validate number of arguments if (!AL.checkExactlyNumArgs(SemaRef, AL.getMinArgs())) return false; + Attr *A = nullptr; switch (AL.getKind()) { case ParsedAttr::AT_HLSLResourceClass: { if (!AL.isArgIdent(0)) { diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 950bd6db0359d..a7beb9d222c3b 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -8860,7 +8860,7 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type, // decl-specifier-seq; do not collect attributes on declarations or those // that get to slide after declaration name. if (TAL == TAL_DeclSpec && - state.getSema().HLSL().handleResourceTypeAttr(attr)) + state.getSema().HLSL().handleResourceTypeAttr(type, attr)) attr.setUsedAsTypeAttr(); break; } diff --git a/clang/test/ParserHLSL/hlsl_contained_type_attr_error.hlsl b/clang/test/ParserHLSL/hlsl_contained_type_attr_error.hlsl index 1c37d72de8614..b2d492d95945c 100644 --- a/clang/test/ParserHLSL/hlsl_contained_type_attr_error.hlsl +++ b/clang/test/ParserHLSL/hlsl_contained_type_attr_error.hlsl @@ -22,3 +22,7 @@ __hlsl_resource_t [[hlsl::resource_class(UAV)]] [[hlsl::contained_type(float)]] // expected-warning@+1{{attribute 'contained_type' is already applied with different arguments}} __hlsl_resource_t [[hlsl::resource_class(UAV)]] [[hlsl::contained_type(float)]] [[hlsl::contained_type(int)]] h8; + +// expected-error@+2{{attribute 'resource_class' can be used only on HLSL intangible type '__hlsl_resource_t'}} +// expected-error@+1{{attribute 'contained_type' can be used only on HLSL intangible type '__hlsl_resource_t'}} +float [[hlsl::resource_class(UAV)]] [[hlsl::contained_type(float)]] res5; diff --git a/clang/test/ParserHLSL/hlsl_is_rov_attr_error.hlsl b/clang/test/ParserHLSL/hlsl_is_rov_attr_error.hlsl index 15685bd1a3baa..3b2c12e7a96c5 100644 --- a/clang/test/ParserHLSL/hlsl_is_rov_attr_error.hlsl +++ b/clang/test/ParserHLSL/hlsl_is_rov_attr_error.hlsl @@ -14,3 +14,7 @@ __hlsl_resource_t [[hlsl::resource_class(UAV)]] [[hlsl::is_rov(gibberish)]] res3 // expected-warning@+1{{attribute 'is_rov' is already applied}} __hlsl_resource_t [[hlsl::resource_class(UAV)]] [[hlsl::is_rov]] [[hlsl::is_rov]] res4; + +// expected-error@+2{{attribute 'resource_class' can be used only on HLSL intangible type '__hlsl_resource_t'}} +// expected-error@+1{{attribute 'is_rov' can be used only on HLSL intangible type '__hlsl_resource_t'}} +float [[hlsl::resource_class(UAV)]] [[hlsl::is_rov]] res5; diff --git a/clang/test/ParserHLSL/hlsl_raw_buffer_attr_error.hlsl b/clang/test/ParserHLSL/hlsl_raw_buffer_attr_error.hlsl index 83273426017ed..77530cbf9e4d9 100644 --- a/clang/test/ParserHLSL/hlsl_raw_buffer_attr_error.hlsl +++ b/clang/test/ParserHLSL/hlsl_raw_buffer_attr_error.hlsl @@ -11,3 +11,7 @@ __hlsl_resource_t [[hlsl::resource_class(UAV)]] [[hlsl::raw_buffer(gibberish)]] // expected-warning@+1{{attribute 'raw_buffer' is already applied}} __hlsl_resource_t [[hlsl::resource_class(UAV)]] [[hlsl::raw_buffer]] [[hlsl::raw_buffer]] res4; + +// expected-error@+2{{attribute 'resource_class' can be used only on HLSL intangible type '__hlsl_resource_t'}} +// expected-error@+1{{attribute 'raw_buffer' can be used only on HLSL intangible type '__hlsl_resource_t'}} +float [[hlsl::resource_class(UAV)]] [[hlsl::raw_buffer]] res5; diff --git a/clang/test/ParserHLSL/hlsl_resource_class_attr_error.hlsl b/clang/test/ParserHLSL/hlsl_resource_class_attr_error.hlsl index 01ff1c007e2b5..63e39daff949b 100644 --- a/clang/test/ParserHLSL/hlsl_resource_class_attr_error.hlsl +++ b/clang/test/ParserHLSL/hlsl_resource_class_attr_error.hlsl @@ -17,3 +17,6 @@ __hlsl_resource_t [[hlsl::resource_class(SRV)]] [[hlsl::resource_class(SRV)]] e4 // expected-error@+1{{'resource_class' attribute takes one argument}} __hlsl_resource_t [[hlsl::resource_class(SRV, "aa")]] e5; + +// expected-error@+1{{attribute 'resource_class' can be used only on HLSL intangible type '__hlsl_resource_t'}} +float [[hlsl::resource_class(UAV)]] e6; From 3d9ed92630fb2a3282ba4a49b43d6eccca2f3509 Mon Sep 17 00:00:00 2001 From: Jorge Gorbe Moya Date: Thu, 26 Sep 2024 14:48:28 -0700 Subject: [PATCH 013/469] [SandboxIR][NFC] Move Region from SandboxVectorizer to SandboxIR. (#110173) I'm planning to add RegionPass and RegionPassManager next to the equivalent FunctionPass and FunctionPassManager in SandboxIR, which means that SandboxIR has to know about Regions. There's nothing vectorizer-specific about the Region class, and the only thing using Regions at this moment is the unit test, so this is a straightforward file move. --- .../Vectorize/SandboxVectorizer => SandboxIR}/Region.h | 0 llvm/lib/SandboxIR/CMakeLists.txt | 1 + .../Vectorize/SandboxVectorizer => SandboxIR}/Region.cpp | 2 +- llvm/lib/Transforms/Vectorize/CMakeLists.txt | 1 - llvm/unittests/SandboxIR/CMakeLists.txt | 1 + .../Vectorize/SandboxVectorizer => SandboxIR}/RegionTest.cpp | 0 .../Transforms/Vectorize/SandboxVectorizer/CMakeLists.txt | 1 - 7 files changed, 3 insertions(+), 3 deletions(-) rename llvm/include/llvm/{Transforms/Vectorize/SandboxVectorizer => SandboxIR}/Region.h (100%) rename llvm/lib/{Transforms/Vectorize/SandboxVectorizer => SandboxIR}/Region.cpp (96%) rename llvm/unittests/{Transforms/Vectorize/SandboxVectorizer => SandboxIR}/RegionTest.cpp (100%) diff --git a/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/Region.h b/llvm/include/llvm/SandboxIR/Region.h similarity index 100% rename from llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/Region.h rename to llvm/include/llvm/SandboxIR/Region.h diff --git a/llvm/lib/SandboxIR/CMakeLists.txt b/llvm/lib/SandboxIR/CMakeLists.txt index 6386fc908388a..a1295d67bc54f 100644 --- a/llvm/lib/SandboxIR/CMakeLists.txt +++ b/llvm/lib/SandboxIR/CMakeLists.txt @@ -3,6 +3,7 @@ add_llvm_component_library(LLVMSandboxIR Module.cpp Pass.cpp PassManager.cpp + Region.cpp SandboxIR.cpp Tracker.cpp Type.cpp diff --git a/llvm/lib/Transforms/Vectorize/SandboxVectorizer/Region.cpp b/llvm/lib/SandboxIR/Region.cpp similarity index 96% rename from llvm/lib/Transforms/Vectorize/SandboxVectorizer/Region.cpp rename to llvm/lib/SandboxIR/Region.cpp index 5f2c28484f62b..b14c87f44260f 100644 --- a/llvm/lib/Transforms/Vectorize/SandboxVectorizer/Region.cpp +++ b/llvm/lib/SandboxIR/Region.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -#include "llvm/Transforms/Vectorize/SandboxVectorizer/Region.h" +#include "llvm/SandboxIR/Region.h" namespace llvm::sandboxir { diff --git a/llvm/lib/Transforms/Vectorize/CMakeLists.txt b/llvm/lib/Transforms/Vectorize/CMakeLists.txt index 8bd3dbf069573..eeff4a9f6a8ba 100644 --- a/llvm/lib/Transforms/Vectorize/CMakeLists.txt +++ b/llvm/lib/Transforms/Vectorize/CMakeLists.txt @@ -5,7 +5,6 @@ add_llvm_component_library(LLVMVectorize LoopVectorize.cpp SandboxVectorizer/DependencyGraph.cpp SandboxVectorizer/Passes/BottomUpVec.cpp - SandboxVectorizer/Region.cpp SandboxVectorizer/SandboxVectorizer.cpp SLPVectorizer.cpp Vectorize.cpp diff --git a/llvm/unittests/SandboxIR/CMakeLists.txt b/llvm/unittests/SandboxIR/CMakeLists.txt index 2ab284a511fca..622496ada567f 100644 --- a/llvm/unittests/SandboxIR/CMakeLists.txt +++ b/llvm/unittests/SandboxIR/CMakeLists.txt @@ -7,6 +7,7 @@ set(LLVM_LINK_COMPONENTS add_llvm_unittest(SandboxIRTests PassTest.cpp + RegionTest.cpp SandboxIRTest.cpp TrackerTest.cpp TypesTest.cpp diff --git a/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/RegionTest.cpp b/llvm/unittests/SandboxIR/RegionTest.cpp similarity index 100% rename from llvm/unittests/Transforms/Vectorize/SandboxVectorizer/RegionTest.cpp rename to llvm/unittests/SandboxIR/RegionTest.cpp diff --git a/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/CMakeLists.txt b/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/CMakeLists.txt index 86b1d968094ca..b0ef71ba2114a 100644 --- a/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/CMakeLists.txt +++ b/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/CMakeLists.txt @@ -11,5 +11,4 @@ add_llvm_unittest(SandboxVectorizerTests DependencyGraphTest.cpp InstrIntervalTest.cpp LegalityTest.cpp - RegionTest.cpp ) From 74f276dd0f77cf5958e74eb8deb97e5b953c9e35 Mon Sep 17 00:00:00 2001 From: Jorge Gorbe Moya Date: Thu, 26 Sep 2024 14:56:19 -0700 Subject: [PATCH 014/469] Revert "[SandboxIR][NFC] Move Region from SandboxVectorizer to SandboxIR." (#110177) Reverts llvm/llvm-project#110173. Missed an #include with the old path. --- .../Vectorize/SandboxVectorizer}/Region.h | 0 llvm/lib/SandboxIR/CMakeLists.txt | 1 - llvm/lib/Transforms/Vectorize/CMakeLists.txt | 1 + .../Vectorize/SandboxVectorizer}/Region.cpp | 2 +- llvm/unittests/SandboxIR/CMakeLists.txt | 1 - .../Transforms/Vectorize/SandboxVectorizer/CMakeLists.txt | 1 + .../Vectorize/SandboxVectorizer}/RegionTest.cpp | 0 7 files changed, 3 insertions(+), 3 deletions(-) rename llvm/include/llvm/{SandboxIR => Transforms/Vectorize/SandboxVectorizer}/Region.h (100%) rename llvm/lib/{SandboxIR => Transforms/Vectorize/SandboxVectorizer}/Region.cpp (96%) rename llvm/unittests/{SandboxIR => Transforms/Vectorize/SandboxVectorizer}/RegionTest.cpp (100%) diff --git a/llvm/include/llvm/SandboxIR/Region.h b/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/Region.h similarity index 100% rename from llvm/include/llvm/SandboxIR/Region.h rename to llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/Region.h diff --git a/llvm/lib/SandboxIR/CMakeLists.txt b/llvm/lib/SandboxIR/CMakeLists.txt index a1295d67bc54f..6386fc908388a 100644 --- a/llvm/lib/SandboxIR/CMakeLists.txt +++ b/llvm/lib/SandboxIR/CMakeLists.txt @@ -3,7 +3,6 @@ add_llvm_component_library(LLVMSandboxIR Module.cpp Pass.cpp PassManager.cpp - Region.cpp SandboxIR.cpp Tracker.cpp Type.cpp diff --git a/llvm/lib/Transforms/Vectorize/CMakeLists.txt b/llvm/lib/Transforms/Vectorize/CMakeLists.txt index eeff4a9f6a8ba..8bd3dbf069573 100644 --- a/llvm/lib/Transforms/Vectorize/CMakeLists.txt +++ b/llvm/lib/Transforms/Vectorize/CMakeLists.txt @@ -5,6 +5,7 @@ add_llvm_component_library(LLVMVectorize LoopVectorize.cpp SandboxVectorizer/DependencyGraph.cpp SandboxVectorizer/Passes/BottomUpVec.cpp + SandboxVectorizer/Region.cpp SandboxVectorizer/SandboxVectorizer.cpp SLPVectorizer.cpp Vectorize.cpp diff --git a/llvm/lib/SandboxIR/Region.cpp b/llvm/lib/Transforms/Vectorize/SandboxVectorizer/Region.cpp similarity index 96% rename from llvm/lib/SandboxIR/Region.cpp rename to llvm/lib/Transforms/Vectorize/SandboxVectorizer/Region.cpp index b14c87f44260f..5f2c28484f62b 100644 --- a/llvm/lib/SandboxIR/Region.cpp +++ b/llvm/lib/Transforms/Vectorize/SandboxVectorizer/Region.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -#include "llvm/SandboxIR/Region.h" +#include "llvm/Transforms/Vectorize/SandboxVectorizer/Region.h" namespace llvm::sandboxir { diff --git a/llvm/unittests/SandboxIR/CMakeLists.txt b/llvm/unittests/SandboxIR/CMakeLists.txt index 622496ada567f..2ab284a511fca 100644 --- a/llvm/unittests/SandboxIR/CMakeLists.txt +++ b/llvm/unittests/SandboxIR/CMakeLists.txt @@ -7,7 +7,6 @@ set(LLVM_LINK_COMPONENTS add_llvm_unittest(SandboxIRTests PassTest.cpp - RegionTest.cpp SandboxIRTest.cpp TrackerTest.cpp TypesTest.cpp diff --git a/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/CMakeLists.txt b/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/CMakeLists.txt index b0ef71ba2114a..86b1d968094ca 100644 --- a/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/CMakeLists.txt +++ b/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/CMakeLists.txt @@ -11,4 +11,5 @@ add_llvm_unittest(SandboxVectorizerTests DependencyGraphTest.cpp InstrIntervalTest.cpp LegalityTest.cpp + RegionTest.cpp ) diff --git a/llvm/unittests/SandboxIR/RegionTest.cpp b/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/RegionTest.cpp similarity index 100% rename from llvm/unittests/SandboxIR/RegionTest.cpp rename to llvm/unittests/Transforms/Vectorize/SandboxVectorizer/RegionTest.cpp From 139688a699f6db784bd559b147334f1d51314f9c Mon Sep 17 00:00:00 2001 From: Tex Riddell Date: Thu, 26 Sep 2024 15:00:59 -0700 Subject: [PATCH 015/469] [SPIRV] Add atan2 function lowering (p2) (#110037) This change is part of this proposal: https://discourse.llvm.org/t/rfc-all-the-math-intrinsics/78294 - Add generic opcode for atan2 - Add SPIRV lowering for atan2 Part 2 for Implement the atan2 HLSL Function #70096. --- llvm/docs/GlobalISel/GenericOpcode.rst | 4 +- llvm/include/llvm/Support/TargetOpcodes.def | 3 ++ llvm/include/llvm/Target/GenericOpcodes.td | 7 +++ llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp | 2 + .../Target/SPIRV/SPIRVInstructionSelector.cpp | 2 + llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp | 1 + .../GlobalISel/legalizer-info-validation.mir | 3 ++ .../CodeGen/SPIRV/hlsl-intrinsics/atan2.ll | 49 +++++++++++++++++++ 8 files changed, 69 insertions(+), 2 deletions(-) create mode 100644 llvm/test/CodeGen/SPIRV/hlsl-intrinsics/atan2.ll diff --git a/llvm/docs/GlobalISel/GenericOpcode.rst b/llvm/docs/GlobalISel/GenericOpcode.rst index c42adc10b10a2..1c4e00b956bc4 100644 --- a/llvm/docs/GlobalISel/GenericOpcode.rst +++ b/llvm/docs/GlobalISel/GenericOpcode.rst @@ -633,8 +633,8 @@ G_FCEIL, G_FSQRT, G_FFLOOR, G_FRINT, G_FNEARBYINT These correspond to the standard C functions of the same name. -G_FCOS, G_FSIN, G_FTAN, G_FACOS, G_FASIN, G_FATAN, G_FCOSH, G_FSINH, G_FTANH -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +G_FCOS, G_FSIN, G_FTAN, G_FACOS, G_FASIN, G_FATAN, G_FATAN2, G_FCOSH, G_FSINH, G_FTANH +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ These correspond to the standard C trigonometry functions of the same name. diff --git a/llvm/include/llvm/Support/TargetOpcodes.def b/llvm/include/llvm/Support/TargetOpcodes.def index 9e70eb8d8fdd3..3556a253d875f 100644 --- a/llvm/include/llvm/Support/TargetOpcodes.def +++ b/llvm/include/llvm/Support/TargetOpcodes.def @@ -821,6 +821,9 @@ HANDLE_TARGET_OPCODE(G_FASIN) /// Floating point arctangent. HANDLE_TARGET_OPCODE(G_FATAN) +/// Floating point arctangent of y/x. +HANDLE_TARGET_OPCODE(G_FATAN2) + /// Floating point hyperbolic cosine. HANDLE_TARGET_OPCODE(G_FCOSH) diff --git a/llvm/include/llvm/Target/GenericOpcodes.td b/llvm/include/llvm/Target/GenericOpcodes.td index f5e62dda6fd04..8b8bc9a0e9cf5 100644 --- a/llvm/include/llvm/Target/GenericOpcodes.td +++ b/llvm/include/llvm/Target/GenericOpcodes.td @@ -1048,6 +1048,13 @@ def G_FATAN : GenericInstruction { let hasSideEffects = false; } +// Floating point arctangent of a value. +def G_FATAN2 : GenericInstruction { + let OutOperandList = (outs type0:$dst); + let InOperandList = (ins type0:$src1, type0:$src2); + let hasSideEffects = false; +} + // Floating point hyperbolic cosine of a value. def G_FCOSH : GenericInstruction { let OutOperandList = (outs type0:$dst); diff --git a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp index 8e860a1f74029..7ff8d2446eec5 100644 --- a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp +++ b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp @@ -1885,6 +1885,8 @@ unsigned IRTranslator::getSimpleIntrinsicOpcode(Intrinsic::ID ID) { return TargetOpcode::G_FASIN; case Intrinsic::atan: return TargetOpcode::G_FATAN; + case Intrinsic::atan2: + return TargetOpcode::G_FATAN2; case Intrinsic::bswap: return TargetOpcode::G_BSWAP; case Intrinsic::bitreverse: diff --git a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp index 43c92f24a0ad1..2f7efbdc81f84 100644 --- a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp @@ -540,6 +540,8 @@ bool SPIRVInstructionSelector::spvSelect(Register ResVReg, return selectExtInst(ResVReg, ResType, I, CL::asin, GL::Asin); case TargetOpcode::G_FATAN: return selectExtInst(ResVReg, ResType, I, CL::atan, GL::Atan); + case TargetOpcode::G_FATAN2: + return selectExtInst(ResVReg, ResType, I, CL::atan2, GL::Atan2); case TargetOpcode::G_FCOSH: return selectExtInst(ResVReg, ResType, I, CL::cosh, GL::Cosh); case TargetOpcode::G_FSINH: diff --git a/llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp b/llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp index de9c495d4cbac..460f0127d4ffc 100644 --- a/llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp @@ -321,6 +321,7 @@ SPIRVLegalizerInfo::SPIRVLegalizerInfo(const SPIRVSubtarget &ST) { G_FACOS, G_FASIN, G_FATAN, + G_FATAN2, G_FCOSH, G_FSINH, G_FTANH, diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/legalizer-info-validation.mir b/llvm/test/CodeGen/AArch64/GlobalISel/legalizer-info-validation.mir index db2412de48b56..a21b786a2bae9 100644 --- a/llvm/test/CodeGen/AArch64/GlobalISel/legalizer-info-validation.mir +++ b/llvm/test/CodeGen/AArch64/GlobalISel/legalizer-info-validation.mir @@ -717,6 +717,9 @@ # DEBUG-NEXT: .. opcode {{[0-9]+}} is aliased to {{[0-9]+}} # DEBUG-NEXT: .. the first uncovered type index: 1, OK # DEBUG-NEXT: .. the first uncovered imm index: 0, OK +# DEBUG-NEXT: G_FATAN2 (opcode {{[0-9]+}}): 1 type index, 0 imm indices +# DEBUG-NEXT: .. type index coverage check SKIPPED: no rules defined +# DEBUG-NEXT: .. imm index coverage check SKIPPED: no rules defined # DEBUG-NEXT: G_FCOSH (opcode {{[0-9]+}}): 1 type index, 0 imm indices # DEBUG-NEXT: .. opcode {{[0-9]+}} is aliased to {{[0-9]+}} # DEBUG-NEXT: .. the first uncovered type index: 1, OK diff --git a/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/atan2.ll b/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/atan2.ll new file mode 100644 index 0000000000000..bdbfc133efa29 --- /dev/null +++ b/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/atan2.ll @@ -0,0 +1,49 @@ +; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s +; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-unknown %s -o - -filetype=obj | spirv-val %} + +; CHECK-DAG: %[[#op_ext_glsl:]] = OpExtInstImport "GLSL.std.450" +; CHECK-DAG: %[[#float_32:]] = OpTypeFloat 32 +; CHECK-DAG: %[[#float_16:]] = OpTypeFloat 16 +; CHECK-DAG: %[[#vec4_float_32:]] = OpTypeVector %[[#float_32]] 4 +; CHECK-DAG: %[[#vec4_float_16:]] = OpTypeVector %[[#float_16]] 4 + +define noundef float @atan2_float(float noundef %a, float noundef %b) { +entry: +; CHECK: %[[#arg0:]] = OpFunctionParameter %[[#]] +; CHECK: %[[#arg1:]] = OpFunctionParameter %[[#]] +; CHECK: %[[#]] = OpExtInst %[[#float_32]] %[[#op_ext_glsl]] Atan2 %[[#arg0]] %[[#arg1]] + %elt.atan2 = call float @llvm.atan2.f32(float %a, float %b) + ret float %elt.atan2 +} + +define noundef half @atan2_half(half noundef %a, half noundef %b) { +entry: +; CHECK: %[[#arg0:]] = OpFunctionParameter %[[#]] +; CHECK: %[[#arg1:]] = OpFunctionParameter %[[#]] +; CHECK: %[[#]] = OpExtInst %[[#float_16]] %[[#op_ext_glsl]] Atan2 %[[#arg0]] %[[#arg1]] + %elt.atan2 = call half @llvm.atan2.f16(half %a, half %b) + ret half %elt.atan2 +} + +define noundef <4 x float> @atan2_float4(<4 x float> noundef %a, <4 x float> noundef %b) { +entry: + ; CHECK: %[[#arg0:]] = OpFunctionParameter %[[#]] + ; CHECK: %[[#arg1:]] = OpFunctionParameter %[[#]] + ; CHECK: %[[#]] = OpExtInst %[[#vec4_float_32]] %[[#op_ext_glsl]] Atan2 %[[#arg0]] %[[#arg1]] + %elt.atan2 = call <4 x float> @llvm.atan2.v4f32(<4 x float> %a, <4 x float> %b) + ret <4 x float> %elt.atan2 +} + +define noundef <4 x half> @atan2_half4(<4 x half> noundef %a, <4 x half> noundef %b) { +entry: + ; CHECK: %[[#arg0:]] = OpFunctionParameter %[[#]] + ; CHECK: %[[#arg1:]] = OpFunctionParameter %[[#]] + ; CHECK: %[[#]] = OpExtInst %[[#vec4_float_16]] %[[#op_ext_glsl]] Atan2 %[[#arg0]] %[[#arg1]] + %elt.atan2 = call <4 x half> @llvm.atan2.v4f16(<4 x half> %a, <4 x half> %b) + ret <4 x half> %elt.atan2 +} + +declare half @llvm.atan2.f16(half, half) +declare float @llvm.atan2.f32(float, float) +declare <4 x half> @llvm.atan2.v4f16(<4 x half>, <4 x half>) +declare <4 x float> @llvm.atan2.v4f32(<4 x float>, <4 x float>) From 1eecc1346a9c13eab078c4fd981c755adfda97d5 Mon Sep 17 00:00:00 2001 From: Walter Lee <49250218+googlewalt@users.noreply.github.com> Date: Thu, 26 Sep 2024 18:30:52 -0400 Subject: [PATCH 016/469] [mlir] NFC: Fix layering check / parse headers violations (#110117) Those tools check strict dependency and standalone headers in Google, but some internal build optimizations caused some violations not to be detected. This change adds a missing dependency, and includes some types that are needed for template instantiation. --- .../mlir/Dialect/Linalg/TransformOps/LinalgTransformOps.h | 5 +---- utils/bazel/llvm-project-overlay/mlir/BUILD.bazel | 1 + 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/mlir/include/mlir/Dialect/Linalg/TransformOps/LinalgTransformOps.h b/mlir/include/mlir/Dialect/Linalg/TransformOps/LinalgTransformOps.h index db25c9b241734..9ede21e87cf53 100644 --- a/mlir/include/mlir/Dialect/Linalg/TransformOps/LinalgTransformOps.h +++ b/mlir/include/mlir/Dialect/Linalg/TransformOps/LinalgTransformOps.h @@ -14,6 +14,7 @@ #include "mlir/Dialect/Linalg/IR/Linalg.h" #include "mlir/Dialect/Transform/IR/TransformAttrs.h" #include "mlir/Dialect/Transform/IR/TransformDialect.h" +#include "mlir/Dialect/Transform/IR/TransformTypes.h" #include "mlir/Dialect/Transform/Interfaces/TransformInterfaces.h" #include "mlir/Dialect/Utils/StructuredOpsUtils.h" #include "mlir/IR/OpImplementation.h" @@ -42,10 +43,6 @@ class UnPackOp; } // namespace tensor namespace transform { -class AnyOpType; -class AnyValueType; -class OperationType; -class TransformHandleTypeInterface; // Types needed for builders. struct TileSizesSpec {}; struct NumThreadsSpec {}; diff --git a/utils/bazel/llvm-project-overlay/mlir/BUILD.bazel b/utils/bazel/llvm-project-overlay/mlir/BUILD.bazel index 1f47d603e9576..81598ab077919 100644 --- a/utils/bazel/llvm-project-overlay/mlir/BUILD.bazel +++ b/utils/bazel/llvm-project-overlay/mlir/BUILD.bazel @@ -12371,6 +12371,7 @@ cc_library( hdrs = glob(["include/mlir/Dialect/Transform/IR/*.h"]), deps = [ ":Analysis", + ":BytecodeOpInterface", ":CallOpInterfaces", ":CastInterfaces", ":ControlFlowInterfaces", From d8a281590311010955c323806fb24fa484376f4d Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Thu, 26 Sep 2024 15:56:33 -0700 Subject: [PATCH 017/469] [clang] implement current direction of CWG2765 for string literal comparisons in constant evaluation (#109208) Track the identity of each string literal object produced by evaluation with a global version number. Accept comparisons between literals of the same version, and between literals of different versions that cannot possibly be placed in overlapping storage. Treat the remaining comparisons as non-constant. --------- Co-authored-by: Timm Baeder Co-authored-by: Aaron Ballman --- clang/docs/ReleaseNotes.rst | 18 +++ clang/include/clang/AST/ASTContext.h | 12 ++ .../include/clang/Basic/DiagnosticASTKinds.td | 3 + clang/lib/AST/ExprConstant.cpp | 130 ++++++++++++++++-- clang/test/AST/ByteCode/builtin-functions.cpp | 3 +- clang/test/AST/ByteCode/cxx20.cpp | 20 +-- .../Modules/string-literal-uniqueness.cpp | 60 ++++++++ clang/test/SemaCXX/builtins.cpp | 14 +- .../SemaCXX/constant-expression-cxx11.cpp | 41 ++++-- .../SemaCXX/constant-expression-cxx14.cpp | 15 ++ clang/test/SemaCXX/ptrauth-sign-constant.cpp | 7 + 11 files changed, 282 insertions(+), 41 deletions(-) create mode 100644 clang/test/Modules/string-literal-uniqueness.cpp create mode 100644 clang/test/SemaCXX/ptrauth-sign-constant.cpp diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 14907e7db18de..1fbcac807d0b3 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -81,6 +81,24 @@ C++ Specific Potentially Breaking Changes template void f(); +- During constant evaluation, comparisons between different evaluations of the + same string literal are now correctly treated as non-constant, and comparisons + between string literals that cannot possibly overlap in memory are now treated + as constant. This updates Clang to match the anticipated direction of open core + issue `CWG2765 `, but is subject to change once that + issue is resolved. + + .. code-block:: c++ + + constexpr const char *f() { return "hello"; } + constexpr const char *g() { return "world"; } + // Used to evaluate to false, now error: non-constant comparison. + constexpr bool a = f() == f(); + // Might evaluate to true or false, as before. + bool at_runtime() { return f() == f(); } + // Was error, now evaluates to false. + constexpr bool b = f() == g(); + ABI Changes in This Version --------------------------- diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index fbf38ab4da6c8..3db9871a4b07b 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -324,6 +324,14 @@ class ASTContext : public RefCountedBase { /// This is lazily created. This is intentionally not serialized. mutable llvm::StringMap StringLiteralCache; + /// The next string literal "version" to allocate during constant evaluation. + /// This is used to distinguish between repeated evaluations of the same + /// string literal. + /// + /// We don't need to serialize this because constants get re-evaluated in the + /// current file before they are compared locally. + unsigned NextStringLiteralVersion = 0; + /// MD5 hash of CUID. It is calculated when first used and cached by this /// data member. mutable std::string CUIDHash; @@ -3300,6 +3308,10 @@ class ASTContext : public RefCountedBase { /// PredefinedExpr to cache evaluated results. StringLiteral *getPredefinedStringLiteralFromCache(StringRef Key) const; + /// Return the next version number to be used for a string literal evaluated + /// as part of constant evaluation. + unsigned getNextStringLiteralVersion() { return NextStringLiteralVersion++; } + /// Return a declaration for the global GUID object representing the given /// GUID value. MSGuidDecl *getMSGuidDecl(MSGuidDeclParts Parts) const; diff --git a/clang/include/clang/Basic/DiagnosticASTKinds.td b/clang/include/clang/Basic/DiagnosticASTKinds.td index 21a307d1e8987..6a658cf14356f 100644 --- a/clang/include/clang/Basic/DiagnosticASTKinds.td +++ b/clang/include/clang/Basic/DiagnosticASTKinds.td @@ -96,6 +96,9 @@ def note_constexpr_pointer_constant_comparison : Note< "at runtime">; def note_constexpr_literal_comparison : Note< "comparison of addresses of literals has unspecified value">; +def note_constexpr_opaque_call_comparison : Note< + "comparison against opaque constant address '%0' can only be performed at " + "runtime">; def note_constexpr_pointer_weak_comparison : Note< "comparison against address of weak declaration '%0' can only be performed " "at runtime">; diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 6387e375dda79..960eae36ed1f5 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -54,8 +54,10 @@ #include "clang/Basic/DiagnosticSema.h" #include "clang/Basic/TargetInfo.h" #include "llvm/ADT/APFixedPoint.h" +#include "llvm/ADT/Sequence.h" #include "llvm/ADT/SmallBitVector.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/Support/Casting.h" #include "llvm/Support/Debug.h" #include "llvm/Support/SaveAndRestore.h" #include "llvm/Support/SipHash.h" @@ -2061,8 +2063,8 @@ static bool EvaluateIgnoredValue(EvalInfo &Info, const Expr *E) { return true; } -/// Should this call expression be treated as a no-op? -static bool IsNoOpCall(const CallExpr *E) { +/// Should this call expression be treated as forming an opaque constant? +static bool IsOpaqueConstantCall(const CallExpr *E) { unsigned Builtin = E->getBuiltinCallee(); return (Builtin == Builtin::BI__builtin___CFStringMakeConstantString || Builtin == Builtin::BI__builtin___NSStringMakeConstantString || @@ -2070,6 +2072,12 @@ static bool IsNoOpCall(const CallExpr *E) { Builtin == Builtin::BI__builtin_function_start); } +static bool IsOpaqueConstantCall(const LValue &LVal) { + const auto *BaseExpr = + llvm::dyn_cast_if_present(LVal.Base.dyn_cast()); + return BaseExpr && IsOpaqueConstantCall(BaseExpr); +} + static bool IsGlobalLValue(APValue::LValueBase B) { // C++11 [expr.const]p3 An address constant expression is a prvalue core // constant expression of pointer type that evaluates to... @@ -2115,7 +2123,7 @@ static bool IsGlobalLValue(APValue::LValueBase B) { case Expr::ObjCBoxedExprClass: return cast(E)->isExpressibleAsConstantInitializer(); case Expr::CallExprClass: - return IsNoOpCall(cast(E)); + return IsOpaqueConstantCall(cast(E)); // For GCC compatibility, &&label has static storage duration. case Expr::AddrLabelExprClass: return true; @@ -2142,11 +2150,91 @@ static const ValueDecl *GetLValueBaseDecl(const LValue &LVal) { return LVal.Base.dyn_cast(); } -static bool IsLiteralLValue(const LValue &Value) { - if (Value.getLValueCallIndex()) +// Information about an LValueBase that is some kind of string. +struct LValueBaseString { + std::string ObjCEncodeStorage; + StringRef Bytes; + int CharWidth; +}; + +// Gets the lvalue base of LVal as a string. +static bool GetLValueBaseAsString(const EvalInfo &Info, const LValue &LVal, + LValueBaseString &AsString) { + const auto *BaseExpr = LVal.Base.dyn_cast(); + if (!BaseExpr) + return false; + + // For ObjCEncodeExpr, we need to compute and store the string. + if (const auto *EE = dyn_cast(BaseExpr)) { + Info.Ctx.getObjCEncodingForType(EE->getEncodedType(), + AsString.ObjCEncodeStorage); + AsString.Bytes = AsString.ObjCEncodeStorage; + AsString.CharWidth = 1; + return true; + } + + // Otherwise, we have a StringLiteral. + const auto *Lit = dyn_cast(BaseExpr); + if (const auto *PE = dyn_cast(BaseExpr)) + Lit = PE->getFunctionName(); + + if (!Lit) return false; - const Expr *E = Value.Base.dyn_cast(); - return E && !isa(E); + + AsString.Bytes = Lit->getBytes(); + AsString.CharWidth = Lit->getCharByteWidth(); + return true; +} + +// Determine whether two string literals potentially overlap. This will be the +// case if they agree on the values of all the bytes on the overlapping region +// between them. +// +// The overlapping region is the portion of the two string literals that must +// overlap in memory if the pointers actually point to the same address at +// runtime. For example, if LHS is "abcdef" + 3 and RHS is "cdef\0gh" + 1 then +// the overlapping region is "cdef\0", which in this case does agree, so the +// strings are potentially overlapping. Conversely, for "foobar" + 3 versus +// "bazbar" + 3, the overlapping region contains all of both strings, so they +// are not potentially overlapping, even though they agree from the given +// addresses onwards. +// +// See open core issue CWG2765 which is discussing the desired rule here. +static bool ArePotentiallyOverlappingStringLiterals(const EvalInfo &Info, + const LValue &LHS, + const LValue &RHS) { + LValueBaseString LHSString, RHSString; + if (!GetLValueBaseAsString(Info, LHS, LHSString) || + !GetLValueBaseAsString(Info, RHS, RHSString)) + return false; + + // This is the byte offset to the location of the first character of LHS + // within RHS. We don't need to look at the characters of one string that + // would appear before the start of the other string if they were merged. + CharUnits Offset = RHS.Offset - LHS.Offset; + if (Offset.isNegative()) + LHSString.Bytes = LHSString.Bytes.drop_front(-Offset.getQuantity()); + else + RHSString.Bytes = RHSString.Bytes.drop_front(Offset.getQuantity()); + + bool LHSIsLonger = LHSString.Bytes.size() > RHSString.Bytes.size(); + StringRef Longer = LHSIsLonger ? LHSString.Bytes : RHSString.Bytes; + StringRef Shorter = LHSIsLonger ? RHSString.Bytes : LHSString.Bytes; + int ShorterCharWidth = (LHSIsLonger ? RHSString : LHSString).CharWidth; + + // The null terminator isn't included in the string data, so check for it + // manually. If the longer string doesn't have a null terminator where the + // shorter string ends, they aren't potentially overlapping. + for (int NullByte : llvm::seq(ShorterCharWidth)) { + if (Shorter.size() + NullByte >= Longer.size()) + break; + if (Longer[Shorter.size() + NullByte]) + return false; + } + + // Otherwise, they're potentially overlapping if and only if the overlapping + // region is the same. + return Shorter == Longer.take_front(Shorter.size()); } static bool IsWeakLValue(const LValue &Value) { @@ -8573,7 +8661,10 @@ class LValueExprEvaluator bool VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *E); bool VisitCompoundLiteralExpr(const CompoundLiteralExpr *E); bool VisitMemberExpr(const MemberExpr *E); - bool VisitStringLiteral(const StringLiteral *E) { return Success(E); } + bool VisitStringLiteral(const StringLiteral *E) { + return Success(APValue::LValueBase( + E, 0, Info.getASTContext().getNextStringLiteralVersion())); + } bool VisitObjCEncodeExpr(const ObjCEncodeExpr *E) { return Success(E); } bool VisitCXXTypeidExpr(const CXXTypeidExpr *E); bool VisitCXXUuidofExpr(const CXXUuidofExpr *E); @@ -9639,7 +9730,7 @@ static bool isOneByteCharacterType(QualType T) { bool PointerExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, unsigned BuiltinOp) { - if (IsNoOpCall(E)) + if (IsOpaqueConstantCall(E)) return Success(E); switch (BuiltinOp) { @@ -13889,13 +13980,22 @@ EvaluateComparisonBinaryOperator(EvalInfo &Info, const BinaryOperator *E, (!RHSValue.Base && !RHSValue.Offset.isZero())) return DiagComparison(diag::note_constexpr_pointer_constant_comparison, !RHSValue.Base); - // It's implementation-defined whether distinct literals will have - // distinct addresses. In clang, the result of such a comparison is - // unspecified, so it is not a constant expression. However, we do know - // that the address of a literal will be non-null. - if ((IsLiteralLValue(LHSValue) || IsLiteralLValue(RHSValue)) && - LHSValue.Base && RHSValue.Base) + // C++2c [intro.object]/10: + // Two objects [...] may have the same address if [...] they are both + // potentially non-unique objects. + // C++2c [intro.object]/9: + // An object is potentially non-unique if it is a string literal object, + // the backing array of an initializer list, or a subobject thereof. + // + // This makes the comparison result unspecified, so it's not a constant + // expression. + // + // TODO: Do we need to handle the initializer list case here? + if (ArePotentiallyOverlappingStringLiterals(Info, LHSValue, RHSValue)) return DiagComparison(diag::note_constexpr_literal_comparison); + if (IsOpaqueConstantCall(LHSValue) || IsOpaqueConstantCall(RHSValue)) + return DiagComparison(diag::note_constexpr_opaque_call_comparison, + !IsOpaqueConstantCall(LHSValue)); // We can't tell whether weak symbols will end up pointing to the same // object. if (IsWeakLValue(LHSValue) || IsWeakLValue(RHSValue)) diff --git a/clang/test/AST/ByteCode/builtin-functions.cpp b/clang/test/AST/ByteCode/builtin-functions.cpp index 9fd5eae67a21f..18ccee382d44e 100644 --- a/clang/test/AST/ByteCode/builtin-functions.cpp +++ b/clang/test/AST/ByteCode/builtin-functions.cpp @@ -966,7 +966,8 @@ namespace shufflevector { namespace FunctionStart { void a(void) {} static_assert(__builtin_function_start(a) == a, ""); // both-error {{not an integral constant expression}} \ - // both-note {{comparison of addresses of literals has unspecified value}} + // ref-note {{comparison against opaque constant address '&__builtin_function_start(a)'}} \ + // expected-note {{comparison of addresses of literals has unspecified value}} } namespace BuiltinInImplicitCtor { diff --git a/clang/test/AST/ByteCode/cxx20.cpp b/clang/test/AST/ByteCode/cxx20.cpp index 68e212ff8933f..dea4055c531d2 100644 --- a/clang/test/AST/ByteCode/cxx20.cpp +++ b/clang/test/AST/ByteCode/cxx20.cpp @@ -99,7 +99,7 @@ constexpr int f() { static_assert(f()); #endif -/// Distinct literals have disctinct addresses. +/// Distinct literals have distinct addresses. /// see https://github.com/llvm/llvm-project/issues/58754 constexpr auto foo(const char *p) { return p; } constexpr auto p1 = "test1"; @@ -108,22 +108,16 @@ constexpr auto p2 = "test2"; constexpr bool b1 = foo(p1) == foo(p1); static_assert(b1); -constexpr bool b2 = foo(p1) == foo(p2); // ref-error {{must be initialized by a constant expression}} \ - // ref-note {{comparison of addresses of literals}} \ - // ref-note {{declared here}} -static_assert(!b2); // ref-error {{not an integral constant expression}} \ - // ref-note {{not a constant expression}} +constexpr bool b2 = foo(p1) == foo(p2); +static_assert(!b2); constexpr auto name1() { return "name1"; } constexpr auto name2() { return "name2"; } -constexpr auto b3 = name1() == name1(); -static_assert(b3); -constexpr auto b4 = name1() == name2(); // ref-error {{must be initialized by a constant expression}} \ - // ref-note {{has unspecified value}} \ - // ref-note {{declared here}} -static_assert(!b4); // ref-error {{not an integral constant expression}} \ - // ref-note {{not a constant expression}} +constexpr auto b3 = name1() == name1(); // ref-error {{must be initialized by a constant expression}} \ + // ref-note {{comparison of addresses of literals}} +constexpr auto b4 = name1() == name2(); +static_assert(!b4); namespace UninitializedFields { class A { diff --git a/clang/test/Modules/string-literal-uniqueness.cpp b/clang/test/Modules/string-literal-uniqueness.cpp new file mode 100644 index 0000000000000..34adc2b0303bd --- /dev/null +++ b/clang/test/Modules/string-literal-uniqueness.cpp @@ -0,0 +1,60 @@ +// RUN: rm -rf %t +// RUN: mkdir -p %t +// RUN: split-file %s %t + +// RUN: %clang_cc1 -std=c++20 -emit-module-interface %t/a.cpp \ +// RUN: -o %t/A.pcm + +// RUN: %clang_cc1 -std=c++20 -emit-module-interface %t/b.cpp \ +// RUN: -fmodule-file=A=%t/A.pcm -o %t/B.pcm + +// RUN: %clang_cc1 -std=c++20 -emit-module-interface %t/c.cpp \ +// RUN: -fmodule-file=A=%t/A.pcm -o %t/C.pcm + +// RUN: %clang_cc1 -std=c++20 -verify %t/main.cpp \ +// RUN: -fmodule-file=A=%t/A.pcm \ +// RUN: -fmodule-file=B=%t/B.pcm \ +// RUN: -fmodule-file=C=%t/C.pcm + +// expected-no-diagnostics + +//--- a.cpp + +export module A; +export consteval const char *hello() { return "hello"; } +export constexpr const char *helloA0 = hello(); +export constexpr const char *helloA1 = helloA0; +export constexpr const char *helloA2 = hello(); + +//--- b.cpp + +export module B; +import A; +export constexpr const char *helloB1 = helloA0; +export constexpr const char *helloB2 = hello(); + +//--- c.cpp + +export module C; +import A; +export constexpr const char *helloC1 = helloA1; +export constexpr const char *helloC2 = hello(); + +//--- main.cpp + +import A; +import B; +import C; + +// These are valid: they refer to the same evaluation of the same constant. +static_assert(helloA0 == helloA1); +static_assert(helloA0 == helloB1); +static_assert(helloA0 == helloC1); + +// These refer to distinct evaluations, and so may or may not be equal. +static_assert(helloA1 == helloA2); // expected-error {{}} expected-note {{unspecified value}} +static_assert(helloA1 == helloB2); // expected-error {{}} expected-note {{unspecified value}} +static_assert(helloA1 == helloC2); // expected-error {{}} expected-note {{unspecified value}} +static_assert(helloA2 == helloB2); // expected-error {{}} expected-note {{unspecified value}} +static_assert(helloA2 == helloC2); // expected-error {{}} expected-note {{unspecified value}} +static_assert(helloB2 == helloC2); // expected-error {{}} expected-note {{unspecified value}} diff --git a/clang/test/SemaCXX/builtins.cpp b/clang/test/SemaCXX/builtins.cpp index f47ed3a1f7ebf..f99bb87b9cbd4 100644 --- a/clang/test/SemaCXX/builtins.cpp +++ b/clang/test/SemaCXX/builtins.cpp @@ -1,13 +1,21 @@ -// RUN: %clang_cc1 %s -fsyntax-only -verify -std=c++11 -fcxx-exceptions -// RUN: %clang_cc1 %s -fsyntax-only -verify -std=c++1z -fcxx-exceptions +// RUN: %clang_cc1 %s -fsyntax-only -verify -std=c++11 -fcxx-exceptions -fptrauth-intrinsics +// RUN: %clang_cc1 %s -fsyntax-only -verify -std=c++1z -fcxx-exceptions -fptrauth-intrinsics typedef const struct __CFString * CFStringRef; #define CFSTR __builtin___CFStringMakeConstantString +#define NSSTR __builtin___NSStringMakeConstantString void f() { #if !defined(__MVS__) && !defined(_AIX) // Builtin function __builtin___CFStringMakeConstantString is currently // unsupported on z/OS and AIX. (void)CFStringRef(CFSTR("Hello")); + + constexpr bool a = CFSTR("Hello") == CFSTR("Hello"); + // expected-error@-1 {{constant expression}} + // expected-note@-2 {{comparison against opaque constant address '&__builtin___CFStringMakeConstantString("Hello")'}} + constexpr bool b = NSSTR("Hello") == NSSTR("Hello"); + // expected-error@-1 {{constant expression}} + // expected-note@-2 {{comparison against opaque constant address '&__builtin___NSStringMakeConstantString("Hello")'}} #endif } @@ -47,7 +55,7 @@ void a(void) {} int n; void *p = __builtin_function_start(n); // expected-error {{argument must be a function}} static_assert(__builtin_function_start(a) == a, ""); // expected-error {{static assertion expression is not an integral constant expression}} -// expected-note@-1 {{comparison of addresses of literals has unspecified value}} +// expected-note@-1 {{comparison against opaque constant address '&__builtin_function_start(a)'}} } // namespace function_start void no_ms_builtins() { diff --git a/clang/test/SemaCXX/constant-expression-cxx11.cpp b/clang/test/SemaCXX/constant-expression-cxx11.cpp index 44ef540f41fa8..e2ea984b37cd0 100644 --- a/clang/test/SemaCXX/constant-expression-cxx11.cpp +++ b/clang/test/SemaCXX/constant-expression-cxx11.cpp @@ -2,6 +2,10 @@ // RUN: %clang_cc1 -std=c++20 -isystem %S/Inputs -fsyntax-only -verify=expected,cxx11_20,cxx20_23,pre-cxx23 -triple x86_64-linux -Wno-string-plus-int -Wno-pointer-arith -Wno-zero-length-array -Wno-c99-designator -fcxx-exceptions -pedantic %s -Wno-comment -Wno-tautological-pointer-compare -Wno-bool-conversion // RUN: %clang_cc1 -std=c++11 -isystem %S/Inputs -fsyntax-only -verify=expected,cxx11_20,cxx11,pre-cxx23 -triple x86_64-linux -Wno-string-plus-int -Wno-pointer-arith -Wno-zero-length-array -Wno-c99-designator -fcxx-exceptions -pedantic %s -Wno-comment -Wno-tautological-pointer-compare -Wno-bool-conversion +// This macro forces its argument to be constant-folded, even if it's not +// otherwise a constant expression. +#define fold(x) (__builtin_constant_p(x) ? (x) : (x)) + namespace StaticAssertFoldTest { int x; @@ -358,11 +362,36 @@ struct Str { extern char externalvar[]; constexpr bool constaddress = (void *)externalvar == (void *)0x4000UL; // expected-error {{must be initialized by a constant expression}} expected-note {{reinterpret_cast}} -constexpr bool litaddress = "foo" == "foo"; // expected-error {{must be initialized by a constant expression}} -// expected-note@-1 {{comparison of addresses of literals has unspecified value}} -// cxx20_23-warning@-2 {{comparison between two arrays is deprecated}} static_assert(0 != "foo", ""); +// OK: These string literals cannot possibly overlap. +static_assert(+"foo" != +"bar", ""); +static_assert("xfoo" + 1 != "yfoo" + 1, ""); +static_assert(+"foot" != +"foo", ""); +static_assert(+"foo\0bar" != +"foo\0baz", ""); + +// These can't overlap because the null terminator for UTF-16 is two bytes wide. +static_assert(fold((const char*)u"A" != (const char*)"\0A\0x"), ""); +static_assert(fold((const char*)u"A" != (const char*)"A\0\0x"), ""); + +constexpr const char *string = "hello"; +constexpr const char *also_string = string; +static_assert(string == string, ""); +static_assert(string == also_string, ""); + +// These strings may overlap, and so the result of the comparison is unknown. +constexpr bool may_overlap_1 = +"foo" == +"foo"; // expected-error {{}} expected-note {{addresses of literals}} +constexpr bool may_overlap_2 = +"foo" == +"foo\0bar"; // expected-error {{}} expected-note {{addresses of literals}} +constexpr bool may_overlap_3 = +"foo" == "bar\0foo" + 4; // expected-error {{}} expected-note {{addresses of literals}} +constexpr bool may_overlap_4 = "xfoo" + 1 == "xfoo" + 1; // expected-error {{}} expected-note {{addresses of literals}} + +// These may overlap even though they have different encodings. +// One of these two comparisons is non-constant, but due to endianness we don't +// know which one. +constexpr bool may_overlap_different_encoding[] = + {fold((const char*)u"A" != (const char*)"xA\0\0\0x" + 1), fold((const char*)u"A" != (const char*)"x\0A\0\0x" + 1)}; + // expected-error@-2 {{}} expected-note@-1 {{addresses of literals}} + } namespace MaterializeTemporary { @@ -1543,16 +1572,10 @@ namespace MutableMembers { namespace Fold { - // This macro forces its argument to be constant-folded, even if it's not - // otherwise a constant expression. - #define fold(x) (__builtin_constant_p(x) ? (x) : (x)) - constexpr int n = (long)(char*)123; // expected-error {{constant expression}} expected-note {{reinterpret_cast}} constexpr int m = fold((long)(char*)123); // ok static_assert(m == 123, ""); - #undef fold - } namespace DR1454 { diff --git a/clang/test/SemaCXX/constant-expression-cxx14.cpp b/clang/test/SemaCXX/constant-expression-cxx14.cpp index 70ab5dcd357c1..936d3600953b9 100644 --- a/clang/test/SemaCXX/constant-expression-cxx14.cpp +++ b/clang/test/SemaCXX/constant-expression-cxx14.cpp @@ -1306,3 +1306,18 @@ constexpr int field(int a) { static_assert(field(3), ""); // expected-error {{constant expression}} \ // expected-note {{in call to 'field(3)'}} } + +namespace literal_comparison { + +constexpr bool different_in_loop(bool b = false) { + if (b) return false; + + const char *p[2] = {}; + for (const char *&r : p) + r = "hello"; + return p[0] == p[1]; // expected-note {{addresses of literals}} +} +constexpr bool check = different_in_loop(); + // expected-error@-1 {{}} expected-note@-1 {{in call}} + +} diff --git a/clang/test/SemaCXX/ptrauth-sign-constant.cpp b/clang/test/SemaCXX/ptrauth-sign-constant.cpp new file mode 100644 index 0000000000000..396962e33e2fa --- /dev/null +++ b/clang/test/SemaCXX/ptrauth-sign-constant.cpp @@ -0,0 +1,7 @@ +// RUN: %clang_cc1 -triple arm64-apple-ios -std=c++17 -Wno-vla -fsyntax-only -verify -fptrauth-intrinsics %s +// RUN: %clang_cc1 -triple aarch64-linux-gnu -std=c++17 -Wno-vla -fsyntax-only -verify -fptrauth-intrinsics %s + +int n; +constexpr bool compare_result = __builtin_ptrauth_sign_constant(&n, 2, 0) == &n; +// expected-error@-1 {{constant expression}} +// expected-note@-2 {{comparison against opaque constant address '&__builtin_ptrauth_sign_constant(&n, 2, 0)'}} \ No newline at end of file From a82fd981d841dea4fd8cee2223a133f2d687a3bd Mon Sep 17 00:00:00 2001 From: Jorge Gorbe Moya Date: Thu, 26 Sep 2024 16:18:14 -0700 Subject: [PATCH 018/469] [bazel][SandboxIR] Add cc_test rule for SandboxIR tests. (#110184) --- .../bazel/llvm-project-overlay/llvm/BUILD.bazel | 1 + .../llvm/unittests/BUILD.bazel | 17 +++++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/utils/bazel/llvm-project-overlay/llvm/BUILD.bazel b/utils/bazel/llvm-project-overlay/llvm/BUILD.bazel index 62f1c2a50acf7..eb87b6f7cef54 100644 --- a/utils/bazel/llvm-project-overlay/llvm/BUILD.bazel +++ b/utils/bazel/llvm-project-overlay/llvm/BUILD.bazel @@ -1457,6 +1457,7 @@ cc_library( copts = llvm_copts, textual_hdrs = ["include/llvm/SandboxIR/SandboxIRValues.def"], deps = [ + ":Analysis", ":Core", ":Support", ], diff --git a/utils/bazel/llvm-project-overlay/llvm/unittests/BUILD.bazel b/utils/bazel/llvm-project-overlay/llvm/unittests/BUILD.bazel index 1170458664250..2c73f03dd70a3 100644 --- a/utils/bazel/llvm-project-overlay/llvm/unittests/BUILD.bazel +++ b/utils/bazel/llvm-project-overlay/llvm/unittests/BUILD.bazel @@ -632,6 +632,23 @@ cc_test( ], ) +cc_test( + name = "sandboxir_tests", + size = "small", + srcs = glob( + ["SandboxIR/*.cpp"], + allow_empty = False, + ), + deps = [ + "//llvm:AsmParser", + "//llvm:Core", + "//llvm:SandboxIR", + "//llvm:Support", + "//third-party/unittest:gmock", + "//third-party/unittest:gtest", + ], +) + cc_test( name = "profile_data_tests", size = "small", From 14afac0d1a5d4d64a7d9622b78dc38ba5c925c56 Mon Sep 17 00:00:00 2001 From: vporpo Date: Thu, 26 Sep 2024 16:37:24 -0700 Subject: [PATCH 019/469] [SandboxIR][NFC] Move Argument into a separate file (#110174) --- llvm/include/llvm/SandboxIR/Argument.h | 38 +++++++++++++++++++++++++ llvm/include/llvm/SandboxIR/SandboxIR.h | 20 +------------ llvm/include/llvm/SandboxIR/Value.h | 2 ++ llvm/lib/SandboxIR/Argument.cpp | 23 +++++++++++++++ llvm/lib/SandboxIR/CMakeLists.txt | 1 + llvm/lib/SandboxIR/SandboxIR.cpp | 11 +------ 6 files changed, 66 insertions(+), 29 deletions(-) create mode 100644 llvm/include/llvm/SandboxIR/Argument.h create mode 100644 llvm/lib/SandboxIR/Argument.cpp diff --git a/llvm/include/llvm/SandboxIR/Argument.h b/llvm/include/llvm/SandboxIR/Argument.h new file mode 100644 index 0000000000000..aed886e8f22f2 --- /dev/null +++ b/llvm/include/llvm/SandboxIR/Argument.h @@ -0,0 +1,38 @@ +//===- Argument.h -----------------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SANDBOXIR_ARGUMENT_H +#define LLVM_SANDBOXIR_ARGUMENT_H + +#include "llvm/IR/Argument.h" +#include "llvm/SandboxIR/Value.h" + +namespace llvm::sandboxir { + +/// Argument of a sandboxir::Function. +class Argument : public sandboxir::Value { + Argument(llvm::Argument *Arg, sandboxir::Context &Ctx) + : Value(ClassID::Argument, Arg, Ctx) {} + friend class Context; // For constructor. + +public: + static bool classof(const sandboxir::Value *From) { + return From->getSubclassID() == ClassID::Argument; + } +#ifndef NDEBUG + void verify() const final { + assert(isa(Val) && "Expected Argument!"); + } + void printAsOperand(raw_ostream &OS) const; + void dumpOS(raw_ostream &OS) const final; +#endif +}; + +} // namespace llvm::sandboxir + +#endif // LLVM_SANDBOXIR_ARGUMENT_H diff --git a/llvm/include/llvm/SandboxIR/SandboxIR.h b/llvm/include/llvm/SandboxIR/SandboxIR.h index 3d206bca9eae6..66de9ee078d61 100644 --- a/llvm/include/llvm/SandboxIR/SandboxIR.h +++ b/llvm/include/llvm/SandboxIR/SandboxIR.h @@ -109,6 +109,7 @@ #include "llvm/IR/PatternMatch.h" #include "llvm/IR/User.h" #include "llvm/IR/Value.h" +#include "llvm/SandboxIR/Argument.h" #include "llvm/SandboxIR/Context.h" #include "llvm/SandboxIR/Module.h" #include "llvm/SandboxIR/Tracker.h" @@ -189,25 +190,6 @@ class CmpInst; class ICmpInst; class FCmpInst; -/// Argument of a sandboxir::Function. -class Argument : public sandboxir::Value { - Argument(llvm::Argument *Arg, sandboxir::Context &Ctx) - : sandboxir::Value(ClassID::Argument, Arg, Ctx) {} - friend class Context; // For constructor. - -public: - static bool classof(const sandboxir::Value *From) { - return From->getSubclassID() == ClassID::Argument; - } -#ifndef NDEBUG - void verify() const final { - assert(isa(Val) && "Expected Argument!"); - } - void printAsOperand(raw_ostream &OS) const; - void dumpOS(raw_ostream &OS) const final; -#endif -}; - class Constant : public sandboxir::User { protected: Constant(llvm::Constant *C, sandboxir::Context &SBCtx) diff --git a/llvm/include/llvm/SandboxIR/Value.h b/llvm/include/llvm/SandboxIR/Value.h index 5dc06c5fc39bf..49bd9be82b0df 100644 --- a/llvm/include/llvm/SandboxIR/Value.h +++ b/llvm/include/llvm/SandboxIR/Value.h @@ -16,6 +16,8 @@ namespace llvm::sandboxir { // Forward declare all classes to avoid some MSVC build errors. #define DEF_INSTR(ID, OPC, CLASS) class CLASS; +#define DEF_CONST(ID, CLASS) class CLASS; +#define DEF_USER(ID, CLASS) class CLASS; #include "llvm/SandboxIR/SandboxIRValues.def" class Context; class FuncletPadInst; diff --git a/llvm/lib/SandboxIR/Argument.cpp b/llvm/lib/SandboxIR/Argument.cpp new file mode 100644 index 0000000000000..e35da2d1dbcb7 --- /dev/null +++ b/llvm/lib/SandboxIR/Argument.cpp @@ -0,0 +1,23 @@ +//===- Argument.cpp - The function Argument class of Sandbox IR -----------===// +// +// 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 "llvm/SandboxIR/Argument.h" + +namespace llvm::sandboxir { + +#ifndef NDEBUG +void Argument::printAsOperand(raw_ostream &OS) const { + printAsOperandCommon(OS); +} +void Argument::dumpOS(raw_ostream &OS) const { + dumpCommonPrefix(OS); + dumpCommonSuffix(OS); +} +#endif // NDEBUG + +} // namespace llvm::sandboxir diff --git a/llvm/lib/SandboxIR/CMakeLists.txt b/llvm/lib/SandboxIR/CMakeLists.txt index 6386fc908388a..d9259db970da5 100644 --- a/llvm/lib/SandboxIR/CMakeLists.txt +++ b/llvm/lib/SandboxIR/CMakeLists.txt @@ -1,4 +1,5 @@ add_llvm_component_library(LLVMSandboxIR + Argument.cpp Context.cpp Module.cpp Pass.cpp diff --git a/llvm/lib/SandboxIR/SandboxIR.cpp b/llvm/lib/SandboxIR/SandboxIR.cpp index 92b1ebeedc55b..12cac66480b0c 100644 --- a/llvm/lib/SandboxIR/SandboxIR.cpp +++ b/llvm/lib/SandboxIR/SandboxIR.cpp @@ -10,6 +10,7 @@ #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/IR/Constants.h" +#include "llvm/SandboxIR/Argument.h" #include "llvm/Support/Debug.h" #include @@ -105,16 +106,6 @@ int OperandUseIterator::operator-(const OperandUseIterator &Other) const { return ThisOpNo - OtherOpNo; } -#ifndef NDEBUG -void Argument::printAsOperand(raw_ostream &OS) const { - printAsOperandCommon(OS); -} -void Argument::dumpOS(raw_ostream &OS) const { - dumpCommonPrefix(OS); - dumpCommonSuffix(OS); -} -#endif // NDEBUG - BBIterator &BBIterator::operator++() { auto ItE = BB->end(); assert(It != ItE && "Already at end!"); From 2f2d8df080c7352afea050a468e9bac622b60b26 Mon Sep 17 00:00:00 2001 From: LLVM GN Syncbot Date: Thu, 26 Sep 2024 23:37:49 +0000 Subject: [PATCH 020/469] [gn build] Port 14afac0d1a5d --- llvm/utils/gn/secondary/llvm/lib/SandboxIR/BUILD.gn | 1 + 1 file changed, 1 insertion(+) diff --git a/llvm/utils/gn/secondary/llvm/lib/SandboxIR/BUILD.gn b/llvm/utils/gn/secondary/llvm/lib/SandboxIR/BUILD.gn index c6fbddb4bf13a..abf09e9d84045 100644 --- a/llvm/utils/gn/secondary/llvm/lib/SandboxIR/BUILD.gn +++ b/llvm/utils/gn/secondary/llvm/lib/SandboxIR/BUILD.gn @@ -6,6 +6,7 @@ static_library("SandboxIR") { "//llvm/lib/Support", ] sources = [ + "Argument.cpp", "Context.cpp", "Module.cpp", "Pass.cpp", From e82b26a3d388594a8af5640cd8aa570f7ecda469 Mon Sep 17 00:00:00 2001 From: Chris B Date: Thu, 26 Sep 2024 18:57:57 -0500 Subject: [PATCH 021/469] [HLSL] Vector Usual Arithmetic Conversions (#108659) HLSL has a different set of usual arithmetic conversions for vector types to resolve a common type for binary operator expressions. This PR implements the current spec proposal from: https://github.com/microsoft/hlsl-specs/pull/311 There is one case that may need additional handling for implicitly truncating `vector` to `T` early to allow other transformations. Fixes #106253 --- .../clang/Basic/DiagnosticSemaKinds.td | 3 + clang/include/clang/Driver/Options.td | 2 +- clang/include/clang/Sema/Sema.h | 3 +- clang/include/clang/Sema/SemaHLSL.h | 5 + clang/lib/Sema/SemaExpr.cpp | 18 +- clang/lib/Sema/SemaHLSL.cpp | 188 +++++++++ .../Language/UsualArithmeticConversions.hlsl | 379 ++++++++++++++++++ 7 files changed, 594 insertions(+), 4 deletions(-) create mode 100644 clang/test/SemaHLSL/Language/UsualArithmeticConversions.hlsl diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index f3d5d4c56606c..9e8f152852fd1 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -12395,6 +12395,9 @@ def err_hlsl_operator_unsupported : Error< def err_hlsl_param_qualifier_mismatch : Error<"conflicting parameter qualifier %0 on parameter %1">; +def err_hlsl_vector_compound_assignment_truncation : Error< + "left hand operand of type %0 to compound assignment cannot be truncated " + "when used with right hand operand of type %1">; def warn_hlsl_impcast_vector_truncation : Warning< "implicit conversion truncates vector: %0 to %1">, InGroup; diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index 932cf13edab53..1dc2ff18170ab 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -2978,7 +2978,7 @@ def flax_vector_conversions_EQ : Joined<["-"], "flax-vector-conversions=">, Grou "LangOptions::LaxVectorConversionKind::Integer", "LangOptions::LaxVectorConversionKind::All"]>, MarshallingInfoEnum, - open_cl.KeyPath # + !strconcat("(", open_cl.KeyPath, " || ", hlsl.KeyPath, ")") # " ? LangOptions::LaxVectorConversionKind::None" # " : LangOptions::LaxVectorConversionKind::All">; def flax_vector_conversions : Flag<["-"], "flax-vector-conversions">, Group, diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index e1c3a99cfa167..a9ce3681338d4 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -7423,7 +7423,8 @@ class Sema final : public SemaBase { SourceLocation Loc, BinaryOperatorKind Opc); QualType CheckVectorLogicalOperands(ExprResult &LHS, ExprResult &RHS, - SourceLocation Loc); + SourceLocation Loc, + BinaryOperatorKind Opc); /// Context in which we're performing a usual arithmetic conversion. enum ArithConvKind { diff --git a/clang/include/clang/Sema/SemaHLSL.h b/clang/include/clang/Sema/SemaHLSL.h index 311cd58bbcac2..fa957abc9791a 100644 --- a/clang/include/clang/Sema/SemaHLSL.h +++ b/clang/include/clang/Sema/SemaHLSL.h @@ -63,6 +63,11 @@ class SemaHLSL : public SemaBase { std::initializer_list AllowedStages); void DiagnoseAvailabilityViolations(TranslationUnitDecl *TU); + QualType handleVectorBinOpConversion(ExprResult &LHS, ExprResult &RHS, + QualType LHSType, QualType RHSType, + bool IsCompAssign); + void emitLogicalOperatorFixIt(Expr *LHS, Expr *RHS, BinaryOperatorKind Opc); + void handleNumThreadsAttr(Decl *D, const ParsedAttr &AL); void handleWaveSizeAttr(Decl *D, const ParsedAttr &AL); void handleSV_DispatchThreadIDAttr(Decl *D, const ParsedAttr &AL); diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 66df9c969256a..e072fb65b8132 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -10133,6 +10133,10 @@ QualType Sema::CheckVectorOperands(ExprResult &LHS, ExprResult &RHS, const VectorType *RHSVecType = RHSType->getAs(); assert(LHSVecType || RHSVecType); + if (getLangOpts().HLSL) + return HLSL().handleVectorBinOpConversion(LHS, RHS, LHSType, RHSType, + IsCompAssign); + // AltiVec-style "vector bool op vector bool" combinations are allowed // for some operators but not others. if (!AllowBothBool && LHSVecType && @@ -12863,7 +12867,8 @@ static void diagnoseXorMisusedAsPow(Sema &S, const ExprResult &XorLHS, } QualType Sema::CheckVectorLogicalOperands(ExprResult &LHS, ExprResult &RHS, - SourceLocation Loc) { + SourceLocation Loc, + BinaryOperatorKind Opc) { // Ensure that either both operands are of the same vector type, or // one operand is of a vector type and the other is of its element type. QualType vType = CheckVectorOperands(LHS, RHS, Loc, false, @@ -12883,6 +12888,15 @@ QualType Sema::CheckVectorLogicalOperands(ExprResult &LHS, ExprResult &RHS, if (!getLangOpts().CPlusPlus && !(isa(vType->getAs()))) return InvalidLogicalVectorOperands(Loc, LHS, RHS); + // Beginning with HLSL 2021, HLSL disallows logical operators on vector + // operands and instead requires the use of the `and`, `or`, `any`, `all`, and + // `select` functions. + if (getLangOpts().HLSL && + getLangOpts().getHLSLVersion() >= LangOptionsBase::HLSL_2021) { + (void)InvalidOperands(Loc, LHS, RHS); + HLSL().emitLogicalOperatorFixIt(LHS.get(), RHS.get(), Opc); + return QualType(); + } return GetSignedVectorType(LHS.get()->getType()); } @@ -13054,7 +13068,7 @@ inline QualType Sema::CheckLogicalOperands(ExprResult &LHS, ExprResult &RHS, // Check vector operands differently. if (LHS.get()->getType()->isVectorType() || RHS.get()->getType()->isVectorType()) - return CheckVectorLogicalOperands(LHS, RHS, Loc); + return CheckVectorLogicalOperands(LHS, RHS, Loc, Opc); bool EnumConstantInBoolContext = false; for (const ExprResult &HS : {LHS, RHS}) { diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp index 1d8ccdda45573..f17b606a8f262 100644 --- a/clang/lib/Sema/SemaHLSL.cpp +++ b/clang/lib/Sema/SemaHLSL.cpp @@ -401,6 +401,194 @@ void SemaHLSL::DiagnoseAttrStageMismatch( << (AllowedStages.size() != 1) << join(StageStrings, ", "); } +template +static void castVector(Sema &S, ExprResult &E, QualType &Ty, unsigned Sz) { + if (const auto *VTy = Ty->getAs()) + Ty = VTy->getElementType(); + Ty = S.getASTContext().getExtVectorType(Ty, Sz); + E = S.ImpCastExprToType(E.get(), Ty, Kind); +} + +template +static QualType castElement(Sema &S, ExprResult &E, QualType Ty) { + E = S.ImpCastExprToType(E.get(), Ty, Kind); + return Ty; +} + +static QualType handleFloatVectorBinOpConversion( + Sema &SemaRef, ExprResult &LHS, ExprResult &RHS, QualType LHSType, + QualType RHSType, QualType LElTy, QualType RElTy, bool IsCompAssign) { + bool LHSFloat = LElTy->isRealFloatingType(); + bool RHSFloat = RElTy->isRealFloatingType(); + + if (LHSFloat && RHSFloat) { + if (IsCompAssign || + SemaRef.getASTContext().getFloatingTypeOrder(LElTy, RElTy) > 0) + return castElement(SemaRef, RHS, LHSType); + + return castElement(SemaRef, LHS, RHSType); + } + + if (LHSFloat) + return castElement(SemaRef, RHS, LHSType); + + assert(RHSFloat); + if (IsCompAssign) + return castElement(SemaRef, RHS, LHSType); + + return castElement(SemaRef, LHS, RHSType); +} + +static QualType handleIntegerVectorBinOpConversion( + Sema &SemaRef, ExprResult &LHS, ExprResult &RHS, QualType LHSType, + QualType RHSType, QualType LElTy, QualType RElTy, bool IsCompAssign) { + + int IntOrder = SemaRef.Context.getIntegerTypeOrder(LElTy, RElTy); + bool LHSSigned = LElTy->hasSignedIntegerRepresentation(); + bool RHSSigned = RElTy->hasSignedIntegerRepresentation(); + auto &Ctx = SemaRef.getASTContext(); + + // If both types have the same signedness, use the higher ranked type. + if (LHSSigned == RHSSigned) { + if (IsCompAssign || IntOrder >= 0) + return castElement(SemaRef, RHS, LHSType); + + return castElement(SemaRef, LHS, RHSType); + } + + // If the unsigned type has greater than or equal rank of the signed type, use + // the unsigned type. + if (IntOrder != (LHSSigned ? 1 : -1)) { + if (IsCompAssign || RHSSigned) + return castElement(SemaRef, RHS, LHSType); + return castElement(SemaRef, LHS, RHSType); + } + + // At this point the signed type has higher rank than the unsigned type, which + // means it will be the same size or bigger. If the signed type is bigger, it + // can represent all the values of the unsigned type, so select it. + if (Ctx.getIntWidth(LElTy) != Ctx.getIntWidth(RElTy)) { + if (IsCompAssign || LHSSigned) + return castElement(SemaRef, RHS, LHSType); + return castElement(SemaRef, LHS, RHSType); + } + + // This is a bit of an odd duck case in HLSL. It shouldn't happen, but can due + // to C/C++ leaking through. The place this happens today is long vs long + // long. When arguments are vector and vector, + // the long long has higher rank than long even though they are the same size. + + // If this is a compound assignment cast the right hand side to the left hand + // side's type. + if (IsCompAssign) + return castElement(SemaRef, RHS, LHSType); + + // If this isn't a compound assignment we convert to unsigned long long. + QualType ElTy = Ctx.getCorrespondingUnsignedType(LHSSigned ? LElTy : RElTy); + QualType NewTy = Ctx.getExtVectorType( + ElTy, RHSType->castAs()->getNumElements()); + (void)castElement(SemaRef, RHS, NewTy); + + return castElement(SemaRef, LHS, NewTy); +} + +static CastKind getScalarCastKind(ASTContext &Ctx, QualType DestTy, + QualType SrcTy) { + if (DestTy->isRealFloatingType() && SrcTy->isRealFloatingType()) + return CK_FloatingCast; + if (DestTy->isIntegralType(Ctx) && SrcTy->isIntegralType(Ctx)) + return CK_IntegralCast; + if (DestTy->isRealFloatingType()) + return CK_IntegralToFloating; + assert(SrcTy->isRealFloatingType() && DestTy->isIntegralType(Ctx)); + return CK_FloatingToIntegral; +} + +QualType SemaHLSL::handleVectorBinOpConversion(ExprResult &LHS, ExprResult &RHS, + QualType LHSType, + QualType RHSType, + bool IsCompAssign) { + const auto *LVecTy = LHSType->getAs(); + const auto *RVecTy = RHSType->getAs(); + auto &Ctx = getASTContext(); + + // If the LHS is not a vector and this is a compound assignment, we truncate + // the argument to a scalar then convert it to the LHS's type. + if (!LVecTy && IsCompAssign) { + QualType RElTy = RHSType->castAs()->getElementType(); + RHS = SemaRef.ImpCastExprToType(RHS.get(), RElTy, CK_HLSLVectorTruncation); + RHSType = RHS.get()->getType(); + if (Ctx.hasSameUnqualifiedType(LHSType, RHSType)) + return LHSType; + RHS = SemaRef.ImpCastExprToType(RHS.get(), LHSType, + getScalarCastKind(Ctx, LHSType, RHSType)); + return LHSType; + } + + unsigned EndSz = std::numeric_limits::max(); + unsigned LSz = 0; + if (LVecTy) + LSz = EndSz = LVecTy->getNumElements(); + if (RVecTy) + EndSz = std::min(RVecTy->getNumElements(), EndSz); + assert(EndSz != std::numeric_limits::max() && + "one of the above should have had a value"); + + // In a compound assignment, the left operand does not change type, the right + // operand is converted to the type of the left operand. + if (IsCompAssign && LSz != EndSz) { + Diag(LHS.get()->getBeginLoc(), + diag::err_hlsl_vector_compound_assignment_truncation) + << LHSType << RHSType; + return QualType(); + } + + if (RVecTy && RVecTy->getNumElements() > EndSz) + castVector(SemaRef, RHS, RHSType, EndSz); + if (!IsCompAssign && LVecTy && LVecTy->getNumElements() > EndSz) + castVector(SemaRef, LHS, LHSType, EndSz); + + if (!RVecTy) + castVector(SemaRef, RHS, RHSType, EndSz); + if (!IsCompAssign && !LVecTy) + castVector(SemaRef, LHS, LHSType, EndSz); + + // If we're at the same type after resizing we can stop here. + if (Ctx.hasSameUnqualifiedType(LHSType, RHSType)) + return Ctx.getCommonSugaredType(LHSType, RHSType); + + QualType LElTy = LHSType->castAs()->getElementType(); + QualType RElTy = RHSType->castAs()->getElementType(); + + // Handle conversion for floating point vectors. + if (LElTy->isRealFloatingType() || RElTy->isRealFloatingType()) + return handleFloatVectorBinOpConversion(SemaRef, LHS, RHS, LHSType, RHSType, + LElTy, RElTy, IsCompAssign); + + assert(LElTy->isIntegralType(Ctx) && RElTy->isIntegralType(Ctx) && + "HLSL Vectors can only contain integer or floating point types"); + return handleIntegerVectorBinOpConversion(SemaRef, LHS, RHS, LHSType, RHSType, + LElTy, RElTy, IsCompAssign); +} + +void SemaHLSL::emitLogicalOperatorFixIt(Expr *LHS, Expr *RHS, + BinaryOperatorKind Opc) { + assert((Opc == BO_LOr || Opc == BO_LAnd) && + "Called with non-logical operator"); + llvm::SmallVector Buff; + llvm::raw_svector_ostream OS(Buff); + PrintingPolicy PP(SemaRef.getLangOpts()); + StringRef NewFnName = Opc == BO_LOr ? "or" : "and"; + OS << NewFnName << "("; + LHS->printPretty(OS, nullptr, PP); + OS << ", "; + RHS->printPretty(OS, nullptr, PP); + OS << ")"; + SourceRange FullRange = SourceRange(LHS->getBeginLoc(), RHS->getEndLoc()); + SemaRef.Diag(LHS->getBeginLoc(), diag::note_function_suggestion) + << NewFnName << FixItHint::CreateReplacement(FullRange, OS.str()); +} + void SemaHLSL::handleNumThreadsAttr(Decl *D, const ParsedAttr &AL) { llvm::VersionTuple SMVersion = getASTContext().getTargetInfo().getTriple().getOSVersion(); diff --git a/clang/test/SemaHLSL/Language/UsualArithmeticConversions.hlsl b/clang/test/SemaHLSL/Language/UsualArithmeticConversions.hlsl new file mode 100644 index 0000000000000..6138169e299fd --- /dev/null +++ b/clang/test/SemaHLSL/Language/UsualArithmeticConversions.hlsl @@ -0,0 +1,379 @@ +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -finclude-default-header -fnative-half-type %s -DERRORS -Wconversion -Wdouble-promotion -verify +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -std=hlsl2018 -finclude-default-header -fnative-half-type %s -DERRORS -Wconversion -Wdouble-promotion -verify +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -finclude-default-header -fnative-half-type %s -ast-dump | FileCheck %s + +//----------------------------------------------------------------------------// +// Case 1: float4 * int4 and inverse. +// +// In both cases here the int is converted to a float and the computation +// produces a float value. +//----------------------------------------------------------------------------// + +// CHECK-LABEL: FunctionDecl {{.*}} used f4f4i4 'float4 (float4, int4)' +// CHECK: BinaryOperator {{.*}} 'float4':'vector' '*' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float4':'vector' +// CHECK-NEXT: DeclRefExpr {{.*}} 'float4':'vector' lvalue ParmVar {{.*}} 'A' 'float4':'vector' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float4':'vector' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int4':'vector' +// CHECK-NEXT: DeclRefExpr {{.*}} 'int4':'vector' lvalue ParmVar {{.*}} 'B' 'int4':'vector' +export float4 f4f4i4(float4 A, int4 B) { + return A * B; // expected-warning{{implicit conversion from 'int4' (aka 'vector') to 'float4' (aka 'vector') may lose precision}} +} + +// CHECK-LABEL: FunctionDecl {{.*}} used f4i4f4 'float4 (float4, int4)' +// CHECK: BinaryOperator {{.*}} 'float4':'vector' '*' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float4':'vector' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int4':'vector' +// CHECK-NEXT: DeclRefExpr {{.*}} 'int4':'vector' lvalue ParmVar {{.*}} 'B' 'int4':'vector' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float4':'vector' +// CHECK-NEXT: DeclRefExpr {{.*}} 'float4':'vector' lvalue ParmVar {{.*}} 'A' 'float4':'vector' +export float4 f4i4f4(float4 A, int4 B) { + return B * A; // expected-warning{{implicit conversion from 'int4' (aka 'vector') to 'float4' (aka 'vector') may lose precision}} +} + +//----------------------------------------------------------------------------// +// Case 2: float4 * int2 and inverse. +// +// In both cases the float vector is trunctated to a float2 and the integer +// vector is converted to a float2. +//----------------------------------------------------------------------------// + +// CHECK-LABEL: FunctionDecl {{.*}} used f2f4i2 'float2 (float4, int2)' +// CHECK: BinaryOperator {{.*}} 'vector' '*' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector' +// CHECK-NEXT: ImplicitCastExpr {{.*}}'float4':'vector' +// CHECK-NEXT: DeclRefExpr {{.*}} 'float4':'vector' lvalue ParmVar {{.*}} 'A' 'float4':'vector' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int2':'vector' +// CHECK-NEXT: DeclRefExpr {{.*}} 'int2':'vector' lvalue ParmVar {{.*}} 'B' 'int2':'vector' +export float2 f2f4i2(float4 A, int2 B) { + // expected-warning@#f2f4i2 {{implicit conversion from 'int2' (aka 'vector') to 'vector' (vector of 2 'float' values) may lose precision}} + // expected-warning@#f2f4i2 {{implicit conversion truncates vector: 'float4' (aka 'vector') to 'vector' (vector of 2 'float' values)}} + return A * B; // #f2f4i2 +} + +// CHECK-LABEL: FunctionDecl {{.*}} used f2i2f4 'float2 (float4, int2)' +// CHECK: BinaryOperator {{.*}} 'vector' '*' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int2':'vector' +// CHECK-NEXT: DeclRefExpr {{.*}} 'int2':'vector' lvalue ParmVar {{.*}} 'B' 'int2':'vector' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector' +// CHECK-NEXT: ImplicitCastExpr {{.*}}'float4':'vector' +// CHECK-NEXT: DeclRefExpr {{.*}} 'float4':'vector' lvalue ParmVar {{.*}} 'A' 'float4':'vector' +export float2 f2i2f4(float4 A, int2 B) { + // expected-warning@#f2i2f4 {{implicit conversion from 'int2' (aka 'vector') to 'vector' (vector of 2 'float' values) may lose precision}} + // expected-warning@#f2i2f4 {{implicit conversion truncates vector: 'float4' (aka 'vector') to 'vector' (vector of 2 'float' values)}} + return B * A; // #f2i2f4 +} + +//----------------------------------------------------------------------------// +// Case 3: Integers of mismatched sign, equivalent size, but the unsigned type +// has lower conversion rank. +// +// This is the odd-ball case for HLSL that isn't really in spec, but we should +// handle gracefully. The lower-ranked unsigned type is converted to the +// equivalent unsigned type of higher rank, and the signed type is also +// converted to that unsigned type (meaning `unsigned long` becomes `unsinged +// long long`, and `long long` becomes `unsigned long long`). +//----------------------------------------------------------------------------// + +// CHECK-LABEL: FunctionDecl {{.*}} used wierdo 'int4 (vector, vector)' +// CHECK: BinaryOperator {{.*}} 'vector' '*' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector' +// CHECK-NEXT: DeclRefExpr{{.*}} 'vector' lvalue ParmVar {{.*}} 'A' 'vector' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector' +// CHECK-NEXT: ImplicitCastExpr{{.*}}> 'vector' +// CHECK-NEXT: DeclRefExpr {{.*}}'vector' lvalue ParmVar {{.*}} 'B' 'vector' +export int4 wierdo(vector A, vector B) { + // expected-warning@#wierdo {{implicit conversion loses integer precision: 'vector' (vector of 4 'unsigned long long' values) to 'vector' (vector of 4 'int' values)}} + // expected-warning@#wierdo {{implicit conversion changes signedness: 'vector' (vector of 4 'long long' values) to 'vector' (vector of 4 'unsigned long long' values)}} + return A * B; // #wierdo +} + +//----------------------------------------------------------------------------// +// Case 4: Compound assignment of float4 with an int4. +// +// In compound assignment the RHS is converted to match the LHS. +//----------------------------------------------------------------------------// + +// CHECK-LABEL: FunctionDecl {{.*}} used f4f4i4compound 'float4 (float4, int4)' +// CHECK: CompoundAssignOperator {{.*}} 'float4':'vector' lvalue '+=' ComputeLHSTy='float4':'vector' ComputeResultTy='float4':'vector' +// CHECK-NEXT: DeclRefExpr {{.*}} 'float4':'vector' lvalue ParmVar {{.*}} 'A' 'float4':'vector' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float4':'vector' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int4':'vector' +// CHECK-NEXT: DeclRefExpr {{.*}} 'int4':'vector' lvalue ParmVar {{.*}} 'B' 'int4':'vector' +export float4 f4f4i4compound(float4 A, int4 B) { + A += B; // expected-warning{{implicit conversion from 'int4' (aka 'vector') to 'float4' (aka 'vector') may lose precision}} + return A; +} + + +//----------------------------------------------------------------------------// +// Case 5: Compound assignment of float2 with an int4. +// +// In compound assignment the RHS is converted to match the LHS. +//----------------------------------------------------------------------------// + +// CHECK-LABEL: FunctionDecl {{.*}} used f4f2i4compound 'float4 (float2, int4)' +// CHECK: CompoundAssignOperator {{.*}} 'float2':'vector' lvalue '+=' ComputeLHSTy='float2':'vector' ComputeResultTy='float2':'vector' +// CHECK-NEXT: DeclRefExpr {{.*}} 'float2':'vector' lvalue ParmVar {{.*}} 'A' 'float2':'vector' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float2':'vector' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int4':'vector' +// CHECK-NEXT: DeclRefExpr {{.*}} 'int4':'vector' lvalue ParmVar {{.*}} 'B' 'int4':'vector' +export float4 f4f2i4compound(float2 A, int4 B) { + // expected-warning@#f4f2i4compound{{implicit conversion truncates vector: 'int4' (aka 'vector') to 'float2' (aka 'vector')}} + // expected-warning@#f4f2i4compound{{implicit conversion from 'int4' (aka 'vector') to 'float2' (aka 'vector') may lose precision}} + A += B; // #f4f2i4compound + return A.xyxy; +} + +//----------------------------------------------------------------------------// +// Case 6: float2 * int4 +// +// The int4 vector is trunctated to int2 then converted to float2. +//----------------------------------------------------------------------------// + +// CHECK-LABEL: FunctionDecl {{.*}} used f4f2i4 'float2 (float2, int4)' +// CHECK: BinaryOperator {{.*}} 'float2':'vector' '*' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float2':'vector' +// CHECK-NEXT: DeclRefExpr {{.*}} 'float2':'vector' lvalue ParmVar {{.*}} 'A' 'float2':'vector' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float2':'vector' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int4':'vector' +// CHECK-NEXT: DeclRefExpr {{.*}} 'int4':'vector' lvalue ParmVar {{.*}} 'B' 'int4':'vector' +export float2 f4f2i4(float2 A, int4 B) { + // expected-warning@#f4f2i4{{implicit conversion truncates vector: 'int4' (aka 'vector') to 'float2' (aka 'vector')}} + // expected-warning@#f4f2i4{{implicit conversion from 'int4' (aka 'vector') to 'float2' (aka 'vector') may lose precision}} + return A * B; // #f4f2i4 +} + +//----------------------------------------------------------------------------// +// Case 7: Compound assignment of half4 with float4, and inverse. +// +// In compound assignment the RHS is converted to match the LHS. +//----------------------------------------------------------------------------// + +// CHECK-LABEL: FunctionDecl {{.*}} used f4h4f4compound 'float4 (half4, float4)' +// CHECK: CompoundAssignOperator {{.*}} 'half4':'vector' lvalue '+=' ComputeLHSTy='half4':'vector' ComputeResultTy='half4':'vector' +// CHECK-NEXT: DeclRefExpr {{.*}} 'half4':'vector' lvalue ParmVar {{.*}} 'A' 'half4':'vector' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'half4':'vector' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float4':'vector' +// CHECK-NEXT: DeclRefExpr {{.*}} 'float4':'vector' lvalue ParmVar {{.*}} 'B' 'float4':'vector' +export float4 f4h4f4compound(half4 A, float4 B) { + A += B; // expected-warning{{implicit conversion loses floating-point precision: 'float4' (aka 'vector') to 'half4' (aka 'vector')}} + return B; +} + +// CHECK-LABEL: FunctionDecl {{.*}} used f4f4h4compound 'float4 (float4, half4)' +// CHECK: CompoundAssignOperator {{.*}} 'float4':'vector' lvalue '+=' ComputeLHSTy='float4':'vector' ComputeResultTy='float4':'vector' +// CHECK-NEXT: DeclRefExpr {{.*}} 'float4':'vector' lvalue ParmVar {{.*}} 'A' 'float4':'vector' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float4':'vector' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'half4':'vector' +// CHECK-NEXT: DeclRefExpr {{.*}} 'half4':'vector' lvalue ParmVar {{.*}} 'B' 'half4':'vector' +export float4 f4f4h4compound(float4 A, half4 B) { + A += B; // expected-warning{{implicit conversion increases floating-point precision: 'half4' (aka 'vector') to 'float4' (aka 'vector')}} + return A; +} + +//----------------------------------------------------------------------------// +// Case 8: int64_t4 * uint4 +// +// The unsigned argument is promoted to the higher ranked signed type since it +// can express all values of the unsgined argument. +//----------------------------------------------------------------------------// + +// CHECK-LABEL: FunctionDecl {{.*}} used l4l4i4 'int64_t4 (int64_t4, uint4)' +// CHECK: BinaryOperator {{.*}} 'int64_t4':'vector' '*' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int64_t4':'vector' +// CHECK-NEXT: DeclRefExpr {{.*}} 'int64_t4':'vector' lvalue ParmVar {{.*}} 'A' 'int64_t4':'vector' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int64_t4':'vector' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'uint4':'vector' +// CHECK-NEXT: DeclRefExpr {{.*}} 'uint4':'vector' lvalue ParmVar {{.*}} 'B' 'uint4':'vector' +export int64_t4 l4l4i4(int64_t4 A, uint4 B) { + return A * B; +} + +//----------------------------------------------------------------------------// +// Case 9: Compound assignment of int4 from int64_t4 +// +// In compound assignment the RHS is converted to match the LHS. +//----------------------------------------------------------------------------// + +// CHECK-LABEL: FunctionDecl {{.*}} used i4i4l4compound 'int4 (int4, int64_t4)' +// CHECK: CompoundAssignOperator {{.*}} 'int4':'vector' lvalue '+=' ComputeLHSTy='int4':'vector' ComputeResultTy='int4':'vector' +// CHECK-NEXT: DeclRefExpr {{.*}} 'int4':'vector' lvalue ParmVar {{.*}} 'A' 'int4':'vector' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int4':'vector' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int64_t4':'vector' +// CHECK-NEXT: DeclRefExpr {{.*}} 'int64_t4':'vector' lvalue ParmVar {{.*}} 'B' 'int64_t4':'vector' +export int4 i4i4l4compound(int4 A, int64_t4 B) { + A += B; // expected-warning{{implicit conversion loses integer precision: 'int64_t4' (aka 'vector') to 'int4' (aka 'vector')}} + return A; +} + +//----------------------------------------------------------------------------// +// Case 10: Compound assignment of vector with argument of +// vector +// +// In compound assignment the RHS is converted to match the LHS. This one is +// also the weird case because it is out of spec, but we should handle it +// gracefully. +//----------------------------------------------------------------------------// + +// CHECK-LABEL: FunctionDecl {{.*}} used wierdocompound 'vector (vector, vector)' +// CHECK: CompoundAssignOperator {{.*}} 'vector' lvalue '+=' ComputeLHSTy='vector' ComputeResultTy='vector' +// CHECK-NEXT: DeclRefExpr {{.*}} 'vector' lvalue ParmVar {{.*}} 'A' 'vector' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector' +// CHECK-NEXT: DeclRefExpr {{.*}} 'vector' lvalue ParmVar {{.*}} 'B' 'vector' +export vector wierdocompound(vector A, vector B) { + // expected-warning@#wierdocompound{{implicit conversion changes signedness: 'vector' (vector of 4 'long long' values) to 'vector' (vector of 4 'unsigned long' values)}} + A += B; // #wierdocompound + return A; +} + +//----------------------------------------------------------------------------// +// Case 11: Compound assignment of scalar with vector argument. +// +// Because the LHS of a compound assignment cannot change type, the RHS must be +// implicitly convertable to the LHS type. +//----------------------------------------------------------------------------// + +// CHECK-LABEL: FunctionDecl {{.*}} used ffi2compound 'float (float, int2)' +// CHECK: CompoundAssignOperator {{.*}} 'float' lvalue '+=' ComputeLHSTy='float' ComputeResultTy='float' +// CHECK-NEXT: DeclRefExpr {{.*}} 'float' lvalue ParmVar {{.*}} 'A' 'float' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int2':'vector' +// CHECK-NEXT: DeclRefExpr {{.*}} 'int2':'vector' lvalue ParmVar {{.*}} 'B' 'int2':'vector' +export float ffi2compound(float A, int2 B) { + A += B; // expected-warning {{implicit conversion turns vector to scalar: 'int2' (aka 'vector') to 'float'}} + return A; +} + +// CHECK-LABEL: FunctionDecl {{.*}} used iif2compound 'int (int, float2)' +// CHECK: CompoundAssignOperator {{.*}} 'int' lvalue '+=' ComputeLHSTy='int' ComputeResultTy='int' +// CHECK-NEXT: DeclRefExpr {{.*}} 'int' lvalue ParmVar {{.*}} 'A' 'int' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' +// CHECK-NEXT: mplicitCastExpr {{.*}} 'float' +// CHECK-NEXT: ImplicitCastExpr{{.*}} 'float2':'vector' +// CHECK-NEXT: DeclRefExpr {{.*}} 'float2':'vector' lvalue ParmVar {{.*}} 'B' 'float2':'vector' +export int iif2compound(int A, float2 B) { + A += B; // expected-warning{{implicit conversion turns vector to scalar: 'float2' (aka 'vector') to 'int'}} + return A; +} + + +//----------------------------------------------------------------------------// +// Case 12: Compound assignment of vector of larger size than the argument. +// +// Because the LHS of a compound assignment cannot change type, the RHS must be +// implicitly convertable to the LHS type. This fails since the RHS type can't +// be vector-extended implicitly. +//----------------------------------------------------------------------------// + +#ifdef ERRORS +// The only cases that are really illegal here are when the RHS is a vector that +// is larger than the LHS or when the LHS is a scalar. + +export float2 f2f4i2compound(float4 A, int2 B) { + A += B; // expected-error{{left hand operand of type 'float4' (aka 'vector') to compound assignment cannot be truncated when used with right hand operand of type 'int2' (aka 'vector')}} + return A.xy; +} + +#endif + +//----------------------------------------------------------------------------// +// Case 13: Comparison operators for mismatched arguments follow the same rules. +// +// Compare operators convert each argument following the usual arithmetic +// conversions. +//----------------------------------------------------------------------------// + +// Note: these cases work and generate correct code, but the way they get there +// may change with https://github.com/llvm/llvm-project/issues/91639, because +// representing boolean vectors as 32-bit integer vectors will allow more +// efficient code generation. + +// CHECK-LABEL: FunctionDecl {{.*}} used b4f4i4Compare 'bool4 (float4, int4)' +// CHECK: ImplicitCastExpr {{.*}} 'vector' +// CHECK-NEXT: BinaryOperator {{.*}} 'vector' '<' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float4':'vector' +// CHECK-NEXT: DeclRefExpr {{.*}} 'float4':'vector' lvalue ParmVar {{.*}} 'A' 'float4':'vector' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float4':'vector' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int4':'vector' +// CHECK-NEXT: DeclRefExpr {{.*}} 'int4':'vector' lvalue ParmVar {{.*}} 'B' 'int4':'vector' +export bool4 b4f4i4Compare(float4 A, int4 B) { + return A < B; // expected-warning{{implicit conversion from 'int4' (aka 'vector') to 'float4' (aka 'vector') may lose precision}} +} + + +// CHECK-LABEL: FunctionDecl {{.*}} used b2f2i4Compare 'bool2 (float2, int4)' +// CHECK: ImplicitCastExpr {{.*}} 'vector' +// CHECK-NEXT: BinaryOperator {{.*}} 'vector' '<=' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float2':'vector' +// CHECK-NEXT: DeclRefExpr {{.*}} 'float2':'vector' lvalue ParmVar {{.*}} 'A' 'float2':'vector' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float2':'vector' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int4':'vector' +// CHECK-NEXT: DeclRefExpr {{.*}} 'int4':'vector' lvalue ParmVar {{.*}} 'B' 'int4':'vector' + +export bool2 b2f2i4Compare(float2 A, int4 B) { + // expected-warning@#b2f2i4Compare{{implicit conversion truncates vector: 'int4' (aka 'vector') to 'float2' (aka 'vector')}} + // expected-warning@#b2f2i4Compare{{implicit conversion from 'int4' (aka 'vector') to 'float2' (aka 'vector') may lose precision}} + return A <= B; // #b2f2i4Compare +} + +// CHECK-LABEL: FunctionDecl {{.*}} used b4fi4Compare 'bool4 (float, int4)' +// CHECK: ImplicitCastExpr {{.*}} 'vector' +// CHECK-NEXT: BinaryOperator {{.*}} 'vector' '>' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' +// CHECK-NEXT: DeclRefExpr {{.*}} 'float' lvalue ParmVar {{.*}} 'A' 'float' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int4':'vector' +// CHECK-NEXT: DeclRefExpr {{.*}} 'int4':'vector' lvalue ParmVar {{.*}} 'B' 'int4':'vector' +export bool4 b4fi4Compare(float A, int4 B) { + return A > B; // expected-warning{{implicit conversion from 'int4' (aka 'vector') to 'vector' (vector of 4 'float' values) may lose precision}} +} + +//----------------------------------------------------------------------------// +// Case 14: Logical operators on vectors are disallowed in HLSL 2021+ +//----------------------------------------------------------------------------// + +#ifdef ERRORS + +#if __HLSL_VERSION >= 2021 +// expected-error@#b4f4i4Logical{{invalid operands to binary expression ('float4' (aka 'vector') and 'int4' (aka 'vector'))}} +// expected-note@#b4f4i4Logical{{did you mean or?}} +#else +// expected-warning@#b4f4i4Logical{{implicit conversion from 'int4' (aka 'vector') to 'float4' (aka 'vector') may lose precision}} +#endif + +export bool4 b4f4i4Logical(float4 A, int4 B) { + return A || B; // #b4f4i4Logical +} + +#if __HLSL_VERSION >= 2021 +// expected-error@#b2f2i4Logical{{invalid operands to binary expression ('float2' (aka 'vector') and 'int4' (aka 'vector'))}} +// expected-note@#b2f2i4Logical{{did you mean and?}} +#else +// expected-warning@#b2f2i4Logical{{implicit conversion truncates vector: 'int4' (aka 'vector') to 'float2' (aka 'vector')}} +// expected-warning@#b2f2i4Logical{{implicit conversion from 'int4' (aka 'vector') to 'float2' (aka 'vector') may lose precision}} +#endif + +export bool2 b2f2i4Logical(float2 A, int4 B) { + return A && B; // #b2f2i4Logical +} + +#if __HLSL_VERSION >= 2021 +// expected-error@#b2b2b2Logical{{invalid operands to binary expression ('bool2' (aka 'vector') and 'bool2')}} +// expected-note@#b2b2b2Logical{{did you mean and?}} +#endif + +export bool2 b2b2b2Logical(bool2 A, bool2 B) { + return A && B; // #b2b2b2Logical +} + +#endif From 2b84ef06ac55ac8de3c210d059ec3a3c96666a90 Mon Sep 17 00:00:00 2001 From: Luke Lau Date: Fri, 27 Sep 2024 08:00:59 +0800 Subject: [PATCH 022/469] [RISCV] Handle f16/bf16 extract_vector_elt when scalar type is legal (#110144) When the scalar type is illegal, it gets softened during type legalization and gets lowered as an integer. However with zfhmin/zfbfmin the type is now legal and it passes through type legalization where it crashes because we didn't have any custom lowering or patterns for it. This handles said case via the existing custom lowering to a vslidedown and vfmv.f.s. It also handles the case where we only have zvfhmin/zvfbfmin and don't have vfmv.f.s, in which case we need to extract it to a GPR and then use fmv.h.x. Fixes #110126 --- llvm/lib/Target/RISCV/RISCVISelLowering.cpp | 15 +- llvm/test/CodeGen/RISCV/rvv/extractelt-fp.ll | 922 ++++++++++++++++--- 2 files changed, 823 insertions(+), 114 deletions(-) diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp index 7a19a879ca342..d52b802bdd52b 100644 --- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp +++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp @@ -1082,8 +1082,9 @@ RISCVTargetLowering::RISCVTargetLowering(const TargetMachine &TM, VT, Custom); MVT EltVT = VT.getVectorElementType(); if (isTypeLegal(EltVT)) - setOperationAction({ISD::SPLAT_VECTOR, ISD::EXPERIMENTAL_VP_SPLAT}, VT, - Custom); + setOperationAction({ISD::SPLAT_VECTOR, ISD::EXPERIMENTAL_VP_SPLAT, + ISD::EXTRACT_VECTOR_ELT}, + VT, Custom); else setOperationAction({ISD::SPLAT_VECTOR, ISD::EXPERIMENTAL_VP_SPLAT}, EltVT, Custom); @@ -8990,6 +8991,16 @@ SDValue RISCVTargetLowering::lowerEXTRACT_VECTOR_ELT(SDValue Op, return DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, EltVT, Vec, Idx); } + if ((EltVT == MVT::f16 && !Subtarget.hasVInstructionsF16()) || + EltVT == MVT::bf16) { + // If we don't have vfmv.f.s for f16/bf16, extract to a gpr then use fmv.h.x + MVT IntVT = VecVT.changeTypeToInteger(); + SDValue IntVec = DAG.getBitcast(IntVT, Vec); + SDValue IntExtract = + DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, XLenVT, IntVec, Idx); + return DAG.getNode(RISCVISD::FMV_H_X, DL, EltVT, IntExtract); + } + // If this is a fixed vector, we need to convert it to a scalable vector. MVT ContainerVT = VecVT; if (VecVT.isFixedLengthVector()) { diff --git a/llvm/test/CodeGen/RISCV/rvv/extractelt-fp.ll b/llvm/test/CodeGen/RISCV/rvv/extractelt-fp.ll index 209a37bf66ae3..86ef78be97afb 100644 --- a/llvm/test/CodeGen/RISCV/rvv/extractelt-fp.ll +++ b/llvm/test/CodeGen/RISCV/rvv/extractelt-fp.ll @@ -1,197 +1,895 @@ ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py -; RUN: llc -mtriple=riscv32 -mattr=+d,+zfh,+zvfh,+v -target-abi=ilp32d \ -; RUN: -verify-machineinstrs < %s | FileCheck %s --check-prefixes=CHECK,RV32 -; RUN: llc -mtriple=riscv64 -mattr=+d,+zfh,+zvfh,+v -target-abi=lp64d \ -; RUN: -verify-machineinstrs < %s | FileCheck %s --check-prefixes=CHECK,RV64 +; RUN: llc -mtriple=riscv32 -mattr=+v,+d,+zvfh,+zvfbfmin -verify-machineinstrs < %s | FileCheck %s --check-prefixes=CHECK,RV32,NOZFMIN,ZVFH +; RUN: llc -mtriple=riscv64 -mattr=+v,+d,+zvfh,+zvfbfmin -verify-machineinstrs < %s | FileCheck %s --check-prefixes=CHECK,RV64,NOZFMIN,ZVFH +; RUN: llc -mtriple=riscv32 -mattr=+v,+d,+zvfhmin,+zvfbfmin -verify-machineinstrs < %s | FileCheck %s --check-prefixes=CHECK,RV32,NOZFMIN,ZVFHMIN +; RUN: llc -mtriple=riscv64 -mattr=+v,+d,+zvfhmin,+zvfbfmin -verify-machineinstrs < %s | FileCheck %s --check-prefixes=CHECK,RV64,NOZFMIN,ZVFHMIN +; RUN: llc -mtriple=riscv32 -mattr=+v,+d,+zfhmin,+zfbfmin,+zvfhmin,+zvfbfmin -verify-machineinstrs < %s | FileCheck %s --check-prefixes=CHECK,RV32,ZFMIN +; RUN: llc -mtriple=riscv64 -mattr=+v,+d,+zfhmin,+zfbfmin,+zvfhmin,+zvfbfmin -verify-machineinstrs < %s | FileCheck %s --check-prefixes=CHECK,RV64,ZFMIN + +define bfloat @extractelt_nxv1bf16_0( %v) { +; NOZFMIN-LABEL: extractelt_nxv1bf16_0: +; NOZFMIN: # %bb.0: +; NOZFMIN-NEXT: vsetivli zero, 1, e16, m1, ta, ma +; NOZFMIN-NEXT: vmv.x.s a0, v8 +; NOZFMIN-NEXT: lui a1, 1048560 +; NOZFMIN-NEXT: or a0, a0, a1 +; NOZFMIN-NEXT: fmv.w.x fa0, a0 +; NOZFMIN-NEXT: ret +; +; ZFMIN-LABEL: extractelt_nxv1bf16_0: +; ZFMIN: # %bb.0: +; ZFMIN-NEXT: vsetivli zero, 1, e16, m1, ta, ma +; ZFMIN-NEXT: vmv.x.s a0, v8 +; ZFMIN-NEXT: fmv.h.x fa0, a0 +; ZFMIN-NEXT: ret + %r = extractelement %v, i32 0 + ret bfloat %r +} + +define bfloat @extractelt_nxv1bf16_imm( %v) { +; NOZFMIN-LABEL: extractelt_nxv1bf16_imm: +; NOZFMIN: # %bb.0: +; NOZFMIN-NEXT: vsetivli zero, 1, e16, mf4, ta, ma +; NOZFMIN-NEXT: vslidedown.vi v8, v8, 2 +; NOZFMIN-NEXT: vmv.x.s a0, v8 +; NOZFMIN-NEXT: lui a1, 1048560 +; NOZFMIN-NEXT: or a0, a0, a1 +; NOZFMIN-NEXT: fmv.w.x fa0, a0 +; NOZFMIN-NEXT: ret +; +; ZFMIN-LABEL: extractelt_nxv1bf16_imm: +; ZFMIN: # %bb.0: +; ZFMIN-NEXT: vsetivli zero, 1, e16, mf4, ta, ma +; ZFMIN-NEXT: vslidedown.vi v8, v8, 2 +; ZFMIN-NEXT: vmv.x.s a0, v8 +; ZFMIN-NEXT: fmv.h.x fa0, a0 +; ZFMIN-NEXT: ret + %r = extractelement %v, i32 2 + ret bfloat %r +} + +define bfloat @extractelt_nxv1bf16_idx( %v, i32 zeroext %idx) { +; NOZFMIN-LABEL: extractelt_nxv1bf16_idx: +; NOZFMIN: # %bb.0: +; NOZFMIN-NEXT: vsetivli zero, 1, e16, mf4, ta, ma +; NOZFMIN-NEXT: vslidedown.vx v8, v8, a0 +; NOZFMIN-NEXT: vmv.x.s a0, v8 +; NOZFMIN-NEXT: lui a1, 1048560 +; NOZFMIN-NEXT: or a0, a0, a1 +; NOZFMIN-NEXT: fmv.w.x fa0, a0 +; NOZFMIN-NEXT: ret +; +; ZFMIN-LABEL: extractelt_nxv1bf16_idx: +; ZFMIN: # %bb.0: +; ZFMIN-NEXT: vsetivli zero, 1, e16, mf4, ta, ma +; ZFMIN-NEXT: vslidedown.vx v8, v8, a0 +; ZFMIN-NEXT: vmv.x.s a0, v8 +; ZFMIN-NEXT: fmv.h.x fa0, a0 +; ZFMIN-NEXT: ret + %r = extractelement %v, i32 %idx + ret bfloat %r +} + +define bfloat @extractelt_nxv2bf16_0( %v) { +; NOZFMIN-LABEL: extractelt_nxv2bf16_0: +; NOZFMIN: # %bb.0: +; NOZFMIN-NEXT: vsetivli zero, 1, e16, m1, ta, ma +; NOZFMIN-NEXT: vmv.x.s a0, v8 +; NOZFMIN-NEXT: lui a1, 1048560 +; NOZFMIN-NEXT: or a0, a0, a1 +; NOZFMIN-NEXT: fmv.w.x fa0, a0 +; NOZFMIN-NEXT: ret +; +; ZFMIN-LABEL: extractelt_nxv2bf16_0: +; ZFMIN: # %bb.0: +; ZFMIN-NEXT: vsetivli zero, 1, e16, m1, ta, ma +; ZFMIN-NEXT: vmv.x.s a0, v8 +; ZFMIN-NEXT: fmv.h.x fa0, a0 +; ZFMIN-NEXT: ret + %r = extractelement %v, i32 0 + ret bfloat %r +} + +define bfloat @extractelt_nxv2bf16_imm( %v) { +; NOZFMIN-LABEL: extractelt_nxv2bf16_imm: +; NOZFMIN: # %bb.0: +; NOZFMIN-NEXT: vsetivli zero, 1, e16, mf2, ta, ma +; NOZFMIN-NEXT: vslidedown.vi v8, v8, 2 +; NOZFMIN-NEXT: vmv.x.s a0, v8 +; NOZFMIN-NEXT: lui a1, 1048560 +; NOZFMIN-NEXT: or a0, a0, a1 +; NOZFMIN-NEXT: fmv.w.x fa0, a0 +; NOZFMIN-NEXT: ret +; +; ZFMIN-LABEL: extractelt_nxv2bf16_imm: +; ZFMIN: # %bb.0: +; ZFMIN-NEXT: vsetivli zero, 1, e16, mf2, ta, ma +; ZFMIN-NEXT: vslidedown.vi v8, v8, 2 +; ZFMIN-NEXT: vmv.x.s a0, v8 +; ZFMIN-NEXT: fmv.h.x fa0, a0 +; ZFMIN-NEXT: ret + %r = extractelement %v, i32 2 + ret bfloat %r +} + +define bfloat @extractelt_nxv2bf16_idx( %v, i32 zeroext %idx) { +; NOZFMIN-LABEL: extractelt_nxv2bf16_idx: +; NOZFMIN: # %bb.0: +; NOZFMIN-NEXT: vsetivli zero, 1, e16, mf2, ta, ma +; NOZFMIN-NEXT: vslidedown.vx v8, v8, a0 +; NOZFMIN-NEXT: vmv.x.s a0, v8 +; NOZFMIN-NEXT: lui a1, 1048560 +; NOZFMIN-NEXT: or a0, a0, a1 +; NOZFMIN-NEXT: fmv.w.x fa0, a0 +; NOZFMIN-NEXT: ret +; +; ZFMIN-LABEL: extractelt_nxv2bf16_idx: +; ZFMIN: # %bb.0: +; ZFMIN-NEXT: vsetivli zero, 1, e16, mf2, ta, ma +; ZFMIN-NEXT: vslidedown.vx v8, v8, a0 +; ZFMIN-NEXT: vmv.x.s a0, v8 +; ZFMIN-NEXT: fmv.h.x fa0, a0 +; ZFMIN-NEXT: ret + %r = extractelement %v, i32 %idx + ret bfloat %r +} + +define bfloat @extractelt_nxv4bf16_0( %v) { +; NOZFMIN-LABEL: extractelt_nxv4bf16_0: +; NOZFMIN: # %bb.0: +; NOZFMIN-NEXT: vsetivli zero, 1, e16, m1, ta, ma +; NOZFMIN-NEXT: vmv.x.s a0, v8 +; NOZFMIN-NEXT: lui a1, 1048560 +; NOZFMIN-NEXT: or a0, a0, a1 +; NOZFMIN-NEXT: fmv.w.x fa0, a0 +; NOZFMIN-NEXT: ret +; +; ZFMIN-LABEL: extractelt_nxv4bf16_0: +; ZFMIN: # %bb.0: +; ZFMIN-NEXT: vsetivli zero, 1, e16, m1, ta, ma +; ZFMIN-NEXT: vmv.x.s a0, v8 +; ZFMIN-NEXT: fmv.h.x fa0, a0 +; ZFMIN-NEXT: ret + %r = extractelement %v, i32 0 + ret bfloat %r +} + +define bfloat @extractelt_nxv4bf16_imm( %v) { +; NOZFMIN-LABEL: extractelt_nxv4bf16_imm: +; NOZFMIN: # %bb.0: +; NOZFMIN-NEXT: vsetivli zero, 1, e16, m1, ta, ma +; NOZFMIN-NEXT: vslidedown.vi v8, v8, 2 +; NOZFMIN-NEXT: vmv.x.s a0, v8 +; NOZFMIN-NEXT: lui a1, 1048560 +; NOZFMIN-NEXT: or a0, a0, a1 +; NOZFMIN-NEXT: fmv.w.x fa0, a0 +; NOZFMIN-NEXT: ret +; +; ZFMIN-LABEL: extractelt_nxv4bf16_imm: +; ZFMIN: # %bb.0: +; ZFMIN-NEXT: vsetivli zero, 1, e16, m1, ta, ma +; ZFMIN-NEXT: vslidedown.vi v8, v8, 2 +; ZFMIN-NEXT: vmv.x.s a0, v8 +; ZFMIN-NEXT: fmv.h.x fa0, a0 +; ZFMIN-NEXT: ret + %r = extractelement %v, i32 2 + ret bfloat %r +} + +define bfloat @extractelt_nxv4bf16_idx( %v, i32 zeroext %idx) { +; NOZFMIN-LABEL: extractelt_nxv4bf16_idx: +; NOZFMIN: # %bb.0: +; NOZFMIN-NEXT: vsetivli zero, 1, e16, m1, ta, ma +; NOZFMIN-NEXT: vslidedown.vx v8, v8, a0 +; NOZFMIN-NEXT: vmv.x.s a0, v8 +; NOZFMIN-NEXT: lui a1, 1048560 +; NOZFMIN-NEXT: or a0, a0, a1 +; NOZFMIN-NEXT: fmv.w.x fa0, a0 +; NOZFMIN-NEXT: ret +; +; ZFMIN-LABEL: extractelt_nxv4bf16_idx: +; ZFMIN: # %bb.0: +; ZFMIN-NEXT: vsetivli zero, 1, e16, m1, ta, ma +; ZFMIN-NEXT: vslidedown.vx v8, v8, a0 +; ZFMIN-NEXT: vmv.x.s a0, v8 +; ZFMIN-NEXT: fmv.h.x fa0, a0 +; ZFMIN-NEXT: ret + %r = extractelement %v, i32 %idx + ret bfloat %r +} + +define bfloat @extractelt_nxv8bf16_0( %v) { +; NOZFMIN-LABEL: extractelt_nxv8bf16_0: +; NOZFMIN: # %bb.0: +; NOZFMIN-NEXT: vsetivli zero, 1, e16, m1, ta, ma +; NOZFMIN-NEXT: vmv.x.s a0, v8 +; NOZFMIN-NEXT: lui a1, 1048560 +; NOZFMIN-NEXT: or a0, a0, a1 +; NOZFMIN-NEXT: fmv.w.x fa0, a0 +; NOZFMIN-NEXT: ret +; +; ZFMIN-LABEL: extractelt_nxv8bf16_0: +; ZFMIN: # %bb.0: +; ZFMIN-NEXT: vsetivli zero, 1, e16, m1, ta, ma +; ZFMIN-NEXT: vmv.x.s a0, v8 +; ZFMIN-NEXT: fmv.h.x fa0, a0 +; ZFMIN-NEXT: ret + %r = extractelement %v, i32 0 + ret bfloat %r +} + +define bfloat @extractelt_nxv8bf16_imm( %v) { +; NOZFMIN-LABEL: extractelt_nxv8bf16_imm: +; NOZFMIN: # %bb.0: +; NOZFMIN-NEXT: vsetivli zero, 1, e16, m1, ta, ma +; NOZFMIN-NEXT: vslidedown.vi v8, v8, 2 +; NOZFMIN-NEXT: vmv.x.s a0, v8 +; NOZFMIN-NEXT: lui a1, 1048560 +; NOZFMIN-NEXT: or a0, a0, a1 +; NOZFMIN-NEXT: fmv.w.x fa0, a0 +; NOZFMIN-NEXT: ret +; +; ZFMIN-LABEL: extractelt_nxv8bf16_imm: +; ZFMIN: # %bb.0: +; ZFMIN-NEXT: vsetivli zero, 1, e16, m1, ta, ma +; ZFMIN-NEXT: vslidedown.vi v8, v8, 2 +; ZFMIN-NEXT: vmv.x.s a0, v8 +; ZFMIN-NEXT: fmv.h.x fa0, a0 +; ZFMIN-NEXT: ret + %r = extractelement %v, i32 2 + ret bfloat %r +} + +define bfloat @extractelt_nxv8bf16_idx( %v, i32 zeroext %idx) { +; NOZFMIN-LABEL: extractelt_nxv8bf16_idx: +; NOZFMIN: # %bb.0: +; NOZFMIN-NEXT: vsetivli zero, 1, e16, m2, ta, ma +; NOZFMIN-NEXT: vslidedown.vx v8, v8, a0 +; NOZFMIN-NEXT: vmv.x.s a0, v8 +; NOZFMIN-NEXT: lui a1, 1048560 +; NOZFMIN-NEXT: or a0, a0, a1 +; NOZFMIN-NEXT: fmv.w.x fa0, a0 +; NOZFMIN-NEXT: ret +; +; ZFMIN-LABEL: extractelt_nxv8bf16_idx: +; ZFMIN: # %bb.0: +; ZFMIN-NEXT: vsetivli zero, 1, e16, m2, ta, ma +; ZFMIN-NEXT: vslidedown.vx v8, v8, a0 +; ZFMIN-NEXT: vmv.x.s a0, v8 +; ZFMIN-NEXT: fmv.h.x fa0, a0 +; ZFMIN-NEXT: ret + %r = extractelement %v, i32 %idx + ret bfloat %r +} + +define bfloat @extractelt_nxv16bf16_0( %v) { +; NOZFMIN-LABEL: extractelt_nxv16bf16_0: +; NOZFMIN: # %bb.0: +; NOZFMIN-NEXT: vsetivli zero, 1, e16, m1, ta, ma +; NOZFMIN-NEXT: vmv.x.s a0, v8 +; NOZFMIN-NEXT: lui a1, 1048560 +; NOZFMIN-NEXT: or a0, a0, a1 +; NOZFMIN-NEXT: fmv.w.x fa0, a0 +; NOZFMIN-NEXT: ret +; +; ZFMIN-LABEL: extractelt_nxv16bf16_0: +; ZFMIN: # %bb.0: +; ZFMIN-NEXT: vsetivli zero, 1, e16, m1, ta, ma +; ZFMIN-NEXT: vmv.x.s a0, v8 +; ZFMIN-NEXT: fmv.h.x fa0, a0 +; ZFMIN-NEXT: ret + %r = extractelement %v, i32 0 + ret bfloat %r +} + +define bfloat @extractelt_nxv16bf16_imm( %v) { +; NOZFMIN-LABEL: extractelt_nxv16bf16_imm: +; NOZFMIN: # %bb.0: +; NOZFMIN-NEXT: vsetivli zero, 1, e16, m1, ta, ma +; NOZFMIN-NEXT: vslidedown.vi v8, v8, 2 +; NOZFMIN-NEXT: vmv.x.s a0, v8 +; NOZFMIN-NEXT: lui a1, 1048560 +; NOZFMIN-NEXT: or a0, a0, a1 +; NOZFMIN-NEXT: fmv.w.x fa0, a0 +; NOZFMIN-NEXT: ret +; +; ZFMIN-LABEL: extractelt_nxv16bf16_imm: +; ZFMIN: # %bb.0: +; ZFMIN-NEXT: vsetivli zero, 1, e16, m1, ta, ma +; ZFMIN-NEXT: vslidedown.vi v8, v8, 2 +; ZFMIN-NEXT: vmv.x.s a0, v8 +; ZFMIN-NEXT: fmv.h.x fa0, a0 +; ZFMIN-NEXT: ret + %r = extractelement %v, i32 2 + ret bfloat %r +} + +define bfloat @extractelt_nxv16bf16_idx( %v, i32 zeroext %idx) { +; NOZFMIN-LABEL: extractelt_nxv16bf16_idx: +; NOZFMIN: # %bb.0: +; NOZFMIN-NEXT: vsetivli zero, 1, e16, m4, ta, ma +; NOZFMIN-NEXT: vslidedown.vx v8, v8, a0 +; NOZFMIN-NEXT: vmv.x.s a0, v8 +; NOZFMIN-NEXT: lui a1, 1048560 +; NOZFMIN-NEXT: or a0, a0, a1 +; NOZFMIN-NEXT: fmv.w.x fa0, a0 +; NOZFMIN-NEXT: ret +; +; ZFMIN-LABEL: extractelt_nxv16bf16_idx: +; ZFMIN: # %bb.0: +; ZFMIN-NEXT: vsetivli zero, 1, e16, m4, ta, ma +; ZFMIN-NEXT: vslidedown.vx v8, v8, a0 +; ZFMIN-NEXT: vmv.x.s a0, v8 +; ZFMIN-NEXT: fmv.h.x fa0, a0 +; ZFMIN-NEXT: ret + %r = extractelement %v, i32 %idx + ret bfloat %r +} + +define bfloat @extractelt_nxv32bf16_0( %v) { +; NOZFMIN-LABEL: extractelt_nxv32bf16_0: +; NOZFMIN: # %bb.0: +; NOZFMIN-NEXT: vsetivli zero, 1, e16, m1, ta, ma +; NOZFMIN-NEXT: vmv.x.s a0, v8 +; NOZFMIN-NEXT: lui a1, 1048560 +; NOZFMIN-NEXT: or a0, a0, a1 +; NOZFMIN-NEXT: fmv.w.x fa0, a0 +; NOZFMIN-NEXT: ret +; +; ZFMIN-LABEL: extractelt_nxv32bf16_0: +; ZFMIN: # %bb.0: +; ZFMIN-NEXT: vsetivli zero, 1, e16, m1, ta, ma +; ZFMIN-NEXT: vmv.x.s a0, v8 +; ZFMIN-NEXT: fmv.h.x fa0, a0 +; ZFMIN-NEXT: ret + %r = extractelement %v, i32 0 + ret bfloat %r +} + +define bfloat @extractelt_nxv32bf16_imm( %v) { +; NOZFMIN-LABEL: extractelt_nxv32bf16_imm: +; NOZFMIN: # %bb.0: +; NOZFMIN-NEXT: vsetivli zero, 1, e16, m1, ta, ma +; NOZFMIN-NEXT: vslidedown.vi v8, v8, 2 +; NOZFMIN-NEXT: vmv.x.s a0, v8 +; NOZFMIN-NEXT: lui a1, 1048560 +; NOZFMIN-NEXT: or a0, a0, a1 +; NOZFMIN-NEXT: fmv.w.x fa0, a0 +; NOZFMIN-NEXT: ret +; +; ZFMIN-LABEL: extractelt_nxv32bf16_imm: +; ZFMIN: # %bb.0: +; ZFMIN-NEXT: vsetivli zero, 1, e16, m1, ta, ma +; ZFMIN-NEXT: vslidedown.vi v8, v8, 2 +; ZFMIN-NEXT: vmv.x.s a0, v8 +; ZFMIN-NEXT: fmv.h.x fa0, a0 +; ZFMIN-NEXT: ret + %r = extractelement %v, i32 2 + ret bfloat %r +} + +define bfloat @extractelt_nxv32bf16_idx( %v, i32 zeroext %idx) { +; NOZFMIN-LABEL: extractelt_nxv32bf16_idx: +; NOZFMIN: # %bb.0: +; NOZFMIN-NEXT: vsetivli zero, 1, e16, m8, ta, ma +; NOZFMIN-NEXT: vslidedown.vx v8, v8, a0 +; NOZFMIN-NEXT: vmv.x.s a0, v8 +; NOZFMIN-NEXT: lui a1, 1048560 +; NOZFMIN-NEXT: or a0, a0, a1 +; NOZFMIN-NEXT: fmv.w.x fa0, a0 +; NOZFMIN-NEXT: ret +; +; ZFMIN-LABEL: extractelt_nxv32bf16_idx: +; ZFMIN: # %bb.0: +; ZFMIN-NEXT: vsetivli zero, 1, e16, m8, ta, ma +; ZFMIN-NEXT: vslidedown.vx v8, v8, a0 +; ZFMIN-NEXT: vmv.x.s a0, v8 +; ZFMIN-NEXT: fmv.h.x fa0, a0 +; ZFMIN-NEXT: ret + %r = extractelement %v, i32 %idx + ret bfloat %r +} define half @extractelt_nxv1f16_0( %v) { -; CHECK-LABEL: extractelt_nxv1f16_0: -; CHECK: # %bb.0: -; CHECK-NEXT: vsetivli zero, 1, e16, m1, ta, ma -; CHECK-NEXT: vfmv.f.s fa0, v8 -; CHECK-NEXT: ret +; ZVFH-LABEL: extractelt_nxv1f16_0: +; ZVFH: # %bb.0: +; ZVFH-NEXT: vsetivli zero, 1, e16, m1, ta, ma +; ZVFH-NEXT: vfmv.f.s fa0, v8 +; ZVFH-NEXT: ret +; +; ZVFHMIN-LABEL: extractelt_nxv1f16_0: +; ZVFHMIN: # %bb.0: +; ZVFHMIN-NEXT: vsetivli zero, 1, e16, m1, ta, ma +; ZVFHMIN-NEXT: vmv.x.s a0, v8 +; ZVFHMIN-NEXT: lui a1, 1048560 +; ZVFHMIN-NEXT: or a0, a0, a1 +; ZVFHMIN-NEXT: fmv.w.x fa0, a0 +; ZVFHMIN-NEXT: ret +; +; ZFMIN-LABEL: extractelt_nxv1f16_0: +; ZFMIN: # %bb.0: +; ZFMIN-NEXT: vsetivli zero, 1, e16, m1, ta, ma +; ZFMIN-NEXT: vmv.x.s a0, v8 +; ZFMIN-NEXT: fmv.h.x fa0, a0 +; ZFMIN-NEXT: ret %r = extractelement %v, i32 0 ret half %r } define half @extractelt_nxv1f16_imm( %v) { -; CHECK-LABEL: extractelt_nxv1f16_imm: -; CHECK: # %bb.0: -; CHECK-NEXT: vsetivli zero, 1, e16, mf4, ta, ma -; CHECK-NEXT: vslidedown.vi v8, v8, 2 -; CHECK-NEXT: vfmv.f.s fa0, v8 -; CHECK-NEXT: ret +; ZVFH-LABEL: extractelt_nxv1f16_imm: +; ZVFH: # %bb.0: +; ZVFH-NEXT: vsetivli zero, 1, e16, mf4, ta, ma +; ZVFH-NEXT: vslidedown.vi v8, v8, 2 +; ZVFH-NEXT: vfmv.f.s fa0, v8 +; ZVFH-NEXT: ret +; +; ZVFHMIN-LABEL: extractelt_nxv1f16_imm: +; ZVFHMIN: # %bb.0: +; ZVFHMIN-NEXT: vsetivli zero, 1, e16, mf4, ta, ma +; ZVFHMIN-NEXT: vslidedown.vi v8, v8, 2 +; ZVFHMIN-NEXT: vmv.x.s a0, v8 +; ZVFHMIN-NEXT: lui a1, 1048560 +; ZVFHMIN-NEXT: or a0, a0, a1 +; ZVFHMIN-NEXT: fmv.w.x fa0, a0 +; ZVFHMIN-NEXT: ret +; +; ZFMIN-LABEL: extractelt_nxv1f16_imm: +; ZFMIN: # %bb.0: +; ZFMIN-NEXT: vsetivli zero, 1, e16, mf4, ta, ma +; ZFMIN-NEXT: vslidedown.vi v8, v8, 2 +; ZFMIN-NEXT: vmv.x.s a0, v8 +; ZFMIN-NEXT: fmv.h.x fa0, a0 +; ZFMIN-NEXT: ret %r = extractelement %v, i32 2 ret half %r } define half @extractelt_nxv1f16_idx( %v, i32 zeroext %idx) { -; CHECK-LABEL: extractelt_nxv1f16_idx: -; CHECK: # %bb.0: -; CHECK-NEXT: vsetivli zero, 1, e16, mf4, ta, ma -; CHECK-NEXT: vslidedown.vx v8, v8, a0 -; CHECK-NEXT: vfmv.f.s fa0, v8 -; CHECK-NEXT: ret +; ZVFH-LABEL: extractelt_nxv1f16_idx: +; ZVFH: # %bb.0: +; ZVFH-NEXT: vsetivli zero, 1, e16, mf4, ta, ma +; ZVFH-NEXT: vslidedown.vx v8, v8, a0 +; ZVFH-NEXT: vfmv.f.s fa0, v8 +; ZVFH-NEXT: ret +; +; ZVFHMIN-LABEL: extractelt_nxv1f16_idx: +; ZVFHMIN: # %bb.0: +; ZVFHMIN-NEXT: vsetivli zero, 1, e16, mf4, ta, ma +; ZVFHMIN-NEXT: vslidedown.vx v8, v8, a0 +; ZVFHMIN-NEXT: vmv.x.s a0, v8 +; ZVFHMIN-NEXT: lui a1, 1048560 +; ZVFHMIN-NEXT: or a0, a0, a1 +; ZVFHMIN-NEXT: fmv.w.x fa0, a0 +; ZVFHMIN-NEXT: ret +; +; ZFMIN-LABEL: extractelt_nxv1f16_idx: +; ZFMIN: # %bb.0: +; ZFMIN-NEXT: vsetivli zero, 1, e16, mf4, ta, ma +; ZFMIN-NEXT: vslidedown.vx v8, v8, a0 +; ZFMIN-NEXT: vmv.x.s a0, v8 +; ZFMIN-NEXT: fmv.h.x fa0, a0 +; ZFMIN-NEXT: ret %r = extractelement %v, i32 %idx ret half %r } define half @extractelt_nxv2f16_0( %v) { -; CHECK-LABEL: extractelt_nxv2f16_0: -; CHECK: # %bb.0: -; CHECK-NEXT: vsetivli zero, 1, e16, m1, ta, ma -; CHECK-NEXT: vfmv.f.s fa0, v8 -; CHECK-NEXT: ret +; ZVFH-LABEL: extractelt_nxv2f16_0: +; ZVFH: # %bb.0: +; ZVFH-NEXT: vsetivli zero, 1, e16, m1, ta, ma +; ZVFH-NEXT: vfmv.f.s fa0, v8 +; ZVFH-NEXT: ret +; +; ZVFHMIN-LABEL: extractelt_nxv2f16_0: +; ZVFHMIN: # %bb.0: +; ZVFHMIN-NEXT: vsetivli zero, 1, e16, m1, ta, ma +; ZVFHMIN-NEXT: vmv.x.s a0, v8 +; ZVFHMIN-NEXT: lui a1, 1048560 +; ZVFHMIN-NEXT: or a0, a0, a1 +; ZVFHMIN-NEXT: fmv.w.x fa0, a0 +; ZVFHMIN-NEXT: ret +; +; ZFMIN-LABEL: extractelt_nxv2f16_0: +; ZFMIN: # %bb.0: +; ZFMIN-NEXT: vsetivli zero, 1, e16, m1, ta, ma +; ZFMIN-NEXT: vmv.x.s a0, v8 +; ZFMIN-NEXT: fmv.h.x fa0, a0 +; ZFMIN-NEXT: ret %r = extractelement %v, i32 0 ret half %r } define half @extractelt_nxv2f16_imm( %v) { -; CHECK-LABEL: extractelt_nxv2f16_imm: -; CHECK: # %bb.0: -; CHECK-NEXT: vsetivli zero, 1, e16, mf2, ta, ma -; CHECK-NEXT: vslidedown.vi v8, v8, 2 -; CHECK-NEXT: vfmv.f.s fa0, v8 -; CHECK-NEXT: ret +; ZVFH-LABEL: extractelt_nxv2f16_imm: +; ZVFH: # %bb.0: +; ZVFH-NEXT: vsetivli zero, 1, e16, mf2, ta, ma +; ZVFH-NEXT: vslidedown.vi v8, v8, 2 +; ZVFH-NEXT: vfmv.f.s fa0, v8 +; ZVFH-NEXT: ret +; +; ZVFHMIN-LABEL: extractelt_nxv2f16_imm: +; ZVFHMIN: # %bb.0: +; ZVFHMIN-NEXT: vsetivli zero, 1, e16, mf2, ta, ma +; ZVFHMIN-NEXT: vslidedown.vi v8, v8, 2 +; ZVFHMIN-NEXT: vmv.x.s a0, v8 +; ZVFHMIN-NEXT: lui a1, 1048560 +; ZVFHMIN-NEXT: or a0, a0, a1 +; ZVFHMIN-NEXT: fmv.w.x fa0, a0 +; ZVFHMIN-NEXT: ret +; +; ZFMIN-LABEL: extractelt_nxv2f16_imm: +; ZFMIN: # %bb.0: +; ZFMIN-NEXT: vsetivli zero, 1, e16, mf2, ta, ma +; ZFMIN-NEXT: vslidedown.vi v8, v8, 2 +; ZFMIN-NEXT: vmv.x.s a0, v8 +; ZFMIN-NEXT: fmv.h.x fa0, a0 +; ZFMIN-NEXT: ret %r = extractelement %v, i32 2 ret half %r } define half @extractelt_nxv2f16_idx( %v, i32 zeroext %idx) { -; CHECK-LABEL: extractelt_nxv2f16_idx: -; CHECK: # %bb.0: -; CHECK-NEXT: vsetivli zero, 1, e16, mf2, ta, ma -; CHECK-NEXT: vslidedown.vx v8, v8, a0 -; CHECK-NEXT: vfmv.f.s fa0, v8 -; CHECK-NEXT: ret +; ZVFH-LABEL: extractelt_nxv2f16_idx: +; ZVFH: # %bb.0: +; ZVFH-NEXT: vsetivli zero, 1, e16, mf2, ta, ma +; ZVFH-NEXT: vslidedown.vx v8, v8, a0 +; ZVFH-NEXT: vfmv.f.s fa0, v8 +; ZVFH-NEXT: ret +; +; ZVFHMIN-LABEL: extractelt_nxv2f16_idx: +; ZVFHMIN: # %bb.0: +; ZVFHMIN-NEXT: vsetivli zero, 1, e16, mf2, ta, ma +; ZVFHMIN-NEXT: vslidedown.vx v8, v8, a0 +; ZVFHMIN-NEXT: vmv.x.s a0, v8 +; ZVFHMIN-NEXT: lui a1, 1048560 +; ZVFHMIN-NEXT: or a0, a0, a1 +; ZVFHMIN-NEXT: fmv.w.x fa0, a0 +; ZVFHMIN-NEXT: ret +; +; ZFMIN-LABEL: extractelt_nxv2f16_idx: +; ZFMIN: # %bb.0: +; ZFMIN-NEXT: vsetivli zero, 1, e16, mf2, ta, ma +; ZFMIN-NEXT: vslidedown.vx v8, v8, a0 +; ZFMIN-NEXT: vmv.x.s a0, v8 +; ZFMIN-NEXT: fmv.h.x fa0, a0 +; ZFMIN-NEXT: ret %r = extractelement %v, i32 %idx ret half %r } define half @extractelt_nxv4f16_0( %v) { -; CHECK-LABEL: extractelt_nxv4f16_0: -; CHECK: # %bb.0: -; CHECK-NEXT: vsetivli zero, 1, e16, m1, ta, ma -; CHECK-NEXT: vfmv.f.s fa0, v8 -; CHECK-NEXT: ret +; ZVFH-LABEL: extractelt_nxv4f16_0: +; ZVFH: # %bb.0: +; ZVFH-NEXT: vsetivli zero, 1, e16, m1, ta, ma +; ZVFH-NEXT: vfmv.f.s fa0, v8 +; ZVFH-NEXT: ret +; +; ZVFHMIN-LABEL: extractelt_nxv4f16_0: +; ZVFHMIN: # %bb.0: +; ZVFHMIN-NEXT: vsetivli zero, 1, e16, m1, ta, ma +; ZVFHMIN-NEXT: vmv.x.s a0, v8 +; ZVFHMIN-NEXT: lui a1, 1048560 +; ZVFHMIN-NEXT: or a0, a0, a1 +; ZVFHMIN-NEXT: fmv.w.x fa0, a0 +; ZVFHMIN-NEXT: ret +; +; ZFMIN-LABEL: extractelt_nxv4f16_0: +; ZFMIN: # %bb.0: +; ZFMIN-NEXT: vsetivli zero, 1, e16, m1, ta, ma +; ZFMIN-NEXT: vmv.x.s a0, v8 +; ZFMIN-NEXT: fmv.h.x fa0, a0 +; ZFMIN-NEXT: ret %r = extractelement %v, i32 0 ret half %r } define half @extractelt_nxv4f16_imm( %v) { -; CHECK-LABEL: extractelt_nxv4f16_imm: -; CHECK: # %bb.0: -; CHECK-NEXT: vsetivli zero, 1, e16, m1, ta, ma -; CHECK-NEXT: vslidedown.vi v8, v8, 2 -; CHECK-NEXT: vfmv.f.s fa0, v8 -; CHECK-NEXT: ret +; ZVFH-LABEL: extractelt_nxv4f16_imm: +; ZVFH: # %bb.0: +; ZVFH-NEXT: vsetivli zero, 1, e16, m1, ta, ma +; ZVFH-NEXT: vslidedown.vi v8, v8, 2 +; ZVFH-NEXT: vfmv.f.s fa0, v8 +; ZVFH-NEXT: ret +; +; ZVFHMIN-LABEL: extractelt_nxv4f16_imm: +; ZVFHMIN: # %bb.0: +; ZVFHMIN-NEXT: vsetivli zero, 1, e16, m1, ta, ma +; ZVFHMIN-NEXT: vslidedown.vi v8, v8, 2 +; ZVFHMIN-NEXT: vmv.x.s a0, v8 +; ZVFHMIN-NEXT: lui a1, 1048560 +; ZVFHMIN-NEXT: or a0, a0, a1 +; ZVFHMIN-NEXT: fmv.w.x fa0, a0 +; ZVFHMIN-NEXT: ret +; +; ZFMIN-LABEL: extractelt_nxv4f16_imm: +; ZFMIN: # %bb.0: +; ZFMIN-NEXT: vsetivli zero, 1, e16, m1, ta, ma +; ZFMIN-NEXT: vslidedown.vi v8, v8, 2 +; ZFMIN-NEXT: vmv.x.s a0, v8 +; ZFMIN-NEXT: fmv.h.x fa0, a0 +; ZFMIN-NEXT: ret %r = extractelement %v, i32 2 ret half %r } define half @extractelt_nxv4f16_idx( %v, i32 zeroext %idx) { -; CHECK-LABEL: extractelt_nxv4f16_idx: -; CHECK: # %bb.0: -; CHECK-NEXT: vsetivli zero, 1, e16, m1, ta, ma -; CHECK-NEXT: vslidedown.vx v8, v8, a0 -; CHECK-NEXT: vfmv.f.s fa0, v8 -; CHECK-NEXT: ret +; ZVFH-LABEL: extractelt_nxv4f16_idx: +; ZVFH: # %bb.0: +; ZVFH-NEXT: vsetivli zero, 1, e16, m1, ta, ma +; ZVFH-NEXT: vslidedown.vx v8, v8, a0 +; ZVFH-NEXT: vfmv.f.s fa0, v8 +; ZVFH-NEXT: ret +; +; ZVFHMIN-LABEL: extractelt_nxv4f16_idx: +; ZVFHMIN: # %bb.0: +; ZVFHMIN-NEXT: vsetivli zero, 1, e16, m1, ta, ma +; ZVFHMIN-NEXT: vslidedown.vx v8, v8, a0 +; ZVFHMIN-NEXT: vmv.x.s a0, v8 +; ZVFHMIN-NEXT: lui a1, 1048560 +; ZVFHMIN-NEXT: or a0, a0, a1 +; ZVFHMIN-NEXT: fmv.w.x fa0, a0 +; ZVFHMIN-NEXT: ret +; +; ZFMIN-LABEL: extractelt_nxv4f16_idx: +; ZFMIN: # %bb.0: +; ZFMIN-NEXT: vsetivli zero, 1, e16, m1, ta, ma +; ZFMIN-NEXT: vslidedown.vx v8, v8, a0 +; ZFMIN-NEXT: vmv.x.s a0, v8 +; ZFMIN-NEXT: fmv.h.x fa0, a0 +; ZFMIN-NEXT: ret %r = extractelement %v, i32 %idx ret half %r } define half @extractelt_nxv8f16_0( %v) { -; CHECK-LABEL: extractelt_nxv8f16_0: -; CHECK: # %bb.0: -; CHECK-NEXT: vsetivli zero, 1, e16, m1, ta, ma -; CHECK-NEXT: vfmv.f.s fa0, v8 -; CHECK-NEXT: ret +; ZVFH-LABEL: extractelt_nxv8f16_0: +; ZVFH: # %bb.0: +; ZVFH-NEXT: vsetivli zero, 1, e16, m1, ta, ma +; ZVFH-NEXT: vfmv.f.s fa0, v8 +; ZVFH-NEXT: ret +; +; ZVFHMIN-LABEL: extractelt_nxv8f16_0: +; ZVFHMIN: # %bb.0: +; ZVFHMIN-NEXT: vsetivli zero, 1, e16, m1, ta, ma +; ZVFHMIN-NEXT: vmv.x.s a0, v8 +; ZVFHMIN-NEXT: lui a1, 1048560 +; ZVFHMIN-NEXT: or a0, a0, a1 +; ZVFHMIN-NEXT: fmv.w.x fa0, a0 +; ZVFHMIN-NEXT: ret +; +; ZFMIN-LABEL: extractelt_nxv8f16_0: +; ZFMIN: # %bb.0: +; ZFMIN-NEXT: vsetivli zero, 1, e16, m1, ta, ma +; ZFMIN-NEXT: vmv.x.s a0, v8 +; ZFMIN-NEXT: fmv.h.x fa0, a0 +; ZFMIN-NEXT: ret %r = extractelement %v, i32 0 ret half %r } define half @extractelt_nxv8f16_imm( %v) { -; CHECK-LABEL: extractelt_nxv8f16_imm: -; CHECK: # %bb.0: -; CHECK-NEXT: vsetivli zero, 1, e16, m1, ta, ma -; CHECK-NEXT: vslidedown.vi v8, v8, 2 -; CHECK-NEXT: vfmv.f.s fa0, v8 -; CHECK-NEXT: ret +; ZVFH-LABEL: extractelt_nxv8f16_imm: +; ZVFH: # %bb.0: +; ZVFH-NEXT: vsetivli zero, 1, e16, m1, ta, ma +; ZVFH-NEXT: vslidedown.vi v8, v8, 2 +; ZVFH-NEXT: vfmv.f.s fa0, v8 +; ZVFH-NEXT: ret +; +; ZVFHMIN-LABEL: extractelt_nxv8f16_imm: +; ZVFHMIN: # %bb.0: +; ZVFHMIN-NEXT: vsetivli zero, 1, e16, m1, ta, ma +; ZVFHMIN-NEXT: vslidedown.vi v8, v8, 2 +; ZVFHMIN-NEXT: vmv.x.s a0, v8 +; ZVFHMIN-NEXT: lui a1, 1048560 +; ZVFHMIN-NEXT: or a0, a0, a1 +; ZVFHMIN-NEXT: fmv.w.x fa0, a0 +; ZVFHMIN-NEXT: ret +; +; ZFMIN-LABEL: extractelt_nxv8f16_imm: +; ZFMIN: # %bb.0: +; ZFMIN-NEXT: vsetivli zero, 1, e16, m1, ta, ma +; ZFMIN-NEXT: vslidedown.vi v8, v8, 2 +; ZFMIN-NEXT: vmv.x.s a0, v8 +; ZFMIN-NEXT: fmv.h.x fa0, a0 +; ZFMIN-NEXT: ret %r = extractelement %v, i32 2 ret half %r } define half @extractelt_nxv8f16_idx( %v, i32 zeroext %idx) { -; CHECK-LABEL: extractelt_nxv8f16_idx: -; CHECK: # %bb.0: -; CHECK-NEXT: vsetivli zero, 1, e16, m2, ta, ma -; CHECK-NEXT: vslidedown.vx v8, v8, a0 -; CHECK-NEXT: vfmv.f.s fa0, v8 -; CHECK-NEXT: ret +; ZVFH-LABEL: extractelt_nxv8f16_idx: +; ZVFH: # %bb.0: +; ZVFH-NEXT: vsetivli zero, 1, e16, m2, ta, ma +; ZVFH-NEXT: vslidedown.vx v8, v8, a0 +; ZVFH-NEXT: vfmv.f.s fa0, v8 +; ZVFH-NEXT: ret +; +; ZVFHMIN-LABEL: extractelt_nxv8f16_idx: +; ZVFHMIN: # %bb.0: +; ZVFHMIN-NEXT: vsetivli zero, 1, e16, m2, ta, ma +; ZVFHMIN-NEXT: vslidedown.vx v8, v8, a0 +; ZVFHMIN-NEXT: vmv.x.s a0, v8 +; ZVFHMIN-NEXT: lui a1, 1048560 +; ZVFHMIN-NEXT: or a0, a0, a1 +; ZVFHMIN-NEXT: fmv.w.x fa0, a0 +; ZVFHMIN-NEXT: ret +; +; ZFMIN-LABEL: extractelt_nxv8f16_idx: +; ZFMIN: # %bb.0: +; ZFMIN-NEXT: vsetivli zero, 1, e16, m2, ta, ma +; ZFMIN-NEXT: vslidedown.vx v8, v8, a0 +; ZFMIN-NEXT: vmv.x.s a0, v8 +; ZFMIN-NEXT: fmv.h.x fa0, a0 +; ZFMIN-NEXT: ret %r = extractelement %v, i32 %idx ret half %r } define half @extractelt_nxv16f16_0( %v) { -; CHECK-LABEL: extractelt_nxv16f16_0: -; CHECK: # %bb.0: -; CHECK-NEXT: vsetivli zero, 1, e16, m1, ta, ma -; CHECK-NEXT: vfmv.f.s fa0, v8 -; CHECK-NEXT: ret +; ZVFH-LABEL: extractelt_nxv16f16_0: +; ZVFH: # %bb.0: +; ZVFH-NEXT: vsetivli zero, 1, e16, m1, ta, ma +; ZVFH-NEXT: vfmv.f.s fa0, v8 +; ZVFH-NEXT: ret +; +; ZVFHMIN-LABEL: extractelt_nxv16f16_0: +; ZVFHMIN: # %bb.0: +; ZVFHMIN-NEXT: vsetivli zero, 1, e16, m1, ta, ma +; ZVFHMIN-NEXT: vmv.x.s a0, v8 +; ZVFHMIN-NEXT: lui a1, 1048560 +; ZVFHMIN-NEXT: or a0, a0, a1 +; ZVFHMIN-NEXT: fmv.w.x fa0, a0 +; ZVFHMIN-NEXT: ret +; +; ZFMIN-LABEL: extractelt_nxv16f16_0: +; ZFMIN: # %bb.0: +; ZFMIN-NEXT: vsetivli zero, 1, e16, m1, ta, ma +; ZFMIN-NEXT: vmv.x.s a0, v8 +; ZFMIN-NEXT: fmv.h.x fa0, a0 +; ZFMIN-NEXT: ret %r = extractelement %v, i32 0 ret half %r } define half @extractelt_nxv16f16_imm( %v) { -; CHECK-LABEL: extractelt_nxv16f16_imm: -; CHECK: # %bb.0: -; CHECK-NEXT: vsetivli zero, 1, e16, m1, ta, ma -; CHECK-NEXT: vslidedown.vi v8, v8, 2 -; CHECK-NEXT: vfmv.f.s fa0, v8 -; CHECK-NEXT: ret +; ZVFH-LABEL: extractelt_nxv16f16_imm: +; ZVFH: # %bb.0: +; ZVFH-NEXT: vsetivli zero, 1, e16, m1, ta, ma +; ZVFH-NEXT: vslidedown.vi v8, v8, 2 +; ZVFH-NEXT: vfmv.f.s fa0, v8 +; ZVFH-NEXT: ret +; +; ZVFHMIN-LABEL: extractelt_nxv16f16_imm: +; ZVFHMIN: # %bb.0: +; ZVFHMIN-NEXT: vsetivli zero, 1, e16, m1, ta, ma +; ZVFHMIN-NEXT: vslidedown.vi v8, v8, 2 +; ZVFHMIN-NEXT: vmv.x.s a0, v8 +; ZVFHMIN-NEXT: lui a1, 1048560 +; ZVFHMIN-NEXT: or a0, a0, a1 +; ZVFHMIN-NEXT: fmv.w.x fa0, a0 +; ZVFHMIN-NEXT: ret +; +; ZFMIN-LABEL: extractelt_nxv16f16_imm: +; ZFMIN: # %bb.0: +; ZFMIN-NEXT: vsetivli zero, 1, e16, m1, ta, ma +; ZFMIN-NEXT: vslidedown.vi v8, v8, 2 +; ZFMIN-NEXT: vmv.x.s a0, v8 +; ZFMIN-NEXT: fmv.h.x fa0, a0 +; ZFMIN-NEXT: ret %r = extractelement %v, i32 2 ret half %r } define half @extractelt_nxv16f16_idx( %v, i32 zeroext %idx) { -; CHECK-LABEL: extractelt_nxv16f16_idx: -; CHECK: # %bb.0: -; CHECK-NEXT: vsetivli zero, 1, e16, m4, ta, ma -; CHECK-NEXT: vslidedown.vx v8, v8, a0 -; CHECK-NEXT: vfmv.f.s fa0, v8 -; CHECK-NEXT: ret +; ZVFH-LABEL: extractelt_nxv16f16_idx: +; ZVFH: # %bb.0: +; ZVFH-NEXT: vsetivli zero, 1, e16, m4, ta, ma +; ZVFH-NEXT: vslidedown.vx v8, v8, a0 +; ZVFH-NEXT: vfmv.f.s fa0, v8 +; ZVFH-NEXT: ret +; +; ZVFHMIN-LABEL: extractelt_nxv16f16_idx: +; ZVFHMIN: # %bb.0: +; ZVFHMIN-NEXT: vsetivli zero, 1, e16, m4, ta, ma +; ZVFHMIN-NEXT: vslidedown.vx v8, v8, a0 +; ZVFHMIN-NEXT: vmv.x.s a0, v8 +; ZVFHMIN-NEXT: lui a1, 1048560 +; ZVFHMIN-NEXT: or a0, a0, a1 +; ZVFHMIN-NEXT: fmv.w.x fa0, a0 +; ZVFHMIN-NEXT: ret +; +; ZFMIN-LABEL: extractelt_nxv16f16_idx: +; ZFMIN: # %bb.0: +; ZFMIN-NEXT: vsetivli zero, 1, e16, m4, ta, ma +; ZFMIN-NEXT: vslidedown.vx v8, v8, a0 +; ZFMIN-NEXT: vmv.x.s a0, v8 +; ZFMIN-NEXT: fmv.h.x fa0, a0 +; ZFMIN-NEXT: ret %r = extractelement %v, i32 %idx ret half %r } define half @extractelt_nxv32f16_0( %v) { -; CHECK-LABEL: extractelt_nxv32f16_0: -; CHECK: # %bb.0: -; CHECK-NEXT: vsetivli zero, 1, e16, m1, ta, ma -; CHECK-NEXT: vfmv.f.s fa0, v8 -; CHECK-NEXT: ret +; ZVFH-LABEL: extractelt_nxv32f16_0: +; ZVFH: # %bb.0: +; ZVFH-NEXT: vsetivli zero, 1, e16, m1, ta, ma +; ZVFH-NEXT: vfmv.f.s fa0, v8 +; ZVFH-NEXT: ret +; +; ZVFHMIN-LABEL: extractelt_nxv32f16_0: +; ZVFHMIN: # %bb.0: +; ZVFHMIN-NEXT: vsetivli zero, 1, e16, m1, ta, ma +; ZVFHMIN-NEXT: vmv.x.s a0, v8 +; ZVFHMIN-NEXT: lui a1, 1048560 +; ZVFHMIN-NEXT: or a0, a0, a1 +; ZVFHMIN-NEXT: fmv.w.x fa0, a0 +; ZVFHMIN-NEXT: ret +; +; ZFMIN-LABEL: extractelt_nxv32f16_0: +; ZFMIN: # %bb.0: +; ZFMIN-NEXT: vsetivli zero, 1, e16, m1, ta, ma +; ZFMIN-NEXT: vmv.x.s a0, v8 +; ZFMIN-NEXT: fmv.h.x fa0, a0 +; ZFMIN-NEXT: ret %r = extractelement %v, i32 0 ret half %r } define half @extractelt_nxv32f16_imm( %v) { -; CHECK-LABEL: extractelt_nxv32f16_imm: -; CHECK: # %bb.0: -; CHECK-NEXT: vsetivli zero, 1, e16, m1, ta, ma -; CHECK-NEXT: vslidedown.vi v8, v8, 2 -; CHECK-NEXT: vfmv.f.s fa0, v8 -; CHECK-NEXT: ret +; ZVFH-LABEL: extractelt_nxv32f16_imm: +; ZVFH: # %bb.0: +; ZVFH-NEXT: vsetivli zero, 1, e16, m1, ta, ma +; ZVFH-NEXT: vslidedown.vi v8, v8, 2 +; ZVFH-NEXT: vfmv.f.s fa0, v8 +; ZVFH-NEXT: ret +; +; ZVFHMIN-LABEL: extractelt_nxv32f16_imm: +; ZVFHMIN: # %bb.0: +; ZVFHMIN-NEXT: vsetivli zero, 1, e16, m1, ta, ma +; ZVFHMIN-NEXT: vslidedown.vi v8, v8, 2 +; ZVFHMIN-NEXT: vmv.x.s a0, v8 +; ZVFHMIN-NEXT: lui a1, 1048560 +; ZVFHMIN-NEXT: or a0, a0, a1 +; ZVFHMIN-NEXT: fmv.w.x fa0, a0 +; ZVFHMIN-NEXT: ret +; +; ZFMIN-LABEL: extractelt_nxv32f16_imm: +; ZFMIN: # %bb.0: +; ZFMIN-NEXT: vsetivli zero, 1, e16, m1, ta, ma +; ZFMIN-NEXT: vslidedown.vi v8, v8, 2 +; ZFMIN-NEXT: vmv.x.s a0, v8 +; ZFMIN-NEXT: fmv.h.x fa0, a0 +; ZFMIN-NEXT: ret %r = extractelement %v, i32 2 ret half %r } define half @extractelt_nxv32f16_idx( %v, i32 zeroext %idx) { -; CHECK-LABEL: extractelt_nxv32f16_idx: -; CHECK: # %bb.0: -; CHECK-NEXT: vsetivli zero, 1, e16, m8, ta, ma -; CHECK-NEXT: vslidedown.vx v8, v8, a0 -; CHECK-NEXT: vfmv.f.s fa0, v8 -; CHECK-NEXT: ret +; ZVFH-LABEL: extractelt_nxv32f16_idx: +; ZVFH: # %bb.0: +; ZVFH-NEXT: vsetivli zero, 1, e16, m8, ta, ma +; ZVFH-NEXT: vslidedown.vx v8, v8, a0 +; ZVFH-NEXT: vfmv.f.s fa0, v8 +; ZVFH-NEXT: ret +; +; ZVFHMIN-LABEL: extractelt_nxv32f16_idx: +; ZVFHMIN: # %bb.0: +; ZVFHMIN-NEXT: vsetivli zero, 1, e16, m8, ta, ma +; ZVFHMIN-NEXT: vslidedown.vx v8, v8, a0 +; ZVFHMIN-NEXT: vmv.x.s a0, v8 +; ZVFHMIN-NEXT: lui a1, 1048560 +; ZVFHMIN-NEXT: or a0, a0, a1 +; ZVFHMIN-NEXT: fmv.w.x fa0, a0 +; ZVFHMIN-NEXT: ret +; +; ZFMIN-LABEL: extractelt_nxv32f16_idx: +; ZFMIN: # %bb.0: +; ZFMIN-NEXT: vsetivli zero, 1, e16, m8, ta, ma +; ZFMIN-NEXT: vslidedown.vx v8, v8, a0 +; ZFMIN-NEXT: vmv.x.s a0, v8 +; ZFMIN-NEXT: fmv.h.x fa0, a0 +; ZFMIN-NEXT: ret %r = extractelement %v, i32 %idx ret half %r } @@ -636,10 +1334,10 @@ define double @extractelt_nxv16f64_neg1( %v) { ; RV64-NEXT: slli a2, a2, 1 ; RV64-NEXT: addi a2, a2, -1 ; RV64-NEXT: vs8r.v v16, (a3) -; RV64-NEXT: bltu a2, a1, .LBB52_2 +; RV64-NEXT: bltu a2, a1, .LBB70_2 ; RV64-NEXT: # %bb.1: ; RV64-NEXT: mv a2, a1 -; RV64-NEXT: .LBB52_2: +; RV64-NEXT: .LBB70_2: ; RV64-NEXT: slli a2, a2, 3 ; RV64-NEXT: add a0, a0, a2 ; RV64-NEXT: fld fa0, 0(a0) @@ -669,10 +1367,10 @@ define double @extractelt_nxv16f64_idx( %v, i32 zeroext %i ; RV32-NEXT: csrr a1, vlenb ; RV32-NEXT: slli a2, a1, 1 ; RV32-NEXT: addi a2, a2, -1 -; RV32-NEXT: bltu a0, a2, .LBB54_2 +; RV32-NEXT: bltu a0, a2, .LBB72_2 ; RV32-NEXT: # %bb.1: ; RV32-NEXT: mv a0, a2 -; RV32-NEXT: .LBB54_2: +; RV32-NEXT: .LBB72_2: ; RV32-NEXT: addi sp, sp, -80 ; RV32-NEXT: .cfi_def_cfa_offset 80 ; RV32-NEXT: sw ra, 76(sp) # 4-byte Folded Spill @@ -704,10 +1402,10 @@ define double @extractelt_nxv16f64_idx( %v, i32 zeroext %i ; RV64-NEXT: csrr a1, vlenb ; RV64-NEXT: slli a2, a1, 1 ; RV64-NEXT: addi a2, a2, -1 -; RV64-NEXT: bltu a0, a2, .LBB54_2 +; RV64-NEXT: bltu a0, a2, .LBB72_2 ; RV64-NEXT: # %bb.1: ; RV64-NEXT: mv a0, a2 -; RV64-NEXT: .LBB54_2: +; RV64-NEXT: .LBB72_2: ; RV64-NEXT: addi sp, sp, -80 ; RV64-NEXT: .cfi_def_cfa_offset 80 ; RV64-NEXT: sd ra, 72(sp) # 8-byte Folded Spill From 5a6dc614527332254b2b230ff2ff7527ca6d0785 Mon Sep 17 00:00:00 2001 From: Chris B Date: Thu, 26 Sep 2024 19:34:39 -0500 Subject: [PATCH 023/469] Revert "[HLSL] Vector Usual Arithmetic Conversions" (#110191) Reverts llvm/llvm-project#108659 Reverting due to bot breakage. --- .../clang/Basic/DiagnosticSemaKinds.td | 3 - clang/include/clang/Driver/Options.td | 2 +- clang/include/clang/Sema/Sema.h | 3 +- clang/include/clang/Sema/SemaHLSL.h | 5 - clang/lib/Sema/SemaExpr.cpp | 18 +- clang/lib/Sema/SemaHLSL.cpp | 188 --------- .../Language/UsualArithmeticConversions.hlsl | 379 ------------------ 7 files changed, 4 insertions(+), 594 deletions(-) delete mode 100644 clang/test/SemaHLSL/Language/UsualArithmeticConversions.hlsl diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 9e8f152852fd1..f3d5d4c56606c 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -12395,9 +12395,6 @@ def err_hlsl_operator_unsupported : Error< def err_hlsl_param_qualifier_mismatch : Error<"conflicting parameter qualifier %0 on parameter %1">; -def err_hlsl_vector_compound_assignment_truncation : Error< - "left hand operand of type %0 to compound assignment cannot be truncated " - "when used with right hand operand of type %1">; def warn_hlsl_impcast_vector_truncation : Warning< "implicit conversion truncates vector: %0 to %1">, InGroup; diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index 1dc2ff18170ab..932cf13edab53 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -2978,7 +2978,7 @@ def flax_vector_conversions_EQ : Joined<["-"], "flax-vector-conversions=">, Grou "LangOptions::LaxVectorConversionKind::Integer", "LangOptions::LaxVectorConversionKind::All"]>, MarshallingInfoEnum, - !strconcat("(", open_cl.KeyPath, " || ", hlsl.KeyPath, ")") # + open_cl.KeyPath # " ? LangOptions::LaxVectorConversionKind::None" # " : LangOptions::LaxVectorConversionKind::All">; def flax_vector_conversions : Flag<["-"], "flax-vector-conversions">, Group, diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index a9ce3681338d4..e1c3a99cfa167 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -7423,8 +7423,7 @@ class Sema final : public SemaBase { SourceLocation Loc, BinaryOperatorKind Opc); QualType CheckVectorLogicalOperands(ExprResult &LHS, ExprResult &RHS, - SourceLocation Loc, - BinaryOperatorKind Opc); + SourceLocation Loc); /// Context in which we're performing a usual arithmetic conversion. enum ArithConvKind { diff --git a/clang/include/clang/Sema/SemaHLSL.h b/clang/include/clang/Sema/SemaHLSL.h index fa957abc9791a..311cd58bbcac2 100644 --- a/clang/include/clang/Sema/SemaHLSL.h +++ b/clang/include/clang/Sema/SemaHLSL.h @@ -63,11 +63,6 @@ class SemaHLSL : public SemaBase { std::initializer_list AllowedStages); void DiagnoseAvailabilityViolations(TranslationUnitDecl *TU); - QualType handleVectorBinOpConversion(ExprResult &LHS, ExprResult &RHS, - QualType LHSType, QualType RHSType, - bool IsCompAssign); - void emitLogicalOperatorFixIt(Expr *LHS, Expr *RHS, BinaryOperatorKind Opc); - void handleNumThreadsAttr(Decl *D, const ParsedAttr &AL); void handleWaveSizeAttr(Decl *D, const ParsedAttr &AL); void handleSV_DispatchThreadIDAttr(Decl *D, const ParsedAttr &AL); diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index e072fb65b8132..66df9c969256a 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -10133,10 +10133,6 @@ QualType Sema::CheckVectorOperands(ExprResult &LHS, ExprResult &RHS, const VectorType *RHSVecType = RHSType->getAs(); assert(LHSVecType || RHSVecType); - if (getLangOpts().HLSL) - return HLSL().handleVectorBinOpConversion(LHS, RHS, LHSType, RHSType, - IsCompAssign); - // AltiVec-style "vector bool op vector bool" combinations are allowed // for some operators but not others. if (!AllowBothBool && LHSVecType && @@ -12867,8 +12863,7 @@ static void diagnoseXorMisusedAsPow(Sema &S, const ExprResult &XorLHS, } QualType Sema::CheckVectorLogicalOperands(ExprResult &LHS, ExprResult &RHS, - SourceLocation Loc, - BinaryOperatorKind Opc) { + SourceLocation Loc) { // Ensure that either both operands are of the same vector type, or // one operand is of a vector type and the other is of its element type. QualType vType = CheckVectorOperands(LHS, RHS, Loc, false, @@ -12888,15 +12883,6 @@ QualType Sema::CheckVectorLogicalOperands(ExprResult &LHS, ExprResult &RHS, if (!getLangOpts().CPlusPlus && !(isa(vType->getAs()))) return InvalidLogicalVectorOperands(Loc, LHS, RHS); - // Beginning with HLSL 2021, HLSL disallows logical operators on vector - // operands and instead requires the use of the `and`, `or`, `any`, `all`, and - // `select` functions. - if (getLangOpts().HLSL && - getLangOpts().getHLSLVersion() >= LangOptionsBase::HLSL_2021) { - (void)InvalidOperands(Loc, LHS, RHS); - HLSL().emitLogicalOperatorFixIt(LHS.get(), RHS.get(), Opc); - return QualType(); - } return GetSignedVectorType(LHS.get()->getType()); } @@ -13068,7 +13054,7 @@ inline QualType Sema::CheckLogicalOperands(ExprResult &LHS, ExprResult &RHS, // Check vector operands differently. if (LHS.get()->getType()->isVectorType() || RHS.get()->getType()->isVectorType()) - return CheckVectorLogicalOperands(LHS, RHS, Loc, Opc); + return CheckVectorLogicalOperands(LHS, RHS, Loc); bool EnumConstantInBoolContext = false; for (const ExprResult &HS : {LHS, RHS}) { diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp index f17b606a8f262..1d8ccdda45573 100644 --- a/clang/lib/Sema/SemaHLSL.cpp +++ b/clang/lib/Sema/SemaHLSL.cpp @@ -401,194 +401,6 @@ void SemaHLSL::DiagnoseAttrStageMismatch( << (AllowedStages.size() != 1) << join(StageStrings, ", "); } -template -static void castVector(Sema &S, ExprResult &E, QualType &Ty, unsigned Sz) { - if (const auto *VTy = Ty->getAs()) - Ty = VTy->getElementType(); - Ty = S.getASTContext().getExtVectorType(Ty, Sz); - E = S.ImpCastExprToType(E.get(), Ty, Kind); -} - -template -static QualType castElement(Sema &S, ExprResult &E, QualType Ty) { - E = S.ImpCastExprToType(E.get(), Ty, Kind); - return Ty; -} - -static QualType handleFloatVectorBinOpConversion( - Sema &SemaRef, ExprResult &LHS, ExprResult &RHS, QualType LHSType, - QualType RHSType, QualType LElTy, QualType RElTy, bool IsCompAssign) { - bool LHSFloat = LElTy->isRealFloatingType(); - bool RHSFloat = RElTy->isRealFloatingType(); - - if (LHSFloat && RHSFloat) { - if (IsCompAssign || - SemaRef.getASTContext().getFloatingTypeOrder(LElTy, RElTy) > 0) - return castElement(SemaRef, RHS, LHSType); - - return castElement(SemaRef, LHS, RHSType); - } - - if (LHSFloat) - return castElement(SemaRef, RHS, LHSType); - - assert(RHSFloat); - if (IsCompAssign) - return castElement(SemaRef, RHS, LHSType); - - return castElement(SemaRef, LHS, RHSType); -} - -static QualType handleIntegerVectorBinOpConversion( - Sema &SemaRef, ExprResult &LHS, ExprResult &RHS, QualType LHSType, - QualType RHSType, QualType LElTy, QualType RElTy, bool IsCompAssign) { - - int IntOrder = SemaRef.Context.getIntegerTypeOrder(LElTy, RElTy); - bool LHSSigned = LElTy->hasSignedIntegerRepresentation(); - bool RHSSigned = RElTy->hasSignedIntegerRepresentation(); - auto &Ctx = SemaRef.getASTContext(); - - // If both types have the same signedness, use the higher ranked type. - if (LHSSigned == RHSSigned) { - if (IsCompAssign || IntOrder >= 0) - return castElement(SemaRef, RHS, LHSType); - - return castElement(SemaRef, LHS, RHSType); - } - - // If the unsigned type has greater than or equal rank of the signed type, use - // the unsigned type. - if (IntOrder != (LHSSigned ? 1 : -1)) { - if (IsCompAssign || RHSSigned) - return castElement(SemaRef, RHS, LHSType); - return castElement(SemaRef, LHS, RHSType); - } - - // At this point the signed type has higher rank than the unsigned type, which - // means it will be the same size or bigger. If the signed type is bigger, it - // can represent all the values of the unsigned type, so select it. - if (Ctx.getIntWidth(LElTy) != Ctx.getIntWidth(RElTy)) { - if (IsCompAssign || LHSSigned) - return castElement(SemaRef, RHS, LHSType); - return castElement(SemaRef, LHS, RHSType); - } - - // This is a bit of an odd duck case in HLSL. It shouldn't happen, but can due - // to C/C++ leaking through. The place this happens today is long vs long - // long. When arguments are vector and vector, - // the long long has higher rank than long even though they are the same size. - - // If this is a compound assignment cast the right hand side to the left hand - // side's type. - if (IsCompAssign) - return castElement(SemaRef, RHS, LHSType); - - // If this isn't a compound assignment we convert to unsigned long long. - QualType ElTy = Ctx.getCorrespondingUnsignedType(LHSSigned ? LElTy : RElTy); - QualType NewTy = Ctx.getExtVectorType( - ElTy, RHSType->castAs()->getNumElements()); - (void)castElement(SemaRef, RHS, NewTy); - - return castElement(SemaRef, LHS, NewTy); -} - -static CastKind getScalarCastKind(ASTContext &Ctx, QualType DestTy, - QualType SrcTy) { - if (DestTy->isRealFloatingType() && SrcTy->isRealFloatingType()) - return CK_FloatingCast; - if (DestTy->isIntegralType(Ctx) && SrcTy->isIntegralType(Ctx)) - return CK_IntegralCast; - if (DestTy->isRealFloatingType()) - return CK_IntegralToFloating; - assert(SrcTy->isRealFloatingType() && DestTy->isIntegralType(Ctx)); - return CK_FloatingToIntegral; -} - -QualType SemaHLSL::handleVectorBinOpConversion(ExprResult &LHS, ExprResult &RHS, - QualType LHSType, - QualType RHSType, - bool IsCompAssign) { - const auto *LVecTy = LHSType->getAs(); - const auto *RVecTy = RHSType->getAs(); - auto &Ctx = getASTContext(); - - // If the LHS is not a vector and this is a compound assignment, we truncate - // the argument to a scalar then convert it to the LHS's type. - if (!LVecTy && IsCompAssign) { - QualType RElTy = RHSType->castAs()->getElementType(); - RHS = SemaRef.ImpCastExprToType(RHS.get(), RElTy, CK_HLSLVectorTruncation); - RHSType = RHS.get()->getType(); - if (Ctx.hasSameUnqualifiedType(LHSType, RHSType)) - return LHSType; - RHS = SemaRef.ImpCastExprToType(RHS.get(), LHSType, - getScalarCastKind(Ctx, LHSType, RHSType)); - return LHSType; - } - - unsigned EndSz = std::numeric_limits::max(); - unsigned LSz = 0; - if (LVecTy) - LSz = EndSz = LVecTy->getNumElements(); - if (RVecTy) - EndSz = std::min(RVecTy->getNumElements(), EndSz); - assert(EndSz != std::numeric_limits::max() && - "one of the above should have had a value"); - - // In a compound assignment, the left operand does not change type, the right - // operand is converted to the type of the left operand. - if (IsCompAssign && LSz != EndSz) { - Diag(LHS.get()->getBeginLoc(), - diag::err_hlsl_vector_compound_assignment_truncation) - << LHSType << RHSType; - return QualType(); - } - - if (RVecTy && RVecTy->getNumElements() > EndSz) - castVector(SemaRef, RHS, RHSType, EndSz); - if (!IsCompAssign && LVecTy && LVecTy->getNumElements() > EndSz) - castVector(SemaRef, LHS, LHSType, EndSz); - - if (!RVecTy) - castVector(SemaRef, RHS, RHSType, EndSz); - if (!IsCompAssign && !LVecTy) - castVector(SemaRef, LHS, LHSType, EndSz); - - // If we're at the same type after resizing we can stop here. - if (Ctx.hasSameUnqualifiedType(LHSType, RHSType)) - return Ctx.getCommonSugaredType(LHSType, RHSType); - - QualType LElTy = LHSType->castAs()->getElementType(); - QualType RElTy = RHSType->castAs()->getElementType(); - - // Handle conversion for floating point vectors. - if (LElTy->isRealFloatingType() || RElTy->isRealFloatingType()) - return handleFloatVectorBinOpConversion(SemaRef, LHS, RHS, LHSType, RHSType, - LElTy, RElTy, IsCompAssign); - - assert(LElTy->isIntegralType(Ctx) && RElTy->isIntegralType(Ctx) && - "HLSL Vectors can only contain integer or floating point types"); - return handleIntegerVectorBinOpConversion(SemaRef, LHS, RHS, LHSType, RHSType, - LElTy, RElTy, IsCompAssign); -} - -void SemaHLSL::emitLogicalOperatorFixIt(Expr *LHS, Expr *RHS, - BinaryOperatorKind Opc) { - assert((Opc == BO_LOr || Opc == BO_LAnd) && - "Called with non-logical operator"); - llvm::SmallVector Buff; - llvm::raw_svector_ostream OS(Buff); - PrintingPolicy PP(SemaRef.getLangOpts()); - StringRef NewFnName = Opc == BO_LOr ? "or" : "and"; - OS << NewFnName << "("; - LHS->printPretty(OS, nullptr, PP); - OS << ", "; - RHS->printPretty(OS, nullptr, PP); - OS << ")"; - SourceRange FullRange = SourceRange(LHS->getBeginLoc(), RHS->getEndLoc()); - SemaRef.Diag(LHS->getBeginLoc(), diag::note_function_suggestion) - << NewFnName << FixItHint::CreateReplacement(FullRange, OS.str()); -} - void SemaHLSL::handleNumThreadsAttr(Decl *D, const ParsedAttr &AL) { llvm::VersionTuple SMVersion = getASTContext().getTargetInfo().getTriple().getOSVersion(); diff --git a/clang/test/SemaHLSL/Language/UsualArithmeticConversions.hlsl b/clang/test/SemaHLSL/Language/UsualArithmeticConversions.hlsl deleted file mode 100644 index 6138169e299fd..0000000000000 --- a/clang/test/SemaHLSL/Language/UsualArithmeticConversions.hlsl +++ /dev/null @@ -1,379 +0,0 @@ -// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -finclude-default-header -fnative-half-type %s -DERRORS -Wconversion -Wdouble-promotion -verify -// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -std=hlsl2018 -finclude-default-header -fnative-half-type %s -DERRORS -Wconversion -Wdouble-promotion -verify -// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -finclude-default-header -fnative-half-type %s -ast-dump | FileCheck %s - -//----------------------------------------------------------------------------// -// Case 1: float4 * int4 and inverse. -// -// In both cases here the int is converted to a float and the computation -// produces a float value. -//----------------------------------------------------------------------------// - -// CHECK-LABEL: FunctionDecl {{.*}} used f4f4i4 'float4 (float4, int4)' -// CHECK: BinaryOperator {{.*}} 'float4':'vector' '*' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float4':'vector' -// CHECK-NEXT: DeclRefExpr {{.*}} 'float4':'vector' lvalue ParmVar {{.*}} 'A' 'float4':'vector' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float4':'vector' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int4':'vector' -// CHECK-NEXT: DeclRefExpr {{.*}} 'int4':'vector' lvalue ParmVar {{.*}} 'B' 'int4':'vector' -export float4 f4f4i4(float4 A, int4 B) { - return A * B; // expected-warning{{implicit conversion from 'int4' (aka 'vector') to 'float4' (aka 'vector') may lose precision}} -} - -// CHECK-LABEL: FunctionDecl {{.*}} used f4i4f4 'float4 (float4, int4)' -// CHECK: BinaryOperator {{.*}} 'float4':'vector' '*' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float4':'vector' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int4':'vector' -// CHECK-NEXT: DeclRefExpr {{.*}} 'int4':'vector' lvalue ParmVar {{.*}} 'B' 'int4':'vector' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float4':'vector' -// CHECK-NEXT: DeclRefExpr {{.*}} 'float4':'vector' lvalue ParmVar {{.*}} 'A' 'float4':'vector' -export float4 f4i4f4(float4 A, int4 B) { - return B * A; // expected-warning{{implicit conversion from 'int4' (aka 'vector') to 'float4' (aka 'vector') may lose precision}} -} - -//----------------------------------------------------------------------------// -// Case 2: float4 * int2 and inverse. -// -// In both cases the float vector is trunctated to a float2 and the integer -// vector is converted to a float2. -//----------------------------------------------------------------------------// - -// CHECK-LABEL: FunctionDecl {{.*}} used f2f4i2 'float2 (float4, int2)' -// CHECK: BinaryOperator {{.*}} 'vector' '*' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector' -// CHECK-NEXT: ImplicitCastExpr {{.*}}'float4':'vector' -// CHECK-NEXT: DeclRefExpr {{.*}} 'float4':'vector' lvalue ParmVar {{.*}} 'A' 'float4':'vector' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int2':'vector' -// CHECK-NEXT: DeclRefExpr {{.*}} 'int2':'vector' lvalue ParmVar {{.*}} 'B' 'int2':'vector' -export float2 f2f4i2(float4 A, int2 B) { - // expected-warning@#f2f4i2 {{implicit conversion from 'int2' (aka 'vector') to 'vector' (vector of 2 'float' values) may lose precision}} - // expected-warning@#f2f4i2 {{implicit conversion truncates vector: 'float4' (aka 'vector') to 'vector' (vector of 2 'float' values)}} - return A * B; // #f2f4i2 -} - -// CHECK-LABEL: FunctionDecl {{.*}} used f2i2f4 'float2 (float4, int2)' -// CHECK: BinaryOperator {{.*}} 'vector' '*' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int2':'vector' -// CHECK-NEXT: DeclRefExpr {{.*}} 'int2':'vector' lvalue ParmVar {{.*}} 'B' 'int2':'vector' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector' -// CHECK-NEXT: ImplicitCastExpr {{.*}}'float4':'vector' -// CHECK-NEXT: DeclRefExpr {{.*}} 'float4':'vector' lvalue ParmVar {{.*}} 'A' 'float4':'vector' -export float2 f2i2f4(float4 A, int2 B) { - // expected-warning@#f2i2f4 {{implicit conversion from 'int2' (aka 'vector') to 'vector' (vector of 2 'float' values) may lose precision}} - // expected-warning@#f2i2f4 {{implicit conversion truncates vector: 'float4' (aka 'vector') to 'vector' (vector of 2 'float' values)}} - return B * A; // #f2i2f4 -} - -//----------------------------------------------------------------------------// -// Case 3: Integers of mismatched sign, equivalent size, but the unsigned type -// has lower conversion rank. -// -// This is the odd-ball case for HLSL that isn't really in spec, but we should -// handle gracefully. The lower-ranked unsigned type is converted to the -// equivalent unsigned type of higher rank, and the signed type is also -// converted to that unsigned type (meaning `unsigned long` becomes `unsinged -// long long`, and `long long` becomes `unsigned long long`). -//----------------------------------------------------------------------------// - -// CHECK-LABEL: FunctionDecl {{.*}} used wierdo 'int4 (vector, vector)' -// CHECK: BinaryOperator {{.*}} 'vector' '*' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector' -// CHECK-NEXT: DeclRefExpr{{.*}} 'vector' lvalue ParmVar {{.*}} 'A' 'vector' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector' -// CHECK-NEXT: ImplicitCastExpr{{.*}}> 'vector' -// CHECK-NEXT: DeclRefExpr {{.*}}'vector' lvalue ParmVar {{.*}} 'B' 'vector' -export int4 wierdo(vector A, vector B) { - // expected-warning@#wierdo {{implicit conversion loses integer precision: 'vector' (vector of 4 'unsigned long long' values) to 'vector' (vector of 4 'int' values)}} - // expected-warning@#wierdo {{implicit conversion changes signedness: 'vector' (vector of 4 'long long' values) to 'vector' (vector of 4 'unsigned long long' values)}} - return A * B; // #wierdo -} - -//----------------------------------------------------------------------------// -// Case 4: Compound assignment of float4 with an int4. -// -// In compound assignment the RHS is converted to match the LHS. -//----------------------------------------------------------------------------// - -// CHECK-LABEL: FunctionDecl {{.*}} used f4f4i4compound 'float4 (float4, int4)' -// CHECK: CompoundAssignOperator {{.*}} 'float4':'vector' lvalue '+=' ComputeLHSTy='float4':'vector' ComputeResultTy='float4':'vector' -// CHECK-NEXT: DeclRefExpr {{.*}} 'float4':'vector' lvalue ParmVar {{.*}} 'A' 'float4':'vector' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float4':'vector' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int4':'vector' -// CHECK-NEXT: DeclRefExpr {{.*}} 'int4':'vector' lvalue ParmVar {{.*}} 'B' 'int4':'vector' -export float4 f4f4i4compound(float4 A, int4 B) { - A += B; // expected-warning{{implicit conversion from 'int4' (aka 'vector') to 'float4' (aka 'vector') may lose precision}} - return A; -} - - -//----------------------------------------------------------------------------// -// Case 5: Compound assignment of float2 with an int4. -// -// In compound assignment the RHS is converted to match the LHS. -//----------------------------------------------------------------------------// - -// CHECK-LABEL: FunctionDecl {{.*}} used f4f2i4compound 'float4 (float2, int4)' -// CHECK: CompoundAssignOperator {{.*}} 'float2':'vector' lvalue '+=' ComputeLHSTy='float2':'vector' ComputeResultTy='float2':'vector' -// CHECK-NEXT: DeclRefExpr {{.*}} 'float2':'vector' lvalue ParmVar {{.*}} 'A' 'float2':'vector' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float2':'vector' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int4':'vector' -// CHECK-NEXT: DeclRefExpr {{.*}} 'int4':'vector' lvalue ParmVar {{.*}} 'B' 'int4':'vector' -export float4 f4f2i4compound(float2 A, int4 B) { - // expected-warning@#f4f2i4compound{{implicit conversion truncates vector: 'int4' (aka 'vector') to 'float2' (aka 'vector')}} - // expected-warning@#f4f2i4compound{{implicit conversion from 'int4' (aka 'vector') to 'float2' (aka 'vector') may lose precision}} - A += B; // #f4f2i4compound - return A.xyxy; -} - -//----------------------------------------------------------------------------// -// Case 6: float2 * int4 -// -// The int4 vector is trunctated to int2 then converted to float2. -//----------------------------------------------------------------------------// - -// CHECK-LABEL: FunctionDecl {{.*}} used f4f2i4 'float2 (float2, int4)' -// CHECK: BinaryOperator {{.*}} 'float2':'vector' '*' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float2':'vector' -// CHECK-NEXT: DeclRefExpr {{.*}} 'float2':'vector' lvalue ParmVar {{.*}} 'A' 'float2':'vector' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float2':'vector' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int4':'vector' -// CHECK-NEXT: DeclRefExpr {{.*}} 'int4':'vector' lvalue ParmVar {{.*}} 'B' 'int4':'vector' -export float2 f4f2i4(float2 A, int4 B) { - // expected-warning@#f4f2i4{{implicit conversion truncates vector: 'int4' (aka 'vector') to 'float2' (aka 'vector')}} - // expected-warning@#f4f2i4{{implicit conversion from 'int4' (aka 'vector') to 'float2' (aka 'vector') may lose precision}} - return A * B; // #f4f2i4 -} - -//----------------------------------------------------------------------------// -// Case 7: Compound assignment of half4 with float4, and inverse. -// -// In compound assignment the RHS is converted to match the LHS. -//----------------------------------------------------------------------------// - -// CHECK-LABEL: FunctionDecl {{.*}} used f4h4f4compound 'float4 (half4, float4)' -// CHECK: CompoundAssignOperator {{.*}} 'half4':'vector' lvalue '+=' ComputeLHSTy='half4':'vector' ComputeResultTy='half4':'vector' -// CHECK-NEXT: DeclRefExpr {{.*}} 'half4':'vector' lvalue ParmVar {{.*}} 'A' 'half4':'vector' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'half4':'vector' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float4':'vector' -// CHECK-NEXT: DeclRefExpr {{.*}} 'float4':'vector' lvalue ParmVar {{.*}} 'B' 'float4':'vector' -export float4 f4h4f4compound(half4 A, float4 B) { - A += B; // expected-warning{{implicit conversion loses floating-point precision: 'float4' (aka 'vector') to 'half4' (aka 'vector')}} - return B; -} - -// CHECK-LABEL: FunctionDecl {{.*}} used f4f4h4compound 'float4 (float4, half4)' -// CHECK: CompoundAssignOperator {{.*}} 'float4':'vector' lvalue '+=' ComputeLHSTy='float4':'vector' ComputeResultTy='float4':'vector' -// CHECK-NEXT: DeclRefExpr {{.*}} 'float4':'vector' lvalue ParmVar {{.*}} 'A' 'float4':'vector' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float4':'vector' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'half4':'vector' -// CHECK-NEXT: DeclRefExpr {{.*}} 'half4':'vector' lvalue ParmVar {{.*}} 'B' 'half4':'vector' -export float4 f4f4h4compound(float4 A, half4 B) { - A += B; // expected-warning{{implicit conversion increases floating-point precision: 'half4' (aka 'vector') to 'float4' (aka 'vector')}} - return A; -} - -//----------------------------------------------------------------------------// -// Case 8: int64_t4 * uint4 -// -// The unsigned argument is promoted to the higher ranked signed type since it -// can express all values of the unsgined argument. -//----------------------------------------------------------------------------// - -// CHECK-LABEL: FunctionDecl {{.*}} used l4l4i4 'int64_t4 (int64_t4, uint4)' -// CHECK: BinaryOperator {{.*}} 'int64_t4':'vector' '*' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int64_t4':'vector' -// CHECK-NEXT: DeclRefExpr {{.*}} 'int64_t4':'vector' lvalue ParmVar {{.*}} 'A' 'int64_t4':'vector' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int64_t4':'vector' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'uint4':'vector' -// CHECK-NEXT: DeclRefExpr {{.*}} 'uint4':'vector' lvalue ParmVar {{.*}} 'B' 'uint4':'vector' -export int64_t4 l4l4i4(int64_t4 A, uint4 B) { - return A * B; -} - -//----------------------------------------------------------------------------// -// Case 9: Compound assignment of int4 from int64_t4 -// -// In compound assignment the RHS is converted to match the LHS. -//----------------------------------------------------------------------------// - -// CHECK-LABEL: FunctionDecl {{.*}} used i4i4l4compound 'int4 (int4, int64_t4)' -// CHECK: CompoundAssignOperator {{.*}} 'int4':'vector' lvalue '+=' ComputeLHSTy='int4':'vector' ComputeResultTy='int4':'vector' -// CHECK-NEXT: DeclRefExpr {{.*}} 'int4':'vector' lvalue ParmVar {{.*}} 'A' 'int4':'vector' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int4':'vector' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int64_t4':'vector' -// CHECK-NEXT: DeclRefExpr {{.*}} 'int64_t4':'vector' lvalue ParmVar {{.*}} 'B' 'int64_t4':'vector' -export int4 i4i4l4compound(int4 A, int64_t4 B) { - A += B; // expected-warning{{implicit conversion loses integer precision: 'int64_t4' (aka 'vector') to 'int4' (aka 'vector')}} - return A; -} - -//----------------------------------------------------------------------------// -// Case 10: Compound assignment of vector with argument of -// vector -// -// In compound assignment the RHS is converted to match the LHS. This one is -// also the weird case because it is out of spec, but we should handle it -// gracefully. -//----------------------------------------------------------------------------// - -// CHECK-LABEL: FunctionDecl {{.*}} used wierdocompound 'vector (vector, vector)' -// CHECK: CompoundAssignOperator {{.*}} 'vector' lvalue '+=' ComputeLHSTy='vector' ComputeResultTy='vector' -// CHECK-NEXT: DeclRefExpr {{.*}} 'vector' lvalue ParmVar {{.*}} 'A' 'vector' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector' -// CHECK-NEXT: DeclRefExpr {{.*}} 'vector' lvalue ParmVar {{.*}} 'B' 'vector' -export vector wierdocompound(vector A, vector B) { - // expected-warning@#wierdocompound{{implicit conversion changes signedness: 'vector' (vector of 4 'long long' values) to 'vector' (vector of 4 'unsigned long' values)}} - A += B; // #wierdocompound - return A; -} - -//----------------------------------------------------------------------------// -// Case 11: Compound assignment of scalar with vector argument. -// -// Because the LHS of a compound assignment cannot change type, the RHS must be -// implicitly convertable to the LHS type. -//----------------------------------------------------------------------------// - -// CHECK-LABEL: FunctionDecl {{.*}} used ffi2compound 'float (float, int2)' -// CHECK: CompoundAssignOperator {{.*}} 'float' lvalue '+=' ComputeLHSTy='float' ComputeResultTy='float' -// CHECK-NEXT: DeclRefExpr {{.*}} 'float' lvalue ParmVar {{.*}} 'A' 'float' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int2':'vector' -// CHECK-NEXT: DeclRefExpr {{.*}} 'int2':'vector' lvalue ParmVar {{.*}} 'B' 'int2':'vector' -export float ffi2compound(float A, int2 B) { - A += B; // expected-warning {{implicit conversion turns vector to scalar: 'int2' (aka 'vector') to 'float'}} - return A; -} - -// CHECK-LABEL: FunctionDecl {{.*}} used iif2compound 'int (int, float2)' -// CHECK: CompoundAssignOperator {{.*}} 'int' lvalue '+=' ComputeLHSTy='int' ComputeResultTy='int' -// CHECK-NEXT: DeclRefExpr {{.*}} 'int' lvalue ParmVar {{.*}} 'A' 'int' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' -// CHECK-NEXT: mplicitCastExpr {{.*}} 'float' -// CHECK-NEXT: ImplicitCastExpr{{.*}} 'float2':'vector' -// CHECK-NEXT: DeclRefExpr {{.*}} 'float2':'vector' lvalue ParmVar {{.*}} 'B' 'float2':'vector' -export int iif2compound(int A, float2 B) { - A += B; // expected-warning{{implicit conversion turns vector to scalar: 'float2' (aka 'vector') to 'int'}} - return A; -} - - -//----------------------------------------------------------------------------// -// Case 12: Compound assignment of vector of larger size than the argument. -// -// Because the LHS of a compound assignment cannot change type, the RHS must be -// implicitly convertable to the LHS type. This fails since the RHS type can't -// be vector-extended implicitly. -//----------------------------------------------------------------------------// - -#ifdef ERRORS -// The only cases that are really illegal here are when the RHS is a vector that -// is larger than the LHS or when the LHS is a scalar. - -export float2 f2f4i2compound(float4 A, int2 B) { - A += B; // expected-error{{left hand operand of type 'float4' (aka 'vector') to compound assignment cannot be truncated when used with right hand operand of type 'int2' (aka 'vector')}} - return A.xy; -} - -#endif - -//----------------------------------------------------------------------------// -// Case 13: Comparison operators for mismatched arguments follow the same rules. -// -// Compare operators convert each argument following the usual arithmetic -// conversions. -//----------------------------------------------------------------------------// - -// Note: these cases work and generate correct code, but the way they get there -// may change with https://github.com/llvm/llvm-project/issues/91639, because -// representing boolean vectors as 32-bit integer vectors will allow more -// efficient code generation. - -// CHECK-LABEL: FunctionDecl {{.*}} used b4f4i4Compare 'bool4 (float4, int4)' -// CHECK: ImplicitCastExpr {{.*}} 'vector' -// CHECK-NEXT: BinaryOperator {{.*}} 'vector' '<' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float4':'vector' -// CHECK-NEXT: DeclRefExpr {{.*}} 'float4':'vector' lvalue ParmVar {{.*}} 'A' 'float4':'vector' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float4':'vector' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int4':'vector' -// CHECK-NEXT: DeclRefExpr {{.*}} 'int4':'vector' lvalue ParmVar {{.*}} 'B' 'int4':'vector' -export bool4 b4f4i4Compare(float4 A, int4 B) { - return A < B; // expected-warning{{implicit conversion from 'int4' (aka 'vector') to 'float4' (aka 'vector') may lose precision}} -} - - -// CHECK-LABEL: FunctionDecl {{.*}} used b2f2i4Compare 'bool2 (float2, int4)' -// CHECK: ImplicitCastExpr {{.*}} 'vector' -// CHECK-NEXT: BinaryOperator {{.*}} 'vector' '<=' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float2':'vector' -// CHECK-NEXT: DeclRefExpr {{.*}} 'float2':'vector' lvalue ParmVar {{.*}} 'A' 'float2':'vector' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float2':'vector' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int4':'vector' -// CHECK-NEXT: DeclRefExpr {{.*}} 'int4':'vector' lvalue ParmVar {{.*}} 'B' 'int4':'vector' - -export bool2 b2f2i4Compare(float2 A, int4 B) { - // expected-warning@#b2f2i4Compare{{implicit conversion truncates vector: 'int4' (aka 'vector') to 'float2' (aka 'vector')}} - // expected-warning@#b2f2i4Compare{{implicit conversion from 'int4' (aka 'vector') to 'float2' (aka 'vector') may lose precision}} - return A <= B; // #b2f2i4Compare -} - -// CHECK-LABEL: FunctionDecl {{.*}} used b4fi4Compare 'bool4 (float, int4)' -// CHECK: ImplicitCastExpr {{.*}} 'vector' -// CHECK-NEXT: BinaryOperator {{.*}} 'vector' '>' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' -// CHECK-NEXT: DeclRefExpr {{.*}} 'float' lvalue ParmVar {{.*}} 'A' 'float' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int4':'vector' -// CHECK-NEXT: DeclRefExpr {{.*}} 'int4':'vector' lvalue ParmVar {{.*}} 'B' 'int4':'vector' -export bool4 b4fi4Compare(float A, int4 B) { - return A > B; // expected-warning{{implicit conversion from 'int4' (aka 'vector') to 'vector' (vector of 4 'float' values) may lose precision}} -} - -//----------------------------------------------------------------------------// -// Case 14: Logical operators on vectors are disallowed in HLSL 2021+ -//----------------------------------------------------------------------------// - -#ifdef ERRORS - -#if __HLSL_VERSION >= 2021 -// expected-error@#b4f4i4Logical{{invalid operands to binary expression ('float4' (aka 'vector') and 'int4' (aka 'vector'))}} -// expected-note@#b4f4i4Logical{{did you mean or?}} -#else -// expected-warning@#b4f4i4Logical{{implicit conversion from 'int4' (aka 'vector') to 'float4' (aka 'vector') may lose precision}} -#endif - -export bool4 b4f4i4Logical(float4 A, int4 B) { - return A || B; // #b4f4i4Logical -} - -#if __HLSL_VERSION >= 2021 -// expected-error@#b2f2i4Logical{{invalid operands to binary expression ('float2' (aka 'vector') and 'int4' (aka 'vector'))}} -// expected-note@#b2f2i4Logical{{did you mean and?}} -#else -// expected-warning@#b2f2i4Logical{{implicit conversion truncates vector: 'int4' (aka 'vector') to 'float2' (aka 'vector')}} -// expected-warning@#b2f2i4Logical{{implicit conversion from 'int4' (aka 'vector') to 'float2' (aka 'vector') may lose precision}} -#endif - -export bool2 b2f2i4Logical(float2 A, int4 B) { - return A && B; // #b2f2i4Logical -} - -#if __HLSL_VERSION >= 2021 -// expected-error@#b2b2b2Logical{{invalid operands to binary expression ('bool2' (aka 'vector') and 'bool2')}} -// expected-note@#b2b2b2Logical{{did you mean and?}} -#endif - -export bool2 b2b2b2Logical(bool2 A, bool2 B) { - return A && B; // #b2b2b2Logical -} - -#endif From 3c66a51054d7ec1fe42d72917624e7c6d484e498 Mon Sep 17 00:00:00 2001 From: vporpo Date: Thu, 26 Sep 2024 17:47:25 -0700 Subject: [PATCH 024/469] [SandboxVec][Interval] Convert InstrInterval class to a class template (#110021) This patch converts InstrInterval class to a class template and renames InstrInterval to Itnerval. This change will allow us to reuse the Interval for dependency graph nodes. --- .../SandboxVectorizer/DependencyGraph.h | 4 +- .../SandboxVectorizer/InstrInterval.h | 124 ----------------- .../Vectorize/SandboxVectorizer/Interval.h | 125 ++++++++++++++++++ .../SandboxVectorizer/DependencyGraph.cpp | 4 +- .../SandboxVectorizer/CMakeLists.txt | 2 +- ...InstrIntervalTest.cpp => IntervalTest.cpp} | 44 +++--- 6 files changed, 152 insertions(+), 151 deletions(-) delete mode 100644 llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/InstrInterval.h create mode 100644 llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/Interval.h rename llvm/unittests/Transforms/Vectorize/SandboxVectorizer/{InstrIntervalTest.cpp => IntervalTest.cpp} (62%) diff --git a/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/DependencyGraph.h b/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/DependencyGraph.h index 0120d9cf51fe9..5437853c366ae 100644 --- a/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/DependencyGraph.h +++ b/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/DependencyGraph.h @@ -25,7 +25,7 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/iterator_range.h" #include "llvm/SandboxIR/SandboxIR.h" -#include "llvm/Transforms/Vectorize/SandboxVectorizer/InstrInterval.h" +#include "llvm/Transforms/Vectorize/SandboxVectorizer/Interval.h" namespace llvm::sandboxir { @@ -85,7 +85,7 @@ class DependencyGraph { } /// Build/extend the dependency graph such that it includes \p Instrs. Returns /// the interval spanning \p Instrs. - InstrInterval extend(ArrayRef Instrs); + Interval extend(ArrayRef Instrs); #ifndef NDEBUG void print(raw_ostream &OS) const; LLVM_DUMP_METHOD void dump() const; diff --git a/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/InstrInterval.h b/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/InstrInterval.h deleted file mode 100644 index 1343f521b29bb..0000000000000 --- a/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/InstrInterval.h +++ /dev/null @@ -1,124 +0,0 @@ -//===- InstrInterval.h ------------------------------------------*- 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 -// -//===----------------------------------------------------------------------===// -// -// The InstrInterval class is an interval of instructions in a block. -// It provides an API for some basic operations on the interval, including some -// simple set operations, like union, interseciton and others. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_TRANSFORMS_VECTORIZE_SANDBOXVECTORIZER_INSTRINTERVAL_H -#define LLVM_TRANSFORMS_VECTORIZE_SANDBOXVECTORIZER_INSTRINTERVAL_H - -#include "llvm/SandboxIR/SandboxIR.h" -#include - -namespace llvm::sandboxir { - -/// A simple iterator for iterating the interval. -template -class InstrIntervalIterator { - sandboxir::Instruction *I; - InstrIntervalType &R; - -public: - using difference_type = std::ptrdiff_t; - using value_type = sandboxir::Instruction; - using pointer = value_type *; - using reference = sandboxir::Instruction &; - using iterator_category = std::bidirectional_iterator_tag; - - InstrIntervalIterator(sandboxir::Instruction *I, InstrIntervalType &R) - : I(I), R(R) {} - bool operator==(const InstrIntervalIterator &Other) const { - assert(&R == &Other.R && "Iterators belong to different regions!"); - return Other.I == I; - } - bool operator!=(const InstrIntervalIterator &Other) const { - return !(*this == Other); - } - InstrIntervalIterator &operator++() { - assert(I != nullptr && "already at end()!"); - I = I->getNextNode(); - return *this; - } - InstrIntervalIterator operator++(int) { - auto ItCopy = *this; - ++*this; - return ItCopy; - } - InstrIntervalIterator &operator--() { - // `I` is nullptr for end() when ToI is the BB terminator. - I = I != nullptr ? I->getPrevNode() : R.ToI; - return *this; - } - InstrIntervalIterator operator--(int) { - auto ItCopy = *this; - --*this; - return ItCopy; - } - template ::value>> - sandboxir::Instruction &operator*() { - return *I; - } - DerefType operator*() const { return *I; } -}; - -class InstrInterval { - Instruction *FromI; - Instruction *ToI; - -public: - InstrInterval() : FromI(nullptr), ToI(nullptr) {} - InstrInterval(Instruction *FromI, Instruction *ToI) : FromI(FromI), ToI(ToI) { - assert((FromI == ToI || FromI->comesBefore(ToI)) && - "FromI should come before TopI!"); - } - InstrInterval(ArrayRef Instrs) { - assert(!Instrs.empty() && "Expected non-empty Instrs!"); - FromI = Instrs[0]; - ToI = Instrs[0]; - for (auto *I : drop_begin(Instrs)) { - if (I->comesBefore(FromI)) - FromI = I; - else if (ToI->comesBefore(I)) - ToI = I; - } - } - bool empty() const { - assert(((FromI == nullptr && ToI == nullptr) || - (FromI != nullptr && ToI != nullptr)) && - "Either none or both should be null"); - return FromI == nullptr; - } - bool contains(Instruction *I) const { - if (empty()) - return false; - return (FromI == I || FromI->comesBefore(I)) && - (I == ToI || I->comesBefore(ToI)); - } - Instruction *top() const { return FromI; } - Instruction *bottom() const { return ToI; } - - using iterator = - InstrIntervalIterator; - using const_iterator = InstrIntervalIterator; - iterator begin() { return iterator(FromI, *this); } - iterator end() { - return iterator(ToI != nullptr ? ToI->getNextNode() : nullptr, *this); - } - const_iterator begin() const { return const_iterator(FromI, *this); } - const_iterator end() const { - return const_iterator(ToI != nullptr ? ToI->getNextNode() : nullptr, *this); - } -}; -} // namespace llvm::sandboxir - -#endif // LLVM_TRANSFORMS_VECTORIZE_SANDBOXVECTORIZER_INSTRINTERVAL_H diff --git a/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/Interval.h b/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/Interval.h new file mode 100644 index 0000000000000..5c40d1eb28c7a --- /dev/null +++ b/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/Interval.h @@ -0,0 +1,125 @@ +//===- Interval.h -----------------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// +// +// The Interval class is a generic interval of ordered objects that implement: +// - T * T::getPrevNode() +// - T * T::getNextNode() +// - bool T::comesBefore(const T *) const +// +// This is currently used for Instruction intervals. +// It provides an API for some basic operations on the interval, including some +// simple set operations, like union, interseciton and others. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TRANSFORMS_VECTORIZE_SANDBOXVECTORIZER_INSTRINTERVAL_H +#define LLVM_TRANSFORMS_VECTORIZE_SANDBOXVECTORIZER_INSTRINTERVAL_H + +#include "llvm/SandboxIR/SandboxIR.h" +#include + +namespace llvm::sandboxir { + +/// A simple iterator for iterating the interval. +template class IntervalIterator { + T *I; + IntervalType &R; + +public: + using difference_type = std::ptrdiff_t; + using value_type = T; + using pointer = value_type *; + using reference = T &; + using iterator_category = std::bidirectional_iterator_tag; + + IntervalIterator(T *I, IntervalType &R) : I(I), R(R) {} + bool operator==(const IntervalIterator &Other) const { + assert(&R == &Other.R && "Iterators belong to different regions!"); + return Other.I == I; + } + bool operator!=(const IntervalIterator &Other) const { + return !(*this == Other); + } + IntervalIterator &operator++() { + assert(I != nullptr && "already at end()!"); + I = I->getNextNode(); + return *this; + } + IntervalIterator operator++(int) { + auto ItCopy = *this; + ++*this; + return ItCopy; + } + IntervalIterator &operator--() { + // `I` is nullptr for end() when To is the BB terminator. + I = I != nullptr ? I->getPrevNode() : R.To; + return *this; + } + IntervalIterator operator--(int) { + auto ItCopy = *this; + --*this; + return ItCopy; + } + template ::value>> + T &operator*() { + return *I; + } + T &operator*() const { return *I; } +}; + +template class Interval { + T *From; + T *To; + +public: + Interval() : From(nullptr), To(nullptr) {} + Interval(T *From, T *To) : From(From), To(To) { + assert((From == To || From->comesBefore(To)) && + "From should come before From!"); + } + Interval(ArrayRef Elems) { + assert(!Elems.empty() && "Expected non-empty Elems!"); + From = Elems[0]; + To = Elems[0]; + for (auto *I : drop_begin(Elems)) { + if (I->comesBefore(From)) + From = I; + else if (To->comesBefore(I)) + To = I; + } + } + bool empty() const { + assert(((From == nullptr && To == nullptr) || + (From != nullptr && To != nullptr)) && + "Either none or both should be null"); + return From == nullptr; + } + bool contains(T *I) const { + if (empty()) + return false; + return (From == I || From->comesBefore(I)) && + (I == To || I->comesBefore(To)); + } + T *top() const { return From; } + T *bottom() const { return To; } + + using iterator = IntervalIterator; + using const_iterator = IntervalIterator; + iterator begin() { return iterator(From, *this); } + iterator end() { + return iterator(To != nullptr ? To->getNextNode() : nullptr, *this); + } + const_iterator begin() const { return const_iterator(From, *this); } + const_iterator end() const { + return const_iterator(To != nullptr ? To->getNextNode() : nullptr, *this); + } +}; + +} // namespace llvm::sandboxir + +#endif // LLVM_TRANSFORMS_VECTORIZE_SANDBOXVECTORIZER_INSTRINTERVAL_H diff --git a/llvm/lib/Transforms/Vectorize/SandboxVectorizer/DependencyGraph.cpp b/llvm/lib/Transforms/Vectorize/SandboxVectorizer/DependencyGraph.cpp index 139e581ce03d9..67b56451c7b59 100644 --- a/llvm/lib/Transforms/Vectorize/SandboxVectorizer/DependencyGraph.cpp +++ b/llvm/lib/Transforms/Vectorize/SandboxVectorizer/DependencyGraph.cpp @@ -31,11 +31,11 @@ void DGNode::dump() const { } #endif // NDEBUG -InstrInterval DependencyGraph::extend(ArrayRef Instrs) { +Interval DependencyGraph::extend(ArrayRef Instrs) { if (Instrs.empty()) return {}; // TODO: For now create a chain of dependencies. - InstrInterval Interval(Instrs); + Interval Interval(Instrs); auto *TopI = Interval.top(); auto *BotI = Interval.bottom(); DGNode *LastN = getOrCreateNode(TopI); diff --git a/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/CMakeLists.txt b/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/CMakeLists.txt index 86b1d968094ca..deb3cd398d02d 100644 --- a/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/CMakeLists.txt +++ b/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/CMakeLists.txt @@ -9,7 +9,7 @@ set(LLVM_LINK_COMPONENTS add_llvm_unittest(SandboxVectorizerTests DependencyGraphTest.cpp - InstrIntervalTest.cpp + IntervalTest.cpp LegalityTest.cpp RegionTest.cpp ) diff --git a/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/InstrIntervalTest.cpp b/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/IntervalTest.cpp similarity index 62% rename from llvm/unittests/Transforms/Vectorize/SandboxVectorizer/InstrIntervalTest.cpp rename to llvm/unittests/Transforms/Vectorize/SandboxVectorizer/IntervalTest.cpp index e22bb78a07d30..054da8c2a5d12 100644 --- a/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/InstrIntervalTest.cpp +++ b/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/IntervalTest.cpp @@ -1,4 +1,4 @@ -//===- InstrIntervalTest.cpp ----------------------------------------------===// +//===- IntervalTest.cpp ---------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -6,16 +6,15 @@ // //===----------------------------------------------------------------------===// -#include "llvm/Transforms/Vectorize/SandboxVectorizer/InstrInterval.h" +#include "llvm/Transforms/Vectorize/SandboxVectorizer/Interval.h" #include "llvm/AsmParser/Parser.h" #include "llvm/SandboxIR/SandboxIR.h" #include "llvm/Support/SourceMgr.h" -#include "gmock/gmock-matchers.h" #include "gtest/gtest.h" using namespace llvm; -struct InstrIntervalTest : public testing::Test { +struct IntervalTest : public testing::Test { LLVMContext C; std::unique_ptr M; @@ -27,7 +26,7 @@ struct InstrIntervalTest : public testing::Test { } }; -TEST_F(InstrIntervalTest, Basic) { +TEST_F(IntervalTest, Basic) { parseIR(C, R"IR( define void @foo(i8 %v0) { %add0 = add i8 %v0, %v0 @@ -46,39 +45,40 @@ define void @foo(i8 %v0) { auto *I2 = &*It++; auto *Ret = &*It++; - sandboxir::InstrInterval Interval(I0, Ret); + sandboxir::Interval Intvl(I0, Ret); #ifndef NDEBUG - EXPECT_DEATH(sandboxir::InstrInterval(I1, I0), ".*before.*"); + EXPECT_DEATH(sandboxir::Interval(I1, I0), + ".*before.*"); #endif // NDEBUG - // Check InstrInterval(ArrayRef), from(), to(). + // Check Interval(ArrayRef), from(), to(). { - sandboxir::InstrInterval Interval( + sandboxir::Interval Intvl( SmallVector({I0, Ret})); - EXPECT_EQ(Interval.top(), I0); - EXPECT_EQ(Interval.bottom(), Ret); + EXPECT_EQ(Intvl.top(), I0); + EXPECT_EQ(Intvl.bottom(), Ret); } { - sandboxir::InstrInterval Interval( + sandboxir::Interval Intvl( SmallVector({Ret, I0})); - EXPECT_EQ(Interval.top(), I0); - EXPECT_EQ(Interval.bottom(), Ret); + EXPECT_EQ(Intvl.top(), I0); + EXPECT_EQ(Intvl.bottom(), Ret); } { - sandboxir::InstrInterval Interval( + sandboxir::Interval Intvl( SmallVector({I0, I0})); - EXPECT_EQ(Interval.top(), I0); - EXPECT_EQ(Interval.bottom(), I0); + EXPECT_EQ(Intvl.top(), I0); + EXPECT_EQ(Intvl.bottom(), I0); } // Check empty(). - EXPECT_FALSE(Interval.empty()); - sandboxir::InstrInterval Empty; + EXPECT_FALSE(Intvl.empty()); + sandboxir::Interval Empty; EXPECT_TRUE(Empty.empty()); - sandboxir::InstrInterval One(I0, I0); + sandboxir::Interval One(I0, I0); EXPECT_FALSE(One.empty()); // Check contains(). for (auto &I : *BB) { - EXPECT_TRUE(Interval.contains(&I)); + EXPECT_TRUE(Intvl.contains(&I)); EXPECT_FALSE(Empty.contains(&I)); } EXPECT_FALSE(One.contains(I1)); @@ -86,6 +86,6 @@ define void @foo(i8 %v0) { EXPECT_FALSE(One.contains(Ret)); // Check iterator. auto BBIt = BB->begin(); - for (auto &I : Interval) + for (auto &I : Intvl) EXPECT_EQ(&I, &*BBIt++); } From 049fc920e631743dd3ff9e51fd7135adbaf9d1dc Mon Sep 17 00:00:00 2001 From: vporpo Date: Thu, 26 Sep 2024 17:48:00 -0700 Subject: [PATCH 025/469] [SandboxIR][NFC] Move Constant and derived classes into a separate file (#110189) --- llvm/include/llvm/SandboxIR/Constant.h | 1283 +++++++++++++++++++++++ llvm/include/llvm/SandboxIR/SandboxIR.h | 1253 +--------------------- llvm/lib/SandboxIR/CMakeLists.txt | 1 + llvm/lib/SandboxIR/Constant.cpp | 509 +++++++++ llvm/lib/SandboxIR/SandboxIR.cpp | 495 --------- 5 files changed, 1794 insertions(+), 1747 deletions(-) create mode 100644 llvm/include/llvm/SandboxIR/Constant.h create mode 100644 llvm/lib/SandboxIR/Constant.cpp diff --git a/llvm/include/llvm/SandboxIR/Constant.h b/llvm/include/llvm/SandboxIR/Constant.h new file mode 100644 index 0000000000000..bc0e3d8849237 --- /dev/null +++ b/llvm/include/llvm/SandboxIR/Constant.h @@ -0,0 +1,1283 @@ +//===- Constant.h -----------------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SANDBOXIR_CONSTANT_H +#define LLVM_SANDBOXIR_CONSTANT_H + +#include "llvm/IR/BasicBlock.h" +#include "llvm/IR/Constant.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/GlobalAlias.h" +#include "llvm/IR/GlobalIFunc.h" +#include "llvm/IR/GlobalObject.h" +#include "llvm/IR/GlobalValue.h" +#include "llvm/IR/GlobalVariable.h" +#include "llvm/SandboxIR/Context.h" +#include "llvm/SandboxIR/Type.h" +#include "llvm/SandboxIR/User.h" + +namespace llvm::sandboxir { + +class BasicBlock; +class Function; + +class Constant : public sandboxir::User { +protected: + Constant(llvm::Constant *C, sandboxir::Context &SBCtx) + : sandboxir::User(ClassID::Constant, C, SBCtx) {} + Constant(ClassID ID, llvm::Constant *C, sandboxir::Context &SBCtx) + : sandboxir::User(ID, C, SBCtx) {} + friend class ConstantInt; // For constructor. + friend class Function; // For constructor + friend class Context; // For constructor. + Use getOperandUseInternal(unsigned OpIdx, bool Verify) const override { + return getOperandUseDefault(OpIdx, Verify); + } + +public: + /// For isa/dyn_cast. + static bool classof(const sandboxir::Value *From) { + switch (From->getSubclassID()) { +#define DEF_CONST(ID, CLASS) case ClassID::ID: +#include "llvm/SandboxIR/SandboxIRValues.def" + return true; + default: + return false; + } + } + sandboxir::Context &getParent() const { return getContext(); } + unsigned getUseOperandNo(const Use &Use) const override { + return getUseOperandNoDefault(Use); + } +#ifndef NDEBUG + void verify() const override { + assert(isa(Val) && "Expected Constant!"); + } + void dumpOS(raw_ostream &OS) const override; +#endif +}; + +// TODO: This should inherit from ConstantData. +class ConstantInt : public Constant { + ConstantInt(llvm::ConstantInt *C, Context &Ctx) + : Constant(ClassID::ConstantInt, C, Ctx) {} + friend class Context; // For constructor. + + Use getOperandUseInternal(unsigned OpIdx, bool Verify) const final { + llvm_unreachable("ConstantInt has no operands!"); + } + +public: + static ConstantInt *getTrue(Context &Ctx); + static ConstantInt *getFalse(Context &Ctx); + static ConstantInt *getBool(Context &Ctx, bool V); + static Constant *getTrue(Type *Ty); + static Constant *getFalse(Type *Ty); + static Constant *getBool(Type *Ty, bool V); + + /// If Ty is a vector type, return a Constant with a splat of the given + /// value. Otherwise return a ConstantInt for the given value. + static ConstantInt *get(Type *Ty, uint64_t V, bool IsSigned = false); + + /// Return a ConstantInt with the specified integer value for the specified + /// type. If the type is wider than 64 bits, the value will be zero-extended + /// to fit the type, unless IsSigned is true, in which case the value will + /// be interpreted as a 64-bit signed integer and sign-extended to fit + /// the type. + /// Get a ConstantInt for a specific value. + static ConstantInt *get(IntegerType *Ty, uint64_t V, bool IsSigned = false); + + /// Return a ConstantInt with the specified value for the specified type. The + /// value V will be canonicalized to a an unsigned APInt. Accessing it with + /// either getSExtValue() or getZExtValue() will yield a correctly sized and + /// signed value for the type Ty. + /// Get a ConstantInt for a specific signed value. + static ConstantInt *getSigned(IntegerType *Ty, int64_t V); + static Constant *getSigned(Type *Ty, int64_t V); + + /// Return a ConstantInt with the specified value and an implied Type. The + /// type is the integer type that corresponds to the bit width of the value. + static ConstantInt *get(Context &Ctx, const APInt &V); + + /// Return a ConstantInt constructed from the string strStart with the given + /// radix. + static ConstantInt *get(IntegerType *Ty, StringRef Str, uint8_t Radix); + + /// If Ty is a vector type, return a Constant with a splat of the given + /// value. Otherwise return a ConstantInt for the given value. + static Constant *get(Type *Ty, const APInt &V); + + /// Return the constant as an APInt value reference. This allows clients to + /// obtain a full-precision copy of the value. + /// Return the constant's value. + inline const APInt &getValue() const { + return cast(Val)->getValue(); + } + + /// getBitWidth - Return the scalar bitwidth of this constant. + unsigned getBitWidth() const { + return cast(Val)->getBitWidth(); + } + /// Return the constant as a 64-bit unsigned integer value after it + /// has been zero extended as appropriate for the type of this constant. Note + /// that this method can assert if the value does not fit in 64 bits. + /// Return the zero extended value. + inline uint64_t getZExtValue() const { + return cast(Val)->getZExtValue(); + } + + /// Return the constant as a 64-bit integer value after it has been sign + /// extended as appropriate for the type of this constant. Note that + /// this method can assert if the value does not fit in 64 bits. + /// Return the sign extended value. + inline int64_t getSExtValue() const { + return cast(Val)->getSExtValue(); + } + + /// Return the constant as an llvm::MaybeAlign. + /// Note that this method can assert if the value does not fit in 64 bits or + /// is not a power of two. + inline MaybeAlign getMaybeAlignValue() const { + return cast(Val)->getMaybeAlignValue(); + } + + /// Return the constant as an llvm::Align, interpreting `0` as `Align(1)`. + /// Note that this method can assert if the value does not fit in 64 bits or + /// is not a power of two. + inline Align getAlignValue() const { + return cast(Val)->getAlignValue(); + } + + /// A helper method that can be used to determine if the constant contained + /// within is equal to a constant. This only works for very small values, + /// because this is all that can be represented with all types. + /// Determine if this constant's value is same as an unsigned char. + bool equalsInt(uint64_t V) const { + return cast(Val)->equalsInt(V); + } + + /// Variant of the getType() method to always return an IntegerType, which + /// reduces the amount of casting needed in parts of the compiler. + IntegerType *getIntegerType() const; + + /// This static method returns true if the type Ty is big enough to + /// represent the value V. This can be used to avoid having the get method + /// assert when V is larger than Ty can represent. Note that there are two + /// versions of this method, one for unsigned and one for signed integers. + /// Although ConstantInt canonicalizes everything to an unsigned integer, + /// the signed version avoids callers having to convert a signed quantity + /// to the appropriate unsigned type before calling the method. + /// @returns true if V is a valid value for type Ty + /// Determine if the value is in range for the given type. + static bool isValueValidForType(Type *Ty, uint64_t V); + static bool isValueValidForType(Type *Ty, int64_t V); + + bool isNegative() const { return cast(Val)->isNegative(); } + + /// This is just a convenience method to make client code smaller for a + /// common code. It also correctly performs the comparison without the + /// potential for an assertion from getZExtValue(). + bool isZero() const { return cast(Val)->isZero(); } + + /// This is just a convenience method to make client code smaller for a + /// common case. It also correctly performs the comparison without the + /// potential for an assertion from getZExtValue(). + /// Determine if the value is one. + bool isOne() const { return cast(Val)->isOne(); } + + /// This function will return true iff every bit in this constant is set + /// to true. + /// @returns true iff this constant's bits are all set to true. + /// Determine if the value is all ones. + bool isMinusOne() const { return cast(Val)->isMinusOne(); } + + /// This function will return true iff this constant represents the largest + /// value that may be represented by the constant's type. + /// @returns true iff this is the largest value that may be represented + /// by this type. + /// Determine if the value is maximal. + bool isMaxValue(bool IsSigned) const { + return cast(Val)->isMaxValue(IsSigned); + } + + /// This function will return true iff this constant represents the smallest + /// value that may be represented by this constant's type. + /// @returns true if this is the smallest value that may be represented by + /// this type. + /// Determine if the value is minimal. + bool isMinValue(bool IsSigned) const { + return cast(Val)->isMinValue(IsSigned); + } + + /// This function will return true iff this constant represents a value with + /// active bits bigger than 64 bits or a value greater than the given uint64_t + /// value. + /// @returns true iff this constant is greater or equal to the given number. + /// Determine if the value is greater or equal to the given number. + bool uge(uint64_t Num) const { + return cast(Val)->uge(Num); + } + + /// getLimitedValue - If the value is smaller than the specified limit, + /// return it, otherwise return the limit value. This causes the value + /// to saturate to the limit. + /// @returns the min of the value of the constant and the specified value + /// Get the constant's value with a saturation limit + uint64_t getLimitedValue(uint64_t Limit = ~0ULL) const { + return cast(Val)->getLimitedValue(Limit); + } + + /// For isa/dyn_cast. + static bool classof(const sandboxir::Value *From) { + return From->getSubclassID() == ClassID::ConstantInt; + } + unsigned getUseOperandNo(const Use &Use) const override { + llvm_unreachable("ConstantInt has no operands!"); + } +#ifndef NDEBUG + void verify() const override { + assert(isa(Val) && "Expected a ConstantInst!"); + } + void dumpOS(raw_ostream &OS) const override { + dumpCommonPrefix(OS); + dumpCommonSuffix(OS); + } +#endif +}; + +// TODO: This should inherit from ConstantData. +class ConstantFP final : public Constant { + ConstantFP(llvm::ConstantFP *C, Context &Ctx) + : Constant(ClassID::ConstantFP, C, Ctx) {} + friend class Context; // For constructor. + +public: + /// This returns a ConstantFP, or a vector containing a splat of a ConstantFP, + /// for the specified value in the specified type. This should only be used + /// for simple constant values like 2.0/1.0 etc, that are known-valid both as + /// host double and as the target format. + static Constant *get(Type *Ty, double V); + + /// If Ty is a vector type, return a Constant with a splat of the given + /// value. Otherwise return a ConstantFP for the given value. + static Constant *get(Type *Ty, const APFloat &V); + + static Constant *get(Type *Ty, StringRef Str); + + static ConstantFP *get(const APFloat &V, Context &Ctx); + + static Constant *getNaN(Type *Ty, bool Negative = false, + uint64_t Payload = 0); + static Constant *getQNaN(Type *Ty, bool Negative = false, + APInt *Payload = nullptr); + static Constant *getSNaN(Type *Ty, bool Negative = false, + APInt *Payload = nullptr); + static Constant *getZero(Type *Ty, bool Negative = false); + + static Constant *getNegativeZero(Type *Ty); + static Constant *getInfinity(Type *Ty, bool Negative = false); + + /// Return true if Ty is big enough to represent V. + static bool isValueValidForType(Type *Ty, const APFloat &V); + + inline const APFloat &getValueAPF() const { + return cast(Val)->getValueAPF(); + } + inline const APFloat &getValue() const { + return cast(Val)->getValue(); + } + + /// Return true if the value is positive or negative zero. + bool isZero() const { return cast(Val)->isZero(); } + + /// Return true if the sign bit is set. + bool isNegative() const { return cast(Val)->isNegative(); } + + /// Return true if the value is infinity + bool isInfinity() const { return cast(Val)->isInfinity(); } + + /// Return true if the value is a NaN. + bool isNaN() const { return cast(Val)->isNaN(); } + + /// We don't rely on operator== working on double values, as it returns true + /// for things that are clearly not equal, like -0.0 and 0.0. + /// As such, this method can be used to do an exact bit-for-bit comparison of + /// two floating point values. The version with a double operand is retained + /// because it's so convenient to write isExactlyValue(2.0), but please use + /// it only for simple constants. + bool isExactlyValue(const APFloat &V) const { + return cast(Val)->isExactlyValue(V); + } + + bool isExactlyValue(double V) const { + return cast(Val)->isExactlyValue(V); + } + + /// For isa/dyn_cast. + static bool classof(const sandboxir::Value *From) { + return From->getSubclassID() == ClassID::ConstantFP; + } + + // TODO: Better name: getOperandNo(const Use&). Should be private. + unsigned getUseOperandNo(const Use &Use) const final { + llvm_unreachable("ConstantFP has no operands!"); + } +#ifndef NDEBUG + void verify() const override { + assert(isa(Val) && "Expected a ConstantFP!"); + } + void dumpOS(raw_ostream &OS) const override { + dumpCommonPrefix(OS); + dumpCommonSuffix(OS); + } +#endif +}; + +/// Base class for aggregate constants (with operands). +class ConstantAggregate : public Constant { +protected: + ConstantAggregate(ClassID ID, llvm::Constant *C, Context &Ctx) + : Constant(ID, C, Ctx) {} + +public: + /// For isa/dyn_cast. + static bool classof(const sandboxir::Value *From) { + auto ID = From->getSubclassID(); + return ID == ClassID::ConstantVector || ID == ClassID::ConstantStruct || + ID == ClassID::ConstantArray; + } +}; + +class ConstantArray final : public ConstantAggregate { + ConstantArray(llvm::ConstantArray *C, Context &Ctx) + : ConstantAggregate(ClassID::ConstantArray, C, Ctx) {} + friend class Context; // For constructor. + +public: + static Constant *get(ArrayType *T, ArrayRef V); + ArrayType *getType() const; + + // TODO: Missing functions: getType(), getTypeForElements(), getAnon(), get(). + + /// For isa/dyn_cast. + static bool classof(const Value *From) { + return From->getSubclassID() == ClassID::ConstantArray; + } +}; + +class ConstantStruct final : public ConstantAggregate { + ConstantStruct(llvm::ConstantStruct *C, Context &Ctx) + : ConstantAggregate(ClassID::ConstantStruct, C, Ctx) {} + friend class Context; // For constructor. + +public: + static Constant *get(StructType *T, ArrayRef V); + + template + static std::enable_if_t::value, Constant *> + get(StructType *T, Csts *...Vs) { + return get(T, ArrayRef({Vs...})); + } + /// Return an anonymous struct that has the specified elements. + /// If the struct is possibly empty, then you must specify a context. + static Constant *getAnon(ArrayRef V, bool Packed = false) { + return get(getTypeForElements(V, Packed), V); + } + static Constant *getAnon(Context &Ctx, ArrayRef V, + bool Packed = false) { + return get(getTypeForElements(Ctx, V, Packed), V); + } + /// This version of the method allows an empty list. + static StructType *getTypeForElements(Context &Ctx, ArrayRef V, + bool Packed = false); + /// Return an anonymous struct type to use for a constant with the specified + /// set of elements. The list must not be empty. + static StructType *getTypeForElements(ArrayRef V, + bool Packed = false) { + assert(!V.empty() && + "ConstantStruct::getTypeForElements cannot be called on empty list"); + return getTypeForElements(V[0]->getContext(), V, Packed); + } + + /// Specialization - reduce amount of casting. + inline StructType *getType() const { + return cast(Value::getType()); + } + + /// For isa/dyn_cast. + static bool classof(const Value *From) { + return From->getSubclassID() == ClassID::ConstantStruct; + } +}; + +class ConstantVector final : public ConstantAggregate { + ConstantVector(llvm::ConstantVector *C, Context &Ctx) + : ConstantAggregate(ClassID::ConstantVector, C, Ctx) {} + friend class Context; // For constructor. + +public: + // TODO: Missing functions: getSplat(), getType(), getSplatValue(), get(). + + /// For isa/dyn_cast. + static bool classof(const Value *From) { + return From->getSubclassID() == ClassID::ConstantVector; + } +}; + +// TODO: Inherit from ConstantData. +class ConstantAggregateZero final : public Constant { + ConstantAggregateZero(llvm::ConstantAggregateZero *C, Context &Ctx) + : Constant(ClassID::ConstantAggregateZero, C, Ctx) {} + friend class Context; // For constructor. + +public: + static ConstantAggregateZero *get(Type *Ty); + /// If this CAZ has array or vector type, return a zero with the right element + /// type. + Constant *getSequentialElement() const; + /// If this CAZ has struct type, return a zero with the right element type for + /// the specified element. + Constant *getStructElement(unsigned Elt) const; + /// Return a zero of the right value for the specified GEP index if we can, + /// otherwise return null (e.g. if C is a ConstantExpr). + Constant *getElementValue(Constant *C) const; + /// Return a zero of the right value for the specified GEP index. + Constant *getElementValue(unsigned Idx) const; + /// Return the number of elements in the array, vector, or struct. + ElementCount getElementCount() const { + return cast(Val)->getElementCount(); + } + + /// For isa/dyn_cast. + static bool classof(const sandboxir::Value *From) { + return From->getSubclassID() == ClassID::ConstantAggregateZero; + } + unsigned getUseOperandNo(const Use &Use) const final { + llvm_unreachable("ConstantAggregateZero has no operands!"); + } +#ifndef NDEBUG + void verify() const override { + assert(isa(Val) && "Expected a CAZ!"); + } + void dumpOS(raw_ostream &OS) const override { + dumpCommonPrefix(OS); + dumpCommonSuffix(OS); + } +#endif +}; + +// TODO: Inherit from ConstantData. +class ConstantPointerNull final : public Constant { + ConstantPointerNull(llvm::ConstantPointerNull *C, Context &Ctx) + : Constant(ClassID::ConstantPointerNull, C, Ctx) {} + friend class Context; // For constructor. + +public: + static ConstantPointerNull *get(PointerType *Ty); + + PointerType *getType() const; + + /// For isa/dyn_cast. + static bool classof(const sandboxir::Value *From) { + return From->getSubclassID() == ClassID::ConstantPointerNull; + } + unsigned getUseOperandNo(const Use &Use) const final { + llvm_unreachable("ConstantPointerNull has no operands!"); + } +#ifndef NDEBUG + void verify() const override { + assert(isa(Val) && "Expected a CPNull!"); + } + void dumpOS(raw_ostream &OS) const override { + dumpCommonPrefix(OS); + dumpCommonSuffix(OS); + } +#endif +}; + +// TODO: Inherit from ConstantData. +class UndefValue : public Constant { +protected: + UndefValue(llvm::UndefValue *C, Context &Ctx) + : Constant(ClassID::UndefValue, C, Ctx) {} + UndefValue(ClassID ID, llvm::Constant *C, Context &Ctx) + : Constant(ID, C, Ctx) {} + friend class Context; // For constructor. + +public: + /// Static factory methods - Return an 'undef' object of the specified type. + static UndefValue *get(Type *T); + + /// If this Undef has array or vector type, return a undef with the right + /// element type. + UndefValue *getSequentialElement() const; + + /// If this undef has struct type, return a undef with the right element type + /// for the specified element. + UndefValue *getStructElement(unsigned Elt) const; + + /// Return an undef of the right value for the specified GEP index if we can, + /// otherwise return null (e.g. if C is a ConstantExpr). + UndefValue *getElementValue(Constant *C) const; + + /// Return an undef of the right value for the specified GEP index. + UndefValue *getElementValue(unsigned Idx) const; + + /// Return the number of elements in the array, vector, or struct. + unsigned getNumElements() const { + return cast(Val)->getNumElements(); + } + + /// For isa/dyn_cast. + static bool classof(const sandboxir::Value *From) { + return From->getSubclassID() == ClassID::UndefValue || + From->getSubclassID() == ClassID::PoisonValue; + } + unsigned getUseOperandNo(const Use &Use) const final { + llvm_unreachable("UndefValue has no operands!"); + } +#ifndef NDEBUG + void verify() const override { + assert(isa(Val) && "Expected an UndefValue!"); + } + void dumpOS(raw_ostream &OS) const override { + dumpCommonPrefix(OS); + dumpCommonSuffix(OS); + } +#endif +}; + +class PoisonValue final : public UndefValue { + PoisonValue(llvm::PoisonValue *C, Context &Ctx) + : UndefValue(ClassID::PoisonValue, C, Ctx) {} + friend class Context; // For constructor. + +public: + /// Static factory methods - Return an 'poison' object of the specified type. + static PoisonValue *get(Type *T); + + /// If this poison has array or vector type, return a poison with the right + /// element type. + PoisonValue *getSequentialElement() const; + + /// If this poison has struct type, return a poison with the right element + /// type for the specified element. + PoisonValue *getStructElement(unsigned Elt) const; + + /// Return an poison of the right value for the specified GEP index if we can, + /// otherwise return null (e.g. if C is a ConstantExpr). + PoisonValue *getElementValue(Constant *C) const; + + /// Return an poison of the right value for the specified GEP index. + PoisonValue *getElementValue(unsigned Idx) const; + + /// For isa/dyn_cast. + static bool classof(const sandboxir::Value *From) { + return From->getSubclassID() == ClassID::PoisonValue; + } +#ifndef NDEBUG + void verify() const override { + assert(isa(Val) && "Expected a PoisonValue!"); + } + void dumpOS(raw_ostream &OS) const override { + dumpCommonPrefix(OS); + dumpCommonSuffix(OS); + } +#endif +}; + +class GlobalValue : public Constant { +protected: + GlobalValue(ClassID ID, llvm::GlobalValue *C, Context &Ctx) + : Constant(ID, C, Ctx) {} + friend class Context; // For constructor. + +public: + using LinkageTypes = llvm::GlobalValue::LinkageTypes; + /// For isa/dyn_cast. + static bool classof(const sandboxir::Value *From) { + switch (From->getSubclassID()) { + case ClassID::Function: + case ClassID::GlobalVariable: + case ClassID::GlobalAlias: + case ClassID::GlobalIFunc: + return true; + default: + return false; + } + } + + unsigned getAddressSpace() const { + return cast(Val)->getAddressSpace(); + } + bool hasGlobalUnnamedAddr() const { + return cast(Val)->hasGlobalUnnamedAddr(); + } + + /// Returns true if this value's address is not significant in this module. + /// This attribute is intended to be used only by the code generator and LTO + /// to allow the linker to decide whether the global needs to be in the symbol + /// table. It should probably not be used in optimizations, as the value may + /// have uses outside the module; use hasGlobalUnnamedAddr() instead. + bool hasAtLeastLocalUnnamedAddr() const { + return cast(Val)->hasAtLeastLocalUnnamedAddr(); + } + + using UnnamedAddr = llvm::GlobalValue::UnnamedAddr; + + UnnamedAddr getUnnamedAddr() const { + return cast(Val)->getUnnamedAddr(); + } + void setUnnamedAddr(UnnamedAddr V); + + static UnnamedAddr getMinUnnamedAddr(UnnamedAddr A, UnnamedAddr B) { + return llvm::GlobalValue::getMinUnnamedAddr(A, B); + } + + bool hasComdat() const { return cast(Val)->hasComdat(); } + + // TODO: We need a SandboxIR Comdat if we want to implement getComdat(). + using VisibilityTypes = llvm::GlobalValue::VisibilityTypes; + VisibilityTypes getVisibility() const { + return cast(Val)->getVisibility(); + } + bool hasDefaultVisibility() const { + return cast(Val)->hasDefaultVisibility(); + } + bool hasHiddenVisibility() const { + return cast(Val)->hasHiddenVisibility(); + } + bool hasProtectedVisibility() const { + return cast(Val)->hasProtectedVisibility(); + } + void setVisibility(VisibilityTypes V); + + // TODO: Add missing functions. +}; + +class GlobalObject : public GlobalValue { +protected: + GlobalObject(ClassID ID, llvm::GlobalObject *C, Context &Ctx) + : GlobalValue(ID, C, Ctx) {} + friend class Context; // For constructor. + Use getOperandUseInternal(unsigned OpIdx, bool Verify) const final { + return getOperandUseDefault(OpIdx, Verify); + } + +public: + unsigned getUseOperandNo(const Use &Use) const final { + return getUseOperandNoDefault(Use); + } + /// For isa/dyn_cast. + static bool classof(const sandboxir::Value *From) { + switch (From->getSubclassID()) { + case ClassID::Function: + case ClassID::GlobalVariable: + case ClassID::GlobalIFunc: + return true; + default: + return false; + } + } + + /// FIXME: Remove this function once transition to Align is over. + uint64_t getAlignment() const { + return cast(Val)->getAlignment(); + } + + /// Returns the alignment of the given variable or function. + /// + /// Note that for functions this is the alignment of the code, not the + /// alignment of a function pointer. + MaybeAlign getAlign() const { + return cast(Val)->getAlign(); + } + + // TODO: Add missing: setAlignment(Align) + + /// Sets the alignment attribute of the GlobalObject. + /// This method will be deprecated as the alignment property should always be + /// defined. + void setAlignment(MaybeAlign Align); + + unsigned getGlobalObjectSubClassData() const { + return cast(Val)->getGlobalObjectSubClassData(); + } + + void setGlobalObjectSubClassData(unsigned V); + + /// Check if this global has a custom object file section. + /// + /// This is more efficient than calling getSection() and checking for an empty + /// string. + bool hasSection() const { + return cast(Val)->hasSection(); + } + + /// Get the custom section of this global if it has one. + /// + /// If this global does not have a custom section, this will be empty and the + /// default object file section (.text, .data, etc) will be used. + StringRef getSection() const { + return cast(Val)->getSection(); + } + + /// Change the section for this global. + /// + /// Setting the section to the empty string tells LLVM to choose an + /// appropriate default object file section. + void setSection(StringRef S); + + bool hasComdat() const { return cast(Val)->hasComdat(); } + + // TODO: implement get/setComdat(), etc. once we have a sandboxir::Comdat. + + // TODO: We currently don't support Metadata in sandboxir so all + // Metadata-related functions are missing. + + using VCallVisibility = llvm::GlobalObject::VCallVisibility; + + VCallVisibility getVCallVisibility() const { + return cast(Val)->getVCallVisibility(); + } + + /// Returns true if the alignment of the value can be unilaterally + /// increased. + /// + /// Note that for functions this is the alignment of the code, not the + /// alignment of a function pointer. + bool canIncreaseAlignment() const { + return cast(Val)->canIncreaseAlignment(); + } +}; + +/// Provides API functions, like getIterator() and getReverseIterator() to +/// GlobalIFunc, Function, GlobalVariable and GlobalAlias. In LLVM IR these are +/// provided by ilist_node. +template +class GlobalWithNodeAPI : public ParentT { + /// Helper for mapped_iterator. + struct LLVMGVToGV { + Context &Ctx; + LLVMGVToGV(Context &Ctx) : Ctx(Ctx) {} + GlobalT &operator()(LLVMGlobalT &LLVMGV) const; + }; + +public: + GlobalWithNodeAPI(Value::ClassID ID, LLVMParentT *C, Context &Ctx) + : ParentT(ID, C, Ctx) {} + + Module *getParent() const { + llvm::Module *LLVMM = cast(this->Val)->getParent(); + return this->Ctx.getModule(LLVMM); + } + + using iterator = mapped_iterator< + decltype(static_cast(nullptr)->getIterator()), LLVMGVToGV>; + using reverse_iterator = mapped_iterator< + decltype(static_cast(nullptr)->getReverseIterator()), + LLVMGVToGV>; + iterator getIterator() const { + auto *LLVMGV = cast(this->Val); + LLVMGVToGV ToGV(this->Ctx); + return map_iterator(LLVMGV->getIterator(), ToGV); + } + reverse_iterator getReverseIterator() const { + auto *LLVMGV = cast(this->Val); + LLVMGVToGV ToGV(this->Ctx); + return map_iterator(LLVMGV->getReverseIterator(), ToGV); + } +}; + +class GlobalIFunc final + : public GlobalWithNodeAPI { + GlobalIFunc(llvm::GlobalObject *C, Context &Ctx) + : GlobalWithNodeAPI(ClassID::GlobalIFunc, C, Ctx) {} + friend class Context; // For constructor. + +public: + /// For isa/dyn_cast. + static bool classof(const sandboxir::Value *From) { + return From->getSubclassID() == ClassID::GlobalIFunc; + } + + // TODO: Missing create() because we don't have a sandboxir::Module yet. + + // TODO: Missing functions: copyAttributesFrom(), removeFromParent(), + // eraseFromParent() + + void setResolver(Constant *Resolver); + + Constant *getResolver() const; + + // Return the resolver function after peeling off potential ConstantExpr + // indirection. + Function *getResolverFunction(); + const Function *getResolverFunction() const { + return const_cast(this)->getResolverFunction(); + } + + static bool isValidLinkage(LinkageTypes L) { + return llvm::GlobalIFunc::isValidLinkage(L); + } + + // TODO: Missing applyAlongResolverPath(). + +#ifndef NDEBUG + void verify() const override { + assert(isa(Val) && "Expected a GlobalIFunc!"); + } + void dumpOS(raw_ostream &OS) const override { + dumpCommonPrefix(OS); + dumpCommonSuffix(OS); + } +#endif +}; + +class GlobalVariable final + : public GlobalWithNodeAPI { + GlobalVariable(llvm::GlobalObject *C, Context &Ctx) + : GlobalWithNodeAPI(ClassID::GlobalVariable, C, Ctx) {} + friend class Context; // For constructor. + + /// Helper for mapped_iterator. + struct LLVMGVToGV { + Context &Ctx; + LLVMGVToGV(Context &Ctx) : Ctx(Ctx) {} + GlobalVariable &operator()(llvm::GlobalVariable &LLVMGV) const; + }; + +public: + /// For isa/dyn_cast. + static bool classof(const sandboxir::Value *From) { + return From->getSubclassID() == ClassID::GlobalVariable; + } + + /// Definitions have initializers, declarations don't. + /// + inline bool hasInitializer() const { + return cast(Val)->hasInitializer(); + } + + /// hasDefinitiveInitializer - Whether the global variable has an initializer, + /// and any other instances of the global (this can happen due to weak + /// linkage) are guaranteed to have the same initializer. + /// + /// Note that if you want to transform a global, you must use + /// hasUniqueInitializer() instead, because of the *_odr linkage type. + /// + /// Example: + /// + /// @a = global SomeType* null - Initializer is both definitive and unique. + /// + /// @b = global weak SomeType* null - Initializer is neither definitive nor + /// unique. + /// + /// @c = global weak_odr SomeType* null - Initializer is definitive, but not + /// unique. + inline bool hasDefinitiveInitializer() const { + return cast(Val)->hasDefinitiveInitializer(); + } + + /// hasUniqueInitializer - Whether the global variable has an initializer, and + /// any changes made to the initializer will turn up in the final executable. + inline bool hasUniqueInitializer() const { + return cast(Val)->hasUniqueInitializer(); + } + + /// getInitializer - Return the initializer for this global variable. It is + /// illegal to call this method if the global is external, because we cannot + /// tell what the value is initialized to! + /// + Constant *getInitializer() const; + /// setInitializer - Sets the initializer for this global variable, removing + /// any existing initializer if InitVal==NULL. The initializer must have the + /// type getValueType(). + void setInitializer(Constant *InitVal); + + // TODO: Add missing replaceInitializer(). Requires special tracker + + /// If the value is a global constant, its value is immutable throughout the + /// runtime execution of the program. Assigning a value into the constant + /// leads to undefined behavior. + /// + bool isConstant() const { + return cast(Val)->isConstant(); + } + void setConstant(bool V); + + bool isExternallyInitialized() const { + return cast(Val)->isExternallyInitialized(); + } + void setExternallyInitialized(bool Val); + + // TODO: Missing copyAttributesFrom() + + // TODO: Missing removeFromParent(), eraseFromParent(), dropAllReferences() + + // TODO: Missing addDebugInfo(), getDebugInfo() + + // TODO: Missing attribute setter functions: addAttribute(), setAttributes(). + // There seems to be no removeAttribute() so we can't undo them. + + /// Return true if the attribute exists. + bool hasAttribute(Attribute::AttrKind Kind) const { + return cast(Val)->hasAttribute(Kind); + } + + /// Return true if the attribute exists. + bool hasAttribute(StringRef Kind) const { + return cast(Val)->hasAttribute(Kind); + } + + /// Return true if any attributes exist. + bool hasAttributes() const { + return cast(Val)->hasAttributes(); + } + + /// Return the attribute object. + Attribute getAttribute(Attribute::AttrKind Kind) const { + return cast(Val)->getAttribute(Kind); + } + + /// Return the attribute object. + Attribute getAttribute(StringRef Kind) const { + return cast(Val)->getAttribute(Kind); + } + + /// Return the attribute set for this global + AttributeSet getAttributes() const { + return cast(Val)->getAttributes(); + } + + /// Return attribute set as list with index. + /// FIXME: This may not be required once ValueEnumerators + /// in bitcode-writer can enumerate attribute-set. + AttributeList getAttributesAsList(unsigned Index) const { + return cast(Val)->getAttributesAsList(Index); + } + + /// Check if section name is present + bool hasImplicitSection() const { + return cast(Val)->hasImplicitSection(); + } + + /// Get the custom code model raw value of this global. + /// + unsigned getCodeModelRaw() const { + return cast(Val)->getCodeModelRaw(); + } + + /// Get the custom code model of this global if it has one. + /// + /// If this global does not have a custom code model, the empty instance + /// will be returned. + std::optional getCodeModel() const { + return cast(Val)->getCodeModel(); + } + + // TODO: Missing setCodeModel(). Requires custom tracker. + +#ifndef NDEBUG + void verify() const override { + assert(isa(Val) && "Expected a GlobalVariable!"); + } + void dumpOS(raw_ostream &OS) const override { + dumpCommonPrefix(OS); + dumpCommonSuffix(OS); + } +#endif +}; + +class GlobalAlias final + : public GlobalWithNodeAPI { + GlobalAlias(llvm::GlobalAlias *C, Context &Ctx) + : GlobalWithNodeAPI(ClassID::GlobalAlias, C, Ctx) {} + friend class Context; // For constructor. + +public: + /// For isa/dyn_cast. + static bool classof(const sandboxir::Value *From) { + return From->getSubclassID() == ClassID::GlobalAlias; + } + + // TODO: Missing create() due to unimplemented sandboxir::Module. + + // TODO: Missing copyAttributresFrom(). + // TODO: Missing removeFromParent(), eraseFromParent(). + + void setAliasee(Constant *Aliasee); + Constant *getAliasee() const; + + const GlobalObject *getAliaseeObject() const; + GlobalObject *getAliaseeObject() { + return const_cast( + static_cast(this)->getAliaseeObject()); + } + + static bool isValidLinkage(LinkageTypes L) { + return llvm::GlobalAlias::isValidLinkage(L); + } +}; + +class NoCFIValue final : public Constant { + NoCFIValue(llvm::NoCFIValue *C, Context &Ctx) + : Constant(ClassID::NoCFIValue, C, Ctx) {} + friend class Context; // For constructor. + + Use getOperandUseInternal(unsigned OpIdx, bool Verify) const final { + return getOperandUseDefault(OpIdx, Verify); + } + +public: + /// Return a NoCFIValue for the specified function. + static NoCFIValue *get(GlobalValue *GV); + + GlobalValue *getGlobalValue() const; + + /// NoCFIValue is always a pointer. + PointerType *getType() const; + /// For isa/dyn_cast. + static bool classof(const sandboxir::Value *From) { + return From->getSubclassID() == ClassID::NoCFIValue; + } + + unsigned getUseOperandNo(const Use &Use) const final { + return getUseOperandNoDefault(Use); + } + +#ifndef NDEBUG + void verify() const override { + assert(isa(Val) && "Expected a NoCFIValue!"); + } + void dumpOS(raw_ostream &OS) const override { + dumpCommonPrefix(OS); + dumpCommonSuffix(OS); + } +#endif +}; + +class ConstantPtrAuth final : public Constant { + ConstantPtrAuth(llvm::ConstantPtrAuth *C, Context &Ctx) + : Constant(ClassID::ConstantPtrAuth, C, Ctx) {} + friend class Context; // For constructor. + +public: + /// Return a pointer signed with the specified parameters. + static ConstantPtrAuth *get(Constant *Ptr, ConstantInt *Key, + ConstantInt *Disc, Constant *AddrDisc); + /// The pointer that is signed in this ptrauth signed pointer. + Constant *getPointer() const; + + /// The Key ID, an i32 constant. + ConstantInt *getKey() const; + + /// The integer discriminator, an i64 constant, or 0. + ConstantInt *getDiscriminator() const; + + /// The address discriminator if any, or the null constant. + /// If present, this must be a value equivalent to the storage location of + /// the only global-initializer user of the ptrauth signed pointer. + Constant *getAddrDiscriminator() const; + + /// Whether there is any non-null address discriminator. + bool hasAddressDiscriminator() const { + return cast(Val)->hasAddressDiscriminator(); + } + + /// Whether the address uses a special address discriminator. + /// These discriminators can't be used in real pointer-auth values; they + /// can only be used in "prototype" values that indicate how some real + /// schema is supposed to be produced. + bool hasSpecialAddressDiscriminator(uint64_t Value) const { + return cast(Val)->hasSpecialAddressDiscriminator( + Value); + } + + /// Check whether an authentication operation with key \p Key and (possibly + /// blended) discriminator \p Discriminator is known to be compatible with + /// this ptrauth signed pointer. + bool isKnownCompatibleWith(const Value *Key, const Value *Discriminator, + const DataLayout &DL) const { + return cast(Val)->isKnownCompatibleWith( + Key->Val, Discriminator->Val, DL); + } + + /// Produce a new ptrauth expression signing the given value using + /// the same schema as is stored in one. + ConstantPtrAuth *getWithSameSchema(Constant *Pointer) const; + + /// For isa/dyn_cast. + static bool classof(const sandboxir::Value *From) { + return From->getSubclassID() == ClassID::ConstantPtrAuth; + } +}; + +class ConstantExpr : public Constant { + ConstantExpr(llvm::ConstantExpr *C, Context &Ctx) + : Constant(ClassID::ConstantExpr, C, Ctx) {} + friend class Context; // For constructor. + +public: + /// For isa/dyn_cast. + static bool classof(const sandboxir::Value *From) { + return From->getSubclassID() == ClassID::ConstantExpr; + } + // TODO: Missing functions. +}; + +class BlockAddress final : public Constant { + BlockAddress(llvm::BlockAddress *C, Context &Ctx) + : Constant(ClassID::BlockAddress, C, Ctx) {} + friend class Context; // For constructor. + +public: + /// Return a BlockAddress for the specified function and basic block. + static BlockAddress *get(Function *F, BasicBlock *BB); + + /// Return a BlockAddress for the specified basic block. The basic + /// block must be embedded into a function. + static BlockAddress *get(BasicBlock *BB); + + /// Lookup an existing \c BlockAddress constant for the given BasicBlock. + /// + /// \returns 0 if \c !BB->hasAddressTaken(), otherwise the \c BlockAddress. + static BlockAddress *lookup(const BasicBlock *BB); + + Function *getFunction() const; + BasicBlock *getBasicBlock() const; + + /// For isa/dyn_cast. + static bool classof(const sandboxir::Value *From) { + return From->getSubclassID() == ClassID::BlockAddress; + } +}; + +class DSOLocalEquivalent final : public Constant { + DSOLocalEquivalent(llvm::DSOLocalEquivalent *C, Context &Ctx) + : Constant(ClassID::DSOLocalEquivalent, C, Ctx) {} + friend class Context; // For constructor. + +public: + /// Return a DSOLocalEquivalent for the specified global value. + static DSOLocalEquivalent *get(GlobalValue *GV); + + GlobalValue *getGlobalValue() const; + + /// For isa/dyn_cast. + static bool classof(const sandboxir::Value *From) { + return From->getSubclassID() == ClassID::DSOLocalEquivalent; + } + + unsigned getUseOperandNo(const Use &Use) const final { + llvm_unreachable("DSOLocalEquivalent has no operands!"); + } + +#ifndef NDEBUG + void verify() const override { + assert(isa(Val) && + "Expected a DSOLocalEquivalent!"); + } + void dumpOS(raw_ostream &OS) const override { + dumpCommonPrefix(OS); + dumpCommonSuffix(OS); + } +#endif +}; + +// TODO: This should inherit from ConstantData. +class ConstantTokenNone final : public Constant { + ConstantTokenNone(llvm::ConstantTokenNone *C, Context &Ctx) + : Constant(ClassID::ConstantTokenNone, C, Ctx) {} + friend class Context; // For constructor. + +public: + /// Return the ConstantTokenNone. + static ConstantTokenNone *get(Context &Ctx); + + /// For isa/dyn_cast. + static bool classof(const sandboxir::Value *From) { + return From->getSubclassID() == ClassID::ConstantTokenNone; + } + + unsigned getUseOperandNo(const Use &Use) const final { + llvm_unreachable("ConstantTokenNone has no operands!"); + } + +#ifndef NDEBUG + void verify() const override { + assert(isa(Val) && + "Expected a ConstantTokenNone!"); + } + void dumpOS(raw_ostream &OS) const override { + dumpCommonPrefix(OS); + dumpCommonSuffix(OS); + } +#endif +}; + +class Function : public GlobalWithNodeAPI { + /// Helper for mapped_iterator. + struct LLVMBBToBB { + Context &Ctx; + LLVMBBToBB(Context &Ctx) : Ctx(Ctx) {} + BasicBlock &operator()(llvm::BasicBlock &LLVMBB) const { + return *cast(Ctx.getValue(&LLVMBB)); + } + }; + /// Use Context::createFunction() instead. + Function(llvm::Function *F, sandboxir::Context &Ctx) + : GlobalWithNodeAPI(ClassID::Function, F, Ctx) {} + friend class Context; // For constructor. + +public: + /// For isa/dyn_cast. + static bool classof(const sandboxir::Value *From) { + return From->getSubclassID() == ClassID::Function; + } + + Module *getParent() { + return Ctx.getModule(cast(Val)->getParent()); + } + + Argument *getArg(unsigned Idx) const { + llvm::Argument *Arg = cast(Val)->getArg(Idx); + return cast(Ctx.getValue(Arg)); + } + + size_t arg_size() const { return cast(Val)->arg_size(); } + bool arg_empty() const { return cast(Val)->arg_empty(); } + + using iterator = mapped_iterator; + iterator begin() const { + LLVMBBToBB BBGetter(Ctx); + return iterator(cast(Val)->begin(), BBGetter); + } + iterator end() const { + LLVMBBToBB BBGetter(Ctx); + return iterator(cast(Val)->end(), BBGetter); + } + FunctionType *getFunctionType() const; + +#ifndef NDEBUG + void verify() const final { + assert(isa(Val) && "Expected Function!"); + } + void dumpNameAndArgs(raw_ostream &OS) const; + void dumpOS(raw_ostream &OS) const final; +#endif +}; + +} // namespace llvm::sandboxir + +#endif // LLVM_SANDBOXIR_CONSTANT_H diff --git a/llvm/include/llvm/SandboxIR/SandboxIR.h b/llvm/include/llvm/SandboxIR/SandboxIR.h index 66de9ee078d61..02246c303ab61 100644 --- a/llvm/include/llvm/SandboxIR/SandboxIR.h +++ b/llvm/include/llvm/SandboxIR/SandboxIR.h @@ -110,6 +110,7 @@ #include "llvm/IR/User.h" #include "llvm/IR/Value.h" #include "llvm/SandboxIR/Argument.h" +#include "llvm/SandboxIR/Constant.h" #include "llvm/SandboxIR/Context.h" #include "llvm/SandboxIR/Module.h" #include "llvm/SandboxIR/Tracker.h" @@ -190,1205 +191,6 @@ class CmpInst; class ICmpInst; class FCmpInst; -class Constant : public sandboxir::User { -protected: - Constant(llvm::Constant *C, sandboxir::Context &SBCtx) - : sandboxir::User(ClassID::Constant, C, SBCtx) {} - Constant(ClassID ID, llvm::Constant *C, sandboxir::Context &SBCtx) - : sandboxir::User(ID, C, SBCtx) {} - friend class ConstantInt; // For constructor. - friend class Function; // For constructor - friend class Context; // For constructor. - Use getOperandUseInternal(unsigned OpIdx, bool Verify) const override { - return getOperandUseDefault(OpIdx, Verify); - } - -public: - /// For isa/dyn_cast. - static bool classof(const sandboxir::Value *From) { - switch (From->getSubclassID()) { -#define DEF_CONST(ID, CLASS) case ClassID::ID: -#include "llvm/SandboxIR/SandboxIRValues.def" - return true; - default: - return false; - } - } - sandboxir::Context &getParent() const { return getContext(); } - unsigned getUseOperandNo(const Use &Use) const override { - return getUseOperandNoDefault(Use); - } -#ifndef NDEBUG - void verify() const override { - assert(isa(Val) && "Expected Constant!"); - } - void dumpOS(raw_ostream &OS) const override; -#endif -}; - -// TODO: This should inherit from ConstantData. -class ConstantInt : public Constant { - ConstantInt(llvm::ConstantInt *C, Context &Ctx) - : Constant(ClassID::ConstantInt, C, Ctx) {} - friend class Context; // For constructor. - - Use getOperandUseInternal(unsigned OpIdx, bool Verify) const final { - llvm_unreachable("ConstantInt has no operands!"); - } - -public: - static ConstantInt *getTrue(Context &Ctx); - static ConstantInt *getFalse(Context &Ctx); - static ConstantInt *getBool(Context &Ctx, bool V); - static Constant *getTrue(Type *Ty); - static Constant *getFalse(Type *Ty); - static Constant *getBool(Type *Ty, bool V); - - /// If Ty is a vector type, return a Constant with a splat of the given - /// value. Otherwise return a ConstantInt for the given value. - static ConstantInt *get(Type *Ty, uint64_t V, bool IsSigned = false); - - /// Return a ConstantInt with the specified integer value for the specified - /// type. If the type is wider than 64 bits, the value will be zero-extended - /// to fit the type, unless IsSigned is true, in which case the value will - /// be interpreted as a 64-bit signed integer and sign-extended to fit - /// the type. - /// Get a ConstantInt for a specific value. - static ConstantInt *get(IntegerType *Ty, uint64_t V, bool IsSigned = false); - - /// Return a ConstantInt with the specified value for the specified type. The - /// value V will be canonicalized to a an unsigned APInt. Accessing it with - /// either getSExtValue() or getZExtValue() will yield a correctly sized and - /// signed value for the type Ty. - /// Get a ConstantInt for a specific signed value. - static ConstantInt *getSigned(IntegerType *Ty, int64_t V); - static Constant *getSigned(Type *Ty, int64_t V); - - /// Return a ConstantInt with the specified value and an implied Type. The - /// type is the integer type that corresponds to the bit width of the value. - static ConstantInt *get(Context &Ctx, const APInt &V); - - /// Return a ConstantInt constructed from the string strStart with the given - /// radix. - static ConstantInt *get(IntegerType *Ty, StringRef Str, uint8_t Radix); - - /// If Ty is a vector type, return a Constant with a splat of the given - /// value. Otherwise return a ConstantInt for the given value. - static Constant *get(Type *Ty, const APInt &V); - - /// Return the constant as an APInt value reference. This allows clients to - /// obtain a full-precision copy of the value. - /// Return the constant's value. - inline const APInt &getValue() const { - return cast(Val)->getValue(); - } - - /// getBitWidth - Return the scalar bitwidth of this constant. - unsigned getBitWidth() const { - return cast(Val)->getBitWidth(); - } - /// Return the constant as a 64-bit unsigned integer value after it - /// has been zero extended as appropriate for the type of this constant. Note - /// that this method can assert if the value does not fit in 64 bits. - /// Return the zero extended value. - inline uint64_t getZExtValue() const { - return cast(Val)->getZExtValue(); - } - - /// Return the constant as a 64-bit integer value after it has been sign - /// extended as appropriate for the type of this constant. Note that - /// this method can assert if the value does not fit in 64 bits. - /// Return the sign extended value. - inline int64_t getSExtValue() const { - return cast(Val)->getSExtValue(); - } - - /// Return the constant as an llvm::MaybeAlign. - /// Note that this method can assert if the value does not fit in 64 bits or - /// is not a power of two. - inline MaybeAlign getMaybeAlignValue() const { - return cast(Val)->getMaybeAlignValue(); - } - - /// Return the constant as an llvm::Align, interpreting `0` as `Align(1)`. - /// Note that this method can assert if the value does not fit in 64 bits or - /// is not a power of two. - inline Align getAlignValue() const { - return cast(Val)->getAlignValue(); - } - - /// A helper method that can be used to determine if the constant contained - /// within is equal to a constant. This only works for very small values, - /// because this is all that can be represented with all types. - /// Determine if this constant's value is same as an unsigned char. - bool equalsInt(uint64_t V) const { - return cast(Val)->equalsInt(V); - } - - /// Variant of the getType() method to always return an IntegerType, which - /// reduces the amount of casting needed in parts of the compiler. - IntegerType *getIntegerType() const; - - /// This static method returns true if the type Ty is big enough to - /// represent the value V. This can be used to avoid having the get method - /// assert when V is larger than Ty can represent. Note that there are two - /// versions of this method, one for unsigned and one for signed integers. - /// Although ConstantInt canonicalizes everything to an unsigned integer, - /// the signed version avoids callers having to convert a signed quantity - /// to the appropriate unsigned type before calling the method. - /// @returns true if V is a valid value for type Ty - /// Determine if the value is in range for the given type. - static bool isValueValidForType(Type *Ty, uint64_t V); - static bool isValueValidForType(Type *Ty, int64_t V); - - bool isNegative() const { return cast(Val)->isNegative(); } - - /// This is just a convenience method to make client code smaller for a - /// common code. It also correctly performs the comparison without the - /// potential for an assertion from getZExtValue(). - bool isZero() const { return cast(Val)->isZero(); } - - /// This is just a convenience method to make client code smaller for a - /// common case. It also correctly performs the comparison without the - /// potential for an assertion from getZExtValue(). - /// Determine if the value is one. - bool isOne() const { return cast(Val)->isOne(); } - - /// This function will return true iff every bit in this constant is set - /// to true. - /// @returns true iff this constant's bits are all set to true. - /// Determine if the value is all ones. - bool isMinusOne() const { return cast(Val)->isMinusOne(); } - - /// This function will return true iff this constant represents the largest - /// value that may be represented by the constant's type. - /// @returns true iff this is the largest value that may be represented - /// by this type. - /// Determine if the value is maximal. - bool isMaxValue(bool IsSigned) const { - return cast(Val)->isMaxValue(IsSigned); - } - - /// This function will return true iff this constant represents the smallest - /// value that may be represented by this constant's type. - /// @returns true if this is the smallest value that may be represented by - /// this type. - /// Determine if the value is minimal. - bool isMinValue(bool IsSigned) const { - return cast(Val)->isMinValue(IsSigned); - } - - /// This function will return true iff this constant represents a value with - /// active bits bigger than 64 bits or a value greater than the given uint64_t - /// value. - /// @returns true iff this constant is greater or equal to the given number. - /// Determine if the value is greater or equal to the given number. - bool uge(uint64_t Num) const { - return cast(Val)->uge(Num); - } - - /// getLimitedValue - If the value is smaller than the specified limit, - /// return it, otherwise return the limit value. This causes the value - /// to saturate to the limit. - /// @returns the min of the value of the constant and the specified value - /// Get the constant's value with a saturation limit - uint64_t getLimitedValue(uint64_t Limit = ~0ULL) const { - return cast(Val)->getLimitedValue(Limit); - } - - /// For isa/dyn_cast. - static bool classof(const sandboxir::Value *From) { - return From->getSubclassID() == ClassID::ConstantInt; - } - unsigned getUseOperandNo(const Use &Use) const override { - llvm_unreachable("ConstantInt has no operands!"); - } -#ifndef NDEBUG - void verify() const override { - assert(isa(Val) && "Expected a ConstantInst!"); - } - void dumpOS(raw_ostream &OS) const override { - dumpCommonPrefix(OS); - dumpCommonSuffix(OS); - } -#endif -}; - -// TODO: This should inherit from ConstantData. -class ConstantFP final : public Constant { - ConstantFP(llvm::ConstantFP *C, Context &Ctx) - : Constant(ClassID::ConstantFP, C, Ctx) {} - friend class Context; // For constructor. - -public: - /// This returns a ConstantFP, or a vector containing a splat of a ConstantFP, - /// for the specified value in the specified type. This should only be used - /// for simple constant values like 2.0/1.0 etc, that are known-valid both as - /// host double and as the target format. - static Constant *get(Type *Ty, double V); - - /// If Ty is a vector type, return a Constant with a splat of the given - /// value. Otherwise return a ConstantFP for the given value. - static Constant *get(Type *Ty, const APFloat &V); - - static Constant *get(Type *Ty, StringRef Str); - - static ConstantFP *get(const APFloat &V, Context &Ctx); - - static Constant *getNaN(Type *Ty, bool Negative = false, - uint64_t Payload = 0); - static Constant *getQNaN(Type *Ty, bool Negative = false, - APInt *Payload = nullptr); - static Constant *getSNaN(Type *Ty, bool Negative = false, - APInt *Payload = nullptr); - static Constant *getZero(Type *Ty, bool Negative = false); - - static Constant *getNegativeZero(Type *Ty); - static Constant *getInfinity(Type *Ty, bool Negative = false); - - /// Return true if Ty is big enough to represent V. - static bool isValueValidForType(Type *Ty, const APFloat &V); - - inline const APFloat &getValueAPF() const { - return cast(Val)->getValueAPF(); - } - inline const APFloat &getValue() const { - return cast(Val)->getValue(); - } - - /// Return true if the value is positive or negative zero. - bool isZero() const { return cast(Val)->isZero(); } - - /// Return true if the sign bit is set. - bool isNegative() const { return cast(Val)->isNegative(); } - - /// Return true if the value is infinity - bool isInfinity() const { return cast(Val)->isInfinity(); } - - /// Return true if the value is a NaN. - bool isNaN() const { return cast(Val)->isNaN(); } - - /// We don't rely on operator== working on double values, as it returns true - /// for things that are clearly not equal, like -0.0 and 0.0. - /// As such, this method can be used to do an exact bit-for-bit comparison of - /// two floating point values. The version with a double operand is retained - /// because it's so convenient to write isExactlyValue(2.0), but please use - /// it only for simple constants. - bool isExactlyValue(const APFloat &V) const { - return cast(Val)->isExactlyValue(V); - } - - bool isExactlyValue(double V) const { - return cast(Val)->isExactlyValue(V); - } - - /// For isa/dyn_cast. - static bool classof(const sandboxir::Value *From) { - return From->getSubclassID() == ClassID::ConstantFP; - } - - // TODO: Better name: getOperandNo(const Use&). Should be private. - unsigned getUseOperandNo(const Use &Use) const final { - llvm_unreachable("ConstantFP has no operands!"); - } -#ifndef NDEBUG - void verify() const override { - assert(isa(Val) && "Expected a ConstantFP!"); - } - void dumpOS(raw_ostream &OS) const override { - dumpCommonPrefix(OS); - dumpCommonSuffix(OS); - } -#endif -}; - -/// Base class for aggregate constants (with operands). -class ConstantAggregate : public Constant { -protected: - ConstantAggregate(ClassID ID, llvm::Constant *C, Context &Ctx) - : Constant(ID, C, Ctx) {} - -public: - /// For isa/dyn_cast. - static bool classof(const sandboxir::Value *From) { - auto ID = From->getSubclassID(); - return ID == ClassID::ConstantVector || ID == ClassID::ConstantStruct || - ID == ClassID::ConstantArray; - } -}; - -class ConstantArray final : public ConstantAggregate { - ConstantArray(llvm::ConstantArray *C, Context &Ctx) - : ConstantAggregate(ClassID::ConstantArray, C, Ctx) {} - friend class Context; // For constructor. - -public: - static Constant *get(ArrayType *T, ArrayRef V); - ArrayType *getType() const; - - // TODO: Missing functions: getType(), getTypeForElements(), getAnon(), get(). - - /// For isa/dyn_cast. - static bool classof(const Value *From) { - return From->getSubclassID() == ClassID::ConstantArray; - } -}; - -class ConstantStruct final : public ConstantAggregate { - ConstantStruct(llvm::ConstantStruct *C, Context &Ctx) - : ConstantAggregate(ClassID::ConstantStruct, C, Ctx) {} - friend class Context; // For constructor. - -public: - static Constant *get(StructType *T, ArrayRef V); - - template - static std::enable_if_t::value, Constant *> - get(StructType *T, Csts *...Vs) { - return get(T, ArrayRef({Vs...})); - } - /// Return an anonymous struct that has the specified elements. - /// If the struct is possibly empty, then you must specify a context. - static Constant *getAnon(ArrayRef V, bool Packed = false) { - return get(getTypeForElements(V, Packed), V); - } - static Constant *getAnon(Context &Ctx, ArrayRef V, - bool Packed = false) { - return get(getTypeForElements(Ctx, V, Packed), V); - } - /// This version of the method allows an empty list. - static StructType *getTypeForElements(Context &Ctx, ArrayRef V, - bool Packed = false); - /// Return an anonymous struct type to use for a constant with the specified - /// set of elements. The list must not be empty. - static StructType *getTypeForElements(ArrayRef V, - bool Packed = false) { - assert(!V.empty() && - "ConstantStruct::getTypeForElements cannot be called on empty list"); - return getTypeForElements(V[0]->getContext(), V, Packed); - } - - /// Specialization - reduce amount of casting. - inline StructType *getType() const { - return cast(Value::getType()); - } - - /// For isa/dyn_cast. - static bool classof(const Value *From) { - return From->getSubclassID() == ClassID::ConstantStruct; - } -}; - -class ConstantVector final : public ConstantAggregate { - ConstantVector(llvm::ConstantVector *C, Context &Ctx) - : ConstantAggregate(ClassID::ConstantVector, C, Ctx) {} - friend class Context; // For constructor. - -public: - // TODO: Missing functions: getSplat(), getType(), getSplatValue(), get(). - - /// For isa/dyn_cast. - static bool classof(const Value *From) { - return From->getSubclassID() == ClassID::ConstantVector; - } -}; - -// TODO: Inherit from ConstantData. -class ConstantAggregateZero final : public Constant { - ConstantAggregateZero(llvm::ConstantAggregateZero *C, Context &Ctx) - : Constant(ClassID::ConstantAggregateZero, C, Ctx) {} - friend class Context; // For constructor. - -public: - static ConstantAggregateZero *get(Type *Ty); - /// If this CAZ has array or vector type, return a zero with the right element - /// type. - Constant *getSequentialElement() const; - /// If this CAZ has struct type, return a zero with the right element type for - /// the specified element. - Constant *getStructElement(unsigned Elt) const; - /// Return a zero of the right value for the specified GEP index if we can, - /// otherwise return null (e.g. if C is a ConstantExpr). - Constant *getElementValue(Constant *C) const; - /// Return a zero of the right value for the specified GEP index. - Constant *getElementValue(unsigned Idx) const; - /// Return the number of elements in the array, vector, or struct. - ElementCount getElementCount() const { - return cast(Val)->getElementCount(); - } - - /// For isa/dyn_cast. - static bool classof(const sandboxir::Value *From) { - return From->getSubclassID() == ClassID::ConstantAggregateZero; - } - unsigned getUseOperandNo(const Use &Use) const final { - llvm_unreachable("ConstantAggregateZero has no operands!"); - } -#ifndef NDEBUG - void verify() const override { - assert(isa(Val) && "Expected a CAZ!"); - } - void dumpOS(raw_ostream &OS) const override { - dumpCommonPrefix(OS); - dumpCommonSuffix(OS); - } -#endif -}; - -// TODO: Inherit from ConstantData. -class ConstantPointerNull final : public Constant { - ConstantPointerNull(llvm::ConstantPointerNull *C, Context &Ctx) - : Constant(ClassID::ConstantPointerNull, C, Ctx) {} - friend class Context; // For constructor. - -public: - static ConstantPointerNull *get(PointerType *Ty); - - PointerType *getType() const; - - /// For isa/dyn_cast. - static bool classof(const sandboxir::Value *From) { - return From->getSubclassID() == ClassID::ConstantPointerNull; - } - unsigned getUseOperandNo(const Use &Use) const final { - llvm_unreachable("ConstantPointerNull has no operands!"); - } -#ifndef NDEBUG - void verify() const override { - assert(isa(Val) && "Expected a CPNull!"); - } - void dumpOS(raw_ostream &OS) const override { - dumpCommonPrefix(OS); - dumpCommonSuffix(OS); - } -#endif -}; - -// TODO: Inherit from ConstantData. -class UndefValue : public Constant { -protected: - UndefValue(llvm::UndefValue *C, Context &Ctx) - : Constant(ClassID::UndefValue, C, Ctx) {} - UndefValue(ClassID ID, llvm::Constant *C, Context &Ctx) - : Constant(ID, C, Ctx) {} - friend class Context; // For constructor. - -public: - /// Static factory methods - Return an 'undef' object of the specified type. - static UndefValue *get(Type *T); - - /// If this Undef has array or vector type, return a undef with the right - /// element type. - UndefValue *getSequentialElement() const; - - /// If this undef has struct type, return a undef with the right element type - /// for the specified element. - UndefValue *getStructElement(unsigned Elt) const; - - /// Return an undef of the right value for the specified GEP index if we can, - /// otherwise return null (e.g. if C is a ConstantExpr). - UndefValue *getElementValue(Constant *C) const; - - /// Return an undef of the right value for the specified GEP index. - UndefValue *getElementValue(unsigned Idx) const; - - /// Return the number of elements in the array, vector, or struct. - unsigned getNumElements() const { - return cast(Val)->getNumElements(); - } - - /// For isa/dyn_cast. - static bool classof(const sandboxir::Value *From) { - return From->getSubclassID() == ClassID::UndefValue || - From->getSubclassID() == ClassID::PoisonValue; - } - unsigned getUseOperandNo(const Use &Use) const final { - llvm_unreachable("UndefValue has no operands!"); - } -#ifndef NDEBUG - void verify() const override { - assert(isa(Val) && "Expected an UndefValue!"); - } - void dumpOS(raw_ostream &OS) const override { - dumpCommonPrefix(OS); - dumpCommonSuffix(OS); - } -#endif -}; - -class PoisonValue final : public UndefValue { - PoisonValue(llvm::PoisonValue *C, Context &Ctx) - : UndefValue(ClassID::PoisonValue, C, Ctx) {} - friend class Context; // For constructor. - -public: - /// Static factory methods - Return an 'poison' object of the specified type. - static PoisonValue *get(Type *T); - - /// If this poison has array or vector type, return a poison with the right - /// element type. - PoisonValue *getSequentialElement() const; - - /// If this poison has struct type, return a poison with the right element - /// type for the specified element. - PoisonValue *getStructElement(unsigned Elt) const; - - /// Return an poison of the right value for the specified GEP index if we can, - /// otherwise return null (e.g. if C is a ConstantExpr). - PoisonValue *getElementValue(Constant *C) const; - - /// Return an poison of the right value for the specified GEP index. - PoisonValue *getElementValue(unsigned Idx) const; - - /// For isa/dyn_cast. - static bool classof(const sandboxir::Value *From) { - return From->getSubclassID() == ClassID::PoisonValue; - } -#ifndef NDEBUG - void verify() const override { - assert(isa(Val) && "Expected a PoisonValue!"); - } - void dumpOS(raw_ostream &OS) const override { - dumpCommonPrefix(OS); - dumpCommonSuffix(OS); - } -#endif -}; - -class GlobalValue : public Constant { -protected: - GlobalValue(ClassID ID, llvm::GlobalValue *C, Context &Ctx) - : Constant(ID, C, Ctx) {} - friend class Context; // For constructor. - -public: - using LinkageTypes = llvm::GlobalValue::LinkageTypes; - /// For isa/dyn_cast. - static bool classof(const sandboxir::Value *From) { - switch (From->getSubclassID()) { - case ClassID::Function: - case ClassID::GlobalVariable: - case ClassID::GlobalAlias: - case ClassID::GlobalIFunc: - return true; - default: - return false; - } - } - - unsigned getAddressSpace() const { - return cast(Val)->getAddressSpace(); - } - bool hasGlobalUnnamedAddr() const { - return cast(Val)->hasGlobalUnnamedAddr(); - } - - /// Returns true if this value's address is not significant in this module. - /// This attribute is intended to be used only by the code generator and LTO - /// to allow the linker to decide whether the global needs to be in the symbol - /// table. It should probably not be used in optimizations, as the value may - /// have uses outside the module; use hasGlobalUnnamedAddr() instead. - bool hasAtLeastLocalUnnamedAddr() const { - return cast(Val)->hasAtLeastLocalUnnamedAddr(); - } - - using UnnamedAddr = llvm::GlobalValue::UnnamedAddr; - - UnnamedAddr getUnnamedAddr() const { - return cast(Val)->getUnnamedAddr(); - } - void setUnnamedAddr(UnnamedAddr V); - - static UnnamedAddr getMinUnnamedAddr(UnnamedAddr A, UnnamedAddr B) { - return llvm::GlobalValue::getMinUnnamedAddr(A, B); - } - - bool hasComdat() const { return cast(Val)->hasComdat(); } - - // TODO: We need a SandboxIR Comdat if we want to implement getComdat(). - using VisibilityTypes = llvm::GlobalValue::VisibilityTypes; - VisibilityTypes getVisibility() const { - return cast(Val)->getVisibility(); - } - bool hasDefaultVisibility() const { - return cast(Val)->hasDefaultVisibility(); - } - bool hasHiddenVisibility() const { - return cast(Val)->hasHiddenVisibility(); - } - bool hasProtectedVisibility() const { - return cast(Val)->hasProtectedVisibility(); - } - void setVisibility(VisibilityTypes V); - - // TODO: Add missing functions. -}; - -class GlobalObject : public GlobalValue { -protected: - GlobalObject(ClassID ID, llvm::GlobalObject *C, Context &Ctx) - : GlobalValue(ID, C, Ctx) {} - friend class Context; // For constructor. - Use getOperandUseInternal(unsigned OpIdx, bool Verify) const final { - return getOperandUseDefault(OpIdx, Verify); - } - -public: - unsigned getUseOperandNo(const Use &Use) const final { - return getUseOperandNoDefault(Use); - } - /// For isa/dyn_cast. - static bool classof(const sandboxir::Value *From) { - switch (From->getSubclassID()) { - case ClassID::Function: - case ClassID::GlobalVariable: - case ClassID::GlobalIFunc: - return true; - default: - return false; - } - } - - /// FIXME: Remove this function once transition to Align is over. - uint64_t getAlignment() const { - return cast(Val)->getAlignment(); - } - - /// Returns the alignment of the given variable or function. - /// - /// Note that for functions this is the alignment of the code, not the - /// alignment of a function pointer. - MaybeAlign getAlign() const { - return cast(Val)->getAlign(); - } - - // TODO: Add missing: setAlignment(Align) - - /// Sets the alignment attribute of the GlobalObject. - /// This method will be deprecated as the alignment property should always be - /// defined. - void setAlignment(MaybeAlign Align); - - unsigned getGlobalObjectSubClassData() const { - return cast(Val)->getGlobalObjectSubClassData(); - } - - void setGlobalObjectSubClassData(unsigned V); - - /// Check if this global has a custom object file section. - /// - /// This is more efficient than calling getSection() and checking for an empty - /// string. - bool hasSection() const { - return cast(Val)->hasSection(); - } - - /// Get the custom section of this global if it has one. - /// - /// If this global does not have a custom section, this will be empty and the - /// default object file section (.text, .data, etc) will be used. - StringRef getSection() const { - return cast(Val)->getSection(); - } - - /// Change the section for this global. - /// - /// Setting the section to the empty string tells LLVM to choose an - /// appropriate default object file section. - void setSection(StringRef S); - - bool hasComdat() const { return cast(Val)->hasComdat(); } - - // TODO: implement get/setComdat(), etc. once we have a sandboxir::Comdat. - - // TODO: We currently don't support Metadata in sandboxir so all - // Metadata-related functions are missing. - - using VCallVisibility = llvm::GlobalObject::VCallVisibility; - - VCallVisibility getVCallVisibility() const { - return cast(Val)->getVCallVisibility(); - } - - /// Returns true if the alignment of the value can be unilaterally - /// increased. - /// - /// Note that for functions this is the alignment of the code, not the - /// alignment of a function pointer. - bool canIncreaseAlignment() const { - return cast(Val)->canIncreaseAlignment(); - } -}; - -/// Provides API functions, like getIterator() and getReverseIterator() to -/// GlobalIFunc, Function, GlobalVariable and GlobalAlias. In LLVM IR these are -/// provided by ilist_node. -template -class GlobalWithNodeAPI : public ParentT { - /// Helper for mapped_iterator. - struct LLVMGVToGV { - Context &Ctx; - LLVMGVToGV(Context &Ctx) : Ctx(Ctx) {} - GlobalT &operator()(LLVMGlobalT &LLVMGV) const; - }; - -public: - GlobalWithNodeAPI(Value::ClassID ID, LLVMParentT *C, Context &Ctx) - : ParentT(ID, C, Ctx) {} - - Module *getParent() const { - llvm::Module *LLVMM = cast(this->Val)->getParent(); - return this->Ctx.getModule(LLVMM); - } - - using iterator = mapped_iterator< - decltype(static_cast(nullptr)->getIterator()), LLVMGVToGV>; - using reverse_iterator = mapped_iterator< - decltype(static_cast(nullptr)->getReverseIterator()), - LLVMGVToGV>; - iterator getIterator() const { - auto *LLVMGV = cast(this->Val); - LLVMGVToGV ToGV(this->Ctx); - return map_iterator(LLVMGV->getIterator(), ToGV); - } - reverse_iterator getReverseIterator() const { - auto *LLVMGV = cast(this->Val); - LLVMGVToGV ToGV(this->Ctx); - return map_iterator(LLVMGV->getReverseIterator(), ToGV); - } -}; - -class GlobalIFunc final - : public GlobalWithNodeAPI { - GlobalIFunc(llvm::GlobalObject *C, Context &Ctx) - : GlobalWithNodeAPI(ClassID::GlobalIFunc, C, Ctx) {} - friend class Context; // For constructor. - -public: - /// For isa/dyn_cast. - static bool classof(const sandboxir::Value *From) { - return From->getSubclassID() == ClassID::GlobalIFunc; - } - - // TODO: Missing create() because we don't have a sandboxir::Module yet. - - // TODO: Missing functions: copyAttributesFrom(), removeFromParent(), - // eraseFromParent() - - void setResolver(Constant *Resolver); - - Constant *getResolver() const; - - // Return the resolver function after peeling off potential ConstantExpr - // indirection. - Function *getResolverFunction(); - const Function *getResolverFunction() const { - return const_cast(this)->getResolverFunction(); - } - - static bool isValidLinkage(LinkageTypes L) { - return llvm::GlobalIFunc::isValidLinkage(L); - } - - // TODO: Missing applyAlongResolverPath(). - -#ifndef NDEBUG - void verify() const override { - assert(isa(Val) && "Expected a GlobalIFunc!"); - } - void dumpOS(raw_ostream &OS) const override { - dumpCommonPrefix(OS); - dumpCommonSuffix(OS); - } -#endif -}; - -class GlobalVariable final - : public GlobalWithNodeAPI { - GlobalVariable(llvm::GlobalObject *C, Context &Ctx) - : GlobalWithNodeAPI(ClassID::GlobalVariable, C, Ctx) {} - friend class Context; // For constructor. - - /// Helper for mapped_iterator. - struct LLVMGVToGV { - Context &Ctx; - LLVMGVToGV(Context &Ctx) : Ctx(Ctx) {} - GlobalVariable &operator()(llvm::GlobalVariable &LLVMGV) const; - }; - -public: - /// For isa/dyn_cast. - static bool classof(const sandboxir::Value *From) { - return From->getSubclassID() == ClassID::GlobalVariable; - } - - /// Definitions have initializers, declarations don't. - /// - inline bool hasInitializer() const { - return cast(Val)->hasInitializer(); - } - - /// hasDefinitiveInitializer - Whether the global variable has an initializer, - /// and any other instances of the global (this can happen due to weak - /// linkage) are guaranteed to have the same initializer. - /// - /// Note that if you want to transform a global, you must use - /// hasUniqueInitializer() instead, because of the *_odr linkage type. - /// - /// Example: - /// - /// @a = global SomeType* null - Initializer is both definitive and unique. - /// - /// @b = global weak SomeType* null - Initializer is neither definitive nor - /// unique. - /// - /// @c = global weak_odr SomeType* null - Initializer is definitive, but not - /// unique. - inline bool hasDefinitiveInitializer() const { - return cast(Val)->hasDefinitiveInitializer(); - } - - /// hasUniqueInitializer - Whether the global variable has an initializer, and - /// any changes made to the initializer will turn up in the final executable. - inline bool hasUniqueInitializer() const { - return cast(Val)->hasUniqueInitializer(); - } - - /// getInitializer - Return the initializer for this global variable. It is - /// illegal to call this method if the global is external, because we cannot - /// tell what the value is initialized to! - /// - Constant *getInitializer() const; - /// setInitializer - Sets the initializer for this global variable, removing - /// any existing initializer if InitVal==NULL. The initializer must have the - /// type getValueType(). - void setInitializer(Constant *InitVal); - - // TODO: Add missing replaceInitializer(). Requires special tracker - - /// If the value is a global constant, its value is immutable throughout the - /// runtime execution of the program. Assigning a value into the constant - /// leads to undefined behavior. - /// - bool isConstant() const { - return cast(Val)->isConstant(); - } - void setConstant(bool V); - - bool isExternallyInitialized() const { - return cast(Val)->isExternallyInitialized(); - } - void setExternallyInitialized(bool Val); - - // TODO: Missing copyAttributesFrom() - - // TODO: Missing removeFromParent(), eraseFromParent(), dropAllReferences() - - // TODO: Missing addDebugInfo(), getDebugInfo() - - // TODO: Missing attribute setter functions: addAttribute(), setAttributes(). - // There seems to be no removeAttribute() so we can't undo them. - - /// Return true if the attribute exists. - bool hasAttribute(Attribute::AttrKind Kind) const { - return cast(Val)->hasAttribute(Kind); - } - - /// Return true if the attribute exists. - bool hasAttribute(StringRef Kind) const { - return cast(Val)->hasAttribute(Kind); - } - - /// Return true if any attributes exist. - bool hasAttributes() const { - return cast(Val)->hasAttributes(); - } - - /// Return the attribute object. - Attribute getAttribute(Attribute::AttrKind Kind) const { - return cast(Val)->getAttribute(Kind); - } - - /// Return the attribute object. - Attribute getAttribute(StringRef Kind) const { - return cast(Val)->getAttribute(Kind); - } - - /// Return the attribute set for this global - AttributeSet getAttributes() const { - return cast(Val)->getAttributes(); - } - - /// Return attribute set as list with index. - /// FIXME: This may not be required once ValueEnumerators - /// in bitcode-writer can enumerate attribute-set. - AttributeList getAttributesAsList(unsigned Index) const { - return cast(Val)->getAttributesAsList(Index); - } - - /// Check if section name is present - bool hasImplicitSection() const { - return cast(Val)->hasImplicitSection(); - } - - /// Get the custom code model raw value of this global. - /// - unsigned getCodeModelRaw() const { - return cast(Val)->getCodeModelRaw(); - } - - /// Get the custom code model of this global if it has one. - /// - /// If this global does not have a custom code model, the empty instance - /// will be returned. - std::optional getCodeModel() const { - return cast(Val)->getCodeModel(); - } - - // TODO: Missing setCodeModel(). Requires custom tracker. - -#ifndef NDEBUG - void verify() const override { - assert(isa(Val) && "Expected a GlobalVariable!"); - } - void dumpOS(raw_ostream &OS) const override { - dumpCommonPrefix(OS); - dumpCommonSuffix(OS); - } -#endif -}; - -class GlobalAlias final - : public GlobalWithNodeAPI { - GlobalAlias(llvm::GlobalAlias *C, Context &Ctx) - : GlobalWithNodeAPI(ClassID::GlobalAlias, C, Ctx) {} - friend class Context; // For constructor. - -public: - /// For isa/dyn_cast. - static bool classof(const sandboxir::Value *From) { - return From->getSubclassID() == ClassID::GlobalAlias; - } - - // TODO: Missing create() due to unimplemented sandboxir::Module. - - // TODO: Missing copyAttributresFrom(). - // TODO: Missing removeFromParent(), eraseFromParent(). - - void setAliasee(Constant *Aliasee); - Constant *getAliasee() const; - - const GlobalObject *getAliaseeObject() const; - GlobalObject *getAliaseeObject() { - return const_cast( - static_cast(this)->getAliaseeObject()); - } - - static bool isValidLinkage(LinkageTypes L) { - return llvm::GlobalAlias::isValidLinkage(L); - } -}; - -class NoCFIValue final : public Constant { - NoCFIValue(llvm::NoCFIValue *C, Context &Ctx) - : Constant(ClassID::NoCFIValue, C, Ctx) {} - friend class Context; // For constructor. - - Use getOperandUseInternal(unsigned OpIdx, bool Verify) const final { - return getOperandUseDefault(OpIdx, Verify); - } - -public: - /// Return a NoCFIValue for the specified function. - static NoCFIValue *get(GlobalValue *GV); - - GlobalValue *getGlobalValue() const; - - /// NoCFIValue is always a pointer. - PointerType *getType() const; - /// For isa/dyn_cast. - static bool classof(const sandboxir::Value *From) { - return From->getSubclassID() == ClassID::NoCFIValue; - } - - unsigned getUseOperandNo(const Use &Use) const final { - return getUseOperandNoDefault(Use); - } - -#ifndef NDEBUG - void verify() const override { - assert(isa(Val) && "Expected a NoCFIValue!"); - } - void dumpOS(raw_ostream &OS) const override { - dumpCommonPrefix(OS); - dumpCommonSuffix(OS); - } -#endif -}; - -class ConstantPtrAuth final : public Constant { - ConstantPtrAuth(llvm::ConstantPtrAuth *C, Context &Ctx) - : Constant(ClassID::ConstantPtrAuth, C, Ctx) {} - friend class Context; // For constructor. - -public: - /// Return a pointer signed with the specified parameters. - static ConstantPtrAuth *get(Constant *Ptr, ConstantInt *Key, - ConstantInt *Disc, Constant *AddrDisc); - /// The pointer that is signed in this ptrauth signed pointer. - Constant *getPointer() const; - - /// The Key ID, an i32 constant. - ConstantInt *getKey() const; - - /// The integer discriminator, an i64 constant, or 0. - ConstantInt *getDiscriminator() const; - - /// The address discriminator if any, or the null constant. - /// If present, this must be a value equivalent to the storage location of - /// the only global-initializer user of the ptrauth signed pointer. - Constant *getAddrDiscriminator() const; - - /// Whether there is any non-null address discriminator. - bool hasAddressDiscriminator() const { - return cast(Val)->hasAddressDiscriminator(); - } - - /// Whether the address uses a special address discriminator. - /// These discriminators can't be used in real pointer-auth values; they - /// can only be used in "prototype" values that indicate how some real - /// schema is supposed to be produced. - bool hasSpecialAddressDiscriminator(uint64_t Value) const { - return cast(Val)->hasSpecialAddressDiscriminator( - Value); - } - - /// Check whether an authentication operation with key \p Key and (possibly - /// blended) discriminator \p Discriminator is known to be compatible with - /// this ptrauth signed pointer. - bool isKnownCompatibleWith(const Value *Key, const Value *Discriminator, - const DataLayout &DL) const { - return cast(Val)->isKnownCompatibleWith( - Key->Val, Discriminator->Val, DL); - } - - /// Produce a new ptrauth expression signing the given value using - /// the same schema as is stored in one. - ConstantPtrAuth *getWithSameSchema(Constant *Pointer) const; - - /// For isa/dyn_cast. - static bool classof(const sandboxir::Value *From) { - return From->getSubclassID() == ClassID::ConstantPtrAuth; - } -}; - -class ConstantExpr : public Constant { - ConstantExpr(llvm::ConstantExpr *C, Context &Ctx) - : Constant(ClassID::ConstantExpr, C, Ctx) {} - friend class Context; // For constructor. - -public: - /// For isa/dyn_cast. - static bool classof(const sandboxir::Value *From) { - return From->getSubclassID() == ClassID::ConstantExpr; - } - // TODO: Missing functions. -}; - -class BlockAddress final : public Constant { - BlockAddress(llvm::BlockAddress *C, Context &Ctx) - : Constant(ClassID::BlockAddress, C, Ctx) {} - friend class Context; // For constructor. - -public: - /// Return a BlockAddress for the specified function and basic block. - static BlockAddress *get(Function *F, BasicBlock *BB); - - /// Return a BlockAddress for the specified basic block. The basic - /// block must be embedded into a function. - static BlockAddress *get(BasicBlock *BB); - - /// Lookup an existing \c BlockAddress constant for the given BasicBlock. - /// - /// \returns 0 if \c !BB->hasAddressTaken(), otherwise the \c BlockAddress. - static BlockAddress *lookup(const BasicBlock *BB); - - Function *getFunction() const; - BasicBlock *getBasicBlock() const; - - /// For isa/dyn_cast. - static bool classof(const sandboxir::Value *From) { - return From->getSubclassID() == ClassID::BlockAddress; - } -}; - -class DSOLocalEquivalent final : public Constant { - DSOLocalEquivalent(llvm::DSOLocalEquivalent *C, Context &Ctx) - : Constant(ClassID::DSOLocalEquivalent, C, Ctx) {} - friend class Context; // For constructor. - -public: - /// Return a DSOLocalEquivalent for the specified global value. - static DSOLocalEquivalent *get(GlobalValue *GV); - - GlobalValue *getGlobalValue() const; - - /// For isa/dyn_cast. - static bool classof(const sandboxir::Value *From) { - return From->getSubclassID() == ClassID::DSOLocalEquivalent; - } - - unsigned getUseOperandNo(const Use &Use) const final { - llvm_unreachable("DSOLocalEquivalent has no operands!"); - } - -#ifndef NDEBUG - void verify() const override { - assert(isa(Val) && - "Expected a DSOLocalEquivalent!"); - } - void dumpOS(raw_ostream &OS) const override { - dumpCommonPrefix(OS); - dumpCommonSuffix(OS); - } -#endif -}; - -// TODO: This should inherit from ConstantData. -class ConstantTokenNone final : public Constant { - ConstantTokenNone(llvm::ConstantTokenNone *C, Context &Ctx) - : Constant(ClassID::ConstantTokenNone, C, Ctx) {} - friend class Context; // For constructor. - -public: - /// Return the ConstantTokenNone. - static ConstantTokenNone *get(Context &Ctx); - - /// For isa/dyn_cast. - static bool classof(const sandboxir::Value *From) { - return From->getSubclassID() == ClassID::ConstantTokenNone; - } - - unsigned getUseOperandNo(const Use &Use) const final { - llvm_unreachable("ConstantTokenNone has no operands!"); - } - -#ifndef NDEBUG - void verify() const override { - assert(isa(Val) && - "Expected a ConstantTokenNone!"); - } - void dumpOS(raw_ostream &OS) const override { - dumpCommonPrefix(OS); - dumpCommonSuffix(OS); - } -#endif -}; - /// Iterator for `Instruction`s in a `BasicBlock. /// \Returns an sandboxir::Instruction & when derereferenced. class BBIterator { @@ -4196,59 +2998,6 @@ class OpaqueInst : public SingleLLVMInstructionImpl { } }; -class Function : public GlobalWithNodeAPI { - /// Helper for mapped_iterator. - struct LLVMBBToBB { - Context &Ctx; - LLVMBBToBB(Context &Ctx) : Ctx(Ctx) {} - BasicBlock &operator()(llvm::BasicBlock &LLVMBB) const { - return *cast(Ctx.getValue(&LLVMBB)); - } - }; - /// Use Context::createFunction() instead. - Function(llvm::Function *F, sandboxir::Context &Ctx) - : GlobalWithNodeAPI(ClassID::Function, F, Ctx) {} - friend class Context; // For constructor. - -public: - /// For isa/dyn_cast. - static bool classof(const sandboxir::Value *From) { - return From->getSubclassID() == ClassID::Function; - } - - Module *getParent() { - return Ctx.getModule(cast(Val)->getParent()); - } - - Argument *getArg(unsigned Idx) const { - llvm::Argument *Arg = cast(Val)->getArg(Idx); - return cast(Ctx.getValue(Arg)); - } - - size_t arg_size() const { return cast(Val)->arg_size(); } - bool arg_empty() const { return cast(Val)->arg_empty(); } - - using iterator = mapped_iterator; - iterator begin() const { - LLVMBBToBB BBGetter(Ctx); - return iterator(cast(Val)->begin(), BBGetter); - } - iterator end() const { - LLVMBBToBB BBGetter(Ctx); - return iterator(cast(Val)->end(), BBGetter); - } - FunctionType *getFunctionType() const; - -#ifndef NDEBUG - void verify() const final { - assert(isa(Val) && "Expected Function!"); - } - void dumpNameAndArgs(raw_ostream &OS) const; - void dumpOS(raw_ostream &OS) const final; -#endif -}; - } // namespace sandboxir } // namespace llvm diff --git a/llvm/lib/SandboxIR/CMakeLists.txt b/llvm/lib/SandboxIR/CMakeLists.txt index d9259db970da5..52afeb395a9a0 100644 --- a/llvm/lib/SandboxIR/CMakeLists.txt +++ b/llvm/lib/SandboxIR/CMakeLists.txt @@ -1,5 +1,6 @@ add_llvm_component_library(LLVMSandboxIR Argument.cpp + Constant.cpp Context.cpp Module.cpp Pass.cpp diff --git a/llvm/lib/SandboxIR/Constant.cpp b/llvm/lib/SandboxIR/Constant.cpp new file mode 100644 index 0000000000000..83b33f72f19d4 --- /dev/null +++ b/llvm/lib/SandboxIR/Constant.cpp @@ -0,0 +1,509 @@ +//===- Constant.cpp - The Constant classes of Sandbox IR ------------------===// +// +// 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 "llvm/SandboxIR/Constant.h" +#include "llvm/SandboxIR/Context.h" +#include "llvm/SandboxIR/SandboxIR.h" // TODO: Try to remove this + +namespace llvm::sandboxir { + +#ifndef NDEBUG +void Constant::dumpOS(raw_ostream &OS) const { + dumpCommonPrefix(OS); + dumpCommonSuffix(OS); +} +#endif // NDEBUG + +ConstantInt *ConstantInt::getTrue(Context &Ctx) { + auto *LLVMC = llvm::ConstantInt::getTrue(Ctx.LLVMCtx); + return cast(Ctx.getOrCreateConstant(LLVMC)); +} +ConstantInt *ConstantInt::getFalse(Context &Ctx) { + auto *LLVMC = llvm::ConstantInt::getFalse(Ctx.LLVMCtx); + return cast(Ctx.getOrCreateConstant(LLVMC)); +} +ConstantInt *ConstantInt::getBool(Context &Ctx, bool V) { + auto *LLVMC = llvm::ConstantInt::getBool(Ctx.LLVMCtx, V); + return cast(Ctx.getOrCreateConstant(LLVMC)); +} +Constant *ConstantInt::getTrue(Type *Ty) { + auto *LLVMC = llvm::ConstantInt::getTrue(Ty->LLVMTy); + return Ty->getContext().getOrCreateConstant(LLVMC); +} +Constant *ConstantInt::getFalse(Type *Ty) { + auto *LLVMC = llvm::ConstantInt::getFalse(Ty->LLVMTy); + return Ty->getContext().getOrCreateConstant(LLVMC); +} +Constant *ConstantInt::getBool(Type *Ty, bool V) { + auto *LLVMC = llvm::ConstantInt::getBool(Ty->LLVMTy, V); + return Ty->getContext().getOrCreateConstant(LLVMC); +} +ConstantInt *ConstantInt::get(Type *Ty, uint64_t V, bool IsSigned) { + auto *LLVMC = llvm::ConstantInt::get(Ty->LLVMTy, V, IsSigned); + return cast(Ty->getContext().getOrCreateConstant(LLVMC)); +} +ConstantInt *ConstantInt::get(IntegerType *Ty, uint64_t V, bool IsSigned) { + auto *LLVMC = llvm::ConstantInt::get(Ty->LLVMTy, V, IsSigned); + return cast(Ty->getContext().getOrCreateConstant(LLVMC)); +} +ConstantInt *ConstantInt::getSigned(IntegerType *Ty, int64_t V) { + auto *LLVMC = + llvm::ConstantInt::getSigned(cast(Ty->LLVMTy), V); + return cast(Ty->getContext().getOrCreateConstant(LLVMC)); +} +Constant *ConstantInt::getSigned(Type *Ty, int64_t V) { + auto *LLVMC = llvm::ConstantInt::getSigned(Ty->LLVMTy, V); + return Ty->getContext().getOrCreateConstant(LLVMC); +} +ConstantInt *ConstantInt::get(Context &Ctx, const APInt &V) { + auto *LLVMC = llvm::ConstantInt::get(Ctx.LLVMCtx, V); + return cast(Ctx.getOrCreateConstant(LLVMC)); +} +ConstantInt *ConstantInt::get(IntegerType *Ty, StringRef Str, uint8_t Radix) { + auto *LLVMC = + llvm::ConstantInt::get(cast(Ty->LLVMTy), Str, Radix); + return cast(Ty->getContext().getOrCreateConstant(LLVMC)); +} +Constant *ConstantInt::get(Type *Ty, const APInt &V) { + auto *LLVMC = llvm::ConstantInt::get(Ty->LLVMTy, V); + return Ty->getContext().getOrCreateConstant(LLVMC); +} +IntegerType *ConstantInt::getIntegerType() const { + auto *LLVMTy = cast(Val)->getIntegerType(); + return cast(Ctx.getType(LLVMTy)); +} + +bool ConstantInt::isValueValidForType(Type *Ty, uint64_t V) { + return llvm::ConstantInt::isValueValidForType(Ty->LLVMTy, V); +} +bool ConstantInt::isValueValidForType(Type *Ty, int64_t V) { + return llvm::ConstantInt::isValueValidForType(Ty->LLVMTy, V); +} + +Constant *ConstantFP::get(Type *Ty, double V) { + auto *LLVMC = llvm::ConstantFP::get(Ty->LLVMTy, V); + return Ty->getContext().getOrCreateConstant(LLVMC); +} + +Constant *ConstantFP::get(Type *Ty, const APFloat &V) { + auto *LLVMC = llvm::ConstantFP::get(Ty->LLVMTy, V); + return Ty->getContext().getOrCreateConstant(LLVMC); +} + +Constant *ConstantFP::get(Type *Ty, StringRef Str) { + auto *LLVMC = llvm::ConstantFP::get(Ty->LLVMTy, Str); + return Ty->getContext().getOrCreateConstant(LLVMC); +} + +ConstantFP *ConstantFP::get(const APFloat &V, Context &Ctx) { + auto *LLVMC = llvm::ConstantFP::get(Ctx.LLVMCtx, V); + return cast(Ctx.getOrCreateConstant(LLVMC)); +} + +Constant *ConstantFP::getNaN(Type *Ty, bool Negative, uint64_t Payload) { + auto *LLVMC = llvm::ConstantFP::getNaN(Ty->LLVMTy, Negative, Payload); + return cast(Ty->getContext().getOrCreateConstant(LLVMC)); +} +Constant *ConstantFP::getQNaN(Type *Ty, bool Negative, APInt *Payload) { + auto *LLVMC = llvm::ConstantFP::getQNaN(Ty->LLVMTy, Negative, Payload); + return cast(Ty->getContext().getOrCreateConstant(LLVMC)); +} +Constant *ConstantFP::getSNaN(Type *Ty, bool Negative, APInt *Payload) { + auto *LLVMC = llvm::ConstantFP::getSNaN(Ty->LLVMTy, Negative, Payload); + return cast(Ty->getContext().getOrCreateConstant(LLVMC)); +} +Constant *ConstantFP::getZero(Type *Ty, bool Negative) { + auto *LLVMC = llvm::ConstantFP::getZero(Ty->LLVMTy, Negative); + return cast(Ty->getContext().getOrCreateConstant(LLVMC)); +} +Constant *ConstantFP::getNegativeZero(Type *Ty) { + auto *LLVMC = llvm::ConstantFP::getNegativeZero(Ty->LLVMTy); + return cast(Ty->getContext().getOrCreateConstant(LLVMC)); +} +Constant *ConstantFP::getInfinity(Type *Ty, bool Negative) { + auto *LLVMC = llvm::ConstantFP::getInfinity(Ty->LLVMTy, Negative); + return cast(Ty->getContext().getOrCreateConstant(LLVMC)); +} +bool ConstantFP::isValueValidForType(Type *Ty, const APFloat &V) { + return llvm::ConstantFP::isValueValidForType(Ty->LLVMTy, V); +} + +Constant *ConstantArray::get(ArrayType *T, ArrayRef V) { + auto &Ctx = T->getContext(); + SmallVector LLVMValues; + LLVMValues.reserve(V.size()); + for (auto *Elm : V) + LLVMValues.push_back(cast(Elm->Val)); + auto *LLVMC = + llvm::ConstantArray::get(cast(T->LLVMTy), LLVMValues); + return cast(Ctx.getOrCreateConstant(LLVMC)); +} + +ArrayType *ConstantArray::getType() const { + return cast( + Ctx.getType(cast(Val)->getType())); +} + +Constant *ConstantStruct::get(StructType *T, ArrayRef V) { + auto &Ctx = T->getContext(); + SmallVector LLVMValues; + LLVMValues.reserve(V.size()); + for (auto *Elm : V) + LLVMValues.push_back(cast(Elm->Val)); + auto *LLVMC = + llvm::ConstantStruct::get(cast(T->LLVMTy), LLVMValues); + return cast(Ctx.getOrCreateConstant(LLVMC)); +} + +StructType *ConstantStruct::getTypeForElements(Context &Ctx, + ArrayRef V, + bool Packed) { + unsigned VecSize = V.size(); + SmallVector EltTypes; + EltTypes.reserve(VecSize); + for (Constant *Elm : V) + EltTypes.push_back(Elm->getType()); + return StructType::get(Ctx, EltTypes, Packed); +} + +ConstantAggregateZero *ConstantAggregateZero::get(Type *Ty) { + auto *LLVMC = llvm::ConstantAggregateZero::get(Ty->LLVMTy); + return cast( + Ty->getContext().getOrCreateConstant(LLVMC)); +} + +Constant *ConstantAggregateZero::getSequentialElement() const { + return cast(Ctx.getValue( + cast(Val)->getSequentialElement())); +} +Constant *ConstantAggregateZero::getStructElement(unsigned Elt) const { + return cast(Ctx.getValue( + cast(Val)->getStructElement(Elt))); +} +Constant *ConstantAggregateZero::getElementValue(Constant *C) const { + return cast( + Ctx.getValue(cast(Val)->getElementValue( + cast(C->Val)))); +} +Constant *ConstantAggregateZero::getElementValue(unsigned Idx) const { + return cast(Ctx.getValue( + cast(Val)->getElementValue(Idx))); +} + +ConstantPointerNull *ConstantPointerNull::get(PointerType *Ty) { + auto *LLVMC = + llvm::ConstantPointerNull::get(cast(Ty->LLVMTy)); + return cast(Ty->getContext().getOrCreateConstant(LLVMC)); +} + +PointerType *ConstantPointerNull::getType() const { + return cast( + Ctx.getType(cast(Val)->getType())); +} + +UndefValue *UndefValue::get(Type *T) { + auto *LLVMC = llvm::UndefValue::get(T->LLVMTy); + return cast(T->getContext().getOrCreateConstant(LLVMC)); +} + +UndefValue *UndefValue::getSequentialElement() const { + return cast(Ctx.getOrCreateConstant( + cast(Val)->getSequentialElement())); +} + +UndefValue *UndefValue::getStructElement(unsigned Elt) const { + return cast(Ctx.getOrCreateConstant( + cast(Val)->getStructElement(Elt))); +} + +UndefValue *UndefValue::getElementValue(Constant *C) const { + return cast( + Ctx.getOrCreateConstant(cast(Val)->getElementValue( + cast(C->Val)))); +} + +UndefValue *UndefValue::getElementValue(unsigned Idx) const { + return cast(Ctx.getOrCreateConstant( + cast(Val)->getElementValue(Idx))); +} + +PoisonValue *PoisonValue::get(Type *T) { + auto *LLVMC = llvm::PoisonValue::get(T->LLVMTy); + return cast(T->getContext().getOrCreateConstant(LLVMC)); +} + +PoisonValue *PoisonValue::getSequentialElement() const { + return cast(Ctx.getOrCreateConstant( + cast(Val)->getSequentialElement())); +} + +PoisonValue *PoisonValue::getStructElement(unsigned Elt) const { + return cast(Ctx.getOrCreateConstant( + cast(Val)->getStructElement(Elt))); +} + +PoisonValue *PoisonValue::getElementValue(Constant *C) const { + return cast( + Ctx.getOrCreateConstant(cast(Val)->getElementValue( + cast(C->Val)))); +} + +PoisonValue *PoisonValue::getElementValue(unsigned Idx) const { + return cast(Ctx.getOrCreateConstant( + cast(Val)->getElementValue(Idx))); +} + +void GlobalObject::setAlignment(MaybeAlign Align) { + Ctx.getTracker() + .emplaceIfTracking< + GenericSetter<&GlobalObject::getAlign, &GlobalObject::setAlignment>>( + this); + cast(Val)->setAlignment(Align); +} + +void GlobalObject::setGlobalObjectSubClassData(unsigned V) { + Ctx.getTracker() + .emplaceIfTracking< + GenericSetter<&GlobalObject::getGlobalObjectSubClassData, + &GlobalObject::setGlobalObjectSubClassData>>(this); + cast(Val)->setGlobalObjectSubClassData(V); +} + +void GlobalObject::setSection(StringRef S) { + Ctx.getTracker() + .emplaceIfTracking< + GenericSetter<&GlobalObject::getSection, &GlobalObject::setSection>>( + this); + cast(Val)->setSection(S); +} + +template +GlobalT &GlobalWithNodeAPI:: + LLVMGVToGV::operator()(LLVMGlobalT &LLVMGV) const { + return cast(*Ctx.getValue(&LLVMGV)); +} + +// Explicit instantiations. +template class GlobalWithNodeAPI; +template class GlobalWithNodeAPI; +template class GlobalWithNodeAPI; +template class GlobalWithNodeAPI; + +void GlobalIFunc::setResolver(Constant *Resolver) { + Ctx.getTracker() + .emplaceIfTracking< + GenericSetter<&GlobalIFunc::getResolver, &GlobalIFunc::setResolver>>( + this); + cast(Val)->setResolver( + cast(Resolver->Val)); +} + +Constant *GlobalIFunc::getResolver() const { + return Ctx.getOrCreateConstant(cast(Val)->getResolver()); +} + +Function *GlobalIFunc::getResolverFunction() { + return cast(Ctx.getOrCreateConstant( + cast(Val)->getResolverFunction())); +} + +GlobalVariable & +GlobalVariable::LLVMGVToGV::operator()(llvm::GlobalVariable &LLVMGV) const { + return cast(*Ctx.getValue(&LLVMGV)); +} + +Constant *GlobalVariable::getInitializer() const { + return Ctx.getOrCreateConstant( + cast(Val)->getInitializer()); +} + +void GlobalVariable::setInitializer(Constant *InitVal) { + Ctx.getTracker() + .emplaceIfTracking>(this); + cast(Val)->setInitializer( + cast(InitVal->Val)); +} + +void GlobalVariable::setConstant(bool V) { + Ctx.getTracker() + .emplaceIfTracking>(this); + cast(Val)->setConstant(V); +} + +void GlobalVariable::setExternallyInitialized(bool V) { + Ctx.getTracker() + .emplaceIfTracking< + GenericSetter<&GlobalVariable::isExternallyInitialized, + &GlobalVariable::setExternallyInitialized>>(this); + cast(Val)->setExternallyInitialized(V); +} + +void GlobalAlias::setAliasee(Constant *Aliasee) { + Ctx.getTracker() + .emplaceIfTracking< + GenericSetter<&GlobalAlias::getAliasee, &GlobalAlias::setAliasee>>( + this); + cast(Val)->setAliasee(cast(Aliasee->Val)); +} + +Constant *GlobalAlias::getAliasee() const { + return cast( + Ctx.getOrCreateConstant(cast(Val)->getAliasee())); +} + +const GlobalObject *GlobalAlias::getAliaseeObject() const { + return cast(Ctx.getOrCreateConstant( + cast(Val)->getAliaseeObject())); +} + +void GlobalValue::setUnnamedAddr(UnnamedAddr V) { + Ctx.getTracker() + .emplaceIfTracking>(this); + cast(Val)->setUnnamedAddr(V); +} + +void GlobalValue::setVisibility(VisibilityTypes V) { + Ctx.getTracker() + .emplaceIfTracking>(this); + cast(Val)->setVisibility(V); +} + +NoCFIValue *NoCFIValue::get(GlobalValue *GV) { + auto *LLVMC = llvm::NoCFIValue::get(cast(GV->Val)); + return cast(GV->getContext().getOrCreateConstant(LLVMC)); +} + +GlobalValue *NoCFIValue::getGlobalValue() const { + auto *LLVMC = cast(Val)->getGlobalValue(); + return cast(Ctx.getOrCreateConstant(LLVMC)); +} + +PointerType *NoCFIValue::getType() const { + return cast(Ctx.getType(cast(Val)->getType())); +} + +ConstantPtrAuth *ConstantPtrAuth::get(Constant *Ptr, ConstantInt *Key, + ConstantInt *Disc, Constant *AddrDisc) { + auto *LLVMC = llvm::ConstantPtrAuth::get( + cast(Ptr->Val), cast(Key->Val), + cast(Disc->Val), cast(AddrDisc->Val)); + return cast(Ptr->getContext().getOrCreateConstant(LLVMC)); +} + +Constant *ConstantPtrAuth::getPointer() const { + return Ctx.getOrCreateConstant( + cast(Val)->getPointer()); +} + +ConstantInt *ConstantPtrAuth::getKey() const { + return cast( + Ctx.getOrCreateConstant(cast(Val)->getKey())); +} + +ConstantInt *ConstantPtrAuth::getDiscriminator() const { + return cast(Ctx.getOrCreateConstant( + cast(Val)->getDiscriminator())); +} + +Constant *ConstantPtrAuth::getAddrDiscriminator() const { + return Ctx.getOrCreateConstant( + cast(Val)->getAddrDiscriminator()); +} + +ConstantPtrAuth *ConstantPtrAuth::getWithSameSchema(Constant *Pointer) const { + auto *LLVMC = cast(Val)->getWithSameSchema( + cast(Pointer->Val)); + return cast(Ctx.getOrCreateConstant(LLVMC)); +} + +BlockAddress *BlockAddress::get(Function *F, BasicBlock *BB) { + auto *LLVMC = llvm::BlockAddress::get(cast(F->Val), + cast(BB->Val)); + return cast(F->getContext().getOrCreateConstant(LLVMC)); +} + +BlockAddress *BlockAddress::get(BasicBlock *BB) { + auto *LLVMC = llvm::BlockAddress::get(cast(BB->Val)); + return cast(BB->getContext().getOrCreateConstant(LLVMC)); +} + +BlockAddress *BlockAddress::lookup(const BasicBlock *BB) { + auto *LLVMC = llvm::BlockAddress::lookup(cast(BB->Val)); + return cast_or_null(BB->getContext().getValue(LLVMC)); +} + +Function *BlockAddress::getFunction() const { + return cast( + Ctx.getValue(cast(Val)->getFunction())); +} + +BasicBlock *BlockAddress::getBasicBlock() const { + return cast( + Ctx.getValue(cast(Val)->getBasicBlock())); +} + +DSOLocalEquivalent *DSOLocalEquivalent::get(GlobalValue *GV) { + auto *LLVMC = llvm::DSOLocalEquivalent::get(cast(GV->Val)); + return cast(GV->getContext().getValue(LLVMC)); +} + +GlobalValue *DSOLocalEquivalent::getGlobalValue() const { + return cast( + Ctx.getValue(cast(Val)->getGlobalValue())); +} + +FunctionType *Function::getFunctionType() const { + return cast( + Ctx.getType(cast(Val)->getFunctionType())); +} + +#ifndef NDEBUG +void Function::dumpNameAndArgs(raw_ostream &OS) const { + auto *F = cast(Val); + OS << *F->getReturnType() << " @" << F->getName() << "("; + interleave( + F->args(), + [this, &OS](const llvm::Argument &LLVMArg) { + auto *SBArg = cast_or_null(Ctx.getValue(&LLVMArg)); + if (SBArg == nullptr) + OS << "NULL"; + else + SBArg->printAsOperand(OS); + }, + [&] { OS << ", "; }); + OS << ")"; +} + +void Function::dumpOS(raw_ostream &OS) const { + dumpNameAndArgs(OS); + OS << " {\n"; + auto *LLVMF = cast(Val); + interleave( + *LLVMF, + [this, &OS](const llvm::BasicBlock &LLVMBB) { + auto *BB = cast_or_null(Ctx.getValue(&LLVMBB)); + if (BB == nullptr) + OS << "NULL"; + else + OS << *BB; + }, + [&OS] { OS << "\n"; }); + OS << "}\n"; +} +#endif // NDEBUG + +} // namespace llvm::sandboxir diff --git a/llvm/lib/SandboxIR/SandboxIR.cpp b/llvm/lib/SandboxIR/SandboxIR.cpp index 12cac66480b0c..42df9df811973 100644 --- a/llvm/lib/SandboxIR/SandboxIR.cpp +++ b/llvm/lib/SandboxIR/SandboxIR.cpp @@ -2085,506 +2085,11 @@ Value *InsertValueInst::create(Value *Agg, Value *Val, ArrayRef Idxs, return Ctx.getOrCreateConstant(cast(NewV)); } -#ifndef NDEBUG -void Constant::dumpOS(raw_ostream &OS) const { - dumpCommonPrefix(OS); - dumpCommonSuffix(OS); -} -#endif // NDEBUG - -ConstantInt *ConstantInt::getTrue(Context &Ctx) { - auto *LLVMC = llvm::ConstantInt::getTrue(Ctx.LLVMCtx); - return cast(Ctx.getOrCreateConstant(LLVMC)); -} -ConstantInt *ConstantInt::getFalse(Context &Ctx) { - auto *LLVMC = llvm::ConstantInt::getFalse(Ctx.LLVMCtx); - return cast(Ctx.getOrCreateConstant(LLVMC)); -} -ConstantInt *ConstantInt::getBool(Context &Ctx, bool V) { - auto *LLVMC = llvm::ConstantInt::getBool(Ctx.LLVMCtx, V); - return cast(Ctx.getOrCreateConstant(LLVMC)); -} -Constant *ConstantInt::getTrue(Type *Ty) { - auto *LLVMC = llvm::ConstantInt::getTrue(Ty->LLVMTy); - return Ty->getContext().getOrCreateConstant(LLVMC); -} -Constant *ConstantInt::getFalse(Type *Ty) { - auto *LLVMC = llvm::ConstantInt::getFalse(Ty->LLVMTy); - return Ty->getContext().getOrCreateConstant(LLVMC); -} -Constant *ConstantInt::getBool(Type *Ty, bool V) { - auto *LLVMC = llvm::ConstantInt::getBool(Ty->LLVMTy, V); - return Ty->getContext().getOrCreateConstant(LLVMC); -} -ConstantInt *ConstantInt::get(Type *Ty, uint64_t V, bool IsSigned) { - auto *LLVMC = llvm::ConstantInt::get(Ty->LLVMTy, V, IsSigned); - return cast(Ty->getContext().getOrCreateConstant(LLVMC)); -} -ConstantInt *ConstantInt::get(IntegerType *Ty, uint64_t V, bool IsSigned) { - auto *LLVMC = llvm::ConstantInt::get(Ty->LLVMTy, V, IsSigned); - return cast(Ty->getContext().getOrCreateConstant(LLVMC)); -} -ConstantInt *ConstantInt::getSigned(IntegerType *Ty, int64_t V) { - auto *LLVMC = - llvm::ConstantInt::getSigned(cast(Ty->LLVMTy), V); - return cast(Ty->getContext().getOrCreateConstant(LLVMC)); -} -Constant *ConstantInt::getSigned(Type *Ty, int64_t V) { - auto *LLVMC = llvm::ConstantInt::getSigned(Ty->LLVMTy, V); - return Ty->getContext().getOrCreateConstant(LLVMC); -} -ConstantInt *ConstantInt::get(Context &Ctx, const APInt &V) { - auto *LLVMC = llvm::ConstantInt::get(Ctx.LLVMCtx, V); - return cast(Ctx.getOrCreateConstant(LLVMC)); -} -ConstantInt *ConstantInt::get(IntegerType *Ty, StringRef Str, uint8_t Radix) { - auto *LLVMC = - llvm::ConstantInt::get(cast(Ty->LLVMTy), Str, Radix); - return cast(Ty->getContext().getOrCreateConstant(LLVMC)); -} -Constant *ConstantInt::get(Type *Ty, const APInt &V) { - auto *LLVMC = llvm::ConstantInt::get(Ty->LLVMTy, V); - return Ty->getContext().getOrCreateConstant(LLVMC); -} -IntegerType *ConstantInt::getIntegerType() const { - auto *LLVMTy = cast(Val)->getIntegerType(); - return cast(Ctx.getType(LLVMTy)); -} - -bool ConstantInt::isValueValidForType(Type *Ty, uint64_t V) { - return llvm::ConstantInt::isValueValidForType(Ty->LLVMTy, V); -} -bool ConstantInt::isValueValidForType(Type *Ty, int64_t V) { - return llvm::ConstantInt::isValueValidForType(Ty->LLVMTy, V); -} - -Constant *ConstantFP::get(Type *Ty, double V) { - auto *LLVMC = llvm::ConstantFP::get(Ty->LLVMTy, V); - return Ty->getContext().getOrCreateConstant(LLVMC); -} - -Constant *ConstantFP::get(Type *Ty, const APFloat &V) { - auto *LLVMC = llvm::ConstantFP::get(Ty->LLVMTy, V); - return Ty->getContext().getOrCreateConstant(LLVMC); -} - -Constant *ConstantFP::get(Type *Ty, StringRef Str) { - auto *LLVMC = llvm::ConstantFP::get(Ty->LLVMTy, Str); - return Ty->getContext().getOrCreateConstant(LLVMC); -} - -ConstantFP *ConstantFP::get(const APFloat &V, Context &Ctx) { - auto *LLVMC = llvm::ConstantFP::get(Ctx.LLVMCtx, V); - return cast(Ctx.getOrCreateConstant(LLVMC)); -} - -Constant *ConstantFP::getNaN(Type *Ty, bool Negative, uint64_t Payload) { - auto *LLVMC = llvm::ConstantFP::getNaN(Ty->LLVMTy, Negative, Payload); - return cast(Ty->getContext().getOrCreateConstant(LLVMC)); -} -Constant *ConstantFP::getQNaN(Type *Ty, bool Negative, APInt *Payload) { - auto *LLVMC = llvm::ConstantFP::getQNaN(Ty->LLVMTy, Negative, Payload); - return cast(Ty->getContext().getOrCreateConstant(LLVMC)); -} -Constant *ConstantFP::getSNaN(Type *Ty, bool Negative, APInt *Payload) { - auto *LLVMC = llvm::ConstantFP::getSNaN(Ty->LLVMTy, Negative, Payload); - return cast(Ty->getContext().getOrCreateConstant(LLVMC)); -} -Constant *ConstantFP::getZero(Type *Ty, bool Negative) { - auto *LLVMC = llvm::ConstantFP::getZero(Ty->LLVMTy, Negative); - return cast(Ty->getContext().getOrCreateConstant(LLVMC)); -} -Constant *ConstantFP::getNegativeZero(Type *Ty) { - auto *LLVMC = llvm::ConstantFP::getNegativeZero(Ty->LLVMTy); - return cast(Ty->getContext().getOrCreateConstant(LLVMC)); -} -Constant *ConstantFP::getInfinity(Type *Ty, bool Negative) { - auto *LLVMC = llvm::ConstantFP::getInfinity(Ty->LLVMTy, Negative); - return cast(Ty->getContext().getOrCreateConstant(LLVMC)); -} -bool ConstantFP::isValueValidForType(Type *Ty, const APFloat &V) { - return llvm::ConstantFP::isValueValidForType(Ty->LLVMTy, V); -} - -Constant *ConstantArray::get(ArrayType *T, ArrayRef V) { - auto &Ctx = T->getContext(); - SmallVector LLVMValues; - LLVMValues.reserve(V.size()); - for (auto *Elm : V) - LLVMValues.push_back(cast(Elm->Val)); - auto *LLVMC = - llvm::ConstantArray::get(cast(T->LLVMTy), LLVMValues); - return cast(Ctx.getOrCreateConstant(LLVMC)); -} - -ArrayType *ConstantArray::getType() const { - return cast( - Ctx.getType(cast(Val)->getType())); -} - -Constant *ConstantStruct::get(StructType *T, ArrayRef V) { - auto &Ctx = T->getContext(); - SmallVector LLVMValues; - LLVMValues.reserve(V.size()); - for (auto *Elm : V) - LLVMValues.push_back(cast(Elm->Val)); - auto *LLVMC = - llvm::ConstantStruct::get(cast(T->LLVMTy), LLVMValues); - return cast(Ctx.getOrCreateConstant(LLVMC)); -} - -StructType *ConstantStruct::getTypeForElements(Context &Ctx, - ArrayRef V, - bool Packed) { - unsigned VecSize = V.size(); - SmallVector EltTypes; - EltTypes.reserve(VecSize); - for (Constant *Elm : V) - EltTypes.push_back(Elm->getType()); - return StructType::get(Ctx, EltTypes, Packed); -} - -ConstantAggregateZero *ConstantAggregateZero::get(Type *Ty) { - auto *LLVMC = llvm::ConstantAggregateZero::get(Ty->LLVMTy); - return cast( - Ty->getContext().getOrCreateConstant(LLVMC)); -} - -Constant *ConstantAggregateZero::getSequentialElement() const { - return cast(Ctx.getValue( - cast(Val)->getSequentialElement())); -} -Constant *ConstantAggregateZero::getStructElement(unsigned Elt) const { - return cast(Ctx.getValue( - cast(Val)->getStructElement(Elt))); -} -Constant *ConstantAggregateZero::getElementValue(Constant *C) const { - return cast( - Ctx.getValue(cast(Val)->getElementValue( - cast(C->Val)))); -} -Constant *ConstantAggregateZero::getElementValue(unsigned Idx) const { - return cast(Ctx.getValue( - cast(Val)->getElementValue(Idx))); -} - -ConstantPointerNull *ConstantPointerNull::get(PointerType *Ty) { - auto *LLVMC = - llvm::ConstantPointerNull::get(cast(Ty->LLVMTy)); - return cast(Ty->getContext().getOrCreateConstant(LLVMC)); -} - -PointerType *ConstantPointerNull::getType() const { - return cast( - Ctx.getType(cast(Val)->getType())); -} - -UndefValue *UndefValue::get(Type *T) { - auto *LLVMC = llvm::UndefValue::get(T->LLVMTy); - return cast(T->getContext().getOrCreateConstant(LLVMC)); -} - -UndefValue *UndefValue::getSequentialElement() const { - return cast(Ctx.getOrCreateConstant( - cast(Val)->getSequentialElement())); -} - -UndefValue *UndefValue::getStructElement(unsigned Elt) const { - return cast(Ctx.getOrCreateConstant( - cast(Val)->getStructElement(Elt))); -} - -UndefValue *UndefValue::getElementValue(Constant *C) const { - return cast( - Ctx.getOrCreateConstant(cast(Val)->getElementValue( - cast(C->Val)))); -} - -UndefValue *UndefValue::getElementValue(unsigned Idx) const { - return cast(Ctx.getOrCreateConstant( - cast(Val)->getElementValue(Idx))); -} - -PoisonValue *PoisonValue::get(Type *T) { - auto *LLVMC = llvm::PoisonValue::get(T->LLVMTy); - return cast(T->getContext().getOrCreateConstant(LLVMC)); -} - -PoisonValue *PoisonValue::getSequentialElement() const { - return cast(Ctx.getOrCreateConstant( - cast(Val)->getSequentialElement())); -} - -PoisonValue *PoisonValue::getStructElement(unsigned Elt) const { - return cast(Ctx.getOrCreateConstant( - cast(Val)->getStructElement(Elt))); -} - -PoisonValue *PoisonValue::getElementValue(Constant *C) const { - return cast( - Ctx.getOrCreateConstant(cast(Val)->getElementValue( - cast(C->Val)))); -} - -PoisonValue *PoisonValue::getElementValue(unsigned Idx) const { - return cast(Ctx.getOrCreateConstant( - cast(Val)->getElementValue(Idx))); -} - -void GlobalObject::setAlignment(MaybeAlign Align) { - Ctx.getTracker() - .emplaceIfTracking< - GenericSetter<&GlobalObject::getAlign, &GlobalObject::setAlignment>>( - this); - cast(Val)->setAlignment(Align); -} - -void GlobalObject::setGlobalObjectSubClassData(unsigned V) { - Ctx.getTracker() - .emplaceIfTracking< - GenericSetter<&GlobalObject::getGlobalObjectSubClassData, - &GlobalObject::setGlobalObjectSubClassData>>(this); - cast(Val)->setGlobalObjectSubClassData(V); -} - -void GlobalObject::setSection(StringRef S) { - Ctx.getTracker() - .emplaceIfTracking< - GenericSetter<&GlobalObject::getSection, &GlobalObject::setSection>>( - this); - cast(Val)->setSection(S); -} - -template -GlobalT &GlobalWithNodeAPI:: - LLVMGVToGV::operator()(LLVMGlobalT &LLVMGV) const { - return cast(*Ctx.getValue(&LLVMGV)); -} - -namespace llvm::sandboxir { -// Explicit instantiations. -template class GlobalWithNodeAPI; -template class GlobalWithNodeAPI; -template class GlobalWithNodeAPI; -template class GlobalWithNodeAPI; -} // namespace llvm::sandboxir - -void GlobalIFunc::setResolver(Constant *Resolver) { - Ctx.getTracker() - .emplaceIfTracking< - GenericSetter<&GlobalIFunc::getResolver, &GlobalIFunc::setResolver>>( - this); - cast(Val)->setResolver( - cast(Resolver->Val)); -} - -Constant *GlobalIFunc::getResolver() const { - return Ctx.getOrCreateConstant(cast(Val)->getResolver()); -} - -Function *GlobalIFunc::getResolverFunction() { - return cast(Ctx.getOrCreateConstant( - cast(Val)->getResolverFunction())); -} - -GlobalVariable & -GlobalVariable::LLVMGVToGV::operator()(llvm::GlobalVariable &LLVMGV) const { - return cast(*Ctx.getValue(&LLVMGV)); -} - -Constant *GlobalVariable::getInitializer() const { - return Ctx.getOrCreateConstant( - cast(Val)->getInitializer()); -} - -void GlobalVariable::setInitializer(Constant *InitVal) { - Ctx.getTracker() - .emplaceIfTracking>(this); - cast(Val)->setInitializer( - cast(InitVal->Val)); -} - -void GlobalVariable::setConstant(bool V) { - Ctx.getTracker() - .emplaceIfTracking>(this); - cast(Val)->setConstant(V); -} - -void GlobalVariable::setExternallyInitialized(bool V) { - Ctx.getTracker() - .emplaceIfTracking< - GenericSetter<&GlobalVariable::isExternallyInitialized, - &GlobalVariable::setExternallyInitialized>>(this); - cast(Val)->setExternallyInitialized(V); -} - -void GlobalAlias::setAliasee(Constant *Aliasee) { - Ctx.getTracker() - .emplaceIfTracking< - GenericSetter<&GlobalAlias::getAliasee, &GlobalAlias::setAliasee>>( - this); - cast(Val)->setAliasee(cast(Aliasee->Val)); -} - -Constant *GlobalAlias::getAliasee() const { - return cast( - Ctx.getOrCreateConstant(cast(Val)->getAliasee())); -} - -const GlobalObject *GlobalAlias::getAliaseeObject() const { - return cast(Ctx.getOrCreateConstant( - cast(Val)->getAliaseeObject())); -} - -void GlobalValue::setUnnamedAddr(UnnamedAddr V) { - Ctx.getTracker() - .emplaceIfTracking>(this); - cast(Val)->setUnnamedAddr(V); -} - -void GlobalValue::setVisibility(VisibilityTypes V) { - Ctx.getTracker() - .emplaceIfTracking>(this); - cast(Val)->setVisibility(V); -} - -NoCFIValue *NoCFIValue::get(GlobalValue *GV) { - auto *LLVMC = llvm::NoCFIValue::get(cast(GV->Val)); - return cast(GV->getContext().getOrCreateConstant(LLVMC)); -} - -GlobalValue *NoCFIValue::getGlobalValue() const { - auto *LLVMC = cast(Val)->getGlobalValue(); - return cast(Ctx.getOrCreateConstant(LLVMC)); -} - -PointerType *NoCFIValue::getType() const { - return cast(Ctx.getType(cast(Val)->getType())); -} - -ConstantPtrAuth *ConstantPtrAuth::get(Constant *Ptr, ConstantInt *Key, - ConstantInt *Disc, Constant *AddrDisc) { - auto *LLVMC = llvm::ConstantPtrAuth::get( - cast(Ptr->Val), cast(Key->Val), - cast(Disc->Val), cast(AddrDisc->Val)); - return cast(Ptr->getContext().getOrCreateConstant(LLVMC)); -} - -Constant *ConstantPtrAuth::getPointer() const { - return Ctx.getOrCreateConstant( - cast(Val)->getPointer()); -} - -ConstantInt *ConstantPtrAuth::getKey() const { - return cast( - Ctx.getOrCreateConstant(cast(Val)->getKey())); -} - -ConstantInt *ConstantPtrAuth::getDiscriminator() const { - return cast(Ctx.getOrCreateConstant( - cast(Val)->getDiscriminator())); -} - -Constant *ConstantPtrAuth::getAddrDiscriminator() const { - return Ctx.getOrCreateConstant( - cast(Val)->getAddrDiscriminator()); -} - -ConstantPtrAuth *ConstantPtrAuth::getWithSameSchema(Constant *Pointer) const { - auto *LLVMC = cast(Val)->getWithSameSchema( - cast(Pointer->Val)); - return cast(Ctx.getOrCreateConstant(LLVMC)); -} - -BlockAddress *BlockAddress::get(Function *F, BasicBlock *BB) { - auto *LLVMC = llvm::BlockAddress::get(cast(F->Val), - cast(BB->Val)); - return cast(F->getContext().getOrCreateConstant(LLVMC)); -} - -BlockAddress *BlockAddress::get(BasicBlock *BB) { - auto *LLVMC = llvm::BlockAddress::get(cast(BB->Val)); - return cast(BB->getContext().getOrCreateConstant(LLVMC)); -} - -BlockAddress *BlockAddress::lookup(const BasicBlock *BB) { - auto *LLVMC = llvm::BlockAddress::lookup(cast(BB->Val)); - return cast_or_null(BB->getContext().getValue(LLVMC)); -} - -Function *BlockAddress::getFunction() const { - return cast( - Ctx.getValue(cast(Val)->getFunction())); -} - -BasicBlock *BlockAddress::getBasicBlock() const { - return cast( - Ctx.getValue(cast(Val)->getBasicBlock())); -} - -DSOLocalEquivalent *DSOLocalEquivalent::get(GlobalValue *GV) { - auto *LLVMC = llvm::DSOLocalEquivalent::get(cast(GV->Val)); - return cast(GV->getContext().getValue(LLVMC)); -} - -GlobalValue *DSOLocalEquivalent::getGlobalValue() const { - return cast( - Ctx.getValue(cast(Val)->getGlobalValue())); -} - ConstantTokenNone *ConstantTokenNone::get(Context &Ctx) { auto *LLVMC = llvm::ConstantTokenNone::get(Ctx.LLVMCtx); return cast(Ctx.getOrCreateConstant(LLVMC)); } -FunctionType *Function::getFunctionType() const { - return cast( - Ctx.getType(cast(Val)->getFunctionType())); -} - -#ifndef NDEBUG -void Function::dumpNameAndArgs(raw_ostream &OS) const { - auto *F = cast(Val); - OS << *F->getReturnType() << " @" << F->getName() << "("; - interleave( - F->args(), - [this, &OS](const llvm::Argument &LLVMArg) { - auto *SBArg = cast_or_null(Ctx.getValue(&LLVMArg)); - if (SBArg == nullptr) - OS << "NULL"; - else - SBArg->printAsOperand(OS); - }, - [&] { OS << ", "; }); - OS << ")"; -} -void Function::dumpOS(raw_ostream &OS) const { - dumpNameAndArgs(OS); - OS << " {\n"; - auto *LLVMF = cast(Val); - interleave( - *LLVMF, - [this, &OS](const llvm::BasicBlock &LLVMBB) { - auto *BB = cast_or_null(Ctx.getValue(&LLVMBB)); - if (BB == nullptr) - OS << "NULL"; - else - OS << *BB; - }, - [&OS] { OS << "\n"; }); - OS << "}\n"; -} -#endif // NDEBUG - BasicBlock::iterator::pointer BasicBlock::iterator::getInstr(llvm::BasicBlock::iterator It) const { return cast_or_null(Ctx->getValue(&*It)); From 246896b77ecd483747a35468fcf7f92169d5bc3d Mon Sep 17 00:00:00 2001 From: LLVM GN Syncbot Date: Fri, 27 Sep 2024 00:53:58 +0000 Subject: [PATCH 026/469] [gn build] Port 049fc920e631 --- llvm/utils/gn/secondary/llvm/lib/SandboxIR/BUILD.gn | 1 + 1 file changed, 1 insertion(+) diff --git a/llvm/utils/gn/secondary/llvm/lib/SandboxIR/BUILD.gn b/llvm/utils/gn/secondary/llvm/lib/SandboxIR/BUILD.gn index abf09e9d84045..902595fc495ce 100644 --- a/llvm/utils/gn/secondary/llvm/lib/SandboxIR/BUILD.gn +++ b/llvm/utils/gn/secondary/llvm/lib/SandboxIR/BUILD.gn @@ -7,6 +7,7 @@ static_library("SandboxIR") { ] sources = [ "Argument.cpp", + "Constant.cpp", "Context.cpp", "Module.cpp", "Pass.cpp", From fbec6754d6d643762738fe4428e3faf6bae51a7d Mon Sep 17 00:00:00 2001 From: LLVM GN Syncbot Date: Fri, 27 Sep 2024 00:53:59 +0000 Subject: [PATCH 027/469] [gn build] Port 3c66a51054d7 --- .../unittests/Transforms/Vectorize/SandboxVectorizer/BUILD.gn | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/utils/gn/secondary/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/BUILD.gn b/llvm/utils/gn/secondary/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/BUILD.gn index a9e2170ce4be7..ceda3150ff60e 100644 --- a/llvm/utils/gn/secondary/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/BUILD.gn +++ b/llvm/utils/gn/secondary/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/BUILD.gn @@ -11,7 +11,7 @@ unittest("SandboxVectorizerTests") { ] sources = [ "DependencyGraphTest.cpp", - "InstrIntervalTest.cpp", + "IntervalTest.cpp", "LegalityTest.cpp", "RegionTest.cpp", ] From 9efc761d42496335e52bfe6e58b5c721e23d47f0 Mon Sep 17 00:00:00 2001 From: Jorge Gorbe Moya Date: Thu, 26 Sep 2024 18:12:31 -0700 Subject: [PATCH 028/469] Reapply "[SandboxIR][NFC] Move Region from SandboxVectorizer to SandboxIR." (#110173) (#110181) Re-applies llvm/llvm-project#110173 after fixing build break. --- .../Vectorize/SandboxVectorizer => SandboxIR}/Region.h | 0 llvm/lib/SandboxIR/CMakeLists.txt | 1 + .../Vectorize/SandboxVectorizer => SandboxIR}/Region.cpp | 2 +- llvm/lib/Transforms/Vectorize/CMakeLists.txt | 1 - llvm/unittests/SandboxIR/CMakeLists.txt | 1 + .../Vectorize/SandboxVectorizer => SandboxIR}/RegionTest.cpp | 2 +- .../Transforms/Vectorize/SandboxVectorizer/CMakeLists.txt | 1 - 7 files changed, 4 insertions(+), 4 deletions(-) rename llvm/include/llvm/{Transforms/Vectorize/SandboxVectorizer => SandboxIR}/Region.h (100%) rename llvm/lib/{Transforms/Vectorize/SandboxVectorizer => SandboxIR}/Region.cpp (96%) rename llvm/unittests/{Transforms/Vectorize/SandboxVectorizer => SandboxIR}/RegionTest.cpp (98%) diff --git a/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/Region.h b/llvm/include/llvm/SandboxIR/Region.h similarity index 100% rename from llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/Region.h rename to llvm/include/llvm/SandboxIR/Region.h diff --git a/llvm/lib/SandboxIR/CMakeLists.txt b/llvm/lib/SandboxIR/CMakeLists.txt index 52afeb395a9a0..50374de59761e 100644 --- a/llvm/lib/SandboxIR/CMakeLists.txt +++ b/llvm/lib/SandboxIR/CMakeLists.txt @@ -5,6 +5,7 @@ add_llvm_component_library(LLVMSandboxIR Module.cpp Pass.cpp PassManager.cpp + Region.cpp SandboxIR.cpp Tracker.cpp Type.cpp diff --git a/llvm/lib/Transforms/Vectorize/SandboxVectorizer/Region.cpp b/llvm/lib/SandboxIR/Region.cpp similarity index 96% rename from llvm/lib/Transforms/Vectorize/SandboxVectorizer/Region.cpp rename to llvm/lib/SandboxIR/Region.cpp index 5f2c28484f62b..b14c87f44260f 100644 --- a/llvm/lib/Transforms/Vectorize/SandboxVectorizer/Region.cpp +++ b/llvm/lib/SandboxIR/Region.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -#include "llvm/Transforms/Vectorize/SandboxVectorizer/Region.h" +#include "llvm/SandboxIR/Region.h" namespace llvm::sandboxir { diff --git a/llvm/lib/Transforms/Vectorize/CMakeLists.txt b/llvm/lib/Transforms/Vectorize/CMakeLists.txt index 8bd3dbf069573..eeff4a9f6a8ba 100644 --- a/llvm/lib/Transforms/Vectorize/CMakeLists.txt +++ b/llvm/lib/Transforms/Vectorize/CMakeLists.txt @@ -5,7 +5,6 @@ add_llvm_component_library(LLVMVectorize LoopVectorize.cpp SandboxVectorizer/DependencyGraph.cpp SandboxVectorizer/Passes/BottomUpVec.cpp - SandboxVectorizer/Region.cpp SandboxVectorizer/SandboxVectorizer.cpp SLPVectorizer.cpp Vectorize.cpp diff --git a/llvm/unittests/SandboxIR/CMakeLists.txt b/llvm/unittests/SandboxIR/CMakeLists.txt index 2ab284a511fca..622496ada567f 100644 --- a/llvm/unittests/SandboxIR/CMakeLists.txt +++ b/llvm/unittests/SandboxIR/CMakeLists.txt @@ -7,6 +7,7 @@ set(LLVM_LINK_COMPONENTS add_llvm_unittest(SandboxIRTests PassTest.cpp + RegionTest.cpp SandboxIRTest.cpp TrackerTest.cpp TypesTest.cpp diff --git a/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/RegionTest.cpp b/llvm/unittests/SandboxIR/RegionTest.cpp similarity index 98% rename from llvm/unittests/Transforms/Vectorize/SandboxVectorizer/RegionTest.cpp rename to llvm/unittests/SandboxIR/RegionTest.cpp index 0318d32c69219..dc4dad8fed71c 100644 --- a/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/RegionTest.cpp +++ b/llvm/unittests/SandboxIR/RegionTest.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -#include "llvm/Transforms/Vectorize/SandboxVectorizer/Region.h" +#include "llvm/SandboxIR/Region.h" #include "llvm/AsmParser/Parser.h" #include "llvm/SandboxIR/SandboxIR.h" #include "llvm/Support/SourceMgr.h" diff --git a/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/CMakeLists.txt b/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/CMakeLists.txt index deb3cd398d02d..9f1a3409c0c39 100644 --- a/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/CMakeLists.txt +++ b/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/CMakeLists.txt @@ -11,5 +11,4 @@ add_llvm_unittest(SandboxVectorizerTests DependencyGraphTest.cpp IntervalTest.cpp LegalityTest.cpp - RegionTest.cpp ) From e0d6f6623482f6b3d2dc628ac64d96d877ac3756 Mon Sep 17 00:00:00 2001 From: LLVM GN Syncbot Date: Fri, 27 Sep 2024 01:13:06 +0000 Subject: [PATCH 029/469] [gn build] Port 9efc761d4249 --- llvm/utils/gn/secondary/llvm/lib/SandboxIR/BUILD.gn | 1 + llvm/utils/gn/secondary/llvm/lib/Transforms/Vectorize/BUILD.gn | 1 - llvm/utils/gn/secondary/llvm/unittests/SandboxIR/BUILD.gn | 1 + .../unittests/Transforms/Vectorize/SandboxVectorizer/BUILD.gn | 1 - 4 files changed, 2 insertions(+), 2 deletions(-) diff --git a/llvm/utils/gn/secondary/llvm/lib/SandboxIR/BUILD.gn b/llvm/utils/gn/secondary/llvm/lib/SandboxIR/BUILD.gn index 902595fc495ce..f3d3984ccd91c 100644 --- a/llvm/utils/gn/secondary/llvm/lib/SandboxIR/BUILD.gn +++ b/llvm/utils/gn/secondary/llvm/lib/SandboxIR/BUILD.gn @@ -12,6 +12,7 @@ static_library("SandboxIR") { "Module.cpp", "Pass.cpp", "PassManager.cpp", + "Region.cpp", "SandboxIR.cpp", "Tracker.cpp", "Type.cpp", diff --git a/llvm/utils/gn/secondary/llvm/lib/Transforms/Vectorize/BUILD.gn b/llvm/utils/gn/secondary/llvm/lib/Transforms/Vectorize/BUILD.gn index 66db9100fb597..9f85f2ec59511 100644 --- a/llvm/utils/gn/secondary/llvm/lib/Transforms/Vectorize/BUILD.gn +++ b/llvm/utils/gn/secondary/llvm/lib/Transforms/Vectorize/BUILD.gn @@ -15,7 +15,6 @@ static_library("Vectorize") { "SLPVectorizer.cpp", "SandboxVectorizer/DependencyGraph.cpp", "SandboxVectorizer/Passes/BottomUpVec.cpp", - "SandboxVectorizer/Region.cpp", "SandboxVectorizer/SandboxVectorizer.cpp", "VPlan.cpp", "VPlanAnalysis.cpp", diff --git a/llvm/utils/gn/secondary/llvm/unittests/SandboxIR/BUILD.gn b/llvm/utils/gn/secondary/llvm/unittests/SandboxIR/BUILD.gn index 5828d122aede9..11045f4315877 100644 --- a/llvm/utils/gn/secondary/llvm/unittests/SandboxIR/BUILD.gn +++ b/llvm/utils/gn/secondary/llvm/unittests/SandboxIR/BUILD.gn @@ -9,6 +9,7 @@ unittest("SandboxIRTests") { ] sources = [ "PassTest.cpp", + "RegionTest.cpp", "SandboxIRTest.cpp", "TrackerTest.cpp", "TypesTest.cpp", diff --git a/llvm/utils/gn/secondary/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/BUILD.gn b/llvm/utils/gn/secondary/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/BUILD.gn index ceda3150ff60e..a01525a0c80b6 100644 --- a/llvm/utils/gn/secondary/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/BUILD.gn +++ b/llvm/utils/gn/secondary/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/BUILD.gn @@ -13,6 +13,5 @@ unittest("SandboxVectorizerTests") { "DependencyGraphTest.cpp", "IntervalTest.cpp", "LegalityTest.cpp", - "RegionTest.cpp", ] } From d1cd2c3a26106a8d0e39db3749449261c53cc4e5 Mon Sep 17 00:00:00 2001 From: Heejin Ahn Date: Thu, 26 Sep 2024 18:25:43 -0700 Subject: [PATCH 030/469] [WebAssembly] Unify type checking in AsmTypeCheck (#110094) This unifies the way we check types in various places in AsmTypeCheck. The objectives of this PR are: - We now use `checkTypes` for all type checking and `checkAndPopTypes` for type checking + popping. All other functions are helper functions to call these two functions. - We now support comparisons of types between vectors. This lets us printing error messages in more readable way. When an instruction takes [i32, i64] but the stack top is [f32, f64], now instead of ```console error: type mismatch, expected i64 but got f64 error: type mismatch, expected i32 but got f32 ``` we can print this ```console error: type mismatch, expected [i32, i64] but got [f32, f64] ``` which is also the format Wabt checker prints. This also helps printing more meaningful messages when there are superfluous values on the stack at the end of the function, such as: ```console error: type mismatch, expected [] but got [i32, exnref] ``` Actually, many instructions are not utilizing this batch printing now, which still causes multiple error messages to be printed for a single instruction. This will be improved in a follow-up. - The value stack now supports `Any` and `Ref`. There are instructions that requires the type to be anything. Also instructions like `ref.is_null` requires the type to be any reference types. Type comparison function will handle this types accordingly, meaning `match(I32, Any)` or `match(externref, Ref)` will succeed. The changes in `type-checker-errors.s` are mostly the message format changes. One downside of the new message format is that it doesn't have instruction names in it. I plan to improve that in a potential follow-up. This also made some modifications in the instructions in `type-checker-errors.s`. Currently, except for a few functions I've recently added at the end, each function tests for a single error, because the type checker used to bail out after the first error until #109705. But many functions included multiple errors anyway, which I don't think was the intention of the original writer. So I added some instructions to remove the other errors which are not being tested. (In some cases I added more error checking lines instead, when I felt that could be relevant.) Thanks to the new `ExactMatch` option in `checkTypes` function family, we now can distinguish the cases when to check against only the top of the value stack and when to check against the whole stack (e.g. to check whether we have any superfluous values remaining at the end of the function). `return` or `return_call(_indirect)` can set `ExactMatch` to `false` because they don't care about the superfluous values. This makes `type-checker-return.s` succeed and I was able to remove the `FIXME`. This is the basis of the PR that fixes block parameter/return type handling in the checker, but does not yet include the actual block-related functionality, which will be submitted separately after this PR. --- .../AsmParser/WebAssemblyAsmParser.cpp | 2 +- .../AsmParser/WebAssemblyAsmTypeCheck.cpp | 243 +++++++++++------- .../AsmParser/WebAssemblyAsmTypeCheck.h | 31 ++- .../test/MC/WebAssembly/type-checker-errors.s | 220 +++++++++------- .../test/MC/WebAssembly/type-checker-return.s | 5 - 5 files changed, 299 insertions(+), 202 deletions(-) diff --git a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp index 129fdaf37fc0d..95db5500b0e1b 100644 --- a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp +++ b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp @@ -1255,7 +1255,7 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser { void onEndOfFunction(SMLoc ErrorLoc) { if (!SkipTypeCheck) - TC.endOfFunction(ErrorLoc); + TC.endOfFunction(ErrorLoc, true); // Reset the type checker state. TC.clear(); } diff --git a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmTypeCheck.cpp b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmTypeCheck.cpp index 8b1e1dca4f847..845bf3976c22b 100644 --- a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmTypeCheck.cpp +++ b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmTypeCheck.cpp @@ -33,6 +33,7 @@ #include "llvm/MC/TargetRegistry.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/SourceMgr.h" +#include using namespace llvm; @@ -59,14 +60,7 @@ void WebAssemblyAsmTypeCheck::localDecl( } void WebAssemblyAsmTypeCheck::dumpTypeStack(Twine Msg) { - LLVM_DEBUG({ - std::string s; - for (auto VT : Stack) { - s += WebAssembly::typeToString(VT); - s += " "; - } - dbgs() << Msg << s << '\n'; - }); + LLVM_DEBUG({ dbgs() << Msg << getTypesString(Stack, 0) << "\n"; }); } bool WebAssemblyAsmTypeCheck::typeError(SMLoc ErrorLoc, const Twine &Msg) { @@ -77,34 +71,124 @@ bool WebAssemblyAsmTypeCheck::typeError(SMLoc ErrorLoc, const Twine &Msg) { return Parser.Error(ErrorLoc, Msg); } -bool WebAssemblyAsmTypeCheck::popType(SMLoc ErrorLoc, - std::optional EVT) { - if (Stack.empty()) { - return typeError(ErrorLoc, - EVT ? StringRef("empty stack while popping ") + - WebAssembly::typeToString(*EVT) - : StringRef("empty stack while popping value")); +bool WebAssemblyAsmTypeCheck::match(StackType TypeA, StackType TypeB) { + if (TypeA == TypeB) + return false; + if (std::get_if(&TypeA) || std::get_if(&TypeB)) + return false; + + if (std::get_if(&TypeB)) + std::swap(TypeA, TypeB); + assert(std::get_if(&TypeB)); + if (std::get_if(&TypeA) && + WebAssembly::isRefType(std::get(TypeB))) + return false; + return true; +} + +std::string WebAssemblyAsmTypeCheck::getTypesString(ArrayRef Types, + size_t StartPos) { + SmallVector Reverse; + for (auto I = Types.size(); I > StartPos; I--) { + if (std::get_if(&Types[I - 1])) + Reverse.push_back("any"); + else if (std::get_if(&Types[I - 1])) + Reverse.push_back("ref"); + else + Reverse.push_back( + WebAssembly::typeToString(std::get(Types[I - 1]))); } - auto PVT = Stack.pop_back_val(); - if (EVT && *EVT != PVT) { - return typeError(ErrorLoc, - StringRef("popped ") + WebAssembly::typeToString(PVT) + - ", expected " + WebAssembly::typeToString(*EVT)); + + std::stringstream SS; + SS << "["; + bool First = true; + for (auto It = Reverse.rbegin(); It != Reverse.rend(); ++It) { + if (!First) + SS << ", "; + SS << *It; + First = false; } - return false; + SS << "]"; + return SS.str(); } -bool WebAssemblyAsmTypeCheck::popRefType(SMLoc ErrorLoc) { - if (Stack.empty()) { - return typeError(ErrorLoc, StringRef("empty stack while popping reftype")); - } - auto PVT = Stack.pop_back_val(); - if (!WebAssembly::isRefType(PVT)) { - return typeError(ErrorLoc, StringRef("popped ") + - WebAssembly::typeToString(PVT) + - ", expected reftype"); +SmallVector +WebAssemblyAsmTypeCheck::valTypeToStackType(ArrayRef ValTypes) { + SmallVector Types(ValTypes.size()); + std::transform(ValTypes.begin(), ValTypes.end(), Types.begin(), + [](wasm::ValType Val) -> StackType { return Val; }); + return Types; +} + +bool WebAssemblyAsmTypeCheck::checkTypes(SMLoc ErrorLoc, + ArrayRef ValTypes, + bool ExactMatch) { + return checkTypes(ErrorLoc, valTypeToStackType(ValTypes), ExactMatch); +} + +bool WebAssemblyAsmTypeCheck::checkTypes(SMLoc ErrorLoc, + ArrayRef Types, + bool ExactMatch) { + auto StackI = Stack.size(); + auto TypeI = Types.size(); + bool Error = false; + // Compare elements one by one from the stack top + for (; StackI > 0 && TypeI > 0; StackI--, TypeI--) { + if (match(Stack[StackI - 1], Types[TypeI - 1])) { + Error = true; + break; + } } - return false; + // Even if no match failure has happened in the loop above, if not all + // elements of Types has been matched, that means we don't have enough + // elements on the stack. + // + // Also, if not all elements of the Stack has been matched and when + // 'ExactMatch' is true, that means we have superfluous elements remaining on + // the stack (e.g. at the end of a function). + if (TypeI > 0 || (ExactMatch && StackI > 0)) + Error = true; + + if (!Error) + return false; + + auto StackStartPos = + ExactMatch ? 0 : std::max(0, (int)Stack.size() - (int)Types.size()); + return typeError(ErrorLoc, "type mismatch, expected " + + getTypesString(Types, 0) + " but got " + + getTypesString(Stack, StackStartPos)); +} + +bool WebAssemblyAsmTypeCheck::checkAndPopTypes(SMLoc ErrorLoc, + ArrayRef ValTypes, + bool ExactMatch) { + return checkAndPopTypes(ErrorLoc, valTypeToStackType(ValTypes), ExactMatch); +} + +bool WebAssemblyAsmTypeCheck::checkAndPopTypes(SMLoc ErrorLoc, + ArrayRef Types, + bool ExactMatch) { + bool Error = checkTypes(ErrorLoc, Types, ExactMatch); + auto NumPops = std::min(Stack.size(), Types.size()); + for (size_t I = 0, E = NumPops; I != E; I++) + Stack.pop_back(); + return Error; +} + +bool WebAssemblyAsmTypeCheck::popType(SMLoc ErrorLoc, StackType Type) { + return checkAndPopTypes(ErrorLoc, {Type}, false); +} + +bool WebAssemblyAsmTypeCheck::popRefType(SMLoc ErrorLoc) { + return popType(ErrorLoc, Ref{}); +} + +bool WebAssemblyAsmTypeCheck::popAnyType(SMLoc ErrorLoc) { + return popType(ErrorLoc, Any{}); +} + +void WebAssemblyAsmTypeCheck::pushTypes(ArrayRef ValTypes) { + Stack.append(valTypeToStackType(ValTypes)); } bool WebAssemblyAsmTypeCheck::getLocal(SMLoc ErrorLoc, const MCOperand &LocalOp, @@ -117,59 +201,29 @@ bool WebAssemblyAsmTypeCheck::getLocal(SMLoc ErrorLoc, const MCOperand &LocalOp, return false; } -static std::optional -checkStackTop(const SmallVectorImpl &ExpectedStackTop, - const SmallVectorImpl &Got) { - for (size_t I = 0; I < ExpectedStackTop.size(); I++) { - auto EVT = ExpectedStackTop[I]; - auto PVT = Got[Got.size() - ExpectedStackTop.size() + I]; - if (PVT != EVT) - return std::string{"got "} + WebAssembly::typeToString(PVT) + - ", expected " + WebAssembly::typeToString(EVT); - } - return std::nullopt; -} - bool WebAssemblyAsmTypeCheck::checkBr(SMLoc ErrorLoc, size_t Level) { if (Level >= BrStack.size()) return typeError(ErrorLoc, StringRef("br: invalid depth ") + std::to_string(Level)); const SmallVector &Expected = BrStack[BrStack.size() - Level - 1]; - if (Expected.size() > Stack.size()) - return typeError(ErrorLoc, "br: insufficient values on the type stack"); - auto IsStackTopInvalid = checkStackTop(Expected, Stack); - if (IsStackTopInvalid) - return typeError(ErrorLoc, "br " + IsStackTopInvalid.value()); + return checkTypes(ErrorLoc, Expected, false); return false; } bool WebAssemblyAsmTypeCheck::checkEnd(SMLoc ErrorLoc, bool PopVals) { if (!PopVals) BrStack.pop_back(); - if (LastSig.Returns.size() > Stack.size()) - return typeError(ErrorLoc, "end: insufficient values on the type stack"); - if (PopVals) { - for (auto VT : llvm::reverse(LastSig.Returns)) { - if (popType(ErrorLoc, VT)) - return true; - } - return false; - } - - auto IsStackTopInvalid = checkStackTop(LastSig.Returns, Stack); - if (IsStackTopInvalid) - return typeError(ErrorLoc, "end " + IsStackTopInvalid.value()); - return false; + if (PopVals) + return checkAndPopTypes(ErrorLoc, LastSig.Returns, false); + return checkTypes(ErrorLoc, LastSig.Returns, false); } bool WebAssemblyAsmTypeCheck::checkSig(SMLoc ErrorLoc, const wasm::WasmSignature &Sig) { - bool Error = false; - for (auto VT : llvm::reverse(Sig.Params)) - Error |= popType(ErrorLoc, VT); - Stack.insert(Stack.end(), Sig.Returns.begin(), Sig.Returns.end()); + bool Error = checkAndPopTypes(ErrorLoc, Sig.Params, false); + pushTypes(Sig.Returns); return Error; } @@ -246,7 +300,7 @@ bool WebAssemblyAsmTypeCheck::getSignature(SMLoc ErrorLoc, TypeName = "tag"; break; default: - return true; + llvm_unreachable("Signature symbol should either be a function or a tag"); } return typeError(ErrorLoc, StringRef("symbol ") + WasmSym->getName() + ": missing ." + TypeName + "type"); @@ -254,15 +308,8 @@ bool WebAssemblyAsmTypeCheck::getSignature(SMLoc ErrorLoc, return false; } -bool WebAssemblyAsmTypeCheck::endOfFunction(SMLoc ErrorLoc) { - bool Error = false; - // Check the return types. - for (auto RVT : llvm::reverse(ReturnTypes)) - Error |= popType(ErrorLoc, RVT); - if (!Stack.empty()) { - return typeError(ErrorLoc, std::to_string(Stack.size()) + - " superfluous return values"); - } +bool WebAssemblyAsmTypeCheck::endOfFunction(SMLoc ErrorLoc, bool ExactMatch) { + bool Error = checkAndPopTypes(ErrorLoc, ReturnTypes, ExactMatch); Unreachable = true; return Error; } @@ -276,7 +323,7 @@ bool WebAssemblyAsmTypeCheck::typeCheck(SMLoc ErrorLoc, const MCInst &Inst, if (Name == "local.get") { if (!getLocal(Operands[1]->getStartLoc(), Inst.getOperand(0), Type)) { - Stack.push_back(Type); + pushType(Type); return false; } return true; @@ -291,7 +338,7 @@ bool WebAssemblyAsmTypeCheck::typeCheck(SMLoc ErrorLoc, const MCInst &Inst, if (Name == "local.tee") { if (!getLocal(Operands[1]->getStartLoc(), Inst.getOperand(0), Type)) { bool Error = popType(ErrorLoc, Type); - Stack.push_back(Type); + pushType(Type); return Error; } return true; @@ -299,7 +346,7 @@ bool WebAssemblyAsmTypeCheck::typeCheck(SMLoc ErrorLoc, const MCInst &Inst, if (Name == "global.get") { if (!getGlobal(Operands[1]->getStartLoc(), Inst.getOperand(0), Type)) { - Stack.push_back(Type); + pushType(Type); return false; } return true; @@ -314,7 +361,7 @@ bool WebAssemblyAsmTypeCheck::typeCheck(SMLoc ErrorLoc, const MCInst &Inst, if (Name == "table.get") { bool Error = popType(ErrorLoc, wasm::ValType::I32); if (!getTable(Operands[1]->getStartLoc(), Inst.getOperand(0), Type)) { - Stack.push_back(Type); + pushType(Type); return Error; } return true; @@ -332,7 +379,7 @@ bool WebAssemblyAsmTypeCheck::typeCheck(SMLoc ErrorLoc, const MCInst &Inst, if (Name == "table.size") { bool Error = getTable(Operands[1]->getStartLoc(), Inst.getOperand(0), Type); - Stack.push_back(wasm::ValType::I32); + pushType(wasm::ValType::I32); return Error; } @@ -342,7 +389,7 @@ bool WebAssemblyAsmTypeCheck::typeCheck(SMLoc ErrorLoc, const MCInst &Inst, Error |= popType(ErrorLoc, Type); else Error = true; - Stack.push_back(wasm::ValType::I32); + pushType(wasm::ValType::I32); return Error; } @@ -381,7 +428,7 @@ bool WebAssemblyAsmTypeCheck::typeCheck(SMLoc ErrorLoc, const MCInst &Inst, } if (Name == "drop") { - return popType(ErrorLoc, {}); + return popType(ErrorLoc, Any{}); } if (Name == "try" || Name == "block" || Name == "loop" || Name == "if") { @@ -406,7 +453,7 @@ bool WebAssemblyAsmTypeCheck::typeCheck(SMLoc ErrorLoc, const MCInst &Inst, wasm::WASM_SYMBOL_TYPE_TAG, Sig)) // catch instruction pushes values whose types are specified in the // tag's "params" part - Stack.insert(Stack.end(), Sig->Params.begin(), Sig->Params.end()); + pushTypes(Sig->Params); else Error = true; } @@ -421,14 +468,14 @@ bool WebAssemblyAsmTypeCheck::typeCheck(SMLoc ErrorLoc, const MCInst &Inst, } if (Name == "return") { - return endOfFunction(ErrorLoc); + return endOfFunction(ErrorLoc, false); } if (Name == "call_indirect" || Name == "return_call_indirect") { // Function value. bool Error = popType(ErrorLoc, wasm::ValType::I32); Error |= checkSig(ErrorLoc, LastSig); - if (Name == "return_call_indirect" && endOfFunction(ErrorLoc)) + if (Name == "return_call_indirect" && endOfFunction(ErrorLoc, false)) return true; return Error; } @@ -441,7 +488,7 @@ bool WebAssemblyAsmTypeCheck::typeCheck(SMLoc ErrorLoc, const MCInst &Inst, Error |= checkSig(ErrorLoc, *Sig); else Error = true; - if (Name == "return_call" && endOfFunction(ErrorLoc)) + if (Name == "return_call" && endOfFunction(ErrorLoc, false)) return true; return Error; } @@ -453,7 +500,7 @@ bool WebAssemblyAsmTypeCheck::typeCheck(SMLoc ErrorLoc, const MCInst &Inst, if (Name == "ref.is_null") { bool Error = popRefType(ErrorLoc); - Stack.push_back(wasm::ValType::I32); + pushType(wasm::ValType::I32); return Error; } @@ -471,22 +518,22 @@ bool WebAssemblyAsmTypeCheck::typeCheck(SMLoc ErrorLoc, const MCInst &Inst, auto RegOpc = WebAssembly::getRegisterOpcode(Opc); assert(RegOpc != -1 && "Failed to get register version of MC instruction"); const auto &II = MII.get(RegOpc); - bool Error = false; // First pop all the uses off the stack and check them. - for (unsigned I = II.getNumOperands(); I > II.getNumDefs(); I--) { - const auto &Op = II.operands()[I - 1]; - if (Op.OperandType == MCOI::OPERAND_REGISTER) { - auto VT = WebAssembly::regClassToValType(Op.RegClass); - Error |= popType(ErrorLoc, VT); - } + SmallVector PopTypes; + for (unsigned I = II.getNumDefs(); I < II.getNumOperands(); I++) { + const auto &Op = II.operands()[I]; + if (Op.OperandType == MCOI::OPERAND_REGISTER) + PopTypes.push_back(WebAssembly::regClassToValType(Op.RegClass)); } + bool Error = checkAndPopTypes(ErrorLoc, PopTypes, false); + SmallVector PushTypes; // Now push all the defs onto the stack. for (unsigned I = 0; I < II.getNumDefs(); I++) { const auto &Op = II.operands()[I]; assert(Op.OperandType == MCOI::OPERAND_REGISTER && "Register expected"); - auto VT = WebAssembly::regClassToValType(Op.RegClass); - Stack.push_back(VT); + PushTypes.push_back(WebAssembly::regClassToValType(Op.RegClass)); } + pushTypes(PushTypes); return Error; } diff --git a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmTypeCheck.h b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmTypeCheck.h index 972162d3e02f4..9fd35a26f30e5 100644 --- a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmTypeCheck.h +++ b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmTypeCheck.h @@ -21,6 +21,7 @@ #include "llvm/MC/MCParser/MCAsmParser.h" #include "llvm/MC/MCParser/MCTargetAsmParser.h" #include "llvm/MC/MCSymbol.h" +#include namespace llvm { @@ -28,7 +29,10 @@ class WebAssemblyAsmTypeCheck final { MCAsmParser &Parser; const MCInstrInfo &MII; - SmallVector Stack; + struct Ref : public std::monostate {}; + struct Any : public std::monostate {}; + using StackType = std::variant; + SmallVector Stack; SmallVector, 8> BrStack; SmallVector LocalTypes; SmallVector ReturnTypes; @@ -36,10 +40,29 @@ class WebAssemblyAsmTypeCheck final { bool Unreachable = false; bool Is64; + // If ExactMatch is true, 'Types' will be compared against not only the top of + // the value stack but the whole remaining value stack + // (TODO: This should be the whole remaining value stack "at the the current + // block level", which has not been implemented yet) + bool checkTypes(SMLoc ErrorLoc, ArrayRef Types, + bool ExactMatch); + bool checkTypes(SMLoc ErrorLoc, ArrayRef Types, bool ExactMatch); + bool checkAndPopTypes(SMLoc ErrorLoc, ArrayRef Types, + bool ExactMatch); + bool checkAndPopTypes(SMLoc ErrorLoc, ArrayRef Types, + bool ExactMatch); + bool popType(SMLoc ErrorLoc, StackType Type); + bool popRefType(SMLoc ErrorLoc); + bool popAnyType(SMLoc ErrorLoc); + void pushTypes(ArrayRef Types); + void pushType(StackType Type) { Stack.push_back(Type); } + bool match(StackType TypeA, StackType TypeB); + std::string getTypesString(ArrayRef Types, size_t StartPos); + SmallVector + valTypeToStackType(ArrayRef ValTypes); + void dumpTypeStack(Twine Msg); bool typeError(SMLoc ErrorLoc, const Twine &Msg); - bool popType(SMLoc ErrorLoc, std::optional EVT); - bool popRefType(SMLoc ErrorLoc); bool getLocal(SMLoc ErrorLoc, const MCOperand &LocalOp, wasm::ValType &Type); bool checkEnd(SMLoc ErrorLoc, bool PopVals = false); bool checkBr(SMLoc ErrorLoc, size_t Level); @@ -59,7 +82,7 @@ class WebAssemblyAsmTypeCheck final { void funcDecl(const wasm::WasmSignature &Sig); void localDecl(const SmallVectorImpl &Locals); void setLastSig(const wasm::WasmSignature &Sig) { LastSig = Sig; } - bool endOfFunction(SMLoc ErrorLoc); + bool endOfFunction(SMLoc ErrorLoc, bool ExactMatch); bool typeCheck(SMLoc ErrorLoc, const MCInst &Inst, OperandVector &Operands); void clear() { diff --git a/llvm/test/MC/WebAssembly/type-checker-errors.s b/llvm/test/MC/WebAssembly/type-checker-errors.s index 3106fe76c8449..5fdc2f56daf57 100644 --- a/llvm/test/MC/WebAssembly/type-checker-errors.s +++ b/llvm/test/MC/WebAssembly/type-checker-errors.s @@ -19,7 +19,7 @@ local_set_no_local_type: local_set_empty_stack_while_popping: .functype local_set_empty_stack_while_popping () -> () .local i32 -# CHECK: [[@LINE+1]]:3: error: empty stack while popping i32 +# CHECK: [[@LINE+1]]:3: error: type mismatch, expected [i32] but got [] local.set 0 end_function @@ -27,7 +27,7 @@ local_set_type_mismatch: .functype local_set_type_mismatch () -> () .local i32 f32.const 1.0 -# CHECK: [[@LINE+1]]:3: error: popped f32, expected i32 +# CHECK: [[@LINE+1]]:3: error: type mismatch, expected [i32] but got [f32] local.set 0 end_function @@ -40,7 +40,7 @@ local_tee_no_local_type: local_tee_empty_stack_while_popping: .functype local_tee_empty_stack_while_popping () -> () .local f32 -# CHECK: :[[@LINE+1]]:3: error: empty stack while popping f32 +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [f32] but got [] local.tee 0 end_function @@ -48,8 +48,9 @@ local_tee_type_mismatch: .functype local_tee_type_mismatch () -> () .local f32 i32.const 1 -# CHECK: :[[@LINE+1]]:3: error: popped i32, expected f32 +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [f32] but got [i32] local.tee 0 + drop end_function global_get_missing_globaltype: @@ -79,7 +80,7 @@ global_set_expected_expression_operand: global_set_empty_stack_while_popping: .functype global_set_empty_stack_while_popping () -> () .globaltype valid_global, i64 -# CHECK: :[[@LINE+1]]:3: error: empty stack while popping i64 +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i64] but got [] global.set valid_global end_function @@ -87,7 +88,7 @@ global_set_type_mismatch: .functype global_set_type_mismatch () -> () .globaltype valid_global, i64 i32.const 1 -# CHECK: :[[@LINE+1]]:3: error: popped i32, expected i64 +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i64] but got [i32] global.set valid_global end_function @@ -109,46 +110,52 @@ table_get_missing_tabletype: table_get_empty_stack_while_popping: .functype table_get_empty_stack_while_popping () -> () -# CHECK: :[[@LINE+1]]:3: error: empty stack while popping i32 +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32] but got [] table.get valid_table + drop end_function table_get_type_mismatch: .functype table_get_type_mismatch () -> () f32.const 1.0 -# CHECK: :[[@LINE+1]]:3: error: popped f32, expected i32 +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32] but got [f32] table.get valid_table + drop end_function table_set_expected_expression_operand: .functype table_set_expected_expression_operand () -> () + i32.const 0 # CHECK: :[[@LINE+1]]:13: error: expected expression operand table.set 1 end_function table_set_missing_tabletype: .functype table_set_missing_tabletype () -> () + i32.const 0 # CHECK: :[[@LINE+1]]:13: error: symbol foo: missing .tabletype table.set foo end_function table_set_empty_stack_while_popping_1: .functype table_set_empty_stack_while_popping_1 () -> () -# CHECK: :[[@LINE+1]]:3: error: empty stack while popping externref +# CHECK: :[[@LINE+2]]:3: error: type mismatch, expected [externref] but got [] +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32] but got [] table.set valid_table end_function table_set_empty_stack_while_popping_2: .functype table_set_empty_stack_while_popping_2 (externref) -> () local.get 0 -# CHECK: :[[@LINE+1]]:3: error: empty stack while popping i32 +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32] but got [] table.set valid_table end_function table_set_type_mismatch_1: .functype table_set_type_mismatch_1 () -> () + i32.const 0 ref.null_func -# CHECK: :[[@LINE+1]]:3: error: popped funcref, expected externref +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [externref] but got [funcref] table.set valid_table end_function @@ -156,32 +163,41 @@ table_set_type_mismatch_2: .functype table_set_type_mismatch_2 () -> () f32.const 1.0 ref.null_extern -# CHECK: :[[@LINE+1]]:3: error: popped f32, expected i32 +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32] but got [f32] table.set valid_table end_function table_fill_expected_expression_operand: .functype table_fill_expected_expression_operand () -> () + i32.const 0 + ref.null_extern + i32.const 4 # CHECK: :[[@LINE+1]]:14: error: expected expression operand table.fill 1 end_function table_fill_missing_tabletype: .functype table_fill_missing_tabletype () -> () + i32.const 0 + ref.null_extern + i32.const 4 # CHECK: :[[@LINE+1]]:14: error: symbol foo: missing .tabletype table.fill foo end_function table_fill_empty_stack_while_popping_1: .functype table_fill_empty_stack_while_popping_1 () -> () -# CHECK: :[[@LINE+1]]:3: error: empty stack while popping i32 +# CHECK: :[[@LINE+3]]:3: error: type mismatch, expected [i32] but got [] +# CHECK: :[[@LINE+2]]:3: error: type mismatch, expected [externref] but got [] +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32] but got [] table.fill valid_table end_function table_fill_empty_stack_while_popping_2: .functype table_fill_empty_stack_while_popping_2 (i32) -> () local.get 0 -# CHECK: :[[@LINE+1]]:3: error: empty stack while popping externref +# CHECK: :[[@LINE+2]]:3: error: type mismatch, expected [externref] but got [] +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32] but got [] table.fill valid_table end_function @@ -189,22 +205,25 @@ table_fill_empty_stack_while_popping_3: .functype table_fill_empty_stack_while_popping_3 (i32, externref) -> () local.get 1 local.get 0 -# CHECK: :[[@LINE+1]]:3: error: empty stack while popping i32 +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32] but got [] table.fill valid_table end_function table_fill_type_mismatch_1: .functype table_fill_type_mismatch_1 () -> () + i32.const 0 + ref.null_extern ref.null_func -# CHECK: :[[@LINE+1]]:3: error: popped funcref, expected i32 +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32] but got [funcref] table.fill valid_table end_function table_fill_type_mismatch_2: .functype table_fill_type_mismatch_2 () -> () + i32.const 0 ref.null_func i32.const 1 -# CHECK: [[@LINE+1]]:3: error: popped funcref, expected externref +# CHECK: [[@LINE+1]]:3: error: type mismatch, expected [externref] but got [funcref] table.fill valid_table end_function @@ -213,23 +232,16 @@ table_fill_type_mismatch_3: f32.const 2.0 ref.null_extern i32.const 1 -# CHECK: :[[@LINE+1]]:3: error: popped f32, expected i32 +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32] but got [f32] table.fill valid_table end_function table_fill_type_mismatch_4: .functype table_fill_type_mismatch_4 () -> () - ref.null_exn i32.const 1 -# CHECK: [[@LINE+1]]:3: error: popped exnref, expected externref - table.fill valid_table - end_function - -table_fill_type_mismatch_5: - .functype table_fill_type_mismatch_5 () -> () ref.null_exn i32.const 1 -# CHECK: [[@LINE+1]]:3: error: popped exnref, expected externref +# CHECK: [[@LINE+1]]:3: error: type mismatch, expected [externref] but got [exnref] table.fill valid_table end_function @@ -244,14 +256,15 @@ table_grow_non_exist_table: table_grow_type_mismatch_1: .functype table_grow_type_mismatch_1 (externref, i32) -> (i32) local.get 1 -# CHECK: [[@LINE+1]]:3: error: empty stack while popping externref +# CHECK: [[@LINE+1]]:3: error: type mismatch, expected [externref] but got [] table.grow valid_table end_function table_grow_type_mismatch_2: .functype table_grow_type_mismatch_2 (externref, i32) -> (i32) local.get 0 -# CHECK: [[@LINE+1]]:3: error: popped externref, expected i32 + local.get 0 +# CHECK: [[@LINE+1]]:3: error: type mismatch, expected [i32] but got [externref] table.grow valid_table end_function @@ -260,57 +273,62 @@ table_grow_wrong_result: local.get 0 local.get 1 table.grow valid_table -# CHECK: [[@LINE+1]]:3: error: popped i32, expected f32 +# CHECK: [[@LINE+1]]:3: error: type mismatch, expected [f32] but got [i32] end_function drop_empty_stack_while_popping: .functype drop_empty_stack_while_popping () -> () -# CHECK: :[[@LINE+1]]:3: error: empty stack while popping value +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [any] but got [] drop end_function end_block_insufficient_values_on_stack_1: .functype end_block_insufficient_values_on_stack_1 () -> () block i32 -# CHECK: :[[@LINE+1]]:3: error: end: insufficient values on the type stack +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32] but got [] end_block + drop end_function end_block_insufficient_values_on_stack_2: .functype end_block_insufficient_values_on_stack_2 () -> () block () -> (i32) -# CHECK: :[[@LINE+1]]:3: error: end: insufficient values on the type stack +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32] but got [] end_block + drop end_function end_block_type_mismatch: .functype end_block_type_mismatch () -> () block i32 f32.const 1.0 -# CHECK: :[[@LINE+1]]:3: error: end got f32, expected i32 +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32] but got [f32] end_block + drop end_function end_loop_insufficient_values_on_stack: .functype end_loop_insufficient_values_on_stack () -> () loop i32 -# CHECK: :[[@LINE+1]]:3: error: end: insufficient values on the type stack +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32] but got [] end_loop + drop end_function end_loop_type_mismatch: .functype end_loop_type_mismatch () -> () loop f32 i32.const 1 -# CHECK: :[[@LINE+1]]:3: error: end got i32, expected f32 +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [f32] but got [i32] end_loop + drop end_function end_if_insufficient_values_on_stack_1: .functype end_if_insufficient_values_on_stack_1 () -> () i32.const 1 if i32 -# CHECK: :[[@LINE+1]]:3: error: end: insufficient values on the type stack +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32] but got [] end_if end_function @@ -319,8 +337,9 @@ end_if_type_mismatch_1: i32.const 1 if f32 i32.const 1 -# CHECK: :[[@LINE+1]]:3: error: end got i32, expected f32 +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [f32] but got [i32] end_if + drop end_function end_if_insufficient_values_on_stack_2: @@ -329,7 +348,7 @@ end_if_insufficient_values_on_stack_2: if i32 i32.const 2 else -# CHECK: :[[@LINE+1]]:3: error: end: insufficient values on the type stack +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32] but got [] end_if drop end_function @@ -341,7 +360,7 @@ end_if_type_mismatch_2: i32.const 2 else f32.const 3.0 -# CHECK: :[[@LINE+1]]:3: error: end got f32, expected i32 +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32] but got [f32] end_if drop end_function @@ -350,7 +369,7 @@ else_insufficient_values_on_stack: .functype else_insufficient_values_on_stack () -> () i32.const 1 if i32 -# CHECK: :[[@LINE+1]]:3: error: end: insufficient values on the type stack +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32] but got [] else i32.const 0 end_if @@ -362,7 +381,7 @@ else_type_mismatch: i32.const 1 if i32 f32.const 0.0 -# CHECK: :[[@LINE+1]]:3: error: popped f32, expected i32 +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32] but got [f32] else i32.const 0 end_if @@ -377,7 +396,7 @@ end_try_insufficient_values_on_stack: try i32 i32.const 0 catch_all -# CHECK: :[[@LINE+1]]:3: error: end: insufficient values on the type stack +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32] but got [] end_try drop end_function @@ -387,7 +406,7 @@ end_try_type_mismatch: try i32 i32.const 0 catch tag_f32 -# CHECK: :[[@LINE+1]]:3: error: end got f32, expected i32 +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32] but got [f32] end_try drop end_function @@ -395,7 +414,7 @@ end_try_type_mismatch: catch_insufficient_values_on_stack: .functype catch_insufficient_values_on_stack () -> () try i32 -# CHECK: :[[@LINE+1]]:3: error: end: insufficient values on the type stack +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32] but got [] catch tag_i32 end_try drop @@ -405,7 +424,7 @@ catch_type_mismatch: .functype catch_type_mismatch () -> () try i32 f32.const 1.0 -# CHECK: :[[@LINE+1]]:3: error: popped f32, expected i32 +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32] but got [f32] catch tag_i32 end_try drop @@ -414,7 +433,7 @@ catch_type_mismatch: catch_all_insufficient_values_on_stack: .functype catch_all_insufficient_values_on_stack () -> () try i32 -# CHECK: :[[@LINE+1]]:3: error: end: insufficient values on the type stack +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32] but got [] catch_all i32.const 0 end_try @@ -425,7 +444,7 @@ catch_all_type_mismatch: .functype catch_all_type_mismatch () -> () try i32 f32.const 1.0 -# CHECK: :[[@LINE+1]]:3: error: popped f32, expected i32 +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32] but got [f32] catch_all i32.const 0 end_try @@ -435,7 +454,7 @@ catch_all_type_mismatch: delegate_insufficient_values_on_stack: .functype delegate_insufficient_values_on_stack () -> () try i32 -# CHECK: :[[@LINE+1]]:3: error: end: insufficient values on the type stack +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32] but got [] delegate 0 drop end_function @@ -444,46 +463,46 @@ delegate_type_mismatch: .functype delegate_type_mismatch () -> () try i32 f32.const 1.0 -# CHECK: :[[@LINE+1]]:3: error: end got f32, expected i32 +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32] but got [f32] delegate 0 drop end_function end_function_empty_stack_while_popping: .functype end_function_empty_stack_while_popping () -> (i32) -# CHECK: :[[@LINE+1]]:3: error: empty stack while popping i32 +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32] but got [] end_function end_function_type_mismatch: .functype end_function_type_mismatch () -> (f32) i32.const 1 -# CHECK: :[[@LINE+1]]:3: error: popped i32, expected f32 +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [f32] but got [i32] end_function end_function_superfluous_end_function_values: .functype end_function_superfluous_end_function_values () -> () i32.const 1 f32.const 2.0 -# CHECK: :[[@LINE+1]]:3: error: 2 superfluous return values +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [] but got [i32, f32] end_function return_empty_stack_while_popping: .functype return_empty_stack_while_popping () -> (i32) -# CHECK: :[[@LINE+1]]:3: error: empty stack while popping i32 +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32] but got [] return end_function return_type_mismatch: .functype return_type_mismatch () -> (f32) i32.const 1 -# CHECK: :[[@LINE+1]]:3: error: popped i32, expected f32 +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [f32] but got [i32] return end_function # Missing index for call_indirect. call_indirect_empty_stack_while_popping_1: .functype call_indirect_empty_stack_while_popping_1 () -> () -# CHECK: :[[@LINE+1]]:3: error: empty stack while popping i32 +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32] but got [] call_indirect () -> () end_function @@ -491,7 +510,7 @@ call_indirect_empty_stack_while_popping_1: call_indirect_empty_stack_while_popping_2: .functype call_indirect_empty_stack_while_popping_1 (f32) -> () i32.const 1 -# CHECK: :[[@LINE+1]]:3: error: empty stack while popping f32 +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [f32] but got [] call_indirect (f32) -> () end_function @@ -499,7 +518,7 @@ call_indirect_type_mismatch_for_argument: .functype call_indirect_type_mismatch_for_argument () -> () i32.const 1 i32.const 2 -# CHECK: :[[@LINE+1]]:3: error: popped i32, expected f32 +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [f32] but got [i32] call_indirect (f32) -> () end_function @@ -507,13 +526,13 @@ call_indirect_superfluous_value_at_end: .functype call_indirect_superfluous_value_at_end () -> () i32.const 1 call_indirect () -> (i64) -# CHECK: :[[@LINE+1]]:3: error: 1 superfluous return values +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [] but got [i64] end_function # Missing index for return_call_indirect. return_call_indirect_empty_stack_while_popping_1: .functype return_call_indirect_empty_stack_while_popping_1 () -> () -# CHECK: :[[@LINE+1]]:3: error: empty stack while popping i32 +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32] but got [] return_call_indirect () -> () end_function @@ -521,7 +540,7 @@ return_call_indirect_empty_stack_while_popping_1: return_call_indirect_empty_stack_while_popping_2: .functype return_call_indirect_empty_stack_while_popping_2 () -> () i32.const 1 -# CHECK: :[[@LINE+1]]:3: error: empty stack while popping f32 +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [f32] but got [] return_call_indirect (f32) -> () end_function @@ -535,14 +554,14 @@ call_expected_expression_operand: call_empty_stack_while_popping: .functype call_empty_stack_while_popping () -> () -# CHECK: [[@LINE+1]]:3: error: empty stack while popping i32 +# CHECK: [[@LINE+1]]:3: error: type mismatch, expected [i32] but got [] call fn_i32_to_void end_function call_type_mismatch: .functype call_type_mismatch () -> () f32.const 1.0 -# CHECK: :[[@LINE+1]]:3: error: popped f32, expected i32 +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32] but got [f32] call fn_i32_to_void end_function @@ -551,7 +570,7 @@ call_type_mismatch: call_superfluous_value_at_end: .functype call_superfluous_value_at_end () -> () call fn_void_to_i32 -# CHECK: :[[@LINE+1]]:3: error: 1 superfluous return values +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [] but got [i32] end_function call_missing_functype: @@ -568,14 +587,14 @@ return_call_expected_expression_operand: return_call_empty_stack_while_popping: .functype return_call_empty_stack_while_popping () -> () -# CHECK: [[@LINE+1]]:3: error: empty stack while popping i32 +# CHECK: [[@LINE+1]]:3: error: type mismatch, expected [i32] but got [] return_call fn_i32_to_void end_function return_call_type_mismatch: .functype return_call_type_mismatch () -> () f32.const 1.0 -# CHECK: :[[@LINE+1]]:3: error: popped f32, expected i32 +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32] but got [f32] return_call fn_i32_to_void end_function @@ -607,27 +626,29 @@ catch_superfluous_value_at_end: catch tag_i32 end_try # FIXME: Superfluous value should be caught at end_try? -# CHECK: :[[@LINE+1]]:3: error: 1 superfluous return values +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [] but got [i32] end_function ref_is_null_empty_stack_while_popping: .functype ref_is_null_empty_stack_while_popping () -> () -# CHECK: [[@LINE+1]]:3: error: empty stack while popping reftype +# CHECK: [[@LINE+1]]:3: error: type mismatch, expected [ref] but got [] ref.is_null + drop end_function ref_is_null_type_mismatch: .functype ref_is_null_type_mismatch () -> () i32.const 1 -# CHECK: [[@LINE+1]]:3: error: popped i32, expected reftype +# CHECK: [[@LINE+1]]:3: error: type mismatch, expected [ref] but got [i32] ref.is_null + drop end_function ref_is_null_pushes_i32: .functype ref_is_null_pushes_i32 () -> (i64) ref.null_func ref.is_null -# CHECK: :[[@LINE+1]]:3: error: popped i32, expected i64 +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i64] but got [i32] end_function # For the other instructions, the type checker checks vs the operands in the @@ -636,16 +657,18 @@ ref_is_null_pushes_i32: other_insn_test_1: .functype other_insn_test_1 () -> () -# CHECK: [[@LINE+1]]:3: error: empty stack while popping i32 +# CHECK: [[@LINE+1]]:3: error: type mismatch, expected [i32, i32] but got [] i32.add + drop end_function other_insn_test_2: .functype other_insn_test_2 () -> () i32.const 1 ref.null_func -# CHECK: :[[@LINE+1]]:3: error: popped funcref, expected i32 +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32, i32] but got [i32, funcref] i32.add + drop end_function other_insn_test_3: @@ -653,7 +676,7 @@ other_insn_test_3: f32.const 1.0 f32.const 2.0 f32.add -# CHECK: :[[@LINE+1]]:3: error: 1 superfluous return values +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [] but got [f32] end_function # Unreachable code within 'block' does not affect type checking after @@ -663,7 +686,7 @@ check_after_unreachable_within_block: block unreachable end_block -# CHECK: :[[@LINE+1]]:3: error: empty stack while popping value +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [any] but got [] drop end_function @@ -673,7 +696,7 @@ check_after_unreachable_within_loop: loop unreachable end_loop -# CHECK: :[[@LINE+1]]:3: error: empty stack while popping value +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [any] but got [] drop end_function @@ -686,7 +709,7 @@ check_after_unreachable_within_if_1: else unreachable end_if -# CHECK: :[[@LINE+1]]:3: error: empty stack while popping value +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [any] but got [] drop end_function @@ -697,7 +720,7 @@ check_after_unreachable_within_if_2: if unreachable else -# CHECK: :[[@LINE+1]]:3: error: empty stack while popping value +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [any] but got [] drop end_if end_function @@ -710,7 +733,7 @@ check_after_unreachable_within_try_1: catch_all unreachable end_try -# CHECK: :[[@LINE+1]]:3: error: empty stack while popping value +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [any] but got [] drop end_function @@ -721,7 +744,7 @@ check_after_unreachable_within_try_2: unreachable catch tag_i32 drop -# CHECK: :[[@LINE+1]]:3: error: empty stack while popping value +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [any] but got [] drop end_try end_function @@ -732,7 +755,7 @@ check_after_unreachable_within_try_3: try unreachable catch_all -# CHECK: :[[@LINE+1]]:3: error: empty stack while popping value +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [any] but got [] drop end_try end_function @@ -743,7 +766,7 @@ check_after_unreachable_within_try_4: try unreachable delegate 0 -# CHECK: :[[@LINE+1]]:3: error: empty stack while popping value +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [any] but got [] drop end_function @@ -753,7 +776,7 @@ br_invalid_type_loop: loop (i32) -> (f32) drop f32.const 1.0 -# CHECK: :[[@LINE+1]]:5: error: br got f32, expected i32 +# CHECK: :[[@LINE+1]]:5: error: type mismatch, expected [i32] but got [f32] br 0 end_loop drop @@ -763,7 +786,7 @@ br_invalid_type_block: .functype br_invalid_type_block () -> () i32.const 1 block (i32) -> (f32) -# CHECK: :[[@LINE+1]]:5: error: br got i32, expected f32 +# CHECK: :[[@LINE+1]]:5: error: type mismatch, expected [f32] but got [i32] br 0 f32.const 1.0 end_block @@ -777,7 +800,7 @@ br_invalid_type_if: f32.const 1.0 else i32.const 1 -# CHECK: :[[@LINE+1]]:5: error: br got i32, expected f32 +# CHECK: :[[@LINE+1]]:5: error: type mismatch, expected [f32] but got [i32] br 0 end_if drop @@ -787,7 +810,7 @@ br_invalid_type_try: .functype br_invalid_type_try () -> () try f32 i32.const 1 -# CHECK: :[[@LINE+1]]:5: error: br got i32, expected f32 +# CHECK: :[[@LINE+1]]:5: error: type mismatch, expected [f32] but got [i32] br 0 catch tag_f32 end_try @@ -799,7 +822,7 @@ br_invalid_type_catch: try f32 f32.const 1.0 catch tag_i32 -# CHECK: :[[@LINE+1]]:5: error: br got i32, expected f32 +# CHECK: :[[@LINE+1]]:5: error: type mismatch, expected [f32] but got [i32] br 0 end_try drop @@ -811,7 +834,7 @@ br_invalid_type_catch_all: f32.const 1.0 catch_all i32.const 1 -# CHECK: :[[@LINE+1]]:5: error: br got i32, expected f32 +# CHECK: :[[@LINE+1]]:5: error: type mismatch, expected [f32] but got [i32] br 0 end_try drop @@ -834,7 +857,7 @@ br_incorrect_signature: block f32 block i32 i32.const 1 -# CHECK: :[[@LINE+1]]:7: error: br got i32, expected f32 +# CHECK: :[[@LINE+1]]:7: error: type mismatch, expected [f32] but got [i32] br 1 end_block drop @@ -847,7 +870,7 @@ br_incorrect_func_signature: .functype br_incorrect_func_signature () -> (i32) block f32 f32.const 1.0 -# CHECK: :[[@LINE+1]]:5: error: br got f32, expected i32 +# CHECK: :[[@LINE+1]]:5: error: type mismatch, expected [i32] but got [f32] br 1 end_block drop @@ -856,20 +879,29 @@ br_incorrect_func_signature: multiple_errors_in_function: .functype multiple_errors_in_function () -> () -# CHECK: :[[@LINE+2]]:3: error: empty stack while popping i32 +# CHECK: :[[@LINE+2]]:3: error: type mismatch, expected [i32] but got [] # CHECK: :[[@LINE+1]]:13: error: expected expression operand table.get 1 -# CHECK: :[[@LINE+3]]:3: error: empty stack while popping i32 -# CHECK: :[[@LINE+2]]:3: error: empty stack while popping externref -# CHECK: :[[@LINE+1]]:3: error: empty stack while popping i32 +# CHECK: :[[@LINE+3]]:3: error: type mismatch, expected [i32] but got [] +# CHECK: :[[@LINE+2]]:3: error: type mismatch, expected [externref] but got [] +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32] but got [] table.fill valid_table f32.const 0.0 ref.null_extern -# CHECK: :[[@LINE+2]]:3: error: popped externref, expected i32 -# CHECK: :[[@LINE+1]]:3: error: popped f32, expected i32 +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32, i32] but got [f32, externref] i32.add drop + end_function + +.functype take_and_return_multi(i32, i64, f32, f64) -> (i32, i64, f32, f64) +call_with_multi_param_and_return: + .functype call_with_multi_param_and_return () -> (i32) + ref.null_extern + f32.const 0.0 +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32, i64, f32, f64] but got [externref, f32] + call take_and_return_multi +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32] but got [i32, i64, f32, f64] end_function diff --git a/llvm/test/MC/WebAssembly/type-checker-return.s b/llvm/test/MC/WebAssembly/type-checker-return.s index 552093bc555bd..016c034058101 100644 --- a/llvm/test/MC/WebAssembly/type-checker-return.s +++ b/llvm/test/MC/WebAssembly/type-checker-return.s @@ -1,10 +1,5 @@ # RUN: llvm-mc -triple=wasm32 -mattr=+tail-call %s 2>&1 -# XFAIL: * - -# FIXME: These shouldn't produce an error, as return will implicitly drop any -# superfluous values. - return_superfluous_return_values: .functype return_superfluous_return_values () -> () i32.const 1 From f6dacda94907c83942760dd49578a31fc5f990bf Mon Sep 17 00:00:00 2001 From: Luke Lau Date: Fri, 27 Sep 2024 09:35:14 +0800 Subject: [PATCH 031/469] [RISCV] Fold vfmv.f.s into load from stack (#110129) This is the f64/f32 version of #109774. I've left out f16 and bf16 for now because there's a separate issue where we can't select extract_vector_elt when f16/bf16 is a legal type, see #110126. --- llvm/lib/Target/RISCV/RISCVInstrInfo.cpp | 18 ++++ .../CodeGen/RISCV/rvv/fpclamptosat_vec.ll | 50 ++-------- llvm/test/CodeGen/RISCV/rvv/stack-folding.ll | 97 +++++++++++++++++++ 3 files changed, 125 insertions(+), 40 deletions(-) diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp b/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp index 8dafd824963c0..10b4e4870aebe 100644 --- a/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp +++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp @@ -784,6 +784,24 @@ MachineInstr *RISCVInstrInfo::foldMemoryOperandImpl( } break; } + if (RISCV::getRVVMCOpcode(MI.getOpcode()) == RISCV::VFMV_F_S) { + unsigned Log2SEW = + MI.getOperand(RISCVII::getSEWOpNum(MI.getDesc())).getImm(); + switch (Log2SEW) { + case 4: + // TODO: Support f16/bf16 + return nullptr; + case 5: + LoadOpc = RISCV::FLW; + break; + case 6: + LoadOpc = RISCV::FLD; + break; + default: + llvm_unreachable("Unexpected SEW"); + } + break; + } return nullptr; case RISCV::SEXT_H: LoadOpc = RISCV::LH; diff --git a/llvm/test/CodeGen/RISCV/rvv/fpclamptosat_vec.ll b/llvm/test/CodeGen/RISCV/rvv/fpclamptosat_vec.ll index 1395dc914bb40..3c184c112e77a 100644 --- a/llvm/test/CodeGen/RISCV/rvv/fpclamptosat_vec.ll +++ b/llvm/test/CodeGen/RISCV/rvv/fpclamptosat_vec.ll @@ -2261,10 +2261,7 @@ define <2 x i64> @stest_f64i64(<2 x double> %x) { ; CHECK-V-NEXT: call __fixdfti ; CHECK-V-NEXT: mv s0, a0 ; CHECK-V-NEXT: mv s1, a1 -; CHECK-V-NEXT: addi a0, sp, 32 -; CHECK-V-NEXT: vl1r.v v8, (a0) # Unknown-size Folded Reload -; CHECK-V-NEXT: vsetivli zero, 1, e64, m1, ta, ma -; CHECK-V-NEXT: vfmv.f.s fa0, v8 +; CHECK-V-NEXT: fld fa0, 32(sp) # 8-byte Folded Reload ; CHECK-V-NEXT: call __fixdfti ; CHECK-V-NEXT: li a2, -1 ; CHECK-V-NEXT: srli a3, a2, 1 @@ -2394,10 +2391,7 @@ define <2 x i64> @utest_f64i64(<2 x double> %x) { ; CHECK-V-NEXT: call __fixunsdfti ; CHECK-V-NEXT: mv s0, a0 ; CHECK-V-NEXT: mv s1, a1 -; CHECK-V-NEXT: addi a0, sp, 32 -; CHECK-V-NEXT: vl1r.v v8, (a0) # Unknown-size Folded Reload -; CHECK-V-NEXT: vsetivli zero, 1, e64, m1, ta, ma -; CHECK-V-NEXT: vfmv.f.s fa0, v8 +; CHECK-V-NEXT: fld fa0, 32(sp) # 8-byte Folded Reload ; CHECK-V-NEXT: call __fixunsdfti ; CHECK-V-NEXT: snez a1, a1 ; CHECK-V-NEXT: snez a2, s1 @@ -2506,10 +2500,7 @@ define <2 x i64> @ustest_f64i64(<2 x double> %x) { ; CHECK-V-NEXT: call __fixdfti ; CHECK-V-NEXT: mv s0, a0 ; CHECK-V-NEXT: mv s1, a1 -; CHECK-V-NEXT: addi a0, sp, 32 -; CHECK-V-NEXT: vl1r.v v8, (a0) # Unknown-size Folded Reload -; CHECK-V-NEXT: vsetivli zero, 1, e64, m1, ta, ma -; CHECK-V-NEXT: vfmv.f.s fa0, v8 +; CHECK-V-NEXT: fld fa0, 32(sp) # 8-byte Folded Reload ; CHECK-V-NEXT: call __fixdfti ; CHECK-V-NEXT: mv a2, s1 ; CHECK-V-NEXT: blez s1, .LBB20_2 @@ -2668,10 +2659,7 @@ define <2 x i64> @stest_f32i64(<2 x float> %x) { ; CHECK-V-NEXT: call __fixsfti ; CHECK-V-NEXT: mv s0, a0 ; CHECK-V-NEXT: mv s1, a1 -; CHECK-V-NEXT: addi a0, sp, 32 -; CHECK-V-NEXT: vl1r.v v8, (a0) # Unknown-size Folded Reload -; CHECK-V-NEXT: vsetivli zero, 1, e32, m1, ta, ma -; CHECK-V-NEXT: vfmv.f.s fa0, v8 +; CHECK-V-NEXT: flw fa0, 32(sp) # 8-byte Folded Reload ; CHECK-V-NEXT: call __fixsfti ; CHECK-V-NEXT: li a2, -1 ; CHECK-V-NEXT: srli a3, a2, 1 @@ -2801,10 +2789,7 @@ define <2 x i64> @utest_f32i64(<2 x float> %x) { ; CHECK-V-NEXT: call __fixunssfti ; CHECK-V-NEXT: mv s0, a0 ; CHECK-V-NEXT: mv s1, a1 -; CHECK-V-NEXT: addi a0, sp, 32 -; CHECK-V-NEXT: vl1r.v v8, (a0) # Unknown-size Folded Reload -; CHECK-V-NEXT: vsetivli zero, 1, e32, m1, ta, ma -; CHECK-V-NEXT: vfmv.f.s fa0, v8 +; CHECK-V-NEXT: flw fa0, 32(sp) # 8-byte Folded Reload ; CHECK-V-NEXT: call __fixunssfti ; CHECK-V-NEXT: snez a1, a1 ; CHECK-V-NEXT: snez a2, s1 @@ -2913,10 +2898,7 @@ define <2 x i64> @ustest_f32i64(<2 x float> %x) { ; CHECK-V-NEXT: call __fixsfti ; CHECK-V-NEXT: mv s0, a0 ; CHECK-V-NEXT: mv s1, a1 -; CHECK-V-NEXT: addi a0, sp, 32 -; CHECK-V-NEXT: vl1r.v v8, (a0) # Unknown-size Folded Reload -; CHECK-V-NEXT: vsetivli zero, 1, e32, m1, ta, ma -; CHECK-V-NEXT: vfmv.f.s fa0, v8 +; CHECK-V-NEXT: flw fa0, 32(sp) # 8-byte Folded Reload ; CHECK-V-NEXT: call __fixsfti ; CHECK-V-NEXT: mv a2, s1 ; CHECK-V-NEXT: blez s1, .LBB23_2 @@ -5597,10 +5579,7 @@ define <2 x i64> @stest_f64i64_mm(<2 x double> %x) { ; CHECK-V-NEXT: call __fixdfti ; CHECK-V-NEXT: mv s0, a0 ; CHECK-V-NEXT: mv s1, a1 -; CHECK-V-NEXT: addi a0, sp, 32 -; CHECK-V-NEXT: vl1r.v v8, (a0) # Unknown-size Folded Reload -; CHECK-V-NEXT: vsetivli zero, 1, e64, m1, ta, ma -; CHECK-V-NEXT: vfmv.f.s fa0, v8 +; CHECK-V-NEXT: fld fa0, 32(sp) # 8-byte Folded Reload ; CHECK-V-NEXT: call __fixdfti ; CHECK-V-NEXT: li a2, -1 ; CHECK-V-NEXT: srli a3, a2, 1 @@ -5831,10 +5810,7 @@ define <2 x i64> @ustest_f64i64_mm(<2 x double> %x) { ; CHECK-V-NEXT: call __fixdfti ; CHECK-V-NEXT: mv s0, a0 ; CHECK-V-NEXT: mv s1, a1 -; CHECK-V-NEXT: addi a0, sp, 32 -; CHECK-V-NEXT: vl1r.v v8, (a0) # Unknown-size Folded Reload -; CHECK-V-NEXT: vsetivli zero, 1, e64, m1, ta, ma -; CHECK-V-NEXT: vfmv.f.s fa0, v8 +; CHECK-V-NEXT: fld fa0, 32(sp) # 8-byte Folded Reload ; CHECK-V-NEXT: call __fixdfti ; CHECK-V-NEXT: mv a2, a1 ; CHECK-V-NEXT: blez a1, .LBB47_2 @@ -5983,10 +5959,7 @@ define <2 x i64> @stest_f32i64_mm(<2 x float> %x) { ; CHECK-V-NEXT: call __fixsfti ; CHECK-V-NEXT: mv s0, a0 ; CHECK-V-NEXT: mv s1, a1 -; CHECK-V-NEXT: addi a0, sp, 32 -; CHECK-V-NEXT: vl1r.v v8, (a0) # Unknown-size Folded Reload -; CHECK-V-NEXT: vsetivli zero, 1, e32, m1, ta, ma -; CHECK-V-NEXT: vfmv.f.s fa0, v8 +; CHECK-V-NEXT: flw fa0, 32(sp) # 8-byte Folded Reload ; CHECK-V-NEXT: call __fixsfti ; CHECK-V-NEXT: li a2, -1 ; CHECK-V-NEXT: srli a3, a2, 1 @@ -6217,10 +6190,7 @@ define <2 x i64> @ustest_f32i64_mm(<2 x float> %x) { ; CHECK-V-NEXT: call __fixsfti ; CHECK-V-NEXT: mv s0, a0 ; CHECK-V-NEXT: mv s1, a1 -; CHECK-V-NEXT: addi a0, sp, 32 -; CHECK-V-NEXT: vl1r.v v8, (a0) # Unknown-size Folded Reload -; CHECK-V-NEXT: vsetivli zero, 1, e32, m1, ta, ma -; CHECK-V-NEXT: vfmv.f.s fa0, v8 +; CHECK-V-NEXT: flw fa0, 32(sp) # 8-byte Folded Reload ; CHECK-V-NEXT: call __fixsfti ; CHECK-V-NEXT: mv a2, a1 ; CHECK-V-NEXT: blez a1, .LBB50_2 diff --git a/llvm/test/CodeGen/RISCV/rvv/stack-folding.ll b/llvm/test/CodeGen/RISCV/rvv/stack-folding.ll index 4771d7fe6ec92..f966835622a9f 100644 --- a/llvm/test/CodeGen/RISCV/rvv/stack-folding.ll +++ b/llvm/test/CodeGen/RISCV/rvv/stack-folding.ll @@ -160,3 +160,100 @@ truebb: falsebb: ret i8 0 } + +define double @f64( %v, i1 %c) { +; RV32-LABEL: f64: +; RV32: # %bb.0: +; RV32-NEXT: addi sp, sp, -16 +; RV32-NEXT: .cfi_def_cfa_offset 16 +; RV32-NEXT: csrr a1, vlenb +; RV32-NEXT: slli a1, a1, 1 +; RV32-NEXT: sub sp, sp, a1 +; RV32-NEXT: .cfi_escape 0x0f, 0x0d, 0x72, 0x00, 0x11, 0x10, 0x22, 0x11, 0x02, 0x92, 0xa2, 0x38, 0x00, 0x1e, 0x22 # sp + 16 + 2 * vlenb +; RV32-NEXT: addi a1, sp, 16 +; RV32-NEXT: vs1r.v v8, (a1) # Unknown-size Folded Spill +; RV32-NEXT: andi a0, a0, 1 +; RV32-NEXT: #APP +; RV32-NEXT: #NO_APP +; RV32-NEXT: beqz a0, .LBB4_2 +; RV32-NEXT: # %bb.1: # %truebb +; RV32-NEXT: fld fa0, 16(sp) # 8-byte Folded Reload +; RV32-NEXT: j .LBB4_3 +; RV32-NEXT: .LBB4_2: # %falsebb +; RV32-NEXT: fcvt.d.w fa0, zero +; RV32-NEXT: .LBB4_3: # %falsebb +; RV32-NEXT: csrr a0, vlenb +; RV32-NEXT: slli a0, a0, 1 +; RV32-NEXT: add sp, sp, a0 +; RV32-NEXT: addi sp, sp, 16 +; RV32-NEXT: ret +; +; RV64-LABEL: f64: +; RV64: # %bb.0: +; RV64-NEXT: addi sp, sp, -16 +; RV64-NEXT: .cfi_def_cfa_offset 16 +; RV64-NEXT: csrr a1, vlenb +; RV64-NEXT: slli a1, a1, 1 +; RV64-NEXT: sub sp, sp, a1 +; RV64-NEXT: .cfi_escape 0x0f, 0x0d, 0x72, 0x00, 0x11, 0x10, 0x22, 0x11, 0x02, 0x92, 0xa2, 0x38, 0x00, 0x1e, 0x22 # sp + 16 + 2 * vlenb +; RV64-NEXT: addi a1, sp, 16 +; RV64-NEXT: vs1r.v v8, (a1) # Unknown-size Folded Spill +; RV64-NEXT: andi a0, a0, 1 +; RV64-NEXT: #APP +; RV64-NEXT: #NO_APP +; RV64-NEXT: beqz a0, .LBB4_2 +; RV64-NEXT: # %bb.1: # %truebb +; RV64-NEXT: fld fa0, 16(sp) # 8-byte Folded Reload +; RV64-NEXT: j .LBB4_3 +; RV64-NEXT: .LBB4_2: # %falsebb +; RV64-NEXT: fmv.d.x fa0, zero +; RV64-NEXT: .LBB4_3: # %falsebb +; RV64-NEXT: csrr a0, vlenb +; RV64-NEXT: slli a0, a0, 1 +; RV64-NEXT: add sp, sp, a0 +; RV64-NEXT: addi sp, sp, 16 +; RV64-NEXT: ret + tail call void asm sideeffect "", "~{v0},~{v1},~{v2},~{v3},~{v4},~{v5},~{v6},~{v7},~{v8},~{v9},~{v10},~{v11},~{v12},~{v13},~{v14},~{v15},~{v16},~{v17},~{v18},~{v19},~{v20},~{v21},~{v22},~{v23},~{v24},~{v25},~{v26},~{v27},~{v28},~{v29},~{v30},~{v31}"() + br i1 %c, label %truebb, label %falsebb +truebb: + %x = extractelement %v, i32 0 + ret double %x +falsebb: + ret double 0.0 +} + +define float @f32( %v, i1 %c) { +; CHECK-LABEL: f32: +; CHECK: # %bb.0: +; CHECK-NEXT: addi sp, sp, -16 +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: csrr a1, vlenb +; CHECK-NEXT: slli a1, a1, 1 +; CHECK-NEXT: sub sp, sp, a1 +; CHECK-NEXT: .cfi_escape 0x0f, 0x0d, 0x72, 0x00, 0x11, 0x10, 0x22, 0x11, 0x02, 0x92, 0xa2, 0x38, 0x00, 0x1e, 0x22 # sp + 16 + 2 * vlenb +; CHECK-NEXT: addi a1, sp, 16 +; CHECK-NEXT: vs1r.v v8, (a1) # Unknown-size Folded Spill +; CHECK-NEXT: andi a0, a0, 1 +; CHECK-NEXT: #APP +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: beqz a0, .LBB5_2 +; CHECK-NEXT: # %bb.1: # %truebb +; CHECK-NEXT: flw fa0, 16(sp) # 8-byte Folded Reload +; CHECK-NEXT: j .LBB5_3 +; CHECK-NEXT: .LBB5_2: # %falsebb +; CHECK-NEXT: fmv.w.x fa0, zero +; CHECK-NEXT: .LBB5_3: # %falsebb +; CHECK-NEXT: csrr a0, vlenb +; CHECK-NEXT: slli a0, a0, 1 +; CHECK-NEXT: add sp, sp, a0 +; CHECK-NEXT: addi sp, sp, 16 +; CHECK-NEXT: ret + tail call void asm sideeffect "", "~{v0},~{v1},~{v2},~{v3},~{v4},~{v5},~{v6},~{v7},~{v8},~{v9},~{v10},~{v11},~{v12},~{v13},~{v14},~{v15},~{v16},~{v17},~{v18},~{v19},~{v20},~{v21},~{v22},~{v23},~{v24},~{v25},~{v26},~{v27},~{v28},~{v29},~{v30},~{v31}"() + br i1 %c, label %truebb, label %falsebb +truebb: + %x = extractelement %v, i32 0 + ret float %x +falsebb: + ret float 0.0 +} + From f6a756f35a4d0719a96b4e214905369d565d87da Mon Sep 17 00:00:00 2001 From: "xiaohui1.xu" Date: Fri, 27 Sep 2024 09:43:57 +0800 Subject: [PATCH 032/469] [mlir][linalg] fix segmentation fault in isContractionBody function (#108703) Fix Segmentation Fault in function. `getDefiningOp()` may return `nullptr` pointer. --- mlir/lib/Dialect/Linalg/IR/LinalgInterfaces.cpp | 2 +- .../Dialect/Linalg/match-ops-interpreter.mlir | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/mlir/lib/Dialect/Linalg/IR/LinalgInterfaces.cpp b/mlir/lib/Dialect/Linalg/IR/LinalgInterfaces.cpp index 0c48a5aeb26a2..0b5191664a9e2 100644 --- a/mlir/lib/Dialect/Linalg/IR/LinalgInterfaces.cpp +++ b/mlir/lib/Dialect/Linalg/IR/LinalgInterfaces.cpp @@ -222,7 +222,7 @@ bool mlir::linalg::detail::isContractionBody( Value contributed = getSourceSkipUnary( isa(reductionLHS) ? reductionRHS : reductionLHS); Operation *elementwiseOp = contributed.getDefiningOp(); - if (elementwiseOp->getNumResults() != 1 || + if (!elementwiseOp || elementwiseOp->getNumResults() != 1 || elementwiseOp->getNumOperands() != 2) { errs << "expected elementwise op to be binary"; return false; diff --git a/mlir/test/Dialect/Linalg/match-ops-interpreter.mlir b/mlir/test/Dialect/Linalg/match-ops-interpreter.mlir index 4bfed475d44f6..bfe7a07cb38a5 100644 --- a/mlir/test/Dialect/Linalg/match-ops-interpreter.mlir +++ b/mlir/test/Dialect/Linalg/match-ops-interpreter.mlir @@ -996,6 +996,21 @@ module attributes { transform.target_tag = "start_here" } { } -> tensor<40x10x50x15xf32> return %result : tensor<40x10x50x15xf32> } + + func.func @generic_min(%arg0: tensor<1x7x4xf32>, %arg1: tensor<4xf32>, %arg2: tensor<1x1x4xf32>) { + linalg.generic { + indexing_maps = [affine_map<(d0, d1, d2, d3) -> (d0, d1 * 2 + d3 * 2, d2)>, + affine_map<(d0, d1, d2, d3) -> (d3)>, + affine_map<(d0, d1, d2, d3) -> (d0, d1, d2)>], + iterator_types = ["parallel", "parallel", "parallel", "reduction"]} + ins(%arg0, %arg1 : tensor<1x7x4xf32>, tensor<4xf32>) + outs(%arg2 : tensor<1x1x4xf32>) { + ^bb0(%in: f32, %in_1: f32, %out: f32): + %5 = arith.minimumf %out, %in : f32 + linalg.yield %5 : f32 + } -> tensor<1x1x4xf32> + return + } } // ----- From 44950de5b1496aaf524b73201579f56ff4325c52 Mon Sep 17 00:00:00 2001 From: Joseph Huber Date: Thu, 26 Sep 2024 18:48:01 -0700 Subject: [PATCH 033/469] [nvlink-wrapper] Use a symbolic link instead of copying the file (#110139) Summary: We need all inputs to `nvlink` to end in `.cubin` while the rest of the compiler toolchain wants `.o`. Previously we copied `.o` file to `.cubin` files, but this is wasteful. Instead, we can just create a link against it. This saves some disk space during link time. --- .../clang-nvlink-wrapper/ClangNVLinkWrapper.cpp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/clang/tools/clang-nvlink-wrapper/ClangNVLinkWrapper.cpp b/clang/tools/clang-nvlink-wrapper/ClangNVLinkWrapper.cpp index 871fe5e4553cc..8ec1f722fa8a1 100644 --- a/clang/tools/clang-nvlink-wrapper/ClangNVLinkWrapper.cpp +++ b/clang/tools/clang-nvlink-wrapper/ClangNVLinkWrapper.cpp @@ -655,9 +655,11 @@ Expected> getInput(const ArgList &Args) { } } - // Copy all of the input files to a new file ending in `.cubin`. The 'nvlink' + // Create a link for each file to a new file ending in `.cubin`. The 'nvlink' // linker requires all NVPTX inputs to have this extension for some reason. + // Windows cannot create symbolic links so we just copy the whole file. for (auto &Input : LinkerInput) { +#ifdef _WIN32 auto TempFileOrErr = createTempFile( Args, sys::path::stem(Input->getBufferIdentifier()), "cubin"); if (!TempFileOrErr) @@ -671,6 +673,18 @@ Expected> getInput(const ArgList &Args) { if (Error E = Output->commit()) return E; Files.emplace_back(Args.MakeArgString(*TempFileOrErr)); +#else + SmallString<128> TempFile; + if (std::error_code EC = sys::fs::getPotentiallyUniqueTempFileName( + sys::path::stem(Input->getBufferIdentifier()), "cubin", TempFile)) + reportError(createFileError(TempFile, EC)); + if (std::error_code EC = + sys::fs::create_link(Input->getBufferIdentifier(), TempFile)) { + reportError(createFileError(TempFile, EC)); + } + Files.emplace_back(Args.MakeArgString(TempFile)); + TempFiles.emplace_back(std::move(TempFile)); +#endif } return Files; From f7dfaf35065fc858056a206b10c3dfbf8029f801 Mon Sep 17 00:00:00 2001 From: William G Hatch Date: Thu, 26 Sep 2024 19:56:11 -0600 Subject: [PATCH 034/469] [NVPTX] add address class for variables with a single register location (#110030) This is the final piece to enable register debugging for variables in registers that have single locations that last throughout their enclosing scope. The next step after this for supporting register debugging for NVPTX is to support the .debug_loc section. Stacked on top of: https://github.com/llvm/llvm-project/pull/109495 --- .../CodeGen/AsmPrinter/DwarfCompileUnit.cpp | 7 + llvm/test/DebugInfo/NVPTX/cu-range-hole.ll | 26 +- llvm/test/DebugInfo/NVPTX/debug-addr-class.ll | 36 +- llvm/test/DebugInfo/NVPTX/debug-info.ll | 2243 +++++++++-------- 4 files changed, 1165 insertions(+), 1147 deletions(-) diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp index 0a1ff189bedbc..a69184676336c 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp @@ -779,6 +779,13 @@ DIE *DwarfCompileUnit::constructVariableDIE(DbgVariable &DV, bool Abstract) { void DwarfCompileUnit::applyConcreteDbgVariableAttributes( const Loc::Single &Single, const DbgVariable &DV, DIE &VariableDie) { const DbgValueLoc *DVal = &Single.getValueLoc(); + if (Asm->TM.getTargetTriple().isNVPTX() && DD->tuneForGDB() && + !Single.getExpr()) { + // Lack of expression means it is a register. Registers for PTX need to + // be marked with DW_AT_address_class = 2. See + // https://docs.nvidia.com/cuda/archive/10.0/ptx-writers-guide-to-interoperability/index.html#cuda-specific-dwarf + addUInt(VariableDie, dwarf::DW_AT_address_class, dwarf::DW_FORM_data1, 2); + } if (!DVal->isVariadic()) { const DbgValueLocEntry *Entry = DVal->getLocEntries().begin(); if (Entry->isLocation()) { diff --git a/llvm/test/DebugInfo/NVPTX/cu-range-hole.ll b/llvm/test/DebugInfo/NVPTX/cu-range-hole.ll index 6acc1ba251271..2d927b18d976d 100644 --- a/llvm/test/DebugInfo/NVPTX/cu-range-hole.ll +++ b/llvm/test/DebugInfo/NVPTX/cu-range-hole.ll @@ -120,6 +120,8 @@ entry: ; CHECK-NEXT: .b8 3 // Abbreviation Code ; CHECK-NEXT: .b8 5 // DW_TAG_formal_parameter ; CHECK-NEXT: .b8 0 // DW_CHILDREN_no +; CHECK-NEXT: .b8 51 // DW_AT_address_class +; CHECK-NEXT: .b8 11 // DW_FORM_data1 ; CHECK-NEXT: .b8 2 // DW_AT_location ; CHECK-NEXT: .b8 10 // DW_FORM_block1 ; CHECK-NEXT: .b8 3 // DW_AT_name @@ -147,12 +149,12 @@ entry: ; CHECK-NEXT: } ; CHECK-NEXT: .section .debug_info ; CHECK-NEXT: { -; CHECK-NEXT: .b32 195 // Length of Unit +; CHECK-NEXT: .b32 197 // Length of Unit ; CHECK-NEXT: .b8 2 // DWARF version number ; CHECK-NEXT: .b8 0 ; CHECK-NEXT: .b32 .debug_abbrev // Offset Into Abbrev. Section ; CHECK-NEXT: .b8 8 // Address Size (in bytes) -; CHECK-NEXT: .b8 1 // Abbrev [1] 0xb:0xbc DW_TAG_compile_unit +; CHECK-NEXT: .b8 1 // Abbrev [1] 0xb:0xbe DW_TAG_compile_unit ; CHECK-NEXT: .b8 99 // DW_AT_producer ; CHECK-NEXT: .b8 108 ; CHECK-NEXT: .b8 97 @@ -225,7 +227,7 @@ entry: ; CHECK-NEXT: .b8 0 ; CHECK-NEXT: .b64 $L__func_begin0 // DW_AT_low_pc ; CHECK-NEXT: .b64 $L__func_end2 // DW_AT_high_pc -; CHECK-NEXT: .b8 2 // Abbrev [2] 0x65:0x2d DW_TAG_subprogram +; CHECK-NEXT: .b8 2 // Abbrev [2] 0x65:0x2e DW_TAG_subprogram ; CHECK-NEXT: .b64 $L__func_begin0 // DW_AT_low_pc ; CHECK-NEXT: .b64 $L__func_end0 // DW_AT_high_pc ; CHECK-NEXT: .b8 1 // DW_AT_frame_base @@ -235,9 +237,10 @@ entry: ; CHECK-NEXT: .b8 1 // DW_AT_decl_file ; CHECK-NEXT: .b8 1 // DW_AT_decl_line ; CHECK-NEXT: .b8 1 // DW_AT_prototyped -; CHECK-NEXT: .b32 191 // DW_AT_type +; CHECK-NEXT: .b32 193 // DW_AT_type ; CHECK-NEXT: .b8 1 // DW_AT_external -; CHECK-NEXT: .b8 3 // Abbrev [3] 0x82:0xf DW_TAG_formal_parameter +; CHECK-NEXT: .b8 3 // Abbrev [3] 0x82:0x10 DW_TAG_formal_parameter +; CHECK-NEXT: .b8 2 // DW_AT_address_class ; CHECK-NEXT: .b8 5 // DW_AT_location ; CHECK-NEXT: .b8 144 ; CHECK-NEXT: .b8 177 @@ -248,9 +251,9 @@ entry: ; CHECK-NEXT: .b8 0 ; CHECK-NEXT: .b8 1 // DW_AT_decl_file ; CHECK-NEXT: .b8 1 // DW_AT_decl_line -; CHECK-NEXT: .b32 191 // DW_AT_type +; CHECK-NEXT: .b32 193 // DW_AT_type ; CHECK-NEXT: .b8 0 // End Of Children Mark -; CHECK-NEXT: .b8 2 // Abbrev [2] 0x92:0x2d DW_TAG_subprogram +; CHECK-NEXT: .b8 2 // Abbrev [2] 0x93:0x2e DW_TAG_subprogram ; CHECK-NEXT: .b64 $L__func_begin2 // DW_AT_low_pc ; CHECK-NEXT: .b64 $L__func_end2 // DW_AT_high_pc ; CHECK-NEXT: .b8 1 // DW_AT_frame_base @@ -260,9 +263,10 @@ entry: ; CHECK-NEXT: .b8 1 // DW_AT_decl_file ; CHECK-NEXT: .b8 3 // DW_AT_decl_line ; CHECK-NEXT: .b8 1 // DW_AT_prototyped -; CHECK-NEXT: .b32 191 // DW_AT_type +; CHECK-NEXT: .b32 193 // DW_AT_type ; CHECK-NEXT: .b8 1 // DW_AT_external -; CHECK-NEXT: .b8 3 // Abbrev [3] 0xaf:0xf DW_TAG_formal_parameter +; CHECK-NEXT: .b8 3 // Abbrev [3] 0xb0:0x10 DW_TAG_formal_parameter +; CHECK-NEXT: .b8 2 // DW_AT_address_class ; CHECK-NEXT: .b8 5 // DW_AT_location ; CHECK-NEXT: .b8 144 ; CHECK-NEXT: .b8 177 @@ -273,9 +277,9 @@ entry: ; CHECK-NEXT: .b8 0 ; CHECK-NEXT: .b8 1 // DW_AT_decl_file ; CHECK-NEXT: .b8 3 // DW_AT_decl_line -; CHECK-NEXT: .b32 191 // DW_AT_type +; CHECK-NEXT: .b32 193 // DW_AT_type ; CHECK-NEXT: .b8 0 // End Of Children Mark -; CHECK-NEXT: .b8 4 // Abbrev [4] 0xbf:0x7 DW_TAG_base_type +; CHECK-NEXT: .b8 4 // Abbrev [4] 0xc1:0x7 DW_TAG_base_type ; CHECK-NEXT: .b8 105 // DW_AT_name ; CHECK-NEXT: .b8 110 ; CHECK-NEXT: .b8 116 diff --git a/llvm/test/DebugInfo/NVPTX/debug-addr-class.ll b/llvm/test/DebugInfo/NVPTX/debug-addr-class.ll index 03a120cd52fab..3585095151181 100644 --- a/llvm/test/DebugInfo/NVPTX/debug-addr-class.ll +++ b/llvm/test/DebugInfo/NVPTX/debug-addr-class.ll @@ -160,6 +160,8 @@ declare void @llvm.dbg.declare(metadata, metadata, metadata) ; CHECK-NEXT:.b8 5 // Abbreviation Code ; CHECK-NEXT:.b8 5 // DW_TAG_formal_parameter ; CHECK-NEXT:.b8 0 // DW_CHILDREN_no +; CHECK-NEXT:.b8 51 // DW_AT_address_class +; CHECK-NEXT:.b8 11 // DW_FORM_data1 ; CHECK-NEXT:.b8 2 // DW_AT_location ; CHECK-NEXT:.b8 10 // DW_FORM_block1 ; CHECK-NEXT:.b8 3 // DW_AT_name @@ -193,15 +195,15 @@ declare void @llvm.dbg.declare(metadata, metadata, metadata) ; CHECK-NEXT:.b8 0 // EOM(1) ; CHECK-NEXT:.b8 0 // EOM(2) ; CHECK-NEXT:.b8 0 // EOM(3) -; CHECK-NEXT: } -; CHECK-NEXT: .section .debug_info -; CHECK-NEXT: { -; CHECK-NEXT:.b32 252 // Length of Unit +; CHECK-NEXT: } +; CHECK-NEXT: .section .debug_info +; CHECK-NEXT: { +; CHECK-NEXT:.b32 254 // Length of Unit ; CHECK-NEXT:.b8 2 // DWARF version number ; CHECK-NEXT:.b8 0 ; CHECK-NEXT:.b32 .debug_abbrev // Offset Into Abbrev. Section ; CHECK-NEXT:.b8 8 // Address Size (in bytes) -; CHECK-NEXT:.b8 1 // Abbrev [1] 0xb:0xf5 DW_TAG_compile_unit +; CHECK-NEXT:.b8 1 // Abbrev [1] 0xb:0xf7 DW_TAG_compile_unit ; CHECK-NEXT:.b8 99 // DW_AT_producer ; CHECK-NEXT:.b8 108 ; CHECK-NEXT:.b8 97 @@ -313,7 +315,7 @@ declare void @llvm.dbg.declare(metadata, metadata, metadata) ; CHECK-NEXT:.b8 9 // DW_AT_location ; CHECK-NEXT:.b8 3 ; CHECK-NEXT:.b64 SHARED -; CHECK-NEXT:.b8 4 // Abbrev [4] 0xa0:0x51 DW_TAG_subprogram +; CHECK-NEXT:.b8 4 // Abbrev [4] 0xa0:0x53 DW_TAG_subprogram ; CHECK-NEXT:.b64 $L__func_begin0 // DW_AT_low_pc ; CHECK-NEXT:.b64 $L__func_end0 // DW_AT_high_pc ; CHECK-NEXT:.b8 1 // DW_AT_frame_base @@ -331,7 +333,8 @@ declare void @llvm.dbg.declare(metadata, metadata, metadata) ; CHECK-NEXT:.b8 1 // DW_AT_decl_file ; CHECK-NEXT:.b8 6 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 // DW_AT_external -; CHECK-NEXT:.b8 5 // Abbrev [5] 0xc0:0xf DW_TAG_formal_parameter +; CHECK-NEXT:.b8 5 // Abbrev [5] 0xc0:0x10 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 2 // DW_AT_address_class ; CHECK-NEXT:.b8 5 // DW_AT_location ; CHECK-NEXT:.b8 144 ; CHECK-NEXT:.b8 177 @@ -342,20 +345,21 @@ declare void @llvm.dbg.declare(metadata, metadata, metadata) ; CHECK-NEXT:.b8 0 ; CHECK-NEXT:.b8 1 // DW_AT_decl_file ; CHECK-NEXT:.b8 6 // DW_AT_decl_line -; CHECK-NEXT:.b32 241 // DW_AT_type -; CHECK-NEXT:.b8 6 // Abbrev [6] 0xcf:0x9 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 243 // DW_AT_type +; CHECK-NEXT:.b8 6 // Abbrev [6] 0xd0:0x9 DW_TAG_formal_parameter ; CHECK-NEXT:.b8 120 // DW_AT_name ; CHECK-NEXT:.b8 0 ; CHECK-NEXT:.b8 1 // DW_AT_decl_file ; CHECK-NEXT:.b8 6 // DW_AT_decl_line -; CHECK-NEXT:.b32 250 // DW_AT_type -; CHECK-NEXT:.b8 6 // Abbrev [6] 0xd8:0x9 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 252 // DW_AT_type +; CHECK-NEXT:.b8 6 // Abbrev [6] 0xd9:0x9 DW_TAG_formal_parameter ; CHECK-NEXT:.b8 121 // DW_AT_name ; CHECK-NEXT:.b8 0 ; CHECK-NEXT:.b8 1 // DW_AT_decl_file ; CHECK-NEXT:.b8 6 // DW_AT_decl_line -; CHECK-NEXT:.b32 250 // DW_AT_type -; CHECK-NEXT:.b8 5 // Abbrev [5] 0xe1:0xf DW_TAG_formal_parameter +; CHECK-NEXT:.b32 252 // DW_AT_type +; CHECK-NEXT:.b8 5 // Abbrev [5] 0xe2:0x10 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 2 // DW_AT_address_class ; CHECK-NEXT:.b8 5 // DW_AT_location ; CHECK-NEXT:.b8 144 ; CHECK-NEXT:.b8 177 @@ -368,7 +372,7 @@ declare void @llvm.dbg.declare(metadata, metadata, metadata) ; CHECK-NEXT:.b8 6 // DW_AT_decl_line ; CHECK-NEXT:.b32 127 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 3 // Abbrev [3] 0xf1:0x9 DW_TAG_base_type +; CHECK-NEXT:.b8 3 // Abbrev [3] 0xf3:0x9 DW_TAG_base_type ; CHECK-NEXT:.b8 102 // DW_AT_name ; CHECK-NEXT:.b8 108 ; CHECK-NEXT:.b8 111 @@ -377,8 +381,8 @@ declare void @llvm.dbg.declare(metadata, metadata, metadata) ; CHECK-NEXT:.b8 0 ; CHECK-NEXT:.b8 4 // DW_AT_encoding ; CHECK-NEXT:.b8 4 // DW_AT_byte_size -; CHECK-NEXT:.b8 7 // Abbrev [7] 0xfa:0x5 DW_TAG_pointer_type -; CHECK-NEXT:.b32 241 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0xfc:0x5 DW_TAG_pointer_type +; CHECK-NEXT:.b32 243 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark ; CHECK-NEXT: } ; CHECK-NEXT: .section .debug_loc { } diff --git a/llvm/test/DebugInfo/NVPTX/debug-info.ll b/llvm/test/DebugInfo/NVPTX/debug-info.ll index 5c5fb53edd7cb..643ed6484ae9f 100644 --- a/llvm/test/DebugInfo/NVPTX/debug-info.ll +++ b/llvm/test/DebugInfo/NVPTX/debug-info.ll @@ -490,6 +490,8 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 27 // Abbreviation Code ; CHECK-NEXT:.b8 5 // DW_TAG_formal_parameter ; CHECK-NEXT:.b8 0 // DW_CHILDREN_no +; CHECK-NEXT:.b8 51 // DW_AT_address_class +; CHECK-NEXT:.b8 11 // DW_FORM_data1 ; CHECK-NEXT:.b8 2 // DW_AT_location ; CHECK-NEXT:.b8 10 // DW_FORM_block1 ; CHECK-NEXT:.b8 49 // DW_AT_abstract_origin @@ -705,12 +707,12 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT: } ; CHECK-NEXT: .section .debug_info ; CHECK-NEXT: { -; CHECK-NEXT:.b32 10035 // Length of Unit +; CHECK-NEXT:.b32 10036 // Length of Unit ; CHECK-NEXT:.b8 2 // DWARF version number ; CHECK-NEXT:.b8 0 ; CHECK-NEXT:.b32 .debug_abbrev // Offset Into Abbrev. Section ; CHECK-NEXT:.b8 8 // Address Size (in bytes) -; CHECK-NEXT:.b8 1 // Abbrev [1] 0xb:0x272c DW_TAG_compile_unit +; CHECK-NEXT:.b8 1 // Abbrev [1] 0xb:0x272d DW_TAG_compile_unit ; CHECK-NEXT:.b8 0 // DW_AT_producer ; CHECK-NEXT:.b8 4 // DW_AT_language ; CHECK-NEXT:.b8 0 @@ -2602,7 +2604,7 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 4 // DW_AT_byte_size ; CHECK-NEXT:.b8 12 // Abbrev [12] 0x84d:0x5 DW_TAG_pointer_type ; CHECK-NEXT:.b32 2116 // DW_AT_type -; CHECK-NEXT:.b8 23 // Abbrev [23] 0x852:0xc5 DW_TAG_subprogram +; CHECK-NEXT:.b8 23 // Abbrev [23] 0x852:0xc6 DW_TAG_subprogram ; CHECK-NEXT:.b64 $L__func_begin0 // DW_AT_low_pc ; CHECK-NEXT:.b64 $L__func_end0 // DW_AT_high_pc ; CHECK-NEXT:.b8 1 // DW_AT_frame_base @@ -2636,7 +2638,7 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 0 ; CHECK-NEXT:.b8 1 // DW_AT_decl_file ; CHECK-NEXT:.b8 5 // DW_AT_decl_line -; CHECK-NEXT:.b32 4585 // DW_AT_type +; CHECK-NEXT:.b32 4586 // DW_AT_type ; CHECK-NEXT:.b8 22 // Abbrev [22] 0x886:0x9 DW_TAG_formal_parameter ; CHECK-NEXT:.b8 97 // DW_AT_name ; CHECK-NEXT:.b8 0 @@ -2660,7 +2662,7 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 0 ; CHECK-NEXT:.b8 1 // DW_AT_decl_file ; CHECK-NEXT:.b8 6 // DW_AT_decl_line -; CHECK-NEXT:.b32 4585 // DW_AT_type +; CHECK-NEXT:.b32 4586 // DW_AT_type ; CHECK-NEXT:.b8 25 // Abbrev [25] 0x8aa:0x18 DW_TAG_inlined_subroutine ; CHECK-NEXT:.b32 707 // DW_AT_abstract_origin ; CHECK-NEXT:.b64 $L__tmp0 // DW_AT_low_pc @@ -2682,14 +2684,15 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 1 // DW_AT_call_file ; CHECK-NEXT:.b8 6 // DW_AT_call_line ; CHECK-NEXT:.b8 37 // DW_AT_call_column -; CHECK-NEXT:.b8 26 // Abbrev [26] 0x8f2:0x24 DW_TAG_inlined_subroutine +; CHECK-NEXT:.b8 26 // Abbrev [26] 0x8f2:0x25 DW_TAG_inlined_subroutine ; CHECK-NEXT:.b32 2066 // DW_AT_abstract_origin ; CHECK-NEXT:.b64 $L__tmp9 // DW_AT_low_pc ; CHECK-NEXT:.b64 $L__tmp10 // DW_AT_high_pc ; CHECK-NEXT:.b8 1 // DW_AT_call_file ; CHECK-NEXT:.b8 8 // DW_AT_call_line ; CHECK-NEXT:.b8 5 // DW_AT_call_column -; CHECK-NEXT:.b8 27 // Abbrev [27] 0x90a:0xb DW_TAG_formal_parameter +; CHECK-NEXT:.b8 27 // Abbrev [27] 0x90a:0xc DW_TAG_formal_parameter +; CHECK-NEXT:.b8 2 // DW_AT_address_class ; CHECK-NEXT:.b8 5 // DW_AT_location ; CHECK-NEXT:.b8 144 ; CHECK-NEXT:.b8 179 @@ -2699,856 +2702,856 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b32 2095 // DW_AT_abstract_origin ; CHECK-NEXT:.b8 0 // End Of Children Mark ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 28 // Abbrev [28] 0x917:0x588 DW_TAG_namespace +; CHECK-NEXT:.b8 28 // Abbrev [28] 0x918:0x588 DW_TAG_namespace ; CHECK-NEXT:.b8 115 // DW_AT_name ; CHECK-NEXT:.b8 116 ; CHECK-NEXT:.b8 100 ; CHECK-NEXT:.b8 0 -; CHECK-NEXT:.b8 29 // Abbrev [29] 0x91c:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b8 29 // Abbrev [29] 0x91d:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 4 // DW_AT_decl_file ; CHECK-NEXT:.b8 202 // DW_AT_decl_line -; CHECK-NEXT:.b32 3743 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0x923:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 3744 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0x924:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 4 // DW_AT_decl_file ; CHECK-NEXT:.b8 203 // DW_AT_decl_line -; CHECK-NEXT:.b32 3787 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0x92a:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 3788 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0x92b:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 4 // DW_AT_decl_file ; CHECK-NEXT:.b8 204 // DW_AT_decl_line -; CHECK-NEXT:.b32 3816 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0x931:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 3817 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0x932:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 4 // DW_AT_decl_file ; CHECK-NEXT:.b8 205 // DW_AT_decl_line -; CHECK-NEXT:.b32 3847 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0x938:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 3848 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0x939:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 4 // DW_AT_decl_file ; CHECK-NEXT:.b8 206 // DW_AT_decl_line -; CHECK-NEXT:.b32 3876 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0x93f:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 3877 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0x940:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 4 // DW_AT_decl_file ; CHECK-NEXT:.b8 207 // DW_AT_decl_line -; CHECK-NEXT:.b32 3907 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0x946:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 3908 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0x947:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 4 // DW_AT_decl_file ; CHECK-NEXT:.b8 208 // DW_AT_decl_line -; CHECK-NEXT:.b32 3936 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0x94d:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 3937 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0x94e:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 4 // DW_AT_decl_file ; CHECK-NEXT:.b8 209 // DW_AT_decl_line -; CHECK-NEXT:.b32 3973 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0x954:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 3974 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0x955:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 4 // DW_AT_decl_file ; CHECK-NEXT:.b8 210 // DW_AT_decl_line -; CHECK-NEXT:.b32 4004 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0x95b:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 4005 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0x95c:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 4 // DW_AT_decl_file ; CHECK-NEXT:.b8 211 // DW_AT_decl_line -; CHECK-NEXT:.b32 4033 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0x962:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 4034 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0x963:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 4 // DW_AT_decl_file ; CHECK-NEXT:.b8 212 // DW_AT_decl_line -; CHECK-NEXT:.b32 4062 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0x969:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 4063 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0x96a:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 4 // DW_AT_decl_file ; CHECK-NEXT:.b8 213 // DW_AT_decl_line -; CHECK-NEXT:.b32 4105 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0x970:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 4106 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0x971:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 4 // DW_AT_decl_file ; CHECK-NEXT:.b8 214 // DW_AT_decl_line -; CHECK-NEXT:.b32 4132 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0x977:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 4133 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0x978:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 4 // DW_AT_decl_file ; CHECK-NEXT:.b8 215 // DW_AT_decl_line -; CHECK-NEXT:.b32 4161 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0x97e:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 4162 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0x97f:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 4 // DW_AT_decl_file ; CHECK-NEXT:.b8 216 // DW_AT_decl_line -; CHECK-NEXT:.b32 4188 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0x985:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 4189 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0x986:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 4 // DW_AT_decl_file ; CHECK-NEXT:.b8 217 // DW_AT_decl_line -; CHECK-NEXT:.b32 4217 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0x98c:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 4218 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0x98d:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 4 // DW_AT_decl_file ; CHECK-NEXT:.b8 218 // DW_AT_decl_line -; CHECK-NEXT:.b32 4244 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0x993:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 4245 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0x994:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 4 // DW_AT_decl_file ; CHECK-NEXT:.b8 219 // DW_AT_decl_line -; CHECK-NEXT:.b32 4273 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0x99a:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 4274 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0x99b:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 4 // DW_AT_decl_file ; CHECK-NEXT:.b8 220 // DW_AT_decl_line -; CHECK-NEXT:.b32 4304 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0x9a1:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 4305 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0x9a2:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 4 // DW_AT_decl_file ; CHECK-NEXT:.b8 221 // DW_AT_decl_line -; CHECK-NEXT:.b32 4333 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0x9a8:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 4334 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0x9a9:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 4 // DW_AT_decl_file ; CHECK-NEXT:.b8 222 // DW_AT_decl_line -; CHECK-NEXT:.b32 4368 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0x9af:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 4369 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0x9b0:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 4 // DW_AT_decl_file ; CHECK-NEXT:.b8 223 // DW_AT_decl_line -; CHECK-NEXT:.b32 4399 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0x9b6:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 4400 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0x9b7:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 4 // DW_AT_decl_file ; CHECK-NEXT:.b8 224 // DW_AT_decl_line -; CHECK-NEXT:.b32 4438 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0x9bd:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 4439 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0x9be:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 4 // DW_AT_decl_file ; CHECK-NEXT:.b8 225 // DW_AT_decl_line -; CHECK-NEXT:.b32 4473 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0x9c4:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 4474 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0x9c5:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 4 // DW_AT_decl_file ; CHECK-NEXT:.b8 226 // DW_AT_decl_line -; CHECK-NEXT:.b32 4508 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0x9cb:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 4509 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0x9cc:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 4 // DW_AT_decl_file ; CHECK-NEXT:.b8 227 // DW_AT_decl_line -; CHECK-NEXT:.b32 4543 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0x9d2:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 4544 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0x9d3:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 4 // DW_AT_decl_file ; CHECK-NEXT:.b8 228 // DW_AT_decl_line -; CHECK-NEXT:.b32 4592 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0x9d9:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 4593 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0x9da:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 4 // DW_AT_decl_file ; CHECK-NEXT:.b8 229 // DW_AT_decl_line -; CHECK-NEXT:.b32 4635 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0x9e0:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 4636 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0x9e1:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 4 // DW_AT_decl_file ; CHECK-NEXT:.b8 230 // DW_AT_decl_line -; CHECK-NEXT:.b32 4672 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0x9e7:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 4673 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0x9e8:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 4 // DW_AT_decl_file ; CHECK-NEXT:.b8 231 // DW_AT_decl_line -; CHECK-NEXT:.b32 4703 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0x9ee:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 4704 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0x9ef:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 4 // DW_AT_decl_file ; CHECK-NEXT:.b8 232 // DW_AT_decl_line -; CHECK-NEXT:.b32 4748 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0x9f5:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 4749 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0x9f6:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 4 // DW_AT_decl_file ; CHECK-NEXT:.b8 233 // DW_AT_decl_line -; CHECK-NEXT:.b32 4793 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0x9fc:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 4794 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0x9fd:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 4 // DW_AT_decl_file ; CHECK-NEXT:.b8 234 // DW_AT_decl_line -; CHECK-NEXT:.b32 4849 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0xa03:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 4850 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0xa04:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 4 // DW_AT_decl_file ; CHECK-NEXT:.b8 235 // DW_AT_decl_line -; CHECK-NEXT:.b32 4880 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0xa0a:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 4881 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0xa0b:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 4 // DW_AT_decl_file ; CHECK-NEXT:.b8 236 // DW_AT_decl_line -; CHECK-NEXT:.b32 4919 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0xa11:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 4920 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0xa12:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 4 // DW_AT_decl_file ; CHECK-NEXT:.b8 237 // DW_AT_decl_line -; CHECK-NEXT:.b32 4969 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0xa18:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 4970 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0xa19:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 4 // DW_AT_decl_file ; CHECK-NEXT:.b8 238 // DW_AT_decl_line -; CHECK-NEXT:.b32 5023 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0xa1f:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 5024 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0xa20:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 4 // DW_AT_decl_file ; CHECK-NEXT:.b8 239 // DW_AT_decl_line -; CHECK-NEXT:.b32 5054 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0xa26:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 5055 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0xa27:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 4 // DW_AT_decl_file ; CHECK-NEXT:.b8 240 // DW_AT_decl_line -; CHECK-NEXT:.b32 5091 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0xa2d:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 5092 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0xa2e:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 4 // DW_AT_decl_file ; CHECK-NEXT:.b8 241 // DW_AT_decl_line -; CHECK-NEXT:.b32 5141 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0xa34:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 5142 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0xa35:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 4 // DW_AT_decl_file ; CHECK-NEXT:.b8 242 // DW_AT_decl_line -; CHECK-NEXT:.b32 5182 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0xa3b:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 5183 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0xa3c:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 4 // DW_AT_decl_file ; CHECK-NEXT:.b8 243 // DW_AT_decl_line -; CHECK-NEXT:.b32 5219 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0xa42:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 5220 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0xa43:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 4 // DW_AT_decl_file ; CHECK-NEXT:.b8 244 // DW_AT_decl_line -; CHECK-NEXT:.b32 5252 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0xa49:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 5253 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0xa4a:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 4 // DW_AT_decl_file ; CHECK-NEXT:.b8 245 // DW_AT_decl_line -; CHECK-NEXT:.b32 5283 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0xa50:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 5284 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0xa51:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 4 // DW_AT_decl_file ; CHECK-NEXT:.b8 246 // DW_AT_decl_line -; CHECK-NEXT:.b32 5316 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0xa57:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 5317 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0xa58:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 4 // DW_AT_decl_file ; CHECK-NEXT:.b8 247 // DW_AT_decl_line -; CHECK-NEXT:.b32 5343 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0xa5e:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 5344 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0xa5f:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 4 // DW_AT_decl_file ; CHECK-NEXT:.b8 248 // DW_AT_decl_line -; CHECK-NEXT:.b32 5374 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0xa65:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 5375 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0xa66:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 4 // DW_AT_decl_file ; CHECK-NEXT:.b8 249 // DW_AT_decl_line -; CHECK-NEXT:.b32 5405 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0xa6c:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 5406 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0xa6d:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 4 // DW_AT_decl_file ; CHECK-NEXT:.b8 250 // DW_AT_decl_line -; CHECK-NEXT:.b32 5434 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0xa73:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 5435 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0xa74:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 4 // DW_AT_decl_file ; CHECK-NEXT:.b8 251 // DW_AT_decl_line -; CHECK-NEXT:.b32 5463 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0xa7a:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 5464 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0xa7b:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 4 // DW_AT_decl_file ; CHECK-NEXT:.b8 252 // DW_AT_decl_line -; CHECK-NEXT:.b32 5494 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0xa81:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 5495 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0xa82:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 4 // DW_AT_decl_file ; CHECK-NEXT:.b8 253 // DW_AT_decl_line -; CHECK-NEXT:.b32 5527 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0xa88:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 5528 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0xa89:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 4 // DW_AT_decl_file ; CHECK-NEXT:.b8 254 // DW_AT_decl_line -; CHECK-NEXT:.b32 5562 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0xa8f:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 5563 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0xa90:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 4 // DW_AT_decl_file ; CHECK-NEXT:.b8 255 // DW_AT_decl_line -; CHECK-NEXT:.b32 5598 // DW_AT_import -; CHECK-NEXT:.b8 30 // Abbrev [30] 0xa96:0x8 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 5599 // DW_AT_import +; CHECK-NEXT:.b8 30 // Abbrev [30] 0xa97:0x8 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 4 // DW_AT_decl_file ; CHECK-NEXT:.b8 0 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 -; CHECK-NEXT:.b32 5655 // DW_AT_import -; CHECK-NEXT:.b8 30 // Abbrev [30] 0xa9e:0x8 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 5656 // DW_AT_import +; CHECK-NEXT:.b8 30 // Abbrev [30] 0xa9f:0x8 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 4 // DW_AT_decl_file ; CHECK-NEXT:.b8 1 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 -; CHECK-NEXT:.b32 5686 // DW_AT_import -; CHECK-NEXT:.b8 30 // Abbrev [30] 0xaa6:0x8 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 5687 // DW_AT_import +; CHECK-NEXT:.b8 30 // Abbrev [30] 0xaa7:0x8 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 4 // DW_AT_decl_file ; CHECK-NEXT:.b8 2 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 -; CHECK-NEXT:.b32 5725 // DW_AT_import -; CHECK-NEXT:.b8 30 // Abbrev [30] 0xaae:0x8 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 5726 // DW_AT_import +; CHECK-NEXT:.b8 30 // Abbrev [30] 0xaaf:0x8 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 4 // DW_AT_decl_file ; CHECK-NEXT:.b8 3 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 -; CHECK-NEXT:.b32 5770 // DW_AT_import -; CHECK-NEXT:.b8 30 // Abbrev [30] 0xab6:0x8 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 5771 // DW_AT_import +; CHECK-NEXT:.b8 30 // Abbrev [30] 0xab7:0x8 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 4 // DW_AT_decl_file ; CHECK-NEXT:.b8 4 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 -; CHECK-NEXT:.b32 5803 // DW_AT_import -; CHECK-NEXT:.b8 30 // Abbrev [30] 0xabe:0x8 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 5804 // DW_AT_import +; CHECK-NEXT:.b8 30 // Abbrev [30] 0xabf:0x8 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 4 // DW_AT_decl_file ; CHECK-NEXT:.b8 5 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 -; CHECK-NEXT:.b32 5848 // DW_AT_import -; CHECK-NEXT:.b8 30 // Abbrev [30] 0xac6:0x8 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 5849 // DW_AT_import +; CHECK-NEXT:.b8 30 // Abbrev [30] 0xac7:0x8 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 4 // DW_AT_decl_file ; CHECK-NEXT:.b8 6 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 -; CHECK-NEXT:.b32 5894 // DW_AT_import -; CHECK-NEXT:.b8 30 // Abbrev [30] 0xace:0x8 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 5895 // DW_AT_import +; CHECK-NEXT:.b8 30 // Abbrev [30] 0xacf:0x8 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 4 // DW_AT_decl_file ; CHECK-NEXT:.b8 7 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 -; CHECK-NEXT:.b32 5923 // DW_AT_import -; CHECK-NEXT:.b8 30 // Abbrev [30] 0xad6:0x8 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 5924 // DW_AT_import +; CHECK-NEXT:.b8 30 // Abbrev [30] 0xad7:0x8 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 4 // DW_AT_decl_file ; CHECK-NEXT:.b8 8 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 -; CHECK-NEXT:.b32 5954 // DW_AT_import -; CHECK-NEXT:.b8 30 // Abbrev [30] 0xade:0x8 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 5955 // DW_AT_import +; CHECK-NEXT:.b8 30 // Abbrev [30] 0xadf:0x8 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 4 // DW_AT_decl_file ; CHECK-NEXT:.b8 9 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 -; CHECK-NEXT:.b32 5995 // DW_AT_import -; CHECK-NEXT:.b8 30 // Abbrev [30] 0xae6:0x8 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 5996 // DW_AT_import +; CHECK-NEXT:.b8 30 // Abbrev [30] 0xae7:0x8 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 4 // DW_AT_decl_file ; CHECK-NEXT:.b8 10 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 -; CHECK-NEXT:.b32 6034 // DW_AT_import -; CHECK-NEXT:.b8 30 // Abbrev [30] 0xaee:0x8 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 6035 // DW_AT_import +; CHECK-NEXT:.b8 30 // Abbrev [30] 0xaef:0x8 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 4 // DW_AT_decl_file ; CHECK-NEXT:.b8 11 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 -; CHECK-NEXT:.b32 6069 // DW_AT_import -; CHECK-NEXT:.b8 30 // Abbrev [30] 0xaf6:0x8 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 6070 // DW_AT_import +; CHECK-NEXT:.b8 30 // Abbrev [30] 0xaf7:0x8 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 4 // DW_AT_decl_file ; CHECK-NEXT:.b8 12 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 -; CHECK-NEXT:.b32 6096 // DW_AT_import -; CHECK-NEXT:.b8 30 // Abbrev [30] 0xafe:0x8 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 6097 // DW_AT_import +; CHECK-NEXT:.b8 30 // Abbrev [30] 0xaff:0x8 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 4 // DW_AT_decl_file ; CHECK-NEXT:.b8 13 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 -; CHECK-NEXT:.b32 6125 // DW_AT_import -; CHECK-NEXT:.b8 30 // Abbrev [30] 0xb06:0x8 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 6126 // DW_AT_import +; CHECK-NEXT:.b8 30 // Abbrev [30] 0xb07:0x8 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 4 // DW_AT_decl_file ; CHECK-NEXT:.b8 14 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 -; CHECK-NEXT:.b32 6154 // DW_AT_import -; CHECK-NEXT:.b8 30 // Abbrev [30] 0xb0e:0x8 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 6155 // DW_AT_import +; CHECK-NEXT:.b8 30 // Abbrev [30] 0xb0f:0x8 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 4 // DW_AT_decl_file ; CHECK-NEXT:.b8 15 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 -; CHECK-NEXT:.b32 6181 // DW_AT_import -; CHECK-NEXT:.b8 30 // Abbrev [30] 0xb16:0x8 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 6182 // DW_AT_import +; CHECK-NEXT:.b8 30 // Abbrev [30] 0xb17:0x8 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 4 // DW_AT_decl_file ; CHECK-NEXT:.b8 16 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 -; CHECK-NEXT:.b32 6210 // DW_AT_import -; CHECK-NEXT:.b8 30 // Abbrev [30] 0xb1e:0x8 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 6211 // DW_AT_import +; CHECK-NEXT:.b8 30 // Abbrev [30] 0xb1f:0x8 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 4 // DW_AT_decl_file ; CHECK-NEXT:.b8 17 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 -; CHECK-NEXT:.b32 6243 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0xb26:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 6244 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0xb27:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 6 // DW_AT_decl_file ; CHECK-NEXT:.b8 102 // DW_AT_decl_line -; CHECK-NEXT:.b32 6274 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0xb2d:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 6275 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0xb2e:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 6 // DW_AT_decl_file ; CHECK-NEXT:.b8 121 // DW_AT_decl_line -; CHECK-NEXT:.b32 6294 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0xb34:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 6295 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0xb35:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 6 // DW_AT_decl_file ; CHECK-NEXT:.b8 140 // DW_AT_decl_line -; CHECK-NEXT:.b32 6314 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0xb3b:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 6315 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0xb3c:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 6 // DW_AT_decl_file ; CHECK-NEXT:.b8 159 // DW_AT_decl_line -; CHECK-NEXT:.b32 6334 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0xb42:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 6335 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0xb43:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 6 // DW_AT_decl_file ; CHECK-NEXT:.b8 180 // DW_AT_decl_line -; CHECK-NEXT:.b32 6360 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0xb49:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 6361 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0xb4a:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 6 // DW_AT_decl_file ; CHECK-NEXT:.b8 199 // DW_AT_decl_line -; CHECK-NEXT:.b32 6380 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0xb50:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 6381 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0xb51:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 6 // DW_AT_decl_file ; CHECK-NEXT:.b8 218 // DW_AT_decl_line -; CHECK-NEXT:.b32 6399 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0xb57:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 6400 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0xb58:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 6 // DW_AT_decl_file ; CHECK-NEXT:.b8 237 // DW_AT_decl_line -; CHECK-NEXT:.b32 6419 // DW_AT_import -; CHECK-NEXT:.b8 30 // Abbrev [30] 0xb5e:0x8 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 6420 // DW_AT_import +; CHECK-NEXT:.b8 30 // Abbrev [30] 0xb5f:0x8 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 6 // DW_AT_decl_file ; CHECK-NEXT:.b8 0 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 -; CHECK-NEXT:.b32 6438 // DW_AT_import -; CHECK-NEXT:.b8 30 // Abbrev [30] 0xb66:0x8 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 6439 // DW_AT_import +; CHECK-NEXT:.b8 30 // Abbrev [30] 0xb67:0x8 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 6 // DW_AT_decl_file ; CHECK-NEXT:.b8 19 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 -; CHECK-NEXT:.b32 6458 // DW_AT_import -; CHECK-NEXT:.b8 30 // Abbrev [30] 0xb6e:0x8 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 6459 // DW_AT_import +; CHECK-NEXT:.b8 30 // Abbrev [30] 0xb6f:0x8 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 6 // DW_AT_decl_file ; CHECK-NEXT:.b8 38 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 -; CHECK-NEXT:.b32 6479 // DW_AT_import -; CHECK-NEXT:.b8 30 // Abbrev [30] 0xb76:0x8 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 6480 // DW_AT_import +; CHECK-NEXT:.b8 30 // Abbrev [30] 0xb77:0x8 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 6 // DW_AT_decl_file ; CHECK-NEXT:.b8 59 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 -; CHECK-NEXT:.b32 6504 // DW_AT_import -; CHECK-NEXT:.b8 30 // Abbrev [30] 0xb7e:0x8 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 6505 // DW_AT_import +; CHECK-NEXT:.b8 30 // Abbrev [30] 0xb7f:0x8 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 6 // DW_AT_decl_file ; CHECK-NEXT:.b8 78 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 -; CHECK-NEXT:.b32 6530 // DW_AT_import -; CHECK-NEXT:.b8 30 // Abbrev [30] 0xb86:0x8 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 6531 // DW_AT_import +; CHECK-NEXT:.b8 30 // Abbrev [30] 0xb87:0x8 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 6 // DW_AT_decl_file ; CHECK-NEXT:.b8 97 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 -; CHECK-NEXT:.b32 6556 // DW_AT_import -; CHECK-NEXT:.b8 30 // Abbrev [30] 0xb8e:0x8 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 6557 // DW_AT_import +; CHECK-NEXT:.b8 30 // Abbrev [30] 0xb8f:0x8 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 6 // DW_AT_decl_file ; CHECK-NEXT:.b8 116 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 -; CHECK-NEXT:.b32 6575 // DW_AT_import -; CHECK-NEXT:.b8 30 // Abbrev [30] 0xb96:0x8 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 6576 // DW_AT_import +; CHECK-NEXT:.b8 30 // Abbrev [30] 0xb97:0x8 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 6 // DW_AT_decl_file ; CHECK-NEXT:.b8 135 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 -; CHECK-NEXT:.b32 6596 // DW_AT_import -; CHECK-NEXT:.b8 30 // Abbrev [30] 0xb9e:0x8 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 6597 // DW_AT_import +; CHECK-NEXT:.b8 30 // Abbrev [30] 0xb9f:0x8 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 6 // DW_AT_decl_file ; CHECK-NEXT:.b8 147 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 -; CHECK-NEXT:.b32 6626 // DW_AT_import -; CHECK-NEXT:.b8 30 // Abbrev [30] 0xba6:0x8 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 6627 // DW_AT_import +; CHECK-NEXT:.b8 30 // Abbrev [30] 0xba7:0x8 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 6 // DW_AT_decl_file ; CHECK-NEXT:.b8 184 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 -; CHECK-NEXT:.b32 6650 // DW_AT_import -; CHECK-NEXT:.b8 30 // Abbrev [30] 0xbae:0x8 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 6651 // DW_AT_import +; CHECK-NEXT:.b8 30 // Abbrev [30] 0xbaf:0x8 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 6 // DW_AT_decl_file ; CHECK-NEXT:.b8 203 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 -; CHECK-NEXT:.b32 6669 // DW_AT_import -; CHECK-NEXT:.b8 30 // Abbrev [30] 0xbb6:0x8 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 6670 // DW_AT_import +; CHECK-NEXT:.b8 30 // Abbrev [30] 0xbb7:0x8 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 6 // DW_AT_decl_file ; CHECK-NEXT:.b8 222 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 -; CHECK-NEXT:.b32 6689 // DW_AT_import -; CHECK-NEXT:.b8 30 // Abbrev [30] 0xbbe:0x8 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 6690 // DW_AT_import +; CHECK-NEXT:.b8 30 // Abbrev [30] 0xbbf:0x8 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 6 // DW_AT_decl_file ; CHECK-NEXT:.b8 241 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 -; CHECK-NEXT:.b32 6709 // DW_AT_import -; CHECK-NEXT:.b8 30 // Abbrev [30] 0xbc6:0x8 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 6710 // DW_AT_import +; CHECK-NEXT:.b8 30 // Abbrev [30] 0xbc7:0x8 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 6 // DW_AT_decl_file ; CHECK-NEXT:.b8 4 // DW_AT_decl_line ; CHECK-NEXT:.b8 2 -; CHECK-NEXT:.b32 6728 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0xbce:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 6729 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0xbcf:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 8 // DW_AT_decl_file ; CHECK-NEXT:.b8 118 // DW_AT_decl_line -; CHECK-NEXT:.b32 6748 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0xbd5:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 6749 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0xbd6:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 8 // DW_AT_decl_file ; CHECK-NEXT:.b8 119 // DW_AT_decl_line -; CHECK-NEXT:.b32 6763 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0xbdc:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 6764 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0xbdd:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 8 // DW_AT_decl_file ; CHECK-NEXT:.b8 121 // DW_AT_decl_line -; CHECK-NEXT:.b32 6811 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0xbe3:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 6812 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0xbe4:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 8 // DW_AT_decl_file ; CHECK-NEXT:.b8 122 // DW_AT_decl_line -; CHECK-NEXT:.b32 6824 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0xbea:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 6825 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0xbeb:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 8 // DW_AT_decl_file ; CHECK-NEXT:.b8 123 // DW_AT_decl_line -; CHECK-NEXT:.b32 6844 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0xbf1:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 6845 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0xbf2:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 8 // DW_AT_decl_file ; CHECK-NEXT:.b8 129 // DW_AT_decl_line -; CHECK-NEXT:.b32 6873 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0xbf8:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 6874 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0xbf9:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 8 // DW_AT_decl_file ; CHECK-NEXT:.b8 130 // DW_AT_decl_line -; CHECK-NEXT:.b32 6893 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0xbff:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 6894 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0xc00:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 8 // DW_AT_decl_file ; CHECK-NEXT:.b8 131 // DW_AT_decl_line -; CHECK-NEXT:.b32 6914 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0xc06:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 6915 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0xc07:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 8 // DW_AT_decl_file ; CHECK-NEXT:.b8 132 // DW_AT_decl_line -; CHECK-NEXT:.b32 6935 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0xc0d:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 6936 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0xc0e:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 8 // DW_AT_decl_file ; CHECK-NEXT:.b8 133 // DW_AT_decl_line -; CHECK-NEXT:.b32 7063 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0xc14:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 7064 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0xc15:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 8 // DW_AT_decl_file ; CHECK-NEXT:.b8 134 // DW_AT_decl_line -; CHECK-NEXT:.b32 7091 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0xc1b:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 7092 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0xc1c:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 8 // DW_AT_decl_file ; CHECK-NEXT:.b8 135 // DW_AT_decl_line -; CHECK-NEXT:.b32 7116 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0xc22:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 7117 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0xc23:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 8 // DW_AT_decl_file ; CHECK-NEXT:.b8 136 // DW_AT_decl_line -; CHECK-NEXT:.b32 7134 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0xc29:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 7135 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0xc2a:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 8 // DW_AT_decl_file ; CHECK-NEXT:.b8 137 // DW_AT_decl_line -; CHECK-NEXT:.b32 7151 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0xc30:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 7152 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0xc31:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 8 // DW_AT_decl_file ; CHECK-NEXT:.b8 138 // DW_AT_decl_line -; CHECK-NEXT:.b32 7179 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0xc37:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 7180 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0xc38:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 8 // DW_AT_decl_file ; CHECK-NEXT:.b8 139 // DW_AT_decl_line -; CHECK-NEXT:.b32 7200 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0xc3e:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 7201 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0xc3f:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 8 // DW_AT_decl_file ; CHECK-NEXT:.b8 140 // DW_AT_decl_line -; CHECK-NEXT:.b32 7226 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0xc45:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 7227 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0xc46:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 8 // DW_AT_decl_file ; CHECK-NEXT:.b8 142 // DW_AT_decl_line -; CHECK-NEXT:.b32 7249 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0xc4c:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 7250 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0xc4d:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 8 // DW_AT_decl_file ; CHECK-NEXT:.b8 143 // DW_AT_decl_line -; CHECK-NEXT:.b32 7276 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0xc53:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 7277 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0xc54:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 8 // DW_AT_decl_file ; CHECK-NEXT:.b8 144 // DW_AT_decl_line -; CHECK-NEXT:.b32 7327 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0xc5a:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 7328 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0xc5b:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 8 // DW_AT_decl_file ; CHECK-NEXT:.b8 146 // DW_AT_decl_line -; CHECK-NEXT:.b32 7360 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0xc61:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 7361 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0xc62:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 8 // DW_AT_decl_file ; CHECK-NEXT:.b8 152 // DW_AT_decl_line -; CHECK-NEXT:.b32 7393 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0xc68:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 7394 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0xc69:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 8 // DW_AT_decl_file ; CHECK-NEXT:.b8 153 // DW_AT_decl_line -; CHECK-NEXT:.b32 7408 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0xc6f:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 7409 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0xc70:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 8 // DW_AT_decl_file ; CHECK-NEXT:.b8 154 // DW_AT_decl_line -; CHECK-NEXT:.b32 7437 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0xc76:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 7438 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0xc77:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 8 // DW_AT_decl_file ; CHECK-NEXT:.b8 155 // DW_AT_decl_line -; CHECK-NEXT:.b32 7455 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0xc7d:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 7456 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0xc7e:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 8 // DW_AT_decl_file ; CHECK-NEXT:.b8 156 // DW_AT_decl_line -; CHECK-NEXT:.b32 7487 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0xc84:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 7488 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0xc85:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 8 // DW_AT_decl_file ; CHECK-NEXT:.b8 157 // DW_AT_decl_line -; CHECK-NEXT:.b32 7519 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0xc8b:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 7520 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0xc8c:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 8 // DW_AT_decl_file ; CHECK-NEXT:.b8 158 // DW_AT_decl_line -; CHECK-NEXT:.b32 7552 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0xc92:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 7553 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0xc93:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 8 // DW_AT_decl_file ; CHECK-NEXT:.b8 160 // DW_AT_decl_line -; CHECK-NEXT:.b32 7575 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0xc99:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 7576 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0xc9a:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 8 // DW_AT_decl_file ; CHECK-NEXT:.b8 161 // DW_AT_decl_line -; CHECK-NEXT:.b32 7620 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0xca0:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 7621 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0xca1:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 8 // DW_AT_decl_file ; CHECK-NEXT:.b8 241 // DW_AT_decl_line -; CHECK-NEXT:.b32 7768 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0xca7:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 7769 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0xca8:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 8 // DW_AT_decl_file ; CHECK-NEXT:.b8 243 // DW_AT_decl_line -; CHECK-NEXT:.b32 7817 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0xcae:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 7818 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0xcaf:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 8 // DW_AT_decl_file ; CHECK-NEXT:.b8 245 // DW_AT_decl_line -; CHECK-NEXT:.b32 7836 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0xcb5:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 7837 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0xcb6:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 8 // DW_AT_decl_file ; CHECK-NEXT:.b8 246 // DW_AT_decl_line -; CHECK-NEXT:.b32 7722 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0xcbc:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 7723 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0xcbd:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 8 // DW_AT_decl_file ; CHECK-NEXT:.b8 247 // DW_AT_decl_line -; CHECK-NEXT:.b32 7858 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0xcc3:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 7859 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0xcc4:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 8 // DW_AT_decl_file ; CHECK-NEXT:.b8 249 // DW_AT_decl_line -; CHECK-NEXT:.b32 7885 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0xcca:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 7886 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0xccb:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 8 // DW_AT_decl_file ; CHECK-NEXT:.b8 250 // DW_AT_decl_line -; CHECK-NEXT:.b32 8000 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0xcd1:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 8001 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0xcd2:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 8 // DW_AT_decl_file ; CHECK-NEXT:.b8 251 // DW_AT_decl_line -; CHECK-NEXT:.b32 7907 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0xcd8:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 7908 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0xcd9:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 8 // DW_AT_decl_file ; CHECK-NEXT:.b8 252 // DW_AT_decl_line -; CHECK-NEXT:.b32 7940 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0xcdf:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 7941 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0xce0:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 8 // DW_AT_decl_file ; CHECK-NEXT:.b8 253 // DW_AT_decl_line -; CHECK-NEXT:.b32 8027 // DW_AT_import -; CHECK-NEXT:.b8 30 // Abbrev [30] 0xce6:0x8 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 8028 // DW_AT_import +; CHECK-NEXT:.b8 30 // Abbrev [30] 0xce7:0x8 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 13 // DW_AT_decl_file ; CHECK-NEXT:.b8 149 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 -; CHECK-NEXT:.b32 8070 // DW_AT_import -; CHECK-NEXT:.b8 30 // Abbrev [30] 0xcee:0x8 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 8071 // DW_AT_import +; CHECK-NEXT:.b8 30 // Abbrev [30] 0xcef:0x8 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 13 // DW_AT_decl_file ; CHECK-NEXT:.b8 150 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 -; CHECK-NEXT:.b32 8102 // DW_AT_import -; CHECK-NEXT:.b8 30 // Abbrev [30] 0xcf6:0x8 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 8103 // DW_AT_import +; CHECK-NEXT:.b8 30 // Abbrev [30] 0xcf7:0x8 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 13 // DW_AT_decl_file ; CHECK-NEXT:.b8 151 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 -; CHECK-NEXT:.b32 8136 // DW_AT_import -; CHECK-NEXT:.b8 30 // Abbrev [30] 0xcfe:0x8 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 8137 // DW_AT_import +; CHECK-NEXT:.b8 30 // Abbrev [30] 0xcff:0x8 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 13 // DW_AT_decl_file ; CHECK-NEXT:.b8 152 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 -; CHECK-NEXT:.b32 8168 // DW_AT_import -; CHECK-NEXT:.b8 30 // Abbrev [30] 0xd06:0x8 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 8169 // DW_AT_import +; CHECK-NEXT:.b8 30 // Abbrev [30] 0xd07:0x8 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 13 // DW_AT_decl_file ; CHECK-NEXT:.b8 153 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 -; CHECK-NEXT:.b32 8202 // DW_AT_import -; CHECK-NEXT:.b8 30 // Abbrev [30] 0xd0e:0x8 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 8203 // DW_AT_import +; CHECK-NEXT:.b8 30 // Abbrev [30] 0xd0f:0x8 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 13 // DW_AT_decl_file ; CHECK-NEXT:.b8 154 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 -; CHECK-NEXT:.b32 8242 // DW_AT_import -; CHECK-NEXT:.b8 30 // Abbrev [30] 0xd16:0x8 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 8243 // DW_AT_import +; CHECK-NEXT:.b8 30 // Abbrev [30] 0xd17:0x8 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 13 // DW_AT_decl_file ; CHECK-NEXT:.b8 155 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 -; CHECK-NEXT:.b32 8274 // DW_AT_import -; CHECK-NEXT:.b8 30 // Abbrev [30] 0xd1e:0x8 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 8275 // DW_AT_import +; CHECK-NEXT:.b8 30 // Abbrev [30] 0xd1f:0x8 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 13 // DW_AT_decl_file ; CHECK-NEXT:.b8 156 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 -; CHECK-NEXT:.b32 8308 // DW_AT_import -; CHECK-NEXT:.b8 30 // Abbrev [30] 0xd26:0x8 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 8309 // DW_AT_import +; CHECK-NEXT:.b8 30 // Abbrev [30] 0xd27:0x8 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 13 // DW_AT_decl_file ; CHECK-NEXT:.b8 157 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 -; CHECK-NEXT:.b32 8340 // DW_AT_import -; CHECK-NEXT:.b8 30 // Abbrev [30] 0xd2e:0x8 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 8341 // DW_AT_import +; CHECK-NEXT:.b8 30 // Abbrev [30] 0xd2f:0x8 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 13 // DW_AT_decl_file ; CHECK-NEXT:.b8 158 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 -; CHECK-NEXT:.b32 8372 // DW_AT_import -; CHECK-NEXT:.b8 30 // Abbrev [30] 0xd36:0x8 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 8373 // DW_AT_import +; CHECK-NEXT:.b8 30 // Abbrev [30] 0xd37:0x8 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 13 // DW_AT_decl_file ; CHECK-NEXT:.b8 159 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 -; CHECK-NEXT:.b32 8418 // DW_AT_import -; CHECK-NEXT:.b8 30 // Abbrev [30] 0xd3e:0x8 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 8419 // DW_AT_import +; CHECK-NEXT:.b8 30 // Abbrev [30] 0xd3f:0x8 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 13 // DW_AT_decl_file ; CHECK-NEXT:.b8 160 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 -; CHECK-NEXT:.b32 8448 // DW_AT_import -; CHECK-NEXT:.b8 30 // Abbrev [30] 0xd46:0x8 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 8449 // DW_AT_import +; CHECK-NEXT:.b8 30 // Abbrev [30] 0xd47:0x8 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 13 // DW_AT_decl_file ; CHECK-NEXT:.b8 161 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 -; CHECK-NEXT:.b32 8480 // DW_AT_import -; CHECK-NEXT:.b8 30 // Abbrev [30] 0xd4e:0x8 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 8481 // DW_AT_import +; CHECK-NEXT:.b8 30 // Abbrev [30] 0xd4f:0x8 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 13 // DW_AT_decl_file ; CHECK-NEXT:.b8 162 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 -; CHECK-NEXT:.b32 8512 // DW_AT_import -; CHECK-NEXT:.b8 30 // Abbrev [30] 0xd56:0x8 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 8513 // DW_AT_import +; CHECK-NEXT:.b8 30 // Abbrev [30] 0xd57:0x8 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 13 // DW_AT_decl_file ; CHECK-NEXT:.b8 163 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 -; CHECK-NEXT:.b32 8542 // DW_AT_import -; CHECK-NEXT:.b8 30 // Abbrev [30] 0xd5e:0x8 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 8543 // DW_AT_import +; CHECK-NEXT:.b8 30 // Abbrev [30] 0xd5f:0x8 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 13 // DW_AT_decl_file ; CHECK-NEXT:.b8 164 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 -; CHECK-NEXT:.b32 8574 // DW_AT_import -; CHECK-NEXT:.b8 30 // Abbrev [30] 0xd66:0x8 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 8575 // DW_AT_import +; CHECK-NEXT:.b8 30 // Abbrev [30] 0xd67:0x8 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 13 // DW_AT_decl_file ; CHECK-NEXT:.b8 165 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 -; CHECK-NEXT:.b32 8604 // DW_AT_import -; CHECK-NEXT:.b8 30 // Abbrev [30] 0xd6e:0x8 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 8605 // DW_AT_import +; CHECK-NEXT:.b8 30 // Abbrev [30] 0xd6f:0x8 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 13 // DW_AT_decl_file ; CHECK-NEXT:.b8 166 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 -; CHECK-NEXT:.b32 8638 // DW_AT_import -; CHECK-NEXT:.b8 30 // Abbrev [30] 0xd76:0x8 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 8639 // DW_AT_import +; CHECK-NEXT:.b8 30 // Abbrev [30] 0xd77:0x8 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 13 // DW_AT_decl_file ; CHECK-NEXT:.b8 167 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 -; CHECK-NEXT:.b32 8670 // DW_AT_import -; CHECK-NEXT:.b8 30 // Abbrev [30] 0xd7e:0x8 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 8671 // DW_AT_import +; CHECK-NEXT:.b8 30 // Abbrev [30] 0xd7f:0x8 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 13 // DW_AT_decl_file ; CHECK-NEXT:.b8 168 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 -; CHECK-NEXT:.b32 8708 // DW_AT_import -; CHECK-NEXT:.b8 30 // Abbrev [30] 0xd86:0x8 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 8709 // DW_AT_import +; CHECK-NEXT:.b8 30 // Abbrev [30] 0xd87:0x8 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 13 // DW_AT_decl_file ; CHECK-NEXT:.b8 169 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 -; CHECK-NEXT:.b32 8742 // DW_AT_import -; CHECK-NEXT:.b8 30 // Abbrev [30] 0xd8e:0x8 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 8743 // DW_AT_import +; CHECK-NEXT:.b8 30 // Abbrev [30] 0xd8f:0x8 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 13 // DW_AT_decl_file ; CHECK-NEXT:.b8 170 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 -; CHECK-NEXT:.b32 8784 // DW_AT_import -; CHECK-NEXT:.b8 30 // Abbrev [30] 0xd96:0x8 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 8785 // DW_AT_import +; CHECK-NEXT:.b8 30 // Abbrev [30] 0xd97:0x8 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 13 // DW_AT_decl_file ; CHECK-NEXT:.b8 171 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 -; CHECK-NEXT:.b32 8822 // DW_AT_import -; CHECK-NEXT:.b8 30 // Abbrev [30] 0xd9e:0x8 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 8823 // DW_AT_import +; CHECK-NEXT:.b8 30 // Abbrev [30] 0xd9f:0x8 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 13 // DW_AT_decl_file ; CHECK-NEXT:.b8 172 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 -; CHECK-NEXT:.b32 8860 // DW_AT_import -; CHECK-NEXT:.b8 30 // Abbrev [30] 0xda6:0x8 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 8861 // DW_AT_import +; CHECK-NEXT:.b8 30 // Abbrev [30] 0xda7:0x8 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 13 // DW_AT_decl_file ; CHECK-NEXT:.b8 173 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 -; CHECK-NEXT:.b32 8898 // DW_AT_import -; CHECK-NEXT:.b8 30 // Abbrev [30] 0xdae:0x8 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 8899 // DW_AT_import +; CHECK-NEXT:.b8 30 // Abbrev [30] 0xdaf:0x8 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 13 // DW_AT_decl_file ; CHECK-NEXT:.b8 174 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 -; CHECK-NEXT:.b32 8939 // DW_AT_import -; CHECK-NEXT:.b8 30 // Abbrev [30] 0xdb6:0x8 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 8940 // DW_AT_import +; CHECK-NEXT:.b8 30 // Abbrev [30] 0xdb7:0x8 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 13 // DW_AT_decl_file ; CHECK-NEXT:.b8 175 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 -; CHECK-NEXT:.b32 8979 // DW_AT_import -; CHECK-NEXT:.b8 30 // Abbrev [30] 0xdbe:0x8 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 8980 // DW_AT_import +; CHECK-NEXT:.b8 30 // Abbrev [30] 0xdbf:0x8 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 13 // DW_AT_decl_file ; CHECK-NEXT:.b8 176 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 -; CHECK-NEXT:.b32 9013 // DW_AT_import -; CHECK-NEXT:.b8 30 // Abbrev [30] 0xdc6:0x8 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 9014 // DW_AT_import +; CHECK-NEXT:.b8 30 // Abbrev [30] 0xdc7:0x8 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 13 // DW_AT_decl_file ; CHECK-NEXT:.b8 177 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 -; CHECK-NEXT:.b32 9053 // DW_AT_import -; CHECK-NEXT:.b8 30 // Abbrev [30] 0xdce:0x8 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 9054 // DW_AT_import +; CHECK-NEXT:.b8 30 // Abbrev [30] 0xdcf:0x8 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 13 // DW_AT_decl_file ; CHECK-NEXT:.b8 178 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 -; CHECK-NEXT:.b32 9089 // DW_AT_import -; CHECK-NEXT:.b8 30 // Abbrev [30] 0xdd6:0x8 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 9090 // DW_AT_import +; CHECK-NEXT:.b8 30 // Abbrev [30] 0xdd7:0x8 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 13 // DW_AT_decl_file ; CHECK-NEXT:.b8 179 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 -; CHECK-NEXT:.b32 9125 // DW_AT_import -; CHECK-NEXT:.b8 30 // Abbrev [30] 0xdde:0x8 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 9126 // DW_AT_import +; CHECK-NEXT:.b8 30 // Abbrev [30] 0xddf:0x8 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 13 // DW_AT_decl_file ; CHECK-NEXT:.b8 180 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 -; CHECK-NEXT:.b32 9163 // DW_AT_import -; CHECK-NEXT:.b8 30 // Abbrev [30] 0xde6:0x8 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 9164 // DW_AT_import +; CHECK-NEXT:.b8 30 // Abbrev [30] 0xde7:0x8 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 13 // DW_AT_decl_file ; CHECK-NEXT:.b8 181 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 -; CHECK-NEXT:.b32 9197 // DW_AT_import -; CHECK-NEXT:.b8 30 // Abbrev [30] 0xdee:0x8 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 9198 // DW_AT_import +; CHECK-NEXT:.b8 30 // Abbrev [30] 0xdef:0x8 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 13 // DW_AT_decl_file ; CHECK-NEXT:.b8 182 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 -; CHECK-NEXT:.b32 9231 // DW_AT_import -; CHECK-NEXT:.b8 30 // Abbrev [30] 0xdf6:0x8 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 9232 // DW_AT_import +; CHECK-NEXT:.b8 30 // Abbrev [30] 0xdf7:0x8 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 13 // DW_AT_decl_file ; CHECK-NEXT:.b8 183 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 -; CHECK-NEXT:.b32 9263 // DW_AT_import -; CHECK-NEXT:.b8 30 // Abbrev [30] 0xdfe:0x8 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 9264 // DW_AT_import +; CHECK-NEXT:.b8 30 // Abbrev [30] 0xdff:0x8 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 13 // DW_AT_decl_file ; CHECK-NEXT:.b8 184 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 -; CHECK-NEXT:.b32 9295 // DW_AT_import -; CHECK-NEXT:.b8 30 // Abbrev [30] 0xe06:0x8 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 9296 // DW_AT_import +; CHECK-NEXT:.b8 30 // Abbrev [30] 0xe07:0x8 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 13 // DW_AT_decl_file ; CHECK-NEXT:.b8 185 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 -; CHECK-NEXT:.b32 9325 // DW_AT_import -; CHECK-NEXT:.b8 30 // Abbrev [30] 0xe0e:0x8 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 9326 // DW_AT_import +; CHECK-NEXT:.b8 30 // Abbrev [30] 0xe0f:0x8 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 13 // DW_AT_decl_file ; CHECK-NEXT:.b8 186 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 -; CHECK-NEXT:.b32 9359 // DW_AT_import -; CHECK-NEXT:.b8 30 // Abbrev [30] 0xe16:0x8 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 9360 // DW_AT_import +; CHECK-NEXT:.b8 30 // Abbrev [30] 0xe17:0x8 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 13 // DW_AT_decl_file ; CHECK-NEXT:.b8 187 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 -; CHECK-NEXT:.b32 9395 // DW_AT_import -; CHECK-NEXT:.b8 30 // Abbrev [30] 0xe1e:0x8 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 9396 // DW_AT_import +; CHECK-NEXT:.b8 30 // Abbrev [30] 0xe1f:0x8 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 13 // DW_AT_decl_file ; CHECK-NEXT:.b8 188 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 -; CHECK-NEXT:.b32 9434 // DW_AT_import -; CHECK-NEXT:.b8 30 // Abbrev [30] 0xe26:0x8 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 9435 // DW_AT_import +; CHECK-NEXT:.b8 30 // Abbrev [30] 0xe27:0x8 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 13 // DW_AT_decl_file ; CHECK-NEXT:.b8 189 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 -; CHECK-NEXT:.b32 9477 // DW_AT_import -; CHECK-NEXT:.b8 30 // Abbrev [30] 0xe2e:0x8 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 9478 // DW_AT_import +; CHECK-NEXT:.b8 30 // Abbrev [30] 0xe2f:0x8 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 13 // DW_AT_decl_file ; CHECK-NEXT:.b8 190 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 -; CHECK-NEXT:.b32 9526 // DW_AT_import -; CHECK-NEXT:.b8 30 // Abbrev [30] 0xe36:0x8 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 9527 // DW_AT_import +; CHECK-NEXT:.b8 30 // Abbrev [30] 0xe37:0x8 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 13 // DW_AT_decl_file ; CHECK-NEXT:.b8 191 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 -; CHECK-NEXT:.b32 9562 // DW_AT_import -; CHECK-NEXT:.b8 30 // Abbrev [30] 0xe3e:0x8 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 9563 // DW_AT_import +; CHECK-NEXT:.b8 30 // Abbrev [30] 0xe3f:0x8 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 13 // DW_AT_decl_file ; CHECK-NEXT:.b8 192 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 -; CHECK-NEXT:.b32 9611 // DW_AT_import -; CHECK-NEXT:.b8 30 // Abbrev [30] 0xe46:0x8 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 9612 // DW_AT_import +; CHECK-NEXT:.b8 30 // Abbrev [30] 0xe47:0x8 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 13 // DW_AT_decl_file ; CHECK-NEXT:.b8 193 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 -; CHECK-NEXT:.b32 9660 // DW_AT_import -; CHECK-NEXT:.b8 30 // Abbrev [30] 0xe4e:0x8 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 9661 // DW_AT_import +; CHECK-NEXT:.b8 30 // Abbrev [30] 0xe4f:0x8 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 13 // DW_AT_decl_file ; CHECK-NEXT:.b8 194 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 -; CHECK-NEXT:.b32 9692 // DW_AT_import -; CHECK-NEXT:.b8 30 // Abbrev [30] 0xe56:0x8 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 9693 // DW_AT_import +; CHECK-NEXT:.b8 30 // Abbrev [30] 0xe57:0x8 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 13 // DW_AT_decl_file ; CHECK-NEXT:.b8 195 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 -; CHECK-NEXT:.b32 9726 // DW_AT_import -; CHECK-NEXT:.b8 30 // Abbrev [30] 0xe5e:0x8 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 9727 // DW_AT_import +; CHECK-NEXT:.b8 30 // Abbrev [30] 0xe5f:0x8 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 13 // DW_AT_decl_file ; CHECK-NEXT:.b8 196 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 -; CHECK-NEXT:.b32 9770 // DW_AT_import -; CHECK-NEXT:.b8 30 // Abbrev [30] 0xe66:0x8 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 9771 // DW_AT_import +; CHECK-NEXT:.b8 30 // Abbrev [30] 0xe67:0x8 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 13 // DW_AT_decl_file ; CHECK-NEXT:.b8 197 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 -; CHECK-NEXT:.b32 9812 // DW_AT_import -; CHECK-NEXT:.b8 30 // Abbrev [30] 0xe6e:0x8 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 9813 // DW_AT_import +; CHECK-NEXT:.b8 30 // Abbrev [30] 0xe6f:0x8 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 13 // DW_AT_decl_file ; CHECK-NEXT:.b8 198 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 -; CHECK-NEXT:.b32 9842 // DW_AT_import -; CHECK-NEXT:.b8 30 // Abbrev [30] 0xe76:0x8 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 9843 // DW_AT_import +; CHECK-NEXT:.b8 30 // Abbrev [30] 0xe77:0x8 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 13 // DW_AT_decl_file ; CHECK-NEXT:.b8 199 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 -; CHECK-NEXT:.b32 9874 // DW_AT_import -; CHECK-NEXT:.b8 30 // Abbrev [30] 0xe7e:0x8 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 9875 // DW_AT_import +; CHECK-NEXT:.b8 30 // Abbrev [30] 0xe7f:0x8 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 13 // DW_AT_decl_file ; CHECK-NEXT:.b8 200 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 -; CHECK-NEXT:.b32 9906 // DW_AT_import -; CHECK-NEXT:.b8 30 // Abbrev [30] 0xe86:0x8 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 9907 // DW_AT_import +; CHECK-NEXT:.b8 30 // Abbrev [30] 0xe87:0x8 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 13 // DW_AT_decl_file ; CHECK-NEXT:.b8 201 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 -; CHECK-NEXT:.b32 9936 // DW_AT_import -; CHECK-NEXT:.b8 30 // Abbrev [30] 0xe8e:0x8 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 9937 // DW_AT_import +; CHECK-NEXT:.b8 30 // Abbrev [30] 0xe8f:0x8 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 13 // DW_AT_decl_file ; CHECK-NEXT:.b8 202 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 -; CHECK-NEXT:.b32 9968 // DW_AT_import -; CHECK-NEXT:.b8 30 // Abbrev [30] 0xe96:0x8 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 9969 // DW_AT_import +; CHECK-NEXT:.b8 30 // Abbrev [30] 0xe97:0x8 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 13 // DW_AT_decl_file ; CHECK-NEXT:.b8 203 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 -; CHECK-NEXT:.b32 10004 // DW_AT_import +; CHECK-NEXT:.b32 10005 // DW_AT_import ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 31 // Abbrev [31] 0xe9f:0x1b DW_TAG_subprogram +; CHECK-NEXT:.b8 31 // Abbrev [31] 0xea0:0x1b DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -3564,12 +3567,12 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 0 ; CHECK-NEXT:.b8 4 // DW_AT_decl_file ; CHECK-NEXT:.b8 44 // DW_AT_decl_line -; CHECK-NEXT:.b32 3770 // DW_AT_type +; CHECK-NEXT:.b32 3771 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0xeb4:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 3770 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0xeb5:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 3771 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 10 // Abbrev [10] 0xeba:0x11 DW_TAG_base_type +; CHECK-NEXT:.b8 10 // Abbrev [10] 0xebb:0x11 DW_TAG_base_type ; CHECK-NEXT:.b8 108 // DW_AT_name ; CHECK-NEXT:.b8 111 ; CHECK-NEXT:.b8 110 @@ -3586,7 +3589,7 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 0 ; CHECK-NEXT:.b8 5 // DW_AT_encoding ; CHECK-NEXT:.b8 8 // DW_AT_byte_size -; CHECK-NEXT:.b8 31 // Abbrev [31] 0xecb:0x1d DW_TAG_subprogram +; CHECK-NEXT:.b8 31 // Abbrev [31] 0xecc:0x1d DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -3606,10 +3609,10 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 46 // DW_AT_decl_line ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0xee2:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0xee3:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 31 // Abbrev [31] 0xee8:0x1f DW_TAG_subprogram +; CHECK-NEXT:.b8 31 // Abbrev [31] 0xee9:0x1f DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -3631,10 +3634,10 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 48 // DW_AT_decl_line ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0xf01:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0xf02:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 31 // Abbrev [31] 0xf07:0x1d DW_TAG_subprogram +; CHECK-NEXT:.b8 31 // Abbrev [31] 0xf08:0x1d DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -3654,10 +3657,10 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 50 // DW_AT_decl_line ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0xf1e:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0xf1f:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 31 // Abbrev [31] 0xf24:0x1f DW_TAG_subprogram +; CHECK-NEXT:.b8 31 // Abbrev [31] 0xf25:0x1f DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -3679,10 +3682,10 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 52 // DW_AT_decl_line ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0xf3d:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0xf3e:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 31 // Abbrev [31] 0xf43:0x1d DW_TAG_subprogram +; CHECK-NEXT:.b8 31 // Abbrev [31] 0xf44:0x1d DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -3702,10 +3705,10 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 56 // DW_AT_decl_line ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0xf5a:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0xf5b:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 31 // Abbrev [31] 0xf60:0x25 DW_TAG_subprogram +; CHECK-NEXT:.b8 31 // Abbrev [31] 0xf61:0x25 DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -3728,12 +3731,12 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 54 // DW_AT_decl_line ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0xf7a:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0xf7b:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type -; CHECK-NEXT:.b8 7 // Abbrev [7] 0xf7f:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0xf80:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 31 // Abbrev [31] 0xf85:0x1f DW_TAG_subprogram +; CHECK-NEXT:.b8 31 // Abbrev [31] 0xf86:0x1f DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -3755,10 +3758,10 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 58 // DW_AT_decl_line ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0xf9e:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0xf9f:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 31 // Abbrev [31] 0xfa4:0x1d DW_TAG_subprogram +; CHECK-NEXT:.b8 31 // Abbrev [31] 0xfa5:0x1d DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -3778,10 +3781,10 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 60 // DW_AT_decl_line ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0xfbb:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0xfbc:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 31 // Abbrev [31] 0xfc1:0x1d DW_TAG_subprogram +; CHECK-NEXT:.b8 31 // Abbrev [31] 0xfc2:0x1d DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -3801,10 +3804,10 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 62 // DW_AT_decl_line ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0xfd8:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0xfd9:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 31 // Abbrev [31] 0xfde:0x2b DW_TAG_subprogram +; CHECK-NEXT:.b8 31 // Abbrev [31] 0xfdf:0x2b DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -3833,12 +3836,12 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 64 // DW_AT_decl_line ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0xffe:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0xfff:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1003:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1004:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 31 // Abbrev [31] 0x1009:0x1b DW_TAG_subprogram +; CHECK-NEXT:.b8 31 // Abbrev [31] 0x100a:0x1b DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -3856,10 +3859,10 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 66 // DW_AT_decl_line ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x101e:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x101f:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 31 // Abbrev [31] 0x1024:0x1d DW_TAG_subprogram +; CHECK-NEXT:.b8 31 // Abbrev [31] 0x1025:0x1d DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -3879,10 +3882,10 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 68 // DW_AT_decl_line ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x103b:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x103c:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 31 // Abbrev [31] 0x1041:0x1b DW_TAG_subprogram +; CHECK-NEXT:.b8 31 // Abbrev [31] 0x1042:0x1b DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -3900,10 +3903,10 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 72 // DW_AT_decl_line ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1056:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1057:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 31 // Abbrev [31] 0x105c:0x1d DW_TAG_subprogram +; CHECK-NEXT:.b8 31 // Abbrev [31] 0x105d:0x1d DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -3923,10 +3926,10 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 70 // DW_AT_decl_line ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1073:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1074:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 31 // Abbrev [31] 0x1079:0x1b DW_TAG_subprogram +; CHECK-NEXT:.b8 31 // Abbrev [31] 0x107a:0x1b DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -3944,10 +3947,10 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 76 // DW_AT_decl_line ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x108e:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x108f:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 31 // Abbrev [31] 0x1094:0x1d DW_TAG_subprogram +; CHECK-NEXT:.b8 31 // Abbrev [31] 0x1095:0x1d DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -3967,10 +3970,10 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 74 // DW_AT_decl_line ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x10ab:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x10ac:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 31 // Abbrev [31] 0x10b1:0x1f DW_TAG_subprogram +; CHECK-NEXT:.b8 31 // Abbrev [31] 0x10b2:0x1f DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -3992,10 +3995,10 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 78 // DW_AT_decl_line ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x10ca:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x10cb:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 31 // Abbrev [31] 0x10d0:0x1d DW_TAG_subprogram +; CHECK-NEXT:.b8 31 // Abbrev [31] 0x10d1:0x1d DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -4015,10 +4018,10 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 80 // DW_AT_decl_line ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x10e7:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x10e8:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 31 // Abbrev [31] 0x10ed:0x23 DW_TAG_subprogram +; CHECK-NEXT:.b8 31 // Abbrev [31] 0x10ee:0x23 DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -4039,12 +4042,12 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 82 // DW_AT_decl_line ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1105:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1106:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x110a:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x110b:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 31 // Abbrev [31] 0x1110:0x1f DW_TAG_subprogram +; CHECK-NEXT:.b8 31 // Abbrev [31] 0x1111:0x1f DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -4066,10 +4069,10 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 84 // DW_AT_decl_line ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1129:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x112a:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 31 // Abbrev [31] 0x112f:0x27 DW_TAG_subprogram +; CHECK-NEXT:.b8 31 // Abbrev [31] 0x1130:0x27 DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -4089,14 +4092,14 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 86 // DW_AT_decl_line ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1146:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1147:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x114b:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x114c:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1150:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1151:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 31 // Abbrev [31] 0x1156:0x23 DW_TAG_subprogram +; CHECK-NEXT:.b8 31 // Abbrev [31] 0x1157:0x23 DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -4117,12 +4120,12 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 88 // DW_AT_decl_line ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x116e:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x116f:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1173:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1174:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 31 // Abbrev [31] 0x1179:0x23 DW_TAG_subprogram +; CHECK-NEXT:.b8 31 // Abbrev [31] 0x117a:0x23 DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -4143,12 +4146,12 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 90 // DW_AT_decl_line ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1191:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1192:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1196:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1197:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 31 // Abbrev [31] 0x119c:0x23 DW_TAG_subprogram +; CHECK-NEXT:.b8 31 // Abbrev [31] 0x119d:0x23 DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -4169,12 +4172,12 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 92 // DW_AT_decl_line ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x11b4:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x11b5:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x11b9:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x11ba:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 31 // Abbrev [31] 0x11bf:0x2a DW_TAG_subprogram +; CHECK-NEXT:.b8 31 // Abbrev [31] 0x11c0:0x2a DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -4205,19 +4208,19 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 0 ; CHECK-NEXT:.b8 4 // DW_AT_decl_file ; CHECK-NEXT:.b8 94 // DW_AT_decl_line -; CHECK-NEXT:.b32 4585 // DW_AT_type +; CHECK-NEXT:.b32 4586 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x11e3:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x11e4:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 10 // Abbrev [10] 0x11e9:0x7 DW_TAG_base_type +; CHECK-NEXT:.b8 10 // Abbrev [10] 0x11ea:0x7 DW_TAG_base_type ; CHECK-NEXT:.b8 105 // DW_AT_name ; CHECK-NEXT:.b8 110 ; CHECK-NEXT:.b8 116 ; CHECK-NEXT:.b8 0 ; CHECK-NEXT:.b8 5 // DW_AT_encoding ; CHECK-NEXT:.b8 4 // DW_AT_byte_size -; CHECK-NEXT:.b8 31 // Abbrev [31] 0x11f0:0x26 DW_TAG_subprogram +; CHECK-NEXT:.b8 31 // Abbrev [31] 0x11f1:0x26 DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -4241,14 +4244,14 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 96 // DW_AT_decl_line ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x120b:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x120c:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1210:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 4630 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1211:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 4631 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 12 // Abbrev [12] 0x1216:0x5 DW_TAG_pointer_type -; CHECK-NEXT:.b32 4585 // DW_AT_type -; CHECK-NEXT:.b8 31 // Abbrev [31] 0x121b:0x25 DW_TAG_subprogram +; CHECK-NEXT:.b8 12 // Abbrev [12] 0x1217:0x5 DW_TAG_pointer_type +; CHECK-NEXT:.b32 4586 // DW_AT_type +; CHECK-NEXT:.b8 31 // Abbrev [31] 0x121c:0x25 DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -4271,12 +4274,12 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 98 // DW_AT_decl_line ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1235:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1236:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x123a:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x123b:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 31 // Abbrev [31] 0x1240:0x1f DW_TAG_subprogram +; CHECK-NEXT:.b8 31 // Abbrev [31] 0x1241:0x1f DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -4296,12 +4299,12 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 0 ; CHECK-NEXT:.b8 4 // DW_AT_decl_file ; CHECK-NEXT:.b8 100 // DW_AT_decl_line -; CHECK-NEXT:.b32 4585 // DW_AT_type +; CHECK-NEXT:.b32 4586 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1259:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x125a:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 31 // Abbrev [31] 0x125f:0x25 DW_TAG_subprogram +; CHECK-NEXT:.b8 31 // Abbrev [31] 0x1260:0x25 DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -4327,12 +4330,12 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 0 ; CHECK-NEXT:.b8 4 // DW_AT_decl_file ; CHECK-NEXT:.b8 102 // DW_AT_decl_line -; CHECK-NEXT:.b32 4740 // DW_AT_type +; CHECK-NEXT:.b32 4741 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x127e:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x127f:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 10 // Abbrev [10] 0x1284:0x8 DW_TAG_base_type +; CHECK-NEXT:.b8 10 // Abbrev [10] 0x1285:0x8 DW_TAG_base_type ; CHECK-NEXT:.b8 98 // DW_AT_name ; CHECK-NEXT:.b8 111 ; CHECK-NEXT:.b8 111 @@ -4340,7 +4343,7 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 0 ; CHECK-NEXT:.b8 2 // DW_AT_encoding ; CHECK-NEXT:.b8 1 // DW_AT_byte_size -; CHECK-NEXT:.b8 31 // Abbrev [31] 0x128c:0x2d DW_TAG_subprogram +; CHECK-NEXT:.b8 31 // Abbrev [31] 0x128d:0x2d DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -4369,14 +4372,14 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 0 ; CHECK-NEXT:.b8 4 // DW_AT_decl_file ; CHECK-NEXT:.b8 106 // DW_AT_decl_line -; CHECK-NEXT:.b32 4740 // DW_AT_type +; CHECK-NEXT:.b32 4741 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x12ae:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x12af:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x12b3:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x12b4:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 31 // Abbrev [31] 0x12b9:0x38 DW_TAG_subprogram +; CHECK-NEXT:.b8 31 // Abbrev [31] 0x12ba:0x38 DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -4416,14 +4419,14 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 0 ; CHECK-NEXT:.b8 4 // DW_AT_decl_file ; CHECK-NEXT:.b8 105 // DW_AT_decl_line -; CHECK-NEXT:.b32 4740 // DW_AT_type +; CHECK-NEXT:.b32 4741 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x12e6:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x12e7:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x12eb:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x12ec:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 31 // Abbrev [31] 0x12f1:0x1f DW_TAG_subprogram +; CHECK-NEXT:.b8 31 // Abbrev [31] 0x12f2:0x1f DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -4443,12 +4446,12 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 0 ; CHECK-NEXT:.b8 4 // DW_AT_decl_file ; CHECK-NEXT:.b8 108 // DW_AT_decl_line -; CHECK-NEXT:.b32 4740 // DW_AT_type +; CHECK-NEXT:.b32 4741 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x130a:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x130b:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 31 // Abbrev [31] 0x1310:0x27 DW_TAG_subprogram +; CHECK-NEXT:.b8 31 // Abbrev [31] 0x1311:0x27 DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -4471,14 +4474,14 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 0 ; CHECK-NEXT:.b8 4 // DW_AT_decl_file ; CHECK-NEXT:.b8 112 // DW_AT_decl_line -; CHECK-NEXT:.b32 4740 // DW_AT_type +; CHECK-NEXT:.b32 4741 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x132c:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x132d:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1331:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1332:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 31 // Abbrev [31] 0x1337:0x32 DW_TAG_subprogram +; CHECK-NEXT:.b8 31 // Abbrev [31] 0x1338:0x32 DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -4512,14 +4515,14 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 0 ; CHECK-NEXT:.b8 4 // DW_AT_decl_file ; CHECK-NEXT:.b8 111 // DW_AT_decl_line -; CHECK-NEXT:.b32 4740 // DW_AT_type +; CHECK-NEXT:.b32 4741 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x135e:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x135f:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1363:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1364:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 31 // Abbrev [31] 0x1369:0x36 DW_TAG_subprogram +; CHECK-NEXT:.b8 31 // Abbrev [31] 0x136a:0x36 DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -4557,14 +4560,14 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 0 ; CHECK-NEXT:.b8 4 // DW_AT_decl_file ; CHECK-NEXT:.b8 114 // DW_AT_decl_line -; CHECK-NEXT:.b32 4740 // DW_AT_type +; CHECK-NEXT:.b32 4741 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1394:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1395:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1399:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x139a:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 31 // Abbrev [31] 0x139f:0x1f DW_TAG_subprogram +; CHECK-NEXT:.b8 31 // Abbrev [31] 0x13a0:0x1f DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -4584,12 +4587,12 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 0 ; CHECK-NEXT:.b8 4 // DW_AT_decl_file ; CHECK-NEXT:.b8 116 // DW_AT_decl_line -; CHECK-NEXT:.b32 4740 // DW_AT_type +; CHECK-NEXT:.b32 4741 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x13b8:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x13b9:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 31 // Abbrev [31] 0x13be:0x25 DW_TAG_subprogram +; CHECK-NEXT:.b8 31 // Abbrev [31] 0x13bf:0x25 DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -4615,12 +4618,12 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 0 ; CHECK-NEXT:.b8 4 // DW_AT_decl_file ; CHECK-NEXT:.b8 118 // DW_AT_decl_line -; CHECK-NEXT:.b32 4740 // DW_AT_type +; CHECK-NEXT:.b32 4741 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x13dd:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x13de:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 31 // Abbrev [31] 0x13e3:0x32 DW_TAG_subprogram +; CHECK-NEXT:.b8 31 // Abbrev [31] 0x13e4:0x32 DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -4654,14 +4657,14 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 0 ; CHECK-NEXT:.b8 4 // DW_AT_decl_file ; CHECK-NEXT:.b8 120 // DW_AT_decl_line -; CHECK-NEXT:.b32 4740 // DW_AT_type +; CHECK-NEXT:.b32 4741 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x140a:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x140b:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x140f:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1410:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 31 // Abbrev [31] 0x1415:0x1d DW_TAG_subprogram +; CHECK-NEXT:.b8 31 // Abbrev [31] 0x1416:0x1d DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -4679,12 +4682,12 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 0 ; CHECK-NEXT:.b8 4 // DW_AT_decl_file ; CHECK-NEXT:.b8 121 // DW_AT_decl_line -; CHECK-NEXT:.b32 5170 // DW_AT_type +; CHECK-NEXT:.b32 5171 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x142c:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 5170 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x142d:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 5171 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 10 // Abbrev [10] 0x1432:0xc DW_TAG_base_type +; CHECK-NEXT:.b8 10 // Abbrev [10] 0x1433:0xc DW_TAG_base_type ; CHECK-NEXT:.b8 108 // DW_AT_name ; CHECK-NEXT:.b8 111 ; CHECK-NEXT:.b8 110 @@ -4696,7 +4699,7 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 0 ; CHECK-NEXT:.b8 5 // DW_AT_encoding ; CHECK-NEXT:.b8 8 // DW_AT_byte_size -; CHECK-NEXT:.b8 31 // Abbrev [31] 0x143e:0x25 DW_TAG_subprogram +; CHECK-NEXT:.b8 31 // Abbrev [31] 0x143f:0x25 DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -4719,12 +4722,12 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 123 // DW_AT_decl_line ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1458:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1459:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x145d:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 4585 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x145e:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 4586 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 31 // Abbrev [31] 0x1463:0x21 DW_TAG_subprogram +; CHECK-NEXT:.b8 31 // Abbrev [31] 0x1464:0x21 DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -4748,10 +4751,10 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 125 // DW_AT_decl_line ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x147e:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x147f:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 31 // Abbrev [31] 0x1484:0x1f DW_TAG_subprogram +; CHECK-NEXT:.b8 31 // Abbrev [31] 0x1485:0x1f DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -4771,12 +4774,12 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 0 ; CHECK-NEXT:.b8 4 // DW_AT_decl_file ; CHECK-NEXT:.b8 126 // DW_AT_decl_line -; CHECK-NEXT:.b32 3770 // DW_AT_type +; CHECK-NEXT:.b32 3771 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x149d:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 3770 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x149e:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 3771 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 31 // Abbrev [31] 0x14a3:0x21 DW_TAG_subprogram +; CHECK-NEXT:.b8 31 // Abbrev [31] 0x14a4:0x21 DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -4798,12 +4801,12 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 0 ; CHECK-NEXT:.b8 4 // DW_AT_decl_file ; CHECK-NEXT:.b8 128 // DW_AT_decl_line -; CHECK-NEXT:.b32 3770 // DW_AT_type +; CHECK-NEXT:.b32 3771 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x14be:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x14bf:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 31 // Abbrev [31] 0x14c4:0x1b DW_TAG_subprogram +; CHECK-NEXT:.b8 31 // Abbrev [31] 0x14c5:0x1b DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -4821,10 +4824,10 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 138 // DW_AT_decl_line ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x14d9:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x14da:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 31 // Abbrev [31] 0x14df:0x1f DW_TAG_subprogram +; CHECK-NEXT:.b8 31 // Abbrev [31] 0x14e0:0x1f DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -4846,10 +4849,10 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 130 // DW_AT_decl_line ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x14f8:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x14f9:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 31 // Abbrev [31] 0x14fe:0x1f DW_TAG_subprogram +; CHECK-NEXT:.b8 31 // Abbrev [31] 0x14ff:0x1f DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -4871,10 +4874,10 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 132 // DW_AT_decl_line ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1517:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1518:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 31 // Abbrev [31] 0x151d:0x1d DW_TAG_subprogram +; CHECK-NEXT:.b8 31 // Abbrev [31] 0x151e:0x1d DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -4894,10 +4897,10 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 134 // DW_AT_decl_line ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1534:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1535:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 31 // Abbrev [31] 0x153a:0x1d DW_TAG_subprogram +; CHECK-NEXT:.b8 31 // Abbrev [31] 0x153b:0x1d DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -4917,10 +4920,10 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 136 // DW_AT_decl_line ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1551:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1552:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 31 // Abbrev [31] 0x1557:0x1f DW_TAG_subprogram +; CHECK-NEXT:.b8 31 // Abbrev [31] 0x1558:0x1f DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -4940,12 +4943,12 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 0 ; CHECK-NEXT:.b8 4 // DW_AT_decl_file ; CHECK-NEXT:.b8 140 // DW_AT_decl_line -; CHECK-NEXT:.b32 5170 // DW_AT_type +; CHECK-NEXT:.b32 5171 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1570:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1571:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 31 // Abbrev [31] 0x1576:0x21 DW_TAG_subprogram +; CHECK-NEXT:.b8 31 // Abbrev [31] 0x1577:0x21 DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -4967,12 +4970,12 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 0 ; CHECK-NEXT:.b8 4 // DW_AT_decl_file ; CHECK-NEXT:.b8 142 // DW_AT_decl_line -; CHECK-NEXT:.b32 5170 // DW_AT_type +; CHECK-NEXT:.b32 5171 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1591:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1592:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 31 // Abbrev [31] 0x1597:0x23 DW_TAG_subprogram +; CHECK-NEXT:.b8 31 // Abbrev [31] 0x1598:0x23 DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -4996,12 +4999,12 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 0 ; CHECK-NEXT:.b8 4 // DW_AT_decl_file ; CHECK-NEXT:.b8 143 // DW_AT_decl_line -; CHECK-NEXT:.b32 3770 // DW_AT_type +; CHECK-NEXT:.b32 3771 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x15b4:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x15b5:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 31 // Abbrev [31] 0x15ba:0x24 DW_TAG_subprogram +; CHECK-NEXT:.b8 31 // Abbrev [31] 0x15bb:0x24 DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -5023,12 +5026,12 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 145 // DW_AT_decl_line ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x15d3:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x15d4:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x15d8:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x15d9:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2125 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 31 // Abbrev [31] 0x15de:0x1d DW_TAG_subprogram +; CHECK-NEXT:.b8 31 // Abbrev [31] 0x15df:0x1d DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -5046,12 +5049,12 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 0 ; CHECK-NEXT:.b8 4 // DW_AT_decl_file ; CHECK-NEXT:.b8 146 // DW_AT_decl_line -; CHECK-NEXT:.b32 5627 // DW_AT_type +; CHECK-NEXT:.b32 5628 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x15f5:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 5637 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x15f6:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 5638 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 10 // Abbrev [10] 0x15fb:0xa DW_TAG_base_type +; CHECK-NEXT:.b8 10 // Abbrev [10] 0x15fc:0xa DW_TAG_base_type ; CHECK-NEXT:.b8 100 // DW_AT_name ; CHECK-NEXT:.b8 111 ; CHECK-NEXT:.b8 117 @@ -5061,11 +5064,11 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 0 ; CHECK-NEXT:.b8 4 // DW_AT_encoding ; CHECK-NEXT:.b8 8 // DW_AT_byte_size -; CHECK-NEXT:.b8 12 // Abbrev [12] 0x1605:0x5 DW_TAG_pointer_type -; CHECK-NEXT:.b32 5642 // DW_AT_type -; CHECK-NEXT:.b8 13 // Abbrev [13] 0x160a:0x5 DW_TAG_const_type -; CHECK-NEXT:.b32 5647 // DW_AT_type -; CHECK-NEXT:.b8 10 // Abbrev [10] 0x160f:0x8 DW_TAG_base_type +; CHECK-NEXT:.b8 12 // Abbrev [12] 0x1606:0x5 DW_TAG_pointer_type +; CHECK-NEXT:.b32 5643 // DW_AT_type +; CHECK-NEXT:.b8 13 // Abbrev [13] 0x160b:0x5 DW_TAG_const_type +; CHECK-NEXT:.b32 5648 // DW_AT_type +; CHECK-NEXT:.b8 10 // Abbrev [10] 0x1610:0x8 DW_TAG_base_type ; CHECK-NEXT:.b8 99 // DW_AT_name ; CHECK-NEXT:.b8 104 ; CHECK-NEXT:.b8 97 @@ -5073,7 +5076,7 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 0 ; CHECK-NEXT:.b8 8 // DW_AT_encoding ; CHECK-NEXT:.b8 1 // DW_AT_byte_size -; CHECK-NEXT:.b8 31 // Abbrev [31] 0x1617:0x1f DW_TAG_subprogram +; CHECK-NEXT:.b8 31 // Abbrev [31] 0x1618:0x1f DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -5095,10 +5098,10 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 147 // DW_AT_decl_line ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1630:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 5637 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1631:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 5638 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 31 // Abbrev [31] 0x1636:0x27 DW_TAG_subprogram +; CHECK-NEXT:.b8 31 // Abbrev [31] 0x1637:0x27 DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -5128,10 +5131,10 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 149 // DW_AT_decl_line ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1657:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1658:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 31 // Abbrev [31] 0x165d:0x2d DW_TAG_subprogram +; CHECK-NEXT:.b8 31 // Abbrev [31] 0x165e:0x2d DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -5162,12 +5165,12 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 151 // DW_AT_decl_line ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x167f:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1680:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1684:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1685:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 31 // Abbrev [31] 0x168a:0x21 DW_TAG_subprogram +; CHECK-NEXT:.b8 31 // Abbrev [31] 0x168b:0x21 DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -5186,12 +5189,12 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 155 // DW_AT_decl_line ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x16a0:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x16a1:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x16a5:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 4585 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x16a6:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 4586 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 31 // Abbrev [31] 0x16ab:0x2d DW_TAG_subprogram +; CHECK-NEXT:.b8 31 // Abbrev [31] 0x16ac:0x2d DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -5222,12 +5225,12 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 157 // DW_AT_decl_line ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x16cd:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x16ce:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x16d2:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x16d3:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 31 // Abbrev [31] 0x16d8:0x2e DW_TAG_subprogram +; CHECK-NEXT:.b8 31 // Abbrev [31] 0x16d9:0x2e DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -5254,14 +5257,14 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 159 // DW_AT_decl_line ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x16f6:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x16f7:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x16fb:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x16fc:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1700:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 4630 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1701:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 4631 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 31 // Abbrev [31] 0x1706:0x1d DW_TAG_subprogram +; CHECK-NEXT:.b8 31 // Abbrev [31] 0x1707:0x1d DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -5281,10 +5284,10 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 161 // DW_AT_decl_line ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x171d:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x171e:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 31 // Abbrev [31] 0x1723:0x1f DW_TAG_subprogram +; CHECK-NEXT:.b8 31 // Abbrev [31] 0x1724:0x1f DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -5306,10 +5309,10 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 163 // DW_AT_decl_line ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x173c:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x173d:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 31 // Abbrev [31] 0x1742:0x29 DW_TAG_subprogram +; CHECK-NEXT:.b8 31 // Abbrev [31] 0x1743:0x29 DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -5336,12 +5339,12 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 165 // DW_AT_decl_line ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1760:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1761:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1765:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 5170 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1766:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 5171 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 31 // Abbrev [31] 0x176b:0x27 DW_TAG_subprogram +; CHECK-NEXT:.b8 31 // Abbrev [31] 0x176c:0x27 DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -5366,12 +5369,12 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 167 // DW_AT_decl_line ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1787:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1788:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x178c:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 4585 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x178d:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 4586 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 31 // Abbrev [31] 0x1792:0x23 DW_TAG_subprogram +; CHECK-NEXT:.b8 31 // Abbrev [31] 0x1793:0x23 DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -5395,12 +5398,12 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 0 ; CHECK-NEXT:.b8 4 // DW_AT_decl_file ; CHECK-NEXT:.b8 169 // DW_AT_decl_line -; CHECK-NEXT:.b32 4740 // DW_AT_type +; CHECK-NEXT:.b32 4741 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x17af:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x17b0:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 31 // Abbrev [31] 0x17b5:0x1b DW_TAG_subprogram +; CHECK-NEXT:.b8 31 // Abbrev [31] 0x17b6:0x1b DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -5418,10 +5421,10 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 171 // DW_AT_decl_line ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x17ca:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x17cb:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 31 // Abbrev [31] 0x17d0:0x1d DW_TAG_subprogram +; CHECK-NEXT:.b8 31 // Abbrev [31] 0x17d1:0x1d DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -5441,10 +5444,10 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 173 // DW_AT_decl_line ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x17e7:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x17e8:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 31 // Abbrev [31] 0x17ed:0x1d DW_TAG_subprogram +; CHECK-NEXT:.b8 31 // Abbrev [31] 0x17ee:0x1d DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -5464,10 +5467,10 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 175 // DW_AT_decl_line ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1804:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1805:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 31 // Abbrev [31] 0x180a:0x1b DW_TAG_subprogram +; CHECK-NEXT:.b8 31 // Abbrev [31] 0x180b:0x1b DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -5485,10 +5488,10 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 177 // DW_AT_decl_line ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x181f:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1820:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 31 // Abbrev [31] 0x1825:0x1d DW_TAG_subprogram +; CHECK-NEXT:.b8 31 // Abbrev [31] 0x1826:0x1d DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -5508,10 +5511,10 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 179 // DW_AT_decl_line ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x183c:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x183d:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 31 // Abbrev [31] 0x1842:0x21 DW_TAG_subprogram +; CHECK-NEXT:.b8 31 // Abbrev [31] 0x1843:0x21 DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -5535,10 +5538,10 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 181 // DW_AT_decl_line ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x185d:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x185e:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 31 // Abbrev [31] 0x1863:0x1f DW_TAG_subprogram +; CHECK-NEXT:.b8 31 // Abbrev [31] 0x1864:0x1f DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -5560,10 +5563,10 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 183 // DW_AT_decl_line ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x187c:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x187d:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 32 // Abbrev [32] 0x1882:0x14 DW_TAG_subprogram +; CHECK-NEXT:.b8 32 // Abbrev [32] 0x1883:0x14 DW_TAG_subprogram ; CHECK-NEXT:.b8 97 // DW_AT_name ; CHECK-NEXT:.b8 99 ; CHECK-NEXT:.b8 111 @@ -5571,13 +5574,13 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 0 ; CHECK-NEXT:.b8 5 // DW_AT_decl_file ; CHECK-NEXT:.b8 54 // DW_AT_decl_line -; CHECK-NEXT:.b32 5627 // DW_AT_type +; CHECK-NEXT:.b32 5628 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration ; CHECK-NEXT:.b8 1 // DW_AT_external -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1890:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 5627 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1891:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 5628 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 32 // Abbrev [32] 0x1896:0x14 DW_TAG_subprogram +; CHECK-NEXT:.b8 32 // Abbrev [32] 0x1897:0x14 DW_TAG_subprogram ; CHECK-NEXT:.b8 97 // DW_AT_name ; CHECK-NEXT:.b8 115 ; CHECK-NEXT:.b8 105 @@ -5585,13 +5588,13 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 0 ; CHECK-NEXT:.b8 5 // DW_AT_decl_file ; CHECK-NEXT:.b8 56 // DW_AT_decl_line -; CHECK-NEXT:.b32 5627 // DW_AT_type +; CHECK-NEXT:.b32 5628 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration ; CHECK-NEXT:.b8 1 // DW_AT_external -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x18a4:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 5627 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x18a5:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 5628 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 32 // Abbrev [32] 0x18aa:0x14 DW_TAG_subprogram +; CHECK-NEXT:.b8 32 // Abbrev [32] 0x18ab:0x14 DW_TAG_subprogram ; CHECK-NEXT:.b8 97 // DW_AT_name ; CHECK-NEXT:.b8 116 ; CHECK-NEXT:.b8 97 @@ -5599,13 +5602,13 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 0 ; CHECK-NEXT:.b8 5 // DW_AT_decl_file ; CHECK-NEXT:.b8 58 // DW_AT_decl_line -; CHECK-NEXT:.b32 5627 // DW_AT_type +; CHECK-NEXT:.b32 5628 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration ; CHECK-NEXT:.b8 1 // DW_AT_external -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x18b8:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 5627 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x18b9:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 5628 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 32 // Abbrev [32] 0x18be:0x1a DW_TAG_subprogram +; CHECK-NEXT:.b8 32 // Abbrev [32] 0x18bf:0x1a DW_TAG_subprogram ; CHECK-NEXT:.b8 97 // DW_AT_name ; CHECK-NEXT:.b8 116 ; CHECK-NEXT:.b8 97 @@ -5614,15 +5617,15 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 0 ; CHECK-NEXT:.b8 5 // DW_AT_decl_file ; CHECK-NEXT:.b8 60 // DW_AT_decl_line -; CHECK-NEXT:.b32 5627 // DW_AT_type +; CHECK-NEXT:.b32 5628 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration ; CHECK-NEXT:.b8 1 // DW_AT_external -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x18cd:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 5627 // DW_AT_type -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x18d2:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 5627 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x18ce:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 5628 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x18d3:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 5628 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 32 // Abbrev [32] 0x18d8:0x14 DW_TAG_subprogram +; CHECK-NEXT:.b8 32 // Abbrev [32] 0x18d9:0x14 DW_TAG_subprogram ; CHECK-NEXT:.b8 99 // DW_AT_name ; CHECK-NEXT:.b8 101 ; CHECK-NEXT:.b8 105 @@ -5630,26 +5633,26 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 0 ; CHECK-NEXT:.b8 5 // DW_AT_decl_file ; CHECK-NEXT:.b8 178 // DW_AT_decl_line -; CHECK-NEXT:.b32 5627 // DW_AT_type +; CHECK-NEXT:.b32 5628 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration ; CHECK-NEXT:.b8 1 // DW_AT_external -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x18e6:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 5627 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x18e7:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 5628 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 32 // Abbrev [32] 0x18ec:0x13 DW_TAG_subprogram +; CHECK-NEXT:.b8 32 // Abbrev [32] 0x18ed:0x13 DW_TAG_subprogram ; CHECK-NEXT:.b8 99 // DW_AT_name ; CHECK-NEXT:.b8 111 ; CHECK-NEXT:.b8 115 ; CHECK-NEXT:.b8 0 ; CHECK-NEXT:.b8 5 // DW_AT_decl_file ; CHECK-NEXT:.b8 63 // DW_AT_decl_line -; CHECK-NEXT:.b32 5627 // DW_AT_type +; CHECK-NEXT:.b32 5628 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration ; CHECK-NEXT:.b8 1 // DW_AT_external -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x18f9:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 5627 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x18fa:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 5628 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 32 // Abbrev [32] 0x18ff:0x14 DW_TAG_subprogram +; CHECK-NEXT:.b8 32 // Abbrev [32] 0x1900:0x14 DW_TAG_subprogram ; CHECK-NEXT:.b8 99 // DW_AT_name ; CHECK-NEXT:.b8 111 ; CHECK-NEXT:.b8 115 @@ -5657,26 +5660,26 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 0 ; CHECK-NEXT:.b8 5 // DW_AT_decl_file ; CHECK-NEXT:.b8 72 // DW_AT_decl_line -; CHECK-NEXT:.b32 5627 // DW_AT_type +; CHECK-NEXT:.b32 5628 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration ; CHECK-NEXT:.b8 1 // DW_AT_external -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x190d:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 5627 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x190e:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 5628 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 32 // Abbrev [32] 0x1913:0x13 DW_TAG_subprogram +; CHECK-NEXT:.b8 32 // Abbrev [32] 0x1914:0x13 DW_TAG_subprogram ; CHECK-NEXT:.b8 101 // DW_AT_name ; CHECK-NEXT:.b8 120 ; CHECK-NEXT:.b8 112 ; CHECK-NEXT:.b8 0 ; CHECK-NEXT:.b8 5 // DW_AT_decl_file ; CHECK-NEXT:.b8 100 // DW_AT_decl_line -; CHECK-NEXT:.b32 5627 // DW_AT_type +; CHECK-NEXT:.b32 5628 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration ; CHECK-NEXT:.b8 1 // DW_AT_external -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1920:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 5627 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1921:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 5628 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 32 // Abbrev [32] 0x1926:0x14 DW_TAG_subprogram +; CHECK-NEXT:.b8 32 // Abbrev [32] 0x1927:0x14 DW_TAG_subprogram ; CHECK-NEXT:.b8 102 // DW_AT_name ; CHECK-NEXT:.b8 97 ; CHECK-NEXT:.b8 98 @@ -5684,13 +5687,13 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 0 ; CHECK-NEXT:.b8 5 // DW_AT_decl_file ; CHECK-NEXT:.b8 181 // DW_AT_decl_line -; CHECK-NEXT:.b32 5627 // DW_AT_type +; CHECK-NEXT:.b32 5628 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration ; CHECK-NEXT:.b8 1 // DW_AT_external -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1934:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 5627 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1935:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 5628 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 32 // Abbrev [32] 0x193a:0x15 DW_TAG_subprogram +; CHECK-NEXT:.b8 32 // Abbrev [32] 0x193b:0x15 DW_TAG_subprogram ; CHECK-NEXT:.b8 102 // DW_AT_name ; CHECK-NEXT:.b8 108 ; CHECK-NEXT:.b8 111 @@ -5699,13 +5702,13 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 0 ; CHECK-NEXT:.b8 5 // DW_AT_decl_file ; CHECK-NEXT:.b8 184 // DW_AT_decl_line -; CHECK-NEXT:.b32 5627 // DW_AT_type +; CHECK-NEXT:.b32 5628 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration ; CHECK-NEXT:.b8 1 // DW_AT_external -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1949:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 5627 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x194a:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 5628 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 32 // Abbrev [32] 0x194f:0x19 DW_TAG_subprogram +; CHECK-NEXT:.b8 32 // Abbrev [32] 0x1950:0x19 DW_TAG_subprogram ; CHECK-NEXT:.b8 102 // DW_AT_name ; CHECK-NEXT:.b8 109 ; CHECK-NEXT:.b8 111 @@ -5713,15 +5716,15 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 0 ; CHECK-NEXT:.b8 5 // DW_AT_decl_file ; CHECK-NEXT:.b8 187 // DW_AT_decl_line -; CHECK-NEXT:.b32 5627 // DW_AT_type +; CHECK-NEXT:.b32 5628 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration ; CHECK-NEXT:.b8 1 // DW_AT_external -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x195d:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 5627 // DW_AT_type -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1962:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 5627 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x195e:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 5628 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1963:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 5628 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 32 // Abbrev [32] 0x1968:0x1a DW_TAG_subprogram +; CHECK-NEXT:.b8 32 // Abbrev [32] 0x1969:0x1a DW_TAG_subprogram ; CHECK-NEXT:.b8 102 // DW_AT_name ; CHECK-NEXT:.b8 114 ; CHECK-NEXT:.b8 101 @@ -5730,15 +5733,15 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 0 ; CHECK-NEXT:.b8 5 // DW_AT_decl_file ; CHECK-NEXT:.b8 103 // DW_AT_decl_line -; CHECK-NEXT:.b32 5627 // DW_AT_type +; CHECK-NEXT:.b32 5628 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration ; CHECK-NEXT:.b8 1 // DW_AT_external -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1977:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 5627 // DW_AT_type -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x197c:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 4630 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1978:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 5628 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x197d:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 4631 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 32 // Abbrev [32] 0x1982:0x1a DW_TAG_subprogram +; CHECK-NEXT:.b8 32 // Abbrev [32] 0x1983:0x1a DW_TAG_subprogram ; CHECK-NEXT:.b8 108 // DW_AT_name ; CHECK-NEXT:.b8 100 ; CHECK-NEXT:.b8 101 @@ -5747,28 +5750,28 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 0 ; CHECK-NEXT:.b8 5 // DW_AT_decl_file ; CHECK-NEXT:.b8 106 // DW_AT_decl_line -; CHECK-NEXT:.b32 5627 // DW_AT_type +; CHECK-NEXT:.b32 5628 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration ; CHECK-NEXT:.b8 1 // DW_AT_external -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1991:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 5627 // DW_AT_type -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1996:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 4585 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1992:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 5628 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1997:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 4586 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 32 // Abbrev [32] 0x199c:0x13 DW_TAG_subprogram +; CHECK-NEXT:.b8 32 // Abbrev [32] 0x199d:0x13 DW_TAG_subprogram ; CHECK-NEXT:.b8 108 // DW_AT_name ; CHECK-NEXT:.b8 111 ; CHECK-NEXT:.b8 103 ; CHECK-NEXT:.b8 0 ; CHECK-NEXT:.b8 5 // DW_AT_decl_file ; CHECK-NEXT:.b8 109 // DW_AT_decl_line -; CHECK-NEXT:.b32 5627 // DW_AT_type +; CHECK-NEXT:.b32 5628 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration ; CHECK-NEXT:.b8 1 // DW_AT_external -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x19a9:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 5627 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x19aa:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 5628 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 32 // Abbrev [32] 0x19af:0x15 DW_TAG_subprogram +; CHECK-NEXT:.b8 32 // Abbrev [32] 0x19b0:0x15 DW_TAG_subprogram ; CHECK-NEXT:.b8 108 // DW_AT_name ; CHECK-NEXT:.b8 111 ; CHECK-NEXT:.b8 103 @@ -5777,13 +5780,13 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 0 ; CHECK-NEXT:.b8 5 // DW_AT_decl_file ; CHECK-NEXT:.b8 112 // DW_AT_decl_line -; CHECK-NEXT:.b32 5627 // DW_AT_type +; CHECK-NEXT:.b32 5628 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration ; CHECK-NEXT:.b8 1 // DW_AT_external -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x19be:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 5627 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x19bf:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 5628 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 32 // Abbrev [32] 0x19c4:0x19 DW_TAG_subprogram +; CHECK-NEXT:.b8 32 // Abbrev [32] 0x19c5:0x19 DW_TAG_subprogram ; CHECK-NEXT:.b8 109 // DW_AT_name ; CHECK-NEXT:.b8 111 ; CHECK-NEXT:.b8 100 @@ -5791,45 +5794,45 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 0 ; CHECK-NEXT:.b8 5 // DW_AT_decl_file ; CHECK-NEXT:.b8 115 // DW_AT_decl_line -; CHECK-NEXT:.b32 5627 // DW_AT_type +; CHECK-NEXT:.b32 5628 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration ; CHECK-NEXT:.b8 1 // DW_AT_external -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x19d2:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 5627 // DW_AT_type -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x19d7:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 6621 // DW_AT_type -; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 12 // Abbrev [12] 0x19dd:0x5 DW_TAG_pointer_type -; CHECK-NEXT:.b32 5627 // DW_AT_type -; CHECK-NEXT:.b8 32 // Abbrev [32] 0x19e2:0x18 DW_TAG_subprogram +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x19d3:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 5628 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x19d8:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 6622 // DW_AT_type +; CHECK-NEXT:.b8 0 // End Of Children Mark +; CHECK-NEXT:.b8 12 // Abbrev [12] 0x19de:0x5 DW_TAG_pointer_type +; CHECK-NEXT:.b32 5628 // DW_AT_type +; CHECK-NEXT:.b8 32 // Abbrev [32] 0x19e3:0x18 DW_TAG_subprogram ; CHECK-NEXT:.b8 112 // DW_AT_name ; CHECK-NEXT:.b8 111 ; CHECK-NEXT:.b8 119 ; CHECK-NEXT:.b8 0 ; CHECK-NEXT:.b8 5 // DW_AT_decl_file ; CHECK-NEXT:.b8 153 // DW_AT_decl_line -; CHECK-NEXT:.b32 5627 // DW_AT_type +; CHECK-NEXT:.b32 5628 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration ; CHECK-NEXT:.b8 1 // DW_AT_external -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x19ef:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 5627 // DW_AT_type -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x19f4:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 5627 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x19f0:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 5628 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x19f5:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 5628 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 32 // Abbrev [32] 0x19fa:0x13 DW_TAG_subprogram +; CHECK-NEXT:.b8 32 // Abbrev [32] 0x19fb:0x13 DW_TAG_subprogram ; CHECK-NEXT:.b8 115 // DW_AT_name ; CHECK-NEXT:.b8 105 ; CHECK-NEXT:.b8 110 ; CHECK-NEXT:.b8 0 ; CHECK-NEXT:.b8 5 // DW_AT_decl_file ; CHECK-NEXT:.b8 65 // DW_AT_decl_line -; CHECK-NEXT:.b32 5627 // DW_AT_type +; CHECK-NEXT:.b32 5628 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration ; CHECK-NEXT:.b8 1 // DW_AT_external -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1a07:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 5627 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1a08:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 5628 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 32 // Abbrev [32] 0x1a0d:0x14 DW_TAG_subprogram +; CHECK-NEXT:.b8 32 // Abbrev [32] 0x1a0e:0x14 DW_TAG_subprogram ; CHECK-NEXT:.b8 115 // DW_AT_name ; CHECK-NEXT:.b8 105 ; CHECK-NEXT:.b8 110 @@ -5837,13 +5840,13 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 0 ; CHECK-NEXT:.b8 5 // DW_AT_decl_file ; CHECK-NEXT:.b8 74 // DW_AT_decl_line -; CHECK-NEXT:.b32 5627 // DW_AT_type +; CHECK-NEXT:.b32 5628 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration ; CHECK-NEXT:.b8 1 // DW_AT_external -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1a1b:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 5627 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1a1c:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 5628 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 32 // Abbrev [32] 0x1a21:0x14 DW_TAG_subprogram +; CHECK-NEXT:.b8 32 // Abbrev [32] 0x1a22:0x14 DW_TAG_subprogram ; CHECK-NEXT:.b8 115 // DW_AT_name ; CHECK-NEXT:.b8 113 ; CHECK-NEXT:.b8 114 @@ -5851,26 +5854,26 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 0 ; CHECK-NEXT:.b8 5 // DW_AT_decl_file ; CHECK-NEXT:.b8 156 // DW_AT_decl_line -; CHECK-NEXT:.b32 5627 // DW_AT_type +; CHECK-NEXT:.b32 5628 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration ; CHECK-NEXT:.b8 1 // DW_AT_external -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1a2f:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 5627 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1a30:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 5628 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 32 // Abbrev [32] 0x1a35:0x13 DW_TAG_subprogram +; CHECK-NEXT:.b8 32 // Abbrev [32] 0x1a36:0x13 DW_TAG_subprogram ; CHECK-NEXT:.b8 116 // DW_AT_name ; CHECK-NEXT:.b8 97 ; CHECK-NEXT:.b8 110 ; CHECK-NEXT:.b8 0 ; CHECK-NEXT:.b8 5 // DW_AT_decl_file ; CHECK-NEXT:.b8 67 // DW_AT_decl_line -; CHECK-NEXT:.b32 5627 // DW_AT_type +; CHECK-NEXT:.b32 5628 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration ; CHECK-NEXT:.b8 1 // DW_AT_external -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1a42:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 5627 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1a43:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 5628 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 32 // Abbrev [32] 0x1a48:0x14 DW_TAG_subprogram +; CHECK-NEXT:.b8 32 // Abbrev [32] 0x1a49:0x14 DW_TAG_subprogram ; CHECK-NEXT:.b8 116 // DW_AT_name ; CHECK-NEXT:.b8 97 ; CHECK-NEXT:.b8 110 @@ -5878,14 +5881,14 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 0 ; CHECK-NEXT:.b8 5 // DW_AT_decl_file ; CHECK-NEXT:.b8 76 // DW_AT_decl_line -; CHECK-NEXT:.b32 5627 // DW_AT_type +; CHECK-NEXT:.b32 5628 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration ; CHECK-NEXT:.b8 1 // DW_AT_external -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1a56:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 5627 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1a57:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 5628 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 33 // Abbrev [33] 0x1a5c:0xd DW_TAG_typedef -; CHECK-NEXT:.b32 6761 // DW_AT_type +; CHECK-NEXT:.b8 33 // Abbrev [33] 0x1a5d:0xd DW_TAG_typedef +; CHECK-NEXT:.b32 6762 // DW_AT_type ; CHECK-NEXT:.b8 100 // DW_AT_name ; CHECK-NEXT:.b8 105 ; CHECK-NEXT:.b8 118 @@ -5894,10 +5897,10 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 0 ; CHECK-NEXT:.b8 7 // DW_AT_decl_file ; CHECK-NEXT:.b8 101 // DW_AT_decl_line -; CHECK-NEXT:.b8 34 // Abbrev [34] 0x1a69:0x2 DW_TAG_structure_type +; CHECK-NEXT:.b8 34 // Abbrev [34] 0x1a6a:0x2 DW_TAG_structure_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 33 // Abbrev [33] 0x1a6b:0xe DW_TAG_typedef -; CHECK-NEXT:.b32 6777 // DW_AT_type +; CHECK-NEXT:.b8 33 // Abbrev [33] 0x1a6c:0xe DW_TAG_typedef +; CHECK-NEXT:.b32 6778 // DW_AT_type ; CHECK-NEXT:.b8 108 // DW_AT_name ; CHECK-NEXT:.b8 100 ; CHECK-NEXT:.b8 105 @@ -5907,35 +5910,35 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 0 ; CHECK-NEXT:.b8 7 // DW_AT_decl_file ; CHECK-NEXT:.b8 109 // DW_AT_decl_line -; CHECK-NEXT:.b8 35 // Abbrev [35] 0x1a79:0x22 DW_TAG_structure_type +; CHECK-NEXT:.b8 35 // Abbrev [35] 0x1a7a:0x22 DW_TAG_structure_type ; CHECK-NEXT:.b8 16 // DW_AT_byte_size ; CHECK-NEXT:.b8 7 // DW_AT_decl_file ; CHECK-NEXT:.b8 105 // DW_AT_decl_line -; CHECK-NEXT:.b8 11 // Abbrev [11] 0x1a7d:0xf DW_TAG_member +; CHECK-NEXT:.b8 11 // Abbrev [11] 0x1a7e:0xf DW_TAG_member ; CHECK-NEXT:.b8 113 // DW_AT_name ; CHECK-NEXT:.b8 117 ; CHECK-NEXT:.b8 111 ; CHECK-NEXT:.b8 116 ; CHECK-NEXT:.b8 0 -; CHECK-NEXT:.b32 5170 // DW_AT_type +; CHECK-NEXT:.b32 5171 // DW_AT_type ; CHECK-NEXT:.b8 7 // DW_AT_decl_file ; CHECK-NEXT:.b8 107 // DW_AT_decl_line ; CHECK-NEXT:.b8 2 // DW_AT_data_member_location ; CHECK-NEXT:.b8 35 ; CHECK-NEXT:.b8 0 -; CHECK-NEXT:.b8 11 // Abbrev [11] 0x1a8c:0xe DW_TAG_member +; CHECK-NEXT:.b8 11 // Abbrev [11] 0x1a8d:0xe DW_TAG_member ; CHECK-NEXT:.b8 114 // DW_AT_name ; CHECK-NEXT:.b8 101 ; CHECK-NEXT:.b8 109 ; CHECK-NEXT:.b8 0 -; CHECK-NEXT:.b32 5170 // DW_AT_type +; CHECK-NEXT:.b32 5171 // DW_AT_type ; CHECK-NEXT:.b8 7 // DW_AT_decl_file ; CHECK-NEXT:.b8 108 // DW_AT_decl_line ; CHECK-NEXT:.b8 2 // DW_AT_data_member_location ; CHECK-NEXT:.b8 35 ; CHECK-NEXT:.b8 8 ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 36 // Abbrev [36] 0x1a9b:0xd DW_TAG_subprogram +; CHECK-NEXT:.b8 36 // Abbrev [36] 0x1a9c:0xd DW_TAG_subprogram ; CHECK-NEXT:.b8 97 // DW_AT_name ; CHECK-NEXT:.b8 98 ; CHECK-NEXT:.b8 111 @@ -5948,7 +5951,7 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 1 // DW_AT_declaration ; CHECK-NEXT:.b8 1 // DW_AT_external ; CHECK-NEXT:.b8 1 // DW_AT_noreturn -; CHECK-NEXT:.b8 37 // Abbrev [37] 0x1aa8:0x14 DW_TAG_subprogram +; CHECK-NEXT:.b8 37 // Abbrev [37] 0x1aa9:0x14 DW_TAG_subprogram ; CHECK-NEXT:.b8 97 // DW_AT_name ; CHECK-NEXT:.b8 98 ; CHECK-NEXT:.b8 115 @@ -5956,13 +5959,13 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 7 // DW_AT_decl_file ; CHECK-NEXT:.b8 7 // DW_AT_decl_line ; CHECK-NEXT:.b8 3 -; CHECK-NEXT:.b32 4585 // DW_AT_type +; CHECK-NEXT:.b32 4586 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration ; CHECK-NEXT:.b8 1 // DW_AT_external -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1ab6:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 4585 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1ab7:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 4586 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 37 // Abbrev [37] 0x1abc:0x17 DW_TAG_subprogram +; CHECK-NEXT:.b8 37 // Abbrev [37] 0x1abd:0x17 DW_TAG_subprogram ; CHECK-NEXT:.b8 97 // DW_AT_name ; CHECK-NEXT:.b8 116 ; CHECK-NEXT:.b8 101 @@ -5973,16 +5976,16 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 7 // DW_AT_decl_file ; CHECK-NEXT:.b8 7 // DW_AT_decl_line ; CHECK-NEXT:.b8 2 -; CHECK-NEXT:.b32 4585 // DW_AT_type +; CHECK-NEXT:.b32 4586 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration ; CHECK-NEXT:.b8 1 // DW_AT_external -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1acd:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 6867 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1ace:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 6868 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 12 // Abbrev [12] 0x1ad3:0x5 DW_TAG_pointer_type -; CHECK-NEXT:.b32 6872 // DW_AT_type -; CHECK-NEXT:.b8 38 // Abbrev [38] 0x1ad8:0x1 DW_TAG_subroutine_type -; CHECK-NEXT:.b8 32 // Abbrev [32] 0x1ad9:0x14 DW_TAG_subprogram +; CHECK-NEXT:.b8 12 // Abbrev [12] 0x1ad4:0x5 DW_TAG_pointer_type +; CHECK-NEXT:.b32 6873 // DW_AT_type +; CHECK-NEXT:.b8 38 // Abbrev [38] 0x1ad9:0x1 DW_TAG_subroutine_type +; CHECK-NEXT:.b8 32 // Abbrev [32] 0x1ada:0x14 DW_TAG_subprogram ; CHECK-NEXT:.b8 97 // DW_AT_name ; CHECK-NEXT:.b8 116 ; CHECK-NEXT:.b8 111 @@ -5990,13 +5993,13 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 0 ; CHECK-NEXT:.b8 9 // DW_AT_decl_file ; CHECK-NEXT:.b8 26 // DW_AT_decl_line -; CHECK-NEXT:.b32 5627 // DW_AT_type +; CHECK-NEXT:.b32 5628 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration ; CHECK-NEXT:.b8 1 // DW_AT_external -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1ae7:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 5637 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1ae8:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 5638 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 37 // Abbrev [37] 0x1aed:0x15 DW_TAG_subprogram +; CHECK-NEXT:.b8 37 // Abbrev [37] 0x1aee:0x15 DW_TAG_subprogram ; CHECK-NEXT:.b8 97 // DW_AT_name ; CHECK-NEXT:.b8 116 ; CHECK-NEXT:.b8 111 @@ -6005,13 +6008,13 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 7 // DW_AT_decl_file ; CHECK-NEXT:.b8 22 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 -; CHECK-NEXT:.b32 4585 // DW_AT_type +; CHECK-NEXT:.b32 4586 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration ; CHECK-NEXT:.b8 1 // DW_AT_external -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1afc:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 5637 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1afd:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 5638 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 37 // Abbrev [37] 0x1b02:0x15 DW_TAG_subprogram +; CHECK-NEXT:.b8 37 // Abbrev [37] 0x1b03:0x15 DW_TAG_subprogram ; CHECK-NEXT:.b8 97 // DW_AT_name ; CHECK-NEXT:.b8 116 ; CHECK-NEXT:.b8 111 @@ -6020,13 +6023,13 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 7 // DW_AT_decl_file ; CHECK-NEXT:.b8 27 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 -; CHECK-NEXT:.b32 5170 // DW_AT_type +; CHECK-NEXT:.b32 5171 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration ; CHECK-NEXT:.b8 1 // DW_AT_external -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1b11:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 5637 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1b12:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 5638 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 32 // Abbrev [32] 0x1b17:0x2b DW_TAG_subprogram +; CHECK-NEXT:.b8 32 // Abbrev [32] 0x1b18:0x2b DW_TAG_subprogram ; CHECK-NEXT:.b8 98 // DW_AT_name ; CHECK-NEXT:.b8 115 ; CHECK-NEXT:.b8 101 @@ -6037,26 +6040,26 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 0 ; CHECK-NEXT:.b8 10 // DW_AT_decl_file ; CHECK-NEXT:.b8 20 // DW_AT_decl_line -; CHECK-NEXT:.b32 6978 // DW_AT_type +; CHECK-NEXT:.b32 6979 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration ; CHECK-NEXT:.b8 1 // DW_AT_external -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1b28:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 6979 // DW_AT_type -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1b2d:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 6979 // DW_AT_type -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1b32:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1b29:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 6980 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1b2e:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 6980 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1b33:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 6986 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1b38:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 6986 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1b3d:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 7021 // DW_AT_type +; CHECK-NEXT:.b8 0 // End Of Children Mark +; CHECK-NEXT:.b8 39 // Abbrev [39] 0x1b43:0x1 DW_TAG_pointer_type +; CHECK-NEXT:.b8 12 // Abbrev [12] 0x1b44:0x5 DW_TAG_pointer_type ; CHECK-NEXT:.b32 6985 // DW_AT_type -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1b37:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 6985 // DW_AT_type -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1b3c:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 7020 // DW_AT_type -; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 39 // Abbrev [39] 0x1b42:0x1 DW_TAG_pointer_type -; CHECK-NEXT:.b8 12 // Abbrev [12] 0x1b43:0x5 DW_TAG_pointer_type -; CHECK-NEXT:.b32 6984 // DW_AT_type -; CHECK-NEXT:.b8 40 // Abbrev [40] 0x1b48:0x1 DW_TAG_const_type -; CHECK-NEXT:.b8 33 // Abbrev [33] 0x1b49:0xe DW_TAG_typedef -; CHECK-NEXT:.b32 6999 // DW_AT_type +; CHECK-NEXT:.b8 40 // Abbrev [40] 0x1b49:0x1 DW_TAG_const_type +; CHECK-NEXT:.b8 33 // Abbrev [33] 0x1b4a:0xe DW_TAG_typedef +; CHECK-NEXT:.b32 7000 // DW_AT_type ; CHECK-NEXT:.b8 115 // DW_AT_name ; CHECK-NEXT:.b8 105 ; CHECK-NEXT:.b8 122 @@ -6066,7 +6069,7 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 0 ; CHECK-NEXT:.b8 11 // DW_AT_decl_file ; CHECK-NEXT:.b8 62 // DW_AT_decl_line -; CHECK-NEXT:.b8 10 // Abbrev [10] 0x1b57:0x15 DW_TAG_base_type +; CHECK-NEXT:.b8 10 // Abbrev [10] 0x1b58:0x15 DW_TAG_base_type ; CHECK-NEXT:.b8 108 // DW_AT_name ; CHECK-NEXT:.b8 111 ; CHECK-NEXT:.b8 110 @@ -6087,8 +6090,8 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 0 ; CHECK-NEXT:.b8 7 // DW_AT_encoding ; CHECK-NEXT:.b8 8 // DW_AT_byte_size -; CHECK-NEXT:.b8 20 // Abbrev [20] 0x1b6c:0x16 DW_TAG_typedef -; CHECK-NEXT:.b32 7042 // DW_AT_type +; CHECK-NEXT:.b8 20 // Abbrev [20] 0x1b6d:0x16 DW_TAG_typedef +; CHECK-NEXT:.b32 7043 // DW_AT_type ; CHECK-NEXT:.b8 95 // DW_AT_name ; CHECK-NEXT:.b8 95 ; CHECK-NEXT:.b8 99 @@ -6106,16 +6109,16 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 7 // DW_AT_decl_file ; CHECK-NEXT:.b8 230 // DW_AT_decl_line ; CHECK-NEXT:.b8 2 -; CHECK-NEXT:.b8 12 // Abbrev [12] 0x1b82:0x5 DW_TAG_pointer_type -; CHECK-NEXT:.b32 7047 // DW_AT_type -; CHECK-NEXT:.b8 41 // Abbrev [41] 0x1b87:0x10 DW_TAG_subroutine_type -; CHECK-NEXT:.b32 4585 // DW_AT_type -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1b8c:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 6979 // DW_AT_type -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1b91:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 6979 // DW_AT_type -; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 37 // Abbrev [37] 0x1b97:0x1c DW_TAG_subprogram +; CHECK-NEXT:.b8 12 // Abbrev [12] 0x1b83:0x5 DW_TAG_pointer_type +; CHECK-NEXT:.b32 7048 // DW_AT_type +; CHECK-NEXT:.b8 41 // Abbrev [41] 0x1b88:0x10 DW_TAG_subroutine_type +; CHECK-NEXT:.b32 4586 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1b8d:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 6980 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1b92:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 6980 // DW_AT_type +; CHECK-NEXT:.b8 0 // End Of Children Mark +; CHECK-NEXT:.b8 37 // Abbrev [37] 0x1b98:0x1c DW_TAG_subprogram ; CHECK-NEXT:.b8 99 // DW_AT_name ; CHECK-NEXT:.b8 97 ; CHECK-NEXT:.b8 108 @@ -6126,15 +6129,15 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 7 // DW_AT_decl_file ; CHECK-NEXT:.b8 212 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 -; CHECK-NEXT:.b32 6978 // DW_AT_type +; CHECK-NEXT:.b32 6979 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration ; CHECK-NEXT:.b8 1 // DW_AT_external -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1ba8:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 6985 // DW_AT_type -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1bad:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 6985 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1ba9:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 6986 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1bae:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 6986 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 37 // Abbrev [37] 0x1bb3:0x19 DW_TAG_subprogram +; CHECK-NEXT:.b8 37 // Abbrev [37] 0x1bb4:0x19 DW_TAG_subprogram ; CHECK-NEXT:.b8 100 // DW_AT_name ; CHECK-NEXT:.b8 105 ; CHECK-NEXT:.b8 118 @@ -6142,15 +6145,15 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 7 // DW_AT_decl_file ; CHECK-NEXT:.b8 21 // DW_AT_decl_line ; CHECK-NEXT:.b8 3 -; CHECK-NEXT:.b32 6748 // DW_AT_type +; CHECK-NEXT:.b32 6749 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration ; CHECK-NEXT:.b8 1 // DW_AT_external -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1bc1:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 4585 // DW_AT_type -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1bc6:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 4585 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1bc2:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 4586 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1bc7:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 4586 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 42 // Abbrev [42] 0x1bcc:0x12 DW_TAG_subprogram +; CHECK-NEXT:.b8 42 // Abbrev [42] 0x1bcd:0x12 DW_TAG_subprogram ; CHECK-NEXT:.b8 101 // DW_AT_name ; CHECK-NEXT:.b8 120 ; CHECK-NEXT:.b8 105 @@ -6162,10 +6165,10 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 1 // DW_AT_declaration ; CHECK-NEXT:.b8 1 // DW_AT_external ; CHECK-NEXT:.b8 1 // DW_AT_noreturn -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1bd8:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 4585 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1bd9:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 4586 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 18 // Abbrev [18] 0x1bde:0x11 DW_TAG_subprogram +; CHECK-NEXT:.b8 18 // Abbrev [18] 0x1bdf:0x11 DW_TAG_subprogram ; CHECK-NEXT:.b8 102 // DW_AT_name ; CHECK-NEXT:.b8 114 ; CHECK-NEXT:.b8 101 @@ -6176,10 +6179,10 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 1 ; CHECK-NEXT:.b8 1 // DW_AT_declaration ; CHECK-NEXT:.b8 1 // DW_AT_external -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1be9:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 6978 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1bea:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 6979 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 37 // Abbrev [37] 0x1bef:0x17 DW_TAG_subprogram +; CHECK-NEXT:.b8 37 // Abbrev [37] 0x1bf0:0x17 DW_TAG_subprogram ; CHECK-NEXT:.b8 103 // DW_AT_name ; CHECK-NEXT:.b8 101 ; CHECK-NEXT:.b8 116 @@ -6190,15 +6193,15 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 7 // DW_AT_decl_file ; CHECK-NEXT:.b8 52 // DW_AT_decl_line ; CHECK-NEXT:.b8 2 -; CHECK-NEXT:.b32 7174 // DW_AT_type +; CHECK-NEXT:.b32 7175 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration ; CHECK-NEXT:.b8 1 // DW_AT_external -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1c00:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 5637 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1c01:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 5638 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 12 // Abbrev [12] 0x1c06:0x5 DW_TAG_pointer_type -; CHECK-NEXT:.b32 5647 // DW_AT_type -; CHECK-NEXT:.b8 37 // Abbrev [37] 0x1c0b:0x15 DW_TAG_subprogram +; CHECK-NEXT:.b8 12 // Abbrev [12] 0x1c07:0x5 DW_TAG_pointer_type +; CHECK-NEXT:.b32 5648 // DW_AT_type +; CHECK-NEXT:.b8 37 // Abbrev [37] 0x1c0c:0x15 DW_TAG_subprogram ; CHECK-NEXT:.b8 108 // DW_AT_name ; CHECK-NEXT:.b8 97 ; CHECK-NEXT:.b8 98 @@ -6207,13 +6210,13 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 7 // DW_AT_decl_file ; CHECK-NEXT:.b8 8 // DW_AT_decl_line ; CHECK-NEXT:.b8 3 -; CHECK-NEXT:.b32 5170 // DW_AT_type +; CHECK-NEXT:.b32 5171 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration ; CHECK-NEXT:.b8 1 // DW_AT_external -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1c1a:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 5170 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1c1b:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 5171 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 37 // Abbrev [37] 0x1c20:0x1a DW_TAG_subprogram +; CHECK-NEXT:.b8 37 // Abbrev [37] 0x1c21:0x1a DW_TAG_subprogram ; CHECK-NEXT:.b8 108 // DW_AT_name ; CHECK-NEXT:.b8 100 ; CHECK-NEXT:.b8 105 @@ -6222,15 +6225,15 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 7 // DW_AT_decl_file ; CHECK-NEXT:.b8 23 // DW_AT_decl_line ; CHECK-NEXT:.b8 3 -; CHECK-NEXT:.b32 6763 // DW_AT_type +; CHECK-NEXT:.b32 6764 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration ; CHECK-NEXT:.b8 1 // DW_AT_external -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1c2f:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 5170 // DW_AT_type -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1c34:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 5170 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1c30:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 5171 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1c35:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 5171 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 37 // Abbrev [37] 0x1c3a:0x17 DW_TAG_subprogram +; CHECK-NEXT:.b8 37 // Abbrev [37] 0x1c3b:0x17 DW_TAG_subprogram ; CHECK-NEXT:.b8 109 // DW_AT_name ; CHECK-NEXT:.b8 97 ; CHECK-NEXT:.b8 108 @@ -6241,13 +6244,13 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 7 // DW_AT_decl_file ; CHECK-NEXT:.b8 210 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 -; CHECK-NEXT:.b32 6978 // DW_AT_type +; CHECK-NEXT:.b32 6979 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration ; CHECK-NEXT:.b8 1 // DW_AT_external -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1c4b:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 6985 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1c4c:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 6986 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 37 // Abbrev [37] 0x1c51:0x1b DW_TAG_subprogram +; CHECK-NEXT:.b8 37 // Abbrev [37] 0x1c52:0x1b DW_TAG_subprogram ; CHECK-NEXT:.b8 109 // DW_AT_name ; CHECK-NEXT:.b8 98 ; CHECK-NEXT:.b8 108 @@ -6257,15 +6260,15 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 7 // DW_AT_decl_file ; CHECK-NEXT:.b8 95 // DW_AT_decl_line ; CHECK-NEXT:.b8 3 -; CHECK-NEXT:.b32 4585 // DW_AT_type +; CHECK-NEXT:.b32 4586 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration ; CHECK-NEXT:.b8 1 // DW_AT_external -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1c61:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 5637 // DW_AT_type -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1c66:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 6985 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1c62:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 5638 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1c67:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 6986 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 37 // Abbrev [37] 0x1c6c:0x23 DW_TAG_subprogram +; CHECK-NEXT:.b8 37 // Abbrev [37] 0x1c6d:0x23 DW_TAG_subprogram ; CHECK-NEXT:.b8 109 // DW_AT_name ; CHECK-NEXT:.b8 98 ; CHECK-NEXT:.b8 115 @@ -6278,19 +6281,19 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 7 // DW_AT_decl_file ; CHECK-NEXT:.b8 106 // DW_AT_decl_line ; CHECK-NEXT:.b8 3 -; CHECK-NEXT:.b32 6985 // DW_AT_type +; CHECK-NEXT:.b32 6986 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration ; CHECK-NEXT:.b8 1 // DW_AT_external -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1c7f:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 7311 // DW_AT_type -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1c84:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 5637 // DW_AT_type -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1c89:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 6985 // DW_AT_type -; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 12 // Abbrev [12] 0x1c8f:0x5 DW_TAG_pointer_type -; CHECK-NEXT:.b32 7316 // DW_AT_type -; CHECK-NEXT:.b8 10 // Abbrev [10] 0x1c94:0xb DW_TAG_base_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1c80:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 7312 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1c85:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 5638 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1c8a:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 6986 // DW_AT_type +; CHECK-NEXT:.b8 0 // End Of Children Mark +; CHECK-NEXT:.b8 12 // Abbrev [12] 0x1c90:0x5 DW_TAG_pointer_type +; CHECK-NEXT:.b32 7317 // DW_AT_type +; CHECK-NEXT:.b8 10 // Abbrev [10] 0x1c95:0xb DW_TAG_base_type ; CHECK-NEXT:.b8 119 // DW_AT_name ; CHECK-NEXT:.b8 99 ; CHECK-NEXT:.b8 104 @@ -6301,7 +6304,7 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 0 ; CHECK-NEXT:.b8 5 // DW_AT_encoding ; CHECK-NEXT:.b8 4 // DW_AT_byte_size -; CHECK-NEXT:.b8 37 // Abbrev [37] 0x1c9f:0x21 DW_TAG_subprogram +; CHECK-NEXT:.b8 37 // Abbrev [37] 0x1ca0:0x21 DW_TAG_subprogram ; CHECK-NEXT:.b8 109 // DW_AT_name ; CHECK-NEXT:.b8 98 ; CHECK-NEXT:.b8 116 @@ -6312,17 +6315,17 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 7 // DW_AT_decl_file ; CHECK-NEXT:.b8 98 // DW_AT_decl_line ; CHECK-NEXT:.b8 3 -; CHECK-NEXT:.b32 4585 // DW_AT_type +; CHECK-NEXT:.b32 4586 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration ; CHECK-NEXT:.b8 1 // DW_AT_external -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1cb0:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 7311 // DW_AT_type -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1cb5:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 5637 // DW_AT_type -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1cba:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 6985 // DW_AT_type -; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 18 // Abbrev [18] 0x1cc0:0x21 DW_TAG_subprogram +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1cb1:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 7312 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1cb6:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 5638 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1cbb:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 6986 // DW_AT_type +; CHECK-NEXT:.b8 0 // End Of Children Mark +; CHECK-NEXT:.b8 18 // Abbrev [18] 0x1cc1:0x21 DW_TAG_subprogram ; CHECK-NEXT:.b8 113 // DW_AT_name ; CHECK-NEXT:.b8 115 ; CHECK-NEXT:.b8 111 @@ -6334,16 +6337,16 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 2 ; CHECK-NEXT:.b8 1 // DW_AT_declaration ; CHECK-NEXT:.b8 1 // DW_AT_external -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1ccc:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 6978 // DW_AT_type -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1cd1:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 6985 // DW_AT_type -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1cd6:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 6985 // DW_AT_type -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1cdb:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 7020 // DW_AT_type -; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 43 // Abbrev [43] 0x1ce1:0xf DW_TAG_subprogram +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1ccd:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 6979 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1cd2:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 6986 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1cd7:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 6986 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1cdc:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 7021 // DW_AT_type +; CHECK-NEXT:.b8 0 // End Of Children Mark +; CHECK-NEXT:.b8 43 // Abbrev [43] 0x1ce2:0xf DW_TAG_subprogram ; CHECK-NEXT:.b8 114 // DW_AT_name ; CHECK-NEXT:.b8 97 ; CHECK-NEXT:.b8 110 @@ -6352,10 +6355,10 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 7 // DW_AT_decl_file ; CHECK-NEXT:.b8 118 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 -; CHECK-NEXT:.b32 4585 // DW_AT_type +; CHECK-NEXT:.b32 4586 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration ; CHECK-NEXT:.b8 1 // DW_AT_external -; CHECK-NEXT:.b8 37 // Abbrev [37] 0x1cf0:0x1d DW_TAG_subprogram +; CHECK-NEXT:.b8 37 // Abbrev [37] 0x1cf1:0x1d DW_TAG_subprogram ; CHECK-NEXT:.b8 114 // DW_AT_name ; CHECK-NEXT:.b8 101 ; CHECK-NEXT:.b8 97 @@ -6367,15 +6370,15 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 7 // DW_AT_decl_file ; CHECK-NEXT:.b8 224 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 -; CHECK-NEXT:.b32 6978 // DW_AT_type +; CHECK-NEXT:.b32 6979 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration ; CHECK-NEXT:.b8 1 // DW_AT_external -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1d02:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 6978 // DW_AT_type -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1d07:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 6985 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1d03:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 6979 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1d08:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 6986 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 18 // Abbrev [18] 0x1d0d:0x12 DW_TAG_subprogram +; CHECK-NEXT:.b8 18 // Abbrev [18] 0x1d0e:0x12 DW_TAG_subprogram ; CHECK-NEXT:.b8 115 // DW_AT_name ; CHECK-NEXT:.b8 114 ; CHECK-NEXT:.b8 97 @@ -6387,10 +6390,10 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 1 ; CHECK-NEXT:.b8 1 // DW_AT_declaration ; CHECK-NEXT:.b8 1 // DW_AT_external -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1d19:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1d1a:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 619 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 32 // Abbrev [32] 0x1d1f:0x1b DW_TAG_subprogram +; CHECK-NEXT:.b8 32 // Abbrev [32] 0x1d20:0x1b DW_TAG_subprogram ; CHECK-NEXT:.b8 115 // DW_AT_name ; CHECK-NEXT:.b8 116 ; CHECK-NEXT:.b8 114 @@ -6400,17 +6403,17 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 0 ; CHECK-NEXT:.b8 7 // DW_AT_decl_file ; CHECK-NEXT:.b8 164 // DW_AT_decl_line -; CHECK-NEXT:.b32 5627 // DW_AT_type +; CHECK-NEXT:.b32 5628 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration ; CHECK-NEXT:.b8 1 // DW_AT_external -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1d2f:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 5637 // DW_AT_type -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1d34:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 7482 // DW_AT_type -; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 12 // Abbrev [12] 0x1d3a:0x5 DW_TAG_pointer_type -; CHECK-NEXT:.b32 7174 // DW_AT_type -; CHECK-NEXT:.b8 32 // Abbrev [32] 0x1d3f:0x20 DW_TAG_subprogram +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1d30:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 5638 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1d35:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 7483 // DW_AT_type +; CHECK-NEXT:.b8 0 // End Of Children Mark +; CHECK-NEXT:.b8 12 // Abbrev [12] 0x1d3b:0x5 DW_TAG_pointer_type +; CHECK-NEXT:.b32 7175 // DW_AT_type +; CHECK-NEXT:.b8 32 // Abbrev [32] 0x1d40:0x20 DW_TAG_subprogram ; CHECK-NEXT:.b8 115 // DW_AT_name ; CHECK-NEXT:.b8 116 ; CHECK-NEXT:.b8 114 @@ -6420,17 +6423,17 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 0 ; CHECK-NEXT:.b8 7 // DW_AT_decl_file ; CHECK-NEXT:.b8 183 // DW_AT_decl_line -; CHECK-NEXT:.b32 5170 // DW_AT_type +; CHECK-NEXT:.b32 5171 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration ; CHECK-NEXT:.b8 1 // DW_AT_external -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1d4f:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 5637 // DW_AT_type -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1d54:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 7482 // DW_AT_type -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1d59:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 4585 // DW_AT_type -; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 32 // Abbrev [32] 0x1d5f:0x21 DW_TAG_subprogram +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1d50:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 5638 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1d55:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 7483 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1d5a:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 4586 // DW_AT_type +; CHECK-NEXT:.b8 0 // End Of Children Mark +; CHECK-NEXT:.b8 32 // Abbrev [32] 0x1d60:0x21 DW_TAG_subprogram ; CHECK-NEXT:.b8 115 // DW_AT_name ; CHECK-NEXT:.b8 116 ; CHECK-NEXT:.b8 114 @@ -6441,17 +6444,17 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 0 ; CHECK-NEXT:.b8 7 // DW_AT_decl_file ; CHECK-NEXT:.b8 187 // DW_AT_decl_line -; CHECK-NEXT:.b32 6999 // DW_AT_type +; CHECK-NEXT:.b32 7000 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration ; CHECK-NEXT:.b8 1 // DW_AT_external -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1d70:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 5637 // DW_AT_type -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1d75:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 7482 // DW_AT_type -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1d7a:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 4585 // DW_AT_type -; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 37 // Abbrev [37] 0x1d80:0x17 DW_TAG_subprogram +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1d71:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 5638 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1d76:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 7483 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1d7b:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 4586 // DW_AT_type +; CHECK-NEXT:.b8 0 // End Of Children Mark +; CHECK-NEXT:.b8 37 // Abbrev [37] 0x1d81:0x17 DW_TAG_subprogram ; CHECK-NEXT:.b8 115 // DW_AT_name ; CHECK-NEXT:.b8 121 ; CHECK-NEXT:.b8 115 @@ -6462,13 +6465,13 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 7 // DW_AT_decl_file ; CHECK-NEXT:.b8 205 // DW_AT_decl_line ; CHECK-NEXT:.b8 2 -; CHECK-NEXT:.b32 4585 // DW_AT_type +; CHECK-NEXT:.b32 4586 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration ; CHECK-NEXT:.b8 1 // DW_AT_external -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1d91:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 5637 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1d92:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 5638 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 37 // Abbrev [37] 0x1d97:0x23 DW_TAG_subprogram +; CHECK-NEXT:.b8 37 // Abbrev [37] 0x1d98:0x23 DW_TAG_subprogram ; CHECK-NEXT:.b8 119 // DW_AT_name ; CHECK-NEXT:.b8 99 ; CHECK-NEXT:.b8 115 @@ -6481,21 +6484,21 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 7 // DW_AT_decl_file ; CHECK-NEXT:.b8 109 // DW_AT_decl_line ; CHECK-NEXT:.b8 3 -; CHECK-NEXT:.b32 6985 // DW_AT_type +; CHECK-NEXT:.b32 6986 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration ; CHECK-NEXT:.b8 1 // DW_AT_external -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1daa:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 7174 // DW_AT_type -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1daf:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 7610 // DW_AT_type -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1db4:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 6985 // DW_AT_type -; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 12 // Abbrev [12] 0x1dba:0x5 DW_TAG_pointer_type -; CHECK-NEXT:.b32 7615 // DW_AT_type -; CHECK-NEXT:.b8 13 // Abbrev [13] 0x1dbf:0x5 DW_TAG_const_type -; CHECK-NEXT:.b32 7316 // DW_AT_type -; CHECK-NEXT:.b8 37 // Abbrev [37] 0x1dc4:0x1c DW_TAG_subprogram +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1dab:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 7175 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1db0:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 7611 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1db5:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 6986 // DW_AT_type +; CHECK-NEXT:.b8 0 // End Of Children Mark +; CHECK-NEXT:.b8 12 // Abbrev [12] 0x1dbb:0x5 DW_TAG_pointer_type +; CHECK-NEXT:.b32 7616 // DW_AT_type +; CHECK-NEXT:.b8 13 // Abbrev [13] 0x1dc0:0x5 DW_TAG_const_type +; CHECK-NEXT:.b32 7317 // DW_AT_type +; CHECK-NEXT:.b8 37 // Abbrev [37] 0x1dc5:0x1c DW_TAG_subprogram ; CHECK-NEXT:.b8 119 // DW_AT_name ; CHECK-NEXT:.b8 99 ; CHECK-NEXT:.b8 116 @@ -6506,15 +6509,15 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 7 // DW_AT_decl_file ; CHECK-NEXT:.b8 102 // DW_AT_decl_line ; CHECK-NEXT:.b8 3 -; CHECK-NEXT:.b32 4585 // DW_AT_type +; CHECK-NEXT:.b32 4586 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration ; CHECK-NEXT:.b8 1 // DW_AT_external -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1dd5:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 7174 // DW_AT_type -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1dda:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 7316 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1dd6:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 7175 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1ddb:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 7317 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 28 // Abbrev [28] 0x1de0:0x78 DW_TAG_namespace +; CHECK-NEXT:.b8 28 // Abbrev [28] 0x1de1:0x78 DW_TAG_namespace ; CHECK-NEXT:.b8 95 // DW_AT_name ; CHECK-NEXT:.b8 95 ; CHECK-NEXT:.b8 103 @@ -6525,43 +6528,43 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 120 ; CHECK-NEXT:.b8 120 ; CHECK-NEXT:.b8 0 -; CHECK-NEXT:.b8 29 // Abbrev [29] 0x1deb:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b8 29 // Abbrev [29] 0x1dec:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 8 // DW_AT_decl_file ; CHECK-NEXT:.b8 201 // DW_AT_decl_line -; CHECK-NEXT:.b32 7768 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0x1df2:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 7769 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0x1df3:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 8 // DW_AT_decl_file ; CHECK-NEXT:.b8 207 // DW_AT_decl_line -; CHECK-NEXT:.b32 7817 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0x1df9:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 7818 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0x1dfa:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 8 // DW_AT_decl_file ; CHECK-NEXT:.b8 211 // DW_AT_decl_line -; CHECK-NEXT:.b32 7836 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0x1e00:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 7837 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0x1e01:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 8 // DW_AT_decl_file ; CHECK-NEXT:.b8 217 // DW_AT_decl_line -; CHECK-NEXT:.b32 7858 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0x1e07:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 7859 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0x1e08:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 8 // DW_AT_decl_file ; CHECK-NEXT:.b8 228 // DW_AT_decl_line -; CHECK-NEXT:.b32 7885 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0x1e0e:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 7886 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0x1e0f:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 8 // DW_AT_decl_file ; CHECK-NEXT:.b8 229 // DW_AT_decl_line -; CHECK-NEXT:.b32 7907 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0x1e15:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 7908 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0x1e16:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 8 // DW_AT_decl_file ; CHECK-NEXT:.b8 230 // DW_AT_decl_line -; CHECK-NEXT:.b32 7940 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0x1e1c:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 7941 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0x1e1d:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 8 // DW_AT_decl_file ; CHECK-NEXT:.b8 232 // DW_AT_decl_line -; CHECK-NEXT:.b32 8000 // DW_AT_import -; CHECK-NEXT:.b8 29 // Abbrev [29] 0x1e23:0x7 DW_TAG_imported_declaration +; CHECK-NEXT:.b32 8001 // DW_AT_import +; CHECK-NEXT:.b8 29 // Abbrev [29] 0x1e24:0x7 DW_TAG_imported_declaration ; CHECK-NEXT:.b8 8 // DW_AT_decl_file ; CHECK-NEXT:.b8 233 // DW_AT_decl_line -; CHECK-NEXT:.b32 8027 // DW_AT_import -; CHECK-NEXT:.b8 4 // Abbrev [4] 0x1e2a:0x2d DW_TAG_subprogram +; CHECK-NEXT:.b32 8028 // DW_AT_import +; CHECK-NEXT:.b8 4 // Abbrev [4] 0x1e2b:0x2d DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 78 @@ -6589,17 +6592,17 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 0 ; CHECK-NEXT:.b8 8 // DW_AT_decl_file ; CHECK-NEXT:.b8 214 // DW_AT_decl_line -; CHECK-NEXT:.b32 7768 // DW_AT_type +; CHECK-NEXT:.b32 7769 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration ; CHECK-NEXT:.b8 1 // DW_AT_external -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1e4c:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 3770 // DW_AT_type -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1e51:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 3770 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1e4d:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 3771 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1e52:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 3771 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 33 // Abbrev [33] 0x1e58:0xf DW_TAG_typedef -; CHECK-NEXT:.b32 7783 // DW_AT_type +; CHECK-NEXT:.b8 33 // Abbrev [33] 0x1e59:0xf DW_TAG_typedef +; CHECK-NEXT:.b32 7784 // DW_AT_type ; CHECK-NEXT:.b8 108 // DW_AT_name ; CHECK-NEXT:.b8 108 ; CHECK-NEXT:.b8 100 @@ -6610,35 +6613,35 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 0 ; CHECK-NEXT:.b8 7 // DW_AT_decl_file ; CHECK-NEXT:.b8 121 // DW_AT_decl_line -; CHECK-NEXT:.b8 35 // Abbrev [35] 0x1e67:0x22 DW_TAG_structure_type +; CHECK-NEXT:.b8 35 // Abbrev [35] 0x1e68:0x22 DW_TAG_structure_type ; CHECK-NEXT:.b8 16 // DW_AT_byte_size ; CHECK-NEXT:.b8 7 // DW_AT_decl_file ; CHECK-NEXT:.b8 117 // DW_AT_decl_line -; CHECK-NEXT:.b8 11 // Abbrev [11] 0x1e6b:0xf DW_TAG_member +; CHECK-NEXT:.b8 11 // Abbrev [11] 0x1e6c:0xf DW_TAG_member ; CHECK-NEXT:.b8 113 // DW_AT_name ; CHECK-NEXT:.b8 117 ; CHECK-NEXT:.b8 111 ; CHECK-NEXT:.b8 116 ; CHECK-NEXT:.b8 0 -; CHECK-NEXT:.b32 3770 // DW_AT_type +; CHECK-NEXT:.b32 3771 // DW_AT_type ; CHECK-NEXT:.b8 7 // DW_AT_decl_file ; CHECK-NEXT:.b8 119 // DW_AT_decl_line ; CHECK-NEXT:.b8 2 // DW_AT_data_member_location ; CHECK-NEXT:.b8 35 ; CHECK-NEXT:.b8 0 -; CHECK-NEXT:.b8 11 // Abbrev [11] 0x1e7a:0xe DW_TAG_member +; CHECK-NEXT:.b8 11 // Abbrev [11] 0x1e7b:0xe DW_TAG_member ; CHECK-NEXT:.b8 114 // DW_AT_name ; CHECK-NEXT:.b8 101 ; CHECK-NEXT:.b8 109 ; CHECK-NEXT:.b8 0 -; CHECK-NEXT:.b32 3770 // DW_AT_type +; CHECK-NEXT:.b32 3771 // DW_AT_type ; CHECK-NEXT:.b8 7 // DW_AT_decl_file ; CHECK-NEXT:.b8 120 // DW_AT_decl_line ; CHECK-NEXT:.b8 2 // DW_AT_data_member_location ; CHECK-NEXT:.b8 35 ; CHECK-NEXT:.b8 8 ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 42 // Abbrev [42] 0x1e89:0x13 DW_TAG_subprogram +; CHECK-NEXT:.b8 42 // Abbrev [42] 0x1e8a:0x13 DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_name ; CHECK-NEXT:.b8 69 ; CHECK-NEXT:.b8 120 @@ -6651,10 +6654,10 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 1 // DW_AT_declaration ; CHECK-NEXT:.b8 1 // DW_AT_external ; CHECK-NEXT:.b8 1 // DW_AT_noreturn -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1e96:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 4585 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1e97:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 4586 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 37 // Abbrev [37] 0x1e9c:0x16 DW_TAG_subprogram +; CHECK-NEXT:.b8 37 // Abbrev [37] 0x1e9d:0x16 DW_TAG_subprogram ; CHECK-NEXT:.b8 108 // DW_AT_name ; CHECK-NEXT:.b8 108 ; CHECK-NEXT:.b8 97 @@ -6664,13 +6667,13 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 7 // DW_AT_decl_file ; CHECK-NEXT:.b8 12 // DW_AT_decl_line ; CHECK-NEXT:.b8 3 -; CHECK-NEXT:.b32 3770 // DW_AT_type +; CHECK-NEXT:.b32 3771 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration ; CHECK-NEXT:.b8 1 // DW_AT_external -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1eac:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 3770 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1ead:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 3771 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 37 // Abbrev [37] 0x1eb2:0x1b DW_TAG_subprogram +; CHECK-NEXT:.b8 37 // Abbrev [37] 0x1eb3:0x1b DW_TAG_subprogram ; CHECK-NEXT:.b8 108 // DW_AT_name ; CHECK-NEXT:.b8 108 ; CHECK-NEXT:.b8 100 @@ -6680,15 +6683,15 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 7 // DW_AT_decl_file ; CHECK-NEXT:.b8 29 // DW_AT_decl_line ; CHECK-NEXT:.b8 3 -; CHECK-NEXT:.b32 7768 // DW_AT_type +; CHECK-NEXT:.b32 7769 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration ; CHECK-NEXT:.b8 1 // DW_AT_external -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1ec2:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 3770 // DW_AT_type -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1ec7:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 3770 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1ec3:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 3771 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1ec8:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 3771 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 37 // Abbrev [37] 0x1ecd:0x16 DW_TAG_subprogram +; CHECK-NEXT:.b8 37 // Abbrev [37] 0x1ece:0x16 DW_TAG_subprogram ; CHECK-NEXT:.b8 97 // DW_AT_name ; CHECK-NEXT:.b8 116 ; CHECK-NEXT:.b8 111 @@ -6698,13 +6701,13 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 7 // DW_AT_decl_file ; CHECK-NEXT:.b8 36 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 -; CHECK-NEXT:.b32 3770 // DW_AT_type +; CHECK-NEXT:.b32 3771 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration ; CHECK-NEXT:.b8 1 // DW_AT_external -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1edd:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 5637 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1ede:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 5638 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 32 // Abbrev [32] 0x1ee3:0x21 DW_TAG_subprogram +; CHECK-NEXT:.b8 32 // Abbrev [32] 0x1ee4:0x21 DW_TAG_subprogram ; CHECK-NEXT:.b8 115 // DW_AT_name ; CHECK-NEXT:.b8 116 ; CHECK-NEXT:.b8 114 @@ -6715,17 +6718,17 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 0 ; CHECK-NEXT:.b8 7 // DW_AT_decl_file ; CHECK-NEXT:.b8 209 // DW_AT_decl_line -; CHECK-NEXT:.b32 3770 // DW_AT_type +; CHECK-NEXT:.b32 3771 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration ; CHECK-NEXT:.b8 1 // DW_AT_external -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1ef4:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 5637 // DW_AT_type -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1ef9:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 7482 // DW_AT_type -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1efe:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 4585 // DW_AT_type -; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 32 // Abbrev [32] 0x1f04:0x22 DW_TAG_subprogram +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1ef5:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 5638 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1efa:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 7483 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1eff:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 4586 // DW_AT_type +; CHECK-NEXT:.b8 0 // End Of Children Mark +; CHECK-NEXT:.b8 32 // Abbrev [32] 0x1f05:0x22 DW_TAG_subprogram ; CHECK-NEXT:.b8 115 // DW_AT_name ; CHECK-NEXT:.b8 116 ; CHECK-NEXT:.b8 114 @@ -6737,17 +6740,17 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 0 ; CHECK-NEXT:.b8 7 // DW_AT_decl_file ; CHECK-NEXT:.b8 214 // DW_AT_decl_line -; CHECK-NEXT:.b32 7974 // DW_AT_type +; CHECK-NEXT:.b32 7975 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration ; CHECK-NEXT:.b8 1 // DW_AT_external -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1f16:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 5637 // DW_AT_type -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1f1b:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 7482 // DW_AT_type -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1f20:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 4585 // DW_AT_type -; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 10 // Abbrev [10] 0x1f26:0x1a DW_TAG_base_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1f17:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 5638 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1f1c:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 7483 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1f21:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 4586 // DW_AT_type +; CHECK-NEXT:.b8 0 // End Of Children Mark +; CHECK-NEXT:.b8 10 // Abbrev [10] 0x1f27:0x1a DW_TAG_base_type ; CHECK-NEXT:.b8 108 // DW_AT_name ; CHECK-NEXT:.b8 111 ; CHECK-NEXT:.b8 110 @@ -6773,7 +6776,7 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 0 ; CHECK-NEXT:.b8 7 // DW_AT_encoding ; CHECK-NEXT:.b8 8 // DW_AT_byte_size -; CHECK-NEXT:.b8 32 // Abbrev [32] 0x1f40:0x1b DW_TAG_subprogram +; CHECK-NEXT:.b8 32 // Abbrev [32] 0x1f41:0x1b DW_TAG_subprogram ; CHECK-NEXT:.b8 115 // DW_AT_name ; CHECK-NEXT:.b8 116 ; CHECK-NEXT:.b8 114 @@ -6786,12 +6789,12 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration ; CHECK-NEXT:.b8 1 // DW_AT_external -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1f50:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 5637 // DW_AT_type -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1f55:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 7482 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1f51:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 5638 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1f56:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 7483 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 32 // Abbrev [32] 0x1f5b:0x1c DW_TAG_subprogram +; CHECK-NEXT:.b8 32 // Abbrev [32] 0x1f5c:0x1c DW_TAG_subprogram ; CHECK-NEXT:.b8 115 // DW_AT_name ; CHECK-NEXT:.b8 116 ; CHECK-NEXT:.b8 114 @@ -6802,15 +6805,15 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 0 ; CHECK-NEXT:.b8 7 // DW_AT_decl_file ; CHECK-NEXT:.b8 175 // DW_AT_decl_line -; CHECK-NEXT:.b32 8055 // DW_AT_type +; CHECK-NEXT:.b32 8056 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration ; CHECK-NEXT:.b8 1 // DW_AT_external -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1f6c:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 5637 // DW_AT_type -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1f71:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 7482 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1f6d:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 5638 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1f72:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 7483 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 10 // Abbrev [10] 0x1f77:0xf DW_TAG_base_type +; CHECK-NEXT:.b8 10 // Abbrev [10] 0x1f78:0xf DW_TAG_base_type ; CHECK-NEXT:.b8 108 // DW_AT_name ; CHECK-NEXT:.b8 111 ; CHECK-NEXT:.b8 110 @@ -6825,7 +6828,7 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 0 ; CHECK-NEXT:.b8 4 // DW_AT_encoding ; CHECK-NEXT:.b8 8 // DW_AT_byte_size -; CHECK-NEXT:.b8 44 // Abbrev [44] 0x1f86:0x20 DW_TAG_subprogram +; CHECK-NEXT:.b8 44 // Abbrev [44] 0x1f87:0x20 DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -6848,10 +6851,10 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 5 ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1fa0:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1fa1:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 44 // Abbrev [44] 0x1fa6:0x22 DW_TAG_subprogram +; CHECK-NEXT:.b8 44 // Abbrev [44] 0x1fa7:0x22 DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -6876,10 +6879,10 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 5 ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1fc2:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1fc3:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 44 // Abbrev [44] 0x1fc8:0x20 DW_TAG_subprogram +; CHECK-NEXT:.b8 44 // Abbrev [44] 0x1fc9:0x20 DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -6902,10 +6905,10 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 5 ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1fe2:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x1fe3:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 44 // Abbrev [44] 0x1fe8:0x22 DW_TAG_subprogram +; CHECK-NEXT:.b8 44 // Abbrev [44] 0x1fe9:0x22 DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -6930,10 +6933,10 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 5 ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x2004:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x2005:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 44 // Abbrev [44] 0x200a:0x28 DW_TAG_subprogram +; CHECK-NEXT:.b8 44 // Abbrev [44] 0x200b:0x28 DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -6959,12 +6962,12 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 5 ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x2027:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x2028:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x202c:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x202d:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 44 // Abbrev [44] 0x2032:0x20 DW_TAG_subprogram +; CHECK-NEXT:.b8 44 // Abbrev [44] 0x2033:0x20 DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -6987,10 +6990,10 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 5 ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x204c:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x204d:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 44 // Abbrev [44] 0x2052:0x22 DW_TAG_subprogram +; CHECK-NEXT:.b8 44 // Abbrev [44] 0x2053:0x22 DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -7015,10 +7018,10 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 5 ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x206e:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x206f:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 44 // Abbrev [44] 0x2074:0x20 DW_TAG_subprogram +; CHECK-NEXT:.b8 44 // Abbrev [44] 0x2075:0x20 DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -7041,10 +7044,10 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 5 ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x208e:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x208f:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 44 // Abbrev [44] 0x2094:0x20 DW_TAG_subprogram +; CHECK-NEXT:.b8 44 // Abbrev [44] 0x2095:0x20 DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -7067,10 +7070,10 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 2 ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x20ae:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x20af:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 44 // Abbrev [44] 0x20b4:0x2e DW_TAG_subprogram +; CHECK-NEXT:.b8 44 // Abbrev [44] 0x20b5:0x2e DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -7102,12 +7105,12 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 4 ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x20d7:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x20d8:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x20dc:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x20dd:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 44 // Abbrev [44] 0x20e2:0x1e DW_TAG_subprogram +; CHECK-NEXT:.b8 44 // Abbrev [44] 0x20e3:0x1e DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -7128,10 +7131,10 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 4 ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x20fa:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x20fb:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 44 // Abbrev [44] 0x2100:0x20 DW_TAG_subprogram +; CHECK-NEXT:.b8 44 // Abbrev [44] 0x2101:0x20 DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -7154,10 +7157,10 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 5 ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x211a:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x211b:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 44 // Abbrev [44] 0x2120:0x20 DW_TAG_subprogram +; CHECK-NEXT:.b8 44 // Abbrev [44] 0x2121:0x20 DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -7180,10 +7183,10 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 5 ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x213a:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x213b:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 44 // Abbrev [44] 0x2140:0x1e DW_TAG_subprogram +; CHECK-NEXT:.b8 44 // Abbrev [44] 0x2141:0x1e DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -7204,10 +7207,10 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 5 ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x2158:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x2159:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 44 // Abbrev [44] 0x215e:0x20 DW_TAG_subprogram +; CHECK-NEXT:.b8 44 // Abbrev [44] 0x215f:0x20 DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -7230,10 +7233,10 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 2 ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x2178:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x2179:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 44 // Abbrev [44] 0x217e:0x1e DW_TAG_subprogram +; CHECK-NEXT:.b8 44 // Abbrev [44] 0x217f:0x1e DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -7254,10 +7257,10 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 5 ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x2196:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x2197:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 44 // Abbrev [44] 0x219c:0x22 DW_TAG_subprogram +; CHECK-NEXT:.b8 44 // Abbrev [44] 0x219d:0x22 DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -7282,10 +7285,10 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 5 ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x21b8:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x21b9:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 44 // Abbrev [44] 0x21be:0x20 DW_TAG_subprogram +; CHECK-NEXT:.b8 44 // Abbrev [44] 0x21bf:0x20 DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -7308,10 +7311,10 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 2 ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x21d8:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x21d9:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 44 // Abbrev [44] 0x21de:0x26 DW_TAG_subprogram +; CHECK-NEXT:.b8 44 // Abbrev [44] 0x21df:0x26 DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -7335,12 +7338,12 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 6 ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x21f9:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x21fa:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x21fe:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x21ff:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 44 // Abbrev [44] 0x2204:0x22 DW_TAG_subprogram +; CHECK-NEXT:.b8 44 // Abbrev [44] 0x2205:0x22 DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -7365,10 +7368,10 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 2 ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x2220:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x2221:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 44 // Abbrev [44] 0x2226:0x2a DW_TAG_subprogram +; CHECK-NEXT:.b8 44 // Abbrev [44] 0x2227:0x2a DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -7391,14 +7394,14 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 6 ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x2240:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x2241:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x2245:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x2246:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x224a:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x224b:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 44 // Abbrev [44] 0x2250:0x26 DW_TAG_subprogram +; CHECK-NEXT:.b8 44 // Abbrev [44] 0x2251:0x26 DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -7422,12 +7425,12 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 2 ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x226b:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x226c:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x2270:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x2271:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 44 // Abbrev [44] 0x2276:0x26 DW_TAG_subprogram +; CHECK-NEXT:.b8 44 // Abbrev [44] 0x2277:0x26 DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -7451,12 +7454,12 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 2 ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x2291:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x2292:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x2296:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x2297:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 44 // Abbrev [44] 0x229c:0x26 DW_TAG_subprogram +; CHECK-NEXT:.b8 44 // Abbrev [44] 0x229d:0x26 DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -7480,12 +7483,12 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 6 ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x22b7:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x22b8:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x22bc:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x22bd:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 44 // Abbrev [44] 0x22c2:0x29 DW_TAG_subprogram +; CHECK-NEXT:.b8 44 // Abbrev [44] 0x22c3:0x29 DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -7512,12 +7515,12 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 6 ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x22e0:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x22e1:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x22e5:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 4630 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x22e6:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 4631 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 44 // Abbrev [44] 0x22eb:0x28 DW_TAG_subprogram +; CHECK-NEXT:.b8 44 // Abbrev [44] 0x22ec:0x28 DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -7543,12 +7546,12 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 5 ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x2308:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x2309:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x230d:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x230e:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 44 // Abbrev [44] 0x2313:0x22 DW_TAG_subprogram +; CHECK-NEXT:.b8 44 // Abbrev [44] 0x2314:0x22 DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -7571,12 +7574,12 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 12 // DW_AT_decl_file ; CHECK-NEXT:.b8 85 // DW_AT_decl_line ; CHECK-NEXT:.b8 6 -; CHECK-NEXT:.b32 4585 // DW_AT_type +; CHECK-NEXT:.b32 4586 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x232f:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x2330:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 44 // Abbrev [44] 0x2335:0x28 DW_TAG_subprogram +; CHECK-NEXT:.b8 44 // Abbrev [44] 0x2336:0x28 DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -7602,12 +7605,12 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 5 ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x2352:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x2353:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x2357:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 4585 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x2358:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 4586 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 44 // Abbrev [44] 0x235d:0x24 DW_TAG_subprogram +; CHECK-NEXT:.b8 44 // Abbrev [44] 0x235e:0x24 DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -7634,10 +7637,10 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 5 ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x237b:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x237c:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 44 // Abbrev [44] 0x2381:0x24 DW_TAG_subprogram +; CHECK-NEXT:.b8 44 // Abbrev [44] 0x2382:0x24 DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -7662,12 +7665,12 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 12 // DW_AT_decl_file ; CHECK-NEXT:.b8 125 // DW_AT_decl_line ; CHECK-NEXT:.b8 4 -; CHECK-NEXT:.b32 3770 // DW_AT_type +; CHECK-NEXT:.b32 3771 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x239f:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x23a0:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 44 // Abbrev [44] 0x23a5:0x26 DW_TAG_subprogram +; CHECK-NEXT:.b8 44 // Abbrev [44] 0x23a6:0x26 DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -7694,12 +7697,12 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 12 // DW_AT_decl_file ; CHECK-NEXT:.b8 66 // DW_AT_decl_line ; CHECK-NEXT:.b8 6 -; CHECK-NEXT:.b32 3770 // DW_AT_type +; CHECK-NEXT:.b32 3771 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x23c5:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x23c6:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 44 // Abbrev [44] 0x23cb:0x22 DW_TAG_subprogram +; CHECK-NEXT:.b8 44 // Abbrev [44] 0x23cc:0x22 DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -7724,10 +7727,10 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 5 ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x23e7:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x23e8:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 44 // Abbrev [44] 0x23ed:0x22 DW_TAG_subprogram +; CHECK-NEXT:.b8 44 // Abbrev [44] 0x23ee:0x22 DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -7752,10 +7755,10 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 5 ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x2409:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x240a:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 44 // Abbrev [44] 0x240f:0x20 DW_TAG_subprogram +; CHECK-NEXT:.b8 44 // Abbrev [44] 0x2410:0x20 DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -7778,10 +7781,10 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 5 ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x2429:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x242a:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 44 // Abbrev [44] 0x242f:0x20 DW_TAG_subprogram +; CHECK-NEXT:.b8 44 // Abbrev [44] 0x2430:0x20 DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -7804,10 +7807,10 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 6 ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x2449:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x244a:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 44 // Abbrev [44] 0x244f:0x1e DW_TAG_subprogram +; CHECK-NEXT:.b8 44 // Abbrev [44] 0x2450:0x1e DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -7828,10 +7831,10 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 5 ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x2467:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x2468:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 44 // Abbrev [44] 0x246d:0x22 DW_TAG_subprogram +; CHECK-NEXT:.b8 44 // Abbrev [44] 0x246e:0x22 DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -7854,12 +7857,12 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 12 // DW_AT_decl_file ; CHECK-NEXT:.b8 116 // DW_AT_decl_line ; CHECK-NEXT:.b8 4 -; CHECK-NEXT:.b32 5170 // DW_AT_type +; CHECK-NEXT:.b32 5171 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x2489:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x248a:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 44 // Abbrev [44] 0x248f:0x24 DW_TAG_subprogram +; CHECK-NEXT:.b8 44 // Abbrev [44] 0x2490:0x24 DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -7884,12 +7887,12 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 12 // DW_AT_decl_file ; CHECK-NEXT:.b8 71 // DW_AT_decl_line ; CHECK-NEXT:.b8 6 -; CHECK-NEXT:.b32 5170 // DW_AT_type +; CHECK-NEXT:.b32 5171 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x24ad:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x24ae:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 44 // Abbrev [44] 0x24b3:0x27 DW_TAG_subprogram +; CHECK-NEXT:.b8 44 // Abbrev [44] 0x24b4:0x27 DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -7914,12 +7917,12 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 6 ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x24cf:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x24d0:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x24d4:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x24d5:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2125 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 44 // Abbrev [44] 0x24da:0x2b DW_TAG_subprogram +; CHECK-NEXT:.b8 44 // Abbrev [44] 0x24db:0x2b DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -7953,10 +7956,10 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 4 ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x24ff:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x2500:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 44 // Abbrev [44] 0x2505:0x31 DW_TAG_subprogram +; CHECK-NEXT:.b8 44 // Abbrev [44] 0x2506:0x31 DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -7991,12 +7994,12 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 4 ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x252b:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x252c:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x2530:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x2531:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 44 // Abbrev [44] 0x2536:0x24 DW_TAG_subprogram +; CHECK-NEXT:.b8 44 // Abbrev [44] 0x2537:0x24 DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -8018,12 +8021,12 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 6 ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x254f:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x2550:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x2554:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x2555:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 44 // Abbrev [44] 0x255a:0x31 DW_TAG_subprogram +; CHECK-NEXT:.b8 44 // Abbrev [44] 0x255b:0x31 DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -8058,12 +8061,12 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 6 ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x2580:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x2581:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x2585:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x2586:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 44 // Abbrev [44] 0x258b:0x31 DW_TAG_subprogram +; CHECK-NEXT:.b8 44 // Abbrev [44] 0x258c:0x31 DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -8093,14 +8096,14 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 6 ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x25ac:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x25ad:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x25b1:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x25b2:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x25b6:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 4630 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x25b7:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 4631 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 44 // Abbrev [44] 0x25bc:0x20 DW_TAG_subprogram +; CHECK-NEXT:.b8 44 // Abbrev [44] 0x25bd:0x20 DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -8123,10 +8126,10 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 4 ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x25d6:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x25d7:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 44 // Abbrev [44] 0x25dc:0x22 DW_TAG_subprogram +; CHECK-NEXT:.b8 44 // Abbrev [44] 0x25dd:0x22 DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -8151,10 +8154,10 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 6 ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x25f8:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x25f9:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 44 // Abbrev [44] 0x25fe:0x2c DW_TAG_subprogram +; CHECK-NEXT:.b8 44 // Abbrev [44] 0x25ff:0x2c DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -8184,12 +8187,12 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 5 ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x261f:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x2620:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x2624:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 5170 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x2625:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 5171 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 44 // Abbrev [44] 0x262a:0x2a DW_TAG_subprogram +; CHECK-NEXT:.b8 44 // Abbrev [44] 0x262b:0x2a DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -8217,12 +8220,12 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 5 ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x2649:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x264a:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x264e:0x5 DW_TAG_formal_parameter -; CHECK-NEXT:.b32 4585 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x264f:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 4586 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 44 // Abbrev [44] 0x2654:0x1e DW_TAG_subprogram +; CHECK-NEXT:.b8 44 // Abbrev [44] 0x2655:0x1e DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -8243,10 +8246,10 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 4 ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x266c:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x266d:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 44 // Abbrev [44] 0x2672:0x20 DW_TAG_subprogram +; CHECK-NEXT:.b8 44 // Abbrev [44] 0x2673:0x20 DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -8269,10 +8272,10 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 5 ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x268c:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x268d:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 44 // Abbrev [44] 0x2692:0x20 DW_TAG_subprogram +; CHECK-NEXT:.b8 44 // Abbrev [44] 0x2693:0x20 DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -8295,10 +8298,10 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 3 ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x26ac:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x26ad:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 44 // Abbrev [44] 0x26b2:0x1e DW_TAG_subprogram +; CHECK-NEXT:.b8 44 // Abbrev [44] 0x26b3:0x1e DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -8319,10 +8322,10 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 4 ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x26ca:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x26cb:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 44 // Abbrev [44] 0x26d0:0x20 DW_TAG_subprogram +; CHECK-NEXT:.b8 44 // Abbrev [44] 0x26d1:0x20 DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -8345,10 +8348,10 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 5 ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x26ea:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x26eb:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 44 // Abbrev [44] 0x26f0:0x24 DW_TAG_subprogram +; CHECK-NEXT:.b8 44 // Abbrev [44] 0x26f1:0x24 DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -8375,10 +8378,10 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 6 ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x270e:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x270f:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 44 // Abbrev [44] 0x2714:0x22 DW_TAG_subprogram +; CHECK-NEXT:.b8 44 // Abbrev [44] 0x2715:0x22 DW_TAG_subprogram ; CHECK-NEXT:.b8 95 // DW_AT_MIPS_linkage_name ; CHECK-NEXT:.b8 90 ; CHECK-NEXT:.b8 76 @@ -8403,7 +8406,7 @@ if.end: ; preds = %if.then, %entry ; CHECK-NEXT:.b8 2 ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 1 // DW_AT_declaration -; CHECK-NEXT:.b8 7 // Abbrev [7] 0x2730:0x5 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 7 // Abbrev [7] 0x2731:0x5 DW_TAG_formal_parameter ; CHECK-NEXT:.b32 2116 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark ; CHECK-NEXT:.b8 0 // End Of Children Mark From 3b96294f2d3dd5d9646803c7c4e35039a373792e Mon Sep 17 00:00:00 2001 From: Heejin Ahn Date: Fri, 27 Sep 2024 01:59:36 +0000 Subject: [PATCH 035/469] [WebAssembly] Update type checker message in notypecheck.s This was missing from https://github.com/llvm/llvm-project/pull/110094. --- clang/test/Driver/notypecheck.s | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/test/Driver/notypecheck.s b/clang/test/Driver/notypecheck.s index f6e78d6791182..8e924b57fbdc0 100644 --- a/clang/test/Driver/notypecheck.s +++ b/clang/test/Driver/notypecheck.s @@ -5,7 +5,7 @@ # Verify that without -Wa,--no-type-check the assembler will error out # RUN: not %clang %s -c -o tmp.o -target wasm32-unknown-unknown 2>&1 | FileCheck --check-prefix=ERROR %s -# ERROR: error: popped i64, expected i32 +# ERROR: error: type mismatch, expected [i32] but got [i64] foo: .functype foo () -> (i32) From d9853a8a101a9ec2d2199c6124d1fa826a84336c Mon Sep 17 00:00:00 2001 From: Congcong Cai Date: Fri, 27 Sep 2024 10:05:37 +0800 Subject: [PATCH 036/469] [clang-tidy][bugprone-posix-return] support integer literals as LHS (#109302) Refactor matches to give more generic checker. --------- Co-authored-by: EugeneZelenko --- .../clang-tidy/bugprone/PosixReturnCheck.cpp | 61 +++++++++++-------- clang-tools-extra/docs/ReleaseNotes.rst | 4 ++ .../checkers/bugprone/posix-return.cpp | 25 +++++++- 3 files changed, 62 insertions(+), 28 deletions(-) diff --git a/clang-tools-extra/clang-tidy/bugprone/PosixReturnCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/PosixReturnCheck.cpp index 378427a1eab00..f05924b81c4c0 100644 --- a/clang-tools-extra/clang-tidy/bugprone/PosixReturnCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/PosixReturnCheck.cpp @@ -7,19 +7,17 @@ //===----------------------------------------------------------------------===// #include "PosixReturnCheck.h" -#include "../utils/Matchers.h" #include "clang/AST/ASTContext.h" #include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchers.h" #include "clang/Lex/Lexer.h" using namespace clang::ast_matchers; namespace clang::tidy::bugprone { -static StringRef getFunctionSpelling(const MatchFinder::MatchResult &Result, - const char *BindingStr) { - const CallExpr *MatchedCall = cast( - (Result.Nodes.getNodeAs(BindingStr))->getLHS()); +static StringRef getFunctionSpelling(const MatchFinder::MatchResult &Result) { + const auto *MatchedCall = Result.Nodes.getNodeAs("call"); const SourceManager &SM = *Result.SourceManager; return Lexer::getSourceText(CharSourceRange::getTokenRange( MatchedCall->getCallee()->getSourceRange()), @@ -27,32 +25,40 @@ static StringRef getFunctionSpelling(const MatchFinder::MatchResult &Result, } void PosixReturnCheck::registerMatchers(MatchFinder *Finder) { + const auto PosixCall = + callExpr(callee(functionDecl( + anyOf(matchesName("^::posix_"), matchesName("^::pthread_")), + unless(hasName("::posix_openpt"))))) + .bind("call"); + const auto ZeroIntegerLiteral = integerLiteral(equals(0)); + const auto NegIntegerLiteral = + unaryOperator(hasOperatorName("-"), hasUnaryOperand(integerLiteral())); + Finder->addMatcher( binaryOperator( - hasOperatorName("<"), - hasLHS(callExpr(callee(functionDecl( - anyOf(matchesName("^::posix_"), matchesName("^::pthread_")), - unless(hasName("::posix_openpt")))))), - hasRHS(integerLiteral(equals(0)))) + anyOf(allOf(hasOperatorName("<"), hasLHS(PosixCall), + hasRHS(ZeroIntegerLiteral)), + allOf(hasOperatorName(">"), hasLHS(ZeroIntegerLiteral), + hasRHS(PosixCall)))) .bind("ltzop"), this); Finder->addMatcher( binaryOperator( - hasOperatorName(">="), - hasLHS(callExpr(callee(functionDecl( - anyOf(matchesName("^::posix_"), matchesName("^::pthread_")), - unless(hasName("::posix_openpt")))))), - hasRHS(integerLiteral(equals(0)))) + anyOf(allOf(hasOperatorName(">="), hasLHS(PosixCall), + hasRHS(ZeroIntegerLiteral)), + allOf(hasOperatorName("<="), hasLHS(ZeroIntegerLiteral), + hasRHS(PosixCall)))) .bind("atop"), this); + Finder->addMatcher(binaryOperator(hasAnyOperatorName("==", "!="), + hasOperands(PosixCall, NegIntegerLiteral)) + .bind("binop"), + this); Finder->addMatcher( - binaryOperator( - hasAnyOperatorName("==", "!=", "<=", "<"), - hasLHS(callExpr(callee(functionDecl( - anyOf(matchesName("^::posix_"), matchesName("^::pthread_")), - unless(hasName("::posix_openpt")))))), - hasRHS(unaryOperator(hasOperatorName("-"), - hasUnaryOperand(integerLiteral())))) + binaryOperator(anyOf(allOf(hasAnyOperatorName("<=", "<"), + hasLHS(PosixCall), hasRHS(NegIntegerLiteral)), + allOf(hasAnyOperatorName(">", ">="), + hasLHS(NegIntegerLiteral), hasRHS(PosixCall)))) .bind("binop"), this); } @@ -61,10 +67,13 @@ void PosixReturnCheck::check(const MatchFinder::MatchResult &Result) { if (const auto *LessThanZeroOp = Result.Nodes.getNodeAs("ltzop")) { SourceLocation OperatorLoc = LessThanZeroOp->getOperatorLoc(); + StringRef NewBinOp = + LessThanZeroOp->getOpcode() == BinaryOperator::Opcode::BO_LT ? ">" + : "<"; diag(OperatorLoc, "the comparison always evaluates to false because %0 " "always returns non-negative values") - << getFunctionSpelling(Result, "ltzop") - << FixItHint::CreateReplacement(OperatorLoc, Twine(">").str()); + << getFunctionSpelling(Result) + << FixItHint::CreateReplacement(OperatorLoc, NewBinOp); return; } if (const auto *AlwaysTrueOp = @@ -72,12 +81,12 @@ void PosixReturnCheck::check(const MatchFinder::MatchResult &Result) { diag(AlwaysTrueOp->getOperatorLoc(), "the comparison always evaluates to true because %0 always returns " "non-negative values") - << getFunctionSpelling(Result, "atop"); + << getFunctionSpelling(Result); return; } const auto *BinOp = Result.Nodes.getNodeAs("binop"); diag(BinOp->getOperatorLoc(), "%0 only returns non-negative values") - << getFunctionSpelling(Result, "binop"); + << getFunctionSpelling(Result); } } // namespace clang::tidy::bugprone diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index bec768e30d64f..7d37a4b03222c 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -125,6 +125,10 @@ Changes in existing checks ` check by fixing a crash when determining if an ``enable_if[_t]`` was found. +- Improved :doc:`bugprone-posix-return + ` check to support integer literals + as LHS and posix call as RHS of comparison. + - Improved :doc:`bugprone-sizeof-expression ` check to find suspicious usages of ``sizeof()``, ``alignof()``, and ``offsetof()`` when adding or diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/posix-return.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/posix-return.cpp index 271893c707069..76d447a71d68b 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/posix-return.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/posix-return.cpp @@ -74,6 +74,9 @@ void warningLessThanZero() { if (pthread_yield() < 0) {} // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: // CHECK-FIXES: pthread_yield() > 0 + if (0 > pthread_yield() ) {} + // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: + // CHECK-FIXES: 0 < pthread_yield() } @@ -90,7 +93,8 @@ void warningAlwaysTrue() { // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: if (pthread_yield() >= 0) {} // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: - + if (0 <= pthread_yield()) {} + // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: } void warningEqualsNegative() { @@ -120,7 +124,14 @@ void warningEqualsNegative() { // CHECK-MESSAGES: :[[@LINE-1]]:46: warning: if (pthread_create(NULL, NULL, NULL, NULL) < -1) {} // CHECK-MESSAGES: :[[@LINE-1]]:46: warning: - + if (-1 == pthread_create(NULL, NULL, NULL, NULL)) {} + // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: + if (-1 != pthread_create(NULL, NULL, NULL, NULL)) {} + // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: + if (-1 >= pthread_create(NULL, NULL, NULL, NULL)) {} + // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: + if (-1 > pthread_create(NULL, NULL, NULL, NULL)) {} + // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: } void WarningWithMacro() { @@ -162,6 +173,16 @@ void noWarning() { if (posix_openpt(0) < -1) {} if (posix_fadvise(0, 0, 0, 0) <= 0) {} if (posix_fadvise(0, 0, 0, 0) == 1) {} + if (0 > posix_openpt(0)) {} + if (0 >= posix_openpt(0)) {} + if (-1 == posix_openpt(0)) {} + if (-1 != posix_openpt(0)) {} + if (-1 >= posix_openpt(0)) {} + if (-1 > posix_openpt(0)) {} + if (posix_fadvise(0, 0, 0, 0) <= 0) {} + if (posix_fadvise(0, 0, 0, 0) == 1) {} + if (0 >= posix_fadvise(0, 0, 0, 0)) {} + if (1 == posix_fadvise(0, 0, 0, 0)) {} } namespace i { From e069434afcd21911ad36c55971bb8f754854c09f Mon Sep 17 00:00:00 2001 From: Chris Apple Date: Thu, 26 Sep 2024 19:12:25 -0700 Subject: [PATCH 037/469] [rtsan][NFC] Remove unncessary namespace specifiers (#110197) --- compiler-rt/lib/rtsan/rtsan.cpp | 8 ++++---- compiler-rt/lib/rtsan/rtsan_context.cpp | 13 +++++++------ compiler-rt/lib/rtsan/rtsan_diagnostics.cpp | 2 +- .../lib/rtsan/tests/rtsan_test_assertions.cpp | 8 ++++---- .../lib/rtsan/tests/rtsan_test_context.cpp | 15 ++++++++------- 5 files changed, 24 insertions(+), 22 deletions(-) diff --git a/compiler-rt/lib/rtsan/rtsan.cpp b/compiler-rt/lib/rtsan/rtsan.cpp index 6fcff5e326a52..f9741b4fe3509 100644 --- a/compiler-rt/lib/rtsan/rtsan.cpp +++ b/compiler-rt/lib/rtsan/rtsan.cpp @@ -114,19 +114,19 @@ SANITIZER_INTERFACE_ATTRIBUTE bool __rtsan_is_initialized() { } SANITIZER_INTERFACE_ATTRIBUTE void __rtsan_realtime_enter() { - __rtsan::GetContextForThisThread().RealtimePush(); + GetContextForThisThread().RealtimePush(); } SANITIZER_INTERFACE_ATTRIBUTE void __rtsan_realtime_exit() { - __rtsan::GetContextForThisThread().RealtimePop(); + GetContextForThisThread().RealtimePop(); } SANITIZER_INTERFACE_ATTRIBUTE void __rtsan_disable() { - __rtsan::GetContextForThisThread().BypassPush(); + GetContextForThisThread().BypassPush(); } SANITIZER_INTERFACE_ATTRIBUTE void __rtsan_enable() { - __rtsan::GetContextForThisThread().BypassPop(); + GetContextForThisThread().BypassPop(); } SANITIZER_INTERFACE_ATTRIBUTE void diff --git a/compiler-rt/lib/rtsan/rtsan_context.cpp b/compiler-rt/lib/rtsan/rtsan_context.cpp index 1cf1791f0aaf8..536d62e81e2fb 100644 --- a/compiler-rt/lib/rtsan/rtsan_context.cpp +++ b/compiler-rt/lib/rtsan/rtsan_context.cpp @@ -17,6 +17,7 @@ #include using namespace __sanitizer; +using namespace __rtsan; static pthread_key_t context_key; static pthread_once_t key_once = PTHREAD_ONCE_INIT; @@ -31,12 +32,12 @@ static __rtsan::Context &GetContextForThisThreadImpl() { }; pthread_once(&key_once, MakeThreadLocalContextKey); - __rtsan::Context *current_thread_context = - static_cast<__rtsan::Context *>(pthread_getspecific(context_key)); + Context *current_thread_context = + static_cast(pthread_getspecific(context_key)); if (current_thread_context == nullptr) { - current_thread_context = static_cast<__rtsan::Context *>( - __sanitizer::InternalAlloc(sizeof(__rtsan::Context))); - new (current_thread_context) __rtsan::Context(); + current_thread_context = + static_cast(InternalAlloc(sizeof(Context))); + new (current_thread_context) Context(); pthread_setspecific(context_key, current_thread_context); } @@ -57,6 +58,6 @@ bool __rtsan::Context::InRealtimeContext() const { return realtime_depth_ > 0; } bool __rtsan::Context::IsBypassed() const { return bypass_depth_ > 0; } -__rtsan::Context &__rtsan::GetContextForThisThread() { +Context &__rtsan::GetContextForThisThread() { return GetContextForThisThreadImpl(); } diff --git a/compiler-rt/lib/rtsan/rtsan_diagnostics.cpp b/compiler-rt/lib/rtsan/rtsan_diagnostics.cpp index cfe71481d3dc7..ecba30d2ab8df 100644 --- a/compiler-rt/lib/rtsan/rtsan_diagnostics.cpp +++ b/compiler-rt/lib/rtsan/rtsan_diagnostics.cpp @@ -31,7 +31,7 @@ void BufferedStackTrace::UnwindImpl(uptr pc, uptr bp, void *context, } // namespace __sanitizer namespace { -class Decorator : public __sanitizer::SanitizerCommonDecorator { +class Decorator : public SanitizerCommonDecorator { public: Decorator() : SanitizerCommonDecorator() {} const char *FunctionName() const { return Green(); } diff --git a/compiler-rt/lib/rtsan/tests/rtsan_test_assertions.cpp b/compiler-rt/lib/rtsan/tests/rtsan_test_assertions.cpp index 58f7dbae96e9f..3b279989a49cb 100644 --- a/compiler-rt/lib/rtsan/tests/rtsan_test_assertions.cpp +++ b/compiler-rt/lib/rtsan/tests/rtsan_test_assertions.cpp @@ -23,7 +23,7 @@ class TestRtsanAssertions : public ::testing::Test { void SetUp() override { __rtsan_ensure_initialized(); } }; -static void ExpectViolationAction(__rtsan::Context &context, +static void ExpectViolationAction(Context &context, bool expect_violation_callback) { ::testing::MockFunction mock_on_violation; EXPECT_CALL(mock_on_violation, Call).Times(expect_violation_callback ? 1 : 0); @@ -32,14 +32,14 @@ static void ExpectViolationAction(__rtsan::Context &context, TEST_F(TestRtsanAssertions, ExpectNotRealtimeDoesNotCallViolationActionIfNotInRealtimeContext) { - __rtsan::Context context{}; + Context context{}; ASSERT_FALSE(context.InRealtimeContext()); ExpectViolationAction(context, false); } TEST_F(TestRtsanAssertions, ExpectNotRealtimeCallsViolationActionIfInRealtimeContext) { - __rtsan::Context context{}; + Context context{}; context.RealtimePush(); ASSERT_TRUE(context.InRealtimeContext()); ExpectViolationAction(context, true); @@ -47,7 +47,7 @@ TEST_F(TestRtsanAssertions, TEST_F(TestRtsanAssertions, ExpectNotRealtimeDoesNotCallViolationActionIfRealtimeButBypassed) { - __rtsan::Context context{}; + Context context{}; context.RealtimePush(); context.BypassPush(); ASSERT_TRUE(context.IsBypassed()); diff --git a/compiler-rt/lib/rtsan/tests/rtsan_test_context.cpp b/compiler-rt/lib/rtsan/tests/rtsan_test_context.cpp index 7551f67b38d78..2b6f53b4f572d 100644 --- a/compiler-rt/lib/rtsan/tests/rtsan_test_context.cpp +++ b/compiler-rt/lib/rtsan/tests/rtsan_test_context.cpp @@ -15,6 +15,7 @@ #include +using namespace __rtsan; using namespace ::testing; class TestRtsanContext : public Test { @@ -23,18 +24,18 @@ class TestRtsanContext : public Test { }; TEST_F(TestRtsanContext, IsNotRealtimeAfterDefaultConstruction) { - __rtsan::Context context{}; + Context context{}; EXPECT_THAT(context.InRealtimeContext(), Eq(false)); } TEST_F(TestRtsanContext, IsRealtimeAfterRealtimePush) { - __rtsan::Context context{}; + Context context{}; context.RealtimePush(); EXPECT_THAT(context.InRealtimeContext(), Eq(true)); } TEST_F(TestRtsanContext, IsNotRealtimeAfterRealtimePushAndPop) { - __rtsan::Context context{}; + Context context{}; context.RealtimePush(); ASSERT_THAT(context.InRealtimeContext(), Eq(true)); context.RealtimePop(); @@ -42,7 +43,7 @@ TEST_F(TestRtsanContext, IsNotRealtimeAfterRealtimePushAndPop) { } TEST_F(TestRtsanContext, RealtimeContextStateIsStatefullyTracked) { - __rtsan::Context context{}; + Context context{}; auto const ExpectRealtime = [&context](bool is_rt) { EXPECT_THAT(context.InRealtimeContext(), Eq(is_rt)); }; @@ -64,18 +65,18 @@ TEST_F(TestRtsanContext, RealtimeContextStateIsStatefullyTracked) { } TEST_F(TestRtsanContext, IsNotBypassedAfterDefaultConstruction) { - __rtsan::Context context{}; + Context context{}; EXPECT_THAT(context.IsBypassed(), Eq(false)); } TEST_F(TestRtsanContext, IsBypassedAfterBypassPush) { - __rtsan::Context context{}; + Context context{}; context.BypassPush(); EXPECT_THAT(context.IsBypassed(), Eq(true)); } TEST_F(TestRtsanContext, BypassedStateIsStatefullyTracked) { - __rtsan::Context context{}; + Context context{}; auto const ExpectBypassed = [&context](bool is_bypassed) { EXPECT_THAT(context.IsBypassed(), Eq(is_bypassed)); }; From d435acb8ebb46425e752d1fb02015dbbf6471585 Mon Sep 17 00:00:00 2001 From: sinan Date: Fri, 27 Sep 2024 10:27:04 +0800 Subject: [PATCH 038/469] [DWARF] Don't emit DWARF5 symbols for DWARF2/3 + non-lldb (#110120) Modify other legacy dwarf versions to align with the dwarf4 handling approach when determining whether to generate DWARF5 or GNU extensions. --- llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp | 2 +- .../MIR/X86/call-site-gnu-vs-dwarf5-attrs.mir | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp index a69184676336c..20ee50dca499f 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp @@ -1216,7 +1216,7 @@ void DwarfCompileUnit::constructAbstractSubprogramScopeDIE( } bool DwarfCompileUnit::useGNUAnalogForDwarf5Feature() const { - return DD->getDwarfVersion() == 4 && !DD->tuneForLLDB(); + return DD->getDwarfVersion() <= 4 && !DD->tuneForLLDB(); } dwarf::Tag DwarfCompileUnit::getDwarf5OrGNUTag(dwarf::Tag Tag) const { diff --git a/llvm/test/DebugInfo/MIR/X86/call-site-gnu-vs-dwarf5-attrs.mir b/llvm/test/DebugInfo/MIR/X86/call-site-gnu-vs-dwarf5-attrs.mir index 1790f761585c3..a9c20d774822e 100644 --- a/llvm/test/DebugInfo/MIR/X86/call-site-gnu-vs-dwarf5-attrs.mir +++ b/llvm/test/DebugInfo/MIR/X86/call-site-gnu-vs-dwarf5-attrs.mir @@ -30,6 +30,21 @@ # RUN: -debug-entry-values -mtriple=x86_64-unknown-unknown \ # RUN: -start-after=machineverifier -o - %s | llvm-dwarfdump - | FileCheck %s -check-prefixes=CHECK-DWARF5 +## === DWARF3, tune for gdb === +# RUN: llc -emit-call-site-info -dwarf-version 3 -debugger-tune=gdb -filetype=obj \ +# RUN: -mtriple=x86_64-unknown-unknown -start-after=machineverifier -o - %s \ +# RUN: | llvm-dwarfdump - | FileCheck %s -implicit-check-not=DW_AT_call + +## === DWARF3, tune for lldb === +# RUN: llc -dwarf-version 3 -debugger-tune=lldb -emit-call-site-info -filetype=obj \ +# RUN: -mtriple=x86_64-unknown-unknown -start-after=machineverifier -o - %s \ +# RUN: | llvm-dwarfdump - | FileCheck %s -implicit-check-not=DW_AT_GNU_call + +## === DWARF3, tune for sce === +# RUN: llc -emit-call-site-info -dwarf-version 3 -filetype=obj -debugger-tune=sce \ +# RUN: -debug-entry-values -mtriple=x86_64-unknown-unknown \ +# RUN: -start-after=machineverifier -o - %s | llvm-dwarfdump - | FileCheck %s -implicit-check-not=DW_AT_call + ## This is based on the following reproducer: ## ## extern void fn(); From 09cd5a86733a362f12542a11ffd834cac885eb32 Mon Sep 17 00:00:00 2001 From: Timm Baeder Date: Fri, 27 Sep 2024 05:56:12 +0200 Subject: [PATCH 039/469] [clang][bytecode] Refuse to contruct objects with virtual bases (#110142) --- clang/lib/AST/ByteCode/Interp.cpp | 22 ++++++++++++++++++++++ clang/test/AST/ByteCode/cxx23.cpp | 15 +++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/clang/lib/AST/ByteCode/Interp.cpp b/clang/lib/AST/ByteCode/Interp.cpp index 2f4a05a85753c..c43f64901909c 100644 --- a/clang/lib/AST/ByteCode/Interp.cpp +++ b/clang/lib/AST/ByteCode/Interp.cpp @@ -1043,6 +1043,25 @@ bool CheckLiteralType(InterpState &S, CodePtr OpPC, const Type *T) { return false; } +static bool checkConstructor(InterpState &S, CodePtr OpPC, const Function *Func, + const Pointer &ThisPtr) { + assert(Func->isConstructor()); + + const Descriptor *D = ThisPtr.getFieldDesc(); + + // FIXME: I think this case is not 100% correct. E.g. a pointer into a + // subobject of a composite array. + if (!D->ElemRecord) + return true; + + if (D->ElemRecord->getNumVirtualBases() == 0) + return true; + + S.FFDiag(S.Current->getLocation(OpPC), diag::note_constexpr_virtual_base) + << Func->getParentDecl(); + return false; +} + bool CallVar(InterpState &S, CodePtr OpPC, const Function *Func, uint32_t VarArgSize) { if (Func->hasThisPointer()) { @@ -1117,6 +1136,9 @@ bool Call(InterpState &S, CodePtr OpPC, const Function *Func, if (!CheckInvoke(S, OpPC, ThisPtr)) return cleanup(); } + + if (Func->isConstructor() && !checkConstructor(S, OpPC, Func, ThisPtr)) + return false; } if (!CheckCallable(S, OpPC, Func)) diff --git a/clang/test/AST/ByteCode/cxx23.cpp b/clang/test/AST/ByteCode/cxx23.cpp index 3c50c8927304c..1803fb8ab2e9a 100644 --- a/clang/test/AST/ByteCode/cxx23.cpp +++ b/clang/test/AST/ByteCode/cxx23.cpp @@ -158,6 +158,21 @@ namespace VirtualBases { /// Calls the constructor of D. D d; } + +#if __cplusplus >= 202302L + struct VBase {}; + struct HasVBase : virtual VBase {}; // all23-note 1{{virtual base class declared here}} + struct Derived : HasVBase { + constexpr Derived() {} // all23-error {{constexpr constructor not allowed in struct with virtual base class}} + }; + template struct DerivedFromVBase : T { + constexpr DerivedFromVBase(); + }; + constexpr int f(DerivedFromVBase) {} + template constexpr DerivedFromVBase::DerivedFromVBase() : T() {} + constexpr int nVBase = (DerivedFromVBase(), 0); // all23-error {{constant expression}} \ + // all23-note {{cannot construct object of type 'DerivedFromVBase' with virtual base class in a constant expression}} +#endif } namespace LabelGoto { From 24bc3244d4e221f4e6740f45e2bf15a1441a3076 Mon Sep 17 00:00:00 2001 From: Louis Dionne Date: Fri, 27 Sep 2024 01:02:21 -0400 Subject: [PATCH 040/469] [libc++][NFC] Rename fold.h to ranges_fold.h (#109696) This follows the pattern we use consistently for ranges algorithms. --- libcxx/include/CMakeLists.txt | 2 +- libcxx/include/__algorithm/{fold.h => ranges_fold.h} | 6 +++--- libcxx/include/algorithm | 2 +- libcxx/include/module.modulemap | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) rename libcxx/include/__algorithm/{fold.h => ranges_fold.h} (97%) diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt index c22590b0ddfdb..bbd5057cff937 100644 --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -23,7 +23,6 @@ set(files __algorithm/find_if.h __algorithm/find_if_not.h __algorithm/find_segment_if.h - __algorithm/fold.h __algorithm/for_each.h __algorithm/for_each_n.h __algorithm/for_each_segment.h @@ -98,6 +97,7 @@ set(files __algorithm/ranges_find_if.h __algorithm/ranges_find_if_not.h __algorithm/ranges_find_last.h + __algorithm/ranges_fold.h __algorithm/ranges_for_each.h __algorithm/ranges_for_each_n.h __algorithm/ranges_generate.h diff --git a/libcxx/include/__algorithm/fold.h b/libcxx/include/__algorithm/ranges_fold.h similarity index 97% rename from libcxx/include/__algorithm/fold.h rename to libcxx/include/__algorithm/ranges_fold.h index 1bcb3be9aadab..d2c3921398504 100644 --- a/libcxx/include/__algorithm/fold.h +++ b/libcxx/include/__algorithm/ranges_fold.h @@ -7,8 +7,8 @@ // //===----------------------------------------------------------------------===// -#ifndef _LIBCPP___ALGORITHM_FOLD_H -#define _LIBCPP___ALGORITHM_FOLD_H +#ifndef _LIBCPP___ALGORITHM_RANGES_FOLD_H +#define _LIBCPP___ALGORITHM_RANGES_FOLD_H #include <__concepts/assignable.h> #include <__concepts/constructible.h> @@ -126,4 +126,4 @@ _LIBCPP_END_NAMESPACE_STD _LIBCPP_POP_MACROS -#endif // _LIBCPP___ALGORITHM_FOLD_H +#endif // _LIBCPP___ALGORITHM_RANGES_FOLD_H diff --git a/libcxx/include/algorithm b/libcxx/include/algorithm index 36fd035b7e51b..17d63ce0cf1c0 100644 --- a/libcxx/include/algorithm +++ b/libcxx/include/algorithm @@ -2020,10 +2020,10 @@ template #endif #if _LIBCPP_STD_VER >= 23 -# include <__algorithm/fold.h> # include <__algorithm/ranges_contains_subrange.h> # include <__algorithm/ranges_ends_with.h> # include <__algorithm/ranges_find_last.h> +# include <__algorithm/ranges_fold.h> # include <__algorithm/ranges_starts_with.h> #endif // _LIBCPP_STD_VER >= 23 diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap index 0c5569e6bd9af..97330aa6ad281 100644 --- a/libcxx/include/module.modulemap +++ b/libcxx/include/module.modulemap @@ -412,7 +412,6 @@ module std [system] { module find_if { header "__algorithm/find_if.h" } module find_segment_if { header "__algorithm/find_segment_if.h" } module find { header "__algorithm/find.h" } - module fold { header "__algorithm/fold.h" } module for_each_n { header "__algorithm/for_each_n.h" } module for_each_segment { header "__algorithm/for_each_segment.h" } module for_each { header "__algorithm/for_each.h" } @@ -529,6 +528,7 @@ module std [system] { module ranges_find_if { header "__algorithm/ranges_find_if.h" } module ranges_find_last { header "__algorithm/ranges_find_last.h" } module ranges_find { header "__algorithm/ranges_find.h" } + module ranges_fold { header "__algorithm/ranges_fold.h" } module ranges_for_each_n { header "__algorithm/ranges_for_each_n.h" export std.algorithm.in_fun_result From 9bdcf7aa18ae8061ebe2209433ddeecac4464bc2 Mon Sep 17 00:00:00 2001 From: Jesse Huang Date: Fri, 27 Sep 2024 13:04:16 +0800 Subject: [PATCH 041/469] [RISCV] Software guard direct calls in large code model (#109377) Support for large code model are added recently, and sementically direct calls are lowered to an indirect branch with a constant pool target. By default it does not use the x7 register and this is suboptimal with Zicfilp because it introduces landing pad check, which is unnecessary since the constant pool is read-only and unlikely to be tampered. Change direct calls and tail calls to use x7 as the scratch register (a.k.a. software guarded branch in the CFI spec) --- llvm/lib/Target/RISCV/RISCVISelLowering.cpp | 23 +- llvm/lib/Target/RISCV/RISCVISelLowering.h | 7 +- llvm/lib/Target/RISCV/RISCVInstrInfo.td | 20 +- llvm/test/CodeGen/RISCV/calls.ll | 157 +++++++++++ llvm/test/CodeGen/RISCV/tail-calls.ll | 272 +++++++++++++++++++- 5 files changed, 470 insertions(+), 9 deletions(-) diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp index d52b802bdd52b..bd796efd836c7 100644 --- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp +++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp @@ -19752,11 +19752,14 @@ SDValue RISCVTargetLowering::LowerCall(CallLoweringInfo &CLI, // If the callee is a GlobalAddress/ExternalSymbol node, turn it into a // TargetGlobalAddress/TargetExternalSymbol node so that legalize won't // split it and then direct call can be matched by PseudoCALL. + bool CalleeIsLargeExternalSymbol = false; if (getTargetMachine().getCodeModel() == CodeModel::Large) { if (auto *S = dyn_cast(Callee)) Callee = getLargeGlobalAddress(S, DL, PtrVT, DAG); - else if (auto *S = dyn_cast(Callee)) + else if (auto *S = dyn_cast(Callee)) { Callee = getLargeExternalSymbol(S, DL, PtrVT, DAG); + CalleeIsLargeExternalSymbol = true; + } } else if (GlobalAddressSDNode *S = dyn_cast(Callee)) { const GlobalValue *GV = S->getGlobal(); Callee = DAG.getTargetGlobalAddress(GV, DL, PtrVT, 0, RISCVII::MO_CALL); @@ -19792,16 +19795,28 @@ SDValue RISCVTargetLowering::LowerCall(CallLoweringInfo &CLI, // Emit the call. SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue); + // Use software guarded branch for large code model non-indirect calls + // Tail call to external symbol will have a null CLI.CB and we need another + // way to determine the callsite type + bool NeedSWGuarded = false; + if (getTargetMachine().getCodeModel() == CodeModel::Large && + Subtarget.hasStdExtZicfilp() && + ((CLI.CB && !CLI.CB->isIndirectCall()) || CalleeIsLargeExternalSymbol)) + NeedSWGuarded = true; + if (IsTailCall) { MF.getFrameInfo().setHasTailCall(); - SDValue Ret = DAG.getNode(RISCVISD::TAIL, DL, NodeTys, Ops); + unsigned CallOpc = + NeedSWGuarded ? RISCVISD::SW_GUARDED_TAIL : RISCVISD::TAIL; + SDValue Ret = DAG.getNode(CallOpc, DL, NodeTys, Ops); if (CLI.CFIType) Ret.getNode()->setCFIType(CLI.CFIType->getZExtValue()); DAG.addNoMergeSiteInfo(Ret.getNode(), CLI.NoMerge); return Ret; } - Chain = DAG.getNode(RISCVISD::CALL, DL, NodeTys, Ops); + unsigned CallOpc = NeedSWGuarded ? RISCVISD::SW_GUARDED_CALL : RISCVISD::CALL; + Chain = DAG.getNode(CallOpc, DL, NodeTys, Ops); if (CLI.CFIType) Chain.getNode()->setCFIType(CLI.CFIType->getZExtValue()); DAG.addNoMergeSiteInfo(Chain.getNode(), CLI.NoMerge); @@ -20249,6 +20264,8 @@ const char *RISCVTargetLowering::getTargetNodeName(unsigned Opcode) const { NODE_NAME_CASE(CZERO_EQZ) NODE_NAME_CASE(CZERO_NEZ) NODE_NAME_CASE(SW_GUARDED_BRIND) + NODE_NAME_CASE(SW_GUARDED_CALL) + NODE_NAME_CASE(SW_GUARDED_TAIL) NODE_NAME_CASE(TUPLE_INSERT) NODE_NAME_CASE(TUPLE_EXTRACT) NODE_NAME_CASE(SF_VC_XV_SE) diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.h b/llvm/lib/Target/RISCV/RISCVISelLowering.h index ceb9d49900284..05581552ab604 100644 --- a/llvm/lib/Target/RISCV/RISCVISelLowering.h +++ b/llvm/lib/Target/RISCV/RISCVISelLowering.h @@ -411,9 +411,12 @@ enum NodeType : unsigned { CZERO_EQZ, // vt.maskc for XVentanaCondOps. CZERO_NEZ, // vt.maskcn for XVentanaCondOps. - /// Software guarded BRIND node. Operand 0 is the chain operand and - /// operand 1 is the target address. + // Software guarded BRIND node. Operand 0 is the chain operand and + // operand 1 is the target address. SW_GUARDED_BRIND, + // Software guarded calls for large code model + SW_GUARDED_CALL, + SW_GUARDED_TAIL, SF_VC_XV_SE, SF_VC_IV_SE, diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.td b/llvm/lib/Target/RISCV/RISCVInstrInfo.td index fe5623e2920e2..ed1b3227748a1 100644 --- a/llvm/lib/Target/RISCV/RISCVInstrInfo.td +++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.td @@ -57,6 +57,9 @@ def callseq_end : SDNode<"ISD::CALLSEQ_END", SDT_CallSeqEnd, def riscv_call : SDNode<"RISCVISD::CALL", SDT_RISCVCall, [SDNPHasChain, SDNPOptInGlue, SDNPOutGlue, SDNPVariadic]>; +def riscv_sw_guarded_call : SDNode<"RISCVISD::SW_GUARDED_CALL", SDT_RISCVCall, + [SDNPHasChain, SDNPOptInGlue, SDNPOutGlue, + SDNPVariadic]>; def riscv_ret_glue : SDNode<"RISCVISD::RET_GLUE", SDTNone, [SDNPHasChain, SDNPOptInGlue, SDNPVariadic]>; def riscv_sret_glue : SDNode<"RISCVISD::SRET_GLUE", SDTNone, @@ -69,6 +72,9 @@ def riscv_brcc : SDNode<"RISCVISD::BR_CC", SDT_RISCVBrCC, def riscv_tail : SDNode<"RISCVISD::TAIL", SDT_RISCVCall, [SDNPHasChain, SDNPOptInGlue, SDNPOutGlue, SDNPVariadic]>; +def riscv_sw_guarded_tail : SDNode<"RISCVISD::SW_GUARDED_TAIL", SDT_RISCVCall, + [SDNPHasChain, SDNPOptInGlue, SDNPOutGlue, + SDNPVariadic]>; def riscv_sw_guarded_brind : SDNode<"RISCVISD::SW_GUARDED_BRIND", SDTBrind, [SDNPHasChain]>; def riscv_sllw : SDNode<"RISCVISD::SLLW", SDT_RISCVIntBinOpW>; @@ -1555,10 +1561,15 @@ let Predicates = [NoStdExtZicfilp] in def PseudoCALLIndirect : Pseudo<(outs), (ins GPRJALR:$rs1), [(riscv_call GPRJALR:$rs1)]>, PseudoInstExpansion<(JALR X1, GPR:$rs1, 0)>; -let Predicates = [HasStdExtZicfilp] in +let Predicates = [HasStdExtZicfilp] in { def PseudoCALLIndirectNonX7 : Pseudo<(outs), (ins GPRJALRNonX7:$rs1), [(riscv_call GPRJALRNonX7:$rs1)]>, PseudoInstExpansion<(JALR X1, GPR:$rs1, 0)>; +// For large code model, non-indirect calls could be software-guarded +def PseudoCALLIndirectX7 : Pseudo<(outs), (ins GPRX7:$rs1), + [(riscv_sw_guarded_call GPRX7:$rs1)]>, + PseudoInstExpansion<(JALR X1, GPR:$rs1, 0)>; +} } let isBarrier = 1, isReturn = 1, isTerminator = 1 in @@ -1579,10 +1590,15 @@ let Predicates = [NoStdExtZicfilp] in def PseudoTAILIndirect : Pseudo<(outs), (ins GPRTC:$rs1), [(riscv_tail GPRTC:$rs1)]>, PseudoInstExpansion<(JALR X0, GPR:$rs1, 0)>; -let Predicates = [HasStdExtZicfilp] in +let Predicates = [HasStdExtZicfilp] in { def PseudoTAILIndirectNonX7 : Pseudo<(outs), (ins GPRTCNonX7:$rs1), [(riscv_tail GPRTCNonX7:$rs1)]>, PseudoInstExpansion<(JALR X0, GPR:$rs1, 0)>; +// For large code model, non-indirect calls could be software-guarded +def PseudoTAILIndirectX7 : Pseudo<(outs), (ins GPRX7:$rs1), + [(riscv_sw_guarded_tail GPRX7:$rs1)]>, + PseudoInstExpansion<(JALR X0, GPR:$rs1, 0)>; +} } def : Pat<(riscv_tail (iPTR tglobaladdr:$dst)), diff --git a/llvm/test/CodeGen/RISCV/calls.ll b/llvm/test/CodeGen/RISCV/calls.ll index 598a026fb9552..f18bbb4ed84ee 100644 --- a/llvm/test/CodeGen/RISCV/calls.ll +++ b/llvm/test/CodeGen/RISCV/calls.ll @@ -11,6 +11,8 @@ ; RUN: | FileCheck -check-prefix=RV64I-MEDIUM %s ; RUN: llc -code-model=large -mtriple=riscv64 -verify-machineinstrs < %s \ ; RUN: | FileCheck -check-prefix=RV64I-LARGE %s +; RUN: llc -code-model=large -mtriple=riscv64 -mattr=experimental-zicfilp -verify-machineinstrs < %s \ +; RUN: | FileCheck -check-prefix=RV64I-LARGE-ZICFILP %s declare i32 @external_function(i32) @@ -62,6 +64,19 @@ define i32 @test_call_external(i32 %a) nounwind { ; RV64I-LARGE-NEXT: ld ra, 8(sp) # 8-byte Folded Reload ; RV64I-LARGE-NEXT: addi sp, sp, 16 ; RV64I-LARGE-NEXT: ret +; +; RV64I-LARGE-ZICFILP-LABEL: test_call_external: +; RV64I-LARGE-ZICFILP: # %bb.0: +; RV64I-LARGE-ZICFILP-NEXT: lpad 0 +; RV64I-LARGE-ZICFILP-NEXT: addi sp, sp, -16 +; RV64I-LARGE-ZICFILP-NEXT: sd ra, 8(sp) # 8-byte Folded Spill +; RV64I-LARGE-ZICFILP-NEXT: .Lpcrel_hi0: +; RV64I-LARGE-ZICFILP-NEXT: auipc a1, %pcrel_hi(.LCPI0_0) +; RV64I-LARGE-ZICFILP-NEXT: ld t2, %pcrel_lo(.Lpcrel_hi0)(a1) +; RV64I-LARGE-ZICFILP-NEXT: jalr t2 +; RV64I-LARGE-ZICFILP-NEXT: ld ra, 8(sp) # 8-byte Folded Reload +; RV64I-LARGE-ZICFILP-NEXT: addi sp, sp, 16 +; RV64I-LARGE-ZICFILP-NEXT: ret %1 = call i32 @external_function(i32 %a) ret i32 %1 } @@ -116,6 +131,19 @@ define i32 @test_call_dso_local(i32 %a) nounwind { ; RV64I-LARGE-NEXT: ld ra, 8(sp) # 8-byte Folded Reload ; RV64I-LARGE-NEXT: addi sp, sp, 16 ; RV64I-LARGE-NEXT: ret +; +; RV64I-LARGE-ZICFILP-LABEL: test_call_dso_local: +; RV64I-LARGE-ZICFILP: # %bb.0: +; RV64I-LARGE-ZICFILP-NEXT: lpad 0 +; RV64I-LARGE-ZICFILP-NEXT: addi sp, sp, -16 +; RV64I-LARGE-ZICFILP-NEXT: sd ra, 8(sp) # 8-byte Folded Spill +; RV64I-LARGE-ZICFILP-NEXT: .Lpcrel_hi1: +; RV64I-LARGE-ZICFILP-NEXT: auipc a1, %pcrel_hi(.LCPI1_0) +; RV64I-LARGE-ZICFILP-NEXT: ld t2, %pcrel_lo(.Lpcrel_hi1)(a1) +; RV64I-LARGE-ZICFILP-NEXT: jalr t2 +; RV64I-LARGE-ZICFILP-NEXT: ld ra, 8(sp) # 8-byte Folded Reload +; RV64I-LARGE-ZICFILP-NEXT: addi sp, sp, 16 +; RV64I-LARGE-ZICFILP-NEXT: ret %1 = call i32 @dso_local_function(i32 %a) ret i32 %1 } @@ -145,6 +173,12 @@ define i32 @defined_function(i32 %a) nounwind { ; RV64I-LARGE: # %bb.0: ; RV64I-LARGE-NEXT: addiw a0, a0, 1 ; RV64I-LARGE-NEXT: ret +; +; RV64I-LARGE-ZICFILP-LABEL: defined_function: +; RV64I-LARGE-ZICFILP: # %bb.0: +; RV64I-LARGE-ZICFILP-NEXT: lpad 0 +; RV64I-LARGE-ZICFILP-NEXT: addiw a0, a0, 1 +; RV64I-LARGE-ZICFILP-NEXT: ret %1 = add i32 %a, 1 ret i32 %1 } @@ -197,6 +231,19 @@ define i32 @test_call_defined(i32 %a) nounwind { ; RV64I-LARGE-NEXT: ld ra, 8(sp) # 8-byte Folded Reload ; RV64I-LARGE-NEXT: addi sp, sp, 16 ; RV64I-LARGE-NEXT: ret +; +; RV64I-LARGE-ZICFILP-LABEL: test_call_defined: +; RV64I-LARGE-ZICFILP: # %bb.0: +; RV64I-LARGE-ZICFILP-NEXT: lpad 0 +; RV64I-LARGE-ZICFILP-NEXT: addi sp, sp, -16 +; RV64I-LARGE-ZICFILP-NEXT: sd ra, 8(sp) # 8-byte Folded Spill +; RV64I-LARGE-ZICFILP-NEXT: .Lpcrel_hi2: +; RV64I-LARGE-ZICFILP-NEXT: auipc a1, %pcrel_hi(.LCPI3_0) +; RV64I-LARGE-ZICFILP-NEXT: ld t2, %pcrel_lo(.Lpcrel_hi2)(a1) +; RV64I-LARGE-ZICFILP-NEXT: jalr t2 +; RV64I-LARGE-ZICFILP-NEXT: ld ra, 8(sp) # 8-byte Folded Reload +; RV64I-LARGE-ZICFILP-NEXT: addi sp, sp, 16 +; RV64I-LARGE-ZICFILP-NEXT: ret %1 = call i32 @defined_function(i32 %a) ret i32 %1 } @@ -256,6 +303,18 @@ define i32 @test_call_indirect(ptr %a, i32 %b) nounwind { ; RV64I-LARGE-NEXT: ld ra, 8(sp) # 8-byte Folded Reload ; RV64I-LARGE-NEXT: addi sp, sp, 16 ; RV64I-LARGE-NEXT: ret +; +; RV64I-LARGE-ZICFILP-LABEL: test_call_indirect: +; RV64I-LARGE-ZICFILP: # %bb.0: +; RV64I-LARGE-ZICFILP-NEXT: lpad 0 +; RV64I-LARGE-ZICFILP-NEXT: addi sp, sp, -16 +; RV64I-LARGE-ZICFILP-NEXT: sd ra, 8(sp) # 8-byte Folded Spill +; RV64I-LARGE-ZICFILP-NEXT: mv a2, a0 +; RV64I-LARGE-ZICFILP-NEXT: mv a0, a1 +; RV64I-LARGE-ZICFILP-NEXT: jalr a2 +; RV64I-LARGE-ZICFILP-NEXT: ld ra, 8(sp) # 8-byte Folded Reload +; RV64I-LARGE-ZICFILP-NEXT: addi sp, sp, 16 +; RV64I-LARGE-ZICFILP-NEXT: ret %1 = call i32 %a(i32 %b) ret i32 %1 } @@ -347,6 +406,24 @@ define i32 @test_call_indirect_no_t0(ptr %a, i32 %b, i32 %c, i32 %d, i32 %e, i32 ; RV64I-LARGE-NEXT: ld ra, 8(sp) # 8-byte Folded Reload ; RV64I-LARGE-NEXT: addi sp, sp, 16 ; RV64I-LARGE-NEXT: ret +; +; RV64I-LARGE-ZICFILP-LABEL: test_call_indirect_no_t0: +; RV64I-LARGE-ZICFILP: # %bb.0: +; RV64I-LARGE-ZICFILP-NEXT: lpad 0 +; RV64I-LARGE-ZICFILP-NEXT: addi sp, sp, -16 +; RV64I-LARGE-ZICFILP-NEXT: sd ra, 8(sp) # 8-byte Folded Spill +; RV64I-LARGE-ZICFILP-NEXT: mv t1, a0 +; RV64I-LARGE-ZICFILP-NEXT: mv a0, a1 +; RV64I-LARGE-ZICFILP-NEXT: mv a1, a2 +; RV64I-LARGE-ZICFILP-NEXT: mv a2, a3 +; RV64I-LARGE-ZICFILP-NEXT: mv a3, a4 +; RV64I-LARGE-ZICFILP-NEXT: mv a4, a5 +; RV64I-LARGE-ZICFILP-NEXT: mv a5, a6 +; RV64I-LARGE-ZICFILP-NEXT: mv a6, a7 +; RV64I-LARGE-ZICFILP-NEXT: jalr t1 +; RV64I-LARGE-ZICFILP-NEXT: ld ra, 8(sp) # 8-byte Folded Reload +; RV64I-LARGE-ZICFILP-NEXT: addi sp, sp, 16 +; RV64I-LARGE-ZICFILP-NEXT: ret %1 = call i32 %a(i32 %b, i32 %c, i32 %d, i32 %e, i32 %f, i32 %g, i32 %h) ret i32 %1 } @@ -379,6 +456,12 @@ define fastcc i32 @fastcc_function(i32 %a, i32 %b) nounwind { ; RV64I-LARGE: # %bb.0: ; RV64I-LARGE-NEXT: addw a0, a0, a1 ; RV64I-LARGE-NEXT: ret +; +; RV64I-LARGE-ZICFILP-LABEL: fastcc_function: +; RV64I-LARGE-ZICFILP: # %bb.0: +; RV64I-LARGE-ZICFILP-NEXT: lpad 0 +; RV64I-LARGE-ZICFILP-NEXT: addw a0, a0, a1 +; RV64I-LARGE-ZICFILP-NEXT: ret %1 = add i32 %a, %b ret i32 %1 } @@ -452,6 +535,24 @@ define i32 @test_call_fastcc(i32 %a, i32 %b) nounwind { ; RV64I-LARGE-NEXT: ld s0, 0(sp) # 8-byte Folded Reload ; RV64I-LARGE-NEXT: addi sp, sp, 16 ; RV64I-LARGE-NEXT: ret +; +; RV64I-LARGE-ZICFILP-LABEL: test_call_fastcc: +; RV64I-LARGE-ZICFILP: # %bb.0: +; RV64I-LARGE-ZICFILP-NEXT: lpad 0 +; RV64I-LARGE-ZICFILP-NEXT: addi sp, sp, -16 +; RV64I-LARGE-ZICFILP-NEXT: sd ra, 8(sp) # 8-byte Folded Spill +; RV64I-LARGE-ZICFILP-NEXT: sd s0, 0(sp) # 8-byte Folded Spill +; RV64I-LARGE-ZICFILP-NEXT: mv s0, a0 +; RV64I-LARGE-ZICFILP-NEXT: .Lpcrel_hi3: +; RV64I-LARGE-ZICFILP-NEXT: auipc a0, %pcrel_hi(.LCPI7_0) +; RV64I-LARGE-ZICFILP-NEXT: ld t2, %pcrel_lo(.Lpcrel_hi3)(a0) +; RV64I-LARGE-ZICFILP-NEXT: mv a0, s0 +; RV64I-LARGE-ZICFILP-NEXT: jalr t2 +; RV64I-LARGE-ZICFILP-NEXT: mv a0, s0 +; RV64I-LARGE-ZICFILP-NEXT: ld ra, 8(sp) # 8-byte Folded Reload +; RV64I-LARGE-ZICFILP-NEXT: ld s0, 0(sp) # 8-byte Folded Reload +; RV64I-LARGE-ZICFILP-NEXT: addi sp, sp, 16 +; RV64I-LARGE-ZICFILP-NEXT: ret %1 = call fastcc i32 @fastcc_function(i32 %a, i32 %b) ret i32 %a } @@ -572,6 +673,33 @@ define i32 @test_call_external_many_args(i32 %a) nounwind { ; RV64I-LARGE-NEXT: ld s0, 16(sp) # 8-byte Folded Reload ; RV64I-LARGE-NEXT: addi sp, sp, 32 ; RV64I-LARGE-NEXT: ret +; +; RV64I-LARGE-ZICFILP-LABEL: test_call_external_many_args: +; RV64I-LARGE-ZICFILP: # %bb.0: +; RV64I-LARGE-ZICFILP-NEXT: lpad 0 +; RV64I-LARGE-ZICFILP-NEXT: addi sp, sp, -32 +; RV64I-LARGE-ZICFILP-NEXT: sd ra, 24(sp) # 8-byte Folded Spill +; RV64I-LARGE-ZICFILP-NEXT: sd s0, 16(sp) # 8-byte Folded Spill +; RV64I-LARGE-ZICFILP-NEXT: mv s0, a0 +; RV64I-LARGE-ZICFILP-NEXT: .Lpcrel_hi4: +; RV64I-LARGE-ZICFILP-NEXT: auipc a0, %pcrel_hi(.LCPI8_0) +; RV64I-LARGE-ZICFILP-NEXT: ld t2, %pcrel_lo(.Lpcrel_hi4)(a0) +; RV64I-LARGE-ZICFILP-NEXT: sd s0, 8(sp) +; RV64I-LARGE-ZICFILP-NEXT: sd s0, 0(sp) +; RV64I-LARGE-ZICFILP-NEXT: mv a0, s0 +; RV64I-LARGE-ZICFILP-NEXT: mv a1, s0 +; RV64I-LARGE-ZICFILP-NEXT: mv a2, s0 +; RV64I-LARGE-ZICFILP-NEXT: mv a3, s0 +; RV64I-LARGE-ZICFILP-NEXT: mv a4, s0 +; RV64I-LARGE-ZICFILP-NEXT: mv a5, s0 +; RV64I-LARGE-ZICFILP-NEXT: mv a6, s0 +; RV64I-LARGE-ZICFILP-NEXT: mv a7, s0 +; RV64I-LARGE-ZICFILP-NEXT: jalr t2 +; RV64I-LARGE-ZICFILP-NEXT: mv a0, s0 +; RV64I-LARGE-ZICFILP-NEXT: ld ra, 24(sp) # 8-byte Folded Reload +; RV64I-LARGE-ZICFILP-NEXT: ld s0, 16(sp) # 8-byte Folded Reload +; RV64I-LARGE-ZICFILP-NEXT: addi sp, sp, 32 +; RV64I-LARGE-ZICFILP-NEXT: ret %1 = call i32 @external_many_args(i32 %a, i32 %a, i32 %a, i32 %a, i32 %a, i32 %a, i32 %a, i32 %a, i32 %a, i32 %a) ret i32 %a @@ -607,6 +735,13 @@ define i32 @defined_many_args(i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 % ; RV64I-LARGE-NEXT: lw a0, 8(sp) ; RV64I-LARGE-NEXT: addiw a0, a0, 1 ; RV64I-LARGE-NEXT: ret +; +; RV64I-LARGE-ZICFILP-LABEL: defined_many_args: +; RV64I-LARGE-ZICFILP: # %bb.0: +; RV64I-LARGE-ZICFILP-NEXT: lpad 0 +; RV64I-LARGE-ZICFILP-NEXT: lw a0, 8(sp) +; RV64I-LARGE-ZICFILP-NEXT: addiw a0, a0, 1 +; RV64I-LARGE-ZICFILP-NEXT: ret %added = add i32 %j, 1 ret i32 %added } @@ -704,6 +839,28 @@ define i32 @test_call_defined_many_args(i32 %a) nounwind { ; RV64I-LARGE-NEXT: ld ra, 24(sp) # 8-byte Folded Reload ; RV64I-LARGE-NEXT: addi sp, sp, 32 ; RV64I-LARGE-NEXT: ret +; +; RV64I-LARGE-ZICFILP-LABEL: test_call_defined_many_args: +; RV64I-LARGE-ZICFILP: # %bb.0: +; RV64I-LARGE-ZICFILP-NEXT: lpad 0 +; RV64I-LARGE-ZICFILP-NEXT: addi sp, sp, -32 +; RV64I-LARGE-ZICFILP-NEXT: sd ra, 24(sp) # 8-byte Folded Spill +; RV64I-LARGE-ZICFILP-NEXT: .Lpcrel_hi5: +; RV64I-LARGE-ZICFILP-NEXT: auipc a1, %pcrel_hi(.LCPI10_0) +; RV64I-LARGE-ZICFILP-NEXT: ld t2, %pcrel_lo(.Lpcrel_hi5)(a1) +; RV64I-LARGE-ZICFILP-NEXT: sd a0, 8(sp) +; RV64I-LARGE-ZICFILP-NEXT: sd a0, 0(sp) +; RV64I-LARGE-ZICFILP-NEXT: mv a1, a0 +; RV64I-LARGE-ZICFILP-NEXT: mv a2, a0 +; RV64I-LARGE-ZICFILP-NEXT: mv a3, a0 +; RV64I-LARGE-ZICFILP-NEXT: mv a4, a0 +; RV64I-LARGE-ZICFILP-NEXT: mv a5, a0 +; RV64I-LARGE-ZICFILP-NEXT: mv a6, a0 +; RV64I-LARGE-ZICFILP-NEXT: mv a7, a0 +; RV64I-LARGE-ZICFILP-NEXT: jalr t2 +; RV64I-LARGE-ZICFILP-NEXT: ld ra, 24(sp) # 8-byte Folded Reload +; RV64I-LARGE-ZICFILP-NEXT: addi sp, sp, 32 +; RV64I-LARGE-ZICFILP-NEXT: ret %1 = call i32 @defined_many_args(i32 %a, i32 %a, i32 %a, i32 %a, i32 %a, i32 %a, i32 %a, i32 %a, i32 %a, i32 %a) ret i32 %1 diff --git a/llvm/test/CodeGen/RISCV/tail-calls.ll b/llvm/test/CodeGen/RISCV/tail-calls.ll index d3e495bb723ad..4dd6ed68ff981 100644 --- a/llvm/test/CodeGen/RISCV/tail-calls.ll +++ b/llvm/test/CodeGen/RISCV/tail-calls.ll @@ -1,5 +1,8 @@ ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py ; RUN: llc -mtriple riscv32-unknown-linux-gnu -o - %s | FileCheck %s +; RUN: llc -mtriple riscv32-unknown-linux-gnu -mattr=experimental-zicfilp \ +; RUN: -code-model=large -o - %s \ +; RUN: | FileCheck %s -check-prefix=CHECK-LARGE-ZICFILP ; RUN: llc -mtriple riscv32-unknown-elf -o - %s | FileCheck %s ; Perform tail call optimization for global address. @@ -8,6 +11,14 @@ define i32 @caller_tail(i32 %i) nounwind { ; CHECK-LABEL: caller_tail: ; CHECK: # %bb.0: # %entry ; CHECK-NEXT: tail callee_tail +; +; CHECK-LARGE-ZICFILP-LABEL: caller_tail: +; CHECK-LARGE-ZICFILP: # %bb.0: # %entry +; CHECK-LARGE-ZICFILP-NEXT: lpad 0 +; CHECK-LARGE-ZICFILP-NEXT: .Lpcrel_hi0: +; CHECK-LARGE-ZICFILP-NEXT: auipc a1, %pcrel_hi(.LCPI0_0) +; CHECK-LARGE-ZICFILP-NEXT: lw t2, %pcrel_lo(.Lpcrel_hi0)(a1) +; CHECK-LARGE-ZICFILP-NEXT: jr t2 entry: %r = tail call i32 @callee_tail(i32 %i) ret i32 %r @@ -26,6 +37,21 @@ define void @caller_extern(ptr %src) optsize { ; CHECK-NEXT: mv a0, a1 ; CHECK-NEXT: mv a1, a3 ; CHECK-NEXT: tail memcpy +; +; CHECK-LARGE-ZICFILP-LABEL: caller_extern: +; CHECK-LARGE-ZICFILP: # %bb.0: # %entry +; CHECK-LARGE-ZICFILP-NEXT: lpad 0 +; CHECK-LARGE-ZICFILP-NEXT: .Lpcrel_hi1: +; CHECK-LARGE-ZICFILP-NEXT: auipc a1, %pcrel_hi(.LCPI1_0) +; CHECK-LARGE-ZICFILP-NEXT: lw a1, %pcrel_lo(.Lpcrel_hi1)(a1) +; CHECK-LARGE-ZICFILP-NEXT: .Lpcrel_hi2: +; CHECK-LARGE-ZICFILP-NEXT: auipc a2, %pcrel_hi(.LCPI1_1) +; CHECK-LARGE-ZICFILP-NEXT: lw t2, %pcrel_lo(.Lpcrel_hi2)(a2) +; CHECK-LARGE-ZICFILP-NEXT: li a2, 7 +; CHECK-LARGE-ZICFILP-NEXT: mv a3, a0 +; CHECK-LARGE-ZICFILP-NEXT: mv a0, a1 +; CHECK-LARGE-ZICFILP-NEXT: mv a1, a3 +; CHECK-LARGE-ZICFILP-NEXT: jr t2 entry: tail call void @llvm.memcpy.p0.p0.i32(ptr @dest, ptr %src, i32 7, i1 false) ret void @@ -43,6 +69,21 @@ define void @caller_extern_pgso(ptr %src) !prof !14 { ; CHECK-NEXT: mv a0, a1 ; CHECK-NEXT: mv a1, a3 ; CHECK-NEXT: tail memcpy +; +; CHECK-LARGE-ZICFILP-LABEL: caller_extern_pgso: +; CHECK-LARGE-ZICFILP: # %bb.0: # %entry +; CHECK-LARGE-ZICFILP-NEXT: lpad 0 +; CHECK-LARGE-ZICFILP-NEXT: .Lpcrel_hi3: +; CHECK-LARGE-ZICFILP-NEXT: auipc a1, %pcrel_hi(.LCPI2_0) +; CHECK-LARGE-ZICFILP-NEXT: lw a1, %pcrel_lo(.Lpcrel_hi3)(a1) +; CHECK-LARGE-ZICFILP-NEXT: .Lpcrel_hi4: +; CHECK-LARGE-ZICFILP-NEXT: auipc a2, %pcrel_hi(.LCPI2_1) +; CHECK-LARGE-ZICFILP-NEXT: lw t2, %pcrel_lo(.Lpcrel_hi4)(a2) +; CHECK-LARGE-ZICFILP-NEXT: li a2, 7 +; CHECK-LARGE-ZICFILP-NEXT: mv a3, a0 +; CHECK-LARGE-ZICFILP-NEXT: mv a0, a1 +; CHECK-LARGE-ZICFILP-NEXT: mv a1, a3 +; CHECK-LARGE-ZICFILP-NEXT: jr t2 entry: tail call void @llvm.memcpy.p0.p0.i32(ptr @dest_pgso, ptr %src, i32 7, i1 false) ret void @@ -63,8 +104,21 @@ define void @caller_indirect_tail(i32 %a) nounwind { ; CHECK-NEXT: lui t1, %hi(callee_indirect1) ; CHECK-NEXT: addi t1, t1, %lo(callee_indirect1) ; CHECK-NEXT: jr t1 - - +; +; CHECK-LARGE-ZICFILP-LABEL: caller_indirect_tail: +; CHECK-LARGE-ZICFILP: # %bb.0: # %entry +; CHECK-LARGE-ZICFILP-NEXT: lpad 0 +; CHECK-LARGE-ZICFILP-NEXT: beqz a0, .LBB3_2 +; CHECK-LARGE-ZICFILP-NEXT: # %bb.1: # %entry +; CHECK-LARGE-ZICFILP-NEXT: .Lpcrel_hi6: +; CHECK-LARGE-ZICFILP-NEXT: auipc a0, %pcrel_hi(.LCPI3_0) +; CHECK-LARGE-ZICFILP-NEXT: lw t1, %pcrel_lo(.Lpcrel_hi6)(a0) +; CHECK-LARGE-ZICFILP-NEXT: jr t1 +; CHECK-LARGE-ZICFILP-NEXT: .LBB3_2: +; CHECK-LARGE-ZICFILP-NEXT: .Lpcrel_hi5: +; CHECK-LARGE-ZICFILP-NEXT: auipc a0, %pcrel_hi(.LCPI3_1) +; CHECK-LARGE-ZICFILP-NEXT: lw t1, %pcrel_lo(.Lpcrel_hi5)(a0) +; CHECK-LARGE-ZICFILP-NEXT: jr t1 entry: %tobool = icmp eq i32 %a, 0 %callee = select i1 %tobool, ptr @callee_indirect1, ptr @callee_indirect2 @@ -86,6 +140,19 @@ define i32 @caller_indirect_no_t0(ptr %0, i32 %1, i32 %2, i32 %3, i32 %4, i32 %5 ; CHECK-NEXT: mv a5, a6 ; CHECK-NEXT: mv a6, a7 ; CHECK-NEXT: jr t1 +; +; CHECK-LARGE-ZICFILP-LABEL: caller_indirect_no_t0: +; CHECK-LARGE-ZICFILP: # %bb.0: +; CHECK-LARGE-ZICFILP-NEXT: lpad 0 +; CHECK-LARGE-ZICFILP-NEXT: mv t1, a0 +; CHECK-LARGE-ZICFILP-NEXT: mv a0, a1 +; CHECK-LARGE-ZICFILP-NEXT: mv a1, a2 +; CHECK-LARGE-ZICFILP-NEXT: mv a2, a3 +; CHECK-LARGE-ZICFILP-NEXT: mv a3, a4 +; CHECK-LARGE-ZICFILP-NEXT: mv a4, a5 +; CHECK-LARGE-ZICFILP-NEXT: mv a5, a6 +; CHECK-LARGE-ZICFILP-NEXT: mv a6, a7 +; CHECK-LARGE-ZICFILP-NEXT: jr t1 %9 = tail call i32 %0(i32 %1, i32 %2, i32 %3, i32 %4, i32 %5, i32 %6, i32 %7) ret i32 %9 } @@ -108,6 +175,26 @@ define void @caller_varargs(i32 %a, i32 %b) nounwind { ; CHECK-NEXT: lw ra, 12(sp) # 4-byte Folded Reload ; CHECK-NEXT: addi sp, sp, 16 ; CHECK-NEXT: ret +; +; CHECK-LARGE-ZICFILP-LABEL: caller_varargs: +; CHECK-LARGE-ZICFILP: # %bb.0: # %entry +; CHECK-LARGE-ZICFILP-NEXT: lpad 0 +; CHECK-LARGE-ZICFILP-NEXT: addi sp, sp, -16 +; CHECK-LARGE-ZICFILP-NEXT: sw ra, 12(sp) # 4-byte Folded Spill +; CHECK-LARGE-ZICFILP-NEXT: .Lpcrel_hi7: +; CHECK-LARGE-ZICFILP-NEXT: auipc a2, %pcrel_hi(.LCPI5_0) +; CHECK-LARGE-ZICFILP-NEXT: lw t2, %pcrel_lo(.Lpcrel_hi7)(a2) +; CHECK-LARGE-ZICFILP-NEXT: sw a0, 0(sp) +; CHECK-LARGE-ZICFILP-NEXT: mv a2, a1 +; CHECK-LARGE-ZICFILP-NEXT: mv a3, a0 +; CHECK-LARGE-ZICFILP-NEXT: mv a4, a0 +; CHECK-LARGE-ZICFILP-NEXT: mv a5, a1 +; CHECK-LARGE-ZICFILP-NEXT: mv a6, a1 +; CHECK-LARGE-ZICFILP-NEXT: mv a7, a0 +; CHECK-LARGE-ZICFILP-NEXT: jalr t2 +; CHECK-LARGE-ZICFILP-NEXT: lw ra, 12(sp) # 4-byte Folded Reload +; CHECK-LARGE-ZICFILP-NEXT: addi sp, sp, 16 +; CHECK-LARGE-ZICFILP-NEXT: ret entry: %call = tail call i32 (i32, ...) @callee_varargs(i32 %a, i32 %b, i32 %b, i32 %a, i32 %a, i32 %b, i32 %b, i32 %a, i32 %a) ret void @@ -136,6 +223,31 @@ define i32 @caller_args(i32 %a, i32 %b, i32 %c, i32 %dd, i32 %e, i32 %ff, i32 %g ; CHECK-NEXT: lw ra, 28(sp) # 4-byte Folded Reload ; CHECK-NEXT: addi sp, sp, 32 ; CHECK-NEXT: ret +; +; CHECK-LARGE-ZICFILP-LABEL: caller_args: +; CHECK-LARGE-ZICFILP: # %bb.0: # %entry +; CHECK-LARGE-ZICFILP-NEXT: lpad 0 +; CHECK-LARGE-ZICFILP-NEXT: addi sp, sp, -32 +; CHECK-LARGE-ZICFILP-NEXT: sw ra, 28(sp) # 4-byte Folded Spill +; CHECK-LARGE-ZICFILP-NEXT: lw t0, 32(sp) +; CHECK-LARGE-ZICFILP-NEXT: lw t1, 36(sp) +; CHECK-LARGE-ZICFILP-NEXT: lw t3, 40(sp) +; CHECK-LARGE-ZICFILP-NEXT: lw t4, 44(sp) +; CHECK-LARGE-ZICFILP-NEXT: lw t2, 48(sp) +; CHECK-LARGE-ZICFILP-NEXT: lw t5, 52(sp) +; CHECK-LARGE-ZICFILP-NEXT: sw t5, 20(sp) +; CHECK-LARGE-ZICFILP-NEXT: sw t2, 16(sp) +; CHECK-LARGE-ZICFILP-NEXT: .Lpcrel_hi8: +; CHECK-LARGE-ZICFILP-NEXT: auipc t2, %pcrel_hi(.LCPI6_0) +; CHECK-LARGE-ZICFILP-NEXT: lw t2, %pcrel_lo(.Lpcrel_hi8)(t2) +; CHECK-LARGE-ZICFILP-NEXT: sw t4, 12(sp) +; CHECK-LARGE-ZICFILP-NEXT: sw t3, 8(sp) +; CHECK-LARGE-ZICFILP-NEXT: sw t1, 4(sp) +; CHECK-LARGE-ZICFILP-NEXT: sw t0, 0(sp) +; CHECK-LARGE-ZICFILP-NEXT: jalr t2 +; CHECK-LARGE-ZICFILP-NEXT: lw ra, 28(sp) # 4-byte Folded Reload +; CHECK-LARGE-ZICFILP-NEXT: addi sp, sp, 32 +; CHECK-LARGE-ZICFILP-NEXT: ret entry: %r = tail call i32 @callee_args(i32 %a, i32 %b, i32 %c, i32 %dd, i32 %e, i32 %ff, i32 %g, i32 %h, i32 %i, i32 %j, i32 %k, i32 %l, i32 %m, i32 %n) ret i32 %r @@ -158,6 +270,25 @@ define void @caller_indirect_args() nounwind { ; CHECK-NEXT: lw ra, 28(sp) # 4-byte Folded Reload ; CHECK-NEXT: addi sp, sp, 32 ; CHECK-NEXT: ret +; +; CHECK-LARGE-ZICFILP-LABEL: caller_indirect_args: +; CHECK-LARGE-ZICFILP: # %bb.0: # %entry +; CHECK-LARGE-ZICFILP-NEXT: lpad 0 +; CHECK-LARGE-ZICFILP-NEXT: addi sp, sp, -32 +; CHECK-LARGE-ZICFILP-NEXT: sw ra, 28(sp) # 4-byte Folded Spill +; CHECK-LARGE-ZICFILP-NEXT: lui a0, 262128 +; CHECK-LARGE-ZICFILP-NEXT: sw a0, 12(sp) +; CHECK-LARGE-ZICFILP-NEXT: .Lpcrel_hi9: +; CHECK-LARGE-ZICFILP-NEXT: auipc a0, %pcrel_hi(.LCPI7_0) +; CHECK-LARGE-ZICFILP-NEXT: lw t2, %pcrel_lo(.Lpcrel_hi9)(a0) +; CHECK-LARGE-ZICFILP-NEXT: sw zero, 8(sp) +; CHECK-LARGE-ZICFILP-NEXT: sw zero, 4(sp) +; CHECK-LARGE-ZICFILP-NEXT: mv a0, sp +; CHECK-LARGE-ZICFILP-NEXT: sw zero, 0(sp) +; CHECK-LARGE-ZICFILP-NEXT: jalr t2 +; CHECK-LARGE-ZICFILP-NEXT: lw ra, 28(sp) # 4-byte Folded Reload +; CHECK-LARGE-ZICFILP-NEXT: addi sp, sp, 32 +; CHECK-LARGE-ZICFILP-NEXT: ret entry: %call = tail call i32 @callee_indirect_args(fp128 0xL00000000000000003FFF000000000000) ret void @@ -169,6 +300,14 @@ define void @caller_weak() nounwind { ; CHECK-LABEL: caller_weak: ; CHECK: # %bb.0: # %entry ; CHECK-NEXT: tail callee_weak +; +; CHECK-LARGE-ZICFILP-LABEL: caller_weak: +; CHECK-LARGE-ZICFILP: # %bb.0: # %entry +; CHECK-LARGE-ZICFILP-NEXT: lpad 0 +; CHECK-LARGE-ZICFILP-NEXT: .Lpcrel_hi10: +; CHECK-LARGE-ZICFILP-NEXT: auipc a0, %pcrel_hi(.LCPI8_0) +; CHECK-LARGE-ZICFILP-NEXT: lw t2, %pcrel_lo(.Lpcrel_hi10)(a0) +; CHECK-LARGE-ZICFILP-NEXT: jr t2 entry: tail call void @callee_weak() ret void @@ -217,6 +356,48 @@ define void @caller_irq() nounwind "interrupt"="machine" { ; CHECK-NEXT: lw t6, 0(sp) # 4-byte Folded Reload ; CHECK-NEXT: addi sp, sp, 64 ; CHECK-NEXT: mret +; +; CHECK-LARGE-ZICFILP-LABEL: caller_irq: +; CHECK-LARGE-ZICFILP: # %bb.0: # %entry +; CHECK-LARGE-ZICFILP-NEXT: addi sp, sp, -64 +; CHECK-LARGE-ZICFILP-NEXT: sw ra, 60(sp) # 4-byte Folded Spill +; CHECK-LARGE-ZICFILP-NEXT: sw t0, 56(sp) # 4-byte Folded Spill +; CHECK-LARGE-ZICFILP-NEXT: sw t1, 52(sp) # 4-byte Folded Spill +; CHECK-LARGE-ZICFILP-NEXT: sw t2, 48(sp) # 4-byte Folded Spill +; CHECK-LARGE-ZICFILP-NEXT: sw a0, 44(sp) # 4-byte Folded Spill +; CHECK-LARGE-ZICFILP-NEXT: sw a1, 40(sp) # 4-byte Folded Spill +; CHECK-LARGE-ZICFILP-NEXT: sw a2, 36(sp) # 4-byte Folded Spill +; CHECK-LARGE-ZICFILP-NEXT: sw a3, 32(sp) # 4-byte Folded Spill +; CHECK-LARGE-ZICFILP-NEXT: sw a4, 28(sp) # 4-byte Folded Spill +; CHECK-LARGE-ZICFILP-NEXT: sw a5, 24(sp) # 4-byte Folded Spill +; CHECK-LARGE-ZICFILP-NEXT: sw a6, 20(sp) # 4-byte Folded Spill +; CHECK-LARGE-ZICFILP-NEXT: sw a7, 16(sp) # 4-byte Folded Spill +; CHECK-LARGE-ZICFILP-NEXT: sw t3, 12(sp) # 4-byte Folded Spill +; CHECK-LARGE-ZICFILP-NEXT: sw t4, 8(sp) # 4-byte Folded Spill +; CHECK-LARGE-ZICFILP-NEXT: sw t5, 4(sp) # 4-byte Folded Spill +; CHECK-LARGE-ZICFILP-NEXT: sw t6, 0(sp) # 4-byte Folded Spill +; CHECK-LARGE-ZICFILP-NEXT: .Lpcrel_hi11: +; CHECK-LARGE-ZICFILP-NEXT: auipc a0, %pcrel_hi(.LCPI9_0) +; CHECK-LARGE-ZICFILP-NEXT: lw t2, %pcrel_lo(.Lpcrel_hi11)(a0) +; CHECK-LARGE-ZICFILP-NEXT: jalr t2 +; CHECK-LARGE-ZICFILP-NEXT: lw ra, 60(sp) # 4-byte Folded Reload +; CHECK-LARGE-ZICFILP-NEXT: lw t0, 56(sp) # 4-byte Folded Reload +; CHECK-LARGE-ZICFILP-NEXT: lw t1, 52(sp) # 4-byte Folded Reload +; CHECK-LARGE-ZICFILP-NEXT: lw t2, 48(sp) # 4-byte Folded Reload +; CHECK-LARGE-ZICFILP-NEXT: lw a0, 44(sp) # 4-byte Folded Reload +; CHECK-LARGE-ZICFILP-NEXT: lw a1, 40(sp) # 4-byte Folded Reload +; CHECK-LARGE-ZICFILP-NEXT: lw a2, 36(sp) # 4-byte Folded Reload +; CHECK-LARGE-ZICFILP-NEXT: lw a3, 32(sp) # 4-byte Folded Reload +; CHECK-LARGE-ZICFILP-NEXT: lw a4, 28(sp) # 4-byte Folded Reload +; CHECK-LARGE-ZICFILP-NEXT: lw a5, 24(sp) # 4-byte Folded Reload +; CHECK-LARGE-ZICFILP-NEXT: lw a6, 20(sp) # 4-byte Folded Reload +; CHECK-LARGE-ZICFILP-NEXT: lw a7, 16(sp) # 4-byte Folded Reload +; CHECK-LARGE-ZICFILP-NEXT: lw t3, 12(sp) # 4-byte Folded Reload +; CHECK-LARGE-ZICFILP-NEXT: lw t4, 8(sp) # 4-byte Folded Reload +; CHECK-LARGE-ZICFILP-NEXT: lw t5, 4(sp) # 4-byte Folded Reload +; CHECK-LARGE-ZICFILP-NEXT: lw t6, 0(sp) # 4-byte Folded Reload +; CHECK-LARGE-ZICFILP-NEXT: addi sp, sp, 64 +; CHECK-LARGE-ZICFILP-NEXT: mret entry: tail call void @callee_irq() ret void @@ -238,6 +419,22 @@ define i32 @caller_byval() nounwind { ; CHECK-NEXT: lw ra, 12(sp) # 4-byte Folded Reload ; CHECK-NEXT: addi sp, sp, 16 ; CHECK-NEXT: ret +; +; CHECK-LARGE-ZICFILP-LABEL: caller_byval: +; CHECK-LARGE-ZICFILP: # %bb.0: # %entry +; CHECK-LARGE-ZICFILP-NEXT: lpad 0 +; CHECK-LARGE-ZICFILP-NEXT: addi sp, sp, -16 +; CHECK-LARGE-ZICFILP-NEXT: sw ra, 12(sp) # 4-byte Folded Spill +; CHECK-LARGE-ZICFILP-NEXT: lw a0, 8(sp) +; CHECK-LARGE-ZICFILP-NEXT: sw a0, 4(sp) +; CHECK-LARGE-ZICFILP-NEXT: .Lpcrel_hi12: +; CHECK-LARGE-ZICFILP-NEXT: auipc a0, %pcrel_hi(.LCPI10_0) +; CHECK-LARGE-ZICFILP-NEXT: lw t2, %pcrel_lo(.Lpcrel_hi12)(a0) +; CHECK-LARGE-ZICFILP-NEXT: addi a0, sp, 4 +; CHECK-LARGE-ZICFILP-NEXT: jalr t2 +; CHECK-LARGE-ZICFILP-NEXT: lw ra, 12(sp) # 4-byte Folded Reload +; CHECK-LARGE-ZICFILP-NEXT: addi sp, sp, 16 +; CHECK-LARGE-ZICFILP-NEXT: ret entry: %a = alloca ptr %r = tail call i32 @callee_byval(ptr byval(ptr) %a) @@ -260,6 +457,22 @@ define void @caller_nostruct() nounwind { ; CHECK-NEXT: lw ra, 12(sp) # 4-byte Folded Reload ; CHECK-NEXT: addi sp, sp, 16 ; CHECK-NEXT: ret +; +; CHECK-LARGE-ZICFILP-LABEL: caller_nostruct: +; CHECK-LARGE-ZICFILP: # %bb.0: # %entry +; CHECK-LARGE-ZICFILP-NEXT: lpad 0 +; CHECK-LARGE-ZICFILP-NEXT: addi sp, sp, -16 +; CHECK-LARGE-ZICFILP-NEXT: sw ra, 12(sp) # 4-byte Folded Spill +; CHECK-LARGE-ZICFILP-NEXT: .Lpcrel_hi13: +; CHECK-LARGE-ZICFILP-NEXT: auipc a0, %pcrel_hi(.LCPI11_0) +; CHECK-LARGE-ZICFILP-NEXT: lw a0, %pcrel_lo(.Lpcrel_hi13)(a0) +; CHECK-LARGE-ZICFILP-NEXT: .Lpcrel_hi14: +; CHECK-LARGE-ZICFILP-NEXT: auipc a1, %pcrel_hi(.LCPI11_1) +; CHECK-LARGE-ZICFILP-NEXT: lw t2, %pcrel_lo(.Lpcrel_hi14)(a1) +; CHECK-LARGE-ZICFILP-NEXT: jalr t2 +; CHECK-LARGE-ZICFILP-NEXT: lw ra, 12(sp) # 4-byte Folded Reload +; CHECK-LARGE-ZICFILP-NEXT: addi sp, sp, 16 +; CHECK-LARGE-ZICFILP-NEXT: ret entry: tail call void @callee_struct(ptr sret(%struct.A) @a) ret void @@ -276,6 +489,19 @@ define void @caller_struct(ptr sret(%struct.A) %a) nounwind { ; CHECK-NEXT: lw ra, 12(sp) # 4-byte Folded Reload ; CHECK-NEXT: addi sp, sp, 16 ; CHECK-NEXT: ret +; +; CHECK-LARGE-ZICFILP-LABEL: caller_struct: +; CHECK-LARGE-ZICFILP: # %bb.0: # %entry +; CHECK-LARGE-ZICFILP-NEXT: lpad 0 +; CHECK-LARGE-ZICFILP-NEXT: addi sp, sp, -16 +; CHECK-LARGE-ZICFILP-NEXT: sw ra, 12(sp) # 4-byte Folded Spill +; CHECK-LARGE-ZICFILP-NEXT: .Lpcrel_hi15: +; CHECK-LARGE-ZICFILP-NEXT: auipc a0, %pcrel_hi(.LCPI12_0) +; CHECK-LARGE-ZICFILP-NEXT: lw t2, %pcrel_lo(.Lpcrel_hi15)(a0) +; CHECK-LARGE-ZICFILP-NEXT: jalr t2 +; CHECK-LARGE-ZICFILP-NEXT: lw ra, 12(sp) # 4-byte Folded Reload +; CHECK-LARGE-ZICFILP-NEXT: addi sp, sp, 16 +; CHECK-LARGE-ZICFILP-NEXT: ret entry: tail call void @callee_nostruct() ret void @@ -291,6 +517,19 @@ define i32 @disable_tail_calls(i32 %i) nounwind "disable-tail-calls"="true" { ; CHECK-NEXT: lw ra, 12(sp) # 4-byte Folded Reload ; CHECK-NEXT: addi sp, sp, 16 ; CHECK-NEXT: ret +; +; CHECK-LARGE-ZICFILP-LABEL: disable_tail_calls: +; CHECK-LARGE-ZICFILP: # %bb.0: # %entry +; CHECK-LARGE-ZICFILP-NEXT: lpad 0 +; CHECK-LARGE-ZICFILP-NEXT: addi sp, sp, -16 +; CHECK-LARGE-ZICFILP-NEXT: sw ra, 12(sp) # 4-byte Folded Spill +; CHECK-LARGE-ZICFILP-NEXT: .Lpcrel_hi16: +; CHECK-LARGE-ZICFILP-NEXT: auipc a1, %pcrel_hi(.LCPI13_0) +; CHECK-LARGE-ZICFILP-NEXT: lw t2, %pcrel_lo(.Lpcrel_hi16)(a1) +; CHECK-LARGE-ZICFILP-NEXT: jalr t2 +; CHECK-LARGE-ZICFILP-NEXT: lw ra, 12(sp) # 4-byte Folded Reload +; CHECK-LARGE-ZICFILP-NEXT: addi sp, sp, 16 +; CHECK-LARGE-ZICFILP-NEXT: ret entry: %rv = tail call i32 @callee_tail(i32 %i) ret i32 %rv @@ -317,6 +556,35 @@ define i32 @duplicate_returns(i32 %a, i32 %b) nounwind { ; CHECK-NEXT: tail test1 ; CHECK-NEXT: .LBB14_6: # %if.else8 ; CHECK-NEXT: tail test3 +; +; CHECK-LARGE-ZICFILP-LABEL: duplicate_returns: +; CHECK-LARGE-ZICFILP: # %bb.0: # %entry +; CHECK-LARGE-ZICFILP-NEXT: lpad 0 +; CHECK-LARGE-ZICFILP-NEXT: beqz a0, .LBB14_4 +; CHECK-LARGE-ZICFILP-NEXT: # %bb.1: # %if.else +; CHECK-LARGE-ZICFILP-NEXT: beqz a1, .LBB14_5 +; CHECK-LARGE-ZICFILP-NEXT: # %bb.2: # %if.else4 +; CHECK-LARGE-ZICFILP-NEXT: bge a1, a0, .LBB14_6 +; CHECK-LARGE-ZICFILP-NEXT: # %bb.3: # %if.then6 +; CHECK-LARGE-ZICFILP-NEXT: .Lpcrel_hi19: +; CHECK-LARGE-ZICFILP-NEXT: auipc a0, %pcrel_hi(.LCPI14_1) +; CHECK-LARGE-ZICFILP-NEXT: lw t2, %pcrel_lo(.Lpcrel_hi19)(a0) +; CHECK-LARGE-ZICFILP-NEXT: jr t2 +; CHECK-LARGE-ZICFILP-NEXT: .LBB14_4: # %if.then +; CHECK-LARGE-ZICFILP-NEXT: .Lpcrel_hi17: +; CHECK-LARGE-ZICFILP-NEXT: auipc a0, %pcrel_hi(.LCPI14_3) +; CHECK-LARGE-ZICFILP-NEXT: lw t2, %pcrel_lo(.Lpcrel_hi17)(a0) +; CHECK-LARGE-ZICFILP-NEXT: jr t2 +; CHECK-LARGE-ZICFILP-NEXT: .LBB14_5: # %if.then2 +; CHECK-LARGE-ZICFILP-NEXT: .Lpcrel_hi18: +; CHECK-LARGE-ZICFILP-NEXT: auipc a0, %pcrel_hi(.LCPI14_2) +; CHECK-LARGE-ZICFILP-NEXT: lw t2, %pcrel_lo(.Lpcrel_hi18)(a0) +; CHECK-LARGE-ZICFILP-NEXT: jr t2 +; CHECK-LARGE-ZICFILP-NEXT: .LBB14_6: # %if.else8 +; CHECK-LARGE-ZICFILP-NEXT: .Lpcrel_hi20: +; CHECK-LARGE-ZICFILP-NEXT: auipc a0, %pcrel_hi(.LCPI14_0) +; CHECK-LARGE-ZICFILP-NEXT: lw t2, %pcrel_lo(.Lpcrel_hi20)(a0) +; CHECK-LARGE-ZICFILP-NEXT: jr t2 entry: %cmp = icmp eq i32 %a, 0 br i1 %cmp, label %if.then, label %if.else From e59e30d3f84152d93f45b683a16ebf011e716872 Mon Sep 17 00:00:00 2001 From: LLVM GN Syncbot Date: Fri, 27 Sep 2024 05:08:34 +0000 Subject: [PATCH 042/469] [gn build] Port 24bc3244d4e2 --- llvm/utils/gn/secondary/libcxx/include/BUILD.gn | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/utils/gn/secondary/libcxx/include/BUILD.gn b/llvm/utils/gn/secondary/libcxx/include/BUILD.gn index 91d547da201f2..e4810973985ea 100644 --- a/llvm/utils/gn/secondary/libcxx/include/BUILD.gn +++ b/llvm/utils/gn/secondary/libcxx/include/BUILD.gn @@ -95,7 +95,6 @@ if (current_toolchain == default_toolchain) { "__algorithm/find_if.h", "__algorithm/find_if_not.h", "__algorithm/find_segment_if.h", - "__algorithm/fold.h", "__algorithm/for_each.h", "__algorithm/for_each_n.h", "__algorithm/for_each_segment.h", @@ -170,6 +169,7 @@ if (current_toolchain == default_toolchain) { "__algorithm/ranges_find_if.h", "__algorithm/ranges_find_if_not.h", "__algorithm/ranges_find_last.h", + "__algorithm/ranges_fold.h", "__algorithm/ranges_for_each.h", "__algorithm/ranges_for_each_n.h", "__algorithm/ranges_generate.h", From 91ec9cb96051e4c9044fc47c42732a5f5528e6c8 Mon Sep 17 00:00:00 2001 From: Ryosuke Niwa Date: Thu, 26 Sep 2024 22:18:07 -0700 Subject: [PATCH 043/469] [alpha.webkit.UncountedCallArgsChecker] Use canonical type (#109393) This PR fixes a bug in UncountedCallArgsChecker that calling a function with a member variable which is Ref/RefPtr is erroneously treated as safe by canoniclizing the type before checking whether it's ref counted or not. --- .../Checkers/WebKit/PtrTypesSemantics.cpp | 2 +- .../WebKit/UncountedCallArgsChecker.cpp | 9 ++++--- .../WebKit/uncounted-obj-const-v-muable.cpp | 27 +++++++++++++++++++ 3 files changed, 33 insertions(+), 5 deletions(-) create mode 100644 clang/test/Analysis/Checkers/WebKit/uncounted-obj-const-v-muable.cpp diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp index 9da3e54e45431..54c99c3c1b37f 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp @@ -155,7 +155,7 @@ std::optional isUncounted(const QualType T) { std::optional isUncounted(const CXXRecordDecl* Class) { // Keep isRefCounted first as it's cheaper. - if (isRefCounted(Class)) + if (!Class || isRefCounted(Class)) return false; std::optional IsRefCountable = isRefCountable(Class); diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedCallArgsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedCallArgsChecker.cpp index 81c2434ce6477..31e9b3c4b9d41 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedCallArgsChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedCallArgsChecker.cpp @@ -86,7 +86,7 @@ class UncountedCallArgsChecker return; } auto *E = MemberCallExpr->getImplicitObjectArgument(); - QualType ArgType = MemberCallExpr->getObjectType(); + QualType ArgType = MemberCallExpr->getObjectType().getCanonicalType(); std::optional IsUncounted = isUncounted(ArgType); if (IsUncounted && *IsUncounted && !isPtrOriginSafe(E)) reportBugOnThis(E); @@ -102,12 +102,13 @@ class UncountedCallArgsChecker // if ((*P)->hasAttr()) // continue; - const auto *ArgType = (*P)->getType().getTypePtrOrNull(); - if (!ArgType) + QualType ArgType = (*P)->getType().getCanonicalType(); + const auto *TypePtr = ArgType.getTypePtrOrNull(); + if (!TypePtr) continue; // FIXME? Should we bail? // FIXME: more complex types (arrays, references to raw pointers, etc) - std::optional IsUncounted = isUncountedPtr(ArgType); + std::optional IsUncounted = isUncountedPtr(TypePtr); if (!IsUncounted || !(*IsUncounted)) continue; diff --git a/clang/test/Analysis/Checkers/WebKit/uncounted-obj-const-v-muable.cpp b/clang/test/Analysis/Checkers/WebKit/uncounted-obj-const-v-muable.cpp new file mode 100644 index 0000000000000..2721cd8474e1b --- /dev/null +++ b/clang/test/Analysis/Checkers/WebKit/uncounted-obj-const-v-muable.cpp @@ -0,0 +1,27 @@ +// RUN: %clang_analyze_cc1 -analyzer-checker=alpha.webkit.UncountedCallArgsChecker -verify %s + +#include "mock-types.h" + +class Object { +public: + void ref() const; + void deref() const; + + bool constFunc() const; + void mutableFunc(); +}; + +class Caller { + void someFunction(); + void otherFunction(); +private: + RefPtr m_obj; +}; + +void Caller::someFunction() +{ + m_obj->constFunc(); + // expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}} + m_obj->mutableFunc(); + // expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}} +} From af3837cfd98cbd6bc9fb1fb12a20e29211b88280 Mon Sep 17 00:00:00 2001 From: Craig Topper Date: Thu, 26 Sep 2024 22:35:19 -0700 Subject: [PATCH 044/469] [AArch64] Use MCRegister. NFC --- .../AArch64/MCTargetDesc/AArch64MCTargetDesc.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCTargetDesc.cpp b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCTargetDesc.cpp index 97c5f96388abe..c7f44ec018f5a 100644 --- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCTargetDesc.cpp +++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCTargetDesc.cpp @@ -447,10 +447,10 @@ class AArch64MCInstrAnalysis : public MCInstrAnalysis { const MCRegisterClass &FPR128RC = MRI.getRegClass(AArch64::FPR128RegClassID); - auto ClearsSuperReg = [=](unsigned RegID) { + auto ClearsSuperReg = [=](MCRegister Reg) { // An update to the lower 32 bits of a 64 bit integer register is // architecturally defined to zero extend the upper 32 bits on a write. - if (GPR32RC.contains(RegID)) + if (GPR32RC.contains(Reg)) return true; // SIMD&FP instructions operating on scalar data only acccess the lower // bits of a register, the upper bits are zero extended on a write. For @@ -458,9 +458,9 @@ class AArch64MCInstrAnalysis : public MCInstrAnalysis { // register are zero extended on a write. // When VL is higher than 128 bits, any write to a SIMD&FP register sets // bits higher than 128 to zero. - return FPR8RC.contains(RegID) || FPR16RC.contains(RegID) || - FPR32RC.contains(RegID) || FPR64RC.contains(RegID) || - FPR128RC.contains(RegID); + return FPR8RC.contains(Reg) || FPR16RC.contains(Reg) || + FPR32RC.contains(Reg) || FPR64RC.contains(Reg) || + FPR128RC.contains(Reg); }; Mask.clearAllBits(); From 8a7843ca0ff56a2d5c22bc78ba16309d5af39869 Mon Sep 17 00:00:00 2001 From: Craig Topper Date: Thu, 26 Sep 2024 22:56:12 -0700 Subject: [PATCH 045/469] [RISCV] Add 16 bit GPR sub-register for Zhinx. (#107446) This patches adds a 16 bit register class for use with Zhinx instructions. This makes them more similar to Zfh instructions and allows us to only spill 16 bits. I've added CodeGenOnly instructions for load/store using GPRF16 as that gave better results than insert_subreg/extract_subreg. I'm using FSGNJ for GPRF16 copy with Zhinx as that gave better results. Zhinxmin will use ADDI+subreg operations. Function arguments use this new GPRF16 register class for f16 arguments with Zhinxmin. Eliminating the need to use RISCVISD::FMV* nodes. I plan to extend this idea to Zfinx next. --- .../Target/RISCV/AsmParser/RISCVAsmParser.cpp | 10 + .../RISCV/Disassembler/RISCVDisassembler.cpp | 13 + llvm/lib/Target/RISCV/RISCVCallingConv.cpp | 55 +++- .../RISCV/RISCVDeadRegisterDefinitions.cpp | 9 +- .../Target/RISCV/RISCVExpandPseudoInsts.cpp | 21 ++ llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp | 5 +- llvm/lib/Target/RISCV/RISCVInstrInfo.cpp | 22 ++ llvm/lib/Target/RISCV/RISCVInstrInfo.td | 12 +- llvm/lib/Target/RISCV/RISCVInstrInfoZc.td | 25 +- llvm/lib/Target/RISCV/RISCVInstrInfoZfh.td | 33 +- .../Target/RISCV/RISCVMakeCompressible.cpp | 14 + .../lib/Target/RISCV/RISCVMergeBaseOffset.cpp | 2 + llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp | 14 +- llvm/lib/Target/RISCV/RISCVRegisterInfo.td | 117 ++++++-- llvm/test/CodeGen/RISCV/codemodel-lowering.ll | 282 ++++++++++++++---- .../CodeGen/RISCV/fastcc-without-f-reg.ll | 272 +++++++++-------- llvm/test/CodeGen/RISCV/half-arith.ll | 20 +- .../RISCV/half-bitmanip-dagcombines.ll | 24 +- llvm/test/CodeGen/RISCV/half-convert.ll | 12 + llvm/test/CodeGen/RISCV/half-imm.ll | 4 + llvm/test/CodeGen/RISCV/half-intrinsics.ll | 27 +- llvm/test/CodeGen/RISCV/kcfi-mir.ll | 4 +- .../RISCV/make-compressible-zbc-zhinx.mir | 249 ++++++++++++++++ 23 files changed, 964 insertions(+), 282 deletions(-) create mode 100644 llvm/test/CodeGen/RISCV/make-compressible-zbc-zhinx.mir diff --git a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp index 5e29a92f0bacd..fbad7d5d02db6 100644 --- a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp +++ b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp @@ -480,7 +480,13 @@ struct RISCVOperand final : public MCParsedAsmOperand { RISCVMCRegisterClasses[RISCV::GPRRegClassID].contains(Reg.RegNum); } + bool isGPRF16() const { + return Kind == KindTy::Register && + RISCVMCRegisterClasses[RISCV::GPRF16RegClassID].contains(Reg.RegNum); + } + bool isGPRAsFPR() const { return isGPR() && Reg.IsGPRAsFPR; } + bool isGPRAsFPR16() const { return isGPRF16() && Reg.IsGPRAsFPR; } bool isGPRPairAsFPR() const { return isGPRPair() && Reg.IsGPRAsFPR; } bool isGPRPair() const { @@ -1342,6 +1348,10 @@ unsigned RISCVAsmParser::validateTargetOperandClass(MCParsedAsmOperand &AsmOp, Op.Reg.RegNum = convertFPR64ToFPR16(Reg); return Match_Success; } + if (Kind == MCK_GPRAsFPR16 && Op.isGPRAsFPR()) { + Op.Reg.RegNum = Reg - RISCV::X0 + RISCV::X0_H; + return Match_Success; + } // There are some GPRF64AsFPR instructions that have no RV32 equivalent. We // reject them at parsing thinking we should match as GPRPairAsFPR for RV32. diff --git a/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp b/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp index b869458a25614..c2659a51b0209 100644 --- a/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp +++ b/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp @@ -81,6 +81,19 @@ static DecodeStatus DecodeGPRRegisterClass(MCInst &Inst, uint32_t RegNo, return MCDisassembler::Success; } +static DecodeStatus DecodeGPRF16RegisterClass(MCInst &Inst, uint32_t RegNo, + uint64_t Address, + const MCDisassembler *Decoder) { + bool IsRVE = Decoder->getSubtargetInfo().hasFeature(RISCV::FeatureStdExtE); + + if (RegNo >= 32 || (IsRVE && RegNo >= 16)) + return MCDisassembler::Fail; + + MCRegister Reg = RISCV::X0_H + RegNo; + Inst.addOperand(MCOperand::createReg(Reg)); + return MCDisassembler::Success; +} + static DecodeStatus DecodeGPRX1X5RegisterClass(MCInst &Inst, uint32_t RegNo, uint64_t Address, const MCDisassembler *Decoder) { diff --git a/llvm/lib/Target/RISCV/RISCVCallingConv.cpp b/llvm/lib/Target/RISCV/RISCVCallingConv.cpp index 30a565c8b19db..d610f0b956027 100644 --- a/llvm/lib/Target/RISCV/RISCVCallingConv.cpp +++ b/llvm/lib/Target/RISCV/RISCVCallingConv.cpp @@ -139,6 +139,23 @@ ArrayRef RISCV::getArgGPRs(const RISCVABI::ABI ABI) { return ArrayRef(ArgIGPRs); } +static ArrayRef getArgGPR16s(const RISCVABI::ABI ABI) { + // The GPRs used for passing arguments in the ILP32* and LP64* ABIs, except + // the ILP32E ABI. + static const MCPhysReg ArgIGPRs[] = {RISCV::X10_H, RISCV::X11_H, RISCV::X12_H, + RISCV::X13_H, RISCV::X14_H, RISCV::X15_H, + RISCV::X16_H, RISCV::X17_H}; + // The GPRs used for passing arguments in the ILP32E/LP64E ABI. + static const MCPhysReg ArgEGPRs[] = {RISCV::X10_H, RISCV::X11_H, + RISCV::X12_H, RISCV::X13_H, + RISCV::X14_H, RISCV::X15_H}; + + if (ABI == RISCVABI::ABI_ILP32E || ABI == RISCVABI::ABI_LP64E) + return ArrayRef(ArgEGPRs); + + return ArrayRef(ArgIGPRs); +} + static ArrayRef getFastCCArgGPRs(const RISCVABI::ABI ABI) { // The GPRs used for passing arguments in the FastCC, X5 and X6 might be used // for save-restore libcall, so we don't use them. @@ -157,6 +174,26 @@ static ArrayRef getFastCCArgGPRs(const RISCVABI::ABI ABI) { return ArrayRef(FastCCIGPRs); } +static ArrayRef getFastCCArgGPRF16s(const RISCVABI::ABI ABI) { + // The GPRs used for passing arguments in the FastCC, X5 and X6 might be used + // for save-restore libcall, so we don't use them. + // Don't use X7 for fastcc, since Zicfilp uses X7 as the label register. + static const MCPhysReg FastCCIGPRs[] = { + RISCV::X10_H, RISCV::X11_H, RISCV::X12_H, RISCV::X13_H, + RISCV::X14_H, RISCV::X15_H, RISCV::X16_H, RISCV::X17_H, + RISCV::X28_H, RISCV::X29_H, RISCV::X30_H, RISCV::X31_H}; + + // The GPRs used for passing arguments in the FastCC when using ILP32E/LP64E. + static const MCPhysReg FastCCEGPRs[] = {RISCV::X10_H, RISCV::X11_H, + RISCV::X12_H, RISCV::X13_H, + RISCV::X14_H, RISCV::X15_H}; + + if (ABI == RISCVABI::ABI_ILP32E || ABI == RISCVABI::ABI_LP64E) + return ArrayRef(FastCCEGPRs); + + return ArrayRef(FastCCIGPRs); +} + // Pass a 2*XLEN argument that has been split into two XLEN values through // registers or the stack as necessary. static bool CC_RISCVAssign2XLen(unsigned XLen, CCState &State, CCValAssign VA1, @@ -320,6 +357,13 @@ bool llvm::CC_RISCV(unsigned ValNo, MVT ValVT, MVT LocVT, } } + if ((ValVT == MVT::f16 && Subtarget.hasStdExtZhinxmin())) { + if (MCRegister Reg = State.AllocateReg(getArgGPR16s(ABI))) { + State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo)); + return false; + } + } + ArrayRef ArgGPRs = RISCV::getArgGPRs(ABI); // Zfinx/Zdinx use GPR without a bitcast when possible. @@ -564,9 +608,16 @@ bool llvm::CC_RISCV_FastCC(unsigned ValNo, MVT ValVT, MVT LocVT, MVT XLenVT = Subtarget.getXLenVT(); + // Check if there is an available GPRF16 before hitting the stack. + if ((LocVT == MVT::f16 && Subtarget.hasStdExtZhinxmin())) { + if (MCRegister Reg = State.AllocateReg(getFastCCArgGPRF16s(ABI))) { + State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo)); + return false; + } + } + // Check if there is an available GPR before hitting the stack. - if ((LocVT == MVT::f16 && Subtarget.hasStdExtZhinxmin()) || - (LocVT == MVT::f32 && Subtarget.hasStdExtZfinx()) || + if ((LocVT == MVT::f32 && Subtarget.hasStdExtZfinx()) || (LocVT == MVT::f64 && Subtarget.is64Bit() && Subtarget.hasStdExtZdinx())) { if (MCRegister Reg = State.AllocateReg(getFastCCArgGPRs(ABI))) { diff --git a/llvm/lib/Target/RISCV/RISCVDeadRegisterDefinitions.cpp b/llvm/lib/Target/RISCV/RISCVDeadRegisterDefinitions.cpp index cce0ffe16e5fe..713c7a0661def 100644 --- a/llvm/lib/Target/RISCV/RISCVDeadRegisterDefinitions.cpp +++ b/llvm/lib/Target/RISCV/RISCVDeadRegisterDefinitions.cpp @@ -93,14 +93,19 @@ bool RISCVDeadRegisterDefinitions::runOnMachineFunction(MachineFunction &MF) { continue; LLVM_DEBUG(dbgs() << " Dead def operand #" << I << " in:\n "; MI.print(dbgs())); + Register X0Reg; const TargetRegisterClass *RC = TII->getRegClass(Desc, I, TRI, MF); - if (!(RC && RC->contains(RISCV::X0))) { + if (RC && RC->contains(RISCV::X0)) { + X0Reg = RISCV::X0; + } else if (RC && RC->contains(RISCV::X0_H)) { + X0Reg = RISCV::X0_H; + } else { LLVM_DEBUG(dbgs() << " Ignoring, register is not a GPR.\n"); continue; } assert(LIS.hasInterval(Reg)); LIS.removeInterval(Reg); - MO.setReg(RISCV::X0); + MO.setReg(X0Reg); LLVM_DEBUG(dbgs() << " Replacing with zero register. New:\n "; MI.print(dbgs())); ++NumDeadDefsReplaced; diff --git a/llvm/lib/Target/RISCV/RISCVExpandPseudoInsts.cpp b/llvm/lib/Target/RISCV/RISCVExpandPseudoInsts.cpp index 72f96965ae985..2501256ca6adf 100644 --- a/llvm/lib/Target/RISCV/RISCVExpandPseudoInsts.cpp +++ b/llvm/lib/Target/RISCV/RISCVExpandPseudoInsts.cpp @@ -48,6 +48,8 @@ class RISCVExpandPseudo : public MachineFunctionPass { MachineBasicBlock::iterator &NextMBBI); bool expandVMSET_VMCLR(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, unsigned Opcode); + bool expandMV_FPR16INX(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI); bool expandRV32ZdinxStore(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI); bool expandRV32ZdinxLoad(MachineBasicBlock &MBB, @@ -104,6 +106,8 @@ bool RISCVExpandPseudo::expandMI(MachineBasicBlock &MBB, // expanded instructions for each pseudo is correct in the Size field of the // tablegen definition for the pseudo. switch (MBBI->getOpcode()) { + case RISCV::PseudoMV_FPR16INX: + return expandMV_FPR16INX(MBB, MBBI); case RISCV::PseudoRV32ZdinxSD: return expandRV32ZdinxStore(MBB, MBBI); case RISCV::PseudoRV32ZdinxLD: @@ -266,6 +270,23 @@ bool RISCVExpandPseudo::expandVMSET_VMCLR(MachineBasicBlock &MBB, return true; } +bool RISCVExpandPseudo::expandMV_FPR16INX(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI) { + DebugLoc DL = MBBI->getDebugLoc(); + const TargetRegisterInfo *TRI = STI->getRegisterInfo(); + Register DstReg = TRI->getMatchingSuperReg( + MBBI->getOperand(0).getReg(), RISCV::sub_16, &RISCV::GPRRegClass); + Register SrcReg = TRI->getMatchingSuperReg( + MBBI->getOperand(1).getReg(), RISCV::sub_16, &RISCV::GPRRegClass); + + BuildMI(MBB, MBBI, DL, TII->get(RISCV::ADDI), DstReg) + .addReg(SrcReg, getKillRegState(MBBI->getOperand(1).isKill())) + .addImm(0); + + MBBI->eraseFromParent(); // The pseudo instruction is gone now. + return true; +} + // This function expands the PseudoRV32ZdinxSD for storing a double-precision // floating-point value into memory by generating an equivalent instruction // sequence for RV32. diff --git a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp index 05ba18bf8ebd8..23479c2edf1d9 100644 --- a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp +++ b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp @@ -928,7 +928,10 @@ void RISCVDAGToDAGISel::Select(SDNode *Node) { } SDNode *Res; - if (Opc == RISCV::FCVT_D_W_IN32X || Opc == RISCV::FCVT_D_W) + if (VT.SimpleTy == MVT::f16 && Opc == RISCV::COPY) { + Res = + CurDAG->getTargetExtractSubreg(RISCV::sub_16, DL, VT, Imm).getNode(); + } else if (Opc == RISCV::FCVT_D_W_IN32X || Opc == RISCV::FCVT_D_W) Res = CurDAG->getMachineNode( Opc, DL, VT, Imm, CurDAG->getTargetConstant(RISCVFPRndMode::RNE, DL, XLenVT)); diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp b/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp index 10b4e4870aebe..f0295d289ed86 100644 --- a/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp +++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp @@ -104,6 +104,7 @@ Register RISCVInstrInfo::isLoadFromStackSlot(const MachineInstr &MI, MemBytes = 1; break; case RISCV::LH: + case RISCV::LH_INX: case RISCV::LHU: case RISCV::FLH: MemBytes = 2; @@ -144,6 +145,7 @@ Register RISCVInstrInfo::isStoreToStackSlot(const MachineInstr &MI, MemBytes = 1; break; case RISCV::SH: + case RISCV::SH_INX: case RISCV::FSH: MemBytes = 2; break; @@ -462,6 +464,13 @@ void RISCVInstrInfo::copyPhysReg(MachineBasicBlock &MBB, return; } + if (RISCV::GPRF16RegClass.contains(DstReg, SrcReg)) { + BuildMI(MBB, MBBI, DL, get(RISCV::PseudoMV_FPR16INX), DstReg) + .addReg(SrcReg, + getKillRegState(KillSrc) | getRenamableRegState(RenamableSrc)); + return; + } + if (RISCV::GPRPairRegClass.contains(DstReg, SrcReg)) { // Emit an ADDI for both parts of GPRPair. BuildMI(MBB, MBBI, DL, get(RISCV::ADDI), @@ -583,6 +592,9 @@ void RISCVInstrInfo::storeRegToStackSlot(MachineBasicBlock &MBB, Opcode = TRI->getRegSizeInBits(RISCV::GPRRegClass) == 32 ? RISCV::SW : RISCV::SD; IsScalableVector = false; + } else if (RISCV::GPRF16RegClass.hasSubClassEq(RC)) { + Opcode = RISCV::SH_INX; + IsScalableVector = false; } else if (RISCV::GPRPairRegClass.hasSubClassEq(RC)) { Opcode = RISCV::PseudoRV32ZdinxSD; IsScalableVector = false; @@ -666,6 +678,9 @@ void RISCVInstrInfo::loadRegFromStackSlot(MachineBasicBlock &MBB, Opcode = TRI->getRegSizeInBits(RISCV::GPRRegClass) == 32 ? RISCV::LW : RISCV::LD; IsScalableVector = false; + } else if (RISCV::GPRF16RegClass.hasSubClassEq(RC)) { + Opcode = RISCV::LH_INX; + IsScalableVector = false; } else if (RISCV::GPRPairRegClass.hasSubClassEq(RC)) { Opcode = RISCV::PseudoRV32ZdinxLD; IsScalableVector = false; @@ -1538,6 +1553,9 @@ unsigned RISCVInstrInfo::getInstSizeInBytes(const MachineInstr &MI) const { } switch (Opcode) { + case RISCV::PseudoMV_FPR16INX: + // MV is always compressible to either c.mv or c.li rd, 0. + return STI.hasStdExtCOrZca() ? 2 : 4; case TargetOpcode::STACKMAP: // The upper bound for a stackmap intrinsic is the full length of its shadow return StackMapOpers(&MI).getNumPatchBytes(); @@ -2593,6 +2611,7 @@ bool RISCVInstrInfo::canFoldIntoAddrMode(const MachineInstr &MemI, Register Reg, case RISCV::LB: case RISCV::LBU: case RISCV::LH: + case RISCV::LH_INX: case RISCV::LHU: case RISCV::LW: case RISCV::LWU: @@ -2602,6 +2621,7 @@ bool RISCVInstrInfo::canFoldIntoAddrMode(const MachineInstr &MemI, Register Reg, case RISCV::FLD: case RISCV::SB: case RISCV::SH: + case RISCV::SH_INX: case RISCV::SW: case RISCV::SD: case RISCV::FSH: @@ -2665,9 +2685,11 @@ bool RISCVInstrInfo::getMemOperandsWithOffsetWidth( case RISCV::LBU: case RISCV::SB: case RISCV::LH: + case RISCV::LH_INX: case RISCV::LHU: case RISCV::FLH: case RISCV::SH: + case RISCV::SH_INX: case RISCV::FSH: case RISCV::LW: case RISCV::LWU: diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.td b/llvm/lib/Target/RISCV/RISCVInstrInfo.td index ed1b3227748a1..a2f1e3ded18fe 100644 --- a/llvm/lib/Target/RISCV/RISCVInstrInfo.td +++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.td @@ -520,8 +520,8 @@ class BranchCC_rri funct3, string opcodestr> } let hasSideEffects = 0, mayLoad = 1, mayStore = 0 in { -class Load_ri funct3, string opcodestr> - : RVInstI funct3, string opcodestr, DAGOperand rty = GPR> + : RVInstI; class HLoad_r funct7, bits<5> funct5, string opcodestr> @@ -535,9 +535,9 @@ class HLoad_r funct7, bits<5> funct5, string opcodestr> // reflecting the order these fields are specified in the instruction // encoding. let hasSideEffects = 0, mayLoad = 0, mayStore = 1 in { -class Store_rri funct3, string opcodestr> +class Store_rri funct3, string opcodestr, DAGOperand rty = GPR> : RVInstS; class HStore_rr funct7, string opcodestr> @@ -549,8 +549,8 @@ class HStore_rr funct7, string opcodestr> } let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in -class ALU_ri funct3, string opcodestr> - : RVInstI funct3, string opcodestr, DAGOperand rty = GPR> + : RVInstI, Sched<[WriteIALU, ReadIALU]>; diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoZc.td b/llvm/lib/Target/RISCV/RISCVInstrInfoZc.td index 11c2695a59854..bff740a33c1c1 100644 --- a/llvm/lib/Target/RISCV/RISCVInstrInfoZc.td +++ b/llvm/lib/Target/RISCV/RISCVInstrInfoZc.td @@ -112,8 +112,9 @@ class CLoadB_ri funct6, string OpcodeStr> } let hasSideEffects = 0, mayLoad = 1, mayStore = 0 in -class CLoadH_ri funct6, bit funct1, string OpcodeStr> - : RVInst16CLH funct6, bit funct1, string OpcodeStr, + DAGOperand rty = GPRC> + : RVInst16CLH { bits<2> imm; @@ -132,9 +133,10 @@ class CStoreB_rri funct6, string OpcodeStr> } let hasSideEffects = 0, mayLoad = 0, mayStore = 1 in -class CStoreH_rri funct6, bit funct1, string OpcodeStr> +class CStoreH_rri funct6, bit funct1, string OpcodeStr, + DAGOperand rty = GPRC> : RVInst16CSH { bits<2> imm; @@ -202,7 +204,15 @@ def C_SB : CStoreB_rri<0b100010, "c.sb">, Sched<[WriteSTB, ReadStoreData, ReadMemBase]>; def C_SH : CStoreH_rri<0b100011, 0b0, "c.sh">, Sched<[WriteSTH, ReadStoreData, ReadMemBase]>; + +// Compressed versions of Zhinx load/store. +let isCodeGenOnly = 1 in { +def C_LH_INX : CLoadH_ri<0b100001, 0b1, "c.lh", GPRF16C>, + Sched<[WriteLDH, ReadMemBase]>; +def C_SH_INX : CStoreH_rri<0b100011, 0b0, "c.sh", GPRF16C>, + Sched<[WriteSTH, ReadStoreData, ReadMemBase]>; } +} // Predicates = [HasStdExtZcb] // Zcmp let DecoderNamespace = "RVZcmp", Predicates = [HasStdExtZcmp], @@ -318,6 +328,13 @@ def : CompressPat<(SB GPRC:$rs2, GPRCMem:$rs1, uimm2:$imm), (C_SB GPRC:$rs2, GPRCMem:$rs1, uimm2:$imm)>; def : CompressPat<(SH GPRC:$rs2, GPRCMem:$rs1, uimm2_lsb0:$imm), (C_SH GPRC:$rs2, GPRCMem:$rs1, uimm2_lsb0:$imm)>; + +let isCompressOnly = true in { +def : CompressPat<(LH_INX GPRF16C:$rd, GPRCMem:$rs1, uimm2_lsb0:$imm), + (C_LH_INX GPRF16C:$rd, GPRCMem:$rs1, uimm2_lsb0:$imm)>; +def : CompressPat<(SH_INX GPRF16C:$rs2, GPRCMem:$rs1, uimm2_lsb0:$imm), + (C_SH_INX GPRF16C:$rs2, GPRCMem:$rs1, uimm2_lsb0:$imm)>; +} }// Predicates = [HasStdExtZcb] diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoZfh.td b/llvm/lib/Target/RISCV/RISCVInstrInfoZfh.td index 792cb7fa6dbc2..51123180d47c6 100644 --- a/llvm/lib/Target/RISCV/RISCVInstrInfoZfh.td +++ b/llvm/lib/Target/RISCV/RISCVInstrInfoZfh.td @@ -33,9 +33,14 @@ def riscv_fmv_x_signexth // Zhinxmin and Zhinx +def GPRAsFPR16 : AsmOperandClass { + let Name = "GPRAsFPR16"; + let ParserMethod = "parseGPRAsFPR"; + let RenderMethod = "addRegOperands"; +} + def FPR16INX : RegisterOperand { - let ParserMatchClass = GPRAsFPR; - let DecoderMethod = "DecodeGPRRegisterClass"; + let ParserMatchClass = GPRAsFPR16; } def ZfhExt : ExtInfo<"", "", [HasStdExtZfh], @@ -84,6 +89,19 @@ def FLH : FPLoad_r<0b001, "flh", FPR16, WriteFLD16>; def FSH : FPStore_r<0b001, "fsh", FPR16, WriteFST16>; } // Predicates = [HasHalfFPLoadStoreMove] +let Predicates = [HasStdExtZhinxmin], isCodeGenOnly = 1 in { +def LH_INX : Load_ri<0b001, "lh", GPRF16>, Sched<[WriteLDH, ReadMemBase]>; +def SH_INX : Store_rri<0b001, "sh", GPRF16>, + Sched<[WriteSTH, ReadStoreData, ReadMemBase]>; + +// ADDI with GPRF16 register class to use for copy. This should not be used as +// general ADDI, so the immediate should always be zero. +let isReMaterializable = 1, isAsCheapAsAMove = 1, isMoveReg = 1, + hasSideEffects = 0, mayLoad = 0, mayStore = 0 in +def PseudoMV_FPR16INX : Pseudo<(outs GPRF16:$rd), (ins GPRF16:$rs), []>, + Sched<[WriteIALU, ReadIALU]>; +} + foreach Ext = ZfhExts in { let SchedRW = [WriteFMA16, ReadFMA16, ReadFMA16, ReadFMA16Addend] in { defm FMADD_H : FPFMA_rrr_frm_m; @@ -426,13 +444,10 @@ let Predicates = [HasStdExtZhinxmin] in { defm Select_FPR16INX : SelectCC_GPR_rrirr; /// Loads -def : Pat<(f16 (load (AddrRegImm (XLenVT GPR:$rs1), simm12:$imm12))), - (COPY_TO_REGCLASS (LH GPR:$rs1, simm12:$imm12), GPRF16)>; +def : LdPat; /// Stores -def : Pat<(store (f16 FPR16INX:$rs2), - (AddrRegImm (XLenVT GPR:$rs1), simm12:$imm12)), - (SH (COPY_TO_REGCLASS FPR16INX:$rs2, GPR), GPR:$rs1, simm12:$imm12)>; +def : StPat; } // Predicates = [HasStdExtZhinxmin] let Predicates = [HasStdExtZfhmin] in { @@ -458,8 +473,8 @@ def : Pat<(any_fpround FPR32INX:$rs1), (FCVT_H_S_INX FPR32INX:$rs1, FRM_DYN)>; def : Pat<(any_fpextend FPR16INX:$rs1), (FCVT_S_H_INX FPR16INX:$rs1, FRM_RNE)>; // Moves (no conversion) -def : Pat<(f16 (riscv_fmv_h_x GPR:$src)), (COPY_TO_REGCLASS GPR:$src, GPR)>; -def : Pat<(riscv_fmv_x_anyexth FPR16INX:$src), (COPY_TO_REGCLASS FPR16INX:$src, GPR)>; +def : Pat<(f16 (riscv_fmv_h_x GPR:$src)), (EXTRACT_SUBREG GPR:$src, sub_16)>; +def : Pat<(riscv_fmv_x_anyexth FPR16INX:$src), (INSERT_SUBREG (XLenVT (IMPLICIT_DEF)), FPR16INX:$src, sub_16)>; def : Pat<(fcopysign FPR32INX:$rs1, FPR16INX:$rs2), (FSGNJ_S_INX $rs1, (FCVT_S_H_INX $rs2, FRM_RNE))>; } // Predicates = [HasStdExtZhinxmin] diff --git a/llvm/lib/Target/RISCV/RISCVMakeCompressible.cpp b/llvm/lib/Target/RISCV/RISCVMakeCompressible.cpp index 3f423450618df..5973e5bf2e525 100644 --- a/llvm/lib/Target/RISCV/RISCVMakeCompressible.cpp +++ b/llvm/lib/Target/RISCV/RISCVMakeCompressible.cpp @@ -103,8 +103,10 @@ static unsigned log2LdstWidth(unsigned Opcode) { case RISCV::SB: return 0; case RISCV::LH: + case RISCV::LH_INX: case RISCV::LHU: case RISCV::SH: + case RISCV::SH_INX: return 1; case RISCV::LW: case RISCV::SW: @@ -128,8 +130,10 @@ static unsigned offsetMask(unsigned Opcode) { case RISCV::SB: return maskTrailingOnes(2U); case RISCV::LH: + case RISCV::LH_INX: case RISCV::LHU: case RISCV::SH: + case RISCV::SH_INX: return maskTrailingOnes(1U); case RISCV::LW: case RISCV::SW: @@ -173,6 +177,7 @@ static int64_t getBaseAdjustForCompression(int64_t Offset, unsigned Opcode) { // Return true if Reg is in a compressed register class. static bool isCompressedReg(Register Reg) { return RISCV::GPRCRegClass.contains(Reg) || + RISCV::GPRF16CRegClass.contains(Reg) || RISCV::FPR32CRegClass.contains(Reg) || RISCV::FPR64CRegClass.contains(Reg); } @@ -186,6 +191,7 @@ static bool isCompressibleLoad(const MachineInstr &MI) { return false; case RISCV::LBU: case RISCV::LH: + case RISCV::LH_INX: case RISCV::LHU: return STI.hasStdExtZcb(); case RISCV::LW: @@ -207,6 +213,7 @@ static bool isCompressibleStore(const MachineInstr &MI) { return false; case RISCV::SB: case RISCV::SH: + case RISCV::SH_INX: return STI.hasStdExtZcb(); case RISCV::SW: case RISCV::SD: @@ -320,6 +327,8 @@ static Register analyzeCompressibleUses(MachineInstr &FirstMI, // Work out the compressed register class from which to scavenge. if (RISCV::GPRRegClass.contains(RegImm.Reg)) RCToScavenge = &RISCV::GPRCRegClass; + else if (RISCV::GPRF16RegClass.contains(RegImm.Reg)) + RCToScavenge = &RISCV::GPRF16CRegClass; else if (RISCV::FPR32RegClass.contains(RegImm.Reg)) RCToScavenge = &RISCV::FPR32CRegClass; else if (RISCV::FPR64RegClass.contains(RegImm.Reg)) @@ -410,6 +419,11 @@ bool RISCVMakeCompressibleOpt::runOnMachineFunction(MachineFunction &Fn) { BuildMI(MBB, MI, MI.getDebugLoc(), TII.get(RISCV::ADDI), NewReg) .addReg(RegImm.Reg) .addImm(RegImm.Imm); + } else if (RISCV::GPRF16RegClass.contains(RegImm.Reg)) { + assert(RegImm.Imm == 0); + BuildMI(MBB, MI, MI.getDebugLoc(), TII.get(RISCV::PseudoMV_FPR16INX), + NewReg) + .addReg(RegImm.Reg); } else { // If we are looking at replacing an FPR register we don't expect to // have any offset. The only compressible FP instructions with an offset diff --git a/llvm/lib/Target/RISCV/RISCVMergeBaseOffset.cpp b/llvm/lib/Target/RISCV/RISCVMergeBaseOffset.cpp index b6ac3384e7d3e..b3a2877edde4e 100644 --- a/llvm/lib/Target/RISCV/RISCVMergeBaseOffset.cpp +++ b/llvm/lib/Target/RISCV/RISCVMergeBaseOffset.cpp @@ -385,6 +385,7 @@ bool RISCVMergeBaseOffsetOpt::foldIntoMemoryOps(MachineInstr &Hi, return false; case RISCV::LB: case RISCV::LH: + case RISCV::LH_INX: case RISCV::LW: case RISCV::LBU: case RISCV::LHU: @@ -395,6 +396,7 @@ bool RISCVMergeBaseOffsetOpt::foldIntoMemoryOps(MachineInstr &Hi, case RISCV::FLD: case RISCV::SB: case RISCV::SH: + case RISCV::SH_INX: case RISCV::SW: case RISCV::SD: case RISCV::FSH: diff --git a/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp b/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp index 91d539a355ac2..a8b6be4fe277a 100644 --- a/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp +++ b/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp @@ -115,11 +115,11 @@ BitVector RISCVRegisterInfo::getReservedRegs(const MachineFunction &MF) const { } // Use markSuperRegs to ensure any register aliases are also reserved - markSuperRegs(Reserved, RISCV::X2); // sp - markSuperRegs(Reserved, RISCV::X3); // gp - markSuperRegs(Reserved, RISCV::X4); // tp + markSuperRegs(Reserved, RISCV::X2_H); // sp + markSuperRegs(Reserved, RISCV::X3_H); // gp + markSuperRegs(Reserved, RISCV::X4_H); // tp if (TFI->hasFP(MF)) - markSuperRegs(Reserved, RISCV::X8); // fp + markSuperRegs(Reserved, RISCV::X8_H); // fp // Reserve the base register if we need to realign the stack and allocate // variable-sized objects at runtime. if (TFI->hasBP(MF)) @@ -131,7 +131,7 @@ BitVector RISCVRegisterInfo::getReservedRegs(const MachineFunction &MF) const { // There are only 16 GPRs for RVE. if (Subtarget.hasStdExtE()) - for (MCPhysReg Reg = RISCV::X16; Reg <= RISCV::X31; Reg++) + for (MCPhysReg Reg = RISCV::X16_H; Reg <= RISCV::X31_H; Reg++) markSuperRegs(Reserved, Reg); // V registers for code generation. We handle them manually. @@ -150,8 +150,8 @@ BitVector RISCVRegisterInfo::getReservedRegs(const MachineFunction &MF) const { if (MF.getFunction().getCallingConv() == CallingConv::GRAAL) { if (Subtarget.hasStdExtE()) report_fatal_error("Graal reserved registers do not exist in RVE"); - markSuperRegs(Reserved, RISCV::X23); - markSuperRegs(Reserved, RISCV::X27); + markSuperRegs(Reserved, RISCV::X23_H); + markSuperRegs(Reserved, RISCV::X27_H); } // Shadow stack pointer. diff --git a/llvm/lib/Target/RISCV/RISCVRegisterInfo.td b/llvm/lib/Target/RISCV/RISCVRegisterInfo.td index 5725d8eda88ce..9cb589f2441a2 100644 --- a/llvm/lib/Target/RISCV/RISCVRegisterInfo.td +++ b/llvm/lib/Target/RISCV/RISCVRegisterInfo.td @@ -82,42 +82,84 @@ def sub_gpr_odd : SubRegIndex<32, 32> { // instructions. let RegAltNameIndices = [ABIRegAltName] in { + // 16-bit sub-registers for use by Zhinx. Having a 16-bit sub-register reduces + // the spill size for these operations. let isConstant = true in - def X0 : RISCVReg<0, "x0", ["zero"]>, DwarfRegNum<[0]>; + def X0_H : RISCVReg<0, "x0", ["zero"]>; let CostPerUse = [0, 1] in { - def X1 : RISCVReg<1, "x1", ["ra"]>, DwarfRegNum<[1]>; - def X2 : RISCVReg<2, "x2", ["sp"]>, DwarfRegNum<[2]>; - def X3 : RISCVReg<3, "x3", ["gp"]>, DwarfRegNum<[3]>; - def X4 : RISCVReg<4, "x4", ["tp"]>, DwarfRegNum<[4]>; - def X5 : RISCVReg<5, "x5", ["t0"]>, DwarfRegNum<[5]>; - def X6 : RISCVReg<6, "x6", ["t1"]>, DwarfRegNum<[6]>; - def X7 : RISCVReg<7, "x7", ["t2"]>, DwarfRegNum<[7]>; + def X1_H : RISCVReg<1, "x1", ["ra"]>; + def X2_H : RISCVReg<2, "x2", ["sp"]>; + def X3_H : RISCVReg<3, "x3", ["gp"]>; + def X4_H : RISCVReg<4, "x4", ["tp"]>; + def X5_H : RISCVReg<5, "x5", ["t0"]>; + def X6_H : RISCVReg<6, "x6", ["t1"]>; + def X7_H : RISCVReg<7, "x7", ["t2"]>; } - def X8 : RISCVReg<8, "x8", ["s0", "fp"]>, DwarfRegNum<[8]>; - def X9 : RISCVReg<9, "x9", ["s1"]>, DwarfRegNum<[9]>; - def X10 : RISCVReg<10,"x10", ["a0"]>, DwarfRegNum<[10]>; - def X11 : RISCVReg<11,"x11", ["a1"]>, DwarfRegNum<[11]>; - def X12 : RISCVReg<12,"x12", ["a2"]>, DwarfRegNum<[12]>; - def X13 : RISCVReg<13,"x13", ["a3"]>, DwarfRegNum<[13]>; - def X14 : RISCVReg<14,"x14", ["a4"]>, DwarfRegNum<[14]>; - def X15 : RISCVReg<15,"x15", ["a5"]>, DwarfRegNum<[15]>; + def X8_H : RISCVReg<8, "x8", ["s0", "fp"]>; + def X9_H : RISCVReg<9, "x9", ["s1"]>; + def X10_H : RISCVReg<10,"x10", ["a0"]>; + def X11_H : RISCVReg<11,"x11", ["a1"]>; + def X12_H : RISCVReg<12,"x12", ["a2"]>; + def X13_H : RISCVReg<13,"x13", ["a3"]>; + def X14_H : RISCVReg<14,"x14", ["a4"]>; + def X15_H : RISCVReg<15,"x15", ["a5"]>; let CostPerUse = [0, 1] in { - def X16 : RISCVReg<16,"x16", ["a6"]>, DwarfRegNum<[16]>; - def X17 : RISCVReg<17,"x17", ["a7"]>, DwarfRegNum<[17]>; - def X18 : RISCVReg<18,"x18", ["s2"]>, DwarfRegNum<[18]>; - def X19 : RISCVReg<19,"x19", ["s3"]>, DwarfRegNum<[19]>; - def X20 : RISCVReg<20,"x20", ["s4"]>, DwarfRegNum<[20]>; - def X21 : RISCVReg<21,"x21", ["s5"]>, DwarfRegNum<[21]>; - def X22 : RISCVReg<22,"x22", ["s6"]>, DwarfRegNum<[22]>; - def X23 : RISCVReg<23,"x23", ["s7"]>, DwarfRegNum<[23]>; - def X24 : RISCVReg<24,"x24", ["s8"]>, DwarfRegNum<[24]>; - def X25 : RISCVReg<25,"x25", ["s9"]>, DwarfRegNum<[25]>; - def X26 : RISCVReg<26,"x26", ["s10"]>, DwarfRegNum<[26]>; - def X27 : RISCVReg<27,"x27", ["s11"]>, DwarfRegNum<[27]>; - def X28 : RISCVReg<28,"x28", ["t3"]>, DwarfRegNum<[28]>; - def X29 : RISCVReg<29,"x29", ["t4"]>, DwarfRegNum<[29]>; - def X30 : RISCVReg<30,"x30", ["t5"]>, DwarfRegNum<[30]>; - def X31 : RISCVReg<31,"x31", ["t6"]>, DwarfRegNum<[31]>; + def X16_H : RISCVReg<16,"x16", ["a6"]>; + def X17_H : RISCVReg<17,"x17", ["a7"]>; + def X18_H : RISCVReg<18,"x18", ["s2"]>; + def X19_H : RISCVReg<19,"x19", ["s3"]>; + def X20_H : RISCVReg<20,"x20", ["s4"]>; + def X21_H : RISCVReg<21,"x21", ["s5"]>; + def X22_H : RISCVReg<22,"x22", ["s6"]>; + def X23_H : RISCVReg<23,"x23", ["s7"]>; + def X24_H : RISCVReg<24,"x24", ["s8"]>; + def X25_H : RISCVReg<25,"x25", ["s9"]>; + def X26_H : RISCVReg<26,"x26", ["s10"]>; + def X27_H : RISCVReg<27,"x27", ["s11"]>; + def X28_H : RISCVReg<28,"x28", ["t3"]>; + def X29_H : RISCVReg<29,"x29", ["t4"]>; + def X30_H : RISCVReg<30,"x30", ["t5"]>; + def X31_H : RISCVReg<31,"x31", ["t6"]>; + } + + let SubRegIndices = [sub_16] in { + let isConstant = true in + def X0 : RISCVRegWithSubRegs<0, "x0", [X0_H], ["zero"]>, DwarfRegNum<[0]>; + let CostPerUse = [0, 1] in { + def X1 : RISCVRegWithSubRegs<1, "x1", [X1_H], ["ra"]>, DwarfRegNum<[1]>; + def X2 : RISCVRegWithSubRegs<2, "x2", [X2_H], ["sp"]>, DwarfRegNum<[2]>; + def X3 : RISCVRegWithSubRegs<3, "x3", [X3_H], ["gp"]>, DwarfRegNum<[3]>; + def X4 : RISCVRegWithSubRegs<4, "x4", [X4_H], ["tp"]>, DwarfRegNum<[4]>; + def X5 : RISCVRegWithSubRegs<5, "x5", [X5_H], ["t0"]>, DwarfRegNum<[5]>; + def X6 : RISCVRegWithSubRegs<6, "x6", [X6_H], ["t1"]>, DwarfRegNum<[6]>; + def X7 : RISCVRegWithSubRegs<7, "x7", [X7_H], ["t2"]>, DwarfRegNum<[7]>; + } + def X8 : RISCVRegWithSubRegs<8, "x8", [X8_H], ["s0", "fp"]>, DwarfRegNum<[8]>; + def X9 : RISCVRegWithSubRegs<9, "x9", [X9_H], ["s1"]>, DwarfRegNum<[9]>; + def X10 : RISCVRegWithSubRegs<10,"x10", [X10_H], ["a0"]>, DwarfRegNum<[10]>; + def X11 : RISCVRegWithSubRegs<11,"x11", [X11_H], ["a1"]>, DwarfRegNum<[11]>; + def X12 : RISCVRegWithSubRegs<12,"x12", [X12_H], ["a2"]>, DwarfRegNum<[12]>; + def X13 : RISCVRegWithSubRegs<13,"x13", [X13_H], ["a3"]>, DwarfRegNum<[13]>; + def X14 : RISCVRegWithSubRegs<14,"x14", [X14_H], ["a4"]>, DwarfRegNum<[14]>; + def X15 : RISCVRegWithSubRegs<15,"x15", [X15_H], ["a5"]>, DwarfRegNum<[15]>; + let CostPerUse = [0, 1] in { + def X16 : RISCVRegWithSubRegs<16,"x16", [X16_H], ["a6"]>, DwarfRegNum<[16]>; + def X17 : RISCVRegWithSubRegs<17,"x17", [X17_H], ["a7"]>, DwarfRegNum<[17]>; + def X18 : RISCVRegWithSubRegs<18,"x18", [X18_H], ["s2"]>, DwarfRegNum<[18]>; + def X19 : RISCVRegWithSubRegs<19,"x19", [X19_H], ["s3"]>, DwarfRegNum<[19]>; + def X20 : RISCVRegWithSubRegs<20,"x20", [X20_H], ["s4"]>, DwarfRegNum<[20]>; + def X21 : RISCVRegWithSubRegs<21,"x21", [X21_H], ["s5"]>, DwarfRegNum<[21]>; + def X22 : RISCVRegWithSubRegs<22,"x22", [X22_H], ["s6"]>, DwarfRegNum<[22]>; + def X23 : RISCVRegWithSubRegs<23,"x23", [X23_H], ["s7"]>, DwarfRegNum<[23]>; + def X24 : RISCVRegWithSubRegs<24,"x24", [X24_H], ["s8"]>, DwarfRegNum<[24]>; + def X25 : RISCVRegWithSubRegs<25,"x25", [X25_H], ["s9"]>, DwarfRegNum<[25]>; + def X26 : RISCVRegWithSubRegs<26,"x26", [X26_H], ["s10"]>, DwarfRegNum<[26]>; + def X27 : RISCVRegWithSubRegs<27,"x27", [X27_H], ["s11"]>, DwarfRegNum<[27]>; + def X28 : RISCVRegWithSubRegs<28,"x28", [X28_H], ["t3"]>, DwarfRegNum<[28]>; + def X29 : RISCVRegWithSubRegs<29,"x29", [X29_H], ["t4"]>, DwarfRegNum<[29]>; + def X30 : RISCVRegWithSubRegs<30,"x30", [X30_H], ["t5"]>, DwarfRegNum<[30]>; + def X31 : RISCVRegWithSubRegs<31,"x31", [X31_H], ["t6"]>, DwarfRegNum<[31]>; + } } } @@ -565,8 +607,17 @@ def VRM8NoV0 : VReg; def VMV0 : VReg; +// 16-bit GPR sub-register class used by Zhinx instructions. +def GPRF16 : RISCVRegisterClass<[f16], 16, (add (sequence "X%u_H", 10, 17), + (sequence "X%u_H", 5, 7), + (sequence "X%u_H", 28, 31), + (sequence "X%u_H", 8, 9), + (sequence "X%u_H", 18, 27), + (sequence "X%u_H", 0, 4))>; +def GPRF16C : RISCVRegisterClass<[f16], 16, (add (sequence "X%u_H", 10, 15), + (sequence "X%u_H", 8, 9))>; + let RegInfos = XLenRI in { -def GPRF16 : RISCVRegisterClass<[f16], 16, (add GPR)>; def GPRF32 : RISCVRegisterClass<[f32], 32, (add GPR)>; } // RegInfos = XLenRI diff --git a/llvm/test/CodeGen/RISCV/codemodel-lowering.ll b/llvm/test/CodeGen/RISCV/codemodel-lowering.ll index ad81db75f7bc9..4831f0b24c7fe 100644 --- a/llvm/test/CodeGen/RISCV/codemodel-lowering.ll +++ b/llvm/test/CodeGen/RISCV/codemodel-lowering.ll @@ -1,14 +1,24 @@ ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py -; RUN: llc -mtriple=riscv32 -mattr=+f -target-abi=ilp32f -code-model=small -verify-machineinstrs < %s \ -; RUN: | FileCheck %s -check-prefix=RV32I-SMALL -; RUN: llc -mtriple=riscv32 -mattr=+f -target-abi=ilp32f -code-model=medium -verify-machineinstrs < %s \ -; RUN: | FileCheck %s -check-prefix=RV32I-MEDIUM -; RUN: llc -mtriple=riscv64 -mattr=+f -target-abi=lp64f -code-model=small -verify-machineinstrs < %s \ -; RUN: | FileCheck %s -check-prefix=RV64I-SMALL -; RUN: llc -mtriple=riscv64 -mattr=+f -target-abi=lp64f -code-model=medium -verify-machineinstrs < %s \ -; RUN: | FileCheck %s -check-prefix=RV64I-MEDIUM -; RUN: llc -mtriple=riscv64 -mattr=+f -target-abi=lp64f -code-model=large -verify-machineinstrs < %s \ -; RUN: | FileCheck %s -check-prefix=RV64I-LARGE +; RUN: llc -mtriple=riscv32 -mattr=+f,+zfh -target-abi=ilp32f -code-model=small -verify-machineinstrs < %s \ +; RUN: | FileCheck %s -check-prefixes=RV32I-SMALL,RV32F-SMALL +; RUN: llc -mtriple=riscv32 -mattr=+f,+zfh -target-abi=ilp32f -code-model=medium -verify-machineinstrs < %s \ +; RUN: | FileCheck %s -check-prefixes=RV32I-MEDIUM,RV32F-MEDIUM +; RUN: llc -mtriple=riscv64 -mattr=+f,+zfh -target-abi=lp64f -code-model=small -verify-machineinstrs < %s \ +; RUN: | FileCheck %s -check-prefixes=RV64I-SMALL,RV64F-SMALL +; RUN: llc -mtriple=riscv64 -mattr=+f,+zfh -target-abi=lp64f -code-model=medium -verify-machineinstrs < %s \ +; RUN: | FileCheck %s -check-prefixes=RV64I-MEDIUM,RV64F-MEDIUM +; RUN: llc -mtriple=riscv64 -mattr=+f,+zfh -target-abi=lp64f -code-model=large -verify-machineinstrs < %s \ +; RUN: | FileCheck %s -check-prefixes=RV64I-LARGE,RV64F-LARGE +; RUN: llc -mtriple=riscv32 -mattr=+zfinx,+zhinx -target-abi=ilp32 -code-model=small -verify-machineinstrs < %s \ +; RUN: | FileCheck %s -check-prefixes=RV32I-SMALL,RV32FINX-SMALL +; RUN: llc -mtriple=riscv32 -mattr=+zfinx,+zhinx -target-abi=ilp32 -code-model=medium -verify-machineinstrs < %s \ +; RUN: | FileCheck %s -check-prefixes=RV32I-MEDIUM,RV32FINX-MEDIUM +; RUN: llc -mtriple=riscv64 -mattr=+zfinx,+zhinx -target-abi=lp64 -code-model=small -verify-machineinstrs < %s \ +; RUN: | FileCheck %s -check-prefixes=RV64I-SMALL,RV64FINX-SMALL +; RUN: llc -mtriple=riscv64 -mattr=+zfinx,+zhinx -target-abi=lp64 -code-model=medium -verify-machineinstrs < %s \ +; RUN: | FileCheck %s -check-prefixes=RV64I-MEDIUM,RV64FINX-MEDIUM +; RUN: llc -mtriple=riscv64 -mattr=+zfinx,+zhinx -target-abi=lp64 -code-model=large -verify-machineinstrs < %s \ +; RUN: | FileCheck %s -check-prefixes=RV64I-LARGE,RV64FINX-LARGE ; Check lowering of globals @G = global i32 0 @@ -238,43 +248,78 @@ indirectgoto: ; Check lowering of constantpools define float @lower_constantpool(float %a) nounwind { -; RV32I-SMALL-LABEL: lower_constantpool: -; RV32I-SMALL: # %bb.0: -; RV32I-SMALL-NEXT: lui a0, %hi(.LCPI3_0) -; RV32I-SMALL-NEXT: flw fa5, %lo(.LCPI3_0)(a0) -; RV32I-SMALL-NEXT: fadd.s fa0, fa0, fa5 -; RV32I-SMALL-NEXT: ret +; RV32F-SMALL-LABEL: lower_constantpool: +; RV32F-SMALL: # %bb.0: +; RV32F-SMALL-NEXT: lui a0, %hi(.LCPI3_0) +; RV32F-SMALL-NEXT: flw fa5, %lo(.LCPI3_0)(a0) +; RV32F-SMALL-NEXT: fadd.s fa0, fa0, fa5 +; RV32F-SMALL-NEXT: ret ; -; RV32I-MEDIUM-LABEL: lower_constantpool: -; RV32I-MEDIUM: # %bb.0: -; RV32I-MEDIUM-NEXT: .Lpcrel_hi3: -; RV32I-MEDIUM-NEXT: auipc a0, %pcrel_hi(.LCPI3_0) -; RV32I-MEDIUM-NEXT: flw fa5, %pcrel_lo(.Lpcrel_hi3)(a0) -; RV32I-MEDIUM-NEXT: fadd.s fa0, fa0, fa5 -; RV32I-MEDIUM-NEXT: ret +; RV32F-MEDIUM-LABEL: lower_constantpool: +; RV32F-MEDIUM: # %bb.0: +; RV32F-MEDIUM-NEXT: .Lpcrel_hi3: +; RV32F-MEDIUM-NEXT: auipc a0, %pcrel_hi(.LCPI3_0) +; RV32F-MEDIUM-NEXT: flw fa5, %pcrel_lo(.Lpcrel_hi3)(a0) +; RV32F-MEDIUM-NEXT: fadd.s fa0, fa0, fa5 +; RV32F-MEDIUM-NEXT: ret ; -; RV64I-SMALL-LABEL: lower_constantpool: -; RV64I-SMALL: # %bb.0: -; RV64I-SMALL-NEXT: lui a0, %hi(.LCPI3_0) -; RV64I-SMALL-NEXT: flw fa5, %lo(.LCPI3_0)(a0) -; RV64I-SMALL-NEXT: fadd.s fa0, fa0, fa5 -; RV64I-SMALL-NEXT: ret +; RV64F-SMALL-LABEL: lower_constantpool: +; RV64F-SMALL: # %bb.0: +; RV64F-SMALL-NEXT: lui a0, %hi(.LCPI3_0) +; RV64F-SMALL-NEXT: flw fa5, %lo(.LCPI3_0)(a0) +; RV64F-SMALL-NEXT: fadd.s fa0, fa0, fa5 +; RV64F-SMALL-NEXT: ret ; -; RV64I-MEDIUM-LABEL: lower_constantpool: -; RV64I-MEDIUM: # %bb.0: -; RV64I-MEDIUM-NEXT: .Lpcrel_hi3: -; RV64I-MEDIUM-NEXT: auipc a0, %pcrel_hi(.LCPI3_0) -; RV64I-MEDIUM-NEXT: flw fa5, %pcrel_lo(.Lpcrel_hi3)(a0) -; RV64I-MEDIUM-NEXT: fadd.s fa0, fa0, fa5 -; RV64I-MEDIUM-NEXT: ret +; RV64F-MEDIUM-LABEL: lower_constantpool: +; RV64F-MEDIUM: # %bb.0: +; RV64F-MEDIUM-NEXT: .Lpcrel_hi3: +; RV64F-MEDIUM-NEXT: auipc a0, %pcrel_hi(.LCPI3_0) +; RV64F-MEDIUM-NEXT: flw fa5, %pcrel_lo(.Lpcrel_hi3)(a0) +; RV64F-MEDIUM-NEXT: fadd.s fa0, fa0, fa5 +; RV64F-MEDIUM-NEXT: ret ; -; RV64I-LARGE-LABEL: lower_constantpool: -; RV64I-LARGE: # %bb.0: -; RV64I-LARGE-NEXT: .Lpcrel_hi3: -; RV64I-LARGE-NEXT: auipc a0, %pcrel_hi(.LCPI3_0) -; RV64I-LARGE-NEXT: flw fa5, %pcrel_lo(.Lpcrel_hi3)(a0) -; RV64I-LARGE-NEXT: fadd.s fa0, fa0, fa5 -; RV64I-LARGE-NEXT: ret +; RV64F-LARGE-LABEL: lower_constantpool: +; RV64F-LARGE: # %bb.0: +; RV64F-LARGE-NEXT: .Lpcrel_hi3: +; RV64F-LARGE-NEXT: auipc a0, %pcrel_hi(.LCPI3_0) +; RV64F-LARGE-NEXT: flw fa5, %pcrel_lo(.Lpcrel_hi3)(a0) +; RV64F-LARGE-NEXT: fadd.s fa0, fa0, fa5 +; RV64F-LARGE-NEXT: ret +; +; RV32FINX-SMALL-LABEL: lower_constantpool: +; RV32FINX-SMALL: # %bb.0: +; RV32FINX-SMALL-NEXT: lui a1, 260097 +; RV32FINX-SMALL-NEXT: addi a1, a1, -2048 +; RV32FINX-SMALL-NEXT: fadd.s a0, a0, a1 +; RV32FINX-SMALL-NEXT: ret +; +; RV32FINX-MEDIUM-LABEL: lower_constantpool: +; RV32FINX-MEDIUM: # %bb.0: +; RV32FINX-MEDIUM-NEXT: lui a1, 260097 +; RV32FINX-MEDIUM-NEXT: addi a1, a1, -2048 +; RV32FINX-MEDIUM-NEXT: fadd.s a0, a0, a1 +; RV32FINX-MEDIUM-NEXT: ret +; +; RV64FINX-SMALL-LABEL: lower_constantpool: +; RV64FINX-SMALL: # %bb.0: +; RV64FINX-SMALL-NEXT: lui a1, 260097 +; RV64FINX-SMALL-NEXT: addiw a1, a1, -2048 +; RV64FINX-SMALL-NEXT: fadd.s a0, a0, a1 +; RV64FINX-SMALL-NEXT: ret +; +; RV64FINX-MEDIUM-LABEL: lower_constantpool: +; RV64FINX-MEDIUM: # %bb.0: +; RV64FINX-MEDIUM-NEXT: lui a1, 260097 +; RV64FINX-MEDIUM-NEXT: addiw a1, a1, -2048 +; RV64FINX-MEDIUM-NEXT: fadd.s a0, a0, a1 +; RV64FINX-MEDIUM-NEXT: ret +; +; RV64FINX-LARGE-LABEL: lower_constantpool: +; RV64FINX-LARGE: # %bb.0: +; RV64FINX-LARGE-NEXT: lui a1, 260097 +; RV64FINX-LARGE-NEXT: addiw a1, a1, -2048 +; RV64FINX-LARGE-NEXT: fadd.s a0, a0, a1 +; RV64FINX-LARGE-NEXT: ret %1 = fadd float %a, 1.000244140625 ret float %1 } @@ -289,13 +334,13 @@ define i32 @lower_extern_weak(i32 %a) nounwind { ; RV32I-SMALL-NEXT: lw a0, %lo(W)(a0) ; RV32I-SMALL-NEXT: ret ; -; RV32I-MEDIUM-LABEL: lower_extern_weak: -; RV32I-MEDIUM: # %bb.0: -; RV32I-MEDIUM-NEXT: .Lpcrel_hi4: -; RV32I-MEDIUM-NEXT: auipc a0, %got_pcrel_hi(W) -; RV32I-MEDIUM-NEXT: lw a0, %pcrel_lo(.Lpcrel_hi4)(a0) -; RV32I-MEDIUM-NEXT: lw a0, 0(a0) -; RV32I-MEDIUM-NEXT: ret +; RV32F-MEDIUM-LABEL: lower_extern_weak: +; RV32F-MEDIUM: # %bb.0: +; RV32F-MEDIUM-NEXT: .Lpcrel_hi4: +; RV32F-MEDIUM-NEXT: auipc a0, %got_pcrel_hi(W) +; RV32F-MEDIUM-NEXT: lw a0, %pcrel_lo(.Lpcrel_hi4)(a0) +; RV32F-MEDIUM-NEXT: lw a0, 0(a0) +; RV32F-MEDIUM-NEXT: ret ; ; RV64I-SMALL-LABEL: lower_extern_weak: ; RV64I-SMALL: # %bb.0: @@ -303,21 +348,130 @@ define i32 @lower_extern_weak(i32 %a) nounwind { ; RV64I-SMALL-NEXT: lw a0, %lo(W)(a0) ; RV64I-SMALL-NEXT: ret ; -; RV64I-MEDIUM-LABEL: lower_extern_weak: -; RV64I-MEDIUM: # %bb.0: -; RV64I-MEDIUM-NEXT: .Lpcrel_hi4: -; RV64I-MEDIUM-NEXT: auipc a0, %got_pcrel_hi(W) -; RV64I-MEDIUM-NEXT: ld a0, %pcrel_lo(.Lpcrel_hi4)(a0) -; RV64I-MEDIUM-NEXT: lw a0, 0(a0) -; RV64I-MEDIUM-NEXT: ret +; RV64F-MEDIUM-LABEL: lower_extern_weak: +; RV64F-MEDIUM: # %bb.0: +; RV64F-MEDIUM-NEXT: .Lpcrel_hi4: +; RV64F-MEDIUM-NEXT: auipc a0, %got_pcrel_hi(W) +; RV64F-MEDIUM-NEXT: ld a0, %pcrel_lo(.Lpcrel_hi4)(a0) +; RV64F-MEDIUM-NEXT: lw a0, 0(a0) +; RV64F-MEDIUM-NEXT: ret ; -; RV64I-LARGE-LABEL: lower_extern_weak: -; RV64I-LARGE: # %bb.0: -; RV64I-LARGE-NEXT: .Lpcrel_hi4: -; RV64I-LARGE-NEXT: auipc a0, %pcrel_hi(.LCPI4_0) -; RV64I-LARGE-NEXT: ld a0, %pcrel_lo(.Lpcrel_hi4)(a0) -; RV64I-LARGE-NEXT: lw a0, 0(a0) -; RV64I-LARGE-NEXT: ret +; RV64F-LARGE-LABEL: lower_extern_weak: +; RV64F-LARGE: # %bb.0: +; RV64F-LARGE-NEXT: .Lpcrel_hi4: +; RV64F-LARGE-NEXT: auipc a0, %pcrel_hi(.LCPI4_0) +; RV64F-LARGE-NEXT: ld a0, %pcrel_lo(.Lpcrel_hi4)(a0) +; RV64F-LARGE-NEXT: lw a0, 0(a0) +; RV64F-LARGE-NEXT: ret +; +; RV32FINX-MEDIUM-LABEL: lower_extern_weak: +; RV32FINX-MEDIUM: # %bb.0: +; RV32FINX-MEDIUM-NEXT: .Lpcrel_hi3: +; RV32FINX-MEDIUM-NEXT: auipc a0, %got_pcrel_hi(W) +; RV32FINX-MEDIUM-NEXT: lw a0, %pcrel_lo(.Lpcrel_hi3)(a0) +; RV32FINX-MEDIUM-NEXT: lw a0, 0(a0) +; RV32FINX-MEDIUM-NEXT: ret +; +; RV64FINX-MEDIUM-LABEL: lower_extern_weak: +; RV64FINX-MEDIUM: # %bb.0: +; RV64FINX-MEDIUM-NEXT: .Lpcrel_hi3: +; RV64FINX-MEDIUM-NEXT: auipc a0, %got_pcrel_hi(W) +; RV64FINX-MEDIUM-NEXT: ld a0, %pcrel_lo(.Lpcrel_hi3)(a0) +; RV64FINX-MEDIUM-NEXT: lw a0, 0(a0) +; RV64FINX-MEDIUM-NEXT: ret +; +; RV64FINX-LARGE-LABEL: lower_extern_weak: +; RV64FINX-LARGE: # %bb.0: +; RV64FINX-LARGE-NEXT: .Lpcrel_hi3: +; RV64FINX-LARGE-NEXT: auipc a0, %pcrel_hi(.LCPI4_0) +; RV64FINX-LARGE-NEXT: ld a0, %pcrel_lo(.Lpcrel_hi3)(a0) +; RV64FINX-LARGE-NEXT: lw a0, 0(a0) +; RV64FINX-LARGE-NEXT: ret %1 = load volatile i32, ptr @W ret i32 %1 } + +@X = global half 1.5 + +define half @lower_global_half(half %a) nounwind { +; RV32F-SMALL-LABEL: lower_global_half: +; RV32F-SMALL: # %bb.0: +; RV32F-SMALL-NEXT: lui a0, %hi(X) +; RV32F-SMALL-NEXT: flh fa5, %lo(X)(a0) +; RV32F-SMALL-NEXT: fadd.h fa0, fa0, fa5 +; RV32F-SMALL-NEXT: ret +; +; RV32F-MEDIUM-LABEL: lower_global_half: +; RV32F-MEDIUM: # %bb.0: +; RV32F-MEDIUM-NEXT: .Lpcrel_hi5: +; RV32F-MEDIUM-NEXT: auipc a0, %pcrel_hi(X) +; RV32F-MEDIUM-NEXT: flh fa5, %pcrel_lo(.Lpcrel_hi5)(a0) +; RV32F-MEDIUM-NEXT: fadd.h fa0, fa0, fa5 +; RV32F-MEDIUM-NEXT: ret +; +; RV64F-SMALL-LABEL: lower_global_half: +; RV64F-SMALL: # %bb.0: +; RV64F-SMALL-NEXT: lui a0, %hi(X) +; RV64F-SMALL-NEXT: flh fa5, %lo(X)(a0) +; RV64F-SMALL-NEXT: fadd.h fa0, fa0, fa5 +; RV64F-SMALL-NEXT: ret +; +; RV64F-MEDIUM-LABEL: lower_global_half: +; RV64F-MEDIUM: # %bb.0: +; RV64F-MEDIUM-NEXT: .Lpcrel_hi5: +; RV64F-MEDIUM-NEXT: auipc a0, %pcrel_hi(X) +; RV64F-MEDIUM-NEXT: flh fa5, %pcrel_lo(.Lpcrel_hi5)(a0) +; RV64F-MEDIUM-NEXT: fadd.h fa0, fa0, fa5 +; RV64F-MEDIUM-NEXT: ret +; +; RV64F-LARGE-LABEL: lower_global_half: +; RV64F-LARGE: # %bb.0: +; RV64F-LARGE-NEXT: .Lpcrel_hi5: +; RV64F-LARGE-NEXT: auipc a0, %pcrel_hi(.LCPI5_0) +; RV64F-LARGE-NEXT: ld a0, %pcrel_lo(.Lpcrel_hi5)(a0) +; RV64F-LARGE-NEXT: flh fa5, 0(a0) +; RV64F-LARGE-NEXT: fadd.h fa0, fa0, fa5 +; RV64F-LARGE-NEXT: ret +; +; RV32FINX-SMALL-LABEL: lower_global_half: +; RV32FINX-SMALL: # %bb.0: +; RV32FINX-SMALL-NEXT: lui a1, %hi(X) +; RV32FINX-SMALL-NEXT: lh a1, %lo(X)(a1) +; RV32FINX-SMALL-NEXT: fadd.h a0, a0, a1 +; RV32FINX-SMALL-NEXT: ret +; +; RV32FINX-MEDIUM-LABEL: lower_global_half: +; RV32FINX-MEDIUM: # %bb.0: +; RV32FINX-MEDIUM-NEXT: .Lpcrel_hi4: +; RV32FINX-MEDIUM-NEXT: auipc a1, %pcrel_hi(X) +; RV32FINX-MEDIUM-NEXT: lh a1, %pcrel_lo(.Lpcrel_hi4)(a1) +; RV32FINX-MEDIUM-NEXT: fadd.h a0, a0, a1 +; RV32FINX-MEDIUM-NEXT: ret +; +; RV64FINX-SMALL-LABEL: lower_global_half: +; RV64FINX-SMALL: # %bb.0: +; RV64FINX-SMALL-NEXT: lui a1, %hi(X) +; RV64FINX-SMALL-NEXT: lh a1, %lo(X)(a1) +; RV64FINX-SMALL-NEXT: fadd.h a0, a0, a1 +; RV64FINX-SMALL-NEXT: ret +; +; RV64FINX-MEDIUM-LABEL: lower_global_half: +; RV64FINX-MEDIUM: # %bb.0: +; RV64FINX-MEDIUM-NEXT: .Lpcrel_hi4: +; RV64FINX-MEDIUM-NEXT: auipc a1, %pcrel_hi(X) +; RV64FINX-MEDIUM-NEXT: lh a1, %pcrel_lo(.Lpcrel_hi4)(a1) +; RV64FINX-MEDIUM-NEXT: fadd.h a0, a0, a1 +; RV64FINX-MEDIUM-NEXT: ret +; +; RV64FINX-LARGE-LABEL: lower_global_half: +; RV64FINX-LARGE: # %bb.0: +; RV64FINX-LARGE-NEXT: .Lpcrel_hi4: +; RV64FINX-LARGE-NEXT: auipc a1, %pcrel_hi(.LCPI5_0) +; RV64FINX-LARGE-NEXT: ld a1, %pcrel_lo(.Lpcrel_hi4)(a1) +; RV64FINX-LARGE-NEXT: lh a1, 0(a1) +; RV64FINX-LARGE-NEXT: fadd.h a0, a0, a1 +; RV64FINX-LARGE-NEXT: ret + %b = load half, ptr @X + %1 = fadd half %a, %b + ret half %1 +} diff --git a/llvm/test/CodeGen/RISCV/fastcc-without-f-reg.ll b/llvm/test/CodeGen/RISCV/fastcc-without-f-reg.ll index ca40ba0399973..de5bb8a30db16 100644 --- a/llvm/test/CodeGen/RISCV/fastcc-without-f-reg.ll +++ b/llvm/test/CodeGen/RISCV/fastcc-without-f-reg.ll @@ -246,28 +246,32 @@ define fastcc half @callee_half_32(<32 x half> %A) nounwind { define half @caller_half_32(<32 x half> %A) nounwind { ; ZHINX32-LABEL: caller_half_32: ; ZHINX32: # %bb.0: -; ZHINX32-NEXT: addi sp, sp, -96 -; ZHINX32-NEXT: sw ra, 92(sp) # 4-byte Folded Spill -; ZHINX32-NEXT: sw s0, 88(sp) # 4-byte Folded Spill -; ZHINX32-NEXT: sw s1, 84(sp) # 4-byte Folded Spill -; ZHINX32-NEXT: sw s2, 80(sp) # 4-byte Folded Spill -; ZHINX32-NEXT: sw s3, 76(sp) # 4-byte Folded Spill -; ZHINX32-NEXT: sw s4, 72(sp) # 4-byte Folded Spill -; ZHINX32-NEXT: sw s5, 68(sp) # 4-byte Folded Spill -; ZHINX32-NEXT: sw s6, 64(sp) # 4-byte Folded Spill -; ZHINX32-NEXT: sw s7, 60(sp) # 4-byte Folded Spill -; ZHINX32-NEXT: sw s8, 56(sp) # 4-byte Folded Spill -; ZHINX32-NEXT: sw s9, 52(sp) # 4-byte Folded Spill -; ZHINX32-NEXT: sw s10, 48(sp) # 4-byte Folded Spill -; ZHINX32-NEXT: sw s11, 44(sp) # 4-byte Folded Spill +; ZHINX32-NEXT: addi sp, sp, -112 +; ZHINX32-NEXT: sw ra, 108(sp) # 4-byte Folded Spill +; ZHINX32-NEXT: sw s0, 104(sp) # 4-byte Folded Spill +; ZHINX32-NEXT: sw s1, 100(sp) # 4-byte Folded Spill +; ZHINX32-NEXT: sw s2, 96(sp) # 4-byte Folded Spill +; ZHINX32-NEXT: sw s3, 92(sp) # 4-byte Folded Spill +; ZHINX32-NEXT: sw s4, 88(sp) # 4-byte Folded Spill +; ZHINX32-NEXT: sw s5, 84(sp) # 4-byte Folded Spill +; ZHINX32-NEXT: sw s6, 80(sp) # 4-byte Folded Spill +; ZHINX32-NEXT: sw s7, 76(sp) # 4-byte Folded Spill +; ZHINX32-NEXT: sw s8, 72(sp) # 4-byte Folded Spill +; ZHINX32-NEXT: sw s9, 68(sp) # 4-byte Folded Spill +; ZHINX32-NEXT: sw s10, 64(sp) # 4-byte Folded Spill +; ZHINX32-NEXT: sw s11, 60(sp) # 4-byte Folded Spill ; ZHINX32-NEXT: lh t0, 112(sp) -; ZHINX32-NEXT: lh t1, 116(sp) -; ZHINX32-NEXT: lh t2, 120(sp) -; ZHINX32-NEXT: lh s0, 124(sp) -; ZHINX32-NEXT: lh t3, 128(sp) -; ZHINX32-NEXT: lh t4, 132(sp) -; ZHINX32-NEXT: lh t5, 136(sp) -; ZHINX32-NEXT: lh t6, 140(sp) +; ZHINX32-NEXT: sh t0, 58(sp) # 2-byte Folded Spill +; ZHINX32-NEXT: lh t0, 116(sp) +; ZHINX32-NEXT: sh t0, 56(sp) # 2-byte Folded Spill +; ZHINX32-NEXT: lh t0, 120(sp) +; ZHINX32-NEXT: sh t0, 54(sp) # 2-byte Folded Spill +; ZHINX32-NEXT: lh t0, 124(sp) +; ZHINX32-NEXT: sh t0, 52(sp) # 2-byte Folded Spill +; ZHINX32-NEXT: lh t6, 128(sp) +; ZHINX32-NEXT: lh t5, 132(sp) +; ZHINX32-NEXT: lh t4, 136(sp) +; ZHINX32-NEXT: lh s0, 140(sp) ; ZHINX32-NEXT: lh s1, 144(sp) ; ZHINX32-NEXT: lh s2, 148(sp) ; ZHINX32-NEXT: lh s3, 152(sp) @@ -280,122 +284,134 @@ define half @caller_half_32(<32 x half> %A) nounwind { ; ZHINX32-NEXT: lh s10, 180(sp) ; ZHINX32-NEXT: lh s11, 184(sp) ; ZHINX32-NEXT: lh ra, 188(sp) -; ZHINX32-NEXT: sh ra, 38(sp) -; ZHINX32-NEXT: sh s11, 36(sp) -; ZHINX32-NEXT: sh s10, 34(sp) -; ZHINX32-NEXT: sh s9, 32(sp) -; ZHINX32-NEXT: sh s8, 30(sp) -; ZHINX32-NEXT: sh s7, 28(sp) -; ZHINX32-NEXT: sh s6, 26(sp) -; ZHINX32-NEXT: sh s5, 24(sp) -; ZHINX32-NEXT: sh s4, 22(sp) -; ZHINX32-NEXT: sh s3, 20(sp) -; ZHINX32-NEXT: sh s2, 18(sp) -; ZHINX32-NEXT: sh s1, 16(sp) -; ZHINX32-NEXT: sh t6, 14(sp) -; ZHINX32-NEXT: sh t5, 12(sp) -; ZHINX32-NEXT: sh t4, 10(sp) -; ZHINX32-NEXT: sh t3, 8(sp) -; ZHINX32-NEXT: lh t3, 96(sp) -; ZHINX32-NEXT: lh t4, 100(sp) -; ZHINX32-NEXT: lh t5, 104(sp) -; ZHINX32-NEXT: lh t6, 108(sp) +; ZHINX32-NEXT: lh t3, 192(sp) +; ZHINX32-NEXT: lh t2, 196(sp) +; ZHINX32-NEXT: lh t1, 200(sp) +; ZHINX32-NEXT: lh t0, 204(sp) +; ZHINX32-NEXT: sh t0, 38(sp) +; ZHINX32-NEXT: sh t1, 36(sp) +; ZHINX32-NEXT: sh t2, 34(sp) +; ZHINX32-NEXT: sh t3, 32(sp) +; ZHINX32-NEXT: sh ra, 30(sp) +; ZHINX32-NEXT: sh s11, 28(sp) +; ZHINX32-NEXT: sh s10, 26(sp) +; ZHINX32-NEXT: sh s9, 24(sp) +; ZHINX32-NEXT: sh s8, 22(sp) +; ZHINX32-NEXT: sh s7, 20(sp) +; ZHINX32-NEXT: sh s6, 18(sp) +; ZHINX32-NEXT: sh s5, 16(sp) +; ZHINX32-NEXT: sh s4, 14(sp) +; ZHINX32-NEXT: sh s3, 12(sp) +; ZHINX32-NEXT: sh s2, 10(sp) +; ZHINX32-NEXT: sh s1, 8(sp) ; ZHINX32-NEXT: sh s0, 6(sp) -; ZHINX32-NEXT: sh t2, 4(sp) -; ZHINX32-NEXT: sh t1, 2(sp) -; ZHINX32-NEXT: sh t0, 0(sp) +; ZHINX32-NEXT: sh t4, 4(sp) +; ZHINX32-NEXT: sh t5, 2(sp) +; ZHINX32-NEXT: sh t6, 0(sp) +; ZHINX32-NEXT: lh t3, 58(sp) # 2-byte Folded Reload +; ZHINX32-NEXT: lh t4, 56(sp) # 2-byte Folded Reload +; ZHINX32-NEXT: lh t5, 54(sp) # 2-byte Folded Reload +; ZHINX32-NEXT: lh t6, 52(sp) # 2-byte Folded Reload ; ZHINX32-NEXT: call callee_half_32 -; ZHINX32-NEXT: lw ra, 92(sp) # 4-byte Folded Reload -; ZHINX32-NEXT: lw s0, 88(sp) # 4-byte Folded Reload -; ZHINX32-NEXT: lw s1, 84(sp) # 4-byte Folded Reload -; ZHINX32-NEXT: lw s2, 80(sp) # 4-byte Folded Reload -; ZHINX32-NEXT: lw s3, 76(sp) # 4-byte Folded Reload -; ZHINX32-NEXT: lw s4, 72(sp) # 4-byte Folded Reload -; ZHINX32-NEXT: lw s5, 68(sp) # 4-byte Folded Reload -; ZHINX32-NEXT: lw s6, 64(sp) # 4-byte Folded Reload -; ZHINX32-NEXT: lw s7, 60(sp) # 4-byte Folded Reload -; ZHINX32-NEXT: lw s8, 56(sp) # 4-byte Folded Reload -; ZHINX32-NEXT: lw s9, 52(sp) # 4-byte Folded Reload -; ZHINX32-NEXT: lw s10, 48(sp) # 4-byte Folded Reload -; ZHINX32-NEXT: lw s11, 44(sp) # 4-byte Folded Reload -; ZHINX32-NEXT: addi sp, sp, 96 +; ZHINX32-NEXT: lw ra, 108(sp) # 4-byte Folded Reload +; ZHINX32-NEXT: lw s0, 104(sp) # 4-byte Folded Reload +; ZHINX32-NEXT: lw s1, 100(sp) # 4-byte Folded Reload +; ZHINX32-NEXT: lw s2, 96(sp) # 4-byte Folded Reload +; ZHINX32-NEXT: lw s3, 92(sp) # 4-byte Folded Reload +; ZHINX32-NEXT: lw s4, 88(sp) # 4-byte Folded Reload +; ZHINX32-NEXT: lw s5, 84(sp) # 4-byte Folded Reload +; ZHINX32-NEXT: lw s6, 80(sp) # 4-byte Folded Reload +; ZHINX32-NEXT: lw s7, 76(sp) # 4-byte Folded Reload +; ZHINX32-NEXT: lw s8, 72(sp) # 4-byte Folded Reload +; ZHINX32-NEXT: lw s9, 68(sp) # 4-byte Folded Reload +; ZHINX32-NEXT: lw s10, 64(sp) # 4-byte Folded Reload +; ZHINX32-NEXT: lw s11, 60(sp) # 4-byte Folded Reload +; ZHINX32-NEXT: addi sp, sp, 112 ; ZHINX32-NEXT: ret ; ; ZHINX64-LABEL: caller_half_32: ; ZHINX64: # %bb.0: -; ZHINX64-NEXT: addi sp, sp, -144 -; ZHINX64-NEXT: sd ra, 136(sp) # 8-byte Folded Spill -; ZHINX64-NEXT: sd s0, 128(sp) # 8-byte Folded Spill -; ZHINX64-NEXT: sd s1, 120(sp) # 8-byte Folded Spill -; ZHINX64-NEXT: sd s2, 112(sp) # 8-byte Folded Spill -; ZHINX64-NEXT: sd s3, 104(sp) # 8-byte Folded Spill -; ZHINX64-NEXT: sd s4, 96(sp) # 8-byte Folded Spill -; ZHINX64-NEXT: sd s5, 88(sp) # 8-byte Folded Spill -; ZHINX64-NEXT: sd s6, 80(sp) # 8-byte Folded Spill -; ZHINX64-NEXT: sd s7, 72(sp) # 8-byte Folded Spill -; ZHINX64-NEXT: sd s8, 64(sp) # 8-byte Folded Spill -; ZHINX64-NEXT: sd s9, 56(sp) # 8-byte Folded Spill -; ZHINX64-NEXT: sd s10, 48(sp) # 8-byte Folded Spill -; ZHINX64-NEXT: sd s11, 40(sp) # 8-byte Folded Spill +; ZHINX64-NEXT: addi sp, sp, -160 +; ZHINX64-NEXT: sd ra, 152(sp) # 8-byte Folded Spill +; ZHINX64-NEXT: sd s0, 144(sp) # 8-byte Folded Spill +; ZHINX64-NEXT: sd s1, 136(sp) # 8-byte Folded Spill +; ZHINX64-NEXT: sd s2, 128(sp) # 8-byte Folded Spill +; ZHINX64-NEXT: sd s3, 120(sp) # 8-byte Folded Spill +; ZHINX64-NEXT: sd s4, 112(sp) # 8-byte Folded Spill +; ZHINX64-NEXT: sd s5, 104(sp) # 8-byte Folded Spill +; ZHINX64-NEXT: sd s6, 96(sp) # 8-byte Folded Spill +; ZHINX64-NEXT: sd s7, 88(sp) # 8-byte Folded Spill +; ZHINX64-NEXT: sd s8, 80(sp) # 8-byte Folded Spill +; ZHINX64-NEXT: sd s9, 72(sp) # 8-byte Folded Spill +; ZHINX64-NEXT: sd s10, 64(sp) # 8-byte Folded Spill +; ZHINX64-NEXT: sd s11, 56(sp) # 8-byte Folded Spill +; ZHINX64-NEXT: lh t0, 160(sp) +; ZHINX64-NEXT: sh t0, 54(sp) # 2-byte Folded Spill +; ZHINX64-NEXT: lh t0, 168(sp) +; ZHINX64-NEXT: sh t0, 52(sp) # 2-byte Folded Spill ; ZHINX64-NEXT: lh t0, 176(sp) -; ZHINX64-NEXT: lh t1, 184(sp) -; ZHINX64-NEXT: lh t2, 192(sp) -; ZHINX64-NEXT: lh s0, 200(sp) -; ZHINX64-NEXT: lh t3, 208(sp) -; ZHINX64-NEXT: lh t4, 216(sp) -; ZHINX64-NEXT: lh t5, 224(sp) -; ZHINX64-NEXT: lh t6, 232(sp) -; ZHINX64-NEXT: lh s1, 240(sp) -; ZHINX64-NEXT: lh s2, 248(sp) -; ZHINX64-NEXT: lh s3, 256(sp) -; ZHINX64-NEXT: lh s4, 264(sp) -; ZHINX64-NEXT: lh s5, 272(sp) -; ZHINX64-NEXT: lh s6, 280(sp) -; ZHINX64-NEXT: lh s7, 288(sp) -; ZHINX64-NEXT: lh s8, 296(sp) -; ZHINX64-NEXT: lh s9, 304(sp) -; ZHINX64-NEXT: lh s10, 312(sp) -; ZHINX64-NEXT: lh s11, 320(sp) -; ZHINX64-NEXT: lh ra, 328(sp) -; ZHINX64-NEXT: sh ra, 38(sp) -; ZHINX64-NEXT: sh s11, 36(sp) -; ZHINX64-NEXT: sh s10, 34(sp) -; ZHINX64-NEXT: sh s9, 32(sp) -; ZHINX64-NEXT: sh s8, 30(sp) -; ZHINX64-NEXT: sh s7, 28(sp) -; ZHINX64-NEXT: sh s6, 26(sp) -; ZHINX64-NEXT: sh s5, 24(sp) -; ZHINX64-NEXT: sh s4, 22(sp) -; ZHINX64-NEXT: sh s3, 20(sp) -; ZHINX64-NEXT: sh s2, 18(sp) -; ZHINX64-NEXT: sh s1, 16(sp) -; ZHINX64-NEXT: sh t6, 14(sp) -; ZHINX64-NEXT: sh t5, 12(sp) -; ZHINX64-NEXT: sh t4, 10(sp) -; ZHINX64-NEXT: sh t3, 8(sp) -; ZHINX64-NEXT: lh t3, 144(sp) -; ZHINX64-NEXT: lh t4, 152(sp) -; ZHINX64-NEXT: lh t5, 160(sp) -; ZHINX64-NEXT: lh t6, 168(sp) +; ZHINX64-NEXT: sh t0, 50(sp) # 2-byte Folded Spill +; ZHINX64-NEXT: lh t0, 184(sp) +; ZHINX64-NEXT: sh t0, 48(sp) # 2-byte Folded Spill +; ZHINX64-NEXT: lh t6, 192(sp) +; ZHINX64-NEXT: lh t5, 200(sp) +; ZHINX64-NEXT: lh t4, 208(sp) +; ZHINX64-NEXT: lh s0, 216(sp) +; ZHINX64-NEXT: lh s1, 224(sp) +; ZHINX64-NEXT: lh s2, 232(sp) +; ZHINX64-NEXT: lh s3, 240(sp) +; ZHINX64-NEXT: lh s4, 248(sp) +; ZHINX64-NEXT: lh s5, 256(sp) +; ZHINX64-NEXT: lh s6, 264(sp) +; ZHINX64-NEXT: lh s7, 272(sp) +; ZHINX64-NEXT: lh s8, 280(sp) +; ZHINX64-NEXT: lh s9, 288(sp) +; ZHINX64-NEXT: lh s10, 296(sp) +; ZHINX64-NEXT: lh s11, 304(sp) +; ZHINX64-NEXT: lh ra, 312(sp) +; ZHINX64-NEXT: lh t3, 320(sp) +; ZHINX64-NEXT: lh t2, 328(sp) +; ZHINX64-NEXT: lh t1, 336(sp) +; ZHINX64-NEXT: lh t0, 344(sp) +; ZHINX64-NEXT: sh t0, 38(sp) +; ZHINX64-NEXT: sh t1, 36(sp) +; ZHINX64-NEXT: sh t2, 34(sp) +; ZHINX64-NEXT: sh t3, 32(sp) +; ZHINX64-NEXT: sh ra, 30(sp) +; ZHINX64-NEXT: sh s11, 28(sp) +; ZHINX64-NEXT: sh s10, 26(sp) +; ZHINX64-NEXT: sh s9, 24(sp) +; ZHINX64-NEXT: sh s8, 22(sp) +; ZHINX64-NEXT: sh s7, 20(sp) +; ZHINX64-NEXT: sh s6, 18(sp) +; ZHINX64-NEXT: sh s5, 16(sp) +; ZHINX64-NEXT: sh s4, 14(sp) +; ZHINX64-NEXT: sh s3, 12(sp) +; ZHINX64-NEXT: sh s2, 10(sp) +; ZHINX64-NEXT: sh s1, 8(sp) ; ZHINX64-NEXT: sh s0, 6(sp) -; ZHINX64-NEXT: sh t2, 4(sp) -; ZHINX64-NEXT: sh t1, 2(sp) -; ZHINX64-NEXT: sh t0, 0(sp) +; ZHINX64-NEXT: sh t4, 4(sp) +; ZHINX64-NEXT: sh t5, 2(sp) +; ZHINX64-NEXT: sh t6, 0(sp) +; ZHINX64-NEXT: lh t3, 54(sp) # 2-byte Folded Reload +; ZHINX64-NEXT: lh t4, 52(sp) # 2-byte Folded Reload +; ZHINX64-NEXT: lh t5, 50(sp) # 2-byte Folded Reload +; ZHINX64-NEXT: lh t6, 48(sp) # 2-byte Folded Reload ; ZHINX64-NEXT: call callee_half_32 -; ZHINX64-NEXT: ld ra, 136(sp) # 8-byte Folded Reload -; ZHINX64-NEXT: ld s0, 128(sp) # 8-byte Folded Reload -; ZHINX64-NEXT: ld s1, 120(sp) # 8-byte Folded Reload -; ZHINX64-NEXT: ld s2, 112(sp) # 8-byte Folded Reload -; ZHINX64-NEXT: ld s3, 104(sp) # 8-byte Folded Reload -; ZHINX64-NEXT: ld s4, 96(sp) # 8-byte Folded Reload -; ZHINX64-NEXT: ld s5, 88(sp) # 8-byte Folded Reload -; ZHINX64-NEXT: ld s6, 80(sp) # 8-byte Folded Reload -; ZHINX64-NEXT: ld s7, 72(sp) # 8-byte Folded Reload -; ZHINX64-NEXT: ld s8, 64(sp) # 8-byte Folded Reload -; ZHINX64-NEXT: ld s9, 56(sp) # 8-byte Folded Reload -; ZHINX64-NEXT: ld s10, 48(sp) # 8-byte Folded Reload -; ZHINX64-NEXT: ld s11, 40(sp) # 8-byte Folded Reload -; ZHINX64-NEXT: addi sp, sp, 144 +; ZHINX64-NEXT: ld ra, 152(sp) # 8-byte Folded Reload +; ZHINX64-NEXT: ld s0, 144(sp) # 8-byte Folded Reload +; ZHINX64-NEXT: ld s1, 136(sp) # 8-byte Folded Reload +; ZHINX64-NEXT: ld s2, 128(sp) # 8-byte Folded Reload +; ZHINX64-NEXT: ld s3, 120(sp) # 8-byte Folded Reload +; ZHINX64-NEXT: ld s4, 112(sp) # 8-byte Folded Reload +; ZHINX64-NEXT: ld s5, 104(sp) # 8-byte Folded Reload +; ZHINX64-NEXT: ld s6, 96(sp) # 8-byte Folded Reload +; ZHINX64-NEXT: ld s7, 88(sp) # 8-byte Folded Reload +; ZHINX64-NEXT: ld s8, 80(sp) # 8-byte Folded Reload +; ZHINX64-NEXT: ld s9, 72(sp) # 8-byte Folded Reload +; ZHINX64-NEXT: ld s10, 64(sp) # 8-byte Folded Reload +; ZHINX64-NEXT: ld s11, 56(sp) # 8-byte Folded Reload +; ZHINX64-NEXT: addi sp, sp, 160 ; ZHINX64-NEXT: ret ; ; ZFINX32-LABEL: caller_half_32: diff --git a/llvm/test/CodeGen/RISCV/half-arith.ll b/llvm/test/CodeGen/RISCV/half-arith.ll index 27829f2b65759..4c2deafdc7e66 100644 --- a/llvm/test/CodeGen/RISCV/half-arith.ll +++ b/llvm/test/CodeGen/RISCV/half-arith.ll @@ -466,20 +466,26 @@ define half @fsgnj_h(half %a, half %b) nounwind { ; ; RV32IZHINXMIN-LABEL: fsgnj_h: ; RV32IZHINXMIN: # %bb.0: +; RV32IZHINXMIN-NEXT: # kill: def $x11_h killed $x11_h def $x11 +; RV32IZHINXMIN-NEXT: # kill: def $x10_h killed $x10_h def $x10 ; RV32IZHINXMIN-NEXT: lui a2, 1048568 ; RV32IZHINXMIN-NEXT: and a1, a1, a2 ; RV32IZHINXMIN-NEXT: slli a0, a0, 17 ; RV32IZHINXMIN-NEXT: srli a0, a0, 17 ; RV32IZHINXMIN-NEXT: or a0, a0, a1 +; RV32IZHINXMIN-NEXT: # kill: def $x10_h killed $x10_h killed $x10 ; RV32IZHINXMIN-NEXT: ret ; ; RV64IZHINXMIN-LABEL: fsgnj_h: ; RV64IZHINXMIN: # %bb.0: +; RV64IZHINXMIN-NEXT: # kill: def $x11_h killed $x11_h def $x11 +; RV64IZHINXMIN-NEXT: # kill: def $x10_h killed $x10_h def $x10 ; RV64IZHINXMIN-NEXT: lui a2, 1048568 ; RV64IZHINXMIN-NEXT: and a1, a1, a2 ; RV64IZHINXMIN-NEXT: slli a0, a0, 49 ; RV64IZHINXMIN-NEXT: srli a0, a0, 49 ; RV64IZHINXMIN-NEXT: or a0, a0, a1 +; RV64IZHINXMIN-NEXT: # kill: def $x10_h killed $x10_h killed $x10 ; RV64IZHINXMIN-NEXT: ret %1 = call half @llvm.copysign.f16(half %a, half %b) ret half %1 @@ -725,6 +731,7 @@ define half @fsgnjn_h(half %a, half %b) nounwind { ; ; RV32IZHINXMIN-LABEL: fsgnjn_h: ; RV32IZHINXMIN: # %bb.0: +; RV32IZHINXMIN-NEXT: # kill: def $x10_h killed $x10_h def $x10 ; RV32IZHINXMIN-NEXT: fcvt.s.h a1, a1 ; RV32IZHINXMIN-NEXT: fcvt.s.h a2, a0 ; RV32IZHINXMIN-NEXT: fadd.s a1, a2, a1 @@ -735,10 +742,12 @@ define half @fsgnjn_h(half %a, half %b) nounwind { ; RV32IZHINXMIN-NEXT: slli a0, a0, 17 ; RV32IZHINXMIN-NEXT: srli a0, a0, 17 ; RV32IZHINXMIN-NEXT: or a0, a0, a1 +; RV32IZHINXMIN-NEXT: # kill: def $x10_h killed $x10_h killed $x10 ; RV32IZHINXMIN-NEXT: ret ; ; RV64IZHINXMIN-LABEL: fsgnjn_h: ; RV64IZHINXMIN: # %bb.0: +; RV64IZHINXMIN-NEXT: # kill: def $x10_h killed $x10_h def $x10 ; RV64IZHINXMIN-NEXT: fcvt.s.h a1, a1 ; RV64IZHINXMIN-NEXT: fcvt.s.h a2, a0 ; RV64IZHINXMIN-NEXT: fadd.s a1, a2, a1 @@ -749,6 +758,7 @@ define half @fsgnjn_h(half %a, half %b) nounwind { ; RV64IZHINXMIN-NEXT: slli a0, a0, 49 ; RV64IZHINXMIN-NEXT: srli a0, a0, 49 ; RV64IZHINXMIN-NEXT: or a0, a0, a1 +; RV64IZHINXMIN-NEXT: # kill: def $x10_h killed $x10_h killed $x10 ; RV64IZHINXMIN-NEXT: ret %1 = fadd half %a, %b %2 = fneg half %1 @@ -1702,8 +1712,7 @@ define half @fnmadd_h_3(half %a, half %b, half %c) nounwind { ; CHECKIZHINX-LABEL: fnmadd_h_3: ; CHECKIZHINX: # %bb.0: ; CHECKIZHINX-NEXT: fmadd.h a0, a0, a1, a2 -; CHECKIZHINX-NEXT: lui a1, 1048568 -; CHECKIZHINX-NEXT: xor a0, a0, a1 +; CHECKIZHINX-NEXT: fneg.h a0, a0 ; CHECKIZHINX-NEXT: ret ; ; RV32I-LABEL: fnmadd_h_3: @@ -1798,6 +1807,7 @@ define half @fnmadd_h_3(half %a, half %b, half %c) nounwind { ; CHECKIZHINXMIN-NEXT: fcvt.h.s a0, a0 ; CHECKIZHINXMIN-NEXT: lui a1, 1048568 ; CHECKIZHINXMIN-NEXT: xor a0, a0, a1 +; CHECKIZHINXMIN-NEXT: # kill: def $x10_h killed $x10_h killed $x10 ; CHECKIZHINXMIN-NEXT: ret %1 = call half @llvm.fma.f16(half %a, half %b, half %c) %neg = fneg half %1 @@ -1823,9 +1833,7 @@ define half @fnmadd_nsz(half %a, half %b, half %c) nounwind { ; ; CHECKIZHINX-LABEL: fnmadd_nsz: ; CHECKIZHINX: # %bb.0: -; CHECKIZHINX-NEXT: fmadd.h a0, a0, a1, a2 -; CHECKIZHINX-NEXT: lui a1, 1048568 -; CHECKIZHINX-NEXT: xor a0, a0, a1 +; CHECKIZHINX-NEXT: fnmadd.h a0, a0, a1, a2 ; CHECKIZHINX-NEXT: ret ; ; RV32I-LABEL: fnmadd_nsz: @@ -1920,6 +1928,7 @@ define half @fnmadd_nsz(half %a, half %b, half %c) nounwind { ; CHECKIZHINXMIN-NEXT: fcvt.h.s a0, a0 ; CHECKIZHINXMIN-NEXT: lui a1, 1048568 ; CHECKIZHINXMIN-NEXT: xor a0, a0, a1 +; CHECKIZHINXMIN-NEXT: # kill: def $x10_h killed $x10_h killed $x10 ; CHECKIZHINXMIN-NEXT: ret %1 = call nsz half @llvm.fma.f16(half %a, half %b, half %c) %neg = fneg nsz half %1 @@ -2910,6 +2919,7 @@ define half @fsgnjx_f16(half %x, half %y) nounwind { ; ; CHECKIZHINXMIN-LABEL: fsgnjx_f16: ; CHECKIZHINXMIN: # %bb.0: +; CHECKIZHINXMIN-NEXT: # kill: def $x10_h killed $x10_h def $x10 ; CHECKIZHINXMIN-NEXT: lui a2, 1048568 ; CHECKIZHINXMIN-NEXT: and a0, a0, a2 ; CHECKIZHINXMIN-NEXT: li a2, 15 diff --git a/llvm/test/CodeGen/RISCV/half-bitmanip-dagcombines.ll b/llvm/test/CodeGen/RISCV/half-bitmanip-dagcombines.ll index 506b7027a8b35..e0c47bfac6fec 100644 --- a/llvm/test/CodeGen/RISCV/half-bitmanip-dagcombines.ll +++ b/llvm/test/CodeGen/RISCV/half-bitmanip-dagcombines.ll @@ -55,14 +55,12 @@ define half @fneg(half %a) nounwind { ; ; RV32IZHINX-LABEL: fneg: ; RV32IZHINX: # %bb.0: -; RV32IZHINX-NEXT: lui a1, 1048568 -; RV32IZHINX-NEXT: xor a0, a0, a1 +; RV32IZHINX-NEXT: fneg.h a0, a0 ; RV32IZHINX-NEXT: ret ; ; RV64IZHINX-LABEL: fneg: ; RV64IZHINX: # %bb.0: -; RV64IZHINX-NEXT: lui a1, 1048568 -; RV64IZHINX-NEXT: xor a0, a0, a1 +; RV64IZHINX-NEXT: fneg.h a0, a0 ; RV64IZHINX-NEXT: ret ; ; RV32IZFHMIN-LABEL: fneg: @@ -79,8 +77,10 @@ define half @fneg(half %a) nounwind { ; ; RVIZHINXMIN-LABEL: fneg: ; RVIZHINXMIN: # %bb.0: +; RVIZHINXMIN-NEXT: # kill: def $x10_h killed $x10_h def $x10 ; RVIZHINXMIN-NEXT: lui a1, 1048568 ; RVIZHINXMIN-NEXT: xor a0, a0, a1 +; RVIZHINXMIN-NEXT: # kill: def $x10_h killed $x10_h killed $x10 ; RVIZHINXMIN-NEXT: ret %1 = fneg half %a ret half %1 @@ -115,14 +115,12 @@ define half @fabs(half %a) nounwind { ; ; RV32IZHINX-LABEL: fabs: ; RV32IZHINX: # %bb.0: -; RV32IZHINX-NEXT: slli a0, a0, 17 -; RV32IZHINX-NEXT: srli a0, a0, 17 +; RV32IZHINX-NEXT: fabs.h a0, a0 ; RV32IZHINX-NEXT: ret ; ; RV64IZHINX-LABEL: fabs: ; RV64IZHINX: # %bb.0: -; RV64IZHINX-NEXT: slli a0, a0, 49 -; RV64IZHINX-NEXT: srli a0, a0, 49 +; RV64IZHINX-NEXT: fabs.h a0, a0 ; RV64IZHINX-NEXT: ret ; ; RV32IZFHMIN-LABEL: fabs: @@ -139,14 +137,18 @@ define half @fabs(half %a) nounwind { ; ; RV32IZHINXMIN-LABEL: fabs: ; RV32IZHINXMIN: # %bb.0: +; RV32IZHINXMIN-NEXT: # kill: def $x10_h killed $x10_h def $x10 ; RV32IZHINXMIN-NEXT: slli a0, a0, 17 ; RV32IZHINXMIN-NEXT: srli a0, a0, 17 +; RV32IZHINXMIN-NEXT: # kill: def $x10_h killed $x10_h killed $x10 ; RV32IZHINXMIN-NEXT: ret ; ; RV64IZHINXMIN-LABEL: fabs: ; RV64IZHINXMIN: # %bb.0: +; RV64IZHINXMIN-NEXT: # kill: def $x10_h killed $x10_h def $x10 ; RV64IZHINXMIN-NEXT: slli a0, a0, 49 ; RV64IZHINXMIN-NEXT: srli a0, a0, 49 +; RV64IZHINXMIN-NEXT: # kill: def $x10_h killed $x10_h killed $x10 ; RV64IZHINXMIN-NEXT: ret %1 = call half @llvm.fabs.f16(half %a) ret half %1 @@ -227,22 +229,28 @@ define half @fcopysign_fneg(half %a, half %b) nounwind { ; ; RV32IZHINXMIN-LABEL: fcopysign_fneg: ; RV32IZHINXMIN: # %bb.0: +; RV32IZHINXMIN-NEXT: # kill: def $x11_h killed $x11_h def $x11 +; RV32IZHINXMIN-NEXT: # kill: def $x10_h killed $x10_h def $x10 ; RV32IZHINXMIN-NEXT: not a1, a1 ; RV32IZHINXMIN-NEXT: lui a2, 1048568 ; RV32IZHINXMIN-NEXT: and a1, a1, a2 ; RV32IZHINXMIN-NEXT: slli a0, a0, 17 ; RV32IZHINXMIN-NEXT: srli a0, a0, 17 ; RV32IZHINXMIN-NEXT: or a0, a0, a1 +; RV32IZHINXMIN-NEXT: # kill: def $x10_h killed $x10_h killed $x10 ; RV32IZHINXMIN-NEXT: ret ; ; RV64IZHINXMIN-LABEL: fcopysign_fneg: ; RV64IZHINXMIN: # %bb.0: +; RV64IZHINXMIN-NEXT: # kill: def $x11_h killed $x11_h def $x11 +; RV64IZHINXMIN-NEXT: # kill: def $x10_h killed $x10_h def $x10 ; RV64IZHINXMIN-NEXT: not a1, a1 ; RV64IZHINXMIN-NEXT: lui a2, 1048568 ; RV64IZHINXMIN-NEXT: and a1, a1, a2 ; RV64IZHINXMIN-NEXT: slli a0, a0, 49 ; RV64IZHINXMIN-NEXT: srli a0, a0, 49 ; RV64IZHINXMIN-NEXT: or a0, a0, a1 +; RV64IZHINXMIN-NEXT: # kill: def $x10_h killed $x10_h killed $x10 ; RV64IZHINXMIN-NEXT: ret %1 = fneg half %b %2 = call half @llvm.copysign.f16(half %a, half %1) diff --git a/llvm/test/CodeGen/RISCV/half-convert.ll b/llvm/test/CodeGen/RISCV/half-convert.ll index e5585661ce79a..0c84a08f1fd45 100644 --- a/llvm/test/CodeGen/RISCV/half-convert.ll +++ b/llvm/test/CodeGen/RISCV/half-convert.ll @@ -5536,10 +5536,12 @@ define half @bitcast_h_i16(i16 %a) nounwind { ; ; CHECKIZHINX-LABEL: bitcast_h_i16: ; CHECKIZHINX: # %bb.0: +; CHECKIZHINX-NEXT: # kill: def $x10_h killed $x10_h killed $x10 ; CHECKIZHINX-NEXT: ret ; ; CHECKIZDINXZHINX-LABEL: bitcast_h_i16: ; CHECKIZDINXZHINX: # %bb.0: +; CHECKIZDINXZHINX-NEXT: # kill: def $x10_h killed $x10_h killed $x10 ; CHECKIZDINXZHINX-NEXT: ret ; ; RV32I-LABEL: bitcast_h_i16: @@ -5588,18 +5590,22 @@ define half @bitcast_h_i16(i16 %a) nounwind { ; ; CHECK32-IZHINXMIN-LABEL: bitcast_h_i16: ; CHECK32-IZHINXMIN: # %bb.0: +; CHECK32-IZHINXMIN-NEXT: # kill: def $x10_h killed $x10_h killed $x10 ; CHECK32-IZHINXMIN-NEXT: ret ; ; CHECK64-IZHINXMIN-LABEL: bitcast_h_i16: ; CHECK64-IZHINXMIN: # %bb.0: +; CHECK64-IZHINXMIN-NEXT: # kill: def $x10_h killed $x10_h killed $x10 ; CHECK64-IZHINXMIN-NEXT: ret ; ; CHECK32-IZDINXZHINXMIN-LABEL: bitcast_h_i16: ; CHECK32-IZDINXZHINXMIN: # %bb.0: +; CHECK32-IZDINXZHINXMIN-NEXT: # kill: def $x10_h killed $x10_h killed $x10 ; CHECK32-IZDINXZHINXMIN-NEXT: ret ; ; CHECK64-IZDINXZHINXMIN-LABEL: bitcast_h_i16: ; CHECK64-IZDINXZHINXMIN: # %bb.0: +; CHECK64-IZDINXZHINXMIN-NEXT: # kill: def $x10_h killed $x10_h killed $x10 ; CHECK64-IZDINXZHINXMIN-NEXT: ret %1 = bitcast i16 %a to half ret half %1 @@ -5623,10 +5629,12 @@ define i16 @bitcast_i16_h(half %a) nounwind { ; ; CHECKIZHINX-LABEL: bitcast_i16_h: ; CHECKIZHINX: # %bb.0: +; CHECKIZHINX-NEXT: # kill: def $x10_h killed $x10_h def $x10 ; CHECKIZHINX-NEXT: ret ; ; CHECKIZDINXZHINX-LABEL: bitcast_i16_h: ; CHECKIZDINXZHINX: # %bb.0: +; CHECKIZDINXZHINX-NEXT: # kill: def $x10_h killed $x10_h def $x10 ; CHECKIZDINXZHINX-NEXT: ret ; ; RV32I-LABEL: bitcast_i16_h: @@ -5667,18 +5675,22 @@ define i16 @bitcast_i16_h(half %a) nounwind { ; ; CHECK32-IZHINXMIN-LABEL: bitcast_i16_h: ; CHECK32-IZHINXMIN: # %bb.0: +; CHECK32-IZHINXMIN-NEXT: # kill: def $x10_h killed $x10_h def $x10 ; CHECK32-IZHINXMIN-NEXT: ret ; ; CHECK64-IZHINXMIN-LABEL: bitcast_i16_h: ; CHECK64-IZHINXMIN: # %bb.0: +; CHECK64-IZHINXMIN-NEXT: # kill: def $x10_h killed $x10_h def $x10 ; CHECK64-IZHINXMIN-NEXT: ret ; ; CHECK32-IZDINXZHINXMIN-LABEL: bitcast_i16_h: ; CHECK32-IZDINXZHINXMIN: # %bb.0: +; CHECK32-IZDINXZHINXMIN-NEXT: # kill: def $x10_h killed $x10_h def $x10 ; CHECK32-IZDINXZHINXMIN-NEXT: ret ; ; CHECK64-IZDINXZHINXMIN-LABEL: bitcast_i16_h: ; CHECK64-IZDINXZHINXMIN: # %bb.0: +; CHECK64-IZDINXZHINXMIN-NEXT: # kill: def $x10_h killed $x10_h def $x10 ; CHECK64-IZDINXZHINXMIN-NEXT: ret %1 = bitcast half %a to i16 ret i16 %1 diff --git a/llvm/test/CodeGen/RISCV/half-imm.ll b/llvm/test/CodeGen/RISCV/half-imm.ll index 2ebc28c2ebd44..1045df1c3e766 100644 --- a/llvm/test/CodeGen/RISCV/half-imm.ll +++ b/llvm/test/CodeGen/RISCV/half-imm.ll @@ -32,12 +32,14 @@ define half @half_imm() nounwind { ; RV32IZHINX: # %bb.0: ; RV32IZHINX-NEXT: lui a0, 4 ; RV32IZHINX-NEXT: addi a0, a0, 512 +; RV32IZHINX-NEXT: # kill: def $x10_h killed $x10_h killed $x10 ; RV32IZHINX-NEXT: ret ; ; RV64IZHINX-LABEL: half_imm: ; RV64IZHINX: # %bb.0: ; RV64IZHINX-NEXT: lui a0, 4 ; RV64IZHINX-NEXT: addiw a0, a0, 512 +; RV64IZHINX-NEXT: # kill: def $x10_h killed $x10_h killed $x10 ; RV64IZHINX-NEXT: ret ; ; CHECKIZFHMIN-LABEL: half_imm: @@ -50,12 +52,14 @@ define half @half_imm() nounwind { ; RV32IZHINXMIN: # %bb.0: ; RV32IZHINXMIN-NEXT: lui a0, 4 ; RV32IZHINXMIN-NEXT: addi a0, a0, 512 +; RV32IZHINXMIN-NEXT: # kill: def $x10_h killed $x10_h killed $x10 ; RV32IZHINXMIN-NEXT: ret ; ; RV64IZHINXMIN-LABEL: half_imm: ; RV64IZHINXMIN: # %bb.0: ; RV64IZHINXMIN-NEXT: lui a0, 4 ; RV64IZHINXMIN-NEXT: addiw a0, a0, 512 +; RV64IZHINXMIN-NEXT: # kill: def $x10_h killed $x10_h killed $x10 ; RV64IZHINXMIN-NEXT: ret ret half 3.0 } diff --git a/llvm/test/CodeGen/RISCV/half-intrinsics.ll b/llvm/test/CodeGen/RISCV/half-intrinsics.ll index 3e0f838270aa5..81e29329e7181 100644 --- a/llvm/test/CodeGen/RISCV/half-intrinsics.ll +++ b/llvm/test/CodeGen/RISCV/half-intrinsics.ll @@ -1797,17 +1797,10 @@ define half @fabs_f16(half %a) nounwind { ; CHECKIZFH-NEXT: fabs.h fa0, fa0 ; CHECKIZFH-NEXT: ret ; -; RV32IZHINX-LABEL: fabs_f16: -; RV32IZHINX: # %bb.0: -; RV32IZHINX-NEXT: slli a0, a0, 17 -; RV32IZHINX-NEXT: srli a0, a0, 17 -; RV32IZHINX-NEXT: ret -; -; RV64IZHINX-LABEL: fabs_f16: -; RV64IZHINX: # %bb.0: -; RV64IZHINX-NEXT: slli a0, a0, 49 -; RV64IZHINX-NEXT: srli a0, a0, 49 -; RV64IZHINX-NEXT: ret +; CHECKIZHINX-LABEL: fabs_f16: +; CHECKIZHINX: # %bb.0: +; CHECKIZHINX-NEXT: fabs.h a0, a0 +; CHECKIZHINX-NEXT: ret ; ; RV32I-LABEL: fabs_f16: ; RV32I: # %bb.0: @@ -1839,14 +1832,18 @@ define half @fabs_f16(half %a) nounwind { ; ; RV32IZHINXMIN-LABEL: fabs_f16: ; RV32IZHINXMIN: # %bb.0: +; RV32IZHINXMIN-NEXT: # kill: def $x10_h killed $x10_h def $x10 ; RV32IZHINXMIN-NEXT: slli a0, a0, 17 ; RV32IZHINXMIN-NEXT: srli a0, a0, 17 +; RV32IZHINXMIN-NEXT: # kill: def $x10_h killed $x10_h killed $x10 ; RV32IZHINXMIN-NEXT: ret ; ; RV64IZHINXMIN-LABEL: fabs_f16: ; RV64IZHINXMIN: # %bb.0: +; RV64IZHINXMIN-NEXT: # kill: def $x10_h killed $x10_h def $x10 ; RV64IZHINXMIN-NEXT: slli a0, a0, 49 ; RV64IZHINXMIN-NEXT: srli a0, a0, 49 +; RV64IZHINXMIN-NEXT: # kill: def $x10_h killed $x10_h killed $x10 ; RV64IZHINXMIN-NEXT: ret %1 = call half @llvm.fabs.f16(half %a) ret half %1 @@ -2094,20 +2091,26 @@ define half @copysign_f16(half %a, half %b) nounwind { ; ; RV32IZHINXMIN-LABEL: copysign_f16: ; RV32IZHINXMIN: # %bb.0: +; RV32IZHINXMIN-NEXT: # kill: def $x11_h killed $x11_h def $x11 +; RV32IZHINXMIN-NEXT: # kill: def $x10_h killed $x10_h def $x10 ; RV32IZHINXMIN-NEXT: lui a2, 1048568 ; RV32IZHINXMIN-NEXT: and a1, a1, a2 ; RV32IZHINXMIN-NEXT: slli a0, a0, 17 ; RV32IZHINXMIN-NEXT: srli a0, a0, 17 ; RV32IZHINXMIN-NEXT: or a0, a0, a1 +; RV32IZHINXMIN-NEXT: # kill: def $x10_h killed $x10_h killed $x10 ; RV32IZHINXMIN-NEXT: ret ; ; RV64IZHINXMIN-LABEL: copysign_f16: ; RV64IZHINXMIN: # %bb.0: +; RV64IZHINXMIN-NEXT: # kill: def $x11_h killed $x11_h def $x11 +; RV64IZHINXMIN-NEXT: # kill: def $x10_h killed $x10_h def $x10 ; RV64IZHINXMIN-NEXT: lui a2, 1048568 ; RV64IZHINXMIN-NEXT: and a1, a1, a2 ; RV64IZHINXMIN-NEXT: slli a0, a0, 49 ; RV64IZHINXMIN-NEXT: srli a0, a0, 49 ; RV64IZHINXMIN-NEXT: or a0, a0, a1 +; RV64IZHINXMIN-NEXT: # kill: def $x10_h killed $x10_h killed $x10 ; RV64IZHINXMIN-NEXT: ret %1 = call half @llvm.copysign.f16(half %a, half %b) ret half %1 @@ -2835,6 +2838,7 @@ define i1 @isnan_d_fpclass(half %x) { ; ; RV32IZHINXMIN-LABEL: isnan_d_fpclass: ; RV32IZHINXMIN: # %bb.0: +; RV32IZHINXMIN-NEXT: # kill: def $x10_h killed $x10_h def $x10 ; RV32IZHINXMIN-NEXT: slli a0, a0, 17 ; RV32IZHINXMIN-NEXT: srli a0, a0, 17 ; RV32IZHINXMIN-NEXT: li a1, 31 @@ -2844,6 +2848,7 @@ define i1 @isnan_d_fpclass(half %x) { ; ; RV64IZHINXMIN-LABEL: isnan_d_fpclass: ; RV64IZHINXMIN: # %bb.0: +; RV64IZHINXMIN-NEXT: # kill: def $x10_h killed $x10_h def $x10 ; RV64IZHINXMIN-NEXT: slli a0, a0, 49 ; RV64IZHINXMIN-NEXT: srli a0, a0, 49 ; RV64IZHINXMIN-NEXT: li a1, 31 diff --git a/llvm/test/CodeGen/RISCV/kcfi-mir.ll b/llvm/test/CodeGen/RISCV/kcfi-mir.ll index 9d8475e2171ea..e478930d59abc 100644 --- a/llvm/test/CodeGen/RISCV/kcfi-mir.ll +++ b/llvm/test/CodeGen/RISCV/kcfi-mir.ll @@ -10,7 +10,7 @@ define void @f1(ptr noundef %x) !kcfi_type !1 { ; CHECK-NEXT: frame-setup CFI_INSTRUCTION def_cfa_offset 16 ; CHECK-NEXT: SD killed $x1, $x2, 8 :: (store (s64) into %stack.0) ; CHECK-NEXT: frame-setup CFI_INSTRUCTION offset $x1, -8 - ; CHECK-NEXT: BUNDLE implicit-def $x6, implicit-def $x7, implicit-def $x28, implicit-def $x29, implicit-def $x30, implicit-def $x31, implicit-def dead $x1, implicit-def $x2, implicit killed $x10 { + ; CHECK-NEXT: BUNDLE implicit-def $x6, implicit-def $x6_h, implicit-def $x7, implicit-def $x7_h, implicit-def $x28, implicit-def $x28_h, implicit-def $x29, implicit-def $x29_h, implicit-def $x30, implicit-def $x30_h, implicit-def $x31, implicit-def $x31_h, implicit-def dead $x1, implicit-def $x2, implicit-def $x2_h, implicit killed $x10 { ; CHECK-NEXT: KCFI_CHECK $x10, 12345678, implicit-def $x6, implicit-def $x7, implicit-def $x28, implicit-def $x29, implicit-def $x30, implicit-def $x31 ; CHECK-NEXT: PseudoCALLIndirect killed $x10, csr_ilp32_lp64, implicit-def dead $x1, implicit-def $x2 ; CHECK-NEXT: } @@ -26,7 +26,7 @@ define void @f2(ptr noundef %x) #0 { ; CHECK: bb.0 (%ir-block.0): ; CHECK-NEXT: liveins: $x10 ; CHECK-NEXT: {{ $}} - ; CHECK-NEXT: BUNDLE implicit-def $x6, implicit-def $x7, implicit-def $x28, implicit-def $x29, implicit-def $x30, implicit-def $x31, implicit killed $x10, implicit $x2 { + ; CHECK-NEXT: BUNDLE implicit-def $x6, implicit-def $x6_h, implicit-def $x7, implicit-def $x7_h, implicit-def $x28, implicit-def $x28_h, implicit-def $x29, implicit-def $x29_h, implicit-def $x30, implicit-def $x30_h, implicit-def $x31, implicit-def $x31_h, implicit killed $x10, implicit $x2 { ; CHECK-NEXT: KCFI_CHECK $x10, 12345678, implicit-def $x6, implicit-def $x7, implicit-def $x28, implicit-def $x29, implicit-def $x30, implicit-def $x31 ; CHECK-NEXT: PseudoTAILIndirect killed $x10, implicit $x2 ; CHECK-NEXT: } diff --git a/llvm/test/CodeGen/RISCV/make-compressible-zbc-zhinx.mir b/llvm/test/CodeGen/RISCV/make-compressible-zbc-zhinx.mir new file mode 100644 index 0000000000000..45fcc792d2fca --- /dev/null +++ b/llvm/test/CodeGen/RISCV/make-compressible-zbc-zhinx.mir @@ -0,0 +1,249 @@ +# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py +# RUN: llc -o - %s -mtriple=riscv32 -mattr=+zcb,+zhinx -simplify-mir \ +# RUN: -run-pass=riscv-make-compressible | FileCheck --check-prefixes=CHECK %s +# RUN: llc -o - %s -mtriple=riscv64 -mattr=+zcb,+zhinx -simplify-mir \ +# RUN: -run-pass=riscv-make-compressible | FileCheck --check-prefixes=CHECK %s + +--- | + define void @store_common_value_half(ptr %a, ptr %b, ptr %c) #0 { + entry: + store half 0.0, ptr %a, align 2 + store half 0.0, ptr %b, align 2 + store half 0.0, ptr %c, align 2 + ret void + } + + define void @store_common_ptr_half(ptr %p) #0 { + entry: + store volatile half 2.0, ptr %p, align 2 + store volatile half 32.0, ptr %p, align 2 + store volatile half 512.0, ptr %p, align 2 + ret void + } + + define void @load_common_ptr_half(ptr %p) #0 { + entry: + %0 = load volatile half, ptr %p, align 2 + %1 = load volatile half, ptr %p, align 2 + %2 = load volatile half, ptr %p, align 2 + ret void + } + + define void @store_large_offset_half(ptr %p) #0 { + entry: + %0 = getelementptr inbounds half, ptr %p, i32 100 + store volatile half 2.0, ptr %0, align 2 + %1 = getelementptr inbounds half, ptr %p, i32 101 + store volatile half 32.0, ptr %1, align 2 + %2 = getelementptr inbounds half, ptr %p, i32 102 + store volatile half 512.0, ptr %2, align 2 + %3 = getelementptr inbounds half, ptr %p, i32 103 + store volatile half 16384.0, ptr %3, align 2 + ret void + } + + define void @load_large_offset_half(ptr %p) #0 { + entry: + %0 = getelementptr inbounds half, ptr %p, i32 100 + %a = load volatile half, ptr %0, align 2 + %1 = getelementptr inbounds half, ptr %p, i32 100 + %b = load volatile half, ptr %1, align 2 + %2 = getelementptr inbounds half, ptr %p, i32 101 + %c = load volatile half, ptr %2, align 2 + %3 = getelementptr inbounds half, ptr %p, i32 101 + %d = load volatile half, ptr %3, align 2 + ret void + } + + define void @store_large_offset_no_opt_half(ptr %p) #0 { + entry: + %0 = getelementptr inbounds i8, ptr %p, i8 100 + store volatile half 2.0, ptr %0, align 2 + %1 = getelementptr inbounds i8, ptr %p, i8 101 + store volatile half 32.0, ptr %1, align 2 + %2 = getelementptr inbounds i8, ptr %p, i8 104 + store volatile half 512.0, ptr %2, align 2 + ret void + } + + define void @load_large_offset_no_opt_half(ptr %p) #0 { + entry: + %0 = getelementptr inbounds half, ptr %p, i32 100 + %a = load volatile half, ptr %0, align 2 + %1 = getelementptr inbounds half, ptr %p, i32 101 + %c = load volatile half, ptr %1, align 2 + %2 = getelementptr inbounds half, ptr %p, i32 102 + %d = load volatile half, ptr %2, align 2 + ret void + } + + attributes #0 = { minsize } + +... +--- +name: store_common_value_half +tracksRegLiveness: true +body: | + bb.0.entry: + liveins: $x10, $x11, $x12 + + ; CHECK-LABEL: name: store_common_value_half + ; CHECK: liveins: $x10, $x11, $x12 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: $x13_h = PseudoMV_FPR16INX $x0_h + ; CHECK-NEXT: SH_INX $x13_h, killed renamable $x10, 0 :: (store (s16) into %ir.a) + ; CHECK-NEXT: SH_INX $x13_h, killed renamable $x11, 0 :: (store (s16) into %ir.b) + ; CHECK-NEXT: SH_INX $x13_h, killed renamable $x12, 0 :: (store (s16) into %ir.c) + ; CHECK-NEXT: PseudoRET + SH_INX $x0_h, killed renamable $x10, 0 :: (store (s16) into %ir.a) + SH_INX $x0_h, killed renamable $x11, 0 :: (store (s16) into %ir.b) + SH_INX $x0_h, killed renamable $x12, 0 :: (store (s16) into %ir.c) + PseudoRET + +... +--- +name: store_common_ptr_half +tracksRegLiveness: true +body: | + bb.0.entry: + liveins: $x16 + + ; CHECK-LABEL: name: store_common_ptr_half + ; CHECK: liveins: $x16 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: renamable $x10 = LUI 4 + ; CHECK-NEXT: $x11 = ADDI $x16, 0 + ; CHECK-NEXT: SH_INX killed renamable $x10_h, $x11, 0 :: (volatile store (s16) into %ir.p) + ; CHECK-NEXT: renamable $x10 = LUI 5 + ; CHECK-NEXT: SH_INX killed renamable $x10_h, $x11, 0 :: (volatile store (s16) into %ir.p) + ; CHECK-NEXT: renamable $x10 = LUI 6 + ; CHECK-NEXT: SH_INX killed renamable $x10_h, killed $x11, 0 :: (volatile store (s16) into %ir.p) + ; CHECK-NEXT: PseudoRET + renamable $x10 = LUI 4 + SH_INX killed renamable $x10_h, renamable $x16, 0 :: (volatile store (s16) into %ir.p) + renamable $x10 = LUI 5 + SH_INX killed renamable $x10_h, renamable $x16, 0 :: (volatile store (s16) into %ir.p) + renamable $x10 = LUI 6 + SH_INX killed renamable $x10_h, killed renamable $x16, 0 :: (volatile store (s16) into %ir.p) + PseudoRET + +... +--- +name: load_common_ptr_half +body: | + bb.0.entry: + liveins: $x16 + + ; CHECK-LABEL: name: load_common_ptr_half + ; CHECK: liveins: $x16 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: $x11 = ADDI $x16, 0 + ; CHECK-NEXT: dead $x10_h = LH_INX $x11, 0 :: (volatile load (s16) from %ir.p) + ; CHECK-NEXT: dead $x10_h = LH_INX $x11, 0 :: (volatile load (s16) from %ir.p) + ; CHECK-NEXT: dead $x10_h = LH_INX killed $x11, 0 :: (volatile load (s16) from %ir.p) + ; CHECK-NEXT: PseudoRET + dead $x10_h = LH_INX renamable $x16, 0 :: (volatile load (s16) from %ir.p) + dead $x10_h = LH_INX renamable $x16, 0 :: (volatile load (s16) from %ir.p) + dead $x10_h = LH_INX killed renamable $x16, 0 :: (volatile load (s16) from %ir.p) + PseudoRET + +... +--- +name: store_large_offset_half +tracksRegLiveness: true +body: | + bb.0.entry: + liveins: $x10 + ; CHECK-LABEL: name: store_large_offset_half + ; CHECK: liveins: $x10 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: renamable $x11 = LUI 4 + ; CHECK-NEXT: $x12 = ADDI $x10, 200 + ; CHECK-NEXT: SH_INX killed renamable $x11_h, $x12, 0 :: (volatile store (s16) into %ir.0) + ; CHECK-NEXT: renamable $x11 = LUI 5 + ; CHECK-NEXT: SH_INX killed renamable $x11_h, $x12, 0 :: (volatile store (s16) into %ir.1) + ; CHECK-NEXT: renamable $x11 = LUI 6 + ; CHECK-NEXT: SH_INX killed renamable $x11_h, $x12, 2 :: (volatile store (s16) into %ir.2) + ; CHECK-NEXT: renamable $x11 = LUI 7 + ; CHECK-NEXT: SH_INX killed renamable $x11_h, killed $x12, 2 :: (volatile store (s16) into %ir.3) + ; CHECK-NEXT: PseudoRET + renamable $x11 = LUI 4 + SH_INX killed renamable $x11_h, renamable $x10, 200 :: (volatile store (s16) into %ir.0) + renamable $x11 = LUI 5 + SH_INX killed renamable $x11_h, renamable $x10, 200 :: (volatile store (s16) into %ir.1) + renamable $x11 = LUI 6 + SH_INX killed renamable $x11_h, renamable $x10, 202 :: (volatile store (s16) into %ir.2) + renamable $x11 = LUI 7 + SH_INX killed renamable $x11_h, killed renamable $x10, 202 :: (volatile store (s16) into %ir.3) + PseudoRET + +... +--- +name: load_large_offset_half +tracksRegLiveness: true +body: | + bb.0.entry: + liveins: $x16 + + ; CHECK-LABEL: name: load_large_offset_half + ; CHECK: liveins: $x16 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: $x11 = ADDI $x16, 100 + ; CHECK-NEXT: dead $x10_h = LH_INX $x11, 0 :: (volatile load (s16) from %ir.0) + ; CHECK-NEXT: dead $x10_h = LH_INX $x11, 0 :: (volatile load (s16) from %ir.1) + ; CHECK-NEXT: dead $x10_h = LH_INX $x11, 2 :: (volatile load (s16) from %ir.2) + ; CHECK-NEXT: dead $x10_h = LH_INX killed $x11, 2 :: (volatile load (s16) from %ir.3) + ; CHECK-NEXT: PseudoRET + dead $x10_h = LH_INX renamable $x16, 100 :: (volatile load (s16) from %ir.0) + dead $x10_h = LH_INX renamable $x16, 100 :: (volatile load (s16) from %ir.1) + dead $x10_h = LH_INX renamable $x16, 102 :: (volatile load (s16) from %ir.2) + dead $x10_h = LH_INX killed renamable $x16, 102 :: (volatile load (s16) from %ir.3) + PseudoRET + +... +--- +name: store_large_offset_no_opt_half +tracksRegLiveness: true +body: | + bb.0.entry: + liveins: $x16 + + ; CHECK-LABEL: name: store_large_offset_no_opt_half + ; CHECK: liveins: $x16 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: renamable $x11 = LUI 4 + ; CHECK-NEXT: SH_INX killed renamable $x11_h, renamable $x16, 200 :: (volatile store (s16) into %ir.0) + ; CHECK-NEXT: renamable $x11 = LUI 5 + ; CHECK-NEXT: SH_INX killed renamable $x11_h, renamable $x16, 202 :: (volatile store (s16) into %ir.1) + ; CHECK-NEXT: renamable $x11 = LUI 6 + ; CHECK-NEXT: SH_INX killed renamable $x11_h, renamable $x16, 204 :: (volatile store (s16) into %ir.2) + ; CHECK-NEXT: PseudoRET + renamable $x11 = LUI 4 + SH_INX killed renamable $x11_h, renamable $x16, 200 :: (volatile store (s16) into %ir.0) + renamable $x11 = LUI 5 + SH_INX killed renamable $x11_h, renamable $x16, 202 :: (volatile store (s16) into %ir.1) + renamable $x11 = LUI 6 + SH_INX killed renamable $x11_h, renamable $x16, 204 :: (volatile store (s16) into %ir.2) + PseudoRET + +... +--- +name: load_large_offset_no_opt_half +tracksRegLiveness: true +body: | + bb.0.entry: + liveins: $x16 + + ; CHECK-LABEL: name: load_large_offset_no_opt_half + ; CHECK: liveins: $x16 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: dead $x10_h = LH_INX renamable $x16, 100 :: (volatile load (s8) from %ir.0) + ; CHECK-NEXT: dead $x10_h = LH_INX renamable $x16, 102 :: (volatile load (s8) from %ir.1) + ; CHECK-NEXT: dead $x10_h = LH_INX killed renamable $x16, 104 :: (volatile load (s8) from %ir.2) + ; CHECK-NEXT: PseudoRET + dead $x10_h = LH_INX renamable $x16, 100 :: (volatile load (s8) from %ir.0) + dead $x10_h = LH_INX renamable $x16, 102 :: (volatile load (s8) from %ir.1) + dead $x10_h = LH_INX killed renamable $x16, 104 :: (volatile load (s8) from %ir.2) + PseudoRET + +... From 631bcbe9de13e160d427ad7452a7ef2ca67911ab Mon Sep 17 00:00:00 2001 From: Mike Hommey Date: Fri, 27 Sep 2024 15:15:55 +0900 Subject: [PATCH 046/469] [llvm][cmake] Properly place clang runtime directory on linker command line when WinMsvc.cmake is involved (#110084) WinMsvc.cmake, used for cross-compiling LLVM, targetting Windows, puts -libpath flags on the linker command line for the MSVC directories. Those may contain clang runtime libraries that come from MSVC, and may be incompatible with the clang compiler in use when it doesn't come from MSVC (which is obviously the case on cross-compiles). By prioritizing the clang runtime directory on the linker command line, we avoid those libraries being picked up by the linker. --- llvm/cmake/modules/HandleLLVMOptions.cmake | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/llvm/cmake/modules/HandleLLVMOptions.cmake b/llvm/cmake/modules/HandleLLVMOptions.cmake index ed13a82905b4e..e17e2169cd880 100644 --- a/llvm/cmake/modules/HandleLLVMOptions.cmake +++ b/llvm/cmake/modules/HandleLLVMOptions.cmake @@ -324,6 +324,12 @@ function(append value) endforeach(variable) endfunction() +function(prepend value) + foreach(variable ${ARGN}) + set(${variable} "${value} ${${variable}}" PARENT_SCOPE) + endforeach(variable) +endfunction() + function(append_if condition value) if (${condition}) foreach(variable ${ARGN}) @@ -1196,7 +1202,7 @@ if (CLANG_CL AND (LLVM_BUILD_INSTRUMENTED OR LLVM_USE_SANITIZER)) endif() file(TO_CMAKE_PATH "${clang_compiler_rt_file}" clang_compiler_rt_file) get_filename_component(clang_runtime_dir "${clang_compiler_rt_file}" DIRECTORY) - append("/libpath:\"${clang_runtime_dir}\"" + prepend("/libpath:\"${clang_runtime_dir}\"" CMAKE_EXE_LINKER_FLAGS CMAKE_MODULE_LINKER_FLAGS CMAKE_SHARED_LINKER_FLAGS) From 91b565bd7f98a695535ccea153895e002411e3de Mon Sep 17 00:00:00 2001 From: Amr Hesham Date: Fri, 27 Sep 2024 08:29:19 +0200 Subject: [PATCH 047/469] [LLVM][NFC] Remove redundant copy parameter in lambda (#110156) Remove redundant copy parameter in lambda Fixes: #95643 --- llvm/lib/AsmParser/LLParser.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp index 08b917fdb260a..e088c312c7b44 100644 --- a/llvm/lib/AsmParser/LLParser.cpp +++ b/llvm/lib/AsmParser/LLParser.cpp @@ -5239,7 +5239,7 @@ bool LLParser::parseDISubrange(MDNode *&Result, bool IsDistinct) { Metadata *UpperBound = nullptr; Metadata *Stride = nullptr; - auto convToMetadata = [&](MDSignedOrMDField Bound) -> Metadata * { + auto convToMetadata = [&](const MDSignedOrMDField &Bound) -> Metadata * { if (Bound.isMDSignedField()) return ConstantAsMetadata::get(ConstantInt::getSigned( Type::getInt64Ty(Context), Bound.getMDSignedValue())); @@ -5271,7 +5271,7 @@ bool LLParser::parseDIGenericSubrange(MDNode *&Result, bool IsDistinct) { PARSE_MD_FIELDS(); #undef VISIT_MD_FIELDS - auto ConvToMetadata = [&](MDSignedOrMDField Bound) -> Metadata * { + auto ConvToMetadata = [&](const MDSignedOrMDField &Bound) -> Metadata * { if (Bound.isMDSignedField()) return DIExpression::get( Context, {dwarf::DW_OP_consts, From 9a361684c80a779c28d8315503a423e05f0cc061 Mon Sep 17 00:00:00 2001 From: Dmitry Polukhin <34227995+dmpolukhin@users.noreply.github.com> Date: Fri, 27 Sep 2024 07:33:59 +0100 Subject: [PATCH 048/469] [C++20][Modules] Fix non-determinism in serialized AST (#110131) Summary: https://github.com/llvm/llvm-project/pull/109167 serializes FunctionToLambdasMap in the order of pointers in DenseMap. It gives different order with different memory layouts. Fix this issue by using LocalDeclID instead of pointers. Test Plan: check-clang --- clang/include/clang/AST/DeclID.h | 22 +++++++++++++++++++ clang/include/clang/Serialization/ASTWriter.h | 6 ++--- clang/lib/Serialization/ASTWriter.cpp | 3 +-- clang/lib/Serialization/ASTWriterDecl.cpp | 3 ++- 4 files changed, 28 insertions(+), 6 deletions(-) diff --git a/clang/include/clang/AST/DeclID.h b/clang/include/clang/AST/DeclID.h index f4607e42c4be3..49964b43c7d1d 100644 --- a/clang/include/clang/AST/DeclID.h +++ b/clang/include/clang/AST/DeclID.h @@ -189,6 +189,7 @@ class LocalDeclID : public DeclIDBase { // Every Decl ID is a local decl ID to the module being writing in ASTWriter. friend class ASTWriter; friend class GlobalDeclID; + friend struct llvm::DenseMapInfo; public: LocalDeclID() : Base() {} @@ -267,6 +268,27 @@ template <> struct DenseMapInfo { } }; +template <> struct DenseMapInfo { + using LocalDeclID = clang::LocalDeclID; + using DeclID = LocalDeclID::DeclID; + + static LocalDeclID getEmptyKey() { + return LocalDeclID(DenseMapInfo::getEmptyKey()); + } + + static LocalDeclID getTombstoneKey() { + return LocalDeclID(DenseMapInfo::getTombstoneKey()); + } + + static unsigned getHashValue(const LocalDeclID &Key) { + return DenseMapInfo::getHashValue(Key.getRawValue()); + } + + static bool isEqual(const LocalDeclID &L, const LocalDeclID &R) { + return L == R; + } +}; + } // namespace llvm #endif diff --git a/clang/include/clang/Serialization/ASTWriter.h b/clang/include/clang/Serialization/ASTWriter.h index 760866fd9de93..e21d41c867314 100644 --- a/clang/include/clang/Serialization/ASTWriter.h +++ b/clang/include/clang/Serialization/ASTWriter.h @@ -233,13 +233,13 @@ class ASTWriter : public ASTDeserializationListener, /// instead of comparing the result of `getDeclID()` or `GetDeclRef()`. llvm::SmallPtrSet PredefinedDecls; - /// Mapping from FunctionDecl to the list of lambda IDs inside the function. + /// Mapping from FunctionDecl ID to the list of lambda IDs inside the + /// function. /// /// These lambdas have to be loaded right after the function they belong to. /// In order to have canonical declaration for lambda class from the same /// module as enclosing function during deserialization. - llvm::DenseMap> - FunctionToLambdasMap; + llvm::DenseMap> FunctionToLambdasMap; /// Offset of each declaration in the bitstream, indexed by /// the declaration's ID. diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index 223727366f61b..7a40c5c65d39d 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -5713,8 +5713,7 @@ void ASTWriter::WriteDeclAndTypes(ASTContext &Context) { // efficent becuase it allows lazy deserialization. RecordData FunctionToLambdasMapRecord; for (const auto &Pair : FunctionToLambdasMap) { - FunctionToLambdasMapRecord.push_back( - GetDeclRef(Pair.first).getRawValue()); + FunctionToLambdasMapRecord.push_back(Pair.first.getRawValue()); FunctionToLambdasMapRecord.push_back(Pair.second.size()); for (const auto &Lambda : Pair.second) FunctionToLambdasMapRecord.push_back(Lambda.getRawValue()); diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp index 50c090b195d61..b9222a1b33fd7 100644 --- a/clang/lib/Serialization/ASTWriterDecl.cpp +++ b/clang/lib/Serialization/ASTWriterDecl.cpp @@ -1524,7 +1524,8 @@ void ASTDeclWriter::VisitCXXRecordDecl(CXXRecordDecl *D) { // For lambdas inside canonical FunctionDecl remember the mapping. if (auto FD = llvm::dyn_cast_or_null(D->getDeclContext()); FD && FD->isCanonicalDecl()) { - Writer.FunctionToLambdasMap[FD].push_back(Writer.GetDeclRef(D)); + Writer.FunctionToLambdasMap[Writer.GetDeclRef(FD)].push_back( + Writer.GetDeclRef(D)); } } else { Record.push_back(CXXRecNotTemplate); From 9f255d863f31f3d3c434f662dc9e2255ef54407c Mon Sep 17 00:00:00 2001 From: David Green Date: Fri, 27 Sep 2024 07:43:58 +0100 Subject: [PATCH 049/469] [AArch64][GlobalISel] Lower fp16 abs and neg without fullfp16. (#110096) This changes the existing promote logic to lower, so that it can use normal integer operations. A minor change was needed to fneg lower code to handle vectors. --- .../CodeGen/GlobalISel/LegalizerHelper.cpp | 8 +-- .../AArch64/GISel/AArch64LegalizerInfo.cpp | 4 +- .../GlobalISel/legalize-fp-arith-fp16.mir | 7 +-- llvm/test/CodeGen/AArch64/f16-instructions.ll | 23 +++----- llvm/test/CodeGen/AArch64/fabs.ll | 54 +++++-------------- llvm/test/CodeGen/AArch64/fneg.ll | 54 +++++-------------- 6 files changed, 44 insertions(+), 106 deletions(-) diff --git a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp index c3b6b3033cf5c..2fb2d104f1ce3 100644 --- a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp +++ b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp @@ -4051,12 +4051,8 @@ LegalizerHelper::lower(MachineInstr &MI, unsigned TypeIdx, LLT LowerHintTy) { auto [Res, SubByReg] = MI.getFirst2Regs(); LLT Ty = MRI.getType(Res); - // TODO: Handle vector types once we are able to - // represent them. - if (Ty.isVector()) - return UnableToLegalize; - auto SignMask = - MIRBuilder.buildConstant(Ty, APInt::getSignMask(Ty.getSizeInBits())); + auto SignMask = MIRBuilder.buildConstant( + Ty, APInt::getSignMask(Ty.getScalarSizeInBits())); MIRBuilder.buildXor(Res, SubByReg, SignMask); MI.eraseFromParent(); return Legalized; diff --git a/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp b/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp index 6cb181011f8f6..51aeee023f2e3 100644 --- a/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp +++ b/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp @@ -268,11 +268,11 @@ AArch64LegalizerInfo::AArch64LegalizerInfo(const AArch64Subtarget &ST) }) .scalarizeIf(scalarOrEltWiderThan(0, 64), 0) .lowerIf(scalarOrEltWiderThan(0, 64)) - .minScalarOrElt(0, MinFPScalar) .clampNumElements(0, v4s16, v8s16) .clampNumElements(0, v2s32, v4s32) .clampNumElements(0, v2s64, v2s64) - .moreElementsToNextPow2(0); + .moreElementsToNextPow2(0) + .lowerFor({s16, v4s16, v8s16}); getActionDefinitionsBuilder(G_FREM) .libcallFor({s32, s64}) diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/legalize-fp-arith-fp16.mir b/llvm/test/CodeGen/AArch64/GlobalISel/legalize-fp-arith-fp16.mir index 438b347fcbcab..42538d58c87bf 100644 --- a/llvm/test/CodeGen/AArch64/GlobalISel/legalize-fp-arith-fp16.mir +++ b/llvm/test/CodeGen/AArch64/GlobalISel/legalize-fp-arith-fp16.mir @@ -150,9 +150,10 @@ body: | ; NO-FP16: liveins: $h0 ; NO-FP16-NEXT: {{ $}} ; NO-FP16-NEXT: %x:_(s16) = COPY $h0 - ; NO-FP16-NEXT: [[FPEXT:%[0-9]+]]:_(s32) = G_FPEXT %x(s16) - ; NO-FP16-NEXT: [[FNEG:%[0-9]+]]:_(s32) = G_FNEG [[FPEXT]] - ; NO-FP16-NEXT: %op:_(s16) = G_FPTRUNC [[FNEG]](s32) + ; NO-FP16-NEXT: [[ANYEXT:%[0-9]+]]:_(s32) = G_ANYEXT %x(s16) + ; NO-FP16-NEXT: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 -32768 + ; NO-FP16-NEXT: [[XOR:%[0-9]+]]:_(s32) = G_XOR [[ANYEXT]], [[C]] + ; NO-FP16-NEXT: %op:_(s16) = G_TRUNC [[XOR]](s32) ; NO-FP16-NEXT: $h0 = COPY %op(s16) ; NO-FP16-NEXT: RET_ReallyLR implicit $h0 ; diff --git a/llvm/test/CodeGen/AArch64/f16-instructions.ll b/llvm/test/CodeGen/AArch64/f16-instructions.ll index d8a17b4058710..e058c83f274f1 100644 --- a/llvm/test/CodeGen/AArch64/f16-instructions.ll +++ b/llvm/test/CodeGen/AArch64/f16-instructions.ll @@ -1392,26 +1392,19 @@ define half @test_fma(half %a, half %b, half %c) #0 { } define half @test_fabs(half %a) #0 { -; CHECK-CVT-SD-LABEL: test_fabs: -; CHECK-CVT-SD: // %bb.0: -; CHECK-CVT-SD-NEXT: // kill: def $h0 killed $h0 def $s0 -; CHECK-CVT-SD-NEXT: fmov w8, s0 -; CHECK-CVT-SD-NEXT: and w8, w8, #0x7fff -; CHECK-CVT-SD-NEXT: fmov s0, w8 -; CHECK-CVT-SD-NEXT: // kill: def $h0 killed $h0 killed $s0 -; CHECK-CVT-SD-NEXT: ret +; CHECK-CVT-LABEL: test_fabs: +; CHECK-CVT: // %bb.0: +; CHECK-CVT-NEXT: // kill: def $h0 killed $h0 def $s0 +; CHECK-CVT-NEXT: fmov w8, s0 +; CHECK-CVT-NEXT: and w8, w8, #0x7fff +; CHECK-CVT-NEXT: fmov s0, w8 +; CHECK-CVT-NEXT: // kill: def $h0 killed $h0 killed $s0 +; CHECK-CVT-NEXT: ret ; ; CHECK-FP16-LABEL: test_fabs: ; CHECK-FP16: // %bb.0: ; CHECK-FP16-NEXT: fabs h0, h0 ; CHECK-FP16-NEXT: ret -; -; CHECK-CVT-GI-LABEL: test_fabs: -; CHECK-CVT-GI: // %bb.0: -; CHECK-CVT-GI-NEXT: fcvt s0, h0 -; CHECK-CVT-GI-NEXT: fabs s0, s0 -; CHECK-CVT-GI-NEXT: fcvt h0, s0 -; CHECK-CVT-GI-NEXT: ret %r = call half @llvm.fabs.f16(half %a) ret half %r } diff --git a/llvm/test/CodeGen/AArch64/fabs.ll b/llvm/test/CodeGen/AArch64/fabs.ll index e19e2ead11f4d..43e9007073634 100644 --- a/llvm/test/CodeGen/AArch64/fabs.ll +++ b/llvm/test/CodeGen/AArch64/fabs.ll @@ -41,9 +41,11 @@ define half @fabs_f16(half %a) { ; ; CHECK-GI-NOFP16-LABEL: fabs_f16: ; CHECK-GI-NOFP16: // %bb.0: // %entry -; CHECK-GI-NOFP16-NEXT: fcvt s0, h0 -; CHECK-GI-NOFP16-NEXT: fabs s0, s0 -; CHECK-GI-NOFP16-NEXT: fcvt h0, s0 +; CHECK-GI-NOFP16-NEXT: // kill: def $h0 killed $h0 def $s0 +; CHECK-GI-NOFP16-NEXT: fmov w8, s0 +; CHECK-GI-NOFP16-NEXT: and w8, w8, #0x7fff +; CHECK-GI-NOFP16-NEXT: fmov s0, w8 +; CHECK-GI-NOFP16-NEXT: // kill: def $h0 killed $h0 killed $s0 ; CHECK-GI-NOFP16-NEXT: ret ; ; CHECK-GI-FP16-LABEL: fabs_f16: @@ -160,22 +162,8 @@ define <7 x half> @fabs_v7f16(<7 x half> %a) { ; ; CHECK-GI-NOFP16-LABEL: fabs_v7f16: ; CHECK-GI-NOFP16: // %bb.0: // %entry -; CHECK-GI-NOFP16-NEXT: fcvtl v1.4s, v0.4h -; CHECK-GI-NOFP16-NEXT: mov v2.h[0], v0.h[4] -; CHECK-GI-NOFP16-NEXT: fabs v1.4s, v1.4s -; CHECK-GI-NOFP16-NEXT: mov v2.h[1], v0.h[5] -; CHECK-GI-NOFP16-NEXT: fcvtn v1.4h, v1.4s -; CHECK-GI-NOFP16-NEXT: mov v2.h[2], v0.h[6] -; CHECK-GI-NOFP16-NEXT: mov v0.h[0], v1.h[0] -; CHECK-GI-NOFP16-NEXT: fcvtl v2.4s, v2.4h -; CHECK-GI-NOFP16-NEXT: mov v0.h[1], v1.h[1] -; CHECK-GI-NOFP16-NEXT: fabs v2.4s, v2.4s -; CHECK-GI-NOFP16-NEXT: mov v0.h[2], v1.h[2] -; CHECK-GI-NOFP16-NEXT: fcvtn v2.4h, v2.4s -; CHECK-GI-NOFP16-NEXT: mov v0.h[3], v1.h[3] -; CHECK-GI-NOFP16-NEXT: mov v0.h[4], v2.h[0] -; CHECK-GI-NOFP16-NEXT: mov v0.h[5], v2.h[1] -; CHECK-GI-NOFP16-NEXT: mov v0.h[6], v2.h[2] +; CHECK-GI-NOFP16-NEXT: mvni v1.8h, #128, lsl #8 +; CHECK-GI-NOFP16-NEXT: and v0.16b, v0.16b, v1.16b ; CHECK-GI-NOFP16-NEXT: ret ; ; CHECK-GI-FP16-LABEL: fabs_v7f16: @@ -200,9 +188,8 @@ define <4 x half> @fabs_v4f16(<4 x half> %a) { ; ; CHECK-GI-NOFP16-LABEL: fabs_v4f16: ; CHECK-GI-NOFP16: // %bb.0: // %entry -; CHECK-GI-NOFP16-NEXT: fcvtl v0.4s, v0.4h -; CHECK-GI-NOFP16-NEXT: fabs v0.4s, v0.4s -; CHECK-GI-NOFP16-NEXT: fcvtn v0.4h, v0.4s +; CHECK-GI-NOFP16-NEXT: mvni v1.4h, #128, lsl #8 +; CHECK-GI-NOFP16-NEXT: and v0.8b, v0.8b, v1.8b ; CHECK-GI-NOFP16-NEXT: ret ; ; CHECK-GI-FP16-LABEL: fabs_v4f16: @@ -227,12 +214,8 @@ define <8 x half> @fabs_v8f16(<8 x half> %a) { ; ; CHECK-GI-NOFP16-LABEL: fabs_v8f16: ; CHECK-GI-NOFP16: // %bb.0: // %entry -; CHECK-GI-NOFP16-NEXT: fcvtl v1.4s, v0.4h -; CHECK-GI-NOFP16-NEXT: fcvtl2 v0.4s, v0.8h -; CHECK-GI-NOFP16-NEXT: fabs v1.4s, v1.4s -; CHECK-GI-NOFP16-NEXT: fabs v2.4s, v0.4s -; CHECK-GI-NOFP16-NEXT: fcvtn v0.4h, v1.4s -; CHECK-GI-NOFP16-NEXT: fcvtn2 v0.8h, v2.4s +; CHECK-GI-NOFP16-NEXT: mvni v1.8h, #128, lsl #8 +; CHECK-GI-NOFP16-NEXT: and v0.16b, v0.16b, v1.16b ; CHECK-GI-NOFP16-NEXT: ret ; ; CHECK-GI-FP16-LABEL: fabs_v8f16: @@ -259,18 +242,9 @@ define <16 x half> @fabs_v16f16(<16 x half> %a) { ; ; CHECK-GI-NOFP16-LABEL: fabs_v16f16: ; CHECK-GI-NOFP16: // %bb.0: // %entry -; CHECK-GI-NOFP16-NEXT: fcvtl v2.4s, v0.4h -; CHECK-GI-NOFP16-NEXT: fcvtl v3.4s, v1.4h -; CHECK-GI-NOFP16-NEXT: fcvtl2 v0.4s, v0.8h -; CHECK-GI-NOFP16-NEXT: fcvtl2 v1.4s, v1.8h -; CHECK-GI-NOFP16-NEXT: fabs v2.4s, v2.4s -; CHECK-GI-NOFP16-NEXT: fabs v3.4s, v3.4s -; CHECK-GI-NOFP16-NEXT: fabs v4.4s, v0.4s -; CHECK-GI-NOFP16-NEXT: fabs v5.4s, v1.4s -; CHECK-GI-NOFP16-NEXT: fcvtn v0.4h, v2.4s -; CHECK-GI-NOFP16-NEXT: fcvtn v1.4h, v3.4s -; CHECK-GI-NOFP16-NEXT: fcvtn2 v0.8h, v4.4s -; CHECK-GI-NOFP16-NEXT: fcvtn2 v1.8h, v5.4s +; CHECK-GI-NOFP16-NEXT: mvni v2.8h, #128, lsl #8 +; CHECK-GI-NOFP16-NEXT: and v0.16b, v0.16b, v2.16b +; CHECK-GI-NOFP16-NEXT: and v1.16b, v1.16b, v2.16b ; CHECK-GI-NOFP16-NEXT: ret ; ; CHECK-GI-FP16-LABEL: fabs_v16f16: diff --git a/llvm/test/CodeGen/AArch64/fneg.ll b/llvm/test/CodeGen/AArch64/fneg.ll index a0e9edff733e0..de2671afe60ab 100644 --- a/llvm/test/CodeGen/AArch64/fneg.ll +++ b/llvm/test/CodeGen/AArch64/fneg.ll @@ -41,9 +41,11 @@ define half @fabs_f16(half %a) { ; ; CHECK-GI-NOFP16-LABEL: fabs_f16: ; CHECK-GI-NOFP16: // %bb.0: // %entry -; CHECK-GI-NOFP16-NEXT: fcvt s0, h0 -; CHECK-GI-NOFP16-NEXT: fneg s0, s0 -; CHECK-GI-NOFP16-NEXT: fcvt h0, s0 +; CHECK-GI-NOFP16-NEXT: // kill: def $h0 killed $h0 def $s0 +; CHECK-GI-NOFP16-NEXT: fmov w8, s0 +; CHECK-GI-NOFP16-NEXT: eor w8, w8, #0xffff8000 +; CHECK-GI-NOFP16-NEXT: fmov s0, w8 +; CHECK-GI-NOFP16-NEXT: // kill: def $h0 killed $h0 killed $s0 ; CHECK-GI-NOFP16-NEXT: ret ; ; CHECK-GI-FP16-LABEL: fabs_f16: @@ -161,22 +163,8 @@ define <7 x half> @fabs_v7f16(<7 x half> %a) { ; ; CHECK-GI-NOFP16-LABEL: fabs_v7f16: ; CHECK-GI-NOFP16: // %bb.0: // %entry -; CHECK-GI-NOFP16-NEXT: fcvtl v1.4s, v0.4h -; CHECK-GI-NOFP16-NEXT: mov v2.h[0], v0.h[4] -; CHECK-GI-NOFP16-NEXT: fneg v1.4s, v1.4s -; CHECK-GI-NOFP16-NEXT: mov v2.h[1], v0.h[5] -; CHECK-GI-NOFP16-NEXT: fcvtn v1.4h, v1.4s -; CHECK-GI-NOFP16-NEXT: mov v2.h[2], v0.h[6] -; CHECK-GI-NOFP16-NEXT: mov v0.h[0], v1.h[0] -; CHECK-GI-NOFP16-NEXT: fcvtl v2.4s, v2.4h -; CHECK-GI-NOFP16-NEXT: mov v0.h[1], v1.h[1] -; CHECK-GI-NOFP16-NEXT: fneg v2.4s, v2.4s -; CHECK-GI-NOFP16-NEXT: mov v0.h[2], v1.h[2] -; CHECK-GI-NOFP16-NEXT: fcvtn v2.4h, v2.4s -; CHECK-GI-NOFP16-NEXT: mov v0.h[3], v1.h[3] -; CHECK-GI-NOFP16-NEXT: mov v0.h[4], v2.h[0] -; CHECK-GI-NOFP16-NEXT: mov v0.h[5], v2.h[1] -; CHECK-GI-NOFP16-NEXT: mov v0.h[6], v2.h[2] +; CHECK-GI-NOFP16-NEXT: movi v1.8h, #128, lsl #8 +; CHECK-GI-NOFP16-NEXT: eor v0.16b, v0.16b, v1.16b ; CHECK-GI-NOFP16-NEXT: ret ; ; CHECK-GI-FP16-LABEL: fabs_v7f16: @@ -202,9 +190,8 @@ define <4 x half> @fabs_v4f16(<4 x half> %a) { ; ; CHECK-GI-NOFP16-LABEL: fabs_v4f16: ; CHECK-GI-NOFP16: // %bb.0: // %entry -; CHECK-GI-NOFP16-NEXT: fcvtl v0.4s, v0.4h -; CHECK-GI-NOFP16-NEXT: fneg v0.4s, v0.4s -; CHECK-GI-NOFP16-NEXT: fcvtn v0.4h, v0.4s +; CHECK-GI-NOFP16-NEXT: movi v1.4h, #128, lsl #8 +; CHECK-GI-NOFP16-NEXT: eor v0.8b, v0.8b, v1.8b ; CHECK-GI-NOFP16-NEXT: ret ; ; CHECK-GI-FP16-LABEL: fabs_v4f16: @@ -230,12 +217,8 @@ define <8 x half> @fabs_v8f16(<8 x half> %a) { ; ; CHECK-GI-NOFP16-LABEL: fabs_v8f16: ; CHECK-GI-NOFP16: // %bb.0: // %entry -; CHECK-GI-NOFP16-NEXT: fcvtl v1.4s, v0.4h -; CHECK-GI-NOFP16-NEXT: fcvtl2 v0.4s, v0.8h -; CHECK-GI-NOFP16-NEXT: fneg v1.4s, v1.4s -; CHECK-GI-NOFP16-NEXT: fneg v2.4s, v0.4s -; CHECK-GI-NOFP16-NEXT: fcvtn v0.4h, v1.4s -; CHECK-GI-NOFP16-NEXT: fcvtn2 v0.8h, v2.4s +; CHECK-GI-NOFP16-NEXT: movi v1.8h, #128, lsl #8 +; CHECK-GI-NOFP16-NEXT: eor v0.16b, v0.16b, v1.16b ; CHECK-GI-NOFP16-NEXT: ret ; ; CHECK-GI-FP16-LABEL: fabs_v8f16: @@ -263,18 +246,9 @@ define <16 x half> @fabs_v16f16(<16 x half> %a) { ; ; CHECK-GI-NOFP16-LABEL: fabs_v16f16: ; CHECK-GI-NOFP16: // %bb.0: // %entry -; CHECK-GI-NOFP16-NEXT: fcvtl v2.4s, v0.4h -; CHECK-GI-NOFP16-NEXT: fcvtl v3.4s, v1.4h -; CHECK-GI-NOFP16-NEXT: fcvtl2 v0.4s, v0.8h -; CHECK-GI-NOFP16-NEXT: fcvtl2 v1.4s, v1.8h -; CHECK-GI-NOFP16-NEXT: fneg v2.4s, v2.4s -; CHECK-GI-NOFP16-NEXT: fneg v3.4s, v3.4s -; CHECK-GI-NOFP16-NEXT: fneg v4.4s, v0.4s -; CHECK-GI-NOFP16-NEXT: fneg v5.4s, v1.4s -; CHECK-GI-NOFP16-NEXT: fcvtn v0.4h, v2.4s -; CHECK-GI-NOFP16-NEXT: fcvtn v1.4h, v3.4s -; CHECK-GI-NOFP16-NEXT: fcvtn2 v0.8h, v4.4s -; CHECK-GI-NOFP16-NEXT: fcvtn2 v1.8h, v5.4s +; CHECK-GI-NOFP16-NEXT: movi v2.8h, #128, lsl #8 +; CHECK-GI-NOFP16-NEXT: eor v0.16b, v0.16b, v2.16b +; CHECK-GI-NOFP16-NEXT: eor v1.16b, v1.16b, v2.16b ; CHECK-GI-NOFP16-NEXT: ret ; ; CHECK-GI-FP16-LABEL: fabs_v16f16: From 30f5a3ca150e98d482abc6a4d0e3fe6c12f77695 Mon Sep 17 00:00:00 2001 From: Lang Hames Date: Fri, 27 Sep 2024 16:26:20 +1000 Subject: [PATCH 050/469] [MCJIT][ORC] Change test guards to 'UNSUPPORTED: system-darwin'. These tests were guarded with 'UNSUPPORTED: target={{.*}}-darwin{{.*}}', but that check may unintentionally pass if LLVM is configured with a host triple that specifies a specific Darwin flavor, e.g. macOS with -DLLVM_HOST_TRIPLE:STRING=aarch64-apple-macosx13.0. All darwin flavors should set 'system-darwin', so this is a safer feature to check. rdar://134942819 --- llvm/test/ExecutionEngine/MCJIT/test-global-ctors.ll | 2 +- llvm/test/ExecutionEngine/Orc/weak-comdat.ll | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/llvm/test/ExecutionEngine/MCJIT/test-global-ctors.ll b/llvm/test/ExecutionEngine/MCJIT/test-global-ctors.ll index 2e95e7eda588a..4598c9f71f14c 100644 --- a/llvm/test/ExecutionEngine/MCJIT/test-global-ctors.ll +++ b/llvm/test/ExecutionEngine/MCJIT/test-global-ctors.ll @@ -1,6 +1,6 @@ ; RUN: %lli -jit-kind=mcjit %s > /dev/null ; RUN: %lli %s > /dev/null -; UNSUPPORTED: target={{.*}}-darwin{{.*}} +; UNSUPPORTED: system-darwin @var = global i32 1, align 4 @llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr @ctor_func, ptr null }] @llvm.global_dtors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr @dtor_func, ptr null }] diff --git a/llvm/test/ExecutionEngine/Orc/weak-comdat.ll b/llvm/test/ExecutionEngine/Orc/weak-comdat.ll index e1e1ab02e2981..4ebbfdf4aa35b 100644 --- a/llvm/test/ExecutionEngine/Orc/weak-comdat.ll +++ b/llvm/test/ExecutionEngine/Orc/weak-comdat.ll @@ -1,5 +1,5 @@ ; RUN: lli -extra-module %p/Inputs/weak-comdat-def.ll %s -; UNSUPPORTED: target={{.*}}-darwin{{.*}} +; UNSUPPORTED: system-darwin declare i32 @g() From ff8a9921ec9425e31aa1da273c2e4836f9e4069e Mon Sep 17 00:00:00 2001 From: Ryosuke Niwa Date: Fri, 27 Sep 2024 00:02:59 -0700 Subject: [PATCH 051/469] WebKit Checkers should set DeclWithIssue. (#109389) Set DeclWithIssue in alpha.webkit.UncountedCallArgsChecker and alpha.webkit.UncountedLocalVarsChecker. --- .../WebKit/UncountedCallArgsChecker.cpp | 31 ++++++++++++++----- .../WebKit/UncountedLocalVarsChecker.cpp | 21 ++++++++++--- 2 files changed, 39 insertions(+), 13 deletions(-) diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedCallArgsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedCallArgsChecker.cpp index 31e9b3c4b9d41..0ed93ab26bf5c 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedCallArgsChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedCallArgsChecker.cpp @@ -18,6 +18,8 @@ #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" #include "clang/StaticAnalyzer/Core/Checker.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/Support/SaveAndRestore.h" #include using namespace clang; @@ -44,7 +46,11 @@ class UncountedCallArgsChecker // visit template instantiations or lambda classes. We // want to visit those, so we make our own RecursiveASTVisitor. struct LocalVisitor : public RecursiveASTVisitor { + using Base = RecursiveASTVisitor; + const UncountedCallArgsChecker *Checker; + Decl *DeclWithIssue{nullptr}; + explicit LocalVisitor(const UncountedCallArgsChecker *Checker) : Checker(Checker) { assert(Checker); @@ -56,12 +62,18 @@ class UncountedCallArgsChecker bool TraverseClassTemplateDecl(ClassTemplateDecl *Decl) { if (isRefType(safeGetName(Decl))) return true; - return RecursiveASTVisitor::TraverseClassTemplateDecl( - Decl); + return Base::TraverseClassTemplateDecl(Decl); + } + + bool TraverseDecl(Decl *D) { + llvm::SaveAndRestore SavedDecl(DeclWithIssue); + if (D && (isa(D) || isa(D))) + DeclWithIssue = D; + return Base::TraverseDecl(D); } bool VisitCallExpr(const CallExpr *CE) { - Checker->visitCallExpr(CE); + Checker->visitCallExpr(CE, DeclWithIssue); return true; } }; @@ -70,7 +82,7 @@ class UncountedCallArgsChecker visitor.TraverseDecl(const_cast(TUD)); } - void visitCallExpr(const CallExpr *CE) const { + void visitCallExpr(const CallExpr *CE, const Decl *D) const { if (shouldSkipCall(CE)) return; @@ -89,7 +101,7 @@ class UncountedCallArgsChecker QualType ArgType = MemberCallExpr->getObjectType().getCanonicalType(); std::optional IsUncounted = isUncounted(ArgType); if (IsUncounted && *IsUncounted && !isPtrOriginSafe(E)) - reportBugOnThis(E); + reportBugOnThis(E, D); } for (auto P = F->param_begin(); @@ -120,7 +132,7 @@ class UncountedCallArgsChecker if (isPtrOriginSafe(Arg)) continue; - reportBug(Arg, *P); + reportBug(Arg, *P, D); } } } @@ -241,7 +253,8 @@ class UncountedCallArgsChecker ClsName.ends_with("String")); } - void reportBug(const Expr *CallArg, const ParmVarDecl *Param) const { + void reportBug(const Expr *CallArg, const ParmVarDecl *Param, + const Decl *DeclWithIssue) const { assert(CallArg); SmallString<100> Buf; @@ -262,10 +275,11 @@ class UncountedCallArgsChecker PathDiagnosticLocation BSLoc(SrcLocToReport, BR->getSourceManager()); auto Report = std::make_unique(Bug, Os.str(), BSLoc); Report->addRange(CallArg->getSourceRange()); + Report->setDeclWithIssue(DeclWithIssue); BR->emitReport(std::move(Report)); } - void reportBugOnThis(const Expr *CallArg) const { + void reportBugOnThis(const Expr *CallArg, const Decl *DeclWithIssue) const { assert(CallArg); const SourceLocation SrcLocToReport = CallArg->getSourceRange().getBegin(); @@ -275,6 +289,7 @@ class UncountedCallArgsChecker Bug, "Call argument for 'this' parameter is uncounted and unsafe.", BSLoc); Report->addRange(CallArg->getSourceRange()); + Report->setDeclWithIssue(DeclWithIssue); BR->emitReport(std::move(Report)); } }; diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedLocalVarsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedLocalVarsChecker.cpp index 274da0baf2ce5..9d0a3bb5da732 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedLocalVarsChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedLocalVarsChecker.cpp @@ -121,6 +121,7 @@ class UncountedLocalVarsChecker // want to visit those, so we make our own RecursiveASTVisitor. struct LocalVisitor : public RecursiveASTVisitor { const UncountedLocalVarsChecker *Checker; + Decl *DeclWithIssue{nullptr}; TrivialFunctionAnalysis TFA; @@ -134,10 +135,17 @@ class UncountedLocalVarsChecker bool shouldVisitTemplateInstantiations() const { return true; } bool shouldVisitImplicitCode() const { return false; } + bool TraverseDecl(Decl *D) { + llvm::SaveAndRestore SavedDecl(DeclWithIssue); + if (D && (isa(D) || isa(D))) + DeclWithIssue = D; + return Base::TraverseDecl(D); + } + bool VisitVarDecl(VarDecl *V) { auto *Init = V->getInit(); if (Init && V->isLocalVarDecl()) - Checker->visitVarDecl(V, Init); + Checker->visitVarDecl(V, Init, DeclWithIssue); return true; } @@ -145,7 +153,7 @@ class UncountedLocalVarsChecker if (BO->isAssignmentOp()) { if (auto *VarRef = dyn_cast(BO->getLHS())) { if (auto *V = dyn_cast(VarRef->getDecl())) - Checker->visitVarDecl(V, BO->getRHS()); + Checker->visitVarDecl(V, BO->getRHS(), DeclWithIssue); } } return true; @@ -186,7 +194,8 @@ class UncountedLocalVarsChecker visitor.TraverseDecl(const_cast(TUD)); } - void visitVarDecl(const VarDecl *V, const Expr *Value) const { + void visitVarDecl(const VarDecl *V, const Expr *Value, + const Decl *DeclWithIssue) const { if (shouldSkipVarDecl(V)) return; @@ -240,7 +249,7 @@ class UncountedLocalVarsChecker })) return; - reportBug(V, Value); + reportBug(V, Value, DeclWithIssue); } } @@ -249,7 +258,8 @@ class UncountedLocalVarsChecker return BR->getSourceManager().isInSystemHeader(V->getLocation()); } - void reportBug(const VarDecl *V, const Expr *Value) const { + void reportBug(const VarDecl *V, const Expr *Value, + const Decl *DeclWithIssue) const { assert(V); SmallString<100> Buf; llvm::raw_svector_ostream Os(Buf); @@ -278,6 +288,7 @@ class UncountedLocalVarsChecker PathDiagnosticLocation BSLoc(V->getLocation(), BR->getSourceManager()); auto Report = std::make_unique(Bug, Os.str(), BSLoc); Report->addRange(V->getSourceRange()); + Report->setDeclWithIssue(DeclWithIssue); BR->emitReport(std::move(Report)); } } From 61c8b7159a740d43a6a0fa52756eb479e1a9c1c3 Mon Sep 17 00:00:00 2001 From: Vipul Cariappa Date: Fri, 27 Sep 2024 12:33:32 +0530 Subject: [PATCH 052/469] [clang] return first Decl for CanonicalDecl in TranslationUnitDecl (#110101) Return the first `Decl` when using `TranslationUnitDecl::getCanonicalDecl` --- clang/include/clang/AST/Decl.h | 4 ++++ .../unittests/Interpreter/InterpreterTest.cpp | 22 +++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h index 0600ecc4d14a1..7ff35d73df599 100644 --- a/clang/include/clang/AST/Decl.h +++ b/clang/include/clang/AST/Decl.h @@ -133,6 +133,10 @@ class TranslationUnitDecl : public Decl, static TranslationUnitDecl *castFromDeclContext(const DeclContext *DC) { return static_cast(const_cast(DC)); } + + /// Retrieves the canonical declaration of this translation unit. + TranslationUnitDecl *getCanonicalDecl() override { return getFirstDecl(); } + const TranslationUnitDecl *getCanonicalDecl() const { return getFirstDecl(); } }; /// Represents a `#pragma comment` line. Always a child of diff --git a/clang/unittests/Interpreter/InterpreterTest.cpp b/clang/unittests/Interpreter/InterpreterTest.cpp index a2e960f143111..30b051e747f92 100644 --- a/clang/unittests/Interpreter/InterpreterTest.cpp +++ b/clang/unittests/Interpreter/InterpreterTest.cpp @@ -381,4 +381,26 @@ TEST_F(InterpreterTest, Value) { EXPECT_TRUE(V9.isManuallyAlloc()); } +TEST_F(InterpreterTest, TranslationUnit_CanonicalDecl) { + std::vector Args; + std::unique_ptr Interp = createInterpreter(Args); + + Sema &sema = Interp->getCompilerInstance()->getSema(); + + llvm::cantFail(Interp->ParseAndExecute("int x = 42;")); + + TranslationUnitDecl *TU = + sema.getASTContext().getTranslationUnitDecl()->getCanonicalDecl(); + + llvm::cantFail(Interp->ParseAndExecute("long y = 84;")); + + EXPECT_EQ(TU, + sema.getASTContext().getTranslationUnitDecl()->getCanonicalDecl()); + + llvm::cantFail(Interp->ParseAndExecute("char z = 'z';")); + + EXPECT_EQ(TU, + sema.getASTContext().getTranslationUnitDecl()->getCanonicalDecl()); +} + } // end anonymous namespace From 880ee48d5c9d88be1c611451e84f16eafcebd1a6 Mon Sep 17 00:00:00 2001 From: Youngsuk Kim Date: Fri, 27 Sep 2024 03:07:44 -0400 Subject: [PATCH 053/469] [clang][CGExpr] Avoid Type::getPointerTo() (NFC) (#110209) `Type::getPointerTo()` is to be removed soon. This also removes the whole code section for "C99 6.5.2.2p6"; It's essentially a no-op since llvm uses opaque pointers. --- clang/lib/CodeGen/CGExpr.cpp | 41 +++++------------------------------- 1 file changed, 5 insertions(+), 36 deletions(-) diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index 9166db4c74128..df4994ba9af6e 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -122,7 +122,7 @@ RawAddress CodeGenFunction::CreateTempAlloca(llvm::Type *Ty, CharUnits Align, Builder.SetInsertPoint(getPostAllocaInsertPoint()); V = getTargetHooks().performAddrSpaceCast( *this, V, getASTAllocaAddressSpace(), LangAS::Default, - Ty->getPointerTo(DestAddrSpace), /*non-null*/ true); + Builder.getPtrTy(DestAddrSpace), /*non-null*/ true); } return RawAddress(V, Ty, Align, KnownNonNull); @@ -469,7 +469,8 @@ static RawAddress createReferenceTemporary(CodeGenFunction &CGF, if (AS != LangAS::Default) C = TCG.performAddrSpaceCast( CGF.CGM, GV, AS, LangAS::Default, - GV->getValueType()->getPointerTo( + llvm::PointerType::get( + CGF.getLLVMContext(), CGF.getContext().getTargetAddressSpace(LangAS::Default))); // FIXME: Should we put the new global into a COMDAT? return RawAddress(C, GV->getValueType(), alignment); @@ -3207,7 +3208,7 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) { if (AS != T.getAddressSpace()) { auto TargetAS = getContext().getTargetAddressSpace(T.getAddressSpace()); - auto PtrTy = ATPO.getElementType()->getPointerTo(TargetAS); + auto PtrTy = llvm::PointerType::get(CGM.getLLVMContext(), TargetAS); auto ASC = getTargetHooks().performAddrSpaceCast( CGM, ATPO.getPointer(), AS, T.getAddressSpace(), PtrTy); ATPO = ConstantAddress(ASC, ATPO.getElementType(), ATPO.getAlignment()); @@ -3835,9 +3836,7 @@ void CodeGenFunction::EmitCfiCheckFail() { llvm::StructType::get(Int8Ty, SourceLocationTy, VoidPtrTy); llvm::Value *V = Builder.CreateConstGEP2_32( - CfiCheckFailDataTy, - Builder.CreatePointerCast(Data, CfiCheckFailDataTy->getPointerTo(0)), 0, - 0); + CfiCheckFailDataTy, Builder.CreatePointerCast(Data, UnqualPtrTy), 0, 0); Address CheckKindAddr(V, Int8Ty, getIntAlign()); llvm::Value *CheckKind = Builder.CreateLoad(CheckKindAddr); @@ -6115,36 +6114,6 @@ RValue CodeGenFunction::EmitCall(QualType CalleeType, if (ResolvedFnInfo) *ResolvedFnInfo = &FnInfo; - // C99 6.5.2.2p6: - // If the expression that denotes the called function has a type - // that does not include a prototype, [the default argument - // promotions are performed]. If the number of arguments does not - // equal the number of parameters, the behavior is undefined. If - // the function is defined with a type that includes a prototype, - // and either the prototype ends with an ellipsis (, ...) or the - // types of the arguments after promotion are not compatible with - // the types of the parameters, the behavior is undefined. If the - // function is defined with a type that does not include a - // prototype, and the types of the arguments after promotion are - // not compatible with those of the parameters after promotion, - // the behavior is undefined [except in some trivial cases]. - // That is, in the general case, we should assume that a call - // through an unprototyped function type works like a *non-variadic* - // call. The way we make this work is to cast to the exact type - // of the promoted arguments. - // - // Chain calls use this same code path to add the invisible chain parameter - // to the function type. - if (isa(FnType) || Chain) { - llvm::Type *CalleeTy = getTypes().GetFunctionType(FnInfo); - int AS = Callee.getFunctionPointer()->getType()->getPointerAddressSpace(); - CalleeTy = CalleeTy->getPointerTo(AS); - - llvm::Value *CalleePtr = Callee.getFunctionPointer(); - CalleePtr = Builder.CreateBitCast(CalleePtr, CalleeTy, "callee.knr.cast"); - Callee.setFunctionPointer(CalleePtr); - } - // HIP function pointer contains kernel handle when it is used in triple // chevron. The kernel stub needs to be loaded from kernel handle and used // as callee. From 3c0984309ed338560f902a918d6f99959b4c7c33 Mon Sep 17 00:00:00 2001 From: Ryosuke Niwa Date: Fri, 27 Sep 2024 00:42:18 -0700 Subject: [PATCH 054/469] [alpha.webkit.NoUncheckedPtrMemberChecker] Introduce member variable checker for CheckedPtr/CheckedRef (#108352) This PR introduces new WebKit checker to warn a member variable that is a raw reference or a raw pointer to an object, which is capable of creating a CheckedRef/CheckedPtr. --- clang/docs/analyzer/checkers.rst | 21 +++++ .../clang/StaticAnalyzer/Checkers/Checkers.td | 4 + .../StaticAnalyzer/Checkers/CMakeLists.txt | 2 +- .../Checkers/WebKit/PtrTypesSemantics.cpp | 71 ++++++++++----- .../Checkers/WebKit/PtrTypesSemantics.h | 12 ++- ...Checker.cpp => RawPtrRefMemberChecker.cpp} | 91 +++++++++++++++---- .../Analysis/Checkers/WebKit/mock-types.h | 48 ++++++++++ .../Checkers/WebKit/unchecked-members.cpp | 52 +++++++++++ .../lib/StaticAnalyzer/Checkers/BUILD.gn | 2 +- 9 files changed, 257 insertions(+), 46 deletions(-) rename clang/lib/StaticAnalyzer/Checkers/WebKit/{NoUncountedMembersChecker.cpp => RawPtrRefMemberChecker.cpp} (63%) create mode 100644 clang/test/Analysis/Checkers/WebKit/unchecked-members.cpp diff --git a/clang/docs/analyzer/checkers.rst b/clang/docs/analyzer/checkers.rst index 47c6fc680deb1..9847d449d76d0 100644 --- a/clang/docs/analyzer/checkers.rst +++ b/clang/docs/analyzer/checkers.rst @@ -3442,6 +3442,27 @@ Check for non-determinism caused by sorting of pointers. alpha.WebKit ^^^^^^^^^^^^ +.. _alpha-webkit-NoUncheckedPtrMemberChecker: + +alpha.webkit.NoUncheckedPtrMemberChecker +"""""""""""""""""""""""""""""""""""""""" +Raw pointers and references to an object which supports CheckedPtr or CheckedRef can't be used as class members. Only CheckedPtr, CheckedRef, RefPtr, or Ref are allowed. + +.. code-block:: cpp + + struct CheckableObj { + void incrementPtrCount() {} + void decrementPtrCount() {} + }; + + struct Foo { + CheckableObj* ptr; // warn + CheckableObj& ptr; // warn + // ... + }; + +See `WebKit Guidelines for Safer C++ Programming `_ for details. + .. _alpha-webkit-UncountedCallArgsChecker: alpha.webkit.UncountedCallArgsChecker diff --git a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td index 7da0d0a87e8c0..747ebd8c2e4de 100644 --- a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td +++ b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td @@ -1764,6 +1764,10 @@ def UncountedLambdaCapturesChecker : Checker<"UncountedLambdaCapturesChecker">, let ParentPackage = WebKitAlpha in { +def NoUncheckedPtrMemberChecker : Checker<"NoUncheckedPtrMemberChecker">, + HelpText<"Check for no unchecked member variables.">, + Documentation; + def UncountedCallArgsChecker : Checker<"UncountedCallArgsChecker">, HelpText<"Check uncounted call arguments.">, Documentation; diff --git a/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt b/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt index 414282d58f779..6da3665ab9a4d 100644 --- a/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt +++ b/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt @@ -132,7 +132,7 @@ add_clang_library(clangStaticAnalyzerCheckers VLASizeChecker.cpp ValistChecker.cpp VirtualCallChecker.cpp - WebKit/NoUncountedMembersChecker.cpp + WebKit/RawPtrRefMemberChecker.cpp WebKit/ASTUtils.cpp WebKit/PtrTypesSemantics.cpp WebKit/RefCntblBaseVirtualDtorChecker.cpp diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp index 54c99c3c1b37f..4d145be808f6d 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp @@ -19,8 +19,7 @@ using namespace clang; namespace { -bool hasPublicMethodInBaseClass(const CXXRecordDecl *R, - const char *NameToMatch) { +bool hasPublicMethodInBaseClass(const CXXRecordDecl *R, StringRef NameToMatch) { assert(R); assert(R->hasDefinition()); @@ -37,7 +36,7 @@ bool hasPublicMethodInBaseClass(const CXXRecordDecl *R, namespace clang { std::optional -hasPublicMethodInBase(const CXXBaseSpecifier *Base, const char *NameToMatch) { +hasPublicMethodInBase(const CXXBaseSpecifier *Base, StringRef NameToMatch) { assert(Base); const Type *T = Base->getType().getTypePtrOrNull(); @@ -53,16 +52,17 @@ hasPublicMethodInBase(const CXXBaseSpecifier *Base, const char *NameToMatch) { return hasPublicMethodInBaseClass(R, NameToMatch) ? R : nullptr; } -std::optional isRefCountable(const CXXRecordDecl* R) -{ +std::optional isSmartPtrCompatible(const CXXRecordDecl *R, + StringRef IncMethodName, + StringRef DecMethodName) { assert(R); R = R->getDefinition(); if (!R) return std::nullopt; - bool hasRef = hasPublicMethodInBaseClass(R, "ref"); - bool hasDeref = hasPublicMethodInBaseClass(R, "deref"); + bool hasRef = hasPublicMethodInBaseClass(R, IncMethodName); + bool hasDeref = hasPublicMethodInBaseClass(R, DecMethodName); if (hasRef && hasDeref) return true; @@ -70,15 +70,15 @@ std::optional isRefCountable(const CXXRecordDecl* R) Paths.setOrigin(const_cast(R)); bool AnyInconclusiveBase = false; - const auto hasPublicRefInBase = - [&AnyInconclusiveBase](const CXXBaseSpecifier *Base, CXXBasePath &) { - auto hasRefInBase = clang::hasPublicMethodInBase(Base, "ref"); - if (!hasRefInBase) { - AnyInconclusiveBase = true; - return false; - } - return (*hasRefInBase) != nullptr; - }; + const auto hasPublicRefInBase = [&](const CXXBaseSpecifier *Base, + CXXBasePath &) { + auto hasRefInBase = clang::hasPublicMethodInBase(Base, IncMethodName); + if (!hasRefInBase) { + AnyInconclusiveBase = true; + return false; + } + return (*hasRefInBase) != nullptr; + }; hasRef = hasRef || R->lookupInBases(hasPublicRefInBase, Paths, /*LookupInDependent =*/true); @@ -86,15 +86,15 @@ std::optional isRefCountable(const CXXRecordDecl* R) return std::nullopt; Paths.clear(); - const auto hasPublicDerefInBase = - [&AnyInconclusiveBase](const CXXBaseSpecifier *Base, CXXBasePath &) { - auto hasDerefInBase = clang::hasPublicMethodInBase(Base, "deref"); - if (!hasDerefInBase) { - AnyInconclusiveBase = true; - return false; - } - return (*hasDerefInBase) != nullptr; - }; + const auto hasPublicDerefInBase = [&](const CXXBaseSpecifier *Base, + CXXBasePath &) { + auto hasDerefInBase = clang::hasPublicMethodInBase(Base, DecMethodName); + if (!hasDerefInBase) { + AnyInconclusiveBase = true; + return false; + } + return (*hasDerefInBase) != nullptr; + }; hasDeref = hasDeref || R->lookupInBases(hasPublicDerefInBase, Paths, /*LookupInDependent =*/true); if (AnyInconclusiveBase) @@ -103,11 +103,23 @@ std::optional isRefCountable(const CXXRecordDecl* R) return hasRef && hasDeref; } +std::optional isRefCountable(const clang::CXXRecordDecl *R) { + return isSmartPtrCompatible(R, "ref", "deref"); +} + +std::optional isCheckedPtrCapable(const clang::CXXRecordDecl *R) { + return isSmartPtrCompatible(R, "incrementPtrCount", "decrementPtrCount"); +} + bool isRefType(const std::string &Name) { return Name == "Ref" || Name == "RefAllowingPartiallyDestroyed" || Name == "RefPtr" || Name == "RefPtrAllowingPartiallyDestroyed"; } +bool isCheckedPtr(const std::string &Name) { + return Name == "CheckedPtr" || Name == "CheckedRef"; +} + bool isCtorOfRefCounted(const clang::FunctionDecl *F) { assert(F); const std::string &FunctionName = safeGetName(F); @@ -217,6 +229,15 @@ bool isRefCounted(const CXXRecordDecl *R) { return false; } +bool isCheckedPtr(const CXXRecordDecl *R) { + assert(R); + if (auto *TmplR = R->getTemplateInstantiationPattern()) { + const auto &ClassName = safeGetName(TmplR); + return isCheckedPtr(ClassName); + } + return false; +} + bool isPtrConversion(const FunctionDecl *F) { assert(F); if (isCtorOfRefCounted(F)) diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h index e2d0342bebd52..3528c52a7d659 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h @@ -34,15 +34,23 @@ class Type; /// \returns CXXRecordDecl of the base if the type has ref as a public method, /// nullptr if not, std::nullopt if inconclusive. std::optional -hasPublicMethodInBase(const CXXBaseSpecifier *Base, const char *NameToMatch); +hasPublicMethodInBase(const CXXBaseSpecifier *Base, + llvm::StringRef NameToMatch); /// \returns true if \p Class is ref-countable, false if not, std::nullopt if /// inconclusive. -std::optional isRefCountable(const clang::CXXRecordDecl* Class); +std::optional isRefCountable(const clang::CXXRecordDecl *Class); + +/// \returns true if \p Class is checked-pointer compatible, false if not, +/// std::nullopt if inconclusive. +std::optional isCheckedPtrCapable(const clang::CXXRecordDecl *Class); /// \returns true if \p Class is ref-counted, false if not. bool isRefCounted(const clang::CXXRecordDecl *Class); +/// \returns true if \p Class is a CheckedPtr / CheckedRef, false if not. +bool isCheckedPtr(const clang::CXXRecordDecl *Class); + /// \returns true if \p Class is ref-countable AND not ref-counted, false if /// not, std::nullopt if inconclusive. std::optional isUncounted(const clang::QualType T); diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/NoUncountedMembersChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefMemberChecker.cpp similarity index 63% rename from clang/lib/StaticAnalyzer/Checkers/WebKit/NoUncountedMembersChecker.cpp rename to clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefMemberChecker.cpp index 69a0eb3086ab7..2ce6bc330e0ca 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/NoUncountedMembersChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefMemberChecker.cpp @@ -1,4 +1,4 @@ -//=======- NoUncountedMembersChecker.cpp -------------------------*- C++ -*-==// +//=======- RawPtrRefMemberChecker.cpp ----------------------------*- C++ -*-==// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -25,18 +25,21 @@ using namespace ento; namespace { -class NoUncountedMemberChecker +class RawPtrRefMemberChecker : public Checker> { private: BugType Bug; mutable BugReporter *BR; public: - NoUncountedMemberChecker() - : Bug(this, - "Member variable is a raw-pointer/reference to reference-countable " - "type", - "WebKit coding guidelines") {} + RawPtrRefMemberChecker(const char *description) + : Bug(this, description, "WebKit coding guidelines") {} + + virtual std::optional + isPtrCompatible(const clang::CXXRecordDecl *) const = 0; + virtual bool isPtrCls(const clang::CXXRecordDecl *) const = 0; + virtual const char *typeName() const = 0; + virtual const char *invariant() const = 0; void checkASTDecl(const TranslationUnitDecl *TUD, AnalysisManager &MGR, BugReporter &BRArg) const { @@ -46,8 +49,8 @@ class NoUncountedMemberChecker // visit template instantiations or lambda classes. We // want to visit those, so we make our own RecursiveASTVisitor. struct LocalVisitor : public RecursiveASTVisitor { - const NoUncountedMemberChecker *Checker; - explicit LocalVisitor(const NoUncountedMemberChecker *Checker) + const RawPtrRefMemberChecker *Checker; + explicit LocalVisitor(const RawPtrRefMemberChecker *Checker) : Checker(Checker) { assert(Checker); } @@ -77,9 +80,9 @@ class NoUncountedMemberChecker if (auto *MemberCXXRD = MemberType->getPointeeCXXRecordDecl()) { // If we don't see the definition we just don't know. if (MemberCXXRD->hasDefinition()) { - std::optional isRCAble = isRefCountable(MemberCXXRD); - if (isRCAble && *isRCAble) - reportBug(Member, MemberType, MemberCXXRD, RD); + std::optional isRCAble = isPtrCompatible(MemberCXXRD); + if (isRCAble && *isRCAble) + reportBug(Member, MemberType, MemberCXXRD, RD); } } } @@ -114,7 +117,7 @@ class NoUncountedMemberChecker // a member but we trust them to handle it correctly. auto CXXRD = llvm::dyn_cast_or_null(RD); if (CXXRD) - return isRefCounted(CXXRD); + return isPtrCls(CXXRD); return false; } @@ -134,10 +137,10 @@ class NoUncountedMemberChecker Os << " in "; printQuotedQualifiedName(Os, ClassCXXRD); Os << " is a " - << (isa(MemberType) ? "raw pointer" : "reference") - << " to ref-countable type "; + << (isa(MemberType) ? "raw pointer" : "reference") << " to " + << typeName() << " "; printQuotedQualifiedName(Os, MemberCXXRD); - Os << "; member variables must be ref-counted."; + Os << "; " << invariant() << "."; PathDiagnosticLocation BSLoc(Member->getSourceRange().getBegin(), BR->getSourceManager()); @@ -146,13 +149,67 @@ class NoUncountedMemberChecker BR->emitReport(std::move(Report)); } }; + +class NoUncountedMemberChecker final : public RawPtrRefMemberChecker { +public: + NoUncountedMemberChecker() + : RawPtrRefMemberChecker("Member variable is a raw-pointer/reference to " + "reference-countable type") {} + + std::optional + isPtrCompatible(const clang::CXXRecordDecl *R) const final { + return isRefCountable(R); + } + + bool isPtrCls(const clang::CXXRecordDecl *R) const final { + return isRefCounted(R); + } + + const char *typeName() const final { return "ref-countable type"; } + + const char *invariant() const final { + return "member variables must be Ref, RefPtr, WeakRef, or WeakPtr"; + } +}; + +class NoUncheckedPtrMemberChecker final : public RawPtrRefMemberChecker { +public: + NoUncheckedPtrMemberChecker() + : RawPtrRefMemberChecker("Member variable is a raw-pointer/reference to " + "checked-pointer capable type") {} + + std::optional + isPtrCompatible(const clang::CXXRecordDecl *R) const final { + return isCheckedPtrCapable(R); + } + + bool isPtrCls(const clang::CXXRecordDecl *R) const final { + return isCheckedPtr(R); + } + + const char *typeName() const final { return "CheckedPtr capable type"; } + + const char *invariant() const final { + return "member variables must be a CheckedPtr, CheckedRef, WeakRef, or " + "WeakPtr"; + } +}; + } // namespace void ento::registerNoUncountedMemberChecker(CheckerManager &Mgr) { Mgr.registerChecker(); } -bool ento::shouldRegisterNoUncountedMemberChecker( +bool ento::shouldRegisterNoUncountedMemberChecker(const CheckerManager &Mgr) { + return true; +} + +void ento::registerNoUncheckedPtrMemberChecker(CheckerManager &Mgr) { + Mgr.registerChecker(); +} + +bool ento::shouldRegisterNoUncheckedPtrMemberChecker( const CheckerManager &Mgr) { return true; } diff --git a/clang/test/Analysis/Checkers/WebKit/mock-types.h b/clang/test/Analysis/Checkers/WebKit/mock-types.h index c427b22fd683e..933b4c5e62a79 100644 --- a/clang/test/Analysis/Checkers/WebKit/mock-types.h +++ b/clang/test/Analysis/Checkers/WebKit/mock-types.h @@ -108,4 +108,52 @@ struct RefCountable { template T *downcast(T *t) { return t; } +template struct CheckedRef { +private: + T *t; + +public: + CheckedRef() : t{} {}; + CheckedRef(T &t) : t(t) { t->incrementPtrCount(); } + CheckedRef(const CheckedRef& o) : t(o.t) { if (t) t->incrementPtrCount(); } + ~CheckedRef() { if (t) t->decrementPtrCount(); } + T &get() { return *t; } + T *ptr() { return t; } + T *operator->() { return t; } + operator const T &() const { return *t; } + operator T &() { return *t; } +}; + +template struct CheckedPtr { +private: + T *t; + +public: + CheckedPtr() : t(nullptr) {} + CheckedPtr(T *t) + : t(t) { + if (t) + t->incrementPtrCount(); + } + CheckedPtr(Ref&& o) + : t(o.leakRef()) + { } + ~CheckedPtr() { + if (t) + t->decrementPtrCount(); + } + T *get() { return t; } + T *operator->() { return t; } + const T *operator->() const { return t; } + T &operator*() { return *t; } + CheckedPtr &operator=(T *) { return *this; } + operator bool() const { return t; } +}; + +class CheckedObj { +public: + void incrementPtrCount(); + void decrementPtrCount(); +}; + #endif diff --git a/clang/test/Analysis/Checkers/WebKit/unchecked-members.cpp b/clang/test/Analysis/Checkers/WebKit/unchecked-members.cpp new file mode 100644 index 0000000000000..0189b0cd50fcc --- /dev/null +++ b/clang/test/Analysis/Checkers/WebKit/unchecked-members.cpp @@ -0,0 +1,52 @@ +// RUN: %clang_analyze_cc1 -analyzer-checker=alpha.webkit.NoUncheckedPtrMemberChecker -verify %s + +#include "mock-types.h" + +namespace members { + + struct Foo { + private: + CheckedObj* a = nullptr; +// expected-warning@-1{{Member variable 'a' in 'members::Foo' is a raw pointer to CheckedPtr capable type 'CheckedObj'}} + CheckedObj& b; +// expected-warning@-1{{Member variable 'b' in 'members::Foo' is a reference to CheckedPtr capable type 'CheckedObj'}} + + [[clang::suppress]] + CheckedObj* a_suppressed = nullptr; + + [[clang::suppress]] + CheckedObj& b_suppressed; + + CheckedPtr c; + CheckedRef d; + + public: + Foo(); + }; + + template + struct FooTmpl { + S* e; +// expected-warning@-1{{Member variable 'e' in 'members::FooTmpl' is a raw pointer to CheckedPtr capable type 'CheckedObj'}} + }; + + void forceTmplToInstantiate(FooTmpl) { } + +} // namespace members + +namespace ignore_unions { + + union Foo { + CheckedObj* a; + CheckedPtr c; + CheckedRef d; + }; + + template + union FooTmpl { + T* a; + }; + + void forceTmplToInstantiate(FooTmpl) { } + +} // namespace ignore_unions diff --git a/llvm/utils/gn/secondary/clang/lib/StaticAnalyzer/Checkers/BUILD.gn b/llvm/utils/gn/secondary/clang/lib/StaticAnalyzer/Checkers/BUILD.gn index 3b640ae41b9f6..7a6c360e88c14 100644 --- a/llvm/utils/gn/secondary/clang/lib/StaticAnalyzer/Checkers/BUILD.gn +++ b/llvm/utils/gn/secondary/clang/lib/StaticAnalyzer/Checkers/BUILD.gn @@ -141,7 +141,7 @@ static_library("Checkers") { "VforkChecker.cpp", "VirtualCallChecker.cpp", "WebKit/ASTUtils.cpp", - "WebKit/NoUncountedMembersChecker.cpp", + "WebKit/RawPtrRefMemberChecker.cpp", "WebKit/PtrTypesSemantics.cpp", "WebKit/RefCntblBaseVirtualDtorChecker.cpp", "WebKit/UncountedCallArgsChecker.cpp", From 8dd817b25ae8b666aef839d36ffe028c01d411b5 Mon Sep 17 00:00:00 2001 From: Oliver Stannard Date: Fri, 27 Sep 2024 10:08:05 +0200 Subject: [PATCH 055/469] [LangRef] Disallow accessing byval arguments from tail-called functions (#110093) We already disallow accessing the callee's allocas from a tail-called function, because their stack memory will have been de-allocated before the tail call. I think this should apply to byval arguments too, as they also occupy space in the caller's stack frame. This was originally part of #109943, spilt out for separate review. --- llvm/docs/LangRef.rst | 65 +++++++++++++++++++++++++-- llvm/test/CodeGen/ARM/struct_byval.ll | 19 -------- 2 files changed, 61 insertions(+), 23 deletions(-) diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst index 3b905c2788128..3f39d58b322a4 100644 --- a/llvm/docs/LangRef.rst +++ b/llvm/docs/LangRef.rst @@ -12658,10 +12658,67 @@ This instruction requires several arguments: the return value of the callee is returned to the caller's caller, even if a void return type is in use. - Both markers imply that the callee does not access allocas from the caller. - The ``tail`` marker additionally implies that the callee does not access - varargs from the caller. Calls marked ``musttail`` must obey the following - additional rules: + Both markers imply that the callee does not access allocas, va_args, or + byval arguments from the caller. As an exception to that, an alloca or byval + argument may be passed to the callee as a byval argument, which can be + dereferenced inside the callee. For example: + +.. code-block:: llvm + + declare void @take_byval(ptr byval(i64)) + declare void @take_ptr(ptr) + + ; Invalid (assuming @take_ptr dereferences the pointer), because %local + ; may be de-allocated before the call to @take_ptr. + define void @invalid_alloca() { + entry: + %local = alloca i64 + tail call void @take_ptr(ptr %local) + ret void + } + + ; Valid, the byval attribute causes the memory allocated by %local to be + ; copied into @take_byval's stack frame. + define void @byval_alloca() { + entry: + %local = alloca i64 + tail call void @take_byval(ptr byval(i64) %local) + ret void + } + + ; Invalid, because @use_global_va_list uses the variadic arguments from + ; @invalid_va_list. + %struct.va_list = type { ptr } + @va_list = external global %struct.va_list + define void @use_global_va_list() { + entry: + %arg = va_arg ptr @va_list, i64 + ret void + } + define void @invalid_va_list(i32 %a, ...) { + entry: + call void @llvm.va_start.p0(ptr @va_list) + tail call void @use_global_va_list() + ret void + } + + ; Valid, byval argument forwarded to tail call as another byval argument. + define void @forward_byval(ptr byval(i64) %x) { + entry: + tail call void @take_byval(ptr byval(i64) %x) + ret void + } + + ; Invalid (assuming @take_ptr dereferences the pointer), byval argument + ; passed to tail callee as non-byval ptr. + define void @invalid_byval(ptr byval(i64) %x) { + entry: + tail call void @take_ptr(ptr %x) + ret void + } + + + Calls marked ``musttail`` must obey the following additional rules: - The call must immediately precede a :ref:`ret ` instruction, or a pointer bitcast followed by a ret instruction. diff --git a/llvm/test/CodeGen/ARM/struct_byval.ll b/llvm/test/CodeGen/ARM/struct_byval.ll index 73a1b5ee33bca..2bc4f9c816d53 100644 --- a/llvm/test/CodeGen/ARM/struct_byval.ll +++ b/llvm/test/CodeGen/ARM/struct_byval.ll @@ -63,25 +63,6 @@ declare i32 @e1(ptr nocapture byval(%struct.SmallStruct) %in) nounwind declare i32 @e2(ptr nocapture byval(%struct.LargeStruct) %in) nounwind declare i32 @e3(ptr nocapture byval(%struct.LargeStruct) align 16 %in) nounwind -; rdar://12442472 -; We can't do tail call since address of s is passed to the callee and part of -; s is in caller's local frame. -define void @f3(ptr nocapture byval(%struct.SmallStruct) %s) nounwind optsize { -; CHECK-LABEL: f3 -; CHECK: bl _consumestruct -entry: - tail call void @consumestruct(ptr %s, i32 80) optsize - ret void -} - -define void @f4(ptr nocapture byval(%struct.SmallStruct) %s) nounwind optsize { -; CHECK-LABEL: f4 -; CHECK: bl _consumestruct -entry: - tail call void @consumestruct(ptr %s, i32 80) optsize - ret void -} - ; We can do tail call here since s is in the incoming argument area. define void @f5(i32 %a, i32 %b, i32 %c, i32 %d, ptr nocapture byval(%struct.SmallStruct) %s) nounwind optsize { ; CHECK-LABEL: f5 From 0df88802c69814e7fce662da14f70580e2df4c34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Manuel=20Martinez=20Caama=C3=B1o?= Date: Fri, 27 Sep 2024 09:46:09 +0200 Subject: [PATCH 056/469] [AMDGPU][SIPreEmitPeephole][NFC] remove useless declaration in test --- llvm/test/CodeGen/AMDGPU/amdgpu-demote-scc-branches.ll | 1 - 1 file changed, 1 deletion(-) diff --git a/llvm/test/CodeGen/AMDGPU/amdgpu-demote-scc-branches.ll b/llvm/test/CodeGen/AMDGPU/amdgpu-demote-scc-branches.ll index 9319f0d3f5d40..c293891140008 100644 --- a/llvm/test/CodeGen/AMDGPU/amdgpu-demote-scc-branches.ll +++ b/llvm/test/CodeGen/AMDGPU/amdgpu-demote-scc-branches.ll @@ -359,7 +359,6 @@ if.end: declare void @llvm.amdgcn.raw.ptr.buffer.store.i32(i32, ptr addrspace(8) nocapture writeonly, i32, i32, i32 immarg) declare void @llvm.amdgcn.s.waitcnt(i32) -declare i32 @llvm.amdgcn.workitem.id.x() !0 = !{!"branch_weights", i32 1000, i32 1000} !1 = !{!"branch_weights", i32 2000, i32 1} From 048bc6727644c103044ea22a6f06b80cb2443ec5 Mon Sep 17 00:00:00 2001 From: Timm Baeder Date: Fri, 27 Sep 2024 11:32:43 +0200 Subject: [PATCH 057/469] [clang][bytecode] Start implementing fixed point types (#110216) Add the primitive type and implement to-bool casts. --- clang/lib/AST/ByteCode/ByteCodeEmitter.cpp | 1 + clang/lib/AST/ByteCode/Compiler.cpp | 18 ++++++- clang/lib/AST/ByteCode/Compiler.h | 1 + clang/lib/AST/ByteCode/Context.cpp | 3 ++ clang/lib/AST/ByteCode/Descriptor.cpp | 1 + clang/lib/AST/ByteCode/Disasm.cpp | 3 ++ clang/lib/AST/ByteCode/FixedPoint.h | 63 ++++++++++++++++++++++ clang/lib/AST/ByteCode/Interp.h | 1 + clang/lib/AST/ByteCode/InterpStack.cpp | 1 + clang/lib/AST/ByteCode/InterpStack.h | 3 ++ clang/lib/AST/ByteCode/Opcodes.td | 7 ++- clang/lib/AST/ByteCode/PrimType.cpp | 1 + clang/lib/AST/ByteCode/PrimType.h | 6 +++ clang/test/AST/ByteCode/fixed-point.cpp | 9 ++++ 14 files changed, 114 insertions(+), 4 deletions(-) create mode 100644 clang/lib/AST/ByteCode/FixedPoint.h create mode 100644 clang/test/AST/ByteCode/fixed-point.cpp diff --git a/clang/lib/AST/ByteCode/ByteCodeEmitter.cpp b/clang/lib/AST/ByteCode/ByteCodeEmitter.cpp index b8778f6027894..4fd697ebe4938 100644 --- a/clang/lib/AST/ByteCode/ByteCodeEmitter.cpp +++ b/clang/lib/AST/ByteCode/ByteCodeEmitter.cpp @@ -8,6 +8,7 @@ #include "ByteCodeEmitter.h" #include "Context.h" +#include "FixedPoint.h" #include "Floating.h" #include "IntegralAP.h" #include "Opcode.h" diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp index 93008acde65f9..aac3fd384130d 100644 --- a/clang/lib/AST/ByteCode/Compiler.cpp +++ b/clang/lib/AST/ByteCode/Compiler.cpp @@ -9,6 +9,7 @@ #include "Compiler.h" #include "ByteCodeEmitter.h" #include "Context.h" +#include "FixedPoint.h" #include "Floating.h" #include "Function.h" #include "InterpShared.h" @@ -470,6 +471,7 @@ bool Compiler::VisitCastExpr(const CastExpr *CE) { } case CK_IntegralToBoolean: + case CK_FixedPointToBoolean: case CK_BooleanToSignedIntegral: case CK_IntegralCast: { if (DiscardResult) @@ -717,6 +719,16 @@ bool Compiler::VisitImaginaryLiteral(const ImaginaryLiteral *E) { return this->visitArrayElemInit(1, SubExpr); } +template +bool Compiler::VisitFixedPointLiteral(const FixedPointLiteral *E) { + assert(E->getType()->isFixedPointType()); + assert(classifyPrim(E) == PT_FixedPoint); + + // FIXME: Semantics. + APInt Value = E->getValue(); + return this->emitConstFixedPoint(Value, E); +} + template bool Compiler::VisitParenExpr(const ParenExpr *E) { return this->delegate(E->getSubExpr()); @@ -3685,9 +3697,10 @@ bool Compiler::visitZeroInitializer(PrimType T, QualType QT, return this->emitNullFnPtr(nullptr, E); case PT_MemberPtr: return this->emitNullMemberPtr(nullptr, E); - case PT_Float: { + case PT_Float: return this->emitConstFloat(APFloat::getZero(Ctx.getFloatSemantics(QT)), E); - } + case PT_FixedPoint: + llvm_unreachable("Implement"); } llvm_unreachable("unknown primitive type"); } @@ -3798,6 +3811,7 @@ bool Compiler::emitConst(T Value, PrimType Ty, const Expr *E) { case PT_Float: case PT_IntAP: case PT_IntAPS: + case PT_FixedPoint: llvm_unreachable("Invalid integral type"); break; } diff --git a/clang/lib/AST/ByteCode/Compiler.h b/clang/lib/AST/ByteCode/Compiler.h index 94c0a5cb295b0..d1911f11603a0 100644 --- a/clang/lib/AST/ByteCode/Compiler.h +++ b/clang/lib/AST/ByteCode/Compiler.h @@ -125,6 +125,7 @@ class Compiler : public ConstStmtVisitor, bool>, bool VisitIntegerLiteral(const IntegerLiteral *E); bool VisitFloatingLiteral(const FloatingLiteral *E); bool VisitImaginaryLiteral(const ImaginaryLiteral *E); + bool VisitFixedPointLiteral(const FixedPointLiteral *E); bool VisitParenExpr(const ParenExpr *E); bool VisitBinaryOperator(const BinaryOperator *E); bool VisitLogicalBinOp(const BinaryOperator *E); diff --git a/clang/lib/AST/ByteCode/Context.cpp b/clang/lib/AST/ByteCode/Context.cpp index 8661acf536658..9bca8138cd9f6 100644 --- a/clang/lib/AST/ByteCode/Context.cpp +++ b/clang/lib/AST/ByteCode/Context.cpp @@ -198,6 +198,9 @@ std::optional Context::classify(QualType T) const { if (const auto *DT = dyn_cast(T)) return classify(DT->getUnderlyingType()); + if (T->isFixedPointType()) + return PT_FixedPoint; + return std::nullopt; } diff --git a/clang/lib/AST/ByteCode/Descriptor.cpp b/clang/lib/AST/ByteCode/Descriptor.cpp index 44a7b88b2a1ee..65ac7a3129aba 100644 --- a/clang/lib/AST/ByteCode/Descriptor.cpp +++ b/clang/lib/AST/ByteCode/Descriptor.cpp @@ -8,6 +8,7 @@ #include "Descriptor.h" #include "Boolean.h" +#include "FixedPoint.h" #include "Floating.h" #include "FunctionPointer.h" #include "IntegralAP.h" diff --git a/clang/lib/AST/ByteCode/Disasm.cpp b/clang/lib/AST/ByteCode/Disasm.cpp index e1051e5c2bbf6..85522ffd32dcc 100644 --- a/clang/lib/AST/ByteCode/Disasm.cpp +++ b/clang/lib/AST/ByteCode/Disasm.cpp @@ -13,6 +13,7 @@ #include "Boolean.h" #include "Context.h" #include "EvaluationResult.h" +#include "FixedPoint.h" #include "Floating.h" #include "Function.h" #include "FunctionPointer.h" @@ -126,6 +127,8 @@ static const char *primTypeToString(PrimType T) { return "FnPtr"; case PT_MemberPtr: return "MemberPtr"; + case PT_FixedPoint: + return "FixedPoint"; } llvm_unreachable("Unhandled PrimType"); } diff --git a/clang/lib/AST/ByteCode/FixedPoint.h b/clang/lib/AST/ByteCode/FixedPoint.h new file mode 100644 index 0000000000000..5c4043f060ec5 --- /dev/null +++ b/clang/lib/AST/ByteCode/FixedPoint.h @@ -0,0 +1,63 @@ +//===------- FixedPoint.h - Fixedd point types for the VM -------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_INTERP_FIXED_POINT_H +#define LLVM_CLANG_AST_INTERP_FIXED_POINT_H + +#include "clang/AST/APValue.h" +#include "clang/AST/ComparisonCategories.h" +#include "llvm/ADT/APFixedPoint.h" + +namespace clang { +namespace interp { + +using APInt = llvm::APInt; + +/// Wrapper around fixed point types. +class FixedPoint final { +private: + llvm::APFixedPoint V; + +public: + FixedPoint(APInt V) + : V(V, + llvm::FixedPointSemantics(V.getBitWidth(), 0, false, false, false)) {} + // This needs to be default-constructible so llvm::endian::read works. + FixedPoint() + : V(APInt(0, 0ULL, false), + llvm::FixedPointSemantics(0, 0, false, false, false)) {} + + operator bool() const { return V.getBoolValue(); } + template >> + explicit operator Ty() const { + // FIXME + return 0; + } + + void print(llvm::raw_ostream &OS) const { OS << V; } + + APValue toAPValue(const ASTContext &) const { return APValue(V); } + + ComparisonCategoryResult compare(const FixedPoint &Other) const { + if (Other.V == V) + return ComparisonCategoryResult::Equal; + return ComparisonCategoryResult::Unordered; + } +}; + +inline FixedPoint getSwappedBytes(FixedPoint F) { return F; } + +inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, FixedPoint F) { + F.print(OS); + return OS; +} + +} // namespace interp +} // namespace clang + +#endif diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h index b029399a1554b..79af426f8a913 100644 --- a/clang/lib/AST/ByteCode/Interp.h +++ b/clang/lib/AST/ByteCode/Interp.h @@ -16,6 +16,7 @@ #include "../ExprConstShared.h" #include "Boolean.h" #include "DynamicAllocator.h" +#include "FixedPoint.h" #include "Floating.h" #include "Function.h" #include "FunctionPointer.h" diff --git a/clang/lib/AST/ByteCode/InterpStack.cpp b/clang/lib/AST/ByteCode/InterpStack.cpp index ae3721e983741..b183335dd5884 100644 --- a/clang/lib/AST/ByteCode/InterpStack.cpp +++ b/clang/lib/AST/ByteCode/InterpStack.cpp @@ -8,6 +8,7 @@ #include "InterpStack.h" #include "Boolean.h" +#include "FixedPoint.h" #include "Floating.h" #include "Integral.h" #include "MemberPointer.h" diff --git a/clang/lib/AST/ByteCode/InterpStack.h b/clang/lib/AST/ByteCode/InterpStack.h index 43988bb680d1c..f7b8c386bcc13 100644 --- a/clang/lib/AST/ByteCode/InterpStack.h +++ b/clang/lib/AST/ByteCode/InterpStack.h @@ -13,6 +13,7 @@ #ifndef LLVM_CLANG_AST_INTERP_INTERPSTACK_H #define LLVM_CLANG_AST_INTERP_INTERPSTACK_H +#include "FixedPoint.h" #include "FunctionPointer.h" #include "IntegralAP.h" #include "MemberPointer.h" @@ -190,6 +191,8 @@ class InterpStack final { return PT_IntAP; else if constexpr (std::is_same_v) return PT_MemberPtr; + else if constexpr (std::is_same_v) + return PT_FixedPoint; llvm_unreachable("unknown type push()'ed into InterpStack"); } diff --git a/clang/lib/AST/ByteCode/Opcodes.td b/clang/lib/AST/ByteCode/Opcodes.td index 36191f096aeb8..84c5a1d1ab4c0 100644 --- a/clang/lib/AST/ByteCode/Opcodes.td +++ b/clang/lib/AST/ByteCode/Opcodes.td @@ -31,6 +31,7 @@ def Float : Type; def Ptr : Type; def FnPtr : Type; def MemberPtr : Type; +def FixedPoint : Type; //===----------------------------------------------------------------------===// // Types transferred to the interpreter. @@ -49,6 +50,7 @@ def ArgIntAP : ArgType { let Name = "IntegralAP"; let AsRef = true; } def ArgIntAPS : ArgType { let Name = "IntegralAP"; let AsRef = true; } def ArgFloat : ArgType { let Name = "Floating"; let AsRef = true; } def ArgBool : ArgType { let Name = "bool"; } +def ArgFixedPoint : ArgType { let Name = "FixedPoint"; let AsRef = true; } def ArgFunction : ArgType { let Name = "const Function *"; } def ArgRecordDecl : ArgType { let Name = "const RecordDecl *"; } @@ -108,7 +110,7 @@ def NonPtrTypeClass : TypeClass { } def AllTypeClass : TypeClass { - let Types = !listconcat(AluTypeClass.Types, PtrTypeClass.Types, FloatTypeClass.Types); + let Types = !listconcat(AluTypeClass.Types, PtrTypeClass.Types, FloatTypeClass.Types, [FixedPoint]); } def ComparableTypeClass : TypeClass { @@ -255,6 +257,7 @@ def ConstFloat : ConstOpcode; def constIntAP : ConstOpcode; def constIntAPS : ConstOpcode; def ConstBool : ConstOpcode; +def ConstFixedPoint : ConstOpcode; // [] -> [Integer] def Zero : Opcode { @@ -607,7 +610,7 @@ def IsNonNull : Opcode { //===----------------------------------------------------------------------===// def FromCastTypeClass : TypeClass { - let Types = [Uint8, Sint8, Uint16, Sint16, Uint32, Sint32, Uint64, Sint64, Bool, IntAP, IntAPS]; + let Types = [Uint8, Sint8, Uint16, Sint16, Uint32, Sint32, Uint64, Sint64, Bool, IntAP, IntAPS, FixedPoint]; } def ToCastTypeClass : TypeClass { diff --git a/clang/lib/AST/ByteCode/PrimType.cpp b/clang/lib/AST/ByteCode/PrimType.cpp index 3054e67d5c49f..7dbab996416cc 100644 --- a/clang/lib/AST/ByteCode/PrimType.cpp +++ b/clang/lib/AST/ByteCode/PrimType.cpp @@ -8,6 +8,7 @@ #include "PrimType.h" #include "Boolean.h" +#include "FixedPoint.h" #include "Floating.h" #include "FunctionPointer.h" #include "IntegralAP.h" diff --git a/clang/lib/AST/ByteCode/PrimType.h b/clang/lib/AST/ByteCode/PrimType.h index bb2f59d86e98d..23ca8027599cd 100644 --- a/clang/lib/AST/ByteCode/PrimType.h +++ b/clang/lib/AST/ByteCode/PrimType.h @@ -26,6 +26,7 @@ class Boolean; class Floating; class FunctionPointer; class MemberPointer; +class FixedPoint; template class IntegralAP; template class Integral; @@ -46,6 +47,7 @@ enum PrimType : unsigned { PT_Ptr = 12, PT_FnPtr = 13, PT_MemberPtr = 14, + PT_FixedPoint = 15, }; inline constexpr bool isPtrType(PrimType T) { @@ -118,6 +120,9 @@ template <> struct PrimConv { template <> struct PrimConv { using T = MemberPointer; }; +template <> struct PrimConv { + using T = FixedPoint; +}; /// Returns the size of a primitive type in bytes. size_t primSize(PrimType Type); @@ -163,6 +168,7 @@ static inline bool aligned(const void *P) { TYPE_SWITCH_CASE(PT_Ptr, B) \ TYPE_SWITCH_CASE(PT_FnPtr, B) \ TYPE_SWITCH_CASE(PT_MemberPtr, B) \ + TYPE_SWITCH_CASE(PT_FixedPoint, B) \ } \ } while (0) diff --git a/clang/test/AST/ByteCode/fixed-point.cpp b/clang/test/AST/ByteCode/fixed-point.cpp new file mode 100644 index 0000000000000..24595ed96c166 --- /dev/null +++ b/clang/test/AST/ByteCode/fixed-point.cpp @@ -0,0 +1,9 @@ +// RUN: %clang_cc1 %s -fsyntax-only -ffixed-point -verify=expected,both -fexperimental-new-constant-interpreter +// RUN: %clang_cc1 %s -fsyntax-only -ffixed-point -verify=ref,both + +static_assert((bool)1.0k); +static_assert(!((bool)0.0k)); +static_assert((bool)0.0k); // both-error {{static assertion failed}} + +static_assert(1.0k == 1.0k); +static_assert(1.0k != 1.0k); // both-error {{failed due to requirement '1.0k != 1.0k'}} From 5e9813667958688f5ab0e0b776b509b2b909d1e4 Mon Sep 17 00:00:00 2001 From: Mehdi Amini Date: Fri, 27 Sep 2024 11:52:22 +0200 Subject: [PATCH 058/469] Fix LLVM_ENABLE_ABI_BREAKING_CHECKS macro check: use #if instead of #ifdef (#110185) This macros is always defined: either 0 or 1. The correct pattern is to use #if. --- llvm/include/llvm/Passes/StandardInstrumentations.h | 2 +- .../llvm/Support/GenericDomTreeConstruction.h | 4 ++-- .../include/llvm/Transforms/Scalar/LoopPassManager.h | 4 ++-- .../llvm/Transforms/Utils/ScalarEvolutionExpander.h | 6 +++--- llvm/lib/Passes/StandardInstrumentations.cpp | 6 +++--- .../lib/Transforms/Utils/ScalarEvolutionExpander.cpp | 2 +- .../mlir/Analysis/Presburger/PresburgerSpace.h | 6 +++--- .../Transform/Interfaces/TransformInterfaces.h | 10 +++++----- .../Transform/Interfaces/TransformInterfaces.cpp | 12 ++++++------ 9 files changed, 26 insertions(+), 26 deletions(-) diff --git a/llvm/include/llvm/Passes/StandardInstrumentations.h b/llvm/include/llvm/Passes/StandardInstrumentations.h index fa9c744294a66..80eedc52bc324 100644 --- a/llvm/include/llvm/Passes/StandardInstrumentations.h +++ b/llvm/include/llvm/Passes/StandardInstrumentations.h @@ -171,7 +171,7 @@ class PreservedCFGCheckerInstrumentation { FunctionAnalysisManager::Invalidator &); }; -#ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS +#if LLVM_ENABLE_ABI_BREAKING_CHECKS SmallVector PassStack; #endif diff --git a/llvm/include/llvm/Support/GenericDomTreeConstruction.h b/llvm/include/llvm/Support/GenericDomTreeConstruction.h index 9aab5ec60f4a2..2e21bdc9fce2d 100644 --- a/llvm/include/llvm/Support/GenericDomTreeConstruction.h +++ b/llvm/include/llvm/Support/GenericDomTreeConstruction.h @@ -640,7 +640,7 @@ struct SemiNCAInfo { Bucket; SmallDenseSet Visited; SmallVector Affected; -#ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS +#if LLVM_ENABLE_ABI_BREAKING_CHECKS SmallVector VisitedUnaffected; #endif }; @@ -915,7 +915,7 @@ struct SemiNCAInfo { LLVM_DEBUG(dbgs() << "Deleting edge " << BlockNamePrinter(From) << " -> " << BlockNamePrinter(To) << "\n"); -#ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS +#if LLVM_ENABLE_ABI_BREAKING_CHECKS // Ensure that the edge was in fact deleted from the CFG before informing // the DomTree about it. // The check is O(N), so run it only in debug configuration. diff --git a/llvm/include/llvm/Transforms/Scalar/LoopPassManager.h b/llvm/include/llvm/Transforms/Scalar/LoopPassManager.h index 3858be05c61fa..db479f55d9b03 100644 --- a/llvm/include/llvm/Transforms/Scalar/LoopPassManager.h +++ b/llvm/include/llvm/Transforms/Scalar/LoopPassManager.h @@ -256,7 +256,7 @@ class LPMUpdater { } void setParentLoop(Loop *L) { -#ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS +#if LLVM_ENABLE_ABI_BREAKING_CHECKS ParentL = L; #endif } @@ -347,7 +347,7 @@ class LPMUpdater { const bool LoopNestMode; bool LoopNestChanged; -#ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS +#if LLVM_ENABLE_ABI_BREAKING_CHECKS // In debug builds we also track the parent loop to implement asserts even in // the face of loop deletion. Loop *ParentL; diff --git a/llvm/include/llvm/Transforms/Utils/ScalarEvolutionExpander.h b/llvm/include/llvm/Transforms/Utils/ScalarEvolutionExpander.h index 62c1e15a9a60e..468b50092efcf 100644 --- a/llvm/include/llvm/Transforms/Utils/ScalarEvolutionExpander.h +++ b/llvm/include/llvm/Transforms/Utils/ScalarEvolutionExpander.h @@ -167,7 +167,7 @@ class SCEVExpander : public SCEVVisitor { /// consistent when instructions are moved. SmallVector InsertPointGuards; -#ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS +#if LLVM_ENABLE_ABI_BREAKING_CHECKS const char *DebugType; #endif @@ -183,7 +183,7 @@ class SCEVExpander : public SCEVVisitor { Builder(se.getContext(), InstSimplifyFolder(DL), IRBuilderCallbackInserter( [this](Instruction *I) { rememberInstruction(I); })) { -#ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS +#if LLVM_ENABLE_ABI_BREAKING_CHECKS DebugType = ""; #endif } @@ -193,7 +193,7 @@ class SCEVExpander : public SCEVVisitor { assert(InsertPointGuards.empty()); } -#ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS +#if LLVM_ENABLE_ABI_BREAKING_CHECKS void setDebugType(const char *s) { DebugType = s; } #endif diff --git a/llvm/lib/Passes/StandardInstrumentations.cpp b/llvm/lib/Passes/StandardInstrumentations.cpp index 036484c9c1c0c..a545ae5862397 100644 --- a/llvm/lib/Passes/StandardInstrumentations.cpp +++ b/llvm/lib/Passes/StandardInstrumentations.cpp @@ -1357,7 +1357,7 @@ void PreservedCFGCheckerInstrumentation::registerCallbacks( bool Registered = false; PIC.registerBeforeNonSkippedPassCallback([this, &MAM, Registered]( StringRef P, Any IR) mutable { -#ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS +#if LLVM_ENABLE_ABI_BREAKING_CHECKS assert(&PassStack.emplace_back(P)); #endif (void)this; @@ -1386,7 +1386,7 @@ void PreservedCFGCheckerInstrumentation::registerCallbacks( PIC.registerAfterPassInvalidatedCallback( [this](StringRef P, const PreservedAnalyses &PassPA) { -#ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS +#if LLVM_ENABLE_ABI_BREAKING_CHECKS assert(PassStack.pop_back_val() == P && "Before and After callbacks must correspond"); #endif @@ -1395,7 +1395,7 @@ void PreservedCFGCheckerInstrumentation::registerCallbacks( PIC.registerAfterPassCallback([this, &MAM](StringRef P, Any IR, const PreservedAnalyses &PassPA) { -#ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS +#if LLVM_ENABLE_ABI_BREAKING_CHECKS assert(PassStack.pop_back_val() == P && "Before and After callbacks must correspond"); #endif diff --git a/llvm/lib/Transforms/Utils/ScalarEvolutionExpander.cpp b/llvm/lib/Transforms/Utils/ScalarEvolutionExpander.cpp index 0927a3015818f..2119320566902 100644 --- a/llvm/lib/Transforms/Utils/ScalarEvolutionExpander.cpp +++ b/llvm/lib/Transforms/Utils/ScalarEvolutionExpander.cpp @@ -28,7 +28,7 @@ #include "llvm/Support/raw_ostream.h" #include "llvm/Transforms/Utils/LoopUtils.h" -#ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS +#if LLVM_ENABLE_ABI_BREAKING_CHECKS #define SCEV_DEBUG_WITH_TYPE(TYPE, X) DEBUG_WITH_TYPE(TYPE, X) #else #define SCEV_DEBUG_WITH_TYPE(TYPE, X) diff --git a/mlir/include/mlir/Analysis/Presburger/PresburgerSpace.h b/mlir/include/mlir/Analysis/Presburger/PresburgerSpace.h index cff7957989871..97573b6e45301 100644 --- a/mlir/include/mlir/Analysis/Presburger/PresburgerSpace.h +++ b/mlir/include/mlir/Analysis/Presburger/PresburgerSpace.h @@ -75,7 +75,7 @@ class Identifier { template explicit Identifier(T value) : value(llvm::PointerLikeTypeTraits::getAsVoidPointer(value)) { -#ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS +#if LLVM_ENABLE_ABI_BREAKING_CHECKS idType = llvm::getTypeName(); #endif } @@ -84,7 +84,7 @@ class Identifier { /// the type of the identifier used to create it. template T getValue() const { -#ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS +#if LLVM_ENABLE_ABI_BREAKING_CHECKS assert(llvm::getTypeName() == idType && "Identifier was initialized with a different type than the one used " "to retrieve it."); @@ -108,7 +108,7 @@ class Identifier { /// The value of the identifier. void *value = nullptr; -#ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS +#if LLVM_ENABLE_ABI_BREAKING_CHECKS /// TypeID of the identifiers in space. This should be used in asserts only. llvm::StringRef idType; #endif diff --git a/mlir/include/mlir/Dialect/Transform/Interfaces/TransformInterfaces.h b/mlir/include/mlir/Dialect/Transform/Interfaces/TransformInterfaces.h index 43193e4cd4cf6..e51aac02936b5 100644 --- a/mlir/include/mlir/Dialect/Transform/Interfaces/TransformInterfaces.h +++ b/mlir/include/mlir/Dialect/Transform/Interfaces/TransformInterfaces.h @@ -196,7 +196,7 @@ class TransformState { /// should be emitted when the value is used. using InvalidatedHandleMap = DenseMap>; -#ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS +#if LLVM_ENABLE_ABI_BREAKING_CHECKS /// Debug only: A timestamp is associated with each transform IR value, so /// that invalid iterator usage can be detected more reliably. using TransformIRTimestampMapping = DenseMap; @@ -211,7 +211,7 @@ class TransformState { ValueMapping values; ValueMapping reverseValues; -#ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS +#if LLVM_ENABLE_ABI_BREAKING_CHECKS TransformIRTimestampMapping timestamps; void incrementTimestamp(Value value) { ++timestamps[value]; } #endif // LLVM_ENABLE_ABI_BREAKING_CHECKS @@ -248,7 +248,7 @@ class TransformState { auto getPayloadOps(Value value) const { ArrayRef view = getPayloadOpsView(value); -#ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS +#if LLVM_ENABLE_ABI_BREAKING_CHECKS // Memorize the current timestamp and make sure that it has not changed // when incrementing or dereferencing the iterator returned by this // function. The timestamp is incremented when the "direct" mapping is @@ -259,7 +259,7 @@ class TransformState { // When ops are replaced/erased, they are replaced with nullptr (until // the data structure is compacted). Do not enumerate these ops. return llvm::make_filter_range(view, [=](Operation *op) { -#ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS +#if LLVM_ENABLE_ABI_BREAKING_CHECKS [[maybe_unused]] bool sameTimestamp = currentTimestamp == this->getMapping(value).timestamps.lookup(value); assert(sameTimestamp && "iterator was invalidated during iteration"); @@ -277,7 +277,7 @@ class TransformState { auto getPayloadValues(Value handleValue) const { ArrayRef view = getPayloadValuesView(handleValue); -#ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS +#if LLVM_ENABLE_ABI_BREAKING_CHECKS // Memorize the current timestamp and make sure that it has not changed // when incrementing or dereferencing the iterator returned by this // function. The timestamp is incremented when the "values" mapping is diff --git a/mlir/lib/Dialect/Transform/Interfaces/TransformInterfaces.cpp b/mlir/lib/Dialect/Transform/Interfaces/TransformInterfaces.cpp index 91702ce7cc42b..fdd968238667e 100644 --- a/mlir/lib/Dialect/Transform/Interfaces/TransformInterfaces.cpp +++ b/mlir/lib/Dialect/Transform/Interfaces/TransformInterfaces.cpp @@ -330,7 +330,7 @@ void transform::TransformState::forgetMapping(Value opHandle, for (Operation *op : mappings.direct[opHandle]) dropMappingEntry(mappings.reverse, op, opHandle); mappings.direct.erase(opHandle); -#ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS +#if LLVM_ENABLE_ABI_BREAKING_CHECKS // Payload IR is removed from the mapping. This invalidates the respective // iterators. mappings.incrementTimestamp(opHandle); @@ -342,7 +342,7 @@ void transform::TransformState::forgetMapping(Value opHandle, for (Value resultHandle : resultHandles) { Mappings &localMappings = getMapping(resultHandle); dropMappingEntry(localMappings.values, resultHandle, opResult); -#ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS +#if LLVM_ENABLE_ABI_BREAKING_CHECKS // Payload IR is removed from the mapping. This invalidates the respective // iterators. mappings.incrementTimestamp(resultHandle); @@ -358,7 +358,7 @@ void transform::TransformState::forgetValueMapping( for (Value payloadValue : mappings.reverseValues[valueHandle]) dropMappingEntry(mappings.reverseValues, payloadValue, valueHandle); mappings.values.erase(valueHandle); -#ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS +#if LLVM_ENABLE_ABI_BREAKING_CHECKS // Payload IR is removed from the mapping. This invalidates the respective // iterators. mappings.incrementTimestamp(valueHandle); @@ -372,7 +372,7 @@ void transform::TransformState::forgetValueMapping( dropMappingEntry(localMappings.direct, opHandle, payloadOp); dropMappingEntry(localMappings.reverse, payloadOp, opHandle); -#ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS +#if LLVM_ENABLE_ABI_BREAKING_CHECKS // Payload IR is removed from the mapping. This invalidates the respective // iterators. localMappings.incrementTimestamp(opHandle); @@ -452,7 +452,7 @@ transform::TransformState::replacePayloadValue(Value value, Value replacement) { // between the handles and the IR objects if (!replacement) { dropMappingEntry(mappings.values, handle, value); -#ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS +#if LLVM_ENABLE_ABI_BREAKING_CHECKS // Payload IR is removed from the mapping. This invalidates the respective // iterators. mappings.incrementTimestamp(handle); @@ -804,7 +804,7 @@ checkRepeatedConsumptionInOperand(ArrayRef payload, void transform::TransformState::compactOpHandles() { for (Value handle : opHandlesToCompact) { Mappings &mappings = getMapping(handle, /*allowOutOfScope=*/true); -#ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS +#if LLVM_ENABLE_ABI_BREAKING_CHECKS if (llvm::find(mappings.direct[handle], nullptr) != mappings.direct[handle].end()) // Payload IR is removed from the mapping. This invalidates the respective From 3f8380f3ea4921bce6b388f76d686e3b064182a2 Mon Sep 17 00:00:00 2001 From: Anatoly Trosinenko Date: Fri, 27 Sep 2024 12:54:28 +0300 Subject: [PATCH 059/469] [AArch64] Factor out the emission of MOV and MOVZ/MOVK instructions (#110017) Throughout the AArch64AsmPrinter implementation, there are a few common instructions emitted at many places: ORRXrs as an alias of "mov Xd, Xm" and movz/movk for materialization of constants. This commit introduces utility functions for emission of these three instructions. --- llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp | 205 ++++++------------ 1 file changed, 70 insertions(+), 135 deletions(-) diff --git a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp index c6e88131d5a34..a82a081e4abfe 100644 --- a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp +++ b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp @@ -164,6 +164,8 @@ class AArch64AsmPrinter : public AsmPrinter { /// pseudo instructions. bool lowerPseudoInstExpansion(const MachineInstr *MI, MCInst &Inst); + void EmitToStreamer(MCStreamer &S, const MCInst &Inst); + void emitInstruction(const MachineInstr *MI) override; void emitFunctionHeaderComment() override; @@ -229,6 +231,10 @@ class AArch64AsmPrinter : public AsmPrinter { /// Emit the LOHs contained in AArch64FI. void emitLOHs(); + void emitMovXReg(Register Dest, Register Src); + void emitMOVZ(Register Dest, uint64_t Imm, unsigned Shift); + void emitMOVK(Register Dest, uint64_t Imm, unsigned Shift); + /// Emit instruction to set float register to zero. void emitFMov0(const MachineInstr &MI); @@ -409,16 +415,6 @@ void AArch64AsmPrinter::LowerPATCHABLE_EVENT_CALL(const MachineInstr &MI, auto &O = *OutStreamer; MCSymbol *CurSled = OutContext.createTempSymbol("xray_sled_", true); O.emitLabel(CurSled); - MCInst MovX0Op0 = MCInstBuilder(AArch64::ORRXrs) - .addReg(AArch64::X0) - .addReg(AArch64::XZR) - .addReg(MI.getOperand(0).getReg()) - .addImm(0); - MCInst MovX1Op1 = MCInstBuilder(AArch64::ORRXrs) - .addReg(AArch64::X1) - .addReg(AArch64::XZR) - .addReg(MI.getOperand(1).getReg()) - .addImm(0); bool MachO = TM.getTargetTriple().isOSBinFormatMachO(); auto *Sym = MCSymbolRefExpr::create( OutContext.getOrCreateSymbol( @@ -438,13 +434,9 @@ void AArch64AsmPrinter::LowerPATCHABLE_EVENT_CALL(const MachineInstr &MI, .addReg(AArch64::X2) .addReg(AArch64::SP) .addImm(2)); - EmitToStreamer(O, MovX0Op0); - EmitToStreamer(O, MovX1Op1); - EmitToStreamer(O, MCInstBuilder(AArch64::ORRXrs) - .addReg(AArch64::X2) - .addReg(AArch64::XZR) - .addReg(MI.getOperand(2).getReg()) - .addImm(0)); + emitMovXReg(AArch64::X0, MI.getOperand(0).getReg()); + emitMovXReg(AArch64::X1, MI.getOperand(1).getReg()); + emitMovXReg(AArch64::X2, MI.getOperand(2).getReg()); EmitToStreamer(O, MCInstBuilder(AArch64::BL).addExpr(Sym)); EmitToStreamer(O, MCInstBuilder(AArch64::LDRXui) .addReg(AArch64::X2) @@ -468,8 +460,8 @@ void AArch64AsmPrinter::LowerPATCHABLE_EVENT_CALL(const MachineInstr &MI, .addReg(AArch64::X1) .addReg(AArch64::SP) .addImm(-2)); - EmitToStreamer(O, MovX0Op0); - EmitToStreamer(O, MovX1Op1); + emitMovXReg(AArch64::X0, MI.getOperand(0).getReg()); + emitMovXReg(AArch64::X1, MI.getOperand(1).getReg()); EmitToStreamer(O, MCInstBuilder(AArch64::BL).addExpr(Sym)); O.AddComment("End XRay custom event"); EmitToStreamer(O, MCInstBuilder(AArch64::LDPXpost) @@ -497,11 +489,7 @@ void AArch64AsmPrinter::LowerKCFI_CHECK(const MachineInstr &MI) { // Checking XZR makes no sense. Instead of emitting a load, zero // ScratchRegs[0] and use it for the ESR AddrIndex below. AddrReg = getXRegFromWReg(ScratchRegs[0]); - EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::ORRXrs) - .addReg(AddrReg) - .addReg(AArch64::XZR) - .addReg(AArch64::XZR) - .addImm(0)); + emitMovXReg(AddrReg, AArch64::XZR); } else { // If one of the scratch registers is used for the call target (e.g. // with AArch64::TCRETURNriBTI), we can clobber another caller-saved @@ -534,16 +522,8 @@ void AArch64AsmPrinter::LowerKCFI_CHECK(const MachineInstr &MI) { // Load the expected type hash. const int64_t Type = MI.getOperand(1).getImm(); - EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::MOVKWi) - .addReg(ScratchRegs[1]) - .addReg(ScratchRegs[1]) - .addImm(Type & 0xFFFF) - .addImm(0)); - EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::MOVKWi) - .addReg(ScratchRegs[1]) - .addReg(ScratchRegs[1]) - .addImm((Type >> 16) & 0xFFFF) - .addImm(16)); + emitMOVK(ScratchRegs[1], Type & 0xFFFF, 0); + emitMOVK(ScratchRegs[1], (Type >> 16) & 0xFFFF, 16); // Compare the hashes and trap if there's a mismatch. EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::SUBSWrs) @@ -627,6 +607,7 @@ void AArch64AsmPrinter::emitHwasanMemaccessSymbols(Module &M) { std::unique_ptr STI( TM.getTarget().createMCSubtargetInfo(TT.str(), "", "")); assert(STI && "Unable to create subtarget info"); + this->STI = static_cast(&*STI); MCSymbol *HwasanTagMismatchV1Sym = OutContext.getOrCreateSymbol("__hwasan_tag_mismatch"); @@ -679,11 +660,7 @@ void AArch64AsmPrinter::emitHwasanMemaccessSymbols(Module &M) { // Fortuitously, kShadowBaseAlignment == 32, so we use the 32-bit // left-shift option in the MOV instruction. Combined with the 16-bit // immediate, this is enough to represent any offset up to 2**48. - OutStreamer->emitInstruction(MCInstBuilder(AArch64::MOVZXi) - .addReg(AArch64::X17) - .addImm(FixedShadowOffset >> 32) - .addImm(32), - *STI); + emitMOVZ(AArch64::X17, FixedShadowOffset >> 32, 32); OutStreamer->emitInstruction(MCInstBuilder(AArch64::LDRBBroX) .addReg(AArch64::W16) .addReg(AArch64::X17) @@ -823,18 +800,8 @@ void AArch64AsmPrinter::emitHwasanMemaccessSymbols(Module &M) { *STI); if (Reg != AArch64::X0) - OutStreamer->emitInstruction(MCInstBuilder(AArch64::ORRXrs) - .addReg(AArch64::X0) - .addReg(AArch64::XZR) - .addReg(Reg) - .addImm(0), - *STI); - OutStreamer->emitInstruction( - MCInstBuilder(AArch64::MOVZXi) - .addReg(AArch64::X1) - .addImm(AccessInfo & HWASanAccessInfo::RuntimeMask) - .addImm(0), - *STI); + emitMovXReg(AArch64::X0, Reg); + emitMOVZ(AArch64::X1, AccessInfo & HWASanAccessInfo::RuntimeMask, 0); if (CompileKernel) { // The Linux kernel's dynamic loader doesn't support GOT relative @@ -865,6 +832,7 @@ void AArch64AsmPrinter::emitHwasanMemaccessSymbols(Module &M) { MCInstBuilder(AArch64::BR).addReg(AArch64::X16), *STI); } } + this->STI = nullptr; } static void emitAuthenticatedPointer(MCStreamer &OutStreamer, @@ -1438,11 +1406,7 @@ void AArch64AsmPrinter::LowerHardenedBRJumpTable(const MachineInstr &MI) { .addImm(0)); ++InstsEmitted; } else { - EmitToStreamer(*OutStreamer, - MCInstBuilder(AArch64::MOVZXi) - .addReg(AArch64::X17) - .addImm(static_cast(MaxTableEntry)) - .addImm(0)); + emitMOVZ(AArch64::X17, static_cast(MaxTableEntry), 0); ++InstsEmitted; // It's sad that we have to manually materialize instructions, but we can't // trivially reuse the main pseudo expansion logic. @@ -1450,12 +1414,8 @@ void AArch64AsmPrinter::LowerHardenedBRJumpTable(const MachineInstr &MI) { for (int Offset = 16; Offset < 64; Offset += 16) { if ((MaxTableEntry >> Offset) == 0) break; - EmitToStreamer(*OutStreamer, - MCInstBuilder(AArch64::MOVKXi) - .addReg(AArch64::X17) - .addReg(AArch64::X17) - .addImm(static_cast(MaxTableEntry >> Offset)) - .addImm(Offset)); + emitMOVK(AArch64::X17, static_cast(MaxTableEntry >> Offset), + Offset); ++InstsEmitted; } EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::SUBSXrs) @@ -1615,20 +1575,9 @@ void AArch64AsmPrinter::LowerPATCHPOINT(MCStreamer &OutStreamer, StackMaps &SM, Register ScratchReg = MI.getOperand(Opers.getNextScratchIdx()).getReg(); EncodedBytes = 16; // Materialize the jump address: - EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::MOVZXi) - .addReg(ScratchReg) - .addImm((CallTarget >> 32) & 0xFFFF) - .addImm(32)); - EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::MOVKXi) - .addReg(ScratchReg) - .addReg(ScratchReg) - .addImm((CallTarget >> 16) & 0xFFFF) - .addImm(16)); - EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::MOVKXi) - .addReg(ScratchReg) - .addReg(ScratchReg) - .addImm(CallTarget & 0xFFFF) - .addImm(0)); + emitMOVZ(ScratchReg, (CallTarget >> 32) & 0xFFFF, 32); + emitMOVK(ScratchReg, (CallTarget >> 16) & 0xFFFF, 16); + emitMOVK(ScratchReg, CallTarget & 0xFFFF, 0); EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::BLR).addReg(ScratchReg)); } // Emit padding. @@ -1717,6 +1666,33 @@ void AArch64AsmPrinter::LowerFAULTING_OP(const MachineInstr &FaultingMI) { OutStreamer->emitInstruction(MI, getSubtargetInfo()); } +void AArch64AsmPrinter::emitMovXReg(Register Dest, Register Src) { + EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::ORRXrs) + .addReg(Dest) + .addReg(AArch64::XZR) + .addReg(Src) + .addImm(0)); +} + +void AArch64AsmPrinter::emitMOVZ(Register Dest, uint64_t Imm, unsigned Shift) { + bool Is64Bit = AArch64::GPR64RegClass.contains(Dest); + EmitToStreamer(*OutStreamer, + MCInstBuilder(Is64Bit ? AArch64::MOVZXi : AArch64::MOVZWi) + .addReg(Dest) + .addImm(Imm) + .addImm(Shift)); +} + +void AArch64AsmPrinter::emitMOVK(Register Dest, uint64_t Imm, unsigned Shift) { + bool Is64Bit = AArch64::GPR64RegClass.contains(Dest); + EmitToStreamer(*OutStreamer, + MCInstBuilder(Is64Bit ? AArch64::MOVKXi : AArch64::MOVKWi) + .addReg(Dest) + .addReg(Dest) + .addImm(Imm) + .addImm(Shift)); +} + void AArch64AsmPrinter::emitFMov0(const MachineInstr &MI) { Register DestReg = MI.getOperand(0).getReg(); if (STI->hasZeroCycleZeroingFP() && !STI->hasZeroCycleZeroingFPWorkaround() && @@ -1774,26 +1750,15 @@ unsigned AArch64AsmPrinter::emitPtrauthDiscriminator(uint16_t Disc, // If there's only a constant discriminator, MOV it into x17. if (AddrDisc == AArch64::XZR) { - EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::MOVZXi) - .addReg(AArch64::X17) - .addImm(Disc) - .addImm(/*shift=*/0)); + emitMOVZ(AArch64::X17, Disc, 0); ++InstsEmitted; return AArch64::X17; } // If there are both, emit a blend into x17. - EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::ORRXrs) - .addReg(AArch64::X17) - .addReg(AArch64::XZR) - .addReg(AddrDisc) - .addImm(0)); + emitMovXReg(AArch64::X17, AddrDisc); ++InstsEmitted; - EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::MOVKXi) - .addReg(AArch64::X17) - .addReg(AArch64::X17) - .addImm(Disc) - .addImm(/*shift=*/48)); + emitMOVK(AArch64::X17, Disc, 48); ++InstsEmitted; return AArch64::X17; } @@ -1914,11 +1879,7 @@ void AArch64AsmPrinter::emitPtrauthAuthResign(const MachineInstr *MI) { // XPAC has tied src/dst: use x17 as a temporary copy. // mov x17, x16 - EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::ORRXrs) - .addReg(AArch64::X17) - .addReg(AArch64::XZR) - .addReg(AArch64::X16) - .addImm(0)); + emitMovXReg(AArch64::X17, AArch64::X16); ++InstsEmitted; // xpaci x17 @@ -1955,11 +1916,7 @@ void AArch64AsmPrinter::emitPtrauthAuthResign(const MachineInstr *MI) { // FIXME: can we simply return the AUT result, already in x16? without.. // ..traps this is usable as an oracle anyway, based on high bits // mov x17, x16 - EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::ORRXrs) - .addReg(AArch64::X16) - .addReg(AArch64::XZR) - .addReg(AArch64::X17) - .addImm(0)); + emitMovXReg(AArch64::X16, AArch64::X17); ++InstsEmitted; if (IsAUTPAC) { @@ -2273,13 +2230,9 @@ void AArch64AsmPrinter::LowerMOVaddrPAC(const MachineInstr &MI) { return true; return false; }; - for (int BitPos = 16; BitPos != 64 && NeedMovk(BitPos); BitPos += 16) { - EmitAndIncrement(MCInstBuilder(AArch64::MOVKXi) - .addReg(AArch64::X17) - .addReg(AArch64::X17) - .addImm((UOffset >> BitPos) & 0xffff) - .addImm(/*shift=*/BitPos)); - } + for (int BitPos = 16; BitPos != 64 && NeedMovk(BitPos); BitPos += 16) + emitMOVK(AArch64::X17, (UOffset >> BitPos) & 0xffff, BitPos); + EmitAndIncrement(MCInstBuilder(AArch64::ADDXrs) .addReg(AArch64::X16) .addReg(AArch64::X16) @@ -2291,21 +2244,10 @@ void AArch64AsmPrinter::LowerMOVaddrPAC(const MachineInstr &MI) { unsigned DiscReg = AddrDisc; if (Disc != 0) { if (AddrDisc != AArch64::XZR) { - EmitAndIncrement(MCInstBuilder(AArch64::ORRXrs) - .addReg(AArch64::X17) - .addReg(AArch64::XZR) - .addReg(AddrDisc) - .addImm(0)); - EmitAndIncrement(MCInstBuilder(AArch64::MOVKXi) - .addReg(AArch64::X17) - .addReg(AArch64::X17) - .addImm(Disc) - .addImm(/*shift=*/48)); + emitMovXReg(AArch64::X17, AddrDisc); + emitMOVK(AArch64::X17, Disc, 48); } else { - EmitAndIncrement(MCInstBuilder(AArch64::MOVZXi) - .addReg(AArch64::X17) - .addImm(Disc) - .addImm(/*shift=*/0)); + emitMOVZ(AArch64::X17, Disc, 0); } DiscReg = AArch64::X17; } @@ -2337,6 +2279,10 @@ AArch64AsmPrinter::lowerBlockAddressConstant(const BlockAddress &BA) { // instructions) auto-generated. #include "AArch64GenMCPseudoLowering.inc" +void AArch64AsmPrinter::EmitToStreamer(MCStreamer &S, const MCInst &Inst) { + S.emitInstruction(Inst, *STI); +} + void AArch64AsmPrinter::emitInstruction(const MachineInstr *MI) { AArch64_MC::verifyInstructionPredicates(MI->getOpcode(), STI->getFeatureBits()); @@ -2511,21 +2457,10 @@ void AArch64AsmPrinter::emitInstruction(const MachineInstr *MI) { if (Disc) { if (AddrDisc != AArch64::NoRegister) { if (ScratchReg != AddrDisc) - EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::ORRXrs) - .addReg(ScratchReg) - .addReg(AArch64::XZR) - .addReg(AddrDisc) - .addImm(0)); - EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::MOVKXi) - .addReg(ScratchReg) - .addReg(ScratchReg) - .addImm(Disc) - .addImm(/*shift=*/48)); + emitMovXReg(ScratchReg, AddrDisc); + emitMOVK(ScratchReg, Disc, 48); } else { - EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::MOVZXi) - .addReg(ScratchReg) - .addImm(Disc) - .addImm(/*shift=*/0)); + emitMOVZ(ScratchReg, Disc, 0); } DiscReg = ScratchReg; } From 6fe723441b66c86bbe86bfc9c1f504d0c295c91b Mon Sep 17 00:00:00 2001 From: Ramkumar Ramachandra Date: Fri, 27 Sep 2024 11:05:30 +0100 Subject: [PATCH 060/469] LICM: hoist BO assoc for FAdd and FMul (#108415) Extend hoistBOAssociation to the FAdd and FMul cases, noting that we copy an intersection of the fast-math flags present in both instructions. --- llvm/lib/Transforms/Scalar/LICM.cpp | 17 +- llvm/test/Transforms/LICM/hoist-binop.ll | 234 ++++++++++++++++++++++- 2 files changed, 242 insertions(+), 9 deletions(-) diff --git a/llvm/lib/Transforms/Scalar/LICM.cpp b/llvm/lib/Transforms/Scalar/LICM.cpp index 23e9c70b62642..4b1650b93cc1d 100644 --- a/llvm/lib/Transforms/Scalar/LICM.cpp +++ b/llvm/lib/Transforms/Scalar/LICM.cpp @@ -2819,10 +2819,17 @@ static bool hoistBOAssociation(Instruction &I, Loop &L, if (!BO || !BO->isAssociative()) return false; - // TODO: Only hoist ADDs and MULs for now. + // TODO: Only hoist ADDs, MULs, FADDs, and FMULs for now. Instruction::BinaryOps Opcode = BO->getOpcode(); - if (Opcode != Instruction::Add && Opcode != Instruction::Mul) + switch (Opcode) { + case Instruction::Add: + case Instruction::Mul: + case Instruction::FAdd: + case Instruction::FMul: + break; + default: return false; + } bool LVInRHS = L.isLoopInvariant(BO->getOperand(0)); auto *BO0 = dyn_cast(BO->getOperand(LVInRHS)); @@ -2857,6 +2864,12 @@ static bool hoistBOAssociation(Instruction &I, Loop &L, if (auto *I = dyn_cast(Inv)) I->setHasNoUnsignedWrap(true); NewBO->setHasNoUnsignedWrap(true); + } else if (Opcode == Instruction::FAdd || Opcode == Instruction::FMul) { + // Intersect FMF flags for FADD and FMUL. + FastMathFlags Intersect = BO->getFastMathFlags() & BO0->getFastMathFlags(); + if (auto *I = dyn_cast(Inv)) + I->setFastMathFlags(Intersect); + NewBO->setFastMathFlags(Intersect); } BO->replaceAllUsesWith(NewBO); diff --git a/llvm/test/Transforms/LICM/hoist-binop.ll b/llvm/test/Transforms/LICM/hoist-binop.ll index a840e24757884..74e2b7a2caf4a 100644 --- a/llvm/test/Transforms/LICM/hoist-binop.ll +++ b/llvm/test/Transforms/LICM/hoist-binop.ll @@ -437,17 +437,17 @@ loop: br label %loop } -; Don't hoist floating-point ops, even if they are associative. This would be -; valid, but is currently disabled. -define void @fadd(float %c1, float %c2) { -; CHECK-LABEL: @fadd( +; The simple case. Hoist if fast is present on both instructions. +define void @fadd_fast(float %c1, float %c2) { +; CHECK-LABEL: @fadd_fast( ; CHECK-NEXT: entry: +; CHECK-NEXT: [[INVARIANT_OP:%.*]] = fadd fast float [[C1:%.*]], [[C2:%.*]] ; CHECK-NEXT: br label [[LOOP:%.*]] ; CHECK: loop: -; CHECK-NEXT: [[INDEX:%.*]] = phi float [ 0.000000e+00, [[ENTRY:%.*]] ], [ [[INDEX_NEXT:%.*]], [[LOOP]] ] -; CHECK-NEXT: [[STEP_ADD:%.*]] = fadd fast float [[INDEX]], [[C1:%.*]] +; CHECK-NEXT: [[INDEX:%.*]] = phi float [ 0.000000e+00, [[ENTRY:%.*]] ], [ [[INDEX_NEXT_REASS:%.*]], [[LOOP]] ] +; CHECK-NEXT: [[STEP_ADD:%.*]] = fadd fast float [[INDEX]], [[C1]] ; CHECK-NEXT: call void @use(float [[STEP_ADD]]) -; CHECK-NEXT: [[INDEX_NEXT]] = fadd fast float [[STEP_ADD]], [[C2:%.*]] +; CHECK-NEXT: [[INDEX_NEXT_REASS]] = fadd fast float [[INDEX]], [[INVARIANT_OP]] ; CHECK-NEXT: br label [[LOOP]] ; entry: @@ -461,6 +461,226 @@ loop: br label %loop } +; The simple case. Hoist if fast is present on both instructions. +define void @fmul_fast(float %c1, float %c2) { +; CHECK-LABEL: @fmul_fast( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[INVARIANT_OP:%.*]] = fmul fast float [[C1:%.*]], [[C2:%.*]] +; CHECK-NEXT: br label [[LOOP:%.*]] +; CHECK: loop: +; CHECK-NEXT: [[INDEX:%.*]] = phi float [ 0.000000e+00, [[ENTRY:%.*]] ], [ [[INDEX_NEXT_REASS:%.*]], [[LOOP]] ] +; CHECK-NEXT: [[STEP_ADD:%.*]] = fmul fast float [[INDEX]], [[C1]] +; CHECK-NEXT: call void @use(float [[STEP_ADD]]) +; CHECK-NEXT: [[INDEX_NEXT_REASS]] = fmul fast float [[INDEX]], [[INVARIANT_OP]] +; CHECK-NEXT: br label [[LOOP]] +; +entry: + br label %loop + +loop: + %index = phi float [ 0., %entry ], [ %index.next, %loop ] + %step.add = fmul fast float %index, %c1 + call void @use(float %step.add) + %index.next = fmul fast float %step.add, %c2 + br label %loop +} + +; The minimum case. +; Hoist if reasassoc and nsz are present on both instructions. +define void @fadd_reassoc_nsz(float %c1, float %c2) { +; CHECK-LABEL: @fadd_reassoc_nsz( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[INVARIANT_OP:%.*]] = fadd reassoc nsz float [[C1:%.*]], [[C2:%.*]] +; CHECK-NEXT: br label [[LOOP:%.*]] +; CHECK: loop: +; CHECK-NEXT: [[INDEX:%.*]] = phi float [ 0.000000e+00, [[ENTRY:%.*]] ], [ [[INDEX_NEXT_REASS:%.*]], [[LOOP]] ] +; CHECK-NEXT: [[STEP_ADD:%.*]] = fadd reassoc nsz float [[INDEX]], [[C1]] +; CHECK-NEXT: call void @use(float [[STEP_ADD]]) +; CHECK-NEXT: [[INDEX_NEXT_REASS]] = fadd reassoc nsz float [[INDEX]], [[INVARIANT_OP]] +; CHECK-NEXT: br label [[LOOP]] +; +entry: + br label %loop + +loop: + %index = phi float [ 0., %entry ], [ %index.next, %loop ] + %step.add = fadd reassoc nsz float %index, %c1 + call void @use(float %step.add) + %index.next = fadd reassoc nsz float %step.add, %c2 + br label %loop +} + +; The minimum case. +; Hoist if reasassoc and nsz are present on both instructions. +define void @fmul_reassoc_nsz(float %c1, float %c2) { +; CHECK-LABEL: @fmul_reassoc_nsz( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[INVARIANT_OP:%.*]] = fmul reassoc nsz float [[C1:%.*]], [[C2:%.*]] +; CHECK-NEXT: br label [[LOOP:%.*]] +; CHECK: loop: +; CHECK-NEXT: [[INDEX:%.*]] = phi float [ 0.000000e+00, [[ENTRY:%.*]] ], [ [[INDEX_NEXT_REASS:%.*]], [[LOOP]] ] +; CHECK-NEXT: [[STEP_ADD:%.*]] = fmul reassoc nsz float [[INDEX]], [[C1]] +; CHECK-NEXT: call void @use(float [[STEP_ADD]]) +; CHECK-NEXT: [[INDEX_NEXT_REASS]] = fmul reassoc nsz float [[INDEX]], [[INVARIANT_OP]] +; CHECK-NEXT: br label [[LOOP]] +; +entry: + br label %loop + +loop: + %index = phi float [ 0., %entry ], [ %index.next, %loop ] + %step.add = fmul reassoc nsz float %index, %c1 + call void @use(float %step.add) + %index.next = fmul reassoc nsz float %step.add, %c2 + br label %loop +} + +; Don't hoist if both reassoc and nsz aren't present on both instructions. +define void @fadd_nonassoc(float %c1, float %c2) { +; CHECK-LABEL: @fadd_nonassoc( +; CHECK-NEXT: entry: +; CHECK-NEXT: br label [[LOOP:%.*]] +; CHECK: loop: +; CHECK-NEXT: [[INDEX:%.*]] = phi float [ 0.000000e+00, [[ENTRY:%.*]] ], [ [[INDEX_NEXT:%.*]], [[LOOP]] ] +; CHECK-NEXT: [[STEP_ADD:%.*]] = fadd reassoc float [[INDEX]], [[C1:%.*]] +; CHECK-NEXT: call void @use(float [[STEP_ADD]]) +; CHECK-NEXT: [[INDEX_NEXT]] = fadd reassoc nsz float [[STEP_ADD]], [[C2:%.*]] +; CHECK-NEXT: br label [[LOOP]] +; +entry: + br label %loop + +loop: + %index = phi float [ 0., %entry ], [ %index.next, %loop ] + %step.add = fadd reassoc float %index, %c1 + call void @use(float %step.add) + %index.next = fadd reassoc nsz float %step.add, %c2 + br label %loop +} + +; Don't hoist if both reassoc and nsz aren't present on both instructions. +define void @fmul_noassoc(float %c1, float %c2) { +; CHECK-LABEL: @fmul_noassoc( +; CHECK-NEXT: entry: +; CHECK-NEXT: br label [[LOOP:%.*]] +; CHECK: loop: +; CHECK-NEXT: [[INDEX:%.*]] = phi float [ 0.000000e+00, [[ENTRY:%.*]] ], [ [[INDEX_NEXT:%.*]], [[LOOP]] ] +; CHECK-NEXT: [[STEP_ADD:%.*]] = fmul reassoc nsz float [[INDEX]], [[C1:%.*]] +; CHECK-NEXT: call void @use(float [[STEP_ADD]]) +; CHECK-NEXT: [[INDEX_NEXT]] = fmul nsz float [[STEP_ADD]], [[C2:%.*]] +; CHECK-NEXT: br label [[LOOP]] +; +entry: + br label %loop + +loop: + %index = phi float [ 0., %entry ], [ %index.next, %loop ] + %step.add = fmul reassoc nsz float %index, %c1 + call void @use(float %step.add) + %index.next = fmul nsz float %step.add, %c2 + br label %loop +} + +; No intersection in flags present on both instructions, +; except reassoc and nsz. +define void @fadd_fmf_nointersect(float %c1, float %c2) { +; CHECK-LABEL: @fadd_fmf_nointersect( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[INVARIANT_OP:%.*]] = fadd reassoc nsz float [[C1:%.*]], [[C2:%.*]] +; CHECK-NEXT: br label [[LOOP:%.*]] +; CHECK: loop: +; CHECK-NEXT: [[INDEX:%.*]] = phi float [ 0.000000e+00, [[ENTRY:%.*]] ], [ [[INDEX_NEXT_REASS:%.*]], [[LOOP]] ] +; CHECK-NEXT: [[STEP_ADD:%.*]] = fadd reassoc nnan nsz float [[INDEX]], [[C1]] +; CHECK-NEXT: call void @use(float [[STEP_ADD]]) +; CHECK-NEXT: [[INDEX_NEXT_REASS]] = fadd reassoc nsz float [[INDEX]], [[INVARIANT_OP]] +; CHECK-NEXT: br label [[LOOP]] +; +entry: + br label %loop + +loop: + %index = phi float [ 0., %entry ], [ %index.next, %loop ] + %step.add = fadd reassoc nsz nnan float %index, %c1 + call void @use(float %step.add) + %index.next = fadd reassoc nsz ninf float %step.add, %c2 + br label %loop +} + +; No intersection in flags present on both instructions, +; except reassoc and nsz. +define void @fmul_fmf_nointersect(float %c1, float %c2) { +; CHECK-LABEL: @fmul_fmf_nointersect( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[INVARIANT_OP:%.*]] = fmul reassoc nsz float [[C1:%.*]], [[C2:%.*]] +; CHECK-NEXT: br label [[LOOP:%.*]] +; CHECK: loop: +; CHECK-NEXT: [[INDEX:%.*]] = phi float [ 0.000000e+00, [[ENTRY:%.*]] ], [ [[INDEX_NEXT_REASS:%.*]], [[LOOP]] ] +; CHECK-NEXT: [[STEP_ADD:%.*]] = fmul reassoc nsz contract float [[INDEX]], [[C1]] +; CHECK-NEXT: call void @use(float [[STEP_ADD]]) +; CHECK-NEXT: [[INDEX_NEXT_REASS]] = fmul reassoc nsz float [[INDEX]], [[INVARIANT_OP]] +; CHECK-NEXT: br label [[LOOP]] +; +entry: + br label %loop + +loop: + %index = phi float [ 0., %entry ], [ %index.next, %loop ] + %step.add = fmul reassoc nsz contract float %index, %c1 + call void @use(float %step.add) + %index.next = fmul reassoc nnan nsz float %step.add, %c2 + br label %loop +} + +; Non-empty intersection in flags present on both instructions, +; including reassoc and nsz. +define void @fadd_fmf_intersect(float %c1, float %c2) { +; CHECK-LABEL: @fadd_fmf_intersect( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[INVARIANT_OP:%.*]] = fadd reassoc ninf nsz float [[C1:%.*]], [[C2:%.*]] +; CHECK-NEXT: br label [[LOOP:%.*]] +; CHECK: loop: +; CHECK-NEXT: [[INDEX:%.*]] = phi float [ 0.000000e+00, [[ENTRY:%.*]] ], [ [[INDEX_NEXT_REASS:%.*]], [[LOOP]] ] +; CHECK-NEXT: [[STEP_ADD:%.*]] = fadd reassoc nnan ninf nsz float [[INDEX]], [[C1]] +; CHECK-NEXT: call void @use(float [[STEP_ADD]]) +; CHECK-NEXT: [[INDEX_NEXT_REASS]] = fadd reassoc ninf nsz float [[INDEX]], [[INVARIANT_OP]] +; CHECK-NEXT: br label [[LOOP]] +; +entry: + br label %loop + +loop: + %index = phi float [ 0., %entry ], [ %index.next, %loop ] + %step.add = fadd reassoc nnan nsz ninf float %index, %c1 + call void @use(float %step.add) + %index.next = fadd reassoc ninf nsz float %step.add, %c2 + br label %loop +} + +; Non-empty intersection in flags present on both instructions, +; including reassoc and nsz. +define void @fmul_fmf_intersect(float %c1, float %c2) { +; CHECK-LABEL: @fmul_fmf_intersect( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[INVARIANT_OP:%.*]] = fmul reassoc nsz afn float [[C1:%.*]], [[C2:%.*]] +; CHECK-NEXT: br label [[LOOP:%.*]] +; CHECK: loop: +; CHECK-NEXT: [[INDEX:%.*]] = phi float [ 0.000000e+00, [[ENTRY:%.*]] ], [ [[INDEX_NEXT_REASS:%.*]], [[LOOP]] ] +; CHECK-NEXT: [[STEP_ADD:%.*]] = fmul reassoc nsz arcp afn float [[INDEX]], [[C1]] +; CHECK-NEXT: call void @use(float [[STEP_ADD]]) +; CHECK-NEXT: [[INDEX_NEXT_REASS]] = fmul reassoc nsz afn float [[INDEX]], [[INVARIANT_OP]] +; CHECK-NEXT: br label [[LOOP]] +; +entry: + br label %loop + +loop: + %index = phi float [ 0., %entry ], [ %index.next, %loop ] + %step.add = fmul reassoc afn nsz arcp float %index, %c1 + call void @use(float %step.add) + %index.next = fmul reassoc nsz afn float %step.add, %c2 + br label %loop +} + ; Don't hoist if the intermediate op has more than two uses. This is an ; heuristic that can be adjusted if warranted. Currently we are being ; conservative to minimise potential impact in code size. From 1c26e2b6f90253efdf38a5a70d011722d4eb1216 Mon Sep 17 00:00:00 2001 From: Hari Limaye Date: Fri, 27 Sep 2024 11:06:59 +0100 Subject: [PATCH 061/469] [ArgPromotion] Perform alias analysis on actual arguments of Calls (#106216) Teach Argument Promotion to perform alias analysis on actual arguments of Calls to a Function, to try to prove that all Calls to the Function do not modify the memory pointed to by an argument. This surfaces more opportunities to perform Argument Promotion in cases where simply looking at a Function's instructions is insufficient to prove that the pointer argument is not invalidated before all loads from it. --- llvm/lib/Transforms/IPO/ArgumentPromotion.cpp | 42 ++++++++++++++++--- .../ArgumentPromotion/actual-arguments.ll | 29 ++++++------- 2 files changed, 49 insertions(+), 22 deletions(-) diff --git a/llvm/lib/Transforms/IPO/ArgumentPromotion.cpp b/llvm/lib/Transforms/IPO/ArgumentPromotion.cpp index 1f9b546ed2999..90e8c39e5a90d 100644 --- a/llvm/lib/Transforms/IPO/ArgumentPromotion.cpp +++ b/llvm/lib/Transforms/IPO/ArgumentPromotion.cpp @@ -485,11 +485,36 @@ static bool allCallersPassValidPointerForArgument( }); } +// Try to prove that all Calls to F do not modify the memory pointed to by Arg, +// using alias analysis local to each caller of F. +static bool isArgUnmodifiedByAllCalls(Argument *Arg, + FunctionAnalysisManager &FAM) { + for (User *U : Arg->getParent()->users()) { + + // Bail if we find an unexpected (non CallInst) use of the function. + auto *Call = dyn_cast(U); + if (!Call) + return false; + + MemoryLocation Loc = + MemoryLocation::getForArgument(Call, Arg->getArgNo(), nullptr); + + AAResults &AAR = FAM.getResult(*Call->getFunction()); + // Bail as soon as we find a Call where Arg may be modified. + if (isModSet(AAR.getModRefInfo(Call, Loc))) + return false; + } + + // All Users are Calls which do not modify the Arg. + return true; +} + /// Determine that this argument is safe to promote, and find the argument /// parts it can be promoted into. static bool findArgParts(Argument *Arg, const DataLayout &DL, AAResults &AAR, unsigned MaxElements, bool IsRecursive, - SmallVectorImpl &ArgPartsVec) { + SmallVectorImpl &ArgPartsVec, + FunctionAnalysisManager &FAM) { // Quick exit for unused arguments if (Arg->use_empty()) return true; @@ -716,10 +741,16 @@ static bool findArgParts(Argument *Arg, const DataLayout &DL, AAResults &AAR, return true; // Okay, now we know that the argument is only used by load instructions, and - // it is safe to unconditionally perform all of them. Use alias analysis to - // check to see if the pointer is guaranteed to not be modified from entry of - // the function to each of the load instructions. + // it is safe to unconditionally perform all of them. + + // If we can determine that no call to the Function modifies the memory region + // accessed through Arg, through alias analysis using actual arguments in the + // callers, we know that it is guaranteed to be safe to promote the argument. + if (isArgUnmodifiedByAllCalls(Arg, FAM)) + return true; + // Otherwise, use alias analysis to check if the pointer is guaranteed to not + // be modified from entry of the function to each of the load instructions. for (LoadInst *Load : Loads) { // Check to see if the load is invalidated from the start of the block to // the load itself. @@ -846,7 +877,8 @@ static Function *promoteArguments(Function *F, FunctionAnalysisManager &FAM, // If we can promote the pointer to its value. SmallVector ArgParts; - if (findArgParts(PtrArg, DL, AAR, MaxElements, IsRecursive, ArgParts)) { + if (findArgParts(PtrArg, DL, AAR, MaxElements, IsRecursive, ArgParts, + FAM)) { SmallVector Types; for (const auto &Pair : ArgParts) Types.push_back(Pair.second.Ty); diff --git a/llvm/test/Transforms/ArgumentPromotion/actual-arguments.ll b/llvm/test/Transforms/ArgumentPromotion/actual-arguments.ll index 63366ba998c7b..ca757a165fa4b 100644 --- a/llvm/test/Transforms/ArgumentPromotion/actual-arguments.ll +++ b/llvm/test/Transforms/ArgumentPromotion/actual-arguments.ll @@ -68,18 +68,14 @@ define internal i32 @test_cannot_promote_3(ptr %p, ptr nocapture readonly %test_ ret i32 %sum } -; FIXME: We should perform ArgPromotion here! -; ; This is called only by @caller_safe_args_1, from which we can prove that ; %test_c does not alias %p for any Call to the function, so we can promote it. ; define internal i32 @test_can_promote_1(ptr %p, ptr nocapture readonly %test_c) { ; CHECK-LABEL: define {{[^@]+}}@test_can_promote_1 -; CHECK-SAME: (ptr [[P:%.*]], ptr nocapture readonly [[TEST_C:%.*]]) { -; CHECK-NEXT: [[TEST_C_VAL:%.*]] = load i32, ptr [[TEST_C]], align 4 -; CHECK-NEXT: [[RES:%.*]] = call i32 @callee(ptr [[P]], i32 [[TEST_C_VAL]]) -; CHECK-NEXT: [[LTEST_C:%.*]] = load i32, ptr [[TEST_C]], align 4 -; CHECK-NEXT: [[SUM:%.*]] = add i32 [[LTEST_C]], [[RES]] +; CHECK-SAME: (ptr [[P:%.*]], i32 [[TEST_C_0_VAL:%.*]]) { +; CHECK-NEXT: [[RES:%.*]] = call i32 @callee(ptr [[P]], i32 [[TEST_C_0_VAL]]) +; CHECK-NEXT: [[SUM:%.*]] = add i32 [[TEST_C_0_VAL]], [[RES]] ; CHECK-NEXT: ret i32 [[SUM]] ; %res = call i32 @callee(ptr %p, ptr %test_c) @@ -91,19 +87,15 @@ define internal i32 @test_can_promote_1(ptr %p, ptr nocapture readonly %test_c) ret i32 %sum } -; FIXME: We should perform ArgPromotion here! -; ; This is called by multiple callers (@caller_safe_args_1, @caller_safe_args_2), ; from which we can prove that %test_c does not alias %p for any Call to the ; function, so we can promote it. ; define internal i32 @test_can_promote_2(ptr %p, ptr nocapture readonly %test_c) { ; CHECK-LABEL: define {{[^@]+}}@test_can_promote_2 -; CHECK-SAME: (ptr [[P:%.*]], ptr nocapture readonly [[TEST_C:%.*]]) { -; CHECK-NEXT: [[TEST_C_VAL:%.*]] = load i32, ptr [[TEST_C]], align 4 -; CHECK-NEXT: [[RES:%.*]] = call i32 @callee(ptr [[P]], i32 [[TEST_C_VAL]]) -; CHECK-NEXT: [[LTEST_C:%.*]] = load i32, ptr [[TEST_C]], align 4 -; CHECK-NEXT: [[SUM:%.*]] = add i32 [[LTEST_C]], [[RES]] +; CHECK-SAME: (ptr [[P:%.*]], i32 [[TEST_C_0_VAL:%.*]]) { +; CHECK-NEXT: [[RES:%.*]] = call i32 @callee(ptr [[P]], i32 [[TEST_C_0_VAL]]) +; CHECK-NEXT: [[SUM:%.*]] = add i32 [[TEST_C_0_VAL]], [[RES]] ; CHECK-NEXT: ret i32 [[SUM]] ; %res = call i32 @callee(ptr %p, ptr %test_c) @@ -186,8 +178,10 @@ define i32 @caller_safe_args_1(i64 %n) { ; CHECK-NEXT: [[CALLER_C:%.*]] = alloca i32, align 4 ; CHECK-NEXT: store i32 5, ptr [[CALLER_C]], align 4 ; CHECK-NEXT: [[RES1:%.*]] = call i32 @test_cannot_promote_3(ptr [[P]], ptr [[CALLER_C]]) -; CHECK-NEXT: [[RES2:%.*]] = call i32 @test_can_promote_1(ptr [[P]], ptr [[CALLER_C]]) -; CHECK-NEXT: [[RES3:%.*]] = call i32 @test_can_promote_2(ptr [[P]], ptr [[CALLER_C]]) +; CHECK-NEXT: [[CALLER_C_VAL:%.*]] = load i32, ptr [[CALLER_C]], align 4 +; CHECK-NEXT: [[RES2:%.*]] = call i32 @test_can_promote_1(ptr [[P]], i32 [[CALLER_C_VAL]]) +; CHECK-NEXT: [[CALLER_C_VAL1:%.*]] = load i32, ptr [[CALLER_C]], align 4 +; CHECK-NEXT: [[RES3:%.*]] = call i32 @test_can_promote_2(ptr [[P]], i32 [[CALLER_C_VAL1]]) ; CHECK-NEXT: [[RES12:%.*]] = add i32 [[RES1]], [[RES2]] ; CHECK-NEXT: [[RES:%.*]] = add i32 [[RES12]], [[RES3]] ; CHECK-NEXT: ret i32 [[RES]] @@ -215,7 +209,8 @@ define i32 @caller_safe_args_2(i64 %n, ptr %p) { ; CHECK-NEXT: call void @memset(ptr [[P]], i64 0, i64 [[N]]) ; CHECK-NEXT: [[CALLER_C:%.*]] = alloca i32, align 4 ; CHECK-NEXT: store i32 5, ptr [[CALLER_C]], align 4 -; CHECK-NEXT: [[RES:%.*]] = call i32 @test_can_promote_2(ptr [[P]], ptr [[CALLER_C]]) +; CHECK-NEXT: [[CALLER_C_VAL:%.*]] = load i32, ptr [[CALLER_C]], align 4 +; CHECK-NEXT: [[RES:%.*]] = call i32 @test_can_promote_2(ptr [[P]], i32 [[CALLER_C_VAL]]) ; CHECK-NEXT: ret i32 [[RES]] ; call void @memset(ptr %p, i64 0, i64 %n) From 5cc64bf60bc04b9315de3c679eb753de4d554a8a Mon Sep 17 00:00:00 2001 From: William Huhn Date: Fri, 27 Sep 2024 06:45:17 -0400 Subject: [PATCH 062/469] [Nomination] Update Intel representation in the security group (#109281) I'd like to nominate Sergey Zverev as an Intel representative to replace Andy Kaylor, who will be leaving the security group. Sergey is the one of the main security points of contact for the Intel compiler team. --- llvm/docs/Security.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/docs/Security.rst b/llvm/docs/Security.rst index 2b5b5139858e7..67b6ebb4b04d9 100644 --- a/llvm/docs/Security.rst +++ b/llvm/docs/Security.rst @@ -37,7 +37,6 @@ meet the criteria for inclusion below. The list is in the format username for an individual isn't available, the brackets will be empty. * Ahmed Bougacha (Apple) [@ahmedbougacha] -* Andy Kaylor (Intel) [@andykaylor] * Artur Pilipenko (Azul Systems Inc) [] * Boovaragavan Dasarathan (Nvidia) [@mrragava] * Dimitry Andric (individual; FreeBSD) [@DimitryAndric] @@ -52,6 +51,7 @@ username for an individual isn't available, the brackets will be empty. * Peter Smith (ARM) [@smithp35] * Pietro Albini (Ferrous Systems; Rust) [@pietroalbini] * Serge Guelton (Mozilla) [@serge-sans-paille] +* Sergey Zverev (Intel) [@offsake] * Shayne Hiet-Block (Microsoft) [@GreatKeeper] * Tim Penge (Sony) [@tpenge] * Tulio Magno Quites Machado Filho (Red Hat) [@tuliom] From 3fee3e83a8a802cd23e79fbf2f1320bb8f961d0c Mon Sep 17 00:00:00 2001 From: Ramkumar Ramachandra Date: Fri, 27 Sep 2024 12:00:50 +0100 Subject: [PATCH 063/469] KnownBits: refine srem for high-bits (#109121) KnownBits::srem does not correctly set the leader zero-bits, omitting the fact that LHS may be known-negative or known-non-negative. Fix this. Alive2 proof: https://alive2.llvm.org/ce/z/Ugh-Dq --- llvm/lib/Support/KnownBits.cpp | 10 +++++++--- .../Analysis/ValueTracking/knownbits-rem.ll | 18 +++--------------- llvm/test/CodeGen/ARM/select-imm.ll | 17 +++++++---------- 3 files changed, 17 insertions(+), 28 deletions(-) diff --git a/llvm/lib/Support/KnownBits.cpp b/llvm/lib/Support/KnownBits.cpp index 8e31e0ced2d73..6863c5c0af5dc 100644 --- a/llvm/lib/Support/KnownBits.cpp +++ b/llvm/lib/Support/KnownBits.cpp @@ -1075,9 +1075,13 @@ KnownBits KnownBits::srem(const KnownBits &LHS, const KnownBits &RHS) { // The sign bit is the LHS's sign bit, except when the result of the // remainder is zero. The magnitude of the result should be less than or - // equal to the magnitude of the LHS. Therefore any leading zeros that exist - // in the left hand side must also exist in the result. - Known.Zero.setHighBits(LHS.countMinLeadingZeros()); + // equal to the magnitude of either operand. + if (LHS.isNegative() && Known.isNonZero()) + Known.One.setHighBits( + std::max(LHS.countMinLeadingOnes(), RHS.countMinSignBits())); + else if (LHS.isNonNegative()) + Known.Zero.setHighBits( + std::max(LHS.countMinLeadingZeros(), RHS.countMinSignBits())); return Known; } diff --git a/llvm/test/Analysis/ValueTracking/knownbits-rem.ll b/llvm/test/Analysis/ValueTracking/knownbits-rem.ll index e5512fa71ae0e..0aa340c46bdec 100644 --- a/llvm/test/Analysis/ValueTracking/knownbits-rem.ll +++ b/llvm/test/Analysis/ValueTracking/knownbits-rem.ll @@ -104,11 +104,7 @@ define i8 @srem_low_bits_know2(i8 %xx, i8 %yy) { define i8 @srem_high_bits_know(i8 %xx, i8 %yy) { ; CHECK-LABEL: @srem_high_bits_know( -; CHECK-NEXT: [[X:%.*]] = or i8 [[XX:%.*]], -2 -; CHECK-NEXT: [[Y:%.*]] = and i8 [[YY:%.*]], -4 -; CHECK-NEXT: [[REM:%.*]] = srem i8 [[X]], [[Y]] -; CHECK-NEXT: [[R:%.*]] = and i8 [[REM]], -2 -; CHECK-NEXT: ret i8 [[R]] +; CHECK-NEXT: ret i8 -2 ; %x = or i8 %xx, -2 %y = and i8 %yy, -4 @@ -119,11 +115,7 @@ define i8 @srem_high_bits_know(i8 %xx, i8 %yy) { define i8 @srem_high_bits_know2(i8 %xx, i8 %yy) { ; CHECK-LABEL: @srem_high_bits_know2( -; CHECK-NEXT: [[X:%.*]] = and i8 [[XX:%.*]], 13 -; CHECK-NEXT: [[Y:%.*]] = or i8 [[YY:%.*]], -4 -; CHECK-NEXT: [[REM:%.*]] = srem i8 [[X]], [[Y]] -; CHECK-NEXT: [[R:%.*]] = and i8 [[REM]], 8 -; CHECK-NEXT: ret i8 [[R]] +; CHECK-NEXT: ret i8 0 ; %x = and i8 %xx, 13 %y = or i8 %yy, -4 @@ -134,11 +126,7 @@ define i8 @srem_high_bits_know2(i8 %xx, i8 %yy) { define i8 @srem_high_bits_know3(i8 %xx, i8 %yy) { ; CHECK-LABEL: @srem_high_bits_know3( -; CHECK-NEXT: [[X:%.*]] = or i8 [[XX:%.*]], -13 -; CHECK-NEXT: [[Y:%.*]] = and i8 [[YY:%.*]], 4 -; CHECK-NEXT: [[REM:%.*]] = srem i8 [[X]], [[Y]] -; CHECK-NEXT: [[R:%.*]] = and i8 [[REM]], 8 -; CHECK-NEXT: ret i8 [[R]] +; CHECK-NEXT: ret i8 8 ; %x = or i8 %xx, -13 %y = and i8 %yy, 4 diff --git a/llvm/test/CodeGen/ARM/select-imm.ll b/llvm/test/CodeGen/ARM/select-imm.ll index 65288e1884c74..6427a3e34cf8e 100644 --- a/llvm/test/CodeGen/ARM/select-imm.ll +++ b/llvm/test/CodeGen/ARM/select-imm.ll @@ -655,14 +655,11 @@ define i1 @t10() { ; V8MBASE-NEXT: .pad #8 ; V8MBASE-NEXT: sub sp, #8 ; V8MBASE-NEXT: movs r0, #7 -; V8MBASE-NEXT: mvns r0, r0 -; V8MBASE-NEXT: str r0, [sp] -; V8MBASE-NEXT: adds r1, r0, #5 -; V8MBASE-NEXT: str r1, [sp, #4] -; V8MBASE-NEXT: sdiv r2, r1, r0 -; V8MBASE-NEXT: muls r2, r0, r2 -; V8MBASE-NEXT: subs r0, r1, r2 -; V8MBASE-NEXT: subs r1, r0, r1 +; V8MBASE-NEXT: mvns r1, r0 +; V8MBASE-NEXT: str r1, [sp] +; V8MBASE-NEXT: adds r0, r1, #5 +; V8MBASE-NEXT: str r0, [sp, #4] +; V8MBASE-NEXT: adds r1, #8 ; V8MBASE-NEXT: rsbs r0, r1, #0 ; V8MBASE-NEXT: adcs r0, r1 ; V8MBASE-NEXT: add sp, #8 @@ -719,7 +716,7 @@ define i1 @t11() { ; ARMT2-NEXT: and r1, r1, r2 ; ARMT2-NEXT: orr r0, r1, r0 ; ARMT2-NEXT: str r0, [sp] -; ARMT2-NEXT: bfc r0, #12, #20 +; ARMT2-NEXT: and r0, r0, #15 ; ARMT2-NEXT: sub r0, r0, #3 ; ARMT2-NEXT: clz r0, r0 ; ARMT2-NEXT: lsr r0, r0, #5 @@ -781,7 +778,7 @@ define i1 @t11() { ; THUMB2-NEXT: ands r1, r2 ; THUMB2-NEXT: orrs r0, r1 ; THUMB2-NEXT: str r0, [sp] -; THUMB2-NEXT: bfc r0, #12, #20 +; THUMB2-NEXT: and r0, r0, #15 ; THUMB2-NEXT: subs r0, #3 ; THUMB2-NEXT: clz r0, r0 ; THUMB2-NEXT: lsrs r0, r0, #5 From 7dfdca1961aadc75ca397818bfb9bd32f1879248 Mon Sep 17 00:00:00 2001 From: Julian Schmidt Date: Fri, 27 Sep 2024 13:03:23 +0200 Subject: [PATCH 064/469] [clang][test] add TestLanguage.def to specify all tested language versions (#94243) Adds a def file to have a single location where tested language versions are specified. Removes the need to update multiple locations in the testing infrastructure to add a new language version to be tested. Test instatiation can now include all languages without needing to specify them. This patch also adds pretty printing for instantiated test names. That means, that a test instantiated with C++23 will have the name `...TestSuite/TestName/CXX23` instead ending with some number (index of the argument for instantiation of the test), which provides a better experience when encountering a test failure with a specific language version. The suffix will also contain an `_win` if the target contains `win`. --------- Co-authored-by: Sirraide --- clang/include/clang/Testing/CommandLineArgs.h | 17 ++- clang/include/clang/Testing/TestClangConfig.h | 115 ++++++++++++++--- clang/include/clang/Testing/TestLanguage.def | 47 +++++++ clang/lib/Testing/CommandLineArgs.cpp | 118 ++++++++---------- clang/unittests/AST/MatchVerifier.h | 37 +----- .../ASTMatchers/ASTMatchersNodeTest.cpp | 18 ++- .../ASTMatchers/ASTMatchersTraversalTest.cpp | 10 +- .../Tooling/Syntax/BuildTreeTest.cpp | 8 +- .../Tooling/Syntax/MutationsTest.cpp | 7 +- .../Tooling/Syntax/SynthesisTest.cpp | 7 +- clang/unittests/Tooling/Syntax/TreeTest.cpp | 14 ++- .../unittests/Tooling/Syntax/TreeTestBase.cpp | 7 +- 12 files changed, 256 insertions(+), 149 deletions(-) create mode 100644 clang/include/clang/Testing/TestLanguage.def diff --git a/clang/include/clang/Testing/CommandLineArgs.h b/clang/include/clang/Testing/CommandLineArgs.h index e71907e8bbd0c..52beac7254fef 100644 --- a/clang/include/clang/Testing/CommandLineArgs.h +++ b/clang/include/clang/Testing/CommandLineArgs.h @@ -21,19 +21,18 @@ namespace clang { enum TestLanguage { - Lang_C89, - Lang_C99, - Lang_CXX03, - Lang_CXX11, - Lang_CXX14, - Lang_CXX17, - Lang_CXX20, - Lang_CXX23, +#define TESTLANGUAGE(lang, version, std_flag, version_index) \ + Lang_##lang##version, +#include "clang/Testing/TestLanguage.def" + Lang_OpenCL, Lang_OBJC, - Lang_OBJCXX + Lang_OBJCXX, }; +std::vector getCOrLater(int MinimumStd); +std::vector getCXXOrLater(int MinimumStd); + std::vector getCommandLineArgsForTesting(TestLanguage Lang); std::vector getCC1ArgsForTesting(TestLanguage Lang); diff --git a/clang/include/clang/Testing/TestClangConfig.h b/clang/include/clang/Testing/TestClangConfig.h index 1b4efca80e9d4..e52aa37482dc1 100644 --- a/clang/include/clang/Testing/TestClangConfig.h +++ b/clang/include/clang/Testing/TestClangConfig.h @@ -27,37 +27,90 @@ struct TestClangConfig { /// The argument of the `-target` command line flag. std::string Target; - bool isC() const { return Language == Lang_C89 || Language == Lang_C99; } + bool isC() const { + return false +#define TESTLANGUAGE_C(lang, version, std_flag, version_index) \ + || Language == Lang_##lang##version +#include "clang/Testing/TestLanguage.def" + ; + } - bool isC99OrLater() const { return Language == Lang_C99; } + bool isC(int Version) const { + return false +#define TESTLANGUAGE_C(lang, version, std_flag, version_index) \ + || (Version == version && Language == Lang_##lang##version) +#include "clang/Testing/TestLanguage.def" + ; + } - bool isCXX() const { - return Language == Lang_CXX03 || Language == Lang_CXX11 || - Language == Lang_CXX14 || Language == Lang_CXX17 || - Language == Lang_CXX20 || Language == Lang_CXX23; + bool isCOrLater(int MinimumStdVersion) const { + const auto MinimumStdVersionIndex = 0 +#define TESTLANGUAGE_C(lang, version, std_flag, version_index) \ + +(MinimumStdVersion == version ? version_index : 0) +#include "clang/Testing/TestLanguage.def" + ; + switch (Language) { +#define TESTLANGUAGE_C(lang, version, std_flag, version_index) \ + case Lang_##lang##version: \ + return MinimumStdVersionIndex <= version_index; +#include "clang/Testing/TestLanguage.def" + default: + return false; + } } - bool isCXX11OrLater() const { - return Language == Lang_CXX11 || Language == Lang_CXX14 || - Language == Lang_CXX17 || Language == Lang_CXX20 || - Language == Lang_CXX23; + bool isC99OrLater() const { return isCOrLater(99); } + + bool isCOrEarlier(int MaximumStdVersion) const { + return isC() && (isC(MaximumStdVersion) || !isCOrLater(MaximumStdVersion)); } - bool isCXX14OrLater() const { - return Language == Lang_CXX14 || Language == Lang_CXX17 || - Language == Lang_CXX20 || Language == Lang_CXX23; + bool isCXX() const { + return false +#define TESTLANGUAGE_CXX(lang, version, std_flag, version_index) \ + || Language == Lang_##lang##version +#include "clang/Testing/TestLanguage.def" + ; } - bool isCXX17OrLater() const { - return Language == Lang_CXX17 || Language == Lang_CXX20 || - Language == Lang_CXX23; + bool isCXX(int Version) const { + return false +#define TESTLANGUAGE_CXX(lang, version, std_flag, version_index) \ + || (Version == version && Language == Lang_##lang##version) +#include "clang/Testing/TestLanguage.def" + ; } - bool isCXX20OrLater() const { - return Language == Lang_CXX20 || Language == Lang_CXX23; + bool isCXXOrLater(int MinimumStdVersion) const { + const auto MinimumStdVersionIndex = 0 +#define TESTLANGUAGE_CXX(lang, version, std_flag, version_index) \ + +(MinimumStdVersion == version ? version_index : 0) +#include "clang/Testing/TestLanguage.def" + ; + switch (Language) { +#define TESTLANGUAGE_CXX(lang, version, std_flag, version_index) \ + case Lang_##lang##version: \ + return MinimumStdVersionIndex <= version_index; +#include "clang/Testing/TestLanguage.def" + default: + return false; + } } - bool isCXX23OrLater() const { return Language == Lang_CXX23; } + bool isCXX11OrLater() const { return isCXXOrLater(11); } + + bool isCXX14OrLater() const { return isCXXOrLater(14); } + + bool isCXX17OrLater() const { return isCXXOrLater(17); } + + bool isCXX20OrLater() const { return isCXXOrLater(20); } + + bool isCXX23OrLater() const { return isCXXOrLater(23); } + + bool isCXXOrEarlier(int MaximumStdVersion) const { + return isCXX() && + (isCXX(MaximumStdVersion) || !isCXXOrLater(MaximumStdVersion)); + } bool supportsCXXDynamicExceptionSpecification() const { return Language == Lang_CXX03 || Language == Lang_CXX11 || @@ -75,6 +128,30 @@ struct TestClangConfig { return Result; } + std::string toShortString() const { + std::string Result; + llvm::raw_string_ostream OS(Result); + switch (Language) { +#define TESTLANGUAGE(lang, version, std_flag, version_index) \ + case Lang_##lang##version: \ + OS << (#lang #version); \ + break; +#include "clang/Testing/TestLanguage.def" + case Lang_OpenCL: + OS << "OpenCL"; + break; + case Lang_OBJC: + OS << "OBJC"; + break; + case Lang_OBJCXX: + OS << "OBJCXX"; + break; + } + + OS << (Target.find("win") != std::string::npos ? "_win" : ""); + return Result; + } + std::string toString() const { std::string Result; llvm::raw_string_ostream OS(Result); diff --git a/clang/include/clang/Testing/TestLanguage.def b/clang/include/clang/Testing/TestLanguage.def new file mode 100644 index 0000000000000..ac62b176a0b87 --- /dev/null +++ b/clang/include/clang/Testing/TestLanguage.def @@ -0,0 +1,47 @@ + +//===-- TestLanguage.def - Language Versions for Testing --------*- 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 +// +//===----------------------------------------------------------------------===// + +// The TESTLANGUAGE(-C/-CXX) macros have four parameters: +// the language, the standard version, the corresponding compile-flag, +// and an index of the language version for each language. +// The standard version is used to compare a standard version numerically, +// and the index is used to impose ordering for the language versions +// with respect to each language. + +#ifndef TESTLANGUAGE +# define TESTLANGUAGE(...) +#endif + +#ifndef TESTLANGUAGE_C +# define TESTLANGUAGE_C(...) TESTLANGUAGE(__VA_ARGS__) +#endif + +#ifndef TESTLANGUAGE_CXX +# define TESTLANGUAGE_CXX(...) TESTLANGUAGE(__VA_ARGS__) +#endif + +TESTLANGUAGE_C(C, 89, c89, 0) +TESTLANGUAGE_C(C, 99, c99, 1) +TESTLANGUAGE_C(C, 11, c11, 2) +TESTLANGUAGE_C(C, 17, c17, 3) +TESTLANGUAGE_C(C, 23, c23, 4) +TESTLANGUAGE_C(C, 26, c2y, 5) + +// TESTLANGUAGE_CXX(CXX, 98, c++98, 0) +TESTLANGUAGE_CXX(CXX, 03, c++03, 1) +TESTLANGUAGE_CXX(CXX, 11, c++11, 2) +TESTLANGUAGE_CXX(CXX, 14, c++14, 3) +TESTLANGUAGE_CXX(CXX, 17, c++17, 4) +TESTLANGUAGE_CXX(CXX, 20, c++20, 5) +TESTLANGUAGE_CXX(CXX, 23, c++23, 6) +TESTLANGUAGE_CXX(CXX, 26, c++26, 7) + +#undef TESTLANGUAGE_CXX +#undef TESTLANGUAGE_C +#undef TESTLANGUAGE diff --git a/clang/lib/Testing/CommandLineArgs.cpp b/clang/lib/Testing/CommandLineArgs.cpp index 3abc689b93e8d..88c6ce0e098bf 100644 --- a/clang/lib/Testing/CommandLineArgs.cpp +++ b/clang/lib/Testing/CommandLineArgs.cpp @@ -11,99 +11,79 @@ #include "llvm/Support/ErrorHandling.h" namespace clang { +std::vector getCOrLater(const int MinimumStd) { + std::vector Result{}; + +#define TESTLANGUAGE_C(lang, version, std_flag, version_index) \ + if (version >= MinimumStd) \ + Result.push_back(Lang_##lang##version); +#include "clang/Testing/TestLanguage.def" + + return Result; +} +std::vector getCXXOrLater(const int MinimumStd) { + std::vector Result{}; + +#define TESTLANGUAGE_CXX(lang, version, std_flag, version_index) \ + if (version >= MinimumStd) \ + Result.push_back(Lang_##lang##version); +#include "clang/Testing/TestLanguage.def" + + return Result; +} std::vector getCommandLineArgsForTesting(TestLanguage Lang) { - std::vector Args; // Test with basic arguments. switch (Lang) { - case Lang_C89: - Args = {"-x", "c", "-std=c89"}; - break; - case Lang_C99: - Args = {"-x", "c", "-std=c99"}; - break; - case Lang_CXX03: - Args = {"-std=c++03", "-frtti"}; - break; - case Lang_CXX11: - Args = {"-std=c++11", "-frtti"}; - break; - case Lang_CXX14: - Args = {"-std=c++14", "-frtti"}; - break; - case Lang_CXX17: - Args = {"-std=c++17", "-frtti"}; - break; - case Lang_CXX20: - Args = {"-std=c++20", "-frtti"}; - break; - case Lang_CXX23: - Args = {"-std=c++23", "-frtti"}; - break; +#define TESTLANGUAGE_C(lang, version, std_flag, version_index) \ + case Lang_##lang##version: \ + return { "-x", "c", "-std=" #std_flag }; +#define TESTLANGUAGE_CXX(lang, version, std_flag, version_index) \ + case Lang_##lang##version: \ + return { "-std=" #std_flag, "-frtti" }; +#include "clang/Testing/TestLanguage.def" + case Lang_OBJC: - Args = {"-x", "objective-c", "-frtti", "-fobjc-nonfragile-abi"}; - break; + return {"-x", "objective-c", "-frtti", "-fobjc-nonfragile-abi"}; case Lang_OBJCXX: - Args = {"-x", "objective-c++", "-frtti"}; - break; + return {"-x", "objective-c++", "-frtti"}; case Lang_OpenCL: - llvm_unreachable("Not implemented yet!"); + llvm_unreachable("Unhandled TestLanguage enum"); } - return Args; + llvm_unreachable("Unhandled TestLanguage enum"); } std::vector getCC1ArgsForTesting(TestLanguage Lang) { - std::vector Args; switch (Lang) { - case Lang_C89: - Args = {"-xc", "-std=c89"}; - break; - case Lang_C99: - Args = {"-xc", "-std=c99"}; - break; - case Lang_CXX03: - Args = {"-std=c++03"}; - break; - case Lang_CXX11: - Args = {"-std=c++11"}; - break; - case Lang_CXX14: - Args = {"-std=c++14"}; - break; - case Lang_CXX17: - Args = {"-std=c++17"}; - break; - case Lang_CXX20: - Args = {"-std=c++20"}; - break; - case Lang_CXX23: - Args = {"-std=c++23"}; - break; +#define TESTLANGUAGE_C(lang, version, std_flag, version_index) \ + case Lang_##lang##version: \ + return { "-xc", "-std=" #std_flag }; +#define TESTLANGUAGE_CXX(lang, version, std_flag, version_index) \ + case Lang_##lang##version: \ + return { "-std=" #std_flag }; +#include "clang/Testing/TestLanguage.def" + case Lang_OBJC: - Args = {"-xobjective-c"}; + return {"-xobjective-c"}; break; case Lang_OBJCXX: - Args = {"-xobjective-c++"}; + return {"-xobjective-c++"}; break; case Lang_OpenCL: - llvm_unreachable("Not implemented yet!"); + llvm_unreachable("Unhandled TestLanguage enum"); } - return Args; + llvm_unreachable("Unhandled TestLanguage enum"); } StringRef getFilenameForTesting(TestLanguage Lang) { switch (Lang) { - case Lang_C89: - case Lang_C99: +#define TESTLANGUAGE_C(lang, version, std_flag, version_index) \ + case Lang_##lang##version: \ return "input.c"; - - case Lang_CXX03: - case Lang_CXX11: - case Lang_CXX14: - case Lang_CXX17: - case Lang_CXX20: - case Lang_CXX23: +#define TESTLANGUAGE_CXX(lang, version, std_flag, version_index) \ + case Lang_##lang##version: \ return "input.cc"; +#include "clang/Testing/TestLanguage.def" case Lang_OpenCL: return "input.cl"; diff --git a/clang/unittests/AST/MatchVerifier.h b/clang/unittests/AST/MatchVerifier.h index 60bb4a8716ae8..e28946977de88 100644 --- a/clang/unittests/AST/MatchVerifier.h +++ b/clang/unittests/AST/MatchVerifier.h @@ -88,38 +88,13 @@ MatchVerifier::match(const std::string &Code, StringRef FileName; switch (L) { - case Lang_C89: - Args.push_back("-std=c89"); - FileName = "input.c"; - break; - case Lang_C99: - Args.push_back("-std=c99"); - FileName = "input.c"; - break; - case Lang_CXX03: - Args.push_back("-std=c++03"); - FileName = "input.cc"; - break; - case Lang_CXX11: - Args.push_back("-std=c++11"); - FileName = "input.cc"; - break; - case Lang_CXX14: - Args.push_back("-std=c++14"); - FileName = "input.cc"; - break; - case Lang_CXX17: - Args.push_back("-std=c++17"); - FileName = "input.cc"; - break; - case Lang_CXX20: - Args.push_back("-std=c++20"); - FileName = "input.cc"; - break; - case Lang_CXX23: - Args.push_back("-std=c++23"); - FileName = "input.cc"; +#define TESTLANGUAGE(lang, version, std_flag, version_index) \ + case Lang_##lang##version: \ + Args.push_back("-std=" #std_flag); \ + FileName = getFilenameForTesting(Lang_##lang##version); \ break; +#include "clang/Testing/TestLanguage.def" + case Lang_OpenCL: Args.push_back("-cl-no-stdinc"); FileName = "input.cl"; diff --git a/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp index f2eaf19d61402..3295ad1e21455 100644 --- a/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp +++ b/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp @@ -1224,7 +1224,7 @@ TEST_P(ASTMatchersTest, CastExpression_MatchesImplicitCasts) { } TEST_P(ASTMatchersTest, CastExpr_DoesNotMatchNonCasts) { - if (GetParam().Language == Lang_C89 || GetParam().Language == Lang_C99) { + if (GetParam().isC()) { // This does have a cast in C EXPECT_TRUE(matches("char c = '0';", implicitCastExpr())); } else { @@ -1678,7 +1678,7 @@ TEST_P(ASTMatchersTest, FunctionProtoType) { } TEST_P(ASTMatchersTest, FunctionProtoType_C) { - if (!GetParam().isC()) { + if (!GetParam().isCOrEarlier(17)) { return; } EXPECT_TRUE(notMatches("void f();", functionProtoType())); @@ -2745,8 +2745,11 @@ TEST(MatchFinderAPI, MatchesDynamic) { static std::vector allTestClangConfigs() { std::vector all_configs; - for (TestLanguage lang : {Lang_C89, Lang_C99, Lang_CXX03, Lang_CXX11, - Lang_CXX14, Lang_CXX17, Lang_CXX20, Lang_CXX23}) { + for (TestLanguage lang : { +#define TESTLANGUAGE(lang, version, std_flag, version_index) \ + Lang_##lang##version, +#include "clang/Testing/TestLanguage.def" + }) { TestClangConfig config; config.Language = lang; @@ -2770,8 +2773,11 @@ static std::vector allTestClangConfigs() { return all_configs; } -INSTANTIATE_TEST_SUITE_P(ASTMatchersTests, ASTMatchersTest, - testing::ValuesIn(allTestClangConfigs())); +INSTANTIATE_TEST_SUITE_P( + ASTMatchersTests, ASTMatchersTest, testing::ValuesIn(allTestClangConfigs()), + [](const testing::TestParamInfo &Info) { + return Info.param.toShortString(); + }); } // namespace ast_matchers } // namespace clang diff --git a/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp index ec0be27774d8b..a14803f595f47 100644 --- a/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp +++ b/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp @@ -3082,10 +3082,13 @@ B func1() { return 42; } auto M = expr(unless(integerLiteral(equals(24)))).bind("intLit"); EXPECT_TRUE(matchAndVerifyResultTrue( Code, traverse(TK_AsIs, M), - std::make_unique>("intLit", 6))); + std::make_unique>("intLit", 6), + {"-std=c++11"})); + EXPECT_TRUE(matchAndVerifyResultTrue( Code, traverse(TK_IgnoreUnlessSpelledInSource, M), - std::make_unique>("intLit", 1))); + std::make_unique>("intLit", 1), + {"-std=c++11"})); } { auto M = @@ -3128,7 +3131,8 @@ B func1() { return 42; } auto M = expr().bind("allExprs"); EXPECT_TRUE(matchAndVerifyResultTrue( Code, traverse(TK_AsIs, M), - std::make_unique>("allExprs", 6))); + std::make_unique>("allExprs", 6), + {"-std=c++11"})); EXPECT_TRUE(matchAndVerifyResultTrue( Code, traverse(TK_IgnoreUnlessSpelledInSource, M), std::make_unique>("allExprs", 1))); diff --git a/clang/unittests/Tooling/Syntax/BuildTreeTest.cpp b/clang/unittests/Tooling/Syntax/BuildTreeTest.cpp index 37e3546dc9087..4ff5e8b65a686 100644 --- a/clang/unittests/Tooling/Syntax/BuildTreeTest.cpp +++ b/clang/unittests/Tooling/Syntax/BuildTreeTest.cpp @@ -88,8 +88,12 @@ class BuildSyntaxTreeTest : public SyntaxTreeTest { } }; -INSTANTIATE_TEST_SUITE_P(SyntaxTreeTests, BuildSyntaxTreeTest, - testing::ValuesIn(allTestClangConfigs()) ); +INSTANTIATE_TEST_SUITE_P( + SyntaxTreeTests, BuildSyntaxTreeTest, + testing::ValuesIn(allTestClangConfigs()), + [](const testing::TestParamInfo &Info) { + return Info.param.toShortString(); + }); TEST_P(BuildSyntaxTreeTest, Simple) { EXPECT_TRUE(treeDumpEqual( diff --git a/clang/unittests/Tooling/Syntax/MutationsTest.cpp b/clang/unittests/Tooling/Syntax/MutationsTest.cpp index 1c3d6aac7183b..35692fd52181a 100644 --- a/clang/unittests/Tooling/Syntax/MutationsTest.cpp +++ b/clang/unittests/Tooling/Syntax/MutationsTest.cpp @@ -54,8 +54,11 @@ class MutationTest : public SyntaxTreeTest { }; }; -INSTANTIATE_TEST_SUITE_P(SyntaxTreeTests, MutationTest, - ::testing::ValuesIn(allTestClangConfigs()) ); +INSTANTIATE_TEST_SUITE_P( + SyntaxTreeTests, MutationTest, ::testing::ValuesIn(allTestClangConfigs()), + [](const testing::TestParamInfo &Info) { + return Info.param.toShortString(); + }); TEST_P(MutationTest, RemoveStatement_InCompound) { CheckTransformation(RemoveStatement, "void test() { [[100+100;]] test(); }", diff --git a/clang/unittests/Tooling/Syntax/SynthesisTest.cpp b/clang/unittests/Tooling/Syntax/SynthesisTest.cpp index be8851267532c..ccfdcd05c7848 100644 --- a/clang/unittests/Tooling/Syntax/SynthesisTest.cpp +++ b/clang/unittests/Tooling/Syntax/SynthesisTest.cpp @@ -38,8 +38,11 @@ class SynthesisTest : public SyntaxTreeTest { } }; -INSTANTIATE_TEST_SUITE_P(SynthesisTests, SynthesisTest, - ::testing::ValuesIn(allTestClangConfigs()) ); +INSTANTIATE_TEST_SUITE_P( + SynthesisTests, SynthesisTest, ::testing::ValuesIn(allTestClangConfigs()), + [](const testing::TestParamInfo &Info) { + return Info.param.toShortString(); + }); TEST_P(SynthesisTest, Leaf_Punctuation) { buildTree("", GetParam()); diff --git a/clang/unittests/Tooling/Syntax/TreeTest.cpp b/clang/unittests/Tooling/Syntax/TreeTest.cpp index 44cf42fa944a2..b553f704ae00c 100644 --- a/clang/unittests/Tooling/Syntax/TreeTest.cpp +++ b/clang/unittests/Tooling/Syntax/TreeTest.cpp @@ -103,8 +103,11 @@ class TreeTest : public SyntaxTreeTest { } }; -INSTANTIATE_TEST_SUITE_P(TreeTests, TreeTest, - ::testing::ValuesIn(allTestClangConfigs()) ); +INSTANTIATE_TEST_SUITE_P( + TreeTests, TreeTest, ::testing::ValuesIn(allTestClangConfigs()), + [](const testing::TestParamInfo &Info) { + return Info.param.toShortString(); + }); TEST_P(TreeTest, FirstLeaf) { buildTree("", GetParam()); @@ -221,8 +224,11 @@ class ListTest : public SyntaxTreeTest { } }; -INSTANTIATE_TEST_SUITE_P(TreeTests, ListTest, - ::testing::ValuesIn(allTestClangConfigs()) ); +INSTANTIATE_TEST_SUITE_P( + TreeTests, ListTest, ::testing::ValuesIn(allTestClangConfigs()), + [](const testing::TestParamInfo &Info) { + return Info.param.toShortString(); + }); /// "a, b, c" <=> [("a", ","), ("b", ","), ("c", null)] TEST_P(ListTest, List_Separated_WellFormed) { diff --git a/clang/unittests/Tooling/Syntax/TreeTestBase.cpp b/clang/unittests/Tooling/Syntax/TreeTestBase.cpp index f387b503f3368..14c446c199906 100644 --- a/clang/unittests/Tooling/Syntax/TreeTestBase.cpp +++ b/clang/unittests/Tooling/Syntax/TreeTestBase.cpp @@ -48,8 +48,11 @@ ArrayRef tokens(syntax::Node *N, std::vector clang::syntax::allTestClangConfigs() { std::vector all_configs; - for (TestLanguage lang : {Lang_C89, Lang_C99, Lang_CXX03, Lang_CXX11, - Lang_CXX14, Lang_CXX17, Lang_CXX20}) { + for (TestLanguage lang : { +#define TESTLANGUAGE(lang, version, std_flag, version_index) \ + Lang_##lang##version, +#include "clang/Testing/TestLanguage.def" + }) { TestClangConfig config; config.Language = lang; config.Target = "x86_64-pc-linux-gnu"; From af6354634d2cec14570108ee038ca4b18cf6856a Mon Sep 17 00:00:00 2001 From: Alexey Bataev Date: Fri, 27 Sep 2024 03:55:17 -0700 Subject: [PATCH 065/469] [SLP]Look for vector user when estimating the cost Need to find the first vector node user, not the very first user node at all. The very first user might be a gather, vectorized as clustered, which may cause compiler crash. Fixes https://github.com/llvm/llvm-project/issues/110193 --- .../Transforms/Vectorize/SLPVectorizer.cpp | 13 ++-- .../X86/minbw-multiused-from-gather.ll | 71 +++++++++++++++++++ 2 files changed, 79 insertions(+), 5 deletions(-) create mode 100644 llvm/test/Transforms/SLPVectorizer/X86/minbw-multiused-from-gather.ll diff --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp index 48a8627ab63e0..dee0b7e1f4371 100644 --- a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp +++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp @@ -10340,13 +10340,16 @@ BoUpSLP::getEntryCost(const TreeEntry *E, ArrayRef VectorizedVals, InstructionCost VecCost = VectorCost(CommonCost); // Check if the current node must be resized, if the parent node is not // resized. - if (!UnaryInstruction::isCast(E->getOpcode()) && E->Idx != 0 && + if (It != MinBWs.end() && !UnaryInstruction::isCast(E->getOpcode()) && + E->Idx != 0 && (E->getOpcode() != Instruction::Load || !E->UserTreeIndices.empty())) { - const EdgeInfo &EI = E->UserTreeIndices.front(); - if ((EI.UserTE->getOpcode() != Instruction::Select || - EI.EdgeIdx != 0) && - It != MinBWs.end()) { + const EdgeInfo &EI = + *find_if(E->UserTreeIndices, [](const EdgeInfo &EI) { + return !EI.UserTE->isGather() || EI.EdgeIdx != UINT_MAX; + }); + if (EI.UserTE->getOpcode() != Instruction::Select || + EI.EdgeIdx != 0) { auto UserBWIt = MinBWs.find(EI.UserTE); Type *UserScalarTy = EI.UserTE->getOperand(EI.EdgeIdx).front()->getType(); diff --git a/llvm/test/Transforms/SLPVectorizer/X86/minbw-multiused-from-gather.ll b/llvm/test/Transforms/SLPVectorizer/X86/minbw-multiused-from-gather.ll new file mode 100644 index 0000000000000..8e4b280271051 --- /dev/null +++ b/llvm/test/Transforms/SLPVectorizer/X86/minbw-multiused-from-gather.ll @@ -0,0 +1,71 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 +; RUN: opt -S --passes=slp-vectorizer -mtriple=x86_64-unknown-linux-gnu < %s | FileCheck %s + +define i1 @test() { +; CHECK-LABEL: define i1 @test() { +; CHECK-NEXT: [[ENTRY:.*:]] +; CHECK-NEXT: [[TMP0:%.*]] = trunc i64 0 to i32 +; CHECK-NEXT: [[CONV85_22_I333_I_I:%.*]] = or i32 0, [[TMP0]] +; CHECK-NEXT: [[CMP3_I_22_I334_I_I:%.*]] = icmp ugt i32 [[CONV85_22_I333_I_I]], 0 +; CHECK-NEXT: [[SHL_I111_22_I335_I_I:%.*]] = select i1 [[CMP3_I_22_I334_I_I]], i32 0, i32 0 +; CHECK-NEXT: [[C22_I336_I_I:%.*]] = shl i32 [[CONV85_22_I333_I_I]], [[SHL_I111_22_I335_I_I]] +; CHECK-NEXT: [[TMP1:%.*]] = trunc i64 0 to i32 +; CHECK-NEXT: [[CONV85_23_I340_I_I:%.*]] = or i32 0, [[TMP1]] +; CHECK-NEXT: [[CMP3_I_23_I341_I_I:%.*]] = icmp ugt i32 [[CONV85_23_I340_I_I]], 0 +; CHECK-NEXT: [[SHL_I111_23_I342_I_I:%.*]] = select i1 [[CMP3_I_23_I341_I_I]], i32 0, i32 0 +; CHECK-NEXT: [[C23_I343_I_I:%.*]] = shl i32 [[CONV85_23_I340_I_I]], [[SHL_I111_23_I342_I_I]] +; CHECK-NEXT: [[TMP2:%.*]] = trunc i64 0 to i32 +; CHECK-NEXT: [[CONV85_24_I347_I_I:%.*]] = or i32 0, [[TMP2]] +; CHECK-NEXT: [[CMP3_I_24_I348_I_I:%.*]] = icmp ugt i32 [[CONV85_24_I347_I_I]], 0 +; CHECK-NEXT: [[SHL_I111_24_I349_I_I:%.*]] = select i1 [[CMP3_I_24_I348_I_I]], i32 0, i32 0 +; CHECK-NEXT: [[C24_I350_I_I:%.*]] = shl i32 [[CONV85_24_I347_I_I]], [[SHL_I111_24_I349_I_I]] +; CHECK-NEXT: [[TMP3:%.*]] = trunc i64 0 to i32 +; CHECK-NEXT: [[CONV85_25_I354_I_I:%.*]] = or i32 0, [[TMP3]] +; CHECK-NEXT: [[CMP3_I_25_I355_I_I:%.*]] = icmp ugt i32 [[CONV85_25_I354_I_I]], 0 +; CHECK-NEXT: [[SHL_I111_25_I356_I_I:%.*]] = select i1 [[CMP3_I_25_I355_I_I]], i32 0, i32 0 +; CHECK-NEXT: [[C25_I357_I_I:%.*]] = shl i32 [[CONV85_25_I354_I_I]], [[SHL_I111_25_I356_I_I]] +; CHECK-NEXT: [[TMP4:%.*]] = call i32 @llvm.vector.reduce.and.v4i32(<4 x i32> zeroinitializer) +; CHECK-NEXT: [[OP_RDX:%.*]] = and i32 [[TMP4]], [[C22_I336_I_I]] +; CHECK-NEXT: [[OP_RDX1:%.*]] = and i32 [[C23_I343_I_I]], [[C24_I350_I_I]] +; CHECK-NEXT: [[OP_RDX2:%.*]] = and i32 [[OP_RDX]], [[OP_RDX1]] +; CHECK-NEXT: [[OP_RDX3:%.*]] = and i32 [[OP_RDX2]], [[C25_I357_I_I]] +; CHECK-NEXT: [[CONV109_I_I:%.*]] = trunc i32 [[OP_RDX3]] to i8 +; CHECK-NEXT: [[CMP_I_I54_I:%.*]] = icmp eq i8 [[CONV109_I_I]], 0 +; CHECK-NEXT: ret i1 [[CMP_I_I54_I]] +; +entry: + %c18.i308.i.i = shl i32 0, 0 + %c19.i315.i.i = shl i32 0, 0 + %and.19.i316.i.i = and i32 %c18.i308.i.i, %c19.i315.i.i + %c20.i322.i.i = shl i32 0, 0 + %and.20.i323.i.i = and i32 %and.19.i316.i.i, %c20.i322.i.i + %c21.i329.i.i = shl i32 0, 0 + %and.21.i330.i.i = and i32 %and.20.i323.i.i, %c21.i329.i.i + %0 = trunc i64 0 to i32 + %conv85.22.i333.i.i = or i32 0, %0 + %cmp3.i.22.i334.i.i = icmp ugt i32 %conv85.22.i333.i.i, 0 + %shl.i111.22.i335.i.i = select i1 %cmp3.i.22.i334.i.i, i32 0, i32 0 + %c22.i336.i.i = shl i32 %conv85.22.i333.i.i, %shl.i111.22.i335.i.i + %and.22.i337.i.i = and i32 %and.21.i330.i.i, %c22.i336.i.i + %1 = trunc i64 0 to i32 + %conv85.23.i340.i.i = or i32 0, %1 + %cmp3.i.23.i341.i.i = icmp ugt i32 %conv85.23.i340.i.i, 0 + %shl.i111.23.i342.i.i = select i1 %cmp3.i.23.i341.i.i, i32 0, i32 0 + %c23.i343.i.i = shl i32 %conv85.23.i340.i.i, %shl.i111.23.i342.i.i + %and.23.i344.i.i = and i32 %and.22.i337.i.i, %c23.i343.i.i + %2 = trunc i64 0 to i32 + %conv85.24.i347.i.i = or i32 0, %2 + %cmp3.i.24.i348.i.i = icmp ugt i32 %conv85.24.i347.i.i, 0 + %shl.i111.24.i349.i.i = select i1 %cmp3.i.24.i348.i.i, i32 0, i32 0 + %c24.i350.i.i = shl i32 %conv85.24.i347.i.i, %shl.i111.24.i349.i.i + %and.24.i351.i.i = and i32 %and.23.i344.i.i, %c24.i350.i.i + %3 = trunc i64 0 to i32 + %conv85.25.i354.i.i = or i32 0, %3 + %cmp3.i.25.i355.i.i = icmp ugt i32 %conv85.25.i354.i.i, 0 + %shl.i111.25.i356.i.i = select i1 %cmp3.i.25.i355.i.i, i32 0, i32 0 + %c25.i357.i.i = shl i32 %conv85.25.i354.i.i, %shl.i111.25.i356.i.i + %and.25.i358.i.i = and i32 %and.24.i351.i.i, %c25.i357.i.i + %conv109.i.i = trunc i32 %and.25.i358.i.i to i8 + %cmp.i.i54.i = icmp eq i8 %conv109.i.i, 0 + ret i1 %cmp.i.i54.i +} From d5dc5085a1ac55100b4628e61d12ef01aa0db539 Mon Sep 17 00:00:00 2001 From: Julian Schmidt Date: Fri, 27 Sep 2024 13:23:45 +0200 Subject: [PATCH 066/469] [clang][test] remove unused `run` overload in `BoundNodesCallback` (#105935) The overload that did not take the additional `ASTContext *` argument is unnecessary when the context could simply be commented out, as it is always passed to `run` from `VerifyMatcher::run`. This patch removes the single-argument overload in favor of having a single overload. --- .../unittests/ASTMatchers/ASTMatchersNodeTest.cpp | 2 -- clang/unittests/ASTMatchers/ASTMatchersTest.h | 7 +------ .../ASTMatchers/ASTMatchersTraversalTest.cpp | 15 ++++----------- 3 files changed, 5 insertions(+), 19 deletions(-) diff --git a/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp index 3295ad1e21455..ebf548eb25431 100644 --- a/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp +++ b/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp @@ -2030,8 +2030,6 @@ TEST_P(ASTMatchersTest, template class VerifyAncestorHasChildIsEqual : public BoundNodesCallback { public: - bool run(const BoundNodes *Nodes) override { return false; } - bool run(const BoundNodes *Nodes, ASTContext *Context) override { const T *Node = Nodes->getNodeAs(""); return verify(*Nodes, *Context, Node); diff --git a/clang/unittests/ASTMatchers/ASTMatchersTest.h b/clang/unittests/ASTMatchers/ASTMatchersTest.h index e981299531574..ad2f5f355621c 100644 --- a/clang/unittests/ASTMatchers/ASTMatchersTest.h +++ b/clang/unittests/ASTMatchers/ASTMatchersTest.h @@ -28,7 +28,6 @@ using clang::tooling::runToolOnCodeWithArgs; class BoundNodesCallback { public: virtual ~BoundNodesCallback() {} - virtual bool run(const BoundNodes *BoundNodes) = 0; virtual bool run(const BoundNodes *BoundNodes, ASTContext *Context) = 0; virtual void onEndOfTranslationUnit() {} }; @@ -403,7 +402,7 @@ template class VerifyIdIsBoundTo : public BoundNodesCallback { EXPECT_EQ("", Name); } - bool run(const BoundNodes *Nodes) override { + bool run(const BoundNodes *Nodes, ASTContext * /*Context*/) override { const BoundNodes::IDToNodeMap &M = Nodes->getMap(); if (Nodes->getNodeAs(Id)) { ++Count; @@ -426,10 +425,6 @@ template class VerifyIdIsBoundTo : public BoundNodesCallback { return false; } - bool run(const BoundNodes *Nodes, ASTContext *Context) override { - return run(Nodes); - } - private: const std::string Id; const int ExpectedCount; diff --git a/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp index a14803f595f47..1d18869a6b8af 100644 --- a/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp +++ b/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp @@ -5666,7 +5666,6 @@ TEST(HasParent, MatchesAllParents) { TEST(HasParent, NoDuplicateParents) { class HasDuplicateParents : public BoundNodesCallback { public: - bool run(const BoundNodes *Nodes) override { return false; } bool run(const BoundNodes *Nodes, ASTContext *Context) override { const Stmt *Node = Nodes->getNodeAs("node"); std::set Parents; @@ -5875,16 +5874,14 @@ template class VerifyMatchOnNode : public BoundNodesCallback { public: VerifyMatchOnNode(StringRef Id, const internal::Matcher &InnerMatcher, StringRef InnerId) - : Id(Id), InnerMatcher(InnerMatcher), InnerId(InnerId) { - } - - bool run(const BoundNodes *Nodes) override { return false; } + : Id(Id), InnerMatcher(InnerMatcher), InnerId(InnerId) {} bool run(const BoundNodes *Nodes, ASTContext *Context) override { const T *Node = Nodes->getNodeAs(Id); return selectFirst(InnerId, match(InnerMatcher, *Node, *Context)) != - nullptr; + nullptr; } + private: std::string Id; internal::Matcher InnerMatcher; @@ -6078,7 +6075,7 @@ namespace { class ForCallablePreservesBindingWithMultipleParentsTestCallback : public BoundNodesCallback { public: - bool run(const BoundNodes *BoundNodes) override { + bool run(const BoundNodes *BoundNodes, ASTContext *Context) override { FunctionDecl const *FunDecl = BoundNodes->getNodeAs("funDecl"); // Validate test assumptions. This would be expressed as ASSERT_* in @@ -6115,10 +6112,6 @@ class ForCallablePreservesBindingWithMultipleParentsTestCallback return true; } - bool run(const BoundNodes *BoundNodes, ASTContext *Context) override { - return run(BoundNodes); - } - private: void ExpectCorrectResult(StringRef LogInfo, ArrayRef Results) const { From 581c015ed0cfe05d8dd3450375cd3db316e334f1 Mon Sep 17 00:00:00 2001 From: Timm Baeder Date: Fri, 27 Sep 2024 13:29:14 +0200 Subject: [PATCH 067/469] [clang][bytecode] Implement fixed point negation (#110237) --- clang/lib/AST/ByteCode/Compiler.cpp | 4 ++-- clang/lib/AST/ByteCode/FixedPoint.h | 16 +++++++++++++--- clang/lib/AST/ByteCode/Opcodes.td | 2 +- clang/lib/AST/ByteCode/PrimType.h | 12 ++++++------ clang/test/AST/ByteCode/fixed-point.cpp | 2 ++ 5 files changed, 24 insertions(+), 12 deletions(-) diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp index aac3fd384130d..78ba1a7eec662 100644 --- a/clang/lib/AST/ByteCode/Compiler.cpp +++ b/clang/lib/AST/ByteCode/Compiler.cpp @@ -724,9 +724,9 @@ bool Compiler::VisitFixedPointLiteral(const FixedPointLiteral *E) { assert(E->getType()->isFixedPointType()); assert(classifyPrim(E) == PT_FixedPoint); - // FIXME: Semantics. + auto Sem = Ctx.getASTContext().getFixedPointSemantics(E->getType()); APInt Value = E->getValue(); - return this->emitConstFixedPoint(Value, E); + return this->emitConstFixedPoint(FixedPoint(Value, Sem), E); } template diff --git a/clang/lib/AST/ByteCode/FixedPoint.h b/clang/lib/AST/ByteCode/FixedPoint.h index 5c4043f060ec5..fba793cd59e7e 100644 --- a/clang/lib/AST/ByteCode/FixedPoint.h +++ b/clang/lib/AST/ByteCode/FixedPoint.h @@ -17,16 +17,16 @@ namespace clang { namespace interp { using APInt = llvm::APInt; +using APSInt = llvm::APSInt; /// Wrapper around fixed point types. class FixedPoint final { private: llvm::APFixedPoint V; + FixedPoint(llvm::APFixedPoint &&V) : V(std::move(V)) {} public: - FixedPoint(APInt V) - : V(V, - llvm::FixedPointSemantics(V.getBitWidth(), 0, false, false, false)) {} + FixedPoint(APInt V, llvm::FixedPointSemantics Sem) : V(V, Sem) {} // This needs to be default-constructible so llvm::endian::read works. FixedPoint() : V(APInt(0, 0ULL, false), @@ -42,12 +42,22 @@ class FixedPoint final { void print(llvm::raw_ostream &OS) const { OS << V; } APValue toAPValue(const ASTContext &) const { return APValue(V); } + APSInt toAPSInt(unsigned BitWidth) const { return V.getValue(); } + + unsigned bitWidth() const { return V.getWidth(); } + bool isSigned() const { return V.isSigned(); } ComparisonCategoryResult compare(const FixedPoint &Other) const { if (Other.V == V) return ComparisonCategoryResult::Equal; return ComparisonCategoryResult::Unordered; } + + static bool neg(const FixedPoint &A, FixedPoint *R) { + bool Overflow = false; + *R = FixedPoint(A.V.negate(&Overflow)); + return Overflow; + } }; inline FixedPoint getSwappedBytes(FixedPoint F) { return F; } diff --git a/clang/lib/AST/ByteCode/Opcodes.td b/clang/lib/AST/ByteCode/Opcodes.td index 84c5a1d1ab4c0..5fdafd1bf8198 100644 --- a/clang/lib/AST/ByteCode/Opcodes.td +++ b/clang/lib/AST/ByteCode/Opcodes.td @@ -106,7 +106,7 @@ def PtrTypeClass : TypeClass { } def NonPtrTypeClass : TypeClass { - let Types = !listconcat(IntegerTypeClass.Types, [Bool], [Float]); + let Types = !listconcat(IntegerTypeClass.Types, [Bool], [Float], [FixedPoint]); } def AllTypeClass : TypeClass { diff --git a/clang/lib/AST/ByteCode/PrimType.h b/clang/lib/AST/ByteCode/PrimType.h index 23ca8027599cd..59c04c4673d93 100644 --- a/clang/lib/AST/ByteCode/PrimType.h +++ b/clang/lib/AST/ByteCode/PrimType.h @@ -43,11 +43,11 @@ enum PrimType : unsigned { PT_IntAP = 8, PT_IntAPS = 9, PT_Bool = 10, - PT_Float = 11, - PT_Ptr = 12, - PT_FnPtr = 13, - PT_MemberPtr = 14, - PT_FixedPoint = 15, + PT_FixedPoint = 11, + PT_Float = 12, + PT_Ptr = 13, + PT_FnPtr = 14, + PT_MemberPtr = 15, }; inline constexpr bool isPtrType(PrimType T) { @@ -71,7 +71,7 @@ inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, return OS; } -constexpr bool isIntegralType(PrimType T) { return T <= PT_Bool; } +constexpr bool isIntegralType(PrimType T) { return T <= PT_FixedPoint; } /// Mapping from primitive types to their representation. template struct PrimConv; diff --git a/clang/test/AST/ByteCode/fixed-point.cpp b/clang/test/AST/ByteCode/fixed-point.cpp index 24595ed96c166..42ebdf64e1a9f 100644 --- a/clang/test/AST/ByteCode/fixed-point.cpp +++ b/clang/test/AST/ByteCode/fixed-point.cpp @@ -7,3 +7,5 @@ static_assert((bool)0.0k); // both-error {{static assertion failed}} static_assert(1.0k == 1.0k); static_assert(1.0k != 1.0k); // both-error {{failed due to requirement '1.0k != 1.0k'}} +static_assert(-12.0k == -(-(-12.0k))); + From 097ada2fcb607be09da94a0d11f627a3759a10de Mon Sep 17 00:00:00 2001 From: Julian Schmidt Date: Fri, 27 Sep 2024 13:38:28 +0200 Subject: [PATCH 068/469] [clang][test] add testing for the AST matcher reference (#94248) ## Problem Statement Previously, the examples in the AST matcher reference, which gets generated by the doxygen comments in `ASTMatchers.h`, were untested and best effort. Some of the matchers had no or wrong examples of how to use the matcher. ## Solution This patch introduces a simple DSL around doxygen commands to enable testing the AST matcher documentation in a way that should be relatively easy to use. In `ASTMatchers.h`, most matchers are documented with a doxygen comment. Most of these also have a code example that aims to show what the matcher will match, given a matcher somewhere in the documentation text. The way that the documentation is tested, is by using doxygen's alias feature to declare custom aliases. These aliases forward to `text` (which is what doxygen's `\c` does, but for multiple words). Using the doxygen aliases is the obvious choice, because there are (now) four consumers: - people reading the header/using signature help - the doxygen generated documentation - the generated html AST matcher reference - (new) the generated matcher tests This patch rewrites/extends the documentation such that all matchers have a documented example. The new `generate_ast_matcher_doc_tests.py` script will warn on any undocumented matchers (but not on matchers without a doxygen comment) and provides diagnostics and statistics about the matchers. The current statistics emitted by the parser are: ```text Statistics: doxygen_blocks : 519 missing_tests : 10 skipped_objc : 42 code_snippets : 503 matches : 820 matchers : 580 tested_matchers : 574 none_type_matchers : 6 ``` The tests are generated during building and the script will only print something if it found an issue (compile failure, parsing issues, the expected and actual number of failures differs). ## Description DSL for generating the tests from documentation. TLDR: ``` \header{a.h} \endheader <- zero or more header \code int a = 42; \endcode \compile_args{-std=c++,c23-or-later} <- optional, the std flag supports std ranges and whole languages \matcher{expr()} <- one or more matchers in succession \match{42} <- one or more matches in succession \matcher{varDecl()} <- new matcher resets the context, the above \match will not count for this new matcher(-group) \match{int a = 42} <- only applies to the previous matcher (not to the previous case) ``` The above block can be repeated inside a doxygen command for multiple code examples for a single matcher. The test generation script will only look for these annotations and ignore anything else like `\c` or the sentences where these annotations are embedded into: `The matcher \matcher{expr()} matches the number \match{42}.`. ### Language Grammar [] denotes an optional, and <> denotes user-input ``` compile_args j:= \compile_args{[;]} matcher_tag_key ::= type match_tag_key ::= type || std || count || sub matcher_tags ::= [matcher_tag_key=;]matcher_tag_key= match_tags ::= [match_tag_key=;]match_tag_key= matcher ::= \matcher{[matcher_tags$]} matchers ::= [matcher] matcher match ::= \match{[match_tags$]} matches ::= [match] match case ::= matchers matches cases ::= [case] case header-block ::= \header{} \endheader code-block ::= \code \endcode testcase ::= code-block [compile_args] cases ``` ### Language Standard Versions The 'std' tag and '\compile_args' support specifying a specific language version, a whole language and all of its versions, and thresholds (implies ranges). Multiple arguments are passed with a ',' separator. For a language and version to execute a tested matcher, it has to match the specified '\compile_args' for the code, and the 'std' tag for the matcher. Predicates for the 'std' compiler flag are used with disjunction between languages (e.g. 'c || c++') and conjunction for all predicates specific to each language (e.g. 'c++11-or-later && c++23-or-earlier'). Examples: - `c` all available versions of C - `c++11` only C++11 - `c++11-or-later` C++11 or later - `c++11-or-earlier` C++11 or earlier - `c++11-or-later,c++23-or-earlier,c` all of C and C++ between 11 and 23 (inclusive) - `c++11-23,c` same as above ### Tags #### `type`: **Match types** are used to select where the string that is used to check if a node matches comes from. Available: `code`, `name`, `typestr`, `typeofstr`. The default is `code`. - `code`: Forwards to `tooling::fixit::getText(...)` and should be the preferred way to show what matches. - `name`: Casts the match to a `NamedDecl` and returns the result of `getNameAsString`. Useful when the matched AST node is not easy to spell out (`code` type), e.g., namespaces or classes with many members. - `typestr`: Returns the result of `QualType::getAsString` for the type derived from `Type` (otherwise, if it is derived from `Decl`, recurses with `Node->getTypeForDecl()`) **Matcher types** are used to mark matchers as sub-matcher with 'sub' or as deactivated using 'none'. Testing sub-matcher is not implemented. #### `count`: Specifying a 'count=n' on a match will result in a test that requires that the specified match will be matched n times. Default is 1. #### `std`: A match allows specifying if it matches only in specific language versions. This may be needed when the AST differs between language versions. #### `sub`: The `sub` tag on a `\match` will indicate that the match is for a node of a bound sub-matcher. E.g., `\matcher{expr(expr().bind("inner"))}` has a sub-matcher that binds to `inner`, which is the value for the `sub` tag of the expected match for the sub-matcher `\match{sub=inner$...}`. Currently, sub-matchers are not tested in any way. ### What if ...? #### ... I want to add a matcher? Add a doxygen comment to the matcher with a code example, corresponding matchers and matches, that shows what the matcher is supposed to do. Specify the compile arguments/supported languages if required, and run `ninja check-clang-unit` to test the documentation. #### ... the example I wrote is wrong? The test-generation script will try to compile your example code before it continues. This makes finding issues with your example code easier because the test-failures are much more verbose. The test-failure output of the generated test file will provide information about - where the generated test file is located - which line in `ASTMatcher.h` the example is from - which matches were: found, not-(yet)-found, expected - in case of an unexpected match: what the node looks like using the different `type`s - the language version and if the test ran with a windows `-target` flag (also in failure summary) #### ... I don't adhere to the required order of the syntax? The script will diagnose any found issues, such as `matcher is missing an example` with a `file:line:` prefix, which should provide enough information about the issue. #### ... the script diagnoses a false-positive issue with a doxygen comment? It hopefully shouldn't, but if you, e.g., added some non-matcher code and documented it with doxygen, then the script will consider that as a matcher documentation. As a result, the script will print that it detected a mismatch between the actual and the expected number of failures. If the diagnostic truly is a false-positive, change the `expected_failure_statistics` at the top of the `generate_ast_matcher_doc_tests.py` file. Fixes #57607 Fixes #63748 --- clang/docs/LibASTMatchersReference.html | 7951 ++++++++++++----- clang/docs/ReleaseNotes.rst | 3 + clang/docs/doxygen.cfg.in | 9 +- clang/docs/tools/dump_ast_matchers.py | 68 +- clang/include/clang/ASTMatchers/ASTMatchers.h | 5783 ++++++++---- clang/unittests/ASTMatchers/ASTMatchersTest.h | 428 +- clang/unittests/ASTMatchers/CMakeLists.txt | 15 + clang/utils/generate_ast_matcher_doc_tests.py | 1165 +++ 8 files changed, 11478 insertions(+), 3944 deletions(-) create mode 100755 clang/utils/generate_ast_matcher_doc_tests.py diff --git a/clang/docs/LibASTMatchersReference.html b/clang/docs/LibASTMatchersReference.html index a16b9c44ef0ea..baf39befd796a 100644 --- a/clang/docs/LibASTMatchersReference.html +++ b/clang/docs/LibASTMatchersReference.html @@ -586,28 +586,36 @@

Node Matchers

#pragma omp declare simd int min(); -attr() - matches "nodiscard", "nonnull", "noinline", and the whole "#pragma" line. + +The matcher attr() +matches nodiscard, nonnull, noinline, and +declare simd. Matcher<CXXBaseSpecifier>cxxBaseSpecifierMatcher<CXXBaseSpecifier>...
Matches class bases.
 
-Examples matches public virtual B.
+Given
   class B {};
   class C : public virtual B {};
+
+The matcher cxxRecordDecl(hasDirectBase(cxxBaseSpecifier()))
+matches C.
 
Matcher<CXXCtorInitializer>cxxCtorInitializerMatcher<CXXCtorInitializer>...
Matches constructor initializers.
 
-Examples matches i(42).
+Given
   class C {
     C() : i(42) {}
     int i;
   };
+
+The matcher cxxCtorInitializer()
+matches i(42).
 
@@ -619,17 +627,22 @@

Node Matchers

public: int a; }; -accessSpecDecl() - matches 'public:' + +The matcher accessSpecDecl() +matches public:. Matcher<Decl>bindingDeclMatcher<BindingDecl>...
Matches binding declarations
-Example matches foo and bar
-(matcher = bindingDecl()
 
-  auto [foo, bar] = std::make_pair{42, 42};
+Given
+  struct pair { int x; int y; };
+  pair make(int, int);
+  auto [foo, bar] = make(42, 42);
+
+The matcher bindingDecl()
+matches foo and bar.
 
@@ -642,14 +655,18 @@

Node Matchers

myFunc(^(int p) { printf("%d", p); }) + Matcher<Decl>classTemplateDeclMatcher<ClassTemplateDecl>...
Matches C++ class template declarations.
 
-Example matches Z
+Given
   template<class T> class Z {};
+
+The matcher classTemplateDecl()
+matches Z.
 
@@ -660,13 +677,14 @@

Node Matchers

template<class T1, class T2, int I> class A {}; - template<class T, int I> - class A<T, T*, I> {}; + template<class T, int I> class A<T, T*, I> {}; template<> class A<int, int, 1> {}; -classTemplatePartialSpecializationDecl() - matches the specialization A<T,T*,I> but not A<int,int,1> + +The matcher classTemplatePartialSpecializationDecl() +matches template<class T, int I> class A<T, T*, I> {}, +but does not match A<int, int, 1>. @@ -677,87 +695,128 @@

Node Matchers

template<typename T> class A {}; template<> class A<double> {}; A<int> a; -classTemplateSpecializationDecl() - matches the specializations A<int> and A<double> + +The matcher classTemplateSpecializationDecl() +matches class A<int> +and class A<double>. Matcher<Decl>conceptDeclMatcher<ConceptDecl>...
Matches concept declarations.
 
-Example matches integral
-  template<typename T>
-  concept integral = std::is_integral_v<T>;
+Given
+  template<typename T> concept my_concept = true;
+
+
+The matcher conceptDecl()
+matches template<typename T>
+concept my_concept = true.
 
Matcher<Decl>cxxConstructorDeclMatcher<CXXConstructorDecl>...
Matches C++ constructor declarations.
 
-Example matches Foo::Foo() and Foo::Foo(int)
+Given
   class Foo {
    public:
     Foo();
     Foo(int);
     int DoSomething();
   };
+
+  struct Bar {};
+
+
+The matcher cxxConstructorDecl()
+matches Foo() and Foo(int).
 
Matcher<Decl>cxxConversionDeclMatcher<CXXConversionDecl>...
Matches conversion operator declarations.
 
-Example matches the operator.
+Given
   class X { operator int() const; };
+
+
+The matcher cxxConversionDecl()
+matches operator int() const.
 
Matcher<Decl>cxxDeductionGuideDeclMatcher<CXXDeductionGuideDecl>...
Matches user-defined and implicitly generated deduction guide.
 
-Example matches the deduction guide.
+Given
   template<typename T>
-  class X { X(int) };
+  class X { X(int); };
   X(int) -> X<int>;
+
+
+The matcher cxxDeductionGuideDecl()
+matches the written deduction guide
+auto (int) -> X<int>,
+the implicit copy deduction guide auto (int) -> X<T>
+and the implicitly declared deduction guide
+auto (X<T>) -> X<T>.
 
Matcher<Decl>cxxDestructorDeclMatcher<CXXDestructorDecl>...
Matches explicit C++ destructor declarations.
 
-Example matches Foo::~Foo()
+Given
   class Foo {
    public:
     virtual ~Foo();
   };
+
+  struct Bar {};
+
+
+The matcher cxxDestructorDecl()
+matches virtual ~Foo().
 
Matcher<Decl>cxxMethodDeclMatcher<CXXMethodDecl>...
Matches method declarations.
 
-Example matches y
+Given
   class X { void y(); };
+
+
+The matcher cxxMethodDecl()
+matches void y().
 
Matcher<Decl>cxxRecordDeclMatcher<CXXRecordDecl>...
Matches C++ class declarations.
 
-Example matches X, Z
+Given
   class X;
   template<class T> class Z {};
+
+The matcher cxxRecordDecl()
+matches X and Z.
 
Matcher<Decl>declMatcher<Decl>...
Matches declarations.
 
-Examples matches X, C, and the friend declaration inside C;
+Given
   void X();
   class C {
-    friend X;
+    friend void X();
   };
+
+The matcher decl()
+matches void X(), C
+and friend void X().
 
@@ -767,40 +826,49 @@

Node Matchers

Given class X { int y; }; -declaratorDecl() - matches int y. + +The matcher declaratorDecl() +matches int y. Matcher<Decl>decompositionDeclMatcher<DecompositionDecl>...
Matches decomposition-declarations.
 
-Examples matches the declaration node with foo and bar, but not
-number.
-(matcher = declStmt(has(decompositionDecl())))
-
+Given
+  struct pair { int x; int y; };
+  pair make(int, int);
   int number = 42;
-  auto [foo, bar] = std::make_pair{42, 42};
+  auto [foo, bar] = make(42, 42);
+
+The matcher decompositionDecl()
+matches auto [foo, bar] = make(42, 42),
+but does not match number.
 
Matcher<Decl>enumConstantDeclMatcher<EnumConstantDecl>...
Matches enum constants.
 
-Example matches A, B, C
+Given
   enum X {
     A, B, C
   };
+The matcher enumConstantDecl()
+matches A, B and C.
 
Matcher<Decl>enumDeclMatcher<EnumDecl>...
Matches enum declarations.
 
-Example matches X
+Given
   enum X {
     A, B, C
   };
+
+The matcher enumDecl()
+matches the enum X.
 
@@ -808,9 +876,14 @@

Node Matchers

Matches field declarations.
 
 Given
-  class X { int m; };
-fieldDecl()
-  matches 'm'.
+  int a;
+  struct Foo {
+    int x;
+  };
+  void bar(int val);
+
+The matcher fieldDecl()
+matches int x.
 
@@ -819,16 +892,20 @@

Node Matchers

Given class X { friend void foo(); }; -friendDecl() - matches 'friend void foo()'. + +The matcher friendDecl() +matches friend void foo(). Matcher<Decl>functionDeclMatcher<FunctionDecl>...
Matches function declarations.
 
-Example matches f
+Given
   void f();
+
+The matcher functionDecl()
+matches void f().
 
@@ -837,6 +914,10 @@

Node Matchers

Example matches f template<class T> void f(T t) {} + + +The matcher functionTemplateDecl() +matches template<class T> void f(T t) {}. @@ -845,8 +926,8 @@

Node Matchers

Given struct X { struct { int a; }; }; -indirectFieldDecl() - matches 'a'. +The matcher indirectFieldDecl() +matches a. @@ -854,10 +935,13 @@

Node Matchers

Matches a declaration of label.
 
 Given
-  goto FOO;
-  FOO: bar();
-labelDecl()
-  matches 'FOO:'
+  void bar();
+  void foo() {
+    goto FOO;
+    FOO: bar();
+  }
+The matcher labelDecl()
+matches FOO: bar().
 
@@ -866,8 +950,9 @@

Node Matchers

Given extern "C" {} -linkageSpecDecl() - matches "extern "C" {}" + +The matcher linkageSpecDecl() +matches extern "C" {}. @@ -875,12 +960,18 @@

Node Matchers

Matches a declaration of anything that could have a name.
 
 Example matches X, S, the anonymous union type, i, and U;
+Given
   typedef int X;
   struct S {
     union {
       int i;
     } U;
   };
+The matcher namedDecl()
+matches typedef int X, S, int i
+ and U,
+with S matching twice in C++.
+Once for the injected class name and once for the declaration itself.
 
@@ -890,8 +981,10 @@

Node Matchers

Given namespace test {} namespace alias = ::test; -namespaceAliasDecl() - matches "namespace alias" but not "namespace test" + +The matcher namespaceAliasDecl() +matches alias, +but does not match test. @@ -901,8 +994,9 @@

Node Matchers

Given namespace {} namespace test {} -namespaceDecl() - matches "namespace {}" and "namespace test {}" + +The matcher namespaceDecl() +matches namespace {} and namespace test {}. @@ -911,8 +1005,10 @@

Node Matchers

Given template <typename T, int N> struct C {}; -nonTypeTemplateParmDecl() - matches 'N', but not 'T'. + +The matcher nonTypeTemplateParmDecl() +matches int N, +but does not match typename T. @@ -922,6 +1018,7 @@

Node Matchers

Example matches Foo (Additions) @interface Foo (Additions) @end + @@ -931,6 +1028,7 @@

Node Matchers

Example matches Foo (Additions) @implementation Foo (Additions) @end + @@ -940,6 +1038,7 @@

Node Matchers

Example matches Foo @implementation Foo @end + @@ -949,6 +1048,7 @@

Node Matchers

Example matches Foo @interface Foo @end + @@ -960,6 +1060,7 @@

Node Matchers

BOOL _enabled; } @end + @@ -974,6 +1075,7 @@

Node Matchers

@implementation Foo - (void)method {} @end + @@ -984,6 +1086,7 @@

Node Matchers

@interface Foo @property BOOL enabled; @end + @@ -993,6 +1096,7 @@

Node Matchers

Example matches FooDelegate @protocol FooDelegate @end + @@ -1001,48 +1105,58 @@

Node Matchers

Given void f(int x); -parmVarDecl() - matches int x. +The matcher parmVarDecl() +matches int x. Matcher<Decl>recordDeclMatcher<RecordDecl>...
Matches class, struct, and union declarations.
 
-Example matches X, Z, U, and S
+Given
   class X;
   template<class T> class Z {};
   struct S {};
   union U {};
+
+The matcher recordDecl()
+matches X, Z,
+S and U.
 
Matcher<Decl>staticAssertDeclMatcher<StaticAssertDecl>...
Matches a C++ static_assert declaration.
 
-Example:
-  staticAssertDecl()
-matches
-  static_assert(sizeof(S) == sizeof(int))
-in
+Given
   struct S {
     int x;
   };
   static_assert(sizeof(S) == sizeof(int));
+
+
+The matcher staticAssertDecl()
+matches static_assert(sizeof(S) == sizeof(int)).
 
Matcher<Decl>tagDeclMatcher<TagDecl>...
Matches tag declarations.
 
-Example matches X, Z, U, S, E
+Given
   class X;
   template<class T> class Z {};
   struct S {};
   union U {};
-  enum E {
-    A, B, C
-  };
+  enum E { A, B, C };
+
+
+The matcher tagDecl()
+matches class X, class Z {}, the injected class name
+class Z, struct S {},
+the injected class name struct S, union U {},
+the injected class name union U
+and enum E { A, B, C }.
 
@@ -1051,8 +1165,10 @@

Node Matchers

Given template <template <typename> class Z, int N> struct C {}; -templateTypeParmDecl() - matches 'Z', but not 'N'. + +The matcher templateTemplateParmDecl() +matches template <typename> class Z, +but does not match int N. @@ -1061,8 +1177,10 @@

Node Matchers

Given template <typename T, int N> struct C {}; -templateTypeParmDecl() - matches 'T', but not 'N'. + +The matcher templateTypeParmDecl() +matches typename T, +but does not int N. @@ -1072,10 +1190,12 @@

Node Matchers

Given int X; namespace NS { - int Y; + int Y; } // namespace NS -decl(hasDeclContext(translationUnitDecl())) - matches "int X", but not "int Y". + +The matcher namedDecl(hasDeclContext(translationUnitDecl())) +matches X and NS, +but does not match Y. @@ -1085,17 +1205,22 @@

Node Matchers

Given typedef int X; using Y = int; -typeAliasDecl() - matches "using Y = int", but not "typedef int X" + +The matcher typeAliasDecl() +matches using Y = int, +but does not match typedef int X. Matcher<Decl>typeAliasTemplateDeclMatcher<TypeAliasTemplateDecl>...
Matches type alias template declarations.
 
-typeAliasTemplateDecl() matches
-  template <typename T>
-  using Y = X<T>;
+Given
+  template <typename T> struct X {};
+  template <typename T> using Y = X<T>;
+
+The matcher typeAliasTemplateDecl()
+matches template <typename T> using Y = X<T>.
 
@@ -1105,8 +1230,10 @@

Node Matchers

Given typedef int X; using Y = int; -typedefDecl() - matches "typedef int X", but not "using Y = int" + +The matcher typedefDecl() +matches typedef int X, +but does not match using Y = int. @@ -1116,8 +1243,9 @@

Node Matchers

Given typedef int X; using Y = int; -typedefNameDecl() - matches "typedef int X" and "using Y = int" + +The matcher typedefNameDecl() +matches typedef int X and using Y = int. @@ -1133,8 +1261,10 @@

Node Matchers

struct S : private Base<T> { using typename Base<T>::Foo; }; -unresolvedUsingTypenameDecl() - matches using Base<T>::Foo + +The matcher unresolvedUsingTypenameDecl() + matches using typename Base<T>::Foo + Matcher<Decl>unresolvedUsingValueDeclMatcher<UnresolvedUsingValueDecl>... @@ -1145,8 +1275,10 @@

Node Matchers

class C : private X { using X::x; }; -unresolvedUsingValueDecl() - matches using X::x + +The matcher unresolvedUsingValueDecl() + matches using X::x + Matcher<Decl>usingDeclMatcher<UsingDecl>... @@ -1155,8 +1287,10 @@

Node Matchers

Given namespace X { int x; } using X::x; -usingDecl() - matches using X::x + +The matcher usingDecl() + matches using X::x + Matcher<Decl>usingDirectiveDeclMatcher<UsingDirectiveDecl>... @@ -1165,26 +1299,34 @@

Node Matchers

Given namespace X { int x; } using namespace X; -usingDirectiveDecl() - matches using namespace X + +The matcher usingDirectiveDecl() + matches using namespace X + Matcher<Decl>usingEnumDeclMatcher<UsingEnumDecl>...
Matches using-enum declarations.
 
 Given
-  namespace X { enum x {...}; }
+  namespace X { enum x { val1, val2 }; }
   using enum X::x;
-usingEnumDecl()
-  matches using enum X::x 
+ +The matcher usingEnumDecl() + matches using enum X::x + Matcher<Decl>valueDeclMatcher<ValueDecl>...
Matches any value declaration.
 
-Example matches A, B, C and F
+Given
   enum X { A, B, C };
   void F();
+  int V = 0;
+The matcher valueDecl()
+matches A, B, C, void F()
+and int V = 0.
 
@@ -1196,6 +1338,13 @@

Node Matchers

Example matches a int a; + struct Foo { + int x; + }; + void bar(int val); + +The matcher varDecl() +matches int a and int val, but not int x. @@ -1208,13 +1357,29 @@

Node Matchers

auto f = [x](){}; auto g = [x = 1](){}; } -In the matcher `lambdaExpr(hasAnyCapture(lambdaCapture()))`, -`lambdaCapture()` matches `x` and `x=1`. + +The matcher +lambdaExpr(hasAnyCapture(lambdaCapture().bind("capture"))), +matches [x](){} and [x = 1](){}, +with lambdaCapture() matching +x and x = 1. Matcher<NestedNameSpecifierLoc>nestedNameSpecifierLocMatcher<NestedNameSpecifierLoc>...
Same as nestedNameSpecifier but matches NestedNameSpecifierLoc.
+
+Given
+  namespace ns {
+    struct A { static void f(); };
+    void A::f() {}
+    void g() { A::f(); }
+  }
+  ns::A a;
+
+
+The matcher nestedNameSpecifierLoc() matches
+A:: twice, and ns:: once.
 
@@ -1228,8 +1393,9 @@

Node Matchers

void g() { A::f(); } } ns::A a; -nestedNameSpecifier() - matches "ns::" and both "A::" + +The matcher nestedNameSpecifier() +matches ns and both A @@ -1237,20 +1403,38 @@

Node Matchers

Matches OpenMP ``default`` clause.
 
 Given
+  void foo() {
+    #pragma omp parallel default(none)
+      ;
+    #pragma omp parallel default(shared)
+      ;
+    #pragma omp parallel default(private)
+      ;
+    #pragma omp parallel default(firstprivate)
+      ;
+    #pragma omp parallel
+      ;
+  }
 
-  #pragma omp parallel default(none)
-  #pragma omp parallel default(shared)
-  #pragma omp parallel default(private)
-  #pragma omp parallel default(firstprivate)
-  #pragma omp parallel
 
-``ompDefaultClause()`` matches ``default(none)``, ``default(shared)``,
-`` default(private)`` and ``default(firstprivate)``
+The matcher
+ompExecutableDirective(hasAnyClause(ompDefaultClause())) matches
+#pragma omp parallel default(none),
+#pragma omp parallel default(shared),
+#pragma omp parallel default(private) and
+#pragma omp parallel default(firstprivate).
 
Matcher<QualType>qualTypeMatcher<QualType>...
Matches QualTypes in the clang AST.
+
+Given
+  int a = 0;
+  const int b = 1;
+
+The matcher varDecl(hasType(qualType(isConstQualified())))
+matches const int b = 1, but not int a = 0.
 
@@ -1258,34 +1442,39 @@

Node Matchers

Matches address of label statements (GNU extension).
 
 Given
+void bar();
+void foo() {
   FOO: bar();
   void *ptr = &&FOO;
-  goto *bar;
-addrLabelExpr()
-  matches '&&FOO'
+  goto *ptr;
+}
+The matcher addrLabelExpr()
+matches &&FOO
 
Matcher<Stmt>arrayInitIndexExprMatcher<ArrayInitIndexExpr>...
The arrayInitIndexExpr consists of two subexpressions: a common expression
-(the source array) that is evaluated once up-front, and a per-element initializer
-that runs once for each array element. Within the per-element initializer,
-the current index may be obtained via an ArrayInitIndexExpr.
+(the source array) that is evaluated once up-front, and a per-element
+initializer that runs once for each array element. Within the per-element
+initializer, the current index may be obtained via an ArrayInitIndexExpr.
 
 Given
-  void testStructBinding() {
+  void testStructuredBinding() {
     int a[2] = {1, 2};
     auto [x, y] = a;
   }
-arrayInitIndexExpr() matches the array index that implicitly iterates
-over the array `a` to copy each element to the anonymous array
-that backs the structured binding `[x, y]` elements of which are
-referred to by their aliases `x` and `y`.
+
+
+The matcher arrayInitIndexExpr() matches the array index
+that implicitly iterates over the array `a` to copy each element to the
+anonymous array that backs the structured binding.
 
Matcher<Stmt>arrayInitLoopExprMatcher<ArrayInitLoopExpr>... -
Matches a loop initializing the elements of an array in a number of contexts:
+
Matches a loop initializing the elements of an array in a number of
+contexts:
  * in the implicit copy/move constructor for a class with an array member
  * when a lambda-expression captures an array by value
  * when a decomposition declaration decomposes an array
@@ -1293,13 +1482,12 @@ 

Node Matchers

Given void testLambdaCapture() { int a[10]; - auto Lam1 = [a]() { - return; - }; + [a]() {}; } -arrayInitLoopExpr() matches the implicit loop that initializes each element of -the implicit array field inside the lambda object, that represents the array `a` -captured by value. + +The matcher arrayInitLoopExpr() matches the implicit loop that +initializes each element of the implicit array field inside the lambda +object, that represents the array a captured by value.
@@ -1307,26 +1495,34 @@

Node Matchers

Matches array subscript expressions.
 
 Given
-  int i = a[1];
-arraySubscriptExpr()
-  matches "a[1]"
+  void foo() {
+    int a[2] = {0, 1};
+    int i = a[1];
+  }
+The matcher arraySubscriptExpr()
+matches a[1].
 
Matcher<Stmt>asmStmtMatcher<AsmStmt>...
Matches asm statements.
 
+void foo() {
  int i = 100;
-  __asm("mov al, 2");
-asmStmt()
-  matches '__asm("mov al, 2")'
+  __asm("mov %al, 2");
+}
+The matcher asmStmt()
+matches __asm("mov %al, 2")
 
Matcher<Stmt>atomicExprMatcher<AtomicExpr>...
Matches atomic builtins.
-Example matches __atomic_load_n(ptr, 1)
+
+Given
   void foo() { int *ptr; __atomic_load_n(ptr, 1); }
+
+The matcher atomicExpr() matches __atomic_load_n(ptr, 1).
 
@@ -1337,24 +1533,35 @@

Node Matchers

@autoreleasepool { int x = 0; } -autoreleasePoolStmt(stmt()) matches the declaration of "x" -inside the autorelease pool. + +The matcher autoreleasePoolStmt(stmt()) matches the declaration of +int x = 0 inside the autorelease pool.
Matcher<Stmt>binaryConditionalOperatorMatcher<BinaryConditionalOperator>...
Matches binary conditional operator expressions (GNU extension).
 
-Example matches a ?: b
-  (a ?: b) + 42;
+Given
+  int f(int a, int b) {
+    return (a ?: b) + 42;
+  }
+
+The matcher binaryConditionalOperator() matches a ?: b.
 
Matcher<Stmt>binaryOperatorMatcher<BinaryOperator>...
Matches binary operator expressions.
 
-Example matches a || b
-  !(a || b)
+Given
+  void foo(bool a, bool b) {
+    !(a || b);
+  }
+
+
+The matcher binaryOperator() matches a || b.
+
 See also the binaryOperation() matcher for more-general matching.
 
@@ -1362,8 +1569,11 @@

Node Matchers

Matcher<Stmt>blockExprMatcher<BlockExpr>...
Matches a reference to a block.
 
-Example: matches "^{}":
+Given
   void f() { ^{}(); }
+
+
+The matcher blockExpr() matches ^{}.
 
@@ -1371,17 +1581,23 @@

Node Matchers

Matches break statements.
 
 Given
+void foo() {
   while (true) { break; }
-breakStmt()
-  matches 'break'
+}
+
+The matcher breakStmt()
+matches break
 
Matcher<Stmt>cStyleCastExprMatcher<CStyleCastExpr>...
Matches a C-style cast expression.
 
-Example: Matches (int) 2.2f in
+Given
   int i = (int) 2.2f;
+
+The matcher cStyleCastExpr()
+matches (int) 2.2f.
 
@@ -1389,9 +1605,16 @@

Node Matchers

Matches call expressions.
 
 Example matches x.y() and y()
-  X x;
-  x.y();
-  y();
+  struct X { void foo(); };
+  void bar();
+  void foobar() {
+    X x;
+    x.foo();
+    bar();
+  }
+
+The matcher callExpr()
+matches x.foo() and bar();
 
@@ -1399,22 +1622,41 @@

Node Matchers

Matches case statements inside switch statements.
 
 Given
+void foo(int a) {
   switch(a) { case 42: break; default: break; }
-caseStmt()
-  matches 'case 42:'.
+}
+The matcher caseStmt()
+matches case 42: break.
 
Matcher<Stmt>castExprMatcher<CastExpr>...
Matches any cast nodes of Clang's AST.
 
-Example: castExpr() matches each of the following:
-  (int) 3;
-  const_cast<Expr *>(SubExpr);
-  char c = 0;
-but does not match
-  int i = (0);
-  int k = 0;
+Given
+  struct S {};
+  const S* s;
+  S* s2 = const_cast<S*>(s);
+
+  const int val = 0;
+  char val0 = 1;
+  char val1 = (char)2;
+  char val2 = static_cast<char>(3);
+  int* val3 = reinterpret_cast<int*>(4);
+  char val4 = char(5);
+
+
+The matcher castExpr()
+matches
+const_cast<S*>(s) and the implicit l- to r-value cast for s,
+the implicit cast to char for the initializer 1,
+the c-style cast (char)2 and it's implicit cast to char
+(part of the c-style cast) 2,
+static_cast<char>(3) and it's implicit cast to char
+(part of the static_cast) 3,
+reinterpret_cast<int*>(4),
+char(5) and it's implicit cast to char
+(part of the functional cast) 5.
 
@@ -1424,14 +1666,24 @@

Node Matchers

Not matching Hex-encoded chars (e.g. 0x1234, which is a IntegerLiteral), though. -Example matches 'a', L'a' +Given char ch = 'a'; wchar_t chw = L'a'; + + +The matcher characterLiteral() matches 'a' and +L'a'. Matcher<Stmt>chooseExprMatcher<ChooseExpr>...
Matches GNU __builtin_choose_expr.
+
+Given
+  void f() { (void)__builtin_choose_expr(1, 2, 3); }
+
+The matcher chooseExpr() matches
+__builtin_choose_expr(1, 2, 3).
 
@@ -1439,9 +1691,45 @@

Node Matchers

Matches co_await expressions.
 
 Given
-  co_await 1;
-coawaitExpr()
-  matches 'co_await 1'
+  namespace std {
+  template <typename T = void>
+  struct coroutine_handle {
+      static constexpr coroutine_handle from_address(void* addr) {
+        return {};
+      }
+  };
+
+  struct always_suspend {
+      bool await_ready() const noexcept;
+      bool await_resume() const noexcept;
+      template <typename T>
+      bool await_suspend(coroutine_handle<T>) const noexcept;
+  };
+
+  template <typename T>
+  struct coroutine_traits {
+      using promise_type = T::promise_type;
+  };
+  }  // namespace std
+
+  struct generator {
+      struct promise_type {
+          std::always_suspend yield_value(int&&);
+          std::always_suspend initial_suspend() const noexcept;
+          std::always_suspend final_suspend() const noexcept;
+          void return_void();
+          void unhandled_exception();
+          generator get_return_object();
+      };
+  };
+
+  std::always_suspend h();
+
+  generator g() { co_await h(); }
+
+The matcher
+coawaitExpr(has(callExpr(callee(functionDecl(hasName("h"))))))
+matches co_await h().
 
@@ -1449,35 +1737,48 @@

Node Matchers

Matches compound (i.e. non-scalar) literals
 
 Example match: {1}, (1, 2)
-  int array[4] = {1};
-  vector int myvec = (vector int)(1, 2);
+  struct vector { int x; int y; };
+  struct vector myvec = (struct vector){ 1, 2 };
+
+The matcher compoundLiteralExpr()
+matches (struct vector){ 1, 2 }.
 
Matcher<Stmt>compoundStmtMatcher<CompoundStmt>...
Matches compound statements.
 
-Example matches '{}' and '{{}}' in 'for (;;) {{}}'
-  for (;;) {{}}
+Given
+void foo() { for (;;) {{}} }
+
+The matcher compoundStmt() matches
+{ for (;;) {{}} }, {{}} and {}.
 
Matcher<Stmt>conditionalOperatorMatcher<ConditionalOperator>...
Matches conditional operator expressions.
 
-Example matches a ? b : c
-  (a ? b : c) + 42
+Given
+  int f(int a, int b, int c) {
+    return (a ? b : c) + 42;
+  }
+
+The matcher conditionalOperator() matches a ? b : c.
 
Matcher<Stmt>constantExprMatcher<ConstantExpr>...
Matches a constant expression wrapper.
 
-Example matches the constant in the case statement:
-    (matcher = constantExpr())
-  switch (a) {
-  case 37: break;
+Given
+  void f(int a) {
+    switch (a) {
+      case 37: break;
+    }
   }
+
+The matcher constantExpr() matches 37.
 
@@ -1485,14 +1786,26 @@

Node Matchers

Matches continue statements.
 
 Given
+void foo() {
   while (true) { continue; }
-continueStmt()
-  matches 'continue'
+}
+
+The matcher continueStmt()
+matches continue
 
Matcher<Stmt>convertVectorExprMatcher<ConvertVectorExpr>...
Matches builtin function __builtin_convertvector.
+
+Given
+  typedef double vector4double __attribute__((__vector_size__(32)));
+  typedef float  vector4float  __attribute__((__vector_size__(16)));
+  vector4float vf;
+  void f() { (void)__builtin_convertvector(vf, vector4double); }
+
+The matcher convertVectorExpr() matches
+__builtin_convertvector(vf, vector4double).
 
@@ -1500,19 +1813,85 @@

Node Matchers

Matches co_return statements.
 
 Given
-  while (true) { co_return; }
-coreturnStmt()
-  matches 'co_return'
+  namespace std {
+  template <typename T = void>
+  struct coroutine_handle {
+      static constexpr coroutine_handle from_address(void* addr) {
+        return {};
+      }
+  };
+
+  struct always_suspend {
+      bool await_ready() const noexcept;
+      bool await_resume() const noexcept;
+      template <typename T>
+      bool await_suspend(coroutine_handle<T>) const noexcept;
+  };
+
+  template <typename T>
+  struct coroutine_traits {
+      using promise_type = T::promise_type;
+  };
+  }  // namespace std
+
+  struct generator {
+      struct promise_type {
+          void return_value(int v);
+          std::always_suspend yield_value(int&&);
+          std::always_suspend initial_suspend() const noexcept;
+          std::always_suspend final_suspend() const noexcept;
+          void unhandled_exception();
+          generator get_return_object();
+      };
+  };
+
+  generator f() {
+      co_return 10;
+  }
+
+
+The matcher coreturnStmt(has(integerLiteral()))
+matches co_return 10
 
Matcher<Stmt>coroutineBodyStmtMatcher<CoroutineBodyStmt>...
Matches coroutine body statements.
 
-coroutineBodyStmt() matches the coroutine below
-  generator<int> gen() {
-    co_return;
-  }
+Given
+  namespace std {
+  template <typename T = void>
+  struct coroutine_handle {
+      static constexpr coroutine_handle from_address(void* addr) {
+        return {};
+      }
+  };
+
+  struct suspend_always {
+      bool await_ready() const noexcept;
+      bool await_resume() const noexcept;
+      template <typename T>
+      bool await_suspend(coroutine_handle<T>) const noexcept;
+  };
+
+  template <typename...>
+  struct coroutine_traits {
+      struct promise_type {
+          std::suspend_always initial_suspend() const noexcept;
+          std::suspend_always final_suspend() const noexcept;
+          void return_void();
+          void unhandled_exception();
+          coroutine_traits get_return_object();
+      };
+  };
+  }  // namespace std
+
+  void f() { while (true) { co_return; } }
+
+
+
+The matcher coroutineBodyStmt() matches
+{ while (true) { co_return; } }.
 
@@ -1520,27 +1899,77 @@

Node Matchers

Matches co_yield expressions.
 
 Given
-  co_yield 1;
-coyieldExpr()
-  matches 'co_yield 1'
+  namespace std {
+  template <typename T = void>
+  struct coroutine_handle {
+      static constexpr coroutine_handle from_address(void* addr) {
+        return {};
+      }
+  };
+
+  struct always_suspend {
+      bool await_ready() const noexcept;
+      bool await_resume() const noexcept;
+      template <typename T>
+      bool await_suspend(coroutine_handle<T>) const noexcept;
+  };
+
+  template <typename T>
+  struct coroutine_traits {
+      using promise_type = T::promise_type;
+  };
+  }  // namespace std
+
+  struct generator {
+      struct promise_type {
+          std::always_suspend yield_value(int&&);
+          std::always_suspend initial_suspend() const noexcept;
+          std::always_suspend final_suspend() const noexcept;
+          void return_void();
+          void unhandled_exception();
+          generator get_return_object();
+      };
+  };
+
+  generator f() {
+      while (true) {
+          co_yield 10;
+      }
+  }
+
+The matcher coyieldExpr()
+matches co_yield 10
 
Matcher<Stmt>cudaKernelCallExprMatcher<CUDAKernelCallExpr>...
Matches CUDA kernel call expression.
 
-Example matches,
-  kernel<<<i,j>>>();
+Given
+  __global__ void kernel() {}
+  void f() {
+    kernel<<<32,32>>>();
+  }
+
+The matcher cudaKernelCallExpr()
+matches kernel<<<i, k>>>()
 
Matcher<Stmt>cxxBindTemporaryExprMatcher<CXXBindTemporaryExpr>...
Matches nodes where temporaries are created.
 
-Example matches FunctionTakesString(GetStringByValue())
-    (matcher = cxxBindTemporaryExpr())
-  FunctionTakesString(GetStringByValue());
-  FunctionTakesStringByPointer(GetStringPointer());
+Given
+  struct S {
+    S() { }  // User defined constructor makes S non-POD.
+    ~S() { } // User defined destructor makes it non-trivial.
+  };
+  void test() {
+    const S &s_ref = S(); // Requires a CXXBindTemporaryExpr.
+  }
+
+The matcher cxxBindTemporaryExpr()
+matches the constructor call S().
 
@@ -1548,49 +1977,71 @@

Node Matchers

Matches bool literals.
 
 Example matches true
-  true
+  bool Flag = true;
+
+
+The matcher cxxBoolLiteral() matches true.
 
Matcher<Stmt>cxxCatchStmtMatcher<CXXCatchStmt>...
Matches catch statements.
 
+void foo() {
   try {} catch(int i) {}
-cxxCatchStmt()
-  matches 'catch(int i)'
+}
+
+The matcher cxxCatchStmt()
+matches catch(int i) {}
 
Matcher<Stmt>cxxConstCastExprMatcher<CXXConstCastExpr>...
Matches a const_cast expression.
 
-Example: Matches const_cast<int*>(&r) in
+Given
   int n = 42;
   const int &r(n);
   int* p = const_cast<int*>(&r);
+
+
+The matcher cxxConstCastExpr()
+matches const_cast<int*>(&r).
 
Matcher<Stmt>cxxConstructExprMatcher<CXXConstructExpr>...
Matches constructor call expressions (including implicit ones).
 
-Example matches string(ptr, n) and ptr within arguments of f
-    (matcher = cxxConstructExpr())
+Given
+  struct string {
+    string(const char*);
+    string(const char*s, int n);
+  };
   void f(const string &a, const string &b);
-  char *ptr;
-  int n;
-  f(string(ptr, n), ptr);
+  void foo(char *ptr, int n) {
+    f(string(ptr, n), ptr);
+  }
+
+
+The matcher cxxConstructExpr() matches string(ptr, n)
+and ptr within arguments of f .
 
Matcher<Stmt>cxxDefaultArgExprMatcher<CXXDefaultArgExpr>...
Matches the value of a default argument at the call site.
 
-Example matches the CXXDefaultArgExpr placeholder inserted for the
-    default value of the second parameter in the call expression f(42)
-    (matcher = cxxDefaultArgExpr())
+Given
   void f(int x, int y = 0);
-  f(42);
+  void g() {
+    f(42);
+  }
+
+
+The matcher callExpr(has(cxxDefaultArgExpr()))
+matches the CXXDefaultArgExpr placeholder inserted for the default value
+of the second parameter in the call expression f(42).
 
@@ -1598,9 +2049,17 @@

Node Matchers

Matches delete expressions.
 
 Given
-  delete X;
-cxxDeleteExpr()
-  matches 'delete X'.
+  void* operator new(decltype(sizeof(void*)));
+  void operator delete(void*);
+  struct X {};
+  void foo() {
+    auto* x = new X;
+    delete x;
+  }
+
+
+The matcher cxxDeleteExpr()
+matches delete x.
 
@@ -1610,7 +2069,8 @@

Node Matchers

Given template <class T> void f() { T t; t.g(); } -cxxDependentScopeMemberExpr() + +The matcher cxxDependentScopeMemberExpr() matches t.g @@ -1618,53 +2078,83 @@

Node Matchers

Matcher<Stmt>cxxDynamicCastExprMatcher<CXXDynamicCastExpr>...
Matches a dynamic_cast expression.
 
-Example:
-  cxxDynamicCastExpr()
-matches
-  dynamic_cast<D*>(&b);
-in
+Given
   struct B { virtual ~B() {} }; struct D : B {};
   B b;
   D* p = dynamic_cast<D*>(&b);
+
+
+The matcher cxxDynamicCastExpr()
+matches dynamic_cast<D*>(&b).
 
Matcher<Stmt>cxxFoldExprMatcher<CXXFoldExpr>...
Matches C++17 fold expressions.
 
-Example matches `(0 + ... + args)`:
+Given
   template <typename... Args>
   auto sum(Args... args) {
       return (0 + ... + args);
   }
+
+
+The matcher cxxFoldExpr() matches (0 + ... + args).
 
Matcher<Stmt>cxxForRangeStmtMatcher<CXXForRangeStmt>...
Matches range-based for statements.
 
-cxxForRangeStmt() matches 'for (auto a : i)'
-  int i[] =  {1, 2, 3}; for (auto a : i);
-  for(int j = 0; j < 5; ++j);
+Given
+  void foo() {
+    int i[] =  {1, 2, 3}; for (auto a : i);
+    for(int j = 0; j < 5; ++j);
+  }
+
+The matcher cxxForRangeStmt()
+matches for (auto a : i);
 
Matcher<Stmt>cxxFunctionalCastExprMatcher<CXXFunctionalCastExpr>...
Matches functional cast expressions
 
-Example: Matches Foo(bar);
-  Foo f = bar;
-  Foo g = (Foo) bar;
-  Foo h = Foo(bar);
+Given
+  struct Foo {
+    Foo(int x);
+  };
+
+  void foo(int bar) {
+    Foo f = bar;
+    Foo g = (Foo) bar;
+    Foo h = Foo(bar);
+  }
+
+
+The matcher cxxFunctionalCastExpr()
+matches Foo(bar).
 
Matcher<Stmt>cxxMemberCallExprMatcher<CXXMemberCallExpr>...
Matches member call expressions.
 
-Example matches x.y()
-  X x;
-  x.y();
+Given
+  struct X {
+    void y();
+    void m() { y(); }
+  };
+  void f();
+  void g() {
+    X x;
+    x.y();
+    f();
+  }
+
+
+The matcher cxxMemberCallExpr() matches x.y() and
+y(), but not f().
 
@@ -1672,9 +2162,15 @@

Node Matchers

Matches new expressions.
 
 Given
-  new X;
-cxxNewExpr()
-  matches 'new X'.
+  void* operator new(decltype(sizeof(void*)));
+  struct X {};
+  void foo() {
+    auto* x = new X;
+  }
+
+
+The matcher cxxNewExpr()
+matches new X.
 
@@ -1687,14 +2183,24 @@

Node Matchers

bool c() noexcept(false); bool d() noexcept(noexcept(a())); bool e = noexcept(b()) || noexcept(c()); -cxxNoexceptExpr() - matches `noexcept(a())`, `noexcept(b())` and `noexcept(c())`. - doesn't match the noexcept specifier in the declarations a, b, c or d. + +The matcher cxxNoexceptExpr() +matches noexcept(a()), noexcept(b()) and +noexcept(c()), but does not match the noexcept specifier in the +declarations a, b, c or d. Matcher<Stmt>cxxNullPtrLiteralExprMatcher<CXXNullPtrLiteralExpr>...
Matches nullptr literal.
+
+Given
+  int a = 0;
+  int* b = 0;
+  int *c = nullptr;
+
+
+The matcher cxxNullPtrLiteralExpr() matches nullptr.
 
@@ -1706,11 +2212,16 @@

Node Matchers

Currently it does not match operators such as new delete. FIXME: figure out why these do not match? -Example matches both operator<<((o << b), c) and operator<<(o, b) - (matcher = cxxOperatorCallExpr()) +Given + struct ostream; ostream &operator<< (ostream &out, int i) { }; - ostream &o; int b = 1, c = 1; - o << b << c; + void f(ostream& o, int b, int c) { + o << b << c; + } + + +The matcher cxxOperatorCallExpr() matches o << b << c +and o << b. See also the binaryOperation() matcher for more-general matching of binary uses of this AST node. @@ -1725,6 +2236,10 @@

Node Matchers

Example matches reinterpret_cast<char*>(&p) in void* p = reinterpret_cast<char*>(&p); + + +The matcher cxxReinterpretCastExpr() +matches reinterpret_cast<char*>(&p). @@ -1732,16 +2247,20 @@

Node Matchers

Matches rewritten binary operators
 
 Example matches use of "<":
-  #include <compare>
   struct HasSpaceshipMem {
     int a;
-    constexpr auto operator<=>(const HasSpaceshipMem&) const = default;
+    constexpr bool operator==(const HasSpaceshipMem&) const = default;
   };
   void compare() {
     HasSpaceshipMem hs1, hs2;
-    if (hs1 < hs2)
+    if (hs1 != hs2)
         return;
   }
+
+
+The matcher cxxRewrittenBinaryOperator() matches
+hs1 != hs2.
+
 See also the binaryOperation() matcher for more-general matching
 of this AST node.
 
@@ -1753,12 +2272,12 @@

Node Matchers

See also: hasDestinationType See also: reinterpretCast -Example: - cxxStaticCastExpr() -matches - static_cast<long>(8) -in +Given long eight(static_cast<long>(8)); + + +The matcher cxxStaticCastExpr() +matches static_cast<long>(8). @@ -1766,69 +2285,110 @@

Node Matchers

Matches C++ initializer list expressions.
 
 Given
-  std::vector<int> a({ 1, 2, 3 });
-  std::vector<int> b = { 4, 5 };
+  namespace std {
+    template <typename T>
+    class initializer_list {
+      const T* begin;
+      const T* end;
+    };
+  }
+  template <typename T> class vector {
+    public: vector(std::initializer_list<T>) {}
+  };
+
+  vector<int> a({ 1, 2, 3 });
+  vector<int> b = { 4, 5 };
   int c[] = { 6, 7 };
-  std::pair<int, int> d = { 8, 9 };
-cxxStdInitializerListExpr()
-  matches "{ 1, 2, 3 }" and "{ 4, 5 }"
+  struct pair { int x; int y; };
+  pair d = { 8, 9 };
+
+The matcher cxxStdInitializerListExpr()
+matches { 1, 2, 3 } and { 4, 5 }.
 
Matcher<Stmt>cxxTemporaryObjectExprMatcher<CXXTemporaryObjectExpr>...
Matches functional cast expressions having N != 1 arguments
 
-Example: Matches Foo(bar, bar)
-  Foo h = Foo(bar, bar);
+Given
+  struct Foo {
+    Foo(int x, int y);
+  };
+
+  void foo(int bar) {
+    Foo h = Foo(bar, bar);
+  }
+
+
+The matcher cxxTemporaryObjectExpr()
+matches Foo(bar, bar).
 
-Matcher<Stmt>cxxThisExprMatcher<CXXThisExpr>... -
Matches implicit and explicit this expressions.
+Matcher<Stmt>cxxThisExprMatcher<CXXThisExpr>...
+
Matches implicit and explicit this expressions.
+
+Given
+  struct foo {
+    int i;
+    int f() { return i; }
+    int g() { return this->i; }
+  };
+
 
-Example matches the implicit this expression in "return i".
-    (matcher = cxxThisExpr())
-struct foo {
-  int i;
-  int f() { return i; }
-};
+The matcher cxxThisExpr()
+matches this of this->i and the implicit this expression
+of i.
 
Matcher<Stmt>cxxThrowExprMatcher<CXXThrowExpr>...
Matches throw expressions.
 
+void foo() {
   try { throw 5; } catch(int i) {}
-cxxThrowExpr()
-  matches 'throw 5'
+}
+
+The matcher cxxThrowExpr()
+matches throw 5
 
Matcher<Stmt>cxxTryStmtMatcher<CXXTryStmt>...
Matches try statements.
 
+void foo() {
   try {} catch(int i) {}
-cxxTryStmt()
-  matches 'try {}'
+}
+
+The matcher cxxTryStmt()
+matches try {} catch(int i) {}
 
Matcher<Stmt>cxxUnresolvedConstructExprMatcher<CXXUnresolvedConstructExpr>...
Matches unresolved constructor call expressions.
 
-Example matches T(t) in return statement of f
-    (matcher = cxxUnresolvedConstructExpr())
+Given
   template <typename T>
   void f(const T& t) { return T(t); }
+
+
+The matcher cxxUnresolvedConstructExpr() matches
+T(t).
 
Matcher<Stmt>declRefExprMatcher<DeclRefExpr>...
Matches expressions that refer to declarations.
 
-Example matches x in if (x)
-  bool x;
-  if (x) {}
+Given
+  void f(bool x) {
+    if (x) {}
+  }
+
+
+The matcher declRefExpr() matches x.
 
@@ -1836,9 +2396,11 @@

Node Matchers

Matches declaration statements.
 
 Given
-  int a;
-declStmt()
-  matches 'int a'.
+  void foo() {
+    int a;
+  }
+The matcher declStmt()
+matches int a;.
 
@@ -1846,22 +2408,75 @@

Node Matchers

Matches default statements inside switch statements.
 
 Given
+void foo(int a) {
   switch(a) { case 42: break; default: break; }
-defaultStmt()
-  matches 'default:'.
+}
+The matcher defaultStmt()
+matches default: break.
 
Matcher<Stmt>dependentCoawaitExprMatcher<DependentCoawaitExpr>...
Matches co_await expressions where the type of the promise is dependent
+
+Given
+  namespace std {
+  template <typename T = void>
+  struct coroutine_handle {
+      static constexpr coroutine_handle from_address(void* addr) {
+        return {};
+      }
+  };
+
+  struct always_suspend {
+      bool await_ready() const noexcept;
+      bool await_resume() const noexcept;
+      template <typename T>
+      bool await_suspend(coroutine_handle<T>) const noexcept;
+  };
+
+  template <typename T>
+  struct coroutine_traits {
+      using promise_type = T::promise_type;
+  };
+  }  // namespace std
+
+  template <typename T>
+  struct generator {
+      struct promise_type {
+          std::always_suspend yield_value(int&&);
+          std::always_suspend initial_suspend() const noexcept;
+          std::always_suspend final_suspend() const noexcept;
+          void return_void();
+          void unhandled_exception();
+          generator get_return_object();
+      };
+  };
+
+  template <typename T>
+  std::always_suspend h();
+
+  template <>
+  std::always_suspend h<void>();
+
+  template<typename T>
+  generator<T> g() { co_await h<T>(); }
+
+The matcher dependentCoawaitExpr()
+matches co_await h<T>().
 
Matcher<Stmt>designatedInitExprMatcher<DesignatedInitExpr>...
Matches C99 designated initializer expressions [C99 6.7.8].
 
-Example: Matches { [2].y = 1.0, [0].x = 1.0 }
-  point ptarray[10] = { [2].y = 1.0, [0].x = 1.0 };
+Example: Given
+  struct point2 { double x; double y; };
+  struct point2 ptarray[10] = { [0].x = 1.0 };
+  struct point2 pt = { .x = 2.0 };
+
+The matcher designatedInitExpr()
+matches [0].x = 1.0 and .x = 2.0.
 
@@ -1869,9 +2484,12 @@

Node Matchers

Matches do statements.
 
 Given
+void foo() {
   do {} while (true);
-doStmt()
-  matches 'do {} while(true)'
+}
+
+The matcher doStmt()
+matches do {} while (true)
 
@@ -1889,18 +2507,36 @@

Node Matchers

See also: hasDestinationType. -Example: matches all five of the casts in - int((int)(reinterpret_cast<int>(static_cast<int>(const_cast<int>(42))))) -but does not match the implicit conversion in - long ell = 42; + struct S {}; + const S* s; + S* s2 = const_cast<S*>(s); + + const int val = 0; + char val0 = val; + char val1 = (char)val; + char val2 = static_cast<char>(val); + int* val3 = reinterpret_cast<int*>(val); + char val4 = char(val); + + +The matcher explicitCastExpr() +matches (char)val, static_cast<char>(val), +reinterpret_cast<int*>(val), const_cast<S*>(s) +and char(val), but not the initialization of val0 with +val.
Matcher<Stmt>exprMatcher<Expr>...
Matches expressions.
 
-Example matches x()
-  void f() { x(); }
+Given
+  int f(int x, int y) { return x + y; }
+
+The matcher expr() matches x + y once,
+x twice and y twice, matching the
+DeclRefExpr , and the ImplicitCastExpr that does an l- to r-value
+cast.
 
@@ -1909,12 +2545,33 @@

Node Matchers

of the sub-expression's evaluation. Example matches std::string() - const std::string str = std::string(); + struct A { ~A(); }; + void f(A); + void g(A&); + void h() { + A a = A{}; + f(A{}); + f(a); + g(a); + } + + +The matcher exprWithCleanups() matches A{}, +f(A{}) and f(a), +but does not match passing g(a). Matcher<Stmt>fixedPointLiteralMatcher<FixedPointLiteral>...
Matches fixed point literals
+
+Given
+  void f() {
+    0.0k;
+  }
+
+
+The matcher fixedPointLiteral() matches 0.0k.
 
@@ -1922,27 +2579,62 @@

Node Matchers

Matches float literals of all sizes / encodings, e.g.
 1.0, 1.0f, 1.0L and 1e10.
 
-Does not match implicit conversions such as
-  float a = 10;
+Given
+  int a = 1.0;
+  int b = 1.0F;
+  int c = 1.0L;
+  int d = 1e10;
+  int e = 1;
+
+The matcher floatLiteral() matches
+1.0, 1.0F, 1.0L and 1e10, but does not match
+1.
 
Matcher<Stmt>forStmtMatcher<ForStmt>...
Matches for statements.
 
-Example matches 'for (;;) {}'
-  for (;;) {}
-  int i[] =  {1, 2, 3}; for (auto a : i);
+Given
+  void foo() {
+    for (;;) {}
+    int i[] =  {1, 2, 3}; for (auto a : i);
+  }
+
+
+The matcher forStmt() matches for (;;) {},
+but not for (auto a : i);.
 
Matcher<Stmt>genericSelectionExprMatcher<GenericSelectionExpr>...
Matches C11 _Generic expression.
+
+Given
+  double fdouble(double);
+  float ffloat(float);
+  #define GENERIC_MACRO(X) _Generic((X), double: fdouble, float: ffloat)(X)
+
+  void f() {
+      GENERIC_MACRO(0.0);
+      GENERIC_MACRO(0.0F);
+  }
+
+
+The matcher genericSelectionExpr() matches
+the generic selection expression that is expanded in
+GENERIC_MACRO(0.0) and GENERIC_MACRO(0.0F).
 
Matcher<Stmt>gnuNullExprMatcher<GNUNullExpr>...
Matches GNU __null expression.
+
+Given
+  auto val = __null;
+
+
+The matcher gnuNullExpr() matches __null.
 
@@ -1950,24 +2642,39 @@

Node Matchers

Matches goto statements.
 
 Given
+void bar();
+void foo() {
   goto FOO;
   FOO: bar();
-gotoStmt()
-  matches 'goto FOO'
+}
+The matcher gotoStmt()
+matches goto FOO
 
Matcher<Stmt>ifStmtMatcher<IfStmt>...
Matches if statements.
 
-Example matches 'if (x) {}'
-  if (x) {}
+Given
+  void foo(int x) {
+    if (x) {}
+  }
+
+The matcher ifStmt() matches if (x) {}.
 
Matcher<Stmt>imaginaryLiteralMatcher<ImaginaryLiteral>...
Matches imaginary literals, which are based on integer and floating
 point literals e.g.: 1i, 1.0i
+
+Given
+  auto a = 1i;
+  auto b = 1.0i;
+
+
+The matcher imaginaryLiteral() matches 1i and
+1.0i.
 
@@ -1976,6 +2683,17 @@

Node Matchers

This matches many different places, including function call return value eliding, as well as any type conversions. + +void f(int); +void g(int val1, int val2) { + unsigned int a = val1; + f(val2); +} + +The matcher implicitCastExpr() +matches val1 for the implicit cast from an l- to an r-value +and for the cast to int}, f for the function pointer +decay, and val2 for the cast from an l- to an r-value. @@ -1983,9 +2701,11 @@

Node Matchers

Matches implicit initializers of init list expressions.
 
 Given
-  point ptarray[10] = { [2].y = 1.0, [2].x = 2.0, [0].x = 1.0 };
-implicitValueInitExpr()
-  matches "[0].y" (implicitly)
+  struct point { double x; double y; };
+  struct point pt = { .x = 42.0 };
+The matcher
+initListExpr(has(implicitValueInitExpr().bind("implicit")))
+matches { .x = 42.0 }.
 
@@ -1995,9 +2715,9 @@

Node Matchers

Given int a[] = { 1, 2 }; struct B { int x, y; }; - B b = { 5, 6 }; -initListExpr() - matches "{ 1, 2 }" and "{ 5, 6 }" + struct B b = { 5, 6 }; +The matcher initListExpr() +matches { 1, 2 } and { 5, 6 } @@ -2006,6 +2726,17 @@

Node Matchers

1, 1L, 0x1 and 1U. Does not match character-encoded integers such as L'a'. + +Given + int a = 1; + int b = 1L; + int c = 0x1; + int d = 1U; + int e = 1.0; + +The matcher integerLiteral() matches +1, 1L, 0x1 and 1U, but does not match +1.0. @@ -2013,18 +2744,26 @@

Node Matchers

Matches label statements.
 
 Given
+void bar();
+void foo() {
   goto FOO;
   FOO: bar();
-labelStmt()
-  matches 'FOO:'
+}
+The matcher labelStmt()
+matches FOO: bar()
 
Matcher<Stmt>lambdaExprMatcher<LambdaExpr>...
Matches lambda expressions.
 
-Example matches [&](){return 5;}
-  [&](){return 5;}
+Given
+  void f() {
+    []() { return 5; };
+  }
+
+
+The matcher lambdaExpr() matches []() { return 5; }.
 
@@ -2035,12 +2774,17 @@

Node Matchers

struct T {void func();}; T f(); void g(T); -materializeTemporaryExpr() matches 'f()' in these statements - T u(f()); - g(f()); - f().func(); -but does not match - f(); + void foo() { + T u(f()); + g(f()); + f().func(); + f(); // does not match + } + +The matcher materializeTemporaryExpr() matches +f() three times before C++17 and it +matches f() time with C++17 and later, but +it does not match the f() in the last line in any version. @@ -2052,17 +2796,20 @@

Node Matchers

void x() { this->x(); x(); Y y; y.x(); a; this->b; Y::b; } int a; static int b; }; -memberExpr() - matches this->x, x, y.x, a, this->b + +The matcher memberExpr() +matches this->x, x, y.x, a, this->b. Matcher<Stmt>nullStmtMatcher<NullStmt>...
Matches null statements.
 
+void foo() {
   foo();;
-nullStmt()
-  matches the second ';'
+}
+The matcher nullStmt()
+matches the second ;
 
@@ -2072,6 +2819,7 @@

Node Matchers

Example matches @catch @try {} @catch (...) {} + @@ -2081,19 +2829,23 @@

Node Matchers

Example matches @finally @try {} @finally {} + Matcher<Stmt>objcIvarRefExprMatcher<ObjCIvarRefExpr>...
Matches a reference to an ObjCIvar.
 
-Example: matches "a" in "init" method:
+Given
 @implementation A {
   NSString *a;
 }
 - (void) init {
   a = @"hello";
 }
+
+
+The matcher objcIvarRefExpr() matches a.
 
@@ -2105,6 +2857,10 @@

Node Matchers

"initWithString" instance method on the object returned from NSString's "alloc". This matcher should match both message sends. [[NSString alloc] initWithString:@"Hello"] + + +The matcher objcMessageExpr() matches +[[NSString alloc] initWithString:@"Hello"] @@ -2113,6 +2869,7 @@

Node Matchers

Example matches @"abcd" NSString *s = @"abcd"; + @@ -2120,6 +2877,7 @@

Node Matchers

Matches Objective-C statements.
 
 Example matches @throw obj;
+
 
@@ -2129,6 +2887,7 @@

Node Matchers

Example matches @try @try {} @catch (...) {} + @@ -2136,13 +2895,19 @@

Node Matchers

Matches any ``#pragma omp`` executable directive.
 
 Given
+  void foo() {
+    #pragma omp parallel
+      {}
+    #pragma omp parallel default(none)
+      {
+        #pragma omp taskyield
+      }
+  }
 
-  #pragma omp parallel
-  #pragma omp parallel default(none)
-  #pragma omp taskyield
-
-``ompExecutableDirective()`` matches ``omp parallel``,
-``omp parallel default(none)`` and ``omp taskyield``.
+The matcher ompExecutableDirective()
+matches #pragma omp parallel,
+#pragma omp parallel default(none)
+and #pragma omp taskyield.
 
@@ -2151,17 +2916,27 @@

Node Matchers

to reference another expressions and can be met in BinaryConditionalOperators, for example. -Example matches 'a' - (a ?: c) + 42; +Given + int f(int a, int b) { + return (a ?: b) + 42; + } + + +The matcher opaqueValueExpr() matches a twice, +once for the check and once for the expression of the true path. Matcher<Stmt>parenExprMatcher<ParenExpr>...
Matches parentheses used in expressions.
 
-Example matches (foo() + 1)
+Given
   int foo() { return 1; }
-  int a = (foo() + 1);
+  int bar() {
+    int a = (foo() + 1);
+  }
+
+The matcher parenExpr() matches (foo() + 1).
 
@@ -2177,8 +2952,12 @@

Node Matchers

int a = 0, b = 1; int i = (a, b); } }; -parenListExpr() matches "*this" but NOT matches (a, b) because (a, b) -has a predefined type and is a ParenExpr, not a ParenListExpr. + +The matcher parenListExpr() +matches (*this), +but does not match (a, b) +because (a, b) has a predefined type and is a ParenExpr, not a +ParenListExpr. @@ -2186,7 +2965,12 @@

Node Matchers

Matches predefined identifier expressions [C99 6.4.2.2].
 
 Example: Matches __func__
-  printf("%s", __func__);
+  void f() {
+    const char* func_name = __func__;
+  }
+
+The matcher predefinedExpr()
+matches __func__.
 
@@ -2194,9 +2978,11 @@

Node Matchers

Matches return statements.
 
 Given
+int foo() {
   return 1;
-returnStmt()
-  matches 'return 1'
+}
+The matcher returnStmt()
+matches return 1
 
@@ -2204,26 +2990,35 @@

Node Matchers

Matches statements.
 
 Given
-  { ++a; }
-stmt()
-  matches both the compound statement '{ ++a; }' and '++a'.
+  void foo(int a) { { ++a; } }
+The matcher stmt()
+matches the function body itself { { ++a; } }, the compound
+statement { ++a; }, the expression ++a and a.
 
Matcher<Stmt>stmtExprMatcher<StmtExpr>...
Matches statement expression (GNU extension).
 
-Example match: ({ int X = 4; X; })
-  int C = ({ int X = 4; X; });
+Given
+  void f() {
+    int C = ({ int X = 4; X; });
+  }
+
+The matcher stmtExpr() matches ({ int X = 4; X; }).
 
Matcher<Stmt>stringLiteralMatcher<StringLiteral>...
Matches string literals (also matches wide string literals).
 
-Example matches "abcd", L"abcd"
+Given
   char *s = "abcd";
   wchar_t *ws = L"abcd";
+
+
+The matcher stringLiteral() matches "abcd" and
+L"abcd".
 
@@ -2234,8 +3029,9 @@

Node Matchers

template <int N> struct A { static const int n = N; }; struct B : public A<42> {}; -substNonTypeTemplateParmExpr() - matches "N" in the right-hand side of "static const int n = N;" + +The matcher substNonTypeTemplateParmExpr() +matches N in the right-hand side of "static const int n = N;" @@ -2243,9 +3039,11 @@

Node Matchers

Matches case and default statements inside switch statements.
 
 Given
+void foo(int a) {
   switch(a) { case 42: break; default: break; }
-switchCase()
-  matches 'case 42:' and 'default:'.
+}
+The matcher switchCase()
+matches case 42: break and default: break
 
@@ -2253,9 +3051,11 @@

Node Matchers

Matches switch statements.
 
 Given
+void foo(int a) {
   switch(a) { case 42: break; default: break; }
-switchStmt()
-  matches 'switch(a)'.
+}
+The matcher switchStmt()
+matches switch(a) { case 42: break; default: break; }.
 
@@ -2263,10 +3063,11 @@

Node Matchers

Matches sizeof (C99), alignof (C++11) and vec_step (OpenCL)
 
 Given
-  Foo x = bar;
+  int x = 42;
   int y = sizeof(x) + alignof(x);
-unaryExprOrTypeTraitExpr()
-  matches sizeof(x) and alignof(x)
+
+The matcher unaryExprOrTypeTraitExpr()
+matches sizeof(x) and alignof(x)
 
@@ -2274,7 +3075,12 @@

Node Matchers

Matches unary operator expressions.
 
 Example matches !a
-  !a || b
+  void foo(bool a, bool b) {
+    !a || b;
+  }
+
+
+The matcher unaryOperator() matches !a.
 
@@ -2289,8 +3095,10 @@

Node Matchers

void bar() { foo<T>(); } -unresolvedLookupExpr() - matches foo<T>() + +The matcher unresolvedLookupExpr() +matches foo<T>. + Matcher<Stmt>unresolvedMemberExprMatcher<UnresolvedMemberExpr>... @@ -2302,8 +3110,9 @@

Node Matchers

void g(); }; template <class T> void h() { X x; x.f<T>(); x.g(); } -unresolvedMemberExpr() - matches x.f<T> + +The matcher unresolvedMemberExpr() +matches x.f<T> @@ -2311,6 +3120,12 @@

Node Matchers

Matches user defined literal operator call.
 
 Example match: "foo"_suffix
+Given
+  float operator ""_foo(long double);
+  float a = 1234.5_foo;
+
+
+The matcher userDefinedLiteral() matches 1234.5_foo.
 
@@ -2318,9 +3133,12 @@

Node Matchers

Matches while statements.
 
 Given
+void foo() {
   while (true) {}
-whileStmt()
-  matches 'while (true) {}'.
+}
+
+The matcher whileStmt()
+matches while (true) {}.
 
@@ -2330,8 +3148,9 @@

Node Matchers

Given template <typename T> struct C {}; C<int> c; -templateArgumentLoc() - matches 'int' in C<int>. + +The matcher templateArgumentLoc() +matches int in C<int>. @@ -2341,8 +3160,10 @@

Node Matchers

Given template <typename T> struct C {}; C<int> c; -templateArgument() - matches 'int' in C<int>. + +The matcher +templateSpecializationType(hasAnyTemplateArgument(templateArgument())) +matches C<int>. @@ -2350,10 +3171,14 @@

Node Matchers

Matches template name.
 
 Given
-  template <typename T> class X { };
-  X<int> xi;
-templateName()
-  matches 'X' in X<int>.
+  template<template <typename> class S> class X {};
+  template<typename T> class Y {};
+  X<Y> xi;
+
+The matcher
+classTemplateSpecializationDecl(hasAnyTemplateArgument(
+              refersToTemplate(templateName())))
+matches the specialization class X<Y>
 
@@ -2363,8 +3188,8 @@

Node Matchers

Given struct s {}; struct s ss; -elaboratedTypeLoc() - matches the `TypeLoc` of the variable declaration of `ss`. +The matcher elaboratedTypeLoc() +matches the type struct s of ss. @@ -2373,8 +3198,8 @@

Node Matchers

Given int* x; -pointerTypeLoc() - matches `int*`. +The matcher pointerTypeLoc() + matches int*. @@ -2383,8 +3208,11 @@

Node Matchers

Given const int x = 0; -qualifiedTypeLoc() - matches `const int`. + +The matcher qualifiedTypeLoc() +matches the type of the variable declaration x . However, the +current implementation of QualifiedTypeLoc does not store the source +locations for the qualifiers of the type int. @@ -2395,8 +3223,10 @@

Node Matchers

int x = 3; int& l = x; int&& r = 3; -referenceTypeLoc() - matches `int&` and `int&&`. + + +The matcher referenceTypeLoc() + matches int& and int&&. @@ -2406,13 +3236,25 @@

Node Matchers

Given template <typename T> class C {}; C<char> var; -varDecl(hasTypeLoc(templateSpecializationTypeLoc(typeLoc()))) - matches `C<char> var`. + +The matcher +varDecl(hasTypeLoc(elaboratedTypeLoc(hasNamedTypeLoc( +templateSpecializationTypeLoc(typeLoc()))))) +matches C<char> var. Matcher<TypeLoc>typeLocMatcher<TypeLoc>...
Matches TypeLocs in the clang AST.
+
+That is, information about a type and where it was written.
+
+  void foo(int val);
+
+The matcher declaratorDecl(hasTypeLoc(typeLoc().bind("type")))
+matches void foo(int val) and int val, with
+typeLoc() matching void and
+int respectively.
 
@@ -2423,8 +3265,9 @@

Node Matchers

int a[] = { 2, 3 }; int b[4]; void f() { int c[a[0]]; } -arrayType() - matches "int a[]", "int b[4]" and "int c[a[0]]"; +The matcher arrayType() +int[4], int[a[0]] and +int[]; @@ -2433,20 +3276,25 @@

Node Matchers

Given _Atomic(int) i; -atomicType() - matches "_Atomic(int) i" +The matcher atomicType() +_Atomic(int) Matcher<Type>autoTypeMatcher<AutoType>...
Matches types nodes representing C++11 auto types.
 
-Given:
-  auto n = 4;
-  int v[] = { 2, 3 }
-  for (auto i : v) { }
-autoType()
-  matches "auto n" and "auto i"
+Given
+  void foo() {
+    auto n = 4;
+    int v[] = { 2, 3 };
+    for (auto i : v) { };
+  }
+
+The matcher autoType()
+matches the auto of n and i ,
+as well as the auto types for the implicitly generated code of the range-for
+loop (for the range, the begin iterator and the end iterator).
 
@@ -2462,13 +3310,12 @@

Node Matchers

Matches builtin Types.
 
 Given
-  struct A {};
-  A a;
+  enum E { Ok };
+  enum E e;
   int b;
   float c;
-  bool d;
-builtinType()
-  matches "int b", "float c" and "bool d"
+The matcher varDecl(hasType(builtinType()))
+matches int b and float c.
 
@@ -2477,8 +3324,8 @@

Node Matchers

Given _Complex float f; -complexType() - matches "_Complex float f" +The matcher complexType() +_Complex float @@ -2486,37 +3333,38 @@

Node Matchers

Matches C arrays with a specified constant size.
 
 Given
-  void() {
+  void foo() {
     int a[2];
     int b[] = { 2, 3 };
     int c[b[0]];
   }
-constantArrayType()
-  matches "int a[2]"
+The matcher constantArrayType()
+int[2]
 
Matcher<Type>decayedTypeMatcher<DecayedType>...
Matches decayed type
-Example matches i[] in declaration of f.
-    (matcher = valueDecl(hasType(decayedType(hasDecayedType(pointerType())))))
-Example matches i[1].
-    (matcher = expr(hasType(decayedType(hasDecayedType(pointerType())))))
   void f(int i[]) {
     i[1] = 0;
   }
-
+The matcher +valueDecl(hasType(decayedType(hasDecayedType(pointerType())))) +matches int i[] in declaration of The matcher +expr(hasType(decayedType(hasDecayedType(pointerType())))) +matches i in Matcher<Type>decltypeTypeMatcher<DecltypeType>...
Matches types nodes representing C++11 decltype(<expr>) types.
 
-Given:
+Given
   short i = 1;
   int j = 42;
   decltype(i + j) result = i + j;
-decltypeType()
-  matches "decltype(i + j)"
+
+The matcher decltypeType()
+decltype(i + j)
 
@@ -2529,8 +3377,9 @@

Node Matchers

class C { public: C(T); }; C c(123); -deducedTemplateSpecializationType() matches the type in the declaration -of the variable c. + +The matcher deducedTemplateSpecializationType() matches the type +C of the declaration of the variable c. @@ -2542,8 +3391,9 @@

Node Matchers

class array { T data[Size]; }; -dependentSizedArrayType() - matches "T data[Size]" + +The matcher dependentSizedArrayType() +T[Size] @@ -2556,8 +3406,9 @@

Node Matchers

class vector { typedef T __attribute__((ext_vector_type(Size))) type; }; -dependentSizedExtVectorType() - matches "T __attribute__((ext_vector_type(Size)))" + +The matcher dependentSizedExtVectorType() +T __attribute__((ext_vector_type(Size))) @@ -2573,11 +3424,17 @@

Node Matchers

} class C {}; - class C c; + C c; N::M::D d; -elaboratedType() matches the type of the variable declarations of both -c and d. + +The matcher elaboratedType() matches the type +C three times. Once for the type of the +variable c, once for the type of the class definition and once for the +type in the injected class name. For D}, it matches +N::M::D of variable d and its class definition and +injected class name +D one time respectively. @@ -2591,8 +3448,10 @@

Node Matchers

C c; S s; -enumType() matches the type of the variable declarations of both c and -s. + +The matcher enumType() matches the type +enum C of c , +and the type enum S of s . @@ -2602,9 +3461,11 @@

Node Matchers

Given int (*f)(int); void g(); -functionProtoType() - matches "int (*f)(int)" and the type of "g" in C++ mode. - In C mode, "g" is not matched because it does not contain a prototype. +The matcher functionProtoType() +matches the type int (int) of 'f' and the type +void (void) of 'g' in C++ mode. +In C, the type void () of 'g' is not +matched because it does not contain a prototype. @@ -2614,8 +3475,12 @@

Node Matchers

Given int (*f)(int); void g(); -functionType() - matches "int (*f)(int)" and the type of "g". +The matcher functionType() +int (int) and the type of +void (void) in C++ and in C23 and +later. Before C23, the function type for f will be matched the same way, +but the function type for g will match +void (). @@ -2626,27 +3491,30 @@

Node Matchers

int a[] = { 2, 3 }; int b[42]; void f(int c[]) { int d[a[0]]; }; -incompleteArrayType() - matches "int a[]" and "int c[]" +The matcher incompleteArrayType() +int[] and int[] Matcher<Type>injectedClassNameTypeMatcher<InjectedClassNameType>...
Matches injected class name types.
 
-Example matches S s, but not S<T> s.
-    (matcher = parmVarDecl(hasType(injectedClassNameType())))
+Given
   template <typename T> struct S {
     void f(S s);
     void g(S<T> s);
   };
+
+The matcher
+parmVarDecl(hasType(elaboratedType(namesType(injectedClassNameType()))))
+matches S s, but not s}
 
Matcher<Type>lValueReferenceTypeMatcher<LValueReferenceType>...
Matches lvalue reference types.
 
-Given:
+Given
   int *a;
   int &b = *a;
   int &&c = 1;
@@ -2655,8 +3523,11 @@ 

Node Matchers

auto &&f = 2; int g = 5; -lValueReferenceType() matches the types of b, d, and e. e is -matched since the type is deduced as int& by reference collapsing rules. + +The matcher lValueReferenceType() matches the type +int & of b and the type auto & +of d. +FIXME: figure out why auto changechange matches twice
@@ -2667,18 +3538,23 @@

Node Matchers

#define CDECL __attribute__((cdecl)) typedef void (CDECL *X)(); typedef void (__attribute__((cdecl)) *Y)(); -macroQualifiedType() - matches the type of the typedef declaration of X but not Y. +The matcher macroQualifiedType() +matches the type CDECL void +(void) of the typedef declaration of X , unless when in C98-C17, there +CDECL void (), +but it does not match the type +__attribute((cdecl)) void () of Y . Matcher<Type>memberPointerTypeMatcher<MemberPointerType>...
Matches member pointer types.
 Given
-  struct A { int i; }
-  A::* ptr = A::i;
-memberPointerType()
-  matches "A::* ptr"
+  struct A { int i; };
+  int A::* ptr = &A::i;
+
+The matcher memberPointerType()
+matches int struct A::*.
 
@@ -2692,8 +3568,10 @@

Node Matchers

@interface Foo @end Foo *f; -pointerType() - matches "Foo *f", but does not match "int *a". + +The matcher pointerType() +matches Foo *, but does not match +int *. @@ -2704,8 +3582,9 @@

Node Matchers

int (*ptr_to_array)[4]; int *array_of_ptrs[4]; -varDecl(hasType(pointsTo(parenType()))) matches ptr_to_array but not -array_of_ptrs. +The matcher varDecl(hasType(pointsTo(parenType()))) + matches ptr_to_array but not + array_of_ptrs. @@ -2714,22 +3593,28 @@

Node Matchers

types. Given - int *a; - int &b = *a; - int c = 5; + typedef int* int_ptr; + void foo(char *str, + int val, + int *val_ptr, + int_ptr not_a_ptr, + int_ptr *ptr); + +The matcher parmVarDecl(hasType(pointerType())) +matches char *str, int *val_ptr and +int_ptr *ptr. @interface Foo @end Foo *f; -pointerType() - matches "int *a", but does not match "Foo *f". + Matcher<Type>rValueReferenceTypeMatcher<RValueReferenceType>...
Matches rvalue reference types.
 
-Given:
+Given
   int *a;
   int &b = *a;
   int &&c = 1;
@@ -2738,8 +3623,10 @@ 

Node Matchers

auto &&f = 2; int g = 5; -rValueReferenceType() matches the types of c and f. e is not -matched as it is deduced to int& by reference collapsing rules. + +The matcher rValueReferenceType() matches the type +int && of c and the type +auto && of f.
@@ -2753,8 +3640,14 @@

Node Matchers

C c; S s; -recordType() matches the type of the variable declarations of both c -and s. + +The matcher recordType() matches the type +class C of the variable declaration of c and +matches the type struct S of the variable +declaration of s. +Both of these types are matched three times, once for the type of the +variable, once for the definition of the class, and once for the type of the +injected class name. @@ -2770,7 +3663,12 @@

Node Matchers

auto &&f = 2; int g = 5; -referenceType() matches the types of b, c, d, e, and f. + +The matcher referenceType() matches the type +int & of b , the type int && of +c, the type +auto & d, and the type +auto && of e and f. @@ -2781,10 +3679,17 @@

Node Matchers

Given template <typename T> void F(T t) { + T local; int i = 1 + t; } + void f() { + F(0); + } -substTemplateTypeParmType() matches the type of 't' but not '1' + +The matcher varDecl(hasType(substTemplateTypeParmType())) +matches T t and T local for the substituted template type +int in the instantiation of F . @@ -2792,14 +3697,18 @@

Node Matchers

Matches tag types (record and enum types).
 
 Given
-  enum E {};
+  enum E { Ok };
   class C {};
 
   E e;
   C c;
 
-tagType() matches the type of the variable declarations of both e
-and c.
+
+The matcher tagType() matches the type
+enum E of variable e and the type
+class C three times, once for the type
+of the variable c , once for the type of the class definition and once of
+the type in the injected class name.
 
@@ -2810,25 +3719,38 @@

Node Matchers

template <typename T> class C { }; - template class C<int>; // A - C<char> var; // B + template class C<int>; + C<int> intvar; + C<char> charvar; -templateSpecializationType() matches the type of the explicit -instantiation in A and the type of the variable declaration in B. + +The matcher templateSpecializationType() matches the type +C<int> of the explicit instantiation in A and the +type C<char> of the variable declaration in +B. Matcher<Type>templateTypeParmTypeMatcher<TemplateTypeParmType>...
Matches template type parameter types.
 
-Example matches T, but not int.
-    (matcher = templateTypeParmType())
+Given
   template <typename T> void f(int i);
+
+The matcher templateTypeParmType() matches T,
+but does not match int.
 
Matcher<Type>typeMatcher<Type>...
Matches Types in the clang AST.
+
+Given
+  const int b = 1;
+
+The matcher varDecl(hasType(type().bind("type")))
+matches const int b = 1, with type()
+matching int.
 
@@ -2837,18 +3759,22 @@

Node Matchers

Given typedef int X; -typedefType() - matches "typedef int X" + X x = 0; +The matcher typedefType() +matches X. Matcher<Type>unaryTransformTypeMatcher<UnaryTransformType>...
Matches types nodes representing unary type transformations.
 
-Given:
-  typedef __underlying_type(T) type;
-unaryTransformType()
-  matches "__underlying_type(T)"
+Given
+  template <typename T> struct A {
+    typedef __underlying_type(T) type;
+  };
+
+The matcher unaryTransformType()
+matches __underlying_type(T)
 
@@ -2860,7 +3786,9 @@

Node Matchers

using a::S; S s; -usingType() matches the type of the variable declaration of s. + +The matcher usingType() matches the type a::S +of the variable declaration of s. @@ -2870,12 +3798,12 @@

Node Matchers

Given void f() { - int a[] = { 2, 3 } + int a[] = { 2, 3 }; int b[42]; int c[a[0]]; } -variableArrayType() - matches "int c[a[0]]" +The matcher variableArrayType() +int[a[0]] @@ -2899,6 +3827,12 @@

Narrowing Matchers

Matches if all given matchers match.
 
 Usable as: Any Matcher
+
+  int v0 = 0;
+  int v1 = 1;
+
+The matcher varDecl(allOf(hasName("v0"), hasType(isInteger())))
+matches int v0 = 0.
 
@@ -2906,6 +3840,13 @@

Narrowing Matchers

Matches if any of the given matchers matches.
 
 Usable as: Any Matcher
+
+  char v0 = 'a';
+  int v1 = 1;
+  float v2 = 2.0;
+
+The matcher varDecl(anyOf(hasName("v0"), hasType(isInteger())))
+matches char v0 = 'a' and int v1 = 1.
 
@@ -2916,11 +3857,11 @@

Narrowing Matchers

additional constraint. This will often be used with an explicit conversion to an internal::Matcher<> type such as TypeMatcher. -Example: DeclarationMatcher(anything()) matches all declarations, e.g., -"int* p" and "void f()" in +Given int* p; void f(); - +The matcher decl(anything()) +matches int* p and void f(). Usable as: Any Matcher @@ -2929,21 +3870,25 @@

Narrowing Matchers

Matches any of the NodeMatchers with InnerMatchers nested within
 
 Given
-  if (true);
-  for (; true; );
-with the matcher
-  mapAnyOf(ifStmt, forStmt).with(
-    hasCondition(cxxBoolLiteralExpr(equals(true)))
-    ).bind("trueCond")
-matches the if and the for. It is equivalent to:
-  auto trueCond = hasCondition(cxxBoolLiteralExpr(equals(true)));
-  anyOf(
-    ifStmt(trueCond).bind("trueCond"),
-    forStmt(trueCond).bind("trueCond")
-    );
+  void f() {
+    if (true);
+    for (; true; );
+  }
+
+
+The matcher stmt(mapAnyOf(ifStmt, forStmt).with(
+    hasCondition(cxxBoolLiteral(equals(true)))
+    )),
+which is equivalent to
+stmt(anyOf(
+    ifStmt(hasCondition(cxxBoolLiteral(equals(true)))).bind("trueCond"),
+    forStmt(hasCondition(cxxBoolLiteral(equals(true)))).bind("trueCond")
+    )),
+matches if (true); and for (; true; );.
 
 The with() chain-call accepts zero or more matchers which are combined
 as-if with allOf() in each of the node matchers.
+
 Usable as: Any Matcher
 
@@ -2951,10 +3896,13 @@

Narrowing Matchers

Matcher<*>unlessMatcher<*>
Matches if the provided matcher does not match.
 
-Example matches Y (matcher = cxxRecordDecl(unless(hasName("X"))))
+Given
   class X {};
   class Y {};
 
+The matcher cxxRecordDecl(unless(hasName("X")))
+matches Y
+
 Usable as: Any Matcher
 
@@ -2962,6 +3910,20 @@

Narrowing Matchers

Matcher<Attr>isImplicit
Matches an entity that has been implicitly added by the compiler (e.g.
 implicit default/copy constructors).
+
+Given
+  struct S {};
+  void f(S obj) {
+    S copy = obj;
+    [&](){ return copy; };
+  }
+
+
+The matcher cxxConstructorDecl(isImplicit(), isCopyConstructor())
+matches the implicit copy constructor of S.
+The matcher lambdaExpr(forEachLambdaCapture(
+    lambdaCapture(isImplicit()))) matches [&](){ return copy; },
+because it implicitly captures copy .
 
@@ -2969,9 +3931,26 @@

Narrowing Matchers

Matches operator expressions (binary or unary) that have any of the
 specified names.
 
-   hasAnyOperatorName("+", "-")
- Is equivalent to
-   anyOf(hasOperatorName("+"), hasOperatorName("-"))
+It provides a compact way of writing if an operator has any of the specified
+names:
+The matcher
+   hasAnyOperatorName("+", "-")
+Is equivalent to
+   hasOperatorName("-"))}
+
+Given
+void foo(bool a, bool b) {
+  !(a || b);
+ }
+
+void bar(bool a, bool b) {
+  a && b;
+ }
+
+The matcher binaryOperator(hasAnyOperatorName("||", "&&"))
+matches a || b and a && b.
+The matcher unaryOperator(hasAnyOperatorName("-", "!"))
+matches !(a || b).
 
@@ -2979,43 +3958,62 @@

Narrowing Matchers

Matches the operator Name of operator expressions and fold expressions
 (binary or unary).
 
-Example matches a || b (matcher = binaryOperator(hasOperatorName("||")))
-  !(a || b)
+Given
+void foo(bool a, bool b) {
+  !(a || b);
+ }
+
+The matcher binaryOperator(hasOperatorName("||"))
+matches a || b
 
-Example matches `(0 + ... + args)`
-    (matcher = cxxFoldExpr(hasOperatorName("+")))
+Given
   template <typename... Args>
   auto sum(Args... args) {
       return (0 + ... + args);
   }
+
+The matcher cxxFoldExpr(hasOperatorName("+"))
+ matches (0 + ... + args).
 
Matcher<BinaryOperator>isAssignmentOperator
Matches all kinds of assignment operators.
 
-Example 1: matches a += b (matcher = binaryOperator(isAssignmentOperator()))
+Given
+void foo(int a, int b) {
   if (a == b)
     a += b;
+}
+The matcher binaryOperator(isAssignmentOperator())
+matches a += b.
 
-Example 2: matches s1 = s2
-           (matcher = cxxOperatorCallExpr(isAssignmentOperator()))
+Given
   struct S { S& operator=(const S&); };
   void x() { S s1, s2; s1 = s2; }
+
+The matcher cxxOperatorCallExpr(isAssignmentOperator())
+matches s1 = s2.
 
Matcher<BinaryOperator>isComparisonOperator
Matches comparison operators.
 
-Example 1: matches a == b (matcher = binaryOperator(isComparisonOperator()))
+Given
+void foo(int a, int b) {
   if (a == b)
     a += b;
+}
+The matcher binaryOperator(isComparisonOperator())
+matches a == b
 
-Example 2: matches s1 < s2
-           (matcher = cxxOperatorCallExpr(isComparisonOperator()))
+Given
   struct S { bool operator<(const S& other); };
   void x(S s1, S s2) { bool b1 = s1 < s2; }
+
+The matcher cxxOperatorCallExpr(isComparisonOperator())
+matches s1 < s2
 
@@ -3023,16 +4021,25 @@

Narrowing Matchers

Matches private C++ declarations and C++ base specifers that specify private
 inheritance.
 
-Examples:
+Given
   class C {
   public:    int a;
   protected: int b;
-  private:   int c; // fieldDecl(isPrivate()) matches 'c'
+  private:   int c;
   };
 
+The matcher fieldDecl(isPrivate())
+matches c.
+
   struct Base {};
-  struct Derived1 : private Base {}; // matches 'Base'
-  class Derived2 : Base {}; // matches 'Base'
+  struct Derived1 : private Base {}; // Base
+  class Derived2 : Base {}; // Base
+
+The matcher
+cxxRecordDecl(hasAnyBase(cxxBaseSpecifier(isPrivate()).bind("base")))
+matches Derived1 and Derived2, with
+cxxBaseSpecifier(isPrivate()) matching
+Base.
 
@@ -3040,15 +4047,24 @@

Narrowing Matchers

Matches protected C++ declarations and C++ base specifers that specify
 protected inheritance.
 
-Examples:
+Given
   class C {
   public:    int a;
-  protected: int b; // fieldDecl(isProtected()) matches 'b'
+  protected: int b;
   private:   int c;
   };
 
+The matcher fieldDecl(isProtected())
+matches b.
+
   class Base {};
-  class Derived : protected Base {}; // matches 'Base'
+  class Derived : protected Base {};
+
+The matcher
+cxxRecordDecl(hasAnyBase(cxxBaseSpecifier(isProtected()).bind("base")))
+matches Derived, with
+cxxBaseSpecifier(isProtected()) matching
+Base.
 
@@ -3056,16 +4072,26 @@

Narrowing Matchers

Matches public C++ declarations and C++ base specifers that specify public
 inheritance.
 
-Examples:
+Given
   class C {
-  public:    int a; // fieldDecl(isPublic()) matches 'a'
+  public:    int a;
   protected: int b;
   private:   int c;
   };
 
+The matcher fieldDecl(isPublic())
+matches a.
+
+Given
   class Base {};
-  class Derived1 : public Base {}; // matches 'Base'
-  struct Derived2 : Base {}; // matches 'Base'
+  class Derived1 : public Base {};
+  struct Derived2 : Base {};
+
+The matcher
+cxxRecordDecl(hasAnyBase(cxxBaseSpecifier(isPublic()).bind("base")))
+matches Derived1 and Derived2,
+with cxxBaseSpecifier(isPublic()) matching
+public Base and Base.
 
@@ -3073,16 +4099,23 @@

Narrowing Matchers

Matches declarations of virtual methods and C++ base specifers that specify
 virtual inheritance.
 
-Example:
+Given
   class A {
    public:
     virtual void x(); // matches x
   };
 
-Example:
-  class Base {};
-  class DirectlyDerived : virtual Base {}; // matches Base
-  class IndirectlyDerived : DirectlyDerived, Base {}; // matches Base
+The matcher cxxMethodDecl(isVirtual())
+matches x.
+
+Given
+  struct Base {};
+  struct DirectlyDerived : virtual Base {}; // matches Base
+  struct IndirectlyDerived : DirectlyDerived, Base {}; // matches Base
+
+The matcher
+cxxRecordDecl(hasDirectBase(cxxBaseSpecifier(isVirtual())))
+matches DirectlyDerived.
 
 Usable as: Matcher<CXXMethodDecl>, Matcher<CXXBaseSpecifier>
 
@@ -3096,22 +4129,27 @@

Narrowing Matchers

Matches literals that are equal to the given value of type ValueT.
 
 Given
+void f(char, bool, double, int);
+void foo() {
   f('false, 3.14, 42);
-characterLiteral(equals(0))
-  matches 'cxxBoolLiteral(equals(false)) and cxxBoolLiteral(equals(0))
-  match false
-floatLiteral(equals(3.14)) and floatLiteral(equals(314e-2))
-  match 3.14
-integerLiteral(equals(42))
-  matches 42
+}
+
+The matcher characterLiteral(equals(0U)) matches 'The matchers cxxBoolLiteral(equals(false)) and
+cxxBoolLiteral(equals(0)) match false.
+The matcher floatLiteral(equals(3.14)) matches 3.14.
+The matcher integerLiteral(equals(42)) matches 42.
 
 Note that you cannot directly match a negative numeric literal because the
 minus sign is not part of the literal: It is a unary operator whose operand
 is the positive numeric literal. Instead, you must use a unaryOperator()
 matcher to match the minus sign:
 
-unaryOperator(hasOperatorName("-"),
-              hasUnaryOperand(integerLiteral(equals(13))))
+Given
+  int val = -1;
+
+The matcher unaryOperator(hasOperatorName("-"),
+              hasUnaryOperand(integerLiteral(equals(1))))
+matches -1.
 
 Usable as: Matcher<CharacterLiteral>, Matcher<CXXBoolLiteralExpr>,
            Matcher<FloatingLiteral>, Matcher<IntegerLiteral>
@@ -3130,14 +4168,15 @@ 

Narrowing Matchers

Matches a C++ catch statement that has a catch-all handler.
 
 Given
-  try {
-    // ...
-  } catch (int) {
-    // ...
-  } catch (...) {
-    // ...
+  void foo() {
+    try {}
+    catch (int) {}
+    catch (...) {}
   }
-cxxCatchStmt(isCatchAll()) matches catch(...) but not catch(int).
+
+The matcher cxxCatchStmt(isCatchAll())
+matches catch (...) {}
+but does not match catch(int)
 
@@ -3145,12 +4184,15 @@

Narrowing Matchers

Checks that a call expression or a constructor call expression has at least
 the specified number of arguments (including absent default arguments).
 
-Example matches f(0, 0) and g(0, 0, 0)
-(matcher = callExpr(argumentCountAtLeast(2)))
+Given
   void f(int x, int y);
   void g(int x, int y, int z);
-  f(0, 0);
-  g(0, 0, 0);
+  void foo() {
+    f(0, 0);
+    g(0, 0, 0);
+  }
+The matcher callExpr(argumentCountAtLeast(2))
+matches f(0, 0) and g(0, 0, 0)
 
@@ -3158,14 +4200,39 @@

Narrowing Matchers

Checks that a call expression or a constructor call expression has
 a specific number of arguments (including absent default arguments).
 
-Example matches f(0, 0) (matcher = callExpr(argumentCountIs(2)))
+Given
   void f(int x, int y);
-  f(0, 0);
+  void foo() {
+    f(0, 0);
+  }
+The matcher callExpr(argumentCountIs(2))
+matches f(0, 0)
 
Matcher<CXXConstructExpr>isListInitialization
Matches a constructor call expression which uses list initialization.
+
+Given
+  namespace std {
+    template <typename T>
+    class initializer_list {
+      const T* begin;
+      const T* end;
+    };
+  }
+  template <typename T> class vector {
+    public: vector(std::initializer_list<T>) {}
+  };
+
+  vector<int> a({ 1, 2, 3 });
+  vector<int> b = { 4, 5 };
+  int c[] = { 6, 7 };
+  struct pair { int x; int y; };
+  pair d = { 8, 9 };
+
+The matcher cxxConstructExpr(isListInitialization())
+matches { 4, 5 }.
 
@@ -3175,11 +4242,15 @@

Narrowing Matchers

Given void foo() { - struct point { double x; double y; }; - point pt[2] = { { 1.0, 2.0 } }; + struct Foo { + double x; + }; + auto Val = Foo(); } -initListExpr(has(cxxConstructExpr(requiresZeroInitialization())) -will match the implicit array filler for pt[1]. + +The matcher +cxxConstructExpr(requiresZeroInitialization()) +matches Foo() because the x member has to be zero initialized.
@@ -3192,7 +4263,10 @@

Narrowing Matchers

S(const S &); // #2 S(S &&); // #3 }; -cxxConstructorDecl(isCopyConstructor()) will match #2, but not #1 or #3. + +The matcher cxxConstructorDecl(isCopyConstructor()) +matches S(const S &), +but does not match S() or S(S &&). @@ -3205,7 +4279,10 @@

Narrowing Matchers

S(const S &); // #2 S(S &&); // #3 }; -cxxConstructorDecl(isDefaultConstructor()) will match #1, but not #2 or #3. + +The matcher cxxConstructorDecl(isDefaultConstructor()) +matches S() +but does not match S(const S &); or S(S &&);. @@ -3219,8 +4296,10 @@

Narrowing Matchers

S(S &&) : S() {} // #3 }; S::S() : S(0) {} // #4 -cxxConstructorDecl(isDelegatingConstructor()) will match #3 and #4, but not -#1 or #2. + +The matcher cxxConstructorDecl(isDelegatingConstructor()) +matches S(S &&) : S() {} and S::S() : S(0) {}, +but does not match S() or S(int). @@ -3236,15 +4315,27 @@

Narrowing Matchers

explicit S(double); // #2 operator int(); // #3 explicit operator bool(); // #4 - explicit(false) S(bool) // # 7 - explicit(true) S(char) // # 8 - explicit(b) S(S) // # 9 + explicit(false) S(bool); // # 7 + explicit(true) S(char); // # 8 + explicit(b) S(float); // # 9 }; - S(int) -> S<true> // #5 - explicit S(double) -> S<false> // #6 -cxxConstructorDecl(isExplicit()) will match #2 and #8, but not #1, #7 or #9. -cxxConversionDecl(isExplicit()) will match #4, but not #3. -cxxDeductionGuideDecl(isExplicit()) will match #6, but not #5. + S(int) -> S<true>; // #5 + explicit S(double) -> S<false>; // #6 + +The matcher cxxConstructorDecl(isExplicit()) +matches explicit S(double) +and explicit(true) S(char) +but does not match S(int);, explicit(false) S(bool); or +explicit(b) S(float) +The matcher cxxConversionDecl(isExplicit()) +matches explicit operator bool() +but does not match operator int(). +The matcher cxxDeductionGuideDecl(isExplicit()) +matches the deduction guide explicit S(double) -> S<false>, +the implicit copy deduction candiate +auto (double) -> S<b> and +the implicitly generated deduction guide for explicit(true) S(char), +but does not match S(int) -> S<true>. @@ -3261,7 +4352,10 @@

Narrowing Matchers

S(const S &); // #2 S(S &&); // #3 }; -cxxConstructorDecl(isMoveConstructor()) will match #3, but not #1 or #2. + +The matcher cxxConstructorDecl(isMoveConstructor()) +matches S(S &&) +but does not match S(); or S(S &&); @@ -3277,15 +4371,27 @@

Narrowing Matchers

explicit S(double); // #2 operator int(); // #3 explicit operator bool(); // #4 - explicit(false) S(bool) // # 7 - explicit(true) S(char) // # 8 - explicit(b) S(S) // # 9 + explicit(false) S(bool); // # 7 + explicit(true) S(char); // # 8 + explicit(b) S(float); // # 9 }; - S(int) -> S<true> // #5 - explicit S(double) -> S<false> // #6 -cxxConstructorDecl(isExplicit()) will match #2 and #8, but not #1, #7 or #9. -cxxConversionDecl(isExplicit()) will match #4, but not #3. -cxxDeductionGuideDecl(isExplicit()) will match #6, but not #5. + S(int) -> S<true>; // #5 + explicit S(double) -> S<false>; // #6 + +The matcher cxxConstructorDecl(isExplicit()) +matches explicit S(double) +and explicit(true) S(char) +but does not match S(int);, explicit(false) S(bool); or +explicit(b) S(float) +The matcher cxxConversionDecl(isExplicit()) +matches explicit operator bool() +but does not match operator int(). +The matcher cxxDeductionGuideDecl(isExplicit()) +matches the deduction guide explicit S(double) -> S<false>, +the implicit copy deduction candiate +auto (double) -> S<b> and +the implicitly generated deduction guide for explicit(true) S(char), +but does not match S(int) -> S<true>. @@ -3302,8 +4408,12 @@

Narrowing Matchers

struct E : B { E() : B() {} }; + +The matcher cxxConstructorDecl(hasAnyConstructorInitializer(isBaseInitializer())) - will match E(), but not match D(int). +matches E() : B() {} and D(int i) : I(i) {}. +The constructor of D is matched, because it implicitly has a constructor +initializer for B . @@ -3320,8 +4430,11 @@

Narrowing Matchers

struct E : B { E() : B() {} }; + +The matcher cxxConstructorDecl(hasAnyConstructorInitializer(isMemberInitializer())) - will match D(int), but not match E(). + will match D(int i) : I(i) {}, but not match E() : B() + {}. @@ -3330,13 +4443,16 @@

Narrowing Matchers

code (as opposed to implicitly added by the compiler). Given + struct Bar { explicit Bar(const char*); }; struct Foo { Foo() { } Foo(int) : foo_("A") { } - string foo_; + Bar foo_{""}; }; -cxxConstructorDecl(hasAnyConstructorInitializer(isWritten())) - will match Foo(int), but not Foo() + +The matcher +cxxConstructorDecl(hasAnyConstructorInitializer(isWritten())) will +match Foo(int) : foo_("A") { }, but not Foo() { } @@ -3352,15 +4468,27 @@

Narrowing Matchers

explicit S(double); // #2 operator int(); // #3 explicit operator bool(); // #4 - explicit(false) S(bool) // # 7 - explicit(true) S(char) // # 8 - explicit(b) S(S) // # 9 + explicit(false) S(bool); // # 7 + explicit(true) S(char); // # 8 + explicit(b) S(float); // # 9 }; - S(int) -> S<true> // #5 - explicit S(double) -> S<false> // #6 -cxxConstructorDecl(isExplicit()) will match #2 and #8, but not #1, #7 or #9. -cxxConversionDecl(isExplicit()) will match #4, but not #3. -cxxDeductionGuideDecl(isExplicit()) will match #6, but not #5. + S(int) -> S<true>; // #5 + explicit S(double) -> S<false>; // #6 + +The matcher cxxConstructorDecl(isExplicit()) +matches explicit S(double) +and explicit(true) S(char) +but does not match S(int);, explicit(false) S(bool); or +explicit(b) S(float) +The matcher cxxConversionDecl(isExplicit()) +matches explicit operator bool() +but does not match operator int(). +The matcher cxxDeductionGuideDecl(isExplicit()) +matches the deduction guide explicit S(double) -> S<false>, +the implicit copy deduction candiate +auto (double) -> S<b> and +the implicitly generated deduction guide for explicit(true) S(char), +but does not match S(int) -> S<true>. @@ -3382,7 +4510,9 @@

Narrowing Matchers

S<T> s; s.mem(); } -cxxDependentScopeMemberExpr(hasMemberName("mem")) matches `s.mem()` + +The matcher cxxDependentScopeMemberExpr(hasMemberName("mem")) +matches s.mem. @@ -3401,14 +4531,25 @@

Narrowing Matchers

}; template <class T> class Z { - void x() { this->m; } + void x() { + this->m; + this->t; + this->t->m; + } + int m; + T* t; }; -memberExpr(isArrow()) - matches this->x, x, y.x, a, this->b -cxxDependentScopeMemberExpr(isArrow()) - matches this->m -unresolvedMemberExpr(isArrow()) - matches this->f<T>, f<T> + +The matcher memberExpr(isArrow()) +matches this->x, x, a, +this->b, this->m and two times this->t, +once for the standalone member expression, and once for the member +expression that later accesses m . +Additionally, it does not match this->t->t. +The matcher cxxDependentScopeMemberExpr(isArrow()) +matches this->t->m, but not this->m or this->t. +The matcher unresolvedMemberExpr(isArrow()) +matches this->f<T>, f<T> @@ -3432,19 +4573,20 @@

Narrowing Matchers

S<T> s; s.mem(); } -The matcher -@code -cxxDependentScopeMemberExpr( - hasObjectExpression(declRefExpr(hasType(templateSpecializationType( + +The matcher cxxDependentScopeMemberExpr( + hasObjectExpression(declRefExpr(hasType( + elaboratedType(namesType(templateSpecializationType( hasDeclaration(classTemplateDecl(has(cxxRecordDecl(has( cxxMethodDecl(hasName("mem")).bind("templMem") ))))) - )))), + ))) + ))), memberHasSameNameAsBoundNode("templMem") - ) -@endcode -first matches and binds the @c mem member of the @c S template, then -compares its name to the usage in @c s.mem() in the @c x function template +) +matches s.mem, with the inner matcher +cxxMethodDecl(hasName("mem")) matching +void mem() of the S template. @@ -3452,23 +4594,29 @@

Narrowing Matchers

Matches the operator Name of operator expressions and fold expressions
 (binary or unary).
 
-Example matches a || b (matcher = binaryOperator(hasOperatorName("||")))
-  !(a || b)
+Given
+void foo(bool a, bool b) {
+  !(a || b);
+ }
+
+The matcher binaryOperator(hasOperatorName("||"))
+matches a || b
 
-Example matches `(0 + ... + args)`
-    (matcher = cxxFoldExpr(hasOperatorName("+")))
+Given
   template <typename... Args>
   auto sum(Args... args) {
       return (0 + ... + args);
   }
+
+The matcher cxxFoldExpr(hasOperatorName("+"))
+ matches (0 + ... + args).
 
Matcher<CXXFoldExpr>isBinaryFold
Matches binary fold expressions, i.e. fold expressions with an initializer.
 
-Example matches `(0 + ... + args)`
-    (matcher = cxxFoldExpr(isBinaryFold()))
+Given
   template <typename... Args>
   auto sum(Args... args) {
       return (0 + ... + args);
@@ -3478,14 +4626,17 @@ 

Narrowing Matchers

auto multiply(Args... args) { return (args * ...); } + + +The matcher cxxFoldExpr(isBinaryFold()) +matches (0 + ... + args).
Matcher<CXXFoldExpr>isLeftFold
Matches left-folding fold expressions.
 
-Example matches `(0 + ... + args)`
-    (matcher = cxxFoldExpr(isLeftFold()))
+Given
   template <typename... Args>
   auto sum(Args... args) {
       return (0 + ... + args);
@@ -3495,14 +4646,17 @@ 

Narrowing Matchers

auto multiply(Args... args) { return (args * ... * 1); } + + +The matcher cxxFoldExpr(isLeftFold()) +matches (0 + ... + args).
Matcher<CXXFoldExpr>isRightFold
Matches right-folding fold expressions.
 
-Example matches `(args * ... * 1)`
-    (matcher = cxxFoldExpr(isRightFold()))
+Given
   template <typename... Args>
   auto sum(Args... args) {
       return (0 + ... + args);
@@ -3512,6 +4666,10 @@ 

Narrowing Matchers

auto multiply(Args... args) { return (args * ... * 1); } + + +The matcher cxxFoldExpr(isRightFold()) +matches (args * ... * 1).
@@ -3519,8 +4677,7 @@

Narrowing Matchers

Matches unary fold expressions, i.e. fold expressions without an
 initializer.
 
-Example matches `(args * ...)`
-    (matcher = cxxFoldExpr(isUnaryFold()))
+Given
   template <typename... Args>
   auto sum(Args... args) {
       return (0 + ... + args);
@@ -3530,6 +4687,10 @@ 

Narrowing Matchers

auto multiply(Args... args) { return (args * ...); } + + +The matcher cxxFoldExpr(isUnaryFold()) +matches (args * ...), but not (0 + ... + args).
@@ -3542,7 +4703,9 @@

Narrowing Matchers

void bar(); }; -cxxMethodDecl(isConst()) matches A::foo() but not A::bar() + +The matcher cxxMethodDecl(isConst()) +matches foo but not bar @@ -3556,8 +4719,10 @@

Narrowing Matchers

A &operator=(A &&); }; -cxxMethodDecl(isCopyAssignmentOperator()) matches the first method but not -the second one. + +The matcher cxxMethodDecl(isCopyAssignmentOperator()) +matches A &operator=(const A &) +but does not match A &operator=(A &&) @@ -3573,15 +4738,19 @@

Narrowing Matchers

int operator+(int); }; -cxxMethodDecl(isExplicitObjectMemberFunction()) matches the first two -methods but not the last two. + +The matcher cxxMethodDecl(isExplicitObjectMemberFunction()) +matches int operator-(this A, int) and +void fun(this A &&self), +but not static int operator()(int) or +int operator+(int). Matcher<CXXMethodDecl>isFinal
Matches if the given method or class declaration is final.
 
-Given:
+Given
   class A final {};
 
   struct B {
@@ -3591,7 +4760,13 @@ 

Narrowing Matchers

struct C : B { void f() final; }; -matches A and C::f, but not B, C, or B::f + +The matcher cxxRecordDecl(isFinal()) +matches A, +but does not match B or C. +The matcher cxxMethodDecl(isFinal()) +matches void f() final in C , +but does not match virtual void f() in B .
@@ -3605,8 +4780,10 @@

Narrowing Matchers

A &operator=(A &&); }; -cxxMethodDecl(isMoveAssignmentOperator()) matches the second method but not -the first one. + +The matcher cxxMethodDecl(isMoveAssignmentOperator()) +matches A &operator=(A &&) +but does not match A &operator=(const A &) @@ -3620,9 +4797,11 @@

Narrowing Matchers

}; class B : public A { public: - virtual void x(); + void x() override; }; - matches B::x + +The matcher cxxMethodDecl(isOverride()) + matches void x() override @@ -3634,7 +4813,9 @@

Narrowing Matchers

public: virtual void x() = 0; }; - matches A::x + +The matcher cxxMethodDecl(isPure()) +matches virtual void x() = 0 @@ -3647,7 +4828,10 @@

Narrowing Matchers

S(const S &) = default; // #2 S(S &&) = delete; // #3 }; -cxxConstructorDecl(isUserProvided()) will match #1, but not #2 or #3. + +The matcher cxxConstructorDecl(isUserProvided()) +will match S(), but not S &) = default} or +&&) = delete} @@ -3655,16 +4839,23 @@

Narrowing Matchers

Matches declarations of virtual methods and C++ base specifers that specify
 virtual inheritance.
 
-Example:
+Given
   class A {
    public:
     virtual void x(); // matches x
   };
 
-Example:
-  class Base {};
-  class DirectlyDerived : virtual Base {}; // matches Base
-  class IndirectlyDerived : DirectlyDerived, Base {}; // matches Base
+The matcher cxxMethodDecl(isVirtual())
+matches x.
+
+Given
+  struct Base {};
+  struct DirectlyDerived : virtual Base {}; // matches Base
+  struct IndirectlyDerived : DirectlyDerived, Base {}; // matches Base
+
+The matcher
+cxxRecordDecl(hasDirectBase(cxxBaseSpecifier(isVirtual())))
+matches DirectlyDerived.
 
 Usable as: Matcher<CXXMethodDecl>, Matcher<CXXBaseSpecifier>
 
@@ -3682,17 +4873,22 @@

Narrowing Matchers

public: void x(); }; - matches A::x but not B::x + +The matcher cxxMethodDecl(isVirtualAsWritten()) +matches virtual void x() of A, +but does not match x()} of B . Matcher<CXXNewExpr>isArray
Matches array new expressions.
 
-Given:
+Given
+  struct MyClass { int x; };
   MyClass *p1 = new MyClass[10];
-cxxNewExpr(isArray())
-  matches the expression 'new MyClass[10]'.
+
+The matcher cxxNewExpr(isArray())
+matches new MyClass[10].
 
@@ -3700,9 +4896,26 @@

Narrowing Matchers

Matches operator expressions (binary or unary) that have any of the
 specified names.
 
+It provides a compact way of writing if an operator has any of the specified
+names:
+The matcher
    hasAnyOperatorName("+", "-")
- Is equivalent to
-   anyOf(hasOperatorName("+"), hasOperatorName("-"))
+Is equivalent to
+   hasOperatorName("-"))}
+
+Given
+void foo(bool a, bool b) {
+  !(a || b);
+ }
+
+void bar(bool a, bool b) {
+  a && b;
+ }
+
+The matcher binaryOperator(hasAnyOperatorName("||", "&&"))
+matches a || b and a && b.
+The matcher unaryOperator(hasAnyOperatorName("-", "!"))
+matches !(a || b).
 
@@ -3713,6 +4926,30 @@

Narrowing Matchers

"operator" prefix: e.g. "<<". hasAnyOverloadedOperatorName("+", "-") + +Given + struct Point { double x; double y; }; + Point operator+(const Point&, const Point&); + Point operator-(const Point&, const Point&); + + Point sub(Point a, Point b) { + return b - a; + } + + +The matcher functionDecl(hasAnyOverloadedOperatorName("+", "-")), +which is equivalent to +functionDecl(anyOf(hasAnyOverloadedOperatorName("+"), +hasOverloadedOperatorName("-"))), +matches Point operator+(const Point&, const Point&) and +Point operator-(const Point&, const Point&). +The matcher +cxxOperatorCallExpr(hasAnyOverloadedOperatorName("+", "-")), +which is equivalent to +cxxOperatorCallExpr(anyOf(hasOverloadedOperatorName("+"), +hasOverloadedOperatorName("-"))), +matches b - a. + Is equivalent to anyOf(hasOverloadedOperatorName("+"), hasOverloadedOperatorName("-")) @@ -3722,15 +4959,22 @@

Narrowing Matchers

Matches the operator Name of operator expressions and fold expressions
 (binary or unary).
 
-Example matches a || b (matcher = binaryOperator(hasOperatorName("||")))
-  !(a || b)
+Given
+void foo(bool a, bool b) {
+  !(a || b);
+ }
+
+The matcher binaryOperator(hasOperatorName("||"))
+matches a || b
 
-Example matches `(0 + ... + args)`
-    (matcher = cxxFoldExpr(hasOperatorName("+")))
+Given
   template <typename... Args>
   auto sum(Args... args) {
       return (0 + ... + args);
   }
+
+The matcher cxxFoldExpr(hasOperatorName("+"))
+ matches (0 + ... + args).
 
@@ -3740,16 +4984,19 @@

Narrowing Matchers

Matches overloaded operator names specified in strings without the "operator" prefix: e.g. "<<". -Given: - class A { int operator*(); }; +Given + struct A { int operator*(); }; const A &operator<<(const A &a, const A &b); - A a; - a << a; // <-- This matches + void f(A a) { + a << a; // <-- This matches + } -cxxOperatorCallExpr(hasOverloadedOperatorName("<<"))) matches the -specified line and + +The matcher cxxOperatorCallExpr(hasOverloadedOperatorName("<<")) +matches a << a. +The matcher cxxRecordDecl(hasMethod(hasOverloadedOperatorName("*"))) -matches the declaration of A. +matches struct A { int operator*(); }. Usable as: Matcher<CXXOperatorCallExpr>, Matcher<FunctionDecl> @@ -3758,47 +5005,104 @@

Narrowing Matchers

Matcher<CXXOperatorCallExpr>isAssignmentOperator
Matches all kinds of assignment operators.
 
-Example 1: matches a += b (matcher = binaryOperator(isAssignmentOperator()))
+Given
+void foo(int a, int b) {
   if (a == b)
     a += b;
+}
+The matcher binaryOperator(isAssignmentOperator())
+matches a += b.
 
-Example 2: matches s1 = s2
-           (matcher = cxxOperatorCallExpr(isAssignmentOperator()))
+Given
   struct S { S& operator=(const S&); };
   void x() { S s1, s2; s1 = s2; }
+
+The matcher cxxOperatorCallExpr(isAssignmentOperator())
+matches s1 = s2.
 
Matcher<CXXOperatorCallExpr>isComparisonOperator
Matches comparison operators.
 
-Example 1: matches a == b (matcher = binaryOperator(isComparisonOperator()))
+Given
+void foo(int a, int b) {
   if (a == b)
     a += b;
+}
+The matcher binaryOperator(isComparisonOperator())
+matches a == b
 
-Example 2: matches s1 < s2
-           (matcher = cxxOperatorCallExpr(isComparisonOperator()))
+Given
   struct S { bool operator<(const S& other); };
   void x(S s1, S s2) { bool b1 = s1 < s2; }
+
+The matcher cxxOperatorCallExpr(isComparisonOperator())
+matches s1 < s2
 
Matcher<CXXRecordDecl>hasDefinition
Matches a class declaration that is defined.
 
-Example matches x (matcher = cxxRecordDecl(hasDefinition()))
+Given
 class x {};
 class y;
+
+The matcher cxxRecordDecl(hasDefinition())
+matches class x {}
 
Matcher<CXXRecordDecl>isDerivedFromstd::string BaseName
Overloaded method as shortcut for isDerivedFrom(hasName(...)).
+
+Matches C++ classes that are directly or indirectly derived from a class
+matching Base, or Objective-C classes that directly or indirectly
+subclass a class matching Base.
+
+Note that a class is not considered to be derived from itself.
+
+Example matches Y, Z, C (Base == hasName("X"))
+  class X {};
+  class Y : public X {};  // directly derived
+  class Z : public Y {};  // indirectly derived
+  typedef X A;
+  typedef A B;
+  class C : public B {};  // derived from a typedef of X
+
+  class Foo {};
+  typedef Foo Alias;
+  class Bar : public Alias {};  // derived from Alias, which is a
+                                // typedef of Foo
+
+
+The matcher cxxRecordDecl(isDerivedFrom("X"))
+matches Y, Z and C.
+The matcher cxxRecordDecl(isDerivedFrom("Foo"))
+matches Bar.
+
+In the following example, Bar matches isDerivedFrom(hasName("NSObject"))
+  @interface NSObject @end
+  @interface Bar : NSObject @end
+
+
+Usable as: Matcher<CXXRecordDecl>, Matcher<ObjCInterfaceDecl>
 
Matcher<CXXRecordDecl>isDirectlyDerivedFromstd::string BaseName
Overloaded method as shortcut for isDirectlyDerivedFrom(hasName(...)).
+
+Given
+  struct Base {};
+  struct DirectlyDerived : public Base {};
+  struct IndirectlyDerived : public DirectlyDerived {};
+
+
+The matcher cxxRecordDecl(isDirectlyDerivedFrom("Base"))
+matches DirectlyDerived, but not
+IndirectlyDerived.
 
@@ -3809,8 +5113,9 @@

Narrowing Matchers

Given template<typename T> void A(T t) { } template<> void A(int N) { } -functionDecl(isExplicitTemplateSpecialization()) - matches the specialization A<int>(). + +The matcher functionDecl(isExplicitTemplateSpecialization()) + matches the specialization template<> void A(int N) { }. Usable as: Matcher<FunctionDecl>, Matcher<VarDecl>, Matcher<CXXRecordDecl> @@ -3819,7 +5124,7 @@

Narrowing Matchers

Matcher<CXXRecordDecl>isFinal
Matches if the given method or class declaration is final.
 
-Given:
+Given
   class A final {};
 
   struct B {
@@ -3829,24 +5134,46 @@ 

Narrowing Matchers

struct C : B { void f() final; }; -matches A and C::f, but not B, C, or B::f + +The matcher cxxRecordDecl(isFinal()) +matches A, +but does not match B or C. +The matcher cxxMethodDecl(isFinal()) +matches void f() final in C , +but does not match virtual void f() in B .
Matcher<CXXRecordDecl>isLambda
Matches the generated class of lambda expressions.
 
-Given:
+Given
   auto x = []{};
 
-cxxRecordDecl(isLambda()) matches the implicit class declaration of
-decltype(x)
+
+The matcher varDecl(hasType(cxxRecordDecl(isLambda())))
+matches auto x = []{}.
 
Matcher<CXXRecordDecl>isSameOrDerivedFromstd::string BaseName -
Overloaded method as shortcut for
+
Similar to isDerivedFrom(), but also matches classes that directly
+match Base.
+Overloaded method as shortcut for
 isSameOrDerivedFrom(hasName(...)).
+
+Given
+  class X {};
+  class Y : public X {};  // directly derived
+  class Z : public Y {};  // indirectly derived
+  typedef X A;
+  typedef A B;
+  class C : public B {};  // derived from a typedef of X
+
+The matcher
+cxxRecordDecl(isSameOrDerivedFrom("X"), isDefinition())
+matches class X {}, class Y : public X {},
+class Z : public Y {} and class C : public B {}.
 
@@ -3855,18 +5182,36 @@

Narrowing Matchers

member variable template instantiations. Given - template <typename T> class X {}; class A {}; X<A> x; -or - template <typename T> class X {}; class A {}; template class X<A>; -or - template <typename T> class X {}; class A {}; extern template class X<A>; -cxxRecordDecl(hasName("::X"), isTemplateInstantiation()) - matches the template instantiation of X<A>. + template <typename T> class X {}; + class A {}; + X<A> x; + +The matcher cxxRecordDecl(hasName("::X"), +isTemplateInstantiation()) +matches class X<class A>. + template <typename T> class X {}; + class A {}; + template class X<A>; + +The matcher cxxRecordDecl(hasName("::X"), +isTemplateInstantiation()) +matches template class X<A> + template <typename T> class X {}; + class A {}; + extern template class X<A>; + +The matcher cxxRecordDecl(hasName("::X"), +isTemplateInstantiation()) +matches extern template class X<A> But given - template <typename T> class X {}; class A {}; - template <> class X<A> {}; X<A> x; -cxxRecordDecl(hasName("::X"), isTemplateInstantiation()) + template <typename T> class X {}; + class A {}; + template <> class X<A> {}; + X<A> x; + +The matcher cxxRecordDecl(hasName("::X"), +isTemplateInstantiation()) does not match, as X<A> is an explicit template specialization. Usable as: Matcher<FunctionDecl>, Matcher<VarDecl>, Matcher<CXXRecordDecl> @@ -3877,9 +5222,26 @@

Narrowing Matchers

Matches operator expressions (binary or unary) that have any of the
 specified names.
 
+It provides a compact way of writing if an operator has any of the specified
+names:
+The matcher
    hasAnyOperatorName("+", "-")
- Is equivalent to
-   anyOf(hasOperatorName("+"), hasOperatorName("-"))
+Is equivalent to
+   hasOperatorName("-"))}
+
+Given
+void foo(bool a, bool b) {
+  !(a || b);
+ }
+
+void bar(bool a, bool b) {
+  a && b;
+ }
+
+The matcher binaryOperator(hasAnyOperatorName("||", "&&"))
+matches a || b and a && b.
+The matcher unaryOperator(hasAnyOperatorName("-", "!"))
+matches !(a || b).
 
@@ -3887,43 +5249,62 @@

Narrowing Matchers

Matches the operator Name of operator expressions and fold expressions
 (binary or unary).
 
-Example matches a || b (matcher = binaryOperator(hasOperatorName("||")))
-  !(a || b)
+Given
+void foo(bool a, bool b) {
+  !(a || b);
+ }
+
+The matcher binaryOperator(hasOperatorName("||"))
+matches a || b
 
-Example matches `(0 + ... + args)`
-    (matcher = cxxFoldExpr(hasOperatorName("+")))
+Given
   template <typename... Args>
   auto sum(Args... args) {
       return (0 + ... + args);
   }
+
+The matcher cxxFoldExpr(hasOperatorName("+"))
+ matches (0 + ... + args).
 
Matcher<CXXRewrittenBinaryOperator>isAssignmentOperator
Matches all kinds of assignment operators.
 
-Example 1: matches a += b (matcher = binaryOperator(isAssignmentOperator()))
+Given
+void foo(int a, int b) {
   if (a == b)
     a += b;
+}
+The matcher binaryOperator(isAssignmentOperator())
+matches a += b.
 
-Example 2: matches s1 = s2
-           (matcher = cxxOperatorCallExpr(isAssignmentOperator()))
+Given
   struct S { S& operator=(const S&); };
   void x() { S s1, s2; s1 = s2; }
+
+The matcher cxxOperatorCallExpr(isAssignmentOperator())
+matches s1 = s2.
 
Matcher<CXXRewrittenBinaryOperator>isComparisonOperator
Matches comparison operators.
 
-Example 1: matches a == b (matcher = binaryOperator(isComparisonOperator()))
+Given
+void foo(int a, int b) {
   if (a == b)
     a += b;
+}
+The matcher binaryOperator(isComparisonOperator())
+matches a == b
 
-Example 2: matches s1 < s2
-           (matcher = cxxOperatorCallExpr(isComparisonOperator()))
+Given
   struct S { bool operator<(const S& other); };
   void x(S s1, S s2) { bool b1 = s1 < s2; }
+
+The matcher cxxOperatorCallExpr(isComparisonOperator())
+matches s1 < s2
 
@@ -3931,12 +5312,15 @@

Narrowing Matchers

Checks that a call expression or a constructor call expression has at least
 the specified number of arguments (including absent default arguments).
 
-Example matches f(0, 0) and g(0, 0, 0)
-(matcher = callExpr(argumentCountAtLeast(2)))
+Given
   void f(int x, int y);
   void g(int x, int y, int z);
-  f(0, 0);
-  g(0, 0, 0);
+  void foo() {
+    f(0, 0);
+    g(0, 0, 0);
+  }
+The matcher callExpr(argumentCountAtLeast(2))
+matches f(0, 0) and g(0, 0, 0)
 
@@ -3944,9 +5328,13 @@

Narrowing Matchers

Checks that a call expression or a constructor call expression has
 a specific number of arguments (including absent default arguments).
 
-Example matches f(0, 0) (matcher = callExpr(argumentCountIs(2)))
+Given
   void f(int x, int y);
-  f(0, 0);
+  void foo() {
+    f(0, 0);
+  }
+The matcher callExpr(argumentCountIs(2))
+matches f(0, 0)
 
@@ -3954,12 +5342,15 @@

Narrowing Matchers

Checks that a call expression or a constructor call expression has at least
 the specified number of arguments (including absent default arguments).
 
-Example matches f(0, 0) and g(0, 0, 0)
-(matcher = callExpr(argumentCountAtLeast(2)))
+Given
   void f(int x, int y);
   void g(int x, int y, int z);
-  f(0, 0);
-  g(0, 0, 0);
+  void foo() {
+    f(0, 0);
+    g(0, 0, 0);
+  }
+The matcher callExpr(argumentCountAtLeast(2))
+matches f(0, 0) and g(0, 0, 0)
 
@@ -3967,16 +5358,20 @@

Narrowing Matchers

Checks that a call expression or a constructor call expression has
 a specific number of arguments (including absent default arguments).
 
-Example matches f(0, 0) (matcher = callExpr(argumentCountIs(2)))
+Given
   void f(int x, int y);
-  f(0, 0);
+  void foo() {
+    f(0, 0);
+  }
+The matcher callExpr(argumentCountIs(2))
+matches f(0, 0)
 
Matcher<CallExpr>usesADL
Matches call expressions which were resolved using ADL.
 
-Example matches y(x) but not y(42) or NS::y(x).
+Given
   namespace NS {
     struct X {};
     void y(X);
@@ -3992,15 +5387,20 @@ 

Narrowing Matchers

using NS::y; y(x); // Found by both unqualified lookup and ADL, doesn't match } + + +The matcher callExpr(usesADL()) +matches y(x), but not y(42) or NS::y(x).
Matcher<CastExpr>hasCastKindCastKind Kind
Matches casts that has a given cast kind.
 
-Example: matches the implicit cast around 0
-(matcher = castExpr(hasCastKind(CK_NullToPointer)))
+Given
   int *p = 0;
+The matcher castExpr(hasCastKind(CK_NullToPointer))
+matches the implicit cast around 0
 
 If the matcher is use from clang-query, CastKind parameter
 should be passed as a quoted string. e.g., hasCastKind("CK_NullToPointer").
@@ -4015,22 +5415,27 @@ 

Narrowing Matchers

Matches literals that are equal to the given value of type ValueT.
 
 Given
+void f(char, bool, double, int);
+void foo() {
   f('false, 3.14, 42);
-characterLiteral(equals(0))
-  matches 'cxxBoolLiteral(equals(false)) and cxxBoolLiteral(equals(0))
-  match false
-floatLiteral(equals(3.14)) and floatLiteral(equals(314e-2))
-  match 3.14
-integerLiteral(equals(42))
-  matches 42
+}
+
+The matcher characterLiteral(equals(0U)) matches 'The matchers cxxBoolLiteral(equals(false)) and
+cxxBoolLiteral(equals(0)) match false.
+The matcher floatLiteral(equals(3.14)) matches 3.14.
+The matcher integerLiteral(equals(42)) matches 42.
 
 Note that you cannot directly match a negative numeric literal because the
 minus sign is not part of the literal: It is a unary operator whose operand
 is the positive numeric literal. Instead, you must use a unaryOperator()
 matcher to match the minus sign:
 
-unaryOperator(hasOperatorName("-"),
-              hasUnaryOperand(integerLiteral(equals(13))))
+Given
+  int val = -1;
+
+The matcher unaryOperator(hasOperatorName("-"),
+              hasUnaryOperand(integerLiteral(equals(1))))
+matches -1.
 
 Usable as: Matcher<CharacterLiteral>, Matcher<CXXBoolLiteralExpr>,
            Matcher<FloatingLiteral>, Matcher<IntegerLiteral>
@@ -4051,8 +5456,10 @@ 

Narrowing Matchers

Given template<typename T> struct C {}; C<int> c; + +The matcher classTemplateSpecializationDecl(templateArgumentCountIs(1)) - matches C<int>. +matches struct C<int>.
@@ -4061,9 +5468,11 @@

Narrowing Matchers

child statements. Example: Given +void foo() { { for (;;) {} } -compoundStmt(statementCountIs(0))) - matches '{}' +} +The matcher compoundStmt(statementCountIs(0)) +{} but does not match the outer compound statement.
@@ -4078,10 +5487,11 @@

Narrowing Matchers

char *s = "abcd"; wchar_t *ws = L"abcd"; char *w = "a"; -constantArrayType(hasSize(42)) - matches "int a[42]" and "int b[2 * 21]" -stringLiteral(hasSize(4)) - matches "abcd", L"abcd" + +The matcher constantArrayType(hasSize(42)) +matches int[42] twice. +The matcher stringLiteral(hasSize(4)) +matches "abcd" and L"abcd".
@@ -4089,12 +5499,15 @@

Narrowing Matchers

Matches declaration statements that contain a specific number of
 declarations.
 
-Example: Given
-  int a, b;
-  int c;
-  int d = 2, e;
-declCountIs(2)
-  matches 'int a, b;' and 'int d = 2, e;', but not 'int c;'.
+Given
+  void foo() {
+    int a, b;
+    int c;
+    int d = 2, e;
+  }
+The matcher declStmt(declCountIs(2))
+matches int a, b; and int d = 2, e;,
+but does not match int c;
 
@@ -4105,10 +5518,11 @@

Narrowing Matchers

Given class X { int a; int b; }; -cxxRecordDecl( + +The matcher cxxRecordDecl( has(fieldDecl(hasName("a"), hasType(type().bind("t")))), has(fieldDecl(hasName("b"), hasType(type(equalsBoundNode("t")))))) - matches the class X, as a and b have the same type. + matches X, as a and b have the same type. Note that when multiple matches are involved via forEach* matchers, equalsBoundNodes acts as a filter. @@ -4121,7 +5535,7 @@

Narrowing Matchers

-Matcher<Decl>equalsNodeconst Decl* Other +Matcher<Decl>equalsNodeconst Decl * Other
Matches if a node equals another node.
 
 Decl has pointer identity in the AST.
@@ -4132,10 +5546,13 @@ 

Narrowing Matchers

Matches declaration that has a given attribute.
 
 Given
-  __attribute__((device)) void f() { ... }
-decl(hasAttr(clang::attr::CUDADevice)) matches the function declaration of
-f. If the matcher is used from clang-query, attr::Kind parameter should be
-passed as a quoted string. e.g., hasAttr("attr::CUDADevice").
+  __attribute__((device)) void f() {}
+
+The matcher decl(hasAttr(clang::attr::CUDADevice))
+matches f.
+If the matcher is used from clang-query, attr::Kind
+parameter should be passed as a quoted string. e.g.,
+hasAttr("attr::CUDADevice").
 
@@ -4144,6 +5561,15 @@

Narrowing Matchers

Does not match if only part of the statement is expanded from that macro or if different parts of the statement are expanded from different appearances of the macro. + +Given + #define A 0 + #define B A + int c = B; + +The matcher integerLiteral(isExpandedFromMacro("A")) +matches the literal expanded at the initializer B of the variable +c .
@@ -4151,12 +5577,25 @@

Narrowing Matchers

Matches AST nodes that were expanded within files whose name is
 partially matching a given regex.
 
-Example matches Y but not X
-    (matcher = cxxRecordDecl(isExpansionInFileMatching("AST.*"))
-  #include "ASTMatcher.h"
-  class X {};
-ASTMatcher.h:
-  class Y {};
+Given the headers Y.h
+  #pragma once
+  typedef int my_y_int;
+and X.h
+  #pragma once
+  typedef int my_x_int;
+and the source code
+  #include "X.h"
+  #include "Y.h"
+  typedef int my_main_file_int;
+  my_main_file_int a = 0;
+  my_x_int b = 1;
+  my_y_int c = 2;
+
+The matcher
+typedefDecl(isExpansionInFileMatching("Y.h"))
+matches typedef int my_y_int,
+but does not match typedef int my_main_file_int or
+typedef int my_x_int.
 
 Usable as: Matcher<Decl>, Matcher<Stmt>, Matcher<TypeLoc>
 
@@ -4169,12 +5608,18 @@ 

Narrowing Matchers

Matcher<Decl>isExpansionInMainFile
Matches AST nodes that were expanded within the main-file.
 
-Example matches X but not Y
-  (matcher = cxxRecordDecl(isExpansionInMainFile())
-  #include <Y.h>
-  class X {};
-Y.h:
-  class Y {};
+Given the header Y.h
+  #pragma once
+  typedef int my_header_int;
+and the source file
+  #include "Y.h"
+  typedef int my_main_file_int;
+  my_main_file_int a = 0;
+  my_header_int b = 1;
+
+The matcher typedefDecl(isExpansionInMainFile())
+matches typedef int my_main_file_int,
+but does not match typedef int my_header_int.
 
 Usable as: Matcher<Decl>, Matcher<Stmt>, Matcher<TypeLoc>
 
@@ -4183,12 +5628,17 @@

Narrowing Matchers

Matcher<Decl>isExpansionInSystemHeader
Matches AST nodes that were expanded within system-header-files.
 
-Example matches Y but not X
-    (matcher = cxxRecordDecl(isExpansionInSystemHeader())
+Given the header SystemHeader.h
+  #pragma once
+  int header();
+and the source code
   #include <SystemHeader.h>
-  class X {};
-SystemHeader.h:
-  class Y {};
+  static int main_file();
+
+
+The matcher functionDecl(isExpansionInSystemHeader())
+matches int header(),
+but does not match static int main_file().
 
 Usable as: Matcher<Decl>, Matcher<Stmt>, Matcher<TypeLoc>
 
@@ -4197,6 +5647,20 @@

Narrowing Matchers

Matcher<Decl>isImplicit
Matches an entity that has been implicitly added by the compiler (e.g.
 implicit default/copy constructors).
+
+Given
+  struct S {};
+  void f(S obj) {
+    S copy = obj;
+    [&](){ return copy; };
+  }
+
+
+The matcher cxxConstructorDecl(isImplicit(), isCopyConstructor())
+matches the implicit copy constructor of S.
+The matcher lambdaExpr(forEachLambdaCapture(
+    lambdaCapture(isImplicit()))) matches [&](){ return copy; },
+because it implicitly captures copy .
 
@@ -4214,11 +5678,14 @@

Narrowing Matchers

namespace { class vector {}; // #2 namespace foo { - class vector{}; // #3 + class vector {}; // #3 } } -cxxRecordDecl(hasName("vector"), isInAnonymousNamespace()) will match -#1, #2 and #3. + +The matcher cxxRecordDecl(hasName("vector"), + isInAnonymousNamespace()) +matches vector, +twice per declaration at #1, #2 and #3.
@@ -4241,7 +5708,9 @@

Narrowing Matchers

} } } -cxxRecordDecl(hasName("vector"), isInStdNamespace()) will match only #1. + +The matcher cxxRecordDecl(hasName("vector"), isInStdNamespace()) +matches class vector {} inside of namespace std. @@ -4251,10 +5720,14 @@

Narrowing Matchers

Given template<typename T> void A(T t) { T i; } - A(0); - A(0U); -functionDecl(isInstantiated()) - matches 'A(int) {...};' and 'A(unsigned) {...}'. + void foo() { + A(0); + A(0U); + } + +The matcher functionDecl(isInstantiated()) +matches the two instantiations of void A(T t) { T i; } that +are generated for int , and for int}. @@ -4262,16 +5735,25 @@

Narrowing Matchers

Matches private C++ declarations and C++ base specifers that specify private
 inheritance.
 
-Examples:
+Given
   class C {
   public:    int a;
   protected: int b;
-  private:   int c; // fieldDecl(isPrivate()) matches 'c'
+  private:   int c;
   };
 
+The matcher fieldDecl(isPrivate())
+matches c.
+
   struct Base {};
-  struct Derived1 : private Base {}; // matches 'Base'
-  class Derived2 : Base {}; // matches 'Base'
+  struct Derived1 : private Base {}; // Base
+  class Derived2 : Base {}; // Base
+
+The matcher
+cxxRecordDecl(hasAnyBase(cxxBaseSpecifier(isPrivate()).bind("base")))
+matches Derived1 and Derived2, with
+cxxBaseSpecifier(isPrivate()) matching
+Base.
 
@@ -4279,15 +5761,24 @@

Narrowing Matchers

Matches protected C++ declarations and C++ base specifers that specify
 protected inheritance.
 
-Examples:
+Given
   class C {
   public:    int a;
-  protected: int b; // fieldDecl(isProtected()) matches 'b'
+  protected: int b;
   private:   int c;
   };
 
+The matcher fieldDecl(isProtected())
+matches b.
+
   class Base {};
-  class Derived : protected Base {}; // matches 'Base'
+  class Derived : protected Base {};
+
+The matcher
+cxxRecordDecl(hasAnyBase(cxxBaseSpecifier(isProtected()).bind("base")))
+matches Derived, with
+cxxBaseSpecifier(isProtected()) matching
+Base.
 
@@ -4295,16 +5786,26 @@

Narrowing Matchers

Matches public C++ declarations and C++ base specifers that specify public
 inheritance.
 
-Examples:
+Given
   class C {
-  public:    int a; // fieldDecl(isPublic()) matches 'a'
+  public:    int a;
   protected: int b;
   private:   int c;
   };
 
+The matcher fieldDecl(isPublic())
+matches a.
+
+Given
   class Base {};
-  class Derived1 : public Base {}; // matches 'Base'
-  struct Derived2 : Base {}; // matches 'Base'
+  class Derived1 : public Base {};
+  struct Derived2 : Base {};
+
+The matcher
+cxxRecordDecl(hasAnyBase(cxxBaseSpecifier(isPublic()).bind("base")))
+matches Derived1 and Derived2,
+with cxxBaseSpecifier(isPublic()) matching
+public Base and Base.
 
@@ -4313,20 +5814,24 @@

Narrowing Matchers

a specific number of designators. Example: Given - point ptarray[10] = { [2].y = 1.0, [0].x = 1.0 }; - point ptarray2[10] = { [2].y = 1.0, [2].x = 0.0, [0].x = 1.0 }; -designatorCountIs(2) - matches '{ [2].y = 1.0, [0].x = 1.0 }', - but not '{ [2].y = 1.0, [2].x = 0.0, [0].x = 1.0 }'. + struct point2 { double x; double y; }; + struct point2 ptarray[10] = { [0].x = 1.0 }; + struct point2 pt = { .x = 2.0 }; + +The matcher designatedInitExpr(designatorCountIs(2)) +matches [0].x = 1.0, but not .x = 2.0. Matcher<EnumDecl>isScoped
Matches C++11 scoped enum declaration.
 
-Example matches Y (matcher = enumDecl(isScoped()))
+Given
 enum X {};
 enum class Y {};
+
+The matcher enumDecl(isScoped())
+matches enum class Y {}
 
@@ -4340,8 +5845,12 @@

Narrowing Matchers

sizeof is known (std::size_t) and therefore the size of the outer sizeof is known. template<typename T> - void f(T x, T y) { sizeof(sizeof(T() + T()); } -expr(isInstantiationDependent()) matches sizeof(sizeof(T() + T()) + void f(T x, T y) { sizeof(T() + T()); } + +The matcher expr(isInstantiationDependent()) +matches sizeof(T() + T()), +(T() + T()), +T() + T() and T(). @@ -4355,7 +5864,9 @@

Narrowing Matchers

void add(T x, int y) { x + y; } -expr(isTypeDependent()) matches x + y + +The matcher expr(isTypeDependent()) +matches x + y and x. @@ -4366,7 +5877,9 @@

Narrowing Matchers

For example, the array bound of "Chars" in the following example is value-dependent. template<int Size> int f() { return Size; } -expr(isValueDependent()) matches return Size + +The matcher expr(isValueDependent()) +matches the return value Size. @@ -4374,16 +5887,22 @@

Narrowing Matchers

Matches expressions that resolve to a null pointer constant, such as
 GNU's __null, C++11's nullptr, or C's NULL macro.
 
-Given:
+Given
+  #define NULL 0
   void *v1 = NULL;
   void *v2 = nullptr;
   void *v3 = __null; // GNU extension
   char *cp = (char *)0;
   int *ip = 0;
   int i = 0;
-expr(nullPointerConstant())
-  matches the initializer for v1, v2, v3, cp, and ip. Does not match the
-  initializer for i.
+
+The matcher expr(nullPointerConstant())
+matches the initializer NULL of v1,
+matches the initializer nullptr of v2,
+matches the initializer __null of v3,
+matches the initializer 0 of cp and
+matches the initializer 0 of ip,
+but does not match the initializer i of i.
 
@@ -4397,8 +5916,10 @@

Narrowing Matchers

int b : 4; int c : 2; }; -fieldDecl(hasBitWidth(2)) - matches 'int a;' and 'int c;' but not 'int b;'. + +The matcher fieldDecl(hasBitWidth(2)) +matches a and c, +but not b. @@ -4410,8 +5931,10 @@

Narrowing Matchers

int a : 2; int b; }; -fieldDecl(isBitField()) - matches 'int a;' but not 'int b;'. + +The matcher fieldDecl(isBitField()) +matches a, +but does not match b. @@ -4419,22 +5942,27 @@

Narrowing Matchers

Matches literals that are equal to the given value of type ValueT.
 
 Given
+void f(char, bool, double, int);
+void foo() {
   f('false, 3.14, 42);
-characterLiteral(equals(0))
-  matches 'cxxBoolLiteral(equals(false)) and cxxBoolLiteral(equals(0))
-  match false
-floatLiteral(equals(3.14)) and floatLiteral(equals(314e-2))
-  match 3.14
-integerLiteral(equals(42))
-  matches 42
+}
+
+The matcher characterLiteral(equals(0U)) matches 'The matchers cxxBoolLiteral(equals(false)) and
+cxxBoolLiteral(equals(0)) match false.
+The matcher floatLiteral(equals(3.14)) matches 3.14.
+The matcher integerLiteral(equals(42)) matches 42.
 
 Note that you cannot directly match a negative numeric literal because the
 minus sign is not part of the literal: It is a unary operator whose operand
 is the positive numeric literal. Instead, you must use a unaryOperator()
 matcher to match the minus sign:
 
-unaryOperator(hasOperatorName("-"),
-              hasUnaryOperand(integerLiteral(equals(13))))
+Given
+  int val = -1;
+
+The matcher unaryOperator(hasOperatorName("-"),
+              hasUnaryOperand(integerLiteral(equals(1))))
+matches -1.
 
 Usable as: Matcher<CharacterLiteral>, Matcher<CXXBoolLiteralExpr>,
            Matcher<FloatingLiteral>, Matcher<IntegerLiteral>
@@ -4452,6 +5980,30 @@ 

Narrowing Matchers

"operator" prefix: e.g. "<<". hasAnyOverloadedOperatorName("+", "-") + +Given + struct Point { double x; double y; }; + Point operator+(const Point&, const Point&); + Point operator-(const Point&, const Point&); + + Point sub(Point a, Point b) { + return b - a; + } + + +The matcher functionDecl(hasAnyOverloadedOperatorName("+", "-")), +which is equivalent to +functionDecl(anyOf(hasAnyOverloadedOperatorName("+"), +hasOverloadedOperatorName("-"))), +matches Point operator+(const Point&, const Point&) and +Point operator-(const Point&, const Point&). +The matcher +cxxOperatorCallExpr(hasAnyOverloadedOperatorName("+", "-")), +which is equivalent to +cxxOperatorCallExpr(anyOf(hasOverloadedOperatorName("+"), +hasOverloadedOperatorName("-"))), +matches b - a. + Is equivalent to anyOf(hasOverloadedOperatorName("+"), hasOverloadedOperatorName("-"))
@@ -4460,17 +6012,32 @@

Narrowing Matchers

Matcher<FunctionDecl>hasDynamicExceptionSpec
Matches functions that have a dynamic exception specification.
 
-Given:
-  void f();
-  void g() noexcept;
-  void h() noexcept(true);
-  void i() noexcept(false);
-  void j() throw();
-  void k() throw(int);
-  void l() throw(...);
-functionDecl(hasDynamicExceptionSpec()) and
-  functionProtoType(hasDynamicExceptionSpec())
-  match the declarations of j, k, and l, but not f, g, h, or i.
+Given
+  void f(int);
+  void g(int) noexcept;
+  void h(int) noexcept(true);
+  void i(int) noexcept(false);
+  void j(int) throw();
+  void k(int) throw(int);
+  void l(int) throw(...);
+
+The matcher functionDecl(hasDynamicExceptionSpec())
+matches the declarations void j(int) throw(),
+void k(int) throw(int)
+and void l(int) throw(...),
+but does not match void f(int), void g(int) noexcept,
+void h(int) noexcept(true)
+or void i(int) noexcept(true).
+The matcher
+functionProtoType(hasDynamicExceptionSpec()) matches
+the type void (int) throw() of j ,
+the type void (int) throw(int) of k and
+the type void (int) throw(...) of l .
+It does not match
+the type void (int) noexcept of f ,
+the type void (int) noexcept of g ,
+the type void (int) noexcept(int) of h or
+the type void (int) noexcept(...) of i .
 
@@ -4480,16 +6047,19 @@

Narrowing Matchers

Matches overloaded operator names specified in strings without the "operator" prefix: e.g. "<<". -Given: - class A { int operator*(); }; +Given + struct A { int operator*(); }; const A &operator<<(const A &a, const A &b); - A a; - a << a; // <-- This matches + void f(A a) { + a << a; // <-- This matches + } + -cxxOperatorCallExpr(hasOverloadedOperatorName("<<"))) matches the -specified line and +The matcher cxxOperatorCallExpr(hasOverloadedOperatorName("<<")) +matches a << a. +The matcher cxxRecordDecl(hasMethod(hasOverloadedOperatorName("*"))) -matches the declaration of A. +matches struct A { int operator*(); }. Usable as: Matcher<CXXOperatorCallExpr>, Matcher<FunctionDecl> @@ -4498,9 +6068,12 @@

Narrowing Matchers

Matcher<FunctionDecl>hasTrailingReturn
Matches a function declared with a trailing return type.
 
-Example matches Y (matcher = functionDecl(hasTrailingReturn()))
+Given
 int X() {}
 auto Y() -> int {}
+
+The matcher functionDecl(hasTrailingReturn())
+matches auto Y() -> int {}.
 
@@ -4508,15 +6081,18 @@

Narrowing Matchers

Matches consteval function declarations and if consteval/if ! consteval
 statements.
 
-Given:
+Given
   consteval int a();
   void b() { if consteval {} }
   void c() { if ! consteval {} }
   void d() { if ! consteval {} else {} }
-functionDecl(isConsteval())
-  matches the declaration of "int a()".
-ifStmt(isConsteval())
-  matches the if statement in "void b()", "void c()", "void d()".
+
+The matcher functionDecl(isConsteval())
+matches a.
+The matcher ifStmt(isConsteval())
+matches the if statements
+if consteval {}, if ! consteval {} and
+if ! consteval {} else {}.
 
@@ -4524,27 +6100,30 @@

Narrowing Matchers

Matches constexpr variable and function declarations,
        and if constexpr.
 
-Given:
+Given
   constexpr int foo = 42;
   constexpr int bar();
   void baz() { if constexpr(1 > 0) {} }
-varDecl(isConstexpr())
-  matches the declaration of foo.
-functionDecl(isConstexpr())
-  matches the declaration of bar.
-ifStmt(isConstexpr())
-  matches the if statement in baz.
+
+The matcher varDecl(isConstexpr())
+matches foo.
+The matcher functionDecl(isConstexpr())
+matches bar.
+The matcher ifStmt(isConstexpr())
+matches if constexpr(1 > 0) {}.
 
Matcher<FunctionDecl>isDefaulted
Matches defaulted function declarations.
 
-Given:
+Given
   class A { ~A(); };
   class B { ~B() = default; };
-functionDecl(isDefaulted())
-  matches the declaration of ~B, but not ~A.
+
+The matcher functionDecl(isDefaulted())
+  matches ~B() = default,
+but does not match ~A().
 
@@ -4558,6 +6137,14 @@

Narrowing Matchers

extern int vb; // Doesn't match, as it doesn't define the variable. void fa() {} void fb(); // Doesn't match, as it has no body. + +The matcher tagDecl(isDefinition()) +matches A +The matcher varDecl(isDefinition()) +matches va +The matcher functionDecl(isDefinition()) +matches fa + @interface X - (void)ma; // Doesn't match, interface is declaration. @end @@ -4565,6 +6152,9 @@

Narrowing Matchers

- (void)ma {} @end +The matcher objcMethodDecl(isDefinition()) +matches - (void)ma {} + Usable as: Matcher<TagDecl>, Matcher<VarDecl>, Matcher<FunctionDecl>, Matcher<ObjCMethodDecl> @@ -4573,11 +6163,13 @@

Narrowing Matchers

Matcher<FunctionDecl>isDeleted
Matches deleted function declarations.
 
-Given:
+Given
   void Func();
   void DeletedFunc() = delete;
-functionDecl(isDeleted())
-  matches the declaration of DeletedFunc, but not Func.
+
+The matcher functionDecl(isDeleted())
+matches DeletedFunc,
+but does not match Func.
 
@@ -4588,8 +6180,9 @@

Narrowing Matchers

Given template<typename T> void A(T t) { } template<> void A(int N) { } -functionDecl(isExplicitTemplateSpecialization()) - matches the specialization A<int>(). + +The matcher functionDecl(isExplicitTemplateSpecialization()) + matches the specialization template<> void A(int N) { }. Usable as: Matcher<FunctionDecl>, Matcher<VarDecl>, Matcher<CXXRecordDecl> @@ -4598,17 +6191,21 @@

Narrowing Matchers

Matcher<FunctionDecl>isExternC
Matches extern "C" function or variable declarations.
 
-Given:
+Given
   extern "C" void f() {}
   extern "C" { void g() {} }
   void h() {}
   extern "C" int x = 1;
   extern "C" int y = 2;
   int z = 3;
-functionDecl(isExternC())
-  matches the declaration of f and g, but not the declaration of h.
-varDecl(isExternC())
-  matches the declaration of x and y, but not the declaration of z.
+
+The matcher functionDecl(isExternC())
+matches f
+and g.
+The matcher varDecl(isExternC())
+matches x
+and y,
+but does not match z.
 
@@ -4623,15 +6220,22 @@

Narrowing Matchers

inline namespace m {} } inline int Foo = 5; -functionDecl(isInline()) will match ::f(). -namespaceDecl(isInline()) will match n::m. -varDecl(isInline()) will match Foo; + +The matcher functionDecl(isInline()) matches f. +The matcher namespaceDecl(isInline()) matches m. +The matcher varDecl(isInline()) matches Foo Matcher<FunctionDecl>isMain
Determines whether the function is "main", which is the entry point
 into an executable program.
+
+Given
+  void f();
+  int main() {}
+
+The matcher functionDecl(isMain()) matches int main() {}.
 
@@ -4643,23 +6247,38 @@

Narrowing Matchers

[[noreturn]] void a(); __attribute__((noreturn)) void b(); struct c { [[noreturn]] c(); }; -functionDecl(isNoReturn()) - matches all of those except - void nope(); + +The matcher functionDecl(isNoReturn()) +match a, b +and c +but do not match nope Matcher<FunctionDecl>isNoThrow
Matches functions that have a non-throwing exception specification.
 
-Given:
-  void f();
-  void g() noexcept;
-  void h() throw();
-  void i() throw(int);
-  void j() noexcept(false);
-functionDecl(isNoThrow()) and functionProtoType(isNoThrow())
-  match the declarations of g, and h, but not f, i or j.
+Given
+  void f(int);
+  void g(int) noexcept;
+  void h(int) noexcept(false);
+  void i(int) throw();
+  void j(int) throw(int);
+
+The matcher functionDecl(isNoThrow())
+matches the declaration void g(int) noexcept
+and void i(int) throw(),
+but does not match void f(int),
+void h(int) noexcept(false)
+or void j(int) throw(int).
+The matcher
+functionProtoType(isNoThrow())
+matches the type void (int) throw() of i
+and the type void (int) noexcept of g,
+but does not match
+the type void (int) of f ,
+the type void (int) noexcept(false) of h or
+the type void (int) throw(int) of j .
 
@@ -4667,15 +6286,15 @@

Narrowing Matchers

Matches variable/function declarations that have "static" storage
 class specifier ("static" keyword) written in the source.
 
-Given:
+Given
   static void f() {}
   static int i = 0;
   extern int j;
   int k;
-functionDecl(isStaticStorageClass())
-  matches the function declaration f.
-varDecl(isStaticStorageClass())
-  matches the variable declaration i.
+The matcher functionDecl(isStaticStorageClass())
+  matches f
+The matcher varDecl(isStaticStorageClass())
+  matches i
 
@@ -4684,18 +6303,36 @@

Narrowing Matchers

member variable template instantiations. Given - template <typename T> class X {}; class A {}; X<A> x; -or - template <typename T> class X {}; class A {}; template class X<A>; -or - template <typename T> class X {}; class A {}; extern template class X<A>; -cxxRecordDecl(hasName("::X"), isTemplateInstantiation()) - matches the template instantiation of X<A>. + template <typename T> class X {}; + class A {}; + X<A> x; + +The matcher cxxRecordDecl(hasName("::X"), +isTemplateInstantiation()) +matches class X<class A>. + template <typename T> class X {}; + class A {}; + template class X<A>; + +The matcher cxxRecordDecl(hasName("::X"), +isTemplateInstantiation()) +matches template class X<A> + template <typename T> class X {}; + class A {}; + extern template class X<A>; + +The matcher cxxRecordDecl(hasName("::X"), +isTemplateInstantiation()) +matches extern template class X<A> But given - template <typename T> class X {}; class A {}; - template <> class X<A> {}; X<A> x; -cxxRecordDecl(hasName("::X"), isTemplateInstantiation()) + template <typename T> class X {}; + class A {}; + template <> class X<A> {}; + X<A> x; + +The matcher cxxRecordDecl(hasName("::X"), +isTemplateInstantiation()) does not match, as X<A> is an explicit template specialization. Usable as: Matcher<FunctionDecl>, Matcher<VarDecl>, Matcher<CXXRecordDecl> @@ -4711,17 +6348,25 @@

Narrowing Matchers

void g(int); template <typename... Ts> void h(Ts...); void i(); + +The matcher functionDecl(isVariadic()) +matches void f(...), +but does not match void g(int), +template <typename... Ts> void h(Ts...), +or void i(). Matcher<FunctionDecl>isWeak
Matches weak function declarations.
 
-Given:
-  void foo() __attribute__((__weakref__("__foo")));
-  void bar();
-functionDecl(isWeak())
-  matches the weak declaration "foo", but not "bar".
+Given
+  static void f();
+  void g() __attribute__((weak));
+The matcher functionDecl(isWeak())
+  matches the weak declaration
+void g() __attribute__((weak)),
+but does not match static void foo_v1().
 
@@ -4735,43 +6380,71 @@

Narrowing Matchers

void h(int i, int j); void j(int i); void k(int x, int y, int z, ...); -functionDecl(parameterCountIs(2)) - matches g and h -functionProtoType(parameterCountIs(2)) - matches g and h -functionProtoType(parameterCountIs(3)) - matches k +The matcher functionDecl(parameterCountIs(2)) +matches g and h +The matcher functionProtoType(parameterCountIs(1)) +matches the type void (int) of f and j. +The matcher functionProtoType(parameterCountIs(3)) matches the +type void (int, int, int, ...) of k. Matcher<FunctionProtoType>hasDynamicExceptionSpec
Matches functions that have a dynamic exception specification.
 
-Given:
-  void f();
-  void g() noexcept;
-  void h() noexcept(true);
-  void i() noexcept(false);
-  void j() throw();
-  void k() throw(int);
-  void l() throw(...);
-functionDecl(hasDynamicExceptionSpec()) and
-  functionProtoType(hasDynamicExceptionSpec())
-  match the declarations of j, k, and l, but not f, g, h, or i.
+Given
+  void f(int);
+  void g(int) noexcept;
+  void h(int) noexcept(true);
+  void i(int) noexcept(false);
+  void j(int) throw();
+  void k(int) throw(int);
+  void l(int) throw(...);
+
+The matcher functionDecl(hasDynamicExceptionSpec())
+matches the declarations void j(int) throw(),
+void k(int) throw(int)
+and void l(int) throw(...),
+but does not match void f(int), void g(int) noexcept,
+void h(int) noexcept(true)
+or void i(int) noexcept(true).
+The matcher
+functionProtoType(hasDynamicExceptionSpec()) matches
+the type void (int) throw() of j ,
+the type void (int) throw(int) of k and
+the type void (int) throw(...) of l .
+It does not match
+the type void (int) noexcept of f ,
+the type void (int) noexcept of g ,
+the type void (int) noexcept(int) of h or
+the type void (int) noexcept(...) of i .
 
Matcher<FunctionProtoType>isNoThrow
Matches functions that have a non-throwing exception specification.
 
-Given:
-  void f();
-  void g() noexcept;
-  void h() throw();
-  void i() throw(int);
-  void j() noexcept(false);
-functionDecl(isNoThrow()) and functionProtoType(isNoThrow())
-  match the declarations of g, and h, but not f, i or j.
+Given
+  void f(int);
+  void g(int) noexcept;
+  void h(int) noexcept(false);
+  void i(int) throw();
+  void j(int) throw(int);
+
+The matcher functionDecl(isNoThrow())
+matches the declaration void g(int) noexcept
+and void i(int) throw(),
+but does not match void f(int),
+void h(int) noexcept(false)
+or void j(int) throw(int).
+The matcher
+functionProtoType(isNoThrow())
+matches the type void (int) throw() of i
+and the type void (int) noexcept of g,
+but does not match
+the type void (int) of f ,
+the type void (int) noexcept(false) of h or
+the type void (int) throw(int) of j .
 
@@ -4785,12 +6458,12 @@

Narrowing Matchers

void h(int i, int j); void j(int i); void k(int x, int y, int z, ...); -functionDecl(parameterCountIs(2)) - matches g and h -functionProtoType(parameterCountIs(2)) - matches g and h -functionProtoType(parameterCountIs(3)) - matches k +The matcher functionDecl(parameterCountIs(2)) +matches g and h +The matcher functionProtoType(parameterCountIs(1)) +matches the type void (int) of f and j. +The matcher functionProtoType(parameterCountIs(3)) matches the +type void (int, int, int, ...) of k. @@ -4798,15 +6471,18 @@

Narrowing Matchers

Matches consteval function declarations and if consteval/if ! consteval
 statements.
 
-Given:
+Given
   consteval int a();
   void b() { if consteval {} }
   void c() { if ! consteval {} }
   void d() { if ! consteval {} else {} }
-functionDecl(isConsteval())
-  matches the declaration of "int a()".
-ifStmt(isConsteval())
-  matches the if statement in "void b()", "void c()", "void d()".
+
+The matcher functionDecl(isConsteval())
+matches a.
+The matcher ifStmt(isConsteval())
+matches the if statements
+if consteval {}, if ! consteval {} and
+if ! consteval {} else {}.
 
@@ -4814,16 +6490,17 @@

Narrowing Matchers

Matches constexpr variable and function declarations,
        and if constexpr.
 
-Given:
+Given
   constexpr int foo = 42;
   constexpr int bar();
   void baz() { if constexpr(1 > 0) {} }
-varDecl(isConstexpr())
-  matches the declaration of foo.
-functionDecl(isConstexpr())
-  matches the declaration of bar.
-ifStmt(isConstexpr())
-  matches the if statement in baz.
+
+The matcher varDecl(isConstexpr())
+matches foo.
+The matcher functionDecl(isConstexpr())
+matches bar.
+The matcher ifStmt(isConstexpr())
+matches if constexpr(1 > 0) {}.
 
@@ -4835,22 +6512,27 @@

Narrowing Matchers

Matches literals that are equal to the given value of type ValueT.
 
 Given
+void f(char, bool, double, int);
+void foo() {
   f('false, 3.14, 42);
-characterLiteral(equals(0))
-  matches 'cxxBoolLiteral(equals(false)) and cxxBoolLiteral(equals(0))
-  match false
-floatLiteral(equals(3.14)) and floatLiteral(equals(314e-2))
-  match 3.14
-integerLiteral(equals(42))
-  matches 42
+}
+
+The matcher characterLiteral(equals(0U)) matches 'The matchers cxxBoolLiteral(equals(false)) and
+cxxBoolLiteral(equals(0)) match false.
+The matcher floatLiteral(equals(3.14)) matches 3.14.
+The matcher integerLiteral(equals(42)) matches 42.
 
 Note that you cannot directly match a negative numeric literal because the
 minus sign is not part of the literal: It is a unary operator whose operand
 is the positive numeric literal. Instead, you must use a unaryOperator()
 matcher to match the minus sign:
 
-unaryOperator(hasOperatorName("-"),
-              hasUnaryOperand(integerLiteral(equals(13))))
+Given
+  int val = -1;
+
+The matcher unaryOperator(hasOperatorName("-"),
+              hasUnaryOperand(integerLiteral(equals(1))))
+matches -1.
 
 Usable as: Matcher<CharacterLiteral>, Matcher<CXXBoolLiteralExpr>,
            Matcher<FloatingLiteral>, Matcher<IntegerLiteral>
@@ -4876,14 +6558,30 @@ 

Narrowing Matchers

return l(); } }; + +The matcher lambdaExpr(hasAnyCapture(lambdaCapture(capturesThis()))) - matches `[this]() { return cc; }`. +matches [this]() { return cc; }.
Matcher<LambdaCapture>isImplicit
Matches an entity that has been implicitly added by the compiler (e.g.
 implicit default/copy constructors).
+
+Given
+  struct S {};
+  void f(S obj) {
+    S copy = obj;
+    [&](){ return copy; };
+  }
+
+
+The matcher cxxConstructorDecl(isImplicit(), isCopyConstructor())
+matches the implicit copy constructor of S.
+The matcher lambdaExpr(forEachLambdaCapture(
+    lambdaCapture(isImplicit()))) matches [&](){ return copy; },
+because it implicitly captures copy .
 
@@ -4902,14 +6600,25 @@

Narrowing Matchers

}; template <class T> class Z { - void x() { this->m; } + void x() { + this->m; + this->t; + this->t->m; + } + int m; + T* t; }; -memberExpr(isArrow()) - matches this->x, x, y.x, a, this->b -cxxDependentScopeMemberExpr(isArrow()) - matches this->m -unresolvedMemberExpr(isArrow()) - matches this->f<T>, f<T> + +The matcher memberExpr(isArrow()) +matches this->x, x, a, +this->b, this->m and two times this->t, +once for the standalone member expression, and once for the member +expression that later accesses m . +Additionally, it does not match this->t->t. +The matcher cxxDependentScopeMemberExpr(isArrow()) +matches this->t->m, but not this->m or this->t. +The matcher unresolvedMemberExpr(isArrow()) +matches this->f<T>, f<T> @@ -4917,29 +6626,43 @@

Narrowing Matchers

Matches NamedDecl nodes that have any of the specified names.
 
 This matcher is only provided as a performance optimization of hasName.
-    hasAnyName(a, b, c)
- is equivalent to, but faster than
-    anyOf(hasName(a), hasName(b), hasName(c))
+
+Given
+  void f(int a, int b);
+
+The matcher namedDecl(hasAnyName("a", "b")),
+which is equivalent to the matcher
+namedDecl(hasAnyName("a", "b")),
+matches int a and int b, but not
+void f(int a, int b).
 
Matcher<NamedDecl>hasExternalFormalLinkage
Matches a declaration that has external formal linkage.
 
-Example matches only z (matcher = varDecl(hasExternalFormalLinkage()))
+Given
 void f() {
-  int x;
-  static int y;
+  int a;
+  static int b;
 }
-int z;
+int c;
+static int d;
+The matcher varDecl(hasExternalFormalLinkage())
+matches int c,
+but not int a, static int b or int d.
 
-Example matches f() because it has external formal linkage despite being
-unique to the translation unit as though it has internal likage
-(matcher = functionDecl(hasExternalFormalLinkage()))
+Given
+  namespace {
+    void f() {}
+  }
+  void g() {}
+  static void h() {}
 
-namespace {
-void f() {}
-}
+
+The matcher functionDecl(hasExternalFormalLinkage())
+matches void g() {}, but not void f() {} or
+static void h() {}.
 
@@ -4950,11 +6673,22 @@

Narrowing Matchers

with '<enclosing>::'. Does not match typedefs of an underlying type with the given name. -Example matches X (Name == "X") +Given class X; -Example matches X (Name is one of "::a::b::X", "a::b::X", "b::X", "X") + +The matcher namedDecl(hasName("X")) +matches class X. + +Given namespace a { namespace b { class X; } } + + +The matchers namedDecl(hasName("::a::b::X")), +namedDecl(hasName("a::b::X")), +namedDecl(hasName("b::X")) and +namedDecl(hasName("X")) +match class X. @@ -4966,12 +6700,13 @@

Narrowing Matchers

prefixing the name with '<enclosing>::'. Does not match typedefs of an underlying type with the given name. -Example matches X (regexp == "::X") - class X; - -Example matches X (regexp is one of "::X", "^foo::.*X", among others) +Given namespace foo { namespace bar { class X; } } + +The matcher namedDecl(matchesName("^::foo:.*X")) +matches class X. + If the matcher is used in clang-query, RegexFlags parameter should be passed as a quoted string. e.g: "NoFlags". Flags can be combined with '|' example "IgnoreCase | BasicRegex" @@ -4985,7 +6720,9 @@

Narrowing Matchers

namespace n { namespace {} // #1 } -namespaceDecl(isAnonymous()) will match #1 but not ::n. + +The matcher namespaceDecl(isAnonymous()) +matches namespace {}, but not namespace n. @@ -5000,9 +6737,10 @@

Narrowing Matchers

inline namespace m {} } inline int Foo = 5; -functionDecl(isInline()) will match ::f(). -namespaceDecl(isInline()) will match n::m. -varDecl(isInline()) will match Foo; + +The matcher functionDecl(isInline()) matches f. +The matcher namespaceDecl(isInline()) matches m. +The matcher varDecl(isInline()) matches Foo @@ -5011,15 +6749,23 @@

Narrowing Matchers

specified. Given + void foo() { + #pragma omp parallel + ; + #pragma omp parallel default(none) + ; + #pragma omp parallel default(shared) + ; + #pragma omp parallel default(private) + ; + #pragma omp parallel default(firstprivate) + ; + } - #pragma omp parallel - #pragma omp parallel default(none) - #pragma omp parallel default(shared) - #pragma omp parallel default(private) - #pragma omp parallel default(firstprivate) -``ompDefaultClause(isFirstPrivateKind())`` matches only -``default(firstprivate)``. +The matcher +ompExecutableDirective(hasAnyClause(ompDefaultClause(isFirstPrivateKind()))) +matches #pragma omp parallel default(firstprivate). @@ -5027,14 +6773,23 @@

Narrowing Matchers

Matches if the OpenMP ``default`` clause has ``none`` kind specified.
 
 Given
+  void foo() {
+    #pragma omp parallel
+      ;
+    #pragma omp parallel default(none)
+      ;
+    #pragma omp parallel default(shared)
+      ;
+    #pragma omp parallel default(private)
+      ;
+    #pragma omp parallel default(firstprivate)
+      ;
+  }
 
-  #pragma omp parallel
-  #pragma omp parallel default(none)
-  #pragma omp parallel default(shared)
-  #pragma omp parallel default(private)
-  #pragma omp parallel default(firstprivate)
 
-``ompDefaultClause(isNoneKind())`` matches only ``default(none)``.
+The matcher
+ompExecutableDirective(hasAnyClause(ompDefaultClause(isNoneKind())))
+matches only #pragma omp parallel default(none).
 
@@ -5043,15 +6798,23 @@

Narrowing Matchers

specified. Given - - #pragma omp parallel + void foo() { + #pragma omp parallel + ; #pragma omp parallel default(none) + ; #pragma omp parallel default(shared) + ; #pragma omp parallel default(private) + ; #pragma omp parallel default(firstprivate) + ; + } + -``ompDefaultClause(isPrivateKind())`` matches only -``default(private)``. +The matcher +ompExecutableDirective(hasAnyClause(ompDefaultClause(isPrivateKind()))) +matches #pragma omp parallel default(private). @@ -5059,14 +6822,23 @@

Narrowing Matchers

Matches if the OpenMP ``default`` clause has ``shared`` kind specified.
 
 Given
-
-  #pragma omp parallel
-  #pragma omp parallel default(none)
+  void foo() {
+    #pragma omp parallel
+      ;
+    #pragma omp parallel default(none)
+      ;
   #pragma omp parallel default(shared)
+      ;
   #pragma omp parallel default(private)
+      ;
   #pragma omp parallel default(firstprivate)
+      ;
+  }
 
-``ompDefaultClause(isSharedKind())`` matches only ``default(shared)``.
+
+The matcher
+ompExecutableDirective(hasAnyClause(ompDefaultClause(isSharedKind())))
+matches #pragma omp parallel default(shared).
 
@@ -5075,13 +6847,21 @@

Narrowing Matchers

clause kind. Given + void foo() { + #pragma omp parallel + ; + #pragma omp parallel for + for (int i = 0; i < 10; ++i) {} + #pragma omp for + for (int i = 0; i < 10; ++i) {} + } - #pragma omp parallel - #pragma omp parallel for - #pragma omp for -`ompExecutableDirective(isAllowedToContainClause(OMPC_default))`` matches -``omp parallel`` and ``omp parallel for``. +The matcher +ompExecutableDirective(isAllowedToContainClauseKind( +OpenMPClauseKind::OMPC_default)) +matches #pragma omp parallel +and #pragma omp parallel for. If the matcher is use from clang-query, ``OpenMPClauseKind`` parameter should be passed as a quoted string. e.g., @@ -5094,29 +6874,89 @@

Narrowing Matchers

i.e., directives that can't have a structured block. Given + void foo() { + #pragma omp parallel + { + #pragma omp taskyield + } + } - #pragma omp parallel - {} - #pragma omp taskyield -``ompExecutableDirective(isStandaloneDirective()))`` matches -``omp taskyield``. +The matcher ompExecutableDirective(isStandaloneDirective()) +matches #pragma omp taskyield. Matcher<ObjCInterfaceDecl>isDerivedFromstd::string BaseName
Overloaded method as shortcut for isDerivedFrom(hasName(...)).
+
+Matches C++ classes that are directly or indirectly derived from a class
+matching Base, or Objective-C classes that directly or indirectly
+subclass a class matching Base.
+
+Note that a class is not considered to be derived from itself.
+
+Example matches Y, Z, C (Base == hasName("X"))
+  class X {};
+  class Y : public X {};  // directly derived
+  class Z : public Y {};  // indirectly derived
+  typedef X A;
+  typedef A B;
+  class C : public B {};  // derived from a typedef of X
+
+  class Foo {};
+  typedef Foo Alias;
+  class Bar : public Alias {};  // derived from Alias, which is a
+                                // typedef of Foo
+
+
+The matcher cxxRecordDecl(isDerivedFrom("X"))
+matches Y, Z and C.
+The matcher cxxRecordDecl(isDerivedFrom("Foo"))
+matches Bar.
+
+In the following example, Bar matches isDerivedFrom(hasName("NSObject"))
+  @interface NSObject @end
+  @interface Bar : NSObject @end
+
+
+Usable as: Matcher<CXXRecordDecl>, Matcher<ObjCInterfaceDecl>
 
Matcher<ObjCInterfaceDecl>isDirectlyDerivedFromstd::string BaseName
Overloaded method as shortcut for isDirectlyDerivedFrom(hasName(...)).
+
+Given
+  struct Base {};
+  struct DirectlyDerived : public Base {};
+  struct IndirectlyDerived : public DirectlyDerived {};
+
+
+The matcher cxxRecordDecl(isDirectlyDerivedFrom("Base"))
+matches DirectlyDerived, but not
+IndirectlyDerived.
 
Matcher<ObjCInterfaceDecl>isSameOrDerivedFromstd::string BaseName -
Overloaded method as shortcut for
+
Similar to isDerivedFrom(), but also matches classes that directly
+match Base.
+Overloaded method as shortcut for
 isSameOrDerivedFrom(hasName(...)).
+
+Given
+  class X {};
+  class Y : public X {};  // directly derived
+  class Z : public Y {};  // indirectly derived
+  typedef X A;
+  typedef A B;
+  class C : public B {};  // derived from a typedef of X
+
+The matcher
+cxxRecordDecl(isSameOrDerivedFrom("X"), isDefinition())
+matches class X {}, class Y : public X {},
+class Z : public Y {} and class C : public B {}.
 
@@ -5124,12 +6964,15 @@

Narrowing Matchers

Checks that a call expression or a constructor call expression has at least
 the specified number of arguments (including absent default arguments).
 
-Example matches f(0, 0) and g(0, 0, 0)
-(matcher = callExpr(argumentCountAtLeast(2)))
+Given
   void f(int x, int y);
   void g(int x, int y, int z);
-  f(0, 0);
-  g(0, 0, 0);
+  void foo() {
+    f(0, 0);
+    g(0, 0, 0);
+  }
+The matcher callExpr(argumentCountAtLeast(2))
+matches f(0, 0) and g(0, 0, 0)
 
@@ -5137,9 +6980,13 @@

Narrowing Matchers

Checks that a call expression or a constructor call expression has
 a specific number of arguments (including absent default arguments).
 
-Example matches f(0, 0) (matcher = callExpr(argumentCountIs(2)))
+Given
   void f(int x, int y);
-  f(0, 0);
+  void foo() {
+    f(0, 0);
+  }
+The matcher callExpr(argumentCountIs(2))
+matches f(0, 0)
 
@@ -5147,24 +6994,27 @@

Narrowing Matchers

Matches when at least one of the supplied string equals to the
 Selector.getAsString()
 
- matcher = objCMessageExpr(hasSelector("methodA:", "methodB:"));
- matches both of the expressions below:
     [myObj methodA:argA];
     [myObj methodB:argB];
+
+ The matcher objCMessageExpr(hasSelector("methodA:", "methodB:"));
+ matches [myObj methodA:argA]; and [myObj methodB:argB];
 
Matcher<ObjCMessageExpr>hasKeywordSelector
Matches when the selector is a keyword selector
 
-objCMessageExpr(hasKeywordSelector()) matches the generated setFrame
-message expression in
-
+Given
   UIWebView *webView = ...;
   CGRect bodyFrame = webView.frame;
   bodyFrame.size.height = self.bodyContentHeight;
   webView.frame = bodyFrame;
   //     ^---- matches here
+
+
+The matcher objCMessageExpr(hasKeywordSelector()) matches the
+generated setFrame message expression in
 
@@ -5179,56 +7029,68 @@

Narrowing Matchers

Matcher<ObjCMessageExpr>hasSelectorstd::string BaseName
Matches when BaseName == Selector.getAsString()
 
- matcher = objCMessageExpr(hasSelector("loadHTMLString:baseURL:"));
- matches the outer message expr in the code below, but NOT the message
- invocation for self.bodyView.
     [self.bodyView loadHTMLString:html baseURL:NULL];
+
+The matcher
+objCMessageExpr(hasSelector("loadHTMLString:baseURL:")); matches
+the outer message expr in the code below, but NOT the message invocation
+for self.bodyView.
 
Matcher<ObjCMessageExpr>hasUnarySelector
Matches when the selector is a Unary Selector
 
- matcher = objCMessageExpr(matchesSelector(hasUnarySelector());
- matches self.bodyView in the code below, but NOT the outer message
- invocation of "loadHTMLString:baseURL:".
+Given
     [self.bodyView loadHTMLString:html baseURL:NULL];
+
+
+ The matcher objCMessageExpr(matchesSelector(hasUnarySelector());
+ matches self.bodyView, but does not match the outer message
+ invocation of "loadHTMLString:baseURL:".
 
Matcher<ObjCMessageExpr>isClassMessage
Returns true when the Objective-C message is sent to a class.
 
-Example
-matcher = objcMessageExpr(isClassMessage())
-matches
+Given
   [NSString stringWithFormat:@"format"];
-but not
   NSString *x = @"hello";
   [x containsString:@"h"];
+
+The matcher objcMessageExpr(isClassMessage())
+matches [NSString stringWithFormat:@"format"];
+but does not match [[x containsString:@"h"]
 
Matcher<ObjCMessageExpr>isInstanceMessage
Returns true when the Objective-C message is sent to an instance.
 
-Example
-matcher = objcMessageExpr(isInstanceMessage())
-matches
+Given
   NSString *x = @"hello";
   [x containsString:@"h"];
-but not
   [NSString stringWithFormat:@"format"];
+
+The matcher objcMessageExpr(isInstanceMessage())
+matches [x containsString:@"h"];
+but does not match [NSString stringWithFormat:@"format"];
 
Matcher<ObjCMessageExpr>matchesSelectorStringRef RegExp, Regex::RegexFlags Flags = NoFlags
Matches ObjC selectors whose name contains
 a substring matched by the given RegExp.
- matcher = objCMessageExpr(matchesSelector("loadHTMLStringmatches the outer message expr in the code below, but NOT the message
- invocation for self.bodyView.
+
+Given
     [self.bodyView loadHTMLString:html baseURL:NULL];
 
+
+The matcher
+objCMessageExpr(matchesSelector("loadHTMLStringmatches the outer message expr in the code below, but NOT the message
+invocation for self.bodyView.
+
 If the matcher is used in clang-query, RegexFlags parameter
 should be passed as a quoted string. e.g: "NoFlags".
 Flags can be combined with '|' example "IgnoreCase | BasicRegex"
@@ -5238,25 +7100,26 @@ 

Narrowing Matchers

Matcher<ObjCMessageExpr>numSelectorArgsunsigned N
Matches when the selector has the specified number of arguments
 
- matcher = objCMessageExpr(numSelectorArgs(0));
- matches self.bodyView in the code below
-
- matcher = objCMessageExpr(numSelectorArgs(2));
- matches the invocation of "loadHTMLString:baseURL:" but not that
- of self.bodyView
     [self.bodyView loadHTMLString:html baseURL:NULL];
+
+The matcher objCMessageExpr(numSelectorArgs(0))
+matches self.bodyView.
+The matcher objCMessageExpr(numSelectorArgs(2))
+matches the invocation of loadHTMLString:baseURL:
+but does not match self.bodyView
 
Matcher<ObjCMethodDecl>isClassMethod
Returns true when the Objective-C method declaration is a class method.
 
-Example
-matcher = objcMethodDecl(isClassMethod())
-matches
+Given
 @interface I + (void)foo; @end
-but not
 @interface I - (void)bar; @end
+
+The matcher objcMethodDecl(isClassMethod())
+matches @interface I + (void)foo; @end
+but does not match interface I + (void)foo; @end
 
@@ -5270,6 +7133,14 @@

Narrowing Matchers

extern int vb; // Doesn't match, as it doesn't define the variable. void fa() {} void fb(); // Doesn't match, as it has no body. + +The matcher tagDecl(isDefinition()) +matches A +The matcher varDecl(isDefinition()) +matches va +The matcher functionDecl(isDefinition()) +matches fa + @interface X - (void)ma; // Doesn't match, interface is declaration. @end @@ -5277,6 +7148,9 @@

Narrowing Matchers

- (void)ma {} @end +The matcher objcMethodDecl(isDefinition()) +matches - (void)ma {} + Usable as: Matcher<TagDecl>, Matcher<VarDecl>, Matcher<FunctionDecl>, Matcher<ObjCMethodDecl>
@@ -5285,33 +7159,39 @@

Narrowing Matchers

Matcher<ObjCMethodDecl>isInstanceMethod
Returns true when the Objective-C method declaration is an instance method.
 
-Example
-matcher = objcMethodDecl(isInstanceMethod())
-matches
+Given
 @interface I - (void)bar; @end
-but not
 @interface I + (void)foo; @end
+
+The matcher objcMethodDecl(isInstanceMethod())
+matches @interface I - (void)bar; @end
+but does not match @interface I - (void)foo; @end
+
 
Matcher<ParmVarDecl>hasDefaultArgument
Matches a declaration that has default arguments.
 
-Example matches y (matcher = parmVarDecl(hasDefaultArgument()))
-void x(int val) {}
-void y(int val = 0) {}
+Given
+  void x(int val) {}
+  void y(int val = 0) {}
+
+
+The matcher parmVarDecl(hasDefaultArgument())
+matches int val = 0.
 
 Deprecated. Use hasInitializer() instead to be able to
 match on the contents of the default argument.  For example:
 
-void x(int val = 7) {}
-void y(int val = 42) {}
-parmVarDecl(hasInitializer(integerLiteral(equals(42))))
-  matches the parameter of y
+Given
+  void x(int val = 7) {}
+  void y(int val = 42) {}
+
 
-A matcher such as
-  parmVarDecl(hasInitializer(anything()))
-is equivalent to parmVarDecl(hasDefaultArgument()).
+The matcher
+parmVarDecl(hasInitializer(integerLiteral(equals(42)))),
+matches int val = 42.
 
@@ -5326,9 +7206,9 @@

Narrowing Matchers

void f(int a, int b, int c) { } -``parmVarDecl(isAtPosition(0))`` matches ``int a``. - -``parmVarDecl(isAtPosition(1))`` matches ``int b``. +The matcher parmVarDecl(isAtPosition(0)) matches +a. The matcher parmVarDecl(isAtPosition(1)) +matches b.
@@ -5338,8 +7218,9 @@

Narrowing Matchers

Given class Y { public: void x(); }; void z() { Y* y; y->x(); } -cxxMemberCallExpr(on(hasType(asString("class Y *")))) - matches y->x() + +The matcher cxxMemberCallExpr(on(hasType(asString("Y *")))) +matches y->x() @@ -5350,10 +7231,11 @@

Narrowing Matchers

Given class X { int a; int b; }; -cxxRecordDecl( + +The matcher cxxRecordDecl( has(fieldDecl(hasName("a"), hasType(type().bind("t")))), has(fieldDecl(hasName("b"), hasType(type(equalsBoundNode("t")))))) - matches the class X, as a and b have the same type. + matches X, as a and b have the same type. Note that when multiple matches are involved via forEach* matchers, equalsBoundNodes acts as a filter. @@ -5372,12 +7254,15 @@

Narrowing Matchers

Given typedef const int const_int; - const_int i; - int *const j; + const_int i = 0; + int *const j = nullptr; int *volatile k; int m; -varDecl(hasType(hasLocalQualifiers())) matches only j and k. -i is const-qualified but the qualifier is not local. + + +The matcher varDecl(hasType(hasLocalQualifiers())) matches only +j and k. is +const-qualified but the qualifier is not local. @@ -5388,9 +7273,11 @@

Narrowing Matchers

void a(char); void b(wchar_t); void c(double); + + +The matcher functionDecl(hasAnyParameter(hasType(isAnyCharacter()))) -matches "a(char)", "b(wchar_t)", but not "c(double)". - +a, b, but not Matcher<QualType>isAnyPointer @@ -5406,8 +7293,9 @@

Narrowing Matchers

Foo *f; int j; -varDecl(hasType(isAnyPointer())) - matches "int *i" and "Foo *f", but not "int j". + +The matcher varDecl(hasType(isAnyPointer())) +int *i and Foo *f, but not int j. @@ -5421,9 +7309,11 @@

Narrowing Matchers

void c(const int); void d(const int*); void e(int const) {}; +The matcher functionDecl(hasAnyParameter(hasType(isConstQualified()))) - matches "void b(int const)", "void c(const int)" and - "void e(int const) {}". It does not match d as there + matches b, c and + e. + It does not match as there is no top-level const on the parameter type "const int *". @@ -5435,8 +7325,8 @@

Narrowing Matchers

void a(int); void b(long); void c(double); -functionDecl(hasAnyParameter(hasType(isInteger()))) -matches "a(int)", "b(long)", but not "c(double)". +The matcher functionDecl(hasAnyParameter(hasType(isInteger()))) +a, b, but not c. @@ -5447,8 +7337,9 @@

Narrowing Matchers

void a(int); void b(unsigned long); void c(double); -functionDecl(hasAnyParameter(hasType(isSignedInteger()))) -matches "a(int)", but not "b(unsigned long)" and "c(double)". +The matcher +functionDecl(hasAnyParameter(hasType(isSignedInteger()))) matches +a, but not and not @@ -5459,8 +7350,10 @@

Narrowing Matchers

void a(int); void b(unsigned long); void c(double); +The matcher functionDecl(hasAnyParameter(hasType(isUnsignedInteger()))) -matches "b(unsigned long)", but not "a(int)" and "c(double)". +matches b, +but does not match a and c. @@ -5474,9 +7367,11 @@

Narrowing Matchers

void c(volatile int); void d(volatile int*); void e(int volatile) {}; +The matcher functionDecl(hasAnyParameter(hasType(isVolatileQualified()))) - matches "void b(int volatile)", "void c(volatile int)" and - "void e(int volatile) {}". It does not match d as there + matches b, c and + e. + It does not match as there is no top-level volatile on the parameter type "volatile int *". @@ -5488,10 +7383,11 @@

Narrowing Matchers

Given class X { int a; int b; }; -cxxRecordDecl( + +The matcher cxxRecordDecl( has(fieldDecl(hasName("a"), hasType(type().bind("t")))), has(fieldDecl(hasName("b"), hasType(type(equalsBoundNode("t")))))) - matches the class X, as a and b have the same type. + matches X, as a and b have the same type. Note that when multiple matches are involved via forEach* matchers, equalsBoundNodes acts as a filter. @@ -5504,7 +7400,7 @@

Narrowing Matchers

-Matcher<Stmt>equalsNodeconst Stmt* Other +Matcher<Stmt>equalsNodeconst Stmt * Other
Matches if a node equals another node.
 
 Stmt has pointer identity in the AST.
@@ -5516,6 +7412,15 @@ 

Narrowing Matchers

Does not match if only part of the statement is expanded from that macro or if different parts of the statement are expanded from different appearances of the macro. + +Given + #define A 0 + #define B A + int c = B; + +The matcher integerLiteral(isExpandedFromMacro("A")) +matches the literal expanded at the initializer B of the variable +c .
@@ -5523,12 +7428,25 @@

Narrowing Matchers

Matches AST nodes that were expanded within files whose name is
 partially matching a given regex.
 
-Example matches Y but not X
-    (matcher = cxxRecordDecl(isExpansionInFileMatching("AST.*"))
-  #include "ASTMatcher.h"
-  class X {};
-ASTMatcher.h:
-  class Y {};
+Given the headers Y.h
+  #pragma once
+  typedef int my_y_int;
+and X.h
+  #pragma once
+  typedef int my_x_int;
+and the source code
+  #include "X.h"
+  #include "Y.h"
+  typedef int my_main_file_int;
+  my_main_file_int a = 0;
+  my_x_int b = 1;
+  my_y_int c = 2;
+
+The matcher
+typedefDecl(isExpansionInFileMatching("Y.h"))
+matches typedef int my_y_int,
+but does not match typedef int my_main_file_int or
+typedef int my_x_int.
 
 Usable as: Matcher<Decl>, Matcher<Stmt>, Matcher<TypeLoc>
 
@@ -5541,12 +7459,18 @@ 

Narrowing Matchers

Matcher<Stmt>isExpansionInMainFile
Matches AST nodes that were expanded within the main-file.
 
-Example matches X but not Y
-  (matcher = cxxRecordDecl(isExpansionInMainFile())
-  #include <Y.h>
-  class X {};
-Y.h:
-  class Y {};
+Given the header Y.h
+  #pragma once
+  typedef int my_header_int;
+and the source file
+  #include "Y.h"
+  typedef int my_main_file_int;
+  my_main_file_int a = 0;
+  my_header_int b = 1;
+
+The matcher typedefDecl(isExpansionInMainFile())
+matches typedef int my_main_file_int,
+but does not match typedef int my_header_int.
 
 Usable as: Matcher<Decl>, Matcher<Stmt>, Matcher<TypeLoc>
 
@@ -5555,12 +7479,17 @@

Narrowing Matchers

Matcher<Stmt>isExpansionInSystemHeader
Matches AST nodes that were expanded within system-header-files.
 
-Example matches Y but not X
-    (matcher = cxxRecordDecl(isExpansionInSystemHeader())
+Given the header SystemHeader.h
+  #pragma once
+  int header();
+and the source code
   #include <SystemHeader.h>
-  class X {};
-SystemHeader.h:
-  class Y {};
+  static int main_file();
+
+
+The matcher functionDecl(isExpansionInSystemHeader())
+matches int header(),
+but does not match static int main_file().
 
 Usable as: Matcher<Decl>, Matcher<Stmt>, Matcher<TypeLoc>
 
@@ -5571,14 +7500,18 @@

Narrowing Matchers

Given int j; - template<typename T> void A(T t) { T i; j += 42;} - A(0); - A(0U); -declStmt(isInTemplateInstantiation()) - matches 'int i;' and 'unsigned i'. -unless(stmt(isInTemplateInstantiation())) - will NOT match j += 42; as it's shared between the template definition and - instantiation. + template<typename T> void A(T t) { T i; } + void foo() { + A(0); + A(0U); + } + +The matcher declStmt(isInTemplateInstantiation()) +matches T i; twice, once for int and once for +int}. +The matcher declStmt(unless(isInTemplateInstantiation())) will +match T i; once inside the template definition, but not for any of +the instantiated bodies.
@@ -5592,21 +7525,28 @@

Narrowing Matchers

char *s = "abcd"; wchar_t *ws = L"abcd"; char *w = "a"; -constantArrayType(hasSize(42)) - matches "int a[42]" and "int b[2 * 21]" -stringLiteral(hasSize(4)) - matches "abcd", L"abcd" + +The matcher constantArrayType(hasSize(42)) +matches int[42] twice. +The matcher stringLiteral(hasSize(4)) +matches "abcd" and L"abcd". Matcher<TagDecl>isClass
Matches TagDecl object that are spelled with "class."
 
-Example matches C, but not S, U or E.
+Given
   struct S {};
   class C {};
   union U {};
-  enum E {};
+  enum E { Ok };
+
+The matcher tagDecl(isClass())
+matches class C,
+but does not match struct S,
+union U
+or enum E.
 
@@ -5620,6 +7560,14 @@

Narrowing Matchers

extern int vb; // Doesn't match, as it doesn't define the variable. void fa() {} void fb(); // Doesn't match, as it has no body. + +The matcher tagDecl(isDefinition()) +matches A +The matcher varDecl(isDefinition()) +matches va +The matcher functionDecl(isDefinition()) +matches fa + @interface X - (void)ma; // Doesn't match, interface is declaration. @end @@ -5627,6 +7575,9 @@

Narrowing Matchers

- (void)ma {} @end +The matcher objcMethodDecl(isDefinition()) +matches - (void)ma {} + Usable as: Matcher<TagDecl>, Matcher<VarDecl>, Matcher<FunctionDecl>, Matcher<ObjCMethodDecl> @@ -5635,11 +7586,16 @@

Narrowing Matchers

Matcher<TagDecl>isEnum
Matches TagDecl object that are spelled with "enum."
 
-Example matches E, but not C, S or U.
+Given
   struct S {};
   class C {};
   union U {};
-  enum E {};
+  enum E { Ok };
+
+The matcher tagDecl(isEnum())
+matches enum E { Ok },
+but does not match struct S {},
+class C {} or union U {}.
 
@@ -5650,18 +7606,30 @@

Narrowing Matchers

struct S {}; class C {}; union U {}; - enum E {}; + enum E { Ok }; + +The matcher tagDecl(isStruct()) +matches struct S, +but does not match class C, +union U +or enum E. Matcher<TagDecl>isUnion
Matches TagDecl object that are spelled with "union."
 
-Example matches U, but not C, S or E.
+Given
   struct S {};
   class C {};
   union U {};
-  enum E {};
+  enum E { Ok };
+
+The matcher tagDecl(isUnion())
+matches union U,
+does not match struct S,
+class C
+or enum E.
 
@@ -5675,9 +7643,12 @@

Narrowing Matchers

Given template<int T> struct C {}; C<42> c; -classTemplateSpecializationDecl( + +The matcher classTemplateSpecializationDecl( hasAnyTemplateArgument(equalsIntegralValue("42"))) - matches the implicit instantiation of C in C<42>. +matches the implicitly declared specialization +struct C<42> from the instantiation for the type of the +variable c . @@ -5687,10 +7658,12 @@

Narrowing Matchers

Given template<int T> struct C {}; C<42> c; -classTemplateSpecializationDecl( + +The matcher classTemplateSpecializationDecl( hasAnyTemplateArgument(isIntegral())) - matches the implicit instantiation of C in C<42> - with isIntegral() matching 42. +matches the implicitly declared specialization +struct C<42> from the instantiation for the type of the +variable c . @@ -5700,8 +7673,10 @@

Narrowing Matchers

Given template<typename T> struct C {}; C<int> c; + +The matcher classTemplateSpecializationDecl(templateArgumentCountIs(1)) - matches C<int>. +matches struct C<int>. @@ -5710,6 +7685,15 @@

Narrowing Matchers

Does not match if only part of the statement is expanded from that macro or if different parts of the statement are expanded from different appearances of the macro. + +Given + #define A 0 + #define B A + int c = B; + +The matcher integerLiteral(isExpandedFromMacro("A")) +matches the literal expanded at the initializer B of the variable +c . @@ -5717,12 +7701,25 @@

Narrowing Matchers

Matches AST nodes that were expanded within files whose name is
 partially matching a given regex.
 
-Example matches Y but not X
-    (matcher = cxxRecordDecl(isExpansionInFileMatching("AST.*"))
-  #include "ASTMatcher.h"
-  class X {};
-ASTMatcher.h:
-  class Y {};
+Given the headers Y.h
+  #pragma once
+  typedef int my_y_int;
+and X.h
+  #pragma once
+  typedef int my_x_int;
+and the source code
+  #include "X.h"
+  #include "Y.h"
+  typedef int my_main_file_int;
+  my_main_file_int a = 0;
+  my_x_int b = 1;
+  my_y_int c = 2;
+
+The matcher
+typedefDecl(isExpansionInFileMatching("Y.h"))
+matches typedef int my_y_int,
+but does not match typedef int my_main_file_int or
+typedef int my_x_int.
 
 Usable as: Matcher<Decl>, Matcher<Stmt>, Matcher<TypeLoc>
 
@@ -5735,12 +7732,18 @@ 

Narrowing Matchers

Matcher<TypeLoc>isExpansionInMainFile
Matches AST nodes that were expanded within the main-file.
 
-Example matches X but not Y
-  (matcher = cxxRecordDecl(isExpansionInMainFile())
-  #include <Y.h>
-  class X {};
-Y.h:
-  class Y {};
+Given the header Y.h
+  #pragma once
+  typedef int my_header_int;
+and the source file
+  #include "Y.h"
+  typedef int my_main_file_int;
+  my_main_file_int a = 0;
+  my_header_int b = 1;
+
+The matcher typedefDecl(isExpansionInMainFile())
+matches typedef int my_main_file_int,
+but does not match typedef int my_header_int.
 
 Usable as: Matcher<Decl>, Matcher<Stmt>, Matcher<TypeLoc>
 
@@ -5749,12 +7752,17 @@

Narrowing Matchers

Matcher<TypeLoc>isExpansionInSystemHeader
Matches AST nodes that were expanded within system-header-files.
 
-Example matches Y but not X
-    (matcher = cxxRecordDecl(isExpansionInSystemHeader())
+Given the header SystemHeader.h
+  #pragma once
+  int header();
+and the source code
   #include <SystemHeader.h>
-  class X {};
-SystemHeader.h:
-  class Y {};
+  static int main_file();
+
+
+The matcher functionDecl(isExpansionInSystemHeader())
+matches int header(),
+but does not match static int main_file().
 
 Usable as: Matcher<Decl>, Matcher<Stmt>, Matcher<TypeLoc>
 
@@ -5765,8 +7773,9 @@

Narrowing Matchers

Given struct S { bool func(); }; -functionDecl(returns(booleanType())) - matches "bool func();" + +The matcher functionDecl(returns(booleanType())) +func
@@ -5777,10 +7786,11 @@

Narrowing Matchers

Given class X { int a; int b; }; -cxxRecordDecl( + +The matcher cxxRecordDecl( has(fieldDecl(hasName("a"), hasType(type().bind("t")))), has(fieldDecl(hasName("b"), hasType(type(equalsBoundNode("t")))))) - matches the class X, as a and b have the same type. + matches X, as a and b have the same type. Note that when multiple matches are involved via forEach* matchers, equalsBoundNodes acts as a filter. @@ -5793,7 +7803,7 @@

Narrowing Matchers

-Matcher<Type>equalsNodeconst Type* Other +Matcher<Type>equalsNodeconst Type * Other
Matches if a node equals another node.
 
 Type has pointer identity in the AST.
@@ -5806,8 +7816,9 @@ 

Narrowing Matchers

Given int i; float f; -realFloatingPointType() - matches "float f" but not "int i" +The matcher type(realFloatingPointType()) +matches float +but does not match int.
@@ -5816,8 +7827,10 @@

Narrowing Matchers

Given struct S { void func(); }; -functionDecl(returns(voidType())) - matches "void func();" + + +The matcher functionDecl(returns(voidType())) +func @@ -5826,9 +7839,10 @@

Narrowing Matchers

Given int x; - int s = sizeof(x) + alignof(x) -unaryExprOrTypeTraitExpr(ofKind(UETT_SizeOf)) - matches sizeof(x) + int s = sizeof(x) + alignof(x); + +The matcher unaryExprOrTypeTraitExpr(ofKind(UETT_SizeOf)) +matches sizeof(x) If the matcher is use from clang-query, UnaryExprOrTypeTrait parameter should be passed as a quoted string. e.g., ofKind("UETT_SizeOf"). @@ -5839,9 +7853,26 @@

Narrowing Matchers

Matches operator expressions (binary or unary) that have any of the
 specified names.
 
+It provides a compact way of writing if an operator has any of the specified
+names:
+The matcher
    hasAnyOperatorName("+", "-")
- Is equivalent to
-   anyOf(hasOperatorName("+"), hasOperatorName("-"))
+Is equivalent to
+   hasOperatorName("-"))}
+
+Given
+void foo(bool a, bool b) {
+  !(a || b);
+ }
+
+void bar(bool a, bool b) {
+  a && b;
+ }
+
+The matcher binaryOperator(hasAnyOperatorName("||", "&&"))
+matches a || b and a && b.
+The matcher unaryOperator(hasAnyOperatorName("-", "!"))
+matches !(a || b).
 
@@ -5849,15 +7880,22 @@

Narrowing Matchers

Matches the operator Name of operator expressions and fold expressions
 (binary or unary).
 
-Example matches a || b (matcher = binaryOperator(hasOperatorName("||")))
-  !(a || b)
+Given
+void foo(bool a, bool b) {
+  !(a || b);
+ }
+
+The matcher binaryOperator(hasOperatorName("||"))
+matches a || b
 
-Example matches `(0 + ... + args)`
-    (matcher = cxxFoldExpr(hasOperatorName("+")))
+Given
   template <typename... Args>
   auto sum(Args... args) {
       return (0 + ... + args);
   }
+
+The matcher cxxFoldExpr(hasOperatorName("+"))
+ matches (0 + ... + args).
 
@@ -5876,40 +7914,57 @@

Narrowing Matchers

}; template <class T> class Z { - void x() { this->m; } + void x() { + this->m; + this->t; + this->t->m; + } + int m; + T* t; }; -memberExpr(isArrow()) - matches this->x, x, y.x, a, this->b -cxxDependentScopeMemberExpr(isArrow()) - matches this->m -unresolvedMemberExpr(isArrow()) - matches this->f<T>, f<T> + +The matcher memberExpr(isArrow()) +matches this->x, x, a, +this->b, this->m and two times this->t, +once for the standalone member expression, and once for the member +expression that later accesses m . +Additionally, it does not match this->t->t. +The matcher cxxDependentScopeMemberExpr(isArrow()) +matches this->t->m, but not this->m or this->t. +The matcher unresolvedMemberExpr(isArrow()) +matches this->f<T>, f<T> Matcher<VarDecl>hasAutomaticStorageDuration
Matches a variable declaration that has automatic storage duration.
 
-Example matches x, but not y, z, or a.
-(matcher = varDecl(hasAutomaticStorageDuration())
+Given
 void f() {
   int x;
   static int y;
   thread_local int z;
 }
 int a;
+
+The matcher varDecl(hasAutomaticStorageDuration())
+matches x
+but does not match y, z or
+a
 
Matcher<VarDecl>hasGlobalStorage
Matches a variable declaration that does not have local storage.
 
-Example matches y and z (matcher = varDecl(hasGlobalStorage())
+Given
 void f() {
   int x;
   static int y;
 }
 int z;
+The matcher varDecl(hasGlobalStorage())
+matches y and z
 
@@ -5917,12 +7972,14 @@

Narrowing Matchers

Matches a variable declaration that has function scope and is a
 non-static local variable.
 
-Example matches x (matcher = varDecl(hasLocalStorage())
+Given
 void f() {
   int x;
   static int y;
 }
 int z;
+The matcher varDecl(hasLocalStorage())
+matches x
 
@@ -5939,22 +7996,28 @@

Narrowing Matchers

int a; static int b; extern int c; -varDecl(hasStaticStorageDuration()) - matches the function declaration y, a, b and c. + +The matcher varDecl(hasStaticStorageDuration()) +matches y, a, b and +c Matcher<VarDecl>hasThreadStorageDuration
Matches a variable declaration that has thread storage duration.
 
-Example matches z, but not x, z, or a.
-(matcher = varDecl(hasThreadStorageDuration())
+Given
 void f() {
   int x;
   static int y;
   thread_local int z;
 }
 int a;
+
+The matcher varDecl(hasThreadStorageDuration())
+matches z
+but does not match x, z or
+a
 
@@ -5962,29 +8025,34 @@

Narrowing Matchers

Matches constexpr variable and function declarations,
        and if constexpr.
 
-Given:
+Given
   constexpr int foo = 42;
   constexpr int bar();
   void baz() { if constexpr(1 > 0) {} }
-varDecl(isConstexpr())
-  matches the declaration of foo.
-functionDecl(isConstexpr())
-  matches the declaration of bar.
-ifStmt(isConstexpr())
-  matches the if statement in baz.
+
+The matcher varDecl(isConstexpr())
+matches foo.
+The matcher functionDecl(isConstexpr())
+matches bar.
+The matcher ifStmt(isConstexpr())
+matches if constexpr(1 > 0) {}.
 
Matcher<VarDecl>isConstinit
Matches constinit variable declarations.
 
-Given:
+Given
   constinit int foo = 42;
   constinit const char* bar = "bar";
   int baz = 42;
   [[clang::require_constant_initialization]] int xyz = 42;
-varDecl(isConstinit())
-  matches the declaration of `foo` and `bar`, but not `baz` and `xyz`.
+
+The matcher varDecl(isConstinit())
+matches the declaration of foo
+and bar,
+but does not match baz or
+xyz.
 
@@ -5998,6 +8066,14 @@

Narrowing Matchers

extern int vb; // Doesn't match, as it doesn't define the variable. void fa() {} void fb(); // Doesn't match, as it has no body. + +The matcher tagDecl(isDefinition()) +matches A +The matcher varDecl(isDefinition()) +matches va +The matcher functionDecl(isDefinition()) +matches fa + @interface X - (void)ma; // Doesn't match, interface is declaration. @end @@ -6005,6 +8081,9 @@

Narrowing Matchers

- (void)ma {} @end +The matcher objcMethodDecl(isDefinition()) +matches - (void)ma {} + Usable as: Matcher<TagDecl>, Matcher<VarDecl>, Matcher<FunctionDecl>, Matcher<ObjCMethodDecl> @@ -6014,12 +8093,15 @@

Narrowing Matchers

Matches a variable declaration that is an exception variable from
 a C++ catch block, or an Objective-C statement.
 
-Example matches x (matcher = varDecl(isExceptionVariable())
+Given
 void f(int y) {
   try {
   } catch (int x) {
   }
 }
+
+The matcher varDecl(isExceptionVariable())
+matches x
 
@@ -6030,8 +8112,9 @@

Narrowing Matchers

Given template<typename T> void A(T t) { } template<> void A(int N) { } -functionDecl(isExplicitTemplateSpecialization()) - matches the specialization A<int>(). + +The matcher functionDecl(isExplicitTemplateSpecialization()) + matches the specialization template<> void A(int N) { }. Usable as: Matcher<FunctionDecl>, Matcher<VarDecl>, Matcher<CXXRecordDecl> @@ -6040,17 +8123,21 @@

Narrowing Matchers

Matcher<VarDecl>isExternC
Matches extern "C" function or variable declarations.
 
-Given:
+Given
   extern "C" void f() {}
   extern "C" { void g() {} }
   void h() {}
   extern "C" int x = 1;
   extern "C" int y = 2;
   int z = 3;
-functionDecl(isExternC())
-  matches the declaration of f and g, but not the declaration of h.
-varDecl(isExternC())
-  matches the declaration of x and y, but not the declaration of z.
+
+The matcher functionDecl(isExternC())
+matches f
+and g.
+The matcher varDecl(isExternC())
+matches x
+and y,
+but does not match z.
 
@@ -6058,8 +8145,11 @@

Narrowing Matchers

Matches a variable serving as the implicit variable for a lambda init-
 capture.
 
-Example matches x (matcher = varDecl(isInitCapture()))
-auto f = [x=3]() { return x; };
+Given
+auto f = [x = 3]() { return x; };
+
+The matcher varDecl(isInitCapture())
+matches x = 3.
 
@@ -6074,21 +8164,24 @@

Narrowing Matchers

inline namespace m {} } inline int Foo = 5; -functionDecl(isInline()) will match ::f(). -namespaceDecl(isInline()) will match n::m. -varDecl(isInline()) will match Foo; + +The matcher functionDecl(isInline()) matches f. +The matcher namespaceDecl(isInline()) matches m. +The matcher varDecl(isInline()) matches Foo Matcher<VarDecl>isStaticLocal
Matches a static variable with local scope.
 
-Example matches y (matcher = varDecl(isStaticLocal()))
+Given
 void f() {
   int x;
   static int y;
 }
 static int z;
+The matcher varDecl(isStaticLocal())
+matches y
 
@@ -6096,15 +8189,15 @@

Narrowing Matchers

Matches variable/function declarations that have "static" storage
 class specifier ("static" keyword) written in the source.
 
-Given:
+Given
   static void f() {}
   static int i = 0;
   extern int j;
   int k;
-functionDecl(isStaticStorageClass())
-  matches the function declaration f.
-varDecl(isStaticStorageClass())
-  matches the variable declaration i.
+The matcher functionDecl(isStaticStorageClass())
+  matches f
+The matcher varDecl(isStaticStorageClass())
+  matches i
 
@@ -6113,18 +8206,36 @@

Narrowing Matchers

member variable template instantiations. Given - template <typename T> class X {}; class A {}; X<A> x; -or - template <typename T> class X {}; class A {}; template class X<A>; -or - template <typename T> class X {}; class A {}; extern template class X<A>; -cxxRecordDecl(hasName("::X"), isTemplateInstantiation()) - matches the template instantiation of X<A>. + template <typename T> class X {}; + class A {}; + X<A> x; + +The matcher cxxRecordDecl(hasName("::X"), +isTemplateInstantiation()) +matches class X<class A>. + template <typename T> class X {}; + class A {}; + template class X<A>; + +The matcher cxxRecordDecl(hasName("::X"), +isTemplateInstantiation()) +matches template class X<A> + template <typename T> class X {}; + class A {}; + extern template class X<A>; + +The matcher cxxRecordDecl(hasName("::X"), +isTemplateInstantiation()) +matches extern template class X<A> But given - template <typename T> class X {}; class A {}; - template <> class X<A> {}; X<A> x; -cxxRecordDecl(hasName("::X"), isTemplateInstantiation()) + template <typename T> class X {}; + class A {}; + template <> class X<A> {}; + X<A> x; + +The matcher cxxRecordDecl(hasName("::X"), +isTemplateInstantiation()) does not match, as X<A> is an explicit template specialization. Usable as: Matcher<FunctionDecl>, Matcher<VarDecl>, Matcher<CXXRecordDecl> @@ -6151,10 +8262,9 @@

AST Traversal Matchers

Matcher<*>binaryOperationMatcher<*>...Matcher<*>
Matches nodes which can be used with binary operators.
 
-The code
-  var1 != var2;
-might be represented in the clang AST as a binaryOperator, a
-cxxOperatorCallExpr or a cxxRewrittenBinaryOperator, depending on
+A comparison of two expressions might be represented in the clang AST as a
+binaryOperator, a cxxOperatorCallExpr or a
+cxxRewrittenBinaryOperator, depending on
 
 * whether the types of var1 and var2 are fundamental (binaryOperator) or at
   least one is a class type (cxxOperatorCallExpr)
@@ -6168,12 +8278,6 @@ 

AST Traversal Matchers

compatible. Given - binaryOperation( - hasOperatorName("!="), - hasLHS(expr().bind("lhs")), - hasRHS(expr().bind("rhs")) - ) -matches each use of "!=" in: struct S{ bool operator!=(const S&) const; }; @@ -6187,25 +8291,28 @@

AST Traversal Matchers

template<typename T> void templ() { - 1 != 2; + 3 != 4; T() != S(); } struct HasOpEq { - bool operator==(const HasOpEq &) const; + friend bool + operator==(const HasOpEq &, const HasOpEq&) noexcept = default; }; void inverse() { - HasOpEq s1; - HasOpEq s2; - if (s1 != s2) + HasOpEq e1; + HasOpEq e2; + if (e1 != e2) return; } struct HasSpaceship { - bool operator<=>(const HasOpEq &) const; + friend bool + operator<=>(const HasSpaceship &, + const HasSpaceship&) noexcept = default; }; void use_spaceship() @@ -6215,6 +8322,15 @@

AST Traversal Matchers

if (s1 != s2) return; } + + +The matcher binaryOperation( + hasOperatorName("!="), + hasLHS(expr().bind("lhs")), + hasRHS(expr().bind("rhs")) + ) +matches 1 != 2, S() != S(), 3 != 4, +T() != S(), e1 != e2 and s1 != s2.
@@ -6224,14 +8340,18 @@

AST Traversal Matchers

Unlike anyOf, eachOf will generate a match result for each matching submatcher. -For example, in: - class A { int a; int b; }; -The matcher: - cxxRecordDecl(eachOf(has(fieldDecl(hasName("a")).bind("v")), - has(fieldDecl(hasName("b")).bind("v")))) -will generate two results binding "v", the first of which binds -the field declaration of a, the second the field declaration of -b. +Given + void f(int a, int b); + + +The matcher functionDecl(hasAnyParameter( +eachOf(parmVarDecl(hasName("a")).bind("v"), + parmVarDecl(hasName("b")).bind("v")))) +matches void f(int a, int b), +with parmVarDecl(hasName("a")) matching a +for one match, +and with parmVarDecl(hasName("b")) matching +b for the other match. Usable as: Any Matcher @@ -6244,10 +8364,14 @@

AST Traversal Matchers

For example, in: class A { class B {}; class C {}; }; -The matcher: - cxxRecordDecl(hasName("::A"), + +The matcher +cxxRecordDecl(hasName("::A"), findAll(cxxRecordDecl(isDefinition()).bind("m"))) -will generate results for A, B and C. +matches A three times, +with cxxRecordDecl(isDefinition()).bind("m") +matching A, +B and C. Usable as: Any Matcher @@ -6257,24 +8381,71 @@

AST Traversal Matchers

Matches AST nodes that have descendant AST nodes that match the
 provided matcher.
 
-Example matches X, A, A::X, B, B::C, B::C::X
-  (matcher = cxxRecordDecl(forEachDescendant(cxxRecordDecl(hasName("X")))))
+Given
   class X {};
   class A { class X {}; };  // Matches A, because A::X is a class of name
                             // X inside A.
   class B { class C { class X {}; }; };
 
+The matcher
+cxxRecordDecl(forEachDescendant(cxxRecordDecl(hasName("X"))))
+matches X, A,
+B, class B::C
+and class B::C::X
+
 DescendantT must be an AST base type.
 
 As opposed to 'hasDescendant', 'forEachDescendant' will cause a match for
 each result that matches instead of only on the first one.
 
 Note: Recursively combined ForEachDescendant can cause many matches:
-  cxxRecordDecl(forEachDescendant(cxxRecordDecl(
-    forEachDescendant(cxxRecordDecl())
-  )))
-will match 10 times (plus injected class name matches) on:
-  class A { class B { class C { class D { class E {}; }; }; }; };
+  struct A {
+    struct B {
+      struct C {};
+      struct D {};
+    };
+  };
+
+
+The matcher cxxRecordDecl(forEachDescendant(cxxRecordDecl(
+    forEachDescendant(cxxRecordDecl().bind("inner"))
+  ).bind("middle")))
+will match 9 times:
+It matches the definition of A with the definition of
+B in the middle and the injected class name of
+B as the innermost cxxRecordDecl.
+
+It matches the definition of A with the definition of
+C in the middle and the definition of
+B as the innermost cxxRecordDecl.
+
+It matches the definition of A with the definition of
+C in the middle and the injected class name of
+B as the innermost cxxRecordDecl.
+
+It matches the definition of A with the definition of
+B in the middle and the definition of
+D as the innermost cxxRecordDecl.
+
+It matches the definition of A with the definition of
+B in the middle and the injected class name of
+D as the innermost cxxRecordDecl.
+
+It matches the definition of A with the definition of
+C in the middle and the injected class name of
+C as the innermost cxxRecordDecl.
+
+It matches the definition of A with the definition of
+D in the middle and the injected class name of
+D as the innermost cxxRecordDecl.
+
+It matches the definition of B with the definition of
+C in the middle and the injected class name of
+C as the innermost cxxRecordDecl.
+
+It matches the definition of B with the definition of
+D in the middle and the injected class name of
+D as the innermost cxxRecordDecl.
 
 Usable as: Any Matcher
 
@@ -6284,17 +8455,22 @@

AST Traversal Matchers

Matches AST nodes that have child AST nodes that match the
 provided matcher.
 
-Example matches X, Y, Y::X, Z::Y, Z::Y::X
-  (matcher = cxxRecordDecl(forEach(cxxRecordDecl(hasName("X")))
+Given
   class X {};
   class Y { class X {}; };  // Matches Y, because Y::X is a class of name X
                             // inside Y.
   class Z { class Y { class X {}; }; };  // Does not match Z.
 
+The matcher cxxRecordDecl(forEach(cxxRecordDecl(hasName("X"))))
+matches class X,
+class Y,
+class Y::X,
+class Z::Y::X and class Z::Y
+
 ChildT must be an AST base type.
 
 As opposed to 'has', 'forEach' will cause a match for each result that
-matches instead of only on the first one.
+  matches instead of only on the first one.
 
 Usable as: Any Matcher
 
@@ -6307,7 +8483,10 @@

AST Traversal Matchers

Given void f() { if (true) { int x = 42; } } void g() { for (;;) { int x = 43; } } -expr(integerLiteral(hasAncestor(ifStmt()))) matches 42, but not 43. + +The matcher expr(integerLiteral(hasAncestor(ifStmt()))) +matches 42 +but does not match 43 Usable as: Any Matcher @@ -6317,12 +8496,16 @@

AST Traversal Matchers

Matches AST nodes that have descendant AST nodes that match the
 provided matcher.
 
-Example matches X, Y, Z
-    (matcher = cxxRecordDecl(hasDescendant(cxxRecordDecl(hasName("X")))))
+Given
   class X {};  // Matches X, because X::X is a class of name X inside X.
   class Y { class X {}; };
   class Z { class Y { class X {}; }; };
 
+The matcher
+cxxRecordDecl(hasDescendant(cxxRecordDecl(hasName("X"))))
+matches class X {}, class Y { class X {}; }
+and class Z { class Y { class X {}; }; }.
+
 DescendantT must be an AST base type.
 
 Usable as: Any Matcher
@@ -6333,19 +8516,29 @@ 

AST Traversal Matchers

Matches AST nodes that have child AST nodes that match the
 provided matcher.
 
-Example matches X, Y
-  (matcher = cxxRecordDecl(has(cxxRecordDecl(hasName("X")))
+Given
   class X {};  // Matches X, because X::X is a class of name X inside X.
   class Y { class X {}; };
   class Z { class Y { class X {}; }; };  // Does not match Z.
 
+The matcher cxxRecordDecl(has(cxxRecordDecl(hasName("X"))))
+matches class X {} three times,
+and class Y { class X {}; } two times.
+
 ChildT must be an AST base type.
 
 Usable as: Any Matcher
 Note that has is direct matcher, so it also matches things like implicit
 casts and paren casts. If you are matching with expr then you should
-probably consider using ignoringParenImpCasts like:
-has(ignoringParenImpCasts(expr())).
+probably consider using ignoringParenImpCasts:
+
+Given
+  int x =0;
+  double y = static_cast<double>(x);
+
+The matcher
+cxxStaticCastExpr(has(ignoringParenImpCasts(declRefExpr()))).
+matches static_cast<double>(x)
 
@@ -6355,7 +8548,9 @@

AST Traversal Matchers

Given void f() { for (;;) { int x = 42; if (true) { int x = 43; } } } -compoundStmt(hasParent(ifStmt())) matches "{ int x = 43; }". + +The matcher compoundStmt(hasParent(ifStmt())) +matches { int x = 43; } Usable as: Any Matcher
@@ -6369,7 +8564,7 @@

AST Traversal Matchers

which should match both are typically duplicated. This matcher removes the need for duplication. -Given code +Given struct ConstructorTakesInt { ConstructorTakesInt(int i) {} @@ -6389,9 +8584,11 @@

AST Traversal Matchers

ConstructorTakesInt cti(42); } + The matcher -invocation(hasArgument(0, integerLiteral(equals(42)))) -matches the expression in both doCall and doConstruct +expr(invocation(hasArgument(0, integerLiteral(equals(42))))) +matches the expressions callTakesInt(42) +and cti(42). @@ -6402,18 +8599,12 @@

AST Traversal Matchers

Useful when additional information which may or may not present about a main matching node is desired. -For example, in: - class Foo { - int bar; - } -The matcher: - cxxRecordDecl( - optionally(has( - fieldDecl(hasName("bar")).bind("var") - ))).bind("record") -will produce a result binding for both "record" and "var". -The matcher will produce a "record" binding for even if there is no data -member named "bar" in that class. +Given + int a = 0; + int b; + +The matcher varDecl(optionally(hasInitializer(expr()))) +matches int a = 0 and int b. Usable as: Any Matcher @@ -6428,10 +8619,10 @@

AST Traversal Matchers

int i = 3.0; } The matcher - traverse(TK_IgnoreUnlessSpelledInSource, +traverse(TK_IgnoreUnlessSpelledInSource, varDecl(hasInitializer(floatLiteral().bind("init"))) ) -matches the variable declaration with "init" bound to the "3.0". + matches int i = 3.0 with "init" bound to 3.0. @@ -6439,8 +8630,13 @@

AST Traversal Matchers

Matches the condition expression of an if statement, for loop,
 switch statement or conditional operator.
 
-Example matches true (matcher = hasCondition(cxxBoolLiteral(equals(true))))
+Given
+void foo() {
   if (true) {}
+}
+
+The matcher ifStmt(hasCondition(cxxBoolLiteral(equals(true))))
+if (true) {}
 
@@ -6449,8 +8645,19 @@

AST Traversal Matchers

(binary or ternary). Example matches b - condition ? a : b - condition ?: b + void foo(bool condition, int a, int b) { + condition ? a : b; + condition ?: b; + } + +The matcher +conditionalOperator(hasFalseExpression(expr().bind("false"))) +matches condition ? a : b, +with expr() matching b. +The matcher +binaryConditionalOperator(hasFalseExpression(expr().bind("false"))) +matches condition ?: b, +with expr() matching b. @@ -6458,16 +8665,31 @@

AST Traversal Matchers

Matches the true branch expression of a conditional operator.
 
 Example 1 (conditional ternary operator): matches a
-  condition ? a : b
+Given
+  void foo(bool condition, int a, int b) {
+    condition ? a : b;
+  }
+
+The matcher
+conditionalOperator(hasTrueExpression(expr().bind("true")))
+matches condition ? a : b,
+with expr() matching a.
 
 Example 2 (conditional binary operator): matches opaqueValueExpr(condition)
-  condition ?: b
+Given
+  void foo(bool condition, int a, int b) {
+    condition ?: b;
+  }
+
+The matcher binaryConditionalOperator(hasTrueExpression(expr()))
+matches condition ?: b,
+with expr() matching conditoin.
 
Matcher<AddrLabelExpr>hasDeclarationMatcher<Decl> InnerMatcher
Matches a node if the declaration associated with that node
-matches the given matcher.
+  matches the given matcher.
 
 The associated declaration is:
 - for type nodes, the declaration of the underlying type
@@ -6477,17 +8699,25 @@ 

AST Traversal Matchers

- for CXXNewExpr, the declaration of the operator new - for ObjCIvarExpr, the declaration of the ivar -For type nodes, hasDeclaration will generally match the declaration of the -sugared type. Given +Given class X {}; typedef X Y; Y y; -in varDecl(hasType(hasDeclaration(decl()))) the decl will match the -typedefDecl. A common use case is to match the underlying, desugared type. + +For type nodes, hasDeclaration will generally match the declaration of the +sugared type, i.e., the matcher +varDecl(hasType(qualType(hasDeclaration(decl().bind("d"))))), +matches Y y, with +the matcher decl() matching +typedef X Y;. +A common use case is to match the underlying, desugared type. This can be achieved by using the hasUnqualifiedDesugaredType matcher: - varDecl(hasType(hasUnqualifiedDesugaredType( - recordType(hasDeclaration(decl()))))) -In this matcher, the decl will match the CXXRecordDecl of class X. +varDecl(hasType(hasUnqualifiedDesugaredType( + recordType(hasDeclaration(decl().bind("d")))))) +matches Y y. +In this matcher, the matcher decl() will match the +CXXRecordDecl +class X {};. Usable as: Matcher<AddrLabelExpr>, Matcher<CallExpr>, Matcher<CXXConstructExpr>, Matcher<CXXNewExpr>, Matcher<DeclRefExpr>, @@ -6505,7 +8735,7 @@

AST Traversal Matchers

Given int i[5]; void f() { i[1] = 42; } -arraySubscriptExpression(hasBase(implicitCastExpr( +The matcher arraySubscriptExpr(hasBase(implicitCastExpr( hasSourceExpression(declRefExpr())))) matches i[1] with the declRefExpr() matching i
@@ -6517,7 +8747,7 @@

AST Traversal Matchers

Given int i[5]; void f() { i[1] = 42; } -arraySubscriptExpression(hasIndex(integerLiteral())) +The matcher arraySubscriptExpr(hasIndex(integerLiteral())) matches i[1] with the integerLiteral() matching 1 @@ -6525,16 +8755,30 @@

AST Traversal Matchers

Matcher<ArraySubscriptExpr>hasLHSMatcher<Expr> InnerMatcher
Matches the left hand side of binary operator expressions.
 
-Example matches a (matcher = binaryOperator(hasLHS()))
-  a || b
+Given
+void foo(bool a, bool b) {
+  a || b;
+}
+
+The matcher binaryOperator(hasLHS(expr().bind("lhs")))
+matches a || b,
+with expr()
+matching a.
 
Matcher<ArraySubscriptExpr>hasRHSMatcher<Expr> InnerMatcher
Matches the right hand side of binary operator expressions.
 
-Example matches b (matcher = binaryOperator(hasRHS()))
-  a || b
+Given
+void foo(bool a, bool b) {
+  a || b;
+}
+
+The matcher binaryOperator(hasRHS(expr().bind("rhs")))
+matches a || b,
+with expr()
+matching b.
 
@@ -6546,8 +8790,10 @@

AST Traversal Matchers

struct A {}; A a[7]; int b[7]; -arrayType(hasElementType(builtinType())) - matches "int b[7]" + + +The matcher arrayType(hasElementType(builtinType())) +int[7] Usable as: Matcher<ArrayType>, Matcher<ComplexType> @@ -6559,8 +8805,8 @@

AST Traversal Matchers

Given _Atomic(int) i; _Atomic(float) f; -atomicType(hasValueType(isInteger())) - matches "_Atomic(int) i" +The matcher atomicType(hasValueType(isInteger())) +_Atomic(int). Usable as: Matcher<AtomicType> @@ -6575,8 +8821,10 @@

AST Traversal Matchers

Given auto a = 1; auto b = 2.0; -autoType(hasDeducedType(isInteger())) - matches "auto a" + +The matcher +varDecl(hasType(autoType(hasDeducedType(isInteger())))) +matches auto a = 1, but does not match auto b = 2.0. Usable as: Matcher<AutoType> @@ -6588,21 +8836,54 @@

AST Traversal Matchers

Given namespace X { void b(); } using X::b; -usingDecl(hasAnyUsingShadowDecl(hasName("b")))) - matches using X::b + +The matcher usingDecl(hasAnyUsingShadowDecl(hasName("b"))) + matches using X::b + Matcher<BinaryOperator>hasEitherOperandMatcher<Expr> InnerMatcher
Matches if either the left hand side or the right hand side of a
 binary operator or fold expression matches.
+
+Given
+  struct S {};
+  bool operator ==(const S&, const S&);
+
+  void f(int a, const S&lhs, const S&rhs) {
+      a + 0;
+      lhs == rhs;
+      lhs != rhs;
+  }
+
+  template <typename ...Ts>
+  auto sum(Ts... args) {
+    return (0 + ... + args);
+  }
+
+
+The matcher binaryOperator(hasEitherOperand(integerLiteral()))
+matches a + 0.
+The matcher cxxOperatorCallExpr(hasEitherOperand(declRefExpr(to(
+parmVarDecl(hasName("lhs")))))) matches lhs == rhs and
+lhs != rhs.
+The matcher cxxFoldExpr(hasEitherOperand(integerLiteral()))
+matches (0 + ... + args).
 
Matcher<BinaryOperator>hasLHSMatcher<Expr> InnerMatcher
Matches the left hand side of binary operator expressions.
 
-Example matches a (matcher = binaryOperator(hasLHS()))
-  a || b
+Given
+void foo(bool a, bool b) {
+  a || b;
+}
+
+The matcher binaryOperator(hasLHS(expr().bind("lhs")))
+matches a || b,
+with expr()
+matching a.
 
@@ -6610,27 +8891,40 @@

AST Traversal Matchers

Matches if both matchers match with opposite sides of the binary operator
 or fold expression.
 
-Example matcher = binaryOperator(hasOperands(integerLiteral(equals(1),
-                                             integerLiteral(equals(2)))
-  1 + 2 // Match
-  2 + 1 // Match
-  1 + 1 // No match
-  2 + 2 // No match
+Given
+void foo() {
+  1 + 2; // Match
+  2 + 1; // Match
+  1 + 1; // No match
+  2 + 2; // No match
+}
+The matcher binaryOperator(hasOperands(integerLiteral(equals(1)),
+                                            integerLiteral(equals(2))))
+matches 1 + 2 and 2 + 1,
+but does not match 1 + 1
+or 2 + 2.
 
Matcher<BinaryOperator>hasRHSMatcher<Expr> InnerMatcher
Matches the right hand side of binary operator expressions.
 
-Example matches b (matcher = binaryOperator(hasRHS()))
-  a || b
+Given
+void foo(bool a, bool b) {
+  a || b;
+}
+
+The matcher binaryOperator(hasRHS(expr().bind("rhs")))
+matches a || b,
+with expr()
+matching b.
 
Matcher<BindingDecl>forDecompositionMatcher<ValueDecl> InnerMatcher
Matches the DecompositionDecl the binding belongs to.
 
-For example, in:
+Given
 void foo()
 {
     int arr[3];
@@ -6638,10 +8932,10 @@ 

AST Traversal Matchers

f = 42; } -The matcher: - bindingDecl(hasName("f"), - forDecomposition(decompositionDecl()) -matches 'f' in 'auto &[f, s, t]'. + +The matcher bindingDecl(hasName("f"), + forDecomposition(decompositionDecl())) +matches f in 'auto &[f, s, t]'.
@@ -6653,23 +8947,26 @@

AST Traversal Matchers

Given class X { void f(int x, int y, int z) {} }; -cxxMethodDecl(hasAnyParameter(hasName("y"))) - matches f(int x, int y, int z) {} + +The matcher cxxMethodDecl(hasAnyParameter(hasName("y"))) + matches f with hasAnyParameter(...) matching int y For ObjectiveC, given @interface I - (void) f:(int) y; @end + the matcher objcMethodDecl(hasAnyParameter(hasName("y"))) -matches the declaration of method f with hasParameter + matches the declaration of method f with hasParameter matching y. For blocks, given b = ^(int y) { printf("%d", y) }; + the matcher blockDecl(hasAnyParameter(hasName("y"))) -matches the declaration of the block b with hasParameter + matches the declaration of the block b with hasParameter matching y. @@ -6680,15 +8977,18 @@

AST Traversal Matchers

Given class X { void f(int x) {} }; -cxxMethodDecl(hasParameter(0, hasType(varDecl()))) - matches f(int x) {} + +The matcher +cxxMethodDecl(hasParameter(0, hasType(asString("int")))) +matches f with hasParameter(...) - matching int x +matching int x. For ObjectiveC, given @interface I - (void) f:(int) y; @end -the matcher objcMethodDecl(hasParameter(0, hasName("y"))) + +The matcher objcMethodDecl(hasParameter(0, hasName("y"))) matches the declaration of method f with hasParameter matching y. @@ -6697,19 +8997,26 @@

AST Traversal Matchers

Matcher<BlockDecl>hasTypeLocMatcher<TypeLoc> Inner
Matches if the type location of a node matches the inner matcher.
 
-Examples:
+Given
   int x;
-declaratorDecl(hasTypeLoc(loc(asString("int"))))
-  matches int x
+The matcher declaratorDecl(hasTypeLoc(loc(asString("int"))))
+matches int x.
+
+Given
+struct point { point(double, double); };
+point p = point(1.0, -1.0);
 
-auto x = int(3);
-cxxTemporaryObjectExpr(hasTypeLoc(loc(asString("int"))))
-  matches int(3)
+The matcher
+cxxTemporaryObjectExpr(hasTypeLoc(loc(asString("point"))))
+matches point(1.0, -1.0).
 
+Given
 struct Foo { Foo(int, int); };
-auto x = Foo(1, 2);
-cxxFunctionalCastExpr(hasTypeLoc(loc(asString("struct Foo"))))
-  matches Foo(1, 2)
+Foo x = Foo(1, 2);
+
+The matcher cxxTemporaryObjectExpr(hasTypeLoc(
+                          loc(asString("Foo"))))
+matches Foo(1, 2).
 
 Usable as: Matcher<BlockDecl>, Matcher<CXXBaseSpecifier>,
   Matcher<CXXCtorInitializer>, Matcher<CXXFunctionalCastExpr>,
@@ -6728,10 +9035,14 @@ 

AST Traversal Matchers

Given int *a; - int const *b; - float const *f; -pointerType(pointee(isConstQualified(), isInteger())) - matches "int const *b" + const int *b; + int * const c = nullptr; + const float *f; + +The matcher pointerType(pointee(isConstQualified(), isInteger())) +matches const int *, +but does not match int * const +or const float *. Usable as: Matcher<BlockPointerType>, Matcher<MemberPointerType>, Matcher<PointerType>, Matcher<ReferenceType> @@ -6741,19 +9052,26 @@

AST Traversal Matchers

Matcher<CXXBaseSpecifier>hasTypeLocMatcher<TypeLoc> Inner
Matches if the type location of a node matches the inner matcher.
 
-Examples:
+Given
   int x;
-declaratorDecl(hasTypeLoc(loc(asString("int"))))
-  matches int x
+The matcher declaratorDecl(hasTypeLoc(loc(asString("int"))))
+matches int x.
+
+Given
+struct point { point(double, double); };
+point p = point(1.0, -1.0);
 
-auto x = int(3);
-cxxTemporaryObjectExpr(hasTypeLoc(loc(asString("int"))))
-  matches int(3)
+The matcher
+cxxTemporaryObjectExpr(hasTypeLoc(loc(asString("point"))))
+matches point(1.0, -1.0).
 
+Given
 struct Foo { Foo(int, int); };
-auto x = Foo(1, 2);
-cxxFunctionalCastExpr(hasTypeLoc(loc(asString("struct Foo"))))
-  matches Foo(1, 2)
+Foo x = Foo(1, 2);
+
+The matcher cxxTemporaryObjectExpr(hasTypeLoc(
+                          loc(asString("Foo"))))
+matches Foo(1, 2).
 
 Usable as: Matcher<BlockDecl>, Matcher<CXXBaseSpecifier>,
   Matcher<CXXCtorInitializer>, Matcher<CXXFunctionalCastExpr>,
@@ -6776,21 +9094,31 @@ 

AST Traversal Matchers

X, while varDecl(hasType(cxxRecordDecl(hasName("X")))) matches the declaration of x. -Example matches x (matcher = expr(hasType(cxxRecordDecl(hasName("X"))))) - and z (matcher = varDecl(hasType(cxxRecordDecl(hasName("X"))))) - and friend class X (matcher = friendDecl(hasType("X")) - and public virtual X (matcher = cxxBaseSpecifier(hasType( - cxxRecordDecl(hasName("X")))) class X {}; void y(X &x) { x; X z; } class Y { friend class X; }; class Z : public virtual X {}; -Example matches class Derived -(matcher = cxxRecordDecl(hasAnyBase(hasType(cxxRecordDecl(hasName("Base")))))) +The matcher expr(hasType(cxxRecordDecl(hasName("X")))) +matches x and z. +The matcher varDecl(hasType(cxxRecordDecl(hasName("X")))) +matches z. +The matcher friendDecl(hasType(asString("class X"))) +matches friend class X. +The matcher cxxRecordDecl(hasAnyBase(cxxBaseSpecifier(hasType( +asString("X"))).bind("b"))) matches +class Z : public virtual X {}, +with cxxBaseSpecifier(...) +matching public virtual X. + +Given class Base {}; class Derived : Base {}; +The matcher +cxxRecordDecl(hasAnyBase(hasType(cxxRecordDecl(hasName("Base"))))) +matches class Derived : Base {}. + Usable as: Matcher<Expr>, Matcher<FriendDecl>, Matcher<ValueDecl>, Matcher<CXXBaseSpecifier>
@@ -6800,17 +9128,25 @@

AST Traversal Matchers

Matches if the expression's or declaration's type matches a type
 matcher.
 
-Example matches x (matcher = expr(hasType(cxxRecordDecl(hasName("X")))))
-            and z (matcher = varDecl(hasType(cxxRecordDecl(hasName("X")))))
-            and U (matcher = typedefDecl(hasType(asString("int")))
-            and friend class X (matcher = friendDecl(hasType("X"))
-            and public virtual X (matcher = cxxBaseSpecifier(hasType(
-                                              asString("class X")))
+Exmaple
  class X {};
  void y(X &x) { x; X z; }
  typedef int U;
  class Y { friend class X; };
  class Z : public virtual X {};
+
+The matcher expr(hasType(cxxRecordDecl(hasName("X"))))
+matches x and z.
+The matcher varDecl(hasType(cxxRecordDecl(hasName("X"))))
+matches z
+The matcher typedefDecl(hasType(asString("int")))
+matches typedef int U
+The matcher friendDecl(hasType(asString("class X")))
+matches friend class X
+The matcher cxxRecordDecl(hasAnyBase(cxxBaseSpecifier(hasType(
+asString("X"))).bind("b"))) matches class Z : public virtual X {},
+with cxxBaseSpecifier(...)
+matching public virtual X.
 
@@ -6820,8 +9156,10 @@

AST Traversal Matchers

Given void f(int i); int y; - f(y); -callExpr( + void foo() { + f(y); + } +The matcher callExpr( forEachArgumentWithParam( declRefExpr(to(varDecl(hasName("y")))), parmVarDecl(hasType(isInteger())) @@ -6844,14 +9182,15 @@

AST Traversal Matchers

Given void f(int i); - int y; - f(y); - void (*f_ptr)(int) = f; - f_ptr(y); -callExpr( + void foo(int y) { + f(y); + void (*f_ptr)(int) = f; + f_ptr(y); + } +The matcher callExpr( forEachArgumentWithParamType( declRefExpr(to(varDecl(hasName("y")))), - qualType(isInteger()).bind("type) + qualType(isInteger()).bind("type") )) matches f(y) and f_ptr(y) with declRefExpr(...) @@ -6866,17 +9205,19 @@

AST Traversal Matchers

expression, or an ObjC-message-send expression. Given - void x(int, int, int) { int y; x(1, y, 42); } -callExpr(hasAnyArgument(declRefExpr())) - matches x(1, y, 42) -with hasAnyArgument(...) + void x(int, int, int) { int y = 42; x(1, y, 42); } +The matcher +callExpr(hasAnyArgument(ignoringImplicit(declRefExpr()))) matches +x(1, y, 42) with hasAnyArgument(...) matching y For ObjectiveC, given @interface I - (void) f:(int) y; @end void foo(I *i) { [i f:12]; } + +The matcher objcMessageExpr(hasAnyArgument(integerLiteral(equals(12)))) - matches [i f:12] +matches [i f:12]
@@ -6884,15 +9225,17 @@

AST Traversal Matchers

Matches the n'th argument of a call expression or a constructor
 call expression.
 
-Example matches y in x(y)
-    (matcher = callExpr(hasArgument(0, declRefExpr())))
+Given
   void x(int) { int y; x(y); }
+The matcher callExpr(hasArgument(0, declRefExpr().bind("arg")))
+matches x(y),
+with declRefExpr() matching y.
 
Matcher<CXXConstructExpr>hasDeclarationMatcher<Decl> InnerMatcher
Matches a node if the declaration associated with that node
-matches the given matcher.
+  matches the given matcher.
 
 The associated declaration is:
 - for type nodes, the declaration of the underlying type
@@ -6902,17 +9245,25 @@ 

AST Traversal Matchers

- for CXXNewExpr, the declaration of the operator new - for ObjCIvarExpr, the declaration of the ivar -For type nodes, hasDeclaration will generally match the declaration of the -sugared type. Given +Given class X {}; typedef X Y; Y y; -in varDecl(hasType(hasDeclaration(decl()))) the decl will match the -typedefDecl. A common use case is to match the underlying, desugared type. + +For type nodes, hasDeclaration will generally match the declaration of the +sugared type, i.e., the matcher +varDecl(hasType(qualType(hasDeclaration(decl().bind("d"))))), +matches Y y, with +the matcher decl() matching +typedef X Y;. +A common use case is to match the underlying, desugared type. This can be achieved by using the hasUnqualifiedDesugaredType matcher: - varDecl(hasType(hasUnqualifiedDesugaredType( - recordType(hasDeclaration(decl()))))) -In this matcher, the decl will match the CXXRecordDecl of class X. +varDecl(hasType(hasUnqualifiedDesugaredType( + recordType(hasDeclaration(decl().bind("d")))))) +matches Y y. +In this matcher, the matcher decl() will match the +CXXRecordDecl +class X {};. Usable as: Matcher<AddrLabelExpr>, Matcher<CallExpr>, Matcher<CXXConstructExpr>, Matcher<CXXNewExpr>, Matcher<DeclRefExpr>, @@ -6929,10 +9280,12 @@

AST Traversal Matchers

Given class A { A() : i(42), j(42) {} int i; int j; }; -cxxConstructorDecl(forEachConstructorInitializer( - forField(decl().bind("x")) -)) - will trigger two matches, binding for 'i' and 'j' respectively. + +The matcher cxxConstructorDecl(forEachConstructorInitializer( + forField(fieldDecl().bind("x")))) +matches the constructor of A twice, with +fieldDecl() matching i and +j respectively.
@@ -6944,10 +9297,11 @@

AST Traversal Matchers

Foo() : foo_(1) { } int foo_; }; -cxxRecordDecl(has(cxxConstructorDecl( + +The matcher cxxRecordDecl(has(cxxConstructorDecl( hasAnyConstructorInitializer(anything()) ))) - record matches Foo, hasAnyConstructorInitializer matches foo_(1) +matches Foo, hasAnyConstructorInitializer matches foo_(1) @@ -6959,9 +9313,11 @@

AST Traversal Matchers

Foo() : foo_(1) { } int foo_; }; + +The matcher cxxRecordDecl(has(cxxConstructorDecl(hasAnyConstructorInitializer( forField(hasName("foo_")))))) - matches Foo +matches Foo with forField matching foo_ @@ -6969,19 +9325,26 @@

AST Traversal Matchers

Matcher<CXXCtorInitializer>hasTypeLocMatcher<TypeLoc> Inner
Matches if the type location of a node matches the inner matcher.
 
-Examples:
+Given
   int x;
-declaratorDecl(hasTypeLoc(loc(asString("int"))))
-  matches int x
+The matcher declaratorDecl(hasTypeLoc(loc(asString("int"))))
+matches int x.
+
+Given
+struct point { point(double, double); };
+point p = point(1.0, -1.0);
 
-auto x = int(3);
-cxxTemporaryObjectExpr(hasTypeLoc(loc(asString("int"))))
-  matches int(3)
+The matcher
+cxxTemporaryObjectExpr(hasTypeLoc(loc(asString("point"))))
+matches point(1.0, -1.0).
 
+Given
 struct Foo { Foo(int, int); };
-auto x = Foo(1, 2);
-cxxFunctionalCastExpr(hasTypeLoc(loc(asString("struct Foo"))))
-  matches Foo(1, 2)
+Foo x = Foo(1, 2);
+
+The matcher cxxTemporaryObjectExpr(hasTypeLoc(
+                          loc(asString("Foo"))))
+matches Foo(1, 2).
 
 Usable as: Matcher<BlockDecl>, Matcher<CXXBaseSpecifier>,
   Matcher<CXXCtorInitializer>, Matcher<CXXFunctionalCastExpr>,
@@ -7002,9 +9365,11 @@ 

AST Traversal Matchers

Foo() : foo_(1) { } int foo_; }; + +The matcher cxxRecordDecl(has(cxxConstructorDecl(hasAnyConstructorInitializer( withInitializer(integerLiteral(equals(1))))))) - matches Foo +matches Foo with withInitializer matching (1)
@@ -7019,11 +9384,14 @@

AST Traversal Matchers

int m; int f(X x) { x.m; return m; } }; + + +The matcher memberExpr(hasObjectExpression(hasType(cxxRecordDecl(hasName("X"))))) - matches `x.m`, but not `m`; however, -memberExpr(hasObjectExpression(hasType(pointsTo( - cxxRecordDecl(hasName("X")))))) - matches `m` (aka. `this->m`), but not `x.m`. +matches x.m, but not m; however, +The matcher memberExpr(hasObjectExpression(hasType(pointsTo( +cxxRecordDecl(hasName("X")))))) +matches m (aka. this->m), but not x.m. @@ -7033,12 +9401,20 @@

AST Traversal Matchers

Given class Y { void x() { this->x(); x(); Y y; y.x(); } }; void f() { f(); } -callExpr(callee(expr())) - matches this->x(), x(), y.x(), f() -with callee(...) - matching this->x, x, y.x, f respectively + +The matcher callExpr(callee(expr().bind("callee"))) +matches this->x(), x(), y.x(), f() +with expr() inside of callee +matching this->x, x, +y.x, f respectively Given + struct Dummy {}; + // makes sure there is a callee, otherwise there would be no callee, + // just a builtin operator + Dummy operator+(Dummy, Dummy); + // not defining a '*' operator + template <typename... Args> auto sum(Args... args) { return (0 + ... + args); @@ -7048,10 +9424,14 @@

AST Traversal Matchers

auto multiply(Args... args) { return (args * ... * 1); } -cxxFoldExpr(callee(expr())) - matches (args * ... * 1) -with callee(...) - matching * + +The matcher cxxFoldExpr(callee(expr().bind("op"))) +matches (0 + ... + args) +with callee(...) matching *, +but does not match (args * ... * 1). +A CXXFoldExpr only has an UnresolvedLookupExpr as a callee. +When there are no define operators that could be used instead of builtin +ones, then there will be no callee . Note: Callee cannot take the more general internal::Matcher<Expr> because this introduces ambiguous overloads with calls to Callee taking a @@ -7063,16 +9443,37 @@

AST Traversal Matchers

Matcher<CXXFoldExpr>hasEitherOperandMatcher<Expr> InnerMatcher
Matches if either the left hand side or the right hand side of a
 binary operator or fold expression matches.
+
+Given
+  struct S {};
+  bool operator ==(const S&, const S&);
+
+  void f(int a, const S&lhs, const S&rhs) {
+      a + 0;
+      lhs == rhs;
+      lhs != rhs;
+  }
+
+  template <typename ...Ts>
+  auto sum(Ts... args) {
+    return (0 + ... + args);
+  }
+
+
+The matcher binaryOperator(hasEitherOperand(integerLiteral()))
+matches a + 0.
+The matcher cxxOperatorCallExpr(hasEitherOperand(declRefExpr(to(
+parmVarDecl(hasName("lhs")))))) matches lhs == rhs and
+lhs != rhs.
+The matcher cxxFoldExpr(hasEitherOperand(integerLiteral()))
+matches (0 + ... + args).
 
Matcher<CXXFoldExpr>hasFoldInitMatcher<Expr> InnerMacher
Matches the operand that does not contain the parameter pack.
 
-Example matches `(0 + ... + args)` and `(args * ... * 1)`
-    (matcher = cxxFoldExpr(hasFoldInit(expr())))
-  with hasFoldInit(...)
-    matching `0` and `1` respectively
+Given
   template <typename... Args>
   auto sum(Args... args) {
       return (0 + ... + args);
@@ -7082,14 +9483,27 @@ 

AST Traversal Matchers

auto multiply(Args... args) { return (args * ... * 1); } + + +The matcher cxxFoldExpr(hasFoldInit(expr().bind("init"))) +matches (0 + ... + args) and (args * ... * 1) +with hasFoldInit(expr().bind("init")) matching +0 and 1.
Matcher<CXXFoldExpr>hasLHSMatcher<Expr> InnerMatcher
Matches the left hand side of binary operator expressions.
 
-Example matches a (matcher = binaryOperator(hasLHS()))
-  a || b
+Given
+void foo(bool a, bool b) {
+  a || b;
+}
+
+The matcher binaryOperator(hasLHS(expr().bind("lhs")))
+matches a || b,
+with expr()
+matching a.
 
@@ -7097,22 +9511,25 @@

AST Traversal Matchers

Matches if both matchers match with opposite sides of the binary operator
 or fold expression.
 
-Example matcher = binaryOperator(hasOperands(integerLiteral(equals(1),
-                                             integerLiteral(equals(2)))
-  1 + 2 // Match
-  2 + 1 // Match
-  1 + 1 // No match
-  2 + 2 // No match
+Given
+void foo() {
+  1 + 2; // Match
+  2 + 1; // Match
+  1 + 1; // No match
+  2 + 2; // No match
+}
+The matcher binaryOperator(hasOperands(integerLiteral(equals(1)),
+                                            integerLiteral(equals(2))))
+matches 1 + 2 and 2 + 1,
+but does not match 1 + 1
+or 2 + 2.
 
Matcher<CXXFoldExpr>hasPatternMatcher<Expr> InnerMacher
Matches the operand that contains the parameter pack.
 
-Example matches `(0 + ... + args)`
-    (matcher = cxxFoldExpr(hasPattern(expr())))
-  with hasPattern(...)
-    matching `args`
+Given
   template <typename... Args>
   auto sum(Args... args) {
       return (0 + ... + args);
@@ -7122,14 +9539,27 @@ 

AST Traversal Matchers

auto multiply(Args... args) { return (args * ... * 1); } + + +The matcher cxxFoldExpr(hasPattern(expr().bind("pattern"))) +matches (0 + ... + args) and (args * ... * 1), +with hasPattern(expr().bind("pattern")) matching +args two times.
Matcher<CXXFoldExpr>hasRHSMatcher<Expr> InnerMatcher
Matches the right hand side of binary operator expressions.
 
-Example matches b (matcher = binaryOperator(hasRHS()))
-  a || b
+Given
+void foo(bool a, bool b) {
+  a || b;
+}
+
+The matcher binaryOperator(hasRHS(expr().bind("rhs")))
+matches a || b,
+with expr()
+matching b.
 
@@ -7140,27 +9570,32 @@

AST Traversal Matchers

other declarations of the same function or coroutine. Given +void foo() { for (;;) {} -forStmt(hasBody(compoundStmt())) - matches 'for (;;) {}' +} +The matcher forStmt(hasBody(compoundStmt().bind("body"))) +matches for (;;) {} with compoundStmt() - matching '{}' + matching {} Given void f(); void f() {} -functionDecl(hasBody(compoundStmt())) - matches 'void f() {}' +The matcher functionDecl(hasBody(compoundStmt().bind("compound"))) +f with compoundStmt() - matching '{}' - but does not match 'void f();' +matching {} +but does not match void f(); Matcher<CXXForRangeStmt>hasInitStatementMatcher<Stmt> InnerMatcher
Matches selection statements with initializer.
 
-Given:
+Given
+ struct vec { int* begin(); int* end(); };
+ int foobar();
+ vec& get_range();
  void foo() {
    if (int i = foobar(); i > 0) {}
    switch (int i = foobar(); i) {}
@@ -7171,51 +9606,71 @@ 

AST Traversal Matchers

switch (foobar()) {} for (auto& x : get_range()) {} } -ifStmt(hasInitStatement(anything())) - matches the if statement in foo but not in bar. -switchStmt(hasInitStatement(anything())) - matches the switch statement in foo but not in bar. -cxxForRangeStmt(hasInitStatement(anything())) - matches the range for statement in foo but not in bar. + +The matcher ifStmt(hasInitStatement(anything())) + matches the if statement if (int i = foobar(); i > 0) {} + in foo but not if (foobar() > 0) {} in bar. +The matcher switchStmt(hasInitStatement(anything())) + matches the switch statement switch (int i = foobar(); i) {} + in foo but not switch (foobar()) {} in bar. +The matcher cxxForRangeStmt(hasInitStatement(anything())) + matches the range for statement + for (auto& a = get_range(); auto& x : a) {} in foo + but not for (auto& x : get_range()) {} in bar.
Matcher<CXXForRangeStmt>hasLoopVariableMatcher<VarDecl> InnerMatcher
Matches the initialization statement of a for loop.
 
-Example:
-    forStmt(hasLoopVariable(anything()))
-matches 'int x' in
+Given
+  void foo() {
+    int a[42] = {};
     for (int x : a) { }
+  }
+
+The matcher cxxForRangeStmt(hasLoopVariable(anything()))
+matches for (int x : a) { }
 
Matcher<CXXForRangeStmt>hasRangeInitMatcher<Expr> InnerMatcher
Matches the range initialization statement of a for loop.
 
-Example:
-    forStmt(hasRangeInit(anything()))
-matches 'a' in
+Given
+  void foo() {
+    int a[42] = {};
     for (int x : a) { }
+  }
+
+The matcher cxxForRangeStmt(hasRangeInit(anything()))
+matches for (int x : a) { }
 
Matcher<CXXFunctionalCastExpr>hasTypeLocMatcher<TypeLoc> Inner
Matches if the type location of a node matches the inner matcher.
 
-Examples:
+Given
   int x;
-declaratorDecl(hasTypeLoc(loc(asString("int"))))
-  matches int x
+The matcher declaratorDecl(hasTypeLoc(loc(asString("int"))))
+matches int x.
+
+Given
+struct point { point(double, double); };
+point p = point(1.0, -1.0);
 
-auto x = int(3);
-cxxTemporaryObjectExpr(hasTypeLoc(loc(asString("int"))))
-  matches int(3)
+The matcher
+cxxTemporaryObjectExpr(hasTypeLoc(loc(asString("point"))))
+matches point(1.0, -1.0).
 
+Given
 struct Foo { Foo(int, int); };
-auto x = Foo(1, 2);
-cxxFunctionalCastExpr(hasTypeLoc(loc(asString("struct Foo"))))
-  matches Foo(1, 2)
+Foo x = Foo(1, 2);
+
+The matcher cxxTemporaryObjectExpr(hasTypeLoc(
+                          loc(asString("Foo"))))
+matches Foo(1, 2).
 
 Usable as: Matcher<BlockDecl>, Matcher<CXXBaseSpecifier>,
   Matcher<CXXCtorInitializer>, Matcher<CXXFunctionalCastExpr>,
@@ -7235,13 +9690,16 @@ 

AST Traversal Matchers

Given class Y { public: void m(); }; Y g(); - class X : public Y { void g(); }; + class X : public Y { public: void g(); }; void z(Y y, X x) { y.m(); x.m(); x.g(); (g()).m(); } -cxxMemberCallExpr(onImplicitObjectArgument(hasType( + +The matcher cxxMemberCallExpr(onImplicitObjectArgument(hasType( cxxRecordDecl(hasName("Y"))))) - matches `y.m()`, `x.m()` and (g()).m(), but not `x.g()`. -cxxMemberCallExpr(on(callExpr())) - does not match `(g()).m()`, because the parens are not ignored. +matches y.m(), x.m() and (g()).m() +but does not match x.g(). +The matcher cxxMemberCallExpr(on(callExpr())) +matches (g()).m(), because the parens are ignored. +FIXME: should they be ignored? (ignored bc of `on`) FIXME: Overload to allow directly matching types?
@@ -7256,12 +9714,15 @@

AST Traversal Matchers

Y g(); class X : public Y {}; void z(Y y, X x) { y.m(); (g()).m(); x.m(); } + +The matcher cxxMemberCallExpr(on(hasType(cxxRecordDecl(hasName("Y"))))) - matches `y.m()` and `(g()).m()`. + matches y.m() and (g()).m(). +The matcher cxxMemberCallExpr(on(hasType(cxxRecordDecl(hasName("X"))))) - matches `x.m()`. -cxxMemberCallExpr(on(callExpr())) - matches `(g()).m()`. + matches x.m(). +The matcher cxxMemberCallExpr(on(callExpr())) + matches (g()).m(). FIXME: Overload to allow directly matching types? @@ -7269,24 +9730,35 @@

AST Traversal Matchers

Matcher<CXXMemberCallExpr>thisPointerTypeMatcher<Decl> InnerMatcher
Overloaded to match the type's declaration.
+
+Given
+  class Y { public: void m(); };
+  class X : public Y { public: void g(); };
+  void z() { Y y; y.m(); Y *p; p->m(); X x; x.m(); x.g(); }
+
+The matcher cxxMemberCallExpr(thisPointerType(
+    cxxRecordDecl(hasName("Y"))))
+  matches y.m(), p->m() and x.m().
+The matcher cxxMemberCallExpr(thisPointerType(
+    cxxRecordDecl(hasName("X"))))
+  matches x.g().
 
Matcher<CXXMemberCallExpr>thisPointerTypeMatcher<QualType> InnerMatcher
Matches if the type of the expression's implicit object argument either
-matches the InnerMatcher, or is a pointer to a type that matches the
+  matches the InnerMatcher, or is a pointer to a type that matches the
 InnerMatcher.
 
 Given
-  class Y { public: void m(); };
-  class X : public Y { void g(); };
-  void z() { Y y; y.m(); Y *p; p->m(); X x; x.m(); x.g(); }
-cxxMemberCallExpr(thisPointerType(hasDeclaration(
-    cxxRecordDecl(hasName("Y")))))
-  matches `y.m()`, `p->m()` and `x.m()`.
-cxxMemberCallExpr(thisPointerType(hasDeclaration(
-    cxxRecordDecl(hasName("X")))))
-  matches `x.g()`.
+  class Y { public: void m() const; };
+  class X : public Y { public: void g(); };
+  void z() { const Y y; y.m(); const Y *p; p->m(); X x; x.m(); x.g(); }
+
+The matcher
+cxxMemberCallExpr(thisPointerType(isConstQualified()))
+matches y.m(), x.m() and p->m(),
+but not x.g().
 
@@ -7298,19 +9770,27 @@

AST Traversal Matchers

class A { virtual void f(); }; class B : public A { void f(); }; class C : public B { void f(); }; -cxxMethodDecl(ofClass(hasName("C")), - forEachOverridden(cxxMethodDecl().bind("b"))).bind("d") - matches once, with "b" binding "A::f" and "d" binding "C::f" (Note - that B::f is not overridden by C::f). + +The matcher cxxMethodDecl(ofClass(hasName("C")), + forEachOverridden(cxxMethodDecl().bind("b"))) +matches void f() of C , +with cxxMethodDecl() matching +virtual void f() of A , +but the matcher does not match void f() of B because +it is not overridden by C::f. The check can produce multiple matches in case of multiple inheritance, e.g. class A1 { virtual void f(); }; class A2 { virtual void f(); }; class C : public A1, public A2 { void f(); }; -cxxMethodDecl(ofClass(hasName("C")), - forEachOverridden(cxxMethodDecl().bind("b"))).bind("d") - matches twice, once with "b" binding "A1::f" and "d" binding "C::f", and - once with "b" binding "A2::f" and "d" binding "C::f". + +The matcher cxxMethodDecl(ofClass(hasName("C")), + forEachOverridden(cxxMethodDecl().bind("b"))) +matches void f() of C with the inner +cxxMethodDecl() matching virtual void f() +inside of A1 , and void f() of C with the inner +cxxMethodDecl() matching virtual void f() +inside of A2. @@ -7322,40 +9802,52 @@

AST Traversal Matchers

FIXME: What other kind of declarations would we need to generalize this to? -Example matches A() in the last line - (matcher = cxxConstructExpr(hasDeclaration(cxxMethodDecl( - ofClass(hasName("A")))))) +Given class A { public: A(); + void foo(); }; - A a = A(); + +The matcher cxxMethodDecl(ofClass(hasName("A"))) +matches A() and void foo(). Matcher<CXXNewExpr>hasAnyPlacementArgMatcher<Expr> InnerMatcher
Matches any placement new expression arguments.
 
-Given:
+Given
+  void* operator new(decltype(sizeof(void*)), void*);
+  struct MyClass { int x; };
+  unsigned char Storage[sizeof(MyClass) * 10];
   MyClass *p1 = new (Storage) MyClass();
-cxxNewExpr(hasAnyPlacementArg(anything()))
-  matches the expression 'new (Storage, 16) MyClass()'.
+
+
+The matcher cxxNewExpr(hasAnyPlacementArg(anything()))
+matches new (Storage) MyClass().
 
Matcher<CXXNewExpr>hasArraySizeMatcher<Expr> InnerMatcher
Matches array new expressions with a given array size.
 
-Given:
+Given
+  void* operator new(decltype(sizeof(void*)));
+  struct MyClass { int x; };
   MyClass *p1 = new MyClass[10];
-cxxNewExpr(hasArraySize(integerLiteral(equals(10))))
-  matches the expression 'new MyClass[10]'.
+
+
+The matcher
+cxxNewExpr(hasArraySize(
+            ignoringImplicit(integerLiteral(equals(10)))))
+matches new MyClass[10].
 
Matcher<CXXNewExpr>hasDeclarationMatcher<Decl> InnerMatcher
Matches a node if the declaration associated with that node
-matches the given matcher.
+  matches the given matcher.
 
 The associated declaration is:
 - for type nodes, the declaration of the underlying type
@@ -7365,17 +9857,25 @@ 

AST Traversal Matchers

- for CXXNewExpr, the declaration of the operator new - for ObjCIvarExpr, the declaration of the ivar -For type nodes, hasDeclaration will generally match the declaration of the -sugared type. Given +Given class X {}; typedef X Y; Y y; -in varDecl(hasType(hasDeclaration(decl()))) the decl will match the -typedefDecl. A common use case is to match the underlying, desugared type. + +For type nodes, hasDeclaration will generally match the declaration of the +sugared type, i.e., the matcher +varDecl(hasType(qualType(hasDeclaration(decl().bind("d"))))), +matches Y y, with +the matcher decl() matching +typedef X Y;. +A common use case is to match the underlying, desugared type. This can be achieved by using the hasUnqualifiedDesugaredType matcher: - varDecl(hasType(hasUnqualifiedDesugaredType( - recordType(hasDeclaration(decl()))))) -In this matcher, the decl will match the CXXRecordDecl of class X. +varDecl(hasType(hasUnqualifiedDesugaredType( + recordType(hasDeclaration(decl().bind("d")))))) +matches Y y. +In this matcher, the matcher decl() will match the +CXXRecordDecl +class X {};. Usable as: Matcher<AddrLabelExpr>, Matcher<CallExpr>, Matcher<CXXConstructExpr>, Matcher<CXXNewExpr>, Matcher<DeclRefExpr>, @@ -7390,29 +9890,42 @@

AST Traversal Matchers

Matcher<CXXNewExpr>hasPlacementArgunsigned Index, Matcher<Expr> InnerMatcher
Matches placement new expression arguments.
 
-Given:
-  MyClass *p1 = new (Storage, 16) MyClass();
-cxxNewExpr(hasPlacementArg(1, integerLiteral(equals(16))))
-  matches the expression 'new (Storage, 16) MyClass()'.
+Given
+  void *operator new(decltype(sizeof(void*)), int, void*);
+  struct MyClass { int x; };
+  unsigned char Storage[sizeof(MyClass) * 10];
+  MyClass *p1 = new (16, Storage) MyClass();
+
+
+The matcher cxxNewExpr(hasPlacementArg(0,
+                      integerLiteral(equals(16))))
+matches new (16, Storage) MyClass().
 
Matcher<CXXNewExpr>hasTypeLocMatcher<TypeLoc> Inner
Matches if the type location of a node matches the inner matcher.
 
-Examples:
+Given
   int x;
-declaratorDecl(hasTypeLoc(loc(asString("int"))))
-  matches int x
+The matcher declaratorDecl(hasTypeLoc(loc(asString("int"))))
+matches int x.
+
+Given
+struct point { point(double, double); };
+point p = point(1.0, -1.0);
 
-auto x = int(3);
-cxxTemporaryObjectExpr(hasTypeLoc(loc(asString("int"))))
-  matches int(3)
+The matcher
+cxxTemporaryObjectExpr(hasTypeLoc(loc(asString("point"))))
+matches point(1.0, -1.0).
 
+Given
 struct Foo { Foo(int, int); };
-auto x = Foo(1, 2);
-cxxFunctionalCastExpr(hasTypeLoc(loc(asString("struct Foo"))))
-  matches Foo(1, 2)
+Foo x = Foo(1, 2);
+
+The matcher cxxTemporaryObjectExpr(hasTypeLoc(
+                          loc(asString("Foo"))))
+matches Foo(1, 2).
 
 Usable as: Matcher<BlockDecl>, Matcher<CXXBaseSpecifier>,
   Matcher<CXXCtorInitializer>, Matcher<CXXFunctionalCastExpr>,
@@ -7428,14 +9941,45 @@ 

AST Traversal Matchers

Matcher<CXXOperatorCallExpr>hasEitherOperandMatcher<Expr> InnerMatcher
Matches if either the left hand side or the right hand side of a
 binary operator or fold expression matches.
+
+Given
+  struct S {};
+  bool operator ==(const S&, const S&);
+
+  void f(int a, const S&lhs, const S&rhs) {
+      a + 0;
+      lhs == rhs;
+      lhs != rhs;
+  }
+
+  template <typename ...Ts>
+  auto sum(Ts... args) {
+    return (0 + ... + args);
+  }
+
+
+The matcher binaryOperator(hasEitherOperand(integerLiteral()))
+matches a + 0.
+The matcher cxxOperatorCallExpr(hasEitherOperand(declRefExpr(to(
+parmVarDecl(hasName("lhs")))))) matches lhs == rhs and
+lhs != rhs.
+The matcher cxxFoldExpr(hasEitherOperand(integerLiteral()))
+matches (0 + ... + args).
 
Matcher<CXXOperatorCallExpr>hasLHSMatcher<Expr> InnerMatcher
Matches the left hand side of binary operator expressions.
 
-Example matches a (matcher = binaryOperator(hasLHS()))
-  a || b
+Given
+void foo(bool a, bool b) {
+  a || b;
+}
+
+The matcher binaryOperator(hasLHS(expr().bind("lhs")))
+matches a || b,
+with expr()
+matching a.
 
@@ -7443,44 +9987,64 @@

AST Traversal Matchers

Matches if both matchers match with opposite sides of the binary operator
 or fold expression.
 
-Example matcher = binaryOperator(hasOperands(integerLiteral(equals(1),
-                                             integerLiteral(equals(2)))
-  1 + 2 // Match
-  2 + 1 // Match
-  1 + 1 // No match
-  2 + 2 // No match
+Given
+void foo() {
+  1 + 2; // Match
+  2 + 1; // Match
+  1 + 1; // No match
+  2 + 2; // No match
+}
+The matcher binaryOperator(hasOperands(integerLiteral(equals(1)),
+                                            integerLiteral(equals(2))))
+matches 1 + 2 and 2 + 1,
+but does not match 1 + 1
+or 2 + 2.
 
Matcher<CXXOperatorCallExpr>hasRHSMatcher<Expr> InnerMatcher
Matches the right hand side of binary operator expressions.
 
-Example matches b (matcher = binaryOperator(hasRHS()))
-  a || b
+Given
+void foo(bool a, bool b) {
+  a || b;
+}
+
+The matcher binaryOperator(hasRHS(expr().bind("rhs")))
+matches a || b,
+with expr()
+matching b.
 
Matcher<CXXOperatorCallExpr>hasUnaryOperandMatcher<Expr> InnerMatcher
Matches if the operand of a unary operator matches.
 
-Example matches true (matcher = hasUnaryOperand(
-                                  cxxBoolLiteral(equals(true))))
-  !true
+void foo() {
+  !true;
+}
+
+The matcher
+unaryOperator(hasUnaryOperand(cxxBoolLiteral(equals(true))))
+matches !true.
 
Matcher<CXXRecordDecl>hasAnyBaseMatcher<CXXBaseSpecifier> BaseSpecMatcher
Matches C++ classes that have a direct or indirect base matching BaseSpecMatcher.
 
-Example:
-matcher hasAnyBase(hasType(cxxRecordDecl(hasName("SpecialBase"))))
-  class Foo;
+Given
+  class Foo {};
   class Bar : Foo {};
   class Baz : Bar {};
-  class SpecialBase;
+  class SpecialBase {};
   class Proxy : SpecialBase {};  // matches Proxy
   class IndirectlyDerived : Proxy {};  //matches IndirectlyDerived
 
+
+The matcher
+cxxRecordDecl(hasAnyBase(hasType(cxxRecordDecl(hasName("SpecialBase")))))
+matches Proxy and IndirectlyDerived
 FIXME: Refactor this and isDerivedFrom to reuse implementation.
 
@@ -7488,26 +10052,31 @@

AST Traversal Matchers

Matcher<CXXRecordDecl>hasDirectBaseMatcher<CXXBaseSpecifier> BaseSpecMatcher
Matches C++ classes that have a direct base matching BaseSpecMatcher.
 
-Example:
-matcher hasDirectBase(hasType(cxxRecordDecl(hasName("SpecialBase"))))
-  class Foo;
+Given
+  class Foo {};
   class Bar : Foo {};
   class Baz : Bar {};
-  class SpecialBase;
+  class SpecialBase {};
   class Proxy : SpecialBase {};  // matches Proxy
   class IndirectlyDerived : Proxy {};  // doesn't match
+
+The matcher
+cxxRecordDecl(hasDirectBase(hasType(cxxRecordDecl(hasName("SpecialBase")))))
+matches Proxy
 
Matcher<CXXRecordDecl>hasMethodMatcher<CXXMethodDecl> InnerMatcher
Matches the first method of a class or struct that satisfies InnerMatcher.
 
-Given:
+Given
   class A { void func(); };
   class B { void member(); };
 
-cxxRecordDecl(hasMethod(hasName("func"))) matches the declaration of
-A but not B.
+
+The matcher cxxRecordDecl(hasMethod(hasName("func")))
+matches the declaration of class A { void func(); }
+but does not match class B { void member(); }
 
@@ -7519,22 +10088,29 @@

AST Traversal Matchers

Note that a class is not considered to be derived from itself. Example matches Y, Z, C (Base == hasName("X")) - class X; + class X {}; class Y : public X {}; // directly derived class Z : public Y {}; // indirectly derived typedef X A; typedef A B; class C : public B {}; // derived from a typedef of X -In the following example, Bar matches isDerivedFrom(hasName("X")): - class Foo; - typedef Foo X; - class Bar : public Foo {}; // derived from a type that X is a typedef of + class Foo {}; + typedef Foo Alias; + class Bar : public Alias {}; + // derived from a type that Alias is a typedef of Foo + + +The matcher cxxRecordDecl(isDerivedFrom(hasName("X"))) +matches Y, Z and C. +The matcher cxxRecordDecl(isDerivedFrom(hasName("Foo"))) +matches Bar. In the following example, Bar matches isDerivedFrom(hasName("NSObject")) @interface NSObject @end @interface Bar : NSObject @end + Usable as: Matcher<CXXRecordDecl>, Matcher<ObjCInterfaceDecl>
@@ -7545,38 +10121,90 @@

AST Traversal Matchers

Note that a class is not considered to be derived from itself. -Example matches Y, C (Base == hasName("X")) - class X; +Given + class X {}; class Y : public X {}; // directly derived class Z : public Y {}; // indirectly derived typedef X A; typedef A B; class C : public B {}; // derived from a typedef of X +The matcher +cxxRecordDecl(isDirectlyDerivedFrom(namedDecl(hasName("X")))) +matches Y and C (Base == hasName("X") + In the following example, Bar matches isDerivedFrom(hasName("X")): - class Foo; + class Foo {}; typedef Foo X; class Bar : public Foo {}; // derived from a type that X is a typedef of + +The matcher cxxRecordDecl(isDerivedFrom(hasName("X"))) +matches Bar
Matcher<CXXRecordDecl>isSameOrDerivedFromMatcher<NamedDecl> Base
Similar to isDerivedFrom(), but also matches classes that directly
 match Base.
+
+Given
+  class X {};
+  class Y : public X {};  // directly derived
+  class Z : public Y {};  // indirectly derived
+  typedef X A;
+  typedef A B;
+  class C : public B {};  // derived from a typedef of X
+
+The matcher
+cxxRecordDecl(isSameOrDerivedFrom(cxxRecordDecl(hasName("X"))),
+isDefinition())
+matches class X {}, class Y : public X {},
+class Z : public Y {} and class C : public B {}.
 
Matcher<CXXRewrittenBinaryOperator>hasEitherOperandMatcher<Expr> InnerMatcher
Matches if either the left hand side or the right hand side of a
 binary operator or fold expression matches.
+
+Given
+  struct S {};
+  bool operator ==(const S&, const S&);
+
+  void f(int a, const S&lhs, const S&rhs) {
+      a + 0;
+      lhs == rhs;
+      lhs != rhs;
+  }
+
+  template <typename ...Ts>
+  auto sum(Ts... args) {
+    return (0 + ... + args);
+  }
+
+
+The matcher binaryOperator(hasEitherOperand(integerLiteral()))
+matches a + 0.
+The matcher cxxOperatorCallExpr(hasEitherOperand(declRefExpr(to(
+parmVarDecl(hasName("lhs")))))) matches lhs == rhs and
+lhs != rhs.
+The matcher cxxFoldExpr(hasEitherOperand(integerLiteral()))
+matches (0 + ... + args).
 
Matcher<CXXRewrittenBinaryOperator>hasLHSMatcher<Expr> InnerMatcher
Matches the left hand side of binary operator expressions.
 
-Example matches a (matcher = binaryOperator(hasLHS()))
-  a || b
+Given
+void foo(bool a, bool b) {
+  a || b;
+}
+
+The matcher binaryOperator(hasLHS(expr().bind("lhs")))
+matches a || b,
+with expr()
+matching a.
 
@@ -7584,39 +10212,59 @@

AST Traversal Matchers

Matches if both matchers match with opposite sides of the binary operator
 or fold expression.
 
-Example matcher = binaryOperator(hasOperands(integerLiteral(equals(1),
-                                             integerLiteral(equals(2)))
-  1 + 2 // Match
-  2 + 1 // Match
-  1 + 1 // No match
-  2 + 2 // No match
+Given
+void foo() {
+  1 + 2; // Match
+  2 + 1; // Match
+  1 + 1; // No match
+  2 + 2; // No match
+}
+The matcher binaryOperator(hasOperands(integerLiteral(equals(1)),
+                                            integerLiteral(equals(2))))
+matches 1 + 2 and 2 + 1,
+but does not match 1 + 1
+or 2 + 2.
 
Matcher<CXXRewrittenBinaryOperator>hasRHSMatcher<Expr> InnerMatcher
Matches the right hand side of binary operator expressions.
 
-Example matches b (matcher = binaryOperator(hasRHS()))
-  a || b
+Given
+void foo(bool a, bool b) {
+  a || b;
+}
+
+The matcher binaryOperator(hasRHS(expr().bind("rhs")))
+matches a || b,
+with expr()
+matching b.
 
Matcher<CXXTemporaryObjectExpr>hasTypeLocMatcher<TypeLoc> Inner
Matches if the type location of a node matches the inner matcher.
 
-Examples:
+Given
   int x;
-declaratorDecl(hasTypeLoc(loc(asString("int"))))
-  matches int x
+The matcher declaratorDecl(hasTypeLoc(loc(asString("int"))))
+matches int x.
+
+Given
+struct point { point(double, double); };
+point p = point(1.0, -1.0);
 
-auto x = int(3);
-cxxTemporaryObjectExpr(hasTypeLoc(loc(asString("int"))))
-  matches int(3)
+The matcher
+cxxTemporaryObjectExpr(hasTypeLoc(loc(asString("point"))))
+matches point(1.0, -1.0).
 
+Given
 struct Foo { Foo(int, int); };
-auto x = Foo(1, 2);
-cxxFunctionalCastExpr(hasTypeLoc(loc(asString("struct Foo"))))
-  matches Foo(1, 2)
+Foo x = Foo(1, 2);
+
+The matcher cxxTemporaryObjectExpr(hasTypeLoc(
+                          loc(asString("Foo"))))
+matches Foo(1, 2).
 
 Usable as: Matcher<BlockDecl>, Matcher<CXXBaseSpecifier>,
   Matcher<CXXCtorInitializer>, Matcher<CXXFunctionalCastExpr>,
@@ -7634,17 +10282,19 @@ 

AST Traversal Matchers

expression, or an ObjC-message-send expression. Given - void x(int, int, int) { int y; x(1, y, 42); } -callExpr(hasAnyArgument(declRefExpr())) - matches x(1, y, 42) -with hasAnyArgument(...) + void x(int, int, int) { int y = 42; x(1, y, 42); } +The matcher +callExpr(hasAnyArgument(ignoringImplicit(declRefExpr()))) matches +x(1, y, 42) with hasAnyArgument(...) matching y For ObjectiveC, given @interface I - (void) f:(int) y; @end void foo(I *i) { [i f:12]; } + +The matcher objcMessageExpr(hasAnyArgument(integerLiteral(equals(12)))) - matches [i f:12] +matches [i f:12]
@@ -7652,28 +10302,37 @@

AST Traversal Matchers

Matches the n'th argument of a call expression or a constructor
 call expression.
 
-Example matches y in x(y)
-    (matcher = callExpr(hasArgument(0, declRefExpr())))
+Given
   void x(int) { int y; x(y); }
+The matcher callExpr(hasArgument(0, declRefExpr().bind("arg")))
+matches x(y),
+with declRefExpr() matching y.
 
Matcher<CXXUnresolvedConstructExpr>hasTypeLocMatcher<TypeLoc> Inner
Matches if the type location of a node matches the inner matcher.
 
-Examples:
+Given
   int x;
-declaratorDecl(hasTypeLoc(loc(asString("int"))))
-  matches int x
+The matcher declaratorDecl(hasTypeLoc(loc(asString("int"))))
+matches int x.
+
+Given
+struct point { point(double, double); };
+point p = point(1.0, -1.0);
 
-auto x = int(3);
-cxxTemporaryObjectExpr(hasTypeLoc(loc(asString("int"))))
-  matches int(3)
+The matcher
+cxxTemporaryObjectExpr(hasTypeLoc(loc(asString("point"))))
+matches point(1.0, -1.0).
 
+Given
 struct Foo { Foo(int, int); };
-auto x = Foo(1, 2);
-cxxFunctionalCastExpr(hasTypeLoc(loc(asString("struct Foo"))))
-  matches Foo(1, 2)
+Foo x = Foo(1, 2);
+
+The matcher cxxTemporaryObjectExpr(hasTypeLoc(
+                          loc(asString("Foo"))))
+matches Foo(1, 2).
 
 Usable as: Matcher<BlockDecl>, Matcher<CXXBaseSpecifier>,
   Matcher<CXXCtorInitializer>, Matcher<CXXFunctionalCastExpr>,
@@ -7691,19 +10350,23 @@ 

AST Traversal Matchers

given matcher; or 2) if the Obj-C message expression's callee's method declaration matches the given matcher. -Example matches y.x() (matcher = callExpr(callee( - cxxMethodDecl(hasName("x"))))) +Example 1 class Y { public: void x(); }; void z() { Y y; y.x(); } -Example 2. Matches [I foo] with -objcMessageExpr(callee(objcMethodDecl(hasName("foo")))) +The matcher callExpr(callee(cxxMethodDecl(hasName("x")))) +matches y.x() +Example 2 @interface I: NSObject +(void)foo; @end ... [I foo] + +The matcher +objcMessageExpr(callee(objcMethodDecl(hasName("foo")))) +matches [I foo]
@@ -7713,12 +10376,20 @@

AST Traversal Matchers

Given class Y { void x() { this->x(); x(); Y y; y.x(); } }; void f() { f(); } -callExpr(callee(expr())) - matches this->x(), x(), y.x(), f() -with callee(...) - matching this->x, x, y.x, f respectively + +The matcher callExpr(callee(expr().bind("callee"))) +matches this->x(), x(), y.x(), f() +with expr() inside of callee +matching this->x, x, +y.x, f respectively Given + struct Dummy {}; + // makes sure there is a callee, otherwise there would be no callee, + // just a builtin operator + Dummy operator+(Dummy, Dummy); + // not defining a '*' operator + template <typename... Args> auto sum(Args... args) { return (0 + ... + args); @@ -7728,10 +10399,14 @@

AST Traversal Matchers

auto multiply(Args... args) { return (args * ... * 1); } -cxxFoldExpr(callee(expr())) - matches (args * ... * 1) -with callee(...) - matching * + +The matcher cxxFoldExpr(callee(expr().bind("op"))) +matches (0 + ... + args) +with callee(...) matching *, +but does not match (args * ... * 1). +A CXXFoldExpr only has an UnresolvedLookupExpr as a callee. +When there are no define operators that could be used instead of builtin +ones, then there will be no callee . Note: Callee cannot take the more general internal::Matcher<Expr> because this introduces ambiguous overloads with calls to Callee taking a @@ -7746,8 +10421,10 @@

AST Traversal Matchers

Given void f(int i); int y; - f(y); -callExpr( + void foo() { + f(y); + } +The matcher callExpr( forEachArgumentWithParam( declRefExpr(to(varDecl(hasName("y")))), parmVarDecl(hasType(isInteger())) @@ -7770,14 +10447,15 @@

AST Traversal Matchers

Given void f(int i); - int y; - f(y); - void (*f_ptr)(int) = f; - f_ptr(y); -callExpr( + void foo(int y) { + f(y); + void (*f_ptr)(int) = f; + f_ptr(y); + } +The matcher callExpr( forEachArgumentWithParamType( declRefExpr(to(varDecl(hasName("y")))), - qualType(isInteger()).bind("type) + qualType(isInteger()).bind("type") )) matches f(y) and f_ptr(y) with declRefExpr(...) @@ -7792,17 +10470,19 @@

AST Traversal Matchers

expression, or an ObjC-message-send expression. Given - void x(int, int, int) { int y; x(1, y, 42); } -callExpr(hasAnyArgument(declRefExpr())) - matches x(1, y, 42) -with hasAnyArgument(...) + void x(int, int, int) { int y = 42; x(1, y, 42); } +The matcher +callExpr(hasAnyArgument(ignoringImplicit(declRefExpr()))) matches +x(1, y, 42) with hasAnyArgument(...) matching y For ObjectiveC, given @interface I - (void) f:(int) y; @end void foo(I *i) { [i f:12]; } + +The matcher objcMessageExpr(hasAnyArgument(integerLiteral(equals(12)))) - matches [i f:12] +matches [i f:12] @@ -7810,15 +10490,17 @@

AST Traversal Matchers

Matches the n'th argument of a call expression or a constructor
 call expression.
 
-Example matches y in x(y)
-    (matcher = callExpr(hasArgument(0, declRefExpr())))
+Given
   void x(int) { int y; x(y); }
+The matcher callExpr(hasArgument(0, declRefExpr().bind("arg")))
+matches x(y),
+with declRefExpr() matching y.
 
Matcher<CallExpr>hasDeclarationMatcher<Decl> InnerMatcher
Matches a node if the declaration associated with that node
-matches the given matcher.
+  matches the given matcher.
 
 The associated declaration is:
 - for type nodes, the declaration of the underlying type
@@ -7828,17 +10510,25 @@ 

AST Traversal Matchers

- for CXXNewExpr, the declaration of the operator new - for ObjCIvarExpr, the declaration of the ivar -For type nodes, hasDeclaration will generally match the declaration of the -sugared type. Given +Given class X {}; typedef X Y; Y y; -in varDecl(hasType(hasDeclaration(decl()))) the decl will match the -typedefDecl. A common use case is to match the underlying, desugared type. + +For type nodes, hasDeclaration will generally match the declaration of the +sugared type, i.e., the matcher +varDecl(hasType(qualType(hasDeclaration(decl().bind("d"))))), +matches Y y, with +the matcher decl() matching +typedef X Y;. +A common use case is to match the underlying, desugared type. This can be achieved by using the hasUnqualifiedDesugaredType matcher: - varDecl(hasType(hasUnqualifiedDesugaredType( - recordType(hasDeclaration(decl()))))) -In this matcher, the decl will match the CXXRecordDecl of class X. +varDecl(hasType(hasUnqualifiedDesugaredType( + recordType(hasDeclaration(decl().bind("d")))))) +matches Y y. +In this matcher, the matcher decl() will match the +CXXRecordDecl +class X {};. Usable as: Matcher<AddrLabelExpr>, Matcher<CallExpr>, Matcher<CXXConstructExpr>, Matcher<CXXNewExpr>, Matcher<DeclRefExpr>, @@ -7855,9 +10545,12 @@

AST Traversal Matchers

extension, matches the constant given in the statement. Given - switch (1) { case 1: case 1+1: case 3 ... 4: ; } -caseStmt(hasCaseConstant(integerLiteral())) - matches "case 1:" + void foo() { + switch (1) { case 1: break; case 1+1: break; case 3 ... 4: break; } + } +The matcher +caseStmt(hasCaseConstant(constantExpr(has(integerLiteral())))) +matches case 1: break.
@@ -7865,14 +10558,23 @@

AST Traversal Matchers

Matches if the cast's source expression
 or opaque value's source expression matches the given matcher.
 
-Example 1: matches "a string"
-(matcher = castExpr(hasSourceExpression(cxxConstructExpr())))
-class URL { URL(string); };
-URL url = "a string";
+Given
+ struct URL { URL(const char*); };
+ URL url = "a string";
+
+The matcher castExpr(hasSourceExpression(cxxConstructExpr()))
+matches "a string".
+
+Given
+void foo(bool b) {
+  int a = b ?: 1;
+}
 
-Example 2: matches 'b' (matcher =
-opaqueValueExpr(hasSourceExpression(implicitCastExpr(declRefExpr())))
-int a = b ?: 1;
+The matcher
+opaqueValueExpr(hasSourceExpression(
+              implicitCastExpr(has(
+                implicitCastExpr(has(declRefExpr()))))))
+matches b twice, for the conditiona and the true expression.
 
@@ -7892,13 +10594,22 @@

AST Traversal Matchers

template <typename T, typename U> void f(T&& t, U&& u) {} - bool B = false; - f(R, B); -templateSpecializationType(forEachTemplateArgument(isExpr(expr()))) - matches twice, with expr() matching 'R * 2' and 'R * 4' -functionDecl(forEachTemplateArgument(refersToType(builtinType()))) - matches the specialization f<unsigned, bool> twice, for 'unsigned' - and 'bool' + void foo() { + bool B = false; + f(R, B); + } + +The matcher +templateSpecializationType(forEachTemplateArgument(isExpr(expr().bind("t_arg")))) +matches Matrix<int, R * 2, R * 4> twice, with +expr() matching R * 2 and +R * 4. +The matcher +functionDecl(forEachTemplateArgument(refersToType(qualType().bind("type")))) +matches the specialization of f twice, +with qualType() matching +unsigned and +bool. @@ -7911,9 +10622,11 @@

AST Traversal Matchers

Given template<typename T> class A {}; A<int> a; -varDecl(hasTypeLoc(templateSpecializationTypeLoc(hasAnyTemplateArgumentLoc( - hasTypeLoc(loc(asString("int"))))))) - matches `A<int> a`. + +The matcher +varDecl(hasTypeLoc(elaboratedTypeLoc(hasNamedTypeLoc( +templateSpecializationTypeLoc(hasAnyTemplateArgumentLoc( +hasTypeLoc(loc(asString("int"))))))))) matches A<int> a. @@ -7927,15 +10640,19 @@

AST Traversal Matchers

template<> class A<double> {}; A<int> a; - template<typename T> f() {}; + template<typename T> void f() {}; void func() { f<int>(); }; -classTemplateSpecializationDecl(hasAnyTemplateArgument( - refersToType(asString("int")))) - matches the specialization A<int> -functionDecl(hasAnyTemplateArgument(refersToType(asString("int")))) - matches the specialization f<int> +The matcher classTemplateSpecializationDecl( + hasAnyTemplateArgument( + refersToType(asString("int")))) +matches class A<int>. + +The matcher +functionDecl(hasAnyTemplateArgument( + refersToType(asString("int")))) +matches the instantiation of f. @@ -7943,11 +10660,14 @@

AST Traversal Matchers

Matches the specialized template of a specialization declaration.
 
 Given
-  template<typename T> class A {}; #1
-  template<> class A<int> {}; #2
-classTemplateSpecializationDecl(hasSpecializedTemplate(classTemplateDecl()))
-  matches '#2' with classTemplateDecl() matching the class template
-  declaration of 'A' at #1.
+  template<typename T> class A {}; // #1
+  template<> class A<int> {}; // #2
+
+The matcher
+classTemplateSpecializationDecl(hasSpecializedTemplate(classTemplateDecl().bind("ctd")))
+matches template<> class A<int> {},
+with classTemplateDecl() matching the class template
+declaration template <typename T> class A {}.
 
@@ -7960,9 +10680,12 @@

AST Traversal Matchers

template<typename T, typename U> class A {}; A<double, int> b; A<int, double> c; -varDecl(hasTypeLoc(templateSpecializationTypeLoc(hasTemplateArgumentLoc(0, - hasTypeLoc(loc(asString("double"))))))) - matches `A<double, int> b`, but not `A<int, double> c`. + +The matcher +varDecl(hasTypeLoc(elaboratedTypeLoc(hasNamedTypeLoc( +templateSpecializationTypeLoc(hasTemplateArgumentLoc(0, +hasTypeLoc(loc(asString("double"))))))))) +matches A<double, int> b, but not double> c}. @@ -7973,17 +10696,20 @@

AST Traversal Matchers

Given template<typename T, typename U> class A {}; - A<bool, int> b; - A<int, bool> c; + A<double, int> b; + A<int, double> c; template<typename T> void f() {} void func() { f<int>(); }; + +The matcher classTemplateSpecializationDecl(hasTemplateArgument( 1, refersToType(asString("int")))) - matches the specialization A<bool, int> +matches the specialization class A<double, int>. -functionDecl(hasTemplateArgument(0, refersToType(asString("int")))) - matches the specialization f<int> +The matcher functionDecl(hasTemplateArgument(0, + refersToType(asString("int")))) +matches the specialization of f. @@ -7995,8 +10721,10 @@

AST Traversal Matchers

struct A {}; A a[7]; int b[7]; -arrayType(hasElementType(builtinType())) - matches "int b[7]" + + +The matcher arrayType(hasElementType(builtinType())) +int[7] Usable as: Matcher<ArrayType>, Matcher<ComplexType> @@ -8005,19 +10733,26 @@

AST Traversal Matchers

Matcher<CompoundLiteralExpr>hasTypeLocMatcher<TypeLoc> Inner
Matches if the type location of a node matches the inner matcher.
 
-Examples:
+Given
   int x;
-declaratorDecl(hasTypeLoc(loc(asString("int"))))
-  matches int x
+The matcher declaratorDecl(hasTypeLoc(loc(asString("int"))))
+matches int x.
+
+Given
+struct point { point(double, double); };
+point p = point(1.0, -1.0);
 
-auto x = int(3);
-cxxTemporaryObjectExpr(hasTypeLoc(loc(asString("int"))))
-  matches int(3)
+The matcher
+cxxTemporaryObjectExpr(hasTypeLoc(loc(asString("point"))))
+matches point(1.0, -1.0).
 
+Given
 struct Foo { Foo(int, int); };
-auto x = Foo(1, 2);
-cxxFunctionalCastExpr(hasTypeLoc(loc(asString("struct Foo"))))
-  matches Foo(1, 2)
+Foo x = Foo(1, 2);
+
+The matcher cxxTemporaryObjectExpr(hasTypeLoc(
+                          loc(asString("Foo"))))
+matches Foo(1, 2).
 
 Usable as: Matcher<BlockDecl>, Matcher<CXXBaseSpecifier>,
   Matcher<CXXCtorInitializer>, Matcher<CXXFunctionalCastExpr>,
@@ -8035,11 +10770,12 @@ 

AST Traversal Matchers

a given matcher. Also matches StmtExprs that have CompoundStmt as children. Given - { {}; 1+2; } -hasAnySubstatement(compoundStmt()) - matches '{ {}; 1+2; }' +void foo() { { {}; 1+2; } } +The matcher +compoundStmt(hasAnySubstatement(compoundStmt().bind("compound"))) +{ {}; 1+2; } and { { {}; 1+2; } } with compoundStmt() - matching '{}' +matching {} and { {}; 1+2; }.
@@ -8050,25 +10786,35 @@

AST Traversal Matchers

other declarations of the same function or coroutine. Given +void foo() { for (;;) {} -forStmt(hasBody(compoundStmt())) - matches 'for (;;) {}' +} +The matcher forStmt(hasBody(compoundStmt().bind("body"))) +matches for (;;) {} with compoundStmt() - matching '{}' + matching {} Given void f(); void f() {} -functionDecl(hasBody(compoundStmt())) - matches 'void f() {}' +The matcher functionDecl(hasBody(compoundStmt().bind("compound"))) +f with compoundStmt() - matching '{}' - but does not match 'void f();' +matching {} +but does not match void f(); Matcher<DecayedType>hasDecayedTypeMatcher<QualType> InnerType
Matches the decayed type, whoes decayed type matches InnerMatcher
+
+Given
+  void f(int i[]) {
+    i[1] = 0;
+  }
+
+The matcher parmVarDecl(hasType(decayedType()))
+matches int i[].
 
@@ -8081,15 +10827,17 @@

AST Traversal Matchers

Given template<typename T> class A {}; A<int> a; -varDecl(hasTypeLoc(templateSpecializationTypeLoc(hasAnyTemplateArgumentLoc( - hasTypeLoc(loc(asString("int"))))))) - matches `A<int> a`. + +The matcher +varDecl(hasTypeLoc(elaboratedTypeLoc(hasNamedTypeLoc( +templateSpecializationTypeLoc(hasAnyTemplateArgumentLoc( +hasTypeLoc(loc(asString("int"))))))))) matches A<int> a. Matcher<DeclRefExpr>hasDeclarationMatcher<Decl> InnerMatcher
Matches a node if the declaration associated with that node
-matches the given matcher.
+  matches the given matcher.
 
 The associated declaration is:
 - for type nodes, the declaration of the underlying type
@@ -8099,17 +10847,25 @@ 

AST Traversal Matchers

- for CXXNewExpr, the declaration of the operator new - for ObjCIvarExpr, the declaration of the ivar -For type nodes, hasDeclaration will generally match the declaration of the -sugared type. Given +Given class X {}; typedef X Y; Y y; -in varDecl(hasType(hasDeclaration(decl()))) the decl will match the -typedefDecl. A common use case is to match the underlying, desugared type. + +For type nodes, hasDeclaration will generally match the declaration of the +sugared type, i.e., the matcher +varDecl(hasType(qualType(hasDeclaration(decl().bind("d"))))), +matches Y y, with +the matcher decl() matching +typedef X Y;. +A common use case is to match the underlying, desugared type. This can be achieved by using the hasUnqualifiedDesugaredType matcher: - varDecl(hasType(hasUnqualifiedDesugaredType( - recordType(hasDeclaration(decl()))))) -In this matcher, the decl will match the CXXRecordDecl of class X. +varDecl(hasType(hasUnqualifiedDesugaredType( + recordType(hasDeclaration(decl().bind("d")))))) +matches Y y. +In this matcher, the matcher decl() will match the +CXXRecordDecl +class X {};. Usable as: Matcher<AddrLabelExpr>, Matcher<CallExpr>, Matcher<CXXConstructExpr>, Matcher<CXXNewExpr>, Matcher<DeclRefExpr>, @@ -8130,9 +10886,12 @@

AST Traversal Matchers

template<typename T, typename U> class A {}; A<double, int> b; A<int, double> c; -varDecl(hasTypeLoc(templateSpecializationTypeLoc(hasTemplateArgumentLoc(0, - hasTypeLoc(loc(asString("double"))))))) - matches `A<double, int> b`, but not `A<int, double> c`. + +The matcher +varDecl(hasTypeLoc(elaboratedTypeLoc(hasNamedTypeLoc( +templateSpecializationTypeLoc(hasTemplateArgumentLoc(0, +hasTypeLoc(loc(asString("double"))))))))) +matches A<double, int> b, but not double> c}.
@@ -8140,18 +10899,20 @@

AST Traversal Matchers

Matches if a node refers to a declaration through a specific
 using shadow declaration.
 
-Examples:
+Given
   namespace a { int f(); }
   using a::f;
   int x = f();
-declRefExpr(throughUsingDecl(anything()))
-  matches f
+
+The matcher declRefExpr(throughUsingDecl(anything()))
+matches f
 
   namespace a { class X{}; }
   using a::X;
   X x;
-typeLoc(loc(usingType(throughUsingDecl(anything()))))
-  matches X
+
+The matcher typeLoc(loc(usingType(throughUsingDecl(anything()))))
+matches X
 
 Usable as: Matcher<DeclRefExpr>, Matcher<UsingType>
 
@@ -8161,10 +10922,14 @@

AST Traversal Matchers

Matches a DeclRefExpr that refers to a declaration that matches the
 specified matcher.
 
-Example matches x in if(x)
-    (matcher = declRefExpr(to(varDecl(hasName("x")))))
-  bool x;
-  if (x) {}
+Given
+  void foo() {
+    bool x;
+    if (x) {}
+  }
+
+The matcher declRefExpr(to(varDecl(hasName("x"))))
+matches x inside the condition of the if-stmt.
 
@@ -8174,16 +10939,19 @@

AST Traversal Matchers

Note that this does not work for global declarations because the AST breaks up multiple-declaration DeclStmt's into multiple single-declaration DeclStmt's. -Example: Given non-global declarations - int a, b = 0; - int c; - int d = 2, e; -declStmt(containsDeclaration( + +Given non-global declarations + void foo() { + int a, b = 0; + int c; + int d = 2, e; + } +The matcher declStmt(containsDeclaration( 0, varDecl(hasInitializer(anything())))) - matches only 'int d = 2, e;', and -declStmt(containsDeclaration(1, varDecl())) - matches 'int a, b = 0' as well as 'int d = 2, e;' - but 'int c;' is not matched. +matches int d = 2, e;. +The matcher declStmt(containsDeclaration(1, varDecl())) +matches int a, b = 0; and int d = 2, e; +but does not match int c;. @@ -8191,29 +10959,39 @@

AST Traversal Matchers

Matches the Decl of a DeclStmt which has a single declaration.
 
 Given
-  int a, b;
-  int c;
-declStmt(hasSingleDecl(anything()))
-  matches 'int c;' but not 'int a, b;'.
+  void foo() {
+    int a, b;
+    int c;
+  }
+The matcher declStmt(hasSingleDecl(anything()))
+matches int c;
+but does not match int a, b;
 
Matcher<DeclaratorDecl>hasTypeLocMatcher<TypeLoc> Inner
Matches if the type location of a node matches the inner matcher.
 
-Examples:
+Given
   int x;
-declaratorDecl(hasTypeLoc(loc(asString("int"))))
-  matches int x
+The matcher declaratorDecl(hasTypeLoc(loc(asString("int"))))
+matches int x.
+
+Given
+struct point { point(double, double); };
+point p = point(1.0, -1.0);
 
-auto x = int(3);
-cxxTemporaryObjectExpr(hasTypeLoc(loc(asString("int"))))
-  matches int(3)
+The matcher
+cxxTemporaryObjectExpr(hasTypeLoc(loc(asString("point"))))
+matches point(1.0, -1.0).
 
+Given
 struct Foo { Foo(int, int); };
-auto x = Foo(1, 2);
-cxxFunctionalCastExpr(hasTypeLoc(loc(asString("struct Foo"))))
-  matches Foo(1, 2)
+Foo x = Foo(1, 2);
+
+The matcher cxxTemporaryObjectExpr(hasTypeLoc(
+                          loc(asString("Foo"))))
+matches Foo(1, 2).
 
 Usable as: Matcher<BlockDecl>, Matcher<CXXBaseSpecifier>,
   Matcher<CXXCtorInitializer>, Matcher<CXXFunctionalCastExpr>,
@@ -8237,8 +11015,9 @@ 

AST Traversal Matchers

} } -cxxRcordDecl(hasDeclContext(namedDecl(hasName("M")))) matches the -declaration of class D. + +The matcher cxxRecordDecl(hasDeclContext(namedDecl(hasName("M")))) + matches the declaration of D.
@@ -8248,8 +11027,11 @@

AST Traversal Matchers

Given decltype(1) a = 1; decltype(2.0) b = 2.0; -decltypeType(hasUnderlyingType(isInteger())) - matches the type of "a" + + +The matcher decltypeType(hasUnderlyingType(isInteger())) +matches the type decltype(1) of the variable +declaration of a . Usable as: Matcher<DecltypeType>, Matcher<UsingType> @@ -8266,16 +11048,17 @@

AST Traversal Matchers

f = 42; } -The matcher: - decompositionDecl(hasAnyBinding(bindingDecl(hasName("f").bind("fBinding")))) -matches the decomposition decl with 'f' bound to "fBinding". + +The matcher + decompositionDecl(hasAnyBinding(bindingDecl(hasName("f")).bind("fBinding"))) +matches auto &[f, s, t] = arr with 'f' bound to "fBinding". Matcher<DecompositionDecl>hasBindingunsigned N, Matcher<BindingDecl> InnerMatcher
Matches the Nth binding of a DecompositionDecl.
 
-For example, in:
+Given
 void foo()
 {
     int arr[3];
@@ -8283,10 +11066,10 @@ 

AST Traversal Matchers

f = 42; } -The matcher: - decompositionDecl(hasBinding(0, - bindingDecl(hasName("f").bind("fBinding")))) -matches the decomposition decl with 'f' bound to "fBinding". + +The matcher decompositionDecl(hasBinding(0, + bindingDecl(hasName("f")).bind("fBinding"))) +matches auto &[f, s, t] = arr with 'f' bound to "fBinding".
@@ -8297,20 +11080,22 @@

AST Traversal Matchers

other declarations of the same function or coroutine. Given +void foo() { for (;;) {} -forStmt(hasBody(compoundStmt())) - matches 'for (;;) {}' +} +The matcher forStmt(hasBody(compoundStmt().bind("body"))) +matches for (;;) {} with compoundStmt() - matching '{}' + matching {} Given void f(); void f() {} -functionDecl(hasBody(compoundStmt())) - matches 'void f() {}' +The matcher functionDecl(hasBody(compoundStmt().bind("compound"))) +f with compoundStmt() - matching '{}' - but does not match 'void f();' +matching {} +but does not match void f(); @@ -8318,8 +11103,13 @@

AST Traversal Matchers

Matches the condition expression of an if statement, for loop,
 switch statement or conditional operator.
 
-Example matches true (matcher = hasCondition(cxxBoolLiteral(equals(true))))
+Given
+void foo() {
   if (true) {}
+}
+
+The matcher ifStmt(hasCondition(cxxBoolLiteral(equals(true))))
+if (true) {}
 
@@ -8334,14 +11124,16 @@

AST Traversal Matchers

class D {}; class D d; -elaboratedTypeLoc(hasNamedTypeLoc(templateSpecializationTypeLoc())); - matches the `TypeLoc` of the variable declaration of `c`, but not `d`. + +The matcher +elaboratedTypeLoc(hasNamedTypeLoc(templateSpecializationTypeLoc())) + matches class C<int>, but not D} Matcher<ElaboratedType>hasQualifierMatcher<NestedNameSpecifier> InnerMatcher
Matches ElaboratedTypes whose qualifier, a NestedNameSpecifier,
-matches InnerMatcher if the qualifier exists.
+  matches InnerMatcher if the qualifier exists.
 
 Given
   namespace N {
@@ -8351,8 +11143,11 @@ 

AST Traversal Matchers

} N::M::D d; -elaboratedType(hasQualifier(hasPrefix(specifiesNamespace(hasName("N")))) -matches the type of the variable declaration of d. + +The matcher +elaboratedType(hasQualifier(hasPrefix(specifiesNamespace(hasName("N"))))) + matches the type N::M::D of the variable declaration + of d.
@@ -8362,20 +11157,20 @@

AST Traversal Matchers

Given namespace N { namespace M { - class D {}; + enum E { Ok }; } } - N::M::D d; + N::M::E e = N::M::Ok; -elaboratedType(namesType(recordType( -hasDeclaration(namedDecl(hasName("D")))))) matches the type of the variable -declaration of d. + +The matcher elaboratedType(namesType(enumType())) +matches the type N::M::E of the declaration of e . Matcher<EnumType>hasDeclarationMatcher<Decl> InnerMatcher
Matches a node if the declaration associated with that node
-matches the given matcher.
+  matches the given matcher.
 
 The associated declaration is:
 - for type nodes, the declaration of the underlying type
@@ -8385,17 +11180,25 @@ 

AST Traversal Matchers

- for CXXNewExpr, the declaration of the operator new - for ObjCIvarExpr, the declaration of the ivar -For type nodes, hasDeclaration will generally match the declaration of the -sugared type. Given +Given class X {}; typedef X Y; Y y; -in varDecl(hasType(hasDeclaration(decl()))) the decl will match the -typedefDecl. A common use case is to match the underlying, desugared type. + +For type nodes, hasDeclaration will generally match the declaration of the +sugared type, i.e., the matcher +varDecl(hasType(qualType(hasDeclaration(decl().bind("d"))))), +matches Y y, with +the matcher decl() matching +typedef X Y;. +A common use case is to match the underlying, desugared type. This can be achieved by using the hasUnqualifiedDesugaredType matcher: - varDecl(hasType(hasUnqualifiedDesugaredType( - recordType(hasDeclaration(decl()))))) -In this matcher, the decl will match the CXXRecordDecl of class X. +varDecl(hasType(hasUnqualifiedDesugaredType( + recordType(hasDeclaration(decl().bind("d")))))) +matches Y y. +In this matcher, the matcher decl() will match the +CXXRecordDecl +class X {};. Usable as: Matcher<AddrLabelExpr>, Matcher<CallExpr>, Matcher<CXXConstructExpr>, Matcher<CXXNewExpr>, Matcher<DeclRefExpr>, @@ -8412,25 +11215,37 @@

AST Traversal Matchers

(Note: Clang's AST refers to other conversions as "casts" too, and calls actual casts "explicit" casts.) + + unsigned int a = (unsigned int)0; + +The matcher explicitCastExpr(hasDestinationType( +qualType(isUnsignedInteger()))) matches (unsigned int)0.
Matcher<ExplicitCastExpr>hasTypeLocMatcher<TypeLoc> Inner
Matches if the type location of a node matches the inner matcher.
 
-Examples:
+Given
   int x;
-declaratorDecl(hasTypeLoc(loc(asString("int"))))
-  matches int x
+The matcher declaratorDecl(hasTypeLoc(loc(asString("int"))))
+matches int x.
+
+Given
+struct point { point(double, double); };
+point p = point(1.0, -1.0);
 
-auto x = int(3);
-cxxTemporaryObjectExpr(hasTypeLoc(loc(asString("int"))))
-  matches int(3)
+The matcher
+cxxTemporaryObjectExpr(hasTypeLoc(loc(asString("point"))))
+matches point(1.0, -1.0).
 
+Given
 struct Foo { Foo(int, int); };
-auto x = Foo(1, 2);
-cxxFunctionalCastExpr(hasTypeLoc(loc(asString("struct Foo"))))
-  matches Foo(1, 2)
+Foo x = Foo(1, 2);
+
+The matcher cxxTemporaryObjectExpr(hasTypeLoc(
+                          loc(asString("Foo"))))
+matches Foo(1, 2).
 
 Usable as: Matcher<BlockDecl>, Matcher<CXXBaseSpecifier>,
   Matcher<CXXCtorInitializer>, Matcher<CXXFunctionalCastExpr>,
@@ -8453,21 +11268,31 @@ 

AST Traversal Matchers

X, while varDecl(hasType(cxxRecordDecl(hasName("X")))) matches the declaration of x. -Example matches x (matcher = expr(hasType(cxxRecordDecl(hasName("X"))))) - and z (matcher = varDecl(hasType(cxxRecordDecl(hasName("X"))))) - and friend class X (matcher = friendDecl(hasType("X")) - and public virtual X (matcher = cxxBaseSpecifier(hasType( - cxxRecordDecl(hasName("X")))) class X {}; void y(X &x) { x; X z; } class Y { friend class X; }; class Z : public virtual X {}; -Example matches class Derived -(matcher = cxxRecordDecl(hasAnyBase(hasType(cxxRecordDecl(hasName("Base")))))) +The matcher expr(hasType(cxxRecordDecl(hasName("X")))) +matches x and z. +The matcher varDecl(hasType(cxxRecordDecl(hasName("X")))) +matches z. +The matcher friendDecl(hasType(asString("class X"))) +matches friend class X. +The matcher cxxRecordDecl(hasAnyBase(cxxBaseSpecifier(hasType( +asString("X"))).bind("b"))) matches +class Z : public virtual X {}, +with cxxBaseSpecifier(...) +matching public virtual X. + +Given class Base {}; class Derived : Base {}; +The matcher +cxxRecordDecl(hasAnyBase(hasType(cxxRecordDecl(hasName("Base"))))) +matches class Derived : Base {}. + Usable as: Matcher<Expr>, Matcher<FriendDecl>, Matcher<ValueDecl>, Matcher<CXXBaseSpecifier>
@@ -8477,17 +11302,25 @@

AST Traversal Matchers

Matches if the expression's or declaration's type matches a type
 matcher.
 
-Example matches x (matcher = expr(hasType(cxxRecordDecl(hasName("X")))))
-            and z (matcher = varDecl(hasType(cxxRecordDecl(hasName("X")))))
-            and U (matcher = typedefDecl(hasType(asString("int")))
-            and friend class X (matcher = friendDecl(hasType("X"))
-            and public virtual X (matcher = cxxBaseSpecifier(hasType(
-                                              asString("class X")))
+Exmaple
  class X {};
  void y(X &x) { x; X z; }
  typedef int U;
  class Y { friend class X; };
  class Z : public virtual X {};
+
+The matcher expr(hasType(cxxRecordDecl(hasName("X"))))
+matches x and z.
+The matcher varDecl(hasType(cxxRecordDecl(hasName("X"))))
+matches z
+The matcher typedefDecl(hasType(asString("int")))
+matches typedef int U
+The matcher friendDecl(hasType(asString("class X")))
+matches friend class X
+The matcher cxxRecordDecl(hasAnyBase(cxxBaseSpecifier(hasType(
+asString("X"))).bind("b"))) matches class Z : public virtual X {},
+with cxxBaseSpecifier(...)
+matching public virtual X.
 
@@ -8504,15 +11337,16 @@

AST Traversal Matchers

appear in the C++17 AST. Given - struct H {}; H G(); void f() { H D = G(); } -``varDecl(hasInitializer(ignoringElidableConstructorCall(callExpr())))`` -matches ``H D = G()`` in C++11 through C++17 (and beyond). + +The matcher +varDecl(hasInitializer(ignoringElidableConstructorCall(callExpr()))) +matches H D = G(). @@ -8523,19 +11357,25 @@

AST Traversal Matchers

Parentheses and explicit casts are not discarded. Given int arr[5]; - int a = 0; + const int a = 0; char b = 0; const int c = a; int *d = arr; long e = (long) 0l; -The matchers - varDecl(hasInitializer(ignoringImpCasts(integerLiteral()))) - varDecl(hasInitializer(ignoringImpCasts(declRefExpr()))) -would match the declarations for a, b, c, and d, but not e. -While - varDecl(hasInitializer(integerLiteral())) - varDecl(hasInitializer(declRefExpr())) -only match the declarations for a. +The matcher +varDecl(hasInitializer(ignoringImpCasts(integerLiteral()))) +matches a and b, +but does not match e. +The matcher +varDecl(hasInitializer(ignoringImpCasts(declRefExpr()))) +matches c and d. + +The matcher +varDecl(hasInitializer(integerLiteral())) +matches a, +but does not match b or e. +The matcher varDecl(hasInitializer(declRefExpr())) +does not match c or d. @@ -8544,17 +11384,34 @@

AST Traversal Matchers

nodes are stripped off. Parentheses and explicit casts are not discarded. + Given - class C {}; - C a = C(); - C b; - C c = b; -The matchers - varDecl(hasInitializer(ignoringImplicit(cxxConstructExpr()))) -would match the declarations for a, b, and c. -While - varDecl(hasInitializer(cxxConstructExpr())) -only match the declarations for b and c. + void f(int param) { + int a = 0; + int b = param; + const int c = 0; + const int d = param; + int e = (0U); + int f = (int)0.0; + const int g = ((int)(((0)))); + } + +The matcher +varDecl(hasInitializer(ignoringImplicit(integerLiteral()))) +matches int a = 0 and const int c = 0, +but not int e = (0U) and ((int)(((0))). +The matcher +varDecl(hasInitializer(integerLiteral())) +matches int a = 0 and const int c = 0, +but not int e = (0U) and ((int)(((0))). + +The matcher +varDecl(hasInitializer(ignoringImplicit(declRefExpr()))) +matches int b = param and const int d = param. +The matcher +varDecl(hasInitializer(declRefExpr())) +matches neither int b = param nor const int d = param, +because an l-to-r-value cast happens. @@ -8568,12 +11425,14 @@

AST Traversal Matchers

char b = (0); void* c = reinterpret_cast<char*>(0); char d = char(0); + The matcher - varDecl(hasInitializer(ignoringParenCasts(integerLiteral()))) -would match the declarations for a, b, c, and d. -while - varDecl(hasInitializer(integerLiteral())) -only match the declaration for a. +varDecl(hasInitializer(ignoringParenCasts(integerLiteral()))) +matches a, b, c +and d. +The matcher +varDecl(hasInitializer(integerLiteral())) +matches a. @@ -8589,14 +11448,21 @@

AST Traversal Matchers

const int c = a; int *d = (arr); long e = ((long) 0l); -The matchers - varDecl(hasInitializer(ignoringParenImpCasts(integerLiteral()))) - varDecl(hasInitializer(ignoringParenImpCasts(declRefExpr()))) -would match the declarations for a, b, c, and d, but not e. -while - varDecl(hasInitializer(integerLiteral())) - varDecl(hasInitializer(declRefExpr())) -would only match the declaration for a. + +The matcher +varDecl(hasInitializer(ignoringParenImpCasts(integerLiteral()))) +matches a and b, +but does not match e. +The matcher +varDecl(hasInitializer(ignoringParenImpCasts(declRefExpr()))) +matches c and d. + +The matcher +varDecl(hasInitializer(integerLiteral())) +matches a, +but does not match b or e. +The matcher varDecl(hasInitializer(declRefExpr())) +does not match c, or d. @@ -8606,8 +11472,9 @@

AST Traversal Matchers

Given const char* str = ("my-string"); The matcher - implicitCastExpr(hasSourceExpression(ignoringParens(stringLiteral()))) -would match the implicit cast resulting from the assignment. +implicitCastExpr(hasSourceExpression(ignoringParens(stringLiteral()))) +would match the implicit cast resulting from the assignment +("my-string"). @@ -8620,10 +11487,14 @@

AST Traversal Matchers

int b = 3; int c; }; + +The matcher fieldDecl(hasInClassInitializer(integerLiteral(equals(2)))) - matches 'int a;' but not 'int b;'. -fieldDecl(hasInClassInitializer(anything())) - matches 'int a;' and 'int b;' but not 'int c;'. +matches a, +but does not match b. +The matcher fieldDecl(hasInClassInitializer(anything())) +matches a and b, +but does not match c. @@ -8634,20 +11505,22 @@

AST Traversal Matchers

other declarations of the same function or coroutine. Given +void foo() { for (;;) {} -forStmt(hasBody(compoundStmt())) - matches 'for (;;) {}' +} +The matcher forStmt(hasBody(compoundStmt().bind("body"))) +matches for (;;) {} with compoundStmt() - matching '{}' + matching {} Given void f(); void f() {} -functionDecl(hasBody(compoundStmt())) - matches 'void f() {}' +The matcher functionDecl(hasBody(compoundStmt().bind("compound"))) +f with compoundStmt() - matching '{}' - but does not match 'void f();' +matching {} +but does not match void f(); @@ -8655,28 +11528,38 @@

AST Traversal Matchers

Matches the condition expression of an if statement, for loop,
 switch statement or conditional operator.
 
-Example matches true (matcher = hasCondition(cxxBoolLiteral(equals(true))))
+Given
+void foo() {
   if (true) {}
+}
+
+The matcher ifStmt(hasCondition(cxxBoolLiteral(equals(true))))
+if (true) {}
 
Matcher<ForStmt>hasIncrementMatcher<Stmt> InnerMatcher
Matches the increment statement of a for loop.
 
-Example:
-    forStmt(hasIncrement(unaryOperator(hasOperatorName("++"))))
-matches '++x' in
-    for (x; x < N; ++x) { }
+Given
+void foo(int N) {
+    for (int x = 0; x < N; ++x) { }
+}
+The matcher
+forStmt(hasIncrement(unaryOperator(hasOperatorName("++"))))
+matches for (int x = 0; x < N; ++x) { }
 
Matcher<ForStmt>hasLoopInitMatcher<Stmt> InnerMatcher
Matches the initialization statement of a for loop.
 
-Example:
-    forStmt(hasLoopInit(declStmt()))
-matches 'int x = 0' in
+Given
+void foo(int N) {
     for (int x = 0; x < N; ++x) { }
+}
+The matcher forStmt(hasLoopInit(declStmt()))
+matches for (int x = 0; x < N; ++x) { }
 
@@ -8690,21 +11573,31 @@

AST Traversal Matchers

X, while varDecl(hasType(cxxRecordDecl(hasName("X")))) matches the declaration of x. -Example matches x (matcher = expr(hasType(cxxRecordDecl(hasName("X"))))) - and z (matcher = varDecl(hasType(cxxRecordDecl(hasName("X"))))) - and friend class X (matcher = friendDecl(hasType("X")) - and public virtual X (matcher = cxxBaseSpecifier(hasType( - cxxRecordDecl(hasName("X")))) class X {}; void y(X &x) { x; X z; } class Y { friend class X; }; class Z : public virtual X {}; -Example matches class Derived -(matcher = cxxRecordDecl(hasAnyBase(hasType(cxxRecordDecl(hasName("Base")))))) +The matcher expr(hasType(cxxRecordDecl(hasName("X")))) +matches x and z. +The matcher varDecl(hasType(cxxRecordDecl(hasName("X")))) +matches z. +The matcher friendDecl(hasType(asString("class X"))) +matches friend class X. +The matcher cxxRecordDecl(hasAnyBase(cxxBaseSpecifier(hasType( +asString("X"))).bind("b"))) matches +class Z : public virtual X {}, +with cxxBaseSpecifier(...) +matching public virtual X. + +Given class Base {}; class Derived : Base {}; +The matcher +cxxRecordDecl(hasAnyBase(hasType(cxxRecordDecl(hasName("Base"))))) +matches class Derived : Base {}. + Usable as: Matcher<Expr>, Matcher<FriendDecl>, Matcher<ValueDecl>, Matcher<CXXBaseSpecifier> @@ -8714,17 +11607,25 @@

AST Traversal Matchers

Matches if the expression's or declaration's type matches a type
 matcher.
 
-Example matches x (matcher = expr(hasType(cxxRecordDecl(hasName("X")))))
-            and z (matcher = varDecl(hasType(cxxRecordDecl(hasName("X")))))
-            and U (matcher = typedefDecl(hasType(asString("int")))
-            and friend class X (matcher = friendDecl(hasType("X"))
-            and public virtual X (matcher = cxxBaseSpecifier(hasType(
-                                              asString("class X")))
+Exmaple
  class X {};
  void y(X &x) { x; X z; }
  typedef int U;
  class Y { friend class X; };
  class Z : public virtual X {};
+
+The matcher expr(hasType(cxxRecordDecl(hasName("X"))))
+matches x and z.
+The matcher varDecl(hasType(cxxRecordDecl(hasName("X"))))
+matches z
+The matcher typedefDecl(hasType(asString("int")))
+matches typedef int U
+The matcher friendDecl(hasType(asString("class X")))
+matches friend class X
+The matcher cxxRecordDecl(hasAnyBase(cxxBaseSpecifier(hasType(
+asString("X"))).bind("b"))) matches class Z : public virtual X {},
+with cxxBaseSpecifier(...)
+matching public virtual X.
 
@@ -8744,13 +11645,22 @@

AST Traversal Matchers

template <typename T, typename U> void f(T&& t, U&& u) {} - bool B = false; - f(R, B); -templateSpecializationType(forEachTemplateArgument(isExpr(expr()))) - matches twice, with expr() matching 'R * 2' and 'R * 4' -functionDecl(forEachTemplateArgument(refersToType(builtinType()))) - matches the specialization f<unsigned, bool> twice, for 'unsigned' - and 'bool' + void foo() { + bool B = false; + f(R, B); + } + +The matcher +templateSpecializationType(forEachTemplateArgument(isExpr(expr().bind("t_arg")))) +matches Matrix<int, R * 2, R * 4> twice, with +expr() matching R * 2 and +R * 4. +The matcher +functionDecl(forEachTemplateArgument(refersToType(qualType().bind("type")))) +matches the specialization of f twice, +with qualType() matching +unsigned and +bool. @@ -8763,12 +11673,12 @@

AST Traversal Matchers

void f(); void f() {} void g(); -functionDecl(hasAnyBody(compoundStmt())) - matches both 'void f();' - and 'void f() {}' +The matcher functionDecl(hasAnyBody(compoundStmt())) + matches f + and f with compoundStmt() - matching '{}' - but does not match 'void g();' + matching {} + but does not match void g(); @@ -8780,23 +11690,26 @@

AST Traversal Matchers

Given class X { void f(int x, int y, int z) {} }; -cxxMethodDecl(hasAnyParameter(hasName("y"))) - matches f(int x, int y, int z) {} + +The matcher cxxMethodDecl(hasAnyParameter(hasName("y"))) + matches f with hasAnyParameter(...) matching int y For ObjectiveC, given @interface I - (void) f:(int) y; @end + the matcher objcMethodDecl(hasAnyParameter(hasName("y"))) -matches the declaration of method f with hasParameter + matches the declaration of method f with hasParameter matching y. For blocks, given b = ^(int y) { printf("%d", y) }; + the matcher blockDecl(hasAnyParameter(hasName("y"))) -matches the declaration of the block b with hasParameter + matches the declaration of the block b with hasParameter matching y. @@ -8810,9 +11723,11 @@

AST Traversal Matchers

Given template<typename T> class A {}; A<int> a; -varDecl(hasTypeLoc(templateSpecializationTypeLoc(hasAnyTemplateArgumentLoc( - hasTypeLoc(loc(asString("int"))))))) - matches `A<int> a`. + +The matcher +varDecl(hasTypeLoc(elaboratedTypeLoc(hasNamedTypeLoc( +templateSpecializationTypeLoc(hasAnyTemplateArgumentLoc( +hasTypeLoc(loc(asString("int"))))))))) matches A<int> a. @@ -8826,15 +11741,19 @@

AST Traversal Matchers

template<> class A<double> {}; A<int> a; - template<typename T> f() {}; + template<typename T> void f() {}; void func() { f<int>(); }; -classTemplateSpecializationDecl(hasAnyTemplateArgument( - refersToType(asString("int")))) - matches the specialization A<int> -functionDecl(hasAnyTemplateArgument(refersToType(asString("int")))) - matches the specialization f<int> +The matcher classTemplateSpecializationDecl( + hasAnyTemplateArgument( + refersToType(asString("int")))) +matches class A<int>. + +The matcher +functionDecl(hasAnyTemplateArgument( + refersToType(asString("int")))) +matches the instantiation of f. @@ -8845,20 +11764,22 @@

AST Traversal Matchers

other declarations of the same function or coroutine. Given +void foo() { for (;;) {} -forStmt(hasBody(compoundStmt())) - matches 'for (;;) {}' +} +The matcher forStmt(hasBody(compoundStmt().bind("body"))) +matches for (;;) {} with compoundStmt() - matching '{}' + matching {} Given void f(); void f() {} -functionDecl(hasBody(compoundStmt())) - matches 'void f() {}' +The matcher functionDecl(hasBody(compoundStmt().bind("compound"))) +f with compoundStmt() - matching '{}' - but does not match 'void f();' +matching {} +but does not match void f(); @@ -8873,15 +11794,27 @@

AST Traversal Matchers

explicit S(double); // #2 operator int(); // #3 explicit operator bool(); // #4 - explicit(false) S(bool) // # 7 - explicit(true) S(char) // # 8 - explicit(b) S(S) // # 9 + explicit(false) S(bool); // # 7 + explicit(true) S(char); // # 8 + explicit(b) S(float); // # 9 }; - S(int) -> S<true> // #5 - explicit S(double) -> S<false> // #6 -cxxConstructorDecl(hasExplicitSpecifier(constantExpr())) will match #7, #8 and #9, but not #1 or #2. -cxxConversionDecl(hasExplicitSpecifier(constantExpr())) will not match #3 or #4. -cxxDeductionGuideDecl(hasExplicitSpecifier(constantExpr())) will not match #5 or #6. + S(int) -> S<true>; // #5 + explicit S(double) -> S<false>; // #6 + +The matcher +cxxConstructorDecl(hasExplicitSpecifier(constantExpr())) matches +explicit(false) S(bool) and explicit(true) S(char), +but does not match explicit(b) S(float), S(int) or +explicit S(double). +The matcher +cxxConversionDecl(hasExplicitSpecifier(constantExpr())) does not +match operator int() or explicit operator bool(). +Matcher +The matcher +cxxDeductionGuideDecl(hasExplicitSpecifier(declRefExpr())) +matches the implicitly generated deduction guide +auto (float) -> S<b> of the constructor +S(float)}. @@ -8891,15 +11824,18 @@

AST Traversal Matchers

Given class X { void f(int x) {} }; -cxxMethodDecl(hasParameter(0, hasType(varDecl()))) - matches f(int x) {} + +The matcher +cxxMethodDecl(hasParameter(0, hasType(asString("int")))) +matches f with hasParameter(...) - matching int x +matching int x. For ObjectiveC, given @interface I - (void) f:(int) y; @end -the matcher objcMethodDecl(hasParameter(0, hasName("y"))) + +The matcher objcMethodDecl(hasParameter(0, hasName("y"))) matches the declaration of method f with hasParameter matching y. @@ -8911,9 +11847,9 @@

AST Traversal Matchers

Given int f() { return 5; } void g() {} -functionDecl(hasReturnTypeLoc(loc(asString("int")))) - matches the declaration of `f`, but not `g`. - +The matcher functionDecl(hasReturnTypeLoc(loc(asString("int")))) + matches the declaration of f, but not + Matcher<FunctionDecl>hasTemplateArgumentLocunsigned Index, Matcher<TemplateArgumentLoc> InnerMatcher @@ -8925,9 +11861,12 @@

AST Traversal Matchers

template<typename T, typename U> class A {}; A<double, int> b; A<int, double> c; -varDecl(hasTypeLoc(templateSpecializationTypeLoc(hasTemplateArgumentLoc(0, - hasTypeLoc(loc(asString("double"))))))) - matches `A<double, int> b`, but not `A<int, double> c`. + +The matcher +varDecl(hasTypeLoc(elaboratedTypeLoc(hasNamedTypeLoc( +templateSpecializationTypeLoc(hasTemplateArgumentLoc(0, +hasTypeLoc(loc(asString("double"))))))))) +matches A<double, int> b, but not double> c}. @@ -8938,27 +11877,31 @@

AST Traversal Matchers

Given template<typename T, typename U> class A {}; - A<bool, int> b; - A<int, bool> c; + A<double, int> b; + A<int, double> c; template<typename T> void f() {} void func() { f<int>(); }; + +The matcher classTemplateSpecializationDecl(hasTemplateArgument( 1, refersToType(asString("int")))) - matches the specialization A<bool, int> +matches the specialization class A<double, int>. -functionDecl(hasTemplateArgument(0, refersToType(asString("int")))) - matches the specialization f<int> +The matcher functionDecl(hasTemplateArgument(0, + refersToType(asString("int")))) +matches the specialization of f. Matcher<FunctionDecl>returnsMatcher<QualType> InnerMatcher
Matches the return type of a function declaration.
 
-Given:
+Given
   class X { int f() { return 1; } };
-cxxMethodDecl(returns(asString("int")))
-  matches int f() { return 1; }
+
+The matcher cxxMethodDecl(returns(asString("int")))
+  matches f
 
@@ -8966,8 +11909,13 @@

AST Traversal Matchers

Matches the condition expression of an if statement, for loop,
 switch statement or conditional operator.
 
-Example matches true (matcher = hasCondition(cxxBoolLiteral(equals(true))))
+Given
+void foo() {
   if (true) {}
+}
+
+The matcher ifStmt(hasCondition(cxxBoolLiteral(equals(true))))
+if (true) {}
 
@@ -8975,25 +11923,37 @@

AST Traversal Matchers

Matches the condition variable statement in an if statement.
 
 Given
+struct A {};
+A* GetAPointer();
+void foo() {
   if (A* a = GetAPointer()) {}
-hasConditionVariableStatement(...)
-  matches 'A* a = GetAPointer()'.
+}
+
+The matcher ifStmt(hasConditionVariableStatement(declStmt()))
+if (A* a = GetAPointer()) {}
 
Matcher<IfStmt>hasElseMatcher<Stmt> InnerMatcher
Matches the else-statement of an if statement.
 
-Examples matches the if statement
-  (matcher = ifStmt(hasElse(cxxBoolLiteral(equals(true)))))
+Given
+void foo() {
   if (false) false; else true;
+}
+
+The matcher ifStmt(hasElse(cxxBoolLiteral(equals(true))))
+if (false) false; else true
 
Matcher<IfStmt>hasInitStatementMatcher<Stmt> InnerMatcher
Matches selection statements with initializer.
 
-Given:
+Given
+ struct vec { int* begin(); int* end(); };
+ int foobar();
+ vec& get_range();
  void foo() {
    if (int i = foobar(); i > 0) {}
    switch (int i = foobar(); i) {}
@@ -9004,48 +11964,77 @@ 

AST Traversal Matchers

switch (foobar()) {} for (auto& x : get_range()) {} } -ifStmt(hasInitStatement(anything())) - matches the if statement in foo but not in bar. -switchStmt(hasInitStatement(anything())) - matches the switch statement in foo but not in bar. -cxxForRangeStmt(hasInitStatement(anything())) - matches the range for statement in foo but not in bar. + +The matcher ifStmt(hasInitStatement(anything())) + matches the if statement if (int i = foobar(); i > 0) {} + in foo but not if (foobar() > 0) {} in bar. +The matcher switchStmt(hasInitStatement(anything())) + matches the switch statement switch (int i = foobar(); i) {} + in foo but not switch (foobar()) {} in bar. +The matcher cxxForRangeStmt(hasInitStatement(anything())) + matches the range for statement + for (auto& a = get_range(); auto& x : a) {} in foo + but not for (auto& x : get_range()) {} in bar.
Matcher<IfStmt>hasThenMatcher<Stmt> InnerMatcher
Matches the then-statement of an if statement.
 
-Examples matches the if statement
-  (matcher = ifStmt(hasThen(cxxBoolLiteral(equals(true)))))
+Given
+void foo() {
   if (false) true; else false;
+}
+
+The matcher ifStmt(hasThen(cxxBoolLiteral(equals(true))))
+if (false) true; else false
 
Matcher<ImplicitCastExpr>hasImplicitDestinationTypeMatcher<QualType> InnerMatcher
Matches implicit casts whose destination type matches a given
 matcher.
+
+Given
+  unsigned int a = 0;
+
+The matcher
+implicitCastExpr(hasImplicitDestinationType(
+qualType(isUnsignedInteger()))) matches 0.
 
Matcher<InitListExpr>hasInitunsigned N, Matcher<Expr> InnerMatcher
Matches the n'th item of an initializer list expression.
 
-Example matches y.
-    (matcher = initListExpr(hasInit(0, expr())))
-  int x{y}.
+Given
+  int y = 42;
+  int x{y};
+
+The matcher initListExpr(hasInit(0, expr()))
+matches {y}.
 
Matcher<InitListExpr>hasSyntacticFormMatcher<Expr> InnerMatcher
Matches the syntactic form of init list expressions
 (if expression have it).
+
+Given
+  int a[] = { 1, 2 };
+  struct B { int x, y; };
+  struct B b = { 5, 6 };
+
+
+The matcher
+initListExpr(hasSyntacticForm(expr().bind("syntactic")))
+matches { 1, 2 } and { 5, 6 }.
 
Matcher<InjectedClassNameType>hasDeclarationMatcher<Decl> InnerMatcher
Matches a node if the declaration associated with that node
-matches the given matcher.
+  matches the given matcher.
 
 The associated declaration is:
 - for type nodes, the declaration of the underlying type
@@ -9055,17 +12044,25 @@ 

AST Traversal Matchers

- for CXXNewExpr, the declaration of the operator new - for ObjCIvarExpr, the declaration of the ivar -For type nodes, hasDeclaration will generally match the declaration of the -sugared type. Given +Given class X {}; typedef X Y; Y y; -in varDecl(hasType(hasDeclaration(decl()))) the decl will match the -typedefDecl. A common use case is to match the underlying, desugared type. + +For type nodes, hasDeclaration will generally match the declaration of the +sugared type, i.e., the matcher +varDecl(hasType(qualType(hasDeclaration(decl().bind("d"))))), +matches Y y, with +the matcher decl() matching +typedef X Y;. +A common use case is to match the underlying, desugared type. This can be achieved by using the hasUnqualifiedDesugaredType matcher: - varDecl(hasType(hasUnqualifiedDesugaredType( - recordType(hasDeclaration(decl()))))) -In this matcher, the decl will match the CXXRecordDecl of class X. +varDecl(hasType(hasUnqualifiedDesugaredType( + recordType(hasDeclaration(decl().bind("d")))))) +matches Y y. +In this matcher, the matcher decl() will match the +CXXRecordDecl +class X {};. Usable as: Matcher<AddrLabelExpr>, Matcher<CallExpr>, Matcher<CXXConstructExpr>, Matcher<CXXNewExpr>, Matcher<DeclRefExpr>, @@ -9079,7 +12076,7 @@

AST Traversal Matchers

Matcher<LabelStmt>hasDeclarationMatcher<Decl> InnerMatcher
Matches a node if the declaration associated with that node
-matches the given matcher.
+  matches the given matcher.
 
 The associated declaration is:
 - for type nodes, the declaration of the underlying type
@@ -9089,17 +12086,25 @@ 

AST Traversal Matchers

- for CXXNewExpr, the declaration of the operator new - for ObjCIvarExpr, the declaration of the ivar -For type nodes, hasDeclaration will generally match the declaration of the -sugared type. Given +Given class X {}; typedef X Y; Y y; -in varDecl(hasType(hasDeclaration(decl()))) the decl will match the -typedefDecl. A common use case is to match the underlying, desugared type. + +For type nodes, hasDeclaration will generally match the declaration of the +sugared type, i.e., the matcher +varDecl(hasType(qualType(hasDeclaration(decl().bind("d"))))), +matches Y y, with +the matcher decl() matching +typedef X Y;. +A common use case is to match the underlying, desugared type. This can be achieved by using the hasUnqualifiedDesugaredType matcher: - varDecl(hasType(hasUnqualifiedDesugaredType( - recordType(hasDeclaration(decl()))))) -In this matcher, the decl will match the CXXRecordDecl of class X. +varDecl(hasType(hasUnqualifiedDesugaredType( + recordType(hasDeclaration(decl().bind("d")))))) +matches Y y. +In this matcher, the matcher decl() will match the +CXXRecordDecl +class X {};. Usable as: Matcher<AddrLabelExpr>, Matcher<CallExpr>, Matcher<CXXConstructExpr>, Matcher<CXXNewExpr>, Matcher<DeclRefExpr>, @@ -9122,9 +12127,13 @@

AST Traversal Matchers

auto f = [x](){}; auto g = [x = 1](){}; } -In the matcher -lambdaExpr(hasAnyCapture(lambdaCapture(capturesVar(hasName("x")))), -capturesVar(hasName("x")) matches `x` and `x = 1`. + +The matcher +lambdaExpr(hasAnyCapture( + lambdaCapture(capturesVar(hasName("x"))).bind("capture"))) +matches [x](){} and [x = 1](){}, with +lambdaCapture(capturesVar(hasName("x"))).bind("capture") +matching x and x = 1.
@@ -9133,13 +12142,18 @@

AST Traversal Matchers

Given int main() { - int x, y; + int x; + int y; float z; auto f = [=]() { return x + y + z; }; } -lambdaExpr(forEachLambdaCapture( - lambdaCapture(capturesVar(varDecl(hasType(isInteger())))))) -will trigger two matches, binding for 'x' and 'y' respectively. + +The matcher lambdaExpr(forEachLambdaCapture( + lambdaCapture(capturesVar( + varDecl(hasType(isInteger())).bind("captured"))))) +matches [=]() { return x + y + z; } two times, +with varDecl(hasType(isInteger())) matching +int x and int y.
@@ -9151,15 +12165,16 @@

AST Traversal Matchers

int t = 5; auto f = [=](){ return t; }; } -lambdaExpr(hasAnyCapture(lambdaCapture())) and -lambdaExpr(hasAnyCapture(lambdaCapture(refersToVarDecl(hasName("t"))))) - both match `[=](){ return t; }`. + +The matcher lambdaExpr(hasAnyCapture(lambdaCapture())) and +lambdaExpr(hasAnyCapture(lambdaCapture(capturesVar(hasName("t"))))) + both match [=](){ return t; }. Matcher<MemberExpr>hasDeclarationMatcher<Decl> InnerMatcher
Matches a node if the declaration associated with that node
-matches the given matcher.
+  matches the given matcher.
 
 The associated declaration is:
 - for type nodes, the declaration of the underlying type
@@ -9169,17 +12184,25 @@ 

AST Traversal Matchers

- for CXXNewExpr, the declaration of the operator new - for ObjCIvarExpr, the declaration of the ivar -For type nodes, hasDeclaration will generally match the declaration of the -sugared type. Given +Given class X {}; typedef X Y; Y y; -in varDecl(hasType(hasDeclaration(decl()))) the decl will match the -typedefDecl. A common use case is to match the underlying, desugared type. + +For type nodes, hasDeclaration will generally match the declaration of the +sugared type, i.e., the matcher +varDecl(hasType(qualType(hasDeclaration(decl().bind("d"))))), +matches Y y, with +the matcher decl() matching +typedef X Y;. +A common use case is to match the underlying, desugared type. This can be achieved by using the hasUnqualifiedDesugaredType matcher: - varDecl(hasType(hasUnqualifiedDesugaredType( - recordType(hasDeclaration(decl()))))) -In this matcher, the decl will match the CXXRecordDecl of class X. +varDecl(hasType(hasUnqualifiedDesugaredType( + recordType(hasDeclaration(decl().bind("d")))))) +matches Y y. +In this matcher, the matcher decl() will match the +CXXRecordDecl +class X {};. Usable as: Matcher<AddrLabelExpr>, Matcher<CallExpr>, Matcher<CXXConstructExpr>, Matcher<CXXNewExpr>, Matcher<DeclRefExpr>, @@ -9201,11 +12224,14 @@

AST Traversal Matchers

int m; int f(X x) { x.m; return m; } }; + + +The matcher memberExpr(hasObjectExpression(hasType(cxxRecordDecl(hasName("X"))))) - matches `x.m`, but not `m`; however, -memberExpr(hasObjectExpression(hasType(pointsTo( - cxxRecordDecl(hasName("X")))))) - matches `m` (aka. `this->m`), but not `x.m`. +matches x.m, but not m; however, +The matcher memberExpr(hasObjectExpression(hasType(pointsTo( +cxxRecordDecl(hasName("X")))))) +matches m (aka. this->m), but not x.m.
@@ -9214,13 +12240,14 @@

AST Traversal Matchers

given matcher. Given - struct { int first, second; } first, second; - int i(second.first); - int j(first.second); -memberExpr(member(hasName("first"))) - matches second.first - but not first.second (because the member name there is "second"). - + struct { int first = 0, second = 1; } first, second; + int i = second.first; + int j = first.second; + + +The matcher memberExpr(member(hasName("first"))) +matches second.first +but not Matcher<MemberPointerType>pointeeMatcher<Type> @@ -9229,10 +12256,14 @@

AST Traversal Matchers

Given int *a; - int const *b; - float const *f; -pointerType(pointee(isConstQualified(), isInteger())) - matches "int const *b" + const int *b; + int * const c = nullptr; + const float *f; + +The matcher pointerType(pointee(isConstQualified(), isInteger())) +matches const int *, +but does not match int * const +or const float *. Usable as: Matcher<BlockPointerType>, Matcher<MemberPointerType>, Matcher<PointerType>, Matcher<ReferenceType> @@ -9246,9 +12277,10 @@

AST Traversal Matchers

Given namespace N { template<class T> void f(T t); } template <class T> void g() { using N::f; f(T()); } -unresolvedLookupExpr(hasAnyDeclaration( + +The matcher unresolvedLookupExpr(hasAnyDeclaration( namedDecl(hasUnderlyingDecl(hasName("::N::f"))))) - matches the use of f in g() . + matches f in g(). @@ -9258,14 +12290,29 @@

AST Traversal Matchers

Given struct A { struct B { struct C {}; }; }; A::B::C c; -nestedNameSpecifierLoc(hasPrefix(loc(specifiesType(asString("struct A"))))) - matches "A::" + +The matcher +nestedNameSpecifierLoc(hasPrefix(loc(specifiesType(asString( +"struct A"))))) matches A::B::. -Matcher<NestedNameSpecifierLoc>locMatcher<NestedNameSpecifier> InnerMatcher -
Matches NestedNameSpecifierLocs for which the given inner
-NestedNameSpecifier-matcher matches.
+Matcher<NestedNameSpecifierLoc>locMatcher<NestedNameSpecifier> InnerMatcher
+
Matches NestedNameSpecifierLocs for which the given inner
+NestedNameSpecifier-matcher matches.
+
+Given
+  namespace ns {
+    struct A { static void f(); };
+    void A::f() {}
+    void g() { A::f(); }
+  }
+  ns::A a;
+
+
+The matcher nestedNameSpecifierLoc(loc(specifiesType(
+hasDeclaration(namedDecl(hasName("A")))))) matches A::
+twice.
 
@@ -9276,9 +12323,10 @@

AST Traversal Matchers

Given struct A { struct B { struct C {}; }; }; A::B::C c; -nestedNameSpecifierLoc(specifiesTypeLoc(loc(type( + +The matcher nestedNameSpecifierLoc(specifiesTypeLoc(loc(qualType( hasDeclaration(cxxRecordDecl(hasName("A"))))))) - matches "A::" +matches A::
@@ -9288,8 +12336,10 @@

AST Traversal Matchers

Given struct A { struct B { struct C {}; }; }; A::B::C c; -nestedNameSpecifier(hasPrefix(specifiesType(asString("struct A")))) and - matches "A::" + +The matcher +nestedNameSpecifier(hasPrefix(specifiesType(asString( +"struct A")))) matches struct A::B @@ -9300,8 +12350,10 @@

AST Traversal Matchers

Given namespace ns { struct A {}; } ns::A a; -nestedNameSpecifier(specifiesNamespace(hasName("ns"))) - matches "ns::" + +The matcher +nestedNameSpecifier(specifiesNamespace(hasName("ns"))) matches +ns. @@ -9312,10 +12364,11 @@

AST Traversal Matchers

Given struct A { struct B { struct C {}; }; }; A::B::C c; -nestedNameSpecifier(specifiesType( + +The matcher nestedNameSpecifier(specifiesType( hasDeclaration(cxxRecordDecl(hasName("A"))) )) - matches "A::" +matches A. @@ -9323,12 +12376,16 @@

AST Traversal Matchers

Matches any clause in an OpenMP directive.
 
 Given
-
+  void foo() {
   #pragma omp parallel
+    ;
   #pragma omp parallel default(none)
+    ;
+  }
 
-``ompExecutableDirective(hasAnyClause(anything()))`` matches
-``omp parallel default(none)``.
+
+The matcher ompExecutableDirective(hasAnyClause(anything()))
+matches #pragma omp parallel default(none).
 
@@ -9339,13 +12396,18 @@

AST Traversal Matchers

If it is, it will never match. Given + void foo() { + #pragma omp parallel + ; + #pragma omp parallel + {} + } - #pragma omp parallel - ; - #pragma omp parallel - {} -``ompExecutableDirective(hasStructuredBlock(nullStmt()))`` will match ``;`` +The matcher +ompExecutableDirective(hasStructuredBlock(nullStmt().bind("stmt"))) +matches #pragma omp parallel, +with stmtt() matching {}. @@ -9357,22 +12419,29 @@

AST Traversal Matchers

Note that a class is not considered to be derived from itself. Example matches Y, Z, C (Base == hasName("X")) - class X; + class X {}; class Y : public X {}; // directly derived class Z : public Y {}; // indirectly derived typedef X A; typedef A B; class C : public B {}; // derived from a typedef of X -In the following example, Bar matches isDerivedFrom(hasName("X")): - class Foo; - typedef Foo X; - class Bar : public Foo {}; // derived from a type that X is a typedef of + class Foo {}; + typedef Foo Alias; + class Bar : public Alias {}; + // derived from a type that Alias is a typedef of Foo + + +The matcher cxxRecordDecl(isDerivedFrom(hasName("X"))) +matches Y, Z and C. +The matcher cxxRecordDecl(isDerivedFrom(hasName("Foo"))) +matches Bar. In the following example, Bar matches isDerivedFrom(hasName("NSObject")) @interface NSObject @end @interface Bar : NSObject @end + Usable as: Matcher<CXXRecordDecl>, Matcher<ObjCInterfaceDecl> @@ -9383,24 +12452,45 @@

AST Traversal Matchers

Note that a class is not considered to be derived from itself. -Example matches Y, C (Base == hasName("X")) - class X; +Given + class X {}; class Y : public X {}; // directly derived class Z : public Y {}; // indirectly derived typedef X A; typedef A B; class C : public B {}; // derived from a typedef of X +The matcher +cxxRecordDecl(isDirectlyDerivedFrom(namedDecl(hasName("X")))) +matches Y and C (Base == hasName("X") + In the following example, Bar matches isDerivedFrom(hasName("X")): - class Foo; + class Foo {}; typedef Foo X; class Bar : public Foo {}; // derived from a type that X is a typedef of + +The matcher cxxRecordDecl(isDerivedFrom(hasName("X"))) +matches Bar Matcher<ObjCInterfaceDecl>isSameOrDerivedFromMatcher<NamedDecl> Base
Similar to isDerivedFrom(), but also matches classes that directly
 match Base.
+
+Given
+  class X {};
+  class Y : public X {};  // directly derived
+  class Z : public Y {};  // indirectly derived
+  typedef X A;
+  typedef A B;
+  class C : public B {};  // derived from a typedef of X
+
+The matcher
+cxxRecordDecl(isSameOrDerivedFrom(cxxRecordDecl(hasName("X"))),
+isDefinition())
+matches class X {}, class Y : public X {},
+class Z : public Y {} and class C : public B {}.
 
@@ -9409,19 +12499,23 @@

AST Traversal Matchers

given matcher; or 2) if the Obj-C message expression's callee's method declaration matches the given matcher. -Example matches y.x() (matcher = callExpr(callee( - cxxMethodDecl(hasName("x"))))) +Example 1 class Y { public: void x(); }; void z() { Y y; y.x(); } -Example 2. Matches [I foo] with -objcMessageExpr(callee(objcMethodDecl(hasName("foo")))) +The matcher callExpr(callee(cxxMethodDecl(hasName("x")))) +matches y.x() +Example 2 @interface I: NSObject +(void)foo; @end ... [I foo] + +The matcher +objcMessageExpr(callee(objcMethodDecl(hasName("foo")))) +matches [I foo] @@ -9430,17 +12524,19 @@

AST Traversal Matchers

expression, or an ObjC-message-send expression. Given - void x(int, int, int) { int y; x(1, y, 42); } -callExpr(hasAnyArgument(declRefExpr())) - matches x(1, y, 42) -with hasAnyArgument(...) + void x(int, int, int) { int y = 42; x(1, y, 42); } +The matcher +callExpr(hasAnyArgument(ignoringImplicit(declRefExpr()))) matches +x(1, y, 42) with hasAnyArgument(...) matching y For ObjectiveC, given @interface I - (void) f:(int) y; @end void foo(I *i) { [i f:12]; } + +The matcher objcMessageExpr(hasAnyArgument(integerLiteral(equals(12)))) - matches [i f:12] +matches [i f:12] @@ -9448,9 +12544,11 @@

AST Traversal Matchers

Matches the n'th argument of a call expression or a constructor
 call expression.
 
-Example matches y in x(y)
-    (matcher = callExpr(hasArgument(0, declRefExpr())))
+Given
   void x(int) { int y; x(y); }
+The matcher callExpr(hasArgument(0, declRefExpr().bind("arg")))
+matches x(y),
+with declRefExpr() matching y.
 
@@ -9458,23 +12556,26 @@

AST Traversal Matchers

Matches if the Objective-C message is sent to an instance,
 and the inner matcher matches on that instance.
 
-For example the method call in
+Given
   NSString *x = @"hello";
   [x containsString:@"h"];
-is matched by
+
+The matcher
 objcMessageExpr(hasReceiver(declRefExpr(to(varDecl(hasName("x"))))))
+matches [x containsString:@"h"];
 
Matcher<ObjCMessageExpr>hasReceiverTypeMatcher<QualType> InnerMatcher
Matches on the receiver of an ObjectiveC Message expression.
 
-Example
-matcher = objCMessageExpr(hasReceiverType(asString("UIWebView *")));
-matches the [webView ...] message invocation.
   NSString *webViewJavaScript = ...
   UIWebView *webView = ...
   [webView stringByEvaluatingJavaScriptFromString:webViewJavascript];
+
+The matcher objCMessageExpr(hasReceiverType(asString("UIWebView
+*"))) matches
+[webViewstringByEvaluatingJavaScriptFromString:webViewJavascript];
 
@@ -9486,23 +12587,26 @@

AST Traversal Matchers

Given class X { void f(int x, int y, int z) {} }; -cxxMethodDecl(hasAnyParameter(hasName("y"))) - matches f(int x, int y, int z) {} + +The matcher cxxMethodDecl(hasAnyParameter(hasName("y"))) + matches f with hasAnyParameter(...) matching int y For ObjectiveC, given @interface I - (void) f:(int) y; @end + the matcher objcMethodDecl(hasAnyParameter(hasName("y"))) -matches the declaration of method f with hasParameter + matches the declaration of method f with hasParameter matching y. For blocks, given b = ^(int y) { printf("%d", y) }; + the matcher blockDecl(hasAnyParameter(hasName("y"))) -matches the declaration of the block b with hasParameter + matches the declaration of the block b with hasParameter matching y. @@ -9513,15 +12617,18 @@

AST Traversal Matchers

Given class X { void f(int x) {} }; -cxxMethodDecl(hasParameter(0, hasType(varDecl()))) - matches f(int x) {} + +The matcher +cxxMethodDecl(hasParameter(0, hasType(asString("int")))) +matches f with hasParameter(...) - matching int x +matching int x. For ObjectiveC, given @interface I - (void) f:(int) y; @end -the matcher objcMethodDecl(hasParameter(0, hasName("y"))) + +The matcher objcMethodDecl(hasParameter(0, hasName("y"))) matches the declaration of method f with hasParameter matching y. @@ -9530,19 +12637,26 @@

AST Traversal Matchers

Matcher<ObjCPropertyDecl>hasTypeLocMatcher<TypeLoc> Inner
Matches if the type location of a node matches the inner matcher.
 
-Examples:
+Given
   int x;
-declaratorDecl(hasTypeLoc(loc(asString("int"))))
-  matches int x
+The matcher declaratorDecl(hasTypeLoc(loc(asString("int"))))
+matches int x.
+
+Given
+struct point { point(double, double); };
+point p = point(1.0, -1.0);
 
-auto x = int(3);
-cxxTemporaryObjectExpr(hasTypeLoc(loc(asString("int"))))
-  matches int(3)
+The matcher
+cxxTemporaryObjectExpr(hasTypeLoc(loc(asString("point"))))
+matches point(1.0, -1.0).
 
+Given
 struct Foo { Foo(int, int); };
-auto x = Foo(1, 2);
-cxxFunctionalCastExpr(hasTypeLoc(loc(asString("struct Foo"))))
-  matches Foo(1, 2)
+Foo x = Foo(1, 2);
+
+The matcher cxxTemporaryObjectExpr(hasTypeLoc(
+                          loc(asString("Foo"))))
+matches Foo(1, 2).
 
 Usable as: Matcher<BlockDecl>, Matcher<CXXBaseSpecifier>,
   Matcher<CXXCtorInitializer>, Matcher<CXXFunctionalCastExpr>,
@@ -9559,14 +12673,23 @@ 

AST Traversal Matchers

Matches if the cast's source expression
 or opaque value's source expression matches the given matcher.
 
-Example 1: matches "a string"
-(matcher = castExpr(hasSourceExpression(cxxConstructExpr())))
-class URL { URL(string); };
-URL url = "a string";
+Given
+ struct URL { URL(const char*); };
+ URL url = "a string";
+
+The matcher castExpr(hasSourceExpression(cxxConstructExpr()))
+matches "a string".
 
-Example 2: matches 'b' (matcher =
-opaqueValueExpr(hasSourceExpression(implicitCastExpr(declRefExpr())))
-int a = b ?: 1;
+Given
+void foo(bool b) {
+  int a = b ?: 1;
+}
+
+The matcher
+opaqueValueExpr(hasSourceExpression(
+              implicitCastExpr(has(
+                implicitCastExpr(has(declRefExpr()))))))
+matches b twice, for the conditiona and the true expression.
 
@@ -9581,9 +12704,11 @@

AST Traversal Matchers

foo(t); bar(t); } -unresolvedLookupExpr(hasAnyDeclaration( + +The matcher unresolvedLookupExpr(hasAnyDeclaration( functionTemplateDecl(hasName("foo")))) - matches foo in foo(t); but not bar in bar(t); +matches foo in foo(t); +but does not match bar in bar(t);
@@ -9594,8 +12719,10 @@

AST Traversal Matchers

int (*ptr_to_array)[4]; int (*ptr_to_func)(int); -varDecl(hasType(pointsTo(parenType(innerType(functionType()))))) matches -ptr_to_func but not ptr_to_array. +The matcher +varDecl(hasType(pointsTo(parenType(innerType(functionType()))))) + matches ptr_to_func but not + ptr_to_array. Usable as: Matcher<ParenType> @@ -9607,8 +12734,8 @@

AST Traversal Matchers

Given int* x; -pointerTypeLoc(hasPointeeLoc(loc(asString("int")))) - matches `int*`. +The matcher pointerTypeLoc(hasPointeeLoc(loc(asString("int")))) + matches int*. @@ -9618,10 +12745,14 @@

AST Traversal Matchers

Given int *a; - int const *b; - float const *f; -pointerType(pointee(isConstQualified(), isInteger())) - matches "int const *b" + const int *b; + int * const c = nullptr; + const float *f; + +The matcher pointerType(pointee(isConstQualified(), isInteger())) +matches const int *, +but does not match int * const +or const float *. Usable as: Matcher<BlockPointerType>, Matcher<MemberPointerType>, Matcher<PointerType>, Matcher<ReferenceType> @@ -9631,19 +12762,22 @@

AST Traversal Matchers

Matcher<QualType>hasCanonicalTypeMatcher<QualType> InnerMatcher
Matches QualTypes whose canonical type matches InnerMatcher.
 
-Given:
+Given
   typedef int &int_ref;
   int a;
   int_ref b = a;
 
-varDecl(hasType(qualType(referenceType()))))) will not match the
-declaration of b but varDecl(hasType(qualType(hasCanonicalType(referenceType())))))) does.
+The matcher varDecl(hasType(qualType(referenceType())))
+does not match int_ref b = a,
+but the matcher
+varDecl(hasType(qualType(hasCanonicalType(referenceType()))))
+does match int_ref b = a.
 
Matcher<QualType>hasDeclarationMatcher<Decl> InnerMatcher
Matches a node if the declaration associated with that node
-matches the given matcher.
+  matches the given matcher.
 
 The associated declaration is:
 - for type nodes, the declaration of the underlying type
@@ -9653,17 +12787,25 @@ 

AST Traversal Matchers

- for CXXNewExpr, the declaration of the operator new - for ObjCIvarExpr, the declaration of the ivar -For type nodes, hasDeclaration will generally match the declaration of the -sugared type. Given +Given class X {}; typedef X Y; Y y; -in varDecl(hasType(hasDeclaration(decl()))) the decl will match the -typedefDecl. A common use case is to match the underlying, desugared type. + +For type nodes, hasDeclaration will generally match the declaration of the +sugared type, i.e., the matcher +varDecl(hasType(qualType(hasDeclaration(decl().bind("d"))))), +matches Y y, with +the matcher decl() matching +typedef X Y;. +A common use case is to match the underlying, desugared type. This can be achieved by using the hasUnqualifiedDesugaredType matcher: - varDecl(hasType(hasUnqualifiedDesugaredType( - recordType(hasDeclaration(decl()))))) -In this matcher, the decl will match the CXXRecordDecl of class X. +varDecl(hasType(hasUnqualifiedDesugaredType( + recordType(hasDeclaration(decl().bind("d")))))) +matches Y y. +In this matcher, the matcher decl() will match the +CXXRecordDecl +class X {};. Usable as: Matcher<AddrLabelExpr>, Matcher<CallExpr>, Matcher<CXXConstructExpr>, Matcher<CXXNewExpr>, Matcher<DeclRefExpr>, @@ -9681,30 +12823,56 @@

AST Traversal Matchers

Given void (*fp)(void); The matcher - varDecl(hasType(pointerType(pointee(ignoringParens(functionType()))))) -would match the declaration for fp. +varDecl(hasType(pointerType(pointee(ignoringParens(functionType()))))) +matches fp.
Matcher<QualType>pointsToMatcher<Decl> InnerMatcher -
Overloaded to match the pointee type's declaration.
+
Matches if the matched type is a pointer type and the pointee type
+  matches the specified matcher.
+Overloaded to match the pointee type's declaration.
+
+Given
+  class Y { public: void x(); };
+  void z() { Y *y; y->x(); }
+
+The matcher cxxMemberCallExpr(on(hasType(pointsTo(
+     cxxRecordDecl(hasName("Y"))))))
+matches y->x()
 
Matcher<QualType>pointsToMatcher<QualType> InnerMatcher
Matches if the matched type is a pointer type and the pointee type
-matches the specified matcher.
+  matches the specified matcher.
 
-Example matches y->x()
-  (matcher = cxxMemberCallExpr(on(hasType(pointsTo
-     cxxRecordDecl(hasName("Y")))))))
+Given
   class Y { public: void x(); };
   void z() { Y *y; y->x(); }
+
+The matcher cxxMemberCallExpr(on(hasType(pointsTo(
+     qualType()))))
+matches y->x()
 
Matcher<QualType>referencesMatcher<Decl> InnerMatcher -
Overloaded to match the referenced type's declaration.
+
Matches if the matched type is a reference type and the referenced
+type matches the specified matcher.
+Overloaded to match the referenced type's declaration.
+
+Given
+  class X {
+    void a(X b) {
+      X &x = b;
+      const X &y = b;
+    }
+  };
+
+The matcher
+varDecl(hasType(references(cxxRecordDecl(hasName("X"))))) matches
+X &x = b and const X &y = b.
 
@@ -9712,14 +12880,17 @@

AST Traversal Matchers

Matches if the matched type is a reference type and the referenced
 type matches the specified matcher.
 
-Example matches X &x and const X &y
-    (matcher = varDecl(hasType(references(cxxRecordDecl(hasName("X"))))))
+Given
   class X {
     void a(X b) {
       X &x = b;
       const X &y = b;
     }
   };
+
+The matcher
+varDecl(hasType(references(qualType()))) matches
+X &x = b and const X &y = b.
 
@@ -9728,16 +12899,18 @@

AST Traversal Matchers

`InnerMatcher`. Given - int* const x; - const int y; -qualifiedTypeLoc(hasUnqualifiedLoc(pointerTypeLoc())) - matches the `TypeLoc` of the variable declaration of `x`, but not `y`. -
+ int* const x = nullptr; + const int y = 0; + + +The matcher qualifiedTypeLoc(hasUnqualifiedLoc(pointerTypeLoc())) +matches the type int* of the variable declaration but +not
Matcher<RecordType>hasDeclarationMatcher<Decl> InnerMatcher
Matches a node if the declaration associated with that node
-matches the given matcher.
+  matches the given matcher.
 
 The associated declaration is:
 - for type nodes, the declaration of the underlying type
@@ -9747,17 +12920,25 @@ 

AST Traversal Matchers

- for CXXNewExpr, the declaration of the operator new - for ObjCIvarExpr, the declaration of the ivar -For type nodes, hasDeclaration will generally match the declaration of the -sugared type. Given +Given class X {}; typedef X Y; Y y; -in varDecl(hasType(hasDeclaration(decl()))) the decl will match the -typedefDecl. A common use case is to match the underlying, desugared type. + +For type nodes, hasDeclaration will generally match the declaration of the +sugared type, i.e., the matcher +varDecl(hasType(qualType(hasDeclaration(decl().bind("d"))))), +matches Y y, with +the matcher decl() matching +typedef X Y;. +A common use case is to match the underlying, desugared type. This can be achieved by using the hasUnqualifiedDesugaredType matcher: - varDecl(hasType(hasUnqualifiedDesugaredType( - recordType(hasDeclaration(decl()))))) -In this matcher, the decl will match the CXXRecordDecl of class X. +varDecl(hasType(hasUnqualifiedDesugaredType( + recordType(hasDeclaration(decl().bind("d")))))) +matches Y y. +In this matcher, the matcher decl() will match the +CXXRecordDecl +class X {};. Usable as: Matcher<AddrLabelExpr>, Matcher<CallExpr>, Matcher<CXXConstructExpr>, Matcher<CXXNewExpr>, Matcher<DeclRefExpr>, @@ -9776,8 +12957,10 @@

AST Traversal Matchers

Given int x = 3; int& xx = x; -referenceTypeLoc(hasReferentLoc(loc(asString("int")))) - matches `int&`. + + +The matcher referenceTypeLoc(hasReferentLoc(loc(asString("int")))) + matches int&.
@@ -9787,10 +12970,14 @@

AST Traversal Matchers

Given int *a; - int const *b; - float const *f; -pointerType(pointee(isConstQualified(), isInteger())) - matches "int const *b" + const int *b; + int * const c = nullptr; + const float *f; + +The matcher pointerType(pointee(isConstQualified(), isInteger())) +matches const int *, +but does not match int * const +or const float *. Usable as: Matcher<BlockPointerType>, Matcher<MemberPointerType>, Matcher<PointerType>, Matcher<ReferenceType> @@ -9801,11 +12988,13 @@

AST Traversal Matchers

Matches the return value expression of a return statement
 
 Given
-  return a + b;
-hasReturnValue(binaryOperator())
-  matches 'return a + b'
-with binaryOperator()
-  matching 'a + b'
+  int foo(int a, int b) {
+    return a + b;
+  }
+The matcher
+returnStmt(hasReturnValue(binaryOperator().bind("op"))) matches
+return a + b, with binaryOperator() matching
+a + b.
 
@@ -9814,17 +13003,25 @@

AST Traversal Matchers

a given matcher. Also matches StmtExprs that have CompoundStmt as children. Given - { {}; 1+2; } -hasAnySubstatement(compoundStmt()) - matches '{ {}; 1+2; }' +void foo() { { {}; 1+2; } } +The matcher +compoundStmt(hasAnySubstatement(compoundStmt().bind("compound"))) +{ {}; 1+2; } and { { {}; 1+2; } } with compoundStmt() - matching '{}' +matching {} and { {}; 1+2; }. Matcher<Stmt>alignOfExprMatcher<UnaryExprOrTypeTraitExpr> InnerMatcher
Same as unaryExprOrTypeTraitExpr, but only matching
 alignof.
+
+Given
+  int align = alignof(int);
+
+
+The matcher alignOfExpr(expr())
+matches alignof(int).
 
@@ -9832,26 +13029,30 @@

AST Traversal Matchers

Matches declaration of the function, method, or block the statement
 belongs to.
 
-Given:
-F& operator=(const F& o) {
-  std::copy_if(o.begin(), o.end(), begin(), [](V v) { return v > 0; });
-  return *this;
-}
-returnStmt(forCallable(functionDecl(hasName("operator="))))
-  matches 'return *this'
-  but does not match 'return v > 0'
+Given
+struct F {
+  F& operator=(const F& other) {
+    []() { return 42 == 42; };
+    return *this;
+  }
+};
 
-Given:
--(void) foo {
+The matcher returnStmt(forFunction(hasName("operator=")))
+matches return *this
+but does not match return 42 == 42.
+
+Given
+void foo {
   int x = 1;
   dispatch_sync(queue, ^{ int y = 2; });
 }
-declStmt(forCallable(objcMethodDecl()))
-  matches 'int x = 1'
-  but does not match 'int y = 2'.
-whereas declStmt(forCallable(blockDecl()))
-  matches 'int y = 2'
-  but does not match 'int x = 1'.
+
+The matcher declStmt(forCallable(objcMethodDecl()))
+matches int x = 1
+but does not match int y = 2.
+The matcher declStmt(forCallable(blockDecl()))
+matches int y = 2
+but does not match int x = 1.
 
@@ -9860,23 +13061,34 @@

AST Traversal Matchers

Deprecated. Use forCallable() to correctly handle the situation when the declaration is not a function (but a block or an Objective-C method). -forFunction() not only fails to take non-functions into account but also -may match the wrong declaration in their presence. +The matcher forFunction() not only fails to take non-functions +into account but also may match the wrong declaration in their presence. -Given: -F& operator=(const F& o) { - std::copy_if(o.begin(), o.end(), begin(), [](V v) { return v > 0; }); - return *this; -} -returnStmt(forFunction(hasName("operator="))) - matches 'return *this' - but does not match 'return v > 0' +Given + struct F { + F& operator=(const F& other) { + []() { return 42 == 42; }; + return *this; + } + }; + + +The matcher returnStmt(forFunction(hasName("operator="))) +matches return *this +but does not match return 42 == 42. Matcher<Stmt>sizeOfExprMatcher<UnaryExprOrTypeTraitExpr> InnerMatcher
Same as unaryExprOrTypeTraitExpr, but only matching
 sizeof.
+
+Given
+  struct S { double x; double y; };
+  int size = sizeof(struct S);
+
+The matcher sizeOfExpr(expr())
+matches sizeof(struct S).
 
@@ -9890,7 +13102,9 @@

AST Traversal Matchers

int i; double j = F(i); -substTemplateTypeParmType(hasReplacementType(type())) matches int + +The matcher substTemplateTypeParmType(hasReplacementType(type())) +matches int. @@ -9899,11 +13113,18 @@

AST Traversal Matchers

statement. This matcher may produce multiple matches. Given - switch (1) { case 1: case 2: default: switch (2) { case 3: case 4: ; } } -switchStmt(forEachSwitchCase(caseStmt().bind("c"))).bind("s") - matches four times, with "c" binding each of "case 1:", "case 2:", -"case 3:" and "case 4:", and "s" respectively binding "switch (1)", -"switch (1)", "switch (2)" and "switch (2)". + void foo() { + switch (1) { case 1: case 2: default: switch (2) { case 3: case 4: ; } } + } +The matcher +switchStmt(forEachSwitchCase(caseStmt().bind("c"))) +matches four times, matching +switch (1) { case 1: case 2: default: switch (2) { case 3: +case 4: ; } } and +switch (2) { case 3: case 4: ; }, with +caseStmt() matching each of case 1:, +case 2:, case 3: +and case 4:. @@ -9911,15 +13132,23 @@

AST Traversal Matchers

Matches the condition expression of an if statement, for loop,
 switch statement or conditional operator.
 
-Example matches true (matcher = hasCondition(cxxBoolLiteral(equals(true))))
+Given
+void foo() {
   if (true) {}
+}
+
+The matcher ifStmt(hasCondition(cxxBoolLiteral(equals(true))))
+if (true) {}
 
Matcher<SwitchStmt>hasInitStatementMatcher<Stmt> InnerMatcher
Matches selection statements with initializer.
 
-Given:
+Given
+ struct vec { int* begin(); int* end(); };
+ int foobar();
+ vec& get_range();
  void foo() {
    if (int i = foobar(); i > 0) {}
    switch (int i = foobar(); i) {}
@@ -9930,18 +13159,23 @@ 

AST Traversal Matchers

switch (foobar()) {} for (auto& x : get_range()) {} } -ifStmt(hasInitStatement(anything())) - matches the if statement in foo but not in bar. -switchStmt(hasInitStatement(anything())) - matches the switch statement in foo but not in bar. -cxxForRangeStmt(hasInitStatement(anything())) - matches the range for statement in foo but not in bar. + +The matcher ifStmt(hasInitStatement(anything())) + matches the if statement if (int i = foobar(); i > 0) {} + in foo but not if (foobar() > 0) {} in bar. +The matcher switchStmt(hasInitStatement(anything())) + matches the switch statement switch (int i = foobar(); i) {} + in foo but not switch (foobar()) {} in bar. +The matcher cxxForRangeStmt(hasInitStatement(anything())) + matches the range for statement + for (auto& a = get_range(); auto& x : a) {} in foo + but not for (auto& x : get_range()) {} in bar.
Matcher<TagType>hasDeclarationMatcher<Decl> InnerMatcher
Matches a node if the declaration associated with that node
-matches the given matcher.
+  matches the given matcher.
 
 The associated declaration is:
 - for type nodes, the declaration of the underlying type
@@ -9951,17 +13185,25 @@ 

AST Traversal Matchers

- for CXXNewExpr, the declaration of the operator new - for ObjCIvarExpr, the declaration of the ivar -For type nodes, hasDeclaration will generally match the declaration of the -sugared type. Given +Given class X {}; typedef X Y; Y y; -in varDecl(hasType(hasDeclaration(decl()))) the decl will match the -typedefDecl. A common use case is to match the underlying, desugared type. + +For type nodes, hasDeclaration will generally match the declaration of the +sugared type, i.e., the matcher +varDecl(hasType(qualType(hasDeclaration(decl().bind("d"))))), +matches Y y, with +the matcher decl() matching +typedef X Y;. +A common use case is to match the underlying, desugared type. This can be achieved by using the hasUnqualifiedDesugaredType matcher: - varDecl(hasType(hasUnqualifiedDesugaredType( - recordType(hasDeclaration(decl()))))) -In this matcher, the decl will match the CXXRecordDecl of class X. +varDecl(hasType(hasUnqualifiedDesugaredType( + recordType(hasDeclaration(decl().bind("d")))))) +matches Y y. +In this matcher, the matcher decl() will match the +CXXRecordDecl +class X {};. Usable as: Matcher<AddrLabelExpr>, Matcher<CallExpr>, Matcher<CXXConstructExpr>, Matcher<CXXNewExpr>, Matcher<DeclRefExpr>, @@ -9976,19 +13218,26 @@

AST Traversal Matchers

Matcher<TemplateArgumentLoc>hasTypeLocMatcher<TypeLoc> Inner
Matches if the type location of a node matches the inner matcher.
 
-Examples:
+Given
   int x;
-declaratorDecl(hasTypeLoc(loc(asString("int"))))
-  matches int x
+The matcher declaratorDecl(hasTypeLoc(loc(asString("int"))))
+matches int x.
+
+Given
+struct point { point(double, double); };
+point p = point(1.0, -1.0);
 
-auto x = int(3);
-cxxTemporaryObjectExpr(hasTypeLoc(loc(asString("int"))))
-  matches int(3)
+The matcher
+cxxTemporaryObjectExpr(hasTypeLoc(loc(asString("point"))))
+matches point(1.0, -1.0).
 
+Given
 struct Foo { Foo(int, int); };
-auto x = Foo(1, 2);
-cxxFunctionalCastExpr(hasTypeLoc(loc(asString("struct Foo"))))
-  matches Foo(1, 2)
+Foo x = Foo(1, 2);
+
+The matcher cxxTemporaryObjectExpr(hasTypeLoc(
+                          loc(asString("Foo"))))
+matches Foo(1, 2).
 
 Usable as: Matcher<BlockDecl>, Matcher<CXXBaseSpecifier>,
   Matcher<CXXCtorInitializer>, Matcher<CXXFunctionalCastExpr>,
@@ -10008,10 +13257,13 @@ 

AST Traversal Matchers

struct B { int next; }; template<int(B::*next_ptr)> struct A {}; A<&B::next> a; + +The matcher templateSpecializationType(hasAnyTemplateArgument( - isExpr(hasDescendant(declRefExpr(to(fieldDecl(hasName("next")))))))) - matches the specialization A<&B::next> with fieldDecl(...) matching - B::next + isExpr(hasDescendant(declRefExpr(to(fieldDecl(hasName("next")).bind("next"))))))) +matches the specialization A<&struct B::next> +with fieldDecl(hasName("next")) matching +B::next.
@@ -10023,10 +13275,13 @@

AST Traversal Matchers

struct B { int next; }; template<int(B::*next_ptr)> struct A {}; A<&B::next> a; + +The matcher classTemplateSpecializationDecl(hasAnyTemplateArgument( - refersToDeclaration(fieldDecl(hasName("next"))))) - matches the specialization A<&B::next> with fieldDecl(...) matching - B::next + refersToDeclaration(fieldDecl(hasName("next")).bind("next")))) +matches the specialization struct A<&B::next> +with fieldDecl(hasName("next")) matching +B::next.
@@ -10036,9 +13291,12 @@

AST Traversal Matchers

Given template<int T> struct C {}; C<42> c; -classTemplateSpecializationDecl( + +The matcher classTemplateSpecializationDecl( hasAnyTemplateArgument(refersToIntegralType(asString("int")))) - matches the implicit instantiation of C in C<42>. +matches the implicitly declared specialization +struct C<42> from the instantiation for the type of the +variable c . @@ -10049,9 +13307,11 @@

AST Traversal Matchers

template<template <typename> class S> class X {}; template<typename T> class Y {}; X<Y> xi; + +The matcher classTemplateSpecializationDecl(hasAnyTemplateArgument( - refersToTemplate(templateName()))) - matches the specialization X<Y> + refersToTemplate(templateName()))) +matches the specialization class X<Y> @@ -10062,9 +13322,11 @@

AST Traversal Matchers

struct X {}; template<typename T> struct A {}; A<X> a; + +The matcher classTemplateSpecializationDecl(hasAnyTemplateArgument(refersToType( - recordType(hasDeclaration(recordDecl(hasName("X"))))))) -matches the specialization of struct A generated by A<X>. + recordType(hasDeclaration(recordDecl(hasName("X"))))))) +matches the specialization struct A<struct X>. @@ -10077,9 +13339,11 @@

AST Traversal Matchers

Given template<typename T> class A {}; A<int> a; -varDecl(hasTypeLoc(templateSpecializationTypeLoc(hasAnyTemplateArgumentLoc( - hasTypeLoc(loc(asString("int"))))))) - matches `A<int> a`. + +The matcher +varDecl(hasTypeLoc(elaboratedTypeLoc(hasNamedTypeLoc( +templateSpecializationTypeLoc(hasAnyTemplateArgumentLoc( +hasTypeLoc(loc(asString("int"))))))))) matches A<int> a. @@ -10092,9 +13356,12 @@

AST Traversal Matchers

template<typename T, typename U> class A {}; A<double, int> b; A<int, double> c; -varDecl(hasTypeLoc(templateSpecializationTypeLoc(hasTemplateArgumentLoc(0, - hasTypeLoc(loc(asString("double"))))))) - matches `A<double, int> b`, but not `A<int, double> c`. + +The matcher +varDecl(hasTypeLoc(elaboratedTypeLoc(hasNamedTypeLoc( +templateSpecializationTypeLoc(hasTemplateArgumentLoc(0, +hasTypeLoc(loc(asString("double"))))))))) +matches A<double, int> b, but not double> c}. @@ -10114,13 +13381,22 @@

AST Traversal Matchers

template <typename T, typename U> void f(T&& t, U&& u) {} - bool B = false; - f(R, B); -templateSpecializationType(forEachTemplateArgument(isExpr(expr()))) - matches twice, with expr() matching 'R * 2' and 'R * 4' -functionDecl(forEachTemplateArgument(refersToType(builtinType()))) - matches the specialization f<unsigned, bool> twice, for 'unsigned' - and 'bool' + void foo() { + bool B = false; + f(R, B); + } + +The matcher +templateSpecializationType(forEachTemplateArgument(isExpr(expr().bind("t_arg")))) +matches Matrix<int, R * 2, R * 4> twice, with +expr() matching R * 2 and +R * 4. +The matcher +functionDecl(forEachTemplateArgument(refersToType(qualType().bind("type")))) +matches the specialization of f twice, +with qualType() matching +unsigned and +bool. @@ -10134,21 +13410,25 @@

AST Traversal Matchers

template<> class A<double> {}; A<int> a; - template<typename T> f() {}; + template<typename T> void f() {}; void func() { f<int>(); }; -classTemplateSpecializationDecl(hasAnyTemplateArgument( - refersToType(asString("int")))) - matches the specialization A<int> -functionDecl(hasAnyTemplateArgument(refersToType(asString("int")))) - matches the specialization f<int> +The matcher classTemplateSpecializationDecl( + hasAnyTemplateArgument( + refersToType(asString("int")))) +matches class A<int>. + +The matcher +functionDecl(hasAnyTemplateArgument( + refersToType(asString("int")))) +matches the instantiation of f. Matcher<TemplateSpecializationType>hasDeclarationMatcher<Decl> InnerMatcher
Matches a node if the declaration associated with that node
-matches the given matcher.
+  matches the given matcher.
 
 The associated declaration is:
 - for type nodes, the declaration of the underlying type
@@ -10158,17 +13438,25 @@ 

AST Traversal Matchers

- for CXXNewExpr, the declaration of the operator new - for ObjCIvarExpr, the declaration of the ivar -For type nodes, hasDeclaration will generally match the declaration of the -sugared type. Given +Given class X {}; typedef X Y; Y y; -in varDecl(hasType(hasDeclaration(decl()))) the decl will match the -typedefDecl. A common use case is to match the underlying, desugared type. + +For type nodes, hasDeclaration will generally match the declaration of the +sugared type, i.e., the matcher +varDecl(hasType(qualType(hasDeclaration(decl().bind("d"))))), +matches Y y, with +the matcher decl() matching +typedef X Y;. +A common use case is to match the underlying, desugared type. This can be achieved by using the hasUnqualifiedDesugaredType matcher: - varDecl(hasType(hasUnqualifiedDesugaredType( - recordType(hasDeclaration(decl()))))) -In this matcher, the decl will match the CXXRecordDecl of class X. +varDecl(hasType(hasUnqualifiedDesugaredType( + recordType(hasDeclaration(decl().bind("d")))))) +matches Y y. +In this matcher, the matcher decl() will match the +CXXRecordDecl +class X {};. Usable as: Matcher<AddrLabelExpr>, Matcher<CallExpr>, Matcher<CXXConstructExpr>, Matcher<CXXNewExpr>, Matcher<DeclRefExpr>, @@ -10187,23 +13475,26 @@

AST Traversal Matchers

Given template<typename T, typename U> class A {}; - A<bool, int> b; - A<int, bool> c; + A<double, int> b; + A<int, double> c; template<typename T> void f() {} void func() { f<int>(); }; + +The matcher classTemplateSpecializationDecl(hasTemplateArgument( 1, refersToType(asString("int")))) - matches the specialization A<bool, int> +matches the specialization class A<double, int>. -functionDecl(hasTemplateArgument(0, refersToType(asString("int")))) - matches the specialization f<int> +The matcher functionDecl(hasTemplateArgument(0, + refersToType(asString("int")))) +matches the specialization of f.
Matcher<TemplateTypeParmType>hasDeclarationMatcher<Decl> InnerMatcher
Matches a node if the declaration associated with that node
-matches the given matcher.
+  matches the given matcher.
 
 The associated declaration is:
 - for type nodes, the declaration of the underlying type
@@ -10213,17 +13504,25 @@ 

AST Traversal Matchers

- for CXXNewExpr, the declaration of the operator new - for ObjCIvarExpr, the declaration of the ivar -For type nodes, hasDeclaration will generally match the declaration of the -sugared type. Given +Given class X {}; typedef X Y; Y y; -in varDecl(hasType(hasDeclaration(decl()))) the decl will match the -typedefDecl. A common use case is to match the underlying, desugared type. + +For type nodes, hasDeclaration will generally match the declaration of the +sugared type, i.e., the matcher +varDecl(hasType(qualType(hasDeclaration(decl().bind("d"))))), +matches Y y, with +the matcher decl() matching +typedef X Y;. +A common use case is to match the underlying, desugared type. This can be achieved by using the hasUnqualifiedDesugaredType matcher: - varDecl(hasType(hasUnqualifiedDesugaredType( - recordType(hasDeclaration(decl()))))) -In this matcher, the decl will match the CXXRecordDecl of class X. +varDecl(hasType(hasUnqualifiedDesugaredType( + recordType(hasDeclaration(decl().bind("d")))))) +matches Y y. +In this matcher, the matcher decl() will match the +CXXRecordDecl +class X {};. Usable as: Matcher<AddrLabelExpr>, Matcher<CallExpr>, Matcher<CXXConstructExpr>, Matcher<CXXNewExpr>, Matcher<DeclRefExpr>, @@ -10238,25 +13537,37 @@

AST Traversal Matchers

Matcher<TypeLoc>locMatcher<QualType> InnerMatcher
Matches TypeLocs for which the given inner
 QualType-matcher matches.
+
+  int a = 10;
+
+The matcher typeLoc(loc(qualType(isInteger())))
+matches the int of a .
 
Matcher<TypedefNameDecl>hasTypeLocMatcher<TypeLoc> Inner
Matches if the type location of a node matches the inner matcher.
 
-Examples:
+Given
   int x;
-declaratorDecl(hasTypeLoc(loc(asString("int"))))
-  matches int x
+The matcher declaratorDecl(hasTypeLoc(loc(asString("int"))))
+matches int x.
+
+Given
+struct point { point(double, double); };
+point p = point(1.0, -1.0);
 
-auto x = int(3);
-cxxTemporaryObjectExpr(hasTypeLoc(loc(asString("int"))))
-  matches int(3)
+The matcher
+cxxTemporaryObjectExpr(hasTypeLoc(loc(asString("point"))))
+matches point(1.0, -1.0).
 
+Given
 struct Foo { Foo(int, int); };
-auto x = Foo(1, 2);
-cxxFunctionalCastExpr(hasTypeLoc(loc(asString("struct Foo"))))
-  matches Foo(1, 2)
+Foo x = Foo(1, 2);
+
+The matcher cxxTemporaryObjectExpr(hasTypeLoc(
+                          loc(asString("Foo"))))
+matches Foo(1, 2).
 
 Usable as: Matcher<BlockDecl>, Matcher<CXXBaseSpecifier>,
   Matcher<CXXCtorInitializer>, Matcher<CXXFunctionalCastExpr>,
@@ -10273,23 +13584,31 @@ 

AST Traversal Matchers

Matches if the expression's or declaration's type matches a type
 matcher.
 
-Example matches x (matcher = expr(hasType(cxxRecordDecl(hasName("X")))))
-            and z (matcher = varDecl(hasType(cxxRecordDecl(hasName("X")))))
-            and U (matcher = typedefDecl(hasType(asString("int")))
-            and friend class X (matcher = friendDecl(hasType("X"))
-            and public virtual X (matcher = cxxBaseSpecifier(hasType(
-                                              asString("class X")))
+Exmaple
  class X {};
  void y(X &x) { x; X z; }
  typedef int U;
  class Y { friend class X; };
  class Z : public virtual X {};
+
+The matcher expr(hasType(cxxRecordDecl(hasName("X"))))
+matches x and z.
+The matcher varDecl(hasType(cxxRecordDecl(hasName("X"))))
+matches z
+The matcher typedefDecl(hasType(asString("int")))
+matches typedef int U
+The matcher friendDecl(hasType(asString("class X")))
+matches friend class X
+The matcher cxxRecordDecl(hasAnyBase(cxxBaseSpecifier(hasType(
+asString("X"))).bind("b"))) matches class Z : public virtual X {},
+with cxxBaseSpecifier(...)
+matching public virtual X.
 
Matcher<TypedefType>hasDeclarationMatcher<Decl> InnerMatcher
Matches a node if the declaration associated with that node
-matches the given matcher.
+  matches the given matcher.
 
 The associated declaration is:
 - for type nodes, the declaration of the underlying type
@@ -10299,17 +13618,25 @@ 

AST Traversal Matchers

- for CXXNewExpr, the declaration of the operator new - for ObjCIvarExpr, the declaration of the ivar -For type nodes, hasDeclaration will generally match the declaration of the -sugared type. Given +Given class X {}; typedef X Y; Y y; -in varDecl(hasType(hasDeclaration(decl()))) the decl will match the -typedefDecl. A common use case is to match the underlying, desugared type. + +For type nodes, hasDeclaration will generally match the declaration of the +sugared type, i.e., the matcher +varDecl(hasType(qualType(hasDeclaration(decl().bind("d"))))), +matches Y y, with +the matcher decl() matching +typedef X Y;. +A common use case is to match the underlying, desugared type. This can be achieved by using the hasUnqualifiedDesugaredType matcher: - varDecl(hasType(hasUnqualifiedDesugaredType( - recordType(hasDeclaration(decl()))))) -In this matcher, the decl will match the CXXRecordDecl of class X. +varDecl(hasType(hasUnqualifiedDesugaredType( + recordType(hasDeclaration(decl().bind("d")))))) +matches Y y. +In this matcher, the matcher decl() will match the +CXXRecordDecl +class X {};. Usable as: Matcher<AddrLabelExpr>, Matcher<CallExpr>, Matcher<CXXConstructExpr>, Matcher<CXXNewExpr>, Matcher<DeclRefExpr>, @@ -10328,8 +13655,11 @@

AST Traversal Matchers

For example, in: class A {}; using B = A; -The matcher type(hasUnqualifiedDesugaredType(recordType())) matches -both B and A. + B b; + +The matcher +varDecl(hasType(hasUnqualifiedDesugaredType(recordType()))) +matches B b.
@@ -10338,17 +13668,23 @@

AST Traversal Matchers

Given int a, c; float b; int s = sizeof(a) + sizeof(b) + alignof(c); -unaryExprOrTypeTraitExpr(hasArgumentOfType(asString("int")) - matches sizeof(a) and alignof(c) + +The matcher +unaryExprOrTypeTraitExpr(hasArgumentOfType(asString("int"))) +matches sizeof(a) and alignof(c)
Matcher<UnaryOperator>hasUnaryOperandMatcher<Expr> InnerMatcher
Matches if the operand of a unary operator matches.
 
-Example matches true (matcher = hasUnaryOperand(
-                                  cxxBoolLiteral(equals(true))))
-  !true
+void foo() {
+  !true;
+}
+
+The matcher
+unaryOperator(hasUnaryOperand(cxxBoolLiteral(equals(true))))
+matches !true.
 
@@ -10362,17 +13698,20 @@

AST Traversal Matchers

int m; int f(X x) { x.m; return m; } }; + + +The matcher memberExpr(hasObjectExpression(hasType(cxxRecordDecl(hasName("X"))))) - matches `x.m`, but not `m`; however, -memberExpr(hasObjectExpression(hasType(pointsTo( - cxxRecordDecl(hasName("X")))))) - matches `m` (aka. `this->m`), but not `x.m`. +matches x.m, but not m; however, +The matcher memberExpr(hasObjectExpression(hasType(pointsTo( +cxxRecordDecl(hasName("X")))))) +matches m (aka. this->m), but not x.m.
Matcher<UnresolvedUsingType>hasDeclarationMatcher<Decl> InnerMatcher
Matches a node if the declaration associated with that node
-matches the given matcher.
+  matches the given matcher.
 
 The associated declaration is:
 - for type nodes, the declaration of the underlying type
@@ -10382,17 +13721,25 @@ 

AST Traversal Matchers

- for CXXNewExpr, the declaration of the operator new - for ObjCIvarExpr, the declaration of the ivar -For type nodes, hasDeclaration will generally match the declaration of the -sugared type. Given +Given class X {}; typedef X Y; Y y; -in varDecl(hasType(hasDeclaration(decl()))) the decl will match the -typedefDecl. A common use case is to match the underlying, desugared type. + +For type nodes, hasDeclaration will generally match the declaration of the +sugared type, i.e., the matcher +varDecl(hasType(qualType(hasDeclaration(decl().bind("d"))))), +matches Y y, with +the matcher decl() matching +typedef X Y;. +A common use case is to match the underlying, desugared type. This can be achieved by using the hasUnqualifiedDesugaredType matcher: - varDecl(hasType(hasUnqualifiedDesugaredType( - recordType(hasDeclaration(decl()))))) -In this matcher, the decl will match the CXXRecordDecl of class X. +varDecl(hasType(hasUnqualifiedDesugaredType( + recordType(hasDeclaration(decl().bind("d")))))) +matches Y y. +In this matcher, the matcher decl() will match the +CXXRecordDecl +class X {};. Usable as: Matcher<AddrLabelExpr>, Matcher<CallExpr>, Matcher<CXXConstructExpr>, Matcher<CXXNewExpr>, Matcher<DeclRefExpr>, @@ -10412,8 +13759,12 @@

AST Traversal Matchers

namespace X { int a; void b(); } using X::a; using X::b; + +The matcher usingDecl(hasAnyUsingShadowDecl(hasTargetDecl(functionDecl()))) - matches using X::b but not using X::a
+ matches using X::b + but not X::a} + Matcher<UsingType>hasUnderlyingTypeMatcher<Type> @@ -10422,8 +13773,11 @@

AST Traversal Matchers

Given decltype(1) a = 1; decltype(2.0) b = 2.0; -decltypeType(hasUnderlyingType(isInteger())) - matches the type of "a" + + +The matcher decltypeType(hasUnderlyingType(isInteger())) +matches the type decltype(1) of the variable +declaration of a . Usable as: Matcher<DecltypeType>, Matcher<UsingType> @@ -10433,18 +13787,20 @@

AST Traversal Matchers

Matches if a node refers to a declaration through a specific
 using shadow declaration.
 
-Examples:
+Given
   namespace a { int f(); }
   using a::f;
   int x = f();
-declRefExpr(throughUsingDecl(anything()))
-  matches f
+
+The matcher declRefExpr(throughUsingDecl(anything()))
+matches f
 
   namespace a { class X{}; }
   using a::X;
   X x;
-typeLoc(loc(usingType(throughUsingDecl(anything()))))
-  matches X
+
+The matcher typeLoc(loc(usingType(throughUsingDecl(anything()))))
+matches X
 
 Usable as: Matcher<DeclRefExpr>, Matcher<UsingType>
 
@@ -10460,21 +13816,31 @@

AST Traversal Matchers

X, while varDecl(hasType(cxxRecordDecl(hasName("X")))) matches the declaration of x. -Example matches x (matcher = expr(hasType(cxxRecordDecl(hasName("X"))))) - and z (matcher = varDecl(hasType(cxxRecordDecl(hasName("X"))))) - and friend class X (matcher = friendDecl(hasType("X")) - and public virtual X (matcher = cxxBaseSpecifier(hasType( - cxxRecordDecl(hasName("X")))) class X {}; void y(X &x) { x; X z; } class Y { friend class X; }; class Z : public virtual X {}; -Example matches class Derived -(matcher = cxxRecordDecl(hasAnyBase(hasType(cxxRecordDecl(hasName("Base")))))) +The matcher expr(hasType(cxxRecordDecl(hasName("X")))) +matches x and z. +The matcher varDecl(hasType(cxxRecordDecl(hasName("X")))) +matches z. +The matcher friendDecl(hasType(asString("class X"))) +matches friend class X. +The matcher cxxRecordDecl(hasAnyBase(cxxBaseSpecifier(hasType( +asString("X"))).bind("b"))) matches +class Z : public virtual X {}, +with cxxBaseSpecifier(...) +matching public virtual X. + +Given class Base {}; class Derived : Base {}; +The matcher +cxxRecordDecl(hasAnyBase(hasType(cxxRecordDecl(hasName("Base"))))) +matches class Derived : Base {}. + Usable as: Matcher<Expr>, Matcher<FriendDecl>, Matcher<ValueDecl>, Matcher<CXXBaseSpecifier> @@ -10484,17 +13850,25 @@

AST Traversal Matchers

Matches if the expression's or declaration's type matches a type
 matcher.
 
-Example matches x (matcher = expr(hasType(cxxRecordDecl(hasName("X")))))
-            and z (matcher = varDecl(hasType(cxxRecordDecl(hasName("X")))))
-            and U (matcher = typedefDecl(hasType(asString("int")))
-            and friend class X (matcher = friendDecl(hasType("X"))
-            and public virtual X (matcher = cxxBaseSpecifier(hasType(
-                                              asString("class X")))
+Exmaple
  class X {};
  void y(X &x) { x; X z; }
  typedef int U;
  class Y { friend class X; };
  class Z : public virtual X {};
+
+The matcher expr(hasType(cxxRecordDecl(hasName("X"))))
+matches x and z.
+The matcher varDecl(hasType(cxxRecordDecl(hasName("X"))))
+matches z
+The matcher typedefDecl(hasType(asString("int")))
+matches typedef int U
+The matcher friendDecl(hasType(asString("class X")))
+matches friend class X
+The matcher cxxRecordDecl(hasAnyBase(cxxBaseSpecifier(hasType(
+asString("X"))).bind("b"))) matches class Z : public virtual X {},
+with cxxBaseSpecifier(...)
+matching public virtual X.
 
@@ -10502,9 +13876,13 @@

AST Traversal Matchers

Matches a variable declaration that has an initializer expression
 that matches the given matcher.
 
-Example matches x (matcher = varDecl(hasInitializer(callExpr())))
-  bool y() { return true; }
-  bool x = y();
+Given
+  int y() { return 0; }
+  void foo() {
+    int x = y();
+  }
+The matcher varDecl(hasInitializer(callExpr()))
+matches x
 
@@ -10524,13 +13902,22 @@

AST Traversal Matchers

template <typename T, typename U> void f(T&& t, U&& u) {} - bool B = false; - f(R, B); -templateSpecializationType(forEachTemplateArgument(isExpr(expr()))) - matches twice, with expr() matching 'R * 2' and 'R * 4' -functionDecl(forEachTemplateArgument(refersToType(builtinType()))) - matches the specialization f<unsigned, bool> twice, for 'unsigned' - and 'bool' + void foo() { + bool B = false; + f(R, B); + } + +The matcher +templateSpecializationType(forEachTemplateArgument(isExpr(expr().bind("t_arg")))) +matches Matrix<int, R * 2, R * 4> twice, with +expr() matching R * 2 and +R * 4. +The matcher +functionDecl(forEachTemplateArgument(refersToType(qualType().bind("type")))) +matches the specialization of f twice, +with qualType() matching +unsigned and +bool. @@ -10543,9 +13930,11 @@

AST Traversal Matchers

Given template<typename T> class A {}; A<int> a; -varDecl(hasTypeLoc(templateSpecializationTypeLoc(hasAnyTemplateArgumentLoc( - hasTypeLoc(loc(asString("int"))))))) - matches `A<int> a`. + +The matcher +varDecl(hasTypeLoc(elaboratedTypeLoc(hasNamedTypeLoc( +templateSpecializationTypeLoc(hasAnyTemplateArgumentLoc( +hasTypeLoc(loc(asString("int"))))))))) matches A<int> a. @@ -10559,15 +13948,19 @@

AST Traversal Matchers

template<> class A<double> {}; A<int> a; - template<typename T> f() {}; + template<typename T> void f() {}; void func() { f<int>(); }; -classTemplateSpecializationDecl(hasAnyTemplateArgument( - refersToType(asString("int")))) - matches the specialization A<int> -functionDecl(hasAnyTemplateArgument(refersToType(asString("int")))) - matches the specialization f<int> +The matcher classTemplateSpecializationDecl( + hasAnyTemplateArgument( + refersToType(asString("int")))) +matches class A<int>. + +The matcher +functionDecl(hasAnyTemplateArgument( + refersToType(asString("int")))) +matches the instantiation of f. @@ -10580,9 +13973,12 @@

AST Traversal Matchers

template<typename T, typename U> class A {}; A<double, int> b; A<int, double> c; -varDecl(hasTypeLoc(templateSpecializationTypeLoc(hasTemplateArgumentLoc(0, - hasTypeLoc(loc(asString("double"))))))) - matches `A<double, int> b`, but not `A<int, double> c`. + +The matcher +varDecl(hasTypeLoc(elaboratedTypeLoc(hasNamedTypeLoc( +templateSpecializationTypeLoc(hasTemplateArgumentLoc(0, +hasTypeLoc(loc(asString("double"))))))))) +matches A<double, int> b, but not double> c}. @@ -10593,17 +13989,20 @@

AST Traversal Matchers

Given template<typename T, typename U> class A {}; - A<bool, int> b; - A<int, bool> c; + A<double, int> b; + A<int, double> c; template<typename T> void f() {} void func() { f<int>(); }; + +The matcher classTemplateSpecializationDecl(hasTemplateArgument( 1, refersToType(asString("int")))) - matches the specialization A<bool, int> +matches the specialization class A<double, int>. -functionDecl(hasTemplateArgument(0, refersToType(asString("int")))) - matches the specialization f<int> +The matcher functionDecl(hasTemplateArgument(0, + refersToType(asString("int")))) +matches the specialization of f. @@ -10615,9 +14014,10 @@

AST Traversal Matchers

void f(int b) { int a[b]; } +The matcher variableArrayType(hasSizeExpr(ignoringImpCasts(declRefExpr(to( varDecl(hasName("b"))))))) - matches "int a[b]" +matches int[b] @@ -10628,20 +14028,22 @@

AST Traversal Matchers

other declarations of the same function or coroutine. Given +void foo() { for (;;) {} -forStmt(hasBody(compoundStmt())) - matches 'for (;;) {}' +} +The matcher forStmt(hasBody(compoundStmt().bind("body"))) +matches for (;;) {} with compoundStmt() - matching '{}' + matching {} Given void f(); void f() {} -functionDecl(hasBody(compoundStmt())) - matches 'void f() {}' +The matcher functionDecl(hasBody(compoundStmt().bind("compound"))) +f with compoundStmt() - matching '{}' - but does not match 'void f();' +matching {} +but does not match void f(); @@ -10649,8 +14051,13 @@

AST Traversal Matchers

Matches the condition expression of an if statement, for loop,
 switch statement or conditional operator.
 
-Example matches true (matcher = hasCondition(cxxBoolLiteral(equals(true))))
+Given
+void foo() {
   if (true) {}
+}
+
+The matcher ifStmt(hasCondition(cxxBoolLiteral(equals(true))))
+if (true) {}
 
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 1fbcac807d0b3..a9cd68d392c75 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -568,6 +568,9 @@ AST Matchers - Fixed a crash when traverse lambda expr with invalid captures. (#GH106444) +- The examples in the AST matcher reference are now tested and additional + examples and descriptions were added. + clang-format ------------ diff --git a/clang/docs/doxygen.cfg.in b/clang/docs/doxygen.cfg.in index 251afb179b205..1d1deb0fcfb07 100644 --- a/clang/docs/doxygen.cfg.in +++ b/clang/docs/doxygen.cfg.in @@ -220,7 +220,14 @@ TAB_SIZE = 2 # "Side Effects:". You can put \n's in the value part of an alias to insert # newlines. -ALIASES = +ALIASES += compile_args{1}="Compiled with \1.\n" +ALIASES += matcher{1}="\1" +ALIASES += matcher{2$}="\2" +ALIASES += match{1}="\1" +ALIASES += match{2$}="\2" +ALIASES += nomatch{1}="\1" +ALIASES += header{1}="\code" +ALIASES += endheader="\endcode" # This tag can be used to specify a number of word-keyword mappings (TCL only). # A mapping has the form "name=value". For example adding "class=itcl::class" diff --git a/clang/docs/tools/dump_ast_matchers.py b/clang/docs/tools/dump_ast_matchers.py index 705ff0d4d4098..a3feac8728c65 100755 --- a/clang/docs/tools/dump_ast_matchers.py +++ b/clang/docs/tools/dump_ast_matchers.py @@ -100,15 +100,72 @@ def extract_result_types(comment): comment = m.group(1) +def find_next_closing_rbrace( + data: str, start_pos: int, braces_to_be_matched: int +) -> int: + """Finds the location of the closing rbrace '}' inside of data.""" + """'start_pos' should be one past the opening lbrace and braces_to_be_matched is initialized with 0""" + next_lbrace = data.find("{", start_pos) + next_rbrace = data.find("}", start_pos) + if next_lbrace != -1: + if next_lbrace < next_rbrace: + return find_next_closing_rbrace( + data, next_lbrace + 1, braces_to_be_matched + 1 + ) + if braces_to_be_matched == 0: + return next_rbrace + return find_next_closing_rbrace(data, next_rbrace + 1, braces_to_be_matched - 1) + + if braces_to_be_matched > 0: + return find_next_closing_rbrace(data, next_rbrace + 1, braces_to_be_matched - 1) + + return next_rbrace + + def strip_doxygen(comment): """Returns the given comment without \-escaped words.""" - # If there is only a doxygen keyword in the line, delete the whole line. - comment = re.sub(r"^\\[^\s]+\n", r"", comment, flags=re.M) - # If there is a doxygen \see command, change the \see prefix into "See also:". # FIXME: it would be better to turn this into a link to the target instead. comment = re.sub(r"\\see", r"See also:", comment) + commands: list[str] = [ + "\\compile_args{", + "\\matcher{", + "\\match{", + "\\nomatch{", + ] + + for command in commands: + delete_command = command == "\\compile_args{" + command_begin_loc = comment.find(command) + while command_begin_loc != -1: + command_end_loc = command_begin_loc + len(command) + end_brace_loc = find_next_closing_rbrace(comment, command_end_loc + 1, 0) + if end_brace_loc == -1: + print("found unmatched {") + command_begin_loc = comment.find(command, command_end_loc) + continue + + if delete_command: + comment = comment[0:command_begin_loc] + comment[end_brace_loc + 1 :] + command_begin_loc = comment.find(command, command_begin_loc) + continue + + tag_seperator_loc = comment.find("$", command_end_loc) + if tag_seperator_loc != -1 and tag_seperator_loc < end_brace_loc: + command_end_loc = tag_seperator_loc + 1 + + comment = ( + comment[0:command_begin_loc] + + comment[command_end_loc:end_brace_loc] + + comment[end_brace_loc + 1 :] + ) + + command_begin_loc = comment.find(command, command_begin_loc) + + # If there is only a doxygen keyword in the line, delete the whole line. + comment = re.sub(r"^\\[^\s]+\n", r"", comment, flags=re.M) + # Delete the doxygen command and the following whitespace. comment = re.sub(r"\\[^\s]+\s+", r"", comment) return comment @@ -191,8 +248,9 @@ def act_on_decl(declaration, comment, allowed_types): definition. """ if declaration.strip(): - - if re.match(r"^\s?(#|namespace|using|template using|})", declaration): + if re.match( + r"^\s?(#|namespace|using|template using|})", declaration + ): return # Node matchers are defined by writing: diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h index f1c72efc23878..4e93a78b5b7a4 100644 --- a/clang/include/clang/ASTMatchers/ASTMatchers.h +++ b/clang/include/clang/ASTMatchers/ASTMatchers.h @@ -39,6 +39,162 @@ // See ASTMatchFinder.h for how to use the generated matchers to run over // an AST. // +// The doxygen comments on matchers are used to: +// - create the doxygen documentation +// - get information in the editor via signature help and goto definition +// - generate the AST matcher reference html file +// - test the documentation using a special syntax +// +// TLDR: +// +// The automatic testing uses doxygen commands (aliases) to extract the +// relevant information about an example of using a matcher from the +// documentation. +// +// \header{a.h} +// \endheader <- zero or more header +// +// \code +// int a = 42; +// \endcode +// \compile_args{-std=c++,c23-or-later} <- optional, the std flag supports +// std ranges and +// whole languages +// +// \matcher{expr()} <- one or more matchers in succession +// \matcher{integerLiteral()} <- one or more matchers in succession +// both matcher will have to match the +// following matches +// \match{42} <- one or more matches in succession +// +// \matcher{varDecl()} <- new matcher resets the context, the above +// \match will not count for this new +// matcher(-group) +// \match{int a = 42} <- only applies to the previous matcher (not to the +// previous case) +// +// +// The above block can be repeated inside a doxygen command for multiple code +// examples for a single matcher. The test generation script will only look for +// these annotations and ignore anything else like `\c` or the sentences where +// these annotations are embedded into: `The matcher \matcher{expr()} matches +// the number \match{42}.`. +// +// Language Grammar: +// +// [] denotes an optional, and <> denotes user-input +// +// compile_args j:= \compile_args{[;]} +// matcher_tag_key ::= type +// match_tag_key ::= type || std || count || sub +// matcher_tags ::= [matcher_tag_key=;]matcher_tag_key= +// match_tags ::= [match_tag_key=;]match_tag_key= +// matcher ::= \matcher{[matcher_tags$]} +// matchers ::= [matcher] matcher +// match ::= \match{[match_tags$]} +// matches ::= [match] match +// case ::= matchers matches +// cases ::= [case] case +// header-block ::= \header{} \endheader +// code-block ::= \code \endcode +// testcase ::= code-block [compile_args] cases +// +// Language Standard Versions: +// +// The 'std' tag and '\compile_args' support specifying a specific language +// version, a whole language and all of its versions, and thresholds (implies +// ranges). Multiple arguments are passed with a ',' separator. For a language +// and version to execute a tested matcher, it has to match the specified +// '\compile_args' for the code, and the 'std' tag for the matcher. Predicates +// for the 'std' compiler flag are used with disjunction between languages +// (e.g. 'c || c++') and conjunction for all predicates specific to each +// language (e.g. 'c++11-or-later && c++23-or-earlier'). +// +// Examples: +// - `c` all available versions of C +// - `c++11` only C++11 +// - `c++11-or-later` C++11 or later +// - `c++11-or-earlier` C++11 or earlier +// - `c++11-or-later,c++23-or-earlier,c` all of C and C++ between 11 and +// 23 (inclusive) +// - `c++11-23,c` same as above +// +// Tags +// +// `type`: +// **Match types** are used to select where the string that is used to check if +// a node matches comes from. Available: `code`, `name`, `typestr`, +// `typeofstr`. The default is `code`. +// +// - `code`: Forwards to `tooling::fixit::getText(...)` and should be the +// preferred way to show what matches. +// - `name`: Casts the match to a `NamedDecl` and returns the result of +// `getNameAsString`. Useful when the matched AST node is not easy to spell +// out (`code` type), e.g., namespaces or classes with many members. +// - `typestr`: Returns the result of `QualType::getAsString` for the type +// derived from `Type` (otherwise, if it is derived from `Decl`, recurses with +// `Node->getTypeForDecl()`) +// +// **Matcher types** are used to mark matchers as sub-matcher with 'sub' or as +// deactivated using 'none'. Testing sub-matcher is not implemented. +// +// `count`: +// Specifying a 'count=n' on a match will result in a test that requires that +// the specified match will be matched n times. Default is 1. +// +// `std`: +// A match allows specifying if it matches only in specific language versions. +// This may be needed when the AST differs between language versions. +// +// `sub`: +// The `sub` tag on a `\match` will indicate that the match is for a node of a +// bound sub-matcher. E.g., `\matcher{expr(expr().bind("inner"))}` has a +// sub-matcher that binds to `inner`, which is the value for the `sub` tag of +// the expected match for the sub-matcher `\match{sub=inner$...}`. Currently, +// sub-matchers are not tested in any way. +// +// +// What if ...? +// +// ... I want to add a matcher? +// +// Add a doxygen comment to the matcher with a code example, corresponding +// matchers and matches, that shows what the matcher is supposed to do. Specify +// the compile arguments/supported languages if required, and run `ninja +// check-clang-unit` to test the documentation. +// +// ... the example I wrote is wrong? +// +// The test-generation script will try to compile your example code before it +// continues. This makes finding issues with your example code easier because +// the test-failures are much more verbose. +// +// The test-failure output of the generated test file will provide information +// about +// - where the generated test file is located +// - which line in `ASTMatcher.h` the example is from +// - which matches were: found, not-(yet)-found, expected +// - in case of an unexpected match: what the node looks like using the +// different `type`s +// - the language version and if the test ran with a windows `-target` flag +// (also in failure summary) +// +// ... I don't adhere to the required order of the syntax? +// +// The script will diagnose any found issues, such as `matcher is missing an +// example` with a `file:line:` prefix, which should provide enough information +// about the issue. +// +// ... the script diagnoses a false-positive issue with a doxygen comment? +// +// It hopefully shouldn't, but if you, e.g., added some non-matcher code and +// documented it with doxygen, then the script will consider that as a matcher +// documentation. As a result, the script will print that it detected a +// mismatch between the actual and the expected number of failures. If the +// diagnostic truly is a false-positive, change the +// `expected_failure_statistics` at the top of the +// `generate_ast_matcher_doc_tests.py` file. +// //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_ASTMATCHERS_ASTMATCHERS_H @@ -160,13 +316,13 @@ using AttrMatcher = internal::Matcher; /// additional constraint. This will often be used with an explicit conversion /// to an \c internal::Matcher<> type such as \c TypeMatcher. /// -/// Example: \c DeclarationMatcher(anything()) matches all declarations, e.g., +/// Given /// \code -/// "int* p" and "void f()" in /// int* p; /// void f(); /// \endcode -/// +/// The matcher \matcher{decl(anything())} +/// matches \match{int* p} and \match{void f()}. /// Usable as: Any Matcher inline internal::TrueMatcher anything() { return internal::TrueMatcher(); } @@ -175,12 +331,13 @@ inline internal::TrueMatcher anything() { return internal::TrueMatcher(); } /// Given /// \code /// int X; -/// namespace NS { -/// int Y; -/// } // namespace NS +/// namespace NS { int Y; } /// \endcode -/// decl(hasDeclContext(translationUnitDecl())) -/// matches "int X", but not "int Y". +/// \compile_args{-std=c++} +/// The matcher \matcher{namedDecl(hasDeclContext(translationUnitDecl()))} +/// matches \match{int X} and \match{namespace NS { int Y; }}, +/// but does not match \nomatch{int Y} because its decl-context is the +/// namespace \c NS . extern const internal::VariadicDynCastAllOfMatcher translationUnitDecl; @@ -191,8 +348,10 @@ extern const internal::VariadicDynCastAllOfMatcher /// typedef int X; /// using Y = int; /// \endcode -/// typedefDecl() -/// matches "typedef int X", but not "using Y = int" +/// \compile_args{-std=c++} +/// The matcher \matcher{typedefDecl()} +/// matches \match{typedef int X}, +/// but does not match \nomatch{using Y = int}. extern const internal::VariadicDynCastAllOfMatcher typedefDecl; @@ -203,8 +362,9 @@ extern const internal::VariadicDynCastAllOfMatcher /// typedef int X; /// using Y = int; /// \endcode -/// typedefNameDecl() -/// matches "typedef int X" and "using Y = int" +/// \compile_args{-std=c++11-or-later} +/// The matcher \matcher{typedefNameDecl()} +/// matches \match{typedef int X} and \match{using Y = int}. extern const internal::VariadicDynCastAllOfMatcher typedefNameDecl; @@ -215,34 +375,45 @@ extern const internal::VariadicDynCastAllOfMatcher /// typedef int X; /// using Y = int; /// \endcode -/// typeAliasDecl() -/// matches "using Y = int", but not "typedef int X" +/// \compile_args{-std=c++11-or-later} +/// The matcher \matcher{typeAliasDecl()} +/// matches \match{using Y = int}, +/// but does not match \nomatch{typedef int X}. extern const internal::VariadicDynCastAllOfMatcher typeAliasDecl; /// Matches type alias template declarations. /// -/// typeAliasTemplateDecl() matches +/// Given /// \code -/// template -/// using Y = X; +/// template struct X {}; +/// template using Y = X; /// \endcode +/// \compile_args{-fno-delayed-template-parsing;-std=c++} +/// The matcher \matcher{typeAliasTemplateDecl()} +/// matches \match{template using Y = X}. extern const internal::VariadicDynCastAllOfMatcher typeAliasTemplateDecl; /// Matches AST nodes that were expanded within the main-file. /// -/// Example matches X but not Y -/// (matcher = cxxRecordDecl(isExpansionInMainFile()) -/// \code -/// #include -/// class X {}; -/// \endcode -/// Y.h: +/// Given the header \c Y.h +/// \header{Y.h} +/// #pragma once +/// typedef int my_header_int; +/// \endheader +/// and the source file /// \code -/// class Y {}; +/// #include "Y.h" +/// typedef int my_main_file_int; +/// my_main_file_int a = 0; +/// my_header_int b = 1; /// \endcode /// +/// The matcher \matcher{typedefDecl(isExpansionInMainFile())} +/// matches \match{typedef int my_main_file_int}, +/// but does not match \nomatch{typedef int my_header_int}. +/// /// Usable as: Matcher, Matcher, Matcher AST_POLYMORPHIC_MATCHER(isExpansionInMainFile, AST_POLYMORPHIC_SUPPORTED_TYPES(Decl, Stmt, TypeLoc)) { @@ -253,16 +424,21 @@ AST_POLYMORPHIC_MATCHER(isExpansionInMainFile, /// Matches AST nodes that were expanded within system-header-files. /// -/// Example matches Y but not X -/// (matcher = cxxRecordDecl(isExpansionInSystemHeader()) +/// Given the header \c SystemHeader.h +/// \header{system_include/SystemHeader.h} +/// #pragma once +/// int header(); +/// \endheader +/// and the source code /// \code /// #include -/// class X {}; -/// \endcode -/// SystemHeader.h: -/// \code -/// class Y {}; +/// static int main_file(); /// \endcode +/// \compile_args{-isystemsystem_include/} +/// +/// The matcher \matcher{type=none$functionDecl(isExpansionInSystemHeader())} +/// matches \match{int header()}, +/// but does not match \nomatch{static int main_file()}. /// /// Usable as: Matcher, Matcher, Matcher AST_POLYMORPHIC_MATCHER(isExpansionInSystemHeader, @@ -278,17 +454,32 @@ AST_POLYMORPHIC_MATCHER(isExpansionInSystemHeader, /// Matches AST nodes that were expanded within files whose name is /// partially matching a given regex. /// -/// Example matches Y but not X -/// (matcher = cxxRecordDecl(isExpansionInFileMatching("AST.*")) -/// \code -/// #include "ASTMatcher.h" -/// class X {}; -/// \endcode -/// ASTMatcher.h: -/// \code -/// class Y {}; +/// Given the headers \c Y.h +/// \header{Y.h} +/// #pragma once +/// typedef int my_y_int; +/// \endheader +/// and \c X.h +/// \header{X.h} +/// #pragma once +/// typedef int my_x_int; +/// \endheader +/// and the source code +/// \code +/// #include "X.h" +/// #include "Y.h" +/// typedef int my_main_file_int; +/// my_main_file_int a = 0; +/// my_x_int b = 1; +/// my_y_int c = 2; /// \endcode /// +/// The matcher +/// \matcher{type=none$typedefDecl(isExpansionInFileMatching("Y.h"))} +/// matches \match{typedef int my_y_int}, +/// but does not match \nomatch{typedef int my_main_file_int} or +/// \nomatch{typedef int my_x_int}. +/// /// Usable as: Matcher, Matcher, Matcher AST_POLYMORPHIC_MATCHER_REGEX(isExpansionInFileMatching, AST_POLYMORPHIC_SUPPORTED_TYPES(Decl, Stmt, @@ -313,6 +504,17 @@ AST_POLYMORPHIC_MATCHER_REGEX(isExpansionInFileMatching, /// Does not match if only part of the statement is expanded from that macro or /// if different parts of the statement are expanded from different /// appearances of the macro. +/// +/// Given +/// \code +/// #define A 0 +/// #define B A +/// int c = B; +/// \endcode +/// +/// The matcher \matcher{integerLiteral(isExpandedFromMacro("A"))} +/// matches the literal expanded at the initializer \match{B} of the variable +/// \c c . AST_POLYMORPHIC_MATCHER_P(isExpandedFromMacro, AST_POLYMORPHIC_SUPPORTED_TYPES(Decl, Stmt, TypeLoc), std::string, MacroName) { @@ -330,35 +532,50 @@ AST_POLYMORPHIC_MATCHER_P(isExpandedFromMacro, /// Matches declarations. /// -/// Examples matches \c X, \c C, and the friend declaration inside \c C; +/// Given /// \code /// void X(); /// class C { -/// friend X; +/// friend void X(); /// }; /// \endcode +/// \compile_args{-std=c++} +/// The matcher \matcher{decl()} +/// matches \match{void X()} once, \match{type=name;count=2$C} +/// twice, once for the definition and once for the implicit class declaration, +/// and \match{count=2$friend void X()} twice, once for the declaration of the +/// friend, and once for the redeclaration of the function itself. extern const internal::VariadicAllOfMatcher decl; /// Matches decomposition-declarations. /// -/// Examples matches the declaration node with \c foo and \c bar, but not -/// \c number. -/// (matcher = declStmt(has(decompositionDecl()))) -/// +/// Given /// \code +/// struct pair { int x; int y; }; +/// pair make(int, int); /// int number = 42; -/// auto [foo, bar] = std::make_pair{42, 42}; +/// auto [foo, bar] = make(42, 42); /// \endcode +/// \compile_args{-std=c++17-or-later} +/// The matcher \matcher{decompositionDecl()} +/// matches \match{auto [foo, bar] = make(42, 42)}, +/// but does not match \nomatch{type=name$number}. extern const internal::VariadicDynCastAllOfMatcher decompositionDecl; /// Matches binding declarations -/// Example matches \c foo and \c bar -/// (matcher = bindingDecl() /// +/// Given /// \code -/// auto [foo, bar] = std::make_pair{42, 42}; +/// struct pair { int x; int y; }; +/// pair make(int, int); +/// void f() { +/// auto [foo, bar] = make(42, 42); +/// } /// \endcode +/// \compile_args{-std=c++17-or-later} +/// The matcher \matcher{bindingDecl()} +/// matches \match{type=name$foo} and \match{type=name$bar}. extern const internal::VariadicDynCastAllOfMatcher bindingDecl; @@ -368,33 +585,41 @@ extern const internal::VariadicDynCastAllOfMatcher /// \code /// extern "C" {} /// \endcode -/// linkageSpecDecl() -/// matches "extern "C" {}" +/// \compile_args{-std=c++} +/// The matcher \matcher{linkageSpecDecl()} +/// matches \match{extern "C" {}}. extern const internal::VariadicDynCastAllOfMatcher linkageSpecDecl; /// Matches a declaration of anything that could have a name. /// /// Example matches \c X, \c S, the anonymous union type, \c i, and \c U; +/// Given /// \code /// typedef int X; -/// struct S { -/// union { -/// int i; -/// } U; -/// }; -/// \endcode +/// struct S { union { int i; } U; }; +/// \endcode +/// The matcher \matcher{namedDecl()} +/// matches \match{typedef int X}, +/// \match{std=c$struct S { union { int i; } U; }}, \match{int i}, +/// the unnamed union\match{type=name$} and the variable +/// \match{union { int i; } U}, +/// with \match{type=name;count=2;std=c++$S} matching twice in C++. +/// Once for the implicit class declaration and once for the declaration itself. extern const internal::VariadicDynCastAllOfMatcher namedDecl; /// Matches a declaration of label. /// /// Given /// \code -/// goto FOO; -/// FOO: bar(); +/// void bar(); +/// void foo() { +/// goto FOO; +/// FOO: bar(); +/// } /// \endcode -/// labelDecl() -/// matches 'FOO:' +/// The matcher \matcher{type=none$labelDecl()} +/// matches \match{FOO: bar()}. extern const internal::VariadicDynCastAllOfMatcher labelDecl; /// Matches a declaration of a namespace. @@ -404,8 +629,9 @@ extern const internal::VariadicDynCastAllOfMatcher labelDecl; /// namespace {} /// namespace test {} /// \endcode -/// namespaceDecl() -/// matches "namespace {}" and "namespace test {}" +/// \compile_args{-std=c++} +/// The matcher \matcher{namespaceDecl()} +/// matches \match{namespace {}} and \match{namespace test {}}. extern const internal::VariadicDynCastAllOfMatcher namespaceDecl; @@ -416,38 +642,53 @@ extern const internal::VariadicDynCastAllOfMatcher /// namespace test {} /// namespace alias = ::test; /// \endcode -/// namespaceAliasDecl() -/// matches "namespace alias" but not "namespace test" +/// \compile_args{-std=c++} +/// The matcher \matcher{namespaceAliasDecl()} +/// matches \match{namespace alias = ::test}, +/// but does not match \nomatch{namespace test {}}. extern const internal::VariadicDynCastAllOfMatcher namespaceAliasDecl; /// Matches class, struct, and union declarations. /// -/// Example matches \c X, \c Z, \c U, and \c S +/// Given /// \code /// class X; /// template class Z {}; /// struct S {}; /// union U {}; /// \endcode +/// \compile_args{-fno-delayed-template-parsing;-std=c++} +/// The matcher \matcher{recordDecl()} +/// matches \match{class X} once, and the rest of the declared records twice, +/// once for their written definition and once for their implicit declaration: +/// \match{type=name;count=2$Z}, \match{type=name;count=2$S} and +/// \match{type=name;count=2$U}. extern const internal::VariadicDynCastAllOfMatcher recordDecl; /// Matches C++ class declarations. /// -/// Example matches \c X, \c Z +/// Given /// \code /// class X; /// template class Z {}; /// \endcode +/// \compile_args{-fno-delayed-template-parsing;-std=c++} +/// The matcher \matcher{cxxRecordDecl()} +/// matches \match{class X} once, and \match{type=name;count=2$Z} twice, +/// once for the written definition and once for the implicit declaration. extern const internal::VariadicDynCastAllOfMatcher cxxRecordDecl; /// Matches C++ class template declarations. /// -/// Example matches \c Z +/// Given /// \code /// template class Z {}; /// \endcode +/// \compile_args{-fno-delayed-template-parsing;-std=c++} +/// The matcher \matcher{classTemplateDecl()} +/// matches \match{template class Z {}}. extern const internal::VariadicDynCastAllOfMatcher classTemplateDecl; @@ -459,8 +700,10 @@ extern const internal::VariadicDynCastAllOfMatcher /// template<> class A {}; /// A a; /// \endcode -/// classTemplateSpecializationDecl() -/// matches the specializations \c A and \c A +/// \compile_args{-fno-delayed-template-parsing;-std=c++} +/// The matcher \matcher{classTemplateSpecializationDecl()} +/// matches \match{type=typestr$class A} +/// and \match{type=typestr$class A}. extern const internal::VariadicDynCastAllOfMatcher< Decl, ClassTemplateSpecializationDecl> classTemplateSpecializationDecl; @@ -472,14 +715,15 @@ extern const internal::VariadicDynCastAllOfMatcher< /// template /// class A {}; /// -/// template -/// class A {}; +/// template class A {}; /// /// template<> /// class A {}; /// \endcode -/// classTemplatePartialSpecializationDecl() -/// matches the specialization \c A but not \c A +/// \compile_args{-fno-delayed-template-parsing;-std=c++} +/// The matcher \matcher{classTemplatePartialSpecializationDecl()} +/// matches \match{template class A {}}, +/// but does not match \nomatch{A}. extern const internal::VariadicDynCastAllOfMatcher< Decl, ClassTemplatePartialSpecializationDecl> classTemplatePartialSpecializationDecl; @@ -491,8 +735,9 @@ extern const internal::VariadicDynCastAllOfMatcher< /// \code /// class X { int y; }; /// \endcode -/// declaratorDecl() -/// matches \c int y. +/// \compile_args{-std=c++} +/// The matcher \matcher{declaratorDecl()} +/// matches \match{int y}. extern const internal::VariadicDynCastAllOfMatcher declaratorDecl; @@ -502,8 +747,8 @@ extern const internal::VariadicDynCastAllOfMatcher /// \code /// void f(int x); /// \endcode -/// parmVarDecl() -/// matches \c int x. +/// The matcher \matcher{parmVarDecl()} +/// matches \match{int x}. extern const internal::VariadicDynCastAllOfMatcher parmVarDecl; @@ -516,29 +761,36 @@ extern const internal::VariadicDynCastAllOfMatcher /// int a; /// }; /// \endcode -/// accessSpecDecl() -/// matches 'public:' +/// \compile_args{-std=c++} +/// The matcher \matcher{accessSpecDecl()} +/// matches \match{public:}. extern const internal::VariadicDynCastAllOfMatcher accessSpecDecl; /// Matches class bases. /// -/// Examples matches \c public virtual B. +/// Given /// \code /// class B {}; -/// class C : public virtual B {}; +/// class C : public B {}; /// \endcode +/// \compile_args{-std=c++} +/// The matcher \matcher{cxxRecordDecl(hasDirectBase(cxxBaseSpecifier()))} +/// matches \match{class C : public B {}}. extern const internal::VariadicAllOfMatcher cxxBaseSpecifier; /// Matches constructor initializers. /// -/// Examples matches \c i(42). +/// Given /// \code /// class C { /// C() : i(42) {} /// int i; /// }; /// \endcode +/// \compile_args{-std=c++} +/// The matcher \matcher{cxxCtorInitializer()} +/// matches \match{i(42)}. extern const internal::VariadicAllOfMatcher cxxCtorInitializer; @@ -549,8 +801,10 @@ extern const internal::VariadicAllOfMatcher /// template struct C {}; /// C c; /// \endcode -/// templateArgument() -/// matches 'int' in C. +/// \compile_args{-fno-delayed-template-parsing;-std=c++} +/// The matcher +/// \matcher{templateSpecializationType(hasAnyTemplateArgument(templateArgument()))} +/// matches \match{type=typestr$C}. extern const internal::VariadicAllOfMatcher templateArgument; /// Matches template arguments (with location info). @@ -560,8 +814,9 @@ extern const internal::VariadicAllOfMatcher templateArgument; /// template struct C {}; /// C c; /// \endcode -/// templateArgumentLoc() -/// matches 'int' in C. +/// \compile_args{-fno-delayed-template-parsing;-std=c++} +/// The matcher \matcher{templateArgumentLoc()} +/// matches \match{int} in C. extern const internal::VariadicAllOfMatcher templateArgumentLoc; @@ -569,11 +824,15 @@ extern const internal::VariadicAllOfMatcher /// /// Given /// \code -/// template class X { }; -/// X xi; +/// template