Currently code extractor uses parameters to pass outputs. Alloca/store/load instructions are used to get the output value in the parent functions. When there is only one output from the extracted code (this is one of the most common cases), using the function return for the only one output can facilitate the other transformations (eg, tail call opt). This is to modify the code for the extracted function to return the output value if there is only one output for the extracted region.
87 lines
2.5 KiB
LLVM
87 lines
2.5 KiB
LLVM
; RUN: opt < %s -S -passes=partial-inliner -skip-partial-inlining-cost-analysis=true | FileCheck %s
|
|
|
|
|
|
define i32 @callee_most(i32 %v) unnamed_addr #0 #1 {
|
|
entry:
|
|
%cmp = icmp sgt i32 %v, 2000
|
|
br i1 %cmp, label %if.then, label %if.end
|
|
|
|
if.then:
|
|
br label %if.then2
|
|
|
|
if.then2:
|
|
%sub = sub i32 %v, 10
|
|
br label %if.end
|
|
|
|
if.end:
|
|
%v2 = phi i32 [ %v, %entry ], [ %sub, %if.then2 ]
|
|
%add = add nsw i32 %v2, 200
|
|
ret i32 %add
|
|
}
|
|
|
|
define i32 @callee_noinline(i32 %v) optnone noinline {
|
|
entry:
|
|
%cmp = icmp sgt i32 %v, 2000
|
|
br i1 %cmp, label %if.then, label %if.end
|
|
|
|
if.then:
|
|
br label %if.then2
|
|
|
|
if.then2:
|
|
%sub = sub i32 %v, 10
|
|
br label %if.end
|
|
|
|
if.end:
|
|
%v2 = phi i32 [ %v, %entry ], [ %sub, %if.then2 ]
|
|
%add = add nsw i32 %v2, 200
|
|
ret i32 %add
|
|
}
|
|
|
|
define i32 @callee_writeonly(i32 %v) writeonly ssp {
|
|
entry:
|
|
%cmp = icmp sgt i32 %v, 2000
|
|
br i1 %cmp, label %if.then, label %if.end
|
|
|
|
if.then:
|
|
br label %if.then2
|
|
|
|
if.then2:
|
|
%sub = sub i32 %v, 10
|
|
br label %if.end
|
|
|
|
if.end:
|
|
%v2 = phi i32 [ %v, %entry ], [ %sub, %if.then2 ]
|
|
%add = add nsw i32 %v2, 200
|
|
ret i32 %add
|
|
}
|
|
; CHECK-LABEL: @caller
|
|
; CHECK: call i32 @callee_most.2.if.then(i32 %v
|
|
; CHECK: call i32 @callee_noinline(i32 %v)
|
|
; CHECK: call i32 @callee_writeonly.1.if.then(i32 %v
|
|
define i32 @caller(i32 %v) ssp {
|
|
entry:
|
|
%c1 = call i32 @callee_most(i32 %v)
|
|
%c2 = call i32 @callee_noinline(i32 %v)
|
|
%c3 = call i32 @callee_writeonly(i32 %v)
|
|
ret i32 %c3
|
|
}
|
|
|
|
; CHECK: define internal i32 @callee_writeonly.1.if.then(i32 %v) [[FN_ATTRS0:#[0-9]+]]
|
|
; CHECK: define internal i32 @callee_most.2.if.then(i32 %v) [[FN_ATTRS:#[0-9]+]]
|
|
|
|
; attributes to preserve
|
|
attributes #0 = {
|
|
inlinehint minsize noduplicate noimplicitfloat norecurse noredzone nounwind
|
|
nonlazybind optsize safestack sanitize_address sanitize_hwaddress sanitize_memory
|
|
sanitize_thread ssp sspreq sspstrong uwtable "foo"="bar"
|
|
"patchable-function"="prologue-short-redirect" "probe-stack"="_foo_guard" "stack-probe-size"="4096" }
|
|
|
|
; CHECK: attributes [[FN_ATTRS0]] = { ssp
|
|
; CHECK: attributes [[FN_ATTRS]] = { inlinehint minsize noduplicate noimplicitfloat norecurse noredzone nounwind nonlazybind optsize safestack sanitize_address sanitize_hwaddress sanitize_memory sanitize_thread ssp sspreq sspstrong uwtable "foo"="bar" "patchable-function"="prologue-short-redirect" "probe-stack"="_foo_guard" "stack-probe-size"="4096" }
|
|
|
|
; attributes to drop
|
|
attributes #1 = {
|
|
alignstack=16 convergent inaccessiblememonly inaccessiblemem_or_argmemonly
|
|
noreturn readonly argmemonly returns_twice speculatable "thunk"
|
|
}
|