[AsmParser] Expose an API to parse a string starting with a type.
authorQuentin Colombet <qcolombet@apple.com>
Tue, 8 Mar 2016 00:37:07 +0000 (00:37 +0000)
committerQuentin Colombet <qcolombet@apple.com>
Tue, 8 Mar 2016 00:37:07 +0000 (00:37 +0000)
Without actually parsing a type it is difficult to perdict where
the type definition ends. In other words, instead of expecting
the user of the parser API to hand over only the relevant bits
of the string being parsed, take the whole string, parse the type,
and get back the number of characters that have been read.

This will be used by the MIR testing infrastructure.

llvm-svn: 262884

llvm/include/llvm/AsmParser/Parser.h
llvm/lib/AsmParser/LLParser.cpp
llvm/lib/AsmParser/LLParser.h
llvm/lib/AsmParser/Parser.cpp
llvm/unittests/AsmParser/AsmParserTest.cpp

index 6136d187c4d810801f46c80738dca83c539e3681..768b089b8a2a693ac3e08d714800f7feab9cfa0f 100644 (file)
@@ -100,6 +100,16 @@ Constant *parseConstantValue(StringRef Asm, SMDiagnostic &Err, const Module &M,
 Type *parseType(StringRef Asm, SMDiagnostic &Err, const Module &M,
                 const SlotMapping *Slots = nullptr);
 
+/// Parse a string \p Asm that starts with a type.
+/// \p Read[out] gives the number of characters that have been read to parse
+/// the type in \p Asm.
+///
+/// \param Slots The optional slot mapping that will restore the parsing state
+/// of the module.
+/// \return null on error.
+Type *parseTypeAtBeginning(StringRef Asm, unsigned &Read, SMDiagnostic &Err,
+                           const Module &M, const SlotMapping *Slots = nullptr);
+
 } // End llvm namespace
 
 #endif
index 9b9054dbaed2a75b0e8dfaa91aca5b9f3c81dc31..0da81e42c68ce2ed447b06d7053b7b65ee9b20e9 100644 (file)
@@ -63,15 +63,19 @@ bool LLParser::parseStandaloneConstantValue(Constant *&C,
   return false;
 }
 
-bool LLParser::parseStandaloneType(Type *&Ty, const SlotMapping *Slots) {
+bool LLParser::parseTypeAtBeginning(Type *&Ty, unsigned &Read,
+                                    const SlotMapping *Slots) {
   restoreParsingState(Slots);
   Lex.Lex();
 
+  Read = 0;
+  SMLoc Start = Lex.getLoc();
   Ty = nullptr;
   if (ParseType(Ty))
     return true;
-  if (Lex.getKind() != lltok::Eof)
-    return Error(Lex.getLoc(), "expected end of string");
+  SMLoc End = Lex.getLoc();
+  Read = End.getPointer() - Start.getPointer();
+
   return false;
 }
 
index 4128fa367f5d3d8ada04ecea9d0aebc45111a6b0..96f864a7f1a5afff3c35cec666ef4f79b625ac1f 100644 (file)
@@ -148,7 +148,8 @@ namespace llvm {
 
     bool parseStandaloneConstantValue(Constant *&C, const SlotMapping *Slots);
 
-    bool parseStandaloneType(Type *&Ty, const SlotMapping *Slots);
+    bool parseTypeAtBeginning(Type *&Ty, unsigned &Read,
+                              const SlotMapping *Slots);
 
     LLVMContext &getContext() { return Context; }
 
index 9b635982477354d041c5d76bebfb5dd47d7f3ad1..bee07ad9e0a52949c88a585a2a50dcaf338b0cb4 100644 (file)
@@ -81,12 +81,29 @@ Constant *llvm::parseConstantValue(StringRef Asm, SMDiagnostic &Err,
 
 Type *llvm::parseType(StringRef Asm, SMDiagnostic &Err, const Module &M,
                       const SlotMapping *Slots) {
+  unsigned Read;
+  Type *Ty = parseTypeAtBeginning(Asm, Read, Err, M, Slots);
+  if (!Ty)
+    return nullptr;
+  if (Read != Asm.size()) {
+    SourceMgr SM;
+    std::unique_ptr<MemoryBuffer> Buf = MemoryBuffer::getMemBuffer(Asm);
+    SM.AddNewSourceBuffer(std::move(Buf), SMLoc());
+    Err = SM.GetMessage(SMLoc::getFromPointer(Asm.begin() + Read),
+                        SourceMgr::DK_Error, "expected end of string");
+    return nullptr;
+  }
+  return Ty;
+}
+Type *llvm::parseTypeAtBeginning(StringRef Asm, unsigned &Read,
+                                 SMDiagnostic &Err, const Module &M,
+                                 const SlotMapping *Slots) {
   SourceMgr SM;
   std::unique_ptr<MemoryBuffer> Buf = MemoryBuffer::getMemBuffer(Asm);
   SM.AddNewSourceBuffer(std::move(Buf), SMLoc());
   Type *Ty;
   if (LLParser(Asm, SM, Err, const_cast<Module *>(&M))
-          .parseStandaloneType(Ty, Slots))
+          .parseTypeAtBeginning(Ty, Read, Slots))
     return nullptr;
   return Ty;
 }
index c881c4e7ca489b247d10cf12e0b03360a88fe377..38810cd7c7a59149da29ef5123d932f227fbd172 100644 (file)
@@ -270,6 +270,149 @@ TEST(AsmParserTest, TypeWithSlotMappingParsing) {
   Ty = PT->getElementType();
   ASSERT_TRUE(Ty->isIntegerTy());
   ASSERT_TRUE(Ty->getPrimitiveSizeInBits() == 32);
+
+  // Check that we reject types with garbage.
+  Ty = parseType("i32 garbage", Error, M, &Mapping);
+  ASSERT_TRUE(!Ty);
+}
+
+TEST(AsmParserTest, TypeAtBeginningWithSlotMappingParsing) {
+  LLVMContext &Ctx = getGlobalContext();
+  SMDiagnostic Error;
+  StringRef Source =
+      "%st = type { i32, i32 }\n"
+      "@v = common global [50 x %st] zeroinitializer, align 16\n"
+      "%0 = type { i32, i32, i32, i32 }\n"
+      "@g = common global [50 x %0] zeroinitializer, align 16\n"
+      "define void @marker4(i64 %d) {\n"
+      "entry:\n"
+      "  %conv = trunc i64 %d to i32\n"
+      "  store i32 %conv, i32* getelementptr inbounds "
+      "    ([50 x %st], [50 x %st]* @v, i64 0, i64 0, i32 0), align 16\n"
+      "  store i32 %conv, i32* getelementptr inbounds "
+      "    ([50 x %0], [50 x %0]* @g, i64 0, i64 0, i32 0), align 16\n"
+      "  ret void\n"
+      "}";
+  SlotMapping Mapping;
+  auto Mod = parseAssemblyString(Source, Error, Ctx, &Mapping);
+  ASSERT_TRUE(Mod != nullptr);
+  auto &M = *Mod;
+  unsigned Read;
+
+  // Check we properly parse integer types.
+  Type *Ty;
+  Ty = parseTypeAtBeginning("i32", Read, Error, M, &Mapping);
+  ASSERT_TRUE(Ty);
+  ASSERT_TRUE(Ty->isIntegerTy());
+  ASSERT_TRUE(Ty->getPrimitiveSizeInBits() == 32);
+  ASSERT_TRUE(Read == 3);
+
+  // Check we properly parse integer types with exotic size.
+  Ty = parseTypeAtBeginning("i13", Read, Error, M, &Mapping);
+  ASSERT_TRUE(Ty);
+  ASSERT_TRUE(Ty->isIntegerTy());
+  ASSERT_TRUE(Ty->getPrimitiveSizeInBits() == 13);
+  ASSERT_TRUE(Read == 3);
+
+  // Check we properly parse floating point types.
+  Ty = parseTypeAtBeginning("float", Read, Error, M, &Mapping);
+  ASSERT_TRUE(Ty);
+  ASSERT_TRUE(Ty->isFloatTy());
+  ASSERT_TRUE(Read == 5);
+
+  Ty = parseTypeAtBeginning("double", Read, Error, M, &Mapping);
+  ASSERT_TRUE(Ty);
+  ASSERT_TRUE(Ty->isDoubleTy());
+  ASSERT_TRUE(Read == 6);
+
+  // Check we properly parse struct types.
+  // Named struct.
+  Ty = parseTypeAtBeginning("%st", Read, Error, M, &Mapping);
+  ASSERT_TRUE(Ty);
+  ASSERT_TRUE(Ty->isStructTy());
+  ASSERT_TRUE(Read == 3);
+
+  // Check the details of the struct.
+  StructType *ST = cast<StructType>(Ty);
+  ASSERT_TRUE(ST->getNumElements() == 2);
+  for (unsigned i = 0, e = ST->getNumElements(); i != e; ++i) {
+    Ty = ST->getElementType(i);
+    ASSERT_TRUE(Ty->isIntegerTy());
+    ASSERT_TRUE(Ty->getPrimitiveSizeInBits() == 32);
+  }
+
+  // Anonymous struct.
+  Ty = parseTypeAtBeginning("%0", Read, Error, M, &Mapping);
+  ASSERT_TRUE(Ty);
+  ASSERT_TRUE(Ty->isStructTy());
+  ASSERT_TRUE(Read == 2);
+
+  // Check the details of the struct.
+  ST = cast<StructType>(Ty);
+  ASSERT_TRUE(ST->getNumElements() == 4);
+  for (unsigned i = 0, e = ST->getNumElements(); i != e; ++i) {
+    Ty = ST->getElementType(i);
+    ASSERT_TRUE(Ty->isIntegerTy());
+    ASSERT_TRUE(Ty->getPrimitiveSizeInBits() == 32);
+  }
+
+  // Check we properly parse vector types.
+  Ty = parseTypeAtBeginning("<5 x i32>", Read, Error, M, &Mapping);
+  ASSERT_TRUE(Ty);
+  ASSERT_TRUE(Ty->isVectorTy());
+  ASSERT_TRUE(Read == 9);
+
+  // Check the details of the vector.
+  VectorType *VT = cast<VectorType>(Ty);
+  ASSERT_TRUE(VT->getNumElements() == 5);
+  ASSERT_TRUE(VT->getBitWidth() == 160);
+  Ty = VT->getElementType();
+  ASSERT_TRUE(Ty->isIntegerTy());
+  ASSERT_TRUE(Ty->getPrimitiveSizeInBits() == 32);
+
+  // Opaque struct.
+  Ty = parseTypeAtBeginning("%opaque", Read, Error, M, &Mapping);
+  ASSERT_TRUE(Ty);
+  ASSERT_TRUE(Ty->isStructTy());
+  ASSERT_TRUE(Read == 7);
+
+  ST = cast<StructType>(Ty);
+  ASSERT_TRUE(ST->isOpaque());
+
+  // Check we properly parse pointer types.
+  // One indirection.
+  Ty = parseTypeAtBeginning("i32*", Read, Error, M, &Mapping);
+  ASSERT_TRUE(Ty);
+  ASSERT_TRUE(Ty->isPointerTy());
+  ASSERT_TRUE(Read == 4);
+
+  PointerType *PT = cast<PointerType>(Ty);
+  Ty = PT->getElementType();
+  ASSERT_TRUE(Ty->isIntegerTy());
+  ASSERT_TRUE(Ty->getPrimitiveSizeInBits() == 32);
+
+  // Two indirections.
+  Ty = parseTypeAtBeginning("i32**", Read, Error, M, &Mapping);
+  ASSERT_TRUE(Ty);
+  ASSERT_TRUE(Ty->isPointerTy());
+  ASSERT_TRUE(Read == 5);
+
+  PT = cast<PointerType>(Ty);
+  Ty = PT->getElementType();
+  ASSERT_TRUE(Ty->isPointerTy());
+
+  PT = cast<PointerType>(Ty);
+  Ty = PT->getElementType();
+  ASSERT_TRUE(Ty->isIntegerTy());
+  ASSERT_TRUE(Ty->getPrimitiveSizeInBits() == 32);
+
+  // Check that we reject types with garbage.
+  Ty = parseTypeAtBeginning("i32 garbage", Read, Error, M, &Mapping);
+  ASSERT_TRUE(Ty);
+  ASSERT_TRUE(Ty->isIntegerTy());
+  ASSERT_TRUE(Ty->getPrimitiveSizeInBits() == 32);
+  // We go to the next token, i.e., we read "i32" + ' '.
+  ASSERT_TRUE(Read == 4);
 }
 
 } // end anonymous namespace