Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Formal Grammar of LLVM IR #2

Closed
mewmew opened this issue Oct 1, 2014 · 20 comments
Closed

Formal Grammar of LLVM IR #2

mewmew opened this issue Oct 1, 2014 · 20 comments
Assignees
Milestone

Comments

@mewmew
Copy link
Member

mewmew commented Oct 1, 2014

I've been unable to locate an official formal grammar for LLVM IR. If anyone has information about work in this direction, please point it out to me.

To address this issue a formal grammar of LLVM IR will be created, prior to the implementation of the LLVM IR Assembly Language parser. This work was taking place at mewlang/llvm/asm/grammar (old link superseded by https://github.com/llir/llvm/blob/master/asm/internal/ll.bnf).

Edit: For anyone who happen to stumble upon this issue. The latest version of the grammar is located in the llir/grammar repository, more specifically see ll.tm for an EBNF grammar for LLVM IR assembly.

@mewmew mewmew added this to the research milestone Oct 1, 2014
@mewmew
Copy link
Member Author

mewmew commented Oct 2, 2014

@reedkotler has started producing a formal specification for the LLVM IR Assembly Language. The initial work took place in 2011, but he has recently started to work on it again; although with low-priority.

@quarnster
Copy link
Contributor

Don't know if LLVM IR assembly is suitable for being described in parsing expression grammar form, but if it is I have a tool in https://github.com/quarnster/parser/pegparser that generates a parser that constructs a node hierarchy from PEG descriptions. The code parsing the PEG input file is self-generated by that tool via peg.peg.

Also of potential interest for the binary IR reader could be https://github.com/quarnster/util/blob/master/encoding/binary/reader.go, which allows you to annotate struct fields with some logic and thus removing the need to write manual handling code is some instances.

Admittedly documentation is lacking for both of these...

@mewmew
Copy link
Member Author

mewmew commented Oct 13, 2014

Hi quarnster!

Don't know if LLVM IR assembly is suitable for being described in parsing expression grammar form, but if it is I have a tool in https://github.com/quarnster/parser/pegparser that generates a parser that constructs a node hierarchy from PEG descriptions. The code parsing the PEG input file is self-generated by that tool via peg.peg.

Neither do I, yet :) Thanks for pointing out your pegparser though. After the formal grammar has been established it should become clear if PEG is suitable for the parser. Admittedly, after watching Rob's talk on Lexical Scanning in Go, I do love writing lexers; so I may end up writing one from the ground up. As with any decision, there are pros and cons that have to be considered. Keeping the PEG definition up to date and regenerating the parsers may be more feasible if the assembly representation of LLVM IR is changing too often.

Also of potential interest for the binary IR reader could be https://github.com/quarnster/util/blob/master/encoding/binary/reader.go, which allows you to annotate struct fields with some logic and thus removing the need to write manual handling code is some instances.

The bitcode format of LLVM IR is quite intricate as it defines its own abbreviations of how to handle various data within the format itself, similar to that of Huffman coding. Your binary package seems to solve a general problem with binary decoding that I've come across quite a few times in the past though, and I'm sure it will come in handy :) Last week me and a friend of mine were parsing some DNS packets, and your binary package would have facilitated that process for sure :)

Admittedly documentation is lacking for both of these...

Everything in the world of computing is subject to constant refinements and improvements. I'll ask you to clarify if anything seems unclear.

P.S. När studerade du på KTH? Min bror har påbörjat sitt andra år som datorvetare vid KTH. Även jag läser till datorvetare; första året vid Uppsala Universitet, och nu andra året som utbytesstudent vid Portsmouth University.

@quarnster
Copy link
Contributor

Ey, Sweden represent! Jag var där 2002-2005 så det var ett tag sedan ;)

As you're a student, I'd say roll your own parser and get some practical experience in that area too if you think you'll have time for it :)

@mewmew
Copy link
Member Author

mewmew commented Oct 13, 2014

Ey, Sweden represent! Jag var där 2002-2005 så det var ett tag sedan ;)

Soft :)

As you're a student, I'd say roll your own parser and get some practical experience in that area too if you think you'll have time for it :)

I'll definitely consider writing my own parser. There are so many interesting areas to investigate, so no matter how much time I would have for the project, I would always love to dive into yet another area :)

As described briefly in issue #3 my personal use of the LLVM IR packages will be that of reverse compilation. That being said, I've followed the progress of llgo for quite some while, and have every intention of making the LLVM IR packages support its requirements. Only time will tell if llgo end up using the library or not; but I'm sure this will be a fun and valuable learning experience nonetheless :)

@mewmew mewmew self-assigned this Jan 8, 2015
@mewmew mewmew removed this from the research milestone Nov 24, 2015
@mewmew
Copy link
Member Author

mewmew commented Jun 19, 2016

The llir/spec repository has been created with the specific aim of defining a formal grammar for LLVM IR. It is currently using Gocc to generate a lexer and a parser from an LR1 grammar of LLVM IR assembly (old link superseded by https://github.com/llir/llvm/blob/master/asm/internal/ll.bnf). Interestingly, using gocc has already helped uncover a language ambiguity with unnamed global variables that was pending inclusion into LLVM, but has since been revoked.

Closing this issue for now, as the issue tracker of the llir/spec will be used for future discussion related to the spec. Feel free to join the effort on defining a formal grammar for LLVM IR assembly :)

Update as of 2016-12-10: Note that the llir/spec repository has been intentionally merged with this one, as using a BNF grammar for generating the lexer and parser is the way to go for this project, and has therefore been integrated into the main repository at https://github.com/llir/llvm/blob/master/asm/internal/ll.bnf

Any feedback, suggestions or thoughts regarding this work is thus best suited for the issue tracker of the main llir/llvm project https://github.com/llir/llvm/issues

Cheers /u

@AljoschaMeyer
Copy link

The links in the previous comment are dead. Does this still exist?

@reedkotler
Copy link

reedkotler commented Dec 10, 2016 via email

@mewmew
Copy link
Member Author

mewmew commented Dec 10, 2016

@AljoschaMeyer A mirror of @reedkotler's repository exists at https://github.com/decomp-mirror/llvm-assembly-language-formal-specification

The llir/spec repository was used to evaluate the suitability of using Gocc for generating a lexer and parser for LLVM IR assembly, from a BNF grammar. The experiment was quite successful, and the BNF grammar has thus been merged back into the main repository for the project; and the llir/spec repository has been removed in favour of using the main repository to track this work.

I updated to comment above to provide some additional background #2 (comment)

I'm doing a new one now using antlr.

@reedkotler Do you have this work public somewhere? I'd be most interested to review it.

Cheers /u

@mewmew
Copy link
Member Author

mewmew commented Dec 10, 2016

@AljoschaMeyer Please note that the BNF grammar for LLVM IR is under active development, as tracked by issue #15.

@reedkotler
Copy link

reedkotler commented Dec 10, 2016 via email

@mewmew
Copy link
Member Author

mewmew commented Dec 10, 2016

I don't need to do a whole new one but my application is in scala so I need to either make gocc generate scala tables or just hand translate yours to antlr. ANtlr has the advantage of lots of nice tools like graphical printout of syntax.

@reedkotler It may definitely be possible to add Scala as output for Gocc. I know that Gocc was originally intended to have several output languages. As of now, output for Go is the only one implemented. I've created an issue dedicated to this development, and invited you to the discussion at goccmack/gocc#39.

Of course, you are still free to use whichever parts of the BNF grammar and translate those to ANTLR.

As the LLVM community is still lacking an official BNF grammar I do personally wish we may collaborate to make the situation better. Either by developing a Gocc and ANTLR grammar in tandem and collaborating on getting these to agree with one another, or to work together on a BNF and then add support to Gocc for your use cases.

Cheerful regards /u

@mewmew
Copy link
Member Author

mewmew commented Apr 5, 2017

Reopening this issue as an officially supported formal grammar for LLVM IR has not yet emerged.

This issue may help track the development of such a grammar, and provide links, resources and the basis for a discussions on how such a grammar may be included upstream into the LLVM project.

@reedkotler How did it go with your Antler grammar? Did you continue developing it? I would be very happy to take a look at what you've written so far, if you decide to release it with the public.

Joyful regards /u

@mewmew mewmew reopened this Apr 5, 2017
@mewmew
Copy link
Member Author

mewmew commented Apr 5, 2017

The llir/llvm project is nearing full read support for LLVM IR assembly, and as such the BNF grammar is soon ready for outside critical review and validating use.

Our aim is to finish adding support for the last remaining parts of the language, as tracked by the todo list at #15 (comment)

Once the grammar supports the known language constructs of LLVM IR assembly, we will try to polish the grammar and look for different approaches of getting it committed to the main LLVM project. This would include looking at how it may be used by parser generates to generate C++ lexers and parsers for LLVM IR assembly.

The dream would be to replace the hand-written C++ parser for LLVM IR assembly of the LLVM project, with parsers generated from a canonical BNF grammar for LLVM IR as this would improve maintainability, readability, documentation (the LLVM language reference manua often gets out of date or imprecise), and support interesting use cases such as the generating syntactically valid LLVM IR for fuzzers (as was the purpose of llvm.grm).

As a step towards a generic BNF grammar for LLVM IR the ll.bnf grammar has once more gained a dedicated repository, and is located at https://github.com/llir/grammar

The intention is to keep improving the BNF grammar until it supports all known LLVM IR assembly language constructs. At this point, we will start looking into how to abstract the target language of the generated parser.

Any and all input are most appreciated, as this is a learning experience for all of us. With bright futures!

Cheers /u & i

@reedkotler
Copy link

reedkotler commented Apr 11, 2017 via email

@mewmew
Copy link
Member Author

mewmew commented Mar 7, 2018

For those interested in having a BNF for LLVM IR, here is our latest efforts:

https://gist.github.com/mewmew/a2487392d5519ef49658fd8f84d9eed5

// ### [ Lexical part ] ########################################################

_ascii_letter_upper
	: 'A' - 'Z'
;

_ascii_letter_lower
	: 'a' - 'z'
;

_ascii_letter
	: _ascii_letter_upper
	| _ascii_letter_lower
;

_letter
	: _ascii_letter
	| '$'
	| '-'
	| '.'
	| '_'
;

_escape_letter
	: _letter
	| '\\'
;

_decimal_digit
	: '0' - '9'
;

_hex_digit
	: _decimal_digit
	| 'A' - 'F'
	| 'a' - 'f'
;

!comment : ';' { . } '\n' ;

!whitespace : '\x00' | ' ' | '\t' | '\r' | '\n' ;

// === [ Identifiers ] =========================================================

_name
	: _letter { _letter | _decimal_digit }
;

_escape_name
	: _escape_letter { _escape_letter | _decimal_digit }
;

_quoted_name
	: _quoted_string
;

_id
	: _decimals
;

// --- [ Global identifiers ] --------------------------------------------------

global_ident
	: _global_name
	| _global_id
;

_global_name
	: '@' ( _name | _quoted_name )
;

_global_id
	: '@' _id
;

// --- [ Local identifiers ] ---------------------------------------------------

local_ident
	: _local_name
	| _local_id
;

_local_name
	: '%' ( _name | _quoted_name )
;

_local_id
	: '%' _id
;

// --- [ Labels ] --------------------------------------------------------------

//   Label             [-a-zA-Z$._0-9]+:

label_ident
	: ( _letter | _decimal_digit ) { _letter | _decimal_digit } ':'
	| _quoted_string ':'
;

// --- [ Attribute group identifiers ] -----------------------------------------

attr_group_id
	: '#' _id
;

// --- [ Comdat identifiers ] --------------------------------------------------

comdat_name
	: '$' ( _name | _quoted_name )
;

// --- [ Metadata identifiers ] ------------------------------------------------

metadata_name
	: '!' _escape_name
;

metadata_id
	: '!' _id
;

// DW_TAG_foo
dwarf_tag
	: 'D' 'W' '_' 'T' 'A' 'G' '_' { _ascii_letter | _decimal_digit | '_' }
;

// DW_ATE_foo
dwarf_att_encoding
	: 'D' 'W' '_' 'A' 'T' 'E' '_' { _ascii_letter | _decimal_digit | '_' }
;

// DIFlagFoo
di_flag
	: 'D' 'I' 'F' 'l' 'a' 'g' { _ascii_letter | _decimal_digit | '_' }
;

// DW_LANG_foo
dwarf_lang
	: 'D' 'W' '_' 'L' 'A' 'N' 'G' '_' { _ascii_letter | _decimal_digit | '_' }
;

// DW_CC_foo
dwarf_cc
	: 'D' 'W' '_' 'C' 'C' '_' { _ascii_letter | _decimal_digit | '_' }
;

// CSK_foo
checksum_kind
	: 'C' 'S' 'K' '_' { _ascii_letter | _decimal_digit | '_' }
;

// DW_VIRTUALITY_foo
dwarf_virtuality
	: 'D' 'W' '_' 'V' 'I' 'R' 'T' 'U' 'A' 'L' 'I' 'T' 'Y' '_' { _ascii_letter | _decimal_digit | '_' }
;

// DW_MACINFO_foo
dwarf_macinfo
	: 'D' 'W' '_' 'M' 'A' 'C' 'I' 'N' 'F' 'O' '_' { _ascii_letter | _decimal_digit | '_' }
;

// DW_OP_foo
dwarf_op
	: 'D' 'W' '_' 'O' 'P' '_' { _ascii_letter | _decimal_digit | '_' }
;

// === [ Integer literals ] ====================================================

//   Integer           [-]?[0-9]+

int_lit
	: _decimal_lit
;

_decimal_lit
	: [ '-' ] _decimals
;

_decimals
	: _decimal_digit { _decimal_digit }
;

// === [ Floating-point literals ] =============================================

//   FPConstant        [-+]?[0-9]+[.][0-9]*([eE][-+]?[0-9]+)?

float_lit
	: _frac_lit
	| _sci_lit
	| _float_hex_lit
;

_frac_lit
	: [ _sign ] _decimals '.' { _decimal_digit }
;

_sign
	: '+'
	| '-'
;

_sci_lit
	: _frac_lit ( 'e' | 'E' ) [ _sign ] _decimals
;

//   HexFPConstant     0x[0-9A-Fa-f]+     // 16 hex digits
//   HexFP80Constant   0xK[0-9A-Fa-f]+    // 20 hex digits
//   HexFP128Constant  0xL[0-9A-Fa-f]+    // 32 hex digits
//   HexPPC128Constant 0xM[0-9A-Fa-f]+    // 32 hex digits
//   HexHalfConstant   0xH[0-9A-Fa-f]+    // 4 hex digits

_float_hex_lit
	:  '0' 'x'      _hex_digit { _hex_digit }
	|  '0' 'x' 'K'  _hex_digit _hex_digit _hex_digit _hex_digit _hex_digit _hex_digit _hex_digit _hex_digit _hex_digit _hex_digit _hex_digit _hex_digit _hex_digit _hex_digit _hex_digit _hex_digit _hex_digit _hex_digit _hex_digit _hex_digit
	|  '0' 'x' 'L'  _hex_digit _hex_digit _hex_digit _hex_digit _hex_digit _hex_digit _hex_digit _hex_digit _hex_digit _hex_digit _hex_digit _hex_digit _hex_digit _hex_digit _hex_digit _hex_digit _hex_digit _hex_digit _hex_digit _hex_digit _hex_digit _hex_digit _hex_digit _hex_digit _hex_digit _hex_digit _hex_digit _hex_digit _hex_digit _hex_digit _hex_digit _hex_digit
	|  '0' 'x' 'M'  _hex_digit _hex_digit _hex_digit _hex_digit _hex_digit _hex_digit _hex_digit _hex_digit _hex_digit _hex_digit _hex_digit _hex_digit _hex_digit _hex_digit _hex_digit _hex_digit _hex_digit _hex_digit _hex_digit _hex_digit _hex_digit _hex_digit _hex_digit _hex_digit _hex_digit _hex_digit _hex_digit _hex_digit _hex_digit _hex_digit _hex_digit _hex_digit
	|  '0' 'x' 'H'  _hex_digit _hex_digit _hex_digit _hex_digit
;

// === [ String literals ] =====================================================

string_lit
	: _quoted_string
;

_quoted_string
	: '"' { . } '"'
;

// === [ Types ] ===============================================================

int_type
	: 'i' _decimals
;

// ### [ Syntax part ] #########################################################

// The LLVM IR grammar has been based on the source code of the official LLVM
// project, as of 2018-02-19 (rev db070bbdacd303ae7da129f59beaf35024d94c53).
//
//    * lib/AsmParser/LLParser.cpp

// === [ Module ] ==============================================================

// https://llvm.org/docs/LangRef.html#module-structure

// ref: Run
//
//   module ::= toplevelentity*

Module
	: TopLevelEntities
;

TopLevelEntities
	: empty
	| TopLevelEntityList
;

TopLevelEntityList
	: TopLevelEntity
	| TopLevelEntityList TopLevelEntity
;

// --- [ Top-level Entities ] --------------------------------------------------

// ref: ParseTopLevelEntities

TopLevelEntity
	: SourceFilename
	| TargetDefinition
	| ModuleAsm
	| TypeDef
	| ComdatDef
	| GlobalDecl
	| GlobalDef
	| IndirectSymbolDef
	| FunctionDecl
	| FunctionDef
	| AttrGroupDef
	| NamedMetadataDef
	| MetadataDef
	| UseListOrder
	| UseListOrderBB
;

// ~~~ [ Source Filename ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// https://llvm.org/docs/LangRef.html#source-filename

// ref: ParseSourceFileName
//
//   ::= 'source_filename' '=' STRINGCONSTANT

SourceFilename
	: "source_filename" "=" StringLit
;

// ~~~ [ Target Definition ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// https://llvm.org/docs/LangRef.html#target-triple
// https://llvm.org/docs/LangRef.html#data-layout

// ref: ParseTargetDefinition
//
//   ::= 'target' 'triple' '=' STRINGCONSTANT
//   ::= 'target' 'datalayout' '=' STRINGCONSTANT

TargetDefinition
	: "target" "triple" "=" StringLit
	| "target" "datalayout" "=" StringLit
;

// ~~~ [ Module-level Inline Assembly ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// https://llvm.org/docs/LangRef.html#module-level-inline-assembly

// ref: ParseModuleAsm
//
//   ::= 'module' 'asm' STRINGCONSTANT

ModuleAsm
	: "module" "asm" StringLit
;

// ~~~ [ Type Defintion ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// https://llvm.org/docs/LangRef.html#structure-type

// ref: ParseUnnamedType
//
//   ::= LocalVarID '=' 'type' type

// ref: ParseNamedType
//
//   ::= LocalVar '=' 'type' type

TypeDef
	: LocalIdent "=" "type" OpaqueType
	| LocalIdent "=" "type" Type
;

// ~~~ [ Comdat Definition ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// https://llvm.org/docs/LangRef.html#langref-comdats

// ref: parseComdat

ComdatDef
	: ComdatName "=" "comdat" SelectionKind
;

SelectionKind
	: "any"
	| "exactmatch"
	| "largest"
	| "noduplicates"
	| "samesize"
;

// ~~~ [ Global Variable Declaration ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// https://llvm.org/docs/LangRef.html#global-variables

// ref: ParseUnnamedGlobal
//
//   OptionalVisibility (ALIAS | IFUNC) ...
//   OptionalLinkage OptionalPreemptionSpecifier OptionalVisibility
//   OptionalDLLStorageClass
//                                                     ...   -> global variable
//   GlobalID '=' OptionalVisibility (ALIAS | IFUNC) ...
//   GlobalID '=' OptionalLinkage OptionalPreemptionSpecifier OptionalVisibility
//                OptionalDLLStorageClass
//                                                     ...   -> global variable

// ref: ParseNamedGlobal
//
//   GlobalVar '=' OptionalVisibility (ALIAS | IFUNC) ...
//   GlobalVar '=' OptionalLinkage OptionalPreemptionSpecifier
//                 OptionalVisibility OptionalDLLStorageClass
//                                                     ...   -> global variable

// ref: ParseGlobal
//
//   ::= GlobalVar '=' OptionalLinkage OptionalPreemptionSpecifier
//       OptionalVisibility OptionalDLLStorageClass
//       OptionalThreadLocal OptionalUnnamedAddr OptionalAddrSpace
//       OptionalExternallyInitialized GlobalType Type Const OptionalAttrs
//   ::= OptionalLinkage OptionalPreemptionSpecifier OptionalVisibility
//       OptionalDLLStorageClass OptionalThreadLocal OptionalUnnamedAddr
//       OptionalAddrSpace OptionalExternallyInitialized GlobalType Type
//       Const OptionalAttrs

GlobalDecl
	: GlobalIdent "=" ExternLinkage OptPreemptionSpecifier OptVisibility OptDLLStorageClass OptThreadLocal OptUnnamedAddr OptAddrSpace OptExternallyInitialized Immutable Type GlobalAttrs FuncAttrs
;

// ~~~ [ Global Variable Definition ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

GlobalDef
	: GlobalIdent "=" OptLinkage OptPreemptionSpecifier OptVisibility OptDLLStorageClass OptThreadLocal OptUnnamedAddr OptAddrSpace OptExternallyInitialized Immutable Type Constant GlobalAttrs FuncAttrs
;

// ref: ParseOptionalThreadLocal
//
//   := empty
//   := 'thread_local'
//   := 'thread_local' '(' tlsmodel ')'

OptThreadLocal
	: empty
	| ThreadLocal
;

ThreadLocal
	: "thread_local"
	| "thread_local" "(" TLSModel ")"
;

// ref: ParseTLSModel
//
//   := 'localdynamic'
//   := 'initialexec'
//   := 'localexec'

TLSModel
	: "initialexec"
	| "localdynamic"
	| "localexec"
;

OptExternallyInitialized
	: empty
	| "externally_initialized"
;

// ref: ParseGlobalType
//
//   ::= 'constant'
//   ::= 'global'

Immutable
	: "constant"
	| "global"
;

GlobalAttrs
	: empty
	| "," GlobalAttrList
;

GlobalAttrList
	: GlobalAttr
	| GlobalAttrList "," GlobalAttr
;

GlobalAttr
	: Section
	| Comdat
	| Alignment
	//   ::= !dbg !57
	| MetadataAttachment
;

// ~~~ [ Indirect Symbol Definition ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// https://llvm.org/docs/LangRef.html#aliases
// https://llvm.org/docs/LangRef.html#ifuncs

// ref: parseIndirectSymbol
//
//   ::= GlobalVar '=' OptionalLinkage OptionalPreemptionSpecifier
//                     OptionalVisibility OptionalDLLStorageClass
//                     OptionalThreadLocal OptionalUnnamedAddr
//                     'alias|ifunc' IndirectSymbol
//
//  IndirectSymbol
//   ::= TypeAndValue

IndirectSymbolDef
	: GlobalIdent "=" ExternLinkage OptPreemptionSpecifier OptVisibility OptDLLStorageClass OptThreadLocal OptUnnamedAddr Alias Type "," Type Constant
	| GlobalIdent "=" OptLinkage OptPreemptionSpecifier OptVisibility OptDLLStorageClass OptThreadLocal OptUnnamedAddr Alias Type "," Type Constant
;

Alias
	: "alias"
	| "ifunc"
;

// ~~~ [ Function Declaration ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// https://llvm.org/docs/LangRef.html#functions

// ref: ParseDeclare
//
//   ::= 'declare' FunctionHeader

FunctionDecl
	: "declare" MetadataAttachments OptExternLinkage FunctionHeader
;

// ~~~ [ Function Definition ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// https://llvm.org/docs/LangRef.html#functions

// ref: ParseDefine
//
//   ::= 'define' FunctionHeader (!dbg !56)* '{' ...

FunctionDef
	: "define" OptLinkage FunctionHeader MetadataAttachments FunctionBody
;

// ref: ParseFunctionHeader
//
//   ::= OptionalLinkage OptionalPreemptionSpecifier OptionalVisibility
//       OptionalCallingConv OptRetAttrs OptUnnamedAddr Type GlobalName
//       '(' ArgList ')' OptFuncAttrs OptSection OptionalAlign OptGC
//       OptionalPrefix OptionalPrologue OptPersonalityFn

// TODO: Add OptAlignment before OptGC once the LR-1 conflict has been resolved,
// as FuncAttrs also contains "align".

FunctionHeader
	: OptPreemptionSpecifier OptVisibility OptDLLStorageClass OptCallingConv ReturnAttrs Type GlobalIdent "(" Params ")" OptUnnamedAddr FuncAttrs OptSection OptComdat OptGC OptPrefix OptPrologue OptPersonality
;

// ref: ParseOptionalCallingConv
//
//   ::= empty
//   ::= 'ccc'
//   ::= 'fastcc'
//   ::= 'intel_ocl_bicc'
//   ::= 'coldcc'
//   ::= 'x86_stdcallcc'
//   ::= 'x86_fastcallcc'
//   ::= 'x86_thiscallcc'
//   ::= 'x86_vectorcallcc'
//   ::= 'arm_apcscc'
//   ::= 'arm_aapcscc'
//   ::= 'arm_aapcs_vfpcc'
//   ::= 'msp430_intrcc'
//   ::= 'avr_intrcc'
//   ::= 'avr_signalcc'
//   ::= 'ptx_kernel'
//   ::= 'ptx_device'
//   ::= 'spir_func'
//   ::= 'spir_kernel'
//   ::= 'x86_64_sysvcc'
//   ::= 'win64cc'
//   ::= 'webkit_jscc'
//   ::= 'anyregcc'
//   ::= 'preserve_mostcc'
//   ::= 'preserve_allcc'
//   ::= 'ghccc'
//   ::= 'swiftcc'
//   ::= 'x86_intrcc'
//   ::= 'hhvmcc'
//   ::= 'hhvm_ccc'
//   ::= 'cxx_fast_tlscc'
//   ::= 'amdgpu_vs'
//   ::= 'amdgpu_ls'
//   ::= 'amdgpu_hs'
//   ::= 'amdgpu_es'
//   ::= 'amdgpu_gs'
//   ::= 'amdgpu_ps'
//   ::= 'amdgpu_cs'
//   ::= 'amdgpu_kernel'
//   ::= 'cc' UINT

OptCallingConv
	: empty
	| CallingConv
;

CallingConv
	: "amdgpu_cs"
	| "amdgpu_es"
	| "amdgpu_gs"
	| "amdgpu_hs"
	| "amdgpu_kernel"
	| "amdgpu_ls"
	| "amdgpu_ps"
	| "amdgpu_vs"
	| "anyregcc"
	| "arm_aapcs_vfpcc"
	| "arm_aapcscc"
	| "arm_apcscc"
	| "avr_intrcc"
	| "avr_signalcc"
	| "ccc"
	| "coldcc"
	| "cxx_fast_tlscc"
	| "fastcc"
	| "ghccc"
	| "hhvm_ccc"
	| "hhvmcc"
	| "intel_ocl_bicc"
	| "msp430_intrcc"
	| "preserve_allcc"
	| "preserve_mostcc"
	| "ptx_device"
	| "ptx_kernel"
	| "spir_func"
	| "spir_kernel"
	| "swiftcc"
	| "webkit_jscc"
	| "win64cc"
	| "x86_64_sysvcc"
	| "x86_fastcallcc"
	| "x86_intrcc"
	| "x86_regcallcc"
	| "x86_stdcallcc"
	| "x86_thiscallcc"
	| "x86_vectorcallcc"
	| "cc" int_lit
;

OptGC
	: empty
	| "gc" StringLit
;

OptPrefix
	: empty
	| "prefix" Type Constant
;

OptPrologue
	: empty
	| "prologue" Type Constant
;

OptPersonality
	: empty
	| "personality" Type Constant
;

// ref: ParseFunctionBody
//
//   ::= '{' BasicBlock+ UseListOrderDirective* '}'

FunctionBody
	: "{" BasicBlockList UseListOrders "}"
;

// ~~~ [ Attribute Group Definition ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// https://llvm.org/docs/LangRef.html#attribute-groups

// ref: ParseUnnamedAttrGrp
//
//   ::= 'attributes' AttrGrpID '=' '{' AttrValPair+ '}'

AttrGroupDef
	: "attributes" AttrGroupID "=" "{" FuncAttrs "}"
;

// ~~~ [ Named Metadata ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// https://llvm.org/docs/LangRef.html#named-metadata

// ref: ParseNamedMetadata
//
//   !foo = !{ !1, !2 }

NamedMetadataDef
	: MetadataName "=" "!" "{" MetadataNodes "}"
;

MetadataNodes
	: empty
	| MetadataNodeList
;

MetadataNodeList
	: MetadataNode
	| MetadataNodeList "," MetadataNode
;

MetadataNode
	: MetadataID
	// Parse DIExpressions inline as a special case. They are still MDNodes, so
	// they can still appear in named metadata. Remove this logic if they become
	// plain Metadata.
	| DIExpression
;

// ~~~ [ Standalone Metadata ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// https://llvm.org/docs/LangRef.html#metadata-nodes-and-metadata-strings

// ref: ParseStandaloneMetadata
//
//   !42 = !{...}

MetadataDef
	: MetadataID "=" OptDistinct MDTuple
	| MetadataID "=" OptDistinct SpecializedMDNode
;

OptDistinct
	: empty
	| "distinct"
;

// ~~~ [ Use-list Order Directives ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// https://llvm.org/docs/LangRef.html#use-list-order-directives

// ref: ParseUseListOrder
//
//   ::= 'uselistorder' Type Value ',' UseListOrderIndexes
//  UseListOrderIndexes
//   ::= '{' uint32 (',' uint32)+ '}'

UseListOrders
	: empty
	| UseListOrderList
;

UseListOrderList
	: UseListOrder
	| UseListOrderList UseListOrder
;

UseListOrder
	: "uselistorder" Type Value "," "{" IndexList "}"
;

// ref: ParseUseListOrderBB
//
//   ::= 'uselistorder_bb' @foo ',' %bar ',' UseListOrderIndexes

UseListOrderBB
	: "uselistorder_bb" GlobalIdent "," LocalIdent "," "{" IndexList "}"
;

// === [ Identifiers ] =========================================================

// --- [ Global Identifiers ] --------------------------------------------------

GlobalIdent
	: global_ident
;

// --- [ Local Identifiers ] ---------------------------------------------------

LocalIdent
	: local_ident
;

// --- [ Label Identifiers ] ---------------------------------------------------

LabelIdent
	: label_ident
;

// --- [ Attribute Group Identifiers ] -----------------------------------------

AttrGroupID
	: attr_group_id
;

// --- [ Comdat Identifiers ] --------------------------------------------------

ComdatName
	: comdat_name
;

// --- [ Metadata Identifiers ] ------------------------------------------------

MetadataName
	: metadata_name
;

MetadataID
	: metadata_id
;

// === [ Types ] ===============================================================

// ref: ParseType
//
//  TYPEKEYWORD("void",      Type::getVoidTy(Context));
//  TYPEKEYWORD("half",      Type::getHalfTy(Context));
//  TYPEKEYWORD("float",     Type::getFloatTy(Context));
//  TYPEKEYWORD("double",    Type::getDoubleTy(Context));
//  TYPEKEYWORD("x86_fp80",  Type::getX86_FP80Ty(Context));
//  TYPEKEYWORD("fp128",     Type::getFP128Ty(Context));
//  TYPEKEYWORD("ppc_fp128", Type::getPPC_FP128Ty(Context));
//  TYPEKEYWORD("label",     Type::getLabelTy(Context));
//  TYPEKEYWORD("metadata",  Type::getMetadataTy(Context));
//  TYPEKEYWORD("x86_mmx",   Type::getX86_MMXTy(Context));
//  TYPEKEYWORD("token",     Type::getTokenTy(Context));

Type
	: VoidType
	// Types '(' ArgTypeListI ')' OptFuncAttrs
	| FuncType
	| FirstClassType
;

FirstClassType
	: ConcreteType
	| MetadataType
;

ConcreteType
	: IntType
	// Type ::= 'float' | 'void' (etc)
	| FloatType
	// Type ::= Type '*'
	// Type ::= Type 'addrspace' '(' uint32 ')' '*'
	| PointerType
	// Type ::= '<' ... '>'
	| VectorType
	| LabelType
	// Type ::= '[' ... ']'
	| ArrayType
	// Type ::= StructType
	| StructType
	// Type ::= %foo
	// Type ::= %4
	| NamedType
	| MMXType
	| TokenType
;

// --- [ Void Types ] ----------------------------------------------------------

VoidType
	: "void"
;

// --- [ Function Types ] ------------------------------------------------------

// ref: ParseFunctionType
//
//  ::= Type ArgumentList OptionalAttrs

FuncType
	: Type "(" Params ")"
;

// --- [ Integer Types ] -------------------------------------------------------

IntType
	: int_type
;

// --- [ Floating-point Types ] ------------------------------------------------

FloatType
	: FloatKind
;

FloatKind
	: "half"
	| "float"
	| "double"
	| "x86_fp80"
	| "fp128"
	| "ppc_fp128"
;

// --- [ MMX Types ] -----------------------------------------------------------

MMXType
	: "x86_mmx"
;

// --- [ Pointer Types ] -------------------------------------------------------

PointerType
	: Type OptAddrSpace "*"
;

// --- [ Vector Types ] --------------------------------------------------------

// ref: ParseArrayVectorType
//
//     ::= '<' APSINTVAL 'x' Types '>'

VectorType
	: "<" int_lit "x" Type ">"
;

// --- [ Label Types ] ---------------------------------------------------------

LabelType
	: "label"
;

// --- [ Token Types ] ---------------------------------------------------------

TokenType
	: "token"
;

// --- [ Metadata Types ] ------------------------------------------------------

MetadataType
	: "metadata"
;

// --- [ Array Types ] ---------------------------------------------------------

// ref: ParseArrayVectorType
//
//     ::= '[' APSINTVAL 'x' Types ']'

ArrayType
	: "[" int_lit "x" Type "]"
;

// --- [ Structure Types ] -----------------------------------------------------

// ref: ParseStructBody
//
//   StructType
//     ::= '{' '}'
//     ::= '{' Type (',' Type)* '}'
//     ::= '<' '{' '}' '>'
//     ::= '<' '{' Type (',' Type)* '}' '>'

// TODO: Simplify when parser generator is not limited by 1 token lookahead.
//
//    StructType
//       : "{" Types "}"
//       | "<" "{" Types "}" ">"
//    ;

StructType
	: "{" "}"
	| "{" TypeList "}"
	| "<" "{" "}" ">"
	| "<" "{" TypeList "}" ">"
;

TypeList
	: Type
	| TypeList "," Type
;

OpaqueType
	: "opaque"
;

// --- [ Named Types ] ---------------------------------------------------------

NamedType
	: LocalIdent
;

// === [ Values ] ==============================================================

// ref: ParseValue

Value
	: Constant
	// %42
	// %foo
	| LocalIdent
	| InlineAsm
;

// --- [ Inline Assembler Expressions ] ----------------------------------------

// https://llvm.org/docs/LangRef.html#inline-assembler-expressions

// ref: ParseValID
//
//  ::= 'asm' SideEffect? AlignStack? IntelDialect? STRINGCONSTANT ','
//             STRINGCONSTANT

InlineAsm
	: "asm" OptSideEffect OptAlignStack OptIntelDialect StringLit "," StringLit
;

OptSideEffect
	: empty
	| "sideeffect"
;

OptAlignStack
	: empty
	| "alignstack"
;

OptIntelDialect
	: empty
	| "inteldialect"
;

// === [ Constants ] ===========================================================

// https://llvm.org/docs/LangRef.html#constants

// ref: ParseValID

Constant
	: BoolConst
	| IntConst
	| FloatConst
	| NullConst
	| NoneConst
	| StructConst
	| ArrayConst
	| CharArrayConst
	| VectorConst
	| ZeroInitializerConst
	// @42
	// @foo
	| GlobalIdent
	| UndefConst
	| BlockAddressConst
	| ConstantExpr
;

// --- [ Boolean Constants ] ---------------------------------------------------

// https://llvm.org/docs/LangRef.html#simple-constants

// ref: ParseValID

BoolConst
	: BoolLit
;

BoolLit
	: "true"
	| "false"
;

// --- [ Integer Constants ] ---------------------------------------------------

// https://llvm.org/docs/LangRef.html#simple-constants

// ref: ParseValID

IntConst
	: int_lit
;

IntLit
	: int_lit
;

// --- [ Floating-point Constants ] --------------------------------------------

// https://llvm.org/docs/LangRef.html#simple-constants

// ref: ParseValID

FloatConst
	: float_lit
;

// --- [ Null Pointer Constants ] ----------------------------------------------

// https://llvm.org/docs/LangRef.html#simple-constants

// ref: ParseValID

NullConst
	: "null"
;

// --- [ Token Constants ] -----------------------------------------------------

// https://llvm.org/docs/LangRef.html#simple-constants

// ref: ParseValID

NoneConst
	: "none"
;

// --- [ Structure Constants ] -------------------------------------------------

// https://llvm.org/docs/LangRef.html#complex-constants

// ref: ParseValID
//
//  ::= '{' ConstVector '}'
//  ::= '<' '{' ConstVector '}' '>' --> Packed Struct.

// TODO: Simplify when parser generator is not limited by 1 token lookahead.
//
//    StructConst
//       : "{" Elems "}"
//       | "<" "{" Elems "}" ">"
//    ;

StructConst
	: "{" "}"
	| "{" TypeConstList "}"
	| "<" "{" "}" ">"
	| "<" "{" TypeConstList "}" ">"
;

// --- [ Array Constants ] -----------------------------------------------------

// https://llvm.org/docs/LangRef.html#complex-constants

// ref: ParseValID
//
//  c "foo"

ArrayConst
	: "[" TypeConsts "]"
;

CharArrayConst
	: "c" StringLit
;

StringLit
	: string_lit
;

// --- [ Vector Constants ] ----------------------------------------------------

// https://llvm.org/docs/LangRef.html#complex-constants

// ref: ParseValID
//
//  ::= '<' ConstVector '>'         --> Vector.

VectorConst
	: "<" TypeConsts ">"
;

// --- [ Zero Initialization Constants ] ---------------------------------------

// https://llvm.org/docs/LangRef.html#complex-constants

// ref: ParseValID

ZeroInitializerConst
	: "zeroinitializer"
;

// --- [ Undefined Values ] ----------------------------------------------------

// https://llvm.org/docs/LangRef.html#undefined-values

// ref: ParseValID

UndefConst
	: "undef"
;

// --- [ Addresses of Basic Blocks ] -------------------------------------------

// https://llvm.org/docs/LangRef.html#addresses-of-basic-blocks

// ref: ParseValID
//
//  ::= 'blockaddress' '(' @foo ',' %bar ')'

BlockAddressConst
	: "blockaddress" "(" GlobalIdent "," LocalIdent ")"
;

// === [ Constant expressions ] ================================================

// https://llvm.org/docs/LangRef.html#constant-expressions

// ref: ParseValID

ConstantExpr
	// Binary expressions
	: AddExpr
	| FAddExpr
	| SubExpr
	| FSubExpr
	| MulExpr
	| FMulExpr
	| UDivExpr
	| SDivExpr
	| FDivExpr
	| URemExpr
	| SRemExpr
	| FRemExpr
	// Bitwise expressions
	| ShlExpr
	| LShrExpr
	| AShrExpr
	| AndExpr
	| OrExpr
	| XorExpr
	// Vector expressions
	| ExtractElementExpr
	| InsertElementExpr
	| ShuffleVectorExpr
	// Aggregate expressions
	| ExtractValueExpr
	| InsertValueExpr
	// Memory expressions
	| GetElementPtrExpr
	// Conversion expressions
	| TruncExpr
	| ZExtExpr
	| SExtExpr
	| FPTruncExpr
	| FPExtExpr
	| FPToUIExpr
	| FPToSIExpr
	| UIToFPExpr
	| SIToFPExpr
	| PtrToIntExpr
	| IntToPtrExpr
	| BitCastExpr
	| AddrSpaceCastExpr
	// Other expressions
	| ICmpExpr
	| FCmpExpr
	| SelectExpr
;

// --- [ Binary expressions ] --------------------------------------------------

// https://llvm.org/docs/LangRef.html#constant-expressions

// ~~~ [ add ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// ref: ParseValID

AddExpr
	: "add" OverflowFlags "(" Type Constant "," Type Constant ")"
;

// ~~~ [ fadd ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// ref: ParseValID

FAddExpr
	: "fadd" "(" Type Constant "," Type Constant ")"
;

// ~~~ [ sub ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// ref: ParseValID

SubExpr
	: "sub" OverflowFlags "(" Type Constant "," Type Constant ")"
;

// ~~~ [ fsub ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// ref: ParseValID

FSubExpr
	: "fsub" "(" Type Constant "," Type Constant ")"
;

// ~~~ [ mul ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// ref: ParseValID

MulExpr
	: "mul" OverflowFlags "(" Type Constant "," Type Constant ")"
;

// ~~~ [ fmul ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// ref: ParseValID

FMulExpr
	: "fmul" "(" Type Constant "," Type Constant ")"
;

// ~~~ [ udiv ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// ref: ParseValID

UDivExpr
	: "udiv" OptExact "(" Type Constant "," Type Constant ")"
;

// ~~~ [ sdiv ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// ref: ParseValID

SDivExpr
	: "sdiv" OptExact "(" Type Constant "," Type Constant ")"
;

// ~~~ [ fdiv ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// ref: ParseValID

FDivExpr
	: "fdiv" "(" Type Constant "," Type Constant ")"
;

// ~~~ [ urem ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// ref: ParseValID

URemExpr
	: "urem" "(" Type Constant "," Type Constant ")"
;

// ~~~ [ srem ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// ref: ParseValID

SRemExpr
	: "srem" "(" Type Constant "," Type Constant ")"
;

// ~~~ [ frem ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// ref: ParseValID

FRemExpr
	: "frem" "(" Type Constant "," Type Constant ")"
;

// --- [ Bitwise expressions ] -------------------------------------------------

// https://llvm.org/docs/LangRef.html#constant-expressions

// ~~~ [ shl ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// ref: ParseValID

ShlExpr
	: "shl" OverflowFlags "(" Type Constant "," Type Constant ")"
;

// ~~~ [ lshr ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// ref: ParseValID

LShrExpr
	: "lshr" OptExact "(" Type Constant "," Type Constant ")"
;

// ~~~ [ ashr ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// ref: ParseValID

AShrExpr
	: "ashr" OptExact "(" Type Constant "," Type Constant ")"
;

// ~~~ [ and ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// ref: ParseValID

AndExpr
	: "and" "(" Type Constant "," Type Constant ")"
;

// ~~~ [ or ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// ref: ParseValID

OrExpr
	: "or" "(" Type Constant "," Type Constant ")"
;

// ~~~ [ xor ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// ref: ParseValID

XorExpr
	: "xor" "(" Type Constant "," Type Constant ")"
;

// --- [ Vector expressions ] --------------------------------------------------

// https://llvm.org/docs/LangRef.html#constant-expressions

// ~~~ [ extractelement ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// ref: ParseValID

ExtractElementExpr
	: "extractelement" "(" Type Constant "," Type Constant ")"
;

// ~~~ [ insertelement ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// ref: ParseValID

InsertElementExpr
	: "insertelement" "(" Type Constant "," Type Constant "," Type Constant ")"
;

// ~~~ [ shufflevector ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// ref: ParseValID

ShuffleVectorExpr
	: "shufflevector" "(" Type Constant "," Type Constant "," Type Constant ")"
;

// --- [ Aggregate expressions ] -----------------------------------------------

// https://llvm.org/docs/LangRef.html#constant-expressions

// ~~~ [ extractvalue ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// ref: ParseValID

ExtractValueExpr
	: "extractvalue" "(" Type Constant Indices ")"
;

// ~~~ [ insertvalue ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// ref: ParseValID

InsertValueExpr
	: "insertvalue" "(" Type Constant "," Type Constant Indices ")"
;

// --- [ Memory expressions ] --------------------------------------------------

// https://llvm.org/docs/LangRef.html#constant-expressions

// ~~~ [ getelementptr ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// ref: ParseValID

GetElementPtrExpr
	: "getelementptr" OptInBounds "(" Type "," Type Constant "," GEPConstIndices ")"
;

// ref: ParseGlobalValueVector
//
//   ::= empty
//   ::= [inrange] TypeAndValue (',' [inrange] TypeAndValue)*

GEPConstIndices
	: empty
	| GEPConstIndexList
;

GEPConstIndexList
	: GEPConstIndex
	| GEPConstIndexList "," GEPConstIndex
;

GEPConstIndex
	: OptInrange Type Constant
;

OptInrange
	: empty
	| "inrange"
;

// --- [ Conversion expressions ] ----------------------------------------------

// https://llvm.org/docs/LangRef.html#constant-expressions

// ~~~ [ trunc ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// ref: ParseValID

TruncExpr
	: "trunc" "(" Type Constant "to" Type ")"
;

// ~~~ [ zext ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// ref: ParseValID

ZExtExpr
	: "zext" "(" Type Constant "to" Type ")"
;

// ~~~ [ sext ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// ref: ParseValID

SExtExpr
	: "sext" "(" Type Constant "to" Type ")"
;

// ~~~ [ fptrunc ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// ref: ParseValID

FPTruncExpr
	: "fptrunc" "(" Type Constant "to" Type ")"
;

// ~~~ [ fpext ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// ref: ParseValID

FPExtExpr
	: "fpext" "(" Type Constant "to" Type ")"
;

// ~~~ [ fptoui ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// ref: ParseValID

FPToUIExpr
	: "fptoui" "(" Type Constant "to" Type ")"
;

// ~~~ [ fptosi ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// ref: ParseValID

FPToSIExpr
	: "fptosi" "(" Type Constant "to" Type ")"
;

// ~~~ [ uitofp ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// ref: ParseValID

UIToFPExpr
	: "uitofp" "(" Type Constant "to" Type ")"
;

// ~~~ [ sitofp ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// ref: ParseValID

SIToFPExpr
	: "sitofp" "(" Type Constant "to" Type ")"
;

// ~~~ [ ptrtoint ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// ref: ParseValID

PtrToIntExpr
	: "ptrtoint" "(" Type Constant "to" Type ")"
;

// ~~~ [ inttoptr ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// ref: ParseValID

IntToPtrExpr
	: "inttoptr" "(" Type Constant "to" Type ")"
;

// ~~~ [ bitcast ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// ref: ParseValID

BitCastExpr
	: "bitcast" "(" Type Constant "to" Type ")"
;

// ~~~ [ addrspacecast ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// ref: ParseValID

AddrSpaceCastExpr
	: "addrspacecast" "(" Type Constant "to" Type ")"
;

// --- [ Other expressions ] ---------------------------------------------------

// https://llvm.org/docs/LangRef.html#constant-expressions

// ~~~ [ icmp ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// ref: ParseValID

ICmpExpr
	: "icmp" IPred "(" Type Constant "," Type Constant ")"
;

// ~~~ [ fcmp ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// ref: ParseValID

FCmpExpr
	: "fcmp" FPred "(" Type Constant "," Type Constant ")"
;

// ~~~ [ select ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// ref: ParseValID

SelectExpr
	: "select" "(" Type Constant "," Type Constant "," Type Constant ")"
;

// === [ Basic blocks ] ========================================================

// ref: ParseBasicBlock
//
//   ::= LabelStr? Instruction*

BasicBlockList
	: BasicBlock
	| BasicBlockList BasicBlock
;

BasicBlock
	: OptLabelIdent Instructions Terminator
;

OptLabelIdent
	: empty
	| LabelIdent
;

// === [ Instructions ] ========================================================

// https://llvm.org/docs/LangRef.html#instruction-reference

// ref: ParseInstruction

Instructions
	: empty
	| InstructionList
;

InstructionList
	: Instruction
	| InstructionList Instruction
;

Instruction
	// Instructions not producing values.
	: StoreInst
	| FenceInst
	| CmpXchgInst
	| AtomicRMWInst
	// Instructions producing values.
	| LocalIdent "=" ValueInstruction
	| ValueInstruction
;

ValueInstruction
	// Binary instructions
	: AddInst
	| FAddInst
	| SubInst
	| FSubInst
	| MulInst
	| FMulInst
	| UDivInst
	| SDivInst
	| FDivInst
	| URemInst
	| SRemInst
	| FRemInst
	// Bitwise instructions
	| ShlInst
	| LShrInst
	| AShrInst
	| AndInst
	| OrInst
	| XorInst
	// Vector instructions
	| ExtractElementInst
	| InsertElementInst
	| ShuffleVectorInst
	// Aggregate instructions
	| ExtractValueInst
	| InsertValueInst
	// Memory instructions
	| AllocaInst
	| LoadInst
	| GetElementPtrInst
	// Conversion instructions
	| TruncInst
	| ZExtInst
	| SExtInst
	| FPTruncInst
	| FPExtInst
	| FPToUIInst
	| FPToSIInst
	| UIToFPInst
	| SIToFPInst
	| PtrToIntInst
	| IntToPtrInst
	| BitCastInst
	| AddrSpaceCastInst
	// Other instructions
	| ICmpInst
	| FCmpInst
	| PhiInst
	| SelectInst
	| CallInst
	| VAArgInst
	| LandingPadInst
	| CatchPadInst
	| CleanupPadInst
;

// --- [ Binary instructions ] -------------------------------------------------

// ~~~ [ add ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// https://llvm.org/docs/LangRef.html#add-instruction

// ref: ParseArithmetic
//
//  ::= ArithmeticOps TypeAndValue ',' Value

AddInst
	: "add" OverflowFlags Type Value "," Value OptCommaSepMetadataAttachmentList
;

// ~~~ [ fadd ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// https://llvm.org/docs/LangRef.html#fadd-instruction

// ref: ParseArithmetic
//
//  ::= ArithmeticOps TypeAndValue ',' Value

FAddInst
	: "fadd" FastMathFlags Type Value "," Value OptCommaSepMetadataAttachmentList
;

// ~~~ [ sub ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// https://llvm.org/docs/LangRef.html#sub-instruction

// ref: ParseArithmetic
//
//  ::= ArithmeticOps TypeAndValue ',' Value

SubInst
	: "sub" OverflowFlags Type Value "," Value OptCommaSepMetadataAttachmentList
;

// ~~~ [ fsub ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// https://llvm.org/docs/LangRef.html#fsub-instruction

// ref: ParseArithmetic
//
//  ::= ArithmeticOps TypeAndValue ',' Value

FSubInst
	: "fsub" FastMathFlags Type Value "," Value OptCommaSepMetadataAttachmentList
;

// ~~~ [ mul ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// https://llvm.org/docs/LangRef.html#mul-instruction

// ref: ParseArithmetic
//
//  ::= ArithmeticOps TypeAndValue ',' Value

MulInst
	: "mul" OverflowFlags Type Value "," Value OptCommaSepMetadataAttachmentList
;

// ~~~ [ fmul ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// https://llvm.org/docs/LangRef.html#fmul-instruction

// ref: ParseArithmetic
//
//  ::= ArithmeticOps TypeAndValue ',' Value

FMulInst
	: "fmul" FastMathFlags Type Value "," Value OptCommaSepMetadataAttachmentList
;

// ~~~ [ udiv ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// https://llvm.org/docs/LangRef.html#udiv-instruction

// ref: ParseArithmetic
//
//  ::= ArithmeticOps TypeAndValue ',' Value

UDivInst
	: "udiv" OptExact Type Value "," Value OptCommaSepMetadataAttachmentList
;

// ~~~ [ sdiv ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// https://llvm.org/docs/LangRef.html#sdiv-instruction

// ref: ParseArithmetic
//
//  ::= ArithmeticOps TypeAndValue ',' Value

SDivInst
	: "sdiv" OptExact Type Value "," Value OptCommaSepMetadataAttachmentList
;

// ~~~ [ fdiv ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// https://llvm.org/docs/LangRef.html#fdiv-instruction

// ref: ParseArithmetic
//
//  ::= ArithmeticOps TypeAndValue ',' Value

FDivInst
	: "fdiv" FastMathFlags Type Value "," Value OptCommaSepMetadataAttachmentList
;

// ~~~ [ urem ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// https://llvm.org/docs/LangRef.html#urem-instruction

// ref: ParseArithmetic
//
//  ::= ArithmeticOps TypeAndValue ',' Value

URemInst
	: "urem" Type Value "," Value OptCommaSepMetadataAttachmentList
;

// ~~~ [ srem ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// https://llvm.org/docs/LangRef.html#srem-instruction

// ref: ParseArithmetic
//
//  ::= ArithmeticOps TypeAndValue ',' Value

SRemInst
	: "srem" Type Value "," Value OptCommaSepMetadataAttachmentList
;

// ~~~ [ frem ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// https://llvm.org/docs/LangRef.html#frem-instruction

// ref: ParseArithmetic
//
//  ::= ArithmeticOps TypeAndValue ',' Value

FRemInst
	: "frem" FastMathFlags Type Value "," Value OptCommaSepMetadataAttachmentList
;

// --- [ Bitwise instructions ] ------------------------------------------------

// ~~~ [ shl ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// https://llvm.org/docs/LangRef.html#shl-instruction

// ref: ParseArithmetic
//
//  ::= ArithmeticOps TypeAndValue ',' Value

ShlInst
	: "shl" OverflowFlags Type Value "," Value OptCommaSepMetadataAttachmentList
;

// ~~~ [ lshr ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// https://llvm.org/docs/LangRef.html#lshr-instruction

// ref: ParseArithmetic
//
//  ::= ArithmeticOps TypeAndValue ',' Value

LShrInst
	: "lshr" OptExact Type Value "," Value OptCommaSepMetadataAttachmentList
;

// ~~~ [ ashr ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// https://llvm.org/docs/LangRef.html#ashr-instruction

// ref: ParseArithmetic
//
//  ::= ArithmeticOps TypeAndValue ',' Value

AShrInst
	: "ashr" OptExact Type Value "," Value OptCommaSepMetadataAttachmentList
;

// ~~~ [ and ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// https://llvm.org/docs/LangRef.html#and-instruction

// ref: ParseLogical
//
//  ::= ArithmeticOps TypeAndValue ',' Value {

AndInst
	: "and" Type Value "," Value OptCommaSepMetadataAttachmentList
;

// ~~~ [ or ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// https://llvm.org/docs/LangRef.html#or-instruction

// ref: ParseLogical
//
//  ::= ArithmeticOps TypeAndValue ',' Value {

OrInst
	: "or" Type Value "," Value OptCommaSepMetadataAttachmentList
;

// ~~~ [ xor ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// https://llvm.org/docs/LangRef.html#xor-instruction

// ref: ParseLogical
//
//  ::= ArithmeticOps TypeAndValue ',' Value {

XorInst
	: "xor" Type Value "," Value OptCommaSepMetadataAttachmentList
;

// --- [ Vector instructions ] -------------------------------------------------

// ~~~ [ extractelement ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// https://llvm.org/docs/LangRef.html#extractelement-instruction

// ref: ParseExtractElement
//
//   ::= 'extractelement' TypeAndValue ',' TypeAndValue

ExtractElementInst
	: "extractelement" Type Value "," Type Value OptCommaSepMetadataAttachmentList
;

// ~~~ [ insertelement ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// https://llvm.org/docs/LangRef.html#insertelement-instruction

// ref: ParseInsertElement
//
//   ::= 'insertelement' TypeAndValue ',' TypeAndValue ',' TypeAndValue

InsertElementInst
	: "insertelement" Type Value "," Type Value "," Type Value OptCommaSepMetadataAttachmentList
;

// ~~~ [ shufflevector ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// https://llvm.org/docs/LangRef.html#shufflevector-instruction

// ref: ParseShuffleVector
//
//   ::= 'shufflevector' TypeAndValue ',' TypeAndValue ',' TypeAndValue

ShuffleVectorInst
	: "shufflevector" Type Value "," Type Value "," Type Value OptCommaSepMetadataAttachmentList
;

// --- [ Aggregate instructions ] ----------------------------------------------

// ~~~ [ extractvalue ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// https://llvm.org/docs/LangRef.html#extractvalue-instruction

// ref: ParseExtractValue
//
//   ::= 'extractvalue' TypeAndValue (',' uint32)+

ExtractValueInst
	: "extractvalue" Type Value "," IndexList OptCommaSepMetadataAttachmentList
;

// ~~~ [ insertvalue ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// https://llvm.org/docs/LangRef.html#insertvalue-instruction

// ref: ParseInsertValue
//
//   ::= 'insertvalue' TypeAndValue ',' TypeAndValue (',' uint32)+

InsertValueInst
	: "insertvalue" Type Value "," Type Value "," IndexList OptCommaSepMetadataAttachmentList
;

// --- [ Memory instructions ] -------------------------------------------------

// ~~~ [ alloca ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// https://llvm.org/docs/LangRef.html#alloca-instruction

// ref: ParseAlloc
//
//   ::= 'alloca' 'inalloca'? 'swifterror'? Type (',' TypeAndValue)?
//       (',' 'align' i32)? (',', 'addrspace(n))?

// TODO: Simplify when parser generator is not limited by 1 token lookahead.
//
//    AllocaInst
//       : "alloca" OptInAlloca OptSwiftError Type OptCommaTypeValue OptCommaAlignment OptCommaAddrSpace OptCommaSepMetadataAttachmentList
//    ;

AllocaInst
	: "alloca" OptInAlloca OptSwiftError Type OptCommaSepMetadataAttachmentList
	| "alloca" OptInAlloca OptSwiftError Type "," Alignment OptCommaSepMetadataAttachmentList
	| "alloca" OptInAlloca OptSwiftError Type "," Type Value OptCommaSepMetadataAttachmentList
	| "alloca" OptInAlloca OptSwiftError Type "," Type Value "," Alignment OptCommaSepMetadataAttachmentList
	| "alloca" OptInAlloca OptSwiftError Type "," AddrSpace OptCommaSepMetadataAttachmentList
	| "alloca" OptInAlloca OptSwiftError Type "," Alignment "," AddrSpace OptCommaSepMetadataAttachmentList
	| "alloca" OptInAlloca OptSwiftError Type "," Type Value "," AddrSpace OptCommaSepMetadataAttachmentList
	| "alloca" OptInAlloca OptSwiftError Type "," Type Value "," Alignment "," AddrSpace OptCommaSepMetadataAttachmentList
;

OptInAlloca
	: empty
	| "inalloca"
;

OptSwiftError
	: empty
	| "swifterror"
;

// ~~~ [ load ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// https://llvm.org/docs/LangRef.html#load-instruction

// ref: ParseLoad
//
//   ::= 'load' 'volatile'? TypeAndValue (',' 'align' i32)?
//   ::= 'load' 'atomic' 'volatile'? TypeAndValue
//       'singlethread'? AtomicOrdering (',' 'align' i32)?

// TODO: Simplify when parser generator is not limited by 1 token lookahead.
//
//    LoadInst
//       : "load" OptVolatile Type "," Type Value OptCommaAlignment OptCommaSepMetadataAttachmentList
//       | "load" "atomic" OptVolatile Type "," Type Value OptSyncScope AtomicOrdering OptCommaAlignment OptCommaSepMetadataAttachmentList
//    ;

LoadInst
	// Load.
	: "load" OptVolatile Type "," Type Value OptCommaSepMetadataAttachmentList
	| "load" OptVolatile Type "," Type Value "," Alignment OptCommaSepMetadataAttachmentList
	// Atomic load.
	| "load" "atomic" OptVolatile Type "," Type Value OptSyncScope AtomicOrdering OptCommaSepMetadataAttachmentList
	| "load" "atomic" OptVolatile Type "," Type Value OptSyncScope AtomicOrdering "," Alignment OptCommaSepMetadataAttachmentList
;

// ~~~ [ store ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// https://llvm.org/docs/LangRef.html#store-instruction

// ref: ParseStore
//
//   ::= 'store' 'volatile'? TypeAndValue ',' TypeAndValue (',' 'align' i32)?
//   ::= 'store' 'atomic' 'volatile'? TypeAndValue ',' TypeAndValue
//       'singlethread'? AtomicOrdering (',' 'align' i32)?

// TODO: Simplify when parser generator is not limited by 1 token lookahead.
//
//    StoreInst
//       : "store" OptVolatile Type Value "," Type Value OptCommaAlignment OptCommaSepMetadataAttachmentList
//       | "store" "atomic" OptVolatile Type Value "," Type Value OptSyncScope AtomicOrdering OptCommaAlignment OptCommaSepMetadataAttachmentList
//    ;

StoreInst
	: "store" OptVolatile Type Value "," Type Value OptCommaSepMetadataAttachmentList
	| "store" OptVolatile Type Value "," Type Value "," Alignment OptCommaSepMetadataAttachmentList
	| "store" "atomic" OptVolatile Type Value "," Type Value OptSyncScope AtomicOrdering OptCommaSepMetadataAttachmentList
	| "store" "atomic" OptVolatile Type Value "," Type Value OptSyncScope AtomicOrdering "," Alignment OptCommaSepMetadataAttachmentList
;

// ~~~ [ fence ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// https://llvm.org/docs/LangRef.html#fence-instruction

// ref: ParseFence
//
//   ::= 'fence' 'singlethread'? AtomicOrdering

FenceInst
	: "fence" OptSyncScope AtomicOrdering OptCommaSepMetadataAttachmentList
;

// ~~~ [ cmpxchg ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// https://llvm.org/docs/LangRef.html#cmpxchg-instruction

// ref: ParseCmpXchg
//
//   ::= 'cmpxchg' 'weak'? 'volatile'? TypeAndValue ',' TypeAndValue ','
//       TypeAndValue 'singlethread'? AtomicOrdering AtomicOrdering

CmpXchgInst
	: "cmpxchg" OptWeak OptVolatile Type Value "," Type Value "," Type Value OptSyncScope AtomicOrdering AtomicOrdering OptCommaSepMetadataAttachmentList
;

OptWeak
	: empty
	| "weak"
;

// ~~~ [ atomicrmw ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// https://llvm.org/docs/LangRef.html#atomicrmw-instruction

// ref: ParseAtomicRMW
//
//   ::= 'atomicrmw' 'volatile'? BinOp TypeAndValue ',' TypeAndValue
//       'singlethread'? AtomicOrdering

AtomicRMWInst
	: "atomicrmw" OptVolatile BinOp Type Value "," Type Value OptSyncScope AtomicOrdering OptCommaSepMetadataAttachmentList
;

BinOp
	: "add"
	| "and"
	| "max"
	| "min"
	| "nand"
	| "or"
	| "sub"
	| "umax"
	| "umin"
	| "xchg"
	| "xor"
;

// ~~~ [ getelementptr ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// https://llvm.org/docs/LangRef.html#getelementptr-instruction

// ref: ParseGetElementPtr
//
//   ::= 'getelementptr' 'inbounds'? TypeAndValue (',' TypeAndValue)*

// TODO: Simplify when parser generator is not limited by 1 token lookahead.
//
//    GetElementPtrInst
//       : "getelementptr" OptInBounds Type "," Type Value GEPIndices OptCommaSepMetadataAttachmentList
//    ;

GetElementPtrInst
	: "getelementptr" OptInBounds Type "," Type Value OptCommaSepMetadataAttachmentList
	| "getelementptr" OptInBounds Type "," Type Value "," CommaSepTypeValueList OptCommaSepMetadataAttachmentList
;

// --- [ Conversion instructions ] ---------------------------------------------

// ~~~ [ trunc ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// https://llvm.org/docs/LangRef.html#trunc-instruction

// ref: ParseCast
//
//   ::= CastOpc TypeAndValue 'to' Type

TruncInst
	: "trunc" Type Value "to" Type OptCommaSepMetadataAttachmentList
;

// ~~~ [ zext ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// https://llvm.org/docs/LangRef.html#zext-instruction

// ref: ParseCast
//
//   ::= CastOpc TypeAndValue 'to' Type

ZExtInst
	: "zext" Type Value "to" Type OptCommaSepMetadataAttachmentList
;

// ~~~ [ sext ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// https://llvm.org/docs/LangRef.html#sext-instruction

// ref: ParseCast
//
//   ::= CastOpc TypeAndValue 'to' Type

SExtInst
	: "sext" Type Value "to" Type OptCommaSepMetadataAttachmentList
;

// ~~~ [ fptrunc ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// https://llvm.org/docs/LangRef.html#fptrunc-instruction

// ref: ParseCast
//
//   ::= CastOpc TypeAndValue 'to' Type

FPTruncInst
	: "fptrunc" Type Value "to" Type OptCommaSepMetadataAttachmentList
;

// ~~~ [ fpext ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// https://llvm.org/docs/LangRef.html#fpext-instruction

// ref: ParseCast
//
//   ::= CastOpc TypeAndValue 'to' Type

FPExtInst
	: "fpext" Type Value "to" Type OptCommaSepMetadataAttachmentList
;

// ~~~ [ fptoui ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// https://llvm.org/docs/LangRef.html#fptoui-instruction

// ref: ParseCast
//
//   ::= CastOpc TypeAndValue 'to' Type

FPToUIInst
	: "fptoui" Type Value "to" Type OptCommaSepMetadataAttachmentList
;

// ~~~ [ fptosi ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// https://llvm.org/docs/LangRef.html#fptosi-instruction

// ref: ParseCast
//
//   ::= CastOpc TypeAndValue 'to' Type

FPToSIInst
	: "fptosi" Type Value "to" Type OptCommaSepMetadataAttachmentList
;

// ~~~ [ uitofp ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// https://llvm.org/docs/LangRef.html#uitofp-instruction

// ref: ParseCast
//
//   ::= CastOpc TypeAndValue 'to' Type

UIToFPInst
	: "uitofp" Type Value "to" Type OptCommaSepMetadataAttachmentList
;

// ~~~ [ sitofp ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// https://llvm.org/docs/LangRef.html#sitofp-instruction

// ref: ParseCast
//
//   ::= CastOpc TypeAndValue 'to' Type

SIToFPInst
	: "sitofp" Type Value "to" Type OptCommaSepMetadataAttachmentList
;

// ~~~ [ ptrtoint ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// https://llvm.org/docs/LangRef.html#ptrtoint-instruction

// ref: ParseCast
//
//   ::= CastOpc TypeAndValue 'to' Type

PtrToIntInst
	: "ptrtoint" Type Value "to" Type OptCommaSepMetadataAttachmentList
;

// ~~~ [ inttoptr ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// https://llvm.org/docs/LangRef.html#inttoptr-instruction

// ref: ParseCast
//
//   ::= CastOpc TypeAndValue 'to' Type

IntToPtrInst
	: "inttoptr" Type Value "to" Type OptCommaSepMetadataAttachmentList
;

// ~~~ [ bitcast ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// https://llvm.org/docs/LangRef.html#bitcast-instruction

// ref: ParseCast
//
//   ::= CastOpc TypeAndValue 'to' Type

BitCastInst
	: "bitcast" Type Value "to" Type OptCommaSepMetadataAttachmentList
;

// ~~~ [ addrspacecast ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// https://llvm.org/docs/LangRef.html#addrspacecast-instruction

// ref: ParseCast
//
//   ::= CastOpc TypeAndValue 'to' Type

AddrSpaceCastInst
	: "addrspacecast" Type Value "to" Type OptCommaSepMetadataAttachmentList
;

// --- [ Other instructions ] --------------------------------------------------

// ~~~ [ icmp ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// https://llvm.org/docs/LangRef.html#icmp-instruction

// ref: ParseCompare
//
//  ::= 'icmp' IPredicates TypeAndValue ',' Value

ICmpInst
	: "icmp" IPred Type Value "," Value OptCommaSepMetadataAttachmentList
;

// ~~~ [ fcmp ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// https://llvm.org/docs/LangRef.html#fcmp-instruction

// ref: ParseCompare
//
//  ::= 'fcmp' FPredicates TypeAndValue ',' Value

FCmpInst
	: "fcmp" FastMathFlags FPred Type Value "," Value OptCommaSepMetadataAttachmentList
;

// ~~~ [ phi ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// https://llvm.org/docs/LangRef.html#phi-instruction

// ref: ParsePHI
//
//   ::= 'phi' Type '[' Value ',' Value ']' (',' '[' Value ',' Value ']')*

PhiInst
	: "phi" Type IncList OptCommaSepMetadataAttachmentList
;

IncList
	: Inc
	| IncList "," Inc
;

Inc
	: "[" Value "," LocalIdent "]"
;

// ~~~ [ select ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// https://llvm.org/docs/LangRef.html#select-instruction

// ref: ParseSelect
//
//   ::= 'select' TypeAndValue ',' TypeAndValue ',' TypeAndValue

SelectInst
	: "select" Type Value "," Type Value "," Type Value OptCommaSepMetadataAttachmentList
;

// ~~~ [ call ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// https://llvm.org/docs/LangRef.html#call-instruction

// ref: ParseCall
//
//   ::= 'call' OptionalFastMathFlags OptionalCallingConv
//           OptionalAttrs Type Value ParameterList OptionalAttrs
//   ::= 'tail' 'call' OptionalFastMathFlags OptionalCallingConv
//           OptionalAttrs Type Value ParameterList OptionalAttrs
//   ::= 'musttail' 'call' OptionalFastMathFlags OptionalCallingConv
//           OptionalAttrs Type Value ParameterList OptionalAttrs
//   ::= 'notail' 'call'  OptionalFastMathFlags OptionalCallingConv
//           OptionalAttrs Type Value ParameterList OptionalAttrs

CallInst
	: OptTail "call" FastMathFlags OptCallingConv ReturnAttrs Type Value "(" Args ")" FuncAttrs OperandBundles OptCommaSepMetadataAttachmentList
;

OptTail
	: empty
	| "musttail"
	| "notail"
	| "tail"
;

// ~~~ [ va_arg ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// https://llvm.org/docs/LangRef.html#va_arg-instruction

// ref: ParseVA_Arg
//
//   ::= 'va_arg' TypeAndValue ',' Type

VAArgInst
	: "va_arg" Type Value "," Type OptCommaSepMetadataAttachmentList
;

// ~~~ [ landingpad ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// https://llvm.org/docs/LangRef.html#landingpad-instruction

// ref: ParseLandingPad
//
//   ::= 'landingpad' Type 'personality' TypeAndValue 'cleanup'? Clause+
//  Clause
//   ::= 'catch' TypeAndValue
//   ::= 'filter'
//   ::= 'filter' TypeAndValue ( ',' TypeAndValue )*

LandingPadInst
	: "landingpad" Type OptCleanup Clauses OptCommaSepMetadataAttachmentList
;

OptCleanup
	: empty
	| "cleanup"
;

Clauses
	: empty
	| ClauseList
;

ClauseList
	: Clause
	| ClauseList Clause
;

Clause
	: "catch" Type Value
	| "filter" Type ArrayConst
;

// --- [ catchpad ] ------------------------------------------------------------

// ref: ParseCatchPad
//
//   ::= 'catchpad' ParamList 'to' TypeAndValue 'unwind' TypeAndValue

CatchPadInst
	: "catchpad" "within" LocalIdent "[" ExceptionArgs "]" OptCommaSepMetadataAttachmentList
;

// --- [ cleanuppad ] ----------------------------------------------------------

// ref: ParseCleanupPad
//
//   ::= 'cleanuppad' within Parent ParamList

CleanupPadInst
	: "cleanuppad" "within" ExceptionScope "[" ExceptionArgs "]" OptCommaSepMetadataAttachmentList
;

// === [ Terminators ] =========================================================

// https://llvm.org/docs/LangRef.html#terminator-instructions

// ref: ParseInstruction

Terminator
	: RetTerm
	| BrTerm
	| CondBrTerm
	| SwitchTerm
	| IndirectBrTerm
	| InvokeTerm
	| ResumeTerm
	| CatchSwitchTerm
	| CatchRetTerm
	| CleanupRetTerm
	| UnreachableTerm
;

// --- [ ret ] -----------------------------------------------------------------

// https://llvm.org/docs/LangRef.html#ret-instruction

// ref: ParseRet
//
//   ::= 'ret' void (',' !dbg, !1)*
//   ::= 'ret' TypeAndValue (',' !dbg, !1)*

RetTerm
	// Void return.
	: "ret" VoidType OptCommaSepMetadataAttachmentList
	// Value return.
	| "ret" ConcreteType Value OptCommaSepMetadataAttachmentList
;

// --- [ br ] ------------------------------------------------------------------

// https://llvm.org/docs/LangRef.html#br-instruction

// ref: ParseBr
//
//   ::= 'br' TypeAndValue
//   ::= 'br' TypeAndValue ',' TypeAndValue ',' TypeAndValue

// Unconditional branch.
BrTerm
	: "br" LabelType LocalIdent OptCommaSepMetadataAttachmentList
;

// Conditional branch.
CondBrTerm
	: "br" IntType Value "," LabelType LocalIdent "," LabelType LocalIdent OptCommaSepMetadataAttachmentList
;

// --- [ switch ] --------------------------------------------------------------

// https://llvm.org/docs/LangRef.html#switch-instruction

// ref: ParseSwitch
//
//    ::= 'switch' TypeAndValue ',' TypeAndValue '[' JumpTable ']'
//  JumpTable
//    ::= (TypeAndValue ',' TypeAndValue)*

SwitchTerm
	: "switch" Type Value "," LabelType LocalIdent "[" Cases "]" OptCommaSepMetadataAttachmentList
;

Cases
	: empty
	| CaseList
;

CaseList
	: Case
	| CaseList Case
;

Case
	: Type IntConst "," LabelType LocalIdent
;

// --- [ indirectbr ] ----------------------------------------------------------

// https://llvm.org/docs/LangRef.html#indirectbr-instruction

// ref: ParseIndirectBr
//
//    ::= 'indirectbr' TypeAndValue ',' '[' LabelList ']'

IndirectBrTerm
	: "indirectbr" Type Value "," "[" LabelList "]" OptCommaSepMetadataAttachmentList
;

LabelList
	: Label
	| LabelList "," Label
;

Label
	: LabelType LocalIdent
;

// --- [ invoke ] --------------------------------------------------------------

// https://llvm.org/docs/LangRef.html#invoke-instruction

// ref: ParseInvoke
//
//   ::= 'invoke' OptionalCallingConv OptionalAttrs Type Value ParamList
//       OptionalAttrs 'to' TypeAndValue 'unwind' TypeAndValue

InvokeTerm
	: "invoke" OptCallingConv ReturnAttrs Type Value "(" Args ")" FuncAttrs OperandBundles "to" LabelType LocalIdent "unwind" LabelType LocalIdent OptCommaSepMetadataAttachmentList
;

// --- [ resume ] --------------------------------------------------------------

// https://llvm.org/docs/LangRef.html#resume-instruction

// ref: ParseResume
//
//   ::= 'resume' TypeAndValue

ResumeTerm
	: "resume" Type Value OptCommaSepMetadataAttachmentList
;

// --- [ catchswitch ] ---------------------------------------------------------

// https://llvm.org/docs/LangRef.html#catchswitch-instruction

// ref: ParseCatchSwitch
//
//   ::= 'catchswitch' within Parent

CatchSwitchTerm
	: "catchswitch" "within" ExceptionScope "[" LabelList "]" "unwind" UnwindTarget OptCommaSepMetadataAttachmentList
;

UnwindTarget
	: "to" "caller"
	| LabelType LocalIdent
;

// --- [ catchret ] ------------------------------------------------------------

// https://llvm.org/docs/LangRef.html#catchret-instruction

// ref: ParseCatchRet
//
//   ::= 'catchret' from Parent Value 'to' TypeAndValue

CatchRetTerm
	: "catchret" "from" Value "to" LabelType LocalIdent OptCommaSepMetadataAttachmentList
;

// --- [ cleanupret ] ----------------------------------------------------------

// https://llvm.org/docs/LangRef.html#cleanupret-instruction

// ref: ParseCleanupRet
//
//   ::= 'cleanupret' from Value unwind ('to' 'caller' | TypeAndValue)

CleanupRetTerm
	: "cleanupret" "from" Value "unwind" UnwindTarget OptCommaSepMetadataAttachmentList
;

// --- [ unreachable ] ---------------------------------------------------------

// https://llvm.org/docs/LangRef.html#unreachable-instruction

// ref: ParseInstruction

UnreachableTerm
	: "unreachable" OptCommaSepMetadataAttachmentList
;

// === [ Metadata Nodes and Metadata Strings ] =================================

// https://llvm.org/docs/LangRef.html#metadata-nodes-and-metadata-strings

// --- [ Metadata Tuple ] ------------------------------------------------------

// ref: ParseMDTuple

MDTuple
	: "!" MDFields
;

// ref: ParseMDNodeVector
//
//   ::= { Element (',' Element)* }
//  Element
//   ::= 'null' | TypeAndValue

// ref: ParseMDField(MDFieldList &)

MDFields
	: "{" "}"
	| "{" MDFieldList "}"
;

MDFieldList
	: MDField
	| MDFieldList "," MDField
;

// ref: ParseMDField(MDField &)

MDField
	// Null is a special case since it is typeless.
	: NullConst
	| Metadata
;

// --- [ Metadata ] ------------------------------------------------------------

// ref: ParseMetadata
//
//  ::= i32 %local
//  ::= i32 @global
//  ::= i32 7
//  ::= !42
//  ::= !{...}
//  ::= !"string"
//  ::= !DILocation(...)

Metadata
	: Type Value
	| MDString
	// !{ ... }
	| MDTuple
	// !7
	| MetadataID
	| SpecializedMDNode
;

// --- [ Metadata String ] -----------------------------------------------------

// ref: ParseMDString
//
//   ::= '!' STRINGCONSTANT

MDString
	: "!" StringLit
;

// --- [ Metadata Attachment ] -------------------------------------------------

// ref: ParseMetadataAttachment
//
//   ::= !dbg !42

MetadataAttachment
	: MetadataName MDNode
;

// --- [ Metadata Node ] -------------------------------------------------------

// ref: ParseMDNode
//
//  ::= !{ ... }
//  ::= !7
//  ::= !DILocation(...)

MDNode
	// !{ ... }
	: MDTuple
	// !42
	| MetadataID
	| SpecializedMDNode
;

// ### [ Helper productions ] ##################################################

// ref: ParseOptionalFunctionMetadata
//
//   ::= (!dbg !57)*

MetadataAttachments
	: empty
	| MetadataAttachmentList
;

MetadataAttachmentList
	: MetadataAttachment
	| MetadataAttachmentList MetadataAttachment
;

// ref: ParseInstructionMetadata
//
//   ::= !dbg !42 (',' !dbg !57)*

OptCommaSepMetadataAttachmentList
	: empty
	| "," CommaSepMetadataAttachmentList
;

CommaSepMetadataAttachmentList
	: MetadataAttachment
	| CommaSepMetadataAttachmentList "," MetadataAttachment
;

// --- [ Specialized Metadata Nodes ] ------------------------------------------

// https://llvm.org/docs/LangRef.html#specialized-metadata-nodes

// ref: ParseSpecializedMDNode

SpecializedMDNode
	: DICompileUnit
	| DIFile
	| DIBasicType
	| DISubroutineType
	| DIDerivedType
	| DICompositeType
	| DISubrange
	| DIEnumerator
	| DITemplateTypeParameter
	| DITemplateValueParameter
	| DIModule // not in spec as of 2018-02-21
	| DINamespace
	| DIGlobalVariable
	| DISubprogram
	| DILexicalBlock
	| DILexicalBlockFile
	| DILocation
	| DILocalVariable
	| DIExpression
	| DIGlobalVariableExpression // not in spec as of 2018-02-21
	| DIObjCProperty
	| DIImportedEntity
	| DIMacro
	| DIMacroFile
	| GenericDINode // not in spec as of 2018-02-21
;

// ~~~ [ DICompileUnit ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// https://llvm.org/docs/LangRef.html#dicompileunit

// ref: ParseDICompileUnit
//
//   ::= !DICompileUnit(language: DW_LANG_C99, file: !0, producer: "clang",
//                      isOptimized: true, flags: "-O2", runtimeVersion: 1,
//                      splitDebugFilename: "abc.debug",
//                      emissionKind: FullDebug, enums: !1, retainedTypes: !2,
//                      globals: !4, imports: !5, macros: !6, dwoId: 0x0abcd)
//
//  REQUIRED(language, DwarfLangField, );
//  REQUIRED(file, MDField, (AllowNull false));
//  OPTIONAL(producer, MDStringField, );
//  OPTIONAL(isOptimized, MDBoolField, );
//  OPTIONAL(flags, MDStringField, );
//  OPTIONAL(runtimeVersion, MDUnsignedField, (0, UINT32_MAX));
//  OPTIONAL(splitDebugFilename, MDStringField, );
//  OPTIONAL(emissionKind, EmissionKindField, );
//  OPTIONAL(enums, MDField, );
//  OPTIONAL(retainedTypes, MDField, );
//  OPTIONAL(globals, MDField, );
//  OPTIONAL(imports, MDField, );
//  OPTIONAL(macros, MDField, );
//  OPTIONAL(dwoId, MDUnsignedField, );
//  OPTIONAL(splitDebugInlining, MDBoolField, = true);
//  OPTIONAL(debugInfoForProfiling, MDBoolField, = false);
//  OPTIONAL(gnuPubnames, MDBoolField, = false);

DICompileUnit
	: "!DICompileUnit" "(" DICompileUnitFields ")"
;

DICompileUnitFields
	: empty
	| DICompileUnitFieldList
;

DICompileUnitFieldList
	: DICompileUnitField
	| DICompileUnitFieldList "," DICompileUnitField
;

DICompileUnitField
	: "language:" DwarfLang
	| FileField
	| "producer:" StringLit
	| IsOptimizedField
	| "flags:" StringLit
	| "runtimeVersion:" IntLit
	| "splitDebugFilename:" StringLit
	| "emissionKind:" EmissionKind
	| "enums:" MDField
	| "retainedTypes:" MDField
	| "globals:" MDField
	| "imports:" MDField
	| "macros:" MDField
	| "dwoId:" IntLit
	| "splitDebugInlining:" BoolLit
	| "debugInfoForProfiling:" BoolLit
	| "gnuPubnames:" BoolLit
;

// ~~~ [ DIFile ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// https://llvm.org/docs/LangRef.html#difile

// ref: ParseDIFileType
//
//   ::= !DIFileType(filename: "path/to/file", directory: "/path/to/dir"
//                   checksumkind: CSK_MD5,
//                   checksum: "000102030405060708090a0b0c0d0e0f")
//
//  REQUIRED(filename, MDStringField, );
//  REQUIRED(directory, MDStringField, );
//  OPTIONAL(checksumkind, ChecksumKindField, (DIFile::CSK_MD5));
//  OPTIONAL(checksum, MDStringField, );

DIFile
	: "!DIFile" "(" DIFileFields ")"
;

DIFileFields
	: empty
	| DIFileFieldList
;

DIFileFieldList
	: DIFileField
	| DIFileFieldList "," DIFileField
;

DIFileField
	: "filename:" StringLit
	| "directory:" StringLit
	| "checksumkind:" ChecksumKind
	| "checksum:" StringLit
;

// ~~~ [ DIBasicType ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// https://llvm.org/docs/LangRef.html#dibasictype

// ref: ParseDIBasicType
//
//   ::= !DIBasicType(tag: DW_TAG_base_type, name: "int", size: 32, align: 32)
//
//  OPTIONAL(tag, DwarfTagField, (dwarf::DW_TAG_base_type));
//  OPTIONAL(name, MDStringField, );
//  OPTIONAL(size, MDUnsignedField, (0, UINT64_MAX));
//  OPTIONAL(align, MDUnsignedField, (0, UINT32_MAX));
//  OPTIONAL(encoding, DwarfAttEncodingField, );

DIBasicType
	: "!DIBasicType" "(" DIBasicTypeFields ")"
;

DIBasicTypeFields
	: empty
	| DIBasicTypeFieldList
;

DIBasicTypeFieldList
	: DIBasicTypeField
	| DIBasicTypeFieldList "," DIBasicTypeField
;

DIBasicTypeField
	: TagField
	| NameField
	| SizeField
	| AlignField
	| "encoding:" DwarfAttEncoding
;

// ~~~ [ DISubroutineType ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// https://llvm.org/docs/LangRef.html#disubroutinetype

// ref: ParseDISubroutineType
//
//  OPTIONAL(flags, DIFlagField, );
//  OPTIONAL(cc, DwarfCCField, );
//  REQUIRED(types, MDField, );

DISubroutineType
	: "!DISubroutineType" "(" DISubroutineTypeFields ")"
;

DISubroutineTypeFields
	: empty
	| DISubroutineTypeFieldList
;

DISubroutineTypeFieldList
	: DISubroutineTypeField
	| DISubroutineTypeFieldList "," DISubroutineTypeField
;

DISubroutineTypeField
	: FlagsField
	| "cc:" DwarfCC
	| "types:" MDField
;

// ~~~ [ DIDerivedType ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// https://llvm.org/docs/LangRef.html#diderivedtype

// ref: ParseDIDerivedType
//
//   ::= !DIDerivedType(tag: DW_TAG_pointer_type, name: "int", file: !0,
//                      line: 7, scope: !1, baseType: !2, size: 32,
//                      align: 32, offset: 0, flags: 0, extraData: !3,
//                      dwarfAddressSpace: 3)
//
//  REQUIRED(tag, DwarfTagField, );
//  OPTIONAL(name, MDStringField, );
//  OPTIONAL(scope, MDField, );
//  OPTIONAL(file, MDField, );
//  OPTIONAL(line, LineField, );
//  REQUIRED(baseType, MDField, );
//  OPTIONAL(size, MDUnsignedField, (0, UINT64_MAX));
//  OPTIONAL(align, MDUnsignedField, (0, UINT32_MAX));
//  OPTIONAL(offset, MDUnsignedField, (0, UINT64_MAX));
//  OPTIONAL(flags, DIFlagField, );
//  OPTIONAL(extraData, MDField, );
//  OPTIONAL(dwarfAddressSpace, MDUnsignedField, (UINT32_MAX, UINT32_MAX));

DIDerivedType
	: "!DIDerivedType" "(" DIDerivedTypeFields ")"
;

DIDerivedTypeFields
	: empty
	| DIDerivedTypeFieldList
;

DIDerivedTypeFieldList
	: DIDerivedTypeField
	| DIDerivedTypeFieldList "," DIDerivedTypeField
;

DIDerivedTypeField
	: TagField
	| NameField
	| ScopeField
	| FileField
	| LineField
	| BaseTypeField
	| SizeField
	| AlignField
	| OffsetField
	| FlagsField
	| "extraData:" MDField
	| "dwarfAddressSpace:" IntLit
;

// ~~~ [ DICompositeType ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// https://llvm.org/docs/LangRef.html#dicompositetype

// ref: ParseDICompositeType
//
//  REQUIRED(tag, DwarfTagField, );
//  OPTIONAL(name, MDStringField, );
//  OPTIONAL(scope, MDField, );
//  OPTIONAL(file, MDField, );
//  OPTIONAL(line, LineField, );
//  OPTIONAL(baseType, MDField, );
//  OPTIONAL(size, MDUnsignedField, (0, UINT64_MAX));
//  OPTIONAL(align, MDUnsignedField, (0, UINT32_MAX));
//  OPTIONAL(offset, MDUnsignedField, (0, UINT64_MAX));
//  OPTIONAL(flags, DIFlagField, );
//  OPTIONAL(elements, MDField, );
//  OPTIONAL(runtimeLang, DwarfLangField, );
//  OPTIONAL(vtableHolder, MDField, );
//  OPTIONAL(templateParams, MDField, );
//  OPTIONAL(identifier, MDStringField, );
//  OPTIONAL(discriminator, MDField, );

DICompositeType
	: "!DICompositeType" "(" DICompositeTypeFields ")"
;

DICompositeTypeFields
	: empty
	| DICompositeTypeFieldList
;

DICompositeTypeFieldList
	: DICompositeTypeField
	| DICompositeTypeFieldList "," DICompositeTypeField
;

DICompositeTypeField
	: TagField
	| NameField
	| ScopeField
	| FileField
	| LineField
	| BaseTypeField
	| SizeField
	| AlignField
	| OffsetField
	| FlagsField
	| "elements:" MDField
	| "runtimeLang:" DwarfLang
	| "vtableHolder:" MDField
	| TemplateParamsField
	| "identifier:" StringLit
	| "discriminator:" MDField
;

// ~~~ [ DISubrange ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// https://llvm.org/docs/LangRef.html#disubrange

// ref: ParseDISubrange
//
//   ::= !DISubrange(count: 30, lowerBound: 2)
//   ::= !DISubrange(count: !node, lowerBound: 2)
//
//  REQUIRED(count, MDSignedOrMDField, (-1, -1, INT64_MAX, false));
//  OPTIONAL(lowerBound, MDSignedField, );

DISubrange
	: "!DISubrange" "(" DISubrangeFields ")"
;

DISubrangeFields
	: empty
	| DISubrangeFieldList
;

DISubrangeFieldList
	: DISubrangeField
	| DISubrangeFieldList "," DISubrangeField
;

DISubrangeField
	: "count:" IntOrMDField
	| "lowerBound:" IntLit
;

// ~~~ [ DIEnumerator ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// https://llvm.org/docs/LangRef.html#dienumerator

// ref: ParseDIEnumerator
//
//   ::= !DIEnumerator(value: 30, isUnsigned: true, name: "SomeKind")
//
//  REQUIRED(name, MDStringField, );
//  REQUIRED(value, MDSignedOrUnsignedField, );
//  OPTIONAL(isUnsigned, MDBoolField, (false));

DIEnumerator
	: "!DIEnumerator" "(" DIEnumeratorFields ")"
;

DIEnumeratorFields
	: empty
	| DIEnumeratorFieldList
;

DIEnumeratorFieldList
	: DIEnumeratorField
	| DIEnumeratorFieldList "," DIEnumeratorField
;

DIEnumeratorField
	: NameField
	| "value:" IntLit
	| "isUnsigned:" BoolLit
;

// ~~~ [ DITemplateTypeParameter ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// https://llvm.org/docs/LangRef.html#ditemplatetypeparameter

// ref: ParseDITemplateTypeParameter
//
//   ::= !DITemplateTypeParameter(name: "Ty", type: !1)
//
//  OPTIONAL(name, MDStringField, );
//  REQUIRED(type, MDField, );

DITemplateTypeParameter
	: "!DITemplateTypeParameter" "(" DITemplateTypeParameterFields ")"
;

DITemplateTypeParameterFields
	: empty
	| DITemplateTypeParameterFieldList
;

DITemplateTypeParameterFieldList
	: DITemplateTypeParameterField
	| DITemplateTypeParameterFieldList "," DITemplateTypeParameterField
;

DITemplateTypeParameterField
	: NameField
	| TypeField
;

// ~~~ [ DITemplateValueParameter ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// https://llvm.org/docs/LangRef.html#ditemplatevalueparameter

// ref: ParseDITemplateValueParameter
//
//   ::= !DITemplateValueParameter(tag: DW_TAG_template_value_parameter,
//                                 name: "V", type: !1, value: i32 7)
//
//  OPTIONAL(tag, DwarfTagField, (dwarf::DW_TAG_template_value_parameter));
//  OPTIONAL(name, MDStringField, );
//  OPTIONAL(type, MDField, );
//  REQUIRED(value, MDField, );

DITemplateValueParameter
	: "!DITemplateValueParameter" "(" DITemplateValueParameterFields ")"
;

DITemplateValueParameterFields
	: empty
	| DITemplateValueParameterFieldList
;

DITemplateValueParameterFieldList
	: DITemplateValueParameterField
	| DITemplateValueParameterFieldList "," DITemplateValueParameterField
;

DITemplateValueParameterField
	: TagField
	| NameField
	| TypeField
	| "value:" MDField
;

// ~~~ [ DIModule ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// ref: ParseDIModule
//
//   ::= !DIModule(scope: !0, name: "SomeModule", configMacros: "-DNDEBUG",
//                 includePath: "/usr/include", isysroot: "/")
//
//  REQUIRED(scope, MDField, );
//  REQUIRED(name, MDStringField, );
//  OPTIONAL(configMacros, MDStringField, );
//  OPTIONAL(includePath, MDStringField, );
//  OPTIONAL(isysroot, MDStringField, );

DIModule
	: "!DIModule" "(" DIModuleFields ")"
;

DIModuleFields
	: empty
	| DIModuleFieldList
;

DIModuleFieldList
	: DIModuleField
	| DIModuleFieldList "," DIModuleField
;

DIModuleField
	: ScopeField
	| NameField
	| "configMacros:" StringLit
	| "includePath:" StringLit
	| "isysroot:" StringLit
;

// ~~~ [ DINamespace ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// https://llvm.org/docs/LangRef.html#dinamespace

// ref: ParseDINamespace
//
//   ::= !DINamespace(scope: !0, file: !2, name: "SomeNamespace", line: 9)
//
//  REQUIRED(scope, MDField, );
//  OPTIONAL(name, MDStringField, );
//  OPTIONAL(exportSymbols, MDBoolField, );

DINamespace
	: "!DINamespace" "(" DINamespaceFields ")"
;

DINamespaceFields
	: empty
	| DINamespaceFieldList
;

DINamespaceFieldList
	: DINamespaceField
	| DINamespaceFieldList "," DINamespaceField
;

DINamespaceField
	: ScopeField
	| NameField
	| "exportSymbols:" BoolLit
;

// ~~~ [ DIGlobalVariable ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// https://llvm.org/docs/LangRef.html#diglobalvariable

// ref: ParseDIGlobalVariable
//
//   ::= !DIGlobalVariable(scope: !0, name: "foo", linkageName: "foo",
//                         file: !1, line: 7, type: !2, isLocal: false,
//                         isDefinition: true, declaration: !3, align: 8)
//
//  REQUIRED(name, MDStringField, (AllowEmpty false));
//  OPTIONAL(scope, MDField, );
//  OPTIONAL(linkageName, MDStringField, );
//  OPTIONAL(file, MDField, );
//  OPTIONAL(line, LineField, );
//  OPTIONAL(type, MDField, );
//  OPTIONAL(isLocal, MDBoolField, );
//  OPTIONAL(isDefinition, MDBoolField, (true));
//  OPTIONAL(declaration, MDField, );
//  OPTIONAL(align, MDUnsignedField, (0, UINT32_MAX));

DIGlobalVariable
	: "!DIGlobalVariable" "(" DIGlobalVariableFields ")"
;

DIGlobalVariableFields
	: empty
	| DIGlobalVariableFieldList
;

DIGlobalVariableFieldList
	: DIGlobalVariableField
	| DIGlobalVariableFieldList "," DIGlobalVariableField
;

DIGlobalVariableField
	: NameField
	| ScopeField
	| LinkageNameField
	| FileField
	| LineField
	| TypeField
	| IsLocalField
	| IsDefinitionField
	| DeclarationField
	| AlignField
;

// ~~~ [ DISubprogram ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// https://llvm.org/docs/LangRef.html#disubprogram

// ref: ParseDISubprogram
//
//   ::= !DISubprogram(scope: !0, name: "foo", linkageName: "_Zfoo",
//                     file: !1, line: 7, type: !2, isLocal: false,
//                     isDefinition: true, scopeLine: 8, containingType: !3,
//                     virtuality: DW_VIRTUALTIY_pure_virtual,
//                     virtualIndex: 10, thisAdjustment: 4, flags: 11,
//                     isOptimized: false, templateParams: !4, declaration: !5,
//                     variables: !6, thrownTypes: !7)
//
//  OPTIONAL(name, MDStringField, );
//  OPTIONAL(scope, MDField, );
//  OPTIONAL(linkageName, MDStringField, );
//  OPTIONAL(file, MDField, );
//  OPTIONAL(line, LineField, );
//  OPTIONAL(type, MDField, );
//  OPTIONAL(isLocal, MDBoolField, );
//  OPTIONAL(isDefinition, MDBoolField, (true));
//  OPTIONAL(scopeLine, LineField, );
//  OPTIONAL(containingType, MDField, );
//  OPTIONAL(virtuality, DwarfVirtualityField, );
//  OPTIONAL(virtualIndex, MDUnsignedField, (0, UINT32_MAX));
//  OPTIONAL(thisAdjustment, MDSignedField, (0, INT32_MIN, INT32_MAX));
//  OPTIONAL(flags, DIFlagField, );
//  OPTIONAL(isOptimized, MDBoolField, );
//  OPTIONAL(unit, MDField, );
//  OPTIONAL(templateParams, MDField, );
//  OPTIONAL(declaration, MDField, );
//  OPTIONAL(variables, MDField, );
//  OPTIONAL(thrownTypes, MDField, );

DISubprogram
	: "!DISubprogram" "(" DISubprogramFields ")"
;

DISubprogramFields
	: empty
	| DISubprogramFieldList
;

DISubprogramFieldList
	: DISubprogramField
	| DISubprogramFieldList "," DISubprogramField
;

DISubprogramField
	: NameField
	| ScopeField
	| LinkageNameField
	| FileField
	| LineField
	| TypeField
	| IsLocalField
	| IsDefinitionField
	| "scopeLine:" IntLit
	| "containingType:" MDField
	| "virtuality:" DwarfVirtuality
	| "virtualIndex:" IntLit
	| "thisAdjustment:" IntLit
	| FlagsField
	| IsOptimizedField
	| "unit:" MDField
	| TemplateParamsField
	| DeclarationField
	| "variables:" MDField
	| "thrownTypes:" MDField
;

// ~~~ [ DILexicalBlock ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// https://llvm.org/docs/LangRef.html#dilexicalblock

// ref: ParseDILexicalBlock
//
//   ::= !DILexicalBlock(scope: !0, file: !2, line: 7, column: 9)
//
//  REQUIRED(scope, MDField, (AllowNull false));
//  OPTIONAL(file, MDField, );
//  OPTIONAL(line, LineField, );
//  OPTIONAL(column, ColumnField, );

DILexicalBlock
	: "!DILexicalBlock" "(" DILexicalBlockFields ")"
;

DILexicalBlockFields
	: empty
	| DILexicalBlockFieldList
;

DILexicalBlockFieldList
	: DILexicalBlockField
	| DILexicalBlockFieldList "," DILexicalBlockField
;

DILexicalBlockField
	: ScopeField
	| FileField
	| LineField
	| ColumnField
;

// ~~~ [ DILexicalBlockFile ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// https://llvm.org/docs/LangRef.html#dilexicalblockfile

// ref: ParseDILexicalBlockFile
//
//   ::= !DILexicalBlockFile(scope: !0, file: !2, discriminator: 9)
//
//  REQUIRED(scope, MDField, (AllowNull false));
//  OPTIONAL(file, MDField, );
//  REQUIRED(discriminator, MDUnsignedField, (0, UINT32_MAX));

DILexicalBlockFile
	: "!DILexicalBlockFile" "(" DILexicalBlockFileFields ")"
;

DILexicalBlockFileFields
	: empty
	| DILexicalBlockFileFieldList
;

DILexicalBlockFileFieldList
	: DILexicalBlockFileField
	| DILexicalBlockFileFieldList "," DILexicalBlockFileField
;

DILexicalBlockFileField
	: ScopeField
	| FileField
	| "discriminator:" IntLit
;

// ~~~ [ DILocation ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// https://llvm.org/docs/LangRef.html#dilocation

// ref: ParseDILocation
//
//   ::= !DILocation(line: 43, column: 8, scope: !5, inlinedAt: !6)
//
//  OPTIONAL(line, LineField, );
//  OPTIONAL(column, ColumnField, );
//  REQUIRED(scope, MDField, (AllowNull false));
//  OPTIONAL(inlinedAt, MDField, );

DILocation
	: "!DILocation" "(" DILocationFields ")"
;

DILocationFields
	: empty
	| DILocationFieldList
;

DILocationFieldList
	: DILocationField
	| DILocationFieldList "," DILocationField
;

DILocationField
	: LineField
	| ColumnField
	| ScopeField
	| "inlinedAt:" MDField
;

// ~~~ [ DILocalVariable ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// https://llvm.org/docs/LangRef.html#dilocalvariable

// ref: ParseDILocalVariable
//
//   ::= !DILocalVariable(arg: 7, scope: !0, name: "foo",
//                        file: !1, line: 7, type: !2, arg: 2, flags: 7,
//                        align: 8)
//   ::= !DILocalVariable(scope: !0, name: "foo",
//                        file: !1, line: 7, type: !2, arg: 2, flags: 7,
//                        align: 8)
//
//  OPTIONAL(name, MDStringField, );
//  OPTIONAL(arg, MDUnsignedField, (0, UINT16_MAX));
//  REQUIRED(scope, MDField, (AllowNull false));
//  OPTIONAL(file, MDField, );
//  OPTIONAL(line, LineField, );
//  OPTIONAL(type, MDField, );
//  OPTIONAL(flags, DIFlagField, );
//  OPTIONAL(align, MDUnsignedField, (0, UINT32_MAX));

DILocalVariable
	: "!DILocalVariable" "(" DILocalVariableFields ")"
;

DILocalVariableFields
	: empty
	| DILocalVariableFieldList
;

DILocalVariableFieldList
	: DILocalVariableField
	| DILocalVariableFieldList "," DILocalVariableField
;

DILocalVariableField
	: NameField
	| "arg:" IntLit
	| ScopeField
	| FileField
	| LineField
	| TypeField
	| FlagsField
	| AlignField
;

// ~~~ [ DIExpression ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// https://llvm.org/docs/LangRef.html#diexpression

// ref: ParseDIExpression
//
//   ::= !DIExpression(0, 7, -1)

DIExpression
	: "!DIExpression" "(" DIExpressionFields ")"
;

DIExpressionFields
	: empty
	| DIExpressionFieldList
;

DIExpressionFieldList
	: DIExpressionField
	| DIExpressionFieldList "," DIExpressionField
;

DIExpressionField
	: IntConst
	| DwarfOp
;

// ~~~ [ DIGlobalVariableExpression ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// ref: ParseDIGlobalVariableExpression
//
//   ::= !DIGlobalVariableExpression(var: !0, expr: !1)
//
//  REQUIRED(var, MDField, );
//  REQUIRED(expr, MDField, );

DIGlobalVariableExpression
	: "!DIGlobalVariableExpression" "(" DIGlobalVariableExpressionFields ")"
;

DIGlobalVariableExpressionFields
	: empty
	| DIGlobalVariableExpressionFieldList
;

DIGlobalVariableExpressionFieldList
	: DIGlobalVariableExpressionField
	| DIGlobalVariableExpressionFieldList "," DIGlobalVariableExpressionField
;

DIGlobalVariableExpressionField
	: "var:" MDField
	| "expr:" MDField
;

// ~~~ [ DIObjCProperty ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// https://llvm.org/docs/LangRef.html#diobjcproperty

// ref: ParseDIObjCProperty
//
//   ::= !DIObjCProperty(name: "foo", file: !1, line: 7, setter: "setFoo",
//                       getter: "getFoo", attributes: 7, type: !2)
//
//  OPTIONAL(name, MDStringField, );
//  OPTIONAL(file, MDField, );
//  OPTIONAL(line, LineField, );
//  OPTIONAL(setter, MDStringField, );
//  OPTIONAL(getter, MDStringField, );
//  OPTIONAL(attributes, MDUnsignedField, (0, UINT32_MAX));
//  OPTIONAL(type, MDField, );

DIObjCProperty
	: "!DIObjCProperty" "(" DIObjCPropertyFields ")"
;

DIObjCPropertyFields
	: empty
	| DIObjCPropertyFieldList
;

DIObjCPropertyFieldList
	: DIObjCPropertyField
	| DIObjCPropertyFieldList "," DIObjCPropertyField
;

DIObjCPropertyField
	: NameField
	| FileField
	| LineField
	| "setter:" StringLit
	| "getter:" StringLit
	| "attributes:" IntLit
	| TypeField
;

// ~~~ [ DIImportedEntity ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// https://llvm.org/docs/LangRef.html#diimportedentity

// ref: ParseDIImportedEntity
//
//   ::= !DIImportedEntity(tag: DW_TAG_imported_module, scope: !0, entity: !1,
//                         line: 7, name: "foo")
//
//  REQUIRED(tag, DwarfTagField, );
//  REQUIRED(scope, MDField, );
//  OPTIONAL(entity, MDField, );
//  OPTIONAL(file, MDField, );
//  OPTIONAL(line, LineField, );
//  OPTIONAL(name, MDStringField, );

DIImportedEntity
	: "!DIImportedEntity" "(" DIImportedEntityFields ")"
;

DIImportedEntityFields
	: empty
	| DIImportedEntityFieldList
;

DIImportedEntityFieldList
	: DIImportedEntityField
	| DIImportedEntityFieldList "," DIImportedEntityField
;

DIImportedEntityField
	: TagField
	| ScopeField
	| "entity:" MDField
	| FileField
	| LineField
	| NameField
;

// ~~~ [ DIMacro ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// https://llvm.org/docs/LangRef.html#dimacro

// ref: ParseDIMacro
//
//   ::= !DIMacro(macinfo: type, line: 9, name: "SomeMacro", value: "SomeValue")
//
//  REQUIRED(type, DwarfMacinfoTypeField, );
//  OPTIONAL(line, LineField, );
//  REQUIRED(name, MDStringField, );
//  OPTIONAL(value, MDStringField, );

DIMacro
	: "!DIMacro" "(" DIMacroFields ")"
;

DIMacroFields
	: empty
	| DIMacroFieldList
;

DIMacroFieldList
	: DIMacroField
	| DIMacroFieldList "," DIMacroField
;

DIMacroField
	: TypeMacinfoField
	| LineField
	| NameField
	| "value:" StringLit
;

// ~~~ [ DIMacroFile ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// https://llvm.org/docs/LangRef.html#dimacrofile

// ref: ParseDIMacroFile
//
//   ::= !DIMacroFile(line: 9, file: !2, nodes: !3)
//
//  OPTIONAL(type, DwarfMacinfoTypeField, (dwarf::DW_MACINFO_start_file));
//  OPTIONAL(line, LineField, );
//  REQUIRED(file, MDField, );
//  OPTIONAL(nodes, MDField, );

DIMacroFile
	: "!DIMacroFile" "(" DIMacroFileFields ")"
;

DIMacroFileFields
	: empty
	| DIMacroFileFieldList
;

DIMacroFileFieldList
	: DIMacroFileField
	| DIMacroFileFieldList "," DIMacroFileField
;

DIMacroFileField
	: TypeMacinfoField
	| LineField
	| FileField
	| "nodes:" MDField
;

// ~~~ [ GenericDINode ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// ref: ParseGenericDINode
//
//   ::= !GenericDINode(tag: 15, header: "...", operands: {...})
//
//  REQUIRED(tag, DwarfTagField, );
//  OPTIONAL(header, MDStringField, );
//  OPTIONAL(operands, MDFieldList, );

GenericDINode
	: "!GenericDINode" "(" GenericDINodeFields ")"
;

GenericDINodeFields
	: empty
	| GenericDINodeFieldList
;

GenericDINodeFieldList
	: GenericDINodeField
	| GenericDINodeFieldList "," GenericDINodeField
;

GenericDINodeField
	: TagField
	| "header:" StringLit
	| "operands:" MDFields
;

// ### [ Helper productions ] ##################################################

// ref: ParseMDField(DwarfLangField &)

DwarfLang
	: IntLit
	// DW_LANG_foo
	| dwarf_lang
;

FileField
	: "file:" MDField
;

IsOptimizedField
	: "isOptimized:" BoolLit
;

EmissionKind
	: IntLit
	| "FullDebug"
	| "LineTablesOnly"
	| "NoDebug"
;

ChecksumKind
	// CSK_foo
	: checksum_kind
;

TagField
	: "tag:" DwarfTag
;

// ref: ParseMDField(DwarfTagField &)

DwarfTag
	: IntLit
	// DW_TAG_foo
	| dwarf_tag
;

NameField
	: "name:" StringLit
;

SizeField
	: "size:" IntLit
;

AlignField
	: "align:" IntLit
;

// ref: ParseMDField(DwarfAttEncodingField &)

DwarfAttEncoding
	: IntLit
	// DW_ATE_foo
	| dwarf_att_encoding
;

FlagsField
	: "flags:" DIFlagList
;

// ref: ParseMDField(DIFlagField &)
//
//  ::= uint32
//  ::= DIFlagVector
//  ::= DIFlagVector '|' DIFlagFwdDecl '|' uint32 '|' DIFlagPublic

DIFlagList
	: DIFlag
	| DIFlagList "|" DIFlag
;

DIFlag
	: IntLit
	// DIFlagFoo
	| di_flag
;

// ref: ParseMDField(DwarfCCField &Result)

DwarfCC
	: IntLit
	// DW_CC_foo
	| dwarf_cc
;

LineField
	: "line:" IntLit
;

ScopeField
	: "scope:" MDField
;

BaseTypeField
	: "baseType:" MDField
;

OffsetField
	: "offset:" IntLit
;

TemplateParamsField
	: "templateParams:" MDField
;

// ref: ParseMDField(MDSignedOrMDField &)

IntOrMDField
	: IntConst
	| MDField
;

TypeField
	: "type:" MDField
;

LinkageNameField
	: "linkageName:" StringLit
;

IsLocalField
	: "isLocal:" BoolLit
;

IsDefinitionField
	: "isDefinition:" BoolLit
;

DeclarationField
	: "declaration:" MDField
;

// ref: ParseMDField(DwarfVirtualityField &)

DwarfVirtuality
	: IntLit
	// DW_VIRTUALITY_foo
	| dwarf_virtuality
;

ColumnField
	: "column:" IntLit
;

DwarfOp
	// DW_OP_foo
	: dwarf_op
;

TypeMacinfoField
	: "type:" DwarfMacinfo
;

// ref: ParseMDField(DwarfMacinfoTypeField &)

DwarfMacinfo
	: IntLit
	// DW_MACINFO_foo
	| dwarf_macinfo
;

// ### [ Helper productions ] ##################################################

// ___ [ Function Attribute ] __________________________________________________

// ref: ParseFnAttributeValuePairs
//
//   ::= <attr> | <attr> '=' <value>

FuncAttrs
	: empty
	| FuncAttrList
;

FuncAttrList
	: FuncAttr
	| FuncAttrList FuncAttr
;

FuncAttr
	// not used in attribute groups.
	: AttrGroupID
	// used in attribute groups.
	| "align" "=" int_lit
	| "alignstack" "=" int_lit
	// used in functions.
	| Alignment
	| AllocSize
	| StackAlignment
	| StringLit
	| StringLit "=" StringLit
	| "alwaysinline"
	| "argmemonly"
	| "builtin"
	| "cold"
	| "convergent"
	| "inaccessiblemem_or_argmemonly"
	| "inaccessiblememonly"
	| "inlinehint"
	| "jumptable"
	| "minsize"
	| "naked"
	| "nobuiltin"
	| "noduplicate"
	| "noimplicitfloat"
	| "noinline"
	| "nonlazybind"
	| "norecurse"
	| "noredzone"
	| "noreturn"
	| "nounwind"
	| "optnone"
	| "optsize"
	| "readnone"
	| "readonly"
	| "returns_twice"
	| "safestack"
	| "sanitize_address"
	| "sanitize_hwaddress"
	| "sanitize_memory"
	| "sanitize_thread"
	| "speculatable"
	| "ssp"
	| "sspreq"
	| "sspstrong"
	| "strictfp"
	| "uwtable"
	| "writeonly"
;

// ___ [ Return Attribute ] __________________________________________________

// ref: ParseOptionalReturnAttrs

ReturnAttrs
	: empty
	| ReturnAttrList
;

ReturnAttrList
	: ReturnAttr
	| ReturnAttrList ReturnAttr
;

ReturnAttr
	: Alignment
	| Dereferenceable
	| StringLit
	| "inreg"
	| "noalias"
	| "nonnull"
	| "signext"
	| "zeroext"
;

// ___ [ Parameter Attribute ] _________________________________________________

// ref: ParseOptionalParamAttrs

ParamAttrs
	: empty
	| ParamAttrList
;

ParamAttrList
	: ParamAttr
	| ParamAttrList ParamAttr
;

// ref: ParseOptionalDerefAttrBytes
//
//   ::= empty
//   ::= AttrKind '(' 4 ')'

ParamAttr
	: Alignment
	| Dereferenceable
	| StringLit
	| "byval"
	| "inalloca"
	| "inreg"
	| "nest"
	| "noalias"
	| "nocapture"
	| "nonnull"
	| "readnone"
	| "readonly"
	| "returned"
	| "signext"
	| "sret"
	| "swifterror"
	| "swiftself"
	| "writeonly"
	| "zeroext"
;

// ___ [ Attributes ] __________________________________________________________

// ref: ParseOptionalAddrSpace
//
//   := empty
//   := 'addrspace' '(' uint32 ')'

OptAddrSpace
	: empty
	| AddrSpace
;

AddrSpace
	: "addrspace" "(" int_lit ")"
;

// ref: ParseOptionalAlignment
//
//   ::= empty
//   ::= 'align' 4

Alignment
	: "align" int_lit
;

// ref: parseAllocSizeArguments

AllocSize
	: "allocsize" "(" int_lit ")"
	| "allocsize" "(" int_lit "," int_lit ")"
;

// ref: parseOptionalComdat

OptComdat
	: empty
	| Comdat
;

Comdat
	: "comdat"
	| "comdat" "(" ComdatName ")"
;

Dereferenceable
	: "dereferenceable" "(" int_lit ")"
	| "dereferenceable_or_null" "(" int_lit ")"
;

// https://llvm.org/docs/LangRef.html#dll-storage-classes

// ref: ParseOptionalDLLStorageClass
//
//   ::= empty
//   ::= 'dllimport'
//   ::= 'dllexport'

OptDLLStorageClass
	: empty
	| DLLStorageClass
;

DLLStorageClass
	: "dllexport"
	| "dllimport"
;

// https://llvm.org/docs/LangRef.html#linkage-types

// ref: ParseOptionalLinkage
//
//   ::= empty
//   ::= 'private'
//   ::= 'internal'
//   ::= 'weak'
//   ::= 'weak_odr'
//   ::= 'linkonce'
//   ::= 'linkonce_odr'
//   ::= 'available_externally'
//   ::= 'appending'
//   ::= 'common'
//   ::= 'extern_weak'
//   ::= 'external'

OptLinkage
	: empty
	| Linkage
;

Linkage
	: "appending"
	| "available_externally"
	| "common"
	| "internal"
	| "linkonce"
	| "linkonce_odr"
	| "private"
	| "weak"
	| "weak_odr"
;

OptExternLinkage
	: empty
	| ExternLinkage
;

ExternLinkage
	: "extern_weak"
	| "external"
;

// https://llvm.org/docs/LangRef.html#runtime-preemption-model

// ref: ParseOptionalDSOLocal

OptPreemptionSpecifier
	: empty
	| PreemptionSpecifier
;

PreemptionSpecifier
	: "dso_local"
	| "dso_preemptable"
;

OptSection
	: empty
	| Section
;

Section
	: "section" StringLit
;

// ref: ParseOptionalStackAlignment
//
//   ::= empty
//   ::= 'alignstack' '(' 4 ')'
StackAlignment
	: "alignstack" "(" int_lit ")"
;

// ref: ParseOptionalUnnamedAddr

OptUnnamedAddr
	: empty
	| UnnamedAddr
;

UnnamedAddr
	: "local_unnamed_addr"
	| "unnamed_addr"
;

// https://llvm.org/docs/LangRef.html#visibility-styles

// ref: ParseOptionalVisibility
//
//   ::= empty
//   ::= 'default'
//   ::= 'hidden'
//   ::= 'protected'

OptVisibility
	: empty
	| Visibility
;

Visibility
	: "default"
	| "hidden"
	| "protected"
;

// ___ [ Instruction Operands ] ________________________________________________

// ref: ParseCmpPredicate

IPred
	: "eq"
	| "ne"
	| "sge"
	| "sgt"
	| "sle"
	| "slt"
	| "uge"
	| "ugt"
	| "ule"
	| "ult"
;

// ref: ParseCmpPredicate

FPred
	: "false"
	| "oeq"
	| "oge"
	| "ogt"
	| "ole"
	| "olt"
	| "one"
	| "ord"
	| "true"
	| "ueq"
	| "uge"
	| "ugt"
	| "ule"
	| "ult"
	| "une"
	| "uno"
;

OverflowFlags
	: empty
	| OverflowFlagList
;

OverflowFlagList
	: OverflowFlag
	| OverflowFlagList OverflowFlag
;

OverflowFlag
	: "nsw"
	| "nuw"
;

OptExact
	: empty
	| "exact"
;

// ref: EatFastMathFlagsIfPresent

FastMathFlags
	: empty
	| FastMathFlagList
;

FastMathFlagList
	: FastMathFlag
	| FastMathFlagList FastMathFlag
;

FastMathFlag
	: "afn"
	| "arcp"
	| "contract"
	| "fast"
	| "ninf"
	| "nnan"
	| "nsz"
	| "reassoc"
;

OptInBounds
	: empty
	| "inbounds"
;

// ref: ParseOptionalOperandBundles
//
//    ::= empty
//    ::= '[' OperandBundle [, OperandBundle ]* ']'
//
//  OperandBundle
//    ::= bundle-tag '(' ')'
//    ::= bundle-tag '(' Type Value [, Type Value ]* ')'
//
//  bundle-tag ::= String Constant

OperandBundles
	: empty
	| "[" OperandBundleList "]"
;

OperandBundleList
	: OperandBundle
	| OperandBundleList OperandBundle
;

OperandBundle
	: StringLit "(" TypeValues ")"
;

OptVolatile
	: empty
	| "volatile"
;

// ref: ParseScope
//
//   ::= syncscope("singlethread" | "<target scope>")?

OptSyncScope
	: empty
	| "syncscope" "(" StringLit ")"
;

// ref: ParseOrdering
//
//   ::= AtomicOrdering

AtomicOrdering
	: "acq_rel"
	| "acquire"
	| "monotonic"
	| "release"
	| "seq_cst"
	| "unordered"
;

ExceptionScope
	: NoneConst
	| LocalIdent
;

// ref: ParseIndexList
//
//    ::=  (',' uint32)+

Indices
	: empty
	| "," IndexList
;

IndexList
	: Index
	| IndexList "," Index
;

Index
	: int_lit
;

TypeValues
	: empty
	| TypeValueList
;

TypeValueList
	: TypeValue
	| TypeValueList TypeValue
;

CommaSepTypeValueList
	: TypeValue
	| CommaSepTypeValueList "," TypeValue
;

TypeValue
	: Type Value
;

TypeConsts
	: empty
	| TypeConstList
;

TypeConstList
	: TypeConst
	| TypeConstList "," TypeConst
;

TypeConst
	: Type Constant
;

// ref: ParseParameterList
//
//    ::= '(' ')'
//    ::= '(' Arg (',' Arg)* ')'
//  Arg
//    ::= Type OptionalAttributes Value OptionalAttributes

Args
	: empty
	| "..."
	| ArgList
	| ArgList "," "..."
;

ArgList
	: Arg
	| ArgList "," Arg
;

// ref: ParseMetadataAsValue
//
//  ::= metadata i32 %local
//  ::= metadata i32 @global
//  ::= metadata i32 7
//  ::= metadata !0
//  ::= metadata !{...}
//  ::= metadata !"string"

Arg
	: ConcreteType ParamAttrs Value
	| MetadataType Metadata
;

// ref: ParseExceptionArgs

ExceptionArgs
	: empty
	| ExceptionArgList
;

ExceptionArgList
	: ExceptionArg
	| ExceptionArgList "," ExceptionArg
;

ExceptionArg
	: ConcreteType Value
	| MetadataType Metadata
;

// ref: ParseArgumentList
//
//   ::= '(' ArgTypeListI ')'
//  ArgTypeListI
//   ::= empty
//   ::= '...'
//   ::= ArgTypeList ',' '...'
//   ::= ArgType (',' ArgType)*

Params
	: empty
	| "..."
	| ParamList
	| ParamList "," "..."
;

ParamList
	: Param
	| ParamList "," Param
;

Param
	: Type ParamAttrs
	| Type ParamAttrs LocalIdent
;

@mewmew
Copy link
Member Author

mewmew commented Mar 7, 2018

Note that this grammar covers the entire LLVM IR language and is based on the source code of the official LLVM project, as of 2018-02-19 (rev llvm-mirror/llvm@db070bb).

  • lib/AsmParser/LLParser.cpp

As such, there is now a complete grammar which covers the LLVM IR language. Thus closing this issue.

@mewmew mewmew closed this as completed Mar 7, 2018
@sbinet
Copy link

sbinet commented Mar 7, 2018

Wow! That's quite an extensive wall of code!
Congrats for the huge amount of work!

@mewmew
Copy link
Member Author

mewmew commented Mar 7, 2018

@sbinet Thanks a lot! It's been a shared effort between @7i, @sangisos and I. Looking forward to playing with the LLVM IR library, now that we're reaching a point of maturity.

mewmew added a commit that referenced this issue Nov 2, 2018
Resolve local variables
@mewmew
Copy link
Member Author

mewmew commented Nov 25, 2018

For anyone who happen to stumble upon this issue. The latest version of the grammar is located in the llir/grammar repository, more specifically see ll.tm for an EBNF grammar for LLVM IR assembly.

mewmew added a commit that referenced this issue Nov 30, 2018
Resolve local variables

Former-commit-id: 904019e
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants