1// RUN: mlir-opt --pass-pipeline='builtin.module(llvm.func(canonicalize{test-convergence}))' %s -split-input-file | FileCheck %s 2 3// CHECK-LABEL: @fold_icmp_eq 4llvm.func @fold_icmp_eq(%arg0 : i32) -> i1 { 5 // CHECK: %[[C0:.*]] = llvm.mlir.constant(true) : i1 6 %0 = llvm.icmp "eq" %arg0, %arg0 : i32 7 // CHECK: llvm.return %[[C0]] 8 llvm.return %0 : i1 9} 10 11// ----- 12 13// CHECK-LABEL: @fold_icmp_ne 14llvm.func @fold_icmp_ne(%arg0 : vector<2xi32>) -> vector<2xi1> { 15 // CHECK: %[[C0:.*]] = llvm.mlir.constant(dense<false> : vector<2xi1>) : vector<2xi1> 16 %0 = llvm.icmp "ne" %arg0, %arg0 : vector<2xi32> 17 // CHECK: llvm.return %[[C0]] 18 llvm.return %0 : vector<2xi1> 19} 20 21// ----- 22 23// CHECK-LABEL: @fold_icmp_alloca 24llvm.func @fold_icmp_alloca() -> i1 { 25 // CHECK: %[[C0:.*]] = llvm.mlir.constant(true) : i1 26 %c0 = llvm.mlir.zero : !llvm.ptr 27 %c1 = arith.constant 1 : i64 28 %0 = llvm.alloca %c1 x i32 : (i64) -> !llvm.ptr 29 %1 = llvm.icmp "ne" %c0, %0 : !llvm.ptr 30 // CHECK: llvm.return %[[C0]] 31 llvm.return %1 : i1 32} 33 34// ----- 35 36// CHECK-LABEL: fold_extractvalue 37llvm.func @fold_extractvalue() -> i32 { 38 // CHECK-DAG: %[[C0:.*]] = arith.constant 0 : i32 39 %c0 = arith.constant 0 : i32 40 // CHECK-DAG: %[[C1:.*]] = arith.constant 1 : i32 41 %c1 = arith.constant 1 : i32 42 43 %0 = llvm.mlir.undef : !llvm.struct<(i32, i32)> 44 45 // CHECK-NOT: insertvalue 46 %1 = llvm.insertvalue %c0, %0[0] : !llvm.struct<(i32, i32)> 47 %2 = llvm.insertvalue %c1, %1[1] : !llvm.struct<(i32, i32)> 48 49 // CHECK-NOT: extractvalue 50 %3 = llvm.extractvalue %2[0] : !llvm.struct<(i32, i32)> 51 %4 = llvm.extractvalue %2[1] : !llvm.struct<(i32, i32)> 52 53 // CHECK: llvm.add %[[C0]], %[[C1]] 54 %5 = llvm.add %3, %4 : i32 55 llvm.return %5 : i32 56} 57 58// ----- 59 60// CHECK-LABEL: no_fold_extractvalue 61llvm.func @no_fold_extractvalue(%arr: !llvm.array<4 x f32>) -> f32 { 62 %f0 = arith.constant 0.0 : f32 63 %0 = llvm.mlir.undef : !llvm.array<4 x !llvm.array<4 x f32>> 64 65 // CHECK: insertvalue 66 // CHECK: insertvalue 67 // CHECK: extractvalue 68 %1 = llvm.insertvalue %f0, %0[0, 0] : !llvm.array<4 x !llvm.array<4 x f32>> 69 %2 = llvm.insertvalue %arr, %1[0] : !llvm.array<4 x !llvm.array<4 x f32>> 70 %3 = llvm.extractvalue %2[0, 0] : !llvm.array<4 x !llvm.array<4 x f32>> 71 72 llvm.return %3 : f32 73} 74 75// ----- 76 77// CHECK-LABEL: fold_unrelated_extractvalue 78llvm.func @fold_unrelated_extractvalue(%arr: !llvm.array<4 x f32>) -> f32 { 79 %f0 = arith.constant 0.0 : f32 80 // CHECK-NOT: insertvalue 81 // CHECK: extractvalue 82 %2 = llvm.insertvalue %f0, %arr[0] : !llvm.array<4 x f32> 83 %3 = llvm.extractvalue %2[1] : !llvm.array<4 x f32> 84 llvm.return %3 : f32 85} 86 87// ----- 88 89// CHECK-LABEL: fold_bitcast 90// CHECK-SAME: %[[ARG:[[:alnum:]]+]] 91// CHECK-NEXT: llvm.return %[[ARG]] 92llvm.func @fold_bitcast(%x : !llvm.ptr) -> !llvm.ptr { 93 %c = llvm.bitcast %x : !llvm.ptr to !llvm.ptr 94 llvm.return %c : !llvm.ptr 95} 96 97// ----- 98 99// CHECK-LABEL: fold_bitcast2 100// CHECK-SAME: %[[ARG:[[:alnum:]]+]] 101// CHECK-NEXT: llvm.return %[[ARG]] 102llvm.func @fold_bitcast2(%x : i32) -> i32 { 103 %c = llvm.bitcast %x : i32 to f32 104 %d = llvm.bitcast %c : f32 to i32 105 llvm.return %d : i32 106} 107 108// ----- 109 110// CHECK-LABEL: fold_bitcast_chain 111// CHECK-SAME: %[[ARG:[[:alnum:]]+]] 112llvm.func @fold_bitcast_chain(%x : i32) -> vector<2xi16> { 113 %c = llvm.bitcast %x : i32 to f32 114 %d = llvm.bitcast %c : f32 to vector<2xi16> 115 // CHECK: %[[BITCAST:.*]] = llvm.bitcast %[[ARG]] : i32 to vector<2xi16> 116 // CHECK: llvm.return %[[BITCAST]] 117 llvm.return %d : vector<2xi16> 118} 119 120// ----- 121 122// CHECK-LABEL: fold_addrcast 123// CHECK-SAME: %[[ARG:[[:alnum:]]+]] 124// CHECK-NEXT: llvm.return %[[ARG]] 125llvm.func @fold_addrcast(%x : !llvm.ptr) -> !llvm.ptr { 126 %c = llvm.addrspacecast %x : !llvm.ptr to !llvm.ptr 127 llvm.return %c : !llvm.ptr 128} 129 130// ----- 131 132// CHECK-LABEL: fold_addrcast2 133// CHECK-SAME: %[[ARG:[[:alnum:]]+]] 134// CHECK-NEXT: llvm.return %[[ARG]] 135llvm.func @fold_addrcast2(%x : !llvm.ptr) -> !llvm.ptr { 136 %c = llvm.addrspacecast %x : !llvm.ptr to !llvm.ptr<5> 137 %d = llvm.addrspacecast %c : !llvm.ptr<5> to !llvm.ptr 138 llvm.return %d : !llvm.ptr 139} 140 141// ----- 142 143// CHECK-LABEL: fold_addrcast_chain 144// CHECK-SAME: %[[ARG:[[:alnum:]]+]] 145llvm.func @fold_addrcast_chain(%x : !llvm.ptr) -> !llvm.ptr<2> { 146 %c = llvm.addrspacecast %x : !llvm.ptr to !llvm.ptr<1> 147 %d = llvm.addrspacecast %c : !llvm.ptr<1> to !llvm.ptr<2> 148 // CHECK: %[[ADDRCAST:.*]] = llvm.addrspacecast %[[ARG]] : !llvm.ptr to !llvm.ptr<2> 149 // CHECK: llvm.return %[[ADDRCAST]] 150 llvm.return %d : !llvm.ptr<2> 151} 152 153// ----- 154 155// CHECK-LABEL: fold_gep 156// CHECK-SAME: %[[ARG:[[:alnum:]]+]] 157// CHECK-NEXT: llvm.return %[[ARG]] 158llvm.func @fold_gep(%x : !llvm.ptr) -> !llvm.ptr { 159 %c0 = arith.constant 0 : i32 160 %c = llvm.getelementptr %x[%c0] : (!llvm.ptr, i32) -> !llvm.ptr, i8 161 llvm.return %c : !llvm.ptr 162} 163 164// ----- 165 166// CHECK-LABEL: fold_gep_neg 167// CHECK-SAME: %[[ARG:[[:alnum:]]+]] 168// CHECK-NEXT: %[[RES:.*]] = llvm.getelementptr inbounds %[[ARG]][0, 1] 169// CHECK-NEXT: llvm.return %[[RES]] 170llvm.func @fold_gep_neg(%x : !llvm.ptr) -> !llvm.ptr { 171 %c0 = arith.constant 0 : i32 172 %0 = llvm.getelementptr inbounds %x[%c0, 1] : (!llvm.ptr, i32) -> !llvm.ptr, !llvm.struct<(i32, i32)> 173 llvm.return %0 : !llvm.ptr 174} 175 176// ----- 177 178// CHECK-LABEL: fold_gep_canon 179// CHECK-SAME: %[[ARG:[[:alnum:]]+]] 180// CHECK-NEXT: %[[RES:.*]] = llvm.getelementptr %[[ARG]][2] 181// CHECK-NEXT: llvm.return %[[RES]] 182llvm.func @fold_gep_canon(%x : !llvm.ptr) -> !llvm.ptr { 183 %c2 = arith.constant 2 : i32 184 %c = llvm.getelementptr %x[%c2] : (!llvm.ptr, i32) -> !llvm.ptr, i8 185 llvm.return %c : !llvm.ptr 186} 187 188// ----- 189 190// Check that LLVM constants participate in cross-dialect constant folding. The 191// resulting constant is created in the arith dialect because the last folded 192// operation belongs to it. 193// CHECK-LABEL: llvm_constant 194llvm.func @llvm_constant() -> i32 { 195 // CHECK-NOT: llvm.mlir.constant 196 %0 = llvm.mlir.constant(40 : i32) : i32 197 %1 = llvm.mlir.constant(42 : i32) : i32 198 // CHECK: %[[RES:.*]] = arith.constant 82 : i32 199 // CHECK-NOT: arith.addi 200 %2 = arith.addi %0, %1 : i32 201 // CHECK: return %[[RES]] 202 llvm.return %2 : i32 203} 204 205// ----- 206 207// CHECK-LABEL: load_dce 208// CHECK-NEXT: llvm.return 209llvm.func @load_dce(%x : !llvm.ptr) { 210 %0 = llvm.load %x : !llvm.ptr -> i8 211 llvm.return 212} 213 214// ----- 215 216llvm.mlir.global external @fp() : !llvm.ptr 217 218// CHECK-LABEL: addr_dce 219// CHECK-NEXT: llvm.return 220llvm.func @addr_dce(%x : !llvm.ptr) { 221 %0 = llvm.mlir.addressof @fp : !llvm.ptr 222 llvm.return 223} 224 225// ----- 226 227// CHECK-LABEL: alloca_dce 228// CHECK-NEXT: llvm.return 229llvm.func @alloca_dce() { 230 %c1_i64 = arith.constant 1 : i64 231 %0 = llvm.alloca %c1_i64 x i32 : (i64) -> !llvm.ptr 232 llvm.return 233} 234 235// ----- 236 237// CHECK-LABEL: func @volatile_load 238llvm.func @volatile_load(%x : !llvm.ptr) { 239 // A volatile load may have side-effects such as a write operation to arbitrary memory. 240 // Make sure it is not removed. 241 // CHECK: llvm.load volatile 242 %0 = llvm.load volatile %x : !llvm.ptr -> i8 243 // Same with monotonic atomics and any stricter modes. 244 // CHECK: llvm.load %{{.*}} atomic monotonic 245 %2 = llvm.load %x atomic monotonic { alignment = 1 } : !llvm.ptr -> i8 246 // But not unordered! 247 // CHECK-NOT: llvm.load %{{.*}} atomic unordered 248 %3 = llvm.load %x atomic unordered { alignment = 1 } : !llvm.ptr -> i8 249 llvm.return 250} 251 252// ----- 253 254// CHECK-LABEL: func @inline_asm_side_effects 255llvm.func @inline_asm_side_effects(%x : i32) { 256 // CHECK-NOT: llvm.inline_asm "pure inline asm" 257 llvm.inline_asm "pure inline asm", "r" %x : (i32) -> () 258 // CHECK: llvm.inline_asm has_side_effects "inline asm with side effects" 259 llvm.inline_asm has_side_effects "inline asm with side effects", "r" %x : (i32) -> () 260 llvm.return 261} 262