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 @@ -944,12 +944,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/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 @@ -177,9 +177,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 { @@ -192,7 +194,8 @@ }; - 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 { @@ -368,7 +371,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; @@ -386,7 +390,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 @@ -1726,21 +1726,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: @@ -1765,7 +1768,7 @@ case 'z': case '0': // XMM0 - if (SSELevel >= SSE1) + if (FeatureMap.lookup("sse")) return Size <= 128U; return false; case 'i': @@ -1779,10 +1782,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/Sema/SemaStmtAsm.cpp b/clang/lib/Sema/SemaStmtAsm.cpp --- a/clang/lib/Sema/SemaStmtAsm.cpp +++ b/clang/lib/Sema/SemaStmtAsm.cpp @@ -237,6 +237,44 @@ return SourceLocation(); } +void getFunctionFeatureMap(llvm::StringMap &FeatureMap, + DiagnosticsEngine &Diags, + const TargetInfo &Target, FunctionDecl *FD) { + StringRef TargetCPU = Target.getTargetOpts().CPU; + if (FD) { + if (const auto *TD = FD->getAttr()) { + TargetAttr::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()); + + 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, Diags, TargetCPU, + ParsedAttr.Features); + return; + } + } + + Target.initFeatureMap(FeatureMap, Diags, TargetCPU, + Target.getTargetOpts().Features); +} + StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple, bool IsVolatile, unsigned NumOutputs, unsigned NumInputs, IdentifierInfo **Names, @@ -255,6 +293,10 @@ // The parser verifies that there is a string literal here. assert(AsmString->isAscii()); + llvm::StringMap FeatureMap; + getFunctionFeatureMap(FeatureMap, Diags, Context.getTargetInfo(), + getCurFunctionDecl()); + for (unsigned i = 0; i != NumOutputs; i++) { StringLiteral *Literal = Constraints[i]; assert(Literal->isAscii()); @@ -325,7 +367,8 @@ } unsigned Size = Context.getTypeSize(OutputExpr->getType()); - if (!Context.getTargetInfo().validateOutputSize(Literal->getString(), + if (!Context.getTargetInfo().validateOutputSize(FeatureMap, + Literal->getString(), Size)) { targetDiag(OutputExpr->getBeginLoc(), diag::err_asm_invalid_output_size) << Info.getConstraintStr(); @@ -427,8 +470,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. +}