diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -95,6 +95,7 @@ class DiagnosticsEngine; class Expr; class FixedPointSemantics; +class GlobalDecl; class MangleContext; class MangleNumberingContext; class MaterializeTemporaryExpr; @@ -112,9 +113,11 @@ class ObjCPropertyImplDecl; class ObjCProtocolDecl; class ObjCTypeParamDecl; +class ParsedTargetAttr; class Preprocessor; class Stmt; class StoredDeclsMap; +class TargetAttr; class TemplateDecl; class TemplateParameterList; class TemplateTemplateParmDecl; @@ -2838,6 +2841,15 @@ /// PredefinedExpr to cache evaluated results. StringLiteral *getPredefinedStringLiteralFromCache(StringRef Key) const; + /// Parses the target attributes passed in, and returns only the ones that are + /// valid feature names. + ParsedTargetAttr filterFunctionTargetAttrs(const TargetAttr *TD) const; + + void getFunctionFeatureMap(llvm::StringMap &FeatureMap, + const FunctionDecl *) const; + void getFunctionFeatureMap(llvm::StringMap &FeatureMap, + GlobalDecl GD) const; + //===--------------------------------------------------------------------===// // Statistics //===--------------------------------------------------------------------===// diff --git a/clang/include/clang/Basic/TargetInfo.h b/clang/include/clang/Basic/TargetInfo.h --- a/clang/include/clang/Basic/TargetInfo.h +++ b/clang/include/clang/Basic/TargetInfo.h @@ -945,12 +945,14 @@ bool validateInputConstraint(MutableArrayRef OutputConstraints, ConstraintInfo &info) const; - virtual bool validateOutputSize(StringRef /*Constraint*/, + virtual bool validateOutputSize(const llvm::StringMap &FeatureMap, + StringRef /*Constraint*/, unsigned /*Size*/) const { return true; } - virtual bool validateInputSize(StringRef /*Constraint*/, + virtual bool validateInputSize(const llvm::StringMap &FeatureMap, + StringRef /*Constraint*/, unsigned /*Size*/) const { return true; } diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -10817,3 +10817,66 @@ llvm_unreachable("Unexpected unsigned fixed point type"); } } + +ParsedTargetAttr +ASTContext::filterFunctionTargetAttrs(const TargetAttr *TD) const { + assert(TD != nullptr); + ParsedTargetAttr ParsedAttr = TD->parse(); + + ParsedAttr.Features.erase( + llvm::remove_if(ParsedAttr.Features, + [&](const std::string &Feat) { + return !Target->isValidFeatureName( + StringRef{Feat}.substr(1)); + }), + ParsedAttr.Features.end()); + return ParsedAttr; +} + +void ASTContext::getFunctionFeatureMap(llvm::StringMap &FeatureMap, + const FunctionDecl *FD) const { + if (FD) + getFunctionFeatureMap(FeatureMap, GlobalDecl().getWithDecl(FD)); + else + Target->initFeatureMap(FeatureMap, getDiagnostics(), + Target->getTargetOpts().CPU, + Target->getTargetOpts().Features); +} + +// Fills in the supplied string map with the set of target features for the +// passed in function. +void ASTContext::getFunctionFeatureMap(llvm::StringMap &FeatureMap, + GlobalDecl GD) const { + StringRef TargetCPU = Target->getTargetOpts().CPU; + const FunctionDecl *FD = GD.getDecl()->getAsFunction(); + if (const auto *TD = FD->getAttr()) { + ParsedTargetAttr ParsedAttr = filterFunctionTargetAttrs(TD); + + // Make a copy of the features as passed on the command line into the + // beginning of the additional features from the function to override. + ParsedAttr.Features.insert( + ParsedAttr.Features.begin(), + Target->getTargetOpts().FeaturesAsWritten.begin(), + Target->getTargetOpts().FeaturesAsWritten.end()); + + if (ParsedAttr.Architecture != "" && + Target->isValidCPUName(ParsedAttr.Architecture)) + TargetCPU = ParsedAttr.Architecture; + + // Now populate the feature map, first with the TargetCPU which is either + // the default or a new one from the target attribute string. Then we'll use + // the passed in features (FeaturesAsWritten) along with the new ones from + // the attribute. + Target->initFeatureMap(FeatureMap, getDiagnostics(), TargetCPU, + ParsedAttr.Features); + } else if (const auto *SD = FD->getAttr()) { + llvm::SmallVector FeaturesTmp; + Target->getCPUSpecificCPUDispatchFeatures( + SD->getCPUName(GD.getMultiVersionIndex())->getName(), FeaturesTmp); + std::vector Features(FeaturesTmp.begin(), FeaturesTmp.end()); + Target->initFeatureMap(FeatureMap, getDiagnostics(), TargetCPU, Features); + } else { + Target->initFeatureMap(FeatureMap, getDiagnostics(), TargetCPU, + Target->getTargetOpts().Features); + } +} diff --git a/clang/lib/Basic/Targets/X86.h b/clang/lib/Basic/Targets/X86.h --- a/clang/lib/Basic/Targets/X86.h +++ b/clang/lib/Basic/Targets/X86.h @@ -194,9 +194,11 @@ return false; } - bool validateOutputSize(StringRef Constraint, unsigned Size) const override; + bool validateOutputSize(const llvm::StringMap &FeatureMap, + StringRef Constraint, unsigned Size) const override; - bool validateInputSize(StringRef Constraint, unsigned Size) const override; + bool validateInputSize(const llvm::StringMap &FeatureMap, + StringRef Constraint, unsigned Size) const override; virtual bool checkCFProtectionReturnSupported(DiagnosticsEngine &Diags) const override { @@ -208,8 +210,8 @@ return true; }; - - virtual bool validateOperandSize(StringRef Constraint, unsigned Size) const; + virtual bool validateOperandSize(const llvm::StringMap &FeatureMap, + StringRef Constraint, unsigned Size) const; std::string convertConstraint(const char *&Constraint) const override; const char *getClobbers() const override { @@ -397,7 +399,8 @@ return -1; } - bool validateOperandSize(StringRef Constraint, unsigned Size) const override { + bool validateOperandSize(const llvm::StringMap &FeatureMap, + StringRef Constraint, unsigned Size) const override { switch (Constraint[0]) { default: break; @@ -415,7 +418,7 @@ return Size <= 64; } - return X86TargetInfo::validateOperandSize(Constraint, Size); + return X86TargetInfo::validateOperandSize(FeatureMap, Constraint, Size); } void setMaxAtomicWidth() override { diff --git a/clang/lib/Basic/Targets/X86.cpp b/clang/lib/Basic/Targets/X86.cpp --- a/clang/lib/Basic/Targets/X86.cpp +++ b/clang/lib/Basic/Targets/X86.cpp @@ -1731,21 +1731,24 @@ } } -bool X86TargetInfo::validateOutputSize(StringRef Constraint, +bool X86TargetInfo::validateOutputSize(const llvm::StringMap &FeatureMap, + StringRef Constraint, unsigned Size) const { // Strip off constraint modifiers. while (Constraint[0] == '=' || Constraint[0] == '+' || Constraint[0] == '&') Constraint = Constraint.substr(1); - return validateOperandSize(Constraint, Size); + return validateOperandSize(FeatureMap, Constraint, Size); } -bool X86TargetInfo::validateInputSize(StringRef Constraint, +bool X86TargetInfo::validateInputSize(const llvm::StringMap &FeatureMap, + StringRef Constraint, unsigned Size) const { - return validateOperandSize(Constraint, Size); + return validateOperandSize(FeatureMap, Constraint, Size); } -bool X86TargetInfo::validateOperandSize(StringRef Constraint, +bool X86TargetInfo::validateOperandSize(const llvm::StringMap &FeatureMap, + StringRef Constraint, unsigned Size) const { switch (Constraint[0]) { default: @@ -1770,7 +1773,7 @@ case 'z': case '0': // XMM0 - if (SSELevel >= SSE1) + if (FeatureMap.lookup("sse")) return Size <= 128U; return false; case 'i': @@ -1784,10 +1787,10 @@ LLVM_FALLTHROUGH; case 'v': case 'x': - if (SSELevel >= AVX512F) + if (FeatureMap.lookup("avx512f")) // 512-bit zmm registers can be used if target supports AVX512F. return Size <= 512U; - else if (SSELevel >= AVX) + else if (FeatureMap.lookup("avx")) // 256-bit ymm registers can be used if target supports AVX. return Size <= 256U; return Size <= 128U; diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -2243,7 +2243,7 @@ // Now build up the set of caller features and verify that all the required // features are there. llvm::StringMap CallerFeatureMap; - CGM.getFunctionFeatureMap(CallerFeatureMap, GlobalDecl().getWithDecl(FD)); + CGM.getContext().getFunctionFeatureMap(CallerFeatureMap, FD); // If we have at least one of the features in the feature list return // true, otherwise return false. @@ -2305,11 +2305,13 @@ // Get the required features for the callee. const TargetAttr *TD = TargetDecl->getAttr(); - ParsedTargetAttr ParsedAttr = CGM.filterFunctionTargetAttrs(TD); + ParsedTargetAttr ParsedAttr = + CGM.getContext().filterFunctionTargetAttrs(TD); SmallVector ReqFeatures; llvm::StringMap CalleeFeatureMap; - CGM.getFunctionFeatureMap(CalleeFeatureMap, TargetDecl); + CGM.getContext().getFunctionFeatureMap(CalleeFeatureMap, + GlobalDecl(TargetDecl)); for (const auto &F : ParsedAttr.Features) { if (F[0] == '+' && CalleeFeatureMap.lookup(F.substr(1))) diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h --- a/clang/lib/CodeGen/CodeGenModule.h +++ b/clang/lib/CodeGen/CodeGenModule.h @@ -1157,14 +1157,6 @@ /// It's up to you to ensure that this is safe. void AddDefaultFnAttrs(llvm::Function &F); - /// Parses the target attributes passed in, and returns only the ones that are - /// valid feature names. - ParsedTargetAttr filterFunctionTargetAttrs(const TargetAttr *TD); - - // Fills in the supplied string map with the set of target features for the - // passed in function. - void getFunctionFeatureMap(llvm::StringMap &FeatureMap, GlobalDecl GD); - StringRef getMangledName(GlobalDecl GD); StringRef getBlockMangledName(GlobalDecl GD, const BlockDecl *BD); diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -1676,7 +1676,7 @@ bool AddedAttr = false; if (TD || SD) { llvm::StringMap FeatureMap; - getFunctionFeatureMap(FeatureMap, GD); + getContext().getFunctionFeatureMap(FeatureMap, GD); // Produce the canonical string for this set of features. for (const llvm::StringMap::value_type &Entry : FeatureMap) @@ -5890,58 +5890,6 @@ } } -ParsedTargetAttr CodeGenModule::filterFunctionTargetAttrs(const TargetAttr *TD) { - assert(TD != nullptr); - ParsedTargetAttr ParsedAttr = TD->parse(); - - ParsedAttr.Features.erase( - llvm::remove_if(ParsedAttr.Features, - [&](const std::string &Feat) { - return !Target.isValidFeatureName( - StringRef{Feat}.substr(1)); - }), - ParsedAttr.Features.end()); - return ParsedAttr; -} - - -// Fills in the supplied string map with the set of target features for the -// passed in function. -void CodeGenModule::getFunctionFeatureMap(llvm::StringMap &FeatureMap, - GlobalDecl GD) { - StringRef TargetCPU = Target.getTargetOpts().CPU; - const FunctionDecl *FD = GD.getDecl()->getAsFunction(); - if (const auto *TD = FD->getAttr()) { - ParsedTargetAttr ParsedAttr = filterFunctionTargetAttrs(TD); - - // Make a copy of the features as passed on the command line into the - // beginning of the additional features from the function to override. - ParsedAttr.Features.insert(ParsedAttr.Features.begin(), - Target.getTargetOpts().FeaturesAsWritten.begin(), - Target.getTargetOpts().FeaturesAsWritten.end()); - - if (ParsedAttr.Architecture != "" && - Target.isValidCPUName(ParsedAttr.Architecture)) - TargetCPU = ParsedAttr.Architecture; - - // Now populate the feature map, first with the TargetCPU which is either - // the default or a new one from the target attribute string. Then we'll use - // the passed in features (FeaturesAsWritten) along with the new ones from - // the attribute. - Target.initFeatureMap(FeatureMap, getDiags(), TargetCPU, - ParsedAttr.Features); - } else if (const auto *SD = FD->getAttr()) { - llvm::SmallVector FeaturesTmp; - Target.getCPUSpecificCPUDispatchFeatures( - SD->getCPUName(GD.getMultiVersionIndex())->getName(), FeaturesTmp); - std::vector Features(FeaturesTmp.begin(), FeaturesTmp.end()); - Target.initFeatureMap(FeatureMap, getDiags(), TargetCPU, Features); - } else { - Target.initFeatureMap(FeatureMap, getDiags(), TargetCPU, - Target.getTargetOpts().Features); - } -} - llvm::SanitizerStatReport &CodeGenModule::getSanStats() { if (!SanStats) SanStats = std::make_unique(&getModule()); diff --git a/clang/lib/Sema/SemaStmtAsm.cpp b/clang/lib/Sema/SemaStmtAsm.cpp --- a/clang/lib/Sema/SemaStmtAsm.cpp +++ b/clang/lib/Sema/SemaStmtAsm.cpp @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// #include "clang/AST/ExprCXX.h" +#include "clang/AST/GlobalDecl.h" #include "clang/AST/RecordLayout.h" #include "clang/AST/TypeLoc.h" #include "clang/Basic/TargetInfo.h" @@ -255,6 +256,10 @@ // The parser verifies that there is a string literal here. assert(AsmString->isAscii()); + FunctionDecl *FD = dyn_cast(getCurLexicalContext()); + llvm::StringMap FeatureMap; + Context.getFunctionFeatureMap(FeatureMap, FD); + for (unsigned i = 0; i != NumOutputs; i++) { StringLiteral *Literal = Constraints[i]; assert(Literal->isAscii()); @@ -325,8 +330,8 @@ } unsigned Size = Context.getTypeSize(OutputExpr->getType()); - if (!Context.getTargetInfo().validateOutputSize(Literal->getString(), - Size)) { + if (!Context.getTargetInfo().validateOutputSize( + FeatureMap, Literal->getString(), Size)) { targetDiag(OutputExpr->getBeginLoc(), diag::err_asm_invalid_output_size) << Info.getConstraintStr(); return new (Context) @@ -427,8 +432,8 @@ return StmtError(); unsigned Size = Context.getTypeSize(Ty); - if (!Context.getTargetInfo().validateInputSize(Literal->getString(), - Size)) + if (!Context.getTargetInfo().validateInputSize(FeatureMap, + Literal->getString(), Size)) return StmtResult( targetDiag(InputExpr->getBeginLoc(), diag::err_asm_invalid_input_size) << Info.getConstraintStr()); diff --git a/clang/test/CodeGen/x86_32-inline-asm.c b/clang/test/CodeGen/x86_32-inline-asm.c --- a/clang/test/CodeGen/x86_32-inline-asm.c +++ b/clang/test/CodeGen/x86_32-inline-asm.c @@ -70,3 +70,35 @@ __asm__ volatile("foo1 %0" : "=x" (val256)); // expected-error {{invalid output size for constraint '=x'}} #endif } + +int __attribute__((__target__("sse"))) _func2() { + __asm__ volatile("foo1 %0" : : "x" (val128)); // No error. + __asm__ volatile("foo1 %0" : "=x" (val128)); // No error. +#ifdef __AVX__ + __asm__ volatile("foo1 %0" : : "x" (val256)); // No error. + __asm__ volatile("foo1 %0" : "=x" (val256)); // No error. +#else + __asm__ volatile("foo1 %0" : : "x" (val256)); // expected-error {{invalid input size for constraint 'x'}} + __asm__ volatile("foo1 %0" : "=x" (val256)); // expected-error {{invalid output size for constraint '=x'}} +#endif + __asm__ volatile("foo1 %0" : : "x" (val512)); // expected-error {{invalid input size for constraint 'x'}} + __asm__ volatile("foo1 %0" : "=x" (val512)); // expected-error {{invalid output size for constraint '=x'}} +} + +int __attribute__((__target__("avx"))) _func3() { + __asm__ volatile("foo1 %0" : : "x" (val128)); // No error. + __asm__ volatile("foo1 %0" : "=x" (val128)); // No error. + __asm__ volatile("foo1 %0" : : "x" (val256)); // No error. + __asm__ volatile("foo1 %0" : "=x" (val256)); // No error. + __asm__ volatile("foo1 %0" : : "x" (val512)); // expected-error {{invalid input size for constraint 'x'}} + __asm__ volatile("foo1 %0" : "=x" (val512)); // expected-error {{invalid output size for constraint '=x'}} +} + +int __attribute__((__target__("avx512f"))) _func4() { + __asm__ volatile("foo1 %0" : : "x" (val128)); // No error. + __asm__ volatile("foo1 %0" : "=x" (val128)); // No error. + __asm__ volatile("foo1 %0" : : "x" (val256)); // No error. + __asm__ volatile("foo1 %0" : "=x" (val256)); // No error. + __asm__ volatile("foo1 %0" : : "x" (val512)); // No error. + __asm__ volatile("foo1 %0" : "=x" (val512)); // No error. +}