diff --git a/include/llvm/AsmParser/Parser.h b/include/llvm/AsmParser/Parser.h index 52151409f94..9fe33603bc6 100644 --- a/include/llvm/AsmParser/Parser.h +++ b/include/llvm/AsmParser/Parser.h @@ -18,6 +18,7 @@ namespace llvm { +class Constant; class LLVMContext; class Module; struct SlotMapping; @@ -79,6 +80,14 @@ std::unique_ptr parseAssembly(MemoryBufferRef F, SMDiagnostic &Err, bool parseAssemblyInto(MemoryBufferRef F, Module &M, SMDiagnostic &Err, SlotMapping *Slots = nullptr); +/// Parse a type and a constant value in the given string. +/// +/// The constant value can be any LLVM constant, including a constant +/// expression. +/// +/// \return null on error. +Constant *parseConstantValue(StringRef Asm, SMDiagnostic &Err, const Module &M); + } // End llvm namespace #endif diff --git a/lib/AsmParser/LLParser.cpp b/lib/AsmParser/LLParser.cpp index 1c6e7bd18d0..74cf5665924 100644 --- a/lib/AsmParser/LLParser.cpp +++ b/lib/AsmParser/LLParser.cpp @@ -48,6 +48,17 @@ bool LLParser::Run() { ValidateEndOfModule(); } +bool LLParser::parseStandaloneConstantValue(Constant *&C) { + Lex.Lex(); + + Type *Ty = nullptr; + if (ParseType(Ty) || parseConstantValue(Ty, C)) + return true; + if (Lex.getKind() != lltok::Eof) + return Error(Lex.getLoc(), "expected end of string"); + return false; +} + /// ValidateEndOfModule - Do final validity and sanity checks at the end of the /// module. bool LLParser::ValidateEndOfModule() { @@ -4065,6 +4076,30 @@ bool LLParser::ConvertValIDToValue(Type *Ty, ValID &ID, Value *&V, llvm_unreachable("Invalid ValID"); } +bool LLParser::parseConstantValue(Type *Ty, Constant *&C) { + C = nullptr; + ValID ID; + auto Loc = Lex.getLoc(); + if (ParseValID(ID, /*PFS=*/nullptr)) + return true; + switch (ID.Kind) { + case ValID::t_APSInt: + case ValID::t_APFloat: + case ValID::t_Constant: + case ValID::t_ConstantStruct: + case ValID::t_PackedConstantStruct: { + Value *V; + if (ConvertValIDToValue(Ty, ID, V, /*PFS=*/nullptr)) + return true; + assert(isa(V) && "Expected a constant value"); + C = cast(V); + return false; + } + default: + return Error(Loc, "expected a constant value"); + } +} + bool LLParser::ParseValue(Type *Ty, Value *&V, PerFunctionState *PFS) { V = nullptr; ValID ID; diff --git a/lib/AsmParser/LLParser.h b/lib/AsmParser/LLParser.h index 6e57b3e0667..7efcac7a19a 100644 --- a/lib/AsmParser/LLParser.h +++ b/lib/AsmParser/LLParser.h @@ -143,6 +143,8 @@ namespace llvm { Slots(Slots), BlockAddressPFS(nullptr) {} bool Run(); + bool parseStandaloneConstantValue(Constant *&C); + LLVMContext &getContext() { return Context; } private: @@ -343,6 +345,7 @@ namespace llvm { bool ConvertValIDToValue(Type *Ty, ValID &ID, Value *&V, PerFunctionState *PFS); + bool parseConstantValue(Type *Ty, Constant *&C); bool ParseValue(Type *Ty, Value *&V, PerFunctionState *PFS); bool ParseValue(Type *Ty, Value *&V, PerFunctionState &PFS) { return ParseValue(Ty, V, &PFS); diff --git a/lib/AsmParser/Parser.cpp b/lib/AsmParser/Parser.cpp index 9145a54f2a7..6135b43f00d 100644 --- a/lib/AsmParser/Parser.cpp +++ b/lib/AsmParser/Parser.cpp @@ -66,3 +66,15 @@ std::unique_ptr llvm::parseAssemblyString(StringRef AsmString, MemoryBufferRef F(AsmString, ""); return parseAssembly(F, Err, Context, Slots); } + +Constant *llvm::parseConstantValue(StringRef Asm, SMDiagnostic &Err, + const Module &M) { + SourceMgr SM; + std::unique_ptr Buf = MemoryBuffer::getMemBuffer(Asm); + SM.AddNewSourceBuffer(std::move(Buf), SMLoc()); + Constant *C; + if (LLParser(Asm, SM, Err, const_cast(&M)) + .parseStandaloneConstantValue(C)) + return nullptr; + return C; +} diff --git a/unittests/AsmParser/AsmParserTest.cpp b/unittests/AsmParser/AsmParserTest.cpp index 9c2081fa2f2..099f5b5f923 100644 --- a/unittests/AsmParser/AsmParserTest.cpp +++ b/unittests/AsmParser/AsmParserTest.cpp @@ -10,6 +10,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/AsmParser/Parser.h" #include "llvm/AsmParser/SlotMapping.h" +#include "llvm/IR/Constants.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" #include "llvm/Support/SourceMgr.h" @@ -64,4 +65,51 @@ TEST(AsmParserTest, SlotMappingTest) { EXPECT_EQ(Mapping.MetadataNodes.count(1), 0u); } +TEST(AsmParserTest, TypeAndConstantValueParsing) { + LLVMContext &Ctx = getGlobalContext(); + SMDiagnostic Error; + StringRef Source = "define void @test() {\n entry:\n ret void\n}"; + auto Mod = parseAssemblyString(Source, Error, Ctx); + ASSERT_TRUE(Mod != nullptr); + auto &M = *Mod; + + const Value *V; + V = parseConstantValue("double 3.5", Error, M); + ASSERT_TRUE(V); + EXPECT_TRUE(V->getType()->isDoubleTy()); + ASSERT_TRUE(isa(V)); + EXPECT_TRUE(cast(V)->isExactlyValue(3.5)); + + V = parseConstantValue("i32 42", Error, M); + ASSERT_TRUE(V); + EXPECT_TRUE(V->getType()->isIntegerTy()); + ASSERT_TRUE(isa(V)); + EXPECT_TRUE(cast(V)->equalsInt(42)); + + V = parseConstantValue("<4 x i32> ", Error, M); + ASSERT_TRUE(V); + EXPECT_TRUE(V->getType()->isVectorTy()); + ASSERT_TRUE(isa(V)); + + V = parseConstantValue("i32 add (i32 1, i32 2)", Error, M); + ASSERT_TRUE(V); + ASSERT_TRUE(isa(V)); + + V = parseConstantValue("i8* blockaddress(@test, %entry)", Error, M); + ASSERT_TRUE(V); + ASSERT_TRUE(isa(V)); + + EXPECT_FALSE(parseConstantValue("duble 3.25", Error, M)); + EXPECT_EQ(Error.getMessage(), "expected type"); + + EXPECT_FALSE(parseConstantValue("i32 3.25", Error, M)); + EXPECT_EQ(Error.getMessage(), "floating point constant invalid for type"); + + EXPECT_FALSE(parseConstantValue("i32* @foo", Error, M)); + EXPECT_EQ(Error.getMessage(), "expected a constant value"); + + EXPECT_FALSE(parseConstantValue("i32 3, ", Error, M)); + EXPECT_EQ(Error.getMessage(), "expected end of string"); +} + } // end anonymous namespace