diff --git a/clang/include/clang/AST/DependenceFlags.h b/clang/include/clang/AST/DependenceFlags.h index ee6439fc984cf..788227156c4d9 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 1073174bcf913..7e845ad03587c 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 c5198cd805877..85a7d682f5c8c 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -1826,23 +1826,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; @@ -1852,41 +1840,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; @@ -2527,10 +2485,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; } @@ -2600,10 +2557,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: @@ -2630,11 +2584,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; } @@ -2660,10 +2610,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: @@ -2711,10 +2658,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: @@ -2763,10 +2707,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: @@ -2796,10 +2737,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(); @@ -2884,13 +2822,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; } @@ -3715,14 +3649,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; } @@ -3774,9 +3703,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. @@ -4268,9 +4198,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; } @@ -4299,11 +4229,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"); } @@ -4326,10 +4253,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."); @@ -4401,11 +4325,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"); } @@ -4614,10 +4534,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; } @@ -4719,18 +4636,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; @@ -4787,10 +4702,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: @@ -4887,23 +4799,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(); } @@ -4932,7 +4837,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 { @@ -5003,9 +4908,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: @@ -5207,10 +5113,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()); @@ -5289,11 +5193,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; } @@ -5357,10 +5258,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) { @@ -5431,10 +5329,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: @@ -5571,10 +5468,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; @@ -5793,8 +5689,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; @@ -6009,11 +5905,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: @@ -6183,11 +6075,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. @@ -6218,10 +6106,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 4afd9790d8750..994f932170ae1 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/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index e9d1c56b31bce..383a37bf57a1a 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -468,6 +468,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 18b73e9c61d6d..4e0bda105fa47 100644 --- a/clang/include/clang/Driver/ToolChain.h +++ b/clang/include/clang/Driver/ToolChain.h @@ -311,10 +311,20 @@ class ToolChain { Action::OffloadKind DeviceOffloadKind) 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/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 0d5d8cf888f22..29f028bfc2020 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" @@ -5130,8 +5131,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); @@ -5191,11 +5196,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 6e1c70f952629..69c942e46f729 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); } diff --git a/clang/lib/Driver/Compilation.cpp b/clang/lib/Driver/Compilation.cpp index 28eacdb055441..c24a6f3765f26 100644 --- a/clang/lib/Driver/Compilation.cpp +++ b/clang/lib/Driver/Compilation.cpp @@ -80,16 +80,29 @@ Compilation::getArgsForToolChain(const ToolChain *TC, StringRef BoundArch, *TranslatedArgs, SameTripleAsHost, AllocatedArgs, DeviceOffloadKind); } + DerivedArgList *NewDAL = nullptr; if (!OffloadArgs) { + NewDAL = TC->TranslateXarchArgs(*TranslatedArgs, BoundArch, + DeviceOffloadKind, &AllocatedArgs); + } else { + NewDAL = TC->TranslateXarchArgs(*OffloadArgs, BoundArch, DeviceOffloadKind, + &AllocatedArgs); + if (!NewDAL) + NewDAL = OffloadArgs; + else + delete OffloadArgs; + } + + if (!NewDAL) { Entry = TC->TranslateArgs(*TranslatedArgs, BoundArch, DeviceOffloadKind); if (!Entry) Entry = TranslatedArgs; } else { - Entry = TC->TranslateArgs(*OffloadArgs, BoundArch, DeviceOffloadKind); + Entry = TC->TranslateArgs(*NewDAL, BoundArch, DeviceOffloadKind); if (!Entry) - Entry = OffloadArgs; + Entry = NewDAL; else - delete OffloadArgs; + delete NewDAL; } // Add allocated arguments to the final DAL. diff --git a/clang/lib/Driver/ToolChain.cpp b/clang/lib/Driver/ToolChain.cpp index 215d632e53c90..dc8b05f2b1cce 100644 --- a/clang/lib/Driver/ToolChain.cpp +++ b/clang/lib/Driver/ToolChain.cpp @@ -1206,11 +1206,20 @@ llvm::opt::DerivedArgList *ToolChain::TranslateOffloadTargetArgs( 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)); @@ -1233,5 +1242,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 0bce8d1f0f4c9..54cde5cc28425 100644 --- a/clang/lib/Driver/ToolChains/Cuda.cpp +++ b/clang/lib/Driver/ToolChains/Cuda.cpp @@ -848,12 +848,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 c6787e70a051d..157dca7e0c8db 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/lib/Tooling/Syntax/BuildTree.cpp b/clang/lib/Tooling/Syntax/BuildTree.cpp index 4103a4d92c7d0..82c87ba02b744 100644 --- a/clang/lib/Tooling/Syntax/BuildTree.cpp +++ b/clang/lib/Tooling/Syntax/BuildTree.cpp @@ -1059,7 +1059,7 @@ void syntax::TreeBuilder::markStmtChild(Stmt *Child, NodeRole Role) { // This is an expression in a statement position, consume the trailing // semicolon and form an 'ExpressionStatement' node. - if (auto *E = dyn_cast(Child)) { + if (isa(Child)) { setRole(ChildNode, NodeRole::ExpressionStatement_expression); ChildNode = new (allocator()) syntax::ExpressionStatement; // (!) 'getStmtRange()' ensures this covers a trailing semicolon. diff --git a/clang/test/CodeGen/attr-noreturn.c b/clang/test/CodeGen/attr-noreturn.c index b420edfc05954..5dca4fa1f520a 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 diff --git a/clang/test/Driver/hip-options.hip b/clang/test/Driver/hip-options.hip index 59afa3fdb2d7b..a7a6e02a3c81c 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={{.*}}" diff --git a/lld/COFF/CMakeLists.txt b/lld/COFF/CMakeLists.txt index 1d310f8419f55..4592ace373efa 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 af86b69922729..e376ea51f133d 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 5320b8b83ce0a..8b3ba1cdf24b5 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 0000000000000..0e069724f8163 --- /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 0000000000000..b731293a8625d --- /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 a80c553637aa1..0958a79b14029 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 cea02e7a0042c..72fe9ce8c118c 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 7e7aaafe18ed5..d5e2b59027b4f 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 0000000000000..7a834344cc5b0 --- /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 d705a16c6c2a0..0000000000000 --- 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 0000000000000..0ec27fb33bdce --- /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 diff --git a/lldb/source/Core/ValueObject.cpp b/lldb/source/Core/ValueObject.cpp index 4c9c44ea15f4d..9e20ba76dccbd 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 0000000000000..99998b20bcb05 --- /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 0000000000000..c05e9e9b06ba7 --- /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 0000000000000..c1e8bcf242f4f --- /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 +} diff --git a/llvm/include/llvm/CodeGen/FastISel.h b/llvm/include/llvm/CodeGen/FastISel.h index d9c680392e50a..326a7eb2e9387 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 4bc8d7bd42f0e..17e8f53c23008 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 52c3e0c6148af..084badcbe0291 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/include/llvm/IR/ConstantRange.h b/llvm/include/llvm/IR/ConstantRange.h index e6bac8a5f9339..8ecb9aa0ce020 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/CodeGen/SelectionDAG/FastISel.cpp b/llvm/lib/CodeGen/SelectionDAG/FastISel.cpp index ada09092c4782..461d481c822f5 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 3955490a3f85e..0248b5121e3f2 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 8126c42e44988..aee4ab1fcd619 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 ad3e02f9921a2..8231a320b4f3e 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 09934bbb29fe0..afed415af5ed9 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 06fe247b02705..1ad86208ed4ea 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 0fd132f03af8b..aca462f566746 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 51b2439dddc3d..6fa6bde047c54 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 436857d6b2150..27440b2dd02c3 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/lib/DebugInfo/DWARF/DWARFDebugLine.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp index 3c8fd0da62960..366f0479c93a6 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/lib/IR/ConstantRange.cpp b/llvm/lib/IR/ConstantRange.cpp index 3d25cb5bfbdf0..b8c57533568be 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/lib/Support/OptimalLayout.cpp b/llvm/lib/Support/OptimalLayout.cpp index b0c7720e71c60..93f912bf73a3b 100644 --- a/llvm/lib/Support/OptimalLayout.cpp +++ b/llvm/lib/Support/OptimalLayout.cpp @@ -15,8 +15,8 @@ using namespace llvm; #ifndef NDEBUG -void checkValidLayout(ArrayRef Fields, - uint64_t Size, Align MaxAlign) { +static void checkValidLayout(ArrayRef Fields, uint64_t Size, + Align MaxAlign) { uint64_t LastEnd = 0; Align ComputedMaxAlign; for (auto &Field : Fields) { 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 0000000000000..fee53ca93f542 --- /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 dbc13ba7ed780..e9a8a6b539500 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 0000000000000..6bbd0b8e59493 --- /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 0000000000000..9ae9661a148c8 --- /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 +} diff --git a/llvm/test/CodeGen/X86/pr42870.ll b/llvm/test/CodeGen/X86/pr42870.ll index 575a2653a33f8..e4ffcb4787e86 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 +} diff --git a/llvm/test/Transforms/InstSimplify/freeze.ll b/llvm/test/Transforms/InstSimplify/freeze.ll index 0e631426b6474..52d1f72edacba 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 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 0000000000000..280ec6df1f343 --- /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: diff --git a/llvm/unittests/IR/ConstantRangeTest.cpp b/llvm/unittests/IR/ConstantRangeTest.cpp index 2e5ab82f256e7..4d19dd59cae64 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 diff --git a/mlir/lib/Conversion/AVX512ToLLVM/ConvertAVX512ToLLVM.cpp b/mlir/lib/Conversion/AVX512ToLLVM/ConvertAVX512ToLLVM.cpp index 7a8c1e81fcb8a..af29714eb69a8 100644 --- a/mlir/lib/Conversion/AVX512ToLLVM/ConvertAVX512ToLLVM.cpp +++ b/mlir/lib/Conversion/AVX512ToLLVM/ConvertAVX512ToLLVM.cpp @@ -27,7 +27,8 @@ using namespace mlir::edsc::intrinsics; using namespace mlir::vector; using namespace mlir::avx512; -template Type getSrcVectorElementType(OpTy op) { +template +static Type getSrcVectorElementType(OpTy op) { return op.src().getType().template cast().getElementType(); } @@ -38,10 +39,11 @@ template Type getSrcVectorElementType(OpTy op) { /// LLVM Dialect Ops. Convert the type of the result to an LLVM type, pass /// operands as is, preserve attributes. template -LogicalResult matchAndRewriteOneToOne(const ConvertToLLVMPattern &lowering, - LLVMTypeConverter &typeConverter, - Operation *op, ArrayRef operands, - ConversionPatternRewriter &rewriter) { +static LogicalResult +matchAndRewriteOneToOne(const ConvertToLLVMPattern &lowering, + LLVMTypeConverter &typeConverter, Operation *op, + ArrayRef operands, + ConversionPatternRewriter &rewriter) { unsigned numResults = op->getNumResults(); Type packedType; @@ -75,6 +77,7 @@ LogicalResult matchAndRewriteOneToOne(const ConvertToLLVMPattern &lowering, return success(); } +namespace { // TODO(ntv): Patterns are too verbose due to the fact that we have 1 op (e.g. // MaskRndScaleOp) and different possible target ops. It would be better to take // a Functor so that all these conversions become 1-liners. @@ -145,6 +148,7 @@ struct ScaleFOpPD512Conversion : public ConvertToLLVMPattern { *this, this->typeConverter, op, operands, rewriter); } }; +} // namespace /// Populate the given list with patterns that convert from AVX512 to LLVM. void mlir::populateAVX512ToLLVMConversionPatterns( diff --git a/mlir/lib/Conversion/StandardToSPIRV/ConvertStandardToSPIRV.cpp b/mlir/lib/Conversion/StandardToSPIRV/ConvertStandardToSPIRV.cpp index 69ef69d1de65a..ea8812cebdc4c 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 cb5873a1baf04..91219acc0bd54 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