1# LLVM IR Target 2 3This document describes the mechanisms of producing LLVM IR from MLIR. The 4overall flow is two-stage: 5 61. **conversion** of the IR to a set of dialects translatable to LLVM IR, for 7 example [LLVM Dialect](Dialects/LLVM.md) or one of the hardware-specific 8 dialects derived from LLVM IR intrinsics such as [AMX](Dialects/AMX.md), 9 [X86Vector](Dialects/X86Vector.md) or [ArmNeon](Dialects/ArmNeon.md); 102. **translation** of MLIR dialects to LLVM IR. 11 12This flow allows the non-trivial transformation to be performed within MLIR 13using MLIR APIs and makes the translation between MLIR and LLVM IR *simple* and 14potentially bidirectional. As a corollary, dialect ops translatable to LLVM IR 15are expected to closely match the corresponding LLVM IR instructions and 16intrinsics. This minimizes the dependency on LLVM IR libraries in MLIR as well 17as reduces the churn in case of changes. 18 19SPIR-V to LLVM dialect conversion has a 20[dedicated document](SPIRVToLLVMDialectConversion.md). 21 22[TOC] 23 24## Conversion to the LLVM Dialect 25 26Conversion to the LLVM dialect from other dialects is the first step to produce 27LLVM IR. All non-trivial IR modifications are expected to happen at this stage 28or before. The conversion is *progressive*: most passes convert one dialect to 29the LLVM dialect and keep operations from other dialects intact. For example, 30the `-convert-memref-to-llvm` pass will only convert operations from the 31`memref` dialect but will not convert operations from other dialects even if 32they use or produce `memref`-typed values. 33 34The process relies on the [Dialect Conversion](DialectConversion.md) 35infrastructure and, in particular, on the 36[materialization](DialectConversion.md#type-conversion) hooks of `TypeConverter` 37to support progressive lowering by injecting `unrealized_conversion_cast` 38operations between converted and unconverted operations. After multiple partial 39conversions to the LLVM dialect are performed, the cast operations that became 40noop can be removed by the `-reconcile-unrealized-casts` pass. The latter pass 41is not specific to the LLVM dialect and can remove any noop casts. 42 43### Conversion of Built-in Types 44 45Built-in types have a default conversion to LLVM dialect types provided by the 46`LLVMTypeConverter` class. Users targeting the LLVM dialect can reuse and extend 47this type converter to support other types. Extra care must be taken if the 48conversion rules for built-in types are overridden: all conversion must use the 49same type converter. 50 51#### LLVM Dialect-compatible Types 52 53The types [compatible](Dialects/LLVM.md#built-in-type-compatibility) with the 54LLVM dialect are kept as is. 55 56#### Complex Type 57 58Complex type is converted into an LLVM dialect literal structure type with two 59elements: 60 61- real part; 62- imaginary part. 63 64The elemental type is converted recursively using these rules. 65 66Example: 67 68```mlir 69 complex<f32> 70 // -> 71 !llvm.struct<(f32, f32)> 72``` 73 74#### Index Type 75 76Index type is converted into an LLVM dialect integer type with the bitwidth 77specified by the [data layout](DataLayout.md) of the closest module. For 78example, on x86-64 CPUs it converts to i64. This behavior can be overridden by 79the type converter configuration, which is often exposed as a pass option by 80conversion passes. 81 82Example: 83 84```mlir 85 index 86 // -> on x86_64 87 i64 88``` 89 90#### Ranked MemRef Types 91 92Ranked memref types are converted into an LLVM dialect literal structure type 93that contains the dynamic information associated with the memref object, 94referred to as *descriptor*. Only memrefs in the 95**[strided form](Dialects/Builtin.md/#strided-memref)** can be converted to the 96LLVM dialect with the default descriptor format. Memrefs with other, less 97trivial layouts should be converted into the strided form first, e.g., by 98materializing the non-trivial address remapping due to layout as `affine.apply` 99operations. 100 101The default memref descriptor is a struct with the following fields: 102 1031. The pointer to the data buffer as allocated, referred to as "allocated 104 pointer". This is only useful for deallocating the memref. 1052. The pointer to the properly aligned data pointer that the memref indexes, 106 referred to as "aligned pointer". 1073. A lowered converted `index`-type integer containing the distance in number 108 of elements between the beginning of the (aligned) buffer and the first 109 element to be accessed through the memref, referred to as "offset". 1104. An array containing as many converted `index`-type integers as the rank of 111 the memref: the array represents the size, in number of elements, of the 112 memref along the given dimension. 1135. A second array containing as many converted `index`-type integers as the 114 rank of memref: the second array represents the "stride" (in tensor 115 abstraction sense), i.e. the number of consecutive elements of the 116 underlying buffer one needs to jump over to get to the next logically 117 indexed element. 118 119For constant memref dimensions, the corresponding size entry is a constant whose 120runtime value matches the static value. This normalization serves as an ABI for 121the memref type to interoperate with externally linked functions. In the 122particular case of rank `0` memrefs, the size and stride arrays are omitted, 123resulting in a struct containing two pointers + offset. 124 125Examples: 126 127```mlir 128// Assuming index is converted to i64. 129 130memref<f32> -> !llvm.struct<(ptr<f32> , ptr<f32>, i64)> 131memref<1 x f32> -> !llvm.struct<(ptr<f32>, ptr<f32>, i64, 132 array<1 x 64>, array<1 x i64>)> 133memref<? x f32> -> !llvm.struct<(ptr<f32>, ptr<f32>, i64 134 array<1 x 64>, array<1 x i64>)> 135memref<10x42x42x43x123 x f32> -> !llvm.struct<(ptr<f32>, ptr<f32>, i64 136 array<5 x 64>, array<5 x i64>)> 137memref<10x?x42x?x123 x f32> -> !llvm.struct<(ptr<f32>, ptr<f32>, i64 138 array<5 x 64>, array<5 x i64>)> 139 140// Memref types can have vectors as element types 141memref<1x? x vector<4xf32>> -> !llvm.struct<(ptr<vector<4 x f32>>, 142 ptr<vector<4 x f32>>, i64, 143 array<2 x i64>, array<2 x i64>)> 144``` 145 146#### Unranked MemRef Types 147 148Unranked memref types are converted to LLVM dialect literal structure type that 149contains the dynamic information associated with the memref object, referred to 150as *unranked descriptor*. It contains: 151 1521. a converted `index`-typed integer representing the dynamic rank of the 153 memref; 1542. a type-erased pointer (`!llvm.ptr<i8>`) to a ranked memref descriptor with 155 the contents listed above. 156 157This descriptor is primarily intended for interfacing with rank-polymorphic 158library functions. The pointer to the ranked memref descriptor points to some 159*allocated* memory, which may reside on stack of the current function or in 160heap. Conversion patterns for operations producing unranked memrefs are expected 161to manage the allocation. Note that this may lead to stack allocations 162(`llvm.alloca`) being performed in a loop and not reclaimed until the end of the 163current function. 164 165#### Function Types 166 167Function types are converted to LLVM dialect function types as follows: 168 169- function argument and result types are converted recursively using these 170 rules; 171- if a function type has multiple results, they are wrapped into an LLVM 172 dialect literal structure type since LLVM function types must have exactly 173 one result; 174- if a function type has no results, the corresponding LLVM dialect function 175 type will have one `!llvm.void` result since LLVM function types must have a 176 result; 177- function types used in arguments of another function type are wrapped in an 178 LLVM dialect pointer type to comply with LLVM IR expectations; 179- the structs corresponding to `memref` types, both ranked and unranked, 180 appearing as function arguments are unbundled into individual function 181 arguments to allow for specifying metadata such as aliasing information on 182 individual pointers; 183- the conversion of `memref`-typed arguments is subject to 184 [calling conventions](TargetLLVMIR.md#calling-conventions). 185 186Examples: 187 188```mlir 189// Zero-ary function type with no results: 190() -> () 191// is converted to a zero-ary function with `void` result. 192!llvm.func<void ()> 193 194// Unary function with one result: 195(i32) -> (i64) 196// has its argument and result type converted, before creating the LLVM dialect 197// function type. 198!llvm.func<i64 (i32)> 199 200// Binary function with one result: 201(i32, f32) -> (i64) 202// has its arguments handled separately 203!llvm.func<i64 (i32, f32)> 204 205// Binary function with two results: 206(i32, f32) -> (i64, f64) 207// has its result aggregated into a structure type. 208!llvm.func<struct<(i64, f64)> (i32, f32)> 209 210// Function-typed arguments or results in higher-order functions: 211(() -> ()) -> (() -> ()) 212// are converted into pointers to functions. 213!llvm.func<ptr<func<void ()>> (ptr<func<void ()>>)> 214 215// These rules apply recursively: a function type taking a function that takes 216// another function 217( ( (i32) -> (i64) ) -> () ) -> () 218// is converted into a function type taking a pointer-to-function that takes 219// another point-to-function. 220!llvm.func<void (ptr<func<void (ptr<func<i64 (i32)>>)>>)> 221 222// A memref descriptor appearing as function argument: 223(memref<f32>) -> () 224// gets converted into a list of individual scalar components of a descriptor. 225!llvm.func<void (ptr<f32>, ptr<f32>, i64)> 226 227// The list of arguments is linearized and one can freely mix memref and other 228// types in this list: 229(memref<f32>, f32) -> () 230// which gets converted into a flat list. 231!llvm.func<void (ptr<f32>, ptr<f32>, i64, f32)> 232 233// For nD ranked memref descriptors: 234(memref<?x?xf32>) -> () 235// the converted signature will contain 2n+1 `index`-typed integer arguments, 236// offset, n sizes and n strides, per memref argument type. 237!llvm.func<void (ptr<f32>, ptr<f32>, i64, i64, i64, i64, i64)> 238 239// Same rules apply to unranked descriptors: 240(memref<*xf32>) -> () 241// which get converted into their components. 242!llvm.func<void (i64, ptr<i8>)> 243 244// However, returning a memref from a function is not affected: 245() -> (memref<?xf32>) 246// gets converted to a function returning a descriptor structure. 247!llvm.func<struct<(ptr<f32>, ptr<f32>, i64, array<1xi64>, array<1xi64>)> ()> 248 249// If multiple memref-typed results are returned: 250() -> (memref<f32>, memref<f64>) 251// their descriptor structures are additionally packed into another structure, 252// potentially with other non-memref typed results. 253!llvm.func<struct<(struct<(ptr<f32>, ptr<f32>, i64)>, 254 struct<(ptr<double>, ptr<double>, i64)>)> ()> 255``` 256 257Conversion patterns are available to convert built-in function operations and 258standard call operations targeting those functions using these conversion rules. 259 260#### Multi-dimensional Vector Types 261 262LLVM IR only supports *one-dimensional* vectors, unlike MLIR where vectors can 263be multi-dimensional. Vector types cannot be nested in either IR. In the 264one-dimensional case, MLIR vectors are converted to LLVM IR vectors of the same 265size with element type converted using these conversion rules. In the 266n-dimensional case, MLIR vectors are converted to (n-1)-dimensional array types 267of one-dimensional vectors. 268 269Examples: 270 271``` 272vector<4x8 x f32> 273// -> 274!llvm.array<4 x vector<8 x f32>> 275 276memref<2 x vector<4x8 x f32> 277// -> 278!llvm.struct<(ptr<array<4 x vector<8xf32>>>, ptr<array<4 x vector<8xf32>>> 279 i64, array<1 x i64>, array<1 x i64>)> 280``` 281 282#### Tensor Types 283 284Tensor types cannot be converted to the LLVM dialect. Operations on tensors must 285be [bufferized](Bufferization.md) before being converted. 286 287### Calling Conventions 288 289Calling conventions provides a mechanism to customize the conversion of function 290and function call operations without changing how individual types are handled 291elsewhere. They are implemented simultaneously by the default type converter and 292by the conversion patterns for the relevant operations. 293 294#### Function Result Packing 295 296In case of multi-result functions, the returned values are inserted into a 297structure-typed value before being returned and extracted from it at the call 298site. This transformation is a part of the conversion and is transparent to the 299defines and uses of the values being returned. 300 301Example: 302 303```mlir 304func.func @foo(%arg0: i32, %arg1: i64) -> (i32, i64) { 305 return %arg0, %arg1 : i32, i64 306} 307func.func @bar() { 308 %0 = arith.constant 42 : i32 309 %1 = arith.constant 17 : i64 310 %2:2 = call @foo(%0, %1) : (i32, i64) -> (i32, i64) 311 "use_i32"(%2#0) : (i32) -> () 312 "use_i64"(%2#1) : (i64) -> () 313} 314 315// is transformed into 316 317llvm.func @foo(%arg0: i32, %arg1: i64) -> !llvm.struct<(i32, i64)> { 318 // insert the vales into a structure 319 %0 = llvm.mlir.undef : !llvm.struct<(i32, i64)> 320 %1 = llvm.insertvalue %arg0, %0[0] : !llvm.struct<(i32, i64)> 321 %2 = llvm.insertvalue %arg1, %1[1] : !llvm.struct<(i32, i64)> 322 323 // return the structure value 324 llvm.return %2 : !llvm.struct<(i32, i64)> 325} 326llvm.func @bar() { 327 %0 = llvm.mlir.constant(42 : i32) : i32 328 %1 = llvm.mlir.constant(17) : i64 329 330 // call and extract the values from the structure 331 %2 = llvm.call @bar(%0, %1) 332 : (i32, i32) -> !llvm.struct<(i32, i64)> 333 %3 = llvm.extractvalue %2[0] : !llvm.struct<(i32, i64)> 334 %4 = llvm.extractvalue %2[1] : !llvm.struct<(i32, i64)> 335 336 // use as before 337 "use_i32"(%3) : (i32) -> () 338 "use_i64"(%4) : (i64) -> () 339} 340``` 341 342#### Default Calling Convention for Ranked MemRef 343 344The default calling convention converts `memref`-typed function arguments to 345LLVM dialect literal structs 346[defined above](TargetLLVMIR.md#ranked-memref-types) before unbundling them into 347individual scalar arguments. 348 349Examples: 350 351This convention is implemented in the conversion of `func.func` and `func.call` to 352the LLVM dialect, with the former unpacking the descriptor into a set of 353individual values and the latter packing those values back into a descriptor so 354as to make it transparently usable by other operations. Conversions from other 355dialects should take this convention into account. 356 357This specific convention is motivated by the necessity to specify alignment and 358aliasing attributes on the raw pointers underpinning the memref. 359 360Examples: 361 362```mlir 363func.func @foo(%arg0: memref<?xf32>) -> () { 364 "use"(%arg0) : (memref<?xf32>) -> () 365 return 366} 367 368// Gets converted to the following 369// (using type alias for brevity): 370!llvm.memref_1d = !llvm.struct<(ptr<f32>, ptr<f32>, i64, array<1xi64>, array<1xi64>)> 371 372llvm.func @foo(%arg0: !llvm.ptr<f32>, // Allocated pointer. 373 %arg1: !llvm.ptr<f32>, // Aligned pointer. 374 %arg2: i64, // Offset. 375 %arg3: i64, // Size in dim 0. 376 %arg4: i64) { // Stride in dim 0. 377 // Populate memref descriptor structure. 378 %0 = llvm.mlir.undef : 379 %1 = llvm.insertvalue %arg0, %0[0] : !llvm.memref_1d 380 %2 = llvm.insertvalue %arg1, %1[1] : !llvm.memref_1d 381 %3 = llvm.insertvalue %arg2, %2[2] : !llvm.memref_1d 382 %4 = llvm.insertvalue %arg3, %3[3, 0] : !llvm.memref_1d 383 %5 = llvm.insertvalue %arg4, %4[4, 0] : !llvm.memref_1d 384 385 // Descriptor is now usable as a single value. 386 "use"(%5) : (!llvm.memref_1d) -> () 387 llvm.return 388} 389``` 390 391```mlir 392func.func @bar() { 393 %0 = "get"() : () -> (memref<?xf32>) 394 call @foo(%0) : (memref<?xf32>) -> () 395 return 396} 397 398// Gets converted to the following 399// (using type alias for brevity): 400!llvm.memref_1d = !llvm.struct<(ptr<f32>, ptr<f32>, i64, array<1xi64>, array<1xi64>)> 401 402llvm.func @bar() { 403 %0 = "get"() : () -> !llvm.memref_1d 404 405 // Unpack the memref descriptor. 406 %1 = llvm.extractvalue %0[0] : !llvm.memref_1d 407 %2 = llvm.extractvalue %0[1] : !llvm.memref_1d 408 %3 = llvm.extractvalue %0[2] : !llvm.memref_1d 409 %4 = llvm.extractvalue %0[3, 0] : !llvm.memref_1d 410 %5 = llvm.extractvalue %0[4, 0] : !llvm.memref_1d 411 412 // Pass individual values to the callee. 413 llvm.call @foo(%1, %2, %3, %4, %5) : (!llvm.memref_1d) -> () 414 llvm.return 415} 416``` 417 418#### Default Calling Convention for Unranked MemRef 419 420For unranked memrefs, the list of function arguments always contains two 421elements, same as the unranked memref descriptor: an integer rank, and a 422type-erased (`!llvm<"i8*">`) pointer to the ranked memref descriptor. Note that 423while the *calling convention* does not require allocation, *casting* to 424unranked memref does since one cannot take an address of an SSA value containing 425the ranked memref, which must be stored in some memory instead. The caller is in 426charge of ensuring the thread safety and management of the allocated memory, in 427particular the deallocation. 428 429Example 430 431```mlir 432llvm.func @foo(%arg0: memref<*xf32>) -> () { 433 "use"(%arg0) : (memref<*xf32>) -> () 434 return 435} 436 437// Gets converted to the following. 438 439llvm.func @foo(%arg0: i64 // Rank. 440 %arg1: !llvm.ptr<i8>) { // Type-erased pointer to descriptor. 441 // Pack the unranked memref descriptor. 442 %0 = llvm.mlir.undef : !llvm.struct<(i64, ptr<i8>)> 443 %1 = llvm.insertvalue %arg0, %0[0] : !llvm.struct<(i64, ptr<i8>)> 444 %2 = llvm.insertvalue %arg1, %1[1] : !llvm.struct<(i64, ptr<i8>)> 445 446 "use"(%2) : (!llvm.struct<(i64, ptr<i8>)>) -> () 447 llvm.return 448} 449``` 450 451```mlir 452llvm.func @bar() { 453 %0 = "get"() : () -> (memref<*xf32>) 454 call @foo(%0): (memref<*xf32>) -> () 455 return 456} 457 458// Gets converted to the following. 459 460llvm.func @bar() { 461 %0 = "get"() : () -> (!llvm.struct<(i64, ptr<i8>)>) 462 463 // Unpack the memref descriptor. 464 %1 = llvm.extractvalue %0[0] : !llvm.struct<(i64, ptr<i8>)> 465 %2 = llvm.extractvalue %0[1] : !llvm.struct<(i64, ptr<i8>)> 466 467 // Pass individual values to the callee. 468 llvm.call @foo(%1, %2) : (i64, !llvm.ptr<i8>) 469 llvm.return 470} 471``` 472 473**Lifetime.** The second element of the unranked memref descriptor points to 474some memory in which the ranked memref descriptor is stored. By convention, this 475memory is allocated on stack and has the lifetime of the function. (*Note:* due 476to function-length lifetime, creation of multiple unranked memref descriptors, 477e.g., in a loop, may lead to stack overflows.) If an unranked descriptor has to 478be returned from a function, the ranked descriptor it points to is copied into 479dynamically allocated memory, and the pointer in the unranked descriptor is 480updated accordingly. The allocation happens immediately before returning. It is 481the responsibility of the caller to free the dynamically allocated memory. The 482default conversion of `func.call` and `func.call_indirect` copies the ranked 483descriptor to newly allocated memory on the caller's stack. Thus, the convention 484of the ranked memref descriptor pointed to by an unranked memref descriptor 485being stored on stack is respected. 486 487#### Bare Pointer Calling Convention for Ranked MemRef 488 489The "bare pointer" calling convention converts `memref`-typed function arguments 490to a *single* pointer to the aligned data. Note that this does *not* apply to 491uses of `memref` outside of function signatures, the default descriptor 492structures are still used. This convention further restricts the supported cases 493to the following. 494 495- `memref` types with default layout. 496- `memref` types with all dimensions statically known. 497- `memref` values allocated in such a way that the allocated and aligned 498 pointer match. Alternatively, the same function must handle allocation and 499 deallocation since only one pointer is passed to any callee. 500 501Examples: 502 503``` 504func.func @callee(memref<2x4xf32>) { 505 506func.func @caller(%0 : memref<2x4xf32>) { 507 call @callee(%0) : (memref<2x4xf32>) -> () 508} 509 510// -> 511 512!descriptor = !llvm.struct<(ptr<f32>, ptr<f32>, i64, 513 array<2xi64>, array<2xi64>)> 514 515llvm.func @callee(!llvm.ptr<f32>) 516 517llvm.func @caller(%arg0: !llvm.ptr<f32>) { 518 // A descriptor value is defined at the function entry point. 519 %0 = llvm.mlir.undef : !descriptor 520 521 // Both the allocated and aligned pointer are set up to the same value. 522 %1 = llvm.insertelement %arg0, %0[0] : !descriptor 523 %2 = llvm.insertelement %arg0, %1[1] : !descriptor 524 525 // The offset is set up to zero. 526 %3 = llvm.mlir.constant(0 : index) : i64 527 %4 = llvm.insertelement %3, %2[2] : !descriptor 528 529 // The sizes and strides are derived from the statically known values. 530 %5 = llvm.mlir.constant(2 : index) : i64 531 %6 = llvm.mlir.constant(4 : index) : i64 532 %7 = llvm.insertelement %5, %4[3, 0] : !descriptor 533 %8 = llvm.insertelement %6, %7[3, 1] : !descriptor 534 %9 = llvm.mlir.constant(1 : index) : i64 535 %10 = llvm.insertelement %9, %8[4, 0] : !descriptor 536 %11 = llvm.insertelement %10, %9[4, 1] : !descriptor 537 538 // The function call corresponds to extracting the aligned data pointer. 539 %12 = llvm.extractelement %11[1] : !descriptor 540 llvm.call @callee(%12) : (!llvm.ptr<f32>) -> () 541} 542``` 543 544#### Bare Pointer Calling Convention For Unranked MemRef 545 546The "bare pointer" calling convention does not support unranked memrefs as their 547shape cannot be known at compile time. 548 549### C-compatible wrapper emission 550 551In practical cases, it may be desirable to have externally-facing functions with 552a single attribute corresponding to a MemRef argument. When interfacing with 553LLVM IR produced from C, the code needs to respect the corresponding calling 554convention. The conversion to the LLVM dialect provides an option to generate 555wrapper functions that take memref descriptors as pointers-to-struct compatible 556with data types produced by Clang when compiling C sources. The generation of 557such wrapper functions can additionally be controlled at a function granularity 558by setting the `llvm.emit_c_interface` unit attribute. 559 560More specifically, a memref argument is converted into a pointer-to-struct 561argument of type `{T*, T*, i64, i64[N], i64[N]}*` in the wrapper function, where 562`T` is the converted element type and `N` is the memref rank. This type is 563compatible with that produced by Clang for the following C++ structure template 564instantiations or their equivalents in C. 565 566```cpp 567template<typename T, size_t N> 568struct MemRefDescriptor { 569 T *allocated; 570 T *aligned; 571 intptr_t offset; 572 intptr_t sizes[N]; 573 intptr_t strides[N]; 574}; 575``` 576 577Furthermore, we also rewrite function results to pointer parameters if the 578rewritten function result has a struct type. The special result parameter is 579added as the first parameter and is of pointer-to-struct type. 580 581If enabled, the option will do the following. For *external* functions declared 582in the MLIR module. 583 5841. Declare a new function `_mlir_ciface_<original name>` where memref arguments 585 are converted to pointer-to-struct and the remaining arguments are converted 586 as usual. Results are converted to a special argument if they are of struct 587 type. 5882. Add a body to the original function (making it non-external) that 589 1. allocates memref descriptors, 590 2. populates them, 591 3. potentially allocates space for the result struct, and 592 4. passes the pointers to these into the newly declared interface function, 593 then 594 5. collects the result of the call (potentially from the result struct), 595 and 596 6. returns it to the caller. 597 598For (non-external) functions defined in the MLIR module. 599 6001. Define a new function `_mlir_ciface_<original name>` where memref arguments 601 are converted to pointer-to-struct and the remaining arguments are converted 602 as usual. Results are converted to a special argument if they are of struct 603 type. 6042. Populate the body of the newly defined function with IR that 605 1. loads descriptors from pointers; 606 2. unpacks descriptor into individual non-aggregate values; 607 3. passes these values into the original function; 608 4. collects the results of the call and 609 5. either copies the results into the result struct or returns them to the 610 caller. 611 612Examples: 613 614```mlir 615 616func.func @qux(%arg0: memref<?x?xf32>) 617 618// Gets converted into the following 619// (using type alias for brevity): 620!llvm.memref_2d = !llvm.struct<(ptr<f32>, ptr<f32>, i64, array<2xi64>, array<2xi64>)> 621 622// Function with unpacked arguments. 623llvm.func @qux(%arg0: !llvm.ptr<f32>, %arg1: !llvm.ptr<f32>, 624 %arg2: i64, %arg3: i64, %arg4: i64, 625 %arg5: i64, %arg6: i64) { 626 // Populate memref descriptor (as per calling convention). 627 %0 = llvm.mlir.undef : !llvm.memref_2d 628 %1 = llvm.insertvalue %arg0, %0[0] : !llvm.memref_2d 629 %2 = llvm.insertvalue %arg1, %1[1] : !llvm.memref_2d 630 %3 = llvm.insertvalue %arg2, %2[2] : !llvm.memref_2d 631 %4 = llvm.insertvalue %arg3, %3[3, 0] : !llvm.memref_2d 632 %5 = llvm.insertvalue %arg5, %4[4, 0] : !llvm.memref_2d 633 %6 = llvm.insertvalue %arg4, %5[3, 1] : !llvm.memref_2d 634 %7 = llvm.insertvalue %arg6, %6[4, 1] : !llvm.memref_2d 635 636 // Store the descriptor in a stack-allocated space. 637 %8 = llvm.mlir.constant(1 : index) : i64 638 %9 = llvm.alloca %8 x !llvm.memref_2d 639 : (i64) -> !llvm.ptr<struct<(ptr<f32>, ptr<f32>, i64, 640 array<2xi64>, array<2xi64>)>> 641 llvm.store %7, %9 : !llvm.ptr<struct<(ptr<f32>, ptr<f32>, i64, 642 array<2xi64>, array<2xi64>)>> 643 644 // Call the interface function. 645 llvm.call @_mlir_ciface_qux(%9) 646 : (!llvm.ptr<struct<(ptr<f32>, ptr<f32>, i64, 647 array<2xi64>, array<2xi64>)>>) -> () 648 649 // The stored descriptor will be freed on return. 650 llvm.return 651} 652 653// Interface function. 654llvm.func @_mlir_ciface_qux(!llvm.ptr<struct<(ptr<f32>, ptr<f32>, i64, 655 array<2xi64>, array<2xi64>)>>) 656``` 657 658```mlir 659func.func @foo(%arg0: memref<?x?xf32>) { 660 return 661} 662 663// Gets converted into the following 664// (using type alias for brevity): 665!llvm.memref_2d = !llvm.struct<(ptr<f32>, ptr<f32>, i64, array<2xi64>, array<2xi64>)> 666!llvm.memref_2d_ptr = !llvm.ptr<struct<(ptr<f32>, ptr<f32>, i64, array<2xi64>, array<2xi64>)>> 667 668// Function with unpacked arguments. 669llvm.func @foo(%arg0: !llvm.ptr<f32>, %arg1: !llvm.ptr<f32>, 670 %arg2: i64, %arg3: i64, %arg4: i64, 671 %arg5: i64, %arg6: i64) { 672 llvm.return 673} 674 675// Interface function callable from C. 676llvm.func @_mlir_ciface_foo(%arg0: !llvm.memref_2d_ptr) { 677 // Load the descriptor. 678 %0 = llvm.load %arg0 : !llvm.memref_2d_ptr 679 680 // Unpack the descriptor as per calling convention. 681 %1 = llvm.extractvalue %0[0] : !llvm.memref_2d 682 %2 = llvm.extractvalue %0[1] : !llvm.memref_2d 683 %3 = llvm.extractvalue %0[2] : !llvm.memref_2d 684 %4 = llvm.extractvalue %0[3, 0] : !llvm.memref_2d 685 %5 = llvm.extractvalue %0[3, 1] : !llvm.memref_2d 686 %6 = llvm.extractvalue %0[4, 0] : !llvm.memref_2d 687 %7 = llvm.extractvalue %0[4, 1] : !llvm.memref_2d 688 llvm.call @foo(%1, %2, %3, %4, %5, %6, %7) 689 : (!llvm.ptr<f32>, !llvm.ptr<f32>, i64, i64, i64, 690 i64, i64) -> () 691 llvm.return 692} 693``` 694 695```mlir 696func.func @foo(%arg0: memref<?x?xf32>) -> memref<?x?xf32> { 697 return %arg0 : memref<?x?xf32> 698} 699 700// Gets converted into the following 701// (using type alias for brevity): 702!llvm.memref_2d = !llvm.struct<(ptr<f32>, ptr<f32>, i64, array<2xi64>, array<2xi64>)> 703!llvm.memref_2d_ptr = !llvm.ptr<struct<(ptr<f32>, ptr<f32>, i64, array<2xi64>, array<2xi64>)>> 704 705// Function with unpacked arguments. 706llvm.func @foo(%arg0: !llvm.ptr<f32>, %arg1: !llvm.ptr<f32>, %arg2: i64, 707 %arg3: i64, %arg4: i64, %arg5: i64, %arg6: i64) 708 -> !llvm.memref_2d { 709 %0 = llvm.mlir.undef : !llvm.memref_2d 710 %1 = llvm.insertvalue %arg0, %0[0] : !llvm.memref_2d 711 %2 = llvm.insertvalue %arg1, %1[1] : !llvm.memref_2d 712 %3 = llvm.insertvalue %arg2, %2[2] : !llvm.memref_2d 713 %4 = llvm.insertvalue %arg3, %3[3, 0] : !llvm.memref_2d 714 %5 = llvm.insertvalue %arg5, %4[4, 0] : !llvm.memref_2d 715 %6 = llvm.insertvalue %arg4, %5[3, 1] : !llvm.memref_2d 716 %7 = llvm.insertvalue %arg6, %6[4, 1] : !llvm.memref_2d 717 llvm.return %7 : !llvm.memref_2d 718} 719 720// Interface function callable from C. 721llvm.func @_mlir_ciface_foo(%arg0: !llvm.memref_2d_ptr, %arg1: !llvm.memref_2d_ptr) { 722 %0 = llvm.load %arg1 : !llvm.memref_2d_ptr 723 %1 = llvm.extractvalue %0[0] : !llvm.memref_2d 724 %2 = llvm.extractvalue %0[1] : !llvm.memref_2d 725 %3 = llvm.extractvalue %0[2] : !llvm.memref_2d 726 %4 = llvm.extractvalue %0[3, 0] : !llvm.memref_2d 727 %5 = llvm.extractvalue %0[3, 1] : !llvm.memref_2d 728 %6 = llvm.extractvalue %0[4, 0] : !llvm.memref_2d 729 %7 = llvm.extractvalue %0[4, 1] : !llvm.memref_2d 730 %8 = llvm.call @foo(%1, %2, %3, %4, %5, %6, %7) 731 : (!llvm.ptr<f32>, !llvm.ptr<f32>, i64, i64, i64, i64, i64) -> !llvm.memref_2d 732 llvm.store %8, %arg0 : !llvm.memref_2d_ptr 733 llvm.return 734} 735``` 736 737Rationale: Introducing auxiliary functions for C-compatible interfaces is 738preferred to modifying the calling convention since it will minimize the effect 739of C compatibility on intra-module calls or calls between MLIR-generated 740functions. In particular, when calling external functions from an MLIR module in 741a (parallel) loop, the fact of storing a memref descriptor on stack can lead to 742stack exhaustion and/or concurrent access to the same address. Auxiliary 743interface function serves as an allocation scope in this case. Furthermore, when 744targeting accelerators with separate memory spaces such as GPUs, stack-allocated 745descriptors passed by pointer would have to be transferred to the device memory, 746which introduces significant overhead. In such situations, auxiliary interface 747functions are executed on host and only pass the values through device function 748invocation mechanism. 749 750### Address Computation 751 752Accesses to a memref element are transformed into an access to an element of the 753buffer pointed to by the descriptor. The position of the element in the buffer 754is calculated by linearizing memref indices in row-major order (lexically first 755index is the slowest varying, similar to C, but accounting for strides). The 756computation of the linear address is emitted as arithmetic operation in the LLVM 757IR dialect. Strides are extracted from the memref descriptor. 758 759Examples: 760 761An access to a memref with indices: 762 763```mlir 764%0 = memref.load %m[%1,%2,%3,%4] : memref<?x?x4x8xf32, offset: ?> 765``` 766 767is transformed into the equivalent of the following code: 768 769```mlir 770// Compute the linearized index from strides. 771// When strides or, in absence of explicit strides, the corresponding sizes are 772// dynamic, extract the stride value from the descriptor. 773%stride1 = llvm.extractvalue[4, 0] : !llvm.struct<(ptr<f32>, ptr<f32>, i64, 774 array<4xi64>, array<4xi64>)> 775%addr1 = arith.muli %stride1, %1 : i64 776 777// When the stride or, in absence of explicit strides, the trailing sizes are 778// known statically, this value is used as a constant. The natural value of 779// strides is the product of all sizes following the current dimension. 780%stride2 = llvm.mlir.constant(32 : index) : i64 781%addr2 = arith.muli %stride2, %2 : i64 782%addr3 = arith.addi %addr1, %addr2 : i64 783 784%stride3 = llvm.mlir.constant(8 : index) : i64 785%addr4 = arith.muli %stride3, %3 : i64 786%addr5 = arith.addi %addr3, %addr4 : i64 787 788// Multiplication with the known unit stride can be omitted. 789%addr6 = arith.addi %addr5, %4 : i64 790 791// If the linear offset is known to be zero, it can also be omitted. If it is 792// dynamic, it is extracted from the descriptor. 793%offset = llvm.extractvalue[2] : !llvm.struct<(ptr<f32>, ptr<f32>, i64, 794 array<4xi64>, array<4xi64>)> 795%addr7 = arith.addi %addr6, %offset : i64 796 797// All accesses are based on the aligned pointer. 798%aligned = llvm.extractvalue[1] : !llvm.struct<(ptr<f32>, ptr<f32>, i64, 799 array<4xi64>, array<4xi64>)> 800 801// Get the address of the data pointer. 802%ptr = llvm.getelementptr %aligned[%addr8] 803 : !llvm.struct<(ptr<f32>, ptr<f32>, i64, array<4xi64>, array<4xi64>)> 804 -> !llvm.ptr<f32> 805 806// Perform the actual load. 807%0 = llvm.load %ptr : !llvm.ptr<f32> 808``` 809 810For stores, the address computation code is identical and only the actual store 811operation is different. 812 813Note: the conversion does not perform any sort of common subexpression 814elimination when emitting memref accesses. 815 816### Utility Classes 817 818Utility classes common to many conversions to the LLVM dialect can be found 819under `lib/Conversion/LLVMCommon`. They include the following. 820 821- `LLVMConversionTarget` specifies all LLVM dialect operations as legal. 822- `LLVMTypeConverter` implements the default type conversion as described 823 above. 824- `ConvertOpToLLVMPattern` extends the conversion pattern class with LLVM 825 dialect-specific functionality. 826- `VectorConvertOpToLLVMPattern` extends the previous class to automatically 827 unroll operations on higher-dimensional vectors into lists of operations on 828 one-dimensional vectors before. 829- `StructBuilder` provides a convenient API for building IR that creates or 830 accesses values of LLVM dialect structure types; it is derived by 831 `MemRefDescriptor`, `UrankedMemrefDescriptor` and `ComplexBuilder` for the 832 built-in types convertible to LLVM dialect structure types. 833 834## Translation to LLVM IR 835 836MLIR modules containing `llvm.func`, `llvm.mlir.global` and `llvm.metadata` 837operations can be translated to LLVM IR modules using the following scheme. 838 839- Module-level globals are translated to LLVM IR global values. 840- Module-level metadata are translated to LLVM IR metadata, which can be later 841 augmented with additional metadata defined on specific ops. 842- All functions are declared in the module so that they can be referenced. 843- Each function is then translated separately and has access to the complete 844 mappings between MLIR and LLVM IR globals, metadata, and functions. 845- Within a function, blocks are traversed in topological order and translated 846 to LLVM IR basic blocks. In each basic block, PHI nodes are created for each 847 of the block arguments, but not connected to their source blocks. 848- Within each block, operations are translated in their order. Each operation 849 has access to the same mappings as the function and additionally to the 850 mapping of values between MLIR and LLVM IR, including PHI nodes. Operations 851 with regions are responsible for translated the regions they contain. 852- After operations in a function are translated, the PHI nodes of blocks in 853 this function are connected to their source values, which are now available. 854 855The translation mechanism provides extension hooks for translating custom 856operations to LLVM IR via a dialect interface `LLVMTranslationDialectInterface`: 857 858- `convertOperation` translates an operation that belongs to the current 859 dialect to LLVM IR given an `IRBuilderBase` and various mappings; 860- `amendOperation` performs additional actions on an operation if it contains 861 a dialect attribute that belongs to the current dialect, for example sets up 862 instruction-level metadata. 863 864Dialects containing operations or attributes that want to be translated to LLVM 865IR must provide an implementation of this interface and register it with the 866system. Note that registration may happen without creating the dialect, for 867example, in a separate library to avoid the need for the "main" dialect library 868to depend on LLVM IR libraries. The implementations of these methods may used 869the 870[`ModuleTranslation`](https://mlir.llvm.org/doxygen/classmlir_1_1LLVM_1_1ModuleTranslation.html) 871object provided to them which holds the state of the translation and contains 872numerous utilities. 873 874Note that this extension mechanism is *intentionally restrictive*. LLVM IR has a 875small, relatively stable set of instructions and types that MLIR intends to 876model fully. Therefore, the extension mechanism is provided only for LLVM IR 877constructs that are more often extended -- intrinsics and metadata. The primary 878goal of the extension mechanism is to support sets of intrinsics, for example 879those representing a particular instruction set. The extension mechanism does 880not allow for customizing type or block translation, nor does it support custom 881module-level operations. Such transformations should be performed within MLIR 882and target the corresponding MLIR constructs. 883 884## Translation from LLVM IR 885 886An experimental flow allows one to import a substantially limited subset of LLVM 887IR into MLIR, producing LLVM dialect operations. 888 889``` 890 mlir-translate -import-llvm filename.ll 891``` 892