[llvm] 00797b8 - [InlineAsm] Improve error messages for invalid constraint strings
Nikita Popov via llvm-commits
llvm-commits at lists.llvm.org
Tue Jul 12 02:41:25 PDT 2022
Author: Nikita Popov
Date: 2022-07-12T11:41:16+02:00
New Revision: 00797b88e0113aeea03045b18b3f63332f850dfe
URL: https://github.com/llvm/llvm-project/commit/00797b88e0113aeea03045b18b3f63332f850dfe
DIFF: https://github.com/llvm/llvm-project/commit/00797b88e0113aeea03045b18b3f63332f850dfe.diff
LOG: [InlineAsm] Improve error messages for invalid constraint strings
InlineAsm constraint string verification can fail for many reasons,
but used to always print a generic "invalid type for inline asm
constraint string" message -- which is especially confusing if
the actual error is unrelated to the type, e.g. a failure to parse
the constraint string.
Change the verify API to return an Error with a more specific
error message, and print that in the IR parser.
Added:
llvm/test/Assembler/inline-asm-constraint-error.ll
Modified:
llvm/include/llvm/IR/InlineAsm.h
llvm/lib/AsmParser/LLParser.cpp
llvm/lib/IR/InlineAsm.cpp
llvm/test/Assembler/invalid-inline-constraint.ll
Removed:
llvm/test/Assembler/inline-asm-clobber.ll
################################################################################
diff --git a/llvm/include/llvm/IR/InlineAsm.h b/llvm/include/llvm/IR/InlineAsm.h
index 57f2da27e04e..032a70efdceb 100644
--- a/llvm/include/llvm/IR/InlineAsm.h
+++ b/llvm/include/llvm/IR/InlineAsm.h
@@ -24,6 +24,7 @@
namespace llvm {
+class Error;
class FunctionType;
class PointerType;
template <class ConstantClass> class ConstantUniqueMap;
@@ -83,11 +84,9 @@ class InlineAsm final : public Value {
const std::string &getAsmString() const { return AsmString; }
const std::string &getConstraintString() const { return Constraints; }
- /// Verify - This static method can be used by the parser to check to see if
- /// the specified constraint string is legal for the type. This returns true
- /// if legal, false if not.
- ///
- static bool Verify(FunctionType *Ty, StringRef Constraints);
+ /// This static method can be used by the parser to check to see if the
+ /// specified constraint string is legal for the type.
+ static Error verify(FunctionType *Ty, StringRef Constraints);
// Constraint String Parsing
enum ConstraintPrefix {
diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp
index 030c44e27f7f..62158d306581 100644
--- a/llvm/lib/AsmParser/LLParser.cpp
+++ b/llvm/lib/AsmParser/LLParser.cpp
@@ -5383,8 +5383,15 @@ bool LLParser::convertValIDToValue(Type *Ty, ValID &ID, Value *&V,
V = PFS->getVal(ID.StrVal, Ty, ID.Loc);
return V == nullptr;
case ValID::t_InlineAsm: {
- if (!ID.FTy || !InlineAsm::Verify(ID.FTy, ID.StrVal2))
+ if (!ID.FTy)
return error(ID.Loc, "invalid type for inline asm constraint string");
+ if (Error Err = InlineAsm::verify(ID.FTy, ID.StrVal2)) {
+ std::string Str;
+ raw_string_ostream OS(Str);
+ OS << Err;
+ consumeError(std::move(Err));
+ return error(ID.Loc, Str.c_str());
+ }
V = InlineAsm::get(
ID.FTy, ID.StrVal, ID.StrVal2, ID.UIntVal & 1, (ID.UIntVal >> 1) & 1,
InlineAsm::AsmDialect((ID.UIntVal >> 2) & 1), (ID.UIntVal >> 3) & 1);
diff --git a/llvm/lib/IR/InlineAsm.cpp b/llvm/lib/IR/InlineAsm.cpp
index 203ad6dae1ff..c75b1aa7c1d6 100644
--- a/llvm/lib/IR/InlineAsm.cpp
+++ b/llvm/lib/IR/InlineAsm.cpp
@@ -19,6 +19,7 @@
#include "llvm/IR/Value.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/Compiler.h"
+#include "llvm/Support/Errc.h"
#include <algorithm>
#include <cassert>
#include <cctype>
@@ -33,9 +34,10 @@ InlineAsm::InlineAsm(FunctionType *FTy, const std::string &asmString,
AsmString(asmString), Constraints(constraints), FTy(FTy),
HasSideEffects(hasSideEffects), IsAlignStack(isAlignStack),
Dialect(asmDialect), CanThrow(canThrow) {
+#ifndef NDEBUG
// Do various checks on the constraint string and type.
- assert(Verify(getFunctionType(), constraints) &&
- "Function type not legal for constraints!");
+ cantFail(verify(getFunctionType(), constraints));
+#endif
}
InlineAsm *InlineAsm::get(FunctionType *FTy, StringRef AsmString,
@@ -248,15 +250,19 @@ InlineAsm::ParseConstraints(StringRef Constraints) {
return Result;
}
-/// Verify - Verify that the specified constraint string is reasonable for the
-/// specified function type, and otherwise validate the constraint string.
-bool InlineAsm::Verify(FunctionType *Ty, StringRef ConstStr) {
- if (Ty->isVarArg()) return false;
+static Error makeStringError(const char *Msg) {
+ return createStringError(errc::invalid_argument, Msg);
+}
+
+Error InlineAsm::verify(FunctionType *Ty, StringRef ConstStr) {
+ if (Ty->isVarArg())
+ return makeStringError("inline asm cannot be variadic");
ConstraintInfoVector Constraints = ParseConstraints(ConstStr);
// Error parsing constraints.
- if (Constraints.empty() && !ConstStr.empty()) return false;
+ if (Constraints.empty() && !ConstStr.empty())
+ return makeStringError("failed to parse constraints");
unsigned NumOutputs = 0, NumInputs = 0, NumClobbers = 0;
unsigned NumIndirect = 0;
@@ -265,7 +271,9 @@ bool InlineAsm::Verify(FunctionType *Ty, StringRef ConstStr) {
switch (Constraint.Type) {
case InlineAsm::isOutput:
if ((NumInputs-NumIndirect) != 0 || NumClobbers != 0)
- return false; // outputs before inputs and clobbers.
+ return makeStringError("output constraint occurs after input "
+ "or clobber constraint");
+
if (!Constraint.isIndirect) {
++NumOutputs;
break;
@@ -273,7 +281,9 @@ bool InlineAsm::Verify(FunctionType *Ty, StringRef ConstStr) {
++NumIndirect;
LLVM_FALLTHROUGH; // We fall through for Indirect Outputs.
case InlineAsm::isInput:
- if (NumClobbers) return false; // inputs before clobbers.
+ if (NumClobbers)
+ return makeStringError("input constraint occurs after clobber "
+ "constraint");
++NumInputs;
break;
case InlineAsm::isClobber:
@@ -284,18 +294,23 @@ bool InlineAsm::Verify(FunctionType *Ty, StringRef ConstStr) {
switch (NumOutputs) {
case 0:
- if (!Ty->getReturnType()->isVoidTy()) return false;
+ if (!Ty->getReturnType()->isVoidTy())
+ return makeStringError("inline asm without outputs must return void");
break;
case 1:
- if (Ty->getReturnType()->isStructTy()) return false;
+ if (Ty->getReturnType()->isStructTy())
+ return makeStringError("inline asm with one output cannot return struct");
break;
default:
StructType *STy = dyn_cast<StructType>(Ty->getReturnType());
if (!STy || STy->getNumElements() != NumOutputs)
- return false;
+ return makeStringError("number of output constraints does not match "
+ "number of return struct elements");
break;
}
- if (Ty->getNumParams() != NumInputs) return false;
- return true;
+ if (Ty->getNumParams() != NumInputs)
+ return makeStringError("number of input constraints does not match number "
+ "of parameters");
+ return Error::success();
}
diff --git a/llvm/test/Assembler/inline-asm-clobber.ll b/llvm/test/Assembler/inline-asm-clobber.ll
deleted file mode 100644
index 65c8e444e808..000000000000
--- a/llvm/test/Assembler/inline-asm-clobber.ll
+++ /dev/null
@@ -1,10 +0,0 @@
-; RUN: not llvm-as <%s 2>&1 | FileCheck %s
-
-; "~x{21}" is not a valid clobber constraint.
-
-; CHECK: invalid type for inline asm constraint string
-
-define void @foo() nounwind {
- call void asm sideeffect "mov x0, #42", "~{x0},~{x19},~x{21}"() nounwind
- ret void
-}
diff --git a/llvm/test/Assembler/inline-asm-constraint-error.ll b/llvm/test/Assembler/inline-asm-constraint-error.ll
new file mode 100644
index 000000000000..5ecf67ab34ad
--- /dev/null
+++ b/llvm/test/Assembler/inline-asm-constraint-error.ll
@@ -0,0 +1,58 @@
+; RUN: split-file %s %t
+; RUN: not llvm-as < %t/parse-fail.ll 2>&1 | FileCheck %s --check-prefix=CHECK-PARSE-FAIL
+; RUN: not llvm-as < %t/input-before-output.ll 2>&1 | FileCheck %s --check-prefix=CHECK-INPUT-BEFORE-OUTPUT
+; RUN: not llvm-as < %t/input-after-clobber.ll 2>&1 | FileCheck %s --check-prefix=CHECK-INPUT-AFTER-CLOBBER
+; RUN: not llvm-as < %t/must-return-void.ll 2>&1 | FileCheck %s --check-prefix=CHECK-MUST-RETURN-VOID
+; RUN: not llvm-as < %t/cannot-be-struct.ll 2>&1 | FileCheck %s --check-prefix=CHECK-CANNOT-BE-STRUCT
+; RUN: not llvm-as < %t/incorrect-struct-elements.ll 2>&1 | FileCheck %s --check-prefix=CHECK-INCORRECT-STRUCT-ELEMENTS
+; RUN: not llvm-as < %t/incorrect-arg-num.ll 2>&1 | FileCheck %s --check-prefix=CHECK-INCORRECT-ARG-NUM
+
+;--- parse-fail.ll
+; CHECK-PARSE-FAIL: failed to parse constraints
+define void @foo() {
+ ; "~x{21}" is not a valid clobber constraint.
+ call void asm sideeffect "mov x0, #42", "~{x0},~{x19},~x{21}"()
+ ret void
+}
+
+;--- input-before-output.ll
+; CHECK-INPUT-BEFORE-OUTPUT: output constraint occurs after input or clobber constraint
+define void @foo() {
+ call void asm sideeffect "mov x0, #42", "r,=r"()
+ ret void
+}
+
+;--- input-after-clobber.ll
+; CHECK-INPUT-AFTER-CLOBBER: input constraint occurs after clobber constraint
+define void @foo() {
+ call void asm sideeffect "mov x0, #42", "~{x0},r"()
+ ret void
+}
+
+;--- must-return-void.ll
+; CHECK-MUST-RETURN-VOID: inline asm without outputs must return void
+define void @foo() {
+ call i32 asm sideeffect "mov x0, #42", ""()
+ ret void
+}
+
+;--- cannot-be-struct.ll
+; CHECK-CANNOT-BE-STRUCT: inline asm with one output cannot return struct
+define void @foo() {
+ call { i32 } asm sideeffect "mov x0, #42", "=r"()
+ ret void
+}
+
+;--- incorrect-struct-elements.ll
+; CHECK-INCORRECT-STRUCT-ELEMENTS: number of output constraints does not match number of return struct elements
+define void @foo() {
+ call { i32 } asm sideeffect "mov x0, #42", "=r,=r"()
+ ret void
+}
+
+;--- incorrect-arg-num.ll
+; CHECK-INCORRECT-ARG-NUM: number of input constraints does not match number of parameters
+define void @foo() {
+ call void asm sideeffect "mov x0, #42", "r"()
+ ret void
+}
diff --git a/llvm/test/Assembler/invalid-inline-constraint.ll b/llvm/test/Assembler/invalid-inline-constraint.ll
index 000fb86a8f79..dda32702852e 100644
--- a/llvm/test/Assembler/invalid-inline-constraint.ll
+++ b/llvm/test/Assembler/invalid-inline-constraint.ll
@@ -1,7 +1,7 @@
; RUN: not llvm-as < %s 2>&1 | FileCheck %s
; Tests bug: https://llvm.org/bugs/show_bug.cgi?id=24646
-; CHECK: error: invalid type for inline asm constraint string
+; CHECK: error: failed to parse constraints
define void @foo() nounwind {
call void asm sideeffect "mov x0, #42","=~{x0},~{x19},mov |0,{x19},mov x0, #4~x{21}"()ounwi #4~x{21}"()ounwindret
More information about the llvm-commits
mailing list