[llvm-dev] A BNF grammar for LLVM IR assembly

Robin Eklind via llvm-dev llvm-dev at lists.llvm.org
Sat Jun 2 03:59:18 PDT 2018


Hi,

My friends and I have written a BNF grammar for LLVM IR assembly by
cross-referencing the LLVM Language Reference Manual [1], LLVM blog
posts [2], and the source code and associated comments of the LLVM IR
assembly parser [3]. We did this as we wanted to be able to write tools
for both generating arbitrary syntactically correct LLVM IR (e.g. csmith
[4]) to validate the tool chain, to generate LLVM IR parsers based on
the BNF, and to create a source of truth for the grammar of the LLVM IR
assembly language.

The current version of the BNF covers the entire LLVM IR assembly
language as of 2018-02-19, and is based on the source code of
lib/AsmParser/LLParser.cpp at revision rL324928 [5].

Without further ado, find the BNF grammar attached to this message. It
is also made available through Gist at [6] and a BNF grammar with
annotated production actions for an LLVM IR parser in Go is at [7].

Cheers,
/u & i

[1]: https://llvm.org/docs/LangRef.html
[2]: http://blog.llvm.org/
[3]: https://reviews.llvm.org/diffusion/L/browse/llvm/trunk/lib/AsmParser/
[4]: https://embed.cs.utah.edu/csmith/
[5]:
https://reviews.llvm.org/diffusion/L/browse/llvm/trunk/lib/AsmParser/LLParser.cpp;324928
[6]: Plain BNF:
https://gist.github.com/mewmew/a2487392d5519ef49658fd8f84d9eed5#file-ll-bnf
[7]: BNF annotated with production actions for Go:
https://raw.githubusercontent.com/llir/grammar/master/ll.bnf

-------------- next part --------------
// ### [ 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" "datalayout" "=" StringLit
	| "target" "triple" "=" 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
;

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
;

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 Definition ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// 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
;

// ~~~ [ Metadata Definition ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// 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 "*"
;

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

OptAddrSpace
	: empty
	| AddrSpace
;

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

// --- [ 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
;

// --- [ 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
;

// ___ [ Helpers ] _____________________________________________________________

UnwindTarget
	: "to" "caller"
	| LabelType LocalIdent
;
// === [ 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.
	: "null"
	| 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
	: int_lit
	| 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 ] ##################################################

FileField
	: "file:" MDField
;

IsOptimizedField
	: "isOptimized:" BoolLit
;

TagField
	: "tag:" DwarfTag
;

NameField
	: "name:" StringLit
;

SizeField
	: "size:" IntLit
;

AlignField
	: "align:" IntLit
;

FlagsField
	: "flags:" DIFlagList
;

LineField
	: "line:" IntLit
;

ScopeField
	: "scope:" MDField
;

BaseTypeField
	: "baseType:" MDField
;

OffsetField
	: "offset:" IntLit
;

TemplateParamsField
	: "templateParams:" MDField
;

// ref: ParseMDField(MDSignedOrMDField &)

IntOrMDField
	: int_lit
	| MDField
;

TypeField
	: "type:" MDField
;

LinkageNameField
	: "linkageName:" StringLit
;

IsLocalField
	: "isLocal:" BoolLit
;

IsDefinitionField
	: "isDefinition:" BoolLit
;

DeclarationField
	: "declaration:" MDField
;

ColumnField
	: "column:" IntLit
;

TypeMacinfoField
	: "type:" DwarfMacinfo
;

ChecksumKind
	// CSK_foo
	: checksum_kind
;

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

DIFlagList
	: DIFlag
	| DIFlagList "|" DIFlag
;

DIFlag
	: IntLit
	// DIFlagFoo
	| di_flag
;

// ref: ParseMDField(DwarfAttEncodingField &)

DwarfAttEncoding
	: IntLit
	// DW_ATE_foo
	| dwarf_att_encoding
;

// ref: ParseMDField(DwarfCCField &Result)

DwarfCC
	: IntLit
	// DW_CC_foo
	| dwarf_cc
;

// ref: ParseMDField(DwarfLangField &)

DwarfLang
	: IntLit
	// DW_LANG_foo
	| dwarf_lang
;

// ref: ParseMDField(DwarfMacinfoTypeField &)

DwarfMacinfo
	: IntLit
	// DW_MACINFO_foo
	| dwarf_macinfo
;

DwarfOp
	// DW_OP_foo
	: dwarf_op
;

// ref: ParseMDField(DwarfTagField &)

DwarfTag
	: IntLit
	// DW_TAG_foo
	| dwarf_tag
;

// ref: ParseMDField(DwarfVirtualityField &)

DwarfVirtuality
	: IntLit
	// DW_VIRTUALITY_foo
	| dwarf_virtuality
;

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

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

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: ParseOptionalAlignment
//
//   ::= empty
//   ::= 'align' 4

Alignment
	: "align" int_lit
;

// ref: parseAllocSizeArguments

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

// 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: ParseOrdering
//
//   ::= AtomicOrdering

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

// 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
;

// 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"
;

OptExact
	: empty
	| "exact"
;

// ref: ParseExceptionArgs

ExceptionArgs
	: empty
	| ExceptionArgList
;

ExceptionArgList
	: ExceptionArg
	| ExceptionArgList "," ExceptionArg
;

ExceptionArg
	: ConcreteType Value
	| MetadataType Metadata
;

ExceptionScope
	: NoneConst
	| LocalIdent
;

// ref: EatFastMathFlagsIfPresent

FastMathFlags
	: empty
	| FastMathFlagList
;

FastMathFlagList
	: FastMathFlag
	| FastMathFlagList FastMathFlag
;

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

// ref: ParseCmpPredicate

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

// ___ [ 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"
;

OptInBounds
	: empty
	| "inbounds"
;

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

Indices
	: empty
	| "," IndexList
;

IndexList
	: Index
	| IndexList "," Index
;

Index
	: int_lit
;

// ref: ParseCmpPredicate

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

// 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"
;

// 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 ")"
;

OverflowFlags
	: empty
	| OverflowFlagList
;

OverflowFlagList
	: OverflowFlag
	| OverflowFlagList OverflowFlag
;

OverflowFlag
	: "nsw"
	| "nuw"
;

// ___ [ 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"
;

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

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

ParamList
	: Param
	| ParamList "," Param
;

Param
	: Type ParamAttrs
	| Type ParamAttrs LocalIdent
;

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

// ref: ParseOptionalDSOLocal

OptPreemptionSpecifier
	: empty
	| PreemptionSpecifier
;

PreemptionSpecifier
	: "dso_local"
	| "dso_preemptable"
;

// ___ [ Return Attribute ] __________________________________________________

// ref: ParseOptionalReturnAttrs

ReturnAttrs
	: empty
	| ReturnAttrList
;

ReturnAttrList
	: ReturnAttr
	| ReturnAttrList ReturnAttr
;

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

OptSection
	: empty
	| Section
;

Section
	: "section" StringLit
;

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

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

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

// 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"
;

// 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"
;

OptVolatile
	: empty
	| "volatile"
;



More information about the llvm-dev mailing list