diff --git a/clang/include/clang/Basic/DiagnosticCommonKinds.td b/clang/include/clang/Basic/DiagnosticCommonKinds.td index de758cbe679dc..60dc459d7b5b4 100644 --- a/clang/include/clang/Basic/DiagnosticCommonKinds.td +++ b/clang/include/clang/Basic/DiagnosticCommonKinds.td @@ -309,6 +309,39 @@ def err_asm_invalid_type : Error< def err_ms_asm_bitfield_unsupported : Error< "an inline asm block cannot have an operand which is a bit-field">; +def asm_invalid_constraint_generic : TextSubstitution< + "invalid %select{input|output}0 constraint '%1' in asm">; +def err_asm_invalid_constraint : Error< + "%sub{asm_invalid_constraint_generic}0,1">; +def err_asm_invalid_constraint_start : Error< + "%sub{asm_invalid_constraint_generic}0,1: output constraint must start with" + " '=' or '+'">; +def err_asm_invalid_constraint_rw_clobber : Error< + "%sub{asm_invalid_constraint_generic}0,1: early clobber with a read-write" + " constraint must be a register">; +def err_asm_invalid_constraint_mem_or_reg : Error< + "%sub{asm_invalid_constraint_generic}0,1: constraint must allow either" + " memory or register operands">; +def err_asm_invalid_constraint_missing_bracket : Error< + "%sub{asm_invalid_constraint_generic}0,1: missing ']'">; +def err_asm_invalid_constraint_wrong_symbol : Error< + "%sub{asm_invalid_constraint_generic}0,1: no matching output constraint" + " with the specified name">; +def err_asm_invalid_constraint_empty : Error< + "%sub{asm_invalid_constraint_generic}0,1: empty constraint has been" + " provided">; +def err_asm_invalid_constraint_oob : Error< + "%sub{asm_invalid_constraint_generic}0,1: the index is out of bounds">; +def err_asm_invalid_constraint_missing : Error< + "%sub{asm_invalid_constraint_generic}0,1: references non-existent output" + " constraint">; +def err_asm_invalid_constraint_wrongly_tied : Error< + "%sub{asm_invalid_constraint_generic}0,1: tied constraint must be tied to" + " the same operand referenced to by the number">; +def err_asm_invalid_constraint_output_only : Error< + "%sub{asm_invalid_constraint_generic}0,1: must refer to an output-only" + " operand">; + def warn_stack_clash_protection_inline_asm : Warning< "unable to protect inline asm that clobbers stack pointer against stack " "clash">, InGroup>; diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 25a87078a5709..3cb5b05d23dd0 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -9280,12 +9280,8 @@ let CategoryName = "Inline Assembly Issue" in { : Error<"cannot pass a pointer-to-member through register-constrained " "inline assembly parameter">; def err_asm_invalid_lvalue_in_output : Error<"invalid lvalue in asm output">; - def err_asm_invalid_output_constraint : Error< - "invalid output constraint '%0' in asm">; def err_asm_invalid_lvalue_in_input : Error< "invalid lvalue in asm input for constraint '%0'">; - def err_asm_invalid_input_constraint : Error< - "invalid input constraint '%0' in asm">; def err_asm_tying_incompatible_types : Error< "unsupported inline asm: input with type " "%diff{$ matching output with type $|}0,1">; diff --git a/clang/include/clang/Basic/TargetInfo.h b/clang/include/clang/Basic/TargetInfo.h index 9b0ae2102e098..c8e810c6f5d83 100644 --- a/clang/include/clang/Basic/TargetInfo.h +++ b/clang/include/clang/Basic/TargetInfo.h @@ -17,6 +17,7 @@ #include "clang/Basic/AddressSpaces.h" #include "clang/Basic/BitmaskEnum.h" #include "clang/Basic/CodeGenOptions.h" +#include "clang/Basic/DiagnosticIDs.h" #include "clang/Basic/LLVM.h" #include "clang/Basic/LangOptions.h" #include "clang/Basic/Specifiers.h" @@ -1196,10 +1197,12 @@ class TargetInfo : public TransferrableTargetInfo, // validateOutputConstraint, validateInputConstraint - Checks that // a constraint is valid and provides information about it. - // FIXME: These should return a real error instead of just true/false. - bool validateOutputConstraint(ConstraintInfo &Info) const; - bool validateInputConstraint(MutableArrayRef OutputConstraints, - ConstraintInfo &info) const; + bool validateOutputConstraint(ConstraintInfo &Info, + llvm::StringMap *FeatureMap, + diag::kind &Diag) const; + bool validateInputConstraint( + MutableArrayRef OutputConstraints, ConstraintInfo &Info, + llvm::StringMap *FeatureMap, diag::kind &Diag) const; virtual bool validateOutputSize(const llvm::StringMap &FeatureMap, StringRef /*Constraint*/, @@ -1219,13 +1222,14 @@ class TargetInfo : public TransferrableTargetInfo, std::string &/*SuggestedModifier*/) const { return true; } - virtual bool - validateAsmConstraint(const char *&Name, - TargetInfo::ConstraintInfo &info) const = 0; + virtual bool validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &Info, + llvm::StringMap *FeatureMap, + diag::kind &Diag) const = 0; bool resolveSymbolicName(const char *&Name, ArrayRef OutputConstraints, - unsigned &Index) const; + unsigned &Index, diag::kind &Diag) const; // Constraint parm will be left pointing at the last character of // the constraint. In practice, it won't be changed unless the diff --git a/clang/lib/Basic/TargetInfo.cpp b/clang/lib/Basic/TargetInfo.cpp index 29f5cd14e46e1..adc168410bfe5 100644 --- a/clang/lib/Basic/TargetInfo.cpp +++ b/clang/lib/Basic/TargetInfo.cpp @@ -722,11 +722,15 @@ StringRef TargetInfo::getNormalizedGCCRegisterName(StringRef Name, return Name; } -bool TargetInfo::validateOutputConstraint(ConstraintInfo &Info) const { +bool TargetInfo::validateOutputConstraint(ConstraintInfo &Info, + llvm::StringMap *FeatureMap, + diag::kind &Diag) const { const char *Name = Info.getConstraintStr().c_str(); // An output constraint must start with '=' or '+' - if (*Name != '=' && *Name != '+') + if (*Name != '=' && *Name != '+') { + Diag = diag::err_asm_invalid_constraint_start; return false; + } if (*Name == '+') Info.setIsReadWrite(); @@ -735,7 +739,7 @@ bool TargetInfo::validateOutputConstraint(ConstraintInfo &Info) const { while (*Name) { switch (*Name) { default: - if (!validateAsmConstraint(Name, Info)) { + if (!validateAsmConstraint(Name, Info, FeatureMap, Diag)) { // FIXME: We temporarily return false // so we can add more constraints as we hit it. // Eventually, an unknown constraint should just be treated as 'g'. @@ -788,17 +792,23 @@ bool TargetInfo::validateOutputConstraint(ConstraintInfo &Info) const { // Early clobber with a read-write constraint which doesn't permit registers // is invalid. - if (Info.earlyClobber() && Info.isReadWrite() && !Info.allowsRegister()) + if (Info.earlyClobber() && Info.isReadWrite() && !Info.allowsRegister()) { + Diag = diag::err_asm_invalid_constraint_rw_clobber; return false; + } // If a constraint allows neither memory nor register operands it contains // only modifiers. Reject it. - return Info.allowsMemory() || Info.allowsRegister(); + if (!Info.allowsMemory() && !Info.allowsRegister()) { + Diag = diag::err_asm_invalid_constraint_mem_or_reg; + return false; + } + return true; } bool TargetInfo::resolveSymbolicName(const char *&Name, ArrayRef OutputConstraints, - unsigned &Index) const { + unsigned &Index, diag::kind &Diag) const { assert(*Name == '[' && "Symbolic name did not start with '['"); Name++; const char *Start = Name; @@ -807,6 +817,7 @@ bool TargetInfo::resolveSymbolicName(const char *&Name, if (!*Name) { // Missing ']' + Diag = diag::err_asm_invalid_constraint_missing_bracket; return false; } @@ -816,16 +827,19 @@ bool TargetInfo::resolveSymbolicName(const char *&Name, if (SymbolicName == OutputConstraints[Index].getName()) return true; + Diag = diag::err_asm_invalid_constraint_wrong_symbol; return false; } bool TargetInfo::validateInputConstraint( - MutableArrayRef OutputConstraints, - ConstraintInfo &Info) const { + MutableArrayRef OutputConstraints, ConstraintInfo &Info, + llvm::StringMap *FeatureMap, diag::kind &Diag) const { const char *Name = Info.ConstraintStr.c_str(); - if (!*Name) + if (!*Name) { + Diag = diag::err_asm_invalid_constraint_empty; return false; + } while (*Name) { switch (*Name) { @@ -838,25 +852,34 @@ bool TargetInfo::validateInputConstraint( const char *DigitEnd = Name; unsigned i; if (StringRef(DigitStart, DigitEnd - DigitStart + 1) - .getAsInteger(10, i)) + .getAsInteger(10, i)) { + Diag = diag::err_asm_invalid_constraint_oob; return false; + } // Check if matching constraint is out of bounds. - if (i >= OutputConstraints.size()) return false; + if (i >= OutputConstraints.size()) { + Diag = diag::err_asm_invalid_constraint_missing; + return false; + } // A number must refer to an output only operand. - if (OutputConstraints[i].isReadWrite()) + if (OutputConstraints[i].isReadWrite()) { + Diag = diag::err_asm_invalid_constraint_output_only; return false; + } // If the constraint is already tied, it must be tied to the // same operand referenced to by the number. - if (Info.hasTiedOperand() && Info.getTiedOperand() != i) + if (Info.hasTiedOperand() && Info.getTiedOperand() != i) { + Diag = diag::err_asm_invalid_constraint_wrongly_tied; return false; + } // The constraint should have the same info as the respective // output constraint. Info.setTiedOperand(i, OutputConstraints[i]); - } else if (!validateAsmConstraint(Name, Info)) { + } else if (!validateAsmConstraint(Name, Info, FeatureMap, Diag)) { // FIXME: This error return is in place temporarily so we can // add more constraints as we hit it. Eventually, an unknown // constraint should just be treated as 'g'. @@ -865,17 +888,21 @@ bool TargetInfo::validateInputConstraint( break; case '[': { unsigned Index = 0; - if (!resolveSymbolicName(Name, OutputConstraints, Index)) + if (!resolveSymbolicName(Name, OutputConstraints, Index, Diag)) return false; // If the constraint is already tied, it must be tied to the // same operand referenced to by the number. - if (Info.hasTiedOperand() && Info.getTiedOperand() != Index) + if (Info.hasTiedOperand() && Info.getTiedOperand() != Index) { + Diag = diag::err_asm_invalid_constraint_wrongly_tied; return false; + } // A number must refer to an output only operand. - if (OutputConstraints[Index].isReadWrite()) + if (OutputConstraints[Index].isReadWrite()) { + Diag = diag::err_asm_invalid_constraint_output_only; return false; + } Info.setTiedOperand(Index, OutputConstraints[Index]); break; @@ -896,7 +923,7 @@ bool TargetInfo::validateInputConstraint( case 'N': case 'O': case 'P': - if (!validateAsmConstraint(Name, Info)) + if (!validateAsmConstraint(Name, Info, FeatureMap, Diag)) return false; break; case 'r': // general register. diff --git a/clang/lib/Basic/Targets/AArch64.cpp b/clang/lib/Basic/Targets/AArch64.cpp index 31d8121b91d10..4cd2b7fa821ca 100644 --- a/clang/lib/Basic/Targets/AArch64.cpp +++ b/clang/lib/Basic/Targets/AArch64.cpp @@ -1339,8 +1339,10 @@ AArch64TargetInfo::convertConstraint(const char *&Constraint) const { return R; } -bool AArch64TargetInfo::validateAsmConstraint( - const char *&Name, TargetInfo::ConstraintInfo &Info) const { +bool AArch64TargetInfo::validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &Info, + llvm::StringMap *FeatureMap, + diag::kind &Diag) const { switch (*Name) { default: return false; diff --git a/clang/lib/Basic/Targets/AArch64.h b/clang/lib/Basic/Targets/AArch64.h index 71510fe289510..2cea2d4a3852a 100644 --- a/clang/lib/Basic/Targets/AArch64.h +++ b/clang/lib/Basic/Targets/AArch64.h @@ -176,7 +176,9 @@ class LLVM_LIBRARY_VISIBILITY AArch64TargetInfo : public TargetInfo { std::string convertConstraint(const char *&Constraint) const override; bool validateAsmConstraint(const char *&Name, - TargetInfo::ConstraintInfo &Info) const override; + TargetInfo::ConstraintInfo &Info, + llvm::StringMap *FeatureMap, + diag::kind &Diag) const override; bool validateConstraintModifier(StringRef Constraint, char Modifier, unsigned Size, std::string &SuggestedModifier) const override; diff --git a/clang/lib/Basic/Targets/AMDGPU.h b/clang/lib/Basic/Targets/AMDGPU.h index 94d9ba93ed226..75ddcb3d582a2 100644 --- a/clang/lib/Basic/Targets/AMDGPU.h +++ b/clang/lib/Basic/Targets/AMDGPU.h @@ -137,7 +137,9 @@ class LLVM_LIBRARY_VISIBILITY AMDGPUTargetInfo final : public TargetInfo { /// {s[n:m]} /// {a[n:m]} bool validateAsmConstraint(const char *&Name, - TargetInfo::ConstraintInfo &Info) const override { + TargetInfo::ConstraintInfo &Info, + llvm::StringMap *FeatureMap, + diag::kind &Diag) const override { static const ::llvm::StringSet<> SpecialRegs({ "exec", "vcc", "flat_scratch", "m0", "scc", "tba", "tma", "flat_scratch_lo", "flat_scratch_hi", "vcc_lo", "vcc_hi", "exec_lo", @@ -232,7 +234,8 @@ class LLVM_LIBRARY_VISIBILITY AMDGPUTargetInfo final : public TargetInfo { const char *Begin = Constraint; TargetInfo::ConstraintInfo Info("", ""); - if (validateAsmConstraint(Constraint, Info)) + diag::kind AsmDiag; + if (validateAsmConstraint(Constraint, Info, nullptr, AsmDiag)) return std::string(Begin).substr(0, Constraint - Begin + 1); Constraint = Begin; diff --git a/clang/lib/Basic/Targets/ARC.h b/clang/lib/Basic/Targets/ARC.h index fcbfdd6eec586..fc4755f48fd4a 100644 --- a/clang/lib/Basic/Targets/ARC.h +++ b/clang/lib/Basic/Targets/ARC.h @@ -64,7 +64,9 @@ class LLVM_LIBRARY_VISIBILITY ARCTargetInfo : public TargetInfo { } bool validateAsmConstraint(const char *&Name, - TargetInfo::ConstraintInfo &Info) const override { + TargetInfo::ConstraintInfo &Info, + llvm::StringMap *FeatureMap, + diag::kind &Diag) const override { return false; } diff --git a/clang/lib/Basic/Targets/ARM.cpp b/clang/lib/Basic/Targets/ARM.cpp index 7423626d7c3cb..f1f1ccd3ca103 100644 --- a/clang/lib/Basic/Targets/ARM.cpp +++ b/clang/lib/Basic/Targets/ARM.cpp @@ -1136,8 +1136,10 @@ ArrayRef ARMTargetInfo::getGCCRegAliases() const { return llvm::ArrayRef(GCCRegAliases); } -bool ARMTargetInfo::validateAsmConstraint( - const char *&Name, TargetInfo::ConstraintInfo &Info) const { +bool ARMTargetInfo::validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &Info, + llvm::StringMap *FeatureMap, + diag::kind &Diag) const { switch (*Name) { default: break; diff --git a/clang/lib/Basic/Targets/ARM.h b/clang/lib/Basic/Targets/ARM.h index df9855a52e61c..59e1b7ad64d5f 100644 --- a/clang/lib/Basic/Targets/ARM.h +++ b/clang/lib/Basic/Targets/ARM.h @@ -204,7 +204,9 @@ class LLVM_LIBRARY_VISIBILITY ARMTargetInfo : public TargetInfo { ArrayRef getGCCRegNames() const override; ArrayRef getGCCRegAliases() const override; bool validateAsmConstraint(const char *&Name, - TargetInfo::ConstraintInfo &Info) const override; + TargetInfo::ConstraintInfo &Info, + llvm::StringMap *FeatureMap, + diag::kind &Diag) const override; std::string convertConstraint(const char *&Constraint) const override; bool validateConstraintModifier(StringRef Constraint, char Modifier, unsigned Size, diff --git a/clang/lib/Basic/Targets/AVR.h b/clang/lib/Basic/Targets/AVR.h index feeb04f37eeba..6e2061960e591 100644 --- a/clang/lib/Basic/Targets/AVR.h +++ b/clang/lib/Basic/Targets/AVR.h @@ -94,7 +94,9 @@ class LLVM_LIBRARY_VISIBILITY AVRTargetInfo : public TargetInfo { } bool validateAsmConstraint(const char *&Name, - TargetInfo::ConstraintInfo &Info) const override { + TargetInfo::ConstraintInfo &Info, + llvm::StringMap *FeatureMap, + diag::kind &Diag) const override { // There aren't any multi-character AVR specific constraints. if (StringRef(Name).size() > 1) return false; diff --git a/clang/lib/Basic/Targets/BPF.h b/clang/lib/Basic/Targets/BPF.h index d19b37dd4df7a..94a0fe90a3c68 100644 --- a/clang/lib/Basic/Targets/BPF.h +++ b/clang/lib/Basic/Targets/BPF.h @@ -72,7 +72,9 @@ class LLVM_LIBRARY_VISIBILITY BPFTargetInfo : public TargetInfo { } bool validateAsmConstraint(const char *&Name, - TargetInfo::ConstraintInfo &Info) const override { + TargetInfo::ConstraintInfo &Info, + llvm::StringMap *FeatureMap, + diag::kind &Diag) const override { switch (*Name) { default: break; diff --git a/clang/lib/Basic/Targets/CSKY.cpp b/clang/lib/Basic/Targets/CSKY.cpp index c8bf8b9234d24..f6af91bbe278b 100644 --- a/clang/lib/Basic/Targets/CSKY.cpp +++ b/clang/lib/Basic/Targets/CSKY.cpp @@ -289,8 +289,10 @@ ArrayRef CSKYTargetInfo::getGCCRegAliases() const { return llvm::ArrayRef(GCCRegAliases); } -bool CSKYTargetInfo::validateAsmConstraint( - const char *&Name, TargetInfo::ConstraintInfo &Info) const { +bool CSKYTargetInfo::validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &Info, + llvm::StringMap *FeatureMap, + diag::kind &Diag) const { switch (*Name) { default: return false; diff --git a/clang/lib/Basic/Targets/CSKY.h b/clang/lib/Basic/Targets/CSKY.h index 94d4eeb9a1fff..971bdc5e8b18d 100644 --- a/clang/lib/Basic/Targets/CSKY.h +++ b/clang/lib/Basic/Targets/CSKY.h @@ -80,7 +80,9 @@ class LLVM_LIBRARY_VISIBILITY CSKYTargetInfo : public TargetInfo { } bool validateAsmConstraint(const char *&Name, - TargetInfo::ConstraintInfo &info) const override; + TargetInfo::ConstraintInfo &Info, + llvm::StringMap *FeatureMap, + diag::kind &Diag) const override; std::string_view getClobbers() const override { return ""; } diff --git a/clang/lib/Basic/Targets/DirectX.h b/clang/lib/Basic/Targets/DirectX.h index a084e2823453f..6a10409f844c3 100644 --- a/clang/lib/Basic/Targets/DirectX.h +++ b/clang/lib/Basic/Targets/DirectX.h @@ -83,7 +83,9 @@ class LLVM_LIBRARY_VISIBILITY DirectXTargetInfo : public TargetInfo { } bool validateAsmConstraint(const char *&Name, - TargetInfo::ConstraintInfo &info) const override { + TargetInfo::ConstraintInfo &Info, + llvm::StringMap *FeatureMap, + diag::kind &Diag) const override { return true; } diff --git a/clang/lib/Basic/Targets/Hexagon.h b/clang/lib/Basic/Targets/Hexagon.h index cdb47dbae7999..1dc8cb498603d 100644 --- a/clang/lib/Basic/Targets/Hexagon.h +++ b/clang/lib/Basic/Targets/Hexagon.h @@ -68,7 +68,9 @@ class LLVM_LIBRARY_VISIBILITY HexagonTargetInfo : public TargetInfo { ArrayRef getTargetBuiltins() const override; bool validateAsmConstraint(const char *&Name, - TargetInfo::ConstraintInfo &Info) const override { + TargetInfo::ConstraintInfo &Info, + llvm::StringMap *FeatureMap, + diag::kind &Diag) const override { switch (*Name) { case 'v': case 'q': diff --git a/clang/lib/Basic/Targets/Lanai.h b/clang/lib/Basic/Targets/Lanai.h index 144cbc7de9893..aea2feca2336a 100644 --- a/clang/lib/Basic/Targets/Lanai.h +++ b/clang/lib/Basic/Targets/Lanai.h @@ -83,7 +83,9 @@ class LLVM_LIBRARY_VISIBILITY LanaiTargetInfo : public TargetInfo { } bool validateAsmConstraint(const char *&Name, - TargetInfo::ConstraintInfo &info) const override { + TargetInfo::ConstraintInfo &Info, + llvm::StringMap *FeatureMap, + diag::kind &Diag) const override { return false; } diff --git a/clang/lib/Basic/Targets/Le64.h b/clang/lib/Basic/Targets/Le64.h index 45f6a4e9dd75d..2c1880470d1d9 100644 --- a/clang/lib/Basic/Targets/Le64.h +++ b/clang/lib/Basic/Targets/Le64.h @@ -52,7 +52,9 @@ class LLVM_LIBRARY_VISIBILITY Le64TargetInfo : public TargetInfo { } bool validateAsmConstraint(const char *&Name, - TargetInfo::ConstraintInfo &Info) const override { + TargetInfo::ConstraintInfo &Info, + llvm::StringMap *FeatureMap, + diag::kind &Diag) const override { return false; } diff --git a/clang/lib/Basic/Targets/LoongArch.cpp b/clang/lib/Basic/Targets/LoongArch.cpp index 280bd1d8033cc..f50f91306f1eb 100644 --- a/clang/lib/Basic/Targets/LoongArch.cpp +++ b/clang/lib/Basic/Targets/LoongArch.cpp @@ -119,7 +119,8 @@ LoongArchTargetInfo::getGCCRegAliases() const { } bool LoongArchTargetInfo::validateAsmConstraint( - const char *&Name, TargetInfo::ConstraintInfo &Info) const { + const char *&Name, TargetInfo::ConstraintInfo &Info, + llvm::StringMap *FeatureMap, diag::kind &Diag) const { // See the GCC definitions here: // https://gcc.gnu.org/onlinedocs/gccint/Machine-Constraints.html // Note that the 'm' constraint is handled in TargetInfo. diff --git a/clang/lib/Basic/Targets/LoongArch.h b/clang/lib/Basic/Targets/LoongArch.h index 5fc223483951e..49ef549f85e94 100644 --- a/clang/lib/Basic/Targets/LoongArch.h +++ b/clang/lib/Basic/Targets/LoongArch.h @@ -81,7 +81,9 @@ class LLVM_LIBRARY_VISIBILITY LoongArchTargetInfo : public TargetInfo { ArrayRef getGCCRegAliases() const override; bool validateAsmConstraint(const char *&Name, - TargetInfo::ConstraintInfo &Info) const override; + TargetInfo::ConstraintInfo &Info, + llvm::StringMap *FeatureMap, + diag::kind &Diag) const override; std::string convertConstraint(const char *&Constraint) const override; bool hasBitIntType() const override { return true; } diff --git a/clang/lib/Basic/Targets/M68k.cpp b/clang/lib/Basic/Targets/M68k.cpp index 8b8bf97d6f99a..a61dd0003f363 100644 --- a/clang/lib/Basic/Targets/M68k.cpp +++ b/clang/lib/Basic/Targets/M68k.cpp @@ -144,47 +144,49 @@ ArrayRef M68kTargetInfo::getGCCRegAliases() const { return llvm::ArrayRef(GCCRegAliases); } -bool M68kTargetInfo::validateAsmConstraint( - const char *&Name, TargetInfo::ConstraintInfo &info) const { +bool M68kTargetInfo::validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &Info, + llvm::StringMap *FeatureMap, + diag::kind &Diag) const { switch (*Name) { case 'a': // address register case 'd': // data register - info.setAllowsRegister(); + Info.setAllowsRegister(); return true; case 'I': // constant integer in the range [1,8] - info.setRequiresImmediate(1, 8); + Info.setRequiresImmediate(1, 8); return true; case 'J': // constant signed 16-bit integer - info.setRequiresImmediate(std::numeric_limits::min(), + Info.setRequiresImmediate(std::numeric_limits::min(), std::numeric_limits::max()); return true; case 'K': // constant that is NOT in the range of [-0x80, 0x80) - info.setRequiresImmediate(); + Info.setRequiresImmediate(); return true; case 'L': // constant integer in the range [-8,-1] - info.setRequiresImmediate(-8, -1); + Info.setRequiresImmediate(-8, -1); return true; case 'M': // constant that is NOT in the range of [-0x100, 0x100] - info.setRequiresImmediate(); + Info.setRequiresImmediate(); return true; case 'N': // constant integer in the range [24,31] - info.setRequiresImmediate(24, 31); + Info.setRequiresImmediate(24, 31); return true; case 'O': // constant integer 16 - info.setRequiresImmediate(16); + Info.setRequiresImmediate(16); return true; case 'P': // constant integer in the range [8,15] - info.setRequiresImmediate(8, 15); + Info.setRequiresImmediate(8, 15); return true; case 'C': ++Name; switch (*Name) { case '0': // constant integer 0 - info.setRequiresImmediate(0); + Info.setRequiresImmediate(0); return true; case 'i': // constant integer case 'j': // integer constant that doesn't fit in 16 bits - info.setRequiresImmediate(); + Info.setRequiresImmediate(); return true; default: break; @@ -194,7 +196,7 @@ bool M68kTargetInfo::validateAsmConstraint( case 'U': // address register indirect w/ constant offset addressing // TODO: Handle 'S' (basically 'm' when pc-rel is enforced) when // '-mpcrel' flag is properly handled by the driver. - info.setAllowsMemory(); + Info.setAllowsMemory(); return true; default: break; diff --git a/clang/lib/Basic/Targets/M68k.h b/clang/lib/Basic/Targets/M68k.h index b732add77e034..602033e29ebc8 100644 --- a/clang/lib/Basic/Targets/M68k.h +++ b/clang/lib/Basic/Targets/M68k.h @@ -50,7 +50,9 @@ class LLVM_LIBRARY_VISIBILITY M68kTargetInfo : public TargetInfo { ArrayRef getGCCRegAliases() const override; std::string convertConstraint(const char *&Constraint) const override; bool validateAsmConstraint(const char *&Name, - TargetInfo::ConstraintInfo &info) const override; + TargetInfo::ConstraintInfo &Info, + llvm::StringMap *FeatureMap, + diag::kind &Diag) const override; std::optional handleAsmEscapedChar(char EscChar) const override; std::string_view getClobbers() const override; BuiltinVaListKind getBuiltinVaListKind() const override; diff --git a/clang/lib/Basic/Targets/MSP430.h b/clang/lib/Basic/Targets/MSP430.h index 25639b8c1e0ad..f23548e16f9cd 100644 --- a/clang/lib/Basic/Targets/MSP430.h +++ b/clang/lib/Basic/Targets/MSP430.h @@ -75,7 +75,9 @@ class LLVM_LIBRARY_VISIBILITY MSP430TargetInfo : public TargetInfo { } bool validateAsmConstraint(const char *&Name, - TargetInfo::ConstraintInfo &info) const override { + TargetInfo::ConstraintInfo &Info, + llvm::StringMap *FeatureMap, + diag::kind &Diag) const override { // FIXME: implement switch (*Name) { case 'K': // the constant 1 diff --git a/clang/lib/Basic/Targets/Mips.h b/clang/lib/Basic/Targets/Mips.h index b6f110249fa78..3bc3453e295be 100644 --- a/clang/lib/Basic/Targets/Mips.h +++ b/clang/lib/Basic/Targets/Mips.h @@ -235,7 +235,9 @@ class LLVM_LIBRARY_VISIBILITY MipsTargetInfo : public TargetInfo { } bool validateAsmConstraint(const char *&Name, - TargetInfo::ConstraintInfo &Info) const override { + TargetInfo::ConstraintInfo &Info, + llvm::StringMap *FeatureMap, + diag::kind &Diag) const override { switch (*Name) { default: return false; diff --git a/clang/lib/Basic/Targets/NVPTX.h b/clang/lib/Basic/Targets/NVPTX.h index f476d49047c01..a8f1b5d73dcd9 100644 --- a/clang/lib/Basic/Targets/NVPTX.h +++ b/clang/lib/Basic/Targets/NVPTX.h @@ -95,7 +95,9 @@ class LLVM_LIBRARY_VISIBILITY NVPTXTargetInfo : public TargetInfo { } bool validateAsmConstraint(const char *&Name, - TargetInfo::ConstraintInfo &Info) const override { + TargetInfo::ConstraintInfo &Info, + llvm::StringMap *FeatureMap, + diag::kind &Diag) const override { switch (*Name) { default: return false; diff --git a/clang/lib/Basic/Targets/PNaCl.h b/clang/lib/Basic/Targets/PNaCl.h index 595c4d83b1d1c..6b6286007a094 100644 --- a/clang/lib/Basic/Targets/PNaCl.h +++ b/clang/lib/Basic/Targets/PNaCl.h @@ -65,7 +65,9 @@ class LLVM_LIBRARY_VISIBILITY PNaClTargetInfo : public TargetInfo { ArrayRef getGCCRegAliases() const override; bool validateAsmConstraint(const char *&Name, - TargetInfo::ConstraintInfo &Info) const override { + TargetInfo::ConstraintInfo &Info, + llvm::StringMap *FeatureMap, + diag::kind &Diag) const override { return false; } diff --git a/clang/lib/Basic/Targets/PPC.h b/clang/lib/Basic/Targets/PPC.h index fc23c30c68523..f6f33ef1d3fc3 100644 --- a/clang/lib/Basic/Targets/PPC.h +++ b/clang/lib/Basic/Targets/PPC.h @@ -210,7 +210,9 @@ class LLVM_LIBRARY_VISIBILITY PPCTargetInfo : public TargetInfo { ArrayRef getGCCAddlRegNames() const override; bool validateAsmConstraint(const char *&Name, - TargetInfo::ConstraintInfo &Info) const override { + TargetInfo::ConstraintInfo &Info, + llvm::StringMap *FeatureMap, + diag::kind &Diag) const override { switch (*Name) { default: return false; diff --git a/clang/lib/Basic/Targets/RISCV.cpp b/clang/lib/Basic/Targets/RISCV.cpp index 25ae7d64b577e..2fdd14fad4267 100644 --- a/clang/lib/Basic/Targets/RISCV.cpp +++ b/clang/lib/Basic/Targets/RISCV.cpp @@ -71,8 +71,10 @@ ArrayRef RISCVTargetInfo::getGCCRegAliases() const { return llvm::ArrayRef(GCCRegAliases); } -bool RISCVTargetInfo::validateAsmConstraint( - const char *&Name, TargetInfo::ConstraintInfo &Info) const { +bool RISCVTargetInfo::validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &Info, + llvm::StringMap *FeatureMap, + diag::kind &Diag) const { switch (*Name) { default: return false; diff --git a/clang/lib/Basic/Targets/RISCV.h b/clang/lib/Basic/Targets/RISCV.h index d0e9cdc6da07b..ffa50c7dd0a98 100644 --- a/clang/lib/Basic/Targets/RISCV.h +++ b/clang/lib/Basic/Targets/RISCV.h @@ -89,7 +89,9 @@ class RISCVTargetInfo : public TargetInfo { ArrayRef getGCCRegAliases() const override; bool validateAsmConstraint(const char *&Name, - TargetInfo::ConstraintInfo &Info) const override; + TargetInfo::ConstraintInfo &Info, + llvm::StringMap *FeatureMap, + diag::kind &Diag) const override; std::string convertConstraint(const char *&Constraint) const override; diff --git a/clang/lib/Basic/Targets/SPIR.cpp b/clang/lib/Basic/Targets/SPIR.cpp index 040303983594f..b45ba0b532805 100644 --- a/clang/lib/Basic/Targets/SPIR.cpp +++ b/clang/lib/Basic/Targets/SPIR.cpp @@ -72,8 +72,9 @@ bool SPIRV64AMDGCNTargetInfo::initFeatureMap( } bool SPIRV64AMDGCNTargetInfo::validateAsmConstraint( - const char *&Name, TargetInfo::ConstraintInfo &Info) const { - return AMDGPUTI.validateAsmConstraint(Name, Info); + const char *&Name, TargetInfo::ConstraintInfo &Info, + llvm::StringMap *FeatureMap, diag::kind &Diag) const { + return AMDGPUTI.validateAsmConstraint(Name, Info, FeatureMap, Diag); } std::string diff --git a/clang/lib/Basic/Targets/SPIR.h b/clang/lib/Basic/Targets/SPIR.h index 37cf9d7921bac..1fd5ca02fe1c9 100644 --- a/clang/lib/Basic/Targets/SPIR.h +++ b/clang/lib/Basic/Targets/SPIR.h @@ -170,7 +170,9 @@ class LLVM_LIBRARY_VISIBILITY BaseSPIRTargetInfo : public TargetInfo { } bool validateAsmConstraint(const char *&Name, - TargetInfo::ConstraintInfo &info) const override { + TargetInfo::ConstraintInfo &Info, + llvm::StringMap *FeatureMap, + diag::kind &Diag) const override { return true; } @@ -401,7 +403,9 @@ class LLVM_LIBRARY_VISIBILITY SPIRV64AMDGCNTargetInfo final const std::vector &) const override; bool validateAsmConstraint(const char *&Name, - TargetInfo::ConstraintInfo &Info) const override; + TargetInfo::ConstraintInfo &Info, + llvm::StringMap *FeatureMap, + diag::kind &Diag) const override; std::string convertConstraint(const char *&Constraint) const override; diff --git a/clang/lib/Basic/Targets/Sparc.h b/clang/lib/Basic/Targets/Sparc.h index 3357bee33e1ac..9f2cc452d57c9 100644 --- a/clang/lib/Basic/Targets/Sparc.h +++ b/clang/lib/Basic/Targets/Sparc.h @@ -58,7 +58,9 @@ class LLVM_LIBRARY_VISIBILITY SparcTargetInfo : public TargetInfo { ArrayRef getGCCRegNames() const override; ArrayRef getGCCRegAliases() const override; bool validateAsmConstraint(const char *&Name, - TargetInfo::ConstraintInfo &info) const override { + TargetInfo::ConstraintInfo &Info, + llvm::StringMap *FeatureMap, + diag::kind &Diag) const override { // FIXME: Implement! switch (*Name) { case 'I': // Signed 13-bit constant @@ -72,7 +74,7 @@ class LLVM_LIBRARY_VISIBILITY SparcTargetInfo : public TargetInfo { case 'f': case 'e': - info.setAllowsRegister(); + Info.setAllowsRegister(); return true; } return false; diff --git a/clang/lib/Basic/Targets/SystemZ.cpp b/clang/lib/Basic/Targets/SystemZ.cpp index 06f08db2eadd4..0f9d9ddf5340c 100644 --- a/clang/lib/Basic/Targets/SystemZ.cpp +++ b/clang/lib/Basic/Targets/SystemZ.cpp @@ -53,8 +53,10 @@ ArrayRef SystemZTargetInfo::getGCCAddlRegNames() const return llvm::ArrayRef(GCCAddlRegNames); } -bool SystemZTargetInfo::validateAsmConstraint( - const char *&Name, TargetInfo::ConstraintInfo &Info) const { +bool SystemZTargetInfo::validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &Info, + llvm::StringMap *FeatureMap, + diag::kind &Diag) const { switch (*Name) { default: return false; diff --git a/clang/lib/Basic/Targets/SystemZ.h b/clang/lib/Basic/Targets/SystemZ.h index 3bc6f2c1d3083..3b097cef94f30 100644 --- a/clang/lib/Basic/Targets/SystemZ.h +++ b/clang/lib/Basic/Targets/SystemZ.h @@ -88,7 +88,9 @@ class LLVM_LIBRARY_VISIBILITY SystemZTargetInfo : public TargetInfo { } bool validateAsmConstraint(const char *&Name, - TargetInfo::ConstraintInfo &info) const override; + TargetInfo::ConstraintInfo &Info, + llvm::StringMap *FeatureMap, + diag::kind &Diag) const override; std::string convertConstraint(const char *&Constraint) const override { switch (Constraint[0]) { diff --git a/clang/lib/Basic/Targets/TCE.h b/clang/lib/Basic/Targets/TCE.h index dcf684fe6dbc0..60e576c550116 100644 --- a/clang/lib/Basic/Targets/TCE.h +++ b/clang/lib/Basic/Targets/TCE.h @@ -110,7 +110,9 @@ class LLVM_LIBRARY_VISIBILITY TCETargetInfo : public TargetInfo { } bool validateAsmConstraint(const char *&Name, - TargetInfo::ConstraintInfo &info) const override { + TargetInfo::ConstraintInfo &Info, + llvm::StringMap *FeatureMap, + diag::kind &Diag) const override { return true; } diff --git a/clang/lib/Basic/Targets/VE.h b/clang/lib/Basic/Targets/VE.h index 7e8fdf6096ef2..e533115bee222 100644 --- a/clang/lib/Basic/Targets/VE.h +++ b/clang/lib/Basic/Targets/VE.h @@ -158,7 +158,9 @@ class LLVM_LIBRARY_VISIBILITY VETargetInfo : public TargetInfo { } bool validateAsmConstraint(const char *&Name, - TargetInfo::ConstraintInfo &Info) const override { + TargetInfo::ConstraintInfo &Info, + llvm::StringMap *FeatureMap, + diag::kind &Diag) const override { switch (*Name) { default: return false; diff --git a/clang/lib/Basic/Targets/WebAssembly.h b/clang/lib/Basic/Targets/WebAssembly.h index e4a449d1ff304..65e2e1decdd22 100644 --- a/clang/lib/Basic/Targets/WebAssembly.h +++ b/clang/lib/Basic/Targets/WebAssembly.h @@ -132,7 +132,9 @@ class LLVM_LIBRARY_VISIBILITY WebAssemblyTargetInfo : public TargetInfo { } bool validateAsmConstraint(const char *&Name, - TargetInfo::ConstraintInfo &Info) const final { + TargetInfo::ConstraintInfo &Info, + llvm::StringMap *FeatureMap, + diag::kind &Diag) const final { return false; } diff --git a/clang/lib/Basic/Targets/X86.cpp b/clang/lib/Basic/Targets/X86.cpp index 036a655a4d073..bf4633327f23b 100644 --- a/clang/lib/Basic/Targets/X86.cpp +++ b/clang/lib/Basic/Targets/X86.cpp @@ -1393,8 +1393,10 @@ static unsigned matchAsmCCConstraint(const char *Name) { return RV; } -bool X86TargetInfo::validateAsmConstraint( - const char *&Name, TargetInfo::ConstraintInfo &Info) const { +bool X86TargetInfo::validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &Info, + llvm::StringMap *FeatureMap, + diag::kind &Diag) const { switch (*Name) { default: return false; diff --git a/clang/lib/Basic/Targets/X86.h b/clang/lib/Basic/Targets/X86.h index 9b2ae87adb2e7..56f0c9f64b80e 100644 --- a/clang/lib/Basic/Targets/X86.h +++ b/clang/lib/Basic/Targets/X86.h @@ -239,7 +239,9 @@ class LLVM_LIBRARY_VISIBILITY X86TargetInfo : public TargetInfo { std::optional getCPUCacheLineSize() const override; bool validateAsmConstraint(const char *&Name, - TargetInfo::ConstraintInfo &info) const override; + TargetInfo::ConstraintInfo &Info, + llvm::StringMap *FeatureMap, + diag::kind &Diag) const override; bool validateGlobalRegisterVariable(StringRef RegName, unsigned RegSize, bool &HasSizeMismatch) const override { diff --git a/clang/lib/Basic/Targets/XCore.h b/clang/lib/Basic/Targets/XCore.h index a58d3e8acf479..4b358a9478a84 100644 --- a/clang/lib/Basic/Targets/XCore.h +++ b/clang/lib/Basic/Targets/XCore.h @@ -64,7 +64,9 @@ class LLVM_LIBRARY_VISIBILITY XCoreTargetInfo : public TargetInfo { } bool validateAsmConstraint(const char *&Name, - TargetInfo::ConstraintInfo &Info) const override { + TargetInfo::ConstraintInfo &Info, + llvm::StringMap *FeatureMap, + diag::kind &Diag) const override { return false; } diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp index 39222c0e65353..1d1c4b73754de 100644 --- a/clang/lib/CodeGen/CGStmt.cpp +++ b/clang/lib/CodeGen/CGStmt.cpp @@ -2280,6 +2280,7 @@ static std::string SimplifyConstraint(const char *Constraint, const TargetInfo &Target, SmallVectorImpl *OutCons=nullptr) { std::string Result; + diag::kind Diag; while (*Constraint) { switch (*Constraint) { @@ -2313,8 +2314,9 @@ SimplifyConstraint(const char *Constraint, const TargetInfo &Target, assert(OutCons && "Must pass output names to constraints with a symbolic name"); unsigned Index; - bool result = Target.resolveSymbolicName(Constraint, *OutCons, Index); - assert(result && "Could not resolve symbolic name"); (void)result; + [[maybe_unused]] bool result = + Target.resolveSymbolicName(Constraint, *OutCons, Index, Diag); + assert(result && "Could not resolve symbolic name"); Result += llvm::utostr(Index); break; } @@ -2351,7 +2353,8 @@ AddVariableConstraints(const std::string &Constraint, const Expr &AsmExpr, // We're using validateOutputConstraint here because we only care if // this is a register constraint. TargetInfo::ConstraintInfo Info(Constraint, ""); - if (Target.validateOutputConstraint(Info) && + diag::kind AsmDiag; + if (Target.validateOutputConstraint(Info, nullptr, AsmDiag) && !Info.allowsRegister()) { CGM.ErrorUnsupported(&Stmt, "__asm__"); return Constraint; @@ -2626,14 +2629,20 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { SmallVector OutputConstraintInfos; SmallVector InputConstraintInfos; + const auto *FD = dyn_cast_if_present(CurCodeDecl); + llvm::StringMap FeatureMap; + CGM.getContext().getFunctionFeatureMap(FeatureMap, FD); + bool IsHipStdPar = getLangOpts().HIPStdPar && getLangOpts().CUDAIsDevice; bool IsValidTargetAsm = true; + diag::kind AsmDiag; for (unsigned i = 0, e = S.getNumOutputs(); i != e && IsValidTargetAsm; i++) { StringRef Name; if (const GCCAsmStmt *GAS = dyn_cast(&S)) Name = GAS->getOutputName(i); TargetInfo::ConstraintInfo Info(S.getOutputConstraint(i), Name); - bool IsValid = getTarget().validateOutputConstraint(Info); (void)IsValid; + bool IsValid = + getTarget().validateOutputConstraint(Info, &FeatureMap, AsmDiag); if (IsHipStdPar && !IsValid) IsValidTargetAsm = false; else @@ -2646,8 +2655,8 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { if (const GCCAsmStmt *GAS = dyn_cast(&S)) Name = GAS->getInputName(i); TargetInfo::ConstraintInfo Info(S.getInputConstraint(i), Name); - bool IsValid = - getTarget().validateInputConstraint(OutputConstraintInfos, Info); + bool IsValid = getTarget().validateInputConstraint( + OutputConstraintInfos, Info, &FeatureMap, AsmDiag); if (IsHipStdPar && !IsValid) IsValidTargetAsm = false; else diff --git a/clang/lib/Sema/SemaStmtAsm.cpp b/clang/lib/Sema/SemaStmtAsm.cpp index 32d42f3c3f3bb..72cc4888bc4d2 100644 --- a/clang/lib/Sema/SemaStmtAsm.cpp +++ b/clang/lib/Sema/SemaStmtAsm.cpp @@ -271,11 +271,12 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple, OutputName = Names[i]->getName(); TargetInfo::ConstraintInfo Info(Literal->getString(), OutputName); - if (!Context.getTargetInfo().validateOutputConstraint(Info) && + diag::kind AsmDiag = diag::err_asm_invalid_constraint; + if (!Context.getTargetInfo().validateOutputConstraint(Info, &FeatureMap, + AsmDiag) && !(LangOpts.HIPStdPar && LangOpts.CUDAIsDevice)) { - targetDiag(Literal->getBeginLoc(), - diag::err_asm_invalid_output_constraint) - << Info.getConstraintStr(); + targetDiag(Literal->getBeginLoc(), AsmDiag) + << 1 << Info.getConstraintStr(); return new (Context) GCCAsmStmt(Context, AsmLoc, IsSimple, IsVolatile, NumOutputs, NumInputs, Names, Constraints, Exprs.data(), AsmString, @@ -363,10 +364,11 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple, InputName = Names[i]->getName(); TargetInfo::ConstraintInfo Info(Literal->getString(), InputName); - if (!Context.getTargetInfo().validateInputConstraint(OutputConstraintInfos, - Info)) { - targetDiag(Literal->getBeginLoc(), diag::err_asm_invalid_input_constraint) - << Info.getConstraintStr(); + diag::kind AsmDiag = diag::err_asm_invalid_constraint; + if (!Context.getTargetInfo().validateInputConstraint( + OutputConstraintInfos, Info, &FeatureMap, AsmDiag)) { + targetDiag(Literal->getBeginLoc(), AsmDiag) + << 0 << Info.getConstraintStr(); return new (Context) GCCAsmStmt(Context, AsmLoc, IsSimple, IsVolatile, NumOutputs, NumInputs, Names, Constraints, Exprs.data(), AsmString, diff --git a/clang/test/Sema/asm.c b/clang/test/Sema/asm.c index 630a5e85dd913..3e260c7106f91 100644 --- a/clang/test/Sema/asm.c +++ b/clang/test/Sema/asm.c @@ -10,12 +10,12 @@ void f(void) { asm ("foo\n" : "=a" (i + 2)); // expected-error {{invalid lvalue in asm output}} asm ("foo\n" : [symbolic_name] "=a" (i) : "[symbolic_name]" (i)); - asm ("foo\n" : "=a" (i) : "[" (i)); // expected-error {{invalid input constraint '[' in asm}} - asm ("foo\n" : "=a" (i) : "[foo" (i)); // expected-error {{invalid input constraint '[foo' in asm}} - asm ("foo\n" : "=a" (i) : "[symbolic_name]" (i)); // expected-error {{invalid input constraint '[symbolic_name]' in asm}} + asm ("foo\n" : "=a" (i) : "[" (i)); // expected-error {{invalid input constraint '[' in asm: missing ']'}} + asm ("foo\n" : "=a" (i) : "[foo" (i)); // expected-error {{invalid input constraint '[foo' in asm: missing ']'}} + asm ("foo\n" : "=a" (i) : "[symbolic_name]" (i)); // expected-error {{invalid input constraint '[symbolic_name]' in asm: no matching output constraint with the specified name}} - asm ("foo\n" : : "" (i)); // expected-error {{invalid input constraint '' in asm}} - asm ("foo\n" : "=a" (i) : "" (i)); // expected-error {{invalid input constraint '' in asm}} + asm ("foo\n" : : "" (i)); // expected-error {{invalid input constraint '' in asm: empty constraint has been provided}} + asm ("foo\n" : "=a" (i) : "" (i)); // expected-error {{invalid input constraint '' in asm: empty constraint has been provided}} } void clobbers(void) { @@ -91,13 +91,13 @@ int test7(unsigned long long b) { // PR3904 void test8(int i) { // A number in an input constraint can't point to a read-write constraint. - asm("" : "+r" (i), "=r"(i) : "0" (i)); // expected-error{{invalid input constraint '0' in asm}} + asm("" : "+r" (i), "=r"(i) : "0" (i)); // expected-error{{invalid input constraint '0' in asm: must refer to an output-only operand}} } // PR3905 void test9(int i) { - asm("" : [foo] "=r" (i), "=r"(i) : "1[foo]"(i)); // expected-error{{invalid input constraint '1[foo]' in asm}} - asm("" : [foo] "=r" (i), "=r"(i) : "[foo]1"(i)); // expected-error{{invalid input constraint '[foo]1' in asm}} + asm("" : [foo] "=r" (i), "=r"(i) : "1[foo]"(i)); // expected-error{{invalid input constraint '1[foo]' in asm: tied constraint must be tied to the same operand referenced to by the number}} + asm("" : [foo] "=r" (i), "=r"(i) : "[foo]1"(i)); // expected-error{{invalid input constraint '[foo]1' in asm: tied constraint must be tied to the same operand referenced to by the number}} } void test10(void){ @@ -139,14 +139,14 @@ void test14(struct S *s) { // PR15759. double test15(void) { double ret = 0; - __asm("0.0":"="(ret)); // expected-error {{invalid output constraint '=' in asm}} - __asm("0.0":"=&"(ret)); // expected-error {{invalid output constraint '=&' in asm}} - __asm("0.0":"+?"(ret)); // expected-error {{invalid output constraint '+?' in asm}} - __asm("0.0":"+!"(ret)); // expected-error {{invalid output constraint '+!' in asm}} - __asm("0.0":"+#"(ret)); // expected-error {{invalid output constraint '+#' in asm}} - __asm("0.0":"+*"(ret)); // expected-error {{invalid output constraint '+*' in asm}} - __asm("0.0":"=%"(ret)); // expected-error {{invalid output constraint '=%' in asm}} - __asm("0.0":"=,="(ret)); // expected-error {{invalid output constraint '=,=' in asm}} + __asm("0.0":"="(ret)); // expected-error {{invalid output constraint '=' in asm: constraint must allow either memory or register operands}} + __asm("0.0":"=&"(ret)); // expected-error {{invalid output constraint '=&' in asm: constraint must allow either memory or register operands}} + __asm("0.0":"+?"(ret)); // expected-error {{invalid output constraint '+?' in asm: constraint must allow either memory or register operands}} + __asm("0.0":"+!"(ret)); // expected-error {{invalid output constraint '+!' in asm: constraint must allow either memory or register operands}} + __asm("0.0":"+#"(ret)); // expected-error {{invalid output constraint '+#' in asm: constraint must allow either memory or register operands}} + __asm("0.0":"+*"(ret)); // expected-error {{invalid output constraint '+*' in asm: constraint must allow either memory or register operands}} + __asm("0.0":"=%"(ret)); // expected-error {{invalid output constraint '=%' in asm: constraint must allow either memory or register operands}} + __asm("0.0":"=,="(ret)); // expected-error {{invalid output constraint '=,=' in asm: constraint must allow either memory or register operands}} __asm("0.0":"=,g"(ret)); // no-error __asm("0.0":"=g"(ret)); // no-error return ret; @@ -158,33 +158,33 @@ void iOutputConstraint(int x){ __asm ("nop" : "=ig" (x) : :); // no-error __asm ("nop" : "=im" (x) : :); // no-error __asm ("nop" : "=imr" (x) : :); // no-error - __asm ("nop" : "=i" (x) : :); // expected-error{{invalid output constraint '=i' in asm}} - __asm ("nop" : "+i" (x) : :); // expected-error{{invalid output constraint '+i' in asm}} - __asm ("nop" : "=ii" (x) : :); // expected-error{{invalid output constraint '=ii' in asm}} + __asm ("nop" : "=i" (x) : :); // expected-error{{invalid output constraint '=i' in asm: constraint must allow either memory or register operands}} + __asm ("nop" : "+i" (x) : :); // expected-error{{invalid output constraint '+i' in asm: constraint must allow either memory or register operands}} + __asm ("nop" : "=ii" (x) : :); // expected-error{{invalid output constraint '=ii' in asm: constraint must allow either memory or register operands}} __asm ("nop" : "=nr" (x) : :); // no-error __asm ("nop" : "=rn" (x) : :); // no-error __asm ("nop" : "=ng" (x) : :); // no-error __asm ("nop" : "=nm" (x) : :); // no-error __asm ("nop" : "=nmr" (x) : :); // no-error - __asm ("nop" : "=n" (x) : :); // expected-error{{invalid output constraint '=n' in asm}} - __asm ("nop" : "+n" (x) : :); // expected-error{{invalid output constraint '+n' in asm}} - __asm ("nop" : "=nn" (x) : :); // expected-error{{invalid output constraint '=nn' in asm}} + __asm ("nop" : "=n" (x) : :); // expected-error{{invalid output constraint '=n' in asm: constraint must allow either memory or register operands}} + __asm ("nop" : "+n" (x) : :); // expected-error{{invalid output constraint '+n' in asm: constraint must allow either memory or register operands}} + __asm ("nop" : "=nn" (x) : :); // expected-error{{invalid output constraint '=nn' in asm: constraint must allow either memory or register operands}} __asm ("nop" : "=Fr" (x) : :); // no-error __asm ("nop" : "=rF" (x) : :); // no-error __asm ("nop" : "=Fg" (x) : :); // no-error __asm ("nop" : "=Fm" (x) : :); // no-error __asm ("nop" : "=Fmr" (x) : :); // no-error - __asm ("nop" : "=F" (x) : :); // expected-error{{invalid output constraint '=F' in asm}} - __asm ("nop" : "+F" (x) : :); // expected-error{{invalid output constraint '+F' in asm}} - __asm ("nop" : "=FF" (x) : :); // expected-error{{invalid output constraint '=FF' in asm}} + __asm ("nop" : "=F" (x) : :); // expected-error{{invalid output constraint '=F' in asm: constraint must allow either memory or register operands}} + __asm ("nop" : "+F" (x) : :); // expected-error{{invalid output constraint '+F' in asm: constraint must allow either memory or register operands}} + __asm ("nop" : "=FF" (x) : :); // expected-error{{invalid output constraint '=FF' in asm: constraint must allow either memory or register operands}} __asm ("nop" : "=Er" (x) : :); // no-error __asm ("nop" : "=rE" (x) : :); // no-error __asm ("nop" : "=Eg" (x) : :); // no-error __asm ("nop" : "=Em" (x) : :); // no-error __asm ("nop" : "=Emr" (x) : :); // no-error - __asm ("nop" : "=E" (x) : :); // expected-error{{invalid output constraint '=E' in asm}} - __asm ("nop" : "+E" (x) : :); // expected-error{{invalid output constraint '+E' in asm}} - __asm ("nop" : "=EE" (x) : :); // expected-error{{invalid output constraint '=EE' in asm}} + __asm ("nop" : "=E" (x) : :); // expected-error{{invalid output constraint '=E' in asm: constraint must allow either memory or register operands}} + __asm ("nop" : "+E" (x) : :); // expected-error{{invalid output constraint '+E' in asm: constraint must allow either memory or register operands}} + __asm ("nop" : "=EE" (x) : :); // expected-error{{invalid output constraint '=EE' in asm: constraint must allow either memory or register operands}} } // PR19837 @@ -214,13 +214,13 @@ void fn1(void) { void fn2(void) { int l; __asm__("" - : "+&m"(l)); // expected-error {{invalid output constraint '+&m' in asm}} + : "+&m"(l)); // expected-error {{invalid output constraint '+&m' in asm: early clobber with a read-write constraint must be a register}} } void fn3(void) { int l; __asm__("" - : "+#r"(l)); // expected-error {{invalid output constraint '+#r' in asm}} + : "+#r"(l)); // expected-error {{invalid output constraint '+#r' in asm: constraint must allow either memory or register operands}} } void fn4(void) { @@ -234,14 +234,14 @@ void fn5(void) { int l; __asm__("" : [g] "+r"(l) - : "[g]"(l)); // expected-error {{invalid input constraint '[g]' in asm}} + : "[g]"(l)); // expected-error {{invalid input constraint '[g]' in asm: must refer to an output-only operand}} } void fn6(void) { int a; __asm__("" : "=rm"(a), "=rm"(a) - : "11m"(a)); // expected-error {{invalid input constraint '11m' in asm}} + : "11m"(a)); // expected-error {{invalid input constraint '11m' in asm: references non-existent output constraint}} } // PR14269 @@ -359,3 +359,10 @@ void test19(long long x) // FIXME: This case should be supported by codegen, but it fails now. asm ("" : "=rm" (x): "0" (e)); // expected-error {{unsupported inline asm: input with type 'st_size128' (aka 'struct _st_size128') matching output with type 'long long'}} } + +void test20(long long x) +{ + st_size64 a; + asm ("" : "=rm" (a): "9876543210" (1)); // expected-error {{invalid input constraint '9876543210' in asm: the index is out of bounds}} + asm ("" : "rm" (a): "0" (1)); // expected-error {{invalid output constraint 'rm' in asm: output constraint must start with '=' or '+'}} +}