Mercurial > hg > CbC > CbC_llvm
diff lib/IR/DebugInfoMetadata.cpp @ 148:63bd29f05246
merged
author | Shinji KONO <kono@ie.u-ryukyu.ac.jp> |
---|---|
date | Wed, 14 Aug 2019 19:46:37 +0900 |
parents | c2174574ed3a |
children |
line wrap: on
line diff
--- a/lib/IR/DebugInfoMetadata.cpp Sun Dec 23 19:23:36 2018 +0900 +++ b/lib/IR/DebugInfoMetadata.cpp Wed Aug 14 19:46:37 2019 +0900 @@ -1,9 +1,8 @@ //===- DebugInfoMetadata.cpp - Implement debug info metadata --------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -14,16 +13,19 @@ #include "llvm/IR/DebugInfoMetadata.h" #include "LLVMContextImpl.h" #include "MetadataImpl.h" -#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallSet.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/IR/DIBuilder.h" #include "llvm/IR/Function.h" #include "llvm/IR/Instructions.h" +#include <numeric> + using namespace llvm; DILocation::DILocation(LLVMContext &C, StorageType Storage, unsigned Line, - unsigned Column, ArrayRef<Metadata *> MDs) + unsigned Column, ArrayRef<Metadata *> MDs, + bool ImplicitCode) : MDNode(C, DILocationKind, Storage, MDs) { assert((MDs.size() == 1 || MDs.size() == 2) && "Expected a scope and optional inlined-at"); @@ -33,6 +35,8 @@ SubclassData32 = Line; SubclassData16 = Column; + + setImplicitCode(ImplicitCode); } static void adjustColumn(unsigned &Column) { @@ -43,15 +47,15 @@ DILocation *DILocation::getImpl(LLVMContext &Context, unsigned Line, unsigned Column, Metadata *Scope, - Metadata *InlinedAt, StorageType Storage, - bool ShouldCreate) { + Metadata *InlinedAt, bool ImplicitCode, + StorageType Storage, bool ShouldCreate) { // Fixup column. adjustColumn(Column); if (Storage == Uniqued) { - if (auto *N = - getUniqued(Context.pImpl->DILocations, - DILocationInfo::KeyTy(Line, Column, Scope, InlinedAt))) + if (auto *N = getUniqued(Context.pImpl->DILocations, + DILocationInfo::KeyTy(Line, Column, Scope, + InlinedAt, ImplicitCode))) return N; if (!ShouldCreate) return nullptr; @@ -63,36 +67,94 @@ Ops.push_back(Scope); if (InlinedAt) Ops.push_back(InlinedAt); - return storeImpl(new (Ops.size()) - DILocation(Context, Storage, Line, Column, Ops), + return storeImpl(new (Ops.size()) DILocation(Context, Storage, Line, Column, + Ops, ImplicitCode), Storage, Context.pImpl->DILocations); } -const DILocation * -DILocation::getMergedLocation(const DILocation *LocA, const DILocation *LocB, - const Instruction *ForInst) { +const DILocation *DILocation::getMergedLocation(const DILocation *LocA, + const DILocation *LocB) { if (!LocA || !LocB) return nullptr; - if (LocA == LocB || !LocA->canDiscriminate(*LocB)) + if (LocA == LocB) return LocA; - if (!dyn_cast_or_null<CallInst>(ForInst)) - return nullptr; - SmallPtrSet<DILocation *, 5> InlinedLocationsA; for (DILocation *L = LocA->getInlinedAt(); L; L = L->getInlinedAt()) InlinedLocationsA.insert(L); + SmallSet<std::pair<DIScope *, DILocation *>, 5> Locations; + DIScope *S = LocA->getScope(); + DILocation *L = LocA->getInlinedAt(); + while (S) { + Locations.insert(std::make_pair(S, L)); + S = S->getScope(); + if (!S && L) { + S = L->getScope(); + L = L->getInlinedAt(); + } + } const DILocation *Result = LocB; - for (DILocation *L = LocB->getInlinedAt(); L; L = L->getInlinedAt()) { - Result = L; - if (InlinedLocationsA.count(L)) + S = LocB->getScope(); + L = LocB->getInlinedAt(); + while (S) { + if (Locations.count(std::make_pair(S, L))) break; + S = S->getScope(); + if (!S && L) { + S = L->getScope(); + L = L->getInlinedAt(); + } } - return DILocation::get(Result->getContext(), 0, 0, Result->getScope(), - Result->getInlinedAt()); + + // If the two locations are irreconsilable, just pick one. This is misleading, + // but on the other hand, it's a "line 0" location. + if (!S || !isa<DILocalScope>(S)) + S = LocA->getScope(); + return DILocation::get(Result->getContext(), 0, 0, S, L); } +Optional<unsigned> DILocation::encodeDiscriminator(unsigned BD, unsigned DF, unsigned CI) { + SmallVector<unsigned, 3> Components = {BD, DF, CI}; + uint64_t RemainingWork = 0U; + // We use RemainingWork to figure out if we have no remaining components to + // encode. For example: if BD != 0 but DF == 0 && CI == 0, we don't need to + // encode anything for the latter 2. + // Since any of the input components is at most 32 bits, their sum will be + // less than 34 bits, and thus RemainingWork won't overflow. + RemainingWork = std::accumulate(Components.begin(), Components.end(), RemainingWork); + + int I = 0; + unsigned Ret = 0; + unsigned NextBitInsertionIndex = 0; + while (RemainingWork > 0) { + unsigned C = Components[I++]; + RemainingWork -= C; + unsigned EC = encodeComponent(C); + Ret |= (EC << NextBitInsertionIndex); + NextBitInsertionIndex += encodingBits(C); + } + + // Encoding may be unsuccessful because of overflow. We determine success by + // checking equivalence of components before & after encoding. Alternatively, + // we could determine Success during encoding, but the current alternative is + // simpler. + unsigned TBD, TDF, TCI = 0; + decodeDiscriminator(Ret, TBD, TDF, TCI); + if (TBD == BD && TDF == DF && TCI == CI) + return Ret; + return None; +} + +void DILocation::decodeDiscriminator(unsigned D, unsigned &BD, unsigned &DF, + unsigned &CI) { + BD = getUnsignedFromPrefixEncoding(D); + DF = getUnsignedFromPrefixEncoding(getNextComponentInDiscriminator(D)); + CI = getUnsignedFromPrefixEncoding( + getNextComponentInDiscriminator(getNextComponentInDiscriminator(D))); +} + + DINode::DIFlags DINode::getFlag(StringRef Flag) { return StringSwitch<DIFlags>(Flag) #define HANDLE_DI_FLAG(ID, NAME) .Case("DIFlag" #NAME, Flag##NAME) @@ -147,7 +209,7 @@ return Flags; } -DIScopeRef DIScope::getScope() const { +DIScope *DIScope::getScope() const { if (auto *T = dyn_cast<DIType>(this)) return T->getScope(); @@ -160,6 +222,9 @@ if (auto *NS = dyn_cast<DINamespace>(this)) return NS->getScope(); + if (auto *CB = dyn_cast<DICommonBlock>(this)) + return CB->getScope(); + if (auto *M = dyn_cast<DIModule>(this)) return M->getScope(); @@ -175,6 +240,8 @@ return SP->getName(); if (auto *NS = dyn_cast<DINamespace>(this)) return NS->getName(); + if (auto *CB = dyn_cast<DICommonBlock>(this)) + return CB->getName(); if (auto *M = dyn_cast<DIModule>(this)) return M->getName(); assert((isa<DILexicalBlockBase>(this) || isa<DIFile>(this) || @@ -274,13 +341,27 @@ DIBasicType *DIBasicType::getImpl(LLVMContext &Context, unsigned Tag, MDString *Name, uint64_t SizeInBits, uint32_t AlignInBits, unsigned Encoding, - StorageType Storage, bool ShouldCreate) { + DIFlags Flags, StorageType Storage, + bool ShouldCreate) { assert(isCanonical(Name) && "Expected canonical MDString"); DEFINE_GETIMPL_LOOKUP(DIBasicType, - (Tag, Name, SizeInBits, AlignInBits, Encoding)); + (Tag, Name, SizeInBits, AlignInBits, Encoding, Flags)); Metadata *Ops[] = {nullptr, nullptr, Name}; - DEFINE_GETIMPL_STORE(DIBasicType, (Tag, SizeInBits, AlignInBits, Encoding), - Ops); + DEFINE_GETIMPL_STORE(DIBasicType, (Tag, SizeInBits, AlignInBits, Encoding, + Flags), Ops); +} + +Optional<DIBasicType::Signedness> DIBasicType::getSignedness() const { + switch (getEncoding()) { + case dwarf::DW_ATE_signed: + case dwarf::DW_ATE_signed_char: + return Signedness::Signed; + case dwarf::DW_ATE_unsigned: + case dwarf::DW_ATE_unsigned_char: + return Signedness::Unsigned; + default: + return None; + } } DIDerivedType *DIDerivedType::getImpl( @@ -417,13 +498,16 @@ DIFile *DIFile::getImpl(LLVMContext &Context, MDString *Filename, MDString *Directory, Optional<DIFile::ChecksumInfo<MDString *>> CS, - StorageType Storage, bool ShouldCreate) { + Optional<MDString *> Source, StorageType Storage, + bool ShouldCreate) { assert(isCanonical(Filename) && "Expected canonical MDString"); assert(isCanonical(Directory) && "Expected canonical MDString"); assert((!CS || isCanonical(CS->Value)) && "Expected canonical MDString"); - DEFINE_GETIMPL_LOOKUP(DIFile, (Filename, Directory, CS)); - Metadata *Ops[] = {Filename, Directory, CS ? CS->Value : nullptr}; - DEFINE_GETIMPL_STORE(DIFile, (CS), Ops); + assert((!Source || isCanonical(*Source)) && "Expected canonical MDString"); + DEFINE_GETIMPL_LOOKUP(DIFile, (Filename, Directory, CS, Source)); + Metadata *Ops[] = {Filename, Directory, CS ? CS->Value : nullptr, + Source.getValueOr(nullptr)}; + DEFINE_GETIMPL_STORE(DIFile, (CS, Source), Ops); } DICompileUnit *DICompileUnit::getImpl( @@ -433,7 +517,8 @@ unsigned EmissionKind, Metadata *EnumTypes, Metadata *RetainedTypes, Metadata *GlobalVariables, Metadata *ImportedEntities, Metadata *Macros, uint64_t DWOId, bool SplitDebugInlining, bool DebugInfoForProfiling, - bool GnuPubnames, StorageType Storage, bool ShouldCreate) { + unsigned NameTableKind, bool RangesBaseAddress, StorageType Storage, + bool ShouldCreate) { assert(Storage != Uniqued && "Cannot unique DICompileUnit"); assert(isCanonical(Producer) && "Expected canonical MDString"); assert(isCanonical(Flags) && "Expected canonical MDString"); @@ -446,7 +531,8 @@ return storeImpl(new (array_lengthof(Ops)) DICompileUnit( Context, Storage, SourceLanguage, IsOptimized, RuntimeVersion, EmissionKind, DWOId, SplitDebugInlining, - DebugInfoForProfiling, GnuPubnames, Ops), + DebugInfoForProfiling, NameTableKind, RangesBaseAddress, + Ops), Storage); } @@ -456,14 +542,37 @@ .Case("NoDebug", NoDebug) .Case("FullDebug", FullDebug) .Case("LineTablesOnly", LineTablesOnly) + .Case("DebugDirectivesOnly", DebugDirectivesOnly) .Default(None); } -const char *DICompileUnit::EmissionKindString(DebugEmissionKind EK) { +Optional<DICompileUnit::DebugNameTableKind> +DICompileUnit::getNameTableKind(StringRef Str) { + return StringSwitch<Optional<DebugNameTableKind>>(Str) + .Case("Default", DebugNameTableKind::Default) + .Case("GNU", DebugNameTableKind::GNU) + .Case("None", DebugNameTableKind::None) + .Default(None); +} + +const char *DICompileUnit::emissionKindString(DebugEmissionKind EK) { switch (EK) { case NoDebug: return "NoDebug"; case FullDebug: return "FullDebug"; case LineTablesOnly: return "LineTablesOnly"; + case DebugDirectivesOnly: return "DebugDirectivesOnly"; + } + return nullptr; +} + +const char *DICompileUnit::nameTableKindString(DebugNameTableKind NTK) { + switch (NTK) { + case DebugNameTableKind::Default: + return nullptr; + case DebugNameTableKind::GNU: + return "GNU"; + case DebugNameTableKind::None: + return "None"; } return nullptr; } @@ -480,24 +589,58 @@ return const_cast<DILocalScope *>(this); } +DISubprogram::DISPFlags DISubprogram::getFlag(StringRef Flag) { + return StringSwitch<DISPFlags>(Flag) +#define HANDLE_DISP_FLAG(ID, NAME) .Case("DISPFlag" #NAME, SPFlag##NAME) +#include "llvm/IR/DebugInfoFlags.def" + .Default(SPFlagZero); +} + +StringRef DISubprogram::getFlagString(DISPFlags Flag) { + switch (Flag) { + // Appease a warning. + case SPFlagVirtuality: + return ""; +#define HANDLE_DISP_FLAG(ID, NAME) \ + case SPFlag##NAME: \ + return "DISPFlag" #NAME; +#include "llvm/IR/DebugInfoFlags.def" + } + return ""; +} + +DISubprogram::DISPFlags +DISubprogram::splitFlags(DISPFlags Flags, + SmallVectorImpl<DISPFlags> &SplitFlags) { + // Multi-bit fields can require special handling. In our case, however, the + // only multi-bit field is virtuality, and all its values happen to be + // single-bit values, so the right behavior just falls out. +#define HANDLE_DISP_FLAG(ID, NAME) \ + if (DISPFlags Bit = Flags & SPFlag##NAME) { \ + SplitFlags.push_back(Bit); \ + Flags &= ~Bit; \ + } +#include "llvm/IR/DebugInfoFlags.def" + return Flags; +} + DISubprogram *DISubprogram::getImpl( LLVMContext &Context, Metadata *Scope, MDString *Name, MDString *LinkageName, Metadata *File, unsigned Line, Metadata *Type, - bool IsLocalToUnit, bool IsDefinition, unsigned ScopeLine, - Metadata *ContainingType, unsigned Virtuality, unsigned VirtualIndex, - int ThisAdjustment, DIFlags Flags, bool IsOptimized, Metadata *Unit, - Metadata *TemplateParams, Metadata *Declaration, Metadata *Variables, + unsigned ScopeLine, Metadata *ContainingType, unsigned VirtualIndex, + int ThisAdjustment, DIFlags Flags, DISPFlags SPFlags, Metadata *Unit, + Metadata *TemplateParams, Metadata *Declaration, Metadata *RetainedNodes, Metadata *ThrownTypes, StorageType Storage, bool ShouldCreate) { assert(isCanonical(Name) && "Expected canonical MDString"); assert(isCanonical(LinkageName) && "Expected canonical MDString"); - DEFINE_GETIMPL_LOOKUP( - DISubprogram, (Scope, Name, LinkageName, File, Line, Type, IsLocalToUnit, - IsDefinition, ScopeLine, ContainingType, Virtuality, - VirtualIndex, ThisAdjustment, Flags, IsOptimized, Unit, - TemplateParams, Declaration, Variables, ThrownTypes)); + DEFINE_GETIMPL_LOOKUP(DISubprogram, + (Scope, Name, LinkageName, File, Line, Type, ScopeLine, + ContainingType, VirtualIndex, ThisAdjustment, Flags, + SPFlags, Unit, TemplateParams, Declaration, + RetainedNodes, ThrownTypes)); SmallVector<Metadata *, 11> Ops = { - File, Scope, Name, LinkageName, Type, Unit, - Declaration, Variables, ContainingType, TemplateParams, ThrownTypes}; + File, Scope, Name, LinkageName, Type, Unit, + Declaration, RetainedNodes, ContainingType, TemplateParams, ThrownTypes}; if (!ThrownTypes) { Ops.pop_back(); if (!TemplateParams) { @@ -506,11 +649,10 @@ Ops.pop_back(); } } - DEFINE_GETIMPL_STORE_N(DISubprogram, - (Line, ScopeLine, Virtuality, VirtualIndex, - ThisAdjustment, Flags, IsLocalToUnit, IsDefinition, - IsOptimized), - Ops, Ops.size()); + DEFINE_GETIMPL_STORE_N( + DISubprogram, + (Line, ScopeLine, VirtualIndex, ThisAdjustment, Flags, SPFlags), Ops, + Ops.size()); } bool DISubprogram::describes(const Function *F) const { @@ -557,6 +699,17 @@ DEFINE_GETIMPL_STORE(DINamespace, (ExportSymbols), Ops); } +DICommonBlock *DICommonBlock::getImpl(LLVMContext &Context, Metadata *Scope, + Metadata *Decl, MDString *Name, + Metadata *File, unsigned LineNo, + StorageType Storage, bool ShouldCreate) { + assert(isCanonical(Name) && "Expected canonical MDString"); + DEFINE_GETIMPL_LOOKUP(DICommonBlock, (Scope, Decl, Name, File, LineNo)); + // The nullptr is for DIScope's File operand. This should be refactored. + Metadata *Ops[] = {Scope, Decl, Name, File}; + DEFINE_GETIMPL_STORE(DICommonBlock, (LineNo), Ops); +} + DIModule *DIModule::getImpl(LLVMContext &Context, Metadata *Scope, MDString *Name, MDString *ConfigurationMacros, MDString *IncludePath, MDString *ISysRoot, @@ -593,19 +746,24 @@ MDString *LinkageName, Metadata *File, unsigned Line, Metadata *Type, bool IsLocalToUnit, bool IsDefinition, Metadata *StaticDataMemberDeclaration, - uint32_t AlignInBits, StorageType Storage, - bool ShouldCreate) { + Metadata *TemplateParams, uint32_t AlignInBits, + StorageType Storage, bool ShouldCreate) { assert(isCanonical(Name) && "Expected canonical MDString"); assert(isCanonical(LinkageName) && "Expected canonical MDString"); - DEFINE_GETIMPL_LOOKUP(DIGlobalVariable, - (Scope, Name, LinkageName, File, Line, Type, - IsLocalToUnit, IsDefinition, - StaticDataMemberDeclaration, AlignInBits)); - Metadata *Ops[] = { - Scope, Name, File, Type, Name, LinkageName, StaticDataMemberDeclaration}; + DEFINE_GETIMPL_LOOKUP(DIGlobalVariable, (Scope, Name, LinkageName, File, Line, + Type, IsLocalToUnit, IsDefinition, + StaticDataMemberDeclaration, + TemplateParams, AlignInBits)); + Metadata *Ops[] = {Scope, + Name, + File, + Type, + Name, + LinkageName, + StaticDataMemberDeclaration, + TemplateParams}; DEFINE_GETIMPL_STORE(DIGlobalVariable, - (Line, IsLocalToUnit, IsDefinition, AlignInBits), - Ops); + (Line, IsLocalToUnit, IsDefinition, AlignInBits), Ops); } DILocalVariable *DILocalVariable::getImpl(LLVMContext &Context, Metadata *Scope, @@ -650,6 +808,18 @@ return None; } +DILabel *DILabel::getImpl(LLVMContext &Context, Metadata *Scope, + MDString *Name, Metadata *File, unsigned Line, + StorageType Storage, + bool ShouldCreate) { + assert(Scope && "Expected scope"); + assert(isCanonical(Name) && "Expected canonical MDString"); + DEFINE_GETIMPL_LOOKUP(DILabel, + (Scope, Name, File, Line)); + Metadata *Ops[] = {Scope, Name, File}; + DEFINE_GETIMPL_STORE(DILabel, (Line), Ops); +} + DIExpression *DIExpression::getImpl(LLVMContext &Context, ArrayRef<uint64_t> Elements, StorageType Storage, bool ShouldCreate) { @@ -658,11 +828,23 @@ } unsigned DIExpression::ExprOperand::getSize() const { - switch (getOp()) { + uint64_t Op = getOp(); + + if (Op >= dwarf::DW_OP_breg0 && Op <= dwarf::DW_OP_breg31) + return 2; + + switch (Op) { + case dwarf::DW_OP_LLVM_convert: case dwarf::DW_OP_LLVM_fragment: + case dwarf::DW_OP_bregx: return 3; case dwarf::DW_OP_constu: + case dwarf::DW_OP_consts: + case dwarf::DW_OP_deref_size: case dwarf::DW_OP_plus_uconst: + case dwarf::DW_OP_LLVM_tag_offset: + case dwarf::DW_OP_entry_value: + case dwarf::DW_OP_regx: return 2; default: return 1; @@ -675,8 +857,13 @@ if (I->get() + I->getSize() > E->get()) return false; + uint64_t Op = I->getOp(); + if ((Op >= dwarf::DW_OP_reg0 && Op <= dwarf::DW_OP_reg31) || + (Op >= dwarf::DW_OP_breg0 && Op <= dwarf::DW_OP_breg31)) + return true; + // Check that the operand is valid. - switch (I->getOp()) { + switch (Op) { default: return false; case dwarf::DW_OP_LLVM_fragment: @@ -703,6 +890,15 @@ return false; break; } + case dwarf::DW_OP_entry_value: { + // An entry value operator must appear at the begin and the size + // of following expression should be 1, because we support only + // entry values of a simple register location. + return I->get() == expr_op_begin()->get() && I->getArg(0) == 1 && + getNumElements() == 2; + } + case dwarf::DW_OP_LLVM_convert: + case dwarf::DW_OP_LLVM_tag_offset: case dwarf::DW_OP_constu: case dwarf::DW_OP_plus_uconst: case dwarf::DW_OP_plus: @@ -717,13 +913,55 @@ case dwarf::DW_OP_shr: case dwarf::DW_OP_shra: case dwarf::DW_OP_deref: + case dwarf::DW_OP_deref_size: case dwarf::DW_OP_xderef: + case dwarf::DW_OP_lit0: + case dwarf::DW_OP_not: + case dwarf::DW_OP_dup: + case dwarf::DW_OP_regx: + case dwarf::DW_OP_bregx: break; } } return true; } +bool DIExpression::isImplicit() const { + unsigned N = getNumElements(); + if (isValid() && N > 0) { + switch (getElement(N-1)) { + case dwarf::DW_OP_stack_value: + case dwarf::DW_OP_LLVM_tag_offset: + return true; + case dwarf::DW_OP_LLVM_fragment: + return N > 1 && getElement(N-2) == dwarf::DW_OP_stack_value; + default: break; + } + } + return false; +} + +bool DIExpression::isComplex() const { + if (!isValid()) + return false; + + if (getNumElements() == 0) + return false; + + // If there are any elements other than fragment or tag_offset, then some + // kind of complex computation occurs. + for (const auto &It : expr_ops()) { + switch (It.getOp()) { + case dwarf::DW_OP_LLVM_tag_offset: + case dwarf::DW_OP_LLVM_fragment: + continue; + default: return true; + } + } + + return false; +} + Optional<DIExpression::FragmentInfo> DIExpression::getFragmentInfo(expr_op_iterator Start, expr_op_iterator End) { for (auto I = Start; I != End; ++I) @@ -771,43 +1009,128 @@ return false; } -DIExpression *DIExpression::prepend(const DIExpression *Expr, bool DerefBefore, - int64_t Offset, bool DerefAfter, - bool StackValue) { - SmallVector<uint64_t, 8> Ops; - if (DerefBefore) - Ops.push_back(dwarf::DW_OP_deref); - - appendOffset(Ops, Offset); - if (DerefAfter) - Ops.push_back(dwarf::DW_OP_deref); +const DIExpression *DIExpression::extractAddressClass(const DIExpression *Expr, + unsigned &AddrClass) { + const unsigned PatternSize = 4; + if (Expr->Elements.size() >= PatternSize && + Expr->Elements[PatternSize - 4] == dwarf::DW_OP_constu && + Expr->Elements[PatternSize - 2] == dwarf::DW_OP_swap && + Expr->Elements[PatternSize - 1] == dwarf::DW_OP_xderef) { + AddrClass = Expr->Elements[PatternSize - 3]; - return doPrepend(Expr, Ops, StackValue); + if (Expr->Elements.size() == PatternSize) + return nullptr; + return DIExpression::get(Expr->getContext(), + makeArrayRef(&*Expr->Elements.begin(), + Expr->Elements.size() - PatternSize)); + } + return Expr; } -DIExpression *DIExpression::doPrepend(const DIExpression *Expr, - SmallVectorImpl<uint64_t> &Ops, - bool StackValue) { - if (Expr) - for (auto Op : Expr->expr_ops()) { - // A DW_OP_stack_value comes at the end, but before a DW_OP_LLVM_fragment. - if (StackValue) { - if (Op.getOp() == dwarf::DW_OP_stack_value) - StackValue = false; - else if (Op.getOp() == dwarf::DW_OP_LLVM_fragment) { - Ops.push_back(dwarf::DW_OP_stack_value); - StackValue = false; - } +DIExpression *DIExpression::prepend(const DIExpression *Expr, uint8_t Flags, + int64_t Offset) { + SmallVector<uint64_t, 8> Ops; + if (Flags & DIExpression::DerefBefore) + Ops.push_back(dwarf::DW_OP_deref); + + appendOffset(Ops, Offset); + if (Flags & DIExpression::DerefAfter) + Ops.push_back(dwarf::DW_OP_deref); + + bool StackValue = Flags & DIExpression::StackValue; + bool EntryValue = Flags & DIExpression::EntryValue; + + return prependOpcodes(Expr, Ops, StackValue, EntryValue); +} + +DIExpression *DIExpression::prependOpcodes(const DIExpression *Expr, + SmallVectorImpl<uint64_t> &Ops, + bool StackValue, + bool EntryValue) { + assert(Expr && "Can't prepend ops to this expression"); + + if (EntryValue) { + Ops.push_back(dwarf::DW_OP_entry_value); + // Add size info needed for entry value expression. + // Add plus one for target register operand. + Ops.push_back(Expr->getNumElements() + 1); + } + + // If there are no ops to prepend, do not even add the DW_OP_stack_value. + if (Ops.empty()) + StackValue = false; + for (auto Op : Expr->expr_ops()) { + // A DW_OP_stack_value comes at the end, but before a DW_OP_LLVM_fragment. + if (StackValue) { + if (Op.getOp() == dwarf::DW_OP_stack_value) + StackValue = false; + else if (Op.getOp() == dwarf::DW_OP_LLVM_fragment) { + Ops.push_back(dwarf::DW_OP_stack_value); + StackValue = false; } - Ops.push_back(Op.getOp()); - for (unsigned I = 0; I < Op.getNumArgs(); ++I) - Ops.push_back(Op.getArg(I)); } + Op.appendToVector(Ops); + } if (StackValue) Ops.push_back(dwarf::DW_OP_stack_value); return DIExpression::get(Expr->getContext(), Ops); } +DIExpression *DIExpression::append(const DIExpression *Expr, + ArrayRef<uint64_t> Ops) { + assert(Expr && !Ops.empty() && "Can't append ops to this expression"); + + // Copy Expr's current op list. + SmallVector<uint64_t, 16> NewOps; + for (auto Op : Expr->expr_ops()) { + // Append new opcodes before DW_OP_{stack_value, LLVM_fragment}. + if (Op.getOp() == dwarf::DW_OP_stack_value || + Op.getOp() == dwarf::DW_OP_LLVM_fragment) { + NewOps.append(Ops.begin(), Ops.end()); + + // Ensure that the new opcodes are only appended once. + Ops = None; + } + Op.appendToVector(NewOps); + } + + NewOps.append(Ops.begin(), Ops.end()); + return DIExpression::get(Expr->getContext(), NewOps); +} + +DIExpression *DIExpression::appendToStack(const DIExpression *Expr, + ArrayRef<uint64_t> Ops) { + assert(Expr && !Ops.empty() && "Can't append ops to this expression"); + assert(none_of(Ops, + [](uint64_t Op) { + return Op == dwarf::DW_OP_stack_value || + Op == dwarf::DW_OP_LLVM_fragment; + }) && + "Can't append this op"); + + // Append a DW_OP_deref after Expr's current op list if it's non-empty and + // has no DW_OP_stack_value. + // + // Match .* DW_OP_stack_value (DW_OP_LLVM_fragment A B)?. + Optional<FragmentInfo> FI = Expr->getFragmentInfo(); + unsigned DropUntilStackValue = FI.hasValue() ? 3 : 0; + ArrayRef<uint64_t> ExprOpsBeforeFragment = + Expr->getElements().drop_back(DropUntilStackValue); + bool NeedsDeref = (Expr->getNumElements() > DropUntilStackValue) && + (ExprOpsBeforeFragment.back() != dwarf::DW_OP_stack_value); + bool NeedsStackValue = NeedsDeref || ExprOpsBeforeFragment.empty(); + + // Append a DW_OP_deref after Expr's current op list if needed, then append + // the new ops, and finally ensure that a single DW_OP_stack_value is present. + SmallVector<uint64_t, 16> NewOps; + if (NeedsDeref) + NewOps.push_back(dwarf::DW_OP_deref); + NewOps.append(Ops.begin(), Ops.end()); + if (NeedsStackValue) + NewOps.push_back(dwarf::DW_OP_stack_value); + return DIExpression::append(Expr, NewOps); +} + Optional<DIExpression *> DIExpression::createFragmentExpression( const DIExpression *Expr, unsigned OffsetInBits, unsigned SizeInBits) { SmallVector<uint64_t, 8> Ops; @@ -827,17 +1150,15 @@ case dwarf::DW_OP_LLVM_fragment: { // Make the new offset point into the existing fragment. uint64_t FragmentOffsetInBits = Op.getArg(0); - // Op.getArg(0) is FragmentOffsetInBits. - // Op.getArg(1) is FragmentSizeInBits. - assert((OffsetInBits + SizeInBits <= Op.getArg(0) + Op.getArg(1)) && + uint64_t FragmentSizeInBits = Op.getArg(1); + (void)FragmentSizeInBits; + assert((OffsetInBits + SizeInBits <= FragmentSizeInBits) && "new fragment outside of original fragment"); OffsetInBits += FragmentOffsetInBits; continue; } } - Ops.push_back(Op.getOp()); - for (unsigned I = 0; I < Op.getNumArgs(); ++I) - Ops.push_back(Op.getArg(I)); + Op.appendToVector(Ops); } } Ops.push_back(dwarf::DW_OP_LLVM_fragment);