From a2aa9970e1fec589591f7b8ac5557c47be4e8550 Mon Sep 17 00:00:00 2001 From: Sam McCall Date: Thu, 19 Mar 2020 11:58:00 +0100 Subject: [PATCH 01/15] [AST] Use TypeDependence bitfield to calculate dependence on Types. NFC Summary: This clears the way for adding an Error dependence bit to Type and having it mostly-automatically propagated. Reviewers: hokein Subscribers: jfb, cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D76424 --- clang/include/clang/AST/DependenceFlags.h | 26 +++ clang/include/clang/AST/LocInfoType.h | 5 +- clang/include/clang/AST/Type.h | 245 ++++++-------------- clang/include/clang/AST/TypeProperties.td | 12 +- clang/lib/AST/ASTContext.cpp | 19 +- clang/lib/AST/Type.cpp | 259 ++++++++++------------ 6 files changed, 226 insertions(+), 340 deletions(-) diff --git a/clang/include/clang/AST/DependenceFlags.h b/clang/include/clang/AST/DependenceFlags.h index ee6439fc984cf9..788227156c4d9d 100644 --- a/clang/include/clang/AST/DependenceFlags.h +++ b/clang/include/clang/AST/DependenceFlags.h @@ -115,6 +115,32 @@ inline ExprDependence turnTypeToValueDependence(ExprDependence D) { // type dependency. return D & ~ExprDependence::Type; } +inline ExprDependence turnValueToTypeDependence(ExprDependence D) { + // Type-dependent expressions are always be value-dependent. + if (D & ExprDependence::Value) + D |= ExprDependence::Type; + return D; +} + +// Returned type-dependence will never have VariablyModified set. +inline TypeDependence toTypeDependence(ExprDependence D) { + // Supported bits all have the same representation. + return static_cast(D & (ExprDependence::UnexpandedPack | + ExprDependence::Instantiation | + ExprDependence::Type)); +} +inline TypeDependence toTypeDependence(NestedNameSpecifierDependence D) { + // Supported bits all have the same representation. + return static_cast(D); +} +inline TypeDependence toTypeDependence(TemplateNameDependence D) { + // Supported bits all have the same representation. + return static_cast(D); +} +inline TypeDependence toTypeDependence(TemplateArgumentDependence D) { + // Supported bits all have the same representation. + return static_cast(D); +} inline NestedNameSpecifierDependence toNestedNameSpecifierDependendence(TypeDependence D) { diff --git a/clang/include/clang/AST/LocInfoType.h b/clang/include/clang/AST/LocInfoType.h index 1073174bcf9134..7e845ad03587cb 100644 --- a/clang/include/clang/AST/LocInfoType.h +++ b/clang/include/clang/AST/LocInfoType.h @@ -35,10 +35,7 @@ class LocInfoType : public Type { TypeSourceInfo *DeclInfo; LocInfoType(QualType ty, TypeSourceInfo *TInfo) - : Type((TypeClass)LocInfo, ty, ty->isDependentType(), - ty->isInstantiationDependentType(), ty->isVariablyModifiedType(), - ty->containsUnexpandedParameterPack()), - DeclInfo(TInfo) { + : Type((TypeClass)LocInfo, ty, ty->getDependence()), DeclInfo(TInfo) { assert(getTypeClass() == (TypeClass)LocInfo && "LocInfo didn't fit in TC?"); } friend class Sema; diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index 16db1d5cbc3ad9..b8f49127bbd0ca 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -1818,23 +1818,11 @@ class alignas(8) Type : public ExtQualsTypeCommonBase { protected: friend class ASTContext; - Type(TypeClass tc, QualType canon, bool Dependent, - bool InstantiationDependent, bool VariablyModified, - bool ContainsUnexpandedParameterPack) + Type(TypeClass tc, QualType canon, TypeDependence Dependence) : ExtQualsTypeCommonBase(this, canon.isNull() ? QualType(this_(), 0) : canon) { - auto Deps = TypeDependence::None; - if (Dependent) - Deps |= TypeDependence::Dependent | TypeDependence::Instantiation; - if (InstantiationDependent) - Deps |= TypeDependence::Instantiation; - if (ContainsUnexpandedParameterPack) - Deps |= TypeDependence::UnexpandedPack; - if (VariablyModified) - Deps |= TypeDependence::VariablyModified; - TypeBits.TC = tc; - TypeBits.Dependence = static_cast(Deps); + TypeBits.Dependence = static_cast(Dependence); TypeBits.CacheValid = false; TypeBits.CachedLocalOrUnnamed = false; TypeBits.CachedLinkage = NoLinkage; @@ -1844,41 +1832,11 @@ class alignas(8) Type : public ExtQualsTypeCommonBase { // silence VC++ warning C4355: 'this' : used in base member initializer list Type *this_() { return this; } - void setDependent(bool D = true) { - if (!D) { - TypeBits.Dependence &= ~static_cast(TypeDependence::Dependent); - return; - } - TypeBits.Dependence |= static_cast(TypeDependence::Dependent | - TypeDependence::Instantiation); - } - - void setInstantiationDependent(bool D = true) { - if (D) - TypeBits.Dependence |= - static_cast(TypeDependence::Instantiation); - else - TypeBits.Dependence &= - ~static_cast(TypeDependence::Instantiation); - } - - void setVariablyModified(bool VM = true) { - if (VM) - TypeBits.Dependence |= - static_cast(TypeDependence::VariablyModified); - else - TypeBits.Dependence &= - ~static_cast(TypeDependence::VariablyModified); + void setDependence(TypeDependence D) { + TypeBits.Dependence = static_cast(D); } - void setContainsUnexpandedParameterPack(bool PP = true) { - if (PP) - TypeBits.Dependence |= - static_cast(TypeDependence::UnexpandedPack); - else - TypeBits.Dependence &= - ~static_cast(TypeDependence::UnexpandedPack); - } + void addDependence(TypeDependence D) { setDependence(getDependence() | D); } public: friend class ASTReader; @@ -2519,10 +2477,9 @@ class BuiltinType : public Type { friend class ASTContext; // ASTContext creates these. BuiltinType(Kind K) - : Type(Builtin, QualType(), /*Dependent=*/(K == Dependent), - /*InstantiationDependent=*/(K == Dependent), - /*VariablyModified=*/false, - /*Unexpanded parameter pack=*/false) { + : Type(Builtin, QualType(), + K == Dependent ? TypeDependence::DependentInstantiation + : TypeDependence::None) { BuiltinTypeBits.Kind = K; } @@ -2592,10 +2549,7 @@ class ComplexType : public Type, public llvm::FoldingSetNode { QualType ElementType; ComplexType(QualType Element, QualType CanonicalPtr) - : Type(Complex, CanonicalPtr, Element->isDependentType(), - Element->isInstantiationDependentType(), - Element->isVariablyModifiedType(), - Element->containsUnexpandedParameterPack()), + : Type(Complex, CanonicalPtr, Element->getDependence()), ElementType(Element) {} public: @@ -2622,11 +2576,7 @@ class ParenType : public Type, public llvm::FoldingSetNode { QualType Inner; ParenType(QualType InnerType, QualType CanonType) - : Type(Paren, CanonType, InnerType->isDependentType(), - InnerType->isInstantiationDependentType(), - InnerType->isVariablyModifiedType(), - InnerType->containsUnexpandedParameterPack()), - Inner(InnerType) {} + : Type(Paren, CanonType, InnerType->getDependence()), Inner(InnerType) {} public: QualType getInnerType() const { return Inner; } @@ -2652,10 +2602,7 @@ class PointerType : public Type, public llvm::FoldingSetNode { QualType PointeeType; PointerType(QualType Pointee, QualType CanonicalPtr) - : Type(Pointer, CanonicalPtr, Pointee->isDependentType(), - Pointee->isInstantiationDependentType(), - Pointee->isVariablyModifiedType(), - Pointee->containsUnexpandedParameterPack()), + : Type(Pointer, CanonicalPtr, Pointee->getDependence()), PointeeType(Pointee) {} public: @@ -2703,10 +2650,7 @@ class AdjustedType : public Type, public llvm::FoldingSetNode { AdjustedType(TypeClass TC, QualType OriginalTy, QualType AdjustedTy, QualType CanonicalPtr) - : Type(TC, CanonicalPtr, OriginalTy->isDependentType(), - OriginalTy->isInstantiationDependentType(), - OriginalTy->isVariablyModifiedType(), - OriginalTy->containsUnexpandedParameterPack()), + : Type(TC, CanonicalPtr, OriginalTy->getDependence()), OriginalTy(OriginalTy), AdjustedTy(AdjustedTy) {} public: @@ -2755,10 +2699,7 @@ class BlockPointerType : public Type, public llvm::FoldingSetNode { QualType PointeeType; BlockPointerType(QualType Pointee, QualType CanonicalCls) - : Type(BlockPointer, CanonicalCls, Pointee->isDependentType(), - Pointee->isInstantiationDependentType(), - Pointee->isVariablyModifiedType(), - Pointee->containsUnexpandedParameterPack()), + : Type(BlockPointer, CanonicalCls, Pointee->getDependence()), PointeeType(Pointee) {} public: @@ -2788,10 +2729,7 @@ class ReferenceType : public Type, public llvm::FoldingSetNode { protected: ReferenceType(TypeClass tc, QualType Referencee, QualType CanonicalRef, bool SpelledAsLValue) - : Type(tc, CanonicalRef, Referencee->isDependentType(), - Referencee->isInstantiationDependentType(), - Referencee->isVariablyModifiedType(), - Referencee->containsUnexpandedParameterPack()), + : Type(tc, CanonicalRef, Referencee->getDependence()), PointeeType(Referencee) { ReferenceTypeBits.SpelledAsLValue = SpelledAsLValue; ReferenceTypeBits.InnerRef = Referencee->isReferenceType(); @@ -2876,13 +2814,9 @@ class MemberPointerType : public Type, public llvm::FoldingSetNode { MemberPointerType(QualType Pointee, const Type *Cls, QualType CanonicalPtr) : Type(MemberPointer, CanonicalPtr, - Cls->isDependentType() || Pointee->isDependentType(), - (Cls->isInstantiationDependentType() || - Pointee->isInstantiationDependentType()), - Pointee->isVariablyModifiedType(), - (Cls->containsUnexpandedParameterPack() || - Pointee->containsUnexpandedParameterPack())), - PointeeType(Pointee), Class(Cls) {} + (Cls->getDependence() & ~TypeDependence::VariablyModified) | + Pointee->getDependence()), + PointeeType(Pointee), Class(Cls) {} public: QualType getPointeeType() const { return PointeeType; } @@ -3707,14 +3641,9 @@ class FunctionType : public Type { }; protected: - FunctionType(TypeClass tc, QualType res, - QualType Canonical, bool Dependent, - bool InstantiationDependent, - bool VariablyModified, bool ContainsUnexpandedParameterPack, - ExtInfo Info) - : Type(tc, Canonical, Dependent, InstantiationDependent, VariablyModified, - ContainsUnexpandedParameterPack), - ResultType(res) { + FunctionType(TypeClass tc, QualType res, QualType Canonical, + TypeDependence Dependence, ExtInfo Info) + : Type(tc, Canonical, Dependence), ResultType(res) { FunctionTypeBits.ExtInfo = Info.Bits; } @@ -3766,9 +3695,10 @@ class FunctionNoProtoType : public FunctionType, public llvm::FoldingSetNode { FunctionNoProtoType(QualType Result, QualType Canonical, ExtInfo Info) : FunctionType(FunctionNoProto, Result, Canonical, - /*Dependent=*/false, /*InstantiationDependent=*/false, - Result->isVariablyModifiedType(), - /*ContainsUnexpandedParameterPack=*/false, Info) {} + Result->getDependence() & + ~(TypeDependence::DependentInstantiation | + TypeDependence::UnexpandedPack), + Info) {} public: // No additional state past what FunctionType provides. @@ -4260,9 +4190,9 @@ class UnresolvedUsingType : public Type { UnresolvedUsingTypenameDecl *Decl; UnresolvedUsingType(const UnresolvedUsingTypenameDecl *D) - : Type(UnresolvedUsing, QualType(), true, true, false, - /*ContainsUnexpandedParameterPack=*/false), - Decl(const_cast(D)) {} + : Type(UnresolvedUsing, QualType(), + TypeDependence::DependentInstantiation), + Decl(const_cast(D)) {} public: UnresolvedUsingTypenameDecl *getDecl() const { return Decl; } @@ -4291,11 +4221,8 @@ class TypedefType : public Type { friend class ASTContext; // ASTContext creates these. TypedefType(TypeClass tc, const TypedefNameDecl *D, QualType can) - : Type(tc, can, can->isDependentType(), - can->isInstantiationDependentType(), - can->isVariablyModifiedType(), - /*ContainsUnexpandedParameterPack=*/false), - Decl(const_cast(D)) { + : Type(tc, can, can->getDependence() & ~TypeDependence::UnexpandedPack), + Decl(const_cast(D)) { assert(!isa(can) && "Invalid canonical type"); } @@ -4318,10 +4245,7 @@ class MacroQualifiedType : public Type { MacroQualifiedType(QualType UnderlyingTy, QualType CanonTy, const IdentifierInfo *MacroII) - : Type(MacroQualified, CanonTy, UnderlyingTy->isDependentType(), - UnderlyingTy->isInstantiationDependentType(), - UnderlyingTy->isVariablyModifiedType(), - UnderlyingTy->containsUnexpandedParameterPack()), + : Type(MacroQualified, CanonTy, UnderlyingTy->getDependence()), UnderlyingTy(UnderlyingTy), MacroII(MacroII) { assert(isa(UnderlyingTy) && "Expected a macro qualified type to only wrap attributed types."); @@ -4393,11 +4317,7 @@ class TypeOfType : public Type { QualType TOType; TypeOfType(QualType T, QualType can) - : Type(TypeOf, can, T->isDependentType(), - T->isInstantiationDependentType(), - T->isVariablyModifiedType(), - T->containsUnexpandedParameterPack()), - TOType(T) { + : Type(TypeOf, can, T->getDependence()), TOType(T) { assert(!isa(can) && "Invalid canonical type"); } @@ -4606,10 +4526,7 @@ class AttributedType : public Type, public llvm::FoldingSetNode { AttributedType(QualType canon, attr::Kind attrKind, QualType modified, QualType equivalent) - : Type(Attributed, canon, equivalent->isDependentType(), - equivalent->isInstantiationDependentType(), - equivalent->isVariablyModifiedType(), - equivalent->containsUnexpandedParameterPack()), + : Type(Attributed, canon, equivalent->getDependence()), ModifiedType(modified), EquivalentType(equivalent) { AttributedTypeBits.AttrKind = attrKind; } @@ -4711,18 +4628,16 @@ class TemplateTypeParmType : public Type, public llvm::FoldingSetNode { /// Build a non-canonical type. TemplateTypeParmType(TemplateTypeParmDecl *TTPDecl, QualType Canon) - : Type(TemplateTypeParm, Canon, /*Dependent=*/true, - /*InstantiationDependent=*/true, - /*VariablyModified=*/false, - Canon->containsUnexpandedParameterPack()), + : Type(TemplateTypeParm, Canon, + TypeDependence::DependentInstantiation | + (Canon->getDependence() & TypeDependence::UnexpandedPack)), TTPDecl(TTPDecl) {} /// Build the canonical type. TemplateTypeParmType(unsigned D, unsigned I, bool PP) : Type(TemplateTypeParm, QualType(this, 0), - /*Dependent=*/true, - /*InstantiationDependent=*/true, - /*VariablyModified=*/false, PP) { + TypeDependence::DependentInstantiation | + (PP ? TypeDependence::UnexpandedPack : TypeDependence::None)) { CanTTPTInfo.Depth = D; CanTTPTInfo.Index = I; CanTTPTInfo.ParameterPack = PP; @@ -4779,10 +4694,7 @@ class SubstTemplateTypeParmType : public Type, public llvm::FoldingSetNode { const TemplateTypeParmType *Replaced; SubstTemplateTypeParmType(const TemplateTypeParmType *Param, QualType Canon) - : Type(SubstTemplateTypeParm, Canon, Canon->isDependentType(), - Canon->isInstantiationDependentType(), - Canon->isVariablyModifiedType(), - Canon->containsUnexpandedParameterPack()), + : Type(SubstTemplateTypeParm, Canon, Canon->getDependence()), Replaced(Param) {} public: @@ -4879,23 +4791,16 @@ class SubstTemplateTypeParmPackType : public Type, public llvm::FoldingSetNode { /// the latter case, it is also a dependent type. class DeducedType : public Type { protected: - DeducedType(TypeClass TC, QualType DeducedAsType, bool IsDependent, - bool IsInstantiationDependent, bool ContainsParameterPack) + DeducedType(TypeClass TC, QualType DeducedAsType, + TypeDependence ExtraDependence) : Type(TC, // FIXME: Retain the sugared deduced type? DeducedAsType.isNull() ? QualType(this, 0) : DeducedAsType.getCanonicalType(), - IsDependent, IsInstantiationDependent, - /*VariablyModified=*/false, ContainsParameterPack) { - if (!DeducedAsType.isNull()) { - if (DeducedAsType->isDependentType()) - setDependent(); - if (DeducedAsType->isInstantiationDependentType()) - setInstantiationDependent(); - if (DeducedAsType->containsUnexpandedParameterPack()) - setContainsUnexpandedParameterPack(); - } - } + ExtraDependence | (DeducedAsType.isNull() + ? TypeDependence::None + : DeducedAsType->getDependence() & + ~TypeDependence::VariablyModified)) {} public: bool isSugared() const { return !isCanonicalUnqualified(); } @@ -4924,7 +4829,7 @@ class alignas(8) AutoType : public DeducedType, public llvm::FoldingSetNode { ConceptDecl *TypeConstraintConcept; AutoType(QualType DeducedAsType, AutoTypeKeyword Keyword, - bool IsDeducedAsDependent, bool IsDeducedAsPack, ConceptDecl *CD, + TypeDependence ExtraDependence, ConceptDecl *CD, ArrayRef TypeConstraintArgs); const TemplateArgument *getArgBuffer() const { @@ -4995,9 +4900,10 @@ class DeducedTemplateSpecializationType : public DeducedType, QualType DeducedAsType, bool IsDeducedAsDependent) : DeducedType(DeducedTemplateSpecialization, DeducedAsType, - IsDeducedAsDependent || Template.isDependent(), - IsDeducedAsDependent || Template.isInstantiationDependent(), - Template.containsUnexpandedParameterPack()), + toTypeDependence(Template.getDependence()) | + (IsDeducedAsDependent + ? TypeDependence::DependentInstantiation + : TypeDependence::None)), Template(Template) {} public: @@ -5199,10 +5105,8 @@ class InjectedClassNameType : public Type { QualType InjectedType; InjectedClassNameType(CXXRecordDecl *D, QualType TST) - : Type(InjectedClassName, QualType(), /*Dependent=*/true, - /*InstantiationDependent=*/true, - /*VariablyModified=*/false, - /*ContainsUnexpandedParameterPack=*/false), + : Type(InjectedClassName, QualType(), + TypeDependence::DependentInstantiation), Decl(D), InjectedType(TST) { assert(isa(TST)); assert(!TST.hasQualifiers()); @@ -5281,11 +5185,8 @@ enum ElaboratedTypeKeyword { class TypeWithKeyword : public Type { protected: TypeWithKeyword(ElaboratedTypeKeyword Keyword, TypeClass tc, - QualType Canonical, bool Dependent, - bool InstantiationDependent, bool VariablyModified, - bool ContainsUnexpandedParameterPack) - : Type(tc, Canonical, Dependent, InstantiationDependent, VariablyModified, - ContainsUnexpandedParameterPack) { + QualType Canonical, TypeDependence Dependence) + : Type(tc, Canonical, Dependence) { TypeWithKeywordBits.Keyword = Keyword; } @@ -5349,10 +5250,7 @@ class ElaboratedType final ElaboratedType(ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS, QualType NamedType, QualType CanonType, TagDecl *OwnedTagDecl) : TypeWithKeyword(Keyword, Elaborated, CanonType, - NamedType->isDependentType(), - NamedType->isInstantiationDependentType(), - NamedType->isVariablyModifiedType(), - NamedType->containsUnexpandedParameterPack()), + NamedType->getDependence()), NNS(NNS), NamedType(NamedType) { ElaboratedTypeBits.HasOwnedTagDecl = false; if (OwnedTagDecl) { @@ -5423,10 +5321,9 @@ class DependentNameType : public TypeWithKeyword, public llvm::FoldingSetNode { DependentNameType(ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS, const IdentifierInfo *Name, QualType CanonType) - : TypeWithKeyword(Keyword, DependentName, CanonType, /*Dependent=*/true, - /*InstantiationDependent=*/true, - /*VariablyModified=*/false, - NNS->containsUnexpandedParameterPack()), + : TypeWithKeyword(Keyword, DependentName, CanonType, + TypeDependence::DependentInstantiation | + toTypeDependence(NNS->getDependence())), NNS(NNS), Name(Name) {} public: @@ -5563,10 +5460,9 @@ class PackExpansionType : public Type, public llvm::FoldingSetNode { PackExpansionType(QualType Pattern, QualType Canon, Optional NumExpansions) - : Type(PackExpansion, Canon, /*Dependent=*/Pattern->isDependentType(), - /*InstantiationDependent=*/true, - /*VariablyModified=*/Pattern->isVariablyModifiedType(), - /*ContainsUnexpandedParameterPack=*/false), + : Type(PackExpansion, Canon, + (Pattern->getDependence() | TypeDependence::Instantiation) & + ~TypeDependence::UnexpandedPack), Pattern(Pattern) { PackExpansionTypeBits.NumExpansions = NumExpansions ? *NumExpansions + 1 : 0; @@ -5785,8 +5681,8 @@ class ObjCObjectType : public Type, bool isKindOf); ObjCObjectType(enum Nonce_ObjCInterface) - : Type(ObjCInterface, QualType(), false, false, false, false), - BaseType(QualType(this_(), 0)) { + : Type(ObjCInterface, QualType(), TypeDependence::None), + BaseType(QualType(this_(), 0)) { ObjCObjectTypeBits.NumProtocols = 0; ObjCObjectTypeBits.NumTypeArgs = 0; ObjCObjectTypeBits.IsKindOf = 0; @@ -6001,11 +5897,7 @@ class ObjCObjectPointerType : public Type, public llvm::FoldingSetNode { QualType PointeeType; ObjCObjectPointerType(QualType Canonical, QualType Pointee) - : Type(ObjCObjectPointer, Canonical, - Pointee->isDependentType(), - Pointee->isInstantiationDependentType(), - Pointee->isVariablyModifiedType(), - Pointee->containsUnexpandedParameterPack()), + : Type(ObjCObjectPointer, Canonical, Pointee->getDependence()), PointeeType(Pointee) {} public: @@ -6175,11 +6067,7 @@ class AtomicType : public Type, public llvm::FoldingSetNode { QualType ValueType; AtomicType(QualType ValTy, QualType Canonical) - : Type(Atomic, Canonical, ValTy->isDependentType(), - ValTy->isInstantiationDependentType(), - ValTy->isVariablyModifiedType(), - ValTy->containsUnexpandedParameterPack()), - ValueType(ValTy) {} + : Type(Atomic, Canonical, ValTy->getDependence()), ValueType(ValTy) {} public: /// Gets the type contained by this atomic type, i.e. @@ -6210,10 +6098,7 @@ class PipeType : public Type, public llvm::FoldingSetNode { bool isRead; PipeType(QualType elemType, QualType CanonicalPtr, bool isRead) - : Type(Pipe, CanonicalPtr, elemType->isDependentType(), - elemType->isInstantiationDependentType(), - elemType->isVariablyModifiedType(), - elemType->containsUnexpandedParameterPack()), + : Type(Pipe, CanonicalPtr, elemType->getDependence()), ElementType(elemType), isRead(isRead) {} public: diff --git a/clang/include/clang/AST/TypeProperties.td b/clang/include/clang/AST/TypeProperties.td index 4afd9790d8750c..994f932170ae1f 100644 --- a/clang/include/clang/AST/TypeProperties.td +++ b/clang/include/clang/AST/TypeProperties.td @@ -458,7 +458,9 @@ let Class = TagType in { let Class = EnumType in { def : Creator<[{ QualType result = ctx.getEnumType(cast(declaration)); - const_cast(result.getTypePtr())->setDependent(dependent); + if (dependent) + const_cast(result.getTypePtr()) + ->addDependence(TypeDependence::DependentInstantiation); return result; }]>; } @@ -467,7 +469,9 @@ let Class = RecordType in { def : Creator<[{ auto record = cast(declaration); QualType result = ctx.getRecordType(record); - const_cast(result.getTypePtr())->setDependent(dependent); + if (dependent) + const_cast(result.getTypePtr()) + ->addDependence(TypeDependence::DependentInstantiation); return result; }]>; } @@ -610,7 +614,9 @@ let Class = TemplateSpecializationType in { templateArguments, *underlyingType); } - const_cast(result.getTypePtr())->setDependent(dependent); + if (dependent) + const_cast(result.getTypePtr()) + ->addDependence(TypeDependence::DependentInstantiation); return result; }]>; } diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 390abda466a2ec..dca6523d5176c2 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -29,6 +29,7 @@ #include "clang/AST/DeclOpenMP.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/DeclarationName.h" +#include "clang/AST/DependenceFlags.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprConcepts.h" @@ -5125,8 +5126,12 @@ ASTContext::getAutoType(QualType DeducedType, AutoTypeKeyword Keyword, void *Mem = Allocate(sizeof(AutoType) + sizeof(TemplateArgument) * TypeConstraintArgs.size(), TypeAlignment); - auto *AT = new (Mem) AutoType(DeducedType, Keyword, IsDependent, IsPack, - TypeConstraintConcept, TypeConstraintArgs); + auto *AT = new (Mem) AutoType( + DeducedType, Keyword, + (IsDependent ? TypeDependence::DependentInstantiation + : TypeDependence::None) | + (IsPack ? TypeDependence::UnexpandedPack : TypeDependence::None), + TypeConstraintConcept, TypeConstraintArgs); Types.push_back(AT); if (InsertPos) AutoTypes.InsertNode(AT, InsertPos); @@ -5186,11 +5191,11 @@ QualType ASTContext::getAtomicType(QualType T) const { /// getAutoDeductType - Get type pattern for deducing against 'auto'. QualType ASTContext::getAutoDeductType() const { if (AutoDeductTy.isNull()) - AutoDeductTy = QualType( - new (*this, TypeAlignment) AutoType(QualType(), AutoTypeKeyword::Auto, - /*dependent*/false, /*pack*/false, - /*concept*/nullptr, /*args*/{}), - 0); + AutoDeductTy = QualType(new (*this, TypeAlignment) + AutoType(QualType(), AutoTypeKeyword::Auto, + TypeDependence::None, + /*concept*/ nullptr, /*args*/ {}), + 0); return AutoDeductTy; } diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index 6e1c70f952629b..69c942e46f7298 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -20,6 +20,7 @@ #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" +#include "clang/AST/DependenceFlags.h" #include "clang/AST/Expr.h" #include "clang/AST/NestedNameSpecifier.h" #include "clang/AST/NonTrivialTypeVisitor.h" @@ -123,14 +124,15 @@ ArrayType::ArrayType(TypeClass tc, QualType et, QualType can, // // template int arr[] = {N...}; : Type(tc, can, - et->isDependentType() || (sz && sz->isValueDependent()) || - tc == DependentSizedArray, - et->isInstantiationDependentType() || - (sz && sz->isInstantiationDependent()) || - tc == DependentSizedArray, - (tc == VariableArray || et->isVariablyModifiedType()), - et->containsUnexpandedParameterPack() || - (sz && sz->containsUnexpandedParameterPack())), + et->getDependence() | + (sz ? toTypeDependence( + turnValueToTypeDependence(sz->getDependence())) + : TypeDependence::None) | + (tc == VariableArray ? TypeDependence::VariablyModified + : TypeDependence::None) | + (tc == DependentSizedArray + ? TypeDependence::DependentInstantiation + : TypeDependence::None)), ElementType(et) { ArrayTypeBits.IndexTypeQuals = tq; ArrayTypeBits.SizeModifier = sm; @@ -217,14 +219,16 @@ void DependentSizedArrayType::Profile(llvm::FoldingSetNodeID &ID, E->Profile(ID, Context, true); } -DependentVectorType::DependentVectorType( - const ASTContext &Context, QualType ElementType, QualType CanonType, - Expr *SizeExpr, SourceLocation Loc, VectorType::VectorKind VecKind) - : Type(DependentVector, CanonType, /*Dependent=*/true, - /*InstantiationDependent=*/true, - ElementType->isVariablyModifiedType(), - ElementType->containsUnexpandedParameterPack() || - (SizeExpr && SizeExpr->containsUnexpandedParameterPack())), +DependentVectorType::DependentVectorType(const ASTContext &Context, + QualType ElementType, + QualType CanonType, Expr *SizeExpr, + SourceLocation Loc, + VectorType::VectorKind VecKind) + : Type(DependentVector, CanonType, + TypeDependence::DependentInstantiation | + ElementType->getDependence() | + (SizeExpr ? toTypeDependence(SizeExpr->getDependence()) + : TypeDependence::None)), Context(Context), ElementType(ElementType), SizeExpr(SizeExpr), Loc(Loc) { VectorTypeBits.VecKind = VecKind; } @@ -238,19 +242,16 @@ void DependentVectorType::Profile(llvm::FoldingSetNodeID &ID, SizeExpr->Profile(ID, Context, true); } -DependentSizedExtVectorType::DependentSizedExtVectorType(const - ASTContext &Context, - QualType ElementType, - QualType can, - Expr *SizeExpr, - SourceLocation loc) - : Type(DependentSizedExtVector, can, /*Dependent=*/true, - /*InstantiationDependent=*/true, - ElementType->isVariablyModifiedType(), - (ElementType->containsUnexpandedParameterPack() || - (SizeExpr && SizeExpr->containsUnexpandedParameterPack()))), - Context(Context), SizeExpr(SizeExpr), ElementType(ElementType), - loc(loc) {} +DependentSizedExtVectorType::DependentSizedExtVectorType( + const ASTContext &Context, QualType ElementType, QualType can, + Expr *SizeExpr, SourceLocation loc) + : Type(DependentSizedExtVector, can, + TypeDependence::DependentInstantiation | + ElementType->getDependence() | + (SizeExpr ? toTypeDependence(SizeExpr->getDependence()) + : TypeDependence::None)), + Context(Context), SizeExpr(SizeExpr), ElementType(ElementType), loc(loc) { +} void DependentSizedExtVectorType::Profile(llvm::FoldingSetNodeID &ID, @@ -260,15 +261,16 @@ DependentSizedExtVectorType::Profile(llvm::FoldingSetNodeID &ID, SizeExpr->Profile(ID, Context, true); } -DependentAddressSpaceType::DependentAddressSpaceType( - const ASTContext &Context, QualType PointeeType, QualType can, - Expr *AddrSpaceExpr, SourceLocation loc) - : Type(DependentAddressSpace, can, /*Dependent=*/true, - /*InstantiationDependent=*/true, - PointeeType->isVariablyModifiedType(), - (PointeeType->containsUnexpandedParameterPack() || - (AddrSpaceExpr && - AddrSpaceExpr->containsUnexpandedParameterPack()))), +DependentAddressSpaceType::DependentAddressSpaceType(const ASTContext &Context, + QualType PointeeType, + QualType can, + Expr *AddrSpaceExpr, + SourceLocation loc) + : Type(DependentAddressSpace, can, + TypeDependence::DependentInstantiation | + PointeeType->getDependence() | + (AddrSpaceExpr ? toTypeDependence(AddrSpaceExpr->getDependence()) + : TypeDependence::None)), Context(Context), AddrSpaceExpr(AddrSpaceExpr), PointeeType(PointeeType), loc(loc) {} @@ -286,11 +288,7 @@ VectorType::VectorType(QualType vecType, unsigned nElements, QualType canonType, VectorType::VectorType(TypeClass tc, QualType vecType, unsigned nElements, QualType canonType, VectorKind vecKind) - : Type(tc, canonType, vecType->isDependentType(), - vecType->isInstantiationDependentType(), - vecType->isVariablyModifiedType(), - vecType->containsUnexpandedParameterPack()), - ElementType(vecType) { + : Type(tc, canonType, vecType->getDependence()), ElementType(vecType) { VectorTypeBits.VecKind = vecKind; VectorTypeBits.NumElements = nElements; } @@ -652,14 +650,11 @@ bool Type::isObjCClassOrClassKindOfType() const { return OPT->isObjCClassType() || OPT->isObjCQualifiedClassType(); } -ObjCTypeParamType::ObjCTypeParamType(const ObjCTypeParamDecl *D, - QualType can, +ObjCTypeParamType::ObjCTypeParamType(const ObjCTypeParamDecl *D, QualType can, ArrayRef protocols) - : Type(ObjCTypeParam, can, can->isDependentType(), - can->isInstantiationDependentType(), - can->isVariablyModifiedType(), - /*ContainsUnexpandedParameterPack=*/false), - OTPDecl(const_cast(D)) { + : Type(ObjCTypeParam, can, + can->getDependence() & ~TypeDependence::UnexpandedPack), + OTPDecl(const_cast(D)) { initialize(protocols); } @@ -667,11 +662,7 @@ ObjCObjectType::ObjCObjectType(QualType Canonical, QualType Base, ArrayRef typeArgs, ArrayRef protocols, bool isKindOf) - : Type(ObjCObject, Canonical, Base->isDependentType(), - Base->isInstantiationDependentType(), - Base->isVariablyModifiedType(), - Base->containsUnexpandedParameterPack()), - BaseType(Base) { + : Type(ObjCObject, Canonical, Base->getDependence()), BaseType(Base) { ObjCObjectTypeBits.IsKindOf = isKindOf; ObjCObjectTypeBits.NumTypeArgs = typeArgs.size(); @@ -682,13 +673,7 @@ ObjCObjectType::ObjCObjectType(QualType Canonical, QualType Base, typeArgs.size() * sizeof(QualType)); for (auto typeArg : typeArgs) { - if (typeArg->isDependentType()) - setDependent(); - else if (typeArg->isInstantiationDependentType()) - setInstantiationDependent(); - - if (typeArg->containsUnexpandedParameterPack()) - setContainsUnexpandedParameterPack(); + addDependence(typeArg->getDependence() & ~TypeDependence::VariablyModified); } // Initialize the protocol qualifiers. The protocol storage is known // after we set number of type arguments. @@ -2715,21 +2700,20 @@ StringRef TypeWithKeyword::getKeywordName(ElaboratedTypeKeyword Keyword) { } DependentTemplateSpecializationType::DependentTemplateSpecializationType( - ElaboratedTypeKeyword Keyword, - NestedNameSpecifier *NNS, const IdentifierInfo *Name, - ArrayRef Args, - QualType Canon) - : TypeWithKeyword(Keyword, DependentTemplateSpecialization, Canon, true, true, - /*VariablyModified=*/false, - NNS && NNS->containsUnexpandedParameterPack()), - NNS(NNS), Name(Name) { + ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS, + const IdentifierInfo *Name, ArrayRef Args, QualType Canon) + : TypeWithKeyword(Keyword, DependentTemplateSpecialization, Canon, + TypeDependence::DependentInstantiation | + (NNS ? toTypeDependence(NNS->getDependence()) + : TypeDependence::None)), + NNS(NNS), Name(Name) { DependentTemplateSpecializationTypeBits.NumArgs = Args.size(); assert((!NNS || NNS->isDependent()) && "DependentTemplateSpecializatonType requires dependent qualifier"); TemplateArgument *ArgBuffer = getArgBuffer(); for (const TemplateArgument &Arg : Args) { - if (Arg.containsUnexpandedParameterPack()) - setContainsUnexpandedParameterPack(); + addDependence(toTypeDependence(Arg.getDependence() & + TemplateArgumentDependence::UnexpandedPack)); new (ArgBuffer++) TemplateArgument(Arg); } @@ -2972,10 +2956,8 @@ StringRef FunctionType::getNameForCallConv(CallingConv CC) { FunctionProtoType::FunctionProtoType(QualType result, ArrayRef params, QualType canonical, const ExtProtoInfo &epi) - : FunctionType(FunctionProto, result, canonical, result->isDependentType(), - result->isInstantiationDependentType(), - result->isVariablyModifiedType(), - result->containsUnexpandedParameterPack(), epi.ExtInfo) { + : FunctionType(FunctionProto, result, canonical, result->getDependence(), + epi.ExtInfo) { FunctionTypeBits.FastTypeQuals = epi.TypeQuals.getFastQualifiers(); FunctionTypeBits.RefQualifier = epi.RefQualifier; FunctionTypeBits.NumParams = params.size(); @@ -2994,14 +2976,8 @@ FunctionProtoType::FunctionProtoType(QualType result, ArrayRef params, // Fill in the trailing argument array. auto *argSlot = getTrailingObjects(); for (unsigned i = 0; i != getNumParams(); ++i) { - if (params[i]->isDependentType()) - setDependent(); - else if (params[i]->isInstantiationDependentType()) - setInstantiationDependent(); - - if (params[i]->containsUnexpandedParameterPack()) - setContainsUnexpandedParameterPack(); - + addDependence(params[i]->getDependence() & + ~TypeDependence::VariablyModified); argSlot[i] = params[i]; } @@ -3015,11 +2991,9 @@ FunctionProtoType::FunctionProtoType(QualType result, ArrayRef params, // Note that, before C++17, a dependent exception specification does // *not* make a type dependent; it's not even part of the C++ type // system. - if (ExceptionType->isInstantiationDependentType()) - setInstantiationDependent(); - - if (ExceptionType->containsUnexpandedParameterPack()) - setContainsUnexpandedParameterPack(); + addDependence( + ExceptionType->getDependence() & + (TypeDependence::Instantiation | TypeDependence::UnexpandedPack)); exnSlot[I++] = ExceptionType; } @@ -3033,12 +3007,9 @@ FunctionProtoType::FunctionProtoType(QualType result, ArrayRef params, // Store the noexcept expression and context. *getTrailingObjects() = epi.ExceptionSpec.NoexceptExpr; - if (epi.ExceptionSpec.NoexceptExpr->isValueDependent() || - epi.ExceptionSpec.NoexceptExpr->isInstantiationDependent()) - setInstantiationDependent(); - - if (epi.ExceptionSpec.NoexceptExpr->containsUnexpandedParameterPack()) - setContainsUnexpandedParameterPack(); + addDependence( + toTypeDependence(epi.ExceptionSpec.NoexceptExpr->getDependence()) & + (TypeDependence::Instantiation | TypeDependence::UnexpandedPack)); } // Fill in the FunctionDecl * in the exception specification if present. else if (getExceptionSpecType() == EST_Uninstantiated) { @@ -3062,11 +3033,11 @@ FunctionProtoType::FunctionProtoType(QualType result, ArrayRef params, if (getExceptionSpecType() == EST_Dynamic || getExceptionSpecType() == EST_DependentNoexcept) { assert(hasDependentExceptionSpec() && "type should not be canonical"); - setDependent(); + addDependence(TypeDependence::DependentInstantiation); } } else if (getCanonicalTypeInternal()->isDependentType()) { // Ask our canonical type whether our exception specification was dependent. - setDependent(); + addDependence(TypeDependence::DependentInstantiation); } // Fill in the extra parameter info if present. @@ -3229,10 +3200,10 @@ QualType MacroQualifiedType::getModifiedType() const { } TypeOfExprType::TypeOfExprType(Expr *E, QualType can) - : Type(TypeOfExpr, can, E->isTypeDependent(), - E->isInstantiationDependent(), - E->getType()->isVariablyModifiedType(), - E->containsUnexpandedParameterPack()), + : Type(TypeOfExpr, can, + toTypeDependence(E->getDependence()) | + (E->getType()->getDependence() & + TypeDependence::VariablyModified)), TOExpr(E) {} bool TypeOfExprType::isSugared() const { @@ -3252,13 +3223,15 @@ void DependentTypeOfExprType::Profile(llvm::FoldingSetNodeID &ID, } DecltypeType::DecltypeType(Expr *E, QualType underlyingType, QualType can) - // C++11 [temp.type]p2: "If an expression e involves a template parameter, - // decltype(e) denotes a unique dependent type." Hence a decltype type is - // type-dependent even if its expression is only instantiation-dependent. - : Type(Decltype, can, E->isInstantiationDependent(), - E->isInstantiationDependent(), - E->getType()->isVariablyModifiedType(), - E->containsUnexpandedParameterPack()), + // C++11 [temp.type]p2: "If an expression e involves a template parameter, + // decltype(e) denotes a unique dependent type." Hence a decltype type is + // type-dependent even if its expression is only instantiation-dependent. + : Type(Decltype, can, + toTypeDependence(E->getDependence()) | + (E->isInstantiationDependent() ? TypeDependence::Dependent + : TypeDependence::None) | + (E->getType()->getDependence() & + TypeDependence::VariablyModified)), E(E), UnderlyingType(underlyingType) {} bool DecltypeType::isSugared() const { return !E->isInstantiationDependent(); } @@ -3279,13 +3252,9 @@ void DependentDecltypeType::Profile(llvm::FoldingSetNodeID &ID, } UnaryTransformType::UnaryTransformType(QualType BaseType, - QualType UnderlyingType, - UTTKind UKind, + QualType UnderlyingType, UTTKind UKind, QualType CanonicalType) - : Type(UnaryTransform, CanonicalType, BaseType->isDependentType(), - BaseType->isInstantiationDependentType(), - BaseType->isVariablyModifiedType(), - BaseType->containsUnexpandedParameterPack()), + : Type(UnaryTransform, CanonicalType, BaseType->getDependence()), BaseType(BaseType), UnderlyingType(UnderlyingType), UKind(UKind) {} DependentUnaryTransformType::DependentUnaryTransformType(const ASTContext &C, @@ -3294,11 +3263,10 @@ DependentUnaryTransformType::DependentUnaryTransformType(const ASTContext &C, : UnaryTransformType(BaseType, C.DependentTy, UKind, QualType()) {} TagType::TagType(TypeClass TC, const TagDecl *D, QualType can) - : Type(TC, can, D->isDependentType(), - /*InstantiationDependent=*/D->isDependentType(), - /*VariablyModified=*/false, - /*ContainsUnexpandedParameterPack=*/false), - decl(const_cast(D)) {} + : Type(TC, can, + D->isDependentType() ? TypeDependence::DependentInstantiation + : TypeDependence::None), + decl(const_cast(D)) {} static TagDecl *getInterestingTagDecl(TagDecl *decl) { for (auto I : decl->redecls()) { @@ -3407,11 +3375,12 @@ IdentifierInfo *TemplateTypeParmType::getIdentifier() const { return isCanonicalUnqualified() ? nullptr : getDecl()->getIdentifier(); } -SubstTemplateTypeParmPackType:: -SubstTemplateTypeParmPackType(const TemplateTypeParmType *Param, - QualType Canon, - const TemplateArgument &ArgPack) - : Type(SubstTemplateTypeParmPack, Canon, true, true, false, true), +SubstTemplateTypeParmPackType::SubstTemplateTypeParmPackType( + const TemplateTypeParmType *Param, QualType Canon, + const TemplateArgument &ArgPack) + : Type(SubstTemplateTypeParmPack, Canon, + TypeDependence::DependentInstantiation | + TypeDependence::UnexpandedPack), Replaced(Param), Arguments(ArgPack.pack_begin()) { SubstTemplateTypeParmPackTypeBits.NumArgs = ArgPack.pack_size(); } @@ -3455,16 +3424,17 @@ anyDependentTemplateArguments(ArrayRef Args, return false; } -TemplateSpecializationType:: -TemplateSpecializationType(TemplateName T, - ArrayRef Args, - QualType Canon, QualType AliasedType) - : Type(TemplateSpecialization, - Canon.isNull()? QualType(this, 0) : Canon, - Canon.isNull()? true : Canon->isDependentType(), - Canon.isNull()? true : Canon->isInstantiationDependentType(), - false, - T.containsUnexpandedParameterPack()), Template(T) { +TemplateSpecializationType::TemplateSpecializationType( + TemplateName T, ArrayRef Args, QualType Canon, + QualType AliasedType) + : Type(TemplateSpecialization, Canon.isNull() ? QualType(this, 0) : Canon, + (Canon.isNull() + ? TypeDependence::DependentInstantiation + : Canon->getDependence() & ~(TypeDependence::VariablyModified | + TypeDependence::UnexpandedPack)) | + (toTypeDependence(T.getDependence()) & + TypeDependence::UnexpandedPack)), + Template(T) { TemplateSpecializationTypeBits.NumArgs = Args.size(); TemplateSpecializationTypeBits.TypeAlias = !AliasedType.isNull(); @@ -3485,13 +3455,11 @@ TemplateSpecializationType(TemplateName T, // U is always non-dependent, irrespective of the type T. // However, U contains an unexpanded parameter pack, even though // its expansion (and thus its desugared type) doesn't. - if (Arg.isInstantiationDependent()) - setInstantiationDependent(); - if (Arg.getKind() == TemplateArgument::Type && - Arg.getAsType()->isVariablyModifiedType()) - setVariablyModified(); - if (Arg.containsUnexpandedParameterPack()) - setContainsUnexpandedParameterPack(); + addDependence(toTypeDependence(Arg.getDependence()) & + ~TypeDependence::Dependent); + if (Arg.getKind() == TemplateArgument::Type) + addDependence(Arg.getAsType()->getDependence() & + TypeDependence::VariablyModified); new (TemplateArgs++) TemplateArgument(Arg); } @@ -4178,19 +4146,18 @@ void clang::FixedPointValueToString(SmallVectorImpl &Str, } AutoType::AutoType(QualType DeducedAsType, AutoTypeKeyword Keyword, - bool IsDeducedAsDependent, bool IsDeducedAsPack, + TypeDependence ExtraDependence, ConceptDecl *TypeConstraintConcept, ArrayRef TypeConstraintArgs) - : DeducedType(Auto, DeducedAsType, IsDeducedAsDependent, - IsDeducedAsDependent, IsDeducedAsPack) { + : DeducedType(Auto, DeducedAsType, ExtraDependence) { AutoTypeBits.Keyword = (unsigned)Keyword; AutoTypeBits.NumArgs = TypeConstraintArgs.size(); this->TypeConstraintConcept = TypeConstraintConcept; if (TypeConstraintConcept) { TemplateArgument *ArgBuffer = getArgBuffer(); for (const TemplateArgument &Arg : TypeConstraintArgs) { - if (Arg.containsUnexpandedParameterPack()) - setContainsUnexpandedParameterPack(); + addDependence(toTypeDependence( + Arg.getDependence() & TemplateArgumentDependence::UnexpandedPack)); new (ArgBuffer++) TemplateArgument(Arg); } From 0b5998213415147d901d394cfc47d7daedacc3cf Mon Sep 17 00:00:00 2001 From: Sam McCall Date: Tue, 24 Mar 2020 13:59:16 +0100 Subject: [PATCH 02/15] [CodeGen] Fix test attr-noreturn.c when run from my home directory --- clang/test/CodeGen/attr-noreturn.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/test/CodeGen/attr-noreturn.c b/clang/test/CodeGen/attr-noreturn.c index b420edfc05954b..5dca4fa1f520af 100644 --- a/clang/test/CodeGen/attr-noreturn.c +++ b/clang/test/CodeGen/attr-noreturn.c @@ -6,5 +6,5 @@ fptrs_t p __attribute__((noreturn)); void __attribute__((noreturn)) f() { p[0](); } -// CHECK: call +// CHECK: call void // CHECK-NEXT: unreachable From 7caba33907afce839c092661e20fdfd51b08e7d0 Mon Sep 17 00:00:00 2001 From: Florian Hahn Date: Tue, 24 Mar 2020 12:47:24 +0000 Subject: [PATCH 03/15] [ConstantRange] Add initial support for binaryXor. The initial implementation just delegates to APInt's implementation of XOR for single element ranges and conservatively returns the full set otherwise. Reviewers: nikic, spatel, lebedev.ri Reviewed By: nikic Differential Revision: https://reviews.llvm.org/D76453 --- llvm/include/llvm/IR/ConstantRange.h | 4 ++++ llvm/lib/IR/ConstantRange.cpp | 14 ++++++++++++++ llvm/unittests/IR/ConstantRangeTest.cpp | 16 ++++++++++++++++ 3 files changed, 34 insertions(+) diff --git a/llvm/include/llvm/IR/ConstantRange.h b/llvm/include/llvm/IR/ConstantRange.h index e6bac8a5f93396..8ecb9aa0ce0205 100644 --- a/llvm/include/llvm/IR/ConstantRange.h +++ b/llvm/include/llvm/IR/ConstantRange.h @@ -409,6 +409,10 @@ class LLVM_NODISCARD ConstantRange { /// from a binary-or of a value in this range by a value in \p Other. ConstantRange binaryOr(const ConstantRange &Other) const; + /// Return a new range representing the possible values resulting + /// from a binary-xor of a value in this range by a value in \p Other. + ConstantRange binaryXor(const ConstantRange &Other) const; + /// Return a new range representing the possible values resulting /// from a left shift of a value in this range by a value in \p Other. /// TODO: This isn't fully implemented yet. diff --git a/llvm/lib/IR/ConstantRange.cpp b/llvm/lib/IR/ConstantRange.cpp index 3d25cb5bfbdf0d..b8c57533568bec 100644 --- a/llvm/lib/IR/ConstantRange.cpp +++ b/llvm/lib/IR/ConstantRange.cpp @@ -802,6 +802,8 @@ ConstantRange ConstantRange::binaryOp(Instruction::BinaryOps BinOp, return binaryAnd(Other); case Instruction::Or: return binaryOr(Other); + case Instruction::Xor: + return binaryXor(Other); // Note: floating point operations applied to abstract ranges are just // ideal integer operations with a lossy representation case Instruction::FAdd: @@ -1211,6 +1213,18 @@ ConstantRange::binaryOr(const ConstantRange &Other) const { return getNonEmpty(std::move(umax), APInt::getNullValue(getBitWidth())); } +ConstantRange ConstantRange::binaryXor(const ConstantRange &Other) const { + if (isEmptySet() || Other.isEmptySet()) + return getEmpty(); + + // Use APInt's implementation of XOR for single element ranges. + if (isSingleElement() && Other.isSingleElement()) + return {*getSingleElement() ^ *Other.getSingleElement()}; + + // TODO: replace this with something less conservative + return getFull(); +} + ConstantRange ConstantRange::shl(const ConstantRange &Other) const { if (isEmptySet() || Other.isEmptySet()) diff --git a/llvm/unittests/IR/ConstantRangeTest.cpp b/llvm/unittests/IR/ConstantRangeTest.cpp index 2e5ab82f256e7b..4d19dd59cae645 100644 --- a/llvm/unittests/IR/ConstantRangeTest.cpp +++ b/llvm/unittests/IR/ConstantRangeTest.cpp @@ -2317,4 +2317,20 @@ TEST_F(ConstantRangeTest, castOps) { EXPECT_EQ(64u, IntToPtr.getBitWidth()); EXPECT_TRUE(IntToPtr.isFullSet()); } + +TEST_F(ConstantRangeTest, binaryXor) { + // Single element ranges. + ConstantRange R16(APInt(8, 16)); + ConstantRange R20(APInt(8, 20)); + EXPECT_EQ(*R16.binaryXor(R16).getSingleElement(), APInt(8, 0)); + EXPECT_EQ(*R16.binaryXor(R20).getSingleElement(), APInt(8, 16 ^ 20)); + + // Ranges with more than a single element. Handled conservatively for now. + ConstantRange R16_35(APInt(8, 16), APInt(8, 35)); + ConstantRange R0_99(APInt(8, 0), APInt(8, 99)); + EXPECT_TRUE(R16_35.binaryXor(R16_35).isFullSet()); + EXPECT_TRUE(R16_35.binaryXor(R0_99).isFullSet()); + EXPECT_TRUE(R0_99.binaryXor(R16_35).isFullSet()); +} + } // anonymous namespace From 58cdb8bff067a521dd68d6b699b13da74188a68b Mon Sep 17 00:00:00 2001 From: Hanhan Wang Date: Tue, 24 Mar 2020 09:15:54 -0400 Subject: [PATCH 04/15] [mlir][StandardToSPIRV] Add support for lowering unary ops Differential Revision: https://reviews.llvm.org/D76661 --- .../ConvertStandardToSPIRV.cpp | 46 +++++++++++-------- .../StandardToSPIRV/std-to-spirv.mlir | 30 ++++++++++-- 2 files changed, 55 insertions(+), 21 deletions(-) diff --git a/mlir/lib/Conversion/StandardToSPIRV/ConvertStandardToSPIRV.cpp b/mlir/lib/Conversion/StandardToSPIRV/ConvertStandardToSPIRV.cpp index 69ef69d1de65ac..ea8812cebdc4c5 100644 --- a/mlir/lib/Conversion/StandardToSPIRV/ConvertStandardToSPIRV.cpp +++ b/mlir/lib/Conversion/StandardToSPIRV/ConvertStandardToSPIRV.cpp @@ -107,16 +107,16 @@ static FloatAttr convertFloatAttr(FloatAttr srcAttr, FloatType dstType, namespace { -/// Converts binary standard operations to SPIR-V operations. +/// Converts unary and binary standard operations to SPIR-V operations. template -class BinaryOpPattern final : public SPIRVOpLowering { +class UnaryAndBinaryOpPattern final : public SPIRVOpLowering { public: using SPIRVOpLowering::SPIRVOpLowering; LogicalResult matchAndRewrite(StdOp operation, ArrayRef operands, ConversionPatternRewriter &rewriter) const override { - assert(operands.size() == 2); + assert(operands.size() <= 2); auto dstType = this->typeConverter.convertType(operation.getType()); if (!dstType) return failure(); @@ -572,21 +572,31 @@ void populateStandardToSPIRVPatterns(MLIRContext *context, SPIRVTypeConverter &typeConverter, OwningRewritePatternList &patterns) { patterns.insert< - BinaryOpPattern, - BinaryOpPattern, - BinaryOpPattern, - BinaryOpPattern, - BinaryOpPattern, - BinaryOpPattern, - BinaryOpPattern, - BinaryOpPattern, - BinaryOpPattern, - BinaryOpPattern, - BinaryOpPattern, - BinaryOpPattern, - BinaryOpPattern, - BinaryOpPattern, - BinaryOpPattern, + UnaryAndBinaryOpPattern, + UnaryAndBinaryOpPattern, + UnaryAndBinaryOpPattern, + UnaryAndBinaryOpPattern, + UnaryAndBinaryOpPattern, + UnaryAndBinaryOpPattern, + UnaryAndBinaryOpPattern, + UnaryAndBinaryOpPattern, + UnaryAndBinaryOpPattern, + UnaryAndBinaryOpPattern, + UnaryAndBinaryOpPattern, + UnaryAndBinaryOpPattern, + UnaryAndBinaryOpPattern, + UnaryAndBinaryOpPattern, + UnaryAndBinaryOpPattern, + UnaryAndBinaryOpPattern, + UnaryAndBinaryOpPattern, + UnaryAndBinaryOpPattern, + UnaryAndBinaryOpPattern, + UnaryAndBinaryOpPattern, + UnaryAndBinaryOpPattern, + UnaryAndBinaryOpPattern, + UnaryAndBinaryOpPattern, + UnaryAndBinaryOpPattern, BitwiseOpPattern, BitwiseOpPattern, ConstantCompositeOpPattern, ConstantScalarOpPattern, CmpFOpPattern, diff --git a/mlir/test/Conversion/StandardToSPIRV/std-to-spirv.mlir b/mlir/test/Conversion/StandardToSPIRV/std-to-spirv.mlir index cb5873a1baf04d..91219acc0bd547 100644 --- a/mlir/test/Conversion/StandardToSPIRV/std-to-spirv.mlir +++ b/mlir/test/Conversion/StandardToSPIRV/std-to-spirv.mlir @@ -31,9 +31,33 @@ func @int32_scalar(%lhs: i32, %rhs: i32) { return } -// Check float operation conversions. -// CHECK-LABEL: @float32_scalar -func @float32_scalar(%lhs: f32, %rhs: f32) { +// Check float unary operation conversions. +// CHECK-LABEL: @float32_unary_scalar +func @float32_unary_scalar(%arg0: f32) { + // CHECK: spv.GLSL.FAbs %{{.*}}: f32 + %0 = absf %arg0 : f32 + // CHECK: spv.GLSL.Ceil %{{.*}}: f32 + %1 = ceilf %arg0 : f32 + // CHECK: spv.GLSL.Cos %{{.*}}: f32 + %2 = cos %arg0 : f32 + // CHECK: spv.GLSL.Exp %{{.*}}: f32 + %3 = exp %arg0 : f32 + // CHECK: spv.GLSL.Log %{{.*}}: f32 + %4 = log %arg0 : f32 + // CHECK: spv.FNegate %{{.*}}: f32 + %5 = negf %arg0 : f32 + // CHECK: spv.GLSL.InverseSqrt %{{.*}}: f32 + %6 = rsqrt %arg0 : f32 + // CHECK: spv.GLSL.Sqrt %{{.*}}: f32 + %7 = sqrt %arg0 : f32 + // CHECK: spv.GLSL.Tanh %{{.*}}: f32 + %8 = tanh %arg0 : f32 + return +} + +// Check float binary operation conversions. +// CHECK-LABEL: @float32_binary_scalar +func @float32_binary_scalar(%lhs: f32, %rhs: f32) { // CHECK: spv.FAdd %{{.*}}, %{{.*}}: f32 %0 = addf %lhs, %rhs: f32 // CHECK: spv.FSub %{{.*}}, %{{.*}}: f32 From 865638f5eb57d2a16f4acef7237c54bc6059fae0 Mon Sep 17 00:00:00 2001 From: Simon Pilgrim Date: Tue, 24 Mar 2020 13:20:24 +0000 Subject: [PATCH 05/15] [X86][SSE1] Add additional logic+movmsk patterns that scalarize (PR42870) rL368506 handled the basic case, but we need to account for boolean logic patterns as well. --- llvm/test/CodeGen/X86/pr42870.ll | 129 ++++++++++++++++++++++++++++++- 1 file changed, 125 insertions(+), 4 deletions(-) diff --git a/llvm/test/CodeGen/X86/pr42870.ll b/llvm/test/CodeGen/X86/pr42870.ll index 575a2653a33f82..e4ffcb4787e868 100644 --- a/llvm/test/CodeGen/X86/pr42870.ll +++ b/llvm/test/CodeGen/X86/pr42870.ll @@ -1,8 +1,8 @@ ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py ; RUN: llc < %s -mtriple=i686-apple-darwin -mattr=sse | FileCheck %s -define i32 @foo(<4 x float>* %a) { -; CHECK-LABEL: foo: +define i32 @test_load(<4 x float>* %a) { +; CHECK-LABEL: test_load: ; CHECK: ## %bb.0: ## %start ; CHECK-NEXT: movl {{[0-9]+}}(%esp), %eax ; CHECK-NEXT: movaps (%eax), %xmm0 @@ -17,8 +17,8 @@ start: ret i32 %4 } -define i32 @bar(<4 x float> %a) { -; CHECK-LABEL: bar: +define i32 @test_bitcast(<4 x float> %a) { +; CHECK-LABEL: test_bitcast: ; CHECK: ## %bb.0: ## %start ; CHECK-NEXT: movmskps %xmm0, %eax ; CHECK-NEXT: retl @@ -29,3 +29,124 @@ start: %3 = zext i4 %2 to i32 ret i32 %3 } + +define i32 @test_and(<4 x float> %a, <4 x float> %b) { +; CHECK-LABEL: test_and: +; CHECK: ## %bb.0: ## %start +; CHECK-NEXT: subl $28, %esp +; CHECK-NEXT: .cfi_def_cfa_offset 32 +; CHECK-NEXT: andps %xmm1, %xmm0 +; CHECK-NEXT: movaps %xmm0, (%esp) +; CHECK-NEXT: cmpl $0, (%esp) +; CHECK-NEXT: sets %al +; CHECK-NEXT: cmpl $0, {{[0-9]+}}(%esp) +; CHECK-NEXT: sets %cl +; CHECK-NEXT: addb %cl, %cl +; CHECK-NEXT: orb %al, %cl +; CHECK-NEXT: cmpl $0, {{[0-9]+}}(%esp) +; CHECK-NEXT: sets %al +; CHECK-NEXT: cmpl $0, {{[0-9]+}}(%esp) +; CHECK-NEXT: sets %dl +; CHECK-NEXT: addb %dl, %dl +; CHECK-NEXT: orb %al, %dl +; CHECK-NEXT: shlb $2, %dl +; CHECK-NEXT: orb %cl, %dl +; CHECK-NEXT: movzbl %dl, %eax +; CHECK-NEXT: addl $28, %esp +; CHECK-NEXT: retl +start: + %0 = bitcast <4 x float> %a to <4 x i32> + %1 = bitcast <4 x float> %b to <4 x i32> + %2 = icmp slt <4 x i32> %0, zeroinitializer + %3 = icmp slt <4 x i32> %1, zeroinitializer + %4 = and <4 x i1> %2, %3 + %5 = bitcast <4 x i1> %4 to i4 + %6 = zext i4 %5 to i32 + ret i32 %6 +} + +define i32 @test_or(<4 x float> %a, <4 x float> %b) { +; CHECK-LABEL: test_or: +; CHECK: ## %bb.0: ## %start +; CHECK-NEXT: subl $28, %esp +; CHECK-NEXT: .cfi_def_cfa_offset 32 +; CHECK-NEXT: orps %xmm1, %xmm0 +; CHECK-NEXT: movaps %xmm0, (%esp) +; CHECK-NEXT: cmpl $0, (%esp) +; CHECK-NEXT: sets %al +; CHECK-NEXT: cmpl $0, {{[0-9]+}}(%esp) +; CHECK-NEXT: sets %cl +; CHECK-NEXT: addb %cl, %cl +; CHECK-NEXT: orb %al, %cl +; CHECK-NEXT: cmpl $0, {{[0-9]+}}(%esp) +; CHECK-NEXT: sets %al +; CHECK-NEXT: cmpl $0, {{[0-9]+}}(%esp) +; CHECK-NEXT: sets %dl +; CHECK-NEXT: addb %dl, %dl +; CHECK-NEXT: orb %al, %dl +; CHECK-NEXT: shlb $2, %dl +; CHECK-NEXT: orb %cl, %dl +; CHECK-NEXT: movzbl %dl, %eax +; CHECK-NEXT: addl $28, %esp +; CHECK-NEXT: retl +start: + %0 = bitcast <4 x float> %a to <4 x i32> + %1 = bitcast <4 x float> %b to <4 x i32> + %2 = icmp slt <4 x i32> %0, zeroinitializer + %3 = icmp slt <4 x i32> %1, zeroinitializer + %4 = or <4 x i1> %2, %3 + %5 = bitcast <4 x i1> %4 to i4 + %6 = zext i4 %5 to i32 + ret i32 %6 +} + +define i32 @test_xor(<4 x float> %a, <4 x float> %b) { +; CHECK-LABEL: test_xor: +; CHECK: ## %bb.0: ## %start +; CHECK-NEXT: pushl %ebx +; CHECK-NEXT: .cfi_def_cfa_offset 8 +; CHECK-NEXT: subl $40, %esp +; CHECK-NEXT: .cfi_def_cfa_offset 48 +; CHECK-NEXT: .cfi_offset %ebx, -8 +; CHECK-NEXT: movaps %xmm0, {{[0-9]+}}(%esp) +; CHECK-NEXT: movaps %xmm1, (%esp) +; CHECK-NEXT: cmpl $0, {{[0-9]+}}(%esp) +; CHECK-NEXT: sets %al +; CHECK-NEXT: cmpl $0, {{[0-9]+}}(%esp) +; CHECK-NEXT: sets %cl +; CHECK-NEXT: cmpl $0, {{[0-9]+}}(%esp) +; CHECK-NEXT: sets %dl +; CHECK-NEXT: cmpl $0, {{[0-9]+}}(%esp) +; CHECK-NEXT: sets %ah +; CHECK-NEXT: cmpl $0, {{[0-9]+}}(%esp) +; CHECK-NEXT: sets %ch +; CHECK-NEXT: cmpl $0, {{[0-9]+}}(%esp) +; CHECK-NEXT: sets %dh +; CHECK-NEXT: cmpl $0, {{[0-9]+}}(%esp) +; CHECK-NEXT: sets %bl +; CHECK-NEXT: cmpl $0, (%esp) +; CHECK-NEXT: sets %bh +; CHECK-NEXT: xorb %ah, %bh +; CHECK-NEXT: xorb %dl, %bl +; CHECK-NEXT: addb %bl, %bl +; CHECK-NEXT: orb %bh, %bl +; CHECK-NEXT: xorb %cl, %dh +; CHECK-NEXT: xorb %al, %ch +; CHECK-NEXT: addb %ch, %ch +; CHECK-NEXT: orb %dh, %ch +; CHECK-NEXT: shlb $2, %ch +; CHECK-NEXT: orb %bl, %ch +; CHECK-NEXT: movzbl %ch, %eax +; CHECK-NEXT: addl $40, %esp +; CHECK-NEXT: popl %ebx +; CHECK-NEXT: retl +start: + %0 = bitcast <4 x float> %a to <4 x i32> + %1 = bitcast <4 x float> %b to <4 x i32> + %2 = icmp slt <4 x i32> %0, zeroinitializer + %3 = icmp slt <4 x i32> %1, zeroinitializer + %4 = xor <4 x i1> %2, %3 + %5 = bitcast <4 x i1> %4 to i4 + %6 = zext i4 %5 to i32 + ret i32 %6 +} From 177dd63c8d742250dac6ea365e7c30f0fbab3257 Mon Sep 17 00:00:00 2001 From: Jaroslav Sevcik Date: Tue, 24 Mar 2020 14:08:39 +0100 Subject: [PATCH 06/15] Data formatters: fix detection of C strings Summary: Detection of C strings does not work well for pointers. If the value object holding a (char*) pointer does not have an address (e.g., if it is a temp), the value is not considered a C string and its formatting is left to DumpDataExtractor rather than the special handling in ValueObject::DumpPrintableRepresentation. This leads to inconsistent outputs, e.g., in escaping non-ASCII characters. See the test for an example; the second test expectation is not met (without this patch). With this patch, the C string detection only insists that the pointer value is valid. The patch makes the code consistent with how the pointer is obtained in ValueObject::ReadPointedString. Reviewers: teemperor Reviewed By: teemperor Subscribers: lldb-commits Tags: #lldb Differential Revision: https://reviews.llvm.org/D76650 --- lldb/source/Core/ValueObject.cpp | 2 +- .../cstring-utf8-summary/Makefile | 3 +++ .../cstring-utf8-summary/TestCstringUnicode.py | 18 ++++++++++++++++++ .../cstring-utf8-summary/main.cpp | 4 ++++ 4 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 lldb/test/API/functionalities/data-formatter/cstring-utf8-summary/Makefile create mode 100644 lldb/test/API/functionalities/data-formatter/cstring-utf8-summary/TestCstringUnicode.py create mode 100644 lldb/test/API/functionalities/data-formatter/cstring-utf8-summary/main.cpp diff --git a/lldb/source/Core/ValueObject.cpp b/lldb/source/Core/ValueObject.cpp index 4c9c44ea15f4d9..9e20ba76dccbdf 100644 --- a/lldb/source/Core/ValueObject.cpp +++ b/lldb/source/Core/ValueObject.cpp @@ -764,7 +764,7 @@ bool ValueObject::IsCStringContainer(bool check_pointer) { return true; addr_t cstr_address = LLDB_INVALID_ADDRESS; AddressType cstr_address_type = eAddressTypeInvalid; - cstr_address = GetAddressOf(true, &cstr_address_type); + cstr_address = GetPointerValue(&cstr_address_type); return (cstr_address != LLDB_INVALID_ADDRESS); } diff --git a/lldb/test/API/functionalities/data-formatter/cstring-utf8-summary/Makefile b/lldb/test/API/functionalities/data-formatter/cstring-utf8-summary/Makefile new file mode 100644 index 00000000000000..99998b20bcb050 --- /dev/null +++ b/lldb/test/API/functionalities/data-formatter/cstring-utf8-summary/Makefile @@ -0,0 +1,3 @@ +CXX_SOURCES := main.cpp + +include Makefile.rules diff --git a/lldb/test/API/functionalities/data-formatter/cstring-utf8-summary/TestCstringUnicode.py b/lldb/test/API/functionalities/data-formatter/cstring-utf8-summary/TestCstringUnicode.py new file mode 100644 index 00000000000000..c05e9e9b06ba7c --- /dev/null +++ b/lldb/test/API/functionalities/data-formatter/cstring-utf8-summary/TestCstringUnicode.py @@ -0,0 +1,18 @@ +# coding=utf8 + +import lldb +from lldbsuite.test.lldbtest import * +import lldbsuite.test.lldbutil as lldbutil + + +class CstringUnicodeTestCase(TestBase): + + mydir = TestBase.compute_mydir(__file__) + NO_DEBUG_INFO_TESTCASE = True + + def test_cstring_unicode(self): + self.build() + lldbutil.run_to_source_breakpoint(self, "// break here", + lldb.SBFileSpec("main.cpp", False)) + self.expect_expr("s", result_summary='"🔥"') + self.expect_expr("(const char*)s", result_summary='"🔥"') diff --git a/lldb/test/API/functionalities/data-formatter/cstring-utf8-summary/main.cpp b/lldb/test/API/functionalities/data-formatter/cstring-utf8-summary/main.cpp new file mode 100644 index 00000000000000..c1e8bcf242f4f3 --- /dev/null +++ b/lldb/test/API/functionalities/data-formatter/cstring-utf8-summary/main.cpp @@ -0,0 +1,4 @@ +int main() { + const char *s = u8"🔥"; + return 0; // break here +} From b91905a26378f03c9b56126207771829d89cdcb7 Mon Sep 17 00:00:00 2001 From: Sylvain Audi Date: Mon, 23 Mar 2020 17:06:48 -0400 Subject: [PATCH 07/15] [lld-link] Support /map option, matching link.exe 's /map output format Added support for /map and /map:[filepath]. The output was derived from Microsoft's Link.exe output when using that same option. Note that /MAPINFO support was not added. The previous implementation of MapFile.cpp/.h was meant for /lldmap, and was renamed to LLDMapFile.cpp/.h MapFile.cpp/.h is now for /MAP However, a small fix was added to lldmap, replacing a std::sort with std::stable_sort to enforce reproducibility. Differential Revision: https://reviews.llvm.org/D70557 --- lld/COFF/CMakeLists.txt | 1 + lld/COFF/Config.h | 3 + lld/COFF/Driver.cpp | 18 +- lld/COFF/LLDMapFile.cpp | 123 +++++++++++++ lld/COFF/LLDMapFile.h | 21 +++ lld/COFF/MapFile.cpp | 313 +++++++++++++++++++++++++++------- lld/COFF/Options.td | 2 + lld/COFF/Writer.cpp | 2 + lld/test/COFF/Inputs/map.yaml | 60 +++++++ lld/test/COFF/lldmap.test | 10 -- lld/test/COFF/map.test | 40 +++++ 11 files changed, 521 insertions(+), 72 deletions(-) create mode 100644 lld/COFF/LLDMapFile.cpp create mode 100644 lld/COFF/LLDMapFile.h create mode 100644 lld/test/COFF/Inputs/map.yaml delete mode 100644 lld/test/COFF/lldmap.test create mode 100644 lld/test/COFF/map.test diff --git a/lld/COFF/CMakeLists.txt b/lld/COFF/CMakeLists.txt index 1d310f8419f555..4592ace373efa7 100644 --- a/lld/COFF/CMakeLists.txt +++ b/lld/COFF/CMakeLists.txt @@ -14,6 +14,7 @@ add_lld_library(lldCOFF DriverUtils.cpp ICF.cpp InputFiles.cpp + LLDMapFile.cpp LTO.cpp MapFile.cpp MarkLive.cpp diff --git a/lld/COFF/Config.h b/lld/COFF/Config.h index af86b699227291..e376ea51f133d3 100644 --- a/lld/COFF/Config.h +++ b/lld/COFF/Config.h @@ -182,6 +182,9 @@ struct Configuration { llvm::StringMap order; // Used for /lldmap. + std::string lldmapFile; + + // Used for /map. std::string mapFile; // Used for /thinlto-index-only: diff --git a/lld/COFF/Driver.cpp b/lld/COFF/Driver.cpp index 5320b8b83ce0ac..8b3ba1cdf24b51 100644 --- a/lld/COFF/Driver.cpp +++ b/lld/COFF/Driver.cpp @@ -707,14 +707,15 @@ static unsigned parseDebugTypes(const opt::InputArgList &args) { return debugTypes; } -static std::string getMapFile(const opt::InputArgList &args) { - auto *arg = args.getLastArg(OPT_lldmap, OPT_lldmap_file); +static std::string getMapFile(const opt::InputArgList &args, + opt::OptSpecifier os, opt::OptSpecifier osFile) { + auto *arg = args.getLastArg(os, osFile); if (!arg) return ""; - if (arg->getOption().getID() == OPT_lldmap_file) + if (arg->getOption().getID() == osFile.getID()) return arg->getValue(); - assert(arg->getOption().getID() == OPT_lldmap); + assert(arg->getOption().getID() == os.getID()); StringRef outFile = config->outputFile; return (outFile.substr(0, outFile.rfind('.')) + ".map").str(); } @@ -1564,7 +1565,14 @@ void LinkerDriver::link(ArrayRef argsArr) { if (config->mingw || config->debugDwarf) config->warnLongSectionNames = false; - config->mapFile = getMapFile(args); + config->lldmapFile = getMapFile(args, OPT_lldmap, OPT_lldmap_file); + config->mapFile = getMapFile(args, OPT_map, OPT_map_file); + + if (config->lldmapFile != "" && config->lldmapFile == config->mapFile) { + warn("/lldmap and /map have the same output file '" + config->mapFile + + "'.\n>>> ignoring /lldmap"); + config->lldmapFile.clear(); + } if (config->incremental && args.hasArg(OPT_profile)) { warn("ignoring '/incremental' due to '/profile' specification"); diff --git a/lld/COFF/LLDMapFile.cpp b/lld/COFF/LLDMapFile.cpp new file mode 100644 index 00000000000000..0e069724f8163b --- /dev/null +++ b/lld/COFF/LLDMapFile.cpp @@ -0,0 +1,123 @@ +//===- LLDMapFile.cpp -----------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This file implements the /lldmap option. It shows lists in order and +// hierarchically the output sections, input sections, input files and +// symbol: +// +// Address Size Align Out File Symbol +// 00201000 00000015 4 .text +// 00201000 0000000e 4 test.o:(.text) +// 0020100e 00000000 0 local +// 00201005 00000000 0 f(int) +// +//===----------------------------------------------------------------------===// + +#include "LLDMapFile.h" +#include "SymbolTable.h" +#include "Symbols.h" +#include "Writer.h" +#include "lld/Common/ErrorHandler.h" +#include "lld/Common/Threads.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; +using namespace llvm::object; +using namespace lld; +using namespace lld::coff; + +using SymbolMapTy = + DenseMap>; + +static constexpr char indent8[] = " "; // 8 spaces +static constexpr char indent16[] = " "; // 16 spaces + +// Print out the first three columns of a line. +static void writeHeader(raw_ostream &os, uint64_t addr, uint64_t size, + uint64_t align) { + os << format("%08llx %08llx %5lld ", addr, size, align); +} + +// Returns a list of all symbols that we want to print out. +static std::vector getSymbols() { + std::vector v; + for (ObjFile *file : ObjFile::instances) + for (Symbol *b : file->getSymbols()) + if (auto *sym = dyn_cast_or_null(b)) + if (sym && !sym->getCOFFSymbol().isSectionDefinition()) + v.push_back(sym); + return v; +} + +// Returns a map from sections to their symbols. +static SymbolMapTy getSectionSyms(ArrayRef syms) { + SymbolMapTy ret; + for (DefinedRegular *s : syms) + ret[s->getChunk()].push_back(s); + + // Sort symbols by address. + for (auto &it : ret) { + SmallVectorImpl &v = it.second; + std::stable_sort(v.begin(), v.end(), [](DefinedRegular *a, DefinedRegular *b) { + return a->getRVA() < b->getRVA(); + }); + } + return ret; +} + +// Construct a map from symbols to their stringified representations. +static DenseMap +getSymbolStrings(ArrayRef syms) { + std::vector str(syms.size()); + parallelForEachN((size_t)0, syms.size(), [&](size_t i) { + raw_string_ostream os(str[i]); + writeHeader(os, syms[i]->getRVA(), 0, 0); + os << indent16 << toString(*syms[i]); + }); + + DenseMap ret; + for (size_t i = 0, e = syms.size(); i < e; ++i) + ret[syms[i]] = std::move(str[i]); + return ret; +} + +void lld::coff::writeLLDMapFile(ArrayRef outputSections) { + if (config->lldmapFile.empty()) + return; + + std::error_code ec; + raw_fd_ostream os(config->lldmapFile, ec, sys::fs::OF_None); + if (ec) + fatal("cannot open " + config->lldmapFile + ": " + ec.message()); + + // Collect symbol info that we want to print out. + std::vector syms = getSymbols(); + SymbolMapTy sectionSyms = getSectionSyms(syms); + DenseMap symStr = getSymbolStrings(syms); + + // Print out the header line. + os << "Address Size Align Out In Symbol\n"; + + // Print out file contents. + for (OutputSection *sec : outputSections) { + writeHeader(os, sec->getRVA(), sec->getVirtualSize(), /*align=*/pageSize); + os << sec->name << '\n'; + + for (Chunk *c : sec->chunks) { + auto *sc = dyn_cast(c); + if (!sc) + continue; + + writeHeader(os, sc->getRVA(), sc->getSize(), sc->getAlignment()); + os << indent8 << sc->file->getName() << ":(" << sc->getSectionName() + << ")\n"; + for (DefinedRegular *sym : sectionSyms[sc]) + os << symStr[sym] << '\n'; + } + } +} diff --git a/lld/COFF/LLDMapFile.h b/lld/COFF/LLDMapFile.h new file mode 100644 index 00000000000000..b731293a8625d7 --- /dev/null +++ b/lld/COFF/LLDMapFile.h @@ -0,0 +1,21 @@ +//===- LLDMapFile.h ---------------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_COFF_LLDMAPFILE_H +#define LLD_COFF_LLDMAPFILE_H + +#include "llvm/ADT/ArrayRef.h" + +namespace lld { +namespace coff { +class OutputSection; +void writeLLDMapFile(llvm::ArrayRef outputSections); +} +} + +#endif diff --git a/lld/COFF/MapFile.cpp b/lld/COFF/MapFile.cpp index a80c553637aa16..0958a79b140299 100644 --- a/lld/COFF/MapFile.cpp +++ b/lld/COFF/MapFile.cpp @@ -6,16 +6,25 @@ // //===----------------------------------------------------------------------===// // -// This file implements the /lldmap option. It shows lists in order and -// hierarchically the output sections, input sections, input files and -// symbol: +// This file implements the /map option in the same format as link.exe +// (based on observations) // -// Address Size Align Out File Symbol -// 00201000 00000015 4 .text -// 00201000 0000000e 4 test.o:(.text) -// 0020100e 00000000 0 local -// 00201005 00000000 0 f(int) +// Header (program name, timestamp info, preferred load address) // +// Section list (Start = Section index:Base address): +// Start Length Name Class +// 0001:00001000 00000015H .text CODE +// +// Symbols list: +// Address Publics by Value Rva + Base Lib:Object +// 0001:00001000 main 0000000140001000 main.obj +// 0001:00001300 ?__scrt_common_main@@YAHXZ 0000000140001300 libcmt:exe_main.obj +// +// entry point at 0001:00000360 +// +// Static symbols +// +// 0000:00000000 __guard_fids__ 0000000140000000 libcmt : exe_main.obj //===----------------------------------------------------------------------===// #include "MapFile.h" @@ -24,6 +33,8 @@ #include "Writer.h" #include "lld/Common/ErrorHandler.h" #include "lld/Common/Threads.h" +#include "lld/Common/Timer.h" +#include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" using namespace llvm; @@ -31,56 +42,160 @@ using namespace llvm::object; using namespace lld; using namespace lld::coff; -using SymbolMapTy = - DenseMap>; +static Timer totalMapTimer("MAP emission (Cumulative)", Timer::root()); +static Timer symbolGatherTimer("Gather symbols", totalMapTimer); +static Timer symbolStringsTimer("Build symbol strings", totalMapTimer); +static Timer writeTimer("Write to file", totalMapTimer); -static constexpr char indent8[] = " "; // 8 spaces -static constexpr char indent16[] = " "; // 16 spaces +// Print out the first two columns of a line. +static void writeHeader(raw_ostream &os, uint32_t sec, uint64_t addr) { + os << format(" %04x:%08llx", sec, addr); +} -// Print out the first three columns of a line. -static void writeHeader(raw_ostream &os, uint64_t addr, uint64_t size, - uint64_t align) { - os << format("%08llx %08llx %5lld ", addr, size, align); +// Write the time stamp with the format used by link.exe +// It seems identical to strftime with "%c" on msvc build, but we need a +// locale-agnostic version. +static void writeFormattedTimestamp(raw_ostream &os, time_t tds) { + constexpr const char *const days[7] = {"Sun", "Mon", "Tue", "Wed", + "Thu", "Fri", "Sat"}; + constexpr const char *const months[12] = {"Jan", "Feb", "Mar", "Apr", + "May", "Jun", "Jul", "Aug", + "Sep", "Oct", "Nov", "Dec"}; + tm *time = localtime(&tds); + os << format("%s %s %2d %02d:%02d:%02d %d", days[time->tm_wday], + months[time->tm_mon], time->tm_mday, time->tm_hour, time->tm_min, + time->tm_sec, time->tm_year + 1900); } -// Returns a list of all symbols that we want to print out. -static std::vector getSymbols() { - std::vector v; - for (ObjFile *file : ObjFile::instances) - for (Symbol *b : file->getSymbols()) - if (auto *sym = dyn_cast_or_null(b)) - if (sym && !sym->getCOFFSymbol().isSectionDefinition()) - v.push_back(sym); - return v; +static void sortUniqueSymbols(std::vector &syms) { + // Build helper vector + using SortEntry = std::pair; + std::vector v; + v.resize(syms.size()); + for (size_t i = 0, e = syms.size(); i < e; ++i) + v[i] = SortEntry(syms[i], i); + + // Remove duplicate symbol pointers + parallelSort(v, std::less()); + auto end = std::unique(v.begin(), v.end(), + [](const SortEntry &a, const SortEntry &b) { + return a.first == b.first; + }); + v.erase(end, v.end()); + + // Sort by RVA then original order + parallelSort(v, [](const SortEntry &a, const SortEntry &b) { + // Add config->imageBase to avoid comparing "negative" RVAs. + // This can happen with symbols of Absolute kind + uint64_t rvaa = config->imageBase + a.first->getRVA(); + uint64_t rvab = config->imageBase + b.first->getRVA(); + return rvaa < rvab || (rvaa == rvab && a.second < b.second); + }); + + syms.resize(v.size()); + for (size_t i = 0, e = v.size(); i < e; ++i) + syms[i] = v[i].first; } -// Returns a map from sections to their symbols. -static SymbolMapTy getSectionSyms(ArrayRef syms) { - SymbolMapTy ret; - for (DefinedRegular *s : syms) - ret[s->getChunk()].push_back(s); - - // Sort symbols by address. - for (auto &it : ret) { - SmallVectorImpl &v = it.second; - std::sort(v.begin(), v.end(), [](DefinedRegular *a, DefinedRegular *b) { - return a->getRVA() < b->getRVA(); - }); +// Returns the lists of all symbols that we want to print out. +static void getSymbols(std::vector &syms, + std::vector &staticSyms) { + + for (ObjFile *file : ObjFile::instances) + for (Symbol *b : file->getSymbols()) { + if (!b || !b->isLive()) + continue; + if (auto *sym = dyn_cast(b)) { + COFFSymbolRef symRef = sym->getCOFFSymbol(); + if (!symRef.isSectionDefinition() && + symRef.getStorageClass() != COFF::IMAGE_SYM_CLASS_LABEL) { + if (symRef.getStorageClass() == COFF::IMAGE_SYM_CLASS_STATIC) + staticSyms.push_back(sym); + else + syms.push_back(sym); + } + } else if (auto *sym = dyn_cast(b)) { + syms.push_back(sym); + } + } + + for (ImportFile *file : ImportFile::instances) { + if (!file->live) + continue; + + if (!file->thunkSym) + continue; + + if (!file->thunkLive) + continue; + + if (auto *thunkSym = dyn_cast(file->thunkSym)) + syms.push_back(thunkSym); + + if (auto *impSym = dyn_cast_or_null(file->impSym)) + syms.push_back(impSym); } - return ret; + + sortUniqueSymbols(syms); + sortUniqueSymbols(staticSyms); } // Construct a map from symbols to their stringified representations. -static DenseMap -getSymbolStrings(ArrayRef syms) { +static DenseMap +getSymbolStrings(ArrayRef syms) { std::vector str(syms.size()); parallelForEachN((size_t)0, syms.size(), [&](size_t i) { raw_string_ostream os(str[i]); - writeHeader(os, syms[i]->getRVA(), 0, 0); - os << indent16 << toString(*syms[i]); + Defined *sym = syms[i]; + + uint16_t sectionIdx = 0; + uint64_t address = 0; + SmallString<128> fileDescr; + + if (auto *absSym = dyn_cast(sym)) { + address = absSym->getVA(); + fileDescr = ""; + } else if (isa(sym)) { + fileDescr = ""; + } else if (isa(sym)) { + fileDescr = ""; + } else if (Chunk *chunk = sym->getChunk()) { + address = sym->getRVA(); + if (OutputSection *sec = chunk->getOutputSection()) + address -= sec->header.VirtualAddress; + + sectionIdx = chunk->getOutputSectionIdx(); + + InputFile *file; + if (auto *impSym = dyn_cast(sym)) + file = impSym->file; + else if (auto *thunkSym = dyn_cast(sym)) + file = thunkSym->wrappedSym->file; + else + file = sym->getFile(); + + if (file) { + if (!file->parentName.empty()) { + fileDescr = sys::path::filename(file->parentName); + sys::path::replace_extension(fileDescr, ""); + fileDescr += ":"; + } + fileDescr += sys::path::filename(file->getName()); + } + } + writeHeader(os, sectionIdx, address); + os << " "; + os << left_justify(sym->getName(), 26); + os << " "; + os << format_hex_no_prefix((config->imageBase + sym->getRVA()), 16); + if (!fileDescr.empty()) { + os << " "; // FIXME : Handle "f" and "i" flags sometimes generated + // by link.exe in those spaces + os << fileDescr; + } }); - DenseMap ret; + DenseMap ret; for (size_t i = 0, e = syms.size(); i < e; ++i) ret[syms[i]] = std::move(str[i]); return ret; @@ -95,29 +210,113 @@ void lld::coff::writeMapFile(ArrayRef outputSections) { if (ec) fatal("cannot open " + config->mapFile + ": " + ec.message()); + ScopedTimer t1(totalMapTimer); + // Collect symbol info that we want to print out. - std::vector syms = getSymbols(); - SymbolMapTy sectionSyms = getSectionSyms(syms); - DenseMap symStr = getSymbolStrings(syms); + ScopedTimer t2(symbolGatherTimer); + std::vector syms; + std::vector staticSyms; + getSymbols(syms, staticSyms); + t2.stop(); - // Print out the header line. - os << "Address Size Align Out In Symbol\n"; + ScopedTimer t3(symbolStringsTimer); + DenseMap symStr = getSymbolStrings(syms); + DenseMap staticSymStr = getSymbolStrings(staticSyms); + t3.stop(); - // Print out file contents. - for (OutputSection *sec : outputSections) { - writeHeader(os, sec->getRVA(), sec->getVirtualSize(), /*align=*/pageSize); - os << sec->name << '\n'; + ScopedTimer t4(writeTimer); + SmallString<128> AppName = sys::path::filename(config->outputFile); + sys::path::replace_extension(AppName, ""); + // Print out the file header + os << " " << AppName << "\n"; + os << "\n"; + + os << " Timestamp is " << format_hex_no_prefix(config->timestamp, 8) << " ("; + if (config->repro) { + os << "Repro mode"; + } else { + writeFormattedTimestamp(os, config->timestamp); + } + os << ")\n"; + + os << "\n"; + os << " Preferred load address is " + << format_hex_no_prefix(config->imageBase, 16) << "\n"; + os << "\n"; + + // Print out section table. + os << " Start Length Name Class\n"; + + for (OutputSection *sec : outputSections) { + // Merge display of chunks with same sectionName + std::vector> ChunkRanges; for (Chunk *c : sec->chunks) { auto *sc = dyn_cast(c); if (!sc) continue; - writeHeader(os, sc->getRVA(), sc->getSize(), sc->getAlignment()); - os << indent8 << sc->file->getName() << ":(" << sc->getSectionName() - << ")\n"; - for (DefinedRegular *sym : sectionSyms[sc]) - os << symStr[sym] << '\n'; + if (ChunkRanges.empty() || + c->getSectionName() != ChunkRanges.back().first->getSectionName()) { + ChunkRanges.emplace_back(sc, sc); + } else { + ChunkRanges.back().second = sc; + } + } + + const bool isCodeSection = + (sec->header.Characteristics & COFF::IMAGE_SCN_CNT_CODE) && + (sec->header.Characteristics & COFF::IMAGE_SCN_MEM_READ) && + (sec->header.Characteristics & COFF::IMAGE_SCN_MEM_EXECUTE); + StringRef SectionClass = (isCodeSection ? "CODE" : "DATA"); + + for (auto &cr : ChunkRanges) { + size_t size = + cr.second->getRVA() + cr.second->getSize() - cr.first->getRVA(); + + auto address = cr.first->getRVA() - sec->header.VirtualAddress; + writeHeader(os, sec->sectionIndex, address); + os << " " << format_hex_no_prefix(size, 8) << "H"; + os << " " << left_justify(cr.first->getSectionName(), 23); + os << " " << SectionClass; + os << '\n'; + } + } + + // Print out the symbols table (without static symbols) + os << "\n"; + os << " Address Publics by Value Rva+Base" + " Lib:Object\n"; + os << "\n"; + for (Defined *sym : syms) + os << symStr[sym] << '\n'; + + // Print out the entry point. + os << "\n"; + + uint16_t entrySecIndex = 0; + uint64_t entryAddress = 0; + + if (!config->noEntry) { + Defined *entry = dyn_cast_or_null(config->entry); + if (entry) { + Chunk *chunk = entry->getChunk(); + entrySecIndex = chunk->getOutputSectionIdx(); + entryAddress = + entry->getRVA() - chunk->getOutputSection()->header.VirtualAddress; } } + os << " entry point at "; + os << format("%04x:%08llx", entrySecIndex, entryAddress); + os << "\n"; + + // Print out the static symbols + os << "\n"; + os << " Static symbols\n"; + os << "\n"; + for (Defined *sym : staticSyms) + os << staticSymStr[sym] << '\n'; + + t4.stop(); + t1.stop(); } diff --git a/lld/COFF/Options.td b/lld/COFF/Options.td index cea02e7a0042c7..72fe9ce8c118ce 100644 --- a/lld/COFF/Options.td +++ b/lld/COFF/Options.td @@ -226,6 +226,8 @@ defm threads: B<"threads", // Flags for debugging def lldmap : F<"lldmap">; def lldmap_file : Joined<["/", "-", "/?", "-?"], "lldmap:">; +def map : F<"map">; +def map_file : Joined<["/", "-", "/?", "-?"], "map:">; def show_timing : F<"time">; def summary : F<"summary">; diff --git a/lld/COFF/Writer.cpp b/lld/COFF/Writer.cpp index 7e7aaafe18ed5e..d5e2b59027b4f9 100644 --- a/lld/COFF/Writer.cpp +++ b/lld/COFF/Writer.cpp @@ -10,6 +10,7 @@ #include "Config.h" #include "DLL.h" #include "InputFiles.h" +#include "LLDMapFile.h" #include "MapFile.h" #include "PDB.h" #include "SymbolTable.h" @@ -633,6 +634,7 @@ void Writer::run() { } writeBuildId(); + writeLLDMapFile(outputSections); writeMapFile(outputSections); if (errorCount()) diff --git a/lld/test/COFF/Inputs/map.yaml b/lld/test/COFF/Inputs/map.yaml new file mode 100644 index 00000000000000..7a834344cc5b07 --- /dev/null +++ b/lld/test/COFF/Inputs/map.yaml @@ -0,0 +1,60 @@ +--- !COFF +header: + Machine: IMAGE_FILE_MACHINE_AMD64 + Characteristics: [] +sections: + - Name: .text + Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] + Alignment: 4 + SectionData: 0000000000000000 + Relocations: + - VirtualAddress: 0 + SymbolName: exportfn1 + Type: IMAGE_REL_AMD64_ADDR32NB + - VirtualAddress: 4 + SymbolName: exportfn2 + Type: IMAGE_REL_AMD64_ADDR32NB +symbols: + - Name: .text + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 8 + NumberOfRelocations: 2 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 0 + - Name: main + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_FUNCTION + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: exportfn1 + Value: 0 + SectionNumber: 0 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: exportfn2 + Value: 0 + SectionNumber: 0 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: absolute + Value: 0x00000042 + SectionNumber: -1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + - Name: staticdef + Value: 0x00000043 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC +... diff --git a/lld/test/COFF/lldmap.test b/lld/test/COFF/lldmap.test deleted file mode 100644 index d705a16c6c2a0b..00000000000000 --- a/lld/test/COFF/lldmap.test +++ /dev/null @@ -1,10 +0,0 @@ -# RUN: yaml2obj < %p/Inputs/ret42.yaml > %t.obj -# RUN: lld-link /out:%t.exe /entry:main /lldmap:%T/foo.map %t.obj -# RUN: FileCheck -strict-whitespace %s < %T/foo.map -# RUN: lld-link /out:%T/bar.exe /entry:main /lldmap %t.obj -# RUN: FileCheck -strict-whitespace %s < %T/bar.map - -# CHECK: Address Size Align Out In Symbol -# CHECK-NEXT: 00001000 00000006 4096 .text -# CHECK-NEXT: 00001000 00000006 16 {{.*}}lldmap.test.tmp.obj:(.text$mn) -# CHECK-NEXT: 00001000 00000000 0 main diff --git a/lld/test/COFF/map.test b/lld/test/COFF/map.test new file mode 100644 index 00000000000000..0ec27fb33bdcee --- /dev/null +++ b/lld/test/COFF/map.test @@ -0,0 +1,40 @@ +# RUN: yaml2obj < %p/Inputs/export.yaml > %t-dll.obj +# RUN: lld-link /out:%t.dll /dll %t-dll.obj /implib:%t-dll.lib \ +# RUN: /export:exportfn1 /export:exportfn2 +# RUN: yaml2obj < %p/Inputs/map.yaml > %t.obj +# RUN: lld-link /out:%t.exe /entry:main %t.obj %t-dll.lib /map:%T/foo.map /lldmap +# RUN: FileCheck -check-prefix=MAP -strict-whitespace %s < %T/foo.map +# RUN: FileCheck -check-prefix=LLDMAP -strict-whitespace %s < %t.map +# RUN: lld-link /out:%t.exe /entry:main %t.obj %t-dll.lib /map /lldmap:%T/foo-lld.map +# RUN: FileCheck -check-prefix=MAP -strict-whitespace %s < %t.map +# RUN: FileCheck -check-prefix=LLDMAP -strict-whitespace %s < %T/foo-lld.map + +# MAP: {{.*}} +# MAP-EMPTY: +# MAP-NEXT: Timestamp is {{.*}} +# MAP-EMPTY: +# MAP-NEXT: Preferred load address is 0000000140000000 +# MAP-EMPTY: +# MAP-NEXT: Start Length Name Class +# MAP-NEXT: 0001:00000000 00000008H .text CODE +# MAP-EMPTY: +# MAP-NEXT: Address Publics by Value Rva+Base Lib:Object +# MAP-EMPTY: +# MAP-NEXT: 0000:00000042 absolute 0000000000000042 +# MAP-NEXT: 0001:00000000 main 0000000140001000 map.test.tmp.obj +# MAP-NEXT: 0001:00000010 exportfn1 0000000140001010 map.test.tmp-dll:map.test.tmp.dll +# MAP-NEXT: 0001:00000020 exportfn2 0000000140001020 map.test.tmp-dll:map.test.tmp.dll +# MAP-NEXT: 0002:00000040 __imp_exportfn1 0000000140002040 map.test.tmp-dll:map.test.tmp.dll +# MAP-NEXT: 0002:00000048 __imp_exportfn2 0000000140002048 map.test.tmp-dll:map.test.tmp.dll +# MAP-EMPTY: +# MAP-NEXT: entry point at 0001:00000000 +# MAP-EMPTY: +# MAP-NEXT: Static symbols +# MAP-EMPTY: +# MAP-NEXT: 0001:00000043 staticdef 0000000140001043 map.test.tmp.obj + + +# LLDMAP: Address Size Align Out In Symbol +# LLDMAP-NEXT: 00001000 00000026 4096 .text +# LLDMAP-NEXT: 00001000 00000008 4 {{.*}}map.test.tmp.obj:(.text) +# LLDMAP-NEXT: 00001000 00000000 0 main From 58ec867a3badcc75143d93e8922fc618eb9472c1 Mon Sep 17 00:00:00 2001 From: Sanjay Patel Date: Tue, 24 Mar 2020 09:41:43 -0400 Subject: [PATCH 08/15] [InstSimplify] add more tests for freeze(constant); NFC These should really be moved over to a ConstantFolding test file, but since this may overlap with the in-progress D76010 and similar tests already exist here, we can do that as a later cleanup. --- llvm/test/Transforms/InstSimplify/freeze.ll | 36 +++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/llvm/test/Transforms/InstSimplify/freeze.ll b/llvm/test/Transforms/InstSimplify/freeze.ll index 0e631426b6474d..52d1f72edacba3 100644 --- a/llvm/test/Transforms/InstSimplify/freeze.ll +++ b/llvm/test/Transforms/InstSimplify/freeze.ll @@ -65,6 +65,24 @@ define <2 x i32> @constvector() { ret <2 x i32> %x } +define <3 x i5> @constvector_weird() { +; CHECK-LABEL: @constvector_weird( +; CHECK-NEXT: [[X:%.*]] = freeze <3 x i5> +; CHECK-NEXT: ret <3 x i5> [[X]] +; + %x = freeze <3 x i5> + ret <3 x i5> %x +} + +define <2 x float> @constvector_FP() { +; CHECK-LABEL: @constvector_FP( +; CHECK-NEXT: [[X:%.*]] = freeze <2 x float> +; CHECK-NEXT: ret <2 x float> [[X]] +; + %x = freeze <2 x float> + ret <2 x float> %x +} + define <2 x i32> @constvector_noopt() { ; CHECK-LABEL: @constvector_noopt( ; CHECK-NEXT: [[X:%.*]] = freeze <2 x i32> @@ -74,6 +92,24 @@ define <2 x i32> @constvector_noopt() { ret <2 x i32> %x } +define <3 x i5> @constvector_weird_noopt() { +; CHECK-LABEL: @constvector_weird_noopt( +; CHECK-NEXT: [[X:%.*]] = freeze <3 x i5> +; CHECK-NEXT: ret <3 x i5> [[X]] +; + %x = freeze <3 x i5> + ret <3 x i5> %x +} + +define <2 x float> @constvector_FP_noopt() { +; CHECK-LABEL: @constvector_FP_noopt( +; CHECK-NEXT: [[X:%.*]] = freeze <2 x float> +; CHECK-NEXT: ret <2 x float> [[X]] +; + %x = freeze <2 x float> + ret <2 x float> %x +} + define void @alloca() { ; CHECK-LABEL: @alloca( ; CHECK-NEXT: [[P:%.*]] = alloca i8 From 7802be4a3d86743242273593d43a78df84ece8c1 Mon Sep 17 00:00:00 2001 From: Juneyoung Lee Date: Mon, 23 Mar 2020 13:03:13 +0900 Subject: [PATCH 09/15] [SelDag] Add FREEZE Summary: - Add FREEZE node to SelDag - Lower FreezeInst (in IR) to FREEZE node - Add Legalization for FREEZE node Reviewers: qcolombet, bogner, efriedma, lebedev.ri, nlopes, craig.topper, arsenm Reviewed By: lebedev.ri Subscribers: wdng, xbolva00, Petar.Avramovic, liuz, lkail, dylanmckay, hiraditya, Jim, arsenm, craig.topper, RKSimon, spatel, lebedev.ri, regehr, trentxintong, nlopes, mkuper, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D29014 --- llvm/include/llvm/CodeGen/FastISel.h | 1 + llvm/include/llvm/CodeGen/ISDOpcodes.h | 5 ++ llvm/include/llvm/CodeGen/SelectionDAGISel.h | 2 + llvm/lib/CodeGen/SelectionDAG/FastISel.cpp | 24 +++++ .../SelectionDAG/LegalizeIntegerTypes.cpp | 11 +++ llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.h | 2 + .../SelectionDAG/LegalizeTypesGeneric.cpp | 9 ++ .../SelectionDAG/LegalizeVectorTypes.cpp | 3 + .../SelectionDAG/SelectionDAGBuilder.cpp | 20 ++++- .../SelectionDAG/SelectionDAGDumper.cpp | 1 + .../CodeGen/SelectionDAG/SelectionDAGISel.cpp | 11 +++ llvm/lib/CodeGen/TargetLoweringBase.cpp | 2 +- llvm/test/CodeGen/X86/fast-isel-freeze.ll | 21 +++++ llvm/test/CodeGen/X86/fast-isel.ll | 5 ++ llvm/test/CodeGen/X86/freeze-legalize.ll | 87 ++++++++++++++++++ llvm/test/CodeGen/X86/freeze.ll | 90 +++++++++++++++++++ 16 files changed, 291 insertions(+), 3 deletions(-) create mode 100644 llvm/test/CodeGen/X86/fast-isel-freeze.ll create mode 100644 llvm/test/CodeGen/X86/freeze-legalize.ll create mode 100644 llvm/test/CodeGen/X86/freeze.ll diff --git a/llvm/include/llvm/CodeGen/FastISel.h b/llvm/include/llvm/CodeGen/FastISel.h index d9c680392e50a9..326a7eb2e9387a 100644 --- a/llvm/include/llvm/CodeGen/FastISel.h +++ b/llvm/include/llvm/CodeGen/FastISel.h @@ -534,6 +534,7 @@ class FastISel { bool selectCall(const User *I); bool selectIntrinsicCall(const IntrinsicInst *II); bool selectBitCast(const User *I); + bool selectFreeze(const User *I); bool selectCast(const User *I, unsigned Opcode); bool selectExtractValue(const User *U); bool selectInsertValue(const User *I); diff --git a/llvm/include/llvm/CodeGen/ISDOpcodes.h b/llvm/include/llvm/CodeGen/ISDOpcodes.h index 4bc8d7bd42f0e2..17e8f53c230085 100644 --- a/llvm/include/llvm/CodeGen/ISDOpcodes.h +++ b/llvm/include/llvm/CodeGen/ISDOpcodes.h @@ -178,6 +178,11 @@ namespace ISD { /// UNDEF - An undefined node. UNDEF, + // FREEZE - FREEZE(VAL) returns an arbitrary value if VAL is UNDEF (or + // is evaluated to UNDEF), or returns VAL otherwise. Note that each + // read of UNDEF can yield different value, but FREEZE(UNDEF) cannot. + FREEZE, + /// EXTRACT_ELEMENT - This is used to get the lower or upper (determined by /// a Constant, which is required to be operand #1) half of the integer or /// float value specified as operand #0. This is only for use before diff --git a/llvm/include/llvm/CodeGen/SelectionDAGISel.h b/llvm/include/llvm/CodeGen/SelectionDAGISel.h index 52c3e0c6148af1..084badcbe0291c 100644 --- a/llvm/include/llvm/CodeGen/SelectionDAGISel.h +++ b/llvm/include/llvm/CodeGen/SelectionDAGISel.h @@ -324,6 +324,8 @@ class SelectionDAGISel : public MachineFunctionPass { void Select_UNDEF(SDNode *N); void CannotYetSelect(SDNode *N); + void Select_FREEZE(SDNode *N); + private: void DoInstructionSelection(); SDNode *MorphNode(SDNode *Node, unsigned TargetOpc, SDVTList VTList, diff --git a/llvm/lib/CodeGen/SelectionDAG/FastISel.cpp b/llvm/lib/CodeGen/SelectionDAG/FastISel.cpp index ada09092c4782d..461d481c822f5f 100644 --- a/llvm/lib/CodeGen/SelectionDAG/FastISel.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/FastISel.cpp @@ -1572,6 +1572,27 @@ bool FastISel::selectBitCast(const User *I) { return true; } +bool FastISel::selectFreeze(const User *I) { + Register Reg = getRegForValue(I->getOperand(0)); + if (!Reg) + // Unhandled operand. + return false; + + EVT ETy = TLI.getValueType(DL, I->getOperand(0)->getType()); + if (ETy == MVT::Other || !TLI.isTypeLegal(ETy)) + // Unhandled type, bail out. + return false; + + MVT Ty = ETy.getSimpleVT(); + const TargetRegisterClass *TyRegClass = TLI.getRegClassFor(Ty); + Register ResultReg = createResultReg(TyRegClass); + BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, + TII.get(TargetOpcode::COPY), ResultReg).addReg(Reg); + + updateValueMap(I, ResultReg); + return true; +} + // Remove local value instructions starting from the instruction after // SavedLastLocalValue to the current function insert point. void FastISel::removeDeadLocalValueCode(MachineInstr *SavedLastLocalValue) @@ -1913,6 +1934,9 @@ bool FastISel::selectOperator(const User *I, unsigned Opcode) { case Instruction::ExtractValue: return selectExtractValue(I); + case Instruction::Freeze: + return selectFreeze(I); + case Instruction::PHI: llvm_unreachable("FastISel shouldn't visit PHI nodes!"); diff --git a/llvm/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp b/llvm/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp index 3955490a3f85ea..0248b5121e3f23 100644 --- a/llvm/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp @@ -201,6 +201,10 @@ void DAGTypeLegalizer::PromoteIntegerResult(SDNode *N, unsigned ResNo) { case ISD::VECREDUCE_UMIN: Res = PromoteIntRes_VECREDUCE(N); break; + + case ISD::FREEZE: + Res = PromoteIntRes_FREEZE(N); + break; } // If the result is null then the sub-method took care of registering it. @@ -401,6 +405,12 @@ static EVT getShiftAmountTyForConstant(EVT VT, const TargetLowering &TLI, return ShiftVT; } +SDValue DAGTypeLegalizer::PromoteIntRes_FREEZE(SDNode *N) { + SDValue V = GetPromotedInteger(N->getOperand(0)); + return DAG.getNode(ISD::FREEZE, SDLoc(N), + V.getValueType(), V); +} + SDValue DAGTypeLegalizer::PromoteIntRes_BSWAP(SDNode *N) { SDValue Op = GetPromotedInteger(N->getOperand(0)); EVT OVT = N->getValueType(0); @@ -1868,6 +1878,7 @@ void DAGTypeLegalizer::ExpandIntegerResult(SDNode *N, unsigned ResNo) { case ISD::SELECT: SplitRes_SELECT(N, Lo, Hi); break; case ISD::SELECT_CC: SplitRes_SELECT_CC(N, Lo, Hi); break; case ISD::UNDEF: SplitRes_UNDEF(N, Lo, Hi); break; + case ISD::FREEZE: SplitRes_FREEZE(N, Lo, Hi); break; case ISD::BITCAST: ExpandRes_BITCAST(N, Lo, Hi); break; case ISD::BUILD_PAIR: ExpandRes_BUILD_PAIR(N, Lo, Hi); break; diff --git a/llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.h b/llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.h index 8126c42e44988b..aee4ab1fcd6193 100644 --- a/llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.h +++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.h @@ -309,6 +309,7 @@ class LLVM_LIBRARY_VISIBILITY DAGTypeLegalizer { SDValue PromoteIntRes_EXTRACT_VECTOR_ELT(SDNode *N); SDValue PromoteIntRes_FP_TO_XINT(SDNode *N); SDValue PromoteIntRes_FP_TO_FP16(SDNode *N); + SDValue PromoteIntRes_FREEZE(SDNode *N); SDValue PromoteIntRes_INT_EXTEND(SDNode *N); SDValue PromoteIntRes_LOAD(LoadSDNode *N); SDValue PromoteIntRes_MLOAD(MaskedLoadSDNode *N); @@ -961,6 +962,7 @@ class LLVM_LIBRARY_VISIBILITY DAGTypeLegalizer { void SplitRes_SELECT (SDNode *N, SDValue &Lo, SDValue &Hi); void SplitRes_SELECT_CC (SDNode *N, SDValue &Lo, SDValue &Hi); void SplitRes_UNDEF (SDNode *N, SDValue &Lo, SDValue &Hi); + void SplitRes_FREEZE (SDNode *N, SDValue &Lo, SDValue &Hi); void SplitVSETCC(const SDNode *N); diff --git a/llvm/lib/CodeGen/SelectionDAG/LegalizeTypesGeneric.cpp b/llvm/lib/CodeGen/SelectionDAG/LegalizeTypesGeneric.cpp index ad3e02f9921a28..8231a320b4f3e9 100644 --- a/llvm/lib/CodeGen/SelectionDAG/LegalizeTypesGeneric.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeTypesGeneric.cpp @@ -558,3 +558,12 @@ void DAGTypeLegalizer::SplitRes_UNDEF(SDNode *N, SDValue &Lo, SDValue &Hi) { Lo = DAG.getUNDEF(LoVT); Hi = DAG.getUNDEF(HiVT); } + +void DAGTypeLegalizer::SplitRes_FREEZE(SDNode *N, SDValue &Lo, SDValue &Hi) { + SDValue L, H; + SDLoc dl(N); + GetSplitOp(N->getOperand(0), L, H); + + Lo = DAG.getNode(ISD::FREEZE, dl, L.getValueType(), L); + Hi = DAG.getNode(ISD::FREEZE, dl, H.getValueType(), H); +} diff --git a/llvm/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp b/llvm/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp index 09934bbb29fe03..afed415af5ed97 100644 --- a/llvm/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp @@ -89,6 +89,7 @@ void DAGTypeLegalizer::ScalarizeVectorResult(SDNode *N, unsigned ResNo) { case ISD::FLOG2: case ISD::FNEARBYINT: case ISD::FNEG: + case ISD::FREEZE: case ISD::FP_EXTEND: case ISD::FP_TO_SINT: case ISD::FP_TO_UINT: @@ -879,6 +880,7 @@ void DAGTypeLegalizer::SplitVectorResult(SDNode *N, unsigned ResNo) { case ISD::FLOG2: case ISD::FNEARBYINT: case ISD::FNEG: + case ISD::FREEZE: case ISD::FP_EXTEND: case ISD::FP_ROUND: case ISD::FP_TO_SINT: @@ -2831,6 +2833,7 @@ void DAGTypeLegalizer::WidenVectorResult(SDNode *N, unsigned ResNo) { case ISD::CTTZ: case ISD::CTTZ_ZERO_UNDEF: case ISD::FNEG: + case ISD::FREEZE: case ISD::FCANONICALIZE: Res = WidenVecRes_Unary(N); break; diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp index 06fe247b027051..1ad86208ed4eab 100644 --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -10690,6 +10690,22 @@ void SelectionDAGBuilder::visitSwitch(const SwitchInst &SI) { } void SelectionDAGBuilder::visitFreeze(const FreezeInst &I) { - SDValue N = getValue(I.getOperand(0)); - setValue(&I, N); + SDNodeFlags Flags; + + SDValue Op = getValue(I.getOperand(0)); + if (I.getOperand(0)->getType()->isAggregateType()) { + EVT VT = Op.getValueType(); + SmallVector Values; + for (unsigned i = 0; i < Op.getNumOperands(); ++i) { + SDValue Arg(Op.getNode(), i); + SDValue UnNodeValue = DAG.getNode(ISD::FREEZE, getCurSDLoc(), VT, Arg, Flags); + Values.push_back(UnNodeValue); + } + SDValue MergedValue = DAG.getMergeValues(Values, getCurSDLoc()); + setValue(&I, MergedValue); + } else { + SDValue UnNodeValue = DAG.getNode(ISD::FREEZE, getCurSDLoc(), Op.getValueType(), + Op, Flags); + setValue(&I, UnNodeValue); + } } diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp index 0fd132f03af8bc..aca462f566746a 100644 --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp @@ -392,6 +392,7 @@ std::string SDNode::getOperationName(const SelectionDAG *G) const { case ISD::GC_TRANSITION_START: return "gc_transition.start"; case ISD::GC_TRANSITION_END: return "gc_transition.end"; case ISD::GET_DYNAMIC_AREA_OFFSET: return "get.dynamic.area.offset"; + case ISD::FREEZE: return "freeze"; // Bit manipulation case ISD::ABS: return "abs"; diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp index 51b2439dddc3d0..6fa6bde047c540 100644 --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp @@ -2290,6 +2290,14 @@ void SelectionDAGISel::Select_UNDEF(SDNode *N) { CurDAG->SelectNodeTo(N, TargetOpcode::IMPLICIT_DEF, N->getValueType(0)); } +void SelectionDAGISel::Select_FREEZE(SDNode *N) { + // TODO: We don't have FREEZE pseudo-instruction in MachineInstr-level now. + // If FREEZE instruction is added later, the code below must be changed as + // well. + CurDAG->SelectNodeTo(N, TargetOpcode::COPY, N->getValueType(0), + N->getOperand(0)); +} + /// GetVBR - decode a vbr encoding whose top bit is set. LLVM_ATTRIBUTE_ALWAYS_INLINE static inline uint64_t GetVBR(uint64_t Val, const unsigned char *MatcherTable, unsigned &Idx) { @@ -2826,6 +2834,9 @@ void SelectionDAGISel::SelectCodeCommon(SDNode *NodeToMatch, case ISD::UNDEF: Select_UNDEF(NodeToMatch); return; + case ISD::FREEZE: + Select_FREEZE(NodeToMatch); + return; } assert(!NodeToMatch->isMachineOpcode() && "Node already selected!"); diff --git a/llvm/lib/CodeGen/TargetLoweringBase.cpp b/llvm/lib/CodeGen/TargetLoweringBase.cpp index 436857d6b2150b..27440b2dd02c33 100644 --- a/llvm/lib/CodeGen/TargetLoweringBase.cpp +++ b/llvm/lib/CodeGen/TargetLoweringBase.cpp @@ -1657,7 +1657,7 @@ int TargetLoweringBase::InstructionOpcodeToISD(unsigned Opcode) const { case ExtractValue: return ISD::MERGE_VALUES; case InsertValue: return ISD::MERGE_VALUES; case LandingPad: return 0; - case Freeze: return 0; + case Freeze: return ISD::FREEZE; } llvm_unreachable("Unknown instruction type encountered!"); diff --git a/llvm/test/CodeGen/X86/fast-isel-freeze.ll b/llvm/test/CodeGen/X86/fast-isel-freeze.ll new file mode 100644 index 00000000000000..fee53ca93f5428 --- /dev/null +++ b/llvm/test/CodeGen/X86/fast-isel-freeze.ll @@ -0,0 +1,21 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc < %s -mtriple=x86_64-unknown-linux | FileCheck %s --check-prefix=SDAG +; RUN: llc < %s -fast-isel -fast-isel-abort=1 -mtriple=x86_64-unknown-linux | FileCheck %s --check-prefix=FAST + +define i32 @freeze(i32 %t) { +; SDAG-LABEL: freeze: +; SDAG: # %bb.0: +; SDAG-NEXT: movl $10, %eax +; SDAG-NEXT: xorl %edi, %eax +; SDAG-NEXT: retq +; +; FAST-LABEL: freeze: +; FAST: # %bb.0: +; FAST-NEXT: movl $10, %eax +; FAST-NEXT: xorl %edi, %eax +; FAST-NEXT: retq + %1 = freeze i32 %t + %2 = freeze i32 10 + %3 = xor i32 %1, %2 + ret i32 %3 +} diff --git a/llvm/test/CodeGen/X86/fast-isel.ll b/llvm/test/CodeGen/X86/fast-isel.ll index dbc13ba7ed7808..e9a8a6b5395000 100644 --- a/llvm/test/CodeGen/X86/fast-isel.ll +++ b/llvm/test/CodeGen/X86/fast-isel.ll @@ -99,6 +99,11 @@ define void @load_store_i1(i1* %p, i1* %q) nounwind { ret void } +define void @freeze_i32(i32 %x) { + %t = freeze i32 %x + ret void +} + @crash_test1x = external global <2 x i32>, align 8 define void @crash_test1() nounwind ssp { diff --git a/llvm/test/CodeGen/X86/freeze-legalize.ll b/llvm/test/CodeGen/X86/freeze-legalize.ll new file mode 100644 index 00000000000000..6bbd0b8e594937 --- /dev/null +++ b/llvm/test/CodeGen/X86/freeze-legalize.ll @@ -0,0 +1,87 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; Make sure that seldag legalization works correctly for freeze instruction. +; RUN: llc -mtriple=i386-apple-darwin < %s 2>&1 | FileCheck %s + +define i64 @expand(i32 %x) { +; CHECK-LABEL: expand: +; CHECK: ## %bb.0: +; CHECK-NEXT: movl $303174162, %eax ## imm = 0x12121212 +; CHECK-NEXT: movl $875836468, %ecx ## imm = 0x34343434 +; CHECK-NEXT: movl $1448498774, %edx ## imm = 0x56565656 +; CHECK-NEXT: xorl %eax, %edx +; CHECK-NEXT: movl $2021161080, %eax ## imm = 0x78787878 +; CHECK-NEXT: xorl %ecx, %eax +; CHECK-NEXT: retl + %y1 = freeze i64 1302123111658042420 ; 0x1212121234343434 + %y2 = freeze i64 6221254864647256184 ; 0x5656565678787878 + %t2 = xor i64 %y1, %y2 + ret i64 %t2 +} + + +define <2 x i64> @expand_vec(i32 %x) nounwind { +; CHECK-LABEL: expand_vec: +; CHECK: ## %bb.0: +; CHECK-NEXT: pushl %ebx +; CHECK-NEXT: pushl %edi +; CHECK-NEXT: pushl %esi +; CHECK-NEXT: movl {{[0-9]+}}(%esp), %eax +; CHECK-NEXT: movl $16843009, %ecx ## imm = 0x1010101 +; CHECK-NEXT: movl $589505315, %edx ## imm = 0x23232323 +; CHECK-NEXT: movl $303174162, %esi ## imm = 0x12121212 +; CHECK-NEXT: movl $875836468, %edi ## imm = 0x34343434 +; CHECK-NEXT: movl $1162167621, %ebx ## imm = 0x45454545 +; CHECK-NEXT: xorl %ecx, %ebx +; CHECK-NEXT: movl $1734829927, %ecx ## imm = 0x67676767 +; CHECK-NEXT: xorl %edx, %ecx +; CHECK-NEXT: movl $1448498774, %edx ## imm = 0x56565656 +; CHECK-NEXT: xorl %esi, %edx +; CHECK-NEXT: movl $2021161080, %esi ## imm = 0x78787878 +; CHECK-NEXT: xorl %edi, %esi +; CHECK-NEXT: movl %ebx, 12(%eax) +; CHECK-NEXT: movl %ecx, 8(%eax) +; CHECK-NEXT: movl %edx, 4(%eax) +; CHECK-NEXT: movl %esi, (%eax) +; CHECK-NEXT: popl %esi +; CHECK-NEXT: popl %edi +; CHECK-NEXT: popl %ebx +; CHECK-NEXT: retl $4 + ; <0x1212121234343434, 0x101010123232323> + %y1 = freeze <2 x i64> + ; <0x5656565678787878, 0x4545454567676767> + %y2 = freeze <2 x i64> + %t2 = xor <2 x i64> %y1, %y2 + ret <2 x i64> %t2 +} + +define i10 @promote() { +; CHECK-LABEL: promote: +; CHECK: ## %bb.0: +; CHECK-NEXT: movw $682, %cx ## imm = 0x2AA +; CHECK-NEXT: movw $992, %ax ## imm = 0x3E0 +; CHECK-NEXT: addl %ecx, %eax +; CHECK-NEXT: ## kill: def $ax killed $ax killed $eax +; CHECK-NEXT: retl + %a = freeze i10 682 + %b = freeze i10 992 + %res = add i10 %a, %b + ret i10 %res +} + +define <2 x i10> @promote_vec() { +; CHECK-LABEL: promote_vec: +; CHECK: ## %bb.0: +; CHECK-NEXT: movw $125, %ax +; CHECK-NEXT: movw $682, %cx ## imm = 0x2AA +; CHECK-NEXT: movw $393, %dx ## imm = 0x189 +; CHECK-NEXT: addl %eax, %edx +; CHECK-NEXT: movw $992, %ax ## imm = 0x3E0 +; CHECK-NEXT: addl %ecx, %eax +; CHECK-NEXT: ## kill: def $ax killed $ax killed $eax +; CHECK-NEXT: ## kill: def $dx killed $dx killed $edx +; CHECK-NEXT: retl + %a = freeze <2 x i10> + %b = freeze <2 x i10> + %res = add <2 x i10> %a, %b + ret <2 x i10> %res +} diff --git a/llvm/test/CodeGen/X86/freeze.ll b/llvm/test/CodeGen/X86/freeze.ll new file mode 100644 index 00000000000000..9ae9661a148c80 --- /dev/null +++ b/llvm/test/CodeGen/X86/freeze.ll @@ -0,0 +1,90 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=x86_64-unknown-linux-gnu < %s 2>&1 | FileCheck %s --check-prefix=X86ASM + +%struct.T = type { i32, i32 } + +define i32 @freeze_int() { +; X86ASM-LABEL: freeze_int: +; X86ASM: # %bb.0: +; X86ASM-NEXT: imull %eax, %eax +; X86ASM-NEXT: retq + %y1 = freeze i32 undef + %t1 = mul i32 %y1, %y1 + ret i32 %t1 +} + +define i5 @freeze_int2() { +; X86ASM-LABEL: freeze_int2: +; X86ASM: # %bb.0: +; X86ASM-NEXT: mulb %al +; X86ASM-NEXT: retq + %y1 = freeze i5 undef + %t1 = mul i5 %y1, %y1 + ret i5 %t1 +} + +define float @freeze_float() { +; X86ASM-LABEL: freeze_float: +; X86ASM: # %bb.0: +; X86ASM-NEXT: addss %xmm0, %xmm0 +; X86ASM-NEXT: retq + %y1 = freeze float undef + %t1 = fadd float %y1, %y1 + ret float %t1 +} + +define <2 x i32> @freeze_ivec() { +; X86ASM-LABEL: freeze_ivec: +; X86ASM: # %bb.0: +; X86ASM-NEXT: paddd %xmm0, %xmm0 +; X86ASM-NEXT: retq + %y1 = freeze <2 x i32> undef + %t1 = add <2 x i32> %y1, %y1 + ret <2 x i32> %t1 +} + +define i8* @freeze_ptr() { +; X86ASM-LABEL: freeze_ptr: +; X86ASM: # %bb.0: +; X86ASM-NEXT: addq $4, %rax +; X86ASM-NEXT: retq + %y1 = freeze i8* undef + %t1 = getelementptr i8, i8* %y1, i64 4 + ret i8* %t1 +} + +define i32 @freeze_struct() { +; X86ASM-LABEL: freeze_struct: +; X86ASM: # %bb.0: +; X86ASM-NEXT: addl %eax, %eax +; X86ASM-NEXT: retq + %y1 = freeze %struct.T undef + %v1 = extractvalue %struct.T %y1, 0 + %v2 = extractvalue %struct.T %y1, 1 + %t1 = add i32 %v1, %v2 + ret i32 %t1 +} + +define i32 @freeze_anonstruct() { +; X86ASM-LABEL: freeze_anonstruct: +; X86ASM: # %bb.0: +; X86ASM-NEXT: addl %eax, %eax +; X86ASM-NEXT: retq + %y1 = freeze {i32, i32} undef + %v1 = extractvalue {i32, i32} %y1, 0 + %v2 = extractvalue {i32, i32} %y1, 1 + %t1 = add i32 %v1, %v2 + ret i32 %t1 +} + +define i64 @freeze_array() { +; X86ASM-LABEL: freeze_array: +; X86ASM: # %bb.0: +; X86ASM-NEXT: addq %rax, %rax +; X86ASM-NEXT: retq + %y1 = freeze [2 x i64] undef + %v1 = extractvalue [2 x i64] %y1, 0 + %v2 = extractvalue [2 x i64] %y1, 1 + %t1 = add i64 %v1, %v2 + ret i64 %t1 +} From d381b6a8d3e87d65f4ae9ca4d4333203e01825f5 Mon Sep 17 00:00:00 2001 From: Pavel Labath Date: Fri, 20 Mar 2020 15:27:37 +0100 Subject: [PATCH 10/15] [DWARF] Fix v5 debug_line parsing of prologues with many files Summary: The directory_count and file_name_count fields are (section 6.2.4 of DWARF5 spec) supposed to be uleb128s, not bytes. This bug meant that it was not possible to correctly parse headers with more than 128 files or directories. I've found this bug by code inspection, though the limit is so small someone would have run into it for real sooner or later. I've verified that the producer side handles many files correctly, and that we are able to parse such files after this fix. Reviewers: dblaikie, jhenderson Subscribers: aprantl, hiraditya, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D76498 --- llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp | 8 +-- .../X86/debug_line_many_files_v5.s | 67 +++++++++++++++++++ 2 files changed, 71 insertions(+), 4 deletions(-) create mode 100644 llvm/test/tools/llvm-dwarfdump/X86/debug_line_many_files_v5.s diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp index 3c8fd0da62960f..366f0479c93a69 100644 --- a/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp @@ -255,8 +255,8 @@ parseV5DirFileTables(const DWARFDataExtractor &DebugLineData, return DirDescriptors.takeError(); // Get the directory entries, according to the format described above. - int DirEntryCount = DebugLineData.getU8(OffsetPtr); - for (int I = 0; I != DirEntryCount; ++I) { + uint64_t DirEntryCount = DebugLineData.getULEB128(OffsetPtr); + for (uint64_t I = 0; I != DirEntryCount; ++I) { for (auto Descriptor : *DirDescriptors) { DWARFFormValue Value(Descriptor.Form); switch (Descriptor.Type) { @@ -283,8 +283,8 @@ parseV5DirFileTables(const DWARFDataExtractor &DebugLineData, return FileDescriptors.takeError(); // Get the file entries, according to the format described above. - int FileEntryCount = DebugLineData.getU8(OffsetPtr); - for (int I = 0; I != FileEntryCount; ++I) { + uint64_t FileEntryCount = DebugLineData.getULEB128(OffsetPtr); + for (uint64_t I = 0; I != FileEntryCount; ++I) { DWARFDebugLine::FileNameEntry FileEntry; for (auto Descriptor : *FileDescriptors) { DWARFFormValue Value(Descriptor.Form); diff --git a/llvm/test/tools/llvm-dwarfdump/X86/debug_line_many_files_v5.s b/llvm/test/tools/llvm-dwarfdump/X86/debug_line_many_files_v5.s new file mode 100644 index 00000000000000..280ec6df1f343b --- /dev/null +++ b/llvm/test/tools/llvm-dwarfdump/X86/debug_line_many_files_v5.s @@ -0,0 +1,67 @@ +## An object with many files and directories in a single debug_line contribution +## meant to test the handling of directory_count and file_name_count fields. + +# RUN: llvm-mc -triple x86_64-pc-linux -filetype=obj %s -o %t +# RUN: llvm-dwarfdump -debug-line %t | FileCheck %s + +# CHECK: include_directories[ 0] = "/d000" +# CHECK: include_directories[299] = "/d299" +# CHECK: file_names[ 0]: +# CHECK-NEXT: name: "000.c" +# CHECK-NEXT: dir_index: 0 +# CHECK: file_names[299]: +# CHECK-NEXT: name: "299.c" +# CHECK-NEXT: dir_index: 299 + +.section .debug_line,"",@progbits +.long .Lunit_end0-.Lunit_start0 # Length of Unit +.Lunit_start0: +.short 5 # DWARF version number +.byte 8 # Address Size +.byte 0 # Segment Selector Size +.long .Lunit_header_end0 - .Lunit_params0 # Length of Prologue (invalid) +.Lunit_params0: +.byte 1 # Minimum Instruction Length +.byte 1 # Maximum Operations per Instruction +.byte 1 # Default is_stmt +.byte -5 # Line Base +.byte 14 # Line Range +.byte 13 # Opcode Base +.byte 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1 # Standard Opcode Lengths + +# Directory table format +.byte 1 # One element per directory entry +.byte 1 # DW_LNCT_path +.byte 0x08 # DW_FORM_string + +# Directory table entries +.uleb128 300 # 300 directories +.irpc a,012 +.irpc b,0123456789 +.irpc c,0123456789 +.byte '/', 'd', '0'+\a, '0'+\b, '0'+\c, 0 +.endr +.endr +.endr + +# File table format +.byte 2 # 2 elements per file entry +.byte 1 # DW_LNCT_path +.byte 0x08 # DW_FORM_string +.byte 2 # DW_LNCT_directory_index +.byte 0x05 # DW_FORM_data2 + +# File table entries +.uleb128 300 # 300 files +.irpc a,012 +.irpc b,0123456789 +.irpc c,0123456789 +.byte '0'+\a, '0'+\b, '0'+\c, '.', 'c', 0 # File name +.word \a*100+\b*10+\c # Dir index +.endr +.endr +.endr + +.Lunit_header_end0: +.byte 0, 1, 1 # DW_LNE_end_sequence +.Lunit_end0: From 2ae25647d1a363515ecbd193dc66d8ada80dd054 Mon Sep 17 00:00:00 2001 From: "Yaxun (Sam) Liu" Date: Mon, 23 Mar 2020 14:23:09 -0400 Subject: [PATCH 11/15] [CUDA][HIP] Add -Xarch_device and -Xarch_host options The argument after -Xarch_device will be added to the arguments for CUDA/HIP device compilation and will be removed for host compilation. The argument after -Xarch_host will be added to the arguments for CUDA/HIP host compilation and will be removed for device compilation. Differential Revision: https://reviews.llvm.org/D76520 --- clang/include/clang/Driver/Options.td | 4 ++ clang/include/clang/Driver/ToolChain.h | 18 ++++++-- clang/lib/Driver/Compilation.cpp | 19 ++++++-- clang/lib/Driver/ToolChain.cpp | 63 ++++++++++++++++++++++++-- clang/lib/Driver/ToolChains/Cuda.cpp | 6 --- clang/lib/Driver/ToolChains/HIP.cpp | 6 --- clang/test/Driver/hip-options.hip | 13 ++++++ 7 files changed, 105 insertions(+), 24 deletions(-) diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index 19bb72c55aa806..1358b463eb1a9c 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -466,6 +466,10 @@ def Xanalyzer : Separate<["-"], "Xanalyzer">, HelpText<"Pass to the static analyzer">, MetaVarName<"">, Group; def Xarch__ : JoinedAndSeparate<["-"], "Xarch_">, Flags<[DriverOption]>; +def Xarch_host : Separate<["-"], "Xarch_host">, Flags<[DriverOption]>, + HelpText<"Pass to the CUDA/HIP host compilation">, MetaVarName<"">; +def Xarch_device : Separate<["-"], "Xarch_device">, Flags<[DriverOption]>, + HelpText<"Pass to the CUDA/HIP device compilation">, MetaVarName<"">; def Xassembler : Separate<["-"], "Xassembler">, HelpText<"Pass to the assembler">, MetaVarName<"">, Group; diff --git a/clang/include/clang/Driver/ToolChain.h b/clang/include/clang/Driver/ToolChain.h index 115d5ff20f0798..66f22d53813821 100644 --- a/clang/include/clang/Driver/ToolChain.h +++ b/clang/include/clang/Driver/ToolChain.h @@ -296,10 +296,20 @@ class ToolChain { SmallVectorImpl &AllocatedArgs) const; /// Append the argument following \p A to \p DAL assuming \p A is an Xarch - /// argument. - virtual void TranslateXarchArgs(const llvm::opt::DerivedArgList &Args, - llvm::opt::Arg *&A, - llvm::opt::DerivedArgList *DAL) const; + /// argument. If \p AllocatedArgs is null pointer, synthesized arguments are + /// added to \p DAL, otherwise they are appended to \p AllocatedArgs. + virtual void TranslateXarchArgs( + const llvm::opt::DerivedArgList &Args, llvm::opt::Arg *&A, + llvm::opt::DerivedArgList *DAL, + SmallVectorImpl *AllocatedArgs = nullptr) const; + + /// Translate -Xarch_ arguments. If there are no such arguments, return + /// a null pointer, otherwise return a DerivedArgList containing the + /// translated arguments. + virtual llvm::opt::DerivedArgList * + TranslateXarchArgs(const llvm::opt::DerivedArgList &Args, StringRef BoundArch, + Action::OffloadKind DeviceOffloadKind, + SmallVectorImpl *AllocatedArgs) const; /// Choose a tool to use to handle the action \p JA. /// diff --git a/clang/lib/Driver/Compilation.cpp b/clang/lib/Driver/Compilation.cpp index 52477576b2eb15..05ee5091396b45 100644 --- a/clang/lib/Driver/Compilation.cpp +++ b/clang/lib/Driver/Compilation.cpp @@ -76,16 +76,29 @@ Compilation::getArgsForToolChain(const ToolChain *TC, StringRef BoundArch, *TranslatedArgs, SameTripleAsHost, AllocatedArgs); } + DerivedArgList *NewDAL = nullptr; if (!OpenMPArgs) { + NewDAL = TC->TranslateXarchArgs(*TranslatedArgs, BoundArch, + DeviceOffloadKind, &AllocatedArgs); + } else { + NewDAL = TC->TranslateXarchArgs(*OpenMPArgs, BoundArch, DeviceOffloadKind, + &AllocatedArgs); + if (!NewDAL) + NewDAL = OpenMPArgs; + else + delete OpenMPArgs; + } + + if (!NewDAL) { Entry = TC->TranslateArgs(*TranslatedArgs, BoundArch, DeviceOffloadKind); if (!Entry) Entry = TranslatedArgs; } else { - Entry = TC->TranslateArgs(*OpenMPArgs, BoundArch, DeviceOffloadKind); + Entry = TC->TranslateArgs(*NewDAL, BoundArch, DeviceOffloadKind); if (!Entry) - Entry = OpenMPArgs; + Entry = NewDAL; else - delete OpenMPArgs; + delete NewDAL; } // Add allocated arguments to the final DAL. diff --git a/clang/lib/Driver/ToolChain.cpp b/clang/lib/Driver/ToolChain.cpp index b1626900318f3c..b958473e242314 100644 --- a/clang/lib/Driver/ToolChain.cpp +++ b/clang/lib/Driver/ToolChain.cpp @@ -1103,11 +1103,20 @@ llvm::opt::DerivedArgList *ToolChain::TranslateOpenMPTargetArgs( return nullptr; } -void ToolChain::TranslateXarchArgs(const llvm::opt::DerivedArgList &Args, - llvm::opt::Arg *&A, - llvm::opt::DerivedArgList *DAL) const { +// TODO: Currently argument values separated by space e.g. +// -Xclang -mframe-pointer=no cannot be passed by -Xarch_. This should be +// fixed. +void ToolChain::TranslateXarchArgs( + const llvm::opt::DerivedArgList &Args, llvm::opt::Arg *&A, + llvm::opt::DerivedArgList *DAL, + SmallVectorImpl *AllocatedArgs) const { const OptTable &Opts = getDriver().getOpts(); - unsigned Index = Args.getBaseArgs().MakeIndex(A->getValue(1)); + unsigned ValuePos = 1; + if (A->getOption().matches(options::OPT_Xarch_device) || + A->getOption().matches(options::OPT_Xarch_host)) + ValuePos = 0; + + unsigned Index = Args.getBaseArgs().MakeIndex(A->getValue(ValuePos)); unsigned Prev = Index; std::unique_ptr XarchArg(Opts.ParseOneArg(Args, Index)); @@ -1130,5 +1139,49 @@ void ToolChain::TranslateXarchArgs(const llvm::opt::DerivedArgList &Args, } XarchArg->setBaseArg(A); A = XarchArg.release(); - DAL->AddSynthesizedArg(A); + if (!AllocatedArgs) + DAL->AddSynthesizedArg(A); + else + AllocatedArgs->push_back(A); +} + +llvm::opt::DerivedArgList *ToolChain::TranslateXarchArgs( + const llvm::opt::DerivedArgList &Args, StringRef BoundArch, + Action::OffloadKind OFK, + SmallVectorImpl *AllocatedArgs) const { + DerivedArgList *DAL = new DerivedArgList(Args.getBaseArgs()); + bool Modified = false; + + bool IsGPU = OFK == Action::OFK_Cuda || OFK == Action::OFK_HIP; + for (Arg *A : Args) { + bool NeedTrans = false; + bool Skip = false; + if (A->getOption().matches(options::OPT_Xarch_device)) { + NeedTrans = IsGPU; + Skip = !IsGPU; + } else if (A->getOption().matches(options::OPT_Xarch_host)) { + NeedTrans = !IsGPU; + Skip = IsGPU; + } else if (A->getOption().matches(options::OPT_Xarch__) && IsGPU) { + // Do not translate -Xarch_ options for non CUDA/HIP toolchain since + // they may need special translation. + // Skip this argument unless the architecture matches BoundArch + if (BoundArch.empty() || A->getValue(0) != BoundArch) + Skip = true; + else + NeedTrans = true; + } + if (NeedTrans || Skip) + Modified = true; + if (NeedTrans) + TranslateXarchArgs(Args, A, DAL, AllocatedArgs); + if (!Skip) + DAL->append(A); + } + + if (Modified) + return DAL; + + delete DAL; + return nullptr; } diff --git a/clang/lib/Driver/ToolChains/Cuda.cpp b/clang/lib/Driver/ToolChains/Cuda.cpp index 9ecb247d80d4b4..80259b552df065 100644 --- a/clang/lib/Driver/ToolChains/Cuda.cpp +++ b/clang/lib/Driver/ToolChains/Cuda.cpp @@ -800,12 +800,6 @@ CudaToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args, } for (Arg *A : Args) { - if (A->getOption().matches(options::OPT_Xarch__)) { - // Skip this argument unless the architecture matches BoundArch - if (BoundArch.empty() || A->getValue(0) != BoundArch) - continue; - TranslateXarchArgs(Args, A, DAL); - } DAL->append(A); } diff --git a/clang/lib/Driver/ToolChains/HIP.cpp b/clang/lib/Driver/ToolChains/HIP.cpp index c6787e70a051de..157dca7e0c8dbd 100644 --- a/clang/lib/Driver/ToolChains/HIP.cpp +++ b/clang/lib/Driver/ToolChains/HIP.cpp @@ -378,12 +378,6 @@ HIPToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args, const OptTable &Opts = getDriver().getOpts(); for (Arg *A : Args) { - if (A->getOption().matches(options::OPT_Xarch__)) { - // Skip this argument unless the architecture matches BoundArch. - if (BoundArch.empty() || A->getValue(0) != BoundArch) - continue; - TranslateXarchArgs(Args, A, DAL); - } DAL->append(A); } diff --git a/clang/test/Driver/hip-options.hip b/clang/test/Driver/hip-options.hip index 59afa3fdb2d7b0..a7a6e02a3c81cb 100644 --- a/clang/test/Driver/hip-options.hip +++ b/clang/test/Driver/hip-options.hip @@ -13,3 +13,16 @@ // RUN: -mllvm -amdgpu-early-inline-all=true %s 2>&1 | \ // RUN: FileCheck -check-prefix=MLLVM %s // MLLVM-NOT: "-mllvm"{{.*}}"-amdgpu-early-inline-all=true"{{.*}}"-mllvm"{{.*}}"-amdgpu-early-inline-all=true" + +// RUN: %clang -### -Xarch_device -g -nogpulib --cuda-gpu-arch=gfx900 \ +// RUN: -Xarch_device -fcf-protection=branch \ +// RUN: --cuda-gpu-arch=gfx906 %s 2>&1 | FileCheck -check-prefix=DEV %s +// DEV: clang{{.*}} "-fcuda-is-device" {{.*}} "-debug-info-kind={{.*}}" {{.*}} "-fcf-protection=branch" +// DEV: clang{{.*}} "-fcuda-is-device" {{.*}} "-debug-info-kind={{.*}}" {{.*}} "-fcf-protection=branch" +// DEV-NOT: clang{{.*}} {{.*}} "-debug-info-kind={{.*}}" + +// RUN: %clang -### -Xarch_host -g -nogpulib --cuda-gpu-arch=gfx900 \ +// RUN: --cuda-gpu-arch=gfx906 %s 2>&1 | FileCheck -check-prefix=HOST %s +// HOST-NOT: clang{{.*}} "-fcuda-is-device" {{.*}} "-debug-info-kind={{.*}}" +// HOST-NOT: clang{{.*}} "-fcuda-is-device" {{.*}} "-debug-info-kind={{.*}}" +// HOST: clang{{.*}} "-debug-info-kind={{.*}}" From ce36c5ab643a5ced7da2034288bbfbdd7193058b Mon Sep 17 00:00:00 2001 From: Louis Dionne Date: Tue, 24 Mar 2020 10:06:00 -0400 Subject: [PATCH 12/15] [libc++] Fix installation of cxx_experimental cxx_experimental was never installed because ${experimental_lib} always expands to an empty target. This seems to have been broken by 97d6fcce4ec6. --- libcxx/src/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libcxx/src/CMakeLists.txt b/libcxx/src/CMakeLists.txt index 2a9d05473be6c7..63ca34d1ec4704 100644 --- a/libcxx/src/CMakeLists.txt +++ b/libcxx/src/CMakeLists.txt @@ -349,7 +349,7 @@ if (LIBCXX_INSTALL_LIBRARY) endif() if(LIBCXX_INSTALL_EXPERIMENTAL_LIBRARY) - install(TARGETS ${LIBCXX_INSTALL_TARGETS} ${experimental_lib} + install(TARGETS cxx_experimental LIBRARY DESTINATION ${LIBCXX_INSTALL_PREFIX}${LIBCXX_INSTALL_LIBRARY_DIR} COMPONENT cxx ARCHIVE DESTINATION ${LIBCXX_INSTALL_PREFIX}${LIBCXX_INSTALL_LIBRARY_DIR} COMPONENT cxx RUNTIME DESTINATION ${LIBCXX_INSTALL_PREFIX}bin COMPONENT cxx) From 386f95e168b09603595864a5956624792ccb59c4 Mon Sep 17 00:00:00 2001 From: Haojian Wu Date: Sat, 21 Mar 2020 13:48:35 +0100 Subject: [PATCH 13/15] [Parser] Fix the assertion crash in ActOnStartOfSwitch stmt. Summary: After we parse the switch condition, we don't do the type check for type-dependent expr (e.g. TypoExpr) (in Sema::CheckSwitchCondition), then the TypoExpr is corrected to an invalid-type expr (in Sema::MakeFullExpr) and passed to the ActOnStartOfSwitchStmt, which triggers the assertion. Fix https://github.com/clangd/clangd/issues/311 Reviewers: sammccall Subscribers: ilya-biryukov, kadircet, usaxena95, cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D76592 --- clang/lib/Sema/SemaStmt.cpp | 10 +++++----- clang/test/Parser/switch-typo-correction.cpp | 9 +++++++++ 2 files changed, 14 insertions(+), 5 deletions(-) create mode 100644 clang/test/Parser/switch-typo-correction.cpp diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp index 2104add400e01e..68de776e83e647 100644 --- a/clang/lib/Sema/SemaStmt.cpp +++ b/clang/lib/Sema/SemaStmt.cpp @@ -730,11 +730,11 @@ StmtResult Sema::ActOnStartOfSwitchStmt(SourceLocation SwitchLoc, if (CondExpr && !CondExpr->isTypeDependent()) { // We have already converted the expression to an integral or enumeration - // type, when we parsed the switch condition. If we don't have an - // appropriate type now, enter the switch scope but remember that it's - // invalid. - assert(CondExpr->getType()->isIntegralOrEnumerationType() && - "invalid condition type"); + // type, when we parsed the switch condition. There are cases where we don't + // have an appropriate type, e.g. a typo-expr Cond was corrected to an + // inappropriate-type expr, we just return an error. + if (!CondExpr->getType()->isIntegralOrEnumerationType()) + return StmtError(); if (CondExpr->isKnownToHaveBooleanValue()) { // switch(bool_expr) {...} is often a programmer error, e.g. // switch(n && mask) { ... } // Doh - should be "n & mask". diff --git a/clang/test/Parser/switch-typo-correction.cpp b/clang/test/Parser/switch-typo-correction.cpp new file mode 100644 index 00000000000000..ebf1c18f2b86a0 --- /dev/null +++ b/clang/test/Parser/switch-typo-correction.cpp @@ -0,0 +1,9 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +namespace c { double xxx; } // expected-note{{'c::xxx' declared here}} +namespace d { float xxx; } +namespace z { namespace xxx {} } + +void crash() { + switch (xxx) {} // expected-error{{use of undeclared identifier 'xxx'; did you mean }} +} From 10bd8422d041e2964c146a38b5514d9d92fc458d Mon Sep 17 00:00:00 2001 From: Alexander Belyaev Date: Tue, 24 Mar 2020 15:14:06 +0100 Subject: [PATCH 14/15] [ARM][CMSE] Fix clang/test/Driver/save-temps.c test. Differential Revision: https://reviews.llvm.org/D76703 --- clang/test/Driver/save-temps.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clang/test/Driver/save-temps.c b/clang/test/Driver/save-temps.c index ae46f1e6b56505..b0cfa4fd814a88 100644 --- a/clang/test/Driver/save-temps.c +++ b/clang/test/Driver/save-temps.c @@ -83,9 +83,9 @@ // CHECK-SAVE-TEMPS: "-cc1as" // CHECK-SAVE-TEMPS: "-dwarf-version={{.}}" -// RUN: %clang --target=arm-arm-none-eabi -march=armv8-m.main -mcmse -save-temps -c -v %s 2>&1 \ +// RUN: %clang --target=arm-arm-none-eabi -march=armv8-m.main -mcmse -save-temps -c -v %s -### 2>&1 \ // RUN: | FileCheck %s -check-prefix=CHECK-SAVE-TEMPS-CMSE -// RUN: %clang --target=arm-arm-none-eabi -march=armv8-m.main -mcmse -x assembler -c -v %s 2>&1 \ +// RUN: %clang --target=arm-arm-none-eabi -march=armv8-m.main -mcmse -x assembler -c -v %s -### 2>&1 \ // RUN: | FileCheck %s -check-prefix=CHECK-SAVE-TEMPS-CMSE // CHECK-SAVE-TEMPS-CMSE: -cc1as // CHECK-SAVE-TEMPS-CMSE: +8msecext From 714402147daabad11c0bad2e54be997b7fb06b1d Mon Sep 17 00:00:00 2001 From: Simon Pilgrim Date: Tue, 24 Mar 2020 14:28:25 +0000 Subject: [PATCH 15/15] [X86][SSE1] Add support for logic+movmsk patterns (PR42870) rL368506 handled the basic case, but we need to account for boolean logic patterns as well. --- llvm/lib/Target/X86/X86ISelLowering.cpp | 73 +++++++++++++++++------ llvm/test/CodeGen/X86/pr42870.ll | 78 ++----------------------- 2 files changed, 59 insertions(+), 92 deletions(-) diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp index 017993399c143d..3828de5edd6833 100644 --- a/llvm/lib/Target/X86/X86ISelLowering.cpp +++ b/llvm/lib/Target/X86/X86ISelLowering.cpp @@ -37027,6 +37027,51 @@ static bool checkBitcastSrcVectorSize(SDValue Src, unsigned Size) { return false; } +// Helper to flip between AND/OR/XOR opcodes and their X86ISD FP equivalents. +static unsigned getAltBitOpcode(unsigned Opcode) { + switch(Opcode) { + case ISD::AND: return X86ISD::FAND; + case ISD::OR: return X86ISD::FOR; + case ISD::XOR: return X86ISD::FXOR; + case X86ISD::ANDNP: return X86ISD::FANDN; + } + llvm_unreachable("Unknown bitwise opcode"); +} + +// Helper to adjust v4i32 MOVMSK expansion to work with SSE1-only targets. +static SDValue adjustBitcastSrcVectorSSE1(SelectionDAG &DAG, SDValue Src, + const SDLoc &DL) { + EVT SrcVT = Src.getValueType(); + if (SrcVT != MVT::v4i1) + return SDValue(); + + switch (Src.getOpcode()) { + case ISD::SETCC: + if (Src.getOperand(0).getValueType() == MVT::v4i32 && + ISD::isBuildVectorAllZeros(Src.getOperand(1).getNode()) && + cast(Src.getOperand(2))->get() == ISD::SETLT) { + SDValue Op0 = Src.getOperand(0); + if (ISD::isNormalLoad(Op0.getNode())) + return DAG.getBitcast(MVT::v4f32, Op0); + if (Op0.getOpcode() == ISD::BITCAST && + Op0.getOperand(0).getValueType() == MVT::v4f32) + return Op0.getOperand(0); + } + break; + case ISD::AND: + case ISD::XOR: + case ISD::OR: { + SDValue Op0 = adjustBitcastSrcVectorSSE1(DAG, Src.getOperand(0), DL); + SDValue Op1 = adjustBitcastSrcVectorSSE1(DAG, Src.getOperand(1), DL); + if (Op0 && Op1) + return DAG.getNode(getAltBitOpcode(Src.getOpcode()), DL, MVT::v4f32, Op0, + Op1); + break; + } + } + return SDValue(); +} + // Helper to push sign extension of vXi1 SETCC result through bitops. static SDValue signExtendBitcastSrcVector(SelectionDAG &DAG, EVT SExtVT, SDValue Src, const SDLoc &DL) { @@ -37057,6 +37102,16 @@ static SDValue combineBitcastvxi1(SelectionDAG &DAG, EVT VT, SDValue Src, if (!SrcVT.isSimple() || SrcVT.getScalarType() != MVT::i1) return SDValue(); + // Recognize the IR pattern for the movmsk intrinsic under SSE1 before type + // legalization destroys the v4i32 type. + if (Subtarget.hasSSE1() && !Subtarget.hasSSE2()) { + if (SDValue V = adjustBitcastSrcVectorSSE1(DAG, Src, DL)) { + V = DAG.getNode(X86ISD::MOVMSK, DL, MVT::i32, + DAG.getBitcast(MVT::v4f32, V)); + return DAG.getZExtOrTrunc(V, DL, VT); + } + } + // If the input is a truncate from v16i8 or v32i8 go ahead and use a // movmskb even with avx512. This will be better than truncating to vXi1 and // using a kmov. This can especially help KNL if the input is a v16i8/v32i8 @@ -37319,24 +37374,6 @@ static SDValue combineBitcast(SDNode *N, SelectionDAG &DAG, if (SDValue V = combineBitcastvxi1(DAG, VT, N0, dl, Subtarget)) return V; - // Recognize the IR pattern for the movmsk intrinsic under SSE1 before type - // legalization destroys the v4i32 type. - if (Subtarget.hasSSE1() && !Subtarget.hasSSE2() && SrcVT == MVT::v4i1 && - VT.isScalarInteger() && N0.getOpcode() == ISD::SETCC && - N0.getOperand(0).getValueType() == MVT::v4i32 && - ISD::isBuildVectorAllZeros(N0.getOperand(1).getNode()) && - cast(N0.getOperand(2))->get() == ISD::SETLT) { - SDValue N00 = N0.getOperand(0); - // Only do this if we can avoid scalarizing the input. - if (ISD::isNormalLoad(N00.getNode()) || - (N00.getOpcode() == ISD::BITCAST && - N00.getOperand(0).getValueType() == MVT::v4f32)) { - SDValue V = DAG.getNode(X86ISD::MOVMSK, dl, MVT::i32, - DAG.getBitcast(MVT::v4f32, N00)); - return DAG.getZExtOrTrunc(V, dl, VT); - } - } - // If this is a bitcast between a MVT::v4i1/v2i1 and an illegal integer // type, widen both sides to avoid a trip through memory. if ((VT == MVT::v4i1 || VT == MVT::v2i1) && SrcVT.isScalarInteger() && diff --git a/llvm/test/CodeGen/X86/pr42870.ll b/llvm/test/CodeGen/X86/pr42870.ll index e4ffcb4787e868..c42cb7cb8b2865 100644 --- a/llvm/test/CodeGen/X86/pr42870.ll +++ b/llvm/test/CodeGen/X86/pr42870.ll @@ -33,26 +33,8 @@ start: define i32 @test_and(<4 x float> %a, <4 x float> %b) { ; CHECK-LABEL: test_and: ; CHECK: ## %bb.0: ## %start -; CHECK-NEXT: subl $28, %esp -; CHECK-NEXT: .cfi_def_cfa_offset 32 ; CHECK-NEXT: andps %xmm1, %xmm0 -; CHECK-NEXT: movaps %xmm0, (%esp) -; CHECK-NEXT: cmpl $0, (%esp) -; CHECK-NEXT: sets %al -; CHECK-NEXT: cmpl $0, {{[0-9]+}}(%esp) -; CHECK-NEXT: sets %cl -; CHECK-NEXT: addb %cl, %cl -; CHECK-NEXT: orb %al, %cl -; CHECK-NEXT: cmpl $0, {{[0-9]+}}(%esp) -; CHECK-NEXT: sets %al -; CHECK-NEXT: cmpl $0, {{[0-9]+}}(%esp) -; CHECK-NEXT: sets %dl -; CHECK-NEXT: addb %dl, %dl -; CHECK-NEXT: orb %al, %dl -; CHECK-NEXT: shlb $2, %dl -; CHECK-NEXT: orb %cl, %dl -; CHECK-NEXT: movzbl %dl, %eax -; CHECK-NEXT: addl $28, %esp +; CHECK-NEXT: movmskps %xmm0, %eax ; CHECK-NEXT: retl start: %0 = bitcast <4 x float> %a to <4 x i32> @@ -68,26 +50,8 @@ start: define i32 @test_or(<4 x float> %a, <4 x float> %b) { ; CHECK-LABEL: test_or: ; CHECK: ## %bb.0: ## %start -; CHECK-NEXT: subl $28, %esp -; CHECK-NEXT: .cfi_def_cfa_offset 32 ; CHECK-NEXT: orps %xmm1, %xmm0 -; CHECK-NEXT: movaps %xmm0, (%esp) -; CHECK-NEXT: cmpl $0, (%esp) -; CHECK-NEXT: sets %al -; CHECK-NEXT: cmpl $0, {{[0-9]+}}(%esp) -; CHECK-NEXT: sets %cl -; CHECK-NEXT: addb %cl, %cl -; CHECK-NEXT: orb %al, %cl -; CHECK-NEXT: cmpl $0, {{[0-9]+}}(%esp) -; CHECK-NEXT: sets %al -; CHECK-NEXT: cmpl $0, {{[0-9]+}}(%esp) -; CHECK-NEXT: sets %dl -; CHECK-NEXT: addb %dl, %dl -; CHECK-NEXT: orb %al, %dl -; CHECK-NEXT: shlb $2, %dl -; CHECK-NEXT: orb %cl, %dl -; CHECK-NEXT: movzbl %dl, %eax -; CHECK-NEXT: addl $28, %esp +; CHECK-NEXT: movmskps %xmm0, %eax ; CHECK-NEXT: retl start: %0 = bitcast <4 x float> %a to <4 x i32> @@ -103,42 +67,8 @@ start: define i32 @test_xor(<4 x float> %a, <4 x float> %b) { ; CHECK-LABEL: test_xor: ; CHECK: ## %bb.0: ## %start -; CHECK-NEXT: pushl %ebx -; CHECK-NEXT: .cfi_def_cfa_offset 8 -; CHECK-NEXT: subl $40, %esp -; CHECK-NEXT: .cfi_def_cfa_offset 48 -; CHECK-NEXT: .cfi_offset %ebx, -8 -; CHECK-NEXT: movaps %xmm0, {{[0-9]+}}(%esp) -; CHECK-NEXT: movaps %xmm1, (%esp) -; CHECK-NEXT: cmpl $0, {{[0-9]+}}(%esp) -; CHECK-NEXT: sets %al -; CHECK-NEXT: cmpl $0, {{[0-9]+}}(%esp) -; CHECK-NEXT: sets %cl -; CHECK-NEXT: cmpl $0, {{[0-9]+}}(%esp) -; CHECK-NEXT: sets %dl -; CHECK-NEXT: cmpl $0, {{[0-9]+}}(%esp) -; CHECK-NEXT: sets %ah -; CHECK-NEXT: cmpl $0, {{[0-9]+}}(%esp) -; CHECK-NEXT: sets %ch -; CHECK-NEXT: cmpl $0, {{[0-9]+}}(%esp) -; CHECK-NEXT: sets %dh -; CHECK-NEXT: cmpl $0, {{[0-9]+}}(%esp) -; CHECK-NEXT: sets %bl -; CHECK-NEXT: cmpl $0, (%esp) -; CHECK-NEXT: sets %bh -; CHECK-NEXT: xorb %ah, %bh -; CHECK-NEXT: xorb %dl, %bl -; CHECK-NEXT: addb %bl, %bl -; CHECK-NEXT: orb %bh, %bl -; CHECK-NEXT: xorb %cl, %dh -; CHECK-NEXT: xorb %al, %ch -; CHECK-NEXT: addb %ch, %ch -; CHECK-NEXT: orb %dh, %ch -; CHECK-NEXT: shlb $2, %ch -; CHECK-NEXT: orb %bl, %ch -; CHECK-NEXT: movzbl %ch, %eax -; CHECK-NEXT: addl $40, %esp -; CHECK-NEXT: popl %ebx +; CHECK-NEXT: xorps %xmm1, %xmm0 +; CHECK-NEXT: movmskps %xmm0, %eax ; CHECK-NEXT: retl start: %0 = bitcast <4 x float> %a to <4 x i32>