-
Notifications
You must be signed in to change notification settings - Fork 13.5k
[clang] Improve diagnostics for constraints of inline asm (NFC) #96363
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Introduce more detailed diagnostics for the constrains. Also provide an opportunity for backends to provide detailed diagnostics for target specific constraints based on enabled features.
@llvm/pr-subscribers-backend-webassembly @llvm/pr-subscribers-clang Author: Evgenii Kudriashov (e-kud) ChangesIntroduce more detailed diagnostics for the constrains. Also provide an opportunity for backends to provide detailed diagnostics for target specific constraints based on enabled features. We provide features as a pointer intentionally because they are not available in some of existing uses. So backends need to consider whether features are available or not. Patch is 56.39 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/96363.diff 43 Files Affected:
diff --git a/clang/include/clang/Basic/DiagnosticCommonKinds.td b/clang/include/clang/Basic/DiagnosticCommonKinds.td
index de758cbe679dc..d4b0862337165 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: cannot find an 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 to a non-existing 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<DiagGroup<"stack-protector">>;
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..0d2773546d2f3 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"
@@ -1197,9 +1198,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<ConstraintInfo> OutputConstraints,
- ConstraintInfo &info) const;
+ bool validateOutputConstraint(ConstraintInfo &Info,
+ llvm::StringMap<bool> *FeatureMap,
+ diag::kind &Diag) const;
+ bool validateInputConstraint(
+ MutableArrayRef<ConstraintInfo> OutputConstraints, ConstraintInfo &Info,
+ llvm::StringMap<bool> *FeatureMap, diag::kind &Diag) const;
virtual bool validateOutputSize(const llvm::StringMap<bool> &FeatureMap,
StringRef /*Constraint*/,
@@ -1219,13 +1223,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<bool> *FeatureMap,
+ diag::kind &Diag) const = 0;
bool resolveSymbolicName(const char *&Name,
ArrayRef<ConstraintInfo> 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<bool> *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<ConstraintInfo> 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<ConstraintInfo> OutputConstraints,
- ConstraintInfo &Info) const {
+ MutableArrayRef<ConstraintInfo> OutputConstraints, ConstraintInfo &Info,
+ llvm::StringMap<bool> *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<bool> *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<bool> *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<bool> *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<bool> *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<TargetInfo::GCCRegAlias> 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<bool> *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<const char *> getGCCRegNames() const override;
ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override;
bool validateAsmConstraint(const char *&Name,
- TargetInfo::ConstraintInfo &Info) const override;
+ TargetInfo::ConstraintInfo &Info,
+ llvm::StringMap<bool> *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<bool> *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<bool> *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<TargetInfo::GCCRegAlias> 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<bool> *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<bool> *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/T...
[truncated]
|
@llvm/pr-subscribers-backend-amdgpu Author: Evgenii Kudriashov (e-kud) ChangesIntroduce more detailed diagnostics for the constrains. Also provide an opportunity for backends to provide detailed diagnostics for target specific constraints based on enabled features. We provide features as a pointer intentionally because they are not available in some of existing uses. So backends need to consider whether features are available or not. Patch is 56.39 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/96363.diff 43 Files Affected:
diff --git a/clang/include/clang/Basic/DiagnosticCommonKinds.td b/clang/include/clang/Basic/DiagnosticCommonKinds.td
index de758cbe679dc..d4b0862337165 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: cannot find an 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 to a non-existing 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<DiagGroup<"stack-protector">>;
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..0d2773546d2f3 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"
@@ -1197,9 +1198,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<ConstraintInfo> OutputConstraints,
- ConstraintInfo &info) const;
+ bool validateOutputConstraint(ConstraintInfo &Info,
+ llvm::StringMap<bool> *FeatureMap,
+ diag::kind &Diag) const;
+ bool validateInputConstraint(
+ MutableArrayRef<ConstraintInfo> OutputConstraints, ConstraintInfo &Info,
+ llvm::StringMap<bool> *FeatureMap, diag::kind &Diag) const;
virtual bool validateOutputSize(const llvm::StringMap<bool> &FeatureMap,
StringRef /*Constraint*/,
@@ -1219,13 +1223,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<bool> *FeatureMap,
+ diag::kind &Diag) const = 0;
bool resolveSymbolicName(const char *&Name,
ArrayRef<ConstraintInfo> 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<bool> *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<ConstraintInfo> 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<ConstraintInfo> OutputConstraints,
- ConstraintInfo &Info) const {
+ MutableArrayRef<ConstraintInfo> OutputConstraints, ConstraintInfo &Info,
+ llvm::StringMap<bool> *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<bool> *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<bool> *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<bool> *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<bool> *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<TargetInfo::GCCRegAlias> 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<bool> *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<const char *> getGCCRegNames() const override;
ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override;
bool validateAsmConstraint(const char *&Name,
- TargetInfo::ConstraintInfo &Info) const override;
+ TargetInfo::ConstraintInfo &Info,
+ llvm::StringMap<bool> *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<bool> *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<bool> *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<TargetInfo::GCCRegAlias> 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<bool> *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<bool> *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/T...
[truncated]
|
Initially I've implemented the target errors through std::string. Then changed to diag::kind after reading InternalsManual. I'm not sure what is better. The drawback of returning diagnoistics by reference is that we can't customize them, only fixed messages. Maybe this is not a big problem because we don't have constantly changing constraints. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Frontend changes look sensible, but I can’t really comment on anything target-specific...
"%sub{asm_invalid_constraint_generic}0,1: cannot find an output constraint" | ||
" with the specified name">; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"%sub{asm_invalid_constraint_generic}0,1: cannot find an output constraint" | |
" with the specified name">; | |
"%sub{asm_invalid_constraint_generic}0,1: no matching output constraint">; |
There has to be a corresponding output constraint with the same name as I understand it? This confused me a bit just now while I was looking at the tests, so maybe something like this would make that a bit clearer?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, this is similar to digits. From GCC reference:
Input constraints can also be digits (for example, "0"). This indicates that the specified input must be in the same place as the output constraint at the (zero-based) index in the output constraint list. When using asmSymbolicName syntax for the output operands, you may use these names (enclosed in brackets []) instead of digits.
"%sub{asm_invalid_constraint_generic}0,1: references to a non-existing output" | ||
" constraint">; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"%sub{asm_invalid_constraint_generic}0,1: references to a non-existing output" | |
" constraint">; | |
"%sub{asm_invalid_constraint_generic}0,1: references non-existent output" | |
" constraint">; |
nit
"%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" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"%sub{asm_invalid_constraint_generic}0,1: must refer to an output only" | |
"%sub{asm_invalid_constraint_generic}0,1: must refer to an output-only" |
another nit here too
Hmm, if they’re not changing very often (if at all), then I’d also use DiagIDs for this, yeah. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's really unfortunate to have to add all this asm handling to clang. Can't it rely on backend diagnostic remarks for this?
I've tried to do the similar thing in the backend: https://reviews.llvm.org/D152332. The problem I see is that
I'm not sure whether it is much better. |
In a lot of cases, we report_fatal_error because we don't actually expect users to run into the issues... indicate some internal inconsistency in the compiler, or some unsupported configuration, or something like that. Because of this, report_fatal_error prints the standard "report a bug" crash message. For inline asm specifically, emitError from the backend is probably best in most cases, so non-clang frontends get better diagnostics, and we don't have to duplicate code.
Yes, this can be a bit tricky in some cases, but usually there's something straightforward you can do (for example, drop the inline asm stmt). Note that we don't actually generate an output file, so it doesn't matter what you do as long as it doesn't cause something else to crash. |
So, I think this PR still makes sense but without target changes, right? I've taken a look at the backend and constraints are checked in |
I didn't actually look at this PR closely before I commented. I think the specific checks clang is doing here have to be part of clang: in particular, clang needs to translate from gcc syntax to LLVM IR asm syntax, and that requires parsing the constraints. So these checks are necessary, and emitting better diagnostics for checks we need to do anyway seems fine. |
Co-authored-by: Sirraide <aeternalmail@gmail.com>
Yes. But constraints are checked. The problem here is that they may conflict with features. Should this "features+constraint" combination checked in the frontend or in the backend? I like the idea of checking it in the frontend because we may point to the specific constraint. In the backend we can point only to the whole expression or even emit a generic error without a line. |
What exactly does it mean for a constraint to conflict with a feature? The only thing I can think of is if it somehow involves a register class that doesn't exist on the target with the current set of target features. I guess we could try to diagnose that, but I'm not sure it's worth duplicating that code. |
Yes, indeed. For instance, we have a constraint llvm-project/clang/lib/Basic/Targets/ARM.cpp Lines 1157 to 1161 in a9c12e4
However this implementation is buggy because it doesn't consider function attributes. In case of multiversioning in the same TU we will hit compilation errors.
So, then return to the idea to better diagnose these things from backends? |
If there's some subset of cases that's easy to diagnose, like SSE registers without SSE, maybe we can do that. I mostly care that we don't write a bunch of code to check complicated edge cases, like trying to diagnose if you're using too many registers. |
Introduce more detailed diagnostics for the constrains. Also provide an opportunity for backends to provide detailed diagnostics for target specific constraints based on enabled features. We provide features as a pointer intentionally because they are not available in some of existing uses. So backends need to consider whether features are available or not.