32 changes: 25 additions & 7 deletions clang/include/clang/Driver/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -4854,6 +4854,14 @@ def mstrict_align : Flag<["-"], "mstrict-align">, Group<m_Group>,
HelpText<"Force all memory accesses to be aligned (AArch64/LoongArch/RISC-V only)">;
def mno_strict_align : Flag<["-"], "mno-strict-align">, Group<m_Group>,
HelpText<"Allow memory accesses to be unaligned (AArch64/LoongArch/RISC-V only)">;
def mscalar_strict_align : Flag<["-"], "mscalar-strict-align">, Group<m_Group>,
HelpText<"Force all scalar memory accesses to be aligned (RISC-V only)">;
def mno_scalar_strict_align : Flag<["-"], "mno-scalar-strict-align">, Group<m_Group>,
HelpText<"Allow scalar memory accesses to be unaligned (RISC-V only)">;
def mvector_strict_align : Flag<["-"], "mvector-strict-align">, Group<m_Group>,
HelpText<"Force all vector memory accesses to be aligned (RISC-V only)">;
def mno_vector_strict_align : Flag<["-"], "mno-vector-strict-align">, Group<m_Group>,
HelpText<"Allow vector memory accesses to be unaligned (RISC-V only)">;
def mno_thumb : Flag<["-"], "mno-thumb">, Group<m_arm_Features_Group>;
def mrestrict_it: Flag<["-"], "mrestrict-it">, Group<m_arm_Features_Group>,
HelpText<"Disallow generation of complex IT blocks. It is off by default.">;
Expand Down Expand Up @@ -5171,6 +5179,13 @@ def mvx : Flag<["-"], "mvx">, Group<m_Group>;
def mno_vx : Flag<["-"], "mno-vx">, Group<m_Group>;
} // let Flags = [TargetSpecific]

let Flags = [TargetSpecific] in {
def msse2avx : Flag<["-"], "msse2avx">, Group<m_Group>,
Visibility<[ClangOption, CC1Option, CC1AsOption]>,
HelpText<"Specify that the assembler should encode SSE instructions with VEX prefix">,
MarshallingInfoFlag<CodeGenOpts<"SSE2AVX">>;
} // let Flags = [TargetSpecific]

defm zvector : BoolFOption<"zvector",
LangOpts<"ZVector">, DefaultFalse,
PosFlag<SetTrue, [], [ClangOption, CC1Option],
Expand Down Expand Up @@ -5441,6 +5456,7 @@ def module_file_info : Flag<["-"], "module-file-info">, Flags<[]>,
HelpText<"Provide information about a particular module file">;
def mthumb : Flag<["-"], "mthumb">, Group<m_Group>;
def mtune_EQ : Joined<["-"], "mtune=">, Group<m_Group>,
Visibility<[ClangOption, FlangOption]>,
HelpText<"Only supported on AArch64, PowerPC, RISC-V, SPARC, SystemZ, and X86">;
def multi__module : Flag<["-"], "multi_module">;
def multiply__defined__unused : Separate<["-"], "multiply_defined_unused">;
Expand Down Expand Up @@ -6119,10 +6135,6 @@ def mno_80387 : Flag<["-"], "mno-80387">, Alias<mno_x87>;
def mno_fp_ret_in_387 : Flag<["-"], "mno-fp-ret-in-387">, Alias<mno_x87>;
def mmmx : Flag<["-"], "mmmx">, Group<m_x86_Features_Group>;
def mno_mmx : Flag<["-"], "mno-mmx">, Group<m_x86_Features_Group>;
def m3dnow : Flag<["-"], "m3dnow">, Group<m_x86_Features_Group>;
def mno_3dnow : Flag<["-"], "mno-3dnow">, Group<m_x86_Features_Group>;
def m3dnowa : Flag<["-"], "m3dnowa">, Group<m_x86_Features_Group>;
def mno_3dnowa : Flag<["-"], "mno-3dnowa">, Group<m_x86_Features_Group>;
def mamx_bf16 : Flag<["-"], "mamx-bf16">, Group<m_x86_Features_Group>;
def mno_amx_bf16 : Flag<["-"], "mno-amx-bf16">, Group<m_x86_Features_Group>;
def mamx_complex : Flag<["-"], "mamx-complex">, Group<m_x86_Features_Group>;
Expand Down Expand Up @@ -6356,6 +6368,12 @@ def mvevpu : Flag<["-"], "mvevpu">, Group<m_ve_Features_Group>,
def mno_vevpu : Flag<["-"], "mno-vevpu">, Group<m_ve_Features_Group>;
} // let Flags = [TargetSpecific]

// Unsupported X86 feature flags (triggers a warning)
def m3dnow : Flag<["-"], "m3dnow">;
def mno_3dnow : Flag<["-"], "mno-3dnow">;
def m3dnowa : Flag<["-"], "m3dnowa">;
def mno_3dnowa : Flag<["-"], "mno-3dnowa">;

// These are legacy user-facing driver-level option spellings. They are always
// aliases for options that are spelled using the more common Unix / GNU flag
// style of double-dash and equals-joined flags.
Expand Down Expand Up @@ -6768,9 +6786,6 @@ def emit_hlfir : Flag<["-"], "emit-hlfir">, Group<Action_Group>,

let Visibility = [CC1Option, CC1AsOption] in {

def tune_cpu : Separate<["-"], "tune-cpu">,
HelpText<"Tune for a specific cpu type">,
MarshallingInfoString<TargetOpts<"TuneCPU">>;
def target_abi : Separate<["-"], "target-abi">,
HelpText<"Target a particular ABI type">,
MarshallingInfoString<TargetOpts<"ABI">>;
Expand All @@ -6797,6 +6812,9 @@ def darwin_target_variant_triple : Separate<["-"], "darwin-target-variant-triple

let Visibility = [CC1Option, CC1AsOption, FC1Option] in {

def tune_cpu : Separate<["-"], "tune-cpu">,
HelpText<"Tune for a specific cpu type">,
MarshallingInfoString<TargetOpts<"TuneCPU">>;
def target_cpu : Separate<["-"], "target-cpu">,
HelpText<"Target a specific cpu type">,
MarshallingInfoString<TargetOpts<"CPU">>;
Expand Down
51 changes: 27 additions & 24 deletions clang/include/clang/ExtractAPI/ExtractAPIVisitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -175,22 +175,25 @@ class ExtractAPIVisitorBase : public RecursiveASTVisitor<Derived> {
// skip classes not inherited as public
if (BaseSpecifier.getAccessSpecifier() != AccessSpecifier::AS_public)
continue;
SymbolReference BaseClass;
if (BaseSpecifier.getType().getTypePtr()->isTemplateTypeParmType()) {
BaseClass.Name = API.copyString(BaseSpecifier.getType().getAsString());
if (auto *TTPTD = BaseSpecifier.getType()
->getAs<TemplateTypeParmType>()
->getDecl()) {
SmallString<128> USR;
index::generateUSRForDecl(TTPTD, USR);
BaseClass.USR = API.copyString(USR);
BaseClass.Source = API.copyString(getOwningModuleName(*TTPTD));
}
if (auto *BaseDecl = BaseSpecifier.getType()->getAsTagDecl()) {
Bases.emplace_back(createSymbolReferenceForDecl(*BaseDecl));
} else {
BaseClass = createSymbolReferenceForDecl(
*BaseSpecifier.getType().getTypePtr()->getAsCXXRecordDecl());
SymbolReference BaseClass;
BaseClass.Name = API.copyString(BaseSpecifier.getType().getAsString(
Decl->getASTContext().getPrintingPolicy()));

if (BaseSpecifier.getType().getTypePtr()->isTemplateTypeParmType()) {
if (auto *TTPTD = BaseSpecifier.getType()
->getAs<TemplateTypeParmType>()
->getDecl()) {
SmallString<128> USR;
index::generateUSRForDecl(TTPTD, USR);
BaseClass.USR = API.copyString(USR);
BaseClass.Source = API.copyString(getOwningModuleName(*TTPTD));
}
}
Bases.emplace_back(BaseClass);
}
Bases.emplace_back(BaseClass);
}
return Bases;
}
Expand Down Expand Up @@ -352,7 +355,7 @@ bool ExtractAPIVisitorBase<Derived>::VisitFunctionDecl(
return true;

// Collect symbol information.
StringRef Name = Decl->getName();
auto Name = Decl->getNameAsString();
SmallString<128> USR;
index::generateUSRForDecl(Decl, USR);
PresumedLoc Loc =
Expand Down Expand Up @@ -666,17 +669,17 @@ bool ExtractAPIVisitorBase<Derived>::VisitCXXMethodDecl(
if (FunctionTemplateDecl *TemplateDecl =
Decl->getDescribedFunctionTemplate()) {
API.createRecord<CXXMethodTemplateRecord>(
USR, Decl->getName(), createHierarchyInformationForDecl(*Decl), Loc,
AvailabilityInfo::createFromDecl(Decl), Comment,
USR, Decl->getNameAsString(), createHierarchyInformationForDecl(*Decl),
Loc, AvailabilityInfo::createFromDecl(Decl), Comment,
DeclarationFragmentsBuilder::getFragmentsForFunctionTemplate(
TemplateDecl),
SubHeading, DeclarationFragmentsBuilder::getFunctionSignature(Decl),
DeclarationFragmentsBuilder::getAccessControl(TemplateDecl),
Template(TemplateDecl), isInSystemHeader(Decl));
} else if (Decl->getTemplateSpecializationInfo())
API.createRecord<CXXMethodTemplateSpecializationRecord>(
USR, Decl->getName(), createHierarchyInformationForDecl(*Decl), Loc,
AvailabilityInfo::createFromDecl(Decl), Comment,
USR, Decl->getNameAsString(), createHierarchyInformationForDecl(*Decl),
Loc, AvailabilityInfo::createFromDecl(Decl), Comment,
DeclarationFragmentsBuilder::
getFragmentsForFunctionTemplateSpecialization(Decl),
SubHeading, Signature, Access, isInSystemHeader(Decl));
Expand All @@ -688,14 +691,14 @@ bool ExtractAPIVisitorBase<Derived>::VisitCXXMethodDecl(
SubHeading, Signature, Access, isInSystemHeader(Decl));
else if (Decl->isStatic())
API.createRecord<CXXStaticMethodRecord>(
USR, Decl->getName(), createHierarchyInformationForDecl(*Decl), Loc,
AvailabilityInfo::createFromDecl(Decl), Comment,
USR, Decl->getNameAsString(), createHierarchyInformationForDecl(*Decl),
Loc, AvailabilityInfo::createFromDecl(Decl), Comment,
DeclarationFragmentsBuilder::getFragmentsForCXXMethod(Decl), SubHeading,
Signature, Access, isInSystemHeader(Decl));
else
API.createRecord<CXXInstanceMethodRecord>(
USR, Decl->getName(), createHierarchyInformationForDecl(*Decl), Loc,
AvailabilityInfo::createFromDecl(Decl), Comment,
USR, Decl->getNameAsString(), createHierarchyInformationForDecl(*Decl),
Loc, AvailabilityInfo::createFromDecl(Decl), Comment,
DeclarationFragmentsBuilder::getFragmentsForCXXMethod(Decl), SubHeading,
Signature, Access, isInSystemHeader(Decl));

Expand Down Expand Up @@ -977,7 +980,7 @@ bool ExtractAPIVisitorBase<Derived>::VisitFunctionTemplateDecl(
return true;

// Collect symbol information.
StringRef Name = Decl->getName();
auto Name = Decl->getNameAsString();
SmallString<128> USR;
index::generateUSRForDecl(Decl, USR);
PresumedLoc Loc =
Expand Down
7 changes: 4 additions & 3 deletions clang/include/clang/Lex/Preprocessor.h
Original file line number Diff line number Diff line change
Expand Up @@ -2123,17 +2123,18 @@ class Preprocessor {
char
getSpellingOfSingleCharacterNumericConstant(const Token &Tok,
bool *Invalid = nullptr) const {
assert(Tok.is(tok::numeric_constant) &&
assert((Tok.is(tok::numeric_constant) || Tok.is(tok::binary_data)) &&
Tok.getLength() == 1 && "Called on unsupported token");
assert(!Tok.needsCleaning() && "Token can't need cleaning with length 1");

// If the token is carrying a literal data pointer, just use it.
if (const char *D = Tok.getLiteralData())
return *D;
return (Tok.getKind() == tok::binary_data) ? *D : *D - '0';

assert(Tok.is(tok::numeric_constant) && "binary data with no data");
// Otherwise, fall back on getCharacterData, which is slower, but always
// works.
return *SourceMgr.getCharacterData(Tok.getLocation(), Invalid);
return *SourceMgr.getCharacterData(Tok.getLocation(), Invalid) - '0';
}

/// Retrieve the name of the immediate macro expansion.
Expand Down
17 changes: 10 additions & 7 deletions clang/include/clang/Parse/Parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -2127,7 +2127,7 @@ class Parser : public CodeCompletionHandler {
};
ExprResult ParseInitializerWithPotentialDesignator(DesignatorCompletionInfo);
ExprResult createEmbedExpr();
void ExpandEmbedDirective(SmallVectorImpl<Expr *> &Exprs);
void injectEmbedTokens();

//===--------------------------------------------------------------------===//
// clang Expressions
Expand Down Expand Up @@ -3372,11 +3372,15 @@ class Parser : public CodeCompletionHandler {
BaseResult ParseBaseSpecifier(Decl *ClassDecl);
AccessSpecifier getAccessSpecifierIfPresent() const;

bool ParseUnqualifiedIdTemplateId(
CXXScopeSpec &SS, ParsedType ObjectType, bool ObjectHadErrors,
SourceLocation TemplateKWLoc, SourceLocation TildeLoc,
IdentifierInfo *Name, SourceLocation NameLoc, bool EnteringContext,
UnqualifiedId &Id, bool AssumeTemplateId);
bool ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS,
ParsedType ObjectType,
bool ObjectHadErrors,
SourceLocation TemplateKWLoc,
IdentifierInfo *Name,
SourceLocation NameLoc,
bool EnteringContext,
UnqualifiedId &Id,
bool AssumeTemplateId);
bool ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext,
ParsedType ObjectType,
UnqualifiedId &Result);
Expand Down Expand Up @@ -3830,7 +3834,6 @@ class Parser : public CodeCompletionHandler {
AnnotateTemplateIdTokenAsType(CXXScopeSpec &SS,
ImplicitTypenameContext AllowImplicitTypename,
bool IsClassName = false);
void ExpandEmbedIntoTemplateArgList(TemplateArgList &TemplateArgs);
bool ParseTemplateArgumentList(TemplateArgList &TemplateArgs,
TemplateTy Template, SourceLocation OpenLoc);
ParsedTemplateArgument ParseTemplateTemplateArgument();
Expand Down
8 changes: 0 additions & 8 deletions clang/include/clang/Sema/DeclSpec.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,6 @@ class CXXScopeSpec {
SourceRange Range;
NestedNameSpecifierLocBuilder Builder;
ArrayRef<TemplateParameterList *> TemplateParamLists;
ArrayRef<DeclAccessPair> UnqualifiedLookups;

public:
SourceRange getRange() const { return Range; }
Expand All @@ -92,13 +91,6 @@ class CXXScopeSpec {
return TemplateParamLists;
}

void setUnqualifiedLookups(ArrayRef<DeclAccessPair> Found) {
UnqualifiedLookups = Found;
}
ArrayRef<DeclAccessPair> getUnqualifiedLookups() const {
return UnqualifiedLookups;
}

/// Retrieve the representation of the nested-name-specifier.
NestedNameSpecifier *getScopeRep() const {
return Builder.getRepresentation();
Expand Down
8 changes: 2 additions & 6 deletions clang/include/clang/Sema/Lookup.h
Original file line number Diff line number Diff line change
Expand Up @@ -483,15 +483,11 @@ class LookupResult {
ResultKind = Found;
}

void addAllDecls(ArrayRef<DeclAccessPair> Other) {
Decls.addAllDecls(Other);
ResultKind = Found;
}

/// Add all the declarations from another set of lookup
/// results.
void addAllDecls(const LookupResult &Other) {
addAllDecls(Other.Decls.pairs());
Decls.append(Other.Decls.begin(), Other.Decls.end());
ResultKind = Found;
}

/// Determine whether no result was found because we could not
Expand Down
101 changes: 64 additions & 37 deletions clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -560,13 +560,14 @@ class Sema final : public SemaBase {
// 23. Statement Attribute Handling (SemaStmtAttr.cpp)
// 24. C++ Templates (SemaTemplate.cpp)
// 25. C++ Template Argument Deduction (SemaTemplateDeduction.cpp)
// 26. C++ Template Instantiation (SemaTemplateInstantiate.cpp)
// 27. C++ Template Declaration Instantiation
// 26. C++ Template Deduction Guide (SemaTemplateDeductionGuide.cpp)
// 27. C++ Template Instantiation (SemaTemplateInstantiate.cpp)
// 28. C++ Template Declaration Instantiation
// (SemaTemplateInstantiateDecl.cpp)
// 28. C++ Variadic Templates (SemaTemplateVariadic.cpp)
// 29. Constraints and Concepts (SemaConcept.cpp)
// 30. Types (SemaType.cpp)
// 31. FixIt Helpers (SemaFixItUtils.cpp)
// 29. C++ Variadic Templates (SemaTemplateVariadic.cpp)
// 30. Constraints and Concepts (SemaConcept.cpp)
// 31. Types (SemaType.cpp)
// 32. FixIt Helpers (SemaFixItUtils.cpp)

/// \name Semantic Analysis
/// Implementations are in Sema.cpp
Expand Down Expand Up @@ -2802,8 +2803,7 @@ class Sema final : public SemaBase {
/// (e.g., Base::), perform name lookup for that identifier as a
/// nested-name-specifier within the given scope, and return the result of
/// that name lookup.
bool LookupFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS,
UnresolvedSetImpl &R);
NamedDecl *FindFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS);

/// Keeps information about an identifier in a nested-name-spec.
///
Expand Down Expand Up @@ -2843,6 +2843,9 @@ class Sema final : public SemaBase {
/// \param EnteringContext If true, enter the context specified by the
/// nested-name-specifier.
/// \param SS Optional nested name specifier preceding the identifier.
/// \param ScopeLookupResult Provides the result of name lookup within the
/// scope of the nested-name-specifier that was computed at template
/// definition time.
/// \param ErrorRecoveryLookup Specifies if the method is called to improve
/// error recovery and what kind of recovery is performed.
/// \param IsCorrectedToColon If not null, suggestion of replace '::' -> ':'
Expand All @@ -2851,6 +2854,11 @@ class Sema final : public SemaBase {
/// not '::'.
/// \param OnlyNamespace If true, only considers namespaces in lookup.
///
/// This routine differs only slightly from ActOnCXXNestedNameSpecifier, in
/// that it contains an extra parameter \p ScopeLookupResult, which provides
/// the result of name lookup within the scope of the nested-name-specifier
/// that was computed at template definition time.
///
/// If ErrorRecoveryLookup is true, then this call is used to improve error
/// recovery. This means that it should not emit diagnostics, it should
/// just return true on failure. It also means it should only return a valid
Expand All @@ -2859,6 +2867,7 @@ class Sema final : public SemaBase {
/// specifier.
bool BuildCXXNestedNameSpecifier(Scope *S, NestedNameSpecInfo &IdInfo,
bool EnteringContext, CXXScopeSpec &SS,
NamedDecl *ScopeLookupResult,
bool ErrorRecoveryLookup,
bool *IsCorrectedToColon = nullptr,
bool OnlyNamespace = false);
Expand Down Expand Up @@ -8558,12 +8567,11 @@ class Sema final : public SemaBase {
const TemplateArgumentListInfo *TemplateArgs,
bool IsDefiniteInstance, const Scope *S);

ExprResult
ActOnDependentMemberExpr(Expr *Base, QualType BaseType, bool IsArrow,
SourceLocation OpLoc, const CXXScopeSpec &SS,
SourceLocation TemplateKWLoc,
const DeclarationNameInfo &NameInfo,
const TemplateArgumentListInfo *TemplateArgs);
ExprResult ActOnDependentMemberExpr(
Expr *Base, QualType BaseType, bool IsArrow, SourceLocation OpLoc,
const CXXScopeSpec &SS, SourceLocation TemplateKWLoc,
NamedDecl *FirstQualifierInScope, const DeclarationNameInfo &NameInfo,
const TemplateArgumentListInfo *TemplateArgs);

/// The main callback when the parser finds something like
/// expression . [nested-name-specifier] identifier
Expand Down Expand Up @@ -8619,14 +8627,15 @@ class Sema final : public SemaBase {
ExprResult BuildMemberReferenceExpr(
Expr *Base, QualType BaseType, SourceLocation OpLoc, bool IsArrow,
CXXScopeSpec &SS, SourceLocation TemplateKWLoc,
const DeclarationNameInfo &NameInfo,
NamedDecl *FirstQualifierInScope, const DeclarationNameInfo &NameInfo,
const TemplateArgumentListInfo *TemplateArgs, const Scope *S,
ActOnMemberAccessExtraArgs *ExtraArgs = nullptr);

ExprResult
BuildMemberReferenceExpr(Expr *Base, QualType BaseType, SourceLocation OpLoc,
bool IsArrow, const CXXScopeSpec &SS,
SourceLocation TemplateKWLoc, LookupResult &R,
SourceLocation TemplateKWLoc,
NamedDecl *FirstQualifierInScope, LookupResult &R,
const TemplateArgumentListInfo *TemplateArgs,
const Scope *S, bool SuppressQualifierCheck = false,
ActOnMemberAccessExtraArgs *ExtraArgs = nullptr);
Expand Down Expand Up @@ -11114,14 +11123,15 @@ class Sema final : public SemaBase {
QualType ObjectType, bool EnteringContext,
RequiredTemplateKind RequiredTemplate = SourceLocation(),
AssumedTemplateKind *ATK = nullptr,
bool AllowTypoCorrection = true, bool MayBeNNS = false);
bool AllowTypoCorrection = true);

TemplateNameKind
isTemplateName(Scope *S, CXXScopeSpec &SS, bool hasTemplateKeyword,
const UnqualifiedId &Name, ParsedType ObjectType,
bool EnteringContext, TemplateTy &Template,
bool &MemberOfUnknownSpecialization,
bool Disambiguation = false, bool MayBeNNS = false);
TemplateNameKind isTemplateName(Scope *S, CXXScopeSpec &SS,
bool hasTemplateKeyword,
const UnqualifiedId &Name,
ParsedType ObjectType, bool EnteringContext,
TemplateTy &Template,
bool &MemberOfUnknownSpecialization,
bool Disambiguation = false);

/// Try to resolve an undeclared template name as a type template.
///
Expand Down Expand Up @@ -11347,6 +11357,10 @@ class Sema final : public SemaBase {
bool &IsMemberSpecialization, bool &Invalid,
bool SuppressDiagnostic = false);

/// Returns the template parameter list with all default template argument
/// information.
TemplateParameterList *GetTemplateParameterList(TemplateDecl *TD);

DeclResult CheckClassTemplate(
Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc,
CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc,
Expand Down Expand Up @@ -11450,11 +11464,12 @@ class Sema final : public SemaBase {
/// For example, given "x.MetaFun::template apply", the scope specifier
/// \p SS will be "MetaFun::", \p TemplateKWLoc contains the location
/// of the "template" keyword, and "apply" is the \p Name.
TemplateNameKind
ActOnTemplateName(Scope *S, CXXScopeSpec &SS, SourceLocation TemplateKWLoc,
const UnqualifiedId &Name, ParsedType ObjectType,
bool EnteringContext, TemplateTy &Template,
bool AllowInjectedClassName = false, bool MayBeNNS = false);
TemplateNameKind ActOnTemplateName(Scope *S, CXXScopeSpec &SS,
SourceLocation TemplateKWLoc,
const UnqualifiedId &Name,
ParsedType ObjectType,
bool EnteringContext, TemplateTy &Template,
bool AllowInjectedClassName = false);

DeclResult ActOnClassTemplateSpecialization(
Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc,
Expand Down Expand Up @@ -12009,15 +12024,6 @@ class Sema final : public SemaBase {
unsigned TemplateDepth,
const Expr *Constraint);

/// Declare implicit deduction guides for a class template if we've
/// not already done so.
void DeclareImplicitDeductionGuides(TemplateDecl *Template,
SourceLocation Loc);

FunctionTemplateDecl *DeclareAggregateDeductionGuideFromInitList(
TemplateDecl *Template, MutableArrayRef<QualType> ParamTypes,
SourceLocation Loc);

/// Find the failed Boolean condition within a given Boolean
/// constant expression, and describe it with a string.
std::pair<Expr *, std::string> findFailedBooleanCondition(Expr *Cond);
Expand Down Expand Up @@ -12570,6 +12576,27 @@ class Sema final : public SemaBase {
//
//

/// \name C++ Template Deduction Guide
/// Implementations are in SemaTemplateDeductionGuide.cpp
///@{

/// Declare implicit deduction guides for a class template if we've
/// not already done so.
void DeclareImplicitDeductionGuides(TemplateDecl *Template,
SourceLocation Loc);

FunctionTemplateDecl *DeclareAggregateDeductionGuideFromInitList(
TemplateDecl *Template, MutableArrayRef<QualType> ParamTypes,
SourceLocation Loc);

///@}

//
//
// -------------------------------------------------------------------------
//
//

/// \name C++ Template Instantiation
/// Implementations are in SemaTemplateInstantiate.cpp
///@{
Expand Down
8 changes: 4 additions & 4 deletions clang/lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7250,14 +7250,14 @@ ASTContext::getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS) const {
// A namespace is canonical; build a nested-name-specifier with
// this namespace and no prefix.
return NestedNameSpecifier::Create(*this, nullptr,
NNS->getAsNamespace()->getOriginalNamespace());
NNS->getAsNamespace()->getFirstDecl());

case NestedNameSpecifier::NamespaceAlias:
// A namespace is canonical; build a nested-name-specifier with
// this namespace and no prefix.
return NestedNameSpecifier::Create(*this, nullptr,
NNS->getAsNamespaceAlias()->getNamespace()
->getOriginalNamespace());
return NestedNameSpecifier::Create(
*this, nullptr,
NNS->getAsNamespaceAlias()->getNamespace()->getFirstDecl());

// The difference between TypeSpec and TypeSpecWithTemplate is that the
// latter will have the 'template' keyword when printed.
Expand Down
12 changes: 3 additions & 9 deletions clang/lib/AST/ASTImporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8439,14 +8439,8 @@ ExpectedStmt ASTNodeImporter::VisitCXXDependentScopeMemberExpr(
auto ToOperatorLoc = importChecked(Err, E->getOperatorLoc());
auto ToQualifierLoc = importChecked(Err, E->getQualifierLoc());
auto ToTemplateKeywordLoc = importChecked(Err, E->getTemplateKeywordLoc());

UnresolvedSet<8> ToUnqualifiedLookups;
for (auto D : E->unqualified_lookups())
if (auto ToDOrErr = import(D.getDecl()))
ToUnqualifiedLookups.addDecl(*ToDOrErr);
else
return ToDOrErr.takeError();

auto ToFirstQualifierFoundInScope =
importChecked(Err, E->getFirstQualifierFoundInScope());
if (Err)
return std::move(Err);

Expand Down Expand Up @@ -8480,7 +8474,7 @@ ExpectedStmt ASTNodeImporter::VisitCXXDependentScopeMemberExpr(

return CXXDependentScopeMemberExpr::Create(
Importer.getToContext(), ToBase, ToType, E->isArrow(), ToOperatorLoc,
ToQualifierLoc, ToTemplateKeywordLoc, ToUnqualifiedLookups.pairs(),
ToQualifierLoc, ToTemplateKeywordLoc, ToFirstQualifierFoundInScope,
ToMemberNameInfo, ResInfo);
}

Expand Down
3 changes: 1 addition & 2 deletions clang/lib/AST/DeclBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1422,8 +1422,7 @@ DeclContext *DeclContext::getPrimaryContext() {
case Decl::TranslationUnit:
return static_cast<TranslationUnitDecl *>(this)->getFirstDecl();
case Decl::Namespace:
// The original namespace is our primary context.
return static_cast<NamespaceDecl *>(this)->getOriginalNamespace();
return static_cast<NamespaceDecl *>(this)->getFirstDecl();

case Decl::ObjCMethod:
return this;
Expand Down
31 changes: 4 additions & 27 deletions clang/lib/AST/DeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2941,7 +2941,7 @@ UsingDirectiveDecl *UsingDirectiveDecl::Create(ASTContext &C, DeclContext *DC,
NamedDecl *Used,
DeclContext *CommonAncestor) {
if (auto *NS = dyn_cast_or_null<NamespaceDecl>(Used))
Used = NS->getOriginalNamespace();
Used = NS->getFirstDecl();
return new (C, DC) UsingDirectiveDecl(DC, L, NamespaceLoc, QualifierLoc,
IdentLoc, Used, CommonAncestor);
}
Expand All @@ -2966,16 +2966,9 @@ NamespaceDecl::NamespaceDecl(ASTContext &C, DeclContext *DC, bool Inline,
bool Nested)
: NamedDecl(Namespace, DC, IdLoc, Id), DeclContext(Namespace),
redeclarable_base(C), LocStart(StartLoc) {
unsigned Flags = 0;
if (Inline)
Flags |= F_Inline;
if (Nested)
Flags |= F_Nested;
AnonOrFirstNamespaceAndFlags = {nullptr, Flags};
setInline(Inline);
setNested(Nested);
setPreviousDecl(PrevDecl);

if (PrevDecl)
AnonOrFirstNamespaceAndFlags.setPointer(PrevDecl->getOriginalNamespace());
}

NamespaceDecl *NamespaceDecl::Create(ASTContext &C, DeclContext *DC,
Expand All @@ -2992,22 +2985,6 @@ NamespaceDecl *NamespaceDecl::CreateDeserialized(ASTContext &C,
SourceLocation(), nullptr, nullptr, false);
}

NamespaceDecl *NamespaceDecl::getOriginalNamespace() {
if (isFirstDecl())
return this;

return AnonOrFirstNamespaceAndFlags.getPointer();
}

const NamespaceDecl *NamespaceDecl::getOriginalNamespace() const {
if (isFirstDecl())
return this;

return AnonOrFirstNamespaceAndFlags.getPointer();
}

bool NamespaceDecl::isOriginalNamespace() const { return isFirstDecl(); }

NamespaceDecl *NamespaceDecl::getNextRedeclarationImpl() {
return getNextRedeclaration();
}
Expand Down Expand Up @@ -3043,7 +3020,7 @@ NamespaceAliasDecl *NamespaceAliasDecl::Create(ASTContext &C, DeclContext *DC,
NamedDecl *Namespace) {
// FIXME: Preserve the aliased namespace as written.
if (auto *NS = dyn_cast_or_null<NamespaceDecl>(Namespace))
Namespace = NS->getOriginalNamespace();
Namespace = NS->getFirstDecl();
return new (C, DC) NamespaceAliasDecl(C, DC, UsingLoc, AliasLoc, Alias,
QualifierLoc, IdentLoc, Namespace);
}
Expand Down
67 changes: 27 additions & 40 deletions clang/lib/AST/ExprCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1489,27 +1489,19 @@ SourceLocation CXXUnresolvedConstructExpr::getBeginLoc() const {
CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(
const ASTContext &Ctx, Expr *Base, QualType BaseType, bool IsArrow,
SourceLocation OperatorLoc, NestedNameSpecifierLoc QualifierLoc,
SourceLocation TemplateKWLoc, ArrayRef<DeclAccessPair> UnqualifiedLookups,
SourceLocation TemplateKWLoc, NamedDecl *FirstQualifierFoundInScope,
DeclarationNameInfo MemberNameInfo,
const TemplateArgumentListInfo *TemplateArgs)
: Expr(CXXDependentScopeMemberExprClass, Ctx.DependentTy, VK_LValue,
OK_Ordinary),
Base(Base), BaseType(BaseType), MemberNameInfo(MemberNameInfo),
OperatorLoc(OperatorLoc) {
Base(Base), BaseType(BaseType), QualifierLoc(QualifierLoc),
MemberNameInfo(MemberNameInfo) {
CXXDependentScopeMemberExprBits.IsArrow = IsArrow;
CXXDependentScopeMemberExprBits.HasQualifier = QualifierLoc.hasQualifier();
CXXDependentScopeMemberExprBits.NumUnqualifiedLookups =
UnqualifiedLookups.size();
CXXDependentScopeMemberExprBits.HasTemplateKWAndArgsInfo =
(TemplateArgs != nullptr) || TemplateKWLoc.isValid();

if (hasQualifier())
new (getTrailingObjects<NestedNameSpecifierLoc>())
NestedNameSpecifierLoc(QualifierLoc);

std::uninitialized_copy_n(UnqualifiedLookups.data(),
UnqualifiedLookups.size(),
getTrailingObjects<DeclAccessPair>());
CXXDependentScopeMemberExprBits.HasFirstQualifierFoundInScope =
FirstQualifierFoundInScope != nullptr;
CXXDependentScopeMemberExprBits.OperatorLoc = OperatorLoc;

if (TemplateArgs) {
auto Deps = TemplateArgumentDependence::None;
Expand All @@ -1521,59 +1513,54 @@ CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(
TemplateKWLoc);
}

if (hasFirstQualifierFoundInScope())
*getTrailingObjects<NamedDecl *>() = FirstQualifierFoundInScope;
setDependence(computeDependence(this));
}

CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(
EmptyShell Empty, bool HasQualifier, unsigned NumUnqualifiedLookups,
bool HasTemplateKWAndArgsInfo)
EmptyShell Empty, bool HasTemplateKWAndArgsInfo,
bool HasFirstQualifierFoundInScope)
: Expr(CXXDependentScopeMemberExprClass, Empty) {
CXXDependentScopeMemberExprBits.HasQualifier = HasQualifier;
CXXDependentScopeMemberExprBits.NumUnqualifiedLookups = NumUnqualifiedLookups;
CXXDependentScopeMemberExprBits.HasTemplateKWAndArgsInfo =
HasTemplateKWAndArgsInfo;
CXXDependentScopeMemberExprBits.HasFirstQualifierFoundInScope =
HasFirstQualifierFoundInScope;
}

CXXDependentScopeMemberExpr *CXXDependentScopeMemberExpr::Create(
const ASTContext &Ctx, Expr *Base, QualType BaseType, bool IsArrow,
SourceLocation OperatorLoc, NestedNameSpecifierLoc QualifierLoc,
SourceLocation TemplateKWLoc, ArrayRef<DeclAccessPair> UnqualifiedLookups,
SourceLocation TemplateKWLoc, NamedDecl *FirstQualifierFoundInScope,
DeclarationNameInfo MemberNameInfo,
const TemplateArgumentListInfo *TemplateArgs) {
bool HasQualifier = QualifierLoc.hasQualifier();
unsigned NumUnqualifiedLookups = UnqualifiedLookups.size();
assert(!NumUnqualifiedLookups || HasQualifier);
bool HasTemplateKWAndArgsInfo =
(TemplateArgs != nullptr) || TemplateKWLoc.isValid();
unsigned NumTemplateArgs = TemplateArgs ? TemplateArgs->size() : 0;
unsigned Size =
totalSizeToAlloc<NestedNameSpecifierLoc, DeclAccessPair,
ASTTemplateKWAndArgsInfo, TemplateArgumentLoc>(
HasQualifier, NumUnqualifiedLookups, HasTemplateKWAndArgsInfo,
NumTemplateArgs);
bool HasFirstQualifierFoundInScope = FirstQualifierFoundInScope != nullptr;

unsigned Size = totalSizeToAlloc<ASTTemplateKWAndArgsInfo,
TemplateArgumentLoc, NamedDecl *>(
HasTemplateKWAndArgsInfo, NumTemplateArgs, HasFirstQualifierFoundInScope);

void *Mem = Ctx.Allocate(Size, alignof(CXXDependentScopeMemberExpr));
return new (Mem) CXXDependentScopeMemberExpr(
Ctx, Base, BaseType, IsArrow, OperatorLoc, QualifierLoc, TemplateKWLoc,
UnqualifiedLookups, MemberNameInfo, TemplateArgs);
FirstQualifierFoundInScope, MemberNameInfo, TemplateArgs);
}

CXXDependentScopeMemberExpr *CXXDependentScopeMemberExpr::CreateEmpty(
const ASTContext &Ctx, bool HasQualifier, unsigned NumUnqualifiedLookups,
bool HasTemplateKWAndArgsInfo, unsigned NumTemplateArgs) {
assert(!NumTemplateArgs || HasTemplateKWAndArgsInfo);
assert(!NumUnqualifiedLookups || HasQualifier);
const ASTContext &Ctx, bool HasTemplateKWAndArgsInfo,
unsigned NumTemplateArgs, bool HasFirstQualifierFoundInScope) {
assert(NumTemplateArgs == 0 || HasTemplateKWAndArgsInfo);

unsigned Size =
totalSizeToAlloc<NestedNameSpecifierLoc, DeclAccessPair,
ASTTemplateKWAndArgsInfo, TemplateArgumentLoc>(
HasQualifier, NumUnqualifiedLookups, HasTemplateKWAndArgsInfo,
NumTemplateArgs);
unsigned Size = totalSizeToAlloc<ASTTemplateKWAndArgsInfo,
TemplateArgumentLoc, NamedDecl *>(
HasTemplateKWAndArgsInfo, NumTemplateArgs, HasFirstQualifierFoundInScope);

void *Mem = Ctx.Allocate(Size, alignof(CXXDependentScopeMemberExpr));
return new (Mem) CXXDependentScopeMemberExpr(EmptyShell(), HasQualifier,
NumUnqualifiedLookups,
HasTemplateKWAndArgsInfo);
return new (Mem) CXXDependentScopeMemberExpr(
EmptyShell(), HasTemplateKWAndArgsInfo, HasFirstQualifierFoundInScope);
}

CXXThisExpr *CXXThisExpr::Create(const ASTContext &Ctx, SourceLocation L,
Expand Down
13 changes: 4 additions & 9 deletions clang/lib/AST/Interp/Boolean.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,15 +45,10 @@ class Boolean final {
Boolean operator-(const Boolean &Other) const { return Boolean(V - Other.V); }
Boolean operator~() const { return Boolean(true); }

explicit operator int8_t() const { return V; }
explicit operator uint8_t() const { return V; }
explicit operator int16_t() const { return V; }
explicit operator uint16_t() const { return V; }
explicit operator int32_t() const { return V; }
explicit operator uint32_t() const { return V; }
explicit operator int64_t() const { return V; }
explicit operator uint64_t() const { return V; }
explicit operator bool() const { return V; }
template <typename Ty, typename = std::enable_if_t<std::is_integral_v<Ty>>>
explicit operator Ty() const {
return V;
}

APSInt toAPSInt() const {
return APSInt(APInt(1, static_cast<uint64_t>(V), false), true);
Expand Down
5 changes: 5 additions & 0 deletions clang/lib/AST/Interp/ByteCodeEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,11 @@ Function *ByteCodeEmitter::compileFunc(const FunctionDecl *FuncDecl) {

// Set up lambda capture to closure record field mapping.
if (isLambdaCallOperator(MD)) {
// The parent record needs to be complete, we need to know about all
// the lambda captures.
if (!MD->getParent()->isCompleteDefinition())
return nullptr;

const Record *R = P.getOrCreateRecord(MD->getParent());
llvm::DenseMap<const ValueDecl *, FieldDecl *> LC;
FieldDecl *LTC;
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/AST/Interp/Context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ bool Context::isPotentialConstantExpr(State &Parent, const FunctionDecl *FD) {
if (!Func || !Func->hasBody())
Func = Compiler<ByteCodeEmitter>(*this, *P).compileFunc(FD);

if (!Func)
return false;

APValue DummyResult;
if (!Run(Parent, Func, DummyResult))
return false;
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/AST/Interp/EvalEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,8 @@ template <> bool EvalEmitter::emitRet<PT_Ptr>(const SourceInfo &Info) {

// Implicitly convert lvalue to rvalue, if requested.
if (ConvertResultToRValue) {
if (!Ptr.isZero() && !Ptr.isDereferencable())
return false;
// Never allow reading from a non-const pointer, unless the memory
// has been created in this evaluation.
if (!Ptr.isConst() && Ptr.block()->getEvalID() != Ctx.getEvalID())
Expand Down
8 changes: 4 additions & 4 deletions clang/lib/AST/Interp/Integral.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,10 +98,10 @@ template <unsigned Bits, bool Signed> class Integral final {
return Integral<DstBits, DstSign>(V);
}

explicit operator unsigned() const { return V; }
explicit operator int64_t() const { return V; }
explicit operator uint64_t() const { return V; }
explicit operator int32_t() const { return V; }
template <typename Ty, typename = std::enable_if_t<std::is_integral_v<Ty>>>
explicit operator Ty() const {
return V;
}

APSInt toAPSInt() const {
return APSInt(APInt(Bits, static_cast<uint64_t>(V), Signed), !Signed);
Expand Down
26 changes: 25 additions & 1 deletion clang/lib/AST/Interp/Interp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,8 @@ bool CheckExtern(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
if (!Ptr.isExtern())
return true;

if (Ptr.isInitialized())
if (Ptr.isInitialized() ||
(Ptr.getDeclDesc()->asVarDecl() == S.EvaluatingDecl))
return true;

if (!S.checkingPotentialConstantExpression() && S.getLangOpts().CPlusPlus) {
Expand Down Expand Up @@ -444,6 +445,27 @@ bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
return false;
}

bool CheckVolatile(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
AccessKinds AK) {
assert(Ptr.isLive());

// FIXME: This check here might be kinda expensive. Maybe it would be better
// to have another field in InlineDescriptor for this?
if (!Ptr.isBlockPointer())
return true;

QualType PtrType = Ptr.getType();
if (!PtrType.isVolatileQualified())
return true;

const SourceInfo &Loc = S.Current->getSource(OpPC);
if (S.getLangOpts().CPlusPlus)
S.FFDiag(Loc, diag::note_constexpr_access_volatile_type) << AK << PtrType;
else
S.FFDiag(Loc);
return false;
}

bool CheckInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
AccessKinds AK) {
assert(Ptr.isLive());
Expand Down Expand Up @@ -508,6 +530,8 @@ bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
return false;
if (!CheckMutable(S, OpPC, Ptr))
return false;
if (!CheckVolatile(S, OpPC, Ptr, AK))
return false;
return true;
}

Expand Down
4 changes: 3 additions & 1 deletion clang/lib/AST/Interp/InterpFrame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,9 @@ void InterpFrame::describe(llvm::raw_ostream &OS) const {
// diagnose them. The 'in call to' diagnostics for them add no value to the
// user _and_ it doesn't generally work since the argument types don't always
// match the function prototype. Just ignore them.
if (const auto *F = getFunction(); F && F->isBuiltin())
// Similarly, for lambda static invokers, we would just print __invoke().
if (const auto *F = getFunction();
F && (F->isBuiltin() || F->isLambdaStaticInvoker()))
return;

const FunctionDecl *F = getCallee();
Expand Down
12 changes: 12 additions & 0 deletions clang/lib/AST/Interp/Pointer.h
Original file line number Diff line number Diff line change
Expand Up @@ -584,6 +584,7 @@ class Pointer {
assert(isLive() && "Invalid pointer");
assert(isBlockPointer());
assert(asBlockPointer().Pointee);
assert(isDereferencable());
assert(Offset + sizeof(T) <=
asBlockPointer().Pointee->getDescriptor()->getAllocSize());

Expand All @@ -603,6 +604,17 @@ class Pointer {
sizeof(InitMapPtr))[I];
}

/// Whether this block can be read from at all. This is only true for
/// block pointers that point to a valid location inside that block.
bool isDereferencable() const {
if (!isBlockPointer())
return false;
if (isPastEnd())
return false;

return true;
}

/// Initializes a field.
void initialize() const;
/// Activats a field.
Expand Down
41 changes: 25 additions & 16 deletions clang/lib/AST/ItaniumMangle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -594,10 +594,11 @@ class CXXNameMangler {
void mangleMemberExprBase(const Expr *base, bool isArrow);
void mangleMemberExpr(const Expr *base, bool isArrow,
NestedNameSpecifier *qualifier,
ArrayRef<DeclAccessPair> UnqualifiedLookups,
NamedDecl *firstQualifierLookup,
DeclarationName name,
const TemplateArgumentLoc *TemplateArgs,
unsigned NumTemplateArgs, unsigned knownArity);
unsigned NumTemplateArgs,
unsigned knownArity);
void mangleCastExpression(const Expr *E, StringRef CastEncoding);
void mangleInitListElements(const InitListExpr *InitList);
void mangleRequirement(SourceLocation RequiresExprLoc,
Expand Down Expand Up @@ -960,7 +961,7 @@ bool CXXNameMangler::isStd(const NamespaceDecl *NS) {
if (!Context.getEffectiveParentContext(NS)->isTranslationUnit())
return false;

const IdentifierInfo *II = NS->getOriginalNamespace()->getIdentifier();
const IdentifierInfo *II = NS->getFirstDecl()->getIdentifier();
return II && II->isStr("std");
}

Expand Down Expand Up @@ -4495,11 +4496,14 @@ void CXXNameMangler::mangleMemberExprBase(const Expr *Base, bool IsArrow) {
}

/// Mangles a member expression.
void CXXNameMangler::mangleMemberExpr(
const Expr *base, bool isArrow, NestedNameSpecifier *qualifier,
ArrayRef<DeclAccessPair> UnqualifiedLookups, DeclarationName member,
const TemplateArgumentLoc *TemplateArgs, unsigned NumTemplateArgs,
unsigned arity) {
void CXXNameMangler::mangleMemberExpr(const Expr *base,
bool isArrow,
NestedNameSpecifier *qualifier,
NamedDecl *firstQualifierLookup,
DeclarationName member,
const TemplateArgumentLoc *TemplateArgs,
unsigned NumTemplateArgs,
unsigned arity) {
// <expression> ::= dt <expression> <unresolved-name>
// ::= pt <expression> <unresolved-name>
if (base)
Expand Down Expand Up @@ -4981,19 +4985,22 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity,
case Expr::MemberExprClass: {
NotPrimaryExpr();
const MemberExpr *ME = cast<MemberExpr>(E);
mangleMemberExpr(ME->getBase(), ME->isArrow(), ME->getQualifier(),
std::nullopt, ME->getMemberDecl()->getDeclName(),
ME->getTemplateArgs(), ME->getNumTemplateArgs(), Arity);
mangleMemberExpr(ME->getBase(), ME->isArrow(),
ME->getQualifier(), nullptr,
ME->getMemberDecl()->getDeclName(),
ME->getTemplateArgs(), ME->getNumTemplateArgs(),
Arity);
break;
}

case Expr::UnresolvedMemberExprClass: {
NotPrimaryExpr();
const UnresolvedMemberExpr *ME = cast<UnresolvedMemberExpr>(E);
mangleMemberExpr(ME->isImplicitAccess() ? nullptr : ME->getBase(),
ME->isArrow(), ME->getQualifier(), std::nullopt,
ME->getMemberName(), ME->getTemplateArgs(),
ME->getNumTemplateArgs(), Arity);
ME->isArrow(), ME->getQualifier(), nullptr,
ME->getMemberName(),
ME->getTemplateArgs(), ME->getNumTemplateArgs(),
Arity);
break;
}

Expand All @@ -5003,8 +5010,10 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity,
= cast<CXXDependentScopeMemberExpr>(E);
mangleMemberExpr(ME->isImplicitAccess() ? nullptr : ME->getBase(),
ME->isArrow(), ME->getQualifier(),
ME->unqualified_lookups(), ME->getMember(),
ME->getTemplateArgs(), ME->getNumTemplateArgs(), Arity);
ME->getFirstQualifierFoundInScope(),
ME->getMember(),
ME->getTemplateArgs(), ME->getNumTemplateArgs(),
Arity);
break;
}

Expand Down
5 changes: 2 additions & 3 deletions clang/lib/AST/JSONNodeDumper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -883,9 +883,8 @@ void JSONNodeDumper::VisitNamespaceDecl(const NamespaceDecl *ND) {
VisitNamedDecl(ND);
attributeOnlyIfTrue("isInline", ND->isInline());
attributeOnlyIfTrue("isNested", ND->isNested());
if (!ND->isOriginalNamespace())
JOS.attribute("originalNamespace",
createBareDeclRef(ND->getOriginalNamespace()));
if (!ND->isFirstDecl())
JOS.attribute("originalNamespace", createBareDeclRef(ND->getFirstDecl()));
}

void JSONNodeDumper::VisitUsingDirectiveDecl(const UsingDirectiveDecl *UDD) {
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/AST/TextNodeDumper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2386,8 +2386,8 @@ void TextNodeDumper::VisitNamespaceDecl(const NamespaceDecl *D) {
OS << " inline";
if (D->isNested())
OS << " nested";
if (!D->isOriginalNamespace())
dumpDeclRef(D->getOriginalNamespace(), "original");
if (!D->isFirstDecl())
dumpDeclRef(D->getFirstDecl(), "original");
}

void TextNodeDumper::VisitUsingDirectiveDecl(const UsingDirectiveDecl *D) {
Expand Down
6 changes: 3 additions & 3 deletions clang/lib/Basic/Targets/RISCV.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ void RISCVTargetInfo::getTargetDefines(const LangOptions &Opts,
Builder.defineMacro("__riscv_v_fixed_vlen",
Twine(VScale->first * llvm::RISCV::RVVBitsPerBlock));

if (FastUnalignedAccess)
if (FastScalarUnalignedAccess)
Builder.defineMacro("__riscv_misaligned_fast");
else
Builder.defineMacro("__riscv_misaligned_avoid");
Expand Down Expand Up @@ -353,8 +353,8 @@ bool RISCVTargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
if (ISAInfo->hasExtension("zfh") || ISAInfo->hasExtension("zhinx"))
HasLegalHalfType = true;

FastUnalignedAccess = llvm::is_contained(Features, "+unaligned-scalar-mem") &&
llvm::is_contained(Features, "+unaligned-vector-mem");
FastScalarUnalignedAccess =
llvm::is_contained(Features, "+unaligned-scalar-mem");

if (llvm::is_contained(Features, "+experimental"))
HasExperimental = true;
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Basic/Targets/RISCV.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ class RISCVTargetInfo : public TargetInfo {
std::unique_ptr<llvm::RISCVISAInfo> ISAInfo;

private:
bool FastUnalignedAccess;
bool FastScalarUnalignedAccess;
bool HasExperimental = false;

public:
Expand Down
29 changes: 5 additions & 24 deletions clang/lib/Basic/Targets/X86.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,9 @@ bool X86TargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
if (Feature[0] != '+')
continue;

if (Feature == "+aes") {
if (Feature == "+mmx") {
HasMMX = true;
} else if (Feature == "+aes") {
HasAES = true;
} else if (Feature == "+vaes") {
HasVAES = true;
Expand Down Expand Up @@ -487,13 +489,6 @@ bool X86TargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
// for bfloat16 arithmetic operations in the front-end.
HasBFloat16 = SSELevel >= SSE2;

MMX3DNowEnum ThreeDNowLevel = llvm::StringSwitch<MMX3DNowEnum>(Feature)
.Case("+3dnowa", AMD3DNowAthlon)
.Case("+3dnow", AMD3DNow)
.Case("+mmx", MMX)
.Default(NoMMX3DNow);
MMX3DNowLevel = std::max(MMX3DNowLevel, ThreeDNowLevel);

XOPEnum XLevel = llvm::StringSwitch<XOPEnum>(Feature)
.Case("+xop", XOP)
.Case("+fma4", FMA4)
Expand Down Expand Up @@ -1031,18 +1026,8 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts,
}

// Each case falls through to the previous one here.
switch (MMX3DNowLevel) {
case AMD3DNowAthlon:
Builder.defineMacro("__3dNOW_A__");
[[fallthrough]];
case AMD3DNow:
Builder.defineMacro("__3dNOW__");
[[fallthrough]];
case MMX:
if (HasMMX) {
Builder.defineMacro("__MMX__");
[[fallthrough]];
case NoMMX3DNow:
break;
}

if (CPU >= CK_i486 || CPU == CK_None) {
Expand All @@ -1061,8 +1046,6 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts,

bool X86TargetInfo::isValidFeatureName(StringRef Name) const {
return llvm::StringSwitch<bool>(Name)
.Case("3dnow", true)
.Case("3dnowa", true)
.Case("adx", true)
.Case("aes", true)
.Case("amx-bf16", true)
Expand Down Expand Up @@ -1232,9 +1215,7 @@ bool X86TargetInfo::hasFeature(StringRef Feature) const {
.Case("widekl", HasWIDEKL)
.Case("lwp", HasLWP)
.Case("lzcnt", HasLZCNT)
.Case("mm3dnow", MMX3DNowLevel >= AMD3DNow)
.Case("mm3dnowa", MMX3DNowLevel >= AMD3DNowAthlon)
.Case("mmx", MMX3DNowLevel >= MMX)
.Case("mmx", HasMMX)
.Case("movbe", HasMOVBE)
.Case("movdiri", HasMOVDIRI)
.Case("movdir64b", HasMOVDIR64B)
Expand Down
10 changes: 2 additions & 8 deletions clang/lib/Basic/Targets/X86.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,12 +67,7 @@ class LLVM_LIBRARY_VISIBILITY X86TargetInfo : public TargetInfo {
AVX2,
AVX512F
} SSELevel = NoSSE;
enum MMX3DNowEnum {
NoMMX3DNow,
MMX,
AMD3DNow,
AMD3DNowAthlon
} MMX3DNowLevel = NoMMX3DNow;
bool HasMMX = false;
enum XOPEnum { NoXOP, SSE4A, FMA4, XOP } XOPLevel = NoXOP;
enum AddrSpace { ptr32_sptr = 270, ptr32_uptr = 271, ptr64 = 272 };

Expand Down Expand Up @@ -348,8 +343,7 @@ class LLVM_LIBRARY_VISIBILITY X86TargetInfo : public TargetInfo {
return "avx512";
if (getTriple().getArch() == llvm::Triple::x86_64 && SSELevel >= AVX)
return "avx";
if (getTriple().getArch() == llvm::Triple::x86 &&
MMX3DNowLevel == NoMMX3DNow)
if (getTriple().getArch() == llvm::Triple::x86 && !HasMMX)
return "no-mmx";
return "";
}
Expand Down
35 changes: 35 additions & 0 deletions clang/lib/CodeGen/ABIInfoImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,41 @@ bool CodeGen::isEmptyRecord(ASTContext &Context, QualType T, bool AllowArrays,
return true;
}

bool CodeGen::isEmptyFieldForLayout(const ASTContext &Context,
const FieldDecl *FD) {
if (FD->isZeroLengthBitField(Context))
return true;

if (FD->isUnnamedBitField())
return false;

return isEmptyRecordForLayout(Context, FD->getType());
}

bool CodeGen::isEmptyRecordForLayout(const ASTContext &Context, QualType T) {
const RecordType *RT = T->getAs<RecordType>();
if (!RT)
return false;

const RecordDecl *RD = RT->getDecl();

// If this is a C++ record, check the bases first.
if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD)) {
if (CXXRD->isDynamicClass())
return false;

for (const auto &I : CXXRD->bases())
if (!isEmptyRecordForLayout(Context, I.getType()))
return false;
}

for (const auto *I : RD->fields())
if (!isEmptyFieldForLayout(Context, I))
return false;

return true;
}

const Type *CodeGen::isSingleElementStruct(QualType T, ASTContext &Context) {
const RecordType *RT = T->getAs<RecordType>();
if (!RT)
Expand Down
10 changes: 10 additions & 0 deletions clang/lib/CodeGen/ABIInfoImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,16 @@ bool isEmptyField(ASTContext &Context, const FieldDecl *FD, bool AllowArrays,
bool isEmptyRecord(ASTContext &Context, QualType T, bool AllowArrays,
bool AsIfNoUniqueAddr = false);

/// isEmptyFieldForLayout - Return true iff the field is "empty", that is,
/// either a zero-width bit-field or an \ref isEmptyRecordForLayout.
bool isEmptyFieldForLayout(const ASTContext &Context, const FieldDecl *FD);

/// isEmptyRecordForLayout - Return true iff a structure contains only empty
/// base classes (per \ref isEmptyRecordForLayout) and fields (per
/// \ref isEmptyFieldForLayout). Note, C++ record fields are considered empty
/// if the [[no_unique_address]] attribute would have made them empty.
bool isEmptyRecordForLayout(const ASTContext &Context, QualType T);

/// isSingleElementStruct - Determine if a structure is a "single
/// element struct", i.e. it has exactly one non-empty field or
/// exactly one field which is itself a single element
Expand Down
22 changes: 7 additions & 15 deletions clang/lib/CodeGen/CGBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2587,6 +2587,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
case Builtin::BI__builtin_fma:
case Builtin::BI__builtin_fmaf:
case Builtin::BI__builtin_fmal:
case Builtin::BI__builtin_fmaf16:
case Builtin::BIfma:
case Builtin::BIfmaf:
case Builtin::BIfmal: {
Expand Down Expand Up @@ -15968,14 +15969,6 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
return Builder.CreateCall(F, {Ops[0]});
}

// 3DNow!
case X86::BI__builtin_ia32_pswapdsf:
case X86::BI__builtin_ia32_pswapdsi: {
llvm::Type *MMXTy = llvm::Type::getX86_MMXTy(getLLVMContext());
Ops[0] = Builder.CreateBitCast(Ops[0], MMXTy, "cast");
llvm::Function *F = CGM.getIntrinsic(Intrinsic::x86_3dnowa_pswapd);
return Builder.CreateCall(F, Ops, "pswapd");
}
case X86::BI__builtin_ia32_rdrand16_step:
case X86::BI__builtin_ia32_rdrand32_step:
case X86::BI__builtin_ia32_rdrand64_step:
Expand Down Expand Up @@ -18388,13 +18381,12 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID,
llvm_unreachable("rcp operand must have a float representation");
llvm::Type *Ty = Op0->getType();
llvm::Type *EltTy = Ty->getScalarType();
Constant *One =
Ty->isVectorTy()
? ConstantVector::getSplat(
ElementCount::getFixed(
dyn_cast<FixedVectorType>(Ty)->getNumElements()),
ConstantFP::get(EltTy, 1.0))
: ConstantFP::get(EltTy, 1.0);
Constant *One = Ty->isVectorTy()
? ConstantVector::getSplat(
ElementCount::getFixed(
cast<FixedVectorType>(Ty)->getNumElements()),
ConstantFP::get(EltTy, 1.0))
: ConstantFP::get(EltTy, 1.0);
return Builder.CreateFDiv(One, Op0, "hlsl.rcp");
}
case Builtin::BI__builtin_hlsl_elementwise_rsqrt: {
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/CodeGen/CGCall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3863,7 +3863,8 @@ void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI,
LValue ArgVal =
LValue::MakeAddr(ArgAddr, RetTy, getContext(), BaseInfo, TBAAInfo);
EmitStoreOfScalar(
Builder.CreateLoad(ReturnValue), ArgVal, /*isInit*/ true);
EmitLoadOfScalar(MakeAddrLValue(ReturnValue, RetTy), EndLoc), ArgVal,
/*isInit*/ true);
break;
}
}
Expand Down
5 changes: 3 additions & 2 deletions clang/lib/CodeGen/CGClass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
//
//===----------------------------------------------------------------------===//

#include "ABIInfoImpl.h"
#include "CGBlocks.h"
#include "CGCXXABI.h"
#include "CGDebugInfo.h"
Expand Down Expand Up @@ -933,7 +934,7 @@ namespace {
}

void addMemcpyableField(FieldDecl *F) {
if (F->isZeroSize(CGF.getContext()))
if (isEmptyFieldForLayout(CGF.getContext(), F))
return;
if (!FirstField)
addInitialField(F);
Expand Down Expand Up @@ -1815,7 +1816,7 @@ namespace {
const CXXDestructorDecl *DD)
: Context(Context), EHStack(EHStack), DD(DD), StartIndex(std::nullopt) {}
void PushCleanupForField(const FieldDecl *Field) {
if (Field->isZeroSize(Context))
if (isEmptyFieldForLayout(Context, Field))
return;
unsigned FieldIndex = Field->getFieldIndex();
if (FieldHasTrivialDestructorBody(Context, Field)) {
Expand Down
12 changes: 12 additions & 0 deletions clang/lib/CodeGen/CGDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#include "clang/Basic/TargetInfo.h"
#include "clang/CodeGen/CGFunctionInfo.h"
#include "clang/Sema/Sema.h"
#include "llvm/Analysis/ConstantFolding.h"
#include "llvm/Analysis/ValueTracking.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/GlobalVariable.h"
Expand Down Expand Up @@ -1969,6 +1970,17 @@ void CodeGenFunction::EmitAutoVarInit(const AutoVarEmission &emission) {
constant = constWithPadding(CGM, IsPattern::No,
replaceUndef(CGM, isPattern, constant));
}

if (D.getType()->isBitIntType() &&
CGM.getTypes().typeRequiresSplitIntoByteArray(D.getType())) {
// Constants for long _BitInt types are split into individual bytes.
// Try to fold these back into an integer constant so it can be stored
// properly.
llvm::Type *LoadType = CGM.getTypes().convertTypeForLoadStore(
D.getType(), constant->getType());
constant = llvm::ConstantFoldLoadFromConst(
constant, LoadType, llvm::APInt::getZero(32), CGM.getDataLayout());
}
}

if (!constant) {
Expand Down
67 changes: 38 additions & 29 deletions clang/lib/CodeGen/CGExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
//
//===----------------------------------------------------------------------===//

#include "ABIInfoImpl.h"
#include "CGCUDARuntime.h"
#include "CGCXXABI.h"
#include "CGCall.h"
Expand Down Expand Up @@ -1986,6 +1987,9 @@ llvm::Value *CodeGenFunction::EmitLoadOfScalar(Address Addr, bool Volatile,
return EmitAtomicLoad(AtomicLValue, Loc).getScalarVal();
}

Addr =
Addr.withElementType(convertTypeForLoadStore(Ty, Addr.getElementType()));

llvm::LoadInst *Load = Builder.CreateLoad(Addr, Volatile);
if (isNontemporal) {
llvm::MDNode *Node = llvm::MDNode::get(
Expand All @@ -2008,27 +2012,33 @@ llvm::Value *CodeGenFunction::EmitLoadOfScalar(Address Addr, bool Volatile,
return EmitFromMemory(Load, Ty);
}

/// Converts a scalar value from its primary IR type (as returned
/// by ConvertType) to its load/store type (as returned by
/// convertTypeForLoadStore).
llvm::Value *CodeGenFunction::EmitToMemory(llvm::Value *Value, QualType Ty) {
// Bool has a different representation in memory than in registers.
if (hasBooleanRepresentation(Ty)) {
// This should really always be an i1, but sometimes it's already
// an i8, and it's awkward to track those cases down.
if (Value->getType()->isIntegerTy(1))
return Builder.CreateZExt(Value, ConvertTypeForMem(Ty), "frombool");
assert(Value->getType()->isIntegerTy(getContext().getTypeSize(Ty)) &&
"wrong value rep of bool");
if (hasBooleanRepresentation(Ty) || Ty->isBitIntType()) {
llvm::Type *StoreTy = convertTypeForLoadStore(Ty, Value->getType());
bool Signed = Ty->isSignedIntegerOrEnumerationType();
return Builder.CreateIntCast(Value, StoreTy, Signed, "storedv");
}

if (Ty->isExtVectorBoolType()) {
llvm::Type *StoreTy = convertTypeForLoadStore(Ty, Value->getType());
// Expand to the memory bit width.
unsigned MemNumElems = StoreTy->getPrimitiveSizeInBits();
// <N x i1> --> <P x i1>.
Value = emitBoolVecConversion(Value, MemNumElems, "insertvec");
// <P x i1> --> iP.
Value = Builder.CreateBitCast(Value, StoreTy);
}

return Value;
}

/// Converts a scalar value from its load/store type (as returned
/// by convertTypeForLoadStore) to its primary IR type (as returned
/// by ConvertType).
llvm::Value *CodeGenFunction::EmitFromMemory(llvm::Value *Value, QualType Ty) {
// Bool has a different representation in memory than in registers.
if (hasBooleanRepresentation(Ty)) {
assert(Value->getType()->isIntegerTy(getContext().getTypeSize(Ty)) &&
"wrong value rep of bool");
return Builder.CreateTrunc(Value, Builder.getInt1Ty(), "tobool");
}
if (Ty->isExtVectorBoolType()) {
const auto *RawIntTy = Value->getType();
// Bitcast iP --> <P x i1>.
Expand All @@ -2041,6 +2051,11 @@ llvm::Value *CodeGenFunction::EmitFromMemory(llvm::Value *Value, QualType Ty) {
return emitBoolVecConversion(V, ValNumElems, "extractvec");
}

if (hasBooleanRepresentation(Ty) || Ty->isBitIntType()) {
llvm::Type *ResTy = ConvertType(Ty);
return Builder.CreateTrunc(Value, ResTy, "loadedv");
}

return Value;
}

Expand Down Expand Up @@ -2093,17 +2108,10 @@ void CodeGenFunction::EmitStoreOfScalar(llvm::Value *Value, Address Addr,
llvm::Type *SrcTy = Value->getType();
if (const auto *ClangVecTy = Ty->getAs<VectorType>()) {
auto *VecTy = dyn_cast<llvm::FixedVectorType>(SrcTy);
if (VecTy && ClangVecTy->isExtVectorBoolType()) {
auto *MemIntTy = cast<llvm::IntegerType>(Addr.getElementType());
// Expand to the memory bit width.
unsigned MemNumElems = MemIntTy->getPrimitiveSizeInBits();
// <N x i1> --> <P x i1>.
Value = emitBoolVecConversion(Value, MemNumElems, "insertvec");
// <P x i1> --> iP.
Value = Builder.CreateBitCast(Value, MemIntTy);
} else if (!CGM.getCodeGenOpts().PreserveVec3Type) {
if (!CGM.getCodeGenOpts().PreserveVec3Type) {
// Handle vec3 special.
if (VecTy && cast<llvm::FixedVectorType>(VecTy)->getNumElements() == 3) {
if (VecTy && !ClangVecTy->isExtVectorBoolType() &&
cast<llvm::FixedVectorType>(VecTy)->getNumElements() == 3) {
// Our source is a vec3, do a shuffle vector to make it a vec4.
Value = Builder.CreateShuffleVector(Value, ArrayRef<int>{0, 1, 2, -1},
"extractVec");
Expand Down Expand Up @@ -2477,7 +2485,7 @@ void CodeGenFunction::EmitStoreThroughLValue(RValue Src, LValue Dst,
void CodeGenFunction::EmitStoreThroughBitfieldLValue(RValue Src, LValue Dst,
llvm::Value **Result) {
const CGBitFieldInfo &Info = Dst.getBitFieldInfo();
llvm::Type *ResLTy = ConvertTypeForMem(Dst.getType());
llvm::Type *ResLTy = convertTypeForLoadStore(Dst.getType());
Address Ptr = Dst.getBitFieldAddress();

// Get the source value, truncated to the width of the bit-field.
Expand Down Expand Up @@ -3842,9 +3850,10 @@ void CodeGenFunction::EmitTrapCheck(llvm::Value *Checked,

llvm::CallInst *TrapCall = Builder.CreateCall(
CGM.getIntrinsic(llvm::Intrinsic::ubsantrap),
llvm::ConstantInt::get(CGM.Int8Ty, ClSanitizeDebugDeoptimization
? TrapBB->getParent()->size()
: CheckHandlerID));
llvm::ConstantInt::get(CGM.Int8Ty,
ClSanitizeDebugDeoptimization
? TrapBB->getParent()->size()
: static_cast<uint64_t>(CheckHandlerID)));

if (!CGM.getCodeGenOpts().TrapFuncName.empty()) {
auto A = llvm::Attribute::get(getLLVMContext(), "trap-func-name",
Expand Down Expand Up @@ -4749,7 +4758,7 @@ static Address emitAddrOfZeroSizeField(CodeGenFunction &CGF, Address Base,
/// The resulting address doesn't necessarily have the right type.
static Address emitAddrOfFieldStorage(CodeGenFunction &CGF, Address base,
const FieldDecl *field) {
if (field->isZeroSize(CGF.getContext()))
if (isEmptyFieldForLayout(CGF.getContext(), field))
return emitAddrOfZeroSizeField(CGF, base, field);

const RecordDecl *rec = field->getParent();
Expand Down
74 changes: 55 additions & 19 deletions clang/lib/CodeGen/CGExprConstant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
//
//===----------------------------------------------------------------------===//

#include "ABIInfoImpl.h"
#include "CGCXXABI.h"
#include "CGObjCRuntime.h"
#include "CGRecordLayout.h"
Expand Down Expand Up @@ -585,7 +586,7 @@ class ConstStructBuilder {
bool AllowOverwrite = false);

bool AppendBitField(const FieldDecl *Field, uint64_t FieldOffset,
llvm::ConstantInt *InitExpr, bool AllowOverwrite = false);
llvm::Constant *InitExpr, bool AllowOverwrite = false);

bool Build(const InitListExpr *ILE, bool AllowOverwrite);
bool Build(const APValue &Val, const RecordDecl *RD, bool IsPrimaryBase,
Expand All @@ -609,9 +610,25 @@ bool ConstStructBuilder::AppendBytes(CharUnits FieldOffsetInChars,
return Builder.add(InitCst, StartOffset + FieldOffsetInChars, AllowOverwrite);
}

bool ConstStructBuilder::AppendBitField(
const FieldDecl *Field, uint64_t FieldOffset, llvm::ConstantInt *CI,
bool AllowOverwrite) {
bool ConstStructBuilder::AppendBitField(const FieldDecl *Field,
uint64_t FieldOffset, llvm::Constant *C,
bool AllowOverwrite) {

llvm::ConstantInt *CI = dyn_cast<llvm::ConstantInt>(C);
if (!CI) {
// Constants for long _BitInt types are sometimes split into individual
// bytes. Try to fold these back into an integer constant. If that doesn't
// work out, then we are trying to initialize a bitfield with a non-trivial
// constant, this must require run-time code.
llvm::Type *LoadType =
CGM.getTypes().convertTypeForLoadStore(Field->getType(), C->getType());
llvm::Constant *FoldedConstant = llvm::ConstantFoldLoadFromConst(
C, LoadType, llvm::APInt::getZero(32), CGM.getDataLayout());
CI = dyn_cast_if_present<llvm::ConstantInt>(FoldedConstant);
if (!CI)
return false;
}

const CGRecordLayout &RL =
CGM.getTypes().getCGRecordLayout(Field->getParent());
const CGBitFieldInfo &Info = RL.getBitFieldInfo(Field);
Expand Down Expand Up @@ -720,7 +737,7 @@ bool ConstStructBuilder::Build(const InitListExpr *ILE, bool AllowOverwrite) {

// Zero-sized fields are not emitted, but their initializers may still
// prevent emission of this struct as a constant.
if (Field->isZeroSize(CGM.getContext())) {
if (isEmptyFieldForLayout(CGM.getContext(), Field)) {
if (Init->HasSideEffects(CGM.getContext()))
return false;
continue;
Expand Down Expand Up @@ -762,15 +779,9 @@ bool ConstStructBuilder::Build(const InitListExpr *ILE, bool AllowOverwrite) {
AllowOverwrite = true;
} else {
// Otherwise we have a bitfield.
if (auto *CI = dyn_cast<llvm::ConstantInt>(EltInit)) {
if (!AppendBitField(Field, Layout.getFieldOffset(FieldNo), CI,
AllowOverwrite))
return false;
} else {
// We are trying to initialize a bitfield with a non-trivial constant,
// this must require run-time code.
if (!AppendBitField(Field, Layout.getFieldOffset(FieldNo), EltInit,
AllowOverwrite))
return false;
}
}
}

Expand Down Expand Up @@ -848,7 +859,8 @@ bool ConstStructBuilder::Build(const APValue &Val, const RecordDecl *RD,
continue;

// Don't emit anonymous bitfields or zero-sized fields.
if (Field->isUnnamedBitField() || Field->isZeroSize(CGM.getContext()))
if (Field->isUnnamedBitField() ||
isEmptyFieldForLayout(CGM.getContext(), *Field))
continue;

// Emit the value of the initializer.
Expand All @@ -871,7 +883,7 @@ bool ConstStructBuilder::Build(const APValue &Val, const RecordDecl *RD,
} else {
// Otherwise we have a bitfield.
if (!AppendBitField(*Field, Layout.getFieldOffset(FieldNo) + OffsetBits,
cast<llvm::ConstantInt>(EltInit), AllowOverwrite))
EltInit, AllowOverwrite))
return false;
}
}
Expand Down Expand Up @@ -1888,6 +1900,27 @@ llvm::Constant *ConstantEmitter::emitForMemory(CodeGenModule &CGM,
return Res;
}

if (destType->isBitIntType()) {
ConstantAggregateBuilder Builder(CGM);
llvm::Type *LoadStoreTy = CGM.getTypes().convertTypeForLoadStore(destType);
// ptrtoint/inttoptr should not involve _BitInt in constant expressions, so
// casting to ConstantInt is safe here.
auto *CI = cast<llvm::ConstantInt>(C);
llvm::Constant *Res = llvm::ConstantFoldCastOperand(
destType->isSignedIntegerOrEnumerationType() ? llvm::Instruction::SExt
: llvm::Instruction::ZExt,
CI, LoadStoreTy, CGM.getDataLayout());
if (CGM.getTypes().typeRequiresSplitIntoByteArray(destType, C->getType())) {
// Long _BitInt has array of bytes as in-memory type.
// So, split constant into individual bytes.
llvm::Type *DesiredTy = CGM.getTypes().ConvertTypeForMem(destType);
llvm::APInt Value = cast<llvm::ConstantInt>(Res)->getValue();
Builder.addBits(Value, /*OffsetInBits=*/0, /*AllowOverwrite=*/false);
return Builder.build(DesiredTy, /*AllowOversized*/ false);
}
return Res;
}

return C;
}

Expand Down Expand Up @@ -2495,8 +2528,10 @@ static llvm::Constant *EmitNullConstant(CodeGenModule &CGM,
cast<CXXRecordDecl>(I.getType()->castAs<RecordType>()->getDecl());

// Ignore empty bases.
if (base->isEmpty() ||
CGM.getContext().getASTRecordLayout(base).getNonVirtualSize()
if (isEmptyRecordForLayout(CGM.getContext(), I.getType()) ||
CGM.getContext()
.getASTRecordLayout(base)
.getNonVirtualSize()
.isZero())
continue;

Expand All @@ -2510,7 +2545,8 @@ static llvm::Constant *EmitNullConstant(CodeGenModule &CGM,
for (const auto *Field : record->fields()) {
// Fill in non-bitfields. (Bitfields always use a zero pattern, which we
// will fill in later.)
if (!Field->isBitField() && !Field->isZeroSize(CGM.getContext())) {
if (!Field->isBitField() &&
!isEmptyFieldForLayout(CGM.getContext(), Field)) {
unsigned fieldIndex = layout.getLLVMFieldNo(Field);
elements[fieldIndex] = CGM.EmitNullConstant(Field->getType());
}
Expand All @@ -2532,7 +2568,7 @@ static llvm::Constant *EmitNullConstant(CodeGenModule &CGM,
cast<CXXRecordDecl>(I.getType()->castAs<RecordType>()->getDecl());

// Ignore empty bases.
if (base->isEmpty())
if (isEmptyRecordForLayout(CGM.getContext(), I.getType()))
continue;

unsigned fieldIndex = layout.getVirtualBaseIndex(base);
Expand Down
7 changes: 4 additions & 3 deletions clang/lib/CodeGen/CGExprScalar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -436,9 +436,10 @@ class ScalarExprEmitter

if (Value *Result = ConstantEmitter(CGF).tryEmitConstantExpr(E)) {
if (E->isGLValue())
return CGF.Builder.CreateLoad(Address(
Result, CGF.ConvertTypeForMem(E->getType()),
CGF.getContext().getTypeAlignInChars(E->getType())));
return CGF.EmitLoadOfScalar(
Address(Result, CGF.convertTypeForLoadStore(E->getType()),
CGF.getContext().getTypeAlignInChars(E->getType())),
/*Volatile*/ false, E->getType(), E->getExprLoc());
return Result;
}
return Visit(E->getSubExpr());
Expand Down
23 changes: 15 additions & 8 deletions clang/lib/CodeGen/CGOpenMPRuntime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
//===----------------------------------------------------------------------===//

#include "CGOpenMPRuntime.h"
#include "ABIInfoImpl.h"
#include "CGCXXABI.h"
#include "CGCleanup.h"
#include "CGRecordLayout.h"
Expand Down Expand Up @@ -7729,23 +7730,28 @@ class MappableExprsHandler {
for (const auto &I : RD->bases()) {
if (I.isVirtual())
continue;
const auto *Base = I.getType()->getAsCXXRecordDecl();

QualType BaseTy = I.getType();
const auto *Base = BaseTy->getAsCXXRecordDecl();
// Ignore empty bases.
if (Base->isEmpty() || CGF.getContext()
.getASTRecordLayout(Base)
.getNonVirtualSize()
.isZero())
if (isEmptyRecordForLayout(CGF.getContext(), BaseTy) ||
CGF.getContext()
.getASTRecordLayout(Base)
.getNonVirtualSize()
.isZero())
continue;

unsigned FieldIndex = RL.getNonVirtualBaseLLVMFieldNo(Base);
RecordLayout[FieldIndex] = Base;
}
// Fill in virtual bases.
for (const auto &I : RD->vbases()) {
const auto *Base = I.getType()->getAsCXXRecordDecl();
QualType BaseTy = I.getType();
// Ignore empty bases.
if (Base->isEmpty())
if (isEmptyRecordForLayout(CGF.getContext(), BaseTy))
continue;

const auto *Base = BaseTy->getAsCXXRecordDecl();
unsigned FieldIndex = RL.getVirtualBaseIndex(Base);
if (RecordLayout[FieldIndex])
continue;
Expand All @@ -7756,7 +7762,8 @@ class MappableExprsHandler {
for (const auto *Field : RD->fields()) {
// Fill in non-bitfields. (Bitfields always use a zero pattern, which we
// will fill in later.)
if (!Field->isBitField() && !Field->isZeroSize(CGF.getContext())) {
if (!Field->isBitField() &&
!isEmptyFieldForLayout(CGF.getContext(), Field)) {
unsigned FieldIndex = RL.getLLVMFieldNo(Field);
RecordLayout[FieldIndex] = Field;
}
Expand Down
18 changes: 9 additions & 9 deletions clang/lib/CodeGen/CGRecordLayoutBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@
//
//===----------------------------------------------------------------------===//

#include "CGRecordLayout.h"
#include "ABIInfoImpl.h"
#include "CGCXXABI.h"
#include "CGRecordLayout.h"
#include "CodeGenTypes.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Attr.h"
Expand Down Expand Up @@ -384,7 +385,7 @@ void CGRecordLowering::accumulateFields(bool isNonVirtualBaseType) {
Field = accumulateBitFields(isNonVirtualBaseType, Field, FieldEnd);
assert((Field == FieldEnd || !Field->isBitField()) &&
"Failed to accumulate all the bitfields");
} else if (Field->isZeroSize(Context)) {
} else if (isEmptyFieldForLayout(Context, *Field)) {
// Empty fields have no storage.
++Field;
} else {
Expand Down Expand Up @@ -427,8 +428,7 @@ CGRecordLowering::accumulateBitFields(bool isNonVirtualBaseType,
continue;
}
uint64_t BitOffset = getFieldBitOffset(*Field);
llvm::Type *Type =
Types.ConvertTypeForMem(Field->getType(), /*ForBitField=*/true);
llvm::Type *Type = Types.ConvertTypeForMem(Field->getType());
// If we don't have a run yet, or don't live within the previous run's
// allocated storage then we allocate some storage and start a new run.
if (Run == FieldEnd || BitOffset >= Tail) {
Expand Down Expand Up @@ -634,7 +634,7 @@ CGRecordLowering::accumulateBitFields(bool isNonVirtualBaseType,
// non-reusable tail padding.
CharUnits LimitOffset;
for (auto Probe = Field; Probe != FieldEnd; ++Probe)
if (!Probe->isZeroSize(Context)) {
if (!isEmptyFieldForLayout(Context, *Probe)) {
// A member with storage sets the limit.
assert((getFieldBitOffset(*Probe) % CharBits) == 0 &&
"Next storage is not byte-aligned");
Expand Down Expand Up @@ -732,7 +732,7 @@ void CGRecordLowering::accumulateBases() {
// Bases can be zero-sized even if not technically empty if they
// contain only a trailing array member.
const CXXRecordDecl *BaseDecl = Base.getType()->getAsCXXRecordDecl();
if (!BaseDecl->isEmpty() &&
if (!isEmptyRecordForLayout(Context, Base.getType()) &&
!Context.getASTRecordLayout(BaseDecl).getNonVirtualSize().isZero())
Members.push_back(MemberInfo(Layout.getBaseClassOffset(BaseDecl),
MemberInfo::Base, getStorageType(BaseDecl), BaseDecl));
Expand Down Expand Up @@ -880,7 +880,7 @@ CGRecordLowering::calculateTailClippingOffset(bool isNonVirtualBaseType) const {
if (!isNonVirtualBaseType && isOverlappingVBaseABI())
for (const auto &Base : RD->vbases()) {
const CXXRecordDecl *BaseDecl = Base.getType()->getAsCXXRecordDecl();
if (BaseDecl->isEmpty())
if (isEmptyRecordForLayout(Context, Base.getType()))
continue;
// If the vbase is a primary virtual base of some base, then it doesn't
// get its own storage location but instead lives inside of that base.
Expand All @@ -896,7 +896,7 @@ CGRecordLowering::calculateTailClippingOffset(bool isNonVirtualBaseType) const {
void CGRecordLowering::accumulateVBases() {
for (const auto &Base : RD->vbases()) {
const CXXRecordDecl *BaseDecl = Base.getType()->getAsCXXRecordDecl();
if (BaseDecl->isEmpty())
if (isEmptyRecordForLayout(Context, Base.getType()))
continue;
CharUnits Offset = Layout.getVBaseClassOffset(BaseDecl);
// If the vbase is a primary virtual base of some base, then it doesn't
Expand Down Expand Up @@ -1162,7 +1162,7 @@ CodeGenTypes::ComputeRecordLayout(const RecordDecl *D, llvm::StructType *Ty) {
const FieldDecl *FD = *it;

// Ignore zero-sized fields.
if (FD->isZeroSize(getContext()))
if (isEmptyFieldForLayout(getContext(), FD))
continue;

// For non-bit-fields, just check that the LLVM struct offset matches the
Expand Down
10 changes: 8 additions & 2 deletions clang/lib/CodeGen/CGStmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1537,9 +1537,15 @@ void CodeGenFunction::EmitReturnStmt(const ReturnStmt &S) {
Builder.CreateStore(Result.getScalarVal(), ReturnValue);
} else {
switch (getEvaluationKind(RV->getType())) {
case TEK_Scalar:
Builder.CreateStore(EmitScalarExpr(RV), ReturnValue);
case TEK_Scalar: {
llvm::Value *Ret = EmitScalarExpr(RV);
if (CurFnInfo->getReturnInfo().getKind() == ABIArgInfo::Indirect)
EmitStoreOfScalar(Ret, MakeAddrLValue(ReturnValue, RV->getType()),
/*isInit*/ true);
else
Builder.CreateStore(Ret, ReturnValue);
break;
}
case TEK_Complex:
EmitComplexExprIntoLValue(RV, MakeAddrLValue(ReturnValue, RV->getType()),
/*isInit*/ true);
Expand Down
5 changes: 5 additions & 0 deletions clang/lib/CodeGen/CodeGenFunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,11 @@ llvm::Type *CodeGenFunction::ConvertType(QualType T) {
return CGM.getTypes().ConvertType(T);
}

llvm::Type *CodeGenFunction::convertTypeForLoadStore(QualType ASTTy,
llvm::Type *LLVMTy) {
return CGM.getTypes().convertTypeForLoadStore(ASTTy, LLVMTy);
}

TypeEvaluationKind CodeGenFunction::getEvaluationKind(QualType type) {
type = type.getCanonicalType();
while (true) {
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/CodeGen/CodeGenFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -2576,6 +2576,8 @@ class CodeGenFunction : public CodeGenTypeCache {

llvm::Type *ConvertTypeForMem(QualType T);
llvm::Type *ConvertType(QualType T);
llvm::Type *convertTypeForLoadStore(QualType ASTTy,
llvm::Type *LLVMTy = nullptr);
llvm::Type *ConvertType(const TypeDecl *T) {
return ConvertType(getContext().getTypeDeclType(T));
}
Expand Down
17 changes: 11 additions & 6 deletions clang/lib/CodeGen/CodeGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -721,6 +721,11 @@ void CodeGenModule::checkAliases() {
cast<llvm::GlobalAlias>(Alias)->setAliasee(Aliasee);
}
}
// ifunc resolvers are usually implemented to run before sanitizer
// initialization. Disable instrumentation to prevent the ordering issue.
if (IsIFunc)
cast<llvm::Function>(Aliasee)->addFnAttr(
llvm::Attribute::DisableSanitizerInstrumentation);
}
if (!Error)
return;
Expand Down Expand Up @@ -6106,11 +6111,14 @@ void CodeGenModule::emitIFuncDefinition(GlobalDecl GD) {

Aliases.push_back(GD);

llvm::Type *DeclTy = getTypes().ConvertTypeForMem(D->getType());
llvm::Type *ResolverTy = llvm::GlobalIFunc::getResolverFunctionType(DeclTy);
// The resolver might not be visited yet. Specify a dummy non-function type to
// indicate IsIncompleteFunction. Either the type is ignored (if the resolver
// was emitted) or the whole function will be replaced (if the resolver has
// not been emitted).
llvm::Constant *Resolver =
GetOrCreateLLVMFunction(IFA->getResolver(), ResolverTy, {},
GetOrCreateLLVMFunction(IFA->getResolver(), VoidTy, {},
/*ForVTable=*/false);
llvm::Type *DeclTy = getTypes().ConvertTypeForMem(D->getType());
llvm::GlobalIFunc *GIF =
llvm::GlobalIFunc::create(DeclTy, 0, llvm::Function::ExternalLinkage,
"", Resolver, &getModule());
Expand All @@ -6134,9 +6142,6 @@ void CodeGenModule::emitIFuncDefinition(GlobalDecl GD) {
Entry->eraseFromParent();
} else
GIF->setName(MangledName);
if (auto *F = dyn_cast<llvm::Function>(Resolver)) {
F->addFnAttr(llvm::Attribute::DisableSanitizerInstrumentation);
}
SetCommonAttributes(GD, GIF);
}

Expand Down
3 changes: 2 additions & 1 deletion clang/lib/CodeGen/CodeGenTBAA.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
//===----------------------------------------------------------------------===//

#include "CodeGenTBAA.h"
#include "ABIInfoImpl.h"
#include "CGRecordLayout.h"
#include "CodeGenTypes.h"
#include "clang/AST/ASTContext.h"
Expand Down Expand Up @@ -309,7 +310,7 @@ CodeGenTBAA::CollectFields(uint64_t BaseOffset,
unsigned idx = 0;
for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end();
i != e; ++i, ++idx) {
if ((*i)->isZeroSize(Context))
if (isEmptyFieldForLayout(Context, *i))
continue;

uint64_t Offset =
Expand Down
65 changes: 60 additions & 5 deletions clang/lib/CodeGen/CodeGenTypes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,14 @@ void CodeGenTypes::addRecordTypeName(const RecordDecl *RD,
/// ConvertType in that it is used to convert to the memory representation for
/// a type. For example, the scalar representation for _Bool is i1, but the
/// memory representation is usually i8 or i32, depending on the target.
llvm::Type *CodeGenTypes::ConvertTypeForMem(QualType T, bool ForBitField) {
///
/// We generally assume that the alloc size of this type under the LLVM
/// data layout is the same as the size of the AST type. The alignment
/// does not have to match: Clang should always use explicit alignments
/// and packed structs as necessary to produce the layout it needs.
/// But the size does need to be exactly right or else things like struct
/// layout will break.
llvm::Type *CodeGenTypes::ConvertTypeForMem(QualType T) {
if (T->isConstantMatrixType()) {
const Type *Ty = Context.getCanonicalType(T).getTypePtr();
const ConstantMatrixType *MT = cast<ConstantMatrixType>(Ty);
Expand All @@ -107,17 +114,65 @@ llvm::Type *CodeGenTypes::ConvertTypeForMem(QualType T, bool ForBitField) {
return llvm::IntegerType::get(FixedVT->getContext(), BytePadded);
}

// If this is a bool type, or a bit-precise integer type in a bitfield
// representation, map this integer to the target-specified size.
if ((ForBitField && T->isBitIntType()) ||
(!T->isBitIntType() && R->isIntegerTy(1)))
// If T is _Bool or a _BitInt type, ConvertType will produce an IR type
// with the exact semantic bit-width of the AST type; for example,
// _BitInt(17) will turn into i17. In memory, however, we need to store
// such values extended to their full storage size as decided by AST
// layout; this is an ABI requirement. Ideally, we would always use an
// integer type that's just the bit-size of the AST type; for example, if
// sizeof(_BitInt(17)) == 4, _BitInt(17) would turn into i32. That is what's
// returned by convertTypeForLoadStore. However, that type does not
// always satisfy the size requirement on memory representation types
// describe above. For example, a 32-bit platform might reasonably set
// sizeof(_BitInt(65)) == 12, but i96 is likely to have to have an alloc size
// of 16 bytes in the LLVM data layout. In these cases, we simply return
// a byte array of the appropriate size.
if (T->isBitIntType()) {
if (typeRequiresSplitIntoByteArray(T, R))
return llvm::ArrayType::get(CGM.Int8Ty,
Context.getTypeSizeInChars(T).getQuantity());
return llvm::IntegerType::get(getLLVMContext(),
(unsigned)Context.getTypeSize(T));
}

if (R->isIntegerTy(1))
return llvm::IntegerType::get(getLLVMContext(),
(unsigned)Context.getTypeSize(T));

// Else, don't map it.
return R;
}

bool CodeGenTypes::typeRequiresSplitIntoByteArray(QualType ASTTy,
llvm::Type *LLVMTy) {
if (!LLVMTy)
LLVMTy = ConvertType(ASTTy);

CharUnits ASTSize = Context.getTypeSizeInChars(ASTTy);
CharUnits LLVMSize =
CharUnits::fromQuantity(getDataLayout().getTypeAllocSize(LLVMTy));
return ASTSize != LLVMSize;
}

llvm::Type *CodeGenTypes::convertTypeForLoadStore(QualType T,
llvm::Type *LLVMTy) {
if (!LLVMTy)
LLVMTy = ConvertType(T);

if (T->isBitIntType())
return llvm::Type::getIntNTy(
getLLVMContext(), Context.getTypeSizeInChars(T).getQuantity() * 8);

if (LLVMTy->isIntegerTy(1))
return llvm::IntegerType::get(getLLVMContext(),
(unsigned)Context.getTypeSize(T));

if (T->isExtVectorBoolType())
return ConvertTypeForMem(T);

return LLVMTy;
}

/// isRecordLayoutComplete - Return true if the specified type is already
/// completely laid out.
bool CodeGenTypes::isRecordLayoutComplete(const Type *Ty) const {
Expand Down
25 changes: 24 additions & 1 deletion clang/lib/CodeGen/CodeGenTypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,30 @@ class CodeGenTypes {
/// ConvertType in that it is used to convert to the memory representation for
/// a type. For example, the scalar representation for _Bool is i1, but the
/// memory representation is usually i8 or i32, depending on the target.
llvm::Type *ConvertTypeForMem(QualType T, bool ForBitField = false);
llvm::Type *ConvertTypeForMem(QualType T);

/// Check whether the given type needs to be laid out in memory
/// using an opaque byte-array type because its load/store type
/// does not have the correct alloc size in the LLVM data layout.
/// If this is false, the load/store type (convertTypeForLoadStore)
/// and memory representation type (ConvertTypeForMem) will
/// be the same type.
bool typeRequiresSplitIntoByteArray(QualType ASTTy,
llvm::Type *LLVMTy = nullptr);

/// Given that T is a scalar type, return the IR type that should
/// be used for load and store operations. For example, this might
/// be i8 for _Bool or i96 for _BitInt(65). The store size of the
/// load/store type (as reported by LLVM's data layout) is always
/// the same as the alloc size of the memory representation type
/// returned by ConvertTypeForMem.
///
/// As an optimization, if you already know the scalar value type
/// for T (as would be returned by ConvertType), you can pass
/// it as the second argument so that it does not need to be
/// recomputed in common cases where the value type and
/// load/store type are the same.
llvm::Type *convertTypeForLoadStore(QualType T, llvm::Type *LLVMTy = nullptr);

/// GetFunctionType - Get the LLVM function type for \arg Info.
llvm::FunctionType *GetFunctionType(const CGFunctionInfo &Info);
Expand Down
60 changes: 48 additions & 12 deletions clang/lib/Driver/ToolChains/Arch/RISCV.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,8 @@ void riscv::getRISCVTargetFeatures(const Driver &D, const llvm::Triple &Triple,
if (!getArchFeatures(D, MArch, Features, Args))
return;

bool CPUFastUnaligned = false;
bool CPUFastScalarUnaligned = false;
bool CPUFastVectorUnaligned = false;

// If users give march and mcpu, get std extension feature from MArch
// and other features (ex. mirco architecture feature) from mcpu
Expand All @@ -88,8 +89,10 @@ void riscv::getRISCVTargetFeatures(const Driver &D, const llvm::Triple &Triple,

getRISCFeaturesFromMcpu(D, A, Triple, CPU, Features);

if (llvm::RISCV::hasFastUnalignedAccess(CPU))
CPUFastUnaligned = true;
if (llvm::RISCV::hasFastScalarUnalignedAccess(CPU))
CPUFastScalarUnaligned = true;
if (llvm::RISCV::hasFastVectorUnalignedAccess(CPU))
CPUFastVectorUnaligned = true;
}

// Handle features corresponding to "-ffixed-X" options
Expand Down Expand Up @@ -169,20 +172,37 @@ void riscv::getRISCVTargetFeatures(const Driver &D, const llvm::Triple &Triple,
Features.push_back("-relax");
}

// If -mstrict-align or -mno-strict-align is passed, use it. Otherwise, the
// unaligned-*-mem is enabled if the CPU supports it or the target is
// If -mstrict-align, -mno-strict-align, -mscalar-strict-align, or
// -mno-scalar-strict-align is passed, use it. Otherwise, the
// unaligned-scalar-mem is enabled if the CPU supports it or the target is
// Android.
if (const Arg *A = Args.getLastArg(options::OPT_mno_strict_align,
options::OPT_mstrict_align)) {
if (A->getOption().matches(options::OPT_mno_strict_align)) {
if (const Arg *A = Args.getLastArg(
options::OPT_mno_strict_align, options::OPT_mscalar_strict_align,
options::OPT_mstrict_align, options::OPT_mno_scalar_strict_align)) {
if (A->getOption().matches(options::OPT_mno_strict_align) ||
A->getOption().matches(options::OPT_mno_scalar_strict_align)) {
Features.push_back("+unaligned-scalar-mem");
Features.push_back("+unaligned-vector-mem");
} else {
Features.push_back("-unaligned-scalar-mem");
Features.push_back("-unaligned-vector-mem");
}
} else if (CPUFastUnaligned || Triple.isAndroid()) {
} else if (CPUFastScalarUnaligned || Triple.isAndroid()) {
Features.push_back("+unaligned-scalar-mem");
}

// If -mstrict-align, -mno-strict-align, -mvector-strict-align, or
// -mno-vector-strict-align is passed, use it. Otherwise, the
// unaligned-vector-mem is enabled if the CPU supports it or the target is
// Android.
if (const Arg *A = Args.getLastArg(
options::OPT_mno_strict_align, options::OPT_mvector_strict_align,
options::OPT_mstrict_align, options::OPT_mno_vector_strict_align)) {
if (A->getOption().matches(options::OPT_mno_strict_align) ||
A->getOption().matches(options::OPT_mno_vector_strict_align)) {
Features.push_back("+unaligned-vector-mem");
} else {
Features.push_back("-unaligned-vector-mem");
}
} else if (CPUFastVectorUnaligned || Triple.isAndroid()) {
Features.push_back("+unaligned-vector-mem");
}

Expand Down Expand Up @@ -290,8 +310,24 @@ std::string riscv::getRISCVArch(const llvm::opt::ArgList &Args,
// 2. Get march (isa string) based on `-mcpu=`
if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) {
StringRef CPU = A->getValue();
if (CPU == "native")
if (CPU == "native") {
CPU = llvm::sys::getHostCPUName();
// If the target cpu is unrecognized, use target features.
if (CPU.starts_with("generic")) {
auto FeatureMap = llvm::sys::getHostCPUFeatures();
// hwprobe may be unavailable on older Linux versions.
if (!FeatureMap.empty()) {
std::vector<std::string> Features;
for (auto &F : FeatureMap)
Features.push_back(((F.second ? "+" : "-") + F.first()).str());
auto ParseResult = llvm::RISCVISAInfo::parseFeatures(
Triple.isRISCV32() ? 32 : 64, Features);
if (ParseResult)
return (*ParseResult)->toString();
}
}
}

StringRef MArch = llvm::RISCV::getMArchFromMcpu(CPU);
// Bypass if target cpu's default march is empty.
if (MArch != "")
Expand Down
13 changes: 13 additions & 0 deletions clang/lib/Driver/ToolChains/Arch/X86.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -310,4 +310,17 @@ void x86::getX86TargetFeatures(const Driver &D, const llvm::Triple &Triple,
Features.push_back("+prefer-no-scatter");
if (Args.hasArg(options::OPT_mapx_inline_asm_use_gpr32))
Features.push_back("+inline-asm-use-gpr32");

// Warn for removed 3dnow support
if (const Arg *A =
Args.getLastArg(options::OPT_m3dnowa, options::OPT_mno_3dnowa,
options::OPT_mno_3dnow)) {
if (A->getOption().matches(options::OPT_m3dnowa))
D.Diag(diag::warn_drv_clang_unsupported) << A->getAsString(Args);
}
if (const Arg *A =
Args.getLastArg(options::OPT_m3dnow, options::OPT_mno_3dnow)) {
if (A->getOption().matches(options::OPT_m3dnow))
D.Diag(diag::warn_drv_clang_unsupported) << A->getAsString(Args);
}
}
7 changes: 7 additions & 0 deletions clang/lib/Driver/ToolChains/Clang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2545,6 +2545,13 @@ static void CollectArgsForIntegratedAssembler(Compilation &C,
switch (C.getDefaultToolChain().getArch()) {
default:
break;
case llvm::Triple::x86:
case llvm::Triple::x86_64:
if (Value == "-msse2avx") {
CmdArgs.push_back("-msse2avx");
continue;
}
break;
case llvm::Triple::wasm32:
case llvm::Triple::wasm64:
if (Value == "--no-type-check") {
Expand Down
10 changes: 9 additions & 1 deletion clang/lib/Driver/ToolChains/Flang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "llvm/Frontend/Debug/Options.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include "llvm/TargetParser/Host.h"
#include "llvm/TargetParser/RISCVISAInfo.h"
#include "llvm/TargetParser/RISCVTargetParser.h"

Expand Down Expand Up @@ -419,6 +420,13 @@ void Flang::addTargetOptions(const ArgList &Args,
}

// TODO: Add target specific flags, ABI, mtune option etc.
if (const Arg *A = Args.getLastArg(options::OPT_mtune_EQ)) {
CmdArgs.push_back("-tune-cpu");
if (A->getValue() == StringRef{"native"})
CmdArgs.push_back(Args.MakeArgString(llvm::sys::getHostCPUName()));
else
CmdArgs.push_back(A->getValue());
}
}

void Flang::addOffloadOptions(Compilation &C, const InputInfoList &Inputs,
Expand Down Expand Up @@ -815,7 +823,7 @@ void Flang::ConstructJob(Compilation &C, const JobAction &JA,
case CodeGenOptions::FramePointerKind::None:
FPKeepKindStr = "-mframe-pointer=none";
break;
case CodeGenOptions::FramePointerKind::Reserved:
case CodeGenOptions::FramePointerKind::Reserved:
FPKeepKindStr = "-mframe-pointer=reserved";
break;
case CodeGenOptions::FramePointerKind::NonLeaf:
Expand Down
159 changes: 125 additions & 34 deletions clang/lib/Driver/ToolChains/PS4CPU.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,11 +118,11 @@ void toolchains::PS5CPU::addSanitizerArgs(const ArgList &Args,
CmdArgs.push_back(arg("SceThreadSanitizer_nosubmission_stub_weak"));
}

void tools::PScpu::Linker::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
const InputInfoList &Inputs,
const ArgList &Args,
const char *LinkingOutput) const {
void tools::PS4cpu::Linker::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
const InputInfoList &Inputs,
const ArgList &Args,
const char *LinkingOutput) const {
auto &TC = static_cast<const toolchains::PS4PS5Base &>(getToolChain());
const Driver &D = TC.getDriver();
ArgStringList CmdArgs;
Expand Down Expand Up @@ -155,14 +155,120 @@ void tools::PScpu::Linker::ConstructJob(Compilation &C, const JobAction &JA,
const bool UseLTO = D.isUsingLTO();
const bool UseJMC =
Args.hasFlag(options::OPT_fjmc, options::OPT_fno_jmc, false);
const bool IsPS4 = TC.getTriple().isPS4();

const char *PS4LTOArgs = "";
const char *LTOArgs = "";
auto AddCodeGenFlag = [&](Twine Flag) {
if (IsPS4)
PS4LTOArgs = Args.MakeArgString(Twine(PS4LTOArgs) + " " + Flag);
LTOArgs = Args.MakeArgString(Twine(LTOArgs) + " " + Flag);
};

if (UseLTO) {
// We default to creating the arange section, but LTO does not. Enable it
// here.
AddCodeGenFlag("-generate-arange-section");

// This tells LTO to perform JustMyCode instrumentation.
if (UseJMC)
AddCodeGenFlag("-enable-jmc-instrument");

if (Arg *A = Args.getLastArg(options::OPT_fcrash_diagnostics_dir))
AddCodeGenFlag(Twine("-crash-diagnostics-dir=") + A->getValue());

StringRef Parallelism = getLTOParallelism(Args, D);
if (!Parallelism.empty())
AddCodeGenFlag(Twine("-threads=") + Parallelism);

const char *Prefix = nullptr;
if (D.getLTOMode() == LTOK_Thin)
Prefix = "-lto-thin-debug-options=";
else if (D.getLTOMode() == LTOK_Full)
Prefix = "-lto-debug-options=";
else
CmdArgs.push_back(Args.MakeArgString(Twine("-plugin-opt=") + Flag));
llvm_unreachable("new LTO mode?");

CmdArgs.push_back(Args.MakeArgString(Twine(Prefix) + LTOArgs));
}

if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs))
TC.addSanitizerArgs(Args, CmdArgs, "-l", "");

if (D.isUsingLTO() && Args.hasArg(options::OPT_funified_lto)) {
if (D.getLTOMode() == LTOK_Thin)
CmdArgs.push_back("--lto=thin");
else if (D.getLTOMode() == LTOK_Full)
CmdArgs.push_back("--lto=full");
}

Args.addAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group,
options::OPT_s, options::OPT_t});

if (Args.hasArg(options::OPT_Z_Xlinker__no_demangle))
CmdArgs.push_back("--no-demangle");

AddLinkerInputs(TC, Inputs, Args, CmdArgs, JA);

if (Args.hasArg(options::OPT_pthread)) {
CmdArgs.push_back("-lpthread");
}

if (UseJMC) {
CmdArgs.push_back("--whole-archive");
CmdArgs.push_back("-lSceDbgJmc");
CmdArgs.push_back("--no-whole-archive");
}

if (Args.hasArg(options::OPT_fuse_ld_EQ)) {
D.Diag(diag::err_drv_unsupported_opt_for_target)
<< "-fuse-ld" << TC.getTriple().str();
}

std::string LdName = TC.qualifyPSCmdName(TC.getLinkerBaseName());
const char *Exec = Args.MakeArgString(TC.GetProgramPath(LdName.c_str()));

C.addCommand(std::make_unique<Command>(JA, *this,
ResponseFileSupport::AtFileUTF8(),
Exec, CmdArgs, Inputs, Output));
}

void tools::PS5cpu::Linker::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
const InputInfoList &Inputs,
const ArgList &Args,
const char *LinkingOutput) const {
auto &TC = static_cast<const toolchains::PS4PS5Base &>(getToolChain());
const Driver &D = TC.getDriver();
ArgStringList CmdArgs;

// Silence warning for "clang -g foo.o -o foo"
Args.ClaimAllArgs(options::OPT_g_Group);
// and "clang -emit-llvm foo.o -o foo"
Args.ClaimAllArgs(options::OPT_emit_llvm);
// and for "clang -w foo.o -o foo". Other warning options are already
// handled somewhere else.
Args.ClaimAllArgs(options::OPT_w);

if (!D.SysRoot.empty())
CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot));

if (Args.hasArg(options::OPT_pie))
CmdArgs.push_back("-pie");

if (Args.hasArg(options::OPT_rdynamic))
CmdArgs.push_back("-export-dynamic");
if (Args.hasArg(options::OPT_shared))
CmdArgs.push_back("--shared");

assert((Output.isFilename() || Output.isNothing()) && "Invalid output.");
if (Output.isFilename()) {
CmdArgs.push_back("-o");
CmdArgs.push_back(Output.getFilename());
}

const bool UseLTO = D.isUsingLTO();
const bool UseJMC =
Args.hasFlag(options::OPT_fjmc, options::OPT_fno_jmc, false);

auto AddCodeGenFlag = [&](Twine Flag) {
CmdArgs.push_back(Args.MakeArgString(Twine("-plugin-opt=") + Flag));
};

if (UseLTO) {
Expand All @@ -178,24 +284,8 @@ void tools::PScpu::Linker::ConstructJob(Compilation &C, const JobAction &JA,
AddCodeGenFlag(Twine("-crash-diagnostics-dir=") + A->getValue());

StringRef Parallelism = getLTOParallelism(Args, D);
if (!Parallelism.empty()) {
if (IsPS4)
AddCodeGenFlag(Twine("-threads=") + Parallelism);
else
CmdArgs.push_back(Args.MakeArgString(Twine("-plugin-opt=jobs=") + Parallelism));
}

if (IsPS4) {
const char *Prefix = nullptr;
if (D.getLTOMode() == LTOK_Thin)
Prefix = "-lto-thin-debug-options=";
else if (D.getLTOMode() == LTOK_Full)
Prefix = "-lto-debug-options=";
else
llvm_unreachable("new LTO mode?");

CmdArgs.push_back(Args.MakeArgString(Twine(Prefix) + PS4LTOArgs));
}
if (!Parallelism.empty())
CmdArgs.push_back(Args.MakeArgString(Twine("-plugin-opt=jobs=") + Parallelism));
}

if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs))
Expand All @@ -222,10 +312,7 @@ void tools::PScpu::Linker::ConstructJob(Compilation &C, const JobAction &JA,

if (UseJMC) {
CmdArgs.push_back("--whole-archive");
if (IsPS4)
CmdArgs.push_back("-lSceDbgJmc");
else
CmdArgs.push_back("-lSceJmc_nosubmission");
CmdArgs.push_back("-lSceJmc_nosubmission");
CmdArgs.push_back("--no-whole-archive");
}

Expand Down Expand Up @@ -321,14 +408,18 @@ Tool *toolchains::PS4CPU::buildAssembler() const {
return new tools::PScpu::Assembler(*this);
}

Tool *toolchains::PS4CPU::buildLinker() const {
return new tools::PS4cpu::Linker(*this);
}

Tool *toolchains::PS5CPU::buildAssembler() const {
// PS5 does not support an external assembler.
getDriver().Diag(clang::diag::err_no_external_assembler);
return nullptr;
}

Tool *toolchains::PS4PS5Base::buildLinker() const {
return new tools::PScpu::Linker(*this);
Tool *toolchains::PS5CPU::buildLinker() const {
return new tools::PS5cpu::Linker(*this);
}

SanitizerMask toolchains::PS4PS5Base::getSupportedSanitizers() const {
Expand Down
27 changes: 22 additions & 5 deletions clang/lib/Driver/ToolChains/PS4CPU.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,12 @@ class LLVM_LIBRARY_VISIBILITY Assembler final : public Tool {
const llvm::opt::ArgList &TCArgs,
const char *LinkingOutput) const override;
};
} // namespace PScpu

namespace PS4cpu {
class LLVM_LIBRARY_VISIBILITY Linker final : public Tool {
public:
Linker(const ToolChain &TC) : Tool("PScpu::Linker", "linker", TC) {}
Linker(const ToolChain &TC) : Tool("PS4cpu::Linker", "linker", TC) {}

bool hasIntegratedCPP() const override { return false; }
bool isLinkJob() const override { return true; }
Expand All @@ -51,7 +53,23 @@ class LLVM_LIBRARY_VISIBILITY Linker final : public Tool {
const llvm::opt::ArgList &TCArgs,
const char *LinkingOutput) const override;
};
} // namespace PScpu
} // namespace PS4cpu

namespace PS5cpu {
class LLVM_LIBRARY_VISIBILITY Linker final : public Tool {
public:
Linker(const ToolChain &TC) : Tool("PS5cpu::Linker", "linker", TC) {}

bool hasIntegratedCPP() const override { return false; }
bool isLinkJob() const override { return true; }

void ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output, const InputInfoList &Inputs,
const llvm::opt::ArgList &TCArgs,
const char *LinkingOutput) const override;
};
} // namespace PS5cpu

} // namespace tools

namespace toolchains {
Expand Down Expand Up @@ -110,9 +128,6 @@ class LLVM_LIBRARY_VISIBILITY PS4PS5Base : public Generic_ELF {
const char *Suffix) const = 0;
virtual const char *getProfileRTLibName() const = 0;

protected:
Tool *buildLinker() const override;

private:
// We compute the SDK root dir in the ctor, and use it later.
std::string SDKRootDir;
Expand Down Expand Up @@ -143,6 +158,7 @@ class LLVM_LIBRARY_VISIBILITY PS4CPU : public PS4PS5Base {

protected:
Tool *buildAssembler() const override;
Tool *buildLinker() const override;
};

// PS5-specific Toolchain class.
Expand All @@ -168,6 +184,7 @@ class LLVM_LIBRARY_VISIBILITY PS5CPU : public PS4PS5Base {

protected:
Tool *buildAssembler() const override;
Tool *buildLinker() const override;
};

} // end namespace toolchains
Expand Down
Loading