Alex Zinenko 2ab57c503e [mlir] tighten LLVM dialect verifiers to generate valid LLVM IR
Verification of the LLVM IR produced when translating various MLIR dialects was
only active when calling the translation programmatically. This has led to
several cases of invalid LLVM IR being generated that could not be caught with
textual mlir-translate tests. Add verifiers for these cases and fix the tests
in preparation for enforcing the validation of LLVM IR.

Reviewed By: nicolasvasilache

Differential Revision: https://reviews.llvm.org/D96774
2021-02-16 18:18:21 +01:00

1472 lines
57 KiB
MLIR

// RUN: mlir-translate -mlir-to-llvmir -split-input-file %s | FileCheck %s
// CHECK: @i32_global = internal global i32 42
llvm.mlir.global internal @i32_global(42: i32) : i32
// CHECK: @i32_const = internal constant i53 52
llvm.mlir.global internal constant @i32_const(52: i53) : i53
// CHECK: @int_global_array = internal global [3 x i32] [i32 62, i32 62, i32 62]
llvm.mlir.global internal @int_global_array(dense<62> : vector<3xi32>) : !llvm.array<3 x i32>
// CHECK: @i32_global_addr_space = internal addrspace(7) global i32 62
llvm.mlir.global internal @i32_global_addr_space(62: i32) {addr_space = 7 : i32} : i32
// CHECK: @float_global = internal global float 0.000000e+00
llvm.mlir.global internal @float_global(0.0: f32) : f32
// CHECK: @float_global_array = internal global [1 x float] [float -5.000000e+00]
llvm.mlir.global internal @float_global_array(dense<[-5.0]> : vector<1xf32>) : !llvm.array<1 x f32>
// CHECK: @string_const = internal constant [6 x i8] c"foobar"
llvm.mlir.global internal constant @string_const("foobar") : !llvm.array<6 x i8>
// CHECK: @int_global_undef = internal global i64 undef
llvm.mlir.global internal @int_global_undef() : i64
// CHECK: @int_gep = internal constant i32* getelementptr (i32, i32* @i32_global, i32 2)
llvm.mlir.global internal constant @int_gep() : !llvm.ptr<i32> {
%addr = llvm.mlir.addressof @i32_global : !llvm.ptr<i32>
%_c0 = llvm.mlir.constant(2: i32) :i32
%gepinit = llvm.getelementptr %addr[%_c0] : (!llvm.ptr<i32>, i32) -> !llvm.ptr<i32>
llvm.return %gepinit : !llvm.ptr<i32>
}
//
// Linkage attribute.
//
// CHECK: @private = private global i32 42
llvm.mlir.global private @private(42 : i32) : i32
// CHECK: @internal = internal global i32 42
llvm.mlir.global internal @internal(42 : i32) : i32
// CHECK: @available_externally = available_externally global i32 42
llvm.mlir.global available_externally @available_externally(42 : i32) : i32
// CHECK: @linkonce = linkonce global i32 42
llvm.mlir.global linkonce @linkonce(42 : i32) : i32
// CHECK: @weak = weak global i32 42
llvm.mlir.global weak @weak(42 : i32) : i32
// CHECK: @common = common global i32 0
llvm.mlir.global common @common(0 : i32) : i32
// CHECK: @appending = appending global [3 x i32] [i32 1, i32 2, i32 3]
llvm.mlir.global appending @appending(dense<[1,2,3]> : vector<3xi32>) : !llvm.array<3xi32>
// CHECK: @extern_weak = extern_weak global i32
llvm.mlir.global extern_weak @extern_weak() : i32
// CHECK: @linkonce_odr = linkonce_odr global i32 42
llvm.mlir.global linkonce_odr @linkonce_odr(42 : i32) : i32
// CHECK: @weak_odr = weak_odr global i32 42
llvm.mlir.global weak_odr @weak_odr(42 : i32) : i32
// CHECK: @external = external global i32
llvm.mlir.global external @external() : i32
//
// Declarations of the allocation functions to be linked against. These are
// inserted before other functions in the module.
//
// CHECK: declare i8* @malloc(i64)
llvm.func @malloc(i64) -> !llvm.ptr<i8>
// CHECK: declare void @free(i8*)
//
// Basic functionality: function and block conversion, function calls,
// phi nodes, scalar type conversion, arithmetic operations.
//
// CHECK-LABEL: define void @empty()
// CHECK-NEXT: ret void
// CHECK-NEXT: }
llvm.func @empty() {
llvm.return
}
// CHECK-LABEL: @global_refs
llvm.func @global_refs() {
// Check load from globals.
// CHECK: load i32, i32* @i32_global
%0 = llvm.mlir.addressof @i32_global : !llvm.ptr<i32>
%1 = llvm.load %0 : !llvm.ptr<i32>
// Check the contracted form of load from array constants.
// CHECK: load i8, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @string_const, i64 0, i64 0)
%2 = llvm.mlir.addressof @string_const : !llvm.ptr<array<6 x i8>>
%c0 = llvm.mlir.constant(0 : index) : i64
%3 = llvm.getelementptr %2[%c0, %c0] : (!llvm.ptr<array<6 x i8>>, i64, i64) -> !llvm.ptr<i8>
%4 = llvm.load %3 : !llvm.ptr<i8>
llvm.return
}
// CHECK-LABEL: declare void @body(i64)
llvm.func @body(i64)
// CHECK-LABEL: define void @simple_loop()
llvm.func @simple_loop() {
// CHECK: br label %[[SIMPLE_bb1:[0-9]+]]
llvm.br ^bb1
// Constants are inlined in LLVM rather than a separate instruction.
// CHECK: [[SIMPLE_bb1]]:
// CHECK-NEXT: br label %[[SIMPLE_bb2:[0-9]+]]
^bb1: // pred: ^bb0
%0 = llvm.mlir.constant(1 : index) : i64
%1 = llvm.mlir.constant(42 : index) : i64
llvm.br ^bb2(%0 : i64)
// CHECK: [[SIMPLE_bb2]]:
// CHECK-NEXT: %{{[0-9]+}} = phi i64 [ %{{[0-9]+}}, %[[SIMPLE_bb3:[0-9]+]] ], [ 1, %[[SIMPLE_bb1]] ]
// CHECK-NEXT: %{{[0-9]+}} = icmp slt i64 %{{[0-9]+}}, 42
// CHECK-NEXT: br i1 %{{[0-9]+}}, label %[[SIMPLE_bb3]], label %[[SIMPLE_bb4:[0-9]+]]
^bb2(%2: i64): // 2 preds: ^bb1, ^bb3
%3 = llvm.icmp "slt" %2, %1 : i64
llvm.cond_br %3, ^bb3, ^bb4
// CHECK: [[SIMPLE_bb3]]:
// CHECK-NEXT: call void @body(i64 %{{[0-9]+}})
// CHECK-NEXT: %{{[0-9]+}} = add i64 %{{[0-9]+}}, 1
// CHECK-NEXT: br label %[[SIMPLE_bb2]]
^bb3: // pred: ^bb2
llvm.call @body(%2) : (i64) -> ()
%4 = llvm.mlir.constant(1 : index) : i64
%5 = llvm.add %2, %4 : i64
llvm.br ^bb2(%5 : i64)
// CHECK: [[SIMPLE_bb4]]:
// CHECK-NEXT: ret void
^bb4: // pred: ^bb2
llvm.return
}
// CHECK-LABEL: define void @simple_caller()
// CHECK-NEXT: call void @simple_loop()
// CHECK-NEXT: ret void
// CHECK-NEXT: }
llvm.func @simple_caller() {
llvm.call @simple_loop() : () -> ()
llvm.return
}
//func @simple_indirect_caller() {
//^bb0:
// %f = constant @simple_loop : () -> ()
// call_indirect %f() : () -> ()
// return
//}
// CHECK-LABEL: define void @ml_caller()
// CHECK-NEXT: call void @simple_loop()
// CHECK-NEXT: call void @more_imperfectly_nested_loops()
// CHECK-NEXT: ret void
// CHECK-NEXT: }
llvm.func @ml_caller() {
llvm.call @simple_loop() : () -> ()
llvm.call @more_imperfectly_nested_loops() : () -> ()
llvm.return
}
// CHECK-LABEL: declare i64 @body_args(i64)
llvm.func @body_args(i64) -> i64
// CHECK-LABEL: declare i32 @other(i64, i32)
llvm.func @other(i64, i32) -> i32
// CHECK-LABEL: define i32 @func_args(i32 {{%.*}}, i32 {{%.*}})
// CHECK-NEXT: br label %[[ARGS_bb1:[0-9]+]]
llvm.func @func_args(%arg0: i32, %arg1: i32) -> i32 {
%0 = llvm.mlir.constant(0 : i32) : i32
llvm.br ^bb1
// CHECK: [[ARGS_bb1]]:
// CHECK-NEXT: br label %[[ARGS_bb2:[0-9]+]]
^bb1: // pred: ^bb0
%1 = llvm.mlir.constant(0 : index) : i64
%2 = llvm.mlir.constant(42 : index) : i64
llvm.br ^bb2(%1 : i64)
// CHECK: [[ARGS_bb2]]:
// CHECK-NEXT: %5 = phi i64 [ %12, %[[ARGS_bb3:[0-9]+]] ], [ 0, %[[ARGS_bb1]] ]
// CHECK-NEXT: %6 = icmp slt i64 %5, 42
// CHECK-NEXT: br i1 %6, label %[[ARGS_bb3]], label %[[ARGS_bb4:[0-9]+]]
^bb2(%3: i64): // 2 preds: ^bb1, ^bb3
%4 = llvm.icmp "slt" %3, %2 : i64
llvm.cond_br %4, ^bb3, ^bb4
// CHECK: [[ARGS_bb3]]:
// CHECK-NEXT: %8 = call i64 @body_args(i64 %5)
// CHECK-NEXT: %9 = call i32 @other(i64 %8, i32 %0)
// CHECK-NEXT: %10 = call i32 @other(i64 %8, i32 %9)
// CHECK-NEXT: %11 = call i32 @other(i64 %8, i32 %1)
// CHECK-NEXT: %12 = add i64 %5, 1
// CHECK-NEXT: br label %[[ARGS_bb2]]
^bb3: // pred: ^bb2
%5 = llvm.call @body_args(%3) : (i64) -> i64
%6 = llvm.call @other(%5, %arg0) : (i64, i32) -> i32
%7 = llvm.call @other(%5, %6) : (i64, i32) -> i32
%8 = llvm.call @other(%5, %arg1) : (i64, i32) -> i32
%9 = llvm.mlir.constant(1 : index) : i64
%10 = llvm.add %3, %9 : i64
llvm.br ^bb2(%10 : i64)
// CHECK: [[ARGS_bb4]]:
// CHECK-NEXT: %14 = call i32 @other(i64 0, i32 0)
// CHECK-NEXT: ret i32 %14
^bb4: // pred: ^bb2
%11 = llvm.mlir.constant(0 : index) : i64
%12 = llvm.call @other(%11, %0) : (i64, i32) -> i32
llvm.return %12 : i32
}
// CHECK: declare void @pre(i64)
llvm.func @pre(i64)
// CHECK: declare void @body2(i64, i64)
llvm.func @body2(i64, i64)
// CHECK: declare void @post(i64)
llvm.func @post(i64)
// CHECK-LABEL: define void @imperfectly_nested_loops()
// CHECK-NEXT: br label %[[IMPER_bb1:[0-9]+]]
llvm.func @imperfectly_nested_loops() {
llvm.br ^bb1
// CHECK: [[IMPER_bb1]]:
// CHECK-NEXT: br label %[[IMPER_bb2:[0-9]+]]
^bb1: // pred: ^bb0
%0 = llvm.mlir.constant(0 : index) : i64
%1 = llvm.mlir.constant(42 : index) : i64
llvm.br ^bb2(%0 : i64)
// CHECK: [[IMPER_bb2]]:
// CHECK-NEXT: %3 = phi i64 [ %13, %[[IMPER_bb7:[0-9]+]] ], [ 0, %[[IMPER_bb1]] ]
// CHECK-NEXT: %4 = icmp slt i64 %3, 42
// CHECK-NEXT: br i1 %4, label %[[IMPER_bb3:[0-9]+]], label %[[IMPER_bb8:[0-9]+]]
^bb2(%2: i64): // 2 preds: ^bb1, ^bb7
%3 = llvm.icmp "slt" %2, %1 : i64
llvm.cond_br %3, ^bb3, ^bb8
// CHECK: [[IMPER_bb3]]:
// CHECK-NEXT: call void @pre(i64 %3)
// CHECK-NEXT: br label %[[IMPER_bb4:[0-9]+]]
^bb3: // pred: ^bb2
llvm.call @pre(%2) : (i64) -> ()
llvm.br ^bb4
// CHECK: [[IMPER_bb4]]:
// CHECK-NEXT: br label %[[IMPER_bb5:[0-9]+]]
^bb4: // pred: ^bb3
%4 = llvm.mlir.constant(7 : index) : i64
%5 = llvm.mlir.constant(56 : index) : i64
llvm.br ^bb5(%4 : i64)
// CHECK: [[IMPER_bb5]]:
// CHECK-NEXT: %8 = phi i64 [ %11, %[[IMPER_bb6:[0-9]+]] ], [ 7, %[[IMPER_bb4]] ]
// CHECK-NEXT: %9 = icmp slt i64 %8, 56
// CHECK-NEXT: br i1 %9, label %[[IMPER_bb6]], label %[[IMPER_bb7]]
^bb5(%6: i64): // 2 preds: ^bb4, ^bb6
%7 = llvm.icmp "slt" %6, %5 : i64
llvm.cond_br %7, ^bb6, ^bb7
// CHECK: [[IMPER_bb6]]:
// CHECK-NEXT: call void @body2(i64 %3, i64 %8)
// CHECK-NEXT: %11 = add i64 %8, 2
// CHECK-NEXT: br label %[[IMPER_bb5]]
^bb6: // pred: ^bb5
llvm.call @body2(%2, %6) : (i64, i64) -> ()
%8 = llvm.mlir.constant(2 : index) : i64
%9 = llvm.add %6, %8 : i64
llvm.br ^bb5(%9 : i64)
// CHECK: [[IMPER_bb7]]:
// CHECK-NEXT: call void @post(i64 %3)
// CHECK-NEXT: %13 = add i64 %3, 1
// CHECK-NEXT: br label %[[IMPER_bb2]]
^bb7: // pred: ^bb5
llvm.call @post(%2) : (i64) -> ()
%10 = llvm.mlir.constant(1 : index) : i64
%11 = llvm.add %2, %10 : i64
llvm.br ^bb2(%11 : i64)
// CHECK: [[IMPER_bb8]]:
// CHECK-NEXT: ret void
^bb8: // pred: ^bb2
llvm.return
}
// CHECK: declare void @mid(i64)
llvm.func @mid(i64)
// CHECK: declare void @body3(i64, i64)
llvm.func @body3(i64, i64)
// A complete function transformation check.
// CHECK-LABEL: define void @more_imperfectly_nested_loops()
// CHECK-NEXT: br label %1
// CHECK: 1: ; preds = %0
// CHECK-NEXT: br label %2
// CHECK: 2: ; preds = %19, %1
// CHECK-NEXT: %3 = phi i64 [ %20, %19 ], [ 0, %1 ]
// CHECK-NEXT: %4 = icmp slt i64 %3, 42
// CHECK-NEXT: br i1 %4, label %5, label %21
// CHECK: 5: ; preds = %2
// CHECK-NEXT: call void @pre(i64 %3)
// CHECK-NEXT: br label %6
// CHECK: 6: ; preds = %5
// CHECK-NEXT: br label %7
// CHECK: 7: ; preds = %10, %6
// CHECK-NEXT: %8 = phi i64 [ %11, %10 ], [ 7, %6 ]
// CHECK-NEXT: %9 = icmp slt i64 %8, 56
// CHECK-NEXT: br i1 %9, label %10, label %12
// CHECK: 10: ; preds = %7
// CHECK-NEXT: call void @body2(i64 %3, i64 %8)
// CHECK-NEXT: %11 = add i64 %8, 2
// CHECK-NEXT: br label %7
// CHECK: 12: ; preds = %7
// CHECK-NEXT: call void @mid(i64 %3)
// CHECK-NEXT: br label %13
// CHECK: 13: ; preds = %12
// CHECK-NEXT: br label %14
// CHECK: 14: ; preds = %17, %13
// CHECK-NEXT: %15 = phi i64 [ %18, %17 ], [ 18, %13 ]
// CHECK-NEXT: %16 = icmp slt i64 %15, 37
// CHECK-NEXT: br i1 %16, label %17, label %19
// CHECK: 17: ; preds = %14
// CHECK-NEXT: call void @body3(i64 %3, i64 %15)
// CHECK-NEXT: %18 = add i64 %15, 3
// CHECK-NEXT: br label %14
// CHECK: 19: ; preds = %14
// CHECK-NEXT: call void @post(i64 %3)
// CHECK-NEXT: %20 = add i64 %3, 1
// CHECK-NEXT: br label %2
// CHECK: 21: ; preds = %2
// CHECK-NEXT: ret void
// CHECK-NEXT: }
llvm.func @more_imperfectly_nested_loops() {
llvm.br ^bb1
^bb1: // pred: ^bb0
%0 = llvm.mlir.constant(0 : index) : i64
%1 = llvm.mlir.constant(42 : index) : i64
llvm.br ^bb2(%0 : i64)
^bb2(%2: i64): // 2 preds: ^bb1, ^bb11
%3 = llvm.icmp "slt" %2, %1 : i64
llvm.cond_br %3, ^bb3, ^bb12
^bb3: // pred: ^bb2
llvm.call @pre(%2) : (i64) -> ()
llvm.br ^bb4
^bb4: // pred: ^bb3
%4 = llvm.mlir.constant(7 : index) : i64
%5 = llvm.mlir.constant(56 : index) : i64
llvm.br ^bb5(%4 : i64)
^bb5(%6: i64): // 2 preds: ^bb4, ^bb6
%7 = llvm.icmp "slt" %6, %5 : i64
llvm.cond_br %7, ^bb6, ^bb7
^bb6: // pred: ^bb5
llvm.call @body2(%2, %6) : (i64, i64) -> ()
%8 = llvm.mlir.constant(2 : index) : i64
%9 = llvm.add %6, %8 : i64
llvm.br ^bb5(%9 : i64)
^bb7: // pred: ^bb5
llvm.call @mid(%2) : (i64) -> ()
llvm.br ^bb8
^bb8: // pred: ^bb7
%10 = llvm.mlir.constant(18 : index) : i64
%11 = llvm.mlir.constant(37 : index) : i64
llvm.br ^bb9(%10 : i64)
^bb9(%12: i64): // 2 preds: ^bb8, ^bb10
%13 = llvm.icmp "slt" %12, %11 : i64
llvm.cond_br %13, ^bb10, ^bb11
^bb10: // pred: ^bb9
llvm.call @body3(%2, %12) : (i64, i64) -> ()
%14 = llvm.mlir.constant(3 : index) : i64
%15 = llvm.add %12, %14 : i64
llvm.br ^bb9(%15 : i64)
^bb11: // pred: ^bb9
llvm.call @post(%2) : (i64) -> ()
%16 = llvm.mlir.constant(1 : index) : i64
%17 = llvm.add %2, %16 : i64
llvm.br ^bb2(%17 : i64)
^bb12: // pred: ^bb2
llvm.return
}
//
// Check that linkage is translated for functions. No need to check all linkage
// flags since the logic is the same as for globals.
//
// CHECK: define internal void @func_internal
llvm.func internal @func_internal() {
llvm.return
}
//
// MemRef type conversion, allocation and communication with functions.
//
// CHECK-LABEL: define void @memref_alloc()
llvm.func @memref_alloc() {
// CHECK-NEXT: %{{[0-9]+}} = call i8* @malloc(i64 400)
// CHECK-NEXT: %{{[0-9]+}} = bitcast i8* %{{[0-9]+}} to float*
// CHECK-NEXT: %{{[0-9]+}} = insertvalue { float* } undef, float* %{{[0-9]+}}, 0
%0 = llvm.mlir.constant(10 : index) : i64
%1 = llvm.mlir.constant(10 : index) : i64
%2 = llvm.mul %0, %1 : i64
%3 = llvm.mlir.undef : !llvm.struct<(ptr<f32>)>
%4 = llvm.mlir.constant(4 : index) : i64
%5 = llvm.mul %2, %4 : i64
%6 = llvm.call @malloc(%5) : (i64) -> !llvm.ptr<i8>
%7 = llvm.bitcast %6 : !llvm.ptr<i8> to !llvm.ptr<f32>
%8 = llvm.insertvalue %7, %3[0] : !llvm.struct<(ptr<f32>)>
// CHECK-NEXT: ret void
llvm.return
}
// CHECK-LABEL: declare i64 @get_index()
llvm.func @get_index() -> i64
// CHECK-LABEL: define void @store_load_static()
llvm.func @store_load_static() {
^bb0:
// CHECK-NEXT: %{{[0-9]+}} = call i8* @malloc(i64 40)
// CHECK-NEXT: %{{[0-9]+}} = bitcast i8* %{{[0-9]+}} to float*
// CHECK-NEXT: %{{[0-9]+}} = insertvalue { float* } undef, float* %{{[0-9]+}}, 0
%0 = llvm.mlir.constant(10 : index) : i64
%1 = llvm.mlir.undef : !llvm.struct<(ptr<f32>)>
%2 = llvm.mlir.constant(4 : index) : i64
%3 = llvm.mul %0, %2 : i64
%4 = llvm.call @malloc(%3) : (i64) -> !llvm.ptr<i8>
%5 = llvm.bitcast %4 : !llvm.ptr<i8> to !llvm.ptr<f32>
%6 = llvm.insertvalue %5, %1[0] : !llvm.struct<(ptr<f32>)>
%7 = llvm.mlir.constant(1.000000e+00 : f32) : f32
llvm.br ^bb1
^bb1: // pred: ^bb0
%8 = llvm.mlir.constant(0 : index) : i64
%9 = llvm.mlir.constant(10 : index) : i64
llvm.br ^bb2(%8 : i64)
// CHECK: %{{[0-9]+}} = phi i64 [ %{{[0-9]+}}, %{{[0-9]+}} ], [ 0, %{{[0-9]+}} ]
^bb2(%10: i64): // 2 preds: ^bb1, ^bb3
// CHECK-NEXT: %{{[0-9]+}} = icmp slt i64 %{{[0-9]+}}, 10
%11 = llvm.icmp "slt" %10, %9 : i64
// CHECK-NEXT: br i1 %{{[0-9]+}}, label %{{[0-9]+}}, label %{{[0-9]+}}
llvm.cond_br %11, ^bb3, ^bb4
^bb3: // pred: ^bb2
// CHECK: %{{[0-9]+}} = extractvalue { float* } %{{[0-9]+}}, 0
// CHECK-NEXT: %{{[0-9]+}} = getelementptr float, float* %{{[0-9]+}}, i64 %{{[0-9]+}}
// CHECK-NEXT: store float 1.000000e+00, float* %{{[0-9]+}}
%12 = llvm.mlir.constant(10 : index) : i64
%13 = llvm.extractvalue %6[0] : !llvm.struct<(ptr<f32>)>
%14 = llvm.getelementptr %13[%10] : (!llvm.ptr<f32>, i64) -> !llvm.ptr<f32>
llvm.store %7, %14 : !llvm.ptr<f32>
%15 = llvm.mlir.constant(1 : index) : i64
// CHECK-NEXT: %{{[0-9]+}} = add i64 %{{[0-9]+}}, 1
%16 = llvm.add %10, %15 : i64
// CHECK-NEXT: br label %{{[0-9]+}}
llvm.br ^bb2(%16 : i64)
^bb4: // pred: ^bb2
llvm.br ^bb5
^bb5: // pred: ^bb4
%17 = llvm.mlir.constant(0 : index) : i64
%18 = llvm.mlir.constant(10 : index) : i64
llvm.br ^bb6(%17 : i64)
// CHECK: %{{[0-9]+}} = phi i64 [ %{{[0-9]+}}, %{{[0-9]+}} ], [ 0, %{{[0-9]+}} ]
^bb6(%19: i64): // 2 preds: ^bb5, ^bb7
// CHECK-NEXT: %{{[0-9]+}} = icmp slt i64 %{{[0-9]+}}, 10
%20 = llvm.icmp "slt" %19, %18 : i64
// CHECK-NEXT: br i1 %{{[0-9]+}}, label %{{[0-9]+}}, label %{{[0-9]+}}
llvm.cond_br %20, ^bb7, ^bb8
^bb7: // pred: ^bb6
// CHECK: %{{[0-9]+}} = extractvalue { float* } %{{[0-9]+}}, 0
// CHECK-NEXT: %{{[0-9]+}} = getelementptr float, float* %{{[0-9]+}}, i64 %{{[0-9]+}}
// CHECK-NEXT: %{{[0-9]+}} = load float, float* %{{[0-9]+}}
%21 = llvm.mlir.constant(10 : index) : i64
%22 = llvm.extractvalue %6[0] : !llvm.struct<(ptr<f32>)>
%23 = llvm.getelementptr %22[%19] : (!llvm.ptr<f32>, i64) -> !llvm.ptr<f32>
%24 = llvm.load %23 : !llvm.ptr<f32>
%25 = llvm.mlir.constant(1 : index) : i64
// CHECK-NEXT: %{{[0-9]+}} = add i64 %{{[0-9]+}}, 1
%26 = llvm.add %19, %25 : i64
// CHECK-NEXT: br label %{{[0-9]+}}
llvm.br ^bb6(%26 : i64)
^bb8: // pred: ^bb6
// CHECK: ret void
llvm.return
}
// CHECK-LABEL: define void @store_load_dynamic(i64 {{%.*}})
llvm.func @store_load_dynamic(%arg0: i64) {
// CHECK-NEXT: %{{[0-9]+}} = mul i64 %{{[0-9]+}}, 4
// CHECK-NEXT: %{{[0-9]+}} = call i8* @malloc(i64 %{{[0-9]+}})
// CHECK-NEXT: %{{[0-9]+}} = bitcast i8* %{{[0-9]+}} to float*
// CHECK-NEXT: %{{[0-9]+}} = insertvalue { float*, i64 } undef, float* %{{[0-9]+}}, 0
// CHECK-NEXT: %{{[0-9]+}} = insertvalue { float*, i64 } %{{[0-9]+}}, i64 %{{[0-9]+}}, 1
%0 = llvm.mlir.undef : !llvm.struct<(ptr<f32>, i64)>
%1 = llvm.mlir.constant(4 : index) : i64
%2 = llvm.mul %arg0, %1 : i64
%3 = llvm.call @malloc(%2) : (i64) -> !llvm.ptr<i8>
%4 = llvm.bitcast %3 : !llvm.ptr<i8> to !llvm.ptr<f32>
%5 = llvm.insertvalue %4, %0[0] : !llvm.struct<(ptr<f32>, i64)>
%6 = llvm.insertvalue %arg0, %5[1] : !llvm.struct<(ptr<f32>, i64)>
%7 = llvm.mlir.constant(1.000000e+00 : f32) : f32
// CHECK-NEXT: br label %{{[0-9]+}}
llvm.br ^bb1
^bb1: // pred: ^bb0
%8 = llvm.mlir.constant(0 : index) : i64
llvm.br ^bb2(%8 : i64)
// CHECK: %{{[0-9]+}} = phi i64 [ %{{[0-9]+}}, %{{[0-9]+}} ], [ 0, %{{[0-9]+}} ]
^bb2(%9: i64): // 2 preds: ^bb1, ^bb3
// CHECK-NEXT: %{{[0-9]+}} = icmp slt i64 %{{[0-9]+}}, %{{[0-9]+}}
%10 = llvm.icmp "slt" %9, %arg0 : i64
// CHECK-NEXT: br i1 %{{[0-9]+}}, label %{{[0-9]+}}, label %{{[0-9]+}}
llvm.cond_br %10, ^bb3, ^bb4
^bb3: // pred: ^bb2
// CHECK: %{{[0-9]+}} = extractvalue { float*, i64 } %{{[0-9]+}}, 1
// CHECK-NEXT: %{{[0-9]+}} = extractvalue { float*, i64 } %{{[0-9]+}}, 0
// CHECK-NEXT: %{{[0-9]+}} = getelementptr float, float* %{{[0-9]+}}, i64 %{{[0-9]+}}
// CHECK-NEXT: store float 1.000000e+00, float* %{{[0-9]+}}
%11 = llvm.extractvalue %6[1] : !llvm.struct<(ptr<f32>, i64)>
%12 = llvm.extractvalue %6[0] : !llvm.struct<(ptr<f32>, i64)>
%13 = llvm.getelementptr %12[%9] : (!llvm.ptr<f32>, i64) -> !llvm.ptr<f32>
llvm.store %7, %13 : !llvm.ptr<f32>
%14 = llvm.mlir.constant(1 : index) : i64
// CHECK-NEXT: %{{[0-9]+}} = add i64 %{{[0-9]+}}, 1
%15 = llvm.add %9, %14 : i64
// CHECK-NEXT: br label %{{[0-9]+}}
llvm.br ^bb2(%15 : i64)
^bb4: // pred: ^bb3
llvm.br ^bb5
^bb5: // pred: ^bb4
%16 = llvm.mlir.constant(0 : index) : i64
llvm.br ^bb6(%16 : i64)
// CHECK: %{{[0-9]+}} = phi i64 [ %{{[0-9]+}}, %{{[0-9]+}} ], [ 0, %{{[0-9]+}} ]
^bb6(%17: i64): // 2 preds: ^bb5, ^bb7
// CHECK-NEXT: %{{[0-9]+}} = icmp slt i64 %{{[0-9]+}}, %{{[0-9]+}}
%18 = llvm.icmp "slt" %17, %arg0 : i64
// CHECK-NEXT: br i1 %{{[0-9]+}}, label %{{[0-9]+}}, label %{{[0-9]+}}
llvm.cond_br %18, ^bb7, ^bb8
^bb7: // pred: ^bb6
// CHECK: %{{[0-9]+}} = extractvalue { float*, i64 } %{{[0-9]+}}, 1
// CHECK-NEXT: %{{[0-9]+}} = extractvalue { float*, i64 } %{{[0-9]+}}, 0
// CHECK-NEXT: %{{[0-9]+}} = getelementptr float, float* %{{[0-9]+}}, i64 %{{[0-9]+}}
// CHECK-NEXT: %{{[0-9]+}} = load float, float* %{{[0-9]+}}
%19 = llvm.extractvalue %6[1] : !llvm.struct<(ptr<f32>, i64)>
%20 = llvm.extractvalue %6[0] : !llvm.struct<(ptr<f32>, i64)>
%21 = llvm.getelementptr %20[%17] : (!llvm.ptr<f32>, i64) -> !llvm.ptr<f32>
%22 = llvm.load %21 : !llvm.ptr<f32>
%23 = llvm.mlir.constant(1 : index) : i64
// CHECK-NEXT: %{{[0-9]+}} = add i64 %{{[0-9]+}}, 1
%24 = llvm.add %17, %23 : i64
// CHECK-NEXT: br label %{{[0-9]+}}
llvm.br ^bb6(%24 : i64)
^bb8: // pred: ^bb6
// CHECK: ret void
llvm.return
}
// CHECK-LABEL: define void @store_load_mixed(i64 {{%.*}})
llvm.func @store_load_mixed(%arg0: i64) {
%0 = llvm.mlir.constant(10 : index) : i64
// CHECK-NEXT: %{{[0-9]+}} = mul i64 2, %{{[0-9]+}}
// CHECK-NEXT: %{{[0-9]+}} = mul i64 %{{[0-9]+}}, 4
// CHECK-NEXT: %{{[0-9]+}} = mul i64 %{{[0-9]+}}, 10
// CHECK-NEXT: %{{[0-9]+}} = mul i64 %{{[0-9]+}}, 4
// CHECK-NEXT: %{{[0-9]+}} = call i8* @malloc(i64 %{{[0-9]+}})
// CHECK-NEXT: %{{[0-9]+}} = bitcast i8* %{{[0-9]+}} to float*
// CHECK-NEXT: %{{[0-9]+}} = insertvalue { float*, i64, i64 } undef, float* %{{[0-9]+}}, 0
// CHECK-NEXT: %{{[0-9]+}} = insertvalue { float*, i64, i64 } %{{[0-9]+}}, i64 %{{[0-9]+}}, 1
// CHECK-NEXT: %{{[0-9]+}} = insertvalue { float*, i64, i64 } %{{[0-9]+}}, i64 10, 2
%1 = llvm.mlir.constant(2 : index) : i64
%2 = llvm.mlir.constant(4 : index) : i64
%3 = llvm.mul %1, %arg0 : i64
%4 = llvm.mul %3, %2 : i64
%5 = llvm.mul %4, %0 : i64
%6 = llvm.mlir.undef : !llvm.struct<(ptr<f32>, i64, i64)>
%7 = llvm.mlir.constant(4 : index) : i64
%8 = llvm.mul %5, %7 : i64
%9 = llvm.call @malloc(%8) : (i64) -> !llvm.ptr<i8>
%10 = llvm.bitcast %9 : !llvm.ptr<i8> to !llvm.ptr<f32>
%11 = llvm.insertvalue %10, %6[0] : !llvm.struct<(ptr<f32>, i64, i64)>
%12 = llvm.insertvalue %arg0, %11[1] : !llvm.struct<(ptr<f32>, i64, i64)>
%13 = llvm.insertvalue %0, %12[2] : !llvm.struct<(ptr<f32>, i64, i64)>
// CHECK-NEXT: %{{[0-9]+}} = call i64 @get_index()
// CHECK-NEXT: %{{[0-9]+}} = call i64 @get_index()
%14 = llvm.mlir.constant(1 : index) : i64
%15 = llvm.mlir.constant(2 : index) : i64
%16 = llvm.call @get_index() : () -> i64
%17 = llvm.call @get_index() : () -> i64
%18 = llvm.mlir.constant(4.200000e+01 : f32) : f32
%19 = llvm.mlir.constant(2 : index) : i64
// CHECK-NEXT: %{{[0-9]+}} = extractvalue { float*, i64, i64 } %{{[0-9]+}}, 1
// CHECK-NEXT: %{{[0-9]+}} = extractvalue { float*, i64, i64 } %{{[0-9]+}}, 2
// CHECK-NEXT: %{{[0-9]+}} = mul i64 1, %{{[0-9]+}}
// CHECK-NEXT: %{{[0-9]+}} = add i64 %{{[0-9]+}}, 2
// CHECK-NEXT: %{{[0-9]+}} = mul i64 %{{[0-9]+}}, 4
// CHECK-NEXT: %{{[0-9]+}} = add i64 %{{[0-9]+}}, %{{[0-9]+}}
// CHECK-NEXT: %{{[0-9]+}} = mul i64 %{{[0-9]+}}, %{{[0-9]+}}
// CHECK-NEXT: %{{[0-9]+}} = add i64 %{{[0-9]+}}, %{{[0-9]+}}
// CHECK-NEXT: %{{[0-9]+}} = extractvalue { float*, i64, i64 } %{{[0-9]+}}, 0
// CHECK-NEXT: %{{[0-9]+}} = getelementptr float, float* %{{[0-9]+}}, i64 %{{[0-9]+}}
// CHECK-NEXT: store float 4.200000e+01, float* %{{[0-9]+}}
%20 = llvm.extractvalue %13[1] : !llvm.struct<(ptr<f32>, i64, i64)>
%21 = llvm.mlir.constant(4 : index) : i64
%22 = llvm.extractvalue %13[2] : !llvm.struct<(ptr<f32>, i64, i64)>
%23 = llvm.mul %14, %20 : i64
%24 = llvm.add %23, %15 : i64
%25 = llvm.mul %24, %21 : i64
%26 = llvm.add %25, %16 : i64
%27 = llvm.mul %26, %22 : i64
%28 = llvm.add %27, %17 : i64
%29 = llvm.extractvalue %13[0] : !llvm.struct<(ptr<f32>, i64, i64)>
%30 = llvm.getelementptr %29[%28] : (!llvm.ptr<f32>, i64) -> !llvm.ptr<f32>
llvm.store %18, %30 : !llvm.ptr<f32>
// CHECK-NEXT: %{{[0-9]+}} = extractvalue { float*, i64, i64 } %{{[0-9]+}}, 1
// CHECK-NEXT: %{{[0-9]+}} = extractvalue { float*, i64, i64 } %{{[0-9]+}}, 2
// CHECK-NEXT: %{{[0-9]+}} = mul i64 %{{[0-9]+}}, %{{[0-9]+}}
// CHECK-NEXT: %{{[0-9]+}} = add i64 %{{[0-9]+}}, %{{[0-9]+}}
// CHECK-NEXT: %{{[0-9]+}} = mul i64 %{{[0-9]+}}, 4
// CHECK-NEXT: %{{[0-9]+}} = add i64 %{{[0-9]+}}, 2
// CHECK-NEXT: %{{[0-9]+}} = mul i64 %{{[0-9]+}}, %{{[0-9]+}}
// CHECK-NEXT: %{{[0-9]+}} = add i64 %{{[0-9]+}}, 1
// CHECK-NEXT: %{{[0-9]+}} = extractvalue { float*, i64, i64 } %{{[0-9]+}}, 0
// CHECK-NEXT: %{{[0-9]+}} = getelementptr float, float* %{{[0-9]+}}, i64 %{{[0-9]+}}
// CHECK-NEXT: %{{[0-9]+}} = load float, float* %{{[0-9]+}}
%31 = llvm.mlir.constant(2 : index) : i64
%32 = llvm.extractvalue %13[1] : !llvm.struct<(ptr<f32>, i64, i64)>
%33 = llvm.mlir.constant(4 : index) : i64
%34 = llvm.extractvalue %13[2] : !llvm.struct<(ptr<f32>, i64, i64)>
%35 = llvm.mul %17, %32 : i64
%36 = llvm.add %35, %16 : i64
%37 = llvm.mul %36, %33 : i64
%38 = llvm.add %37, %15 : i64
%39 = llvm.mul %38, %34 : i64
%40 = llvm.add %39, %14 : i64
%41 = llvm.extractvalue %13[0] : !llvm.struct<(ptr<f32>, i64, i64)>
%42 = llvm.getelementptr %41[%40] : (!llvm.ptr<f32>, i64) -> !llvm.ptr<f32>
%43 = llvm.load %42 : !llvm.ptr<f32>
// CHECK-NEXT: ret void
llvm.return
}
// CHECK-LABEL: define { float*, i64 } @memref_args_rets({ float* } {{%.*}}, { float*, i64 } {{%.*}}, { float*, i64 } {{%.*}})
llvm.func @memref_args_rets(%arg0: !llvm.struct<(ptr<f32>)>, %arg1: !llvm.struct<(ptr<f32>, i64)>, %arg2: !llvm.struct<(ptr<f32>, i64)>) -> !llvm.struct<(ptr<f32>, i64)> {
%0 = llvm.mlir.constant(7 : index) : i64
// CHECK-NEXT: %{{[0-9]+}} = call i64 @get_index()
%1 = llvm.call @get_index() : () -> i64
%2 = llvm.mlir.constant(4.200000e+01 : f32) : f32
// CHECK-NEXT: %{{[0-9]+}} = extractvalue { float* } %{{[0-9]+}}, 0
// CHECK-NEXT: %{{[0-9]+}} = getelementptr float, float* %{{[0-9]+}}, i64 7
// CHECK-NEXT: store float 4.200000e+01, float* %{{[0-9]+}}
%3 = llvm.mlir.constant(10 : index) : i64
%4 = llvm.extractvalue %arg0[0] : !llvm.struct<(ptr<f32>)>
%5 = llvm.getelementptr %4[%0] : (!llvm.ptr<f32>, i64) -> !llvm.ptr<f32>
llvm.store %2, %5 : !llvm.ptr<f32>
// CHECK-NEXT: %{{[0-9]+}} = extractvalue { float*, i64 } %{{[0-9]+}}, 1
// CHECK-NEXT: %{{[0-9]+}} = extractvalue { float*, i64 } %{{[0-9]+}}, 0
// CHECK-NEXT: %{{[0-9]+}} = getelementptr float, float* %{{[0-9]+}}, i64 7
// CHECK-NEXT: store float 4.200000e+01, float* %{{[0-9]+}}
%6 = llvm.extractvalue %arg1[1] : !llvm.struct<(ptr<f32>, i64)>
%7 = llvm.extractvalue %arg1[0] : !llvm.struct<(ptr<f32>, i64)>
%8 = llvm.getelementptr %7[%0] : (!llvm.ptr<f32>, i64) -> !llvm.ptr<f32>
llvm.store %2, %8 : !llvm.ptr<f32>
// CHECK-NEXT: %{{[0-9]+}} = extractvalue { float*, i64 } %{{[0-9]+}}, 1
// CHECK-NEXT: %{{[0-9]+}} = mul i64 7, %{{[0-9]+}}
// CHECK-NEXT: %{{[0-9]+}} = add i64 %{{[0-9]+}}, %{{[0-9]+}}
// CHECK-NEXT: %{{[0-9]+}} = extractvalue { float*, i64 } %{{[0-9]+}}, 0
// CHECK-NEXT: %{{[0-9]+}} = getelementptr float, float* %{{[0-9]+}}, i64 %{{[0-9]+}}
// CHECK-NEXT: store float 4.200000e+01, float* %{{[0-9]+}}
%9 = llvm.mlir.constant(10 : index) : i64
%10 = llvm.extractvalue %arg2[1] : !llvm.struct<(ptr<f32>, i64)>
%11 = llvm.mul %0, %10 : i64
%12 = llvm.add %11, %1 : i64
%13 = llvm.extractvalue %arg2[0] : !llvm.struct<(ptr<f32>, i64)>
%14 = llvm.getelementptr %13[%12] : (!llvm.ptr<f32>, i64) -> !llvm.ptr<f32>
llvm.store %2, %14 : !llvm.ptr<f32>
// CHECK-NEXT: %{{[0-9]+}} = mul i64 10, %{{[0-9]+}}
// CHECK-NEXT: %{{[0-9]+}} = mul i64 %{{[0-9]+}}, 4
// CHECK-NEXT: %{{[0-9]+}} = call i8* @malloc(i64 %{{[0-9]+}})
// CHECK-NEXT: %{{[0-9]+}} = bitcast i8* %{{[0-9]+}} to float*
// CHECK-NEXT: %{{[0-9]+}} = insertvalue { float*, i64 } undef, float* %{{[0-9]+}}, 0
// CHECK-NEXT: %{{[0-9]+}} = insertvalue { float*, i64 } %{{[0-9]+}}, i64 %{{[0-9]+}}, 1
%15 = llvm.mlir.constant(10 : index) : i64
%16 = llvm.mul %15, %1 : i64
%17 = llvm.mlir.undef : !llvm.struct<(ptr<f32>, i64)>
%18 = llvm.mlir.constant(4 : index) : i64
%19 = llvm.mul %16, %18 : i64
%20 = llvm.call @malloc(%19) : (i64) -> !llvm.ptr<i8>
%21 = llvm.bitcast %20 : !llvm.ptr<i8> to !llvm.ptr<f32>
%22 = llvm.insertvalue %21, %17[0] : !llvm.struct<(ptr<f32>, i64)>
%23 = llvm.insertvalue %1, %22[1] : !llvm.struct<(ptr<f32>, i64)>
// CHECK-NEXT: ret { float*, i64 } %{{[0-9]+}}
llvm.return %23 : !llvm.struct<(ptr<f32>, i64)>
}
// CHECK-LABEL: define i64 @memref_dim({ float*, i64, i64 } {{%.*}})
llvm.func @memref_dim(%arg0: !llvm.struct<(ptr<f32>, i64, i64)>) -> i64 {
// Expecting this to create an LLVM constant.
%0 = llvm.mlir.constant(42 : index) : i64
// CHECK-NEXT: %2 = extractvalue { float*, i64, i64 } %0, 1
%1 = llvm.extractvalue %arg0[1] : !llvm.struct<(ptr<f32>, i64, i64)>
// Expecting this to create an LLVM constant.
%2 = llvm.mlir.constant(10 : index) : i64
// CHECK-NEXT: %3 = extractvalue { float*, i64, i64 } %0, 2
%3 = llvm.extractvalue %arg0[2] : !llvm.struct<(ptr<f32>, i64, i64)>
// Checking that the constant for d0 has been created.
// CHECK-NEXT: %4 = add i64 42, %2
%4 = llvm.add %0, %1 : i64
// Checking that the constant for d2 has been created.
// CHECK-NEXT: %5 = add i64 10, %3
%5 = llvm.add %2, %3 : i64
// CHECK-NEXT: %6 = add i64 %4, %5
%6 = llvm.add %4, %5 : i64
// CHECK-NEXT: ret i64 %6
llvm.return %6 : i64
}
llvm.func @get_i64() -> i64
llvm.func @get_f32() -> f32
llvm.func @get_memref() -> !llvm.struct<(ptr<f32>, i64, i64)>
// CHECK-LABEL: define { i64, float, { float*, i64, i64 } } @multireturn()
llvm.func @multireturn() -> !llvm.struct<(i64, f32, struct<(ptr<f32>, i64, i64)>)> {
%0 = llvm.call @get_i64() : () -> i64
%1 = llvm.call @get_f32() : () -> f32
%2 = llvm.call @get_memref() : () -> !llvm.struct<(ptr<f32>, i64, i64)>
// CHECK: %{{[0-9]+}} = insertvalue { i64, float, { float*, i64, i64 } } undef, i64 %{{[0-9]+}}, 0
// CHECK-NEXT: %{{[0-9]+}} = insertvalue { i64, float, { float*, i64, i64 } } %{{[0-9]+}}, float %{{[0-9]+}}, 1
// CHECK-NEXT: %{{[0-9]+}} = insertvalue { i64, float, { float*, i64, i64 } } %{{[0-9]+}}, { float*, i64, i64 } %{{[0-9]+}}, 2
// CHECK-NEXT: ret { i64, float, { float*, i64, i64 } } %{{[0-9]+}}
%3 = llvm.mlir.undef : !llvm.struct<(i64, f32, struct<(ptr<f32>, i64, i64)>)>
%4 = llvm.insertvalue %0, %3[0] : !llvm.struct<(i64, f32, struct<(ptr<f32>, i64, i64)>)>
%5 = llvm.insertvalue %1, %4[1] : !llvm.struct<(i64, f32, struct<(ptr<f32>, i64, i64)>)>
%6 = llvm.insertvalue %2, %5[2] : !llvm.struct<(i64, f32, struct<(ptr<f32>, i64, i64)>)>
llvm.return %6 : !llvm.struct<(i64, f32, struct<(ptr<f32>, i64, i64)>)>
}
// CHECK-LABEL: define void @multireturn_caller()
llvm.func @multireturn_caller() {
// CHECK-NEXT: %1 = call { i64, float, { float*, i64, i64 } } @multireturn()
// CHECK-NEXT: [[ret0:%[0-9]+]] = extractvalue { i64, float, { float*, i64, i64 } } %1, 0
// CHECK-NEXT: [[ret1:%[0-9]+]] = extractvalue { i64, float, { float*, i64, i64 } } %1, 1
// CHECK-NEXT: [[ret2:%[0-9]+]] = extractvalue { i64, float, { float*, i64, i64 } } %1, 2
%0 = llvm.call @multireturn() : () -> !llvm.struct<(i64, f32, struct<(ptr<f32>, i64, i64)>)>
%1 = llvm.extractvalue %0[0] : !llvm.struct<(i64, f32, struct<(ptr<f32>, i64, i64)>)>
%2 = llvm.extractvalue %0[1] : !llvm.struct<(i64, f32, struct<(ptr<f32>, i64, i64)>)>
%3 = llvm.extractvalue %0[2] : !llvm.struct<(i64, f32, struct<(ptr<f32>, i64, i64)>)>
%4 = llvm.mlir.constant(42) : i64
// CHECK: add i64 [[ret0]], 42
%5 = llvm.add %1, %4 : i64
%6 = llvm.mlir.constant(4.200000e+01 : f32) : f32
// CHECK: fadd float [[ret1]], 4.200000e+01
%7 = llvm.fadd %2, %6 : f32
%8 = llvm.mlir.constant(0 : index) : i64
%9 = llvm.mlir.constant(42 : index) : i64
// CHECK: extractvalue { float*, i64, i64 } [[ret2]], 0
%10 = llvm.extractvalue %3[1] : !llvm.struct<(ptr<f32>, i64, i64)>
%11 = llvm.mlir.constant(10 : index) : i64
%12 = llvm.extractvalue %3[2] : !llvm.struct<(ptr<f32>, i64, i64)>
%13 = llvm.mul %8, %10 : i64
%14 = llvm.add %13, %8 : i64
%15 = llvm.mul %14, %11 : i64
%16 = llvm.add %15, %8 : i64
%17 = llvm.mul %16, %12 : i64
%18 = llvm.add %17, %8 : i64
%19 = llvm.extractvalue %3[0] : !llvm.struct<(ptr<f32>, i64, i64)>
%20 = llvm.getelementptr %19[%18] : (!llvm.ptr<f32>, i64) -> !llvm.ptr<f32>
%21 = llvm.load %20 : !llvm.ptr<f32>
llvm.return
}
// CHECK-LABEL: define <4 x float> @vector_ops(<4 x float> {{%.*}}, <4 x i1> {{%.*}}, <4 x i64> {{%.*}})
llvm.func @vector_ops(%arg0: vector<4xf32>, %arg1: vector<4xi1>, %arg2: vector<4xi64>) -> vector<4xf32> {
%0 = llvm.mlir.constant(dense<4.200000e+01> : vector<4xf32>) : vector<4xf32>
// CHECK-NEXT: %4 = fadd <4 x float> %0, <float 4.200000e+01, float 4.200000e+01, float 4.200000e+01, float 4.200000e+01>
%1 = llvm.fadd %arg0, %0 : vector<4xf32>
// CHECK-NEXT: %5 = select <4 x i1> %1, <4 x float> %4, <4 x float> %0
%2 = llvm.select %arg1, %1, %arg0 : vector<4xi1>, vector<4xf32>
// CHECK-NEXT: %6 = sdiv <4 x i64> %2, %2
%3 = llvm.sdiv %arg2, %arg2 : vector<4xi64>
// CHECK-NEXT: %7 = udiv <4 x i64> %2, %2
%4 = llvm.udiv %arg2, %arg2 : vector<4xi64>
// CHECK-NEXT: %8 = srem <4 x i64> %2, %2
%5 = llvm.srem %arg2, %arg2 : vector<4xi64>
// CHECK-NEXT: %9 = urem <4 x i64> %2, %2
%6 = llvm.urem %arg2, %arg2 : vector<4xi64>
// CHECK-NEXT: %10 = fdiv <4 x float> %0, <float 4.200000e+01, float 4.200000e+01, float 4.200000e+01, float 4.200000e+01>
%7 = llvm.fdiv %arg0, %0 : vector<4xf32>
// CHECK-NEXT: %11 = frem <4 x float> %0, <float 4.200000e+01, float 4.200000e+01, float 4.200000e+01, float 4.200000e+01>
%8 = llvm.frem %arg0, %0 : vector<4xf32>
// CHECK-NEXT: %12 = and <4 x i64> %2, %2
%9 = llvm.and %arg2, %arg2 : vector<4xi64>
// CHECK-NEXT: %13 = or <4 x i64> %2, %2
%10 = llvm.or %arg2, %arg2 : vector<4xi64>
// CHECK-NEXT: %14 = xor <4 x i64> %2, %2
%11 = llvm.xor %arg2, %arg2 : vector<4xi64>
// CHECK-NEXT: %15 = shl <4 x i64> %2, %2
%12 = llvm.shl %arg2, %arg2 : vector<4xi64>
// CHECK-NEXT: %16 = lshr <4 x i64> %2, %2
%13 = llvm.lshr %arg2, %arg2 : vector<4xi64>
// CHECK-NEXT: %17 = ashr <4 x i64> %2, %2
%14 = llvm.ashr %arg2, %arg2 : vector<4xi64>
// CHECK-NEXT: ret <4 x float> %4
llvm.return %1 : vector<4xf32>
}
// CHECK-LABEL: @vector_splat_1d
llvm.func @vector_splat_1d() -> vector<4xf32> {
// CHECK: ret <4 x float> zeroinitializer
%0 = llvm.mlir.constant(dense<0.000000e+00> : vector<4xf32>) : vector<4xf32>
llvm.return %0 : vector<4xf32>
}
// CHECK-LABEL: @vector_splat_2d
llvm.func @vector_splat_2d() -> !llvm.array<4 x vector<16 x f32>> {
// CHECK: ret [4 x <16 x float>] zeroinitializer
%0 = llvm.mlir.constant(dense<0.000000e+00> : vector<4x16xf32>) : !llvm.array<4 x vector<16 x f32>>
llvm.return %0 : !llvm.array<4 x vector<16 x f32>>
}
// CHECK-LABEL: @vector_splat_3d
llvm.func @vector_splat_3d() -> !llvm.array<4 x array<16 x vector<4 x f32>>> {
// CHECK: ret [4 x [16 x <4 x float>]] zeroinitializer
%0 = llvm.mlir.constant(dense<0.000000e+00> : vector<4x16x4xf32>) : !llvm.array<4 x array<16 x vector<4 x f32>>>
llvm.return %0 : !llvm.array<4 x array<16 x vector<4 x f32>>>
}
// CHECK-LABEL: @vector_splat_nonzero
llvm.func @vector_splat_nonzero() -> vector<4xf32> {
// CHECK: ret <4 x float> <float 1.000000e+00, float 1.000000e+00, float 1.000000e+00, float 1.000000e+00>
%0 = llvm.mlir.constant(dense<1.000000e+00> : vector<4xf32>) : vector<4xf32>
llvm.return %0 : vector<4xf32>
}
// CHECK-LABEL: @ops
llvm.func @ops(%arg0: f32, %arg1: f32, %arg2: i32, %arg3: i32) -> !llvm.struct<(f32, i32)> {
// CHECK-NEXT: fsub float %0, %1
%0 = llvm.fsub %arg0, %arg1 : f32
// CHECK-NEXT: %6 = sub i32 %2, %3
%1 = llvm.sub %arg2, %arg3 : i32
// CHECK-NEXT: %7 = icmp slt i32 %2, %6
%2 = llvm.icmp "slt" %arg2, %1 : i32
// CHECK-NEXT: %8 = select i1 %7, i32 %2, i32 %6
%3 = llvm.select %2, %arg2, %1 : i1, i32
// CHECK-NEXT: %9 = sdiv i32 %2, %3
%4 = llvm.sdiv %arg2, %arg3 : i32
// CHECK-NEXT: %10 = udiv i32 %2, %3
%5 = llvm.udiv %arg2, %arg3 : i32
// CHECK-NEXT: %11 = srem i32 %2, %3
%6 = llvm.srem %arg2, %arg3 : i32
// CHECK-NEXT: %12 = urem i32 %2, %3
%7 = llvm.urem %arg2, %arg3 : i32
%8 = llvm.mlir.undef : !llvm.struct<(f32, i32)>
%9 = llvm.insertvalue %0, %8[0] : !llvm.struct<(f32, i32)>
%10 = llvm.insertvalue %3, %9[1] : !llvm.struct<(f32, i32)>
// CHECK: %15 = fdiv float %0, %1
%11 = llvm.fdiv %arg0, %arg1 : f32
// CHECK-NEXT: %16 = frem float %0, %1
%12 = llvm.frem %arg0, %arg1 : f32
// CHECK-NEXT: %17 = and i32 %2, %3
%13 = llvm.and %arg2, %arg3 : i32
// CHECK-NEXT: %18 = or i32 %2, %3
%14 = llvm.or %arg2, %arg3 : i32
// CHECK-NEXT: %19 = xor i32 %2, %3
%15 = llvm.xor %arg2, %arg3 : i32
// CHECK-NEXT: %20 = shl i32 %2, %3
%16 = llvm.shl %arg2, %arg3 : i32
// CHECK-NEXT: %21 = lshr i32 %2, %3
%17 = llvm.lshr %arg2, %arg3 : i32
// CHECK-NEXT: %22 = ashr i32 %2, %3
%18 = llvm.ashr %arg2, %arg3 : i32
// CHECK-NEXT: fneg float %0
%19 = llvm.fneg %arg0 : f32
llvm.return %10 : !llvm.struct<(f32, i32)>
}
//
// Indirect function calls
//
// CHECK-LABEL: define void @indirect_const_call(i64 {{%.*}})
llvm.func @indirect_const_call(%arg0: i64) {
// CHECK-NEXT: call void @body(i64 %0)
%0 = llvm.mlir.addressof @body : !llvm.ptr<func<void (i64)>>
llvm.call %0(%arg0) : (i64) -> ()
// CHECK-NEXT: ret void
llvm.return
}
// CHECK-LABEL: define i32 @indirect_call(i32 (float)* {{%.*}}, float {{%.*}})
llvm.func @indirect_call(%arg0: !llvm.ptr<func<i32 (f32)>>, %arg1: f32) -> i32 {
// CHECK-NEXT: %3 = call i32 %0(float %1)
%0 = llvm.call %arg0(%arg1) : (f32) -> i32
// CHECK-NEXT: ret i32 %3
llvm.return %0 : i32
}
//
// Check that we properly construct phi nodes in the blocks that have the same
// predecessor more than once.
//
// CHECK-LABEL: define void @cond_br_arguments(i1 {{%.*}}, i1 {{%.*}})
llvm.func @cond_br_arguments(%arg0: i1, %arg1: i1) {
// CHECK-NEXT: br i1 %0, label %3, label %5
llvm.cond_br %arg0, ^bb1(%arg0 : i1), ^bb2
// CHECK: 3:
// CHECK-NEXT: %4 = phi i1 [ %1, %5 ], [ %0, %2 ]
^bb1(%0 : i1):
// CHECK-NEXT: ret void
llvm.return
// CHECK: 5:
^bb2:
// CHECK-NEXT: br label %3
llvm.br ^bb1(%arg1 : i1)
}
// CHECK-LABEL: define void @llvm_noalias(float* noalias {{%*.}})
llvm.func @llvm_noalias(%arg0: !llvm.ptr<f32> {llvm.noalias = true}) {
llvm.return
}
// CHECK-LABEL: define void @byvalattr(i32* byval(i32) %
llvm.func @byvalattr(%arg0: !llvm.ptr<i32> {llvm.byval}) {
llvm.return
}
// CHECK-LABEL: define void @sretattr(i32* sret(i32) %
llvm.func @sretattr(%arg0: !llvm.ptr<i32> {llvm.sret}) {
llvm.return
}
// CHECK-LABEL: define void @llvm_align(float* align 4 {{%*.}})
llvm.func @llvm_align(%arg0: !llvm.ptr<f32> {llvm.align = 4}) {
llvm.return
}
// CHECK-LABEL: @llvm_varargs(...)
llvm.func @llvm_varargs(...)
llvm.func @intpointerconversion(%arg0 : i32) -> i32 {
// CHECK: %2 = inttoptr i32 %0 to i32*
// CHECK-NEXT: %3 = ptrtoint i32* %2 to i32
%1 = llvm.inttoptr %arg0 : i32 to !llvm.ptr<i32>
%2 = llvm.ptrtoint %1 : !llvm.ptr<i32> to i32
llvm.return %2 : i32
}
llvm.func @fpconversion(%arg0 : i32) -> i32 {
// CHECK: %2 = sitofp i32 %0 to float
// CHECK-NEXT: %3 = fptosi float %2 to i32
// CHECK-NEXT: %4 = uitofp i32 %3 to float
// CHECK-NEXT: %5 = fptoui float %4 to i32
%1 = llvm.sitofp %arg0 : i32 to f32
%2 = llvm.fptosi %1 : f32 to i32
%3 = llvm.uitofp %2 : i32 to f32
%4 = llvm.fptoui %3 : f32 to i32
llvm.return %4 : i32
}
// CHECK-LABEL: @addrspace
llvm.func @addrspace(%arg0 : !llvm.ptr<i32>) -> !llvm.ptr<i32, 2> {
// CHECK: %2 = addrspacecast i32* %0 to i32 addrspace(2)*
%1 = llvm.addrspacecast %arg0 : !llvm.ptr<i32> to !llvm.ptr<i32, 2>
llvm.return %1 : !llvm.ptr<i32, 2>
}
llvm.func @stringconstant() -> !llvm.array<12 x i8> {
%1 = llvm.mlir.constant("Hello world!") : !llvm.array<12 x i8>
// CHECK: ret [12 x i8] c"Hello world!"
llvm.return %1 : !llvm.array<12 x i8>
}
llvm.func @noreach() {
// CHECK: unreachable
llvm.unreachable
}
// CHECK-LABEL: define void @fcmp
llvm.func @fcmp(%arg0: f32, %arg1: f32) {
// CHECK: fcmp oeq float %0, %1
// CHECK-NEXT: fcmp ogt float %0, %1
// CHECK-NEXT: fcmp oge float %0, %1
// CHECK-NEXT: fcmp olt float %0, %1
// CHECK-NEXT: fcmp ole float %0, %1
// CHECK-NEXT: fcmp one float %0, %1
// CHECK-NEXT: fcmp ord float %0, %1
// CHECK-NEXT: fcmp ueq float %0, %1
// CHECK-NEXT: fcmp ugt float %0, %1
// CHECK-NEXT: fcmp uge float %0, %1
// CHECK-NEXT: fcmp ult float %0, %1
// CHECK-NEXT: fcmp ule float %0, %1
// CHECK-NEXT: fcmp une float %0, %1
// CHECK-NEXT: fcmp uno float %0, %1
%0 = llvm.fcmp "oeq" %arg0, %arg1 : f32
%1 = llvm.fcmp "ogt" %arg0, %arg1 : f32
%2 = llvm.fcmp "oge" %arg0, %arg1 : f32
%3 = llvm.fcmp "olt" %arg0, %arg1 : f32
%4 = llvm.fcmp "ole" %arg0, %arg1 : f32
%5 = llvm.fcmp "one" %arg0, %arg1 : f32
%6 = llvm.fcmp "ord" %arg0, %arg1 : f32
%7 = llvm.fcmp "ueq" %arg0, %arg1 : f32
%8 = llvm.fcmp "ugt" %arg0, %arg1 : f32
%9 = llvm.fcmp "uge" %arg0, %arg1 : f32
%10 = llvm.fcmp "ult" %arg0, %arg1 : f32
%11 = llvm.fcmp "ule" %arg0, %arg1 : f32
%12 = llvm.fcmp "une" %arg0, %arg1 : f32
%13 = llvm.fcmp "uno" %arg0, %arg1 : f32
llvm.return
}
// CHECK-LABEL: @vect
llvm.func @vect(%arg0: vector<4xf32>, %arg1: i32, %arg2: f32) {
// CHECK-NEXT: extractelement <4 x float> {{.*}}, i32
// CHECK-NEXT: insertelement <4 x float> {{.*}}, float %2, i32
// CHECK-NEXT: shufflevector <4 x float> {{.*}}, <4 x float> {{.*}}, <5 x i32> <i32 0, i32 0, i32 0, i32 0, i32 7>
%0 = llvm.extractelement %arg0[%arg1 : i32] : vector<4xf32>
%1 = llvm.insertelement %arg2, %arg0[%arg1 : i32] : vector<4xf32>
%2 = llvm.shufflevector %arg0, %arg0 [0 : i32, 0 : i32, 0 : i32, 0 : i32, 7 : i32] : vector<4xf32>, vector<4xf32>
llvm.return
}
// CHECK-LABEL: @vect_i64idx
llvm.func @vect_i64idx(%arg0: vector<4xf32>, %arg1: i64, %arg2: f32) {
// CHECK-NEXT: extractelement <4 x float> {{.*}}, i64
// CHECK-NEXT: insertelement <4 x float> {{.*}}, float %2, i64
%0 = llvm.extractelement %arg0[%arg1 : i64] : vector<4xf32>
%1 = llvm.insertelement %arg2, %arg0[%arg1 : i64] : vector<4xf32>
llvm.return
}
// CHECK-LABEL: @alloca
llvm.func @alloca(%size : i64) {
// Alignment automatically set by the LLVM IR builder when alignment attribute
// is 0.
// CHECK: alloca {{.*}} align 4
llvm.alloca %size x i32 {alignment = 0} : (i64) -> (!llvm.ptr<i32>)
// CHECK-NEXT: alloca {{.*}} align 8
llvm.alloca %size x i32 {alignment = 8} : (i64) -> (!llvm.ptr<i32>)
llvm.return
}
// CHECK-LABEL: @constants
llvm.func @constants() -> vector<4xf32> {
// CHECK: ret <4 x float> <float 4.2{{0*}}e+01, float 0.{{0*}}e+00, float 0.{{0*}}e+00, float 0.{{0*}}e+00>
%0 = llvm.mlir.constant(sparse<[[0]], [4.2e+01]> : vector<4xf32>) : vector<4xf32>
llvm.return %0 : vector<4xf32>
}
// CHECK-LABEL: @fp_casts
llvm.func @fp_casts(%fp1 : f32, %fp2 : f64) -> i16 {
// CHECK: fptrunc double {{.*}} to float
%a = llvm.fptrunc %fp2 : f64 to f32
// CHECK: fpext float {{.*}} to double
%b = llvm.fpext %fp1 : f32 to f64
// CHECK: fptosi double {{.*}} to i16
%c = llvm.fptosi %b : f64 to i16
llvm.return %c : i16
}
// CHECK-LABEL: @integer_extension_and_truncation
llvm.func @integer_extension_and_truncation(%a : i32) {
// CHECK: sext i32 {{.*}} to i64
// CHECK: zext i32 {{.*}} to i64
// CHECK: trunc i32 {{.*}} to i16
%0 = llvm.sext %a : i32 to i64
%1 = llvm.zext %a : i32 to i64
%2 = llvm.trunc %a : i32 to i16
llvm.return
}
// Check that the auxiliary `null` operation is converted into a `null` value.
// CHECK-LABEL: @null
llvm.func @null() -> !llvm.ptr<i32> {
%0 = llvm.mlir.null : !llvm.ptr<i32>
// CHECK: ret i32* null
llvm.return %0 : !llvm.ptr<i32>
}
// Check that dense elements attributes are exported properly in constants.
// CHECK-LABEL: @elements_constant_3d_vector
llvm.func @elements_constant_3d_vector() -> !llvm.array<2 x array<2 x vector<2 x i32>>> {
// CHECK: ret [2 x [2 x <2 x i32>]]
// CHECK-SAME: {{\[}}[2 x <2 x i32>] [<2 x i32> <i32 1, i32 2>, <2 x i32> <i32 3, i32 4>],
// CHECK-SAME: [2 x <2 x i32>] [<2 x i32> <i32 42, i32 43>, <2 x i32> <i32 44, i32 45>]]
%0 = llvm.mlir.constant(dense<[[[1, 2], [3, 4]], [[42, 43], [44, 45]]]> : vector<2x2x2xi32>) : !llvm.array<2 x array<2 x vector<2 x i32>>>
llvm.return %0 : !llvm.array<2 x array<2 x vector<2 x i32>>>
}
// CHECK-LABEL: @elements_constant_3d_array
llvm.func @elements_constant_3d_array() -> !llvm.array<2 x array<2 x array<2 x i32>>> {
// CHECK: ret [2 x [2 x [2 x i32]]]
// CHECK-SAME: {{\[}}[2 x [2 x i32]] {{\[}}[2 x i32] [i32 1, i32 2], [2 x i32] [i32 3, i32 4]],
// CHECK-SAME: [2 x [2 x i32]] {{\[}}[2 x i32] [i32 42, i32 43], [2 x i32] [i32 44, i32 45]]]
%0 = llvm.mlir.constant(dense<[[[1, 2], [3, 4]], [[42, 43], [44, 45]]]> : tensor<2x2x2xi32>) : !llvm.array<2 x array<2 x array<2 x i32>>>
llvm.return %0 : !llvm.array<2 x array<2 x array<2 x i32>>>
}
// CHECK-LABEL: @atomicrmw
llvm.func @atomicrmw(
%f32_ptr : !llvm.ptr<f32>, %f32 : f32,
%i32_ptr : !llvm.ptr<i32>, %i32 : i32) {
// CHECK: atomicrmw fadd float* %{{.*}}, float %{{.*}} monotonic
%0 = llvm.atomicrmw fadd %f32_ptr, %f32 monotonic : f32
// CHECK: atomicrmw fsub float* %{{.*}}, float %{{.*}} monotonic
%1 = llvm.atomicrmw fsub %f32_ptr, %f32 monotonic : f32
// CHECK: atomicrmw xchg float* %{{.*}}, float %{{.*}} monotonic
%2 = llvm.atomicrmw xchg %f32_ptr, %f32 monotonic : f32
// CHECK: atomicrmw add i32* %{{.*}}, i32 %{{.*}} acquire
%3 = llvm.atomicrmw add %i32_ptr, %i32 acquire : i32
// CHECK: atomicrmw sub i32* %{{.*}}, i32 %{{.*}} release
%4 = llvm.atomicrmw sub %i32_ptr, %i32 release : i32
// CHECK: atomicrmw and i32* %{{.*}}, i32 %{{.*}} acq_rel
%5 = llvm.atomicrmw _and %i32_ptr, %i32 acq_rel : i32
// CHECK: atomicrmw nand i32* %{{.*}}, i32 %{{.*}} seq_cst
%6 = llvm.atomicrmw nand %i32_ptr, %i32 seq_cst : i32
// CHECK: atomicrmw or i32* %{{.*}}, i32 %{{.*}} monotonic
%7 = llvm.atomicrmw _or %i32_ptr, %i32 monotonic : i32
// CHECK: atomicrmw xor i32* %{{.*}}, i32 %{{.*}} monotonic
%8 = llvm.atomicrmw _xor %i32_ptr, %i32 monotonic : i32
// CHECK: atomicrmw max i32* %{{.*}}, i32 %{{.*}} monotonic
%9 = llvm.atomicrmw max %i32_ptr, %i32 monotonic : i32
// CHECK: atomicrmw min i32* %{{.*}}, i32 %{{.*}} monotonic
%10 = llvm.atomicrmw min %i32_ptr, %i32 monotonic : i32
// CHECK: atomicrmw umax i32* %{{.*}}, i32 %{{.*}} monotonic
%11 = llvm.atomicrmw umax %i32_ptr, %i32 monotonic : i32
// CHECK: atomicrmw umin i32* %{{.*}}, i32 %{{.*}} monotonic
%12 = llvm.atomicrmw umin %i32_ptr, %i32 monotonic : i32
llvm.return
}
// CHECK-LABEL: @cmpxchg
llvm.func @cmpxchg(%ptr : !llvm.ptr<i32>, %cmp : i32, %val: i32) {
// CHECK: cmpxchg i32* %{{.*}}, i32 %{{.*}}, i32 %{{.*}} acq_rel monotonic
%0 = llvm.cmpxchg %ptr, %cmp, %val acq_rel monotonic : i32
// CHECK: %{{[0-9]+}} = extractvalue { i32, i1 } %{{[0-9]+}}, 0
%1 = llvm.extractvalue %0[0] : !llvm.struct<(i32, i1)>
// CHECK: %{{[0-9]+}} = extractvalue { i32, i1 } %{{[0-9]+}}, 1
%2 = llvm.extractvalue %0[1] : !llvm.struct<(i32, i1)>
llvm.return
}
llvm.mlir.global external constant @_ZTIi() : !llvm.ptr<i8>
llvm.func @foo(!llvm.ptr<i8>)
llvm.func @bar(!llvm.ptr<i8>) -> !llvm.ptr<i8>
llvm.func @__gxx_personality_v0(...) -> i32
// CHECK-LABEL: @invokeLandingpad
llvm.func @invokeLandingpad() -> i32 attributes { personality = @__gxx_personality_v0 } {
// CHECK: %[[a1:[0-9]+]] = alloca i8
%0 = llvm.mlir.constant(0 : i32) : i32
%1 = llvm.mlir.constant(dense<0> : vector<1xi8>) : !llvm.array<1 x i8>
%2 = llvm.mlir.addressof @_ZTIi : !llvm.ptr<ptr<i8>>
%3 = llvm.bitcast %2 : !llvm.ptr<ptr<i8>> to !llvm.ptr<i8>
%4 = llvm.mlir.null : !llvm.ptr<ptr<i8>>
%5 = llvm.mlir.constant(1 : i32) : i32
%6 = llvm.alloca %5 x i8 : (i32) -> !llvm.ptr<i8>
// CHECK: invoke void @foo(i8* %[[a1]])
// CHECK-NEXT: to label %[[normal:[0-9]+]] unwind label %[[unwind:[0-9]+]]
llvm.invoke @foo(%6) to ^bb2 unwind ^bb1 : (!llvm.ptr<i8>) -> ()
// CHECK: [[unwind]]:
^bb1:
// CHECK: %{{[0-9]+}} = landingpad { i8*, i32 }
// CHECK-NEXT: catch i8** null
// CHECK-NEXT: catch i8* bitcast (i8** @_ZTIi to i8*)
// CHECK-NEXT: filter [1 x i8] zeroinitializer
%7 = llvm.landingpad (catch %4 : !llvm.ptr<ptr<i8>>) (catch %3 : !llvm.ptr<i8>) (filter %1 : !llvm.array<1 x i8>) : !llvm.struct<(ptr<i8>, i32)>
// CHECK: br label %[[final:[0-9]+]]
llvm.br ^bb3
// CHECK: [[normal]]:
// CHECK-NEXT: ret i32 1
^bb2: // 2 preds: ^bb0, ^bb3
llvm.return %5 : i32
// CHECK: [[final]]:
// CHECK-NEXT: %{{[0-9]+}} = invoke i8* @bar(i8* %[[a1]])
// CHECK-NEXT: to label %[[normal]] unwind label %[[unwind]]
^bb3: // pred: ^bb1
%8 = llvm.invoke @bar(%6) to ^bb2 unwind ^bb1 : (!llvm.ptr<i8>) -> !llvm.ptr<i8>
}
// CHECK-LABEL: @callFreezeOp
llvm.func @callFreezeOp(%x : i32) {
// CHECK: freeze i32 %{{[0-9]+}}
%0 = llvm.freeze %x : i32
%1 = llvm.mlir.undef : i32
// CHECK: freeze i32 undef
%2 = llvm.freeze %1 : i32
llvm.return
}
// CHECK-LABEL: @boolConstArg
llvm.func @boolConstArg() -> i1 {
// CHECK: ret i1 false
%0 = llvm.mlir.constant(true) : i1
%1 = llvm.mlir.constant(false) : i1
%2 = llvm.and %0, %1 : i1
llvm.return %2 : i1
}
// CHECK-LABEL: @callFenceInst
llvm.func @callFenceInst() {
// CHECK: fence syncscope("agent") release
llvm.fence syncscope("agent") release
// CHECK: fence release
llvm.fence release
// CHECK: fence release
llvm.fence syncscope("") release
llvm.return
}
// CHECK-LABEL: @passthrough
// CHECK: #[[ATTR_GROUP:[0-9]*]]
llvm.func @passthrough() attributes {passthrough = ["noinline", ["alignstack", "4"], "null_pointer_is_valid", ["foo", "bar"]]} {
llvm.return
}
// CHECK: attributes #[[ATTR_GROUP]] = {
// CHECK-DAG: noinline
// CHECK-DAG: alignstack=4
// CHECK-DAG: null_pointer_is_valid
// CHECK-DAG: "foo"="bar"
// -----
// CHECK-LABEL: @constant_bf16
llvm.func @constant_bf16() -> bf16 {
%0 = llvm.mlir.constant(1.000000e+01 : bf16) : bf16
llvm.return %0 : bf16
}
// CHECK: ret bfloat 0xR4120
// -----
llvm.func @address_taken() {
llvm.return
}
llvm.mlir.global internal constant @taker_of_address() : !llvm.ptr<func<void ()>> {
%0 = llvm.mlir.addressof @address_taken : !llvm.ptr<func<void ()>>
llvm.return %0 : !llvm.ptr<func<void ()>>
}
// -----
// Check that branch weight attributes are exported properly as metadata.
llvm.func @cond_br_weights(%cond : i1, %arg0 : i32, %arg1 : i32) -> i32 {
// CHECK: !prof ![[NODE:[0-9]+]]
llvm.cond_br %cond weights(dense<[5, 10]> : vector<2xi32>), ^bb1, ^bb2
^bb1: // pred: ^bb0
llvm.return %arg0 : i32
^bb2: // pred: ^bb0
llvm.return %arg1 : i32
}
// CHECK: ![[NODE]] = !{!"branch_weights", i32 5, i32 10}
// -----
llvm.func @volatile_store_and_load() {
%val = llvm.mlir.constant(5 : i32) : i32
%size = llvm.mlir.constant(1 : i64) : i64
%0 = llvm.alloca %size x i32 : (i64) -> (!llvm.ptr<i32>)
// CHECK: store volatile i32 5, i32* %{{.*}}
llvm.store volatile %val, %0 : !llvm.ptr<i32>
// CHECK: %{{.*}} = load volatile i32, i32* %{{.*}}
%1 = llvm.load volatile %0: !llvm.ptr<i32>
llvm.return
}
// -----
// Check that nontemporal attribute is exported as metadata node.
llvm.func @nontemporal_store_and_load() {
%val = llvm.mlir.constant(5 : i32) : i32
%size = llvm.mlir.constant(1 : i64) : i64
%0 = llvm.alloca %size x i32 : (i64) -> (!llvm.ptr<i32>)
// CHECK: !nontemporal ![[NODE:[0-9]+]]
llvm.store %val, %0 {nontemporal} : !llvm.ptr<i32>
// CHECK: !nontemporal ![[NODE]]
%1 = llvm.load %0 {nontemporal} : !llvm.ptr<i32>
llvm.return
}
// CHECK: ![[NODE]] = !{i32 1}
// -----
// Check that the translation does not crash in absence of a data layout.
module {
// CHECK: declare void @module_default_layout
llvm.func @module_default_layout()
}
// -----
// CHECK: target datalayout = "E"
module attributes {llvm.data_layout = "E"} {
llvm.func @module_big_endian()
}
// -----
// CHECK: "CodeView", i32 1
module attributes {llvm.target_triple = "x86_64-pc-windows-msvc"} {}
// -----
// CHECK-NOT: "CodeView", i32 1
// CHECK: aarch64-linux-android
module attributes {llvm.target_triple = "aarch64-linux-android"} {}
// -----
// CHECK-NOT: "CodeView", i32 1
module attributes {} {}
// -----
// CHECK-LABEL: @useInlineAsm
llvm.func @useInlineAsm(%arg0: i32) {
// Constraints string is checked at LLVM InlineAsm instruction construction time.
// So we can't just use "bar" everywhere, number of in/out arguments has to match.
// CHECK-NEXT: call void asm "foo", "r"(i32 {{.*}}), !dbg !7
llvm.inline_asm "foo", "r" %arg0 : (i32) -> ()
// CHECK-NEXT: call i8 asm "foo", "=r,r"(i32 {{.*}}), !dbg !9
%0 = llvm.inline_asm "foo", "=r,r" %arg0 : (i32) -> i8
// CHECK-NEXT: call i8 asm "foo", "=r,r,r"(i32 {{.*}}, i32 {{.*}}), !dbg !10
%1 = llvm.inline_asm "foo", "=r,r,r" %arg0, %arg0 : (i32, i32) -> i8
// CHECK-NEXT: call i8 asm sideeffect "foo", "=r,r,r"(i32 {{.*}}, i32 {{.*}}), !dbg !11
%2 = llvm.inline_asm has_side_effects "foo", "=r,r,r" %arg0, %arg0 : (i32, i32) -> i8
// CHECK-NEXT: call i8 asm alignstack "foo", "=r,r,r"(i32 {{.*}}, i32 {{.*}}), !dbg !12
%3 = llvm.inline_asm is_align_stack "foo", "=r,r,r" %arg0, %arg0 : (i32, i32) -> i8
// CHECK-NEXT: call i8 asm inteldialect "foo", "=r,r,r"(i32 {{.*}}, i32 {{.*}}), !dbg !13
%4 = llvm.inline_asm asm_dialect = "intel" "foo", "=r,r,r" %arg0, %arg0 : (i32, i32) -> i8
// CHECK-NEXT: call { i8, i8 } asm "foo", "=r,=r,r"(i32 {{.*}}), !dbg !14
%5 = llvm.inline_asm "foo", "=r,=r,r" %arg0 : (i32) -> !llvm.struct<(i8, i8)>
llvm.return
}
// -----
llvm.func @fastmathFlagsFunc(f32) -> f32
// CHECK-LABEL: @fastmathFlags
llvm.func @fastmathFlags(%arg0: f32) {
// CHECK: {{.*}} = fadd nnan ninf float {{.*}}, {{.*}}
// CHECK: {{.*}} = fsub nnan ninf float {{.*}}, {{.*}}
// CHECK: {{.*}} = fmul nnan ninf float {{.*}}, {{.*}}
// CHECK: {{.*}} = fdiv nnan ninf float {{.*}}, {{.*}}
// CHECK: {{.*}} = frem nnan ninf float {{.*}}, {{.*}}
%0 = llvm.fadd %arg0, %arg0 {fastmathFlags = #llvm.fastmath<nnan, ninf>} : f32
%1 = llvm.fsub %arg0, %arg0 {fastmathFlags = #llvm.fastmath<nnan, ninf>} : f32
%2 = llvm.fmul %arg0, %arg0 {fastmathFlags = #llvm.fastmath<nnan, ninf>} : f32
%3 = llvm.fdiv %arg0, %arg0 {fastmathFlags = #llvm.fastmath<nnan, ninf>} : f32
%4 = llvm.frem %arg0, %arg0 {fastmathFlags = #llvm.fastmath<nnan, ninf>} : f32
// CHECK: {{.*}} = fcmp nnan ninf oeq {{.*}}, {{.*}}
%5 = llvm.fcmp "oeq" %arg0, %arg0 {fastmathFlags = #llvm.fastmath<nnan, ninf>} : f32
// CHECK: {{.*}} = fneg nnan ninf float {{.*}}
%6 = llvm.fneg %arg0 {fastmathFlags = #llvm.fastmath<nnan, ninf>} : f32
// CHECK: {{.*}} = call float @fastmathFlagsFunc({{.*}})
// CHECK: {{.*}} = call nnan float @fastmathFlagsFunc({{.*}})
// CHECK: {{.*}} = call ninf float @fastmathFlagsFunc({{.*}})
// CHECK: {{.*}} = call nsz float @fastmathFlagsFunc({{.*}})
// CHECK: {{.*}} = call arcp float @fastmathFlagsFunc({{.*}})
// CHECK: {{.*}} = call contract float @fastmathFlagsFunc({{.*}})
// CHECK: {{.*}} = call afn float @fastmathFlagsFunc({{.*}})
// CHECK: {{.*}} = call reassoc float @fastmathFlagsFunc({{.*}})
// CHECK: {{.*}} = call fast float @fastmathFlagsFunc({{.*}})
%8 = llvm.call @fastmathFlagsFunc(%arg0) {fastmathFlags = #llvm.fastmath<>} : (f32) -> (f32)
%9 = llvm.call @fastmathFlagsFunc(%arg0) {fastmathFlags = #llvm.fastmath<nnan>} : (f32) -> (f32)
%10 = llvm.call @fastmathFlagsFunc(%arg0) {fastmathFlags = #llvm.fastmath<ninf>} : (f32) -> (f32)
%11 = llvm.call @fastmathFlagsFunc(%arg0) {fastmathFlags = #llvm.fastmath<nsz>} : (f32) -> (f32)
%12 = llvm.call @fastmathFlagsFunc(%arg0) {fastmathFlags = #llvm.fastmath<arcp>} : (f32) -> (f32)
%13 = llvm.call @fastmathFlagsFunc(%arg0) {fastmathFlags = #llvm.fastmath<contract>} : (f32) -> (f32)
%14 = llvm.call @fastmathFlagsFunc(%arg0) {fastmathFlags = #llvm.fastmath<afn>} : (f32) -> (f32)
%15 = llvm.call @fastmathFlagsFunc(%arg0) {fastmathFlags = #llvm.fastmath<reassoc>} : (f32) -> (f32)
%16 = llvm.call @fastmathFlagsFunc(%arg0) {fastmathFlags = #llvm.fastmath<fast>} : (f32) -> (f32)
llvm.return
}
// -----
// CHECK-LABEL: @switch_args
llvm.func @switch_args(%arg0: i32) -> i32 {
%0 = llvm.mlir.constant(5 : i32) : i32
%1 = llvm.mlir.constant(7 : i32) : i32
%2 = llvm.mlir.constant(11 : i32) : i32
// CHECK: switch i32 %[[SWITCH_arg0:[0-9]+]], label %[[SWITCHDEFAULT_bb1:[0-9]+]] [
// CHECK-NEXT: i32 -1, label %[[SWITCHCASE_bb2:[0-9]+]]
// CHECK-NEXT: i32 1, label %[[SWITCHCASE_bb3:[0-9]+]]
// CHECK-NEXT: ]
llvm.switch %arg0, ^bb1 [
-1: ^bb2(%0 : i32),
1: ^bb3(%1, %2 : i32, i32)
]
// CHECK: [[SWITCHDEFAULT_bb1]]:
// CHECK-NEXT: ret i32 %[[SWITCH_arg0]]
^bb1: // pred: ^bb0
llvm.return %arg0 : i32
// CHECK: [[SWITCHCASE_bb2]]:
// CHECK-NEXT: phi i32 [ 5, %1 ]
// CHECK-NEXT: ret i32
^bb2(%3: i32): // pred: ^bb0
llvm.return %1 : i32
// CHECK: [[SWITCHCASE_bb3]]:
// CHECK-NEXT: phi i32 [ 7, %1 ]
// CHECK-NEXT: phi i32 [ 11, %1 ]
// CHECK-NEXT: ret i32
^bb3(%4: i32, %5: i32): // pred: ^bb0
llvm.return %4 : i32
}
// CHECK-LABEL: @switch_weights
llvm.func @switch_weights(%arg0: i32) -> i32 {
%0 = llvm.mlir.constant(19 : i32) : i32
%1 = llvm.mlir.constant(23 : i32) : i32
%2 = llvm.mlir.constant(29 : i32) : i32
// CHECK: !prof ![[SWITCH_WEIGHT_NODE:[0-9]+]]
llvm.switch %arg0, ^bb1(%0 : i32) [
9: ^bb2(%1, %2 : i32, i32),
99: ^bb3
] {branch_weights = dense<[13, 17, 19]> : vector<3xi32>}
^bb1(%3: i32): // pred: ^bb0
llvm.return %3 : i32
^bb2(%4: i32, %5: i32): // pred: ^bb0
llvm.return %5 : i32
^bb3: // pred: ^bb0
llvm.return %arg0 : i32
}
// CHECK: ![[SWITCH_WEIGHT_NODE]] = !{!"branch_weights", i32 13, i32 17, i32 19}