reference, declarationdefinition
definition → references, declarations, derived classes, virtual overrides
reference to multiple definitions → definitions
unreferenced
    1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
  137
  138
  139
  140
  141
  142
  143
  144
  145
  146
  147
  148
  149
  150
  151
  152
  153
  154
  155
  156
  157
  158
  159
  160
  161
  162
  163
  164
  165
  166
  167
  168
  169
  170
  171
  172
  173
  174
  175
  176
  177
  178
  179
  180
  181
  182
  183
  184
; RUN: opt < %s -aa-pipeline=basic-aa -passes='cgscc(function-attrs,inline)' -S | FileCheck %s
; This test runs the inliner and the function attribute deduction. It ensures
; that when the inliner mutates the call graph it correctly updates the CGSCC
; iteration so that we can compute refined function attributes. In this way it
; is leveraging function attribute computation to observe correct call graph
; updates.

; Boring unknown external function call.
; CHECK: declare void @unknown()
declare void @unknown()

; Sanity check: this should get annotated as readnone.
; CHECK: Function Attrs: nounwind readnone
; CHECK-NEXT: declare void @readnone()
declare void @readnone() readnone nounwind

; The 'test1_' prefixed functions are designed to trigger forming a new direct
; call in the inlined body of the function. After that, we form a new SCC and
; using that can deduce precise function attrs.

; This function should no longer exist.
; CHECK-NOT: @test1_f()
define internal void @test1_f(void()* %p) {
entry:
  call void %p()
  ret void
}

; This function should have had 'readnone' deduced for its SCC.
; CHECK: Function Attrs: noinline nounwind readnone
; CHECK-NEXT: define void @test1_g()
define void @test1_g() noinline {
entry:
  call void @test1_f(void()* @test1_h)
  ret void
}

; This function should have had 'readnone' deduced for its SCC.
; CHECK: Function Attrs: noinline nounwind readnone
; CHECK-NEXT: define void @test1_h()
define void @test1_h() noinline {
entry:
  call void @test1_g()
  call void @readnone()
  ret void
}


; The 'test2_' prefixed functions are designed to trigger forming a new direct
; call due to RAUW-ing the returned value of a called function into the caller.
; This too should form a new SCC which can then be reasoned about to compute
; precise function attrs.

; This function should no longer exist.
; CHECK-NOT: @test2_f()
define internal void()* @test2_f() {
entry:
  ret void()* @test2_h
}

; This function should have had 'readnone' deduced for its SCC.
; CHECK: Function Attrs: noinline nounwind readnone
; CHECK-NEXT: define void @test2_g()
define void @test2_g() noinline {
entry:
  %p = call void()* @test2_f()
  call void %p()
  ret void
}

; This function should have had 'readnone' deduced for its SCC.
; CHECK: Function Attrs: noinline nounwind readnone
; CHECK-NEXT: define void @test2_h()
define void @test2_h() noinline {
entry:
  call void @test2_g()
  call void @readnone()
  ret void
}


; The 'test3_' prefixed functions are designed to inline in a way that causes
; call sites to become trivially dead during the middle of inlining callsites of
; a single function to make sure that the inliner does not get confused by this
; pattern.

; CHECK-NOT: @test3_maybe_unknown(
define internal void @test3_maybe_unknown(i1 %b) {
entry:
  br i1 %b, label %then, label %exit

then:
  call void @unknown()
  br label %exit

exit:
  ret void
}

; CHECK-NOT: @test3_f(
define internal i1 @test3_f() {
entry:
  ret i1 false
}

; CHECK-NOT: @test3_g(
define internal i1 @test3_g(i1 %b) {
entry:
  br i1 %b, label %then1, label %if2

then1:
  call void @test3_maybe_unknown(i1 true)
  br label %if2

if2:
  %f = call i1 @test3_f()
  br i1 %f, label %then2, label %exit

then2:
  call void @test3_maybe_unknown(i1 true)
  br label %exit

exit:
  ret i1 false
}

; FIXME: Currently the inliner doesn't successfully mark this as readnone
; because while it simplifies trivially dead CFGs when inlining callees it
; doesn't simplify the caller's trivially dead CFG and so we end with a dead
; block calling @unknown.
; CHECK-NOT: Function Attrs: readnone
; CHECK: define void @test3_h()
define void @test3_h() {
entry:
  %g = call i1 @test3_g(i1 false)
  br i1 %g, label %then, label %exit

then:
  call void @test3_maybe_unknown(i1 true)
  br label %exit

exit:
  call void @test3_maybe_unknown(i1 false)
  ret void
}


; The 'test4_' prefixed functions are designed to trigger forming a new direct
; call in the inlined body of the function similar to 'test1_'. However, after
; that we continue to inline another edge of the graph forcing us to do a more
; interesting call graph update for the new call edge. Eventually, we still
; form a new SCC and should use that can deduce precise function attrs.

; This function should have had 'readnone' deduced for its SCC.
; CHECK: Function Attrs: noinline nounwind readnone
; CHECK-NEXT: define void @test4_f1()
define void @test4_f1() noinline {
entry:
  call void @test4_h()
  ret void
}

; CHECK-NOT: @test4_f2
define internal void @test4_f2() {
entry:
  call void @test4_f1()
  ret void
}

; CHECK-NOT: @test4_g
define internal void @test4_g(void()* %p) {
entry:
  call void %p()
  ret void
}

; This function should have had 'readnone' deduced for its SCC.
; CHECK: Function Attrs: noinline nounwind readnone
; CHECK-NEXT: define void @test4_h()
define void @test4_h() noinline {
entry:
  call void @test4_g(void()* @test4_f2)
  ret void
}