CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
273 lines
7.6 KiB
LLVM
273 lines
7.6 KiB
LLVM
; RUN: opt < %s -passes='cgscc(inline)' -inline-threshold=0 -S | FileCheck %s
|
|
|
|
; The 'test1_' prefixed functions test the basic 'last callsite' inline
|
|
; threshold adjustment where we specifically inline the last call site of an
|
|
; internal function regardless of cost.
|
|
|
|
define internal void @test1_f() {
|
|
entry:
|
|
%p = alloca i32
|
|
store volatile i32 0, ptr %p
|
|
store volatile i32 0, ptr %p
|
|
store volatile i32 0, ptr %p
|
|
store volatile i32 0, ptr %p
|
|
store volatile i32 0, ptr %p
|
|
store volatile i32 0, ptr %p
|
|
store volatile i32 0, ptr %p
|
|
store volatile i32 0, ptr %p
|
|
ret void
|
|
}
|
|
|
|
; Identical to @test1_f but doesn't get inlined because there is more than one
|
|
; call. If this *does* get inlined, the body used both here and in @test1_f
|
|
; isn't a good test for different threshold based on the last call.
|
|
define internal void @test1_g() {
|
|
entry:
|
|
%p = alloca i32
|
|
store volatile i32 0, ptr %p
|
|
store volatile i32 0, ptr %p
|
|
store volatile i32 0, ptr %p
|
|
store volatile i32 0, ptr %p
|
|
store volatile i32 0, ptr %p
|
|
store volatile i32 0, ptr %p
|
|
store volatile i32 0, ptr %p
|
|
store volatile i32 0, ptr %p
|
|
ret void
|
|
}
|
|
|
|
define void @test1() {
|
|
; CHECK-LABEL: define void @test1()
|
|
entry:
|
|
call void @test1_f()
|
|
; CHECK-NOT: @test1_f
|
|
|
|
call void @test1_g()
|
|
call void @test1_g()
|
|
; CHECK: call void @test1_g()
|
|
; CHECK: call void @test1_g()
|
|
|
|
ret void
|
|
}
|
|
|
|
|
|
; The 'test2_' prefixed functions test that we can discover the last callsite
|
|
; bonus after having inlined the prior call site. For this to work, we need
|
|
; a callsite dependent cost so we have a trivial predicate guarding all the
|
|
; cost, and set that in a particular direction.
|
|
|
|
define internal void @test2_f(i1 %b) {
|
|
entry:
|
|
%p = alloca i32
|
|
br i1 %b, label %then, label %exit
|
|
|
|
then:
|
|
store volatile i32 0, ptr %p
|
|
store volatile i32 0, ptr %p
|
|
store volatile i32 0, ptr %p
|
|
store volatile i32 0, ptr %p
|
|
store volatile i32 0, ptr %p
|
|
store volatile i32 0, ptr %p
|
|
store volatile i32 0, ptr %p
|
|
store volatile i32 0, ptr %p
|
|
br label %exit
|
|
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
; Identical to @test2_f but doesn't get inlined because there is more than one
|
|
; call. If this *does* get inlined, the body used both here and in @test2_f
|
|
; isn't a good test for different threshold based on the last call.
|
|
define internal void @test2_g(i1 %b) {
|
|
entry:
|
|
%p = alloca i32
|
|
br i1 %b, label %then, label %exit
|
|
|
|
then:
|
|
store volatile i32 0, ptr %p
|
|
store volatile i32 0, ptr %p
|
|
store volatile i32 0, ptr %p
|
|
store volatile i32 0, ptr %p
|
|
store volatile i32 0, ptr %p
|
|
store volatile i32 0, ptr %p
|
|
store volatile i32 0, ptr %p
|
|
store volatile i32 0, ptr %p
|
|
br label %exit
|
|
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
define void @test2() {
|
|
; CHECK-LABEL: define void @test2()
|
|
entry:
|
|
; The first call is trivial to inline due to the argument.
|
|
call void @test2_f(i1 false)
|
|
; CHECK-NOT: @test2_f
|
|
|
|
; The second call is too expensive to inline unless we update the number of
|
|
; calls after inlining the second.
|
|
call void @test2_f(i1 true)
|
|
; CHECK-NOT: @test2_f
|
|
|
|
; Check that two calls with the hard predicate remain uninlined.
|
|
call void @test2_g(i1 true)
|
|
call void @test2_g(i1 true)
|
|
; CHECK: call void @test2_g(i1 true)
|
|
; CHECK: call void @test2_g(i1 true)
|
|
|
|
ret void
|
|
}
|
|
|
|
|
|
; The 'test3_' prefixed functions are similar to the 'test2_' functions but the
|
|
; relative order of the trivial and hard to inline callsites is reversed. This
|
|
; checks that the order of calls isn't significant to whether we observe the
|
|
; "last callsite" threshold difference because the next-to-last gets inlined.
|
|
; FIXME: We don't currently catch this case.
|
|
|
|
define internal void @test3_f(i1 %b) {
|
|
entry:
|
|
%p = alloca i32
|
|
br i1 %b, label %then, label %exit
|
|
|
|
then:
|
|
store volatile i32 0, ptr %p
|
|
store volatile i32 0, ptr %p
|
|
store volatile i32 0, ptr %p
|
|
store volatile i32 0, ptr %p
|
|
store volatile i32 0, ptr %p
|
|
store volatile i32 0, ptr %p
|
|
store volatile i32 0, ptr %p
|
|
store volatile i32 0, ptr %p
|
|
br label %exit
|
|
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
; Identical to @test3_f but doesn't get inlined because there is more than one
|
|
; call. If this *does* get inlined, the body used both here and in @test3_f
|
|
; isn't a good test for different threshold based on the last call.
|
|
define internal void @test3_g(i1 %b) {
|
|
entry:
|
|
%p = alloca i32
|
|
br i1 %b, label %then, label %exit
|
|
|
|
then:
|
|
store volatile i32 0, ptr %p
|
|
store volatile i32 0, ptr %p
|
|
store volatile i32 0, ptr %p
|
|
store volatile i32 0, ptr %p
|
|
store volatile i32 0, ptr %p
|
|
store volatile i32 0, ptr %p
|
|
store volatile i32 0, ptr %p
|
|
store volatile i32 0, ptr %p
|
|
br label %exit
|
|
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
define void @test3() {
|
|
; CHECK-LABEL: define void @test3()
|
|
entry:
|
|
; The first call is too expensive to inline unless we update the number of
|
|
; calls after inlining the second.
|
|
call void @test3_f(i1 true)
|
|
; FIXME: We should inline this call without iteration.
|
|
; CHECK: call void @test3_f(i1 true)
|
|
|
|
; But the second call is trivial to inline due to the argument.
|
|
call void @test3_f(i1 false)
|
|
; CHECK-NOT: @test3_f
|
|
|
|
; Check that two calls with the hard predicate remain uninlined.
|
|
call void @test3_g(i1 true)
|
|
call void @test3_g(i1 true)
|
|
; CHECK: call void @test3_g(i1 true)
|
|
; CHECK: call void @test3_g(i1 true)
|
|
|
|
ret void
|
|
}
|
|
|
|
|
|
; The 'test4_' prefixed functions are similar to the 'test2_' prefixed
|
|
; functions but include unusual constant expressions that make discovering that
|
|
; a function is dead harder.
|
|
|
|
define internal void @test4_f(i64 %a, i64 %b) {
|
|
entry:
|
|
%p = alloca i32
|
|
%cmp = icmp ne i64 %a, %b
|
|
br i1 %cmp, label %then, label %exit
|
|
|
|
then:
|
|
store volatile i32 0, ptr %p
|
|
store volatile i32 0, ptr %p
|
|
store volatile i32 0, ptr %p
|
|
store volatile i32 0, ptr %p
|
|
store volatile i32 0, ptr %p
|
|
store volatile i32 0, ptr %p
|
|
store volatile i32 0, ptr %p
|
|
store volatile i32 0, ptr %p
|
|
br label %exit
|
|
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
; Identical to @test4_f but doesn't get inlined because there is more than one
|
|
; call. If this *does* get inlined, the body used both here and in @test4_f
|
|
; isn't a good test for different threshold based on the last call.
|
|
define internal void @test4_g(i1 %b) {
|
|
entry:
|
|
%p = alloca i32
|
|
br i1 %b, label %then, label %exit
|
|
|
|
then:
|
|
store volatile i32 0, ptr %p
|
|
store volatile i32 0, ptr %p
|
|
store volatile i32 0, ptr %p
|
|
store volatile i32 0, ptr %p
|
|
store volatile i32 0, ptr %p
|
|
store volatile i32 0, ptr %p
|
|
store volatile i32 0, ptr %p
|
|
store volatile i32 0, ptr %p
|
|
br label %exit
|
|
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
define void @test4() {
|
|
; CHECK-LABEL: define void @test4()
|
|
entry:
|
|
; The first call is trivial to inline due to the argument. However this
|
|
; argument also uses the function being called as part of a complex
|
|
; constant expression. Merely inlining and deleting the call isn't enough to
|
|
; drop the use count here, we need to GC the dead constant expression as
|
|
; well.
|
|
call void @test4_f(i64 ptrtoint (ptr @test4_f to i64), i64 ptrtoint(ptr @test4_f to i64))
|
|
; CHECK-NOT: @test4_f
|
|
|
|
; The second call is too expensive to inline unless we update the number of
|
|
; calls after inlining the second.
|
|
call void @test4_f(i64 0, i64 1)
|
|
; CHECK-NOT: @test4_f
|
|
|
|
; And check that a single call to a function which is used by a complex
|
|
; constant expression cannot be inlined because the constant expression forms
|
|
; a second use. If this part starts failing we need to use more complex
|
|
; constant expressions to reference a particular function with them.
|
|
%sink = alloca i64
|
|
%mul = mul i64 ptrtoint (ptr @test4_g to i64), ptrtoint(ptr @test4_g to i64)
|
|
store volatile i64 %mul, ptr %sink
|
|
call void @test4_g(i1 true)
|
|
; CHECK: %mul = mul i64 ptrtoint (ptr @test4_g to i64), ptrtoint (ptr @test4_g to i64)
|
|
; CHECK: store volatile i64 %mul, ptr %sink
|
|
; CHECK: call void @test4_g(i1 true)
|
|
|
|
ret void
|
|
}
|