summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang/include/clang/AST/ASTContext.h12
-rw-r--r--clang/include/clang/Basic/TargetInfo.h6
-rw-r--r--clang/lib/AST/ASTContext.cpp63
-rw-r--r--clang/lib/Basic/Targets/X86.cpp19
-rw-r--r--clang/lib/Basic/Targets/X86.h15
-rw-r--r--clang/lib/CodeGen/CodeGenFunction.cpp8
-rw-r--r--clang/lib/CodeGen/CodeGenModule.cpp54
-rw-r--r--clang/lib/CodeGen/CodeGenModule.h8
-rw-r--r--clang/lib/Sema/SemaStmtAsm.cpp13
-rw-r--r--clang/test/CodeGen/x86_32-inline-asm.c32
10 files changed, 146 insertions, 84 deletions
diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h
index 92f81eb55ed..6d1265ca647 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -95,6 +95,7 @@ class CXXRecordDecl;
class DiagnosticsEngine;
class Expr;
class FixedPointSemantics;
+class GlobalDecl;
class MangleContext;
class MangleNumberingContext;
class MaterializeTemporaryExpr;
@@ -112,9 +113,11 @@ class ObjCPropertyDecl;
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 @@ public:
/// 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<bool> &FeatureMap,
+ const FunctionDecl *) const;
+ void getFunctionFeatureMap(llvm::StringMap<bool> &FeatureMap,
+ GlobalDecl GD) const;
+
//===--------------------------------------------------------------------===//
// Statistics
//===--------------------------------------------------------------------===//
diff --git a/clang/include/clang/Basic/TargetInfo.h b/clang/include/clang/Basic/TargetInfo.h
index bc06f59d41d..a32b30f5b7e 100644
--- a/clang/include/clang/Basic/TargetInfo.h
+++ b/clang/include/clang/Basic/TargetInfo.h
@@ -945,12 +945,14 @@ public:
bool validateInputConstraint(MutableArrayRef<ConstraintInfo> OutputConstraints,
ConstraintInfo &info) const;
- virtual bool validateOutputSize(StringRef /*Constraint*/,
+ virtual bool validateOutputSize(const llvm::StringMap<bool> &FeatureMap,
+ StringRef /*Constraint*/,
unsigned /*Size*/) const {
return true;
}
- virtual bool validateInputSize(StringRef /*Constraint*/,
+ virtual bool validateInputSize(const llvm::StringMap<bool> &FeatureMap,
+ StringRef /*Constraint*/,
unsigned /*Size*/) const {
return true;
}
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index a09b1aca7c2..d26e7f789d0 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -10817,3 +10817,66 @@ QualType ASTContext::getCorrespondingSignedFixedPointType(QualType Ty) const {
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<bool> &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<bool> &FeatureMap,
+ GlobalDecl GD) const {
+ StringRef TargetCPU = Target->getTargetOpts().CPU;
+ const FunctionDecl *FD = GD.getDecl()->getAsFunction();
+ if (const auto *TD = FD->getAttr<TargetAttr>()) {
+ 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<CPUSpecificAttr>()) {
+ llvm::SmallVector<StringRef, 32> FeaturesTmp;
+ Target->getCPUSpecificCPUDispatchFeatures(
+ SD->getCPUName(GD.getMultiVersionIndex())->getName(), FeaturesTmp);
+ std::vector<std::string> 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.cpp b/clang/lib/Basic/Targets/X86.cpp
index 51f2006ddbd..d099d3742f0 100644
--- a/clang/lib/Basic/Targets/X86.cpp
+++ b/clang/lib/Basic/Targets/X86.cpp
@@ -1731,21 +1731,24 @@ bool X86TargetInfo::validateAsmConstraint(
}
}
-bool X86TargetInfo::validateOutputSize(StringRef Constraint,
+bool X86TargetInfo::validateOutputSize(const llvm::StringMap<bool> &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<bool> &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<bool> &FeatureMap,
+ StringRef Constraint,
unsigned Size) const {
switch (Constraint[0]) {
default:
@@ -1770,7 +1773,7 @@ bool X86TargetInfo::validateOperandSize(StringRef Constraint,
case 'z':
case '0':
// XMM0
- if (SSELevel >= SSE1)
+ if (FeatureMap.lookup("sse"))
return Size <= 128U;
return false;
case 'i':
@@ -1784,10 +1787,10 @@ bool X86TargetInfo::validateOperandSize(StringRef Constraint,
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/Basic/Targets/X86.h b/clang/lib/Basic/Targets/X86.h
index 604198b0047..5b5e284e514 100644
--- a/clang/lib/Basic/Targets/X86.h
+++ b/clang/lib/Basic/Targets/X86.h
@@ -194,9 +194,11 @@ public:
return false;
}
- bool validateOutputSize(StringRef Constraint, unsigned Size) const override;
+ bool validateOutputSize(const llvm::StringMap<bool> &FeatureMap,
+ StringRef Constraint, unsigned Size) const override;
- bool validateInputSize(StringRef Constraint, unsigned Size) const override;
+ bool validateInputSize(const llvm::StringMap<bool> &FeatureMap,
+ StringRef Constraint, unsigned Size) const override;
virtual bool
checkCFProtectionReturnSupported(DiagnosticsEngine &Diags) const override {
@@ -208,8 +210,8 @@ public:
return true;
};
-
- virtual bool validateOperandSize(StringRef Constraint, unsigned Size) const;
+ virtual bool validateOperandSize(const llvm::StringMap<bool> &FeatureMap,
+ StringRef Constraint, unsigned Size) const;
std::string convertConstraint(const char *&Constraint) const override;
const char *getClobbers() const override {
@@ -397,7 +399,8 @@ public:
return -1;
}
- bool validateOperandSize(StringRef Constraint, unsigned Size) const override {
+ bool validateOperandSize(const llvm::StringMap<bool> &FeatureMap,
+ StringRef Constraint, unsigned Size) const override {
switch (Constraint[0]) {
default:
break;
@@ -415,7 +418,7 @@ public:
return Size <= 64;
}
- return X86TargetInfo::validateOperandSize(Constraint, Size);
+ return X86TargetInfo::validateOperandSize(FeatureMap, Constraint, Size);
}
void setMaxAtomicWidth() override {
diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp
index 0f90f6ecf5b..448b70de971 100644
--- a/clang/lib/CodeGen/CodeGenFunction.cpp
+++ b/clang/lib/CodeGen/CodeGenFunction.cpp
@@ -2243,7 +2243,7 @@ static bool hasRequiredFeatures(const SmallVectorImpl<StringRef> &ReqFeatures,
// Now build up the set of caller features and verify that all the required
// features are there.
llvm::StringMap<bool> 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 @@ void CodeGenFunction::checkTargetFeatures(SourceLocation Loc,
// Get the required features for the callee.
const TargetAttr *TD = TargetDecl->getAttr<TargetAttr>();
- ParsedTargetAttr ParsedAttr = CGM.filterFunctionTargetAttrs(TD);
+ ParsedTargetAttr ParsedAttr =
+ CGM.getContext().filterFunctionTargetAttrs(TD);
SmallVector<StringRef, 1> ReqFeatures;
llvm::StringMap<bool> 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.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index 1fc2beb12ed..963cd82210c 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -1676,7 +1676,7 @@ bool CodeGenModule::GetCPUAndFeaturesAttributes(GlobalDecl GD,
bool AddedAttr = false;
if (TD || SD) {
llvm::StringMap<bool> FeatureMap;
- getFunctionFeatureMap(FeatureMap, GD);
+ getContext().getFunctionFeatureMap(FeatureMap, GD);
// Produce the canonical string for this set of features.
for (const llvm::StringMap<bool>::value_type &Entry : FeatureMap)
@@ -5890,58 +5890,6 @@ void CodeGenModule::AddVTableTypeMetadata(llvm::GlobalVariable *VTable,
}
}
-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<bool> &FeatureMap,
- GlobalDecl GD) {
- StringRef TargetCPU = Target.getTargetOpts().CPU;
- const FunctionDecl *FD = GD.getDecl()->getAsFunction();
- if (const auto *TD = FD->getAttr<TargetAttr>()) {
- 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<CPUSpecificAttr>()) {
- llvm::SmallVector<StringRef, 32> FeaturesTmp;
- Target.getCPUSpecificCPUDispatchFeatures(
- SD->getCPUName(GD.getMultiVersionIndex())->getName(), FeaturesTmp);
- std::vector<std::string> 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<llvm::SanitizerStatReport>(&getModule());
diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h
index 9bf1c5ef610..115e754bb39 100644
--- a/clang/lib/CodeGen/CodeGenModule.h
+++ b/clang/lib/CodeGen/CodeGenModule.h
@@ -1157,14 +1157,6 @@ public:
/// 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<bool> &FeatureMap, GlobalDecl GD);
-
StringRef getMangledName(GlobalDecl GD);
StringRef getBlockMangledName(GlobalDecl GD, const BlockDecl *BD);
diff --git a/clang/lib/Sema/SemaStmtAsm.cpp b/clang/lib/Sema/SemaStmtAsm.cpp
index 9b051e02d12..5161b800191 100644
--- 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 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
// The parser verifies that there is a string literal here.
assert(AsmString->isAscii());
+ FunctionDecl *FD = dyn_cast<FunctionDecl>(getCurLexicalContext());
+ llvm::StringMap<bool> FeatureMap;
+ Context.getFunctionFeatureMap(FeatureMap, FD);
+
for (unsigned i = 0; i != NumOutputs; i++) {
StringLiteral *Literal = Constraints[i];
assert(Literal->isAscii());
@@ -325,8 +330,8 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
}
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 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
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
index c1fba0eee94..5a69064abc0 100644
--- a/clang/test/CodeGen/x86_32-inline-asm.c
+++ b/clang/test/CodeGen/x86_32-inline-asm.c
@@ -70,3 +70,35 @@ int func1() {
__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.
+}
OpenPOWER on IntegriCloud