[PATCH] AsmParser: Add a function to parse a standalone type and value

Duncan P. N. Exon Smith dexonsmith at apple.com
Fri Jun 5 13:06:51 PDT 2015


> On 2015-Jun-05, at 11:29, Alex Lorenz <arphaman at gmail.com> wrote:
> 
> Hi dexonsmith, bogner, bob.wilson,
> 
> This patch extends the interface provided by the AsmParser library by adding a function that allows the user to parse a standalone type and value in a given string.
> 
> This change would be useful for the MachineIR serialization, as it would allow the MIR parser to parse the constant values in a MachineConstantPool. 
> This is an example of a MIR fragment that shows several constant pool entries in a machine function:
> 
>  constants:
>    - value:           'double 3.250000e+00'
>    - value:           'float 6.250000e+00'
>      alignment:       4
> 
> REPOSITORY
>  rL LLVM
> 
> http://reviews.llvm.org/D10280
> 
> Files:
>  include/llvm/AsmParser/Parser.h
>  lib/AsmParser/LLParser.cpp
>  lib/AsmParser/LLParser.h
>  lib/AsmParser/Parser.cpp
>  unittests/AsmParser/AsmParserTest.cpp
> 
> EMAIL PREFERENCES
>  http://reviews.llvm.org/settings/panel/emailpreferences/

> Index: include/llvm/AsmParser/Parser.h
> ===================================================================
> --- include/llvm/AsmParser/Parser.h
> +++ include/llvm/AsmParser/Parser.h
> @@ -21,6 +21,7 @@
>  class Module;
>  class SMDiagnostic;
>  class LLVMContext;
> +class Value;
>  
>  /// This function is the main interface to the LLVM Assembly Parser. It parses
>  /// an ASCII file that (presumably) contains LLVM Assembly code. It returns a
> @@ -67,6 +68,12 @@
>  /// @return true on error.
>  bool parseAssemblyInto(MemoryBufferRef F, Module &M, SMDiagnostic &Err);
>  
> +/// Parses a type and a value in the given string.
> +///
> +/// @return null on error.

I think I've seen the LaTeX variant (`\return`) more often than the
JavaDoc variant (`@return`) in LLVM, and I have a mild preference for
it.  Unless you disagree with this colour of paint, can you update the
header to use this style, and then change your patch to use it?

> +const Value *parseTypeAndValue(StringRef AsmString, SMDiagnostic &Err,
> +                               const Module &M);

I can't see how this could be useful outside of constants.  Unless you
see a use, please change this to return `Constant *`.  (No reason for
the `const` in the return, I don't think.)

Might even want to make this *more* specific... see below.

> +
>  } // End llvm namespace
>  
>  #endif
> Index: lib/AsmParser/LLParser.cpp
> ===================================================================
> --- lib/AsmParser/LLParser.cpp
> +++ lib/AsmParser/LLParser.cpp
> @@ -47,6 +47,19 @@
>           ValidateEndOfModule();
>  }
>  
> +const Value *LLParser::parseStandaloneTypeAndValue() {
> +  Lex.Lex();
> +
> +  Value *V;
> +  if (ParseTypeAndValue(V, /*PFS=*/nullptr))
> +    return nullptr;

I'm not sure this is careful enough.  What do you do for this?

    i32* @var

Is that allowed?  If so, I'm confused (and what about functions?).  If
not, you should do some checking.

  - You should check that this is a constant (there may even be a
    `ParseConstant()` function?).
  - Since this is standalone, you should check that it's not in any way
    referencing a `GlobalValue` (or, if they're reasonable here, please
    explain what I'm missing).
  - Should this support aggregate types?  You should be clear in the
    doxygen of the top-level function, and error out appropriately.
  - Should this support `ConstantExpr`?  Again, be clear in the doxygen
    and error out appropriately.

BTW, I think checking `isa<ConstantFP>(C) || isa<ConstantInt>(C)` would
be pretty reasonable, and would rule out all the corner cases I
mentioned.  You might even add a new class `ConstantScalar` that those
two inherit from, and change the top-level function to:

    ConstantScalar *parseConstantScalar(StringRef Asm, ...);

and rename this to `LLParser::parseStandaloneConstantScalar()`.

> +  if (Lex.getKind() != lltok::Eof) {
> +    Error(Lex.getLoc(), "expected end of string");
> +    return nullptr;
> +  }
> +  return V;
> +}
> +
>  /// ValidateEndOfModule - Do final validity and sanity checks at the end of the
>  /// module.
>  bool LLParser::ValidateEndOfModule() {
> Index: lib/AsmParser/LLParser.h
> ===================================================================
> --- lib/AsmParser/LLParser.h
> +++ lib/AsmParser/LLParser.h
> @@ -140,6 +140,8 @@
>            BlockAddressPFS(nullptr) {}
>      bool Run();
>  
> +    const Value *parseStandaloneTypeAndValue();
> +
>      LLVMContext &getContext() { return Context; }
>  
>    private:
> Index: lib/AsmParser/Parser.cpp
> ===================================================================
> --- lib/AsmParser/Parser.cpp
> +++ lib/AsmParser/Parser.cpp
> @@ -62,3 +62,12 @@
>    MemoryBufferRef F(AsmString, "<string>");
>    return parseAssembly(F, Err, Context);
>  }
> +
> +const Value *llvm::parseTypeAndValue(StringRef AsmString, SMDiagnostic &Err,
> +                                     const Module &M) {
> +  SourceMgr SM;
> +  std::unique_ptr<MemoryBuffer> Buf = MemoryBuffer::getMemBuffer(AsmString);
> +  SM.AddNewSourceBuffer(std::move(Buf), SMLoc());
> +  return LLParser(AsmString, SM, Err, const_cast<Module *>(&M))
> +      .parseStandaloneTypeAndValue();
> +}
> Index: unittests/AsmParser/AsmParserTest.cpp
> ===================================================================
> --- unittests/AsmParser/AsmParserTest.cpp
> +++ unittests/AsmParser/AsmParserTest.cpp
> @@ -9,6 +9,7 @@
>  
>  #include "llvm/ADT/StringRef.h"
>  #include "llvm/AsmParser/Parser.h"
> +#include "llvm/IR/Constants.h"
>  #include "llvm/IR/LLVMContext.h"
>  #include "llvm/IR/Module.h"
>  #include "llvm/Support/SourceMgr.h"
> @@ -44,4 +45,33 @@
>  #endif
>  #endif
>  
> +TEST(AsmParserTest, TypeAndValueParsing) {
> +  LLVMContext &Ctx = getGlobalContext();
> +  Module M("test", Ctx);
> +  SMDiagnostic Error;
> +  const Value *V;
> +
> +  V = parseTypeAndValue("double 3.5", Error, M);
> +  EXPECT_TRUE(V != nullptr);

Either use:

    EXPECT_NE(nullptr, V);

Or, my preference:

    EXPECT_TRUE(V);

> +  EXPECT_TRUE(V->getType()->isDoubleTy());
> +  EXPECT_TRUE(isa<ConstantFP>(V));
> +  EXPECT_TRUE(cast<ConstantFP>(V)->isExactlyValue(3.5));

This will assert out and crash if `V` isn't a `ConstantFP`.  Maybe the
previous check for `isa` should be `ASSERT_TRUE` so that the test is
aborted on failure without hiding results from other tests.

> +
> +  V = parseTypeAndValue("i32 42", Error, M);
> +  EXPECT_TRUE(V != nullptr);
> +  EXPECT_TRUE(V->getType()->isIntegerTy());
> +  EXPECT_TRUE(isa<ConstantInt>(V));
> +  EXPECT_TRUE(cast<ConstantInt>(V)->equalsInt(42));
> +
> +  V = parseTypeAndValue("duble 3.25", Error, M);
> +  EXPECT_FALSE(V != nullptr);

This double negative is confusing.  Here you're not even using the
result `V`, so IMO you should just say:

    EXPECT_FALSE(parseTypeAndValue(...));

Also, should you check `Error`?

> +
> +  V = parseTypeAndValue("i32 3.25", Error, M);
> +  EXPECT_FALSE(V != nullptr);

Should you check `Error`?

> +
> +  V = parseTypeAndValue("i32 3, ", Error, M);
> +  EXPECT_FALSE(V != nullptr);
> +  EXPECT_EQ(Error.getMessage(), "expected end of string");
> +}
> +
>  } // end anonymous namespace
> 






More information about the llvm-commits mailing list