The outliner currently requires that function calls not be indirect calls, and have that the function name, and function type must match, as well as other attributes such as calling conventions. This patch treats called functions as values, and just another operand, and named function calls as constants. This allows functions to be treated like any other constant, or input and output into the outlined functions. There are also debugging flags added to enforce the old behaviors where indirect calls not be allowed, and to enforce the old rule that function calls names must also match. Reviewers: paquette, jroelofs Differential Revision: https://reviews.llvm.org/D109448
97 lines
3.0 KiB
LLVM
97 lines
3.0 KiB
LLVM
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --include-generated-funcs
|
|
; RUN: opt -S -verify -iroutliner -ir-outlining-no-cost < %s | FileCheck %s
|
|
|
|
; This test checks that we do can outline calls, but only if they have the same
|
|
; function type and the same name.
|
|
|
|
declare void @f1(i32*, i32*);
|
|
declare void @f2(i32*, i32*);
|
|
|
|
define void @function1() {
|
|
entry:
|
|
%a = alloca i32, align 4
|
|
%b = alloca i32, align 4
|
|
%c = alloca i32, align 4
|
|
store i32 2, i32* %a, align 4
|
|
store i32 3, i32* %b, align 4
|
|
store i32 4, i32* %c, align 4
|
|
call void @f1(i32* %a, i32* %b)
|
|
%al = load i32, i32* %a
|
|
%bl = load i32, i32* %b
|
|
%cl = load i32, i32* %c
|
|
ret void
|
|
}
|
|
|
|
define void @function2() {
|
|
entry:
|
|
%a = alloca i32, align 4
|
|
%b = alloca i32, align 4
|
|
%c = alloca i32, align 4
|
|
store i32 2, i32* %a, align 4
|
|
store i32 3, i32* %b, align 4
|
|
store i32 4, i32* %c, align 4
|
|
call void @f1(i32* %a, i32* %b)
|
|
%al = load i32, i32* %a
|
|
%bl = load i32, i32* %b
|
|
%cl = load i32, i32* %c
|
|
ret void
|
|
}
|
|
|
|
define void @function3() {
|
|
entry:
|
|
%a = alloca i32, align 4
|
|
%b = alloca i32, align 4
|
|
%c = alloca i32, align 4
|
|
store i32 2, i32* %a, align 4
|
|
store i32 3, i32* %b, align 4
|
|
store i32 4, i32* %c, align 4
|
|
call void @f2(i32* %a, i32* %b)
|
|
%al = load i32, i32* %a
|
|
%bl = load i32, i32* %b
|
|
%cl = load i32, i32* %c
|
|
ret void
|
|
}
|
|
|
|
; CHECK-LABEL: @function1(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
|
|
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
|
|
; CHECK-NEXT: [[C:%.*]] = alloca i32, align 4
|
|
; CHECK-NEXT: call void @outlined_ir_func_0(i32* [[A]], i32* [[B]], i32* [[C]], void (i32*, i32*)* @f1)
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
;
|
|
; CHECK-LABEL: @function2(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
|
|
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
|
|
; CHECK-NEXT: [[C:%.*]] = alloca i32, align 4
|
|
; CHECK-NEXT: call void @outlined_ir_func_0(i32* [[A]], i32* [[B]], i32* [[C]], void (i32*, i32*)* @f1)
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
;
|
|
; CHECK-LABEL: @function3(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
|
|
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
|
|
; CHECK-NEXT: [[C:%.*]] = alloca i32, align 4
|
|
; CHECK-NEXT: call void @outlined_ir_func_0(i32* [[A]], i32* [[B]], i32* [[C]], void (i32*, i32*)* @f2)
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
;
|
|
; CHECK-LABEL: define internal void @outlined_ir_func_0(
|
|
; CHECK-NEXT: newFuncRoot:
|
|
; CHECK-NEXT: br label [[ENTRY_TO_OUTLINE:%.*]]
|
|
; CHECK: entry_to_outline:
|
|
; CHECK-NEXT: store i32 2, i32* [[TMP0:%.*]], align 4
|
|
; CHECK-NEXT: store i32 3, i32* [[TMP1:%.*]], align 4
|
|
; CHECK-NEXT: store i32 4, i32* [[TMP2:%.*]], align 4
|
|
; CHECK-NEXT: call void [[TMP3:%.*]](i32* [[TMP0]], i32* [[TMP1]])
|
|
; CHECK-NEXT: [[AL:%.*]] = load i32, i32* [[TMP0]], align 4
|
|
; CHECK-NEXT: [[BL:%.*]] = load i32, i32* [[TMP1]], align 4
|
|
; CHECK-NEXT: [[CL:%.*]] = load i32, i32* [[TMP2]], align 4
|
|
; CHECK-NEXT: br label [[ENTRY_AFTER_OUTLINE_EXITSTUB:%.*]]
|
|
; CHECK: entry_after_outline.exitStub:
|
|
; CHECK-NEXT: ret void
|
|
;
|