summaryrefslogtreecommitdiffstats
path: root/mlir/docs/Dialects/LLVM.md
diff options
context:
space:
mode:
Diffstat (limited to 'mlir/docs/Dialects/LLVM.md')
-rw-r--r--mlir/docs/Dialects/LLVM.md429
1 files changed, 429 insertions, 0 deletions
diff --git a/mlir/docs/Dialects/LLVM.md b/mlir/docs/Dialects/LLVM.md
new file mode 100644
index 00000000000..00d0fa02fec
--- /dev/null
+++ b/mlir/docs/Dialects/LLVM.md
@@ -0,0 +1,429 @@
+# LLVM IR Dialect
+
+This dialect wraps the LLVM IR types and instructions into MLIR types and
+operations. It provides several additional operations that are necessary to
+cover for the differences in the IR structure (e.g., MLIR does not have `phi`
+operations and LLVM IR does not have a `constant` operation).
+
+In this document, we use "LLVM IR" to designate the
+[intermediate representation of LLVM](https://llvm.org/docs/LangRef.html) and
+"LLVM IR _dialect_" to refer to the MLIR dialect reflecting LLVM instructions
+and types.
+
+[TOC]
+
+## Context and Module Association
+
+The LLVM IR dialect object _contains_ an LLVM Context and an LLVM Module that it
+uses to define, print, parse and manage LLVM IR types. These objects can be
+obtained from the dialect object using `.getLLVMContext()` and
+`getLLVMModule()`. All LLVM IR objects that interact with the LLVM IR dialect
+must exist in the dialect's context.
+
+## Types
+
+The LLVM IR dialect defines a single MLIR type, `LLVM::LLVMType`, that can wrap
+any existing LLVM IR type. Its syntax is as follows
+
+```
+type ::= `!llvm<"` llvm-canonical-type `">
+llvm-canonical-type ::= <canonical textual representation defined by LLVM>
+```
+
+For example, one can use primitive types `!llvm.i32`, pointer types
+`!llvm<"i8*">`, vector types `!llvm<"<4 x float>">` or structure types
+`!llvm<"{i32, float}">`. The parsing and printing of the canonical form is
+delegated to the LLVM assembly parser and printer.
+
+LLVM IR dialect types contain an `llvm::Type*` object that can be obtained by
+calling `.getUnderlyingType()` and used in LLVM API calls directly. These
+objects are allocated within the LLVM context associated with the LLVM IR
+dialect and may be linked to the properties of the associated LLVM module.
+
+LLVM IR dialect type can be constructed from any `llvm::Type*` that is
+associated with the LLVM context of the dialect. In this document, we use the
+term "wrapped LLVM IR type" to refer to the LLVM IR dialect type containing a
+specific LLVM IR type.
+
+## Operations
+
+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
+differently 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
+}
+
+```
+
+### 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
+different 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 different 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 different 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
+
+These operations do not have LLVM IR counterparts but are necessary to map LLVM
+IR into MLIR. They should be prefixed with `llvm.mlir`.
+
+#### `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.
+ %0 = llvm.mlir.addressof @const : !llvm<"i32*">
+
+ // Use it as a regular pointer.
+ %1 = llvm.load %0 : !llvm<"i32*">
+}
+
+// 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 the corresponding MLIR standard 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
+@-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*">
+}
+```
+
+#### `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
+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}">
+```
OpenPOWER on IntegriCloud