[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