[llvm-branch-commits] [mlir] ccdd8c7 - [mlir] Move LLVM Dialect Op documentation to ODS

Alex Zinenko via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Thu Dec 17 03:37:23 PST 2020


Author: Alex Zinenko
Date: 2020-12-17T12:32:35+01:00
New Revision: ccdd8c7759459ef4b9b09820d241081d387be779

URL: https://github.com/llvm/llvm-project/commit/ccdd8c7759459ef4b9b09820d241081d387be779
DIFF: https://github.com/llvm/llvm-project/commit/ccdd8c7759459ef4b9b09820d241081d387be779.diff

LOG: [mlir] Move LLVM Dialect Op documentation to ODS

This was long overdue. The initial documentation for the LLVM dialect was
introduced before ODS had support for long descriptions. This is now possible,
so the documentation is moved to ODS, which can serve as a single source of
truth. The high-level description of the dialect structure is updated to
reflect that.

Depends On: D93315

Reviewed By: rriddle, mehdi_amini

Differential Revision: https://reviews.llvm.org/D93425

Added: 
    

Modified: 
    mlir/docs/Dialects/LLVM.md
    mlir/include/mlir/Dialect/LLVMIR/CMakeLists.txt
    mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td

Removed: 
    


################################################################################
diff  --git a/mlir/docs/Dialects/LLVM.md b/mlir/docs/Dialects/LLVM.md
index c4607dbd735b..fbe1a1cfe7ea 100644
--- a/mlir/docs/Dialects/LLVM.md
+++ b/mlir/docs/Dialects/LLVM.md
@@ -47,6 +47,143 @@ module attributes {llvm.data_layout = "e",
 }
 ```
 
+### Functions
+
+LLVM functions are represented by a special operation, `llvm.func`, that has
+syntax similar to that of the built-in function operation but supports
+LLVM-related features such as linkage and variadic argument lists. See detailed
+description in the operation list [below](#llvmfunc-mlirllvmllvmfuncop).
+
+### PHI Nodes and Block Arguments
+
+MLIR uses block arguments instead of PHI nodes to communicate values between
+blocks. Therefore, the LLVM dialect has no operation directly equivalent to
+`phi` in LLVM IR. Instead, all terminators can pass values as successor operands
+as these values will be forwarded as block arguments when the control flow is
+transferred.
+
+For example:
+
+```mlir
+^bb1:
+  %0 = llvm.addi %arg0, %cst : !llvm.i32
+  llvm.br ^bb2[%0: !llvm.i32]
+
+// If the control flow comes from ^bb1, %arg1 == %0.
+^bb2(%arg1: !llvm.i32)
+  // ...
+```
+
+is equivalent to LLVM IR
+
+```llvm
+%0:
+  %1 = add i32 %arg0, %cst
+  br %3
+
+%3:
+  %arg1 = phi [%1, %0], //...
+```
+
+Since there is no need to use the block identifier to 
diff erentiate the source
+of 
diff erent values, the LLVM dialect supports terminators that transfer the
+control flow to the same block with 
diff erent arguments. For example:
+
+```mlir
+^bb1:
+  llvm.cond_br %cond, ^bb2[%0: !llvm.i32], ^bb2[%1: !llvm.i32]
+
+^bb2(%arg0: !llvm.i32):
+  // ...
+```
+
+### Context-Level Values
+
+Some value kinds in LLVM IR, such as constants and undefs, are uniqued in
+context and used directly in relevant operations. MLIR does not support such
+values for thread-safety and concept parsimony reasons. Instead, regular values
+are produced by dedicated operations that have the corresponding semantics:
+[`llvm.mlir.constant`](#llvmmlirconstant-mlirllvmconstantop),
+[`llvm.mlir.undef`](#llvmmlirundef-mlirllvmundefop),
+[`llvm.mlir.null`](#llvmmlirnull-mlirnullop). Note how these operations are
+prefixed with `mlir.` to indicate that they don't belong to LLVM IR but are only
+necessary to model it in MLIR. The values produced by these operations are
+usable just like any other value.
+
+Examples:
+
+```mlir
+// Create an undefined value of structure type with a 32-bit integer followed
+// by a float.
+%0 = llvm.mlir.undef : !llvm.struct<(i32, float)>
+
+// Null pointer to i8.
+%1 = llvm.mlir.null : !llvm.ptr<i8>
+
+// Null pointer to a function with signature void().
+%2 = llvm.mlir.null : !llvm.ptr<func<void ()>>
+
+// Constant 42 as i32.
+%3 = llvm.mlir.constant(42 : i32) : !llvm.i32
+
+// Splat dense vector constant.
+%3 = llvm.mlir.constant(dense<1.0> : vector<4xf32>) : !llvm.vec<4 x float>
+```
+
+Note that constants use built-in types within the initializer definition: MLIR
+attributes are typed and the attributes used for constants require a built-in
+type.
+
+### Globals
+
+Global variables are also defined using a special operation,
+[`llvm.mlir.global`](#llvmmlirglobal-mlirllvmglobalop), located at the module
+level. Globals are MLIR symbols and are identified by their name.
+
+Since functions need to be isolated-from-above, i.e. values defined outside the
+function cannot be directly used inside the function, an additional operation,
+[`llvm.mlir.addressof`](#llvmmliraddressof-mlirllvmaddressofop), is provided to
+locally define a value containing the _address_ of a global. The actual value
+can then be loaded from that pointer, or a new value can be stored into it if
+the global is not declared constant. This is similar to LLVM IR where globals
+are accessed through name and have a pointer type.
+
+### Linkage
+
+Module-level named objects in the LLVM dialect, namely functions and globals,
+have an optional _linkage_ attribute derived from LLVM IR
+[linkage types](https://llvm.org/docs/LangRef.html#linkage-types). Linkage is
+specified by the same keyword as in LLVM IR and is located between the operation
+name (`llvm.func` or `llvm.global`) and the symbol name. If no linkage keyword
+is present, `external` linkage is assumed by default. Linakge is _distinct_ from
+MLIR symbol visibility.
+
+### Attribute Pass-Through
+
+The LLVM dialect provides a mechanism to forward function-level attributes to
+LLVM IR using the `passthrough` attribute. This is an array attribute containing
+either string attributes or array attributes. In the former case, the value of
+the string is interpreted as the name of LLVM IR function attribute. In the
+latter case, the array is expected to contain exactly two string attributes, the
+first corresponding to the name of LLVM IR function attribute, and the second
+corresponding to its value. Note that even integer LLVM IR function attributes
+have their value represented in the string form.
+
+Example:
+
+```mlir
+llvm.func @func() attributes {
+  passthrough = ["noinline",           // value-less attribute
+                 ["alignstack", "4"],  // integer attribute with value
+                 ["other", "attr"]]    // attribute unknown to LLVM
+} {
+  llvm.return
+}
+```
+
+If the attribute is not known to LLVM IR, it will be attached as a string
+attribute.
+
 ## Types
 
 LLVM dialect defines a set of types that correspond to LLVM IR types. The
@@ -297,453 +434,4 @@ MLIR, blocks are not values and don't need a type.
 All operations in the LLVM IR dialect have a custom form in MLIR. The mnemonic
 of an operation is that used in LLVM IR prefixed with "`llvm.`".
 
-### LLVM functions
-
-MLIR functions are defined by an operation that is not built into the IR itself.
-The LLVM IR dialect provides an `llvm.func` operation to define functions
-compatible with LLVM IR. These functions have wrapped LLVM IR function type but
-use MLIR syntax to express it. They are required to have exactly one result
-type. LLVM function operation is intended to capture additional properties of
-LLVM functions, such as linkage and calling convention, that may be modeled
-
diff erently by the built-in MLIR function.
-
-```mlir
-// The type of @bar is !llvm<"i64 (i64)">
-llvm.func @bar(%arg0: !llvm.i64) -> !llvm.i64 {
-  llvm.return %arg0 : !llvm.i64
-}
-
-// Type type of @foo is !llvm<"void (i64)">
-// !llvm.void type is omitted
-llvm.func @foo(%arg0: !llvm.i64) {
-  llvm.return
-}
-
-// A function with `internal` linkage.
-llvm.func internal @internal_func() {
-  llvm.return
-}
-
-```
-
-#### Attribute pass-through
-
-An LLVM IR dialect function provides a mechanism to forward function-level
-attributes to LLVM IR using the `passthrough` attribute. This is an array
-attribute containing either string attributes or array attributes. In the former
-case, the value of the string is interpreted as the name of LLVM IR function
-attribute. In the latter case, the array is expected to contain exactly two
-string attributes, the first corresponding to the name of LLVM IR function
-attribute, and the second corresponding to its value. Note that even integer
-LLVM IR function attributes have their value represented in the string form.
-
-Example:
-
-```mlir
-llvm.func @func() attributes {
-  passthrough = ["noinline",           // value-less attribute
-                 ["alignstack", "4"],  // integer attribute with value
-                 ["other", "attr"]]    // attribute unknown to LLVM
-} {
-  llvm.return
-}
-```
-
-If the attribute is not known to LLVM IR, it will be attached as a string
-attribute.
-
-#### Linkage
-
-An LLVM IR dialect function has a linkage attribute derived from LLVM IR
-[linkage types](https://llvm.org/docs/LangRef.html#linkage-types). Linkage is
-specified by the same keyword as in LLVM IR and is located between `llvm.func`
-and the symbol name. If no linkage keyword is present, `external` linkage is
-assumed by default.
-
-### LLVM IR operations
-
-The following operations are currently supported. The semantics of these
-operations corresponds to the semantics of the similarly-named LLVM IR
-instructions.
-
-#### Integer binary arithmetic operations
-
-Take two arguments of wrapped LLVM IR integer type, produce one value of the
-same type.
-
--   `add`
--   `sub`
--   `mul`
--   `udiv`
--   `sdiv`
--   `urem`
--   `srem`
-
-Examples:
-
-```mlir
-// Integer addition.
-%0 = llvm.add %a, %b : !llvm.i32
-
-// Unsigned integer division.
-%1 = llvm.udiv %a, %b : !llvm.i32
-```
-
-#### Floating point binary arithmetic operations
-
-Take two arguments of wrapped LLVM IR floating point type, produce one value of
-the same type.
-
--   `fadd`
--   `fsub`
--   `fmul`
--   `fdiv`
--   `frem`
-
-Examples:
-
-```mlir
-// Float addition.
-%0 = llvm.fadd %a, %b : !llvm.float
-
-// Float division.
-%1 = llvm.fdiv %a, %b : !llvm.float
-```
-
-#### Memory-related operations
-
--   `<r> = alloca <size> x <type>`
--   `<r> = getelementptr <address>[<index> (, <index>)+]`
--   `<r> = load <address>`
--   `store <value>, <address>`
-
-In these operations, `<size>` must be a value of wrapped LLVM IR integer type,
-`<address>` must be a value of wrapped LLVM IR pointer type, and `<value>` must
-be a value of wrapped LLVM IR type that corresponds to the pointer type of
-`<address>`.
-
-The `index` operands are integer values whose semantics is identical to the
-non-pointer arguments of LLVM IR's `getelementptr`.
-
-Examples:
-
-```mlir
-// Allocate an array of 4 floats on stack
-%c4 = llvm.mlir.constant(4) : !llvm.i64
-%0 = llvm.alloca %c4 x !llvm.float : (!llvm.i64) -> !llvm<"float*">
-
-// Get the second element of the array (note 0-based indexing).
-%c1 = llvm.mlir.constant(1) : !llvm.i64
-%1 = llvm.getelementptr %0[%c1] : (!llvm<"float*">, !llvm.i64)
-                                   -> !llvm<"float*">
-
-// Store a constant into this element.
-%cf = llvm.mlir.constant(42.0 : f32) : !llvm.float
-llvm.store %cf, %1 : !llvm<"float*">
-
-// Load the value from this element.
-%3 = llvm.load %1 : !llvm<"float*">
-```
-
-#### Operations on values of aggregate type.
-
--   `<value> = extractvalue <struct>[<index> (, <index>)+]`
--   `<struct> = insertvalue <value>, <struct>[<index> (, <index>)+]`
-
-In these operations, `<struct>` must be a value of wrapped LLVM IR structure
-type and `<value>` must be a value that corresponds to one of the (nested)
-structure element types.
-
-Note the use of integer literals to designate subscripts, which is made possible
-by `extractvalue` and `insertvalue` must have constant subscripts. Internally,
-they are modeled as array attributes.
-
-Examples:
-
-```mlir
-// Get the value third element of the second element of a structure.
-%0 = llvm.extractvalue %s[1, 2] : !llvm<"{i32, {i1, i8, i16}">
-
-// Insert the value to the third element of the second element of a structure.
-// Note that this returns a new structure-typed value.
-%1 = llvm.insertvalue %0, %s[1, 2] : !llvm<"{i32, {i1, i8, i16}">
-```
-
-#### Terminator operations.
-
-Branch operations:
-
--   `br [<successor>(<operands>)]`
--   `cond_br <condition> [<true-successor>(<true-operands>),`
-    `<false-successor>(<false-operands>)]`
-
-In order to comply with MLIR design, branch operations in the LLVM IR dialect
-pass arguments to basic blocks. Successors must be valid block MLIR identifiers
-and operand lists for each of them must have the same types as the arguments of
-the respective blocks. `<condition>` must be a wrapped LLVM IR `i1` type.
-
-Since LLVM IR uses the name of the predecessor basic block to identify the
-sources of a PHI node, it is invalid for two entries of the PHI node to indicate
-
diff erent values coming from the same block. Therefore, `cond_br` in the LLVM IR
-dialect disallows its successors to be the same block _if_ this block has
-arguments.
-
-Examples:
-
-```mlir
-// Branch without arguments.
-^bb0:
-  llvm.br ^bb0
-
-// Branch and pass arguments.
-^bb1(%arg: !llvm.i32):
-  llvm.br ^bb1(%arg : !llvm.i32)
-
-// Conditionally branch and pass arguments to one of the blocks.
-llvm.cond_br %cond, ^bb0, %bb1(%arg : !llvm.i32)
-
-// It's okay to use the same block without arguments, but probably useless.
-llvm.cond_br %cond, ^bb0, ^bb0
-
-// ERROR: Passing 
diff erent arguments to the same block in a conditional branch.
-llvm.cond_br %cond, ^bb1(%0 : !llvm.i32), ^bb1(%1 : !llvm.i32)
-
-```
-
-Call operations:
-
--   `<r> = call(<operands>)`
--   `call(<operands>)`
-
-In LLVM IR, functions may return either 0 or 1 value. LLVM IR dialect implements
-this behavior by providing a variadic `call` operation for 0- and 1-result
-functions. Even though MLIR supports multi-result functions, LLVM IR dialect
-disallows them.
-
-The `call` instruction supports both direct and indirect calls. Direct calls
-start with a function name (`@`-prefixed) and indirect calls start with an SSA
-value (`%`-prefixed). The direct callee, if present, is stored as a function
-attribute `callee`. The trailing type of the instruction is always the MLIR
-function type, which may be 
diff erent from the indirect callee that has the
-wrapped LLVM IR function type.
-
-Examples:
-
-```mlir
-// Direct call without arguments and with one result.
-%0 = llvm.call @foo() : () -> (!llvm.float)
-
-// Direct call with arguments and without a result.
-llvm.call @bar(%0) : (!llvm.float) -> ()
-
-// Indirect call with an argument and without a result.
-llvm.call %1(%0) : (!llvm.float) -> ()
-```
-
-#### Miscellaneous operations.
-
-Integer comparisons: `icmp "predicate" <lhs>, <rhs>`. The following predicate
-values are supported:
-
--   `eq` - equality comparison;
--   `ne` - inequality comparison;
--   `slt` - signed less-than comparison
--   `sle` - signed less-than-or-equal comparison
--   `sgt` - signed greater-than comparison
--   `sge` - signed greater-than-or-equal comparison
--   `ult` - unsigned less-than comparison
--   `ule` - unsigned less-than-or-equal comparison
--   `ugt` - unsigned greater-than comparison
--   `uge` - unsigned greater-than-or-equal comparison
-
-Bitwise reinterpretation: `bitcast <value>`.
-
-Selection: `select <condition>, <lhs>, <rhs>`.
-
-### Auxiliary MLIR Operations for Constants and Globals
-
-LLVM IR has broad support for first-class constants, which is not the case for
-MLIR. Instead, constants are defined in MLIR as regular SSA values produced by
-operations with specific traits. The LLVM dialect provides a set of operations
-that model LLVM IR constants. These operations do not correspond to LLVM IR
-instructions and are therefore prefixed with `llvm.mlir`.
-
-Inline constants can be created by `llvm.mlir.constant`, which currently
-supports integer, float, string or elements attributes (constant structs are not
-currently supported). LLVM IR constant expressions are expected to be
-constructed as sequences of regular operations on SSA values produced by
-`llvm.mlir.constant`. Additionally, MLIR provides semantically-charged
-operations `llvm.mlir.undef` and `llvm.mlir.null` for the corresponding
-constants.
-
-LLVM IR globals can be defined using `llvm.mlir.global` at the module level,
-except for functions that are defined with `llvm.func`. Globals, both variables
-and functions, can be accessed by taking their address with the
-`llvm.mlir.addressof` operation, which produces a pointer to the named global,
-unlike the `llvm.mlir.constant` that produces the value of the same type as the
-constant.
-
-#### `llvm.mlir.addressof`
-
-Creates an SSA value containing a pointer to a global variable or constant
-defined by `llvm.mlir.global`. The global value can be defined after its first
-referenced. If the global value is a constant, storing into it is not allowed.
-
-Examples:
-
-```mlir
-func @foo() {
-  // Get the address of a global variable.
-  %0 = llvm.mlir.addressof @const : !llvm<"i32*">
-
-  // Use it as a regular pointer.
-  %1 = llvm.load %0 : !llvm<"i32*">
-
-  // Get the address of a function.
-  %2 = llvm.mlir.addressof @foo : !llvm<"void ()*">
-
-  // The function address can be used for indirect calls.
-  llvm.call %2() : () -> ()
-}
-
-// Define the global.
-llvm.mlir.global @const(42 : i32) : !llvm.i32
-```
-
-#### `llvm.mlir.constant`
-
-Unlike LLVM IR, MLIR does not have first-class constant values. Therefore, all
-constants must be created as SSA values before being used in other operations.
-`llvm.mlir.constant` creates such values for scalars and vectors. It has a
-mandatory `value` attribute, which may be an integer, floating point attribute;
-dense or sparse attribute containing integers or floats. The type of the
-attribute is one of the corresponding MLIR builtin types. It may be omitted for
-`i64` and `f64` types that are implied. The operation produces a new SSA value
-of the specified LLVM IR dialect type. The type of that value _must_ correspond
-to the attribute type converted to LLVM IR.
-
-Examples:
-
-```mlir
-// Integer constant, internal i32 is mandatory
-%0 = llvm.mlir.constant(42 : i32) : !llvm.i32
-
-// It's okay to omit i64.
-%1 = llvm.mlir.constant(42) : !llvm.i64
-
-// Floating point constant.
-%2 = llvm.mlir.constant(42.0 : f32) : !llvm.float
-
-// Splat dense vector constant.
-%3 = llvm.mlir.constant(dense<1.0> : vector<4xf32>) : !llvm<"<4 x float>">
-```
-
-#### `llvm.mlir.global`
-
-Since MLIR allows for arbitrary operations to be present at the top level,
-global variables are defined using the `llvm.mlir.global` operation. Both global
-constants and variables can be defined, and the value may also be initialized in
-both cases.
-
-There are two forms of initialization syntax. Simple constants that can be
-represented as MLIR attributes can be given in-line:
-
-```mlir
-llvm.mlir.global @variable(32.0 : f32) : !llvm.float
-```
-
-This initialization and type syntax is similar to `llvm.mlir.constant` and may
-use two types: one for MLIR attribute and another for the LLVM value. These
-types must be compatible.
-
-More complex constants that cannot be represented as MLIR attributes can be
-given in an initializer region:
-
-```mlir
-// This global is initialized with the equivalent of:
-//   i32* getelementptr (i32* @g2, i32 2)
-llvm.mlir.global constant @int_gep() : !llvm<"i32*"> {
-  %0 = llvm.mlir.addressof @g2 : !llvm<"i32*">
-  %1 = llvm.mlir.constant(2 : i32) : !llvm.i32
-  %2 = llvm.getelementptr %0[%1] : (!llvm<"i32*">, !llvm.i32) -> !llvm<"i32*">
-  // The initializer region must end with `llvm.return`.
-  llvm.return %2 : !llvm<"i32*">
-}
-```
-
-Only one of the initializer attribute or initializer region may be provided.
-
-`llvm.mlir.global` must appear at top-level of the enclosing module. It uses an
- at -identifier for its value, which will be uniqued by the module with respect to
-other @-identifiers in it.
-
-Examples:
-
-```mlir
-// Global values use @-identifiers.
-llvm.mlir.global constant @cst(42 : i32) : !llvm.i32
-
-// Non-constant values must also be initialized.
-llvm.mlir.global @variable(32.0 : f32) : !llvm.float
-
-// Strings are expected to be of wrapped LLVM i8 array type and do not
-// automatically include the trailing zero.
-llvm.mlir.global @string("abc") : !llvm<"[3 x i8]">
-
-// For strings globals, the trailing type may be omitted.
-llvm.mlir.global constant @no_trailing_type("foo bar")
-
-// A complex initializer is constructed with an initializer region.
-llvm.mlir.global constant @int_gep() : !llvm<"i32*"> {
-  %0 = llvm.mlir.addressof @g2 : !llvm<"i32*">
-  %1 = llvm.mlir.constant(2 : i32) : !llvm.i32
-  %2 = llvm.getelementptr %0[%1] : (!llvm<"i32*">, !llvm.i32) -> !llvm<"i32*">
-  llvm.return %2 : !llvm<"i32*">
-}
-```
-
-Similarly to functions, globals have a linkage attribute. In the custom syntax,
-this attribute is placed between `llvm.mlir.global` and the optional `constant`
-keyword. If the attribute is omitted, `external` linkage is assumed by default.
-
-Examples:
-
-```mlir
-// A constant with internal linkage will not participate in linking.
-llvm.mlir.global internal constant @cst(42 : i32) : !llvm.i32
-
-// By default, "external" linkage is assumed and the global participates in
-// symbol resolution at link-time.
-llvm.mlir.global @glob(0 : f32) : !llvm.float
-```
-
-#### `llvm.mlir.null`
-
-Unlike LLVM IR, MLIR does not have first-class null pointers. They must be
-explicitly created as SSA values using `llvm.mlir.null`. This operation has
-no operands or attributes, and returns a null value of a wrapped LLVM IR
-pointer type.
-
-Examples:
-
-```mlir
-// Null pointer to i8 value.
-%0 = llvm.mlir.null : !llvm<"i8*">
-
-// Null pointer to a function with signature void() value.
-%1 = llvm.mlir.null : !llvm<"void()*">
-```
-
-#### `llvm.mlir.undef`
-
-Unlike LLVM IR, MLIR does not have first-class undefined values. Such values
-must be created as SSA values using `llvm.mlir.undef`. This operation has no
-operands or attributes. It creates an undefined value of the specified LLVM IR
-dialect type wrapping an LLVM IR structure type.
-
-Example:
-
-```mlir
-// Create a structure with a 32-bit integer followed by a float.
-%0 = llvm.mlir.undef : !llvm<"{i32, float}">
-```
+[include "Dialects/LLVMOps.md"

diff  --git a/mlir/include/mlir/Dialect/LLVMIR/CMakeLists.txt b/mlir/include/mlir/Dialect/LLVMIR/CMakeLists.txt
index 6bd289097017..6166f3632607 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/CMakeLists.txt
+++ b/mlir/include/mlir/Dialect/LLVMIR/CMakeLists.txt
@@ -8,6 +8,8 @@ mlir_tablegen(LLVMOpsEnums.h.inc -gen-enum-decls)
 mlir_tablegen(LLVMOpsEnums.cpp.inc -gen-enum-defs)
 add_public_tablegen_target(MLIRLLVMOpsIncGen)
 
+add_mlir_doc(LLVMOps -gen-op-doc LLVMOps Dialects/)
+
 set(LLVM_TARGET_DEFINITIONS LLVMOps.td)
 mlir_tablegen(LLVMConversions.inc -gen-llvmir-conversions)
 mlir_tablegen(LLVMConversionEnumsToLLVM.inc -gen-enum-to-llvmir-conversions)

diff  --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
index 59ea92d88330..0088fe38246b 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
@@ -407,6 +407,35 @@ def LLVM_LandingpadOp : LLVM_Op<"landingpad"> {
 }
 
 def LLVM_CallOp : LLVM_Op<"call"> {
+  let summary = "Call to an LLVM function.";
+  let description = [{
+
+
+    In LLVM IR, functions may return either 0 or 1 value. LLVM IR dialect
+    implements this behavior by providing a variadic `call` operation for 0- and
+    1-result functions. Even though MLIR supports multi-result functions, LLVM
+    IR dialect disallows them.
+
+    The `call` instruction supports both direct and indirect calls. Direct calls
+    start with a function name (`@`-prefixed) and indirect calls start with an
+    SSA value (`%`-prefixed). The direct callee, if present, is stored as a
+    function attribute `callee`. The trailing type of the instruction is always
+    the MLIR function type, which may be 
diff erent from the indirect callee that
+    has the wrapped LLVM IR function type.
+
+    Examples:
+
+    ```mlir
+    // Direct call without arguments and with one result.
+    %0 = llvm.call @foo() : () -> (!llvm.float)
+
+    // Direct call with arguments and without a result.
+    llvm.call @bar(%0) : (!llvm.float) -> ()
+
+    // Indirect call with an argument and without a result.
+    llvm.call %1(%0) : (!llvm.float) -> ()
+    ```
+  }];
   let arguments = (ins OptionalAttr<FlatSymbolRefAttr>:$callee,
                    Variadic<LLVM_Type>);
   let results = (outs Variadic<LLVM_Type>);
@@ -656,6 +685,34 @@ def LLVM_AddressOfOp : LLVM_Op<"mlir.addressof"> {
 
   let summary = "Creates a pointer pointing to a global or a function";
 
+  let description = [{
+    Creates an SSA value containing a pointer to a global variable or constant
+    defined by `llvm.mlir.global`. The global value can be defined after its
+    first referenced. If the global value is a constant, storing into it is not
+    allowed.
+
+    Examples:
+
+    ```mlir
+    func @foo() {
+      // Get the address of a global variable.
+      %0 = llvm.mlir.addressof @const : !llvm.ptr<i32>
+
+      // Use it as a regular pointer.
+      %1 = llvm.load %0 : !llvm.ptr<i32>
+
+      // Get the address of a function.
+      %2 = llvm.mlir.addressof @foo : !llvm.ptr<func<void ()>>
+
+      // The function address can be used for indirect calls.
+      llvm.call %2() : () -> ()
+    }
+
+    // Define the global.
+    llvm.mlir.global @const(42 : i32) : !llvm.i32
+    ```
+  }];
+
   let builders = [
     OpBuilderDAG<(ins "LLVMType":$resType, "StringRef":$name,
       CArg<"ArrayRef<NamedAttribute>", "{}">:$attrs),
@@ -701,18 +758,85 @@ def LLVM_GlobalOp : LLVM_Op<"mlir.global",
   );
   let summary = "LLVM dialect global.";
   let description = [{
-    Can contain an optional initializer region or attribute for simple
-    initializers.
+    Since MLIR allows for arbitrary operations to be present at the top level,
+    global variables are defined using the `llvm.mlir.global` operation. Both
+    global constants and variables can be defined, and the value may also be
+    initialized in both cases.
+
+    There are two forms of initialization syntax. Simple constants that can be
+    represented as MLIR attributes can be given in-line:
+
+    ```mlir
+    llvm.mlir.global @variable(32.0 : f32) : !llvm.float
+    ```
+
+    This initialization and type syntax is similar to `llvm.mlir.constant` and
+    may use two types: one for MLIR attribute and another for the LLVM value.
+    These types must be compatible.
+
+    More complex constants that cannot be represented as MLIR attributes can be
+    given in an initializer region:
+
+    ```mlir
+    // This global is initialized with the equivalent of:
+    //   i32* getelementptr (i32* @g2, i32 2)
+    llvm.mlir.global constant @int_gep() : !llvm.ptr<i32> {
+      %0 = llvm.mlir.addressof @g2 : !llvm.ptr<i32>
+      %1 = llvm.mlir.constant(2 : i32) : !llvm.i32
+      %2 = llvm.getelementptr %0[%1]
+         : (!llvm.ptr<i32>, !llvm.i32) -> !llvm.ptr<i32>
+      // The initializer region must end with `llvm.return`.
+      llvm.return %2 : !llvm.ptr<i32>
+    }
+    ```
+
+    Only one of the initializer attribute or initializer region may be provided.
+
+    `llvm.mlir.global` must appear at top-level of the enclosing module. It uses
+    an @-identifier for its value, which will be uniqued by the module with
+    respect to other @-identifiers in it.
+
+    Examples:
+
+    ```mlir
+    // Global values use @-identifiers.
+    llvm.mlir.global constant @cst(42 : i32) : !llvm.i32
+
+    // Non-constant values must also be initialized.
+    llvm.mlir.global @variable(32.0 : f32) : !llvm.float
+
+    // Strings are expected to be of wrapped LLVM i8 array type and do not
+    // automatically include the trailing zero.
+    llvm.mlir.global @string("abc") : !llvm.array<3 x i8>
+
+    // For strings globals, the trailing type may be omitted.
+    llvm.mlir.global constant @no_trailing_type("foo bar")
+
+    // A complex initializer is constructed with an initializer region.
+    llvm.mlir.global constant @int_gep() : !llvm.ptr<i32> {
+      %0 = llvm.mlir.addressof @g2 : !llvm.ptr<i32>
+      %1 = llvm.mlir.constant(2 : i32) : !llvm.i32
+      %2 = llvm.getelementptr %0[%1]
+         : (!llvm.ptr<i32>, !llvm.i32) -> !llvm.ptr<i32>
+      llvm.return %2 : !llvm.ptr<i32>
+    }
+    ```
+
+    Similarly to functions, globals have a linkage attribute. In the custom
+    syntax, this attribute is placed between `llvm.mlir.global` and the optional
+    `constant` keyword. If the attribute is omitted, `external` linkage is
+    assumed by default.
 
     Examples:
-      // Initialized using an attribute.
-      llvm.mlir.global @a("abc") : !llvm<"[3 x i8]">
-      // Initialized using a region.
-      llvm.mlir.global constant @b() : !llvm<"i32*"> {
-        %0 = llvm.constant(0 : i32) : !llvm.i32
-        %1 = llvm.inttoptr %0 : !llvm.i32 to !llvm<"i32*">
-        llvm.return %1 : !llvm<"i32*">
-      }
+
+    ```mlir
+    // A constant with internal linkage will not participate in linking.
+    llvm.mlir.global internal constant @cst(42 : i32) : !llvm.i32
+
+    // By default, "external" linkage is assumed and the global participates in
+    // symbol resolution at link-time.
+    llvm.mlir.global @glob(0 : f32) : !llvm.float
+    ```
   }];
   let regions = (region AnyRegion:$initializer);
 
@@ -752,7 +876,35 @@ def LLVM_GlobalOp : LLVM_Op<"mlir.global",
 
 def LLVM_LLVMFuncOp : LLVM_Op<"func",
     [AutomaticAllocationScope, IsolatedFromAbove, FunctionLike, Symbol]> {
-  let summary = "LLVM dialect function, has wrapped LLVM IR function type";
+  let summary = "LLVM dialect function.";
+
+  let description = [{
+    MLIR functions are defined by an operation that is not built into the IR
+    itself. The LLVM dialect provides an `llvm.func` operation to define
+    functions compatible with LLVM IR. These functions have LLVM dialect
+    function type but use MLIR syntax to express it. They are required to have
+    exactly one result type. LLVM function operation is intended to capture
+    additional properties of LLVM functions, such as linkage and calling
+    convention, that may be modeled 
diff erently by the built-in MLIR function.
+
+    ```mlir
+    // The type of @bar is !llvm<"i64 (i64)">
+    llvm.func @bar(%arg0: !llvm.i64) -> !llvm.i64 {
+      llvm.return %arg0 : !llvm.i64
+    }
+
+    // Type type of @foo is !llvm<"void (i64)">
+    // !llvm.void type is omitted
+    llvm.func @foo(%arg0: !llvm.i64) {
+      llvm.return
+    }
+
+    // A function with `internal` linkage.
+    llvm.func internal @internal_func() {
+      llvm.return
+    }
+    ```
+  }];
 
   let arguments = (ins DefaultValuedAttr<Linkage, "Linkage::External">:$linkage,
                    OptionalAttr<FlatSymbolRefAttr>:$personality,
@@ -805,6 +957,24 @@ def LLVM_NullOp
     : LLVM_Op<"mlir.null", [NoSideEffect]>,
       LLVM_Builder<"$res = llvm::ConstantPointerNull::get("
                    "    cast<llvm::PointerType>($_resultType));"> {
+  let summary = "Defines a value containing a null pointer to LLVM type.";
+  let description = [{
+    Unlike LLVM IR, MLIR does not have first-class null pointers. They must be
+    explicitly created as SSA values using `llvm.mlir.null`. This operation has
+    no operands or attributes, and returns a null value of a wrapped LLVM IR
+    pointer type.
+
+    Examples:
+
+    ```mlir
+    // Null pointer to i8.
+    %0 = llvm.mlir.null : !llvm.ptr<i8>
+
+    // Null pointer to a function with signature void().
+    %1 = llvm.mlir.null : !llvm.ptr<func<void ()>>
+    ```
+  }];
+
   let results = (outs LLVM_AnyPointer:$res);
   let builders = [LLVM_OneResultOpBuilder];
   let assemblyFormat = "attr-dict `:` type($res)";
@@ -812,14 +982,59 @@ def LLVM_NullOp
 
 def LLVM_UndefOp : LLVM_Op<"mlir.undef", [NoSideEffect]>,
                    LLVM_Builder<"$res = llvm::UndefValue::get($_resultType);"> {
+  let summary = "Creates an undefined value of LLVM dialect type.";
+  let description = [{
+    Unlike LLVM IR, MLIR does not have first-class undefined values. Such values
+    must be created as SSA values using `llvm.mlir.undef`. This operation has no
+    operands or attributes. It creates an undefined value of the specified LLVM
+    IR dialect type wrapping an LLVM IR structure type.
+
+    Example:
+
+    ```mlir
+    // Create a structure with a 32-bit integer followed by a float.
+    %0 = llvm.mlir.undef : !llvm.struct<(i32, float)>
+    ```
+  }];
   let results = (outs LLVM_Type:$res);
   let builders = [LLVM_OneResultOpBuilder];
   let assemblyFormat = "attr-dict `:` type($res)";
 }
+
 def LLVM_ConstantOp
     : LLVM_Op<"mlir.constant", [NoSideEffect]>,
       LLVM_Builder<"$res = getLLVMConstant($_resultType, $value, $_location);">
 {
+  let summary = "Defines a constant of LLVM type.";
+  let description = [{
+    Unlike LLVM IR, MLIR does not have first-class constant values. Therefore,
+    all constants must be created as SSA values before being used in other
+    operations. `llvm.mlir.constant` creates such values for scalars and
+    vectors. It has a mandatory `value` attribute, which may be an integer,
+    floating point attribute; dense or sparse attribute containing integers or
+    floats. The type of the attribute is one of the corresponding MLIR builtin
+    types. It may be omitted for `i64` and `f64` types that are implied. The
+    operation produces a new SSA value of the specified LLVM IR dialect type.
+    The type of that value _must_ correspond to the attribute type converted to
+    LLVM IR.
+
+    Examples:
+
+    ```mlir
+    // Integer constant, internal i32 is mandatory
+    %0 = llvm.mlir.constant(42 : i32) : !llvm.i32
+
+    // It's okay to omit i64.
+    %1 = llvm.mlir.constant(42) : !llvm.i64
+
+    // Floating point constant.
+    %2 = llvm.mlir.constant(42.0 : f32) : !llvm.float
+
+    // Splat dense vector constant.
+    %3 = llvm.mlir.constant(dense<1.0> : vector<4xf32>) : !llvm.vec<4 x float>
+    ```
+  }];
+
   let arguments = (ins AnyAttr:$value);
   let results = (outs LLVM_Type:$res);
   let builders = [LLVM_OneResultOpBuilder];


        


More information about the llvm-branch-commits mailing list