From 581a6d8501ff5614297da837b81ed3b6956361ea Mon Sep 17 00:00:00 2001 From: Dimitry Andric Date: Sat, 14 Jan 2017 15:37:50 +0000 Subject: Vendor import of llvm release_40 branch r292009: https://llvm.org/svn/llvm-project/llvm/branches/release_40@292009 --- lib/Analysis/AssumptionCache.cpp | 109 +++ lib/Analysis/CMakeLists.txt | 2 +- lib/Analysis/CostModel.cpp | 5 +- lib/Analysis/IVUsers.cpp | 19 +- lib/Analysis/InlineCost.cpp | 41 +- lib/Analysis/InstructionSimplify.cpp | 80 ++- lib/Analysis/LazyValueInfo.cpp | 2 +- lib/Analysis/LoopAccessAnalysis.cpp | 42 +- lib/Analysis/LoopAnalysisManager.cpp | 160 +++++ lib/Analysis/LoopInfo.cpp | 7 +- lib/Analysis/LoopPass.cpp | 12 +- lib/Analysis/LoopPassManager.cpp | 59 -- lib/Analysis/MemoryDependenceAnalysis.cpp | 67 +- lib/Analysis/ScalarEvolution.cpp | 45 +- lib/Analysis/TargetTransformInfo.cpp | 5 +- lib/Analysis/ValueTracking.cpp | 76 +- lib/CMakeLists.txt | 1 + lib/CodeGen/AsmPrinter/CodeViewDebug.cpp | 11 +- lib/CodeGen/AsmPrinter/DIE.cpp | 16 +- lib/CodeGen/AsmPrinter/DwarfUnit.cpp | 2 + lib/CodeGen/GlobalISel/RegBankSelect.cpp | 39 +- lib/CodeGen/GlobalISel/RegisterBank.cpp | 9 +- lib/CodeGen/GlobalISel/RegisterBankInfo.cpp | 109 +-- lib/CodeGen/MachineInstr.cpp | 3 +- lib/CodeGen/PeepholeOptimizer.cpp | 11 +- lib/CodeGen/ScheduleDAG.cpp | 18 +- lib/CodeGen/SelectionDAG/DAGCombiner.cpp | 27 +- lib/CodeGen/SelectionDAG/LegalizeDAG.cpp | 40 +- lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp | 30 +- lib/CodeGen/SelectionDAG/LegalizeTypes.cpp | 16 - lib/CodeGen/SelectionDAG/LegalizeTypes.h | 5 - lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp | 113 +-- lib/CodeGen/SelectionDAG/ScheduleDAGSDNodes.h | 19 +- lib/CodeGen/SelectionDAG/SelectionDAG.cpp | 29 +- lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp | 33 - lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp | 17 +- lib/CodeGen/SelectionDAG/TargetLowering.cpp | 45 +- lib/DebugInfo/CodeView/CMakeLists.txt | 5 +- lib/DebugInfo/CodeView/CVTypeDumper.cpp | 73 ++ lib/DebugInfo/CodeView/SymbolDumper.cpp | 41 +- lib/DebugInfo/CodeView/TypeDatabase.cpp | 114 +++ lib/DebugInfo/CodeView/TypeDatabaseVisitor.cpp | 289 ++++++++ lib/DebugInfo/CodeView/TypeDumpVisitor.cpp | 532 ++++++++++++++ lib/DebugInfo/CodeView/TypeDumper.cpp | 772 --------------------- .../DWARF/DWARFAbbreviationDeclaration.cpp | 35 +- lib/DebugInfo/DWARF/DWARFContext.cpp | 78 +-- lib/DebugInfo/DWARF/DWARFDebugInfoEntry.cpp | 2 +- lib/DebugInfo/DWARF/DWARFDie.cpp | 45 +- lib/DebugInfo/DWARF/DWARFFormValue.cpp | 4 +- lib/DebugInfo/DWARF/DWARFUnit.cpp | 10 +- lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp | 3 + lib/IR/AutoUpgrade.cpp | 10 + lib/IR/DIBuilder.cpp | 44 ++ lib/IR/Globals.cpp | 26 +- lib/IR/LLVMContextImpl.h | 7 + lib/LTO/LTOBackend.cpp | 2 +- lib/LTO/ThinLTOCodeGenerator.cpp | 36 +- lib/Object/CMakeLists.txt | 1 + lib/Object/Decompressor.cpp | 102 +++ lib/ObjectYAML/DWARFYAML.cpp | 67 +- lib/Passes/PassBuilder.cpp | 14 +- lib/ProfileData/InstrProf.cpp | 43 ++ lib/Support/FileOutputBuffer.cpp | 66 +- lib/Support/Host.cpp | 19 + lib/Support/TarWriter.cpp | 17 +- lib/Target/AArch64/AArch64GenRegisterBankInfo.def | 129 +++- lib/Target/AArch64/AArch64ISelLowering.cpp | 2 + lib/Target/AArch64/AArch64InstrInfo.td | 5 +- lib/Target/AArch64/AArch64RegisterBankInfo.cpp | 33 +- lib/Target/AArch64/AArch64TargetTransformInfo.cpp | 25 +- lib/Target/AArch64/AArch64TargetTransformInfo.h | 3 +- lib/Target/AMDGPU/AMDGPUISelLowering.cpp | 236 +++++++ lib/Target/AMDGPU/AMDGPUISelLowering.h | 1 + lib/Target/AMDGPU/AMDGPUInstructions.td | 3 +- lib/Target/AMDGPU/AMDGPUTargetTransformInfo.cpp | 2 +- lib/Target/AMDGPU/AMDGPUTargetTransformInfo.h | 3 +- lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp | 116 +++- lib/Target/AMDGPU/EvergreenInstructions.td | 4 +- lib/Target/AMDGPU/SIFoldOperands.cpp | 399 +++++++---- lib/Target/AMDGPU/SIInstrInfo.td | 42 +- lib/Target/AMDGPU/SIInstructions.td | 5 + lib/Target/AMDGPU/SIShrinkInstructions.cpp | 36 +- lib/Target/AMDGPU/VOP1Instructions.td | 2 +- lib/Target/AMDGPU/VOP2Instructions.td | 8 +- lib/Target/AMDGPU/VOPCInstructions.td | 4 +- lib/Target/ARM/ARMISelLowering.cpp | 198 +++++- lib/Target/ARM/ARMISelLowering.h | 41 +- lib/Target/ARM/ARMRegisterBankInfo.cpp | 35 +- lib/Target/ARM/ARMTargetTransformInfo.cpp | 3 +- lib/Target/ARM/ARMTargetTransformInfo.h | 3 +- lib/Target/Lanai/LanaiTargetTransformInfo.h | 3 +- lib/Target/Mips/MipsSEISelLowering.cpp | 162 ++++- lib/Target/NVPTX/ManagedStringPool.h | 7 +- lib/Target/NVPTX/NVPTXAsmPrinter.cpp | 152 ++-- lib/Target/NVPTX/NVPTXAsmPrinter.h | 58 +- lib/Target/NVPTX/NVPTXISelLowering.cpp | 118 ++-- lib/Target/NVPTX/NVPTXInstrInfo.td | 2 +- lib/Target/NVPTX/NVPTXSection.h | 10 +- lib/Target/NVPTX/NVPTXTargetMachine.cpp | 37 +- lib/Target/NVPTX/NVPTXTargetObjectFile.h | 10 +- lib/Target/NVPTX/NVPTXTargetTransformInfo.cpp | 2 +- lib/Target/NVPTX/NVPTXTargetTransformInfo.h | 3 +- lib/Target/PowerPC/PPCTargetTransformInfo.cpp | 2 +- lib/Target/PowerPC/PPCTargetTransformInfo.h | 3 +- lib/Target/SystemZ/SystemZISelLowering.cpp | 22 +- lib/Target/TargetMachine.cpp | 9 +- lib/Target/WebAssembly/WebAssemblyFastISel.cpp | 3 + .../WebAssembly/WebAssemblyFixFunctionBitcasts.cpp | 17 +- .../WebAssembly/WebAssemblyTargetTransformInfo.cpp | 2 +- .../WebAssembly/WebAssemblyTargetTransformInfo.h | 3 +- lib/Target/X86/X86.td | 41 +- lib/Target/X86/X86ISelDAGToDAG.cpp | 10 - lib/Target/X86/X86ISelLowering.cpp | 387 ++++++++--- lib/Target/X86/X86InstrAVX512.td | 39 ++ lib/Target/X86/X86InstrSSE.td | 74 +- lib/Target/X86/X86Subtarget.h | 2 +- lib/Target/X86/X86TargetTransformInfo.cpp | 57 +- lib/Target/X86/X86TargetTransformInfo.h | 3 +- lib/Transforms/IPO/LowerTypeTests.cpp | 30 +- lib/Transforms/InstCombine/InstCombineAddSub.cpp | 12 +- lib/Transforms/InstCombine/InstCombineAndOrXor.cpp | 28 +- lib/Transforms/InstCombine/InstCombineCalls.cpp | 19 +- lib/Transforms/InstCombine/InstCombineInternal.h | 19 +- .../InstCombine/InstCombineMulDivRem.cpp | 41 +- lib/Transforms/InstCombine/InstCombinePHI.cpp | 2 +- lib/Transforms/InstCombine/InstCombineShifts.cpp | 9 +- .../InstCombine/InstructionCombining.cpp | 20 +- .../Instrumentation/AddressSanitizer.cpp | 9 +- lib/Transforms/Instrumentation/InstrProfiling.cpp | 16 +- .../Instrumentation/PGOInstrumentation.cpp | 28 +- lib/Transforms/Scalar/CMakeLists.txt | 3 + lib/Transforms/Scalar/IVUsersPrinter.cpp | 22 + lib/Transforms/Scalar/IndVarSimplify.cpp | 26 +- lib/Transforms/Scalar/LICM.cpp | 124 +++- .../Scalar/LoopAccessAnalysisPrinter.cpp | 25 + lib/Transforms/Scalar/LoopDeletion.cpp | 15 +- lib/Transforms/Scalar/LoopDistribute.cpp | 12 +- lib/Transforms/Scalar/LoopIdiomRecognize.cpp | 22 +- lib/Transforms/Scalar/LoopInstSimplify.cpp | 20 +- lib/Transforms/Scalar/LoopPassManager.cpp | 85 +++ lib/Transforms/Scalar/LoopRotation.cpp | 23 +- lib/Transforms/Scalar/LoopSimplifyCFG.cpp | 18 +- lib/Transforms/Scalar/LoopSink.cpp | 5 +- lib/Transforms/Scalar/LoopStrengthReduce.cpp | 28 +- lib/Transforms/Scalar/LoopUnrollPass.cpp | 38 +- lib/Transforms/Scalar/NewGVN.cpp | 135 ++-- lib/Transforms/Scalar/StructurizeCFG.cpp | 1 + lib/Transforms/Utils/LoopUnroll.cpp | 50 +- lib/Transforms/Utils/LoopUnrollRuntime.cpp | 8 +- lib/Transforms/Utils/LoopUtils.cpp | 9 +- lib/Transforms/Utils/SimplifyCFG.cpp | 9 +- lib/Transforms/Utils/SimplifyLibCalls.cpp | 23 +- lib/Transforms/Vectorize/LoopVectorize.cpp | 14 +- lib/Transforms/Vectorize/SLPVectorizer.cpp | 4 - lib/XRay/CMakeLists.txt | 13 + lib/XRay/Trace.cpp | 196 ++++++ 156 files changed, 4956 insertions(+), 2562 deletions(-) create mode 100644 lib/Analysis/LoopAnalysisManager.cpp delete mode 100644 lib/Analysis/LoopPassManager.cpp create mode 100644 lib/DebugInfo/CodeView/CVTypeDumper.cpp create mode 100644 lib/DebugInfo/CodeView/TypeDatabase.cpp create mode 100644 lib/DebugInfo/CodeView/TypeDatabaseVisitor.cpp create mode 100644 lib/DebugInfo/CodeView/TypeDumpVisitor.cpp delete mode 100644 lib/DebugInfo/CodeView/TypeDumper.cpp create mode 100644 lib/Object/Decompressor.cpp create mode 100644 lib/Transforms/Scalar/IVUsersPrinter.cpp create mode 100644 lib/Transforms/Scalar/LoopAccessAnalysisPrinter.cpp create mode 100644 lib/Transforms/Scalar/LoopPassManager.cpp create mode 100644 lib/XRay/CMakeLists.txt create mode 100644 lib/XRay/Trace.cpp (limited to 'lib') diff --git a/lib/Analysis/AssumptionCache.cpp b/lib/Analysis/AssumptionCache.cpp index 3c518034ba62..aa55d79b761e 100644 --- a/lib/Analysis/AssumptionCache.cpp +++ b/lib/Analysis/AssumptionCache.cpp @@ -24,6 +24,109 @@ using namespace llvm; using namespace llvm::PatternMatch; +SmallVector &AssumptionCache::getAffectedValues(Value *V) { + // Try using find_as first to avoid creating extra value handles just for the + // purpose of doing the lookup. + auto AVI = AffectedValues.find_as(V); + if (AVI != AffectedValues.end()) + return AVI->second; + + auto AVIP = AffectedValues.insert({ + AffectedValueCallbackVH(V, this), SmallVector()}); + return AVIP.first->second; +} + +void AssumptionCache::updateAffectedValues(CallInst *CI) { + // Note: This code must be kept in-sync with the code in + // computeKnownBitsFromAssume in ValueTracking. + + SmallVector Affected; + auto AddAffected = [&Affected](Value *V) { + if (isa(V)) { + Affected.push_back(V); + } else if (auto *I = dyn_cast(V)) { + Affected.push_back(I); + + if (I->getOpcode() == Instruction::BitCast || + I->getOpcode() == Instruction::PtrToInt) { + auto *Op = I->getOperand(0); + if (isa(Op) || isa(Op)) + Affected.push_back(Op); + } + } + }; + + Value *Cond = CI->getArgOperand(0), *A, *B; + AddAffected(Cond); + + CmpInst::Predicate Pred; + if (match(Cond, m_ICmp(Pred, m_Value(A), m_Value(B)))) { + AddAffected(A); + AddAffected(B); + + if (Pred == ICmpInst::ICMP_EQ) { + // For equality comparisons, we handle the case of bit inversion. + auto AddAffectedFromEq = [&AddAffected](Value *V) { + Value *A; + if (match(V, m_Not(m_Value(A)))) { + AddAffected(A); + V = A; + } + + Value *B; + ConstantInt *C; + // (A & B) or (A | B) or (A ^ B). + if (match(V, + m_CombineOr(m_And(m_Value(A), m_Value(B)), + m_CombineOr(m_Or(m_Value(A), m_Value(B)), + m_Xor(m_Value(A), m_Value(B)))))) { + AddAffected(A); + AddAffected(B); + // (A << C) or (A >>_s C) or (A >>_u C) where C is some constant. + } else if (match(V, + m_CombineOr(m_Shl(m_Value(A), m_ConstantInt(C)), + m_CombineOr(m_LShr(m_Value(A), m_ConstantInt(C)), + m_AShr(m_Value(A), + m_ConstantInt(C)))))) { + AddAffected(A); + } + }; + + AddAffectedFromEq(A); + AddAffectedFromEq(B); + } + } + + for (auto &AV : Affected) { + auto &AVV = getAffectedValues(AV); + if (std::find(AVV.begin(), AVV.end(), CI) == AVV.end()) + AVV.push_back(CI); + } +} + +void AssumptionCache::AffectedValueCallbackVH::deleted() { + auto AVI = AC->AffectedValues.find(getValPtr()); + if (AVI != AC->AffectedValues.end()) + AC->AffectedValues.erase(AVI); + // 'this' now dangles! +} + +void AssumptionCache::AffectedValueCallbackVH::allUsesReplacedWith(Value *NV) { + if (!isa(NV) && !isa(NV)) + return; + + // Any assumptions that affected this value now affect the new value. + + auto &NAVV = AC->getAffectedValues(NV); + auto AVI = AC->AffectedValues.find(getValPtr()); + if (AVI == AC->AffectedValues.end()) + return; + + for (auto &A : AVI->second) + if (std::find(NAVV.begin(), NAVV.end(), A) == NAVV.end()) + NAVV.push_back(A); +} + void AssumptionCache::scanFunction() { assert(!Scanned && "Tried to scan the function twice!"); assert(AssumeHandles.empty() && "Already have assumes when scanning!"); @@ -37,6 +140,10 @@ void AssumptionCache::scanFunction() { // Mark the scan as complete. Scanned = true; + + // Update affected values. + for (auto &A : AssumeHandles) + updateAffectedValues(cast(A)); } void AssumptionCache::registerAssumption(CallInst *CI) { @@ -72,6 +179,8 @@ void AssumptionCache::registerAssumption(CallInst *CI) { "Cache contains multiple copies of a call!"); } #endif + + updateAffectedValues(CI); } AnalysisKey AssumptionAnalysis::Key; diff --git a/lib/Analysis/CMakeLists.txt b/lib/Analysis/CMakeLists.txt index 08d50c29dfc8..d53364373d7b 100644 --- a/lib/Analysis/CMakeLists.txt +++ b/lib/Analysis/CMakeLists.txt @@ -44,10 +44,10 @@ add_llvm_library(LLVMAnalysis Lint.cpp Loads.cpp LoopAccessAnalysis.cpp + LoopAnalysisManager.cpp LoopUnrollAnalyzer.cpp LoopInfo.cpp LoopPass.cpp - LoopPassManager.cpp MemDepPrinter.cpp MemDerefPrinter.cpp MemoryBuiltins.cpp diff --git a/lib/Analysis/CostModel.cpp b/lib/Analysis/CostModel.cpp index 67d1773f0811..6b77397956cd 100644 --- a/lib/Analysis/CostModel.cpp +++ b/lib/Analysis/CostModel.cpp @@ -438,8 +438,11 @@ unsigned CostModelAnalysis::getInstructionCost(const Instruction *I) const { getOperandInfo(I->getOperand(0)); TargetTransformInfo::OperandValueKind Op2VK = getOperandInfo(I->getOperand(1)); + SmallVector Operands(I->operand_values()); return TTI->getArithmeticInstrCost(I->getOpcode(), I->getType(), Op1VK, - Op2VK); + Op2VK, TargetTransformInfo::OP_None, + TargetTransformInfo::OP_None, + Operands); } case Instruction::Select: { const SelectInst *SI = cast(I); diff --git a/lib/Analysis/IVUsers.cpp b/lib/Analysis/IVUsers.cpp index 76e2561b9da3..a661b0101e6a 100644 --- a/lib/Analysis/IVUsers.cpp +++ b/lib/Analysis/IVUsers.cpp @@ -16,8 +16,8 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/Analysis/AssumptionCache.h" #include "llvm/Analysis/CodeMetrics.h" +#include "llvm/Analysis/LoopAnalysisManager.h" #include "llvm/Analysis/LoopPass.h" -#include "llvm/Analysis/LoopPassManager.h" #include "llvm/Analysis/ScalarEvolutionExpressions.h" #include "llvm/Analysis/ValueTracking.h" #include "llvm/IR/Constants.h" @@ -36,20 +36,9 @@ using namespace llvm; AnalysisKey IVUsersAnalysis::Key; -IVUsers IVUsersAnalysis::run(Loop &L, LoopAnalysisManager &AM) { - const auto &FAM = - AM.getResult(L).getManager(); - Function *F = L.getHeader()->getParent(); - - return IVUsers(&L, FAM.getCachedResult(*F), - FAM.getCachedResult(*F), - FAM.getCachedResult(*F), - FAM.getCachedResult(*F)); -} - -PreservedAnalyses IVUsersPrinterPass::run(Loop &L, LoopAnalysisManager &AM) { - AM.getResult(L).print(OS); - return PreservedAnalyses::all(); +IVUsers IVUsersAnalysis::run(Loop &L, LoopAnalysisManager &AM, + LoopStandardAnalysisResults &AR) { + return IVUsers(&L, &AR.AC, &AR.LI, &AR.DT, &AR.SE); } char IVUsersWrapperPass::ID = 0; diff --git a/lib/Analysis/InlineCost.cpp b/lib/Analysis/InlineCost.cpp index 9b9faacd354c..4109049ecabc 100644 --- a/lib/Analysis/InlineCost.cpp +++ b/lib/Analysis/InlineCost.cpp @@ -636,30 +636,27 @@ void CallAnalyzer::updateThreshold(CallSite CS, Function &Callee) { else if (Caller->optForSize()) Threshold = MinIfValid(Threshold, Params.OptSizeThreshold); - bool HotCallsite = false; - uint64_t TotalWeight; - if (PSI && CS.getInstruction()->extractProfTotalWeight(TotalWeight) && - PSI->isHotCount(TotalWeight)) { - HotCallsite = true; + // Adjust the threshold based on inlinehint attribute and profile based + // hotness information if the caller does not have MinSize attribute. + if (!Caller->optForMinSize()) { + if (Callee.hasFnAttribute(Attribute::InlineHint)) + Threshold = MaxIfValid(Threshold, Params.HintThreshold); + if (PSI) { + uint64_t TotalWeight; + if (CS.getInstruction()->extractProfTotalWeight(TotalWeight) && + PSI->isHotCount(TotalWeight)) { + Threshold = MaxIfValid(Threshold, Params.HotCallSiteThreshold); + } else if (PSI->isFunctionEntryHot(&Callee)) { + // If callsite hotness can not be determined, we may still know + // that the callee is hot and treat it as a weaker hint for threshold + // increase. + Threshold = MaxIfValid(Threshold, Params.HintThreshold); + } else if (PSI->isFunctionEntryCold(&Callee)) { + Threshold = MinIfValid(Threshold, Params.ColdThreshold); + } + } } - // Listen to the inlinehint attribute or profile based hotness information - // when it would increase the threshold and the caller does not need to - // minimize its size. - bool InlineHint = Callee.hasFnAttribute(Attribute::InlineHint) || - (PSI && PSI->isFunctionEntryHot(&Callee)); - if (InlineHint && !Caller->optForMinSize()) - Threshold = MaxIfValid(Threshold, Params.HintThreshold); - - if (HotCallsite && !Caller->optForMinSize()) - Threshold = MaxIfValid(Threshold, Params.HotCallSiteThreshold); - - bool ColdCallee = PSI && PSI->isFunctionEntryCold(&Callee); - // For cold callees, use the ColdThreshold knob if it is available and reduces - // the threshold. - if (ColdCallee) - Threshold = MinIfValid(Threshold, Params.ColdThreshold); - // Finally, take the target-specific inlining threshold multiplier into // account. Threshold *= TTI.getInliningThresholdMultiplier(); diff --git a/lib/Analysis/InstructionSimplify.cpp b/lib/Analysis/InstructionSimplify.cpp index 8da2f0981d0c..796e6e444980 100644 --- a/lib/Analysis/InstructionSimplify.cpp +++ b/lib/Analysis/InstructionSimplify.cpp @@ -3583,7 +3583,7 @@ static Value *simplifySelectBitTest(Value *TrueVal, Value *FalseVal, Value *X, *Y == *C) return TrueWhenUnset ? TrueVal : FalseVal; } - + return nullptr; } @@ -3595,7 +3595,7 @@ static Value *simplifySelectWithFakeICmpEq(Value *CmpLHS, Value *TrueVal, unsigned BitWidth = TrueVal->getType()->getScalarSizeInBits(); if (!BitWidth) return nullptr; - + APInt MinSignedValue; Value *X; if (match(CmpLHS, m_Trunc(m_Value(X))) && (X == TrueVal || X == FalseVal)) { @@ -4252,14 +4252,36 @@ static Value *SimplifyIntrinsic(Function *F, IterTy ArgBegin, IterTy ArgEnd, const Query &Q, unsigned MaxRecurse) { Intrinsic::ID IID = F->getIntrinsicID(); unsigned NumOperands = std::distance(ArgBegin, ArgEnd); - Type *ReturnType = F->getReturnType(); + + // Unary Ops + if (NumOperands == 1) { + // Perform idempotent optimizations + if (IsIdempotent(IID)) { + if (IntrinsicInst *II = dyn_cast(*ArgBegin)) { + if (II->getIntrinsicID() == IID) + return II; + } + } + + switch (IID) { + case Intrinsic::fabs: { + if (SignBitMustBeZero(*ArgBegin, Q.TLI)) + return *ArgBegin; + } + default: + return nullptr; + } + } // Binary Ops if (NumOperands == 2) { Value *LHS = *ArgBegin; Value *RHS = *(ArgBegin + 1); - if (IID == Intrinsic::usub_with_overflow || - IID == Intrinsic::ssub_with_overflow) { + Type *ReturnType = F->getReturnType(); + + switch (IID) { + case Intrinsic::usub_with_overflow: + case Intrinsic::ssub_with_overflow: { // X - X -> { 0, false } if (LHS == RHS) return Constant::getNullValue(ReturnType); @@ -4268,17 +4290,19 @@ static Value *SimplifyIntrinsic(Function *F, IterTy ArgBegin, IterTy ArgEnd, // undef - X -> undef if (isa(LHS) || isa(RHS)) return UndefValue::get(ReturnType); - } - if (IID == Intrinsic::uadd_with_overflow || - IID == Intrinsic::sadd_with_overflow) { + return nullptr; + } + case Intrinsic::uadd_with_overflow: + case Intrinsic::sadd_with_overflow: { // X + undef -> undef if (isa(RHS)) return UndefValue::get(ReturnType); - } - if (IID == Intrinsic::umul_with_overflow || - IID == Intrinsic::smul_with_overflow) { + return nullptr; + } + case Intrinsic::umul_with_overflow: + case Intrinsic::smul_with_overflow: { // X * 0 -> { 0, false } if (match(RHS, m_Zero())) return Constant::getNullValue(ReturnType); @@ -4286,34 +4310,34 @@ static Value *SimplifyIntrinsic(Function *F, IterTy ArgBegin, IterTy ArgEnd, // X * undef -> { 0, false } if (match(RHS, m_Undef())) return Constant::getNullValue(ReturnType); - } - if (IID == Intrinsic::load_relative && isa(LHS) && - isa(RHS)) - return SimplifyRelativeLoad(cast(LHS), cast(RHS), - Q.DL); + return nullptr; + } + case Intrinsic::load_relative: { + Constant *C0 = dyn_cast(LHS); + Constant *C1 = dyn_cast(RHS); + if (C0 && C1) + return SimplifyRelativeLoad(C0, C1, Q.DL); + return nullptr; + } + default: + return nullptr; + } } // Simplify calls to llvm.masked.load.* - if (IID == Intrinsic::masked_load) { + switch (IID) { + case Intrinsic::masked_load: { Value *MaskArg = ArgBegin[2]; Value *PassthruArg = ArgBegin[3]; // If the mask is all zeros or undef, the "passthru" argument is the result. if (maskIsAllZeroOrUndef(MaskArg)) return PassthruArg; + return nullptr; } - - // Perform idempotent optimizations - if (!IsIdempotent(IID)) + default: return nullptr; - - // Unary Ops - if (NumOperands == 1) - if (IntrinsicInst *II = dyn_cast(*ArgBegin)) - if (II->getIntrinsicID() == IID) - return II; - - return nullptr; + } } template diff --git a/lib/Analysis/LazyValueInfo.cpp b/lib/Analysis/LazyValueInfo.cpp index 4f6355236873..d442310476cf 100644 --- a/lib/Analysis/LazyValueInfo.cpp +++ b/lib/Analysis/LazyValueInfo.cpp @@ -925,7 +925,7 @@ void LazyValueInfoImpl::intersectAssumeOrGuardBlockValueConstantRange( if (!BBI) return; - for (auto &AssumeVH : AC->assumptions()) { + for (auto &AssumeVH : AC->assumptionsFor(Val)) { if (!AssumeVH) continue; auto *I = cast(AssumeVH); diff --git a/lib/Analysis/LoopAccessAnalysis.cpp b/lib/Analysis/LoopAccessAnalysis.cpp index 2f3dca3d23fa..bf8007213097 100644 --- a/lib/Analysis/LoopAccessAnalysis.cpp +++ b/lib/Analysis/LoopAccessAnalysis.cpp @@ -12,22 +12,22 @@ // //===----------------------------------------------------------------------===// +#include "llvm/Analysis/LoopAccessAnalysis.h" #include "llvm/ADT/APInt.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DepthFirstIterator.h" #include "llvm/ADT/EquivalenceClasses.h" -#include "llvm/ADT/iterator_range.h" #include "llvm/ADT/PointerIntPair.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SetVector.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/iterator_range.h" #include "llvm/Analysis/AliasAnalysis.h" #include "llvm/Analysis/AliasSetTracker.h" -#include "llvm/Analysis/LoopAccessAnalysis.h" +#include "llvm/Analysis/LoopAnalysisManager.h" #include "llvm/Analysis/LoopInfo.h" -#include "llvm/Analysis/LoopPassManager.h" #include "llvm/Analysis/MemoryLocation.h" #include "llvm/Analysis/OptimizationDiagnosticInfo.h" #include "llvm/Analysis/ScalarEvolution.h" @@ -44,10 +44,10 @@ #include "llvm/IR/DiagnosticInfo.h" #include "llvm/IR/Dominators.h" #include "llvm/IR/Function.h" +#include "llvm/IR/IRBuilder.h" #include "llvm/IR/InstrTypes.h" #include "llvm/IR/Instruction.h" #include "llvm/IR/Instructions.h" -#include "llvm/IR/IRBuilder.h" #include "llvm/IR/Operator.h" #include "llvm/IR/PassManager.h" #include "llvm/IR/Type.h" @@ -2120,35 +2120,9 @@ INITIALIZE_PASS_END(LoopAccessLegacyAnalysis, LAA_NAME, laa_name, false, true) AnalysisKey LoopAccessAnalysis::Key; -LoopAccessInfo LoopAccessAnalysis::run(Loop &L, LoopAnalysisManager &AM) { - const FunctionAnalysisManager &FAM = - AM.getResult(L).getManager(); - Function &F = *L.getHeader()->getParent(); - auto *SE = FAM.getCachedResult(F); - auto *TLI = FAM.getCachedResult(F); - auto *AA = FAM.getCachedResult(F); - auto *DT = FAM.getCachedResult(F); - auto *LI = FAM.getCachedResult(F); - if (!SE) - report_fatal_error( - "ScalarEvolution must have been cached at a higher level"); - if (!AA) - report_fatal_error("AliasAnalysis must have been cached at a higher level"); - if (!DT) - report_fatal_error("DominatorTree must have been cached at a higher level"); - if (!LI) - report_fatal_error("LoopInfo must have been cached at a higher level"); - return LoopAccessInfo(&L, SE, TLI, AA, DT, LI); -} - -PreservedAnalyses LoopAccessInfoPrinterPass::run(Loop &L, - LoopAnalysisManager &AM) { - Function &F = *L.getHeader()->getParent(); - auto &LAI = AM.getResult(L); - OS << "Loop access info in function '" << F.getName() << "':\n"; - OS.indent(2) << L.getHeader()->getName() << ":\n"; - LAI.print(OS, 4); - return PreservedAnalyses::all(); +LoopAccessInfo LoopAccessAnalysis::run(Loop &L, LoopAnalysisManager &AM, + LoopStandardAnalysisResults &AR) { + return LoopAccessInfo(&L, &AR.SE, &AR.TLI, &AR.AA, &AR.DT, &AR.LI); } namespace llvm { diff --git a/lib/Analysis/LoopAnalysisManager.cpp b/lib/Analysis/LoopAnalysisManager.cpp new file mode 100644 index 000000000000..5be3ee341c9c --- /dev/null +++ b/lib/Analysis/LoopAnalysisManager.cpp @@ -0,0 +1,160 @@ +//===- LoopAnalysisManager.cpp - Loop analysis management -----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Analysis/LoopAnalysisManager.h" +#include "llvm/Analysis/BasicAliasAnalysis.h" +#include "llvm/Analysis/GlobalsModRef.h" +#include "llvm/Analysis/LoopInfo.h" +#include "llvm/Analysis/ScalarEvolution.h" +#include "llvm/Analysis/ScalarEvolutionAliasAnalysis.h" +#include "llvm/IR/Dominators.h" + +using namespace llvm; + +// Explicit template instantiations and specialization defininitions for core +// template typedefs. +namespace llvm { +template class AllAnalysesOn; +template class AnalysisManager; +template class InnerAnalysisManagerProxy; +template class OuterAnalysisManagerProxy; + +bool LoopAnalysisManagerFunctionProxy::Result::invalidate( + Function &F, const PreservedAnalyses &PA, + FunctionAnalysisManager::Invalidator &Inv) { + // First compute the sequence of IR units covered by this proxy. We will want + // to visit this in postorder, but because this is a tree structure we can do + // this by building a preorder sequence and walking it in reverse. + SmallVector PreOrderLoops, PreOrderWorklist; + // Note that we want to walk the roots in reverse order because we will end + // up reversing the preorder sequence. However, it happens that the loop nest + // roots are in reverse order within the LoopInfo object. So we just walk + // forward here. + // FIXME: If we change the order of LoopInfo we will want to add a reverse + // here. + for (Loop *RootL : *LI) { + assert(PreOrderWorklist.empty() && + "Must start with an empty preorder walk worklist."); + PreOrderWorklist.push_back(RootL); + do { + Loop *L = PreOrderWorklist.pop_back_val(); + PreOrderWorklist.append(L->begin(), L->end()); + PreOrderLoops.push_back(L); + } while (!PreOrderWorklist.empty()); + } + + // If this proxy or the loop info is going to be invalidated, we also need + // to clear all the keys coming from that analysis. We also completely blow + // away the loop analyses if any of the standard analyses provided by the + // loop pass manager go away so that loop analyses can freely use these + // without worrying about declaring dependencies on them etc. + // FIXME: It isn't clear if this is the right tradeoff. We could instead make + // loop analyses declare any dependencies on these and use the more general + // invalidation logic below to act on that. + auto PAC = PA.getChecker(); + if (!(PAC.preserved() || PAC.preservedSet>()) || + Inv.invalidate(F, PA) || + Inv.invalidate(F, PA) || + Inv.invalidate(F, PA) || + Inv.invalidate(F, PA) || + Inv.invalidate(F, PA)) { + // Note that the LoopInfo may be stale at this point, however the loop + // objects themselves remain the only viable keys that could be in the + // analysis manager's cache. So we just walk the keys and forcibly clear + // those results. Note that the order doesn't matter here as this will just + // directly destroy the results without calling methods on them. + for (Loop *L : PreOrderLoops) + InnerAM->clear(*L); + + // We also need to null out the inner AM so that when the object gets + // destroyed as invalid we don't try to clear the inner AM again. At that + // point we won't be able to reliably walk the loops for this function and + // only clear results associated with those loops the way we do here. + // FIXME: Making InnerAM null at this point isn't very nice. Most analyses + // try to remain valid during invalidation. Maybe we should add an + // `IsClean` flag? + InnerAM = nullptr; + + // Now return true to indicate this *is* invalid and a fresh proxy result + // needs to be built. This is especially important given the null InnerAM. + return true; + } + + // Directly check if the relevant set is preserved so we can short circuit + // invalidating loops. + bool AreLoopAnalysesPreserved = + PA.allAnalysesInSetPreserved>(); + + // Since we have a valid LoopInfo we can actually leave the cached results in + // the analysis manager associated with the Loop keys, but we need to + // propagate any necessary invalidation logic into them. We'd like to + // invalidate things in roughly the same order as they were put into the + // cache and so we walk the preorder list in reverse to form a valid + // postorder. + for (Loop *L : reverse(PreOrderLoops)) { + Optional InnerPA; + + // Check to see whether the preserved set needs to be adjusted based on + // function-level analysis invalidation triggering deferred invalidation + // for this loop. + if (auto *OuterProxy = + InnerAM->getCachedResult(*L)) + for (const auto &OuterInvalidationPair : + OuterProxy->getOuterInvalidations()) { + AnalysisKey *OuterAnalysisID = OuterInvalidationPair.first; + const auto &InnerAnalysisIDs = OuterInvalidationPair.second; + if (Inv.invalidate(OuterAnalysisID, F, PA)) { + if (!InnerPA) + InnerPA = PA; + for (AnalysisKey *InnerAnalysisID : InnerAnalysisIDs) + InnerPA->abandon(InnerAnalysisID); + } + } + + // Check if we needed a custom PA set. If so we'll need to run the inner + // invalidation. + if (InnerPA) { + InnerAM->invalidate(*L, *InnerPA); + continue; + } + + // Otherwise we only need to do invalidation if the original PA set didn't + // preserve all Loop analyses. + if (!AreLoopAnalysesPreserved) + InnerAM->invalidate(*L, PA); + } + + // Return false to indicate that this result is still a valid proxy. + return false; +} + +template <> +LoopAnalysisManagerFunctionProxy::Result +LoopAnalysisManagerFunctionProxy::run(Function &F, + FunctionAnalysisManager &AM) { + return Result(*InnerAM, AM.getResult(F)); +} +} + +PreservedAnalyses llvm::getLoopPassPreservedAnalyses() { + PreservedAnalyses PA; + PA.preserve(); + PA.preserve(); + PA.preserve(); + PA.preserve(); + PA.preserve(); + // TODO: What we really want to do here is preserve an AA category, but that + // concept doesn't exist yet. + PA.preserve(); + PA.preserve(); + PA.preserve(); + PA.preserve(); + return PA; +} diff --git a/lib/Analysis/LoopInfo.cpp b/lib/Analysis/LoopInfo.cpp index 3d85ef6988a9..f449ce94d57c 100644 --- a/lib/Analysis/LoopInfo.cpp +++ b/lib/Analysis/LoopInfo.cpp @@ -689,18 +689,13 @@ PreservedAnalyses LoopPrinterPass::run(Function &F, return PreservedAnalyses::all(); } -PrintLoopPass::PrintLoopPass() : OS(dbgs()) {} -PrintLoopPass::PrintLoopPass(raw_ostream &OS, const std::string &Banner) - : OS(OS), Banner(Banner) {} - -PreservedAnalyses PrintLoopPass::run(Loop &L, AnalysisManager &) { +void llvm::printLoop(Loop &L, raw_ostream &OS, const std::string &Banner) { OS << Banner; for (auto *Block : L.blocks()) if (Block) Block->print(OS); else OS << "Printing block"; - return PreservedAnalyses::all(); } //===----------------------------------------------------------------------===// diff --git a/lib/Analysis/LoopPass.cpp b/lib/Analysis/LoopPass.cpp index b5b8040984d7..3f4a07942154 100644 --- a/lib/Analysis/LoopPass.cpp +++ b/lib/Analysis/LoopPass.cpp @@ -14,7 +14,7 @@ //===----------------------------------------------------------------------===// #include "llvm/Analysis/LoopPass.h" -#include "llvm/Analysis/LoopPassManager.h" +#include "llvm/Analysis/LoopAnalysisManager.h" #include "llvm/IR/Dominators.h" #include "llvm/IR/IRPrintingPasses.h" #include "llvm/IR/LLVMContext.h" @@ -32,13 +32,14 @@ namespace { /// PrintLoopPass - Print a Function corresponding to a Loop. /// class PrintLoopPassWrapper : public LoopPass { - PrintLoopPass P; + raw_ostream &OS; + std::string Banner; public: static char ID; - PrintLoopPassWrapper() : LoopPass(ID) {} + PrintLoopPassWrapper() : LoopPass(ID), OS(dbgs()) {} PrintLoopPassWrapper(raw_ostream &OS, const std::string &Banner) - : LoopPass(ID), P(OS, Banner) {} + : LoopPass(ID), OS(OS), Banner(Banner) {} void getAnalysisUsage(AnalysisUsage &AU) const override { AU.setPreservesAll(); @@ -49,8 +50,7 @@ public: [](BasicBlock *BB) { return BB; }); if (BBI != L->blocks().end() && isFunctionInPrintList((*BBI)->getParent()->getName())) { - LoopAnalysisManager DummyLAM; - P.run(*L, DummyLAM); + printLoop(*L, OS, Banner); } return false; } diff --git a/lib/Analysis/LoopPassManager.cpp b/lib/Analysis/LoopPassManager.cpp deleted file mode 100644 index 044e5d55dafd..000000000000 --- a/lib/Analysis/LoopPassManager.cpp +++ /dev/null @@ -1,59 +0,0 @@ -//===- LoopPassManager.cpp - Loop pass management -------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "llvm/Analysis/LoopPassManager.h" -#include "llvm/Analysis/BasicAliasAnalysis.h" -#include "llvm/Analysis/GlobalsModRef.h" -#include "llvm/Analysis/LoopInfo.h" -#include "llvm/Analysis/ScalarEvolution.h" -#include "llvm/Analysis/ScalarEvolutionAliasAnalysis.h" -#include "llvm/IR/Dominators.h" - -using namespace llvm; - -// Explicit template instantiations and specialization defininitions for core -// template typedefs. -namespace llvm { -template class PassManager; -template class AnalysisManager; -template class InnerAnalysisManagerProxy; -template class OuterAnalysisManagerProxy; - -template <> -bool LoopAnalysisManagerFunctionProxy::Result::invalidate( - Function &F, const PreservedAnalyses &PA, - FunctionAnalysisManager::Invalidator &Inv) { - // If this proxy isn't marked as preserved, the set of Function objects in - // the module may have changed. We therefore can't call - // InnerAM->invalidate(), because any pointers to Functions it has may be - // stale. - auto PAC = PA.getChecker(); - if (!PAC.preserved() && !PAC.preservedSet>()) - InnerAM->clear(); - - // FIXME: Proper suppor for invalidation isn't yet implemented for the LPM. - - // Return false to indicate that this result is still a valid proxy. - return false; -} -} - -PreservedAnalyses llvm::getLoopPassPreservedAnalyses() { - PreservedAnalyses PA; - PA.preserve(); - PA.preserve(); - PA.preserve(); - // TODO: What we really want to do here is preserve an AA category, but that - // concept doesn't exist yet. - PA.preserve(); - PA.preserve(); - PA.preserve(); - PA.preserve(); - return PA; -} diff --git a/lib/Analysis/MemoryDependenceAnalysis.cpp b/lib/Analysis/MemoryDependenceAnalysis.cpp index e7415e623196..66a0d145dcd8 100644 --- a/lib/Analysis/MemoryDependenceAnalysis.cpp +++ b/lib/Analysis/MemoryDependenceAnalysis.cpp @@ -323,17 +323,28 @@ MemDepResult MemoryDependenceResults::getPointerDependencyFrom( const MemoryLocation &MemLoc, bool isLoad, BasicBlock::iterator ScanIt, BasicBlock *BB, Instruction *QueryInst, unsigned *Limit) { + MemDepResult InvariantGroupDependency = MemDepResult::getUnknown(); if (QueryInst != nullptr) { if (auto *LI = dyn_cast(QueryInst)) { - MemDepResult invariantGroupDependency = - getInvariantGroupPointerDependency(LI, BB); + InvariantGroupDependency = getInvariantGroupPointerDependency(LI, BB); - if (invariantGroupDependency.isDef()) - return invariantGroupDependency; + if (InvariantGroupDependency.isDef()) + return InvariantGroupDependency; } } - return getSimplePointerDependencyFrom(MemLoc, isLoad, ScanIt, BB, QueryInst, - Limit); + MemDepResult SimpleDep = getSimplePointerDependencyFrom( + MemLoc, isLoad, ScanIt, BB, QueryInst, Limit); + if (SimpleDep.isDef()) + return SimpleDep; + // Non-local invariant group dependency indicates there is non local Def + // (it only returns nonLocal if it finds nonLocal def), which is better than + // local clobber and everything else. + if (InvariantGroupDependency.isNonLocal()) + return InvariantGroupDependency; + + assert(InvariantGroupDependency.isUnknown() && + "InvariantGroupDependency should be only unknown at this point"); + return SimpleDep; } MemDepResult @@ -358,6 +369,20 @@ MemoryDependenceResults::getInvariantGroupPointerDependency(LoadInst *LI, // Queue to process all pointers that are equivalent to load operand. SmallVector LoadOperandsQueue; LoadOperandsQueue.push_back(LoadOperand); + + Instruction *ClosestDependency = nullptr; + // Order of instructions in uses list is unpredictible. In order to always + // get the same result, we will look for the closest dominance. + auto GetClosestDependency = [this](Instruction *Best, Instruction *Other) { + assert(Other && "Must call it with not null instruction"); + if (Best == nullptr || DT.dominates(Best, Other)) + return Other; + return Best; + }; + + + // FIXME: This loop is O(N^2) because dominates can be O(n) and in worst case + // we will see all the instructions. This should be fixed in MSSA. while (!LoadOperandsQueue.empty()) { const Value *Ptr = LoadOperandsQueue.pop_back_val(); assert(Ptr && !isa(Ptr) && @@ -388,12 +413,24 @@ MemoryDependenceResults::getInvariantGroupPointerDependency(LoadInst *LI, // If we hit load/store with the same invariant.group metadata (and the // same pointer operand) we can assume that value pointed by pointer // operand didn't change. - if ((isa(U) || isa(U)) && U->getParent() == BB && + if ((isa(U) || isa(U)) && U->getMetadata(LLVMContext::MD_invariant_group) == InvariantGroupMD) - return MemDepResult::getDef(U); + ClosestDependency = GetClosestDependency(ClosestDependency, U); } } - return MemDepResult::getUnknown(); + + if (!ClosestDependency) + return MemDepResult::getUnknown(); + if (ClosestDependency->getParent() == BB) + return MemDepResult::getDef(ClosestDependency); + // Def(U) can't be returned here because it is non-local. If local + // dependency won't be found then return nonLocal counting that the + // user will call getNonLocalPointerDependency, which will return cached + // result. + NonLocalDefsCache.try_emplace( + LI, NonLocalDepResult(ClosestDependency->getParent(), + MemDepResult::getDef(ClosestDependency), nullptr)); + return MemDepResult::getNonLocal(); } MemDepResult MemoryDependenceResults::getSimplePointerDependencyFrom( @@ -877,7 +914,17 @@ void MemoryDependenceResults::getNonLocalPointerDependency( assert(Loc.Ptr->getType()->isPointerTy() && "Can't get pointer deps of a non-pointer!"); Result.clear(); - + { + // Check if there is cached Def with invariant.group. FIXME: cache might be + // invalid if cached instruction would be removed between call to + // getPointerDependencyFrom and this function. + auto NonLocalDefIt = NonLocalDefsCache.find(QueryInst); + if (NonLocalDefIt != NonLocalDefsCache.end()) { + Result.push_back(std::move(NonLocalDefIt->second)); + NonLocalDefsCache.erase(NonLocalDefIt); + return; + } + } // This routine does not expect to deal with volatile instructions. // Doing so would require piping through the QueryInst all the way through. // TODO: volatiles can't be elided, but they can be reordered with other diff --git a/lib/Analysis/ScalarEvolution.cpp b/lib/Analysis/ScalarEvolution.cpp index 44f1a6dde0d2..b3905cc01e84 100644 --- a/lib/Analysis/ScalarEvolution.cpp +++ b/lib/Analysis/ScalarEvolution.cpp @@ -7032,20 +7032,21 @@ static const SCEV *SolveLinEquationWithOverflow(const APInt &A, const APInt &B, // 3. Compute I: the multiplicative inverse of (A / D) in arithmetic // modulo (N / D). // - // (N / D) may need BW+1 bits in its representation. Hence, we'll use this - // bit width during computations. + // If D == 1, (N / D) == N == 2^BW, so we need one extra bit to represent + // (N / D) in general. The inverse itself always fits into BW bits, though, + // so we immediately truncate it. APInt AD = A.lshr(Mult2).zext(BW + 1); // AD = A / D APInt Mod(BW + 1, 0); Mod.setBit(BW - Mult2); // Mod = N / D - APInt I = AD.multiplicativeInverse(Mod); + APInt I = AD.multiplicativeInverse(Mod).trunc(BW); // 4. Compute the minimum unsigned root of the equation: // I * (B / D) mod (N / D) - APInt Result = (I * B.lshr(Mult2).zext(BW + 1)).urem(Mod); + // To simplify the computation, we factor out the divide by D: + // (I * B mod N) / D + APInt Result = (I * B).lshr(Mult2); - // The result is guaranteed to be less than 2^BW so we may truncate it to BW - // bits. - return SE.getConstant(Result.trunc(BW)); + return SE.getConstant(Result); } /// Find the roots of the quadratic equation for the given quadratic chrec @@ -7206,17 +7207,25 @@ ScalarEvolution::howFarToZero(const SCEV *V, const Loop *L, bool ControlsExit, // 1*N = -Start; -1*N = Start (mod 2^BW), so: // N = Distance (as unsigned) if (StepC->getValue()->equalsInt(1) || StepC->getValue()->isAllOnesValue()) { - ConstantRange CR = getUnsignedRange(Start); - const SCEV *MaxBECount; - if (!CountDown && CR.getUnsignedMin().isMinValue()) - // When counting up, the worst starting value is 1, not 0. - MaxBECount = CR.getUnsignedMax().isMinValue() - ? getConstant(APInt::getMinValue(CR.getBitWidth())) - : getConstant(APInt::getMaxValue(CR.getBitWidth())); - else - MaxBECount = getConstant(CountDown ? CR.getUnsignedMax() - : -CR.getUnsignedMin()); - return ExitLimit(Distance, MaxBECount, false, Predicates); + APInt MaxBECount = getUnsignedRange(Distance).getUnsignedMax(); + + // When a loop like "for (int i = 0; i != n; ++i) { /* body */ }" is rotated, + // we end up with a loop whose backedge-taken count is n - 1. Detect this + // case, and see if we can improve the bound. + // + // Explicitly handling this here is necessary because getUnsignedRange + // isn't context-sensitive; it doesn't know that we only care about the + // range inside the loop. + const SCEV *Zero = getZero(Distance->getType()); + const SCEV *One = getOne(Distance->getType()); + const SCEV *DistancePlusOne = getAddExpr(Distance, One); + if (isLoopEntryGuardedByCond(L, ICmpInst::ICMP_NE, DistancePlusOne, Zero)) { + // If Distance + 1 doesn't overflow, we can compute the maximum distance + // as "unsigned_max(Distance + 1) - 1". + ConstantRange CR = getUnsignedRange(DistancePlusOne); + MaxBECount = APIntOps::umin(MaxBECount, CR.getUnsignedMax() - 1); + } + return ExitLimit(Distance, getConstant(MaxBECount), false, Predicates); } // As a special case, handle the instance where Step is a positive power of diff --git a/lib/Analysis/TargetTransformInfo.cpp b/lib/Analysis/TargetTransformInfo.cpp index cd8c24630df1..5c0d1aac1b98 100644 --- a/lib/Analysis/TargetTransformInfo.cpp +++ b/lib/Analysis/TargetTransformInfo.cpp @@ -277,9 +277,10 @@ unsigned TargetTransformInfo::getMaxInterleaveFactor(unsigned VF) const { int TargetTransformInfo::getArithmeticInstrCost( unsigned Opcode, Type *Ty, OperandValueKind Opd1Info, OperandValueKind Opd2Info, OperandValueProperties Opd1PropInfo, - OperandValueProperties Opd2PropInfo) const { + OperandValueProperties Opd2PropInfo, + ArrayRef Args) const { int Cost = TTIImpl->getArithmeticInstrCost(Opcode, Ty, Opd1Info, Opd2Info, - Opd1PropInfo, Opd2PropInfo); + Opd1PropInfo, Opd2PropInfo, Args); assert(Cost >= 0 && "TTI should not produce negative costs!"); return Cost; } diff --git a/lib/Analysis/ValueTracking.cpp b/lib/Analysis/ValueTracking.cpp index d31472c0d33c..b79370baad10 100644 --- a/lib/Analysis/ValueTracking.cpp +++ b/lib/Analysis/ValueTracking.cpp @@ -526,7 +526,10 @@ static void computeKnownBitsFromAssume(const Value *V, APInt &KnownZero, unsigned BitWidth = KnownZero.getBitWidth(); - for (auto &AssumeVH : Q.AC->assumptions()) { + // Note that the patterns below need to be kept in sync with the code + // in AssumptionCache::updateAffectedValues. + + for (auto &AssumeVH : Q.AC->assumptionsFor(V)) { if (!AssumeVH) continue; CallInst *I = cast(AssumeVH); @@ -2580,51 +2583,70 @@ bool llvm::CannotBeNegativeZero(const Value *V, const TargetLibraryInfo *TLI, return false; } -bool llvm::CannotBeOrderedLessThanZero(const Value *V, - const TargetLibraryInfo *TLI, - unsigned Depth) { - if (const ConstantFP *CFP = dyn_cast(V)) - return !CFP->getValueAPF().isNegative() || CFP->getValueAPF().isZero(); +/// If \p SignBitOnly is true, test for a known 0 sign bit rather than a +/// standard ordered compare. e.g. make -0.0 olt 0.0 be true because of the sign +/// bit despite comparing equal. +static bool cannotBeOrderedLessThanZeroImpl(const Value *V, + const TargetLibraryInfo *TLI, + bool SignBitOnly, + unsigned Depth) { + if (const ConstantFP *CFP = dyn_cast(V)) { + return !CFP->getValueAPF().isNegative() || + (!SignBitOnly && CFP->getValueAPF().isZero()); + } if (Depth == MaxDepth) - return false; // Limit search depth. + return false; // Limit search depth. const Operator *I = dyn_cast(V); - if (!I) return false; + if (!I) + return false; switch (I->getOpcode()) { - default: break; + default: + break; // Unsigned integers are always nonnegative. case Instruction::UIToFP: return true; case Instruction::FMul: // x*x is always non-negative or a NaN. - if (I->getOperand(0) == I->getOperand(1)) + if (I->getOperand(0) == I->getOperand(1) && + (!SignBitOnly || cast(I)->hasNoNaNs())) return true; + LLVM_FALLTHROUGH; case Instruction::FAdd: case Instruction::FDiv: case Instruction::FRem: - return CannotBeOrderedLessThanZero(I->getOperand(0), TLI, Depth + 1) && - CannotBeOrderedLessThanZero(I->getOperand(1), TLI, Depth + 1); + return cannotBeOrderedLessThanZeroImpl(I->getOperand(0), TLI, SignBitOnly, + Depth + 1) && + cannotBeOrderedLessThanZeroImpl(I->getOperand(1), TLI, SignBitOnly, + Depth + 1); case Instruction::Select: - return CannotBeOrderedLessThanZero(I->getOperand(1), TLI, Depth + 1) && - CannotBeOrderedLessThanZero(I->getOperand(2), TLI, Depth + 1); + return cannotBeOrderedLessThanZeroImpl(I->getOperand(1), TLI, SignBitOnly, + Depth + 1) && + cannotBeOrderedLessThanZeroImpl(I->getOperand(2), TLI, SignBitOnly, + Depth + 1); case Instruction::FPExt: case Instruction::FPTrunc: // Widening/narrowing never change sign. - return CannotBeOrderedLessThanZero(I->getOperand(0), TLI, Depth + 1); + return cannotBeOrderedLessThanZeroImpl(I->getOperand(0), TLI, SignBitOnly, + Depth + 1); case Instruction::Call: Intrinsic::ID IID = getIntrinsicForCallSite(cast(I), TLI); switch (IID) { default: break; case Intrinsic::maxnum: - return CannotBeOrderedLessThanZero(I->getOperand(0), TLI, Depth + 1) || - CannotBeOrderedLessThanZero(I->getOperand(1), TLI, Depth + 1); + return cannotBeOrderedLessThanZeroImpl(I->getOperand(0), TLI, SignBitOnly, + Depth + 1) || + cannotBeOrderedLessThanZeroImpl(I->getOperand(1), TLI, SignBitOnly, + Depth + 1); case Intrinsic::minnum: - return CannotBeOrderedLessThanZero(I->getOperand(0), TLI, Depth + 1) && - CannotBeOrderedLessThanZero(I->getOperand(1), TLI, Depth + 1); + return cannotBeOrderedLessThanZeroImpl(I->getOperand(0), TLI, SignBitOnly, + Depth + 1) && + cannotBeOrderedLessThanZeroImpl(I->getOperand(1), TLI, SignBitOnly, + Depth + 1); case Intrinsic::exp: case Intrinsic::exp2: case Intrinsic::fabs: @@ -2636,18 +2658,30 @@ bool llvm::CannotBeOrderedLessThanZero(const Value *V, if (CI->getBitWidth() <= 64 && CI->getSExtValue() % 2u == 0) return true; } - return CannotBeOrderedLessThanZero(I->getOperand(0), TLI, Depth + 1); + return cannotBeOrderedLessThanZeroImpl(I->getOperand(0), TLI, SignBitOnly, + Depth + 1); case Intrinsic::fma: case Intrinsic::fmuladd: // x*x+y is non-negative if y is non-negative. return I->getOperand(0) == I->getOperand(1) && - CannotBeOrderedLessThanZero(I->getOperand(2), TLI, Depth + 1); + (!SignBitOnly || cast(I)->hasNoNaNs()) && + cannotBeOrderedLessThanZeroImpl(I->getOperand(2), TLI, SignBitOnly, + Depth + 1); } break; } return false; } +bool llvm::CannotBeOrderedLessThanZero(const Value *V, + const TargetLibraryInfo *TLI) { + return cannotBeOrderedLessThanZeroImpl(V, TLI, false, 0); +} + +bool llvm::SignBitMustBeZero(const Value *V, const TargetLibraryInfo *TLI) { + return cannotBeOrderedLessThanZeroImpl(V, TLI, true, 0); +} + /// If the specified value can be set by repeating the same byte in memory, /// return the i8 value that it is represented with. This is /// true for all i8 values obviously, but is also true for i32 0, i32 -1, diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 54aa0a9e3282..76549540ce0f 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -22,3 +22,4 @@ add_subdirectory(ProfileData) add_subdirectory(Fuzzer) add_subdirectory(Passes) add_subdirectory(LibDriver) +add_subdirectory(XRay) diff --git a/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp b/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp index 408b34a3cdc0..83440513225c 100644 --- a/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp +++ b/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp @@ -13,11 +13,13 @@ #include "CodeViewDebug.h" #include "llvm/ADT/TinyPtrVector.h" +#include "llvm/DebugInfo/CodeView/CVTypeDumper.h" #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" #include "llvm/DebugInfo/CodeView/CodeView.h" #include "llvm/DebugInfo/CodeView/Line.h" #include "llvm/DebugInfo/CodeView/SymbolRecord.h" -#include "llvm/DebugInfo/CodeView/TypeDumper.h" +#include "llvm/DebugInfo/CodeView/TypeDatabase.h" +#include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h" #include "llvm/DebugInfo/CodeView/TypeIndex.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" #include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h" @@ -467,7 +469,8 @@ void CodeViewDebug::emitTypeInformation() { CommentPrefix += ' '; } - CVTypeDumper CVTD(nullptr, /*PrintRecordBytes=*/false); + TypeDatabase TypeDB; + CVTypeDumper CVTD(TypeDB); TypeTable.ForEachRecord([&](TypeIndex Index, ArrayRef Record) { if (OS.isVerboseAsm()) { // Emit a block comment describing the type record for readability. @@ -475,8 +478,8 @@ void CodeViewDebug::emitTypeInformation() { raw_svector_ostream CommentOS(CommentBlock); ScopedPrinter SP(CommentOS); SP.setPrefix(CommentPrefix); - CVTD.setPrinter(&SP); - Error E = CVTD.dump(Record); + TypeDumpVisitor TDV(TypeDB, &SP, false); + Error E = CVTD.dump(Record, TDV); if (E) { logAllUnhandledErrors(std::move(E), errs(), "error: "); llvm_unreachable("produced malformed type record"); diff --git a/lib/CodeGen/AsmPrinter/DIE.cpp b/lib/CodeGen/AsmPrinter/DIE.cpp index 8ae2f2487cad..a8a3b30d5b60 100644 --- a/lib/CodeGen/AsmPrinter/DIE.cpp +++ b/lib/CodeGen/AsmPrinter/DIE.cpp @@ -79,6 +79,13 @@ void DIEAbbrev::Emit(const AsmPrinter *AP) const { // Emit form type. AP->EmitULEB128(AttrData.getForm(), dwarf::FormEncodingString(AttrData.getForm()).data()); + + // Emit value for DW_FORM_implicit_const. + if (AttrData.getForm() == dwarf::DW_FORM_implicit_const) { + assert(AP->getDwarfVersion() >= 5 && + "DW_FORM_implicit_const is supported starting from DWARFv5"); + AP->EmitSLEB128(AttrData.getValue()); + } } // Mark end of abbreviation. @@ -160,7 +167,11 @@ DIE *DIE::getParent() const { DIEAbbrev DIE::generateAbbrev() const { DIEAbbrev Abbrev(Tag, hasChildren()); for (const DIEValue &V : values()) - Abbrev.AddAttribute(V.getAttribute(), V.getForm()); + if (V.getForm() == dwarf::DW_FORM_implicit_const) + Abbrev.AddImplicitConstAttribute(V.getAttribute(), + V.getDIEInteger().getValue()); + else + Abbrev.AddAttribute(V.getAttribute(), V.getForm()); return Abbrev; } @@ -342,6 +353,8 @@ void DIEValue::dump() const { /// void DIEInteger::EmitValue(const AsmPrinter *Asm, dwarf::Form Form) const { switch (Form) { + case dwarf::DW_FORM_implicit_const: + LLVM_FALLTHROUGH; case dwarf::DW_FORM_flag_present: // Emit something to keep the lines and comments in sync. // FIXME: Is there a better way to do this? @@ -406,6 +419,7 @@ void DIEInteger::EmitValue(const AsmPrinter *Asm, dwarf::Form Form) const { /// unsigned DIEInteger::SizeOf(const AsmPrinter *AP, dwarf::Form Form) const { switch (Form) { + case dwarf::DW_FORM_implicit_const: LLVM_FALLTHROUGH; case dwarf::DW_FORM_flag_present: return 0; case dwarf::DW_FORM_flag: LLVM_FALLTHROUGH; case dwarf::DW_FORM_ref1: LLVM_FALLTHROUGH; diff --git a/lib/CodeGen/AsmPrinter/DwarfUnit.cpp b/lib/CodeGen/AsmPrinter/DwarfUnit.cpp index 4f90245c6d49..2a866c071f59 100644 --- a/lib/CodeGen/AsmPrinter/DwarfUnit.cpp +++ b/lib/CodeGen/AsmPrinter/DwarfUnit.cpp @@ -200,6 +200,8 @@ void DwarfUnit::addUInt(DIEValueList &Die, dwarf::Attribute Attribute, Optional Form, uint64_t Integer) { if (!Form) Form = DIEInteger::BestForm(false, Integer); + assert(Form != dwarf::DW_FORM_implicit_const && + "DW_FORM_implicit_const is used only for signed integers"); Die.addValue(DIEValueAllocator, Attribute, *Form, DIEInteger(Integer)); } diff --git a/lib/CodeGen/GlobalISel/RegBankSelect.cpp b/lib/CodeGen/GlobalISel/RegBankSelect.cpp index 04bb7ca5ba9e..cc026ef27296 100644 --- a/lib/CodeGen/GlobalISel/RegBankSelect.cpp +++ b/lib/CodeGen/GlobalISel/RegBankSelect.cpp @@ -223,6 +223,7 @@ RegisterBankInfo::InstructionMapping &RegBankSelect::findBestMapping( for (RegisterBankInfo::InstructionMapping &CurMapping : PossibleMappings) { MappingCost CurCost = computeMapping(MI, CurMapping, LocalRepairPts, &Cost); if (CurCost < Cost) { + DEBUG(dbgs() << "New best: " << CurCost << '\n'); Cost = CurCost; BestMapping = &CurMapping; RepairPts.clear(); @@ -377,8 +378,10 @@ RegBankSelect::MappingCost RegBankSelect::computeMapping( DEBUG(dbgs() << "Evaluating mapping cost for: " << MI); DEBUG(dbgs() << "With: " << InstrMapping << '\n'); RepairPts.clear(); - if (BestCost && Cost > *BestCost) + if (BestCost && Cost > *BestCost) { + DEBUG(dbgs() << "Mapping is too expensive from the start\n"); return Cost; + } // Moreover, to realize this mapping, the register bank of each operand must // match this mapping. In other words, we may need to locally reassign the @@ -392,17 +395,17 @@ RegBankSelect::MappingCost RegBankSelect::computeMapping( unsigned Reg = MO.getReg(); if (!Reg) continue; - DEBUG(dbgs() << "Opd" << OpIdx); + DEBUG(dbgs() << "Opd" << OpIdx << '\n'); const RegisterBankInfo::ValueMapping &ValMapping = InstrMapping.getOperandMapping(OpIdx); // If Reg is already properly mapped, this is free. bool Assign; if (assignmentMatch(Reg, ValMapping, Assign)) { - DEBUG(dbgs() << " is free (match).\n"); + DEBUG(dbgs() << "=> is free (match).\n"); continue; } if (Assign) { - DEBUG(dbgs() << " is free (simple assignment).\n"); + DEBUG(dbgs() << "=> is free (simple assignment).\n"); RepairPts.emplace_back(RepairingPlacement(MI, OpIdx, *TRI, *this, RepairingPlacement::Reassign)); continue; @@ -420,8 +423,10 @@ RegBankSelect::MappingCost RegBankSelect::computeMapping( tryAvoidingSplit(RepairPt, MO, ValMapping); // Check that the materialization of the repairing is possible. - if (!RepairPt.canMaterialize()) + if (!RepairPt.canMaterialize()) { + DEBUG(dbgs() << "Mapping involves impossible repairing\n"); return MappingCost::ImpossibleCost(); + } // Account for the split cost and repair cost. // Unless the cost is already saturated or we do not care about the cost. @@ -476,8 +481,10 @@ RegBankSelect::MappingCost RegBankSelect::computeMapping( // Stop looking into what it takes to repair, this is already // too expensive. - if (BestCost && Cost > *BestCost) + if (BestCost && Cost > *BestCost) { + DEBUG(dbgs() << "Mapping is too expensive, stop processing\n"); return Cost; + } // No need to accumulate more cost information. // We need to still gather the repairing information though. @@ -485,6 +492,7 @@ RegBankSelect::MappingCost RegBankSelect::computeMapping( break; } } + DEBUG(dbgs() << "Total cost is: " << Cost << "\n"); return Cost; } @@ -550,7 +558,7 @@ bool RegBankSelect::assignInstr(MachineInstr &MI) { // Make sure the mapping is valid for MI. assert(BestMapping.verify(MI) && "Invalid instruction mapping"); - DEBUG(dbgs() << "Mapping: " << BestMapping << '\n'); + DEBUG(dbgs() << "Best Mapping: " << BestMapping << '\n'); // After this call, MI may not be valid anymore. // Do not use it. @@ -959,3 +967,20 @@ bool RegBankSelect::MappingCost::operator==(const MappingCost &Cost) const { return LocalCost == Cost.LocalCost && NonLocalCost == Cost.NonLocalCost && LocalFreq == Cost.LocalFreq; } + +void RegBankSelect::MappingCost::dump() const { + print(dbgs()); + dbgs() << '\n'; +} + +void RegBankSelect::MappingCost::print(raw_ostream &OS) const { + if (*this == ImpossibleCost()) { + OS << "impossible"; + return; + } + if (isSaturated()) { + OS << "saturated"; + return; + } + OS << LocalFreq << " * " << LocalCost << " + " << NonLocalCost; +} diff --git a/lib/CodeGen/GlobalISel/RegisterBank.cpp b/lib/CodeGen/GlobalISel/RegisterBank.cpp index 0ffc08188ead..49d676f11da6 100644 --- a/lib/CodeGen/GlobalISel/RegisterBank.cpp +++ b/lib/CodeGen/GlobalISel/RegisterBank.cpp @@ -19,12 +19,15 @@ using namespace llvm; const unsigned RegisterBank::InvalidID = UINT_MAX; -RegisterBank::RegisterBank() : ID(InvalidID), Name(nullptr), Size(0) {} +RegisterBank::RegisterBank(unsigned ID, const char *Name, unsigned Size, + const uint32_t *CoveredClasses) + : ID(ID), Name(Name), Size(Size) { + ContainedRegClasses.resize(200); + ContainedRegClasses.setBitsInMask(CoveredClasses); +} bool RegisterBank::verify(const TargetRegisterInfo &TRI) const { assert(isValid() && "Invalid register bank"); - assert(ContainedRegClasses.size() == TRI.getNumRegClasses() && - "TRI does not match the initialization process?"); for (unsigned RCId = 0, End = TRI.getNumRegClasses(); RCId != End; ++RCId) { const TargetRegisterClass &RC = *TRI.getRegClass(RCId); diff --git a/lib/CodeGen/GlobalISel/RegisterBankInfo.cpp b/lib/CodeGen/GlobalISel/RegisterBankInfo.cpp index 7d405dd92ac3..da5ab0b9fb7b 100644 --- a/lib/CodeGen/GlobalISel/RegisterBankInfo.cpp +++ b/lib/CodeGen/GlobalISel/RegisterBankInfo.cpp @@ -56,8 +56,10 @@ RegisterBankInfo::RegisterBankInfo(RegisterBank **RegBanks, unsigned NumRegBanks) : RegBanks(RegBanks), NumRegBanks(NumRegBanks) { #ifndef NDEBUG - for (unsigned Idx = 0, End = getNumRegBanks(); Idx != End; ++Idx) + for (unsigned Idx = 0, End = getNumRegBanks(); Idx != End; ++Idx) { assert(RegBanks[Idx] != nullptr && "Invalid RegisterBank"); + assert(RegBanks[Idx]->isValid() && "RegisterBank should be valid"); + } #endif // NDEBUG } @@ -74,116 +76,13 @@ bool RegisterBankInfo::verify(const TargetRegisterInfo &TRI) const { const RegisterBank &RegBank = getRegBank(Idx); assert(Idx == RegBank.getID() && "ID does not match the index in the array"); - dbgs() << "Verify " << RegBank << '\n'; + DEBUG(dbgs() << "Verify " << RegBank << '\n'); assert(RegBank.verify(TRI) && "RegBank is invalid"); } #endif // NDEBUG return true; } -void RegisterBankInfo::createRegisterBank(unsigned ID, const char *Name) { - DEBUG(dbgs() << "Create register bank: " << ID << " with name \"" << Name - << "\"\n"); - RegisterBank &RegBank = getRegBank(ID); - assert(RegBank.getID() == RegisterBank::InvalidID && - "A register bank should be created only once"); - RegBank.ID = ID; - RegBank.Name = Name; -} - -void RegisterBankInfo::addRegBankCoverage(unsigned ID, unsigned RCId, - const TargetRegisterInfo &TRI) { - RegisterBank &RB = getRegBank(ID); - unsigned NbOfRegClasses = TRI.getNumRegClasses(); - - DEBUG(dbgs() << "Add coverage for: " << RB << '\n'); - - // Check if RB is underconstruction. - if (!RB.isValid()) - RB.ContainedRegClasses.resize(NbOfRegClasses); - else if (RB.covers(*TRI.getRegClass(RCId))) - // If RB already covers this register class, there is nothing - // to do. - return; - - BitVector &Covered = RB.ContainedRegClasses; - SmallVector WorkList; - - WorkList.push_back(RCId); - Covered.set(RCId); - - unsigned &MaxSize = RB.Size; - do { - unsigned RCId = WorkList.pop_back_val(); - - const TargetRegisterClass &CurRC = *TRI.getRegClass(RCId); - - DEBUG(dbgs() << "Examine: " << TRI.getRegClassName(&CurRC) - << "(Size*8: " << (CurRC.getSize() * 8) << ")\n"); - - // Remember the biggest size in bits. - MaxSize = std::max(MaxSize, CurRC.getSize() * 8); - - // Walk through all sub register classes and push them into the worklist. - bool First = true; - for (BitMaskClassIterator It(CurRC.getSubClassMask(), TRI); It.isValid(); - ++It) { - unsigned SubRCId = It.getID(); - if (!Covered.test(SubRCId)) { - if (First) - DEBUG(dbgs() << " Enqueue sub-class: "); - DEBUG(dbgs() << TRI.getRegClassName(TRI.getRegClass(SubRCId)) << ", "); - WorkList.push_back(SubRCId); - // Remember that we saw the sub class. - Covered.set(SubRCId); - First = false; - } - } - if (!First) - DEBUG(dbgs() << '\n'); - - // Push also all the register classes that can be accessed via a - // subreg index, i.e., its subreg-class (which is different than - // its subclass). - // - // Note: It would probably be faster to go the other way around - // and have this method add only super classes, since this - // information is available in a more efficient way. However, it - // feels less natural for the client of this APIs plus we will - // TableGen the whole bitset at some point, so compile time for - // the initialization is not very important. - First = true; - for (unsigned SubRCId = 0; SubRCId < NbOfRegClasses; ++SubRCId) { - if (Covered.test(SubRCId)) - continue; - bool Pushed = false; - const TargetRegisterClass *SubRC = TRI.getRegClass(SubRCId); - for (SuperRegClassIterator SuperRCIt(SubRC, &TRI); SuperRCIt.isValid(); - ++SuperRCIt) { - if (Pushed) - break; - for (BitMaskClassIterator It(SuperRCIt.getMask(), TRI); It.isValid(); - ++It) { - unsigned SuperRCId = It.getID(); - if (SuperRCId == RCId) { - if (First) - DEBUG(dbgs() << " Enqueue subreg-class: "); - DEBUG(dbgs() << TRI.getRegClassName(SubRC) << ", "); - WorkList.push_back(SubRCId); - // Remember that we saw the sub class. - Covered.set(SubRCId); - Pushed = true; - First = false; - break; - } - } - } - } - if (!First) - DEBUG(dbgs() << '\n'); - } while (!WorkList.empty()); -} - const RegisterBank * RegisterBankInfo::getRegBank(unsigned Reg, const MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI) const { diff --git a/lib/CodeGen/MachineInstr.cpp b/lib/CodeGen/MachineInstr.cpp index d2ce001103df..2f2e3b3d8e9f 100644 --- a/lib/CodeGen/MachineInstr.cpp +++ b/lib/CodeGen/MachineInstr.cpp @@ -1840,7 +1840,8 @@ void MachineInstr::print(raw_ostream &OS, ModuleSlotTracker &MST, OS << "!\"" << DIV->getName() << '\"'; else MO.print(OS, MST, TRI); - } else if (TRI && (isInsertSubreg() || isRegSequence()) && MO.isImm()) { + } else if (TRI && (isInsertSubreg() || isRegSequence() || + (isSubregToReg() && i == 3)) && MO.isImm()) { OS << TRI->getSubRegIndexName(MO.getImm()); } else if (i == AsmDescOp && MO.isImm()) { // Pretty print the inline asm operand descriptor. diff --git a/lib/CodeGen/PeepholeOptimizer.cpp b/lib/CodeGen/PeepholeOptimizer.cpp index 11af50fe577c..6d643457e9a9 100644 --- a/lib/CodeGen/PeepholeOptimizer.cpp +++ b/lib/CodeGen/PeepholeOptimizer.cpp @@ -1715,7 +1715,8 @@ ValueTrackerResult ValueTracker::getNextSourceFromBitcast() { // Bitcasts with more than one def are not supported. if (Def->getDesc().getNumDefs() != 1) return ValueTrackerResult(); - if (Def->getOperand(DefIdx).getSubReg() != DefSubReg) + const MachineOperand DefOp = Def->getOperand(DefIdx); + if (DefOp.getSubReg() != DefSubReg) // If we look for a different subreg, it means we want a subreg of the src. // Bails as we do not support composing subregs yet. return ValueTrackerResult(); @@ -1735,6 +1736,14 @@ ValueTrackerResult ValueTracker::getNextSourceFromBitcast() { return ValueTrackerResult(); SrcIdx = OpIdx; } + + // Stop when any user of the bitcast is a SUBREG_TO_REG, replacing with a COPY + // will break the assumed guarantees for the upper bits. + for (const MachineInstr &UseMI : MRI.use_nodbg_instructions(DefOp.getReg())) { + if (UseMI.isSubregToReg()) + return ValueTrackerResult(); + } + const MachineOperand &Src = Def->getOperand(SrcIdx); return ValueTrackerResult(Src.getReg(), Src.getSubReg()); } diff --git a/lib/CodeGen/ScheduleDAG.cpp b/lib/CodeGen/ScheduleDAG.cpp index 1f0c3283ceb1..427d95268c74 100644 --- a/lib/CodeGen/ScheduleDAG.cpp +++ b/lib/CodeGen/ScheduleDAG.cpp @@ -310,19 +310,19 @@ void SUnit::biasCriticalPath() { } #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) -static void dumpSUIdentifier(const ScheduleDAG &DAG, const SUnit &SU) { - if (&SU == &DAG.ExitSU) - dbgs() << "ExitSU"; - else if (&SU == &DAG.EntrySU) - dbgs() << "EntrySU"; +void SUnit::print(raw_ostream &OS, const ScheduleDAG *DAG) const { + if (this == &DAG->ExitSU) + OS << "ExitSU"; + else if (this == &DAG->EntrySU) + OS << "EntrySU"; else - dbgs() << "SU(" << SU.NodeNum << ")"; + OS << "SU(" << NodeNum << ")"; } /// SUnit - Scheduling unit. It's an wrapper around either a single SDNode or /// a group of nodes flagged together. void SUnit::dump(const ScheduleDAG *G) const { - dumpSUIdentifier(*G, *this); + print(dbgs(), G); dbgs() << ": "; G->dumpNode(this); } @@ -352,7 +352,7 @@ void SUnit::dumpAll(const ScheduleDAG *G) const { case SDep::Output: dbgs() << "out "; break; case SDep::Order: dbgs() << "ord "; break; } - dumpSUIdentifier(*G, *I->getSUnit()); + I->getSUnit()->print(dbgs(), G); if (I->isArtificial()) dbgs() << " *"; dbgs() << ": Latency=" << I->getLatency(); @@ -372,7 +372,7 @@ void SUnit::dumpAll(const ScheduleDAG *G) const { case SDep::Output: dbgs() << "out "; break; case SDep::Order: dbgs() << "ord "; break; } - dumpSUIdentifier(*G, *I->getSUnit()); + I->getSUnit()->print(dbgs(), G); if (I->isArtificial()) dbgs() << " *"; dbgs() << ": Latency=" << I->getLatency(); diff --git a/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/lib/CodeGen/SelectionDAG/DAGCombiner.cpp index 4632484055d2..680f62fa91bc 100644 --- a/lib/CodeGen/SelectionDAG/DAGCombiner.cpp +++ b/lib/CodeGen/SelectionDAG/DAGCombiner.cpp @@ -5361,8 +5361,9 @@ SDValue DAGCombiner::visitSELECT(SDNode *N) { // fold (select false, X, Y) -> Y return !N0C->isNullValue() ? N1 : N2; } - // fold (select C, 1, X) -> (or C, X) - if (VT == MVT::i1 && isOneConstant(N1)) + // fold (select X, X, Y) -> (or X, Y) + // fold (select X, 1, Y) -> (or C, Y) + if (VT == VT0 && VT == MVT::i1 && (N0 == N1 || isOneConstant(N1))) return DAG.getNode(ISD::OR, SDLoc(N), VT, N0, N2); if (SDValue V = foldSelectOfConstants(N)) @@ -5380,16 +5381,9 @@ SDValue DAGCombiner::visitSELECT(SDNode *N) { AddToWorklist(NOTNode.getNode()); return DAG.getNode(ISD::OR, SDLoc(N), VT, NOTNode, N1); } - // fold (select C, X, 0) -> (and C, X) - if (VT == MVT::i1 && isNullConstant(N2)) - return DAG.getNode(ISD::AND, SDLoc(N), VT, N0, N1); - // fold (select X, X, Y) -> (or X, Y) - // fold (select X, 1, Y) -> (or X, Y) - if (VT == MVT::i1 && (N0 == N1 || isOneConstant(N1))) - return DAG.getNode(ISD::OR, SDLoc(N), VT, N0, N2); // fold (select X, Y, X) -> (and X, Y) // fold (select X, Y, 0) -> (and X, Y) - if (VT == MVT::i1 && (N0 == N2 || isNullConstant(N2))) + if (VT == VT0 && VT == MVT::i1 && (N0 == N2 || isNullConstant(N2))) return DAG.getNode(ISD::AND, SDLoc(N), VT, N0, N1); // If we can fold this based on the true/false value, do so. @@ -5470,7 +5464,6 @@ SDValue DAGCombiner::visitSELECT(SDNode *N) { } // select (xor Cond, 1), X, Y -> select Cond, Y, X - // select (xor Cond, 0), X, Y -> selext Cond, X, Y if (VT0 == MVT::i1) { if (N0->getOpcode() == ISD::XOR) { if (auto *C = dyn_cast(N0->getOperand(1))) { @@ -5478,9 +5471,6 @@ SDValue DAGCombiner::visitSELECT(SDNode *N) { if (C->isOne()) return DAG.getNode(ISD::SELECT, SDLoc(N), N1.getValueType(), Cond0, N2, N1); - else - return DAG.getNode(ISD::SELECT, SDLoc(N), N1.getValueType(), - Cond0, N1, N2); } } } @@ -8136,7 +8126,8 @@ SDValue DAGCombiner::visitFADDForFMACombine(SDNode *N) { if ((AllowFusion || HasFMAD) && Aggressive) { // fold (fadd (fma x, y, (fmul u, v)), z) -> (fma x, y (fma u, v, z)) if (N0.getOpcode() == PreferredFusedOpcode && - N0.getOperand(2).getOpcode() == ISD::FMUL) { + N0.getOperand(2).getOpcode() == ISD::FMUL && + N0->hasOneUse() && N0.getOperand(2)->hasOneUse()) { return DAG.getNode(PreferredFusedOpcode, SL, VT, N0.getOperand(0), N0.getOperand(1), DAG.getNode(PreferredFusedOpcode, SL, VT, @@ -8147,7 +8138,8 @@ SDValue DAGCombiner::visitFADDForFMACombine(SDNode *N) { // fold (fadd x, (fma y, z, (fmul u, v)) -> (fma y, z (fma u, v, x)) if (N1->getOpcode() == PreferredFusedOpcode && - N1.getOperand(2).getOpcode() == ISD::FMUL) { + N1.getOperand(2).getOpcode() == ISD::FMUL && + N1->hasOneUse() && N1.getOperand(2)->hasOneUse()) { return DAG.getNode(PreferredFusedOpcode, SL, VT, N1.getOperand(0), N1.getOperand(1), DAG.getNode(PreferredFusedOpcode, SL, VT, @@ -8379,7 +8371,8 @@ SDValue DAGCombiner::visitFSUBForFMACombine(SDNode *N) { // fold (fsub (fma x, y, (fmul u, v)), z) // -> (fma x, y (fma u, v, (fneg z))) if (N0.getOpcode() == PreferredFusedOpcode && - N0.getOperand(2).getOpcode() == ISD::FMUL) { + N0.getOperand(2).getOpcode() == ISD::FMUL && + N0->hasOneUse() && N0.getOperand(2)->hasOneUse()) { return DAG.getNode(PreferredFusedOpcode, SL, VT, N0.getOperand(0), N0.getOperand(1), DAG.getNode(PreferredFusedOpcode, SL, VT, diff --git a/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp b/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp index 3485e35e6f5d..b0028252836a 100644 --- a/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp +++ b/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp @@ -330,8 +330,6 @@ SDValue SelectionDAGLegalize::PerformInsertVectorEltInMemory(SDValue Vec, // supported by the target. EVT VT = Tmp1.getValueType(); EVT EltVT = VT.getVectorElementType(); - EVT IdxVT = Tmp3.getValueType(); - EVT PtrVT = TLI.getPointerTy(DAG.getDataLayout()); SDValue StackPtr = DAG.CreateStackTemporary(VT); int SPFI = cast(StackPtr.getNode())->getIndex(); @@ -341,13 +339,8 @@ SDValue SelectionDAGLegalize::PerformInsertVectorEltInMemory(SDValue Vec, DAG.getEntryNode(), dl, Tmp1, StackPtr, MachinePointerInfo::getFixedStack(DAG.getMachineFunction(), SPFI)); - // Truncate or zero extend offset to target pointer type. - Tmp3 = DAG.getZExtOrTrunc(Tmp3, dl, PtrVT); - // Add the offset to the index. - unsigned EltSize = EltVT.getSizeInBits()/8; - Tmp3 = DAG.getNode(ISD::MUL, dl, IdxVT, Tmp3, - DAG.getConstant(EltSize, dl, IdxVT)); - SDValue StackPtr2 = DAG.getNode(ISD::ADD, dl, IdxVT, Tmp3, StackPtr); + SDValue StackPtr2 = TLI.getVectorElementPointer(DAG, StackPtr, VT, Tmp3); + // Store the scalar value. Ch = DAG.getTruncStore(Ch, dl, Tmp2, StackPtr2, MachinePointerInfo(), EltVT); // Load the updated vector. @@ -1209,20 +1202,16 @@ SDValue SelectionDAGLegalize::ExpandExtractFromVectorThroughStack(SDValue Op) { } } + EVT VecVT = Vec.getValueType(); + if (!Ch.getNode()) { // Store the value to a temporary stack slot, then LOAD the returned part. - StackPtr = DAG.CreateStackTemporary(Vec.getValueType()); + StackPtr = DAG.CreateStackTemporary(VecVT); Ch = DAG.getStore(DAG.getEntryNode(), dl, Vec, StackPtr, MachinePointerInfo()); } - // Add the offset to the index. - unsigned EltSize = Vec.getScalarValueSizeInBits() / 8; - Idx = DAG.getNode(ISD::MUL, dl, Idx.getValueType(), Idx, - DAG.getConstant(EltSize, SDLoc(Vec), Idx.getValueType())); - - Idx = DAG.getZExtOrTrunc(Idx, dl, TLI.getPointerTy(DAG.getDataLayout())); - StackPtr = DAG.getNode(ISD::ADD, dl, Idx.getValueType(), Idx, StackPtr); + StackPtr = TLI.getVectorElementPointer(DAG, StackPtr, VecVT, Idx); SDValue NewLoad; @@ -1232,7 +1221,7 @@ SDValue SelectionDAGLegalize::ExpandExtractFromVectorThroughStack(SDValue Op) { else NewLoad = DAG.getExtLoad(ISD::EXTLOAD, dl, Op.getValueType(), Ch, StackPtr, MachinePointerInfo(), - Vec.getValueType().getVectorElementType()); + VecVT.getVectorElementType()); // Replace the chain going out of the store, by the one out of the load. DAG.ReplaceAllUsesOfValueWith(Ch, SDValue(NewLoad.getNode(), 1)); @@ -1256,8 +1245,8 @@ SDValue SelectionDAGLegalize::ExpandInsertToVectorThroughStack(SDValue Op) { SDLoc dl(Op); // Store the value to a temporary stack slot, then LOAD the returned part. - - SDValue StackPtr = DAG.CreateStackTemporary(Vec.getValueType()); + EVT VecVT = Vec.getValueType(); + SDValue StackPtr = DAG.CreateStackTemporary(VecVT); int FI = cast(StackPtr.getNode())->getIndex(); MachinePointerInfo PtrInfo = MachinePointerInfo::getFixedStack(DAG.getMachineFunction(), FI); @@ -1266,16 +1255,7 @@ SDValue SelectionDAGLegalize::ExpandInsertToVectorThroughStack(SDValue Op) { SDValue Ch = DAG.getStore(DAG.getEntryNode(), dl, Vec, StackPtr, PtrInfo); // Then store the inserted part. - - // Add the offset to the index. - unsigned EltSize = Vec.getScalarValueSizeInBits() / 8; - - Idx = DAG.getNode(ISD::MUL, dl, Idx.getValueType(), Idx, - DAG.getConstant(EltSize, SDLoc(Vec), Idx.getValueType())); - Idx = DAG.getZExtOrTrunc(Idx, dl, TLI.getPointerTy(DAG.getDataLayout())); - - SDValue SubStackPtr = DAG.getNode(ISD::ADD, dl, Idx.getValueType(), Idx, - StackPtr); + SDValue SubStackPtr = TLI.getVectorElementPointer(DAG, StackPtr, VecVT, Idx); // Store the subvector. Ch = DAG.getStore(Ch, dl, Part, SubStackPtr, MachinePointerInfo()); diff --git a/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp b/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp index 6b62f11f1240..dc436ce04514 100644 --- a/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp +++ b/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp @@ -57,8 +57,6 @@ void DAGTypeLegalizer::PromoteIntegerResult(SDNode *N, unsigned ResNo) { case ISD::BSWAP: Res = PromoteIntRes_BSWAP(N); break; case ISD::BUILD_PAIR: Res = PromoteIntRes_BUILD_PAIR(N); break; case ISD::Constant: Res = PromoteIntRes_Constant(N); break; - case ISD::CONVERT_RNDSAT: - Res = PromoteIntRes_CONVERT_RNDSAT(N); break; case ISD::CTLZ_ZERO_UNDEF: case ISD::CTLZ: Res = PromoteIntRes_CTLZ(N); break; case ISD::CTPOP: Res = PromoteIntRes_CTPOP(N); break; @@ -354,18 +352,6 @@ SDValue DAGTypeLegalizer::PromoteIntRes_Constant(SDNode *N) { return Result; } -SDValue DAGTypeLegalizer::PromoteIntRes_CONVERT_RNDSAT(SDNode *N) { - ISD::CvtCode CvtCode = cast(N)->getCvtCode(); - assert ((CvtCode == ISD::CVT_SS || CvtCode == ISD::CVT_SU || - CvtCode == ISD::CVT_US || CvtCode == ISD::CVT_UU || - CvtCode == ISD::CVT_SF || CvtCode == ISD::CVT_UF) && - "can only promote integers"); - EVT OutVT = TLI.getTypeToTransformTo(*DAG.getContext(), N->getValueType(0)); - return DAG.getConvertRndSat(OutVT, SDLoc(N), N->getOperand(0), - N->getOperand(1), N->getOperand(2), - N->getOperand(3), N->getOperand(4), CvtCode); -} - SDValue DAGTypeLegalizer::PromoteIntRes_CTLZ(SDNode *N) { // Zero extend to the promoted type and do the count there. SDValue Op = ZExtPromotedInteger(N->getOperand(0)); @@ -512,7 +498,7 @@ SDValue DAGTypeLegalizer::PromoteIntRes_MGATHER(MaskedGatherSDNode *N) { N->getIndex()}; SDValue Res = DAG.getMaskedGather(DAG.getVTList(NVT, MVT::Other), N->getMemoryVT(), dl, Ops, - N->getMemOperand()); + N->getMemOperand()); // Legalize the chain result - switch anything that used the old chain to // use the new one. ReplaceValueWith(SDValue(N, 1), Res.getValue(1)); @@ -887,8 +873,6 @@ bool DAGTypeLegalizer::PromoteIntegerOperand(SDNode *N, unsigned OpNo) { case ISD::BUILD_VECTOR: Res = PromoteIntOp_BUILD_VECTOR(N); break; case ISD::CONCAT_VECTORS: Res = PromoteIntOp_CONCAT_VECTORS(N); break; case ISD::EXTRACT_VECTOR_ELT: Res = PromoteIntOp_EXTRACT_VECTOR_ELT(N); break; - case ISD::CONVERT_RNDSAT: - Res = PromoteIntOp_CONVERT_RNDSAT(N); break; case ISD::INSERT_VECTOR_ELT: Res = PromoteIntOp_INSERT_VECTOR_ELT(N, OpNo);break; case ISD::SCALAR_TO_VECTOR: @@ -1068,18 +1052,6 @@ SDValue DAGTypeLegalizer::PromoteIntOp_BUILD_VECTOR(SDNode *N) { return SDValue(DAG.UpdateNodeOperands(N, NewOps), 0); } -SDValue DAGTypeLegalizer::PromoteIntOp_CONVERT_RNDSAT(SDNode *N) { - ISD::CvtCode CvtCode = cast(N)->getCvtCode(); - assert ((CvtCode == ISD::CVT_SS || CvtCode == ISD::CVT_SU || - CvtCode == ISD::CVT_US || CvtCode == ISD::CVT_UU || - CvtCode == ISD::CVT_FS || CvtCode == ISD::CVT_FU) && - "can only promote integer arguments"); - SDValue InOp = GetPromotedInteger(N->getOperand(0)); - return DAG.getConvertRndSat(N->getValueType(0), SDLoc(N), InOp, - N->getOperand(1), N->getOperand(2), - N->getOperand(3), N->getOperand(4), CvtCode); -} - SDValue DAGTypeLegalizer::PromoteIntOp_INSERT_VECTOR_ELT(SDNode *N, unsigned OpNo) { if (OpNo == 1) { diff --git a/lib/CodeGen/SelectionDAG/LegalizeTypes.cpp b/lib/CodeGen/SelectionDAG/LegalizeTypes.cpp index 693f5e2120a7..cf19d75676cd 100644 --- a/lib/CodeGen/SelectionDAG/LegalizeTypes.cpp +++ b/lib/CodeGen/SelectionDAG/LegalizeTypes.cpp @@ -1021,22 +1021,6 @@ void DAGTypeLegalizer::GetPairElements(SDValue Pair, DAG.getIntPtrConstant(1, dl)); } -SDValue DAGTypeLegalizer::GetVectorElementPointer(SDValue VecPtr, EVT EltVT, - SDValue Index) { - SDLoc dl(Index); - // Make sure the index type is big enough to compute in. - Index = DAG.getZExtOrTrunc(Index, dl, TLI.getPointerTy(DAG.getDataLayout())); - - // Calculate the element offset and add it to the pointer. - unsigned EltSize = EltVT.getSizeInBits() / 8; // FIXME: should be ABI size. - assert(EltSize * 8 == EltVT.getSizeInBits() && - "Converting bits to bytes lost precision"); - - Index = DAG.getNode(ISD::MUL, dl, Index.getValueType(), Index, - DAG.getConstant(EltSize, dl, Index.getValueType())); - return DAG.getNode(ISD::ADD, dl, Index.getValueType(), Index, VecPtr); -} - /// Build an integer with low bits Lo and high bits Hi. SDValue DAGTypeLegalizer::JoinIntegers(SDValue Lo, SDValue Hi) { // Arbitrarily use dlHi for result SDLoc diff --git a/lib/CodeGen/SelectionDAG/LegalizeTypes.h b/lib/CodeGen/SelectionDAG/LegalizeTypes.h index d1022af69477..ec55662d75c0 100644 --- a/lib/CodeGen/SelectionDAG/LegalizeTypes.h +++ b/lib/CodeGen/SelectionDAG/LegalizeTypes.h @@ -173,7 +173,6 @@ private: /// input operand is returned. SDValue DisintegrateMERGE_VALUES(SDNode *N, unsigned ResNo); - SDValue GetVectorElementPointer(SDValue VecPtr, EVT EltVT, SDValue Index); SDValue JoinIntegers(SDValue Lo, SDValue Hi); SDValue LibCallify(RTLIB::Libcall LC, SDNode *N, bool isSigned); @@ -250,7 +249,6 @@ private: SDValue PromoteIntRes_BITREVERSE(SDNode *N); SDValue PromoteIntRes_BUILD_PAIR(SDNode *N); SDValue PromoteIntRes_Constant(SDNode *N); - SDValue PromoteIntRes_CONVERT_RNDSAT(SDNode *N); SDValue PromoteIntRes_CTLZ(SDNode *N); SDValue PromoteIntRes_CTPOP(SDNode *N); SDValue PromoteIntRes_CTTZ(SDNode *N); @@ -289,7 +287,6 @@ private: SDValue PromoteIntOp_BR_CC(SDNode *N, unsigned OpNo); SDValue PromoteIntOp_BRCOND(SDNode *N, unsigned OpNo); SDValue PromoteIntOp_BUILD_VECTOR(SDNode *N); - SDValue PromoteIntOp_CONVERT_RNDSAT(SDNode *N); SDValue PromoteIntOp_INSERT_VECTOR_ELT(SDNode *N, unsigned OpNo); SDValue PromoteIntOp_EXTRACT_VECTOR_ELT(SDNode *N); SDValue PromoteIntOp_EXTRACT_SUBVECTOR(SDNode *N); @@ -603,7 +600,6 @@ private: SDValue ScalarizeVecRes_BITCAST(SDNode *N); SDValue ScalarizeVecRes_BUILD_VECTOR(SDNode *N); - SDValue ScalarizeVecRes_CONVERT_RNDSAT(SDNode *N); SDValue ScalarizeVecRes_EXTRACT_SUBVECTOR(SDNode *N); SDValue ScalarizeVecRes_FP_ROUND(SDNode *N); SDValue ScalarizeVecRes_FPOWI(SDNode *N); @@ -709,7 +705,6 @@ private: SDValue WidenVecRes_BITCAST(SDNode* N); SDValue WidenVecRes_BUILD_VECTOR(SDNode* N); SDValue WidenVecRes_CONCAT_VECTORS(SDNode* N); - SDValue WidenVecRes_CONVERT_RNDSAT(SDNode* N); SDValue WidenVecRes_EXTEND_VECTOR_INREG(SDNode* N); SDValue WidenVecRes_EXTRACT_SUBVECTOR(SDNode* N); SDValue WidenVecRes_INSERT_VECTOR_ELT(SDNode* N); diff --git a/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp b/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp index 57c179ac15b8..27a9ac337f25 100644 --- a/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp +++ b/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp @@ -51,7 +51,6 @@ void DAGTypeLegalizer::ScalarizeVectorResult(SDNode *N, unsigned ResNo) { case ISD::MERGE_VALUES: R = ScalarizeVecRes_MERGE_VALUES(N, ResNo);break; case ISD::BITCAST: R = ScalarizeVecRes_BITCAST(N); break; case ISD::BUILD_VECTOR: R = ScalarizeVecRes_BUILD_VECTOR(N); break; - case ISD::CONVERT_RNDSAT: R = ScalarizeVecRes_CONVERT_RNDSAT(N); break; case ISD::EXTRACT_SUBVECTOR: R = ScalarizeVecRes_EXTRACT_SUBVECTOR(N); break; case ISD::FP_ROUND: R = ScalarizeVecRes_FP_ROUND(N); break; case ISD::FP_ROUND_INREG: R = ScalarizeVecRes_InregOp(N); break; @@ -179,17 +178,6 @@ SDValue DAGTypeLegalizer::ScalarizeVecRes_BUILD_VECTOR(SDNode *N) { return InOp; } -SDValue DAGTypeLegalizer::ScalarizeVecRes_CONVERT_RNDSAT(SDNode *N) { - EVT NewVT = N->getValueType(0).getVectorElementType(); - SDValue Op0 = GetScalarizedVector(N->getOperand(0)); - return DAG.getConvertRndSat(NewVT, SDLoc(N), - Op0, DAG.getValueType(NewVT), - DAG.getValueType(Op0.getValueType()), - N->getOperand(3), - N->getOperand(4), - cast(N)->getCvtCode()); -} - SDValue DAGTypeLegalizer::ScalarizeVecRes_EXTRACT_SUBVECTOR(SDNode *N) { return DAG.getNode(ISD::EXTRACT_VECTOR_ELT, SDLoc(N), N->getValueType(0).getVectorElementType(), @@ -621,7 +609,6 @@ void DAGTypeLegalizer::SplitVectorResult(SDNode *N, unsigned ResNo) { case ISD::BITREVERSE: case ISD::BSWAP: - case ISD::CONVERT_RNDSAT: case ISD::CTLZ: case ISD::CTTZ: case ISD::CTLZ_ZERO_UNDEF: @@ -846,7 +833,6 @@ void DAGTypeLegalizer::SplitVecRes_INSERT_SUBVECTOR(SDNode *N, SDValue &Lo, GetSplitVector(Vec, Lo, Hi); EVT VecVT = Vec.getValueType(); - EVT VecElemVT = VecVT.getVectorElementType(); unsigned VecElems = VecVT.getVectorNumElements(); unsigned SubElems = SubVec.getValueType().getVectorNumElements(); @@ -872,7 +858,7 @@ void DAGTypeLegalizer::SplitVecRes_INSERT_SUBVECTOR(SDNode *N, SDValue &Lo, DAG.getStore(DAG.getEntryNode(), dl, Vec, StackPtr, MachinePointerInfo()); // Store the new subvector into the specified index. - SDValue SubVecPtr = GetVectorElementPointer(StackPtr, VecElemVT, Idx); + SDValue SubVecPtr = TLI.getVectorElementPointer(DAG, StackPtr, VecVT, Idx); Type *VecType = VecVT.getTypeForEVT(*DAG.getContext()); unsigned Alignment = DAG.getDataLayout().getPrefTypeAlignment(VecType); Store = DAG.getStore(Store, dl, SubVec, SubVecPtr, MachinePointerInfo()); @@ -1003,7 +989,7 @@ void DAGTypeLegalizer::SplitVecRes_INSERT_VECTOR_ELT(SDNode *N, SDValue &Lo, // Store the new element. This may be larger than the vector element type, // so use a truncating store. - SDValue EltPtr = GetVectorElementPointer(StackPtr, EltVT, Idx); + SDValue EltPtr = TLI.getVectorElementPointer(DAG, StackPtr, VecVT, Idx); Type *VecType = VecVT.getTypeForEVT(*DAG.getContext()); unsigned Alignment = DAG.getDataLayout().getPrefTypeAlignment(VecType); Store = @@ -1236,18 +1222,6 @@ void DAGTypeLegalizer::SplitVecRes_UnaryOp(SDNode *N, SDValue &Lo, if (N->getOpcode() == ISD::FP_ROUND) { Lo = DAG.getNode(N->getOpcode(), dl, LoVT, Lo, N->getOperand(1)); Hi = DAG.getNode(N->getOpcode(), dl, HiVT, Hi, N->getOperand(1)); - } else if (N->getOpcode() == ISD::CONVERT_RNDSAT) { - SDValue DTyOpLo = DAG.getValueType(LoVT); - SDValue DTyOpHi = DAG.getValueType(HiVT); - SDValue STyOpLo = DAG.getValueType(Lo.getValueType()); - SDValue STyOpHi = DAG.getValueType(Hi.getValueType()); - SDValue RndOp = N->getOperand(3); - SDValue SatOp = N->getOperand(4); - ISD::CvtCode CvtCode = cast(N)->getCvtCode(); - Lo = DAG.getConvertRndSat(LoVT, dl, Lo, DTyOpLo, STyOpLo, RndOp, SatOp, - CvtCode); - Hi = DAG.getConvertRndSat(HiVT, dl, Hi, DTyOpHi, STyOpHi, RndOp, SatOp, - CvtCode); } else { Lo = DAG.getNode(N->getOpcode(), dl, LoVT, Lo); Hi = DAG.getNode(N->getOpcode(), dl, HiVT, Hi); @@ -1650,7 +1624,7 @@ SDValue DAGTypeLegalizer::SplitVecOp_EXTRACT_VECTOR_ELT(SDNode *N) { DAG.getStore(DAG.getEntryNode(), dl, Vec, StackPtr, MachinePointerInfo()); // Load back the required element. - StackPtr = GetVectorElementPointer(StackPtr, EltVT, Idx); + StackPtr = TLI.getVectorElementPointer(DAG, StackPtr, VecVT, Idx); return DAG.getExtLoad(ISD::EXTLOAD, dl, N->getValueType(0), Store, StackPtr, MachinePointerInfo(), EltVT); } @@ -2045,7 +2019,6 @@ void DAGTypeLegalizer::WidenVectorResult(SDNode *N, unsigned ResNo) { case ISD::BITCAST: Res = WidenVecRes_BITCAST(N); break; case ISD::BUILD_VECTOR: Res = WidenVecRes_BUILD_VECTOR(N); break; case ISD::CONCAT_VECTORS: Res = WidenVecRes_CONCAT_VECTORS(N); break; - case ISD::CONVERT_RNDSAT: Res = WidenVecRes_CONVERT_RNDSAT(N); break; case ISD::EXTRACT_SUBVECTOR: Res = WidenVecRes_EXTRACT_SUBVECTOR(N); break; case ISD::FP_ROUND_INREG: Res = WidenVecRes_InregOp(N); break; case ISD::INSERT_VECTOR_ELT: Res = WidenVecRes_INSERT_VECTOR_ELT(N); break; @@ -2693,86 +2666,6 @@ SDValue DAGTypeLegalizer::WidenVecRes_CONCAT_VECTORS(SDNode *N) { return DAG.getNode(ISD::BUILD_VECTOR, dl, WidenVT, Ops); } -SDValue DAGTypeLegalizer::WidenVecRes_CONVERT_RNDSAT(SDNode *N) { - SDLoc dl(N); - SDValue InOp = N->getOperand(0); - SDValue RndOp = N->getOperand(3); - SDValue SatOp = N->getOperand(4); - - EVT WidenVT = TLI.getTypeToTransformTo(*DAG.getContext(), N->getValueType(0)); - unsigned WidenNumElts = WidenVT.getVectorNumElements(); - - EVT InVT = InOp.getValueType(); - EVT InEltVT = InVT.getVectorElementType(); - EVT InWidenVT = EVT::getVectorVT(*DAG.getContext(), InEltVT, WidenNumElts); - - SDValue DTyOp = DAG.getValueType(WidenVT); - SDValue STyOp = DAG.getValueType(InWidenVT); - ISD::CvtCode CvtCode = cast(N)->getCvtCode(); - - unsigned InVTNumElts = InVT.getVectorNumElements(); - if (getTypeAction(InVT) == TargetLowering::TypeWidenVector) { - InOp = GetWidenedVector(InOp); - InVT = InOp.getValueType(); - InVTNumElts = InVT.getVectorNumElements(); - if (InVTNumElts == WidenNumElts) - return DAG.getConvertRndSat(WidenVT, dl, InOp, DTyOp, STyOp, RndOp, - SatOp, CvtCode); - } - - if (TLI.isTypeLegal(InWidenVT)) { - // Because the result and the input are different vector types, widening - // the result could create a legal type but widening the input might make - // it an illegal type that might lead to repeatedly splitting the input - // and then widening it. To avoid this, we widen the input only if - // it results in a legal type. - if (WidenNumElts % InVTNumElts == 0) { - // Widen the input and call convert on the widened input vector. - unsigned NumConcat = WidenNumElts/InVTNumElts; - SmallVector Ops(NumConcat); - Ops[0] = InOp; - SDValue UndefVal = DAG.getUNDEF(InVT); - for (unsigned i = 1; i != NumConcat; ++i) - Ops[i] = UndefVal; - - InOp = DAG.getNode(ISD::CONCAT_VECTORS, dl, InWidenVT, Ops); - return DAG.getConvertRndSat(WidenVT, dl, InOp, DTyOp, STyOp, RndOp, - SatOp, CvtCode); - } - - if (InVTNumElts % WidenNumElts == 0) { - // Extract the input and convert the shorten input vector. - InOp = DAG.getNode( - ISD::EXTRACT_SUBVECTOR, dl, InWidenVT, InOp, - DAG.getConstant(0, dl, TLI.getVectorIdxTy(DAG.getDataLayout()))); - return DAG.getConvertRndSat(WidenVT, dl, InOp, DTyOp, STyOp, RndOp, - SatOp, CvtCode); - } - } - - // Otherwise unroll into some nasty scalar code and rebuild the vector. - SmallVector Ops(WidenNumElts); - EVT EltVT = WidenVT.getVectorElementType(); - DTyOp = DAG.getValueType(EltVT); - STyOp = DAG.getValueType(InEltVT); - - unsigned MinElts = std::min(InVTNumElts, WidenNumElts); - unsigned i; - for (i=0; i < MinElts; ++i) { - SDValue ExtVal = DAG.getNode( - ISD::EXTRACT_VECTOR_ELT, dl, InEltVT, InOp, - DAG.getConstant(i, dl, TLI.getVectorIdxTy(DAG.getDataLayout()))); - Ops[i] = DAG.getConvertRndSat(WidenVT, dl, ExtVal, DTyOp, STyOp, RndOp, - SatOp, CvtCode); - } - - SDValue UndefVal = DAG.getUNDEF(EltVT); - for (; i < WidenNumElts; ++i) - Ops[i] = UndefVal; - - return DAG.getNode(ISD::BUILD_VECTOR, dl, WidenVT, Ops); -} - SDValue DAGTypeLegalizer::WidenVecRes_EXTRACT_SUBVECTOR(SDNode *N) { EVT VT = N->getValueType(0); EVT WidenVT = TLI.getTypeToTransformTo(*DAG.getContext(), VT); diff --git a/lib/CodeGen/SelectionDAG/ScheduleDAGSDNodes.h b/lib/CodeGen/SelectionDAG/ScheduleDAGSDNodes.h index 5cc806668b12..a058942c5689 100644 --- a/lib/CodeGen/SelectionDAG/ScheduleDAGSDNodes.h +++ b/lib/CodeGen/SelectionDAG/ScheduleDAGSDNodes.h @@ -15,10 +15,20 @@ #ifndef LLVM_LIB_CODEGEN_SELECTIONDAG_SCHEDULEDAGSDNODES_H #define LLVM_LIB_CODEGEN_SELECTIONDAG_SCHEDULEDAGSDNODES_H +#include "llvm/CodeGen/ISDOpcodes.h" #include "llvm/CodeGen/MachineBasicBlock.h" +#include "llvm/CodeGen/MachineValueType.h" #include "llvm/CodeGen/ScheduleDAG.h" +#include "llvm/CodeGen/SelectionDAGNodes.h" +#include "llvm/Support/Casting.h" +#include +#include +#include namespace llvm { + +class InstrItineraryData; + /// ScheduleDAGSDNodes - A ScheduleDAG for scheduling SDNode-based DAGs. /// /// Edges between SUnits are initially based on edges in the SelectionDAG, @@ -44,7 +54,7 @@ namespace llvm { explicit ScheduleDAGSDNodes(MachineFunction &mf); - ~ScheduleDAGSDNodes() override {} + ~ScheduleDAGSDNodes() override = default; /// Run - perform scheduling. /// @@ -131,6 +141,7 @@ namespace llvm { unsigned DefIdx; unsigned NodeNumDefs; MVT ValueType; + public: RegDefIter(const SUnit *SU, const ScheduleDAGSDNodes *SD); @@ -150,6 +161,7 @@ namespace llvm { } void Advance(); + private: void InitNodeNumDefs(); }; @@ -175,6 +187,7 @@ namespace llvm { void EmitPhysRegCopy(SUnit *SU, DenseMap &VRBaseMap, MachineBasicBlock::iterator InsertPos); }; -} -#endif +} // end namespace llvm + +#endif // LLVM_LIB_CODEGEN_SELECTIONDAG_SCHEDULEDAGSDNODES_H diff --git a/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/lib/CodeGen/SelectionDAG/SelectionDAG.cpp index b970dc0e5f5f..e225ba8703b7 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAG.cpp +++ b/lib/CodeGen/SelectionDAG/SelectionDAG.cpp @@ -1104,7 +1104,7 @@ SDValue SelectionDAG::getConstant(const ConstantInt &Val, const SDLoc &DL, if (VT.isVector() && TLI->getTypeAction(*getContext(), EltVT) == TargetLowering::TypePromoteInteger) { EltVT = TLI->getTypeToTransformTo(*getContext(), EltVT); - APInt NewVal = Elt->getValue().zext(EltVT.getSizeInBits()); + APInt NewVal = Elt->getValue().zextOrTrunc(EltVT.getSizeInBits()); Elt = ConstantInt::get(*getContext(), NewVal); } // In other cases the element type is illegal and needs to be expanded, for @@ -1130,7 +1130,7 @@ SDValue SelectionDAG::getConstant(const ConstantInt &Val, const SDLoc &DL, SmallVector EltParts; for (unsigned i = 0; i < ViaVecNumElts / VT.getVectorNumElements(); ++i) { EltParts.push_back(getConstant(NewVal.lshr(i * ViaEltSizeInBits) - .trunc(ViaEltSizeInBits), DL, + .zextOrTrunc(ViaEltSizeInBits), DL, ViaEltVT, isT, isO)); } @@ -1629,31 +1629,6 @@ SDValue SelectionDAG::getCommutedVectorShuffle(const ShuffleVectorSDNode &SV) { return getVectorShuffle(VT, SDLoc(&SV), Op1, Op0, MaskVec); } -SDValue SelectionDAG::getConvertRndSat(EVT VT, const SDLoc &dl, SDValue Val, - SDValue DTy, SDValue STy, SDValue Rnd, - SDValue Sat, ISD::CvtCode Code) { - // If the src and dest types are the same and the conversion is between - // integer types of the same sign or two floats, no conversion is necessary. - if (DTy == STy && - (Code == ISD::CVT_UU || Code == ISD::CVT_SS || Code == ISD::CVT_FF)) - return Val; - - FoldingSetNodeID ID; - SDValue Ops[] = { Val, DTy, STy, Rnd, Sat }; - AddNodeIDNode(ID, ISD::CONVERT_RNDSAT, getVTList(VT), Ops); - void* IP = nullptr; - if (SDNode *E = FindNodeOrInsertPos(ID, dl, IP)) - return SDValue(E, 0); - - auto *N = - newSDNode(VT, dl.getIROrder(), dl.getDebugLoc(), Code); - createOperands(N, Ops); - - CSEMap.InsertNode(N, IP); - InsertNode(N); - return SDValue(N, 0); -} - SDValue SelectionDAG::getRegister(unsigned RegNo, EVT VT) { FoldingSetNodeID ID; AddNodeIDNode(ID, ISD::Register, getVTList(VT), None); diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp index a07bd8f83546..9ca646534e2b 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ b/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -5211,39 +5211,6 @@ SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I, unsigned Intrinsic) { setValue(&I, Res); return nullptr; } - case Intrinsic::convertff: - case Intrinsic::convertfsi: - case Intrinsic::convertfui: - case Intrinsic::convertsif: - case Intrinsic::convertuif: - case Intrinsic::convertss: - case Intrinsic::convertsu: - case Intrinsic::convertus: - case Intrinsic::convertuu: { - ISD::CvtCode Code = ISD::CVT_INVALID; - switch (Intrinsic) { - default: llvm_unreachable("Impossible intrinsic"); // Can't reach here. - case Intrinsic::convertff: Code = ISD::CVT_FF; break; - case Intrinsic::convertfsi: Code = ISD::CVT_FS; break; - case Intrinsic::convertfui: Code = ISD::CVT_FU; break; - case Intrinsic::convertsif: Code = ISD::CVT_SF; break; - case Intrinsic::convertuif: Code = ISD::CVT_UF; break; - case Intrinsic::convertss: Code = ISD::CVT_SS; break; - case Intrinsic::convertsu: Code = ISD::CVT_SU; break; - case Intrinsic::convertus: Code = ISD::CVT_US; break; - case Intrinsic::convertuu: Code = ISD::CVT_UU; break; - } - EVT DestVT = TLI.getValueType(DAG.getDataLayout(), I.getType()); - const Value *Op1 = I.getArgOperand(0); - Res = DAG.getConvertRndSat(DestVT, sdl, getValue(Op1), - DAG.getValueType(DestVT), - DAG.getValueType(getValue(Op1).getValueType()), - getValue(I.getArgOperand(1)), - getValue(I.getArgOperand(2)), - Code); - setValue(&I, Res); - return nullptr; - } case Intrinsic::powi: setValue(&I, ExpandPowI(sdl, getValue(I.getArgOperand(0)), getValue(I.getArgOperand(1)), DAG)); diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp b/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp index 340088a5fc96..0faaad8a21b7 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp +++ b/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp @@ -262,21 +262,6 @@ std::string SDNode::getOperationName(const SelectionDAG *G) const { case ISD::FP16_TO_FP: return "fp16_to_fp"; case ISD::FP_TO_FP16: return "fp_to_fp16"; - case ISD::CONVERT_RNDSAT: { - switch (cast(this)->getCvtCode()) { - default: llvm_unreachable("Unknown cvt code!"); - case ISD::CVT_FF: return "cvt_ff"; - case ISD::CVT_FS: return "cvt_fs"; - case ISD::CVT_FU: return "cvt_fu"; - case ISD::CVT_SF: return "cvt_sf"; - case ISD::CVT_UF: return "cvt_uf"; - case ISD::CVT_SS: return "cvt_ss"; - case ISD::CVT_SU: return "cvt_su"; - case ISD::CVT_US: return "cvt_us"; - case ISD::CVT_UU: return "cvt_uu"; - } - } - // Control flow instructions case ISD::BR: return "br"; case ISD::BRIND: return "brind"; @@ -322,7 +307,7 @@ std::string SDNode::getOperationName(const SelectionDAG *G) const { case ISD::CTTZ_ZERO_UNDEF: return "cttz_zero_undef"; case ISD::CTLZ: return "ctlz"; case ISD::CTLZ_ZERO_UNDEF: return "ctlz_zero_undef"; - + // Trampolines case ISD::INIT_TRAMPOLINE: return "init_trampoline"; case ISD::ADJUST_TRAMPOLINE: return "adjust_trampoline"; diff --git a/lib/CodeGen/SelectionDAG/TargetLowering.cpp b/lib/CodeGen/SelectionDAG/TargetLowering.cpp index 591a37d600cc..690f0d2c8082 100644 --- a/lib/CodeGen/SelectionDAG/TargetLowering.cpp +++ b/lib/CodeGen/SelectionDAG/TargetLowering.cpp @@ -3706,7 +3706,7 @@ SDValue TargetLowering::expandUnalignedStore(StoreSDNode *ST, return Result; } -SDValue +SDValue TargetLowering::IncrementMemoryAddress(SDValue Addr, SDValue Mask, const SDLoc &DL, EVT DataVT, SelectionDAG &DAG, @@ -3738,6 +3738,49 @@ TargetLowering::IncrementMemoryAddress(SDValue Addr, SDValue Mask, return DAG.getNode(ISD::ADD, DL, AddrVT, Addr, Increment); } +static SDValue clampDynamicVectorIndex(SelectionDAG &DAG, + SDValue Idx, + EVT VecVT, + const SDLoc &dl) { + if (isa(Idx)) + return Idx; + + EVT IdxVT = Idx.getValueType(); + unsigned NElts = VecVT.getVectorNumElements(); + if (isPowerOf2_32(NElts)) { + APInt Imm = APInt::getLowBitsSet(IdxVT.getSizeInBits(), + Log2_32(NElts)); + return DAG.getNode(ISD::AND, dl, IdxVT, Idx, + DAG.getConstant(Imm, dl, IdxVT)); + } + + return DAG.getNode(ISD::UMIN, dl, IdxVT, Idx, + DAG.getConstant(NElts - 1, dl, IdxVT)); +} + +SDValue TargetLowering::getVectorElementPointer(SelectionDAG &DAG, + SDValue VecPtr, EVT VecVT, + SDValue Index) const { + SDLoc dl(Index); + // Make sure the index type is big enough to compute in. + Index = DAG.getZExtOrTrunc(Index, dl, getPointerTy(DAG.getDataLayout())); + + EVT EltVT = VecVT.getVectorElementType(); + + // Calculate the element offset and add it to the pointer. + unsigned EltSize = EltVT.getSizeInBits() / 8; // FIXME: should be ABI size. + assert(EltSize * 8 == EltVT.getSizeInBits() && + "Converting bits to bytes lost precision"); + + Index = clampDynamicVectorIndex(DAG, Index, VecVT, dl); + + EVT IdxVT = Index.getValueType(); + + Index = DAG.getNode(ISD::MUL, dl, IdxVT, Index, + DAG.getConstant(EltSize, dl, IdxVT)); + return DAG.getNode(ISD::ADD, dl, IdxVT, Index, VecPtr); +} + //===----------------------------------------------------------------------===// // Implementation of Emulated TLS Model //===----------------------------------------------------------------------===// diff --git a/lib/DebugInfo/CodeView/CMakeLists.txt b/lib/DebugInfo/CodeView/CMakeLists.txt index 221a8969965d..f9bff86b41c8 100644 --- a/lib/DebugInfo/CodeView/CMakeLists.txt +++ b/lib/DebugInfo/CodeView/CMakeLists.txt @@ -2,6 +2,7 @@ add_llvm_library(LLVMDebugInfoCodeView CodeViewError.cpp CodeViewRecordIO.cpp CVSymbolVisitor.cpp + CVTypeDumper.cpp CVTypeVisitor.cpp EnumTables.cpp Line.cpp @@ -10,7 +11,9 @@ add_llvm_library(LLVMDebugInfoCodeView RecordSerialization.cpp SymbolRecordMapping.cpp SymbolDumper.cpp - TypeDumper.cpp + TypeDatabase.cpp + TypeDatabaseVisitor.cpp + TypeDumpVisitor.cpp TypeRecord.cpp TypeRecordMapping.cpp TypeSerializer.cpp diff --git a/lib/DebugInfo/CodeView/CVTypeDumper.cpp b/lib/DebugInfo/CodeView/CVTypeDumper.cpp new file mode 100644 index 000000000000..fcd239cce0dd --- /dev/null +++ b/lib/DebugInfo/CodeView/CVTypeDumper.cpp @@ -0,0 +1,73 @@ +//===-- CVTypeDumper.cpp - CodeView type info dumper ------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/CodeView/CVTypeDumper.h" +#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" +#include "llvm/DebugInfo/CodeView/TypeDatabase.h" +#include "llvm/DebugInfo/CodeView/TypeDatabaseVisitor.h" +#include "llvm/DebugInfo/CodeView/TypeDeserializer.h" +#include "llvm/DebugInfo/CodeView/TypeRecord.h" +#include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h" +#include "llvm/DebugInfo/MSF/ByteStream.h" + +using namespace llvm; +using namespace llvm::codeview; + +Error CVTypeDumper::dump(const CVType &Record, TypeVisitorCallbacks &Dumper) { + TypeDatabaseVisitor DBV(TypeDB); + TypeDeserializer Deserializer; + TypeVisitorCallbackPipeline Pipeline; + Pipeline.addCallbackToPipeline(Deserializer); + Pipeline.addCallbackToPipeline(DBV); + Pipeline.addCallbackToPipeline(Dumper); + + CVTypeVisitor Visitor(Pipeline); + + CVType RecordCopy = Record; + if (auto EC = Visitor.visitTypeRecord(RecordCopy)) + return EC; + return Error::success(); +} + +Error CVTypeDumper::dump(const CVTypeArray &Types, + TypeVisitorCallbacks &Dumper) { + TypeDatabaseVisitor DBV(TypeDB); + TypeDeserializer Deserializer; + TypeVisitorCallbackPipeline Pipeline; + Pipeline.addCallbackToPipeline(Deserializer); + Pipeline.addCallbackToPipeline(DBV); + Pipeline.addCallbackToPipeline(Dumper); + + CVTypeVisitor Visitor(Pipeline); + + if (auto EC = Visitor.visitTypeStream(Types)) + return EC; + return Error::success(); +} + +Error CVTypeDumper::dump(ArrayRef Data, TypeVisitorCallbacks &Dumper) { + msf::ByteStream Stream(Data); + CVTypeArray Types; + msf::StreamReader Reader(Stream); + if (auto EC = Reader.readArray(Types, Reader.getLength())) + return EC; + + return dump(Types, Dumper); +} + +void CVTypeDumper::printTypeIndex(ScopedPrinter &Printer, StringRef FieldName, + TypeIndex TI, TypeDatabase &DB) { + StringRef TypeName; + if (!TI.isNoneType()) + TypeName = DB.getTypeName(TI); + if (!TypeName.empty()) + Printer.printHex(FieldName, TypeName, TI.getIndex()); + else + Printer.printHex(FieldName, TI.getIndex()); +} diff --git a/lib/DebugInfo/CodeView/SymbolDumper.cpp b/lib/DebugInfo/CodeView/SymbolDumper.cpp index 326e1f5add65..fd54fba13c76 100644 --- a/lib/DebugInfo/CodeView/SymbolDumper.cpp +++ b/lib/DebugInfo/CodeView/SymbolDumper.cpp @@ -11,13 +11,13 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallString.h" #include "llvm/DebugInfo/CodeView/CVSymbolVisitor.h" +#include "llvm/DebugInfo/CodeView/CVTypeDumper.h" #include "llvm/DebugInfo/CodeView/EnumTables.h" #include "llvm/DebugInfo/CodeView/SymbolDeserializer.h" #include "llvm/DebugInfo/CodeView/SymbolDumpDelegate.h" #include "llvm/DebugInfo/CodeView/SymbolRecord.h" #include "llvm/DebugInfo/CodeView/SymbolVisitorCallbackPipeline.h" #include "llvm/DebugInfo/CodeView/SymbolVisitorCallbacks.h" -#include "llvm/DebugInfo/CodeView/TypeDumper.h" #include "llvm/DebugInfo/CodeView/TypeIndex.h" #include "llvm/Support/Error.h" #include "llvm/Support/ScopedPrinter.h" @@ -32,9 +32,9 @@ namespace { /// the visitor out of SymbolDumper.h. class CVSymbolDumperImpl : public SymbolVisitorCallbacks { public: - CVSymbolDumperImpl(CVTypeDumper &CVTD, SymbolDumpDelegate *ObjDelegate, + CVSymbolDumperImpl(TypeDatabase &TypeDB, SymbolDumpDelegate *ObjDelegate, ScopedPrinter &W, bool PrintRecordBytes) - : CVTD(CVTD), ObjDelegate(ObjDelegate), W(W), + : TypeDB(TypeDB), ObjDelegate(ObjDelegate), W(W), PrintRecordBytes(PrintRecordBytes), InFunctionScope(false) {} /// CVSymbolVisitor overrides. @@ -51,8 +51,9 @@ private: void printLocalVariableAddrRange(const LocalVariableAddrRange &Range, uint32_t RelocationOffset); void printLocalVariableAddrGap(ArrayRef Gaps); + void printTypeIndex(StringRef FieldName, TypeIndex TI); - CVTypeDumper &CVTD; + TypeDatabase &TypeDB; SymbolDumpDelegate *ObjDelegate; ScopedPrinter &W; @@ -80,6 +81,10 @@ void CVSymbolDumperImpl::printLocalVariableAddrGap( } } +void CVSymbolDumperImpl::printTypeIndex(StringRef FieldName, TypeIndex TI) { + CVTypeDumper::printTypeIndex(W, FieldName, TI, TypeDB); +} + Error CVSymbolDumperImpl::visitSymbolBegin(CVSymbol &CVR) { return Error::success(); } @@ -163,7 +168,7 @@ Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, DictScope S(W, "BPRelativeSym"); W.printNumber("Offset", BPRel.Offset); - CVTD.printTypeIndex("Type", BPRel.Type); + printTypeIndex("Type", BPRel.Type); W.printString("VarName", BPRel.Name); return Error::success(); } @@ -187,7 +192,7 @@ Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, CallSiteInfo.CodeOffset, &LinkageName); } W.printHex("Segment", CallSiteInfo.Segment); - CVTD.printTypeIndex("Type", CallSiteInfo.Type); + printTypeIndex("Type", CallSiteInfo.Type); if (!LinkageName.empty()) W.printString("LinkageName", LinkageName); return Error::success(); @@ -278,7 +283,7 @@ Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, ConstantSym &Constant) { DictScope S(W, "Constant"); - CVTD.printTypeIndex("Type", Constant.Type); + printTypeIndex("Type", Constant.Type); W.printNumber("Value", Constant.Value); W.printString("Name", Constant.Name); return Error::success(); @@ -293,7 +298,7 @@ Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, DataSym &Data) { ObjDelegate->printRelocatedField("DataOffset", Data.getRelocationOffset(), Data.DataOffset, &LinkageName); } - CVTD.printTypeIndex("Type", Data.Type); + printTypeIndex("Type", Data.Type); W.printString("DisplayName", Data.Name); if (!LinkageName.empty()) W.printString("LinkageName", LinkageName); @@ -445,7 +450,7 @@ Error CVSymbolDumperImpl::visitKnownRecord( } W.printHex("Segment", HeapAllocSite.Segment); W.printHex("CallInstructionSize", HeapAllocSite.CallInstructionSize); - CVTD.printTypeIndex("Type", HeapAllocSite.Type); + printTypeIndex("Type", HeapAllocSite.Type); if (!LinkageName.empty()) W.printString("LinkageName", LinkageName); return Error::success(); @@ -457,7 +462,7 @@ Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, W.printHex("PtrParent", InlineSite.Parent); W.printHex("PtrEnd", InlineSite.End); - CVTD.printTypeIndex("Inlinee", InlineSite.Inlinee); + printTypeIndex("Inlinee", InlineSite.Inlinee); ListScope BinaryAnnotations(W, "BinaryAnnotations"); for (auto &Annotation : InlineSite.annotations()) { @@ -555,7 +560,7 @@ Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, LabelSym &Label) { Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, LocalSym &Local) { DictScope S(W, "Local"); - CVTD.printTypeIndex("Type", Local.Type); + printTypeIndex("Type", Local.Type); W.printFlags("Flags", uint16_t(Local.Flags), getLocalFlagNames()); W.printString("VarName", Local.Name); return Error::success(); @@ -586,7 +591,7 @@ Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, ProcSym &Proc) { W.printHex("CodeSize", Proc.CodeSize); W.printHex("DbgStart", Proc.DbgStart); W.printHex("DbgEnd", Proc.DbgEnd); - CVTD.printTypeIndex("FunctionType", Proc.FunctionType); + printTypeIndex("FunctionType", Proc.FunctionType); if (ObjDelegate) { ObjDelegate->printRelocatedField("CodeOffset", Proc.getRelocationOffset(), Proc.CodeOffset, &LinkageName); @@ -616,7 +621,7 @@ Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, CallerSym &Caller) { ListScope S(W, CVR.kind() == S_CALLEES ? "Callees" : "Callers"); for (auto FuncID : Caller.Indices) - CVTD.printTypeIndex("FuncID", FuncID); + printTypeIndex("FuncID", FuncID); return Error::success(); } @@ -625,7 +630,7 @@ Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, DictScope S(W, "RegRelativeSym"); W.printHex("Offset", RegRel.Offset); - CVTD.printTypeIndex("Type", RegRel.Type); + printTypeIndex("Type", RegRel.Type); W.printHex("Register", RegRel.Register); W.printString("VarName", RegRel.Name); return Error::success(); @@ -640,7 +645,7 @@ Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, ObjDelegate->printRelocatedField("DataOffset", Data.getRelocationOffset(), Data.DataOffset, &LinkageName); } - CVTD.printTypeIndex("Type", Data.Type); + printTypeIndex("Type", Data.Type); W.printString("DisplayName", Data.Name); if (!LinkageName.empty()) W.printString("LinkageName", LinkageName); @@ -649,7 +654,7 @@ Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, UDTSym &UDT) { DictScope S(W, "UDT"); - CVTD.printTypeIndex("Type", UDT.Type); + printTypeIndex("Type", UDT.Type); W.printString("UDTName", UDT.Name); return Error::success(); } @@ -664,7 +669,7 @@ Error CVSymbolDumperImpl::visitUnknownSymbol(CVSymbol &CVR) { Error CVSymbolDumper::dump(CVRecord &Record) { SymbolVisitorCallbackPipeline Pipeline; SymbolDeserializer Deserializer(ObjDelegate.get()); - CVSymbolDumperImpl Dumper(CVTD, ObjDelegate.get(), W, PrintRecordBytes); + CVSymbolDumperImpl Dumper(TypeDB, ObjDelegate.get(), W, PrintRecordBytes); Pipeline.addCallbackToPipeline(Deserializer); Pipeline.addCallbackToPipeline(Dumper); @@ -675,7 +680,7 @@ Error CVSymbolDumper::dump(CVRecord &Record) { Error CVSymbolDumper::dump(const CVSymbolArray &Symbols) { SymbolVisitorCallbackPipeline Pipeline; SymbolDeserializer Deserializer(ObjDelegate.get()); - CVSymbolDumperImpl Dumper(CVTD, ObjDelegate.get(), W, PrintRecordBytes); + CVSymbolDumperImpl Dumper(TypeDB, ObjDelegate.get(), W, PrintRecordBytes); Pipeline.addCallbackToPipeline(Deserializer); Pipeline.addCallbackToPipeline(Dumper); diff --git a/lib/DebugInfo/CodeView/TypeDatabase.cpp b/lib/DebugInfo/CodeView/TypeDatabase.cpp new file mode 100644 index 000000000000..c7f72551dc8b --- /dev/null +++ b/lib/DebugInfo/CodeView/TypeDatabase.cpp @@ -0,0 +1,114 @@ +//===- TypeDatabase.cpp --------------------------------------- *- C++ --*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/CodeView/TypeDatabase.h" + +using namespace llvm; +using namespace llvm::codeview; + +namespace { +struct SimpleTypeEntry { + StringRef Name; + SimpleTypeKind Kind; +}; +} + +/// The names here all end in "*". If the simple type is a pointer type, we +/// return the whole name. Otherwise we lop off the last character in our +/// StringRef. +static const SimpleTypeEntry SimpleTypeNames[] = { + {"void*", SimpleTypeKind::Void}, + {"*", SimpleTypeKind::NotTranslated}, + {"HRESULT*", SimpleTypeKind::HResult}, + {"signed char*", SimpleTypeKind::SignedCharacter}, + {"unsigned char*", SimpleTypeKind::UnsignedCharacter}, + {"char*", SimpleTypeKind::NarrowCharacter}, + {"wchar_t*", SimpleTypeKind::WideCharacter}, + {"char16_t*", SimpleTypeKind::Character16}, + {"char32_t*", SimpleTypeKind::Character32}, + {"__int8*", SimpleTypeKind::SByte}, + {"unsigned __int8*", SimpleTypeKind::Byte}, + {"short*", SimpleTypeKind::Int16Short}, + {"unsigned short*", SimpleTypeKind::UInt16Short}, + {"__int16*", SimpleTypeKind::Int16}, + {"unsigned __int16*", SimpleTypeKind::UInt16}, + {"long*", SimpleTypeKind::Int32Long}, + {"unsigned long*", SimpleTypeKind::UInt32Long}, + {"int*", SimpleTypeKind::Int32}, + {"unsigned*", SimpleTypeKind::UInt32}, + {"__int64*", SimpleTypeKind::Int64Quad}, + {"unsigned __int64*", SimpleTypeKind::UInt64Quad}, + {"__int64*", SimpleTypeKind::Int64}, + {"unsigned __int64*", SimpleTypeKind::UInt64}, + {"__int128*", SimpleTypeKind::Int128}, + {"unsigned __int128*", SimpleTypeKind::UInt128}, + {"__half*", SimpleTypeKind::Float16}, + {"float*", SimpleTypeKind::Float32}, + {"float*", SimpleTypeKind::Float32PartialPrecision}, + {"__float48*", SimpleTypeKind::Float48}, + {"double*", SimpleTypeKind::Float64}, + {"long double*", SimpleTypeKind::Float80}, + {"__float128*", SimpleTypeKind::Float128}, + {"_Complex float*", SimpleTypeKind::Complex32}, + {"_Complex double*", SimpleTypeKind::Complex64}, + {"_Complex long double*", SimpleTypeKind::Complex80}, + {"_Complex __float128*", SimpleTypeKind::Complex128}, + {"bool*", SimpleTypeKind::Boolean8}, + {"__bool16*", SimpleTypeKind::Boolean16}, + {"__bool32*", SimpleTypeKind::Boolean32}, + {"__bool64*", SimpleTypeKind::Boolean64}, +}; + +/// Gets the type index for the next type record. +TypeIndex TypeDatabase::getNextTypeIndex() const { + return TypeIndex(TypeIndex::FirstNonSimpleIndex + CVUDTNames.size()); +} + +/// Records the name of a type, and reserves its type index. +void TypeDatabase::recordType(StringRef Name, CVType Data) { + CVUDTNames.push_back(Name); + TypeRecords.push_back(Data); +} + +/// Saves the name in a StringSet and creates a stable StringRef. +StringRef TypeDatabase::saveTypeName(StringRef TypeName) { + return TypeNameStorage.save(TypeName); +} + +StringRef TypeDatabase::getTypeName(TypeIndex Index) const { + if (Index.isNoneType()) + return ""; + + if (Index.isSimple()) { + // This is a simple type. + for (const auto &SimpleTypeName : SimpleTypeNames) { + if (SimpleTypeName.Kind == Index.getSimpleKind()) { + if (Index.getSimpleMode() == SimpleTypeMode::Direct) + return SimpleTypeName.Name.drop_back(1); + // Otherwise, this is a pointer type. We gloss over the distinction + // between near, far, 64, 32, etc, and just give a pointer type. + return SimpleTypeName.Name; + } + } + return ""; + } + + uint32_t I = Index.getIndex() - TypeIndex::FirstNonSimpleIndex; + if (I < CVUDTNames.size()) + return CVUDTNames[I]; + + return ""; +} + +bool TypeDatabase::containsTypeIndex(TypeIndex Index) const { + uint32_t I = Index.getIndex() - TypeIndex::FirstNonSimpleIndex; + return I < CVUDTNames.size(); +} + +uint32_t TypeDatabase::size() const { return CVUDTNames.size(); } diff --git a/lib/DebugInfo/CodeView/TypeDatabaseVisitor.cpp b/lib/DebugInfo/CodeView/TypeDatabaseVisitor.cpp new file mode 100644 index 000000000000..d9d563902182 --- /dev/null +++ b/lib/DebugInfo/CodeView/TypeDatabaseVisitor.cpp @@ -0,0 +1,289 @@ +//===- TypeDatabaseVisitor.cpp -------------------------------- *- C++ --*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/CodeView/TypeDatabaseVisitor.h" + +#include "llvm/ADT/SmallString.h" + +using namespace llvm; + +using namespace llvm::codeview; + +Error TypeDatabaseVisitor::visitTypeBegin(CVRecord &Record) { + assert(!IsInFieldList); + // Reset Name to the empty string. If the visitor sets it, we know it. + Name = ""; + + if (Record.Type == LF_FIELDLIST) { + // Record that we're in a field list so that members do not get assigned + // type indices. + IsInFieldList = true; + } + return Error::success(); +} + +Error TypeDatabaseVisitor::visitTypeEnd(CVType &CVR) { + if (CVR.Type == LF_FIELDLIST) { + assert(IsInFieldList); + IsInFieldList = false; + } + assert(!IsInFieldList); + + // Record every type that is not a field list member, even if Name is empty. + // CVUDTNames is indexed by type index, and must have one entry for every + // type. Field list members are not recorded, and are only referenced by + // their containing field list record. + TypeDB.recordType(Name, CVR); + return Error::success(); +} + +Error TypeDatabaseVisitor::visitMemberBegin(CVMemberRecord &Record) { + assert(IsInFieldList); + // Reset Name to the empty string. If the visitor sets it, we know it. + Name = ""; + return Error::success(); +} + +Error TypeDatabaseVisitor::visitMemberEnd(CVMemberRecord &Record) { + assert(IsInFieldList); + return Error::success(); +} + +Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR, + FieldListRecord &FieldList) { + Name = ""; + return Error::success(); +} + +Error TypeDatabaseVisitor::visitKnownRecord(CVRecord &CVR, + StringIdRecord &String) { + // Put this in the database so it gets printed with LF_UDT_SRC_LINE. + Name = String.getString(); + return Error::success(); +} + +Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR, ArgListRecord &Args) { + auto Indices = Args.getIndices(); + uint32_t Size = Indices.size(); + SmallString<256> TypeName("("); + for (uint32_t I = 0; I < Size; ++I) { + StringRef ArgTypeName = TypeDB.getTypeName(Indices[I]); + TypeName.append(ArgTypeName); + if (I + 1 != Size) + TypeName.append(", "); + } + TypeName.push_back(')'); + Name = TypeDB.saveTypeName(TypeName); + return Error::success(); +} + +Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR, ClassRecord &Class) { + Name = Class.getName(); + return Error::success(); +} + +Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR, UnionRecord &Union) { + Name = Union.getName(); + return Error::success(); +} + +Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR, EnumRecord &Enum) { + Name = Enum.getName(); + return Error::success(); +} + +Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR, ArrayRecord &AT) { + Name = AT.getName(); + return Error::success(); +} + +Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR, VFTableRecord &VFT) { + Name = VFT.getName(); + return Error::success(); +} + +Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR, + MemberFuncIdRecord &Id) { + Name = Id.getName(); + return Error::success(); +} + +Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR, + ProcedureRecord &Proc) { + StringRef ReturnTypeName = TypeDB.getTypeName(Proc.getReturnType()); + StringRef ArgListTypeName = TypeDB.getTypeName(Proc.getArgumentList()); + SmallString<256> TypeName(ReturnTypeName); + TypeName.push_back(' '); + TypeName.append(ArgListTypeName); + Name = TypeDB.saveTypeName(TypeName); + return Error::success(); +} + +Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR, + MemberFunctionRecord &MF) { + StringRef ReturnTypeName = TypeDB.getTypeName(MF.getReturnType()); + StringRef ClassTypeName = TypeDB.getTypeName(MF.getClassType()); + StringRef ArgListTypeName = TypeDB.getTypeName(MF.getArgumentList()); + SmallString<256> TypeName(ReturnTypeName); + TypeName.push_back(' '); + TypeName.append(ClassTypeName); + TypeName.append("::"); + TypeName.append(ArgListTypeName); + Name = TypeDB.saveTypeName(TypeName); + return Error::success(); +} + +Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR, FuncIdRecord &Func) { + Name = Func.getName(); + return Error::success(); +} + +Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR, + TypeServer2Record &TS) { + Name = TS.getName(); + return Error::success(); +} + +Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR, PointerRecord &Ptr) { + + if (Ptr.isPointerToMember()) { + const MemberPointerInfo &MI = Ptr.getMemberInfo(); + + StringRef PointeeName = TypeDB.getTypeName(Ptr.getReferentType()); + StringRef ClassName = TypeDB.getTypeName(MI.getContainingType()); + SmallString<256> TypeName(PointeeName); + TypeName.push_back(' '); + TypeName.append(ClassName); + TypeName.append("::*"); + Name = TypeDB.saveTypeName(TypeName); + } else { + SmallString<256> TypeName; + if (Ptr.isConst()) + TypeName.append("const "); + if (Ptr.isVolatile()) + TypeName.append("volatile "); + if (Ptr.isUnaligned()) + TypeName.append("__unaligned "); + + TypeName.append(TypeDB.getTypeName(Ptr.getReferentType())); + + if (Ptr.getMode() == PointerMode::LValueReference) + TypeName.append("&"); + else if (Ptr.getMode() == PointerMode::RValueReference) + TypeName.append("&&"); + else if (Ptr.getMode() == PointerMode::Pointer) + TypeName.append("*"); + + if (!TypeName.empty()) + Name = TypeDB.saveTypeName(TypeName); + } + return Error::success(); +} + +Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR, ModifierRecord &Mod) { + uint16_t Mods = static_cast(Mod.getModifiers()); + + StringRef ModifiedName = TypeDB.getTypeName(Mod.getModifiedType()); + SmallString<256> TypeName; + if (Mods & uint16_t(ModifierOptions::Const)) + TypeName.append("const "); + if (Mods & uint16_t(ModifierOptions::Volatile)) + TypeName.append("volatile "); + if (Mods & uint16_t(ModifierOptions::Unaligned)) + TypeName.append("__unaligned "); + TypeName.append(ModifiedName); + Name = TypeDB.saveTypeName(TypeName); + return Error::success(); +} + +Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR, + VFTableShapeRecord &Shape) { + Name = TypeDB.saveTypeName(""); + return Error::success(); +} + +Error TypeDatabaseVisitor::visitKnownMember(CVMemberRecord &CVR, + NestedTypeRecord &Nested) { + Name = Nested.getName(); + return Error::success(); +} + +Error TypeDatabaseVisitor::visitKnownMember(CVMemberRecord &CVR, + OneMethodRecord &Method) { + Name = Method.getName(); + return Error::success(); +} + +Error TypeDatabaseVisitor::visitKnownMember(CVMemberRecord &CVR, + OverloadedMethodRecord &Method) { + Name = Method.getName(); + return Error::success(); +} + +Error TypeDatabaseVisitor::visitKnownMember(CVMemberRecord &CVR, + DataMemberRecord &Field) { + Name = Field.getName(); + return Error::success(); +} + +Error TypeDatabaseVisitor::visitKnownMember(CVMemberRecord &CVR, + StaticDataMemberRecord &Field) { + Name = Field.getName(); + return Error::success(); +} + +Error TypeDatabaseVisitor::visitKnownMember(CVMemberRecord &CVR, + EnumeratorRecord &Enum) { + Name = Enum.getName(); + return Error::success(); +} + +Error TypeDatabaseVisitor::visitKnownMember(CVMemberRecord &CVR, + BaseClassRecord &Base) { + return Error::success(); +} + +Error TypeDatabaseVisitor::visitKnownMember(CVMemberRecord &CVR, + VirtualBaseClassRecord &VBase) { + return Error::success(); +} + +Error TypeDatabaseVisitor::visitKnownMember(CVMemberRecord &CVR, + ListContinuationRecord &Cont) { + return Error::success(); +} + +Error TypeDatabaseVisitor::visitKnownRecord( + CVType &CVR, UdtModSourceLineRecord &ModSourceLine) { + return Error::success(); +} + +Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR, + UdtSourceLineRecord &SourceLine) { + return Error::success(); +} + +Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR, BitFieldRecord &BF) { + return Error::success(); +} + +Error TypeDatabaseVisitor::visitKnownRecord( + CVType &CVR, MethodOverloadListRecord &Overloads) { + return Error::success(); +} + +Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR, BuildInfoRecord &BI) { + return Error::success(); +} + +Error TypeDatabaseVisitor::visitKnownMember(CVMemberRecord &CVR, + VFPtrRecord &VFP) { + return Error::success(); +} diff --git a/lib/DebugInfo/CodeView/TypeDumpVisitor.cpp b/lib/DebugInfo/CodeView/TypeDumpVisitor.cpp new file mode 100644 index 000000000000..033585ba8cc9 --- /dev/null +++ b/lib/DebugInfo/CodeView/TypeDumpVisitor.cpp @@ -0,0 +1,532 @@ +//===-- TypeDumpVisitor.cpp - CodeView type info dumper -----------*- C++ +//-*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h" + +#include "llvm/ADT/SmallString.h" +#include "llvm/DebugInfo/CodeView/CVTypeDumper.h" +#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" +#include "llvm/DebugInfo/CodeView/TypeDatabase.h" +#include "llvm/DebugInfo/CodeView/TypeDatabaseVisitor.h" +#include "llvm/DebugInfo/CodeView/TypeDeserializer.h" +#include "llvm/DebugInfo/CodeView/TypeIndex.h" +#include "llvm/DebugInfo/CodeView/TypeRecord.h" +#include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h" +#include "llvm/DebugInfo/MSF/ByteStream.h" +#include "llvm/Support/ScopedPrinter.h" + +using namespace llvm; +using namespace llvm::codeview; + +static const EnumEntry LeafTypeNames[] = { +#define CV_TYPE(enum, val) {#enum, enum}, +#include "llvm/DebugInfo/CodeView/TypeRecords.def" +}; + +#define ENUM_ENTRY(enum_class, enum) \ + { #enum, std::underlying_type < enum_class > ::type(enum_class::enum) } + +static const EnumEntry ClassOptionNames[] = { + ENUM_ENTRY(ClassOptions, Packed), + ENUM_ENTRY(ClassOptions, HasConstructorOrDestructor), + ENUM_ENTRY(ClassOptions, HasOverloadedOperator), + ENUM_ENTRY(ClassOptions, Nested), + ENUM_ENTRY(ClassOptions, ContainsNestedClass), + ENUM_ENTRY(ClassOptions, HasOverloadedAssignmentOperator), + ENUM_ENTRY(ClassOptions, HasConversionOperator), + ENUM_ENTRY(ClassOptions, ForwardReference), + ENUM_ENTRY(ClassOptions, Scoped), + ENUM_ENTRY(ClassOptions, HasUniqueName), + ENUM_ENTRY(ClassOptions, Sealed), + ENUM_ENTRY(ClassOptions, Intrinsic), +}; + +static const EnumEntry MemberAccessNames[] = { + ENUM_ENTRY(MemberAccess, None), ENUM_ENTRY(MemberAccess, Private), + ENUM_ENTRY(MemberAccess, Protected), ENUM_ENTRY(MemberAccess, Public), +}; + +static const EnumEntry MethodOptionNames[] = { + ENUM_ENTRY(MethodOptions, Pseudo), + ENUM_ENTRY(MethodOptions, NoInherit), + ENUM_ENTRY(MethodOptions, NoConstruct), + ENUM_ENTRY(MethodOptions, CompilerGenerated), + ENUM_ENTRY(MethodOptions, Sealed), +}; + +static const EnumEntry MemberKindNames[] = { + ENUM_ENTRY(MethodKind, Vanilla), + ENUM_ENTRY(MethodKind, Virtual), + ENUM_ENTRY(MethodKind, Static), + ENUM_ENTRY(MethodKind, Friend), + ENUM_ENTRY(MethodKind, IntroducingVirtual), + ENUM_ENTRY(MethodKind, PureVirtual), + ENUM_ENTRY(MethodKind, PureIntroducingVirtual), +}; + +static const EnumEntry PtrKindNames[] = { + ENUM_ENTRY(PointerKind, Near16), + ENUM_ENTRY(PointerKind, Far16), + ENUM_ENTRY(PointerKind, Huge16), + ENUM_ENTRY(PointerKind, BasedOnSegment), + ENUM_ENTRY(PointerKind, BasedOnValue), + ENUM_ENTRY(PointerKind, BasedOnSegmentValue), + ENUM_ENTRY(PointerKind, BasedOnAddress), + ENUM_ENTRY(PointerKind, BasedOnSegmentAddress), + ENUM_ENTRY(PointerKind, BasedOnType), + ENUM_ENTRY(PointerKind, BasedOnSelf), + ENUM_ENTRY(PointerKind, Near32), + ENUM_ENTRY(PointerKind, Far32), + ENUM_ENTRY(PointerKind, Near64), +}; + +static const EnumEntry PtrModeNames[] = { + ENUM_ENTRY(PointerMode, Pointer), + ENUM_ENTRY(PointerMode, LValueReference), + ENUM_ENTRY(PointerMode, PointerToDataMember), + ENUM_ENTRY(PointerMode, PointerToMemberFunction), + ENUM_ENTRY(PointerMode, RValueReference), +}; + +static const EnumEntry PtrMemberRepNames[] = { + ENUM_ENTRY(PointerToMemberRepresentation, Unknown), + ENUM_ENTRY(PointerToMemberRepresentation, SingleInheritanceData), + ENUM_ENTRY(PointerToMemberRepresentation, MultipleInheritanceData), + ENUM_ENTRY(PointerToMemberRepresentation, VirtualInheritanceData), + ENUM_ENTRY(PointerToMemberRepresentation, GeneralData), + ENUM_ENTRY(PointerToMemberRepresentation, SingleInheritanceFunction), + ENUM_ENTRY(PointerToMemberRepresentation, MultipleInheritanceFunction), + ENUM_ENTRY(PointerToMemberRepresentation, VirtualInheritanceFunction), + ENUM_ENTRY(PointerToMemberRepresentation, GeneralFunction), +}; + +static const EnumEntry TypeModifierNames[] = { + ENUM_ENTRY(ModifierOptions, Const), ENUM_ENTRY(ModifierOptions, Volatile), + ENUM_ENTRY(ModifierOptions, Unaligned), +}; + +static const EnumEntry CallingConventions[] = { + ENUM_ENTRY(CallingConvention, NearC), + ENUM_ENTRY(CallingConvention, FarC), + ENUM_ENTRY(CallingConvention, NearPascal), + ENUM_ENTRY(CallingConvention, FarPascal), + ENUM_ENTRY(CallingConvention, NearFast), + ENUM_ENTRY(CallingConvention, FarFast), + ENUM_ENTRY(CallingConvention, NearStdCall), + ENUM_ENTRY(CallingConvention, FarStdCall), + ENUM_ENTRY(CallingConvention, NearSysCall), + ENUM_ENTRY(CallingConvention, FarSysCall), + ENUM_ENTRY(CallingConvention, ThisCall), + ENUM_ENTRY(CallingConvention, MipsCall), + ENUM_ENTRY(CallingConvention, Generic), + ENUM_ENTRY(CallingConvention, AlphaCall), + ENUM_ENTRY(CallingConvention, PpcCall), + ENUM_ENTRY(CallingConvention, SHCall), + ENUM_ENTRY(CallingConvention, ArmCall), + ENUM_ENTRY(CallingConvention, AM33Call), + ENUM_ENTRY(CallingConvention, TriCall), + ENUM_ENTRY(CallingConvention, SH5Call), + ENUM_ENTRY(CallingConvention, M32RCall), + ENUM_ENTRY(CallingConvention, ClrCall), + ENUM_ENTRY(CallingConvention, Inline), + ENUM_ENTRY(CallingConvention, NearVector), +}; + +static const EnumEntry FunctionOptionEnum[] = { + ENUM_ENTRY(FunctionOptions, CxxReturnUdt), + ENUM_ENTRY(FunctionOptions, Constructor), + ENUM_ENTRY(FunctionOptions, ConstructorWithVirtualBases), +}; + +#undef ENUM_ENTRY + +static StringRef getLeafTypeName(TypeLeafKind LT) { + switch (LT) { +#define TYPE_RECORD(ename, value, name) \ + case ename: \ + return #name; +#include "llvm/DebugInfo/CodeView/TypeRecords.def" + default: + break; + } + return "UnknownLeaf"; +} + +void TypeDumpVisitor::printTypeIndex(StringRef FieldName, TypeIndex TI) const { + CVTypeDumper::printTypeIndex(*W, FieldName, TI, TypeDB); +} + +Error TypeDumpVisitor::visitTypeBegin(CVType &Record) { + W->startLine() << getLeafTypeName(Record.Type); + W->getOStream() << " (" << HexNumber(TypeDB.getNextTypeIndex().getIndex()) + << ")"; + W->getOStream() << " {\n"; + W->indent(); + W->printEnum("TypeLeafKind", unsigned(Record.Type), + makeArrayRef(LeafTypeNames)); + return Error::success(); +} + +Error TypeDumpVisitor::visitTypeEnd(CVType &Record) { + if (PrintRecordBytes) + W->printBinaryBlock("LeafData", getBytesAsCharacters(Record.content())); + + W->unindent(); + W->startLine() << "}\n"; + return Error::success(); +} + +Error TypeDumpVisitor::visitMemberBegin(CVMemberRecord &Record) { + W->startLine() << getLeafTypeName(Record.Kind); + W->getOStream() << " {\n"; + W->indent(); + W->printEnum("TypeLeafKind", unsigned(Record.Kind), + makeArrayRef(LeafTypeNames)); + return Error::success(); +} + +Error TypeDumpVisitor::visitMemberEnd(CVMemberRecord &Record) { + if (PrintRecordBytes) + W->printBinaryBlock("LeafData", getBytesAsCharacters(Record.Data)); + + W->unindent(); + W->startLine() << "}\n"; + return Error::success(); +} + +Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, + FieldListRecord &FieldList) { + CVTypeVisitor Visitor(*this); + if (auto EC = Visitor.visitFieldListMemberStream(FieldList.Data)) + return EC; + + return Error::success(); +} + +Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, StringIdRecord &String) { + printTypeIndex("Id", String.getId()); + W->printString("StringData", String.getString()); + return Error::success(); +} + +Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, ArgListRecord &Args) { + auto Indices = Args.getIndices(); + uint32_t Size = Indices.size(); + W->printNumber("NumArgs", Size); + ListScope Arguments(*W, "Arguments"); + for (uint32_t I = 0; I < Size; ++I) { + printTypeIndex("ArgType", Indices[I]); + } + return Error::success(); +} + +Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, ClassRecord &Class) { + uint16_t Props = static_cast(Class.getOptions()); + W->printNumber("MemberCount", Class.getMemberCount()); + W->printFlags("Properties", Props, makeArrayRef(ClassOptionNames)); + printTypeIndex("FieldList", Class.getFieldList()); + printTypeIndex("DerivedFrom", Class.getDerivationList()); + printTypeIndex("VShape", Class.getVTableShape()); + W->printNumber("SizeOf", Class.getSize()); + W->printString("Name", Class.getName()); + if (Props & uint16_t(ClassOptions::HasUniqueName)) + W->printString("LinkageName", Class.getUniqueName()); + return Error::success(); +} + +Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, UnionRecord &Union) { + uint16_t Props = static_cast(Union.getOptions()); + W->printNumber("MemberCount", Union.getMemberCount()); + W->printFlags("Properties", Props, makeArrayRef(ClassOptionNames)); + printTypeIndex("FieldList", Union.getFieldList()); + W->printNumber("SizeOf", Union.getSize()); + W->printString("Name", Union.getName()); + if (Props & uint16_t(ClassOptions::HasUniqueName)) + W->printString("LinkageName", Union.getUniqueName()); + return Error::success(); +} + +Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, EnumRecord &Enum) { + uint16_t Props = static_cast(Enum.getOptions()); + W->printNumber("NumEnumerators", Enum.getMemberCount()); + W->printFlags("Properties", uint16_t(Enum.getOptions()), + makeArrayRef(ClassOptionNames)); + printTypeIndex("UnderlyingType", Enum.getUnderlyingType()); + printTypeIndex("FieldListType", Enum.getFieldList()); + W->printString("Name", Enum.getName()); + if (Props & uint16_t(ClassOptions::HasUniqueName)) + W->printString("LinkageName", Enum.getUniqueName()); + return Error::success(); +} + +Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, ArrayRecord &AT) { + printTypeIndex("ElementType", AT.getElementType()); + printTypeIndex("IndexType", AT.getIndexType()); + W->printNumber("SizeOf", AT.getSize()); + W->printString("Name", AT.getName()); + return Error::success(); +} + +Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, VFTableRecord &VFT) { + printTypeIndex("CompleteClass", VFT.getCompleteClass()); + printTypeIndex("OverriddenVFTable", VFT.getOverriddenVTable()); + W->printHex("VFPtrOffset", VFT.getVFPtrOffset()); + W->printString("VFTableName", VFT.getName()); + for (auto N : VFT.getMethodNames()) + W->printString("MethodName", N); + return Error::success(); +} + +Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, MemberFuncIdRecord &Id) { + printTypeIndex("ClassType", Id.getClassType()); + printTypeIndex("FunctionType", Id.getFunctionType()); + W->printString("Name", Id.getName()); + return Error::success(); +} + +Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, ProcedureRecord &Proc) { + printTypeIndex("ReturnType", Proc.getReturnType()); + W->printEnum("CallingConvention", uint8_t(Proc.getCallConv()), + makeArrayRef(CallingConventions)); + W->printFlags("FunctionOptions", uint8_t(Proc.getOptions()), + makeArrayRef(FunctionOptionEnum)); + W->printNumber("NumParameters", Proc.getParameterCount()); + printTypeIndex("ArgListType", Proc.getArgumentList()); + return Error::success(); +} + +Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, MemberFunctionRecord &MF) { + printTypeIndex("ReturnType", MF.getReturnType()); + printTypeIndex("ClassType", MF.getClassType()); + printTypeIndex("ThisType", MF.getThisType()); + W->printEnum("CallingConvention", uint8_t(MF.getCallConv()), + makeArrayRef(CallingConventions)); + W->printFlags("FunctionOptions", uint8_t(MF.getOptions()), + makeArrayRef(FunctionOptionEnum)); + W->printNumber("NumParameters", MF.getParameterCount()); + printTypeIndex("ArgListType", MF.getArgumentList()); + W->printNumber("ThisAdjustment", MF.getThisPointerAdjustment()); + return Error::success(); +} + +Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, + MethodOverloadListRecord &MethodList) { + for (auto &M : MethodList.getMethods()) { + ListScope S(*W, "Method"); + printMemberAttributes(M.getAccess(), M.getMethodKind(), M.getOptions()); + printTypeIndex("Type", M.getType()); + if (M.isIntroducingVirtual()) + W->printHex("VFTableOffset", M.getVFTableOffset()); + } + return Error::success(); +} + +Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, FuncIdRecord &Func) { + printTypeIndex("ParentScope", Func.getParentScope()); + printTypeIndex("FunctionType", Func.getFunctionType()); + W->printString("Name", Func.getName()); + return Error::success(); +} + +Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, TypeServer2Record &TS) { + W->printBinary("Signature", TS.getGuid()); + W->printNumber("Age", TS.getAge()); + W->printString("Name", TS.getName()); + return Error::success(); +} + +Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, PointerRecord &Ptr) { + printTypeIndex("PointeeType", Ptr.getReferentType()); + W->printHex("PointerAttributes", uint32_t(Ptr.getOptions())); + W->printEnum("PtrType", unsigned(Ptr.getPointerKind()), + makeArrayRef(PtrKindNames)); + W->printEnum("PtrMode", unsigned(Ptr.getMode()), makeArrayRef(PtrModeNames)); + + W->printNumber("IsFlat", Ptr.isFlat()); + W->printNumber("IsConst", Ptr.isConst()); + W->printNumber("IsVolatile", Ptr.isVolatile()); + W->printNumber("IsUnaligned", Ptr.isUnaligned()); + W->printNumber("SizeOf", Ptr.getSize()); + + if (Ptr.isPointerToMember()) { + const MemberPointerInfo &MI = Ptr.getMemberInfo(); + + printTypeIndex("ClassType", MI.getContainingType()); + W->printEnum("Representation", uint16_t(MI.getRepresentation()), + makeArrayRef(PtrMemberRepNames)); + } + + return Error::success(); +} + +Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, ModifierRecord &Mod) { + uint16_t Mods = static_cast(Mod.getModifiers()); + printTypeIndex("ModifiedType", Mod.getModifiedType()); + W->printFlags("Modifiers", Mods, makeArrayRef(TypeModifierNames)); + + return Error::success(); +} + +Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, BitFieldRecord &BitField) { + printTypeIndex("Type", BitField.getType()); + W->printNumber("BitSize", BitField.getBitSize()); + W->printNumber("BitOffset", BitField.getBitOffset()); + return Error::success(); +} + +Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, + VFTableShapeRecord &Shape) { + W->printNumber("VFEntryCount", Shape.getEntryCount()); + return Error::success(); +} + +Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, + UdtSourceLineRecord &Line) { + printTypeIndex("UDT", Line.getUDT()); + printTypeIndex("SourceFile", Line.getSourceFile()); + W->printNumber("LineNumber", Line.getLineNumber()); + return Error::success(); +} + +Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, + UdtModSourceLineRecord &Line) { + printTypeIndex("UDT", Line.getUDT()); + printTypeIndex("SourceFile", Line.getSourceFile()); + W->printNumber("LineNumber", Line.getLineNumber()); + W->printNumber("Module", Line.getModule()); + return Error::success(); +} + +Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, BuildInfoRecord &Args) { + W->printNumber("NumArgs", static_cast(Args.getArgs().size())); + + ListScope Arguments(*W, "Arguments"); + for (auto Arg : Args.getArgs()) { + printTypeIndex("ArgType", Arg); + } + return Error::success(); +} + +void TypeDumpVisitor::printMemberAttributes(MemberAttributes Attrs) { + return printMemberAttributes(Attrs.getAccess(), Attrs.getMethodKind(), + Attrs.getFlags()); +} + +void TypeDumpVisitor::printMemberAttributes(MemberAccess Access, + MethodKind Kind, + MethodOptions Options) { + W->printEnum("AccessSpecifier", uint8_t(Access), + makeArrayRef(MemberAccessNames)); + // Data members will be vanilla. Don't try to print a method kind for them. + if (Kind != MethodKind::Vanilla) + W->printEnum("MethodKind", unsigned(Kind), makeArrayRef(MemberKindNames)); + if (Options != MethodOptions::None) { + W->printFlags("MethodOptions", unsigned(Options), + makeArrayRef(MethodOptionNames)); + } +} + +Error TypeDumpVisitor::visitUnknownMember(CVMemberRecord &Record) { + W->printHex("UnknownMember", unsigned(Record.Kind)); + return Error::success(); +} + +Error TypeDumpVisitor::visitUnknownType(CVType &Record) { + W->printEnum("Kind", uint16_t(Record.kind()), makeArrayRef(LeafTypeNames)); + W->printNumber("Length", uint32_t(Record.content().size())); + return Error::success(); +} + +Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR, + NestedTypeRecord &Nested) { + printTypeIndex("Type", Nested.getNestedType()); + W->printString("Name", Nested.getName()); + return Error::success(); +} + +Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR, + OneMethodRecord &Method) { + MethodKind K = Method.getMethodKind(); + printMemberAttributes(Method.getAccess(), K, Method.getOptions()); + printTypeIndex("Type", Method.getType()); + // If virtual, then read the vftable offset. + if (Method.isIntroducingVirtual()) + W->printHex("VFTableOffset", Method.getVFTableOffset()); + W->printString("Name", Method.getName()); + return Error::success(); +} + +Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR, + OverloadedMethodRecord &Method) { + W->printHex("MethodCount", Method.getNumOverloads()); + printTypeIndex("MethodListIndex", Method.getMethodList()); + W->printString("Name", Method.getName()); + return Error::success(); +} + +Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR, + DataMemberRecord &Field) { + printMemberAttributes(Field.getAccess(), MethodKind::Vanilla, + MethodOptions::None); + printTypeIndex("Type", Field.getType()); + W->printHex("FieldOffset", Field.getFieldOffset()); + W->printString("Name", Field.getName()); + return Error::success(); +} + +Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR, + StaticDataMemberRecord &Field) { + printMemberAttributes(Field.getAccess(), MethodKind::Vanilla, + MethodOptions::None); + printTypeIndex("Type", Field.getType()); + W->printString("Name", Field.getName()); + return Error::success(); +} + +Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR, + VFPtrRecord &VFTable) { + printTypeIndex("Type", VFTable.getType()); + return Error::success(); +} + +Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR, + EnumeratorRecord &Enum) { + printMemberAttributes(Enum.getAccess(), MethodKind::Vanilla, + MethodOptions::None); + W->printNumber("EnumValue", Enum.getValue()); + W->printString("Name", Enum.getName()); + return Error::success(); +} + +Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR, + BaseClassRecord &Base) { + printMemberAttributes(Base.getAccess(), MethodKind::Vanilla, + MethodOptions::None); + printTypeIndex("BaseType", Base.getBaseType()); + W->printHex("BaseOffset", Base.getBaseOffset()); + return Error::success(); +} + +Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR, + VirtualBaseClassRecord &Base) { + printMemberAttributes(Base.getAccess(), MethodKind::Vanilla, + MethodOptions::None); + printTypeIndex("BaseType", Base.getBaseType()); + printTypeIndex("VBPtrType", Base.getVBPtrType()); + W->printHex("VBPtrOffset", Base.getVBPtrOffset()); + W->printHex("VBTableIndex", Base.getVTableIndex()); + return Error::success(); +} + +Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR, + ListContinuationRecord &Cont) { + printTypeIndex("ContinuationIndex", Cont.getContinuationIndex()); + return Error::success(); +} diff --git a/lib/DebugInfo/CodeView/TypeDumper.cpp b/lib/DebugInfo/CodeView/TypeDumper.cpp deleted file mode 100644 index 4274d834076a..000000000000 --- a/lib/DebugInfo/CodeView/TypeDumper.cpp +++ /dev/null @@ -1,772 +0,0 @@ -//===-- TypeDumper.cpp - CodeView type info dumper --------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/CodeView/TypeDumper.h" -#include "llvm/ADT/SmallString.h" -#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" -#include "llvm/DebugInfo/CodeView/TypeDeserializer.h" -#include "llvm/DebugInfo/CodeView/TypeIndex.h" -#include "llvm/DebugInfo/CodeView/TypeRecord.h" -#include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h" -#include "llvm/DebugInfo/MSF/ByteStream.h" -#include "llvm/Support/ScopedPrinter.h" - -using namespace llvm; -using namespace llvm::codeview; - -/// The names here all end in "*". If the simple type is a pointer type, we -/// return the whole name. Otherwise we lop off the last character in our -/// StringRef. -static const EnumEntry SimpleTypeNames[] = { - {"void*", SimpleTypeKind::Void}, - {"*", SimpleTypeKind::NotTranslated}, - {"HRESULT*", SimpleTypeKind::HResult}, - {"signed char*", SimpleTypeKind::SignedCharacter}, - {"unsigned char*", SimpleTypeKind::UnsignedCharacter}, - {"char*", SimpleTypeKind::NarrowCharacter}, - {"wchar_t*", SimpleTypeKind::WideCharacter}, - {"char16_t*", SimpleTypeKind::Character16}, - {"char32_t*", SimpleTypeKind::Character32}, - {"__int8*", SimpleTypeKind::SByte}, - {"unsigned __int8*", SimpleTypeKind::Byte}, - {"short*", SimpleTypeKind::Int16Short}, - {"unsigned short*", SimpleTypeKind::UInt16Short}, - {"__int16*", SimpleTypeKind::Int16}, - {"unsigned __int16*", SimpleTypeKind::UInt16}, - {"long*", SimpleTypeKind::Int32Long}, - {"unsigned long*", SimpleTypeKind::UInt32Long}, - {"int*", SimpleTypeKind::Int32}, - {"unsigned*", SimpleTypeKind::UInt32}, - {"__int64*", SimpleTypeKind::Int64Quad}, - {"unsigned __int64*", SimpleTypeKind::UInt64Quad}, - {"__int64*", SimpleTypeKind::Int64}, - {"unsigned __int64*", SimpleTypeKind::UInt64}, - {"__int128*", SimpleTypeKind::Int128}, - {"unsigned __int128*", SimpleTypeKind::UInt128}, - {"__half*", SimpleTypeKind::Float16}, - {"float*", SimpleTypeKind::Float32}, - {"float*", SimpleTypeKind::Float32PartialPrecision}, - {"__float48*", SimpleTypeKind::Float48}, - {"double*", SimpleTypeKind::Float64}, - {"long double*", SimpleTypeKind::Float80}, - {"__float128*", SimpleTypeKind::Float128}, - {"_Complex float*", SimpleTypeKind::Complex32}, - {"_Complex double*", SimpleTypeKind::Complex64}, - {"_Complex long double*", SimpleTypeKind::Complex80}, - {"_Complex __float128*", SimpleTypeKind::Complex128}, - {"bool*", SimpleTypeKind::Boolean8}, - {"__bool16*", SimpleTypeKind::Boolean16}, - {"__bool32*", SimpleTypeKind::Boolean32}, - {"__bool64*", SimpleTypeKind::Boolean64}, -}; - -static const EnumEntry LeafTypeNames[] = { -#define CV_TYPE(enum, val) {#enum, enum}, -#include "llvm/DebugInfo/CodeView/TypeRecords.def" -}; - -#define ENUM_ENTRY(enum_class, enum) \ - { #enum, std::underlying_type < enum_class > ::type(enum_class::enum) } - -static const EnumEntry ClassOptionNames[] = { - ENUM_ENTRY(ClassOptions, Packed), - ENUM_ENTRY(ClassOptions, HasConstructorOrDestructor), - ENUM_ENTRY(ClassOptions, HasOverloadedOperator), - ENUM_ENTRY(ClassOptions, Nested), - ENUM_ENTRY(ClassOptions, ContainsNestedClass), - ENUM_ENTRY(ClassOptions, HasOverloadedAssignmentOperator), - ENUM_ENTRY(ClassOptions, HasConversionOperator), - ENUM_ENTRY(ClassOptions, ForwardReference), - ENUM_ENTRY(ClassOptions, Scoped), - ENUM_ENTRY(ClassOptions, HasUniqueName), - ENUM_ENTRY(ClassOptions, Sealed), - ENUM_ENTRY(ClassOptions, Intrinsic), -}; - -static const EnumEntry MemberAccessNames[] = { - ENUM_ENTRY(MemberAccess, None), - ENUM_ENTRY(MemberAccess, Private), - ENUM_ENTRY(MemberAccess, Protected), - ENUM_ENTRY(MemberAccess, Public), -}; - -static const EnumEntry MethodOptionNames[] = { - ENUM_ENTRY(MethodOptions, Pseudo), - ENUM_ENTRY(MethodOptions, NoInherit), - ENUM_ENTRY(MethodOptions, NoConstruct), - ENUM_ENTRY(MethodOptions, CompilerGenerated), - ENUM_ENTRY(MethodOptions, Sealed), -}; - -static const EnumEntry MemberKindNames[] = { - ENUM_ENTRY(MethodKind, Vanilla), - ENUM_ENTRY(MethodKind, Virtual), - ENUM_ENTRY(MethodKind, Static), - ENUM_ENTRY(MethodKind, Friend), - ENUM_ENTRY(MethodKind, IntroducingVirtual), - ENUM_ENTRY(MethodKind, PureVirtual), - ENUM_ENTRY(MethodKind, PureIntroducingVirtual), -}; - -static const EnumEntry PtrKindNames[] = { - ENUM_ENTRY(PointerKind, Near16), - ENUM_ENTRY(PointerKind, Far16), - ENUM_ENTRY(PointerKind, Huge16), - ENUM_ENTRY(PointerKind, BasedOnSegment), - ENUM_ENTRY(PointerKind, BasedOnValue), - ENUM_ENTRY(PointerKind, BasedOnSegmentValue), - ENUM_ENTRY(PointerKind, BasedOnAddress), - ENUM_ENTRY(PointerKind, BasedOnSegmentAddress), - ENUM_ENTRY(PointerKind, BasedOnType), - ENUM_ENTRY(PointerKind, BasedOnSelf), - ENUM_ENTRY(PointerKind, Near32), - ENUM_ENTRY(PointerKind, Far32), - ENUM_ENTRY(PointerKind, Near64), -}; - -static const EnumEntry PtrModeNames[] = { - ENUM_ENTRY(PointerMode, Pointer), - ENUM_ENTRY(PointerMode, LValueReference), - ENUM_ENTRY(PointerMode, PointerToDataMember), - ENUM_ENTRY(PointerMode, PointerToMemberFunction), - ENUM_ENTRY(PointerMode, RValueReference), -}; - -static const EnumEntry PtrMemberRepNames[] = { - ENUM_ENTRY(PointerToMemberRepresentation, Unknown), - ENUM_ENTRY(PointerToMemberRepresentation, SingleInheritanceData), - ENUM_ENTRY(PointerToMemberRepresentation, MultipleInheritanceData), - ENUM_ENTRY(PointerToMemberRepresentation, VirtualInheritanceData), - ENUM_ENTRY(PointerToMemberRepresentation, GeneralData), - ENUM_ENTRY(PointerToMemberRepresentation, SingleInheritanceFunction), - ENUM_ENTRY(PointerToMemberRepresentation, MultipleInheritanceFunction), - ENUM_ENTRY(PointerToMemberRepresentation, VirtualInheritanceFunction), - ENUM_ENTRY(PointerToMemberRepresentation, GeneralFunction), -}; - -static const EnumEntry TypeModifierNames[] = { - ENUM_ENTRY(ModifierOptions, Const), - ENUM_ENTRY(ModifierOptions, Volatile), - ENUM_ENTRY(ModifierOptions, Unaligned), -}; - -static const EnumEntry CallingConventions[] = { - ENUM_ENTRY(CallingConvention, NearC), - ENUM_ENTRY(CallingConvention, FarC), - ENUM_ENTRY(CallingConvention, NearPascal), - ENUM_ENTRY(CallingConvention, FarPascal), - ENUM_ENTRY(CallingConvention, NearFast), - ENUM_ENTRY(CallingConvention, FarFast), - ENUM_ENTRY(CallingConvention, NearStdCall), - ENUM_ENTRY(CallingConvention, FarStdCall), - ENUM_ENTRY(CallingConvention, NearSysCall), - ENUM_ENTRY(CallingConvention, FarSysCall), - ENUM_ENTRY(CallingConvention, ThisCall), - ENUM_ENTRY(CallingConvention, MipsCall), - ENUM_ENTRY(CallingConvention, Generic), - ENUM_ENTRY(CallingConvention, AlphaCall), - ENUM_ENTRY(CallingConvention, PpcCall), - ENUM_ENTRY(CallingConvention, SHCall), - ENUM_ENTRY(CallingConvention, ArmCall), - ENUM_ENTRY(CallingConvention, AM33Call), - ENUM_ENTRY(CallingConvention, TriCall), - ENUM_ENTRY(CallingConvention, SH5Call), - ENUM_ENTRY(CallingConvention, M32RCall), - ENUM_ENTRY(CallingConvention, ClrCall), - ENUM_ENTRY(CallingConvention, Inline), - ENUM_ENTRY(CallingConvention, NearVector), -}; - -static const EnumEntry FunctionOptionEnum[] = { - ENUM_ENTRY(FunctionOptions, CxxReturnUdt), - ENUM_ENTRY(FunctionOptions, Constructor), - ENUM_ENTRY(FunctionOptions, ConstructorWithVirtualBases), -}; - -#undef ENUM_ENTRY - -static StringRef getLeafTypeName(TypeLeafKind LT) { - switch (LT) { -#define TYPE_RECORD(ename, value, name) \ - case ename: \ - return #name; -#include "llvm/DebugInfo/CodeView/TypeRecords.def" - default: - break; - } - return "UnknownLeaf"; -} - -Error CVTypeDumper::visitTypeBegin(CVRecord &Record) { - assert(!IsInFieldList); - // Reset Name to the empty string. If the visitor sets it, we know it. - Name = ""; - - W->startLine() << getLeafTypeName(Record.Type); - W->getOStream() << " (" << HexNumber(getNextTypeIndex()) << ")"; - W->getOStream() << " {\n"; - W->indent(); - W->printEnum("TypeLeafKind", unsigned(Record.Type), - makeArrayRef(LeafTypeNames)); - if (Record.Type == LF_FIELDLIST) { - // Record that we're in a field list so that members do not get assigned - // type indices. - IsInFieldList = true; - } - return Error::success(); -} - -Error CVTypeDumper::visitTypeEnd(CVRecord &Record) { - if (Record.Type == LF_FIELDLIST) { - assert(IsInFieldList); - IsInFieldList = false; - } - assert(!IsInFieldList); - - // Record every type that is not a field list member, even if Name is empty. - // CVUDTNames is indexed by type index, and must have one entry for every - // type. Field list members are not recorded, and are only referenced by - // their containing field list record. - recordType(Name); - - if (PrintRecordBytes) - W->printBinaryBlock("LeafData", getBytesAsCharacters(Record.content())); - - W->unindent(); - W->startLine() << "}\n"; - return Error::success(); -} - -Error CVTypeDumper::visitMemberBegin(CVMemberRecord &Record) { - assert(IsInFieldList); - // Reset Name to the empty string. If the visitor sets it, we know it. - Name = ""; - - W->startLine() << getLeafTypeName(Record.Kind); - W->getOStream() << " {\n"; - W->indent(); - W->printEnum("TypeLeafKind", unsigned(Record.Kind), - makeArrayRef(LeafTypeNames)); - return Error::success(); -} - -Error CVTypeDumper::visitMemberEnd(CVMemberRecord &Record) { - assert(IsInFieldList); - if (PrintRecordBytes) - W->printBinaryBlock("LeafData", getBytesAsCharacters(Record.Data)); - - W->unindent(); - W->startLine() << "}\n"; - return Error::success(); -} - -Error CVTypeDumper::visitKnownRecord(CVRecord &CVR, - FieldListRecord &FieldList) { - CVTypeVisitor Visitor(*this); - if (auto EC = Visitor.visitFieldListMemberStream(FieldList.Data)) - return EC; - - Name = ""; - return Error::success(); -} - -Error CVTypeDumper::visitKnownRecord(CVRecord &CVR, - StringIdRecord &String) { - printTypeIndex("Id", String.getId()); - W->printString("StringData", String.getString()); - // Put this in CVUDTNames so it gets printed with LF_UDT_SRC_LINE. - Name = String.getString(); - return Error::success(); -} - -Error CVTypeDumper::visitKnownRecord(CVRecord &CVR, - ArgListRecord &Args) { - auto Indices = Args.getIndices(); - uint32_t Size = Indices.size(); - W->printNumber("NumArgs", Size); - ListScope Arguments(*W, "Arguments"); - SmallString<256> TypeName("("); - for (uint32_t I = 0; I < Size; ++I) { - printTypeIndex("ArgType", Indices[I]); - StringRef ArgTypeName = getTypeName(Indices[I]); - TypeName.append(ArgTypeName); - if (I + 1 != Size) - TypeName.append(", "); - } - TypeName.push_back(')'); - Name = saveName(TypeName); - return Error::success(); -} - -Error CVTypeDumper::visitKnownRecord(CVRecord &CVR, - ClassRecord &Class) { - uint16_t Props = static_cast(Class.getOptions()); - W->printNumber("MemberCount", Class.getMemberCount()); - W->printFlags("Properties", Props, makeArrayRef(ClassOptionNames)); - printTypeIndex("FieldList", Class.getFieldList()); - printTypeIndex("DerivedFrom", Class.getDerivationList()); - printTypeIndex("VShape", Class.getVTableShape()); - W->printNumber("SizeOf", Class.getSize()); - W->printString("Name", Class.getName()); - if (Props & uint16_t(ClassOptions::HasUniqueName)) - W->printString("LinkageName", Class.getUniqueName()); - Name = Class.getName(); - return Error::success(); -} - -Error CVTypeDumper::visitKnownRecord(CVRecord &CVR, - UnionRecord &Union) { - uint16_t Props = static_cast(Union.getOptions()); - W->printNumber("MemberCount", Union.getMemberCount()); - W->printFlags("Properties", Props, makeArrayRef(ClassOptionNames)); - printTypeIndex("FieldList", Union.getFieldList()); - W->printNumber("SizeOf", Union.getSize()); - W->printString("Name", Union.getName()); - if (Props & uint16_t(ClassOptions::HasUniqueName)) - W->printString("LinkageName", Union.getUniqueName()); - Name = Union.getName(); - return Error::success(); -} - -Error CVTypeDumper::visitKnownRecord(CVRecord &CVR, - EnumRecord &Enum) { - uint16_t Props = static_cast(Enum.getOptions()); - W->printNumber("NumEnumerators", Enum.getMemberCount()); - W->printFlags("Properties", uint16_t(Enum.getOptions()), - makeArrayRef(ClassOptionNames)); - printTypeIndex("UnderlyingType", Enum.getUnderlyingType()); - printTypeIndex("FieldListType", Enum.getFieldList()); - W->printString("Name", Enum.getName()); - if (Props & uint16_t(ClassOptions::HasUniqueName)) - W->printString("LinkageName", Enum.getUniqueName()); - Name = Enum.getName(); - return Error::success(); -} - -Error CVTypeDumper::visitKnownRecord(CVRecord &CVR, - ArrayRecord &AT) { - printTypeIndex("ElementType", AT.getElementType()); - printTypeIndex("IndexType", AT.getIndexType()); - W->printNumber("SizeOf", AT.getSize()); - W->printString("Name", AT.getName()); - Name = AT.getName(); - return Error::success(); -} - -Error CVTypeDumper::visitKnownRecord(CVRecord &CVR, - VFTableRecord &VFT) { - printTypeIndex("CompleteClass", VFT.getCompleteClass()); - printTypeIndex("OverriddenVFTable", VFT.getOverriddenVTable()); - W->printHex("VFPtrOffset", VFT.getVFPtrOffset()); - W->printString("VFTableName", VFT.getName()); - for (auto N : VFT.getMethodNames()) - W->printString("MethodName", N); - Name = VFT.getName(); - return Error::success(); -} - -Error CVTypeDumper::visitKnownRecord(CVRecord &CVR, - MemberFuncIdRecord &Id) { - printTypeIndex("ClassType", Id.getClassType()); - printTypeIndex("FunctionType", Id.getFunctionType()); - W->printString("Name", Id.getName()); - Name = Id.getName(); - return Error::success(); -} - -Error CVTypeDumper::visitKnownRecord(CVRecord &CVR, - ProcedureRecord &Proc) { - printTypeIndex("ReturnType", Proc.getReturnType()); - W->printEnum("CallingConvention", uint8_t(Proc.getCallConv()), - makeArrayRef(CallingConventions)); - W->printFlags("FunctionOptions", uint8_t(Proc.getOptions()), - makeArrayRef(FunctionOptionEnum)); - W->printNumber("NumParameters", Proc.getParameterCount()); - printTypeIndex("ArgListType", Proc.getArgumentList()); - - StringRef ReturnTypeName = getTypeName(Proc.getReturnType()); - StringRef ArgListTypeName = getTypeName(Proc.getArgumentList()); - SmallString<256> TypeName(ReturnTypeName); - TypeName.push_back(' '); - TypeName.append(ArgListTypeName); - Name = saveName(TypeName); - return Error::success(); -} - -Error CVTypeDumper::visitKnownRecord(CVRecord &CVR, - MemberFunctionRecord &MF) { - printTypeIndex("ReturnType", MF.getReturnType()); - printTypeIndex("ClassType", MF.getClassType()); - printTypeIndex("ThisType", MF.getThisType()); - W->printEnum("CallingConvention", uint8_t(MF.getCallConv()), - makeArrayRef(CallingConventions)); - W->printFlags("FunctionOptions", uint8_t(MF.getOptions()), - makeArrayRef(FunctionOptionEnum)); - W->printNumber("NumParameters", MF.getParameterCount()); - printTypeIndex("ArgListType", MF.getArgumentList()); - W->printNumber("ThisAdjustment", MF.getThisPointerAdjustment()); - - StringRef ReturnTypeName = getTypeName(MF.getReturnType()); - StringRef ClassTypeName = getTypeName(MF.getClassType()); - StringRef ArgListTypeName = getTypeName(MF.getArgumentList()); - SmallString<256> TypeName(ReturnTypeName); - TypeName.push_back(' '); - TypeName.append(ClassTypeName); - TypeName.append("::"); - TypeName.append(ArgListTypeName); - Name = saveName(TypeName); - return Error::success(); -} - -Error CVTypeDumper::visitKnownRecord(CVRecord &CVR, - MethodOverloadListRecord &MethodList) { - for (auto &M : MethodList.getMethods()) { - ListScope S(*W, "Method"); - printMemberAttributes(M.getAccess(), M.getMethodKind(), M.getOptions()); - printTypeIndex("Type", M.getType()); - if (M.isIntroducingVirtual()) - W->printHex("VFTableOffset", M.getVFTableOffset()); - } - return Error::success(); -} - -Error CVTypeDumper::visitKnownRecord(CVRecord &CVR, - FuncIdRecord &Func) { - printTypeIndex("ParentScope", Func.getParentScope()); - printTypeIndex("FunctionType", Func.getFunctionType()); - W->printString("Name", Func.getName()); - Name = Func.getName(); - return Error::success(); -} - -Error CVTypeDumper::visitKnownRecord(CVRecord &CVR, - TypeServer2Record &TS) { - W->printBinary("Signature", TS.getGuid()); - W->printNumber("Age", TS.getAge()); - W->printString("Name", TS.getName()); - Name = TS.getName(); - return Error::success(); -} - -Error CVTypeDumper::visitKnownRecord(CVRecord &CVR, - PointerRecord &Ptr) { - printTypeIndex("PointeeType", Ptr.getReferentType()); - W->printHex("PointerAttributes", uint32_t(Ptr.getOptions())); - W->printEnum("PtrType", unsigned(Ptr.getPointerKind()), - makeArrayRef(PtrKindNames)); - W->printEnum("PtrMode", unsigned(Ptr.getMode()), makeArrayRef(PtrModeNames)); - - W->printNumber("IsFlat", Ptr.isFlat()); - W->printNumber("IsConst", Ptr.isConst()); - W->printNumber("IsVolatile", Ptr.isVolatile()); - W->printNumber("IsUnaligned", Ptr.isUnaligned()); - W->printNumber("SizeOf", Ptr.getSize()); - - if (Ptr.isPointerToMember()) { - const MemberPointerInfo &MI = Ptr.getMemberInfo(); - - printTypeIndex("ClassType", MI.getContainingType()); - W->printEnum("Representation", uint16_t(MI.getRepresentation()), - makeArrayRef(PtrMemberRepNames)); - - StringRef PointeeName = getTypeName(Ptr.getReferentType()); - StringRef ClassName = getTypeName(MI.getContainingType()); - SmallString<256> TypeName(PointeeName); - TypeName.push_back(' '); - TypeName.append(ClassName); - TypeName.append("::*"); - Name = saveName(TypeName); - } else { - SmallString<256> TypeName; - if (Ptr.isConst()) - TypeName.append("const "); - if (Ptr.isVolatile()) - TypeName.append("volatile "); - if (Ptr.isUnaligned()) - TypeName.append("__unaligned "); - - TypeName.append(getTypeName(Ptr.getReferentType())); - - if (Ptr.getMode() == PointerMode::LValueReference) - TypeName.append("&"); - else if (Ptr.getMode() == PointerMode::RValueReference) - TypeName.append("&&"); - else if (Ptr.getMode() == PointerMode::Pointer) - TypeName.append("*"); - - if (!TypeName.empty()) - Name = saveName(TypeName); - } - return Error::success(); -} - -Error CVTypeDumper::visitKnownRecord(CVRecord &CVR, - ModifierRecord &Mod) { - uint16_t Mods = static_cast(Mod.getModifiers()); - printTypeIndex("ModifiedType", Mod.getModifiedType()); - W->printFlags("Modifiers", Mods, makeArrayRef(TypeModifierNames)); - - StringRef ModifiedName = getTypeName(Mod.getModifiedType()); - SmallString<256> TypeName; - if (Mods & uint16_t(ModifierOptions::Const)) - TypeName.append("const "); - if (Mods & uint16_t(ModifierOptions::Volatile)) - TypeName.append("volatile "); - if (Mods & uint16_t(ModifierOptions::Unaligned)) - TypeName.append("__unaligned "); - TypeName.append(ModifiedName); - Name = saveName(TypeName); - return Error::success(); -} - -Error CVTypeDumper::visitKnownRecord(CVRecord &CVR, - BitFieldRecord &BitField) { - printTypeIndex("Type", BitField.getType()); - W->printNumber("BitSize", BitField.getBitSize()); - W->printNumber("BitOffset", BitField.getBitOffset()); - return Error::success(); -} - -Error CVTypeDumper::visitKnownRecord(CVRecord &CVR, - VFTableShapeRecord &Shape) { - W->printNumber("VFEntryCount", Shape.getEntryCount()); - Name = saveName(""); - return Error::success(); -} - -Error CVTypeDumper::visitKnownRecord(CVRecord &CVR, - UdtSourceLineRecord &Line) { - printTypeIndex("UDT", Line.getUDT()); - printTypeIndex("SourceFile", Line.getSourceFile()); - W->printNumber("LineNumber", Line.getLineNumber()); - return Error::success(); -} - -Error CVTypeDumper::visitKnownRecord(CVRecord &CVR, - UdtModSourceLineRecord &Line) { - printTypeIndex("UDT", Line.getUDT()); - printTypeIndex("SourceFile", Line.getSourceFile()); - W->printNumber("LineNumber", Line.getLineNumber()); - W->printNumber("Module", Line.getModule()); - return Error::success(); -} - -Error CVTypeDumper::visitKnownRecord(CVRecord &CVR, - BuildInfoRecord &Args) { - W->printNumber("NumArgs", static_cast(Args.getArgs().size())); - - ListScope Arguments(*W, "Arguments"); - for (auto Arg : Args.getArgs()) { - printTypeIndex("ArgType", Arg); - } - return Error::success(); -} - -void CVTypeDumper::printMemberAttributes(MemberAttributes Attrs) { - return printMemberAttributes(Attrs.getAccess(), Attrs.getMethodKind(), - Attrs.getFlags()); -} - -void CVTypeDumper::printMemberAttributes(MemberAccess Access, MethodKind Kind, - MethodOptions Options) { - W->printEnum("AccessSpecifier", uint8_t(Access), - makeArrayRef(MemberAccessNames)); - // Data members will be vanilla. Don't try to print a method kind for them. - if (Kind != MethodKind::Vanilla) - W->printEnum("MethodKind", unsigned(Kind), makeArrayRef(MemberKindNames)); - if (Options != MethodOptions::None) { - W->printFlags("MethodOptions", unsigned(Options), - makeArrayRef(MethodOptionNames)); - } -} - -Error CVTypeDumper::visitUnknownMember(CVMemberRecord &Record) { - W->printHex("UnknownMember", unsigned(Record.Kind)); - return Error::success(); -} - -Error CVTypeDumper::visitUnknownType(CVRecord &Record) { - W->printEnum("Kind", uint16_t(Record.kind()), makeArrayRef(LeafTypeNames)); - W->printNumber("Length", uint32_t(Record.content().size())); - return Error::success(); -} - -Error CVTypeDumper::visitKnownMember(CVMemberRecord &CVR, - NestedTypeRecord &Nested) { - printTypeIndex("Type", Nested.getNestedType()); - W->printString("Name", Nested.getName()); - Name = Nested.getName(); - return Error::success(); -} - -Error CVTypeDumper::visitKnownMember(CVMemberRecord &CVR, - OneMethodRecord &Method) { - MethodKind K = Method.getMethodKind(); - printMemberAttributes(Method.getAccess(), K, Method.getOptions()); - printTypeIndex("Type", Method.getType()); - // If virtual, then read the vftable offset. - if (Method.isIntroducingVirtual()) - W->printHex("VFTableOffset", Method.getVFTableOffset()); - W->printString("Name", Method.getName()); - Name = Method.getName(); - return Error::success(); -} - -Error CVTypeDumper::visitKnownMember(CVMemberRecord &CVR, - OverloadedMethodRecord &Method) { - W->printHex("MethodCount", Method.getNumOverloads()); - printTypeIndex("MethodListIndex", Method.getMethodList()); - W->printString("Name", Method.getName()); - Name = Method.getName(); - return Error::success(); -} - -Error CVTypeDumper::visitKnownMember(CVMemberRecord &CVR, - DataMemberRecord &Field) { - printMemberAttributes(Field.getAccess(), MethodKind::Vanilla, - MethodOptions::None); - printTypeIndex("Type", Field.getType()); - W->printHex("FieldOffset", Field.getFieldOffset()); - W->printString("Name", Field.getName()); - Name = Field.getName(); - return Error::success(); -} - -Error CVTypeDumper::visitKnownMember(CVMemberRecord &CVR, - StaticDataMemberRecord &Field) { - printMemberAttributes(Field.getAccess(), MethodKind::Vanilla, - MethodOptions::None); - printTypeIndex("Type", Field.getType()); - W->printString("Name", Field.getName()); - Name = Field.getName(); - return Error::success(); -} - -Error CVTypeDumper::visitKnownMember(CVMemberRecord &CVR, - VFPtrRecord &VFTable) { - printTypeIndex("Type", VFTable.getType()); - return Error::success(); -} - -Error CVTypeDumper::visitKnownMember(CVMemberRecord &CVR, - EnumeratorRecord &Enum) { - printMemberAttributes(Enum.getAccess(), MethodKind::Vanilla, - MethodOptions::None); - W->printNumber("EnumValue", Enum.getValue()); - W->printString("Name", Enum.getName()); - Name = Enum.getName(); - return Error::success(); -} - -Error CVTypeDumper::visitKnownMember(CVMemberRecord &CVR, - BaseClassRecord &Base) { - printMemberAttributes(Base.getAccess(), MethodKind::Vanilla, - MethodOptions::None); - printTypeIndex("BaseType", Base.getBaseType()); - W->printHex("BaseOffset", Base.getBaseOffset()); - return Error::success(); -} - -Error CVTypeDumper::visitKnownMember(CVMemberRecord &CVR, - VirtualBaseClassRecord &Base) { - printMemberAttributes(Base.getAccess(), MethodKind::Vanilla, - MethodOptions::None); - printTypeIndex("BaseType", Base.getBaseType()); - printTypeIndex("VBPtrType", Base.getVBPtrType()); - W->printHex("VBPtrOffset", Base.getVBPtrOffset()); - W->printHex("VBTableIndex", Base.getVTableIndex()); - return Error::success(); -} - -Error CVTypeDumper::visitKnownMember(CVMemberRecord &CVR, - ListContinuationRecord &Cont) { - printTypeIndex("ContinuationIndex", Cont.getContinuationIndex()); - return Error::success(); -} - -StringRef CVTypeDumper::getTypeName(TypeIndex TI) { - if (TI.isNoneType()) - return ""; - - if (TI.isSimple()) { - // This is a simple type. - for (const auto &SimpleTypeName : SimpleTypeNames) { - if (SimpleTypeName.Value == TI.getSimpleKind()) { - if (TI.getSimpleMode() == SimpleTypeMode::Direct) - return SimpleTypeName.Name.drop_back(1); - // Otherwise, this is a pointer type. We gloss over the distinction - // between near, far, 64, 32, etc, and just give a pointer type. - return SimpleTypeName.Name; - } - } - return ""; - } - - // User-defined type. - StringRef UDTName; - unsigned UDTIndex = TI.getIndex() - 0x1000; - if (UDTIndex < CVUDTNames.size()) - return CVUDTNames[UDTIndex]; - - return ""; -} - -void CVTypeDumper::printTypeIndex(StringRef FieldName, TypeIndex TI) { - StringRef TypeName; - if (!TI.isNoneType()) - TypeName = getTypeName(TI); - if (!TypeName.empty()) - W->printHex(FieldName, TypeName, TI.getIndex()); - else - W->printHex(FieldName, TI.getIndex()); -} - -Error CVTypeDumper::dump(const CVRecord &Record) { - assert(W && "printer should not be null"); - TypeDeserializer Deserializer; - TypeVisitorCallbackPipeline Pipeline; - Pipeline.addCallbackToPipeline(Deserializer); - Pipeline.addCallbackToPipeline(*this); - - CVTypeVisitor Visitor(Pipeline); - - CVRecord RecordCopy = Record; - if (auto EC = Visitor.visitTypeRecord(RecordCopy)) - return EC; - return Error::success(); -} - -Error CVTypeDumper::dump(const CVTypeArray &Types) { - assert(W && "printer should not be null"); - TypeDeserializer Deserializer; - TypeVisitorCallbackPipeline Pipeline; - Pipeline.addCallbackToPipeline(Deserializer); - Pipeline.addCallbackToPipeline(*this); - - CVTypeVisitor Visitor(Pipeline); - - if (auto EC = Visitor.visitTypeStream(Types)) - return EC; - return Error::success(); -} - -Error CVTypeDumper::dump(ArrayRef Data) { - msf::ByteStream Stream(Data); - CVTypeArray Types; - msf::StreamReader Reader(Stream); - if (auto EC = Reader.readArray(Types, Reader.getLength())) - return EC; - - return dump(Types); -} - -void CVTypeDumper::setPrinter(ScopedPrinter *P) { - static ScopedPrinter NullP(llvm::nulls()); - W = P ? P : &NullP; -} diff --git a/lib/DebugInfo/DWARF/DWARFAbbreviationDeclaration.cpp b/lib/DebugInfo/DWARF/DWARFAbbreviationDeclaration.cpp index 6126470aa099..08bc74a81e9a 100644 --- a/lib/DebugInfo/DWARF/DWARFAbbreviationDeclaration.cpp +++ b/lib/DebugInfo/DWARF/DWARFAbbreviationDeclaration.cpp @@ -56,13 +56,20 @@ DWARFAbbreviationDeclaration::extract(DataExtractor Data, auto A = static_cast(Data.getULEB128(OffsetPtr)); auto F = static_cast
(Data.getULEB128(OffsetPtr)); if (A && F) { - auto FixedFormByteSize = DWARFFormValue::getFixedByteSize(F); - AttributeSpecs.push_back(AttributeSpec(A, F, FixedFormByteSize)); + Optional V; + bool IsImplicitConst = (F == DW_FORM_implicit_const); + if (IsImplicitConst) + V = Data.getSLEB128(OffsetPtr); + else if (auto Size = DWARFFormValue::getFixedByteSize(F)) + V = *Size; + AttributeSpecs.push_back(AttributeSpec(A, F, V)); + if (IsImplicitConst) + continue; // If this abbrevation still has a fixed byte size, then update the // FixedAttributeSize as needed. if (FixedAttributeSize) { - if (FixedFormByteSize) - FixedAttributeSize->NumBytes += *FixedFormByteSize; + if (V) + FixedAttributeSize->NumBytes += *V; else { switch (F) { case DW_FORM_addr: @@ -129,6 +136,8 @@ void DWARFAbbreviationDeclaration::dump(raw_ostream &OS) const { OS << formString; else OS << format("DW_FORM_Unknown_%x", Spec.Form); + if (Spec.isImplicitConst()) + OS << '\t' << *Spec.ByteSizeOrValue; OS << '\n'; } OS << '\n'; @@ -160,11 +169,15 @@ Optional DWARFAbbreviationDeclaration::getAttributeValue( if (*MatchAttrIndex == AttrIndex) { // We have arrived at the attribute to extract, extract if from Offset. DWARFFormValue FormValue(Spec.Form); + if (Spec.isImplicitConst()) { + FormValue.setSValue(*Spec.ByteSizeOrValue); + return FormValue; + } if (FormValue.extractValue(DebugInfoData, &Offset, &U)) return FormValue; } // March Offset along until we get to the attribute we want. - if (Optional FixedSize = Spec.getByteSize(U)) + if (auto FixedSize = Spec.getByteSize(U)) Offset += *FixedSize; else DWARFFormValue::skipValue(Spec.Form, DebugInfoData, &Offset, &U); @@ -185,9 +198,17 @@ size_t DWARFAbbreviationDeclaration::FixedSizeInfo::getByteSize( return ByteSize; } -Optional DWARFAbbreviationDeclaration::AttributeSpec::getByteSize( +Optional DWARFAbbreviationDeclaration::AttributeSpec::getByteSize( const DWARFUnit &U) const { - return ByteSize ? ByteSize : DWARFFormValue::getFixedByteSize(Form, &U); + if (isImplicitConst()) + return 0; + if (ByteSizeOrValue) + return ByteSizeOrValue; + Optional S; + auto FixedByteSize = DWARFFormValue::getFixedByteSize(Form, &U); + if (FixedByteSize) + S = *FixedByteSize; + return S; } Optional DWARFAbbreviationDeclaration::getFixedAttributesByteSize( diff --git a/lib/DebugInfo/DWARF/DWARFContext.cpp b/lib/DebugInfo/DWARF/DWARFContext.cpp index 7df66c76e8b5..77f6f65ee131 100644 --- a/lib/DebugInfo/DWARF/DWARFContext.cpp +++ b/lib/DebugInfo/DWARF/DWARFContext.cpp @@ -14,6 +14,7 @@ #include "llvm/DebugInfo/DWARF/DWARFDebugArangeSet.h" #include "llvm/DebugInfo/DWARF/DWARFDebugPubTable.h" #include "llvm/DebugInfo/DWARF/DWARFUnitIndex.h" +#include "llvm/Object/Decompressor.h" #include "llvm/Object/MachO.h" #include "llvm/Object/RelocVisitor.h" #include "llvm/Support/Compression.h" @@ -577,66 +578,6 @@ DWARFContext::getInliningInfoForAddress(uint64_t Address, return InliningInfo; } -static bool consumeCompressedGnuHeader(StringRef &data, - uint64_t &OriginalSize) { - // Consume "ZLIB" prefix. - if (!data.startswith("ZLIB")) - return false; - data = data.substr(4); - // Consume uncompressed section size (big-endian 8 bytes). - DataExtractor extractor(data, false, 8); - uint32_t Offset = 0; - OriginalSize = extractor.getU64(&Offset); - if (Offset == 0) - return false; - data = data.substr(Offset); - return true; -} - -static bool consumeCompressedZLibHeader(StringRef &Data, uint64_t &OriginalSize, - bool IsLE, bool Is64Bit) { - using namespace ELF; - uint64_t HdrSize = Is64Bit ? sizeof(Elf64_Chdr) : sizeof(Elf32_Chdr); - if (Data.size() < HdrSize) - return false; - - DataExtractor Extractor(Data, IsLE, 0); - uint32_t Offset = 0; - if (Extractor.getUnsigned(&Offset, Is64Bit ? sizeof(Elf64_Word) - : sizeof(Elf32_Word)) != - ELFCOMPRESS_ZLIB) - return false; - - // Skip Elf64_Chdr::ch_reserved field. - if (Is64Bit) - Offset += sizeof(Elf64_Word); - - OriginalSize = Extractor.getUnsigned(&Offset, Is64Bit ? sizeof(Elf64_Xword) - : sizeof(Elf32_Word)); - Data = Data.substr(HdrSize); - return true; -} - -static bool tryDecompress(StringRef &Name, StringRef &Data, - SmallString<32> &Out, bool ZLibStyle, bool IsLE, - bool Is64Bit) { - if (!zlib::isAvailable()) - return false; - - uint64_t OriginalSize; - bool Result = - ZLibStyle ? consumeCompressedZLibHeader(Data, OriginalSize, IsLE, Is64Bit) - : consumeCompressedGnuHeader(Data, OriginalSize); - - if (!Result || zlib::uncompress(Data, Out, OriginalSize) != zlib::StatusOK) - return false; - - // gnu-style names are started from "z", consume that. - if (!ZLibStyle) - Name = Name.substr(1); - return true; -} - DWARFContextInMemory::DWARFContextInMemory(const object::ObjectFile &Obj, const LoadedObjectInfo *L) : IsLittleEndian(Obj.isLittleEndian()), @@ -660,18 +601,23 @@ DWARFContextInMemory::DWARFContextInMemory(const object::ObjectFile &Obj, if (!L || !L->getLoadedSectionContents(*RelocatedSection,data)) Section.getContents(data); - name = name.substr(name.find_first_not_of("._")); // Skip . and _ prefixes. - - bool ZLibStyleCompressed = Section.isCompressed(); - if (ZLibStyleCompressed || name.startswith("zdebug_")) { + if (Decompressor::isCompressed(Section)) { + Expected Decompressor = + Decompressor::create(name, data, IsLittleEndian, AddressSize == 8); + if (!Decompressor) + continue; SmallString<32> Out; - if (!tryDecompress(name, data, Out, ZLibStyleCompressed, IsLittleEndian, - AddressSize == 8)) + if (auto Err = Decompressor->decompress(Out)) continue; UncompressedSections.emplace_back(std::move(Out)); data = UncompressedSections.back(); } + // Compressed sections names in GNU style starts from ".z", + // at this point section is decompressed and we drop compression prefix. + name = name.substr( + name.find_first_not_of("._z")); // Skip ".", "z" and "_" prefixes. + StringRef *SectionData = StringSwitch(name) .Case("debug_info", &InfoSection.Data) diff --git a/lib/DebugInfo/DWARF/DWARFDebugInfoEntry.cpp b/lib/DebugInfo/DWARF/DWARFDebugInfoEntry.cpp index 9f623e4954c8..c487e1dca7c6 100644 --- a/lib/DebugInfo/DWARF/DWARFDebugInfoEntry.cpp +++ b/lib/DebugInfo/DWARF/DWARFDebugInfoEntry.cpp @@ -57,7 +57,7 @@ bool DWARFDebugInfoEntry::extractFast(const DWARFUnit &U, uint32_t *OffsetPtr, // Skip all data in the .debug_info for the attributes for (const auto &AttrSpec : AbbrevDecl->attributes()) { // Check if this attribute has a fixed byte size. - if (Optional FixedSize = AttrSpec.getByteSize(U)) { + if (auto FixedSize = AttrSpec.getByteSize(U)) { // Attribute byte size if fixed, just add the size to the offset. *OffsetPtr += *FixedSize; } else if (!DWARFFormValue::skipValue(AttrSpec.Form, DebugInfoData, diff --git a/lib/DebugInfo/DWARF/DWARFDie.cpp b/lib/DebugInfo/DWARF/DWARFDie.cpp index 2aac3474654f..89b83b11ab68 100644 --- a/lib/DebugInfo/DWARF/DWARFDie.cpp +++ b/lib/DebugInfo/DWARF/DWARFDie.cpp @@ -152,13 +152,6 @@ const char *DWARFDie::getAttributeValueAsString(dwarf::Attribute Attr, return Result.hasValue() ? Result.getValue() : FailValue; } -uint64_t DWARFDie::getAttributeValueAsAddress(dwarf::Attribute Attr, - uint64_t FailValue) const { - if (auto Value = getAttributeValueAsAddress(Attr)) - return *Value; - return FailValue; -} - Optional DWARFDie::getAttributeValueAsAddress(dwarf::Attribute Attr) const { if (auto FormValue = getAttributeValue(Attr)) @@ -166,13 +159,6 @@ DWARFDie::getAttributeValueAsAddress(dwarf::Attribute Attr) const { return None; } -int64_t DWARFDie::getAttributeValueAsSignedConstant(dwarf::Attribute Attr, - int64_t FailValue) const { - if (auto Value = getAttributeValueAsSignedConstant(Attr)) - return *Value; - return FailValue; -} - Optional DWARFDie::getAttributeValueAsSignedConstant(dwarf::Attribute Attr) const { if (auto FormValue = getAttributeValue(Attr)) @@ -180,15 +166,6 @@ DWARFDie::getAttributeValueAsSignedConstant(dwarf::Attribute Attr) const { return None; } -uint64_t -DWARFDie::getAttributeValueAsUnsignedConstant(dwarf::Attribute Attr, - uint64_t FailValue) const { - if (auto Value = getAttributeValueAsUnsignedConstant(Attr)) - return *Value; - return FailValue; -} - - Optional DWARFDie::getAttributeValueAsUnsignedConstant(dwarf::Attribute Attr) const { if (auto FormValue = getAttributeValue(Attr)) @@ -196,14 +173,6 @@ DWARFDie::getAttributeValueAsUnsignedConstant(dwarf::Attribute Attr) const { return None; } -uint64_t DWARFDie::getAttributeValueAsReference(dwarf::Attribute Attr, - uint64_t FailValue) const { - if (auto Value = getAttributeValueAsReference(Attr)) - return *Value; - return FailValue; -} - - Optional DWARFDie::getAttributeValueAsReference(dwarf::Attribute Attr) const { if (auto FormValue = getAttributeValue(Attr)) @@ -211,13 +180,6 @@ DWARFDie::getAttributeValueAsReference(dwarf::Attribute Attr) const { return None; } -uint64_t DWARFDie::getAttributeValueAsSectionOffset(dwarf::Attribute Attr, - uint64_t FailValue) const { - if (auto Value = getAttributeValueAsSectionOffset(Attr)) - return *Value; - return FailValue; -} - Optional DWARFDie::getAttributeValueAsSectionOffset(dwarf::Attribute Attr) const { if (auto FormValue = getAttributeValue(Attr)) @@ -345,9 +307,10 @@ DWARFDie::getName(DINameKind Kind) const { void DWARFDie::getCallerFrame(uint32_t &CallFile, uint32_t &CallLine, uint32_t &CallColumn) const { - CallFile = getAttributeValueAsUnsignedConstant(DW_AT_call_file, 0); - CallLine = getAttributeValueAsUnsignedConstant(DW_AT_call_line, 0); - CallColumn = getAttributeValueAsUnsignedConstant(DW_AT_call_column, 0); + CallFile = getAttributeValueAsUnsignedConstant(DW_AT_call_file).getValueOr(0); + CallLine = getAttributeValueAsUnsignedConstant(DW_AT_call_line).getValueOr(0); + CallColumn = + getAttributeValueAsUnsignedConstant(DW_AT_call_column).getValueOr(0); } void DWARFDie::dump(raw_ostream &OS, unsigned RecurseDepth, diff --git a/lib/DebugInfo/DWARF/DWARFFormValue.cpp b/lib/DebugInfo/DWARF/DWARFFormValue.cpp index e48a6f0981b7..dc9310dc4e89 100644 --- a/lib/DebugInfo/DWARF/DWARFFormValue.cpp +++ b/lib/DebugInfo/DWARF/DWARFFormValue.cpp @@ -153,7 +153,7 @@ static Optional getFixedByteSize(dwarf::Form Form, const T *U) { return 16; case DW_FORM_implicit_const: - // The implicit value is stored in the abbreviation as a ULEB128, any + // The implicit value is stored in the abbreviation as a SLEB128, and // there no data in debug info. return 0; @@ -280,6 +280,8 @@ bool DWARFFormValue::isFormClass(DWARFFormValue::FormClass FC) const { case DW_FORM_GNU_str_index: case DW_FORM_GNU_strp_alt: return (FC == FC_String); + case DW_FORM_implicit_const: + return (FC == FC_Constant); default: break; } diff --git a/lib/DebugInfo/DWARF/DWARFUnit.cpp b/lib/DebugInfo/DWARF/DWARFUnit.cpp index 63fb0d3bc368..ee2c569b0bce 100644 --- a/lib/DebugInfo/DWARF/DWARFUnit.cpp +++ b/lib/DebugInfo/DWARF/DWARFUnit.cpp @@ -230,10 +230,12 @@ size_t DWARFUnit::extractDIEsIfNeeded(bool CUDieOnly) { BaseAddr = UnitDie.getAttributeValueAsAddress(DW_AT_entry_pc); if (BaseAddr) setBaseAddress(*BaseAddr); - AddrOffsetSectionBase = UnitDie.getAttributeValueAsSectionOffset( - DW_AT_GNU_addr_base, 0); - RangeSectionBase = UnitDie.getAttributeValueAsSectionOffset( - DW_AT_rnglists_base, 0); + AddrOffsetSectionBase = + UnitDie.getAttributeValueAsSectionOffset(DW_AT_GNU_addr_base) + .getValueOr(0); + RangeSectionBase = + UnitDie.getAttributeValueAsSectionOffset(DW_AT_rnglists_base) + .getValueOr(0); // Don't fall back to DW_AT_GNU_ranges_base: it should be ignored for // skeleton CU DIE, so that DWARF users not aware of it are not broken. } diff --git a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp index 8f6b1849169a..05615d3cc6cf 100644 --- a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp +++ b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp @@ -374,6 +374,9 @@ void RuntimeDyldELF::resolveAArch64Relocation(const SectionEntry &Section, write(isBE, TargetPtr, static_cast(Result & 0xffffffffU)); break; } + case ELF::R_AARCH64_PREL64: + write(isBE, TargetPtr, Value + Addend - FinalAddress); + break; case ELF::R_AARCH64_CALL26: // fallthrough case ELF::R_AARCH64_JUMP26: { // Operation: S+A-P. Set Call or B immediate value to bits fff_fffc of the diff --git a/lib/IR/AutoUpgrade.cpp b/lib/IR/AutoUpgrade.cpp index a87b9bec1ed2..e3a7bae02e0a 100644 --- a/lib/IR/AutoUpgrade.cpp +++ b/lib/IR/AutoUpgrade.cpp @@ -77,6 +77,11 @@ static bool UpgradeIntrinsicFunction1(Function *F, Function *&NewFn) { switch (Name[0]) { default: break; case 'a': { + if (Name.startswith("arm.rbit") || Name.startswith("aarch64.rbit")) { + NewFn = Intrinsic::getDeclaration(F->getParent(), Intrinsic::bitreverse, + F->arg_begin()->getType()); + return true; + } if (Name.startswith("arm.neon.vclz")) { Type* args[2] = { F->arg_begin()->getType(), @@ -1761,6 +1766,11 @@ void llvm::UpgradeIntrinsicCall(CallInst *CI, Function *NewFn) { return; } + case Intrinsic::bitreverse: + CI->replaceAllUsesWith(Builder.CreateCall(NewFn, {CI->getArgOperand(0)})); + CI->eraseFromParent(); + return; + case Intrinsic::ctlz: case Intrinsic::cttz: assert(CI->getNumArgOperands() == 1 && diff --git a/lib/IR/DIBuilder.cpp b/lib/IR/DIBuilder.cpp index 2ea572490b6d..d06161067f5f 100644 --- a/lib/IR/DIBuilder.cpp +++ b/lib/IR/DIBuilder.cpp @@ -90,6 +90,20 @@ void DIBuilder::finalize() { VMContext, SmallVector(AllImportedModules.begin(), AllImportedModules.end()))); + for (const auto &I : AllMacrosPerParent) { + // DIMacroNode's with nullptr parent are DICompileUnit direct children. + if (!I.first) { + CUNode->replaceMacros(MDTuple::get(VMContext, I.second.getArrayRef())); + continue; + } + // Otherwise, it must be a temporary DIMacroFile that need to be resolved. + auto *TMF = cast(I.first); + auto *MF = DIMacroFile::get(VMContext, dwarf::DW_MACINFO_start_file, + TMF->getLine(), TMF->getFile(), + getOrCreateMacroArray(I.second.getArrayRef())); + replaceTemporary(llvm::TempDIMacroNode(TMF), MF); + } + // Now that all temp nodes have been replaced or deleted, resolve remaining // cycles. for (const auto &N : UnresolvedNodes) @@ -179,6 +193,31 @@ DIFile *DIBuilder::createFile(StringRef Filename, StringRef Directory, return DIFile::get(VMContext, Filename, Directory, CSKind, Checksum); } +DIMacro *DIBuilder::createMacro(DIMacroFile *Parent, unsigned LineNumber, + unsigned MacroType, StringRef Name, + StringRef Value) { + assert(!Name.empty() && "Unable to create macro without name"); + assert((MacroType == dwarf::DW_MACINFO_undef || + MacroType == dwarf::DW_MACINFO_define) && + "Unexpected macro type"); + auto *M = DIMacro::get(VMContext, MacroType, LineNumber, Name, Value); + AllMacrosPerParent[Parent].insert(M); + return M; +} + +DIMacroFile *DIBuilder::createTempMacroFile(DIMacroFile *Parent, + unsigned LineNumber, DIFile *File) { + auto *MF = DIMacroFile::getTemporary(VMContext, dwarf::DW_MACINFO_start_file, + LineNumber, File, DIMacroNodeArray()) + .release(); + AllMacrosPerParent[Parent].insert(MF); + // Add the new temporary DIMacroFile to the macro per parent map as a parent. + // This is needed to assure DIMacroFile with no children to have an entry in + // the map. Otherwise, it will not be resolved in DIBuilder::finalize(). + AllMacrosPerParent.insert({MF, {}}); + return MF; +} + DIEnumerator *DIBuilder::createEnumerator(StringRef Name, int64_t Val) { assert(!Name.empty() && "Unable to create enumerator without name"); return DIEnumerator::get(VMContext, Val, Name); @@ -509,6 +548,11 @@ DINodeArray DIBuilder::getOrCreateArray(ArrayRef Elements) { return MDTuple::get(VMContext, Elements); } +DIMacroNodeArray +DIBuilder::getOrCreateMacroArray(ArrayRef Elements) { + return MDTuple::get(VMContext, Elements); +} + DITypeRefArray DIBuilder::getOrCreateTypeArray(ArrayRef Elements) { SmallVector Elts; for (unsigned i = 0, e = Elements.size(); i != e; ++i) { diff --git a/lib/IR/Globals.cpp b/lib/IR/Globals.cpp index 31f89514151c..6f7356524d38 100644 --- a/lib/IR/Globals.cpp +++ b/lib/IR/Globals.cpp @@ -24,6 +24,7 @@ #include "llvm/IR/Operator.h" #include "llvm/Support/Error.h" #include "llvm/Support/ErrorHandling.h" +#include "LLVMContextImpl.h" using namespace llvm; //===----------------------------------------------------------------------===// @@ -37,6 +38,10 @@ static_assert(sizeof(GlobalValue) == sizeof(Constant) + 2 * sizeof(void *) + 2 * sizeof(unsigned), "unexpected GlobalValue size growth"); +// GlobalObject adds a comdat. +static_assert(sizeof(GlobalObject) == sizeof(GlobalValue) + sizeof(void *), + "unexpected GlobalObject size growth"); + bool GlobalValue::isMaterializable() const { if (const Function *F = dyn_cast(this)) return F->isMaterializable(); @@ -160,11 +165,24 @@ Comdat *GlobalValue::getComdat() { return cast(this)->getComdat(); } -void GlobalObject::setSection(StringRef S) { - Section = S; +StringRef GlobalObject::getSectionImpl() const { + assert(hasSection()); + return getContext().pImpl->GlobalObjectSections[this]; +} - // The C api requires this to be null terminated. - Section.c_str(); +void GlobalObject::setSection(StringRef S) { + // Do nothing if we're clearing the section and it is already empty. + if (!hasSection() && S.empty()) + return; + + // Get or create a stable section name string and put it in the table in the + // context. + S = getContext().pImpl->SectionStrings.insert(S).first->first(); + getContext().pImpl->GlobalObjectSections[this] = S; + + // Update the HasSectionHashEntryBit. Setting the section to the empty string + // means this global no longer has a section. + setGlobalObjectFlag(HasSectionHashEntryBit, !S.empty()); } bool GlobalValue::isDeclaration() const { diff --git a/lib/IR/LLVMContextImpl.h b/lib/IR/LLVMContextImpl.h index e9e30ef0656f..850c81cfabb2 100644 --- a/lib/IR/LLVMContextImpl.h +++ b/lib/IR/LLVMContextImpl.h @@ -26,6 +26,7 @@ #include "llvm/ADT/Hashing.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringSet.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DebugInfoMetadata.h" #include "llvm/IR/DerivedTypes.h" @@ -1194,6 +1195,12 @@ public: /// Collection of per-GlobalObject metadata used in this context. DenseMap GlobalObjectMetadata; + /// Collection of per-GlobalObject sections used in this context. + DenseMap GlobalObjectSections; + + /// Stable collection of section strings. + StringSet<> SectionStrings; + /// DiscriminatorTable - This table maps file:line locations to an /// integer representing the next DWARF path discriminator to assign to /// instructions in different blocks at the same location. diff --git a/lib/LTO/LTOBackend.cpp b/lib/LTO/LTOBackend.cpp index 6342cbe4fd90..809db80bc916 100644 --- a/lib/LTO/LTOBackend.cpp +++ b/lib/LTO/LTOBackend.cpp @@ -17,7 +17,6 @@ #include "llvm/LTO/LTOBackend.h" #include "llvm/Analysis/AliasAnalysis.h" #include "llvm/Analysis/CGSCCPassManager.h" -#include "llvm/Analysis/LoopPassManager.h" #include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/Analysis/TargetTransformInfo.h" #include "llvm/Bitcode/BitcodeReader.h" @@ -36,6 +35,7 @@ #include "llvm/Target/TargetMachine.h" #include "llvm/Transforms/IPO.h" #include "llvm/Transforms/IPO/PassManagerBuilder.h" +#include "llvm/Transforms/Scalar/LoopPassManager.h" #include "llvm/Transforms/Utils/FunctionImportUtils.h" #include "llvm/Transforms/Utils/SplitModule.h" diff --git a/lib/LTO/ThinLTOCodeGenerator.cpp b/lib/LTO/ThinLTOCodeGenerator.cpp index 928f69a17de9..a14b86179d6e 100644 --- a/lib/LTO/ThinLTOCodeGenerator.cpp +++ b/lib/LTO/ThinLTOCodeGenerator.cpp @@ -284,7 +284,8 @@ public: const FunctionImporter::ExportSetTy &ExportList, const std::map &ResolvedODR, const GVSummaryMapTy &DefinedFunctions, - const DenseSet &PreservedSymbols) { + const DenseSet &PreservedSymbols, unsigned OptLevel, + const TargetMachineBuilder &TMBuilder) { if (CachePath.empty()) return; @@ -306,12 +307,42 @@ public: SHA1 Hasher; + // Include the parts of the LTO configuration that affect code generation. + auto AddString = [&](StringRef Str) { + Hasher.update(Str); + Hasher.update(ArrayRef{0}); + }; + auto AddUnsigned = [&](unsigned I) { + uint8_t Data[4]; + Data[0] = I; + Data[1] = I >> 8; + Data[2] = I >> 16; + Data[3] = I >> 24; + Hasher.update(ArrayRef{Data, 4}); + }; + // Start with the compiler revision Hasher.update(LLVM_VERSION_STRING); #ifdef HAVE_LLVM_REVISION Hasher.update(LLVM_REVISION); #endif + // Hash the optimization level and the target machine settings. + AddString(TMBuilder.MCpu); + // FIXME: Hash more of Options. For now all clients initialize Options from + // command-line flags (which is unsupported in production), but may set + // RelaxELFRelocations. The clang driver can also pass FunctionSections, + // DataSections and DebuggerTuning via command line flags. + AddUnsigned(TMBuilder.Options.RelaxELFRelocations); + AddUnsigned(TMBuilder.Options.FunctionSections); + AddUnsigned(TMBuilder.Options.DataSections); + AddUnsigned((unsigned)TMBuilder.Options.DebuggerTuning); + AddString(TMBuilder.MAttr); + if (TMBuilder.RelocModel) + AddUnsigned(*TMBuilder.RelocModel); + AddUnsigned(TMBuilder.CGOptLevel); + AddUnsigned(OptLevel); + Hasher.update(ArrayRef((uint8_t *)&ModHash[0], sizeof(ModHash))); for (auto F : ExportList) // The export list can impact the internalization, be conservative here @@ -928,7 +959,8 @@ void ThinLTOCodeGenerator::run() { ModuleCacheEntry CacheEntry(CacheOptions.Path, *Index, ModuleIdentifier, ImportLists[ModuleIdentifier], ExportList, ResolvedODR[ModuleIdentifier], - DefinedFunctions, GUIDPreservedSymbols); + DefinedFunctions, GUIDPreservedSymbols, + OptLevel, TMBuilder); auto CacheEntryPath = CacheEntry.getEntryPath(); { diff --git a/lib/Object/CMakeLists.txt b/lib/Object/CMakeLists.txt index f1a7c1a5ade9..b895c3fcc050 100644 --- a/lib/Object/CMakeLists.txt +++ b/lib/Object/CMakeLists.txt @@ -3,6 +3,7 @@ add_llvm_library(LLVMObject ArchiveWriter.cpp Binary.cpp COFFObjectFile.cpp + Decompressor.cpp ELF.cpp ELFObjectFile.cpp Error.cpp diff --git a/lib/Object/Decompressor.cpp b/lib/Object/Decompressor.cpp new file mode 100644 index 000000000000..bca41fd9f487 --- /dev/null +++ b/lib/Object/Decompressor.cpp @@ -0,0 +1,102 @@ +//===-- Decompressor.cpp --------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Object/Decompressor.h" +#include "llvm/Object/ELFObjectFile.h" +#include "llvm/Support/Compression.h" +#include "llvm/Support/DataExtractor.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/ELF.h" + +using namespace llvm; +using namespace llvm::support::endian; +using namespace object; + +Expected Decompressor::create(StringRef Name, StringRef Data, + bool IsLE, bool Is64Bit) { + if (!zlib::isAvailable()) + return createError("zlib is not available"); + + Decompressor D(Data); + Error Err = isGnuStyle(Name) ? D.consumeCompressedGnuHeader() + : D.consumeCompressedZLibHeader(Is64Bit, IsLE); + if (Err) + return std::move(Err); + return D; +} + +Decompressor::Decompressor(StringRef Data) + : SectionData(Data), DecompressedSize(0) {} + +Error Decompressor::consumeCompressedGnuHeader() { + if (!SectionData.startswith("ZLIB")) + return createError("corrupted compressed section header"); + + SectionData = SectionData.substr(4); + + // Consume uncompressed section size (big-endian 8 bytes). + if (SectionData.size() < 8) + return createError("corrupted uncompressed section size"); + DecompressedSize = read64be(SectionData.data()); + SectionData = SectionData.substr(8); + + return Error::success(); +} + +Error Decompressor::consumeCompressedZLibHeader(bool Is64Bit, + bool IsLittleEndian) { + using namespace ELF; + uint64_t HdrSize = Is64Bit ? sizeof(Elf64_Chdr) : sizeof(Elf32_Chdr); + if (SectionData.size() < HdrSize) + return createError("corrupted compressed section header"); + + DataExtractor Extractor(SectionData, IsLittleEndian, 0); + uint32_t Offset = 0; + if (Extractor.getUnsigned(&Offset, Is64Bit ? sizeof(Elf64_Word) + : sizeof(Elf32_Word)) != + ELFCOMPRESS_ZLIB) + return createError("unsupported compression type"); + + // Skip Elf64_Chdr::ch_reserved field. + if (Is64Bit) + Offset += sizeof(Elf64_Word); + + DecompressedSize = Extractor.getUnsigned( + &Offset, Is64Bit ? sizeof(Elf64_Xword) : sizeof(Elf32_Word)); + SectionData = SectionData.substr(HdrSize); + return Error::success(); +} + +bool Decompressor::isGnuStyle(StringRef Name) { + return Name.startswith(".zdebug"); +} + +bool Decompressor::isCompressed(const object::SectionRef &Section) { + StringRef Name; + if (Section.getName(Name)) + return false; + return Section.isCompressed() || isGnuStyle(Name); +} + +bool Decompressor::isCompressedELFSection(uint64_t Flags, StringRef Name) { + return (Flags & ELF::SHF_COMPRESSED) || isGnuStyle(Name); +} + +Error Decompressor::decompress(SmallString<32> &Out) { + Out.resize(DecompressedSize); + return decompress({Out.data(), (size_t)DecompressedSize}); +} + +Error Decompressor::decompress(MutableArrayRef Buffer) { + size_t Size = Buffer.size(); + zlib::Status Status = zlib::uncompress(SectionData, Buffer.data(), Size); + if (Status != zlib::StatusOK) + return createError("decompression failed"); + return Error::success(); +} diff --git a/lib/ObjectYAML/DWARFYAML.cpp b/lib/ObjectYAML/DWARFYAML.cpp index 42a448a7bdfd..014e63fe7d34 100644 --- a/lib/ObjectYAML/DWARFYAML.cpp +++ b/lib/ObjectYAML/DWARFYAML.cpp @@ -27,17 +27,18 @@ void MappingTraits::mapping(IO &IO, DWARFYAML::Data &DWARF) { IO.setContext(&DWARF); IO.mapOptional("debug_str", DWARF.DebugStrings); IO.mapOptional("debug_abbrev", DWARF.AbbrevDecls); - if(!DWARF.ARanges.empty() || !IO.outputting()) + if (!DWARF.ARanges.empty() || !IO.outputting()) IO.mapOptional("debug_aranges", DWARF.ARanges); - if(!DWARF.PubNames.Entries.empty() || !IO.outputting()) + if (!DWARF.PubNames.Entries.empty() || !IO.outputting()) IO.mapOptional("debug_pubnames", DWARF.PubNames); - if(!DWARF.PubTypes.Entries.empty() || !IO.outputting()) + if (!DWARF.PubTypes.Entries.empty() || !IO.outputting()) IO.mapOptional("debug_pubtypes", DWARF.PubTypes); - if(!DWARF.GNUPubNames.Entries.empty() || !IO.outputting()) + if (!DWARF.GNUPubNames.Entries.empty() || !IO.outputting()) IO.mapOptional("debug_gnu_pubnames", DWARF.GNUPubNames); - if(!DWARF.GNUPubTypes.Entries.empty() || !IO.outputting()) + if (!DWARF.GNUPubTypes.Entries.empty() || !IO.outputting()) IO.mapOptional("debug_gnu_pubtypes", DWARF.GNUPubTypes); IO.mapOptional("debug_info", DWARF.CompileUnits); + IO.mapOptional("debug_line", DWARF.DebugLines); IO.setContext(&oldContext); } @@ -62,7 +63,7 @@ void MappingTraits::mapping( } void MappingTraits::mapping(IO &IO, - DWARFYAML::ARange &Range) { + DWARFYAML::ARange &Range) { IO.mapRequired("Length", Range.Length); IO.mapRequired("Version", Range.Version); IO.mapRequired("CuOffset", Range.CuOffset); @@ -106,15 +107,61 @@ void MappingTraits::mapping(IO &IO, DWARFYAML::Entry &Entry) { IO.mapRequired("Values", Entry.Values); } -void MappingTraits::mapping(IO &IO, - DWARFYAML::FormValue &FormValue) { +void MappingTraits::mapping( + IO &IO, DWARFYAML::FormValue &FormValue) { IO.mapOptional("Value", FormValue.Value); - if(!FormValue.CStr.empty() || !IO.outputting()) + if (!FormValue.CStr.empty() || !IO.outputting()) IO.mapOptional("CStr", FormValue.CStr); - if(!FormValue.BlockData.empty() || !IO.outputting()) + if (!FormValue.BlockData.empty() || !IO.outputting()) IO.mapOptional("BlockData", FormValue.BlockData); } +void MappingTraits::mapping(IO &IO, DWARFYAML::File &File) { + IO.mapRequired("Name", File.Name); + IO.mapRequired("DirIdx", File.DirIdx); + IO.mapRequired("ModTime", File.ModTime); + IO.mapRequired("Length", File.Length); +} + +void MappingTraits::mapping( + IO &IO, DWARFYAML::LineTableOpcode &LineTableOpcode) { + IO.mapRequired("Opcode", LineTableOpcode.Opcode); + if (LineTableOpcode.Opcode == dwarf::DW_LNS_extended_op) { + IO.mapRequired("ExtLen", LineTableOpcode.ExtLen); + IO.mapRequired("SubOpcode", LineTableOpcode.SubOpcode); + } + + if (!LineTableOpcode.UnknownOpcodeData.empty() || !IO.outputting()) + IO.mapOptional("UnknownOpcodeData", LineTableOpcode.UnknownOpcodeData); + if (!LineTableOpcode.UnknownOpcodeData.empty() || !IO.outputting()) + IO.mapOptional("StandardOpcodeData", LineTableOpcode.StandardOpcodeData); + if (!LineTableOpcode.FileEntry.Name.empty() || !IO.outputting()) + IO.mapOptional("FileEntry", LineTableOpcode.FileEntry); + if (LineTableOpcode.Opcode == dwarf::DW_LNS_advance_line || !IO.outputting()) + IO.mapOptional("SData", LineTableOpcode.SData); + IO.mapOptional("Data", LineTableOpcode.Data); +} + +void MappingTraits::mapping( + IO &IO, DWARFYAML::LineTable &LineTable) { + IO.mapRequired("TotalLength", LineTable.TotalLength); + if (LineTable.TotalLength == UINT32_MAX) + IO.mapRequired("TotalLength64", LineTable.TotalLength64); + IO.mapRequired("Version", LineTable.Version); + IO.mapRequired("PrologueLength", LineTable.PrologueLength); + IO.mapRequired("MinInstLength", LineTable.MinInstLength); + if(LineTable.Version >= 4) + IO.mapRequired("MaxOpsPerInst", LineTable.MaxOpsPerInst); + IO.mapRequired("DefaultIsStmt", LineTable.DefaultIsStmt); + IO.mapRequired("LineBase", LineTable.LineBase); + IO.mapRequired("LineRange", LineTable.LineRange); + IO.mapRequired("OpcodeBase", LineTable.OpcodeBase); + IO.mapRequired("StandardOpcodeLengths", LineTable.StandardOpcodeLengths); + IO.mapRequired("IncludeDirs", LineTable.IncludeDirs); + IO.mapRequired("Files", LineTable.Files); + IO.mapRequired("Opcodes", LineTable.Opcodes); +} + } // namespace llvm::yaml } // namespace llvm diff --git a/lib/Passes/PassBuilder.cpp b/lib/Passes/PassBuilder.cpp index 6e0aae5fd852..2994a07b1ccf 100644 --- a/lib/Passes/PassBuilder.cpp +++ b/lib/Passes/PassBuilder.cpp @@ -94,14 +94,17 @@ #include "llvm/Transforms/Scalar/Float2Int.h" #include "llvm/Transforms/Scalar/GVN.h" #include "llvm/Transforms/Scalar/GuardWidening.h" +#include "llvm/Transforms/Scalar/IVUsersPrinter.h" #include "llvm/Transforms/Scalar/IndVarSimplify.h" #include "llvm/Transforms/Scalar/JumpThreading.h" #include "llvm/Transforms/Scalar/LICM.h" +#include "llvm/Transforms/Scalar/LoopAccessAnalysisPrinter.h" #include "llvm/Transforms/Scalar/LoopDataPrefetch.h" #include "llvm/Transforms/Scalar/LoopDeletion.h" #include "llvm/Transforms/Scalar/LoopDistribute.h" #include "llvm/Transforms/Scalar/LoopIdiomRecognize.h" #include "llvm/Transforms/Scalar/LoopInstSimplify.h" +#include "llvm/Transforms/Scalar/LoopPassManager.h" #include "llvm/Transforms/Scalar/LoopRotation.h" #include "llvm/Transforms/Scalar/LoopSimplifyCFG.h" #include "llvm/Transforms/Scalar/LoopStrengthReduce.h" @@ -220,7 +223,8 @@ public: /// \brief No-op loop pass which does nothing. struct NoOpLoopPass { - PreservedAnalyses run(Loop &L, LoopAnalysisManager &) { + PreservedAnalyses run(Loop &L, LoopAnalysisManager &, + LoopStandardAnalysisResults &, LPMUpdater &) { return PreservedAnalyses::all(); } static StringRef name() { return "NoOpLoopPass"; } @@ -233,7 +237,9 @@ class NoOpLoopAnalysis : public AnalysisInfoMixin { public: struct Result {}; - Result run(Loop &, LoopAnalysisManager &) { return Result(); } + Result run(Loop &, LoopAnalysisManager &, LoopStandardAnalysisResults &) { + return Result(); + } static StringRef name() { return "NoOpLoopAnalysis"; } }; @@ -1019,7 +1025,9 @@ bool PassBuilder::parseLoopPass(LoopPassManager &LPM, const PipelineElement &E, #define LOOP_ANALYSIS(NAME, CREATE_PASS) \ if (Name == "require<" NAME ">") { \ LPM.addPass(RequireAnalysisPass< \ - std::remove_reference::type, Loop>()); \ + std::remove_reference::type, Loop, \ + LoopAnalysisManager, LoopStandardAnalysisResults &, \ + LPMUpdater &>()); \ return true; \ } \ if (Name == "invalidate<" NAME ">") { \ diff --git a/lib/ProfileData/InstrProf.cpp b/lib/ProfileData/InstrProf.cpp index 77c6ffc9c253..74acd9e5e207 100644 --- a/lib/ProfileData/InstrProf.cpp +++ b/lib/ProfileData/InstrProf.cpp @@ -811,4 +811,47 @@ bool needsComdatForCounter(const Function &F, const Module &M) { return true; } + +// Check if INSTR_PROF_RAW_VERSION_VAR is defined. +bool isIRPGOFlagSet(const Module *M) { + auto IRInstrVar = + M->getNamedGlobal(INSTR_PROF_QUOTE(INSTR_PROF_RAW_VERSION_VAR)); + if (!IRInstrVar || IRInstrVar->isDeclaration() || + IRInstrVar->hasLocalLinkage()) + return false; + + // Check if the flag is set. + if (!IRInstrVar->hasInitializer()) + return false; + + const Constant *InitVal = IRInstrVar->getInitializer(); + if (!InitVal) + return false; + + return (dyn_cast(InitVal)->getZExtValue() & + VARIANT_MASK_IR_PROF) != 0; +} + +// Check if we can safely rename this Comdat function. +bool canRenameComdatFunc(const Function &F, bool CheckAddressTaken) { + if (F.getName().empty()) + return false; + if (!needsComdatForCounter(F, *(F.getParent()))) + return false; + // Unsafe to rename the address-taken function (which can be used in + // function comparison). + if (CheckAddressTaken && F.hasAddressTaken()) + return false; + // Only safe to do if this function may be discarded if it is not used + // in the compilation unit. + if (!GlobalValue::isDiscardableIfUnused(F.getLinkage())) + return false; + + // For AvailableExternallyLinkage functions. + if (!F.hasComdat()) { + assert(F.getLinkage() == GlobalValue::AvailableExternallyLinkage); + return true; + } + return true; +} } // end namespace llvm diff --git a/lib/Support/FileOutputBuffer.cpp b/lib/Support/FileOutputBuffer.cpp index 2c7bf0435d88..57e5a8d7871c 100644 --- a/lib/Support/FileOutputBuffer.cpp +++ b/lib/Support/FileOutputBuffer.cpp @@ -15,6 +15,7 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" #include "llvm/Support/Errc.h" +#include "llvm/Support/Path.h" #include "llvm/Support/Signals.h" #include @@ -28,8 +29,10 @@ using llvm::sys::fs::mapped_file_region; namespace llvm { FileOutputBuffer::FileOutputBuffer(std::unique_ptr R, - StringRef Path, StringRef TmpPath) - : Region(std::move(R)), FinalPath(Path), TempPath(TmpPath) {} + StringRef Path, StringRef TmpPath, + bool IsRegular) + : Region(std::move(R)), FinalPath(Path), TempPath(TmpPath), + IsRegular(IsRegular) {} FileOutputBuffer::~FileOutputBuffer() { // Close the mapping before deleting the temp file, so that the removal @@ -40,9 +43,10 @@ FileOutputBuffer::~FileOutputBuffer() { ErrorOr> FileOutputBuffer::create(StringRef FilePath, size_t Size, unsigned Flags) { - // If file already exists, it must be a regular file (to be mappable). + // Check file is not a regular file, in which case we cannot remove it. sys::fs::file_status Stat; std::error_code EC = sys::fs::status(FilePath, Stat); + bool IsRegular = true; switch (Stat.type()) { case sys::fs::file_type::file_not_found: // If file does not exist, we'll create one. @@ -56,25 +60,34 @@ FileOutputBuffer::create(StringRef FilePath, size_t Size, unsigned Flags) { default: if (EC) return EC; - else - return make_error_code(errc::operation_not_permitted); + IsRegular = false; } - // Delete target file. - EC = sys::fs::remove(FilePath); - if (EC) - return EC; - - unsigned Mode = sys::fs::all_read | sys::fs::all_write; - // If requested, make the output file executable. - if (Flags & F_executable) - Mode |= sys::fs::all_exe; + if (IsRegular) { + // Delete target file. + EC = sys::fs::remove(FilePath); + if (EC) + return EC; + } - // Create new file in same directory but with random name. SmallString<128> TempFilePath; int FD; - EC = sys::fs::createUniqueFile(Twine(FilePath) + ".tmp%%%%%%%", FD, - TempFilePath, Mode); + if (IsRegular) { + unsigned Mode = sys::fs::all_read | sys::fs::all_write; + // If requested, make the output file executable. + if (Flags & F_executable) + Mode |= sys::fs::all_exe; + // Create new file in same directory but with random name. + EC = sys::fs::createUniqueFile(Twine(FilePath) + ".tmp%%%%%%%", FD, + TempFilePath, Mode); + } else { + // Create a temporary file. Since this is a special file, we will not move + // it and the new file can be in another filesystem. This avoids trying to + // create a temporary file in /dev when outputting to /dev/null for example. + EC = sys::fs::createTemporaryFile(sys::path::filename(FilePath), "", FD, + TempFilePath); + } + if (EC) return EC; @@ -99,8 +112,8 @@ FileOutputBuffer::create(StringRef FilePath, size_t Size, unsigned Flags) { if (Ret) return std::error_code(errno, std::generic_category()); - std::unique_ptr Buf( - new FileOutputBuffer(std::move(MappedFile), FilePath, TempFilePath)); + std::unique_ptr Buf(new FileOutputBuffer( + std::move(MappedFile), FilePath, TempFilePath, IsRegular)); return std::move(Buf); } @@ -108,10 +121,19 @@ std::error_code FileOutputBuffer::commit() { // Unmap buffer, letting OS flush dirty pages to file on disk. Region.reset(); + std::error_code EC; + if (IsRegular) { + // Rename file to final name. + EC = sys::fs::rename(Twine(TempPath), Twine(FinalPath)); + sys::DontRemoveFileOnSignal(TempPath); + } else { + EC = sys::fs::copy_file(TempPath, FinalPath); + std::error_code RMEC = sys::fs::remove(TempPath); + sys::DontRemoveFileOnSignal(TempPath); + if (RMEC) + return RMEC; + } - // Rename file to final name. - std::error_code EC = sys::fs::rename(Twine(TempPath), Twine(FinalPath)); - sys::DontRemoveFileOnSignal(TempPath); return EC; } } // namespace diff --git a/lib/Support/Host.cpp b/lib/Support/Host.cpp index 8a09589aa884..d1b40412a6fc 100644 --- a/lib/Support/Host.cpp +++ b/lib/Support/Host.cpp @@ -111,6 +111,7 @@ enum ProcessorTypes { AMDATHLON, AMDFAM14H, AMDFAM16H, + AMDFAM17H, CPU_TYPE_MAX }; @@ -149,6 +150,7 @@ enum ProcessorSubtypes { AMD_BTVER2, AMDFAM15H_BDVER3, AMDFAM15H_BDVER4, + AMDFAM17H_ZNVER1, CPU_SUBTYPE_MAX }; @@ -742,6 +744,14 @@ static void getAMDProcessorTypeAndSubtype(unsigned int Family, } *Subtype = AMD_BTVER2; break; // "btver2" + case 23: + *Type = AMDFAM17H; + if (Features & (1 << FEATURE_ADX)) { + *Subtype = AMDFAM17H_ZNVER1; + break; // "znver1" + } + *Subtype = AMD_BTVER1; + break; default: break; // "generic" } @@ -950,6 +960,15 @@ StringRef sys::getHostCPUName() { default: return "amdfam16"; } + case AMDFAM17H: + switch (Subtype) { + case AMD_BTVER1: + return "btver1"; + case AMDFAM17H_ZNVER1: + return "znver1"; + default: + return "amdfam17"; + } default: return "generic"; } diff --git a/lib/Support/TarWriter.cpp b/lib/Support/TarWriter.cpp index f79b364dc1f7..f06abf46cce4 100644 --- a/lib/Support/TarWriter.cpp +++ b/lib/Support/TarWriter.cpp @@ -54,6 +54,13 @@ struct UstarHeader { }; static_assert(sizeof(UstarHeader) == BlockSize, "invalid Ustar header"); +static UstarHeader makeUstarHeader() { + UstarHeader Hdr = {}; + memcpy(Hdr.Magic, "ustar", 5); // Ustar magic + memcpy(Hdr.Version, "00", 2); // Ustar version + return Hdr; +} + // A PAX attribute is in the form of " =\n" // where is the length of the entire string including // the length field itself. An example string is this. @@ -98,10 +105,9 @@ static void writePaxHeader(raw_fd_ostream &OS, StringRef Path) { std::string PaxAttr = formatPax("path", Path); // Create a 512-byte header. - UstarHeader Hdr = {}; + UstarHeader Hdr = makeUstarHeader(); snprintf(Hdr.Size, sizeof(Hdr.Size), "%011zo", PaxAttr.size()); - Hdr.TypeFlag = 'x'; // PAX magic - memcpy(Hdr.Magic, "ustar", 6); // Ustar magic + Hdr.TypeFlag = 'x'; // PAX magic computeChecksum(Hdr); // Write them down. @@ -116,7 +122,7 @@ static void writePaxHeader(raw_fd_ostream &OS, StringRef Path) { static std::pair splitPath(StringRef Path) { if (Path.size() <= sizeof(UstarHeader::Name)) return {"", Path}; - size_t Sep = Path.rfind('/', sizeof(UstarHeader::Name) + 1); + size_t Sep = Path.rfind('/', sizeof(UstarHeader::Prefix) + 1); if (Sep == StringRef::npos) return {"", Path}; return {Path.substr(0, Sep), Path.substr(Sep + 1)}; @@ -138,11 +144,10 @@ static void writeUstarHeader(raw_fd_ostream &OS, StringRef Path, size_t Size) { StringRef Name; std::tie(Prefix, Name) = splitPath(Path); - UstarHeader Hdr = {}; + UstarHeader Hdr = makeUstarHeader(); memcpy(Hdr.Name, Name.data(), Name.size()); memcpy(Hdr.Mode, "0000664", 8); snprintf(Hdr.Size, sizeof(Hdr.Size), "%011zo", Size); - memcpy(Hdr.Magic, "ustar", 6); memcpy(Hdr.Prefix, Prefix.data(), Prefix.size()); computeChecksum(Hdr); OS << StringRef(reinterpret_cast(&Hdr), sizeof(Hdr)); diff --git a/lib/Target/AArch64/AArch64GenRegisterBankInfo.def b/lib/Target/AArch64/AArch64GenRegisterBankInfo.def index e927d58ad612..d472a54d9543 100644 --- a/lib/Target/AArch64/AArch64GenRegisterBankInfo.def +++ b/lib/Target/AArch64/AArch64GenRegisterBankInfo.def @@ -18,9 +18,132 @@ namespace llvm { namespace AArch64 { -RegisterBank GPRRegBank; -RegisterBank FPRRegBank; -RegisterBank CCRRegBank; +const uint32_t GPRCoverageData[] = { + // Classes 0-31 + (1u << AArch64::GPR32allRegClassID) | (1u << AArch64::GPR32RegClassID) | + (1u << AArch64::GPR32spRegClassID) | + (1u << AArch64::GPR32commonRegClassID) | + (1u << AArch64::GPR32sponlyRegClassID) | + (1u << AArch64::GPR64allRegClassID) | (1u << AArch64::GPR64RegClassID) | + (1u << AArch64::GPR64spRegClassID) | + (1u << AArch64::GPR64commonRegClassID) | + (1u << AArch64::tcGPR64RegClassID) | + (1u << AArch64::GPR64sponlyRegClassID), + // Classes 32-63 + 0, + // FIXME: The entries below this point can be safely removed once this is + // tablegenerated. It's only needed because of the hardcoded register class + // limit. + // Classes 64-96 + 0, + // Classes 97-128 + 0, + // Classes 129-160 + 0, + // Classes 161-192 + 0, + // Classes 193-224 + 0, +}; + +const uint32_t FPRCoverageData[] = { + // Classes 0-31 + (1u << AArch64::FPR8RegClassID) | (1u << AArch64::FPR16RegClassID) | + (1u << AArch64::FPR32RegClassID) | (1u << AArch64::FPR64RegClassID) | + (1u << AArch64::DDRegClassID) | (1u << AArch64::FPR128RegClassID) | + (1u << AArch64::FPR128_loRegClassID) | (1u << AArch64::DDDRegClassID) | + (1u << AArch64::DDDDRegClassID), + // Classes 32-63 + (1u << (AArch64::QQRegClassID - 32)) | + (1u << (AArch64::QQ_with_qsub0_in_FPR128_loRegClassID - 32)) | + (1u << (AArch64::QQ_with_qsub1_in_FPR128_loRegClassID - 32)) | + (1u + << (AArch64:: + QQQ_with_qsub1_in_FPR128_lo_and_QQQ_with_qsub2_in_FPR128_loRegClassID - + 32)) | + (1u + << (AArch64:: + QQQ_with_qsub0_in_FPR128_lo_and_QQQ_with_qsub2_in_FPR128_loRegClassID - + 32)) | + (1u << (AArch64::QQQQRegClassID - 32)) | + (1u << (AArch64::QQQQ_with_qsub0_in_FPR128_loRegClassID - 32)) | + (1u << (AArch64::QQQQ_with_qsub1_in_FPR128_loRegClassID - 32)) | + (1u << (AArch64::QQQQ_with_qsub2_in_FPR128_loRegClassID - 32)) | + (1u << (AArch64::QQQQ_with_qsub3_in_FPR128_loRegClassID - 32)) | + (1u + << (AArch64:: + QQQQ_with_qsub0_in_FPR128_lo_and_QQQQ_with_qsub1_in_FPR128_loRegClassID - + 32)) | + (1u + << (AArch64:: + QQQQ_with_qsub1_in_FPR128_lo_and_QQQQ_with_qsub2_in_FPR128_loRegClassID - + 32)) | + (1u + << (AArch64:: + QQQQ_with_qsub2_in_FPR128_lo_and_QQQQ_with_qsub3_in_FPR128_loRegClassID - + 32)) | + (1u + << (AArch64:: + QQQQ_with_qsub0_in_FPR128_lo_and_QQQQ_with_qsub2_in_FPR128_loRegClassID - + 32)) | + (1u + << (AArch64:: + QQQQ_with_qsub1_in_FPR128_lo_and_QQQQ_with_qsub3_in_FPR128_loRegClassID - + 32)) | + (1u + << (AArch64:: + QQQQ_with_qsub0_in_FPR128_lo_and_QQQQ_with_qsub3_in_FPR128_loRegClassID - + 32)) | + (1u + << (AArch64:: + QQ_with_qsub0_in_FPR128_lo_and_QQ_with_qsub1_in_FPR128_loRegClassID - + 32)) | + (1u << (AArch64::QQQRegClassID - 32)) | + (1u << (AArch64::QQQ_with_qsub0_in_FPR128_loRegClassID - 32)) | + (1u << (AArch64::QQQ_with_qsub1_in_FPR128_loRegClassID - 32)) | + (1u << (AArch64::QQQ_with_qsub2_in_FPR128_loRegClassID - 32)) | + (1u + << (AArch64:: + QQQ_with_qsub0_in_FPR128_lo_and_QQQ_with_qsub1_in_FPR128_loRegClassID - + 32)), + // FIXME: The entries below this point can be safely removed once this + // is tablegenerated. It's only needed because of the hardcoded register + // class limit. + // Classes 64-96 + 0, + // Classes 97-128 + 0, + // Classes 129-160 + 0, + // Classes 161-192 + 0, + // Classes 193-224 + 0, +}; + +const uint32_t CCRCoverageData[] = { + // Classes 0-31 + 1u << AArch64::CCRRegClassID, + // Classes 32-63 + 0, + // FIXME: The entries below this point can be safely removed once this + // is tablegenerated. It's only needed because of the hardcoded register + // class limit. + // Classes 64-96 + 0, + // Classes 97-128 + 0, + // Classes 129-160 + 0, + // Classes 161-192 + 0, + // Classes 193-224 + 0, +}; + +RegisterBank GPRRegBank(AArch64::GPRRegBankID, "GPR", 64, GPRCoverageData); +RegisterBank FPRRegBank(AArch64::FPRRegBankID, "FPR", 512, FPRCoverageData); +RegisterBank CCRRegBank(AArch64::CCRRegBankID, "CCR", 32, CCRCoverageData); RegisterBank *RegBanks[] = {&GPRRegBank, &FPRRegBank, &CCRRegBank}; diff --git a/lib/Target/AArch64/AArch64ISelLowering.cpp b/lib/Target/AArch64/AArch64ISelLowering.cpp index 74a01835171b..7b581a706fa2 100644 --- a/lib/Target/AArch64/AArch64ISelLowering.cpp +++ b/lib/Target/AArch64/AArch64ISelLowering.cpp @@ -159,6 +159,8 @@ AArch64TargetLowering::AArch64TargetLowering(const TargetMachine &TM, setOperationAction(ISD::SETCC, MVT::i64, Custom); setOperationAction(ISD::SETCC, MVT::f32, Custom); setOperationAction(ISD::SETCC, MVT::f64, Custom); + setOperationAction(ISD::BITREVERSE, MVT::i32, Legal); + setOperationAction(ISD::BITREVERSE, MVT::i64, Legal); setOperationAction(ISD::BRCOND, MVT::Other, Expand); setOperationAction(ISD::BR_CC, MVT::i32, Custom); setOperationAction(ISD::BR_CC, MVT::i64, Custom); diff --git a/lib/Target/AArch64/AArch64InstrInfo.td b/lib/Target/AArch64/AArch64InstrInfo.td index c5b95f282ea8..2244baacca17 100644 --- a/lib/Target/AArch64/AArch64InstrInfo.td +++ b/lib/Target/AArch64/AArch64InstrInfo.td @@ -951,10 +951,7 @@ def : Pat<(not GPR64:$Xm), (ORNXrr XZR, GPR64:$Xm)>; defm CLS : OneOperandData<0b101, "cls">; defm CLZ : OneOperandData<0b100, "clz", ctlz>; -defm RBIT : OneOperandData<0b000, "rbit">; - -def : Pat<(int_aarch64_rbit GPR32:$Rn), (RBITWr $Rn)>; -def : Pat<(int_aarch64_rbit GPR64:$Rn), (RBITXr $Rn)>; +defm RBIT : OneOperandData<0b000, "rbit", bitreverse>; def REV16Wr : OneWRegData<0b001, "rev16", UnOpFrag<(rotr (bswap node:$LHS), (i64 16))>>; diff --git a/lib/Target/AArch64/AArch64RegisterBankInfo.cpp b/lib/Target/AArch64/AArch64RegisterBankInfo.cpp index a5fd2fbdde19..b292c9c87dcd 100644 --- a/lib/Target/AArch64/AArch64RegisterBankInfo.cpp +++ b/lib/Target/AArch64/AArch64RegisterBankInfo.cpp @@ -41,28 +41,30 @@ AArch64RegisterBankInfo::AArch64RegisterBankInfo(const TargetRegisterInfo &TRI) if (AlreadyInit) return; AlreadyInit = true; - // Initialize the GPR bank. - createRegisterBank(AArch64::GPRRegBankID, "GPR"); - // The GPR register bank is fully defined by all the registers in - // GR64all + its subclasses. - addRegBankCoverage(AArch64::GPRRegBankID, AArch64::GPR64allRegClassID, TRI); + const RegisterBank &RBGPR = getRegBank(AArch64::GPRRegBankID); (void)RBGPR; assert(&AArch64::GPRRegBank == &RBGPR && "The order in RegBanks is messed up"); + + const RegisterBank &RBFPR = getRegBank(AArch64::FPRRegBankID); + (void)RBFPR; + assert(&AArch64::FPRRegBank == &RBFPR && + "The order in RegBanks is messed up"); + + const RegisterBank &RBCCR = getRegBank(AArch64::CCRRegBankID); + (void)RBCCR; + assert(&AArch64::CCRRegBank == &RBCCR && + "The order in RegBanks is messed up"); + + // The GPR register bank is fully defined by all the registers in + // GR64all + its subclasses. assert(RBGPR.covers(*TRI.getRegClass(AArch64::GPR32RegClassID)) && "Subclass not added?"); assert(RBGPR.getSize() == 64 && "GPRs should hold up to 64-bit"); - // Initialize the FPR bank. - createRegisterBank(AArch64::FPRRegBankID, "FPR"); // The FPR register bank is fully defined by all the registers in // GR64all + its subclasses. - addRegBankCoverage(AArch64::FPRRegBankID, AArch64::QQQQRegClassID, TRI); - const RegisterBank &RBFPR = getRegBank(AArch64::FPRRegBankID); - (void)RBFPR; - assert(&AArch64::FPRRegBank == &RBFPR && - "The order in RegBanks is messed up"); assert(RBFPR.covers(*TRI.getRegClass(AArch64::QQRegClassID)) && "Subclass not added?"); assert(RBFPR.covers(*TRI.getRegClass(AArch64::FPR64RegClassID)) && @@ -70,13 +72,6 @@ AArch64RegisterBankInfo::AArch64RegisterBankInfo(const TargetRegisterInfo &TRI) assert(RBFPR.getSize() == 512 && "FPRs should hold up to 512-bit via QQQQ sequence"); - // Initialize the CCR bank. - createRegisterBank(AArch64::CCRRegBankID, "CCR"); - addRegBankCoverage(AArch64::CCRRegBankID, AArch64::CCRRegClassID, TRI); - const RegisterBank &RBCCR = getRegBank(AArch64::CCRRegBankID); - (void)RBCCR; - assert(&AArch64::CCRRegBank == &RBCCR && - "The order in RegBanks is messed up"); assert(RBCCR.covers(*TRI.getRegClass(AArch64::CCRRegClassID)) && "Class not added?"); assert(RBCCR.getSize() == 32 && "CCR should hold up to 32-bit"); diff --git a/lib/Target/AArch64/AArch64TargetTransformInfo.cpp b/lib/Target/AArch64/AArch64TargetTransformInfo.cpp index 1a17691fc584..b8833e5a5552 100644 --- a/lib/Target/AArch64/AArch64TargetTransformInfo.cpp +++ b/lib/Target/AArch64/AArch64TargetTransformInfo.cpp @@ -374,7 +374,7 @@ int AArch64TTIImpl::getVectorInstrCost(unsigned Opcode, Type *Val, int AArch64TTIImpl::getArithmeticInstrCost( unsigned Opcode, Type *Ty, TTI::OperandValueKind Opd1Info, TTI::OperandValueKind Opd2Info, TTI::OperandValueProperties Opd1PropInfo, - TTI::OperandValueProperties Opd2PropInfo) { + TTI::OperandValueProperties Opd2PropInfo, ArrayRef Args) { // Legalize the type. std::pair LT = TLI->getTypeLegalizationCost(DL, Ty); @@ -466,28 +466,27 @@ int AArch64TTIImpl::getCmpSelInstrCost(unsigned Opcode, Type *ValTy, return BaseT::getCmpSelInstrCost(Opcode, ValTy, CondTy); } -int AArch64TTIImpl::getMemoryOpCost(unsigned Opcode, Type *Src, +int AArch64TTIImpl::getMemoryOpCost(unsigned Opcode, Type *Ty, unsigned Alignment, unsigned AddressSpace) { - std::pair LT = TLI->getTypeLegalizationCost(DL, Src); + auto LT = TLI->getTypeLegalizationCost(DL, Ty); if (ST->isMisaligned128StoreSlow() && Opcode == Instruction::Store && - Src->isVectorTy() && Alignment != 16 && - Src->getVectorElementType()->isIntegerTy(64)) { - // Unaligned stores are extremely inefficient. We don't split - // unaligned v2i64 stores because the negative impact that has shown in - // practice on inlined memcpy code. - // We make v2i64 stores expensive so that we will only vectorize if there + LT.second.is128BitVector() && Alignment < 16) { + // Unaligned stores are extremely inefficient. We don't split all + // unaligned 128-bit stores because the negative impact that has shown in + // practice on inlined block copy code. + // We make such stores expensive so that we will only vectorize if there // are 6 other instructions getting vectorized. - int AmortizationCost = 6; + const int AmortizationCost = 6; return LT.first * 2 * AmortizationCost; } - if (Src->isVectorTy() && Src->getVectorElementType()->isIntegerTy(8) && - Src->getVectorNumElements() < 8) { + if (Ty->isVectorTy() && Ty->getVectorElementType()->isIntegerTy(8) && + Ty->getVectorNumElements() < 8) { // We scalarize the loads/stores because there is not v.4b register and we // have to promote the elements to v.4h. - unsigned NumVecElts = Src->getVectorNumElements(); + unsigned NumVecElts = Ty->getVectorNumElements(); unsigned NumVectorizableInstsToAmortize = NumVecElts * 2; // We generate 2 instructions per vector element. return NumVectorizableInstsToAmortize * NumVecElts * 2; diff --git a/lib/Target/AArch64/AArch64TargetTransformInfo.h b/lib/Target/AArch64/AArch64TargetTransformInfo.h index 849fd3d9b44a..18287ed6653f 100644 --- a/lib/Target/AArch64/AArch64TargetTransformInfo.h +++ b/lib/Target/AArch64/AArch64TargetTransformInfo.h @@ -102,7 +102,8 @@ public: TTI::OperandValueKind Opd1Info = TTI::OK_AnyValue, TTI::OperandValueKind Opd2Info = TTI::OK_AnyValue, TTI::OperandValueProperties Opd1PropInfo = TTI::OP_None, - TTI::OperandValueProperties Opd2PropInfo = TTI::OP_None); + TTI::OperandValueProperties Opd2PropInfo = TTI::OP_None, + ArrayRef Args = ArrayRef()); int getAddressComputationCost(Type *Ty, ScalarEvolution *SE, const SCEV *Ptr); diff --git a/lib/Target/AMDGPU/AMDGPUISelLowering.cpp b/lib/Target/AMDGPU/AMDGPUISelLowering.cpp index 730bcdcf7afa..e48c1943cb01 100644 --- a/lib/Target/AMDGPU/AMDGPUISelLowering.cpp +++ b/lib/Target/AMDGPU/AMDGPUISelLowering.cpp @@ -434,6 +434,13 @@ AMDGPUTargetLowering::AMDGPUTargetLowering(const TargetMachine &TM, setSchedulingPreference(Sched::RegPressure); setJumpIsExpensive(true); + + // FIXME: This is only partially true. If we have to do vector compares, any + // SGPR pair can be a condition register. If we have a uniform condition, we + // are better off doing SALU operations, where there is only one SCC. For now, + // we don't have a way of knowing during instruction selection if a condition + // will be uniform and we always use vector compares. Assume we are using + // vector compares until that is fixed. setHasMultipleConditionRegisters(true); // SI at least has hardware support for floating point exceptions, but no way @@ -470,12 +477,31 @@ AMDGPUTargetLowering::AMDGPUTargetLowering(const TargetMachine &TM, setTargetDAGCombine(ISD::STORE); setTargetDAGCombine(ISD::FADD); setTargetDAGCombine(ISD::FSUB); + setTargetDAGCombine(ISD::FNEG); } //===----------------------------------------------------------------------===// // Target Information //===----------------------------------------------------------------------===// +static bool fnegFoldsIntoOp(unsigned Opc) { + switch (Opc) { + case ISD::FADD: + case ISD::FSUB: + case ISD::FMUL: + case ISD::FMA: + case ISD::FMAD: + case ISD::FSIN: + case AMDGPUISD::RCP: + case AMDGPUISD::RCP_LEGACY: + case AMDGPUISD::SIN_HW: + case AMDGPUISD::FMUL_LEGACY: + return true; + default: + return false; + } +} + MVT AMDGPUTargetLowering::getVectorIdxTy(const DataLayout &) const { return MVT::i32; } @@ -2679,8 +2705,93 @@ SDValue AMDGPUTargetLowering::performCtlzCombine(const SDLoc &SL, SDValue Cond, return SDValue(); } +static SDValue distributeOpThroughSelect(TargetLowering::DAGCombinerInfo &DCI, + unsigned Op, + const SDLoc &SL, + SDValue Cond, + SDValue N1, + SDValue N2) { + SelectionDAG &DAG = DCI.DAG; + EVT VT = N1.getValueType(); + + SDValue NewSelect = DAG.getNode(ISD::SELECT, SL, VT, Cond, + N1.getOperand(0), N2.getOperand(0)); + DCI.AddToWorklist(NewSelect.getNode()); + return DAG.getNode(Op, SL, VT, NewSelect); +} + +// Pull a free FP operation out of a select so it may fold into uses. +// +// select c, (fneg x), (fneg y) -> fneg (select c, x, y) +// select c, (fneg x), k -> fneg (select c, x, (fneg k)) +// +// select c, (fabs x), (fabs y) -> fabs (select c, x, y) +// select c, (fabs x), +k -> fabs (select c, x, k) +static SDValue foldFreeOpFromSelect(TargetLowering::DAGCombinerInfo &DCI, + SDValue N) { + SelectionDAG &DAG = DCI.DAG; + SDValue Cond = N.getOperand(0); + SDValue LHS = N.getOperand(1); + SDValue RHS = N.getOperand(2); + + EVT VT = N.getValueType(); + if ((LHS.getOpcode() == ISD::FABS && RHS.getOpcode() == ISD::FABS) || + (LHS.getOpcode() == ISD::FNEG && RHS.getOpcode() == ISD::FNEG)) { + return distributeOpThroughSelect(DCI, LHS.getOpcode(), + SDLoc(N), Cond, LHS, RHS); + } + + bool Inv = false; + if (RHS.getOpcode() == ISD::FABS || RHS.getOpcode() == ISD::FNEG) { + std::swap(LHS, RHS); + Inv = true; + } + + // TODO: Support vector constants. + ConstantFPSDNode *CRHS = dyn_cast(RHS); + if ((LHS.getOpcode() == ISD::FNEG || LHS.getOpcode() == ISD::FABS) && CRHS) { + SDLoc SL(N); + // If one side is an fneg/fabs and the other is a constant, we can push the + // fneg/fabs down. If it's an fabs, the constant needs to be non-negative. + SDValue NewLHS = LHS.getOperand(0); + SDValue NewRHS = RHS; + + // Careful: if the neg can be folded up, don't try to pull it back down. + bool ShouldFoldNeg = true; + + if (NewLHS.hasOneUse()) { + unsigned Opc = NewLHS.getOpcode(); + if (LHS.getOpcode() == ISD::FNEG && fnegFoldsIntoOp(Opc)) + ShouldFoldNeg = false; + if (LHS.getOpcode() == ISD::FABS && Opc == ISD::FMUL) + ShouldFoldNeg = false; + } + + if (ShouldFoldNeg) { + if (LHS.getOpcode() == ISD::FNEG) + NewRHS = DAG.getNode(ISD::FNEG, SL, VT, RHS); + else if (CRHS->isNegative()) + return SDValue(); + + if (Inv) + std::swap(NewLHS, NewRHS); + + SDValue NewSelect = DAG.getNode(ISD::SELECT, SL, VT, + Cond, NewLHS, NewRHS); + DCI.AddToWorklist(NewSelect.getNode()); + return DAG.getNode(LHS.getOpcode(), SL, VT, NewSelect); + } + } + + return SDValue(); +} + + SDValue AMDGPUTargetLowering::performSelectCombine(SDNode *N, DAGCombinerInfo &DCI) const { + if (SDValue Folded = foldFreeOpFromSelect(DCI, SDValue(N, 0))) + return Folded; + SDValue Cond = N->getOperand(0); if (Cond.getOpcode() != ISD::SETCC) return SDValue(); @@ -2724,6 +2835,129 @@ SDValue AMDGPUTargetLowering::performSelectCombine(SDNode *N, return performCtlzCombine(SDLoc(N), Cond, True, False, DCI); } +SDValue AMDGPUTargetLowering::performFNegCombine(SDNode *N, + DAGCombinerInfo &DCI) const { + SelectionDAG &DAG = DCI.DAG; + SDValue N0 = N->getOperand(0); + EVT VT = N->getValueType(0); + + unsigned Opc = N0.getOpcode(); + + // If the input has multiple uses and we can either fold the negate down, or + // the other uses cannot, give up. This both prevents unprofitable + // transformations and infinite loops: we won't repeatedly try to fold around + // a negate that has no 'good' form. + // + // TODO: Check users can fold + if (fnegFoldsIntoOp(Opc) && !N0.hasOneUse()) + return SDValue(); + + SDLoc SL(N); + switch (Opc) { + case ISD::FADD: { + // (fneg (fadd x, y)) -> (fadd (fneg x), (fneg y)) + SDValue LHS = N0.getOperand(0); + SDValue RHS = N0.getOperand(1); + + if (LHS.getOpcode() != ISD::FNEG) + LHS = DAG.getNode(ISD::FNEG, SL, VT, LHS); + else + LHS = LHS.getOperand(0); + + if (RHS.getOpcode() != ISD::FNEG) + RHS = DAG.getNode(ISD::FNEG, SL, VT, RHS); + else + RHS = RHS.getOperand(0); + + SDValue Res = DAG.getNode(ISD::FADD, SL, VT, LHS, RHS); + if (!N0.hasOneUse()) + DAG.ReplaceAllUsesWith(N0, DAG.getNode(ISD::FNEG, SL, VT, Res)); + return Res; + } + case ISD::FMUL: + case AMDGPUISD::FMUL_LEGACY: { + // (fneg (fmul x, y)) -> (fmul x, (fneg y)) + // (fneg (fmul_legacy x, y)) -> (fmul_legacy x, (fneg y)) + SDValue LHS = N0.getOperand(0); + SDValue RHS = N0.getOperand(1); + + if (LHS.getOpcode() == ISD::FNEG) + LHS = LHS.getOperand(0); + else if (RHS.getOpcode() == ISD::FNEG) + RHS = RHS.getOperand(0); + else + RHS = DAG.getNode(ISD::FNEG, SL, VT, RHS); + + SDValue Res = DAG.getNode(Opc, SL, VT, LHS, RHS); + if (!N0.hasOneUse()) + DAG.ReplaceAllUsesWith(N0, DAG.getNode(ISD::FNEG, SL, VT, Res)); + return Res; + } + case ISD::FMA: + case ISD::FMAD: { + // (fneg (fma x, y, z)) -> (fma x, (fneg y), (fneg z)) + SDValue LHS = N0.getOperand(0); + SDValue MHS = N0.getOperand(1); + SDValue RHS = N0.getOperand(2); + + if (LHS.getOpcode() == ISD::FNEG) + LHS = LHS.getOperand(0); + else if (MHS.getOpcode() == ISD::FNEG) + MHS = MHS.getOperand(0); + else + MHS = DAG.getNode(ISD::FNEG, SL, VT, MHS); + + if (RHS.getOpcode() != ISD::FNEG) + RHS = DAG.getNode(ISD::FNEG, SL, VT, RHS); + else + RHS = RHS.getOperand(0); + + SDValue Res = DAG.getNode(Opc, SL, VT, LHS, MHS, RHS); + if (!N0.hasOneUse()) + DAG.ReplaceAllUsesWith(N0, DAG.getNode(ISD::FNEG, SL, VT, Res)); + return Res; + } + case ISD::FP_EXTEND: + case AMDGPUISD::RCP: + case AMDGPUISD::RCP_LEGACY: + case ISD::FSIN: + case AMDGPUISD::SIN_HW: { + SDValue CvtSrc = N0.getOperand(0); + if (CvtSrc.getOpcode() == ISD::FNEG) { + // (fneg (fp_extend (fneg x))) -> (fp_extend x) + // (fneg (rcp (fneg x))) -> (rcp x) + return DAG.getNode(Opc, SL, VT, CvtSrc.getOperand(0)); + } + + if (!N0.hasOneUse()) + return SDValue(); + + // (fneg (fp_extend x)) -> (fp_extend (fneg x)) + // (fneg (rcp x)) -> (rcp (fneg x)) + SDValue Neg = DAG.getNode(ISD::FNEG, SL, CvtSrc.getValueType(), CvtSrc); + return DAG.getNode(Opc, SL, VT, Neg); + } + case ISD::FP_ROUND: { + SDValue CvtSrc = N0.getOperand(0); + + if (CvtSrc.getOpcode() == ISD::FNEG) { + // (fneg (fp_round (fneg x))) -> (fp_round x) + return DAG.getNode(ISD::FP_ROUND, SL, VT, + CvtSrc.getOperand(0), N0.getOperand(1)); + } + + if (!N0.hasOneUse()) + return SDValue(); + + // (fneg (fp_round x)) -> (fp_round (fneg x)) + SDValue Neg = DAG.getNode(ISD::FNEG, SL, CvtSrc.getValueType(), CvtSrc); + return DAG.getNode(ISD::FP_ROUND, SL, VT, Neg, N0.getOperand(1)); + } + default: + return SDValue(); + } +} + SDValue AMDGPUTargetLowering::PerformDAGCombine(SDNode *N, DAGCombinerInfo &DCI) const { SelectionDAG &DAG = DCI.DAG; @@ -2829,6 +3063,8 @@ SDValue AMDGPUTargetLowering::PerformDAGCombine(SDNode *N, return performMulLoHi24Combine(N, DCI); case ISD::SELECT: return performSelectCombine(N, DCI); + case ISD::FNEG: + return performFNegCombine(N, DCI); case AMDGPUISD::BFE_I32: case AMDGPUISD::BFE_U32: { assert(!N->getValueType(0).isVector() && diff --git a/lib/Target/AMDGPU/AMDGPUISelLowering.h b/lib/Target/AMDGPU/AMDGPUISelLowering.h index 745c9923de2e..69567aa5f713 100644 --- a/lib/Target/AMDGPU/AMDGPUISelLowering.h +++ b/lib/Target/AMDGPU/AMDGPUISelLowering.h @@ -84,6 +84,7 @@ protected: SDValue performCtlzCombine(const SDLoc &SL, SDValue Cond, SDValue LHS, SDValue RHS, DAGCombinerInfo &DCI) const; SDValue performSelectCombine(SDNode *N, DAGCombinerInfo &DCI) const; + SDValue performFNegCombine(SDNode *N, DAGCombinerInfo &DCI) const; static EVT getEquivalentMemType(LLVMContext &Context, EVT VT); diff --git a/lib/Target/AMDGPU/AMDGPUInstructions.td b/lib/Target/AMDGPU/AMDGPUInstructions.td index 513df3a9cdf3..59cba636c586 100644 --- a/lib/Target/AMDGPU/AMDGPUInstructions.td +++ b/lib/Target/AMDGPU/AMDGPUInstructions.td @@ -629,9 +629,10 @@ def smax_oneuse : HasOneUseBinOp; def smin_oneuse : HasOneUseBinOp; def umax_oneuse : HasOneUseBinOp; def umin_oneuse : HasOneUseBinOp; -def sub_oneuse : HasOneUseBinOp; } // Properties = [SDNPCommutative, SDNPAssociative] +def sub_oneuse : HasOneUseBinOp; + def select_oneuse : HasOneUseTernaryOp