712 lines · plain
1// RUN: mlir-opt %s -inline -split-input-file | FileCheck %s2 3#file = #llvm.di_file<"foo.mlir" in "/foo/">4#variable = #llvm.di_local_variable<scope = #file>5#variableAddr = #llvm.di_local_variable<scope = #file>6#label = #llvm.di_label<scope = #file>7 8func.func @inner_func_inlinable(%ptr : !llvm.ptr) -> i32 {9 %0 = llvm.mlir.constant(42 : i32) : i3210 %stack = llvm.intr.stacksave : !llvm.ptr11 llvm.store %0, %ptr { alignment = 8 } : i32, !llvm.ptr12 %1 = llvm.load %ptr { alignment = 8 } : !llvm.ptr -> i3213 llvm.intr.dbg.value #variable = %0 : i3214 llvm.intr.dbg.declare #variableAddr = %ptr : !llvm.ptr15 llvm.intr.dbg.label #label16 %byte = llvm.mlir.constant(43 : i8) : i817 %true = llvm.mlir.constant(1 : i1) : i118 "llvm.intr.memset"(%ptr, %byte, %0) <{isVolatile = true}> : (!llvm.ptr, i8, i32) -> ()19 "llvm.intr.memmove"(%ptr, %ptr, %0) <{isVolatile = true}> : (!llvm.ptr, !llvm.ptr, i32) -> ()20 "llvm.intr.memcpy"(%ptr, %ptr, %0) <{isVolatile = true}> : (!llvm.ptr, !llvm.ptr, i32) -> ()21 llvm.intr.assume %true : i122 llvm.fence release23 %2 = llvm.atomicrmw add %ptr, %0 monotonic : !llvm.ptr, i3224 %3 = llvm.cmpxchg %ptr, %0, %1 acq_rel monotonic : !llvm.ptr, i3225 llvm.inline_asm has_side_effects "foo", "bar" : () -> ()26 llvm.cond_br %true, ^bb1, ^bb227^bb1:28 llvm.unreachable29^bb2:30 llvm.intr.stackrestore %stack : !llvm.ptr31 llvm.call_intrinsic "llvm.x86.sse41.round.ss"() : () -> (vector<8xf32>)32 return %1 : i3233}34 35// CHECK-LABEL: func.func @test_inline(36// CHECK-SAME: %[[PTR:[a-zA-Z0-9_]+]]37// CHECK: %[[CST:.*]] = llvm.mlir.constant(4238// CHECK: %[[STACK:.+]] = llvm.intr.stacksave39// CHECK: llvm.store %[[CST]], %[[PTR]]40// CHECK: %[[RES:.+]] = llvm.load %[[PTR]]41// CHECK: llvm.intr.dbg.value #{{.+}} = %[[CST]]42// CHECK: llvm.intr.dbg.declare #{{.+}} = %[[PTR]]43// CHECK: llvm.intr.dbg.label #{{.+}}44// CHECK: "llvm.intr.memset"(%[[PTR]]45// CHECK: "llvm.intr.memmove"(%[[PTR]], %[[PTR]]46// CHECK: "llvm.intr.memcpy"(%[[PTR]], %[[PTR]]47// CHECK: llvm.intr.assume48// CHECK: llvm.fence release49// CHECK: llvm.atomicrmw add %[[PTR]], %[[CST]] monotonic50// CHECK: llvm.cmpxchg %[[PTR]], %[[CST]], %[[RES]] acq_rel monotonic51// CHECK: llvm.inline_asm has_side_effects "foo", "bar"52// CHECK: llvm.unreachable53// CHECK: llvm.intr.stackrestore %[[STACK]]54// CHECK: llvm.call_intrinsic "llvm.x86.sse41.round.ss"(55func.func @test_inline(%ptr : !llvm.ptr) -> i32 {56 %0 = call @inner_func_inlinable(%ptr) : (!llvm.ptr) -> i3257 return %0 : i3258}59 60// -----61// Check that llvm.return is correctly handled62 63func.func @func(%arg0 : i32) -> i32 {64 llvm.return %arg0 : i3265}66// CHECK-LABEL: @llvm_ret67// CHECK-NOT: call68// CHECK: return %arg069func.func @llvm_ret(%arg0 : i32) -> i32 {70 %res = call @func(%arg0) : (i32) -> (i32)71 return %res : i3272}73 74// -----75 76// Include all function attributes that don't prevent inlining77llvm.func internal fastcc @callee() -> (i32) attributes { function_entry_count = 42 : i64, dso_local } {78 %0 = llvm.mlir.constant(42 : i32) : i3279 llvm.return %0 : i3280}81 82// CHECK-LABEL: llvm.func @caller83// CHECK-NEXT: %[[CST:.+]] = llvm.mlir.constant84// CHECK-NEXT: llvm.return %[[CST]]85llvm.func @caller() -> (i32) {86 // Include all call attributes that don't prevent inlining.87 %0 = llvm.call fastcc @callee() { fastmathFlags = #llvm.fastmath<nnan, ninf>, branch_weights = dense<42> : vector<1xi32> } : () -> (i32)88 llvm.return %0 : i3289}90 91// -----92 93llvm.func @foo() -> (i32) attributes { no_inline } {94 %0 = llvm.mlir.constant(0 : i32) : i3295 llvm.return %0 : i3296}97 98llvm.func @bar() -> (i32) {99 %0 = llvm.mlir.constant(1 : i32) : i32100 llvm.return %0 : i32101}102 103llvm.func @callee_with_multiple_blocks(%cond: i1) -> (i32) {104 llvm.cond_br %cond, ^bb1, ^bb2105^bb1:106 %0 = llvm.call @foo() : () -> (i32)107 llvm.br ^bb3(%0: i32)108^bb2:109 %1 = llvm.call @bar() { no_inline } : () -> (i32)110 llvm.br ^bb3(%1: i32)111^bb3(%arg: i32):112 llvm.return %arg : i32113}114 115// CHECK-LABEL: llvm.func @caller116// CHECK-NEXT: llvm.cond_br {{.+}}, ^[[BB1:.+]], ^[[BB2:.+]]117// CHECK-NEXT: ^[[BB1]]:118// CHECK-NEXT: llvm.call @foo119// CHECK-NEXT: llvm.br ^[[BB3:[a-zA-Z0-9_]+]]120// CHECK-NEXT: ^[[BB2]]:121// CHECK-NEXT: llvm.call @bar122// CHECK-NEXT: llvm.br ^[[BB3]]123// CHECK-NEXT: ^[[BB3]]124// CHECK-NEXT: llvm.br ^[[BB4:[a-zA-Z0-9_]+]]125// CHECK-NEXT: ^[[BB4]]126// CHECK-NEXT: llvm.return127llvm.func @caller(%cond: i1) -> (i32) {128 %0 = llvm.call @callee_with_multiple_blocks(%cond) : (i1) -> (i32)129 llvm.return %0 : i32130}131 132// -----133 134llvm.func @personality() -> i32135 136llvm.func @callee() -> (i32) attributes { personality = @personality } {137 %0 = llvm.mlir.constant(42 : i32) : i32138 llvm.return %0 : i32139}140 141// CHECK-LABEL: llvm.func @caller142// CHECK-NEXT: llvm.call @callee143// CHECK-NEXT: return144llvm.func @caller() -> (i32) {145 %0 = llvm.call @callee() : () -> (i32)146 llvm.return %0 : i32147}148 149// -----150 151llvm.func @callee() attributes { passthrough = ["foo", "bar"] } {152 llvm.return153}154 155// CHECK-LABEL: llvm.func @caller156// CHECK-NEXT: llvm.return157llvm.func @caller() {158 llvm.call @callee() : () -> ()159 llvm.return160}161 162// -----163 164llvm.func @callee_noinline() attributes { no_inline } {165 llvm.return166}167 168llvm.func @callee_noduplicate() attributes { passthrough = ["noduplicate"] } {169 llvm.return170}171 172llvm.func @callee_presplitcoroutine() attributes { passthrough = ["presplitcoroutine"] } {173 llvm.return174}175 176llvm.func @callee_returns_twice() attributes { passthrough = ["returns_twice"] } {177 llvm.return178}179 180llvm.func @callee_strictfp() attributes { passthrough = ["strictfp"] } {181 llvm.return182}183 184// CHECK-LABEL: llvm.func @caller185// CHECK-NEXT: llvm.call @callee_noinline186// CHECK-NEXT: llvm.call @callee_noduplicate187// CHECK-NEXT: llvm.call @callee_presplitcoroutine188// CHECK-NEXT: llvm.call @callee_returns_twice189// CHECK-NEXT: llvm.call @callee_strictfp190// CHECK-NEXT: llvm.return191llvm.func @caller() {192 llvm.call @callee_noinline() : () -> ()193 llvm.call @callee_noduplicate() : () -> ()194 llvm.call @callee_presplitcoroutine() : () -> ()195 llvm.call @callee_returns_twice() : () -> ()196 llvm.call @callee_strictfp() : () -> ()197 llvm.return198}199 200// -----201 202llvm.func @static_alloca() -> f32 {203 %0 = llvm.mlir.constant(4 : i32) : i32204 %1 = llvm.alloca %0 x f32 : (i32) -> !llvm.ptr205 %2 = llvm.load %1 : !llvm.ptr -> f32206 llvm.return %2 : f32207}208 209llvm.func @dynamic_alloca(%size : i32) -> f32 {210 %0 = llvm.add %size, %size : i32211 %1 = llvm.alloca %0 x f32 : (i32) -> !llvm.ptr212 %2 = llvm.load %1 : !llvm.ptr -> f32213 llvm.return %2 : f32214}215 216// CHECK-LABEL: llvm.func @test_inline217llvm.func @test_inline(%cond : i1, %size : i32) -> f32 {218 // Check that the static alloca was moved to the entry block after inlining219 // with its size defined by a constant.220 // CHECK-NOT: ^{{.+}}:221 // CHECK-NEXT: llvm.mlir.constant222 // CHECK-NEXT: llvm.alloca223 // CHECK: llvm.cond_br224 llvm.cond_br %cond, ^bb1, ^bb2225 // CHECK: ^{{.+}}:226^bb1:227 // CHECK-NOT: llvm.call @static_alloca228 // CHECK: llvm.intr.lifetime.start229 %0 = llvm.call @static_alloca() : () -> f32230 // CHECK: llvm.intr.lifetime.end231 // CHECK: llvm.br ^[[BB3:[a-zA-Z0-9_]+]]232 llvm.br ^bb3(%0: f32)233 // CHECK: ^{{.+}}:234^bb2:235 // Check that the dynamic alloca was inlined, but that it was not moved to the236 // entry block.237 // CHECK: %[[STACK:[a-zA-Z0-9_]+]] = llvm.intr.stacksave238 // CHECK: llvm.add239 // CHECK: llvm.alloca240 // CHECK: llvm.intr.stackrestore %[[STACK]]241 // CHECK-NOT: llvm.call @dynamic_alloca242 %1 = llvm.call @dynamic_alloca(%size) : (i32) -> f32243 // CHECK: llvm.br ^[[BB3]]244 llvm.br ^bb3(%1: f32)245 // CHECK: ^[[BB3]]246^bb3(%arg : f32):247 // CHECK-NEXT: return248 llvm.return %arg : f32249}250 251// -----252 253llvm.func @static_alloca_not_in_entry(%cond : i1) -> f32 {254 llvm.cond_br %cond, ^bb1, ^bb2255^bb1:256 %0 = llvm.mlir.constant(4 : i32) : i32257 %1 = llvm.alloca %0 x f32 : (i32) -> !llvm.ptr258 llvm.br ^bb3(%1: !llvm.ptr)259^bb2:260 %2 = llvm.mlir.constant(8 : i32) : i32261 %3 = llvm.alloca %2 x f32 : (i32) -> !llvm.ptr262 llvm.br ^bb3(%3: !llvm.ptr)263^bb3(%ptr : !llvm.ptr):264 %4 = llvm.load %ptr : !llvm.ptr -> f32265 llvm.return %4 : f32266}267 268// CHECK-LABEL: llvm.func @test_inline269llvm.func @test_inline(%cond : i1) -> f32 {270 // Make sure the alloca was not moved to the entry block.271 // CHECK-NOT: llvm.alloca272 // CHECK: llvm.cond_br273 // CHECK: llvm.alloca274 %0 = llvm.call @static_alloca_not_in_entry(%cond) : (i1) -> f32275 llvm.return %0 : f32276}277 278// -----279 280llvm.func @static_alloca(%cond: i1) -> f32 {281 %0 = llvm.mlir.constant(4 : i32) : i32282 %1 = llvm.alloca %0 x f32 : (i32) -> !llvm.ptr283 llvm.cond_br %cond, ^bb1, ^bb2284^bb1:285 %2 = llvm.load %1 : !llvm.ptr -> f32286 llvm.return %2 : f32287^bb2:288 %3 = llvm.mlir.constant(3.14192 : f32) : f32289 llvm.return %3 : f32290}291 292// CHECK-LABEL: llvm.func @test_inline293llvm.func @test_inline(%cond0 : i1, %cond1 : i1, %funcArg : f32) -> f32 {294 // CHECK-NOT: llvm.cond_br295 // CHECK: %[[PTR:.+]] = llvm.alloca296 // CHECK: llvm.cond_br %{{.+}}, ^[[BB1:.+]], ^{{.+}}297 llvm.cond_br %cond0, ^bb1, ^bb2298 // CHECK: ^[[BB1]]299^bb1:300 // Make sure the lifetime begin intrinsic has been inserted where the call301 // used to be, even though the alloca has been moved to the entry block.302 // CHECK-NEXT: llvm.intr.lifetime.start %[[PTR]]303 %0 = llvm.call @static_alloca(%cond1) : (i1) -> f32304 // CHECK: llvm.cond_br %{{.+}}, ^[[BB2:.+]], ^[[BB3:.+]]305 llvm.br ^bb3(%0: f32)306 // Make sure the lifetime end intrinsic has been inserted at both former307 // return sites of the callee.308 // CHECK: ^[[BB2]]:309 // CHECK-NEXT: llvm.load310 // CHECK-NEXT: llvm.intr.lifetime.end %[[PTR]]311 // CHECK: ^[[BB3]]:312 // CHECK-NEXT: llvm.intr.lifetime.end %[[PTR]]313^bb2:314 llvm.br ^bb3(%funcArg: f32)315^bb3(%blockArg: f32):316 llvm.return %blockArg : f32317}318 319// -----320 321llvm.func @static_alloca() -> f32 {322 %0 = llvm.mlir.constant(4 : i32) : i32323 %1 = llvm.alloca %0 x f32 : (i32) -> !llvm.ptr324 %2 = llvm.load %1 : !llvm.ptr -> f32325 llvm.return %2 : f32326}327 328// CHECK-LABEL: llvm.func @test_inline329llvm.func @test_inline(%cond0 : i1) {330 // Verify the alloca is relocated to the entry block of the parent function331 // if the region operation is neither marked as isolated from above or332 // automatic allocation scope.333 // CHECK: %[[ALLOCA:.+]] = llvm.alloca334 // CHECK: "test.one_region_op"() ({335 "test.one_region_op"() ({336 %0 = llvm.call @static_alloca() : () -> f32337 // CHECK-NEXT: llvm.intr.lifetime.start %[[ALLOCA]]338 // CHECK-NEXT: %[[RES:.+]] = llvm.load %[[ALLOCA]]339 // CHECK-NEXT: llvm.intr.lifetime.end %[[ALLOCA]]340 // CHECK-NEXT: test.region_yield %[[RES]]341 test.region_yield %0 : f32342 }) : () -> ()343 // Verify the alloca is not relocated out of operations that are marked as344 // isolated from above.345 // CHECK-NOT: llvm.alloca346 // CHECK: test.isolated_regions347 test.isolated_regions {348 // CHECK: %[[ALLOCA:.+]] = llvm.alloca349 %0 = llvm.call @static_alloca() : () -> f32350 // CHECK: test.region_yield351 test.region_yield %0 : f32352 }353 // Verify the alloca is not relocated out of operations that are marked as354 // automatic allocation scope.355 // CHECK-NOT: llvm.alloca356 // CHECK: test.alloca_scope_region357 test.alloca_scope_region {358 // CHECK: %[[ALLOCA:.+]] = llvm.alloca359 %0 = llvm.call @static_alloca() : () -> f32360 // CHECK: test.region_yield361 test.region_yield %0 : f32362 }363 llvm.return364}365 366// -----367 368llvm.func @alloca_with_lifetime(%cond: i1) -> f32 {369 %0 = llvm.mlir.constant(4 : i32) : i32370 %1 = llvm.alloca %0 x f32 : (i32) -> !llvm.ptr371 llvm.intr.lifetime.start %1 : !llvm.ptr372 %2 = llvm.load %1 : !llvm.ptr -> f32373 llvm.intr.lifetime.end %1 : !llvm.ptr374 %3 = llvm.fadd %2, %2 : f32375 llvm.return %3 : f32376}377 378// CHECK-LABEL: llvm.func @test_inline379llvm.func @test_inline(%cond0 : i1, %cond1 : i1, %funcArg : f32) -> f32 {380 // CHECK-NOT: llvm.cond_br381 // CHECK: %[[PTR:.+]] = llvm.alloca382 // CHECK: llvm.cond_br %{{.+}}, ^[[BB1:.+]], ^{{.+}}383 llvm.cond_br %cond0, ^bb1, ^bb2384 // CHECK: ^[[BB1]]385^bb1:386 // Make sure the original lifetime intrinsic has been preserved, rather than387 // inserting a new one with a larger scope.388 // CHECK: llvm.intr.lifetime.start %[[PTR]]389 // CHECK-NEXT: llvm.load %[[PTR]]390 // CHECK-NEXT: llvm.intr.lifetime.end %[[PTR]]391 // CHECK: llvm.fadd392 // CHECK-NOT: llvm.intr.lifetime.end393 %0 = llvm.call @alloca_with_lifetime(%cond1) : (i1) -> f32394 llvm.br ^bb3(%0: f32)395^bb2:396 llvm.br ^bb3(%funcArg: f32)397^bb3(%blockArg: f32):398 llvm.return %blockArg : f32399}400 401// -----402 403llvm.func @with_byval_arg(%ptr : !llvm.ptr { llvm.byval = f64 }) {404 llvm.return405}406 407// CHECK-LABEL: llvm.func @test_byval408// CHECK-SAME: %[[PTR:[a-zA-Z0-9_]+]]: !llvm.ptr409llvm.func @test_byval(%ptr : !llvm.ptr) {410 // Make sure the new static alloca goes to the entry block.411 // CHECK: %[[ALLOCA:.+]] = llvm.alloca %{{.+}} x f64412 // CHECK: llvm.br ^[[BB1:[a-zA-Z0-9_]+]]413 llvm.br ^bb1414 // CHECK: ^[[BB1]]415^bb1:416 // CHECK: "llvm.intr.memcpy"(%[[ALLOCA]], %[[PTR]]417 llvm.call @with_byval_arg(%ptr) : (!llvm.ptr) -> ()418 llvm.br ^bb2419^bb2:420 llvm.return421}422 423// -----424 425llvm.func @with_byval_arg(%ptr : !llvm.ptr { llvm.byval = f64 }) attributes {memory_effects = #llvm.memory_effects<other = readwrite, argMem = read, inaccessibleMem = readwrite, errnoMem = none, targetMem0 = none, targetMem1 = none>} {426 llvm.return427}428 429// CHECK-LABEL: llvm.func @test_byval_read_only430// CHECK-NOT: llvm.call431// CHECK-NEXT: llvm.return432llvm.func @test_byval_read_only(%ptr : !llvm.ptr) {433 llvm.call @with_byval_arg(%ptr) : (!llvm.ptr) -> ()434 llvm.return435}436 437// -----438 439llvm.func @with_byval_arg(%ptr : !llvm.ptr { llvm.byval = f64 }) attributes {memory_effects = #llvm.memory_effects<other = readwrite, argMem = write, inaccessibleMem = readwrite, errnoMem = none, targetMem0 = none, targetMem1 = none>} {440 llvm.return441}442 443// CHECK-LABEL: llvm.func @test_byval_write_only444// CHECK-SAME: %[[PTR:[a-zA-Z0-9_]+]]: !llvm.ptr445// CHECK: %[[ALLOCA:.+]] = llvm.alloca %{{.+}} x f64446// CHECK: "llvm.intr.memcpy"(%[[ALLOCA]], %[[PTR]]447llvm.func @test_byval_write_only(%ptr : !llvm.ptr) {448 llvm.call @with_byval_arg(%ptr) : (!llvm.ptr) -> ()449 llvm.return450}451 452// -----453 454llvm.func @aligned_byval_arg(%ptr : !llvm.ptr { llvm.byval = i16, llvm.align = 16 }) attributes {memory_effects = #llvm.memory_effects<other = read, argMem = read, inaccessibleMem = read, errnoMem = none, targetMem0 = none, targetMem1 = none>} {455 llvm.return456}457 458// CHECK-LABEL: llvm.func @test_byval_input_aligned459// CHECK-SAME: %[[UNALIGNED:[a-zA-Z0-9_]+]]: !llvm.ptr460// CHECK-SAME: %[[ALIGNED:[a-zA-Z0-9_]+]]: !llvm.ptr461llvm.func @test_byval_input_aligned(%unaligned : !llvm.ptr, %aligned : !llvm.ptr { llvm.align = 16 }) {462 // Make sure only the unaligned input triggers a memcpy.463 // CHECK: %[[ALLOCA:.+]] = llvm.alloca %{{.+}} x i16 {alignment = 16464 // CHECK: "llvm.intr.memcpy"(%[[ALLOCA]], %[[UNALIGNED]]465 llvm.call @aligned_byval_arg(%unaligned) : (!llvm.ptr) -> ()466 // CHECK-NOT: memcpy467 llvm.call @aligned_byval_arg(%aligned) : (!llvm.ptr) -> ()468 llvm.return469}470 471// -----472 473llvm.func @func_that_uses_ptr(%ptr : !llvm.ptr)474 475llvm.func @aligned_byval_arg(%ptr : !llvm.ptr { llvm.byval = i16, llvm.align = 16 }) attributes {memory_effects = #llvm.memory_effects<other = read, argMem = read, inaccessibleMem = read, errnoMem = none, targetMem0 = none, targetMem1 = none>} {476 llvm.call @func_that_uses_ptr(%ptr) : (!llvm.ptr) -> ()477 llvm.return478}479 480// CHECK-LABEL: llvm.func @test_byval_realign_alloca481llvm.func @test_byval_realign_alloca() {482 %size = llvm.mlir.constant(4 : i64) : i64483 // CHECK-NOT: llvm.alloca{{.+}}alignment = 1484 // CHECK: llvm.alloca {{.+}}alignment = 16 : i64485 // CHECK-NOT: llvm.intr.memcpy486 %unaligned = llvm.alloca %size x i16 { alignment = 1 } : (i64) -> !llvm.ptr487 llvm.call @aligned_byval_arg(%unaligned) : (!llvm.ptr) -> ()488 llvm.return489}490 491// -----492 493module attributes {494 dlti.dl_spec = #dlti.dl_spec<#dlti.dl_entry<"dlti.stack_alignment", 32 : i32>>495} {496 497llvm.func @func_that_uses_ptr(%ptr : !llvm.ptr)498 499llvm.func @aligned_byval_arg(%ptr : !llvm.ptr { llvm.byval = i16, llvm.align = 16 }) attributes {memory_effects = #llvm.memory_effects<other = read, argMem = read, inaccessibleMem = read, errnoMem = none, targetMem0 = none, targetMem1 = none>} {500 llvm.call @func_that_uses_ptr(%ptr) : (!llvm.ptr) -> ()501 llvm.return502}503 504// CHECK-LABEL: llvm.func @test_exceeds_natural_stack_alignment505llvm.func @test_exceeds_natural_stack_alignment() {506 %size = llvm.mlir.constant(4 : i64) : i64507 // Natural stack alignment is exceeded, so prefer a copy instead of508 // triggering a dynamic stack realignment.509 // CHECK-DAG: %[[SRC:[a-zA-Z0-9_]+]] = llvm.alloca{{.+}}alignment = 2510 // CHECK-DAG: %[[DST:[a-zA-Z0-9_]+]] = llvm.alloca{{.+}}alignment = 16511 // CHECK: "llvm.intr.memcpy"(%[[DST]], %[[SRC]]512 %unaligned = llvm.alloca %size x i16 { alignment = 2 } : (i64) -> !llvm.ptr513 llvm.call @aligned_byval_arg(%unaligned) : (!llvm.ptr) -> ()514 llvm.return515}516 517}518 519// -----520 521module attributes {522 dlti.dl_spec = #dlti.dl_spec<#dlti.dl_entry<"dlti.stack_alignment", 32 : i32>>523} {524 525llvm.func @func_that_uses_ptr(%ptr : !llvm.ptr)526 527llvm.func @aligned_byval_arg(%ptr : !llvm.ptr { llvm.byval = i16, llvm.align = 16 }) attributes {memory_effects = #llvm.memory_effects<other = read, argMem = read, inaccessibleMem = read, errnoMem = none, targetMem0 = none, targetMem1 = none>} {528 llvm.call @func_that_uses_ptr(%ptr) : (!llvm.ptr) -> ()529 llvm.return530}531 532// CHECK-LABEL: llvm.func @test_alignment_exceeded_anyway533llvm.func @test_alignment_exceeded_anyway() {534 %size = llvm.mlir.constant(4 : i64) : i64535 // Natural stack alignment is lower than the target alignment, but the536 // alloca's existing alignment already exceeds it, so we might as well avoid537 // the copy.538 // CHECK-NOT: llvm.alloca{{.+}}alignment = 1539 // CHECK: llvm.alloca {{.+}}alignment = 16 : i64540 // CHECK-NOT: llvm.intr.memcpy541 %unaligned = llvm.alloca %size x i16 { alignment = 8 } : (i64) -> !llvm.ptr542 llvm.call @aligned_byval_arg(%unaligned) : (!llvm.ptr) -> ()543 llvm.return544}545 546}547 548// -----549 550llvm.mlir.global private @unaligned_global(42 : i64) : i64551llvm.mlir.global private @aligned_global(42 : i64) { alignment = 64 } : i64552 553llvm.func @aligned_byval_arg(%ptr : !llvm.ptr { llvm.byval = i16, llvm.align = 16 }) attributes {memory_effects = #llvm.memory_effects<other = read, argMem = read, inaccessibleMem = read, errnoMem = none, targetMem0 = none, targetMem1 = none>} {554 llvm.return555}556 557// CHECK-LABEL: llvm.func @test_byval_global558llvm.func @test_byval_global() {559 // Make sure only the unaligned global triggers a memcpy.560 // CHECK-DAG: %[[UNALIGNED:.+]] = llvm.mlir.addressof @unaligned_global561 // CHECK-DAG: %[[ALLOCA:.+]] = llvm.alloca562 // CHECK: "llvm.intr.memcpy"(%[[ALLOCA]], %[[UNALIGNED]]563 // CHECK-NOT: llvm.alloca564 %unaligned = llvm.mlir.addressof @unaligned_global : !llvm.ptr565 llvm.call @aligned_byval_arg(%unaligned) : (!llvm.ptr) -> ()566 %aligned = llvm.mlir.addressof @aligned_global : !llvm.ptr567 llvm.call @aligned_byval_arg(%aligned) : (!llvm.ptr) -> ()568 llvm.return569}570 571// -----572 573llvm.func @ignored_attrs(%ptr : !llvm.ptr { llvm.inreg, llvm.nocapture, llvm.nofree, llvm.preallocated = i32, llvm.returned, llvm.alignstack = 32 : i64, llvm.writeonly, llvm.noundef, llvm.nonnull }, %x : i32 { llvm.zeroext }) -> (!llvm.ptr { llvm.noundef, llvm.inreg, llvm.nonnull }) {574 llvm.return %ptr : !llvm.ptr575}576 577// CHECK-LABEL: @test_ignored_attrs578// CHECK-NOT: llvm.call579// CHECK-NEXT: llvm.return580llvm.func @test_ignored_attrs(%ptr : !llvm.ptr, %x : i32) {581 llvm.call @ignored_attrs(%ptr, %x) : (!llvm.ptr, i32) -> (!llvm.ptr)582 llvm.return583}584 585// -----586 587llvm.func @disallowed_arg_attr(%ptr : !llvm.ptr { llvm.inalloca = i64 }) {588 llvm.return589}590 591// CHECK-LABEL: @test_disallow_arg_attr592// CHECK-NEXT: llvm.call593llvm.func @test_disallow_arg_attr(%ptr : !llvm.ptr) {594 llvm.call @disallowed_arg_attr(%ptr) : (!llvm.ptr) -> ()595 llvm.return596}597 598// -----599 600#callee = #llvm.access_group<id = distinct[0]<>>601#caller = #llvm.access_group<id = distinct[1]<>>602 603llvm.func @inlinee(%ptr : !llvm.ptr) -> i32 {604 %0 = llvm.load %ptr { access_groups = [#callee] } : !llvm.ptr -> i32605 llvm.return %0 : i32606}607 608// CHECK-DAG: #[[$CALLEE:.*]] = #llvm.access_group<id = {{.*}}>609// CHECK-DAG: #[[$CALLER:.*]] = #llvm.access_group<id = {{.*}}>610 611// CHECK-LABEL: func @caller612// CHECK: llvm.load613// CHECK-SAME: access_groups = [#[[$CALLEE]], #[[$CALLER]]]614llvm.func @caller(%ptr : !llvm.ptr) -> i32 {615 %0 = llvm.call @inlinee(%ptr) { access_groups = [#caller] } : (!llvm.ptr) -> (i32)616 llvm.return %0 : i32617}618 619// -----620 621#caller = #llvm.access_group<id = distinct[1]<>>622 623llvm.func @inlinee(%ptr : !llvm.ptr) -> i32 {624 %0 = llvm.load %ptr : !llvm.ptr -> i32625 llvm.return %0 : i32626}627 628// CHECK-DAG: #[[$CALLER:.*]] = #llvm.access_group<id = {{.*}}>629 630// CHECK-LABEL: func @caller631// CHECK: llvm.load632// CHECK-SAME: access_groups = [#[[$CALLER]]]633// CHECK: llvm.store634// CHECK-SAME: access_groups = [#[[$CALLER]]]635llvm.func @caller(%ptr : !llvm.ptr) -> i32 {636 %c5 = llvm.mlir.constant(5 : i32) : i32637 %0 = llvm.call @inlinee(%ptr) { access_groups = [#caller] } : (!llvm.ptr) -> (i32)638 llvm.store %c5, %ptr { access_groups = [#caller] } : i32, !llvm.ptr639 llvm.return %0 : i32640}641 642// -----643 644llvm.func @vararg_func(...) {645 llvm.return646}647 648llvm.func @vararg_intrinrics() {649 %0 = llvm.mlir.constant(1 : i32) : i32650 %list = llvm.alloca %0 x !llvm.struct<"struct.va_list_opaque", (ptr)> : (i32) -> !llvm.ptr651 // The vararg intinriscs should normally be part of a variadic function.652 // However, this test uses a non-variadic function to ensure the presence of653 // the intrinsic alone suffices to prevent inlining.654 llvm.intr.vastart %list : !llvm.ptr655 llvm.return656}657 658// CHECK-LABEL: func @caller659llvm.func @caller() {660 // CHECK-NEXT: llvm.call @vararg_func()661 llvm.call @vararg_func() vararg(!llvm.func<void (...)>) : () -> ()662 // CHECK-NEXT: llvm.call @vararg_intrinrics()663 llvm.call @vararg_intrinrics() : () -> ()664 llvm.return665}666 667// -----668 669llvm.func @private_func(%a : i32) -> i32 attributes {sym_visibility = "private"} {670 llvm.return %a : i32671}672 673// CHECK-LABEL: func @caller674llvm.func @caller(%x : i32) -> i32 {675 // CHECK-NOT: llvm.call @private_func676 %z = llvm.call @private_func(%x) : (i32) -> (i32)677 llvm.return %z : i32678}679 680// -----681 682llvm.func @unreachable_func(%a : i32) -> i32 {683 "llvm.intr.trap"() : () -> ()684 llvm.unreachable685}686 687// CHECK-LABEL: func @caller688llvm.func @caller(%x : i32) -> i32 {689 // CHECK-NOT: llvm.call @unreachable_func690 // CHECK: llvm.intr.trap691 // CHECK: llvm.unreachable692 %z = llvm.call @unreachable_func(%x) : (i32) -> (i32)693 llvm.return %z : i32694}695 696// -----697// Check that @func is not inlined because of llvm.blocktag698 699func.func @func(%arg0 : i32) -> i32 {700 llvm.blocktag <id = 1>701 llvm.return %arg0 : i32702}703 704// CHECK-LABEL: @llvm_ret705func.func @llvm_ret(%arg0 : i32) -> i32 {706 // CHECK-NOT: llvm.blocktag707 // CHECK: %[[R:.*]] = call708 %res = call @func(%arg0) : (i32) -> (i32)709 // CHECK: return %[[R]]710 return %res : i32711}712