[IRSim][IROutliner] Allowing call instructions to be outlined.

We add an extra check to make sure that we do not outline calls to
indirect functions, but outline whatever the IRSimilarityIdentifier
finds with respect to calls.

Tests:
Removing test/Transforms/IROutliner/illegal-calls.ll
Adding test/Transforms/IROutliner/outlining-calls.ll
Adding test/Transforms/IROutliner/illegal-indirect-calls.ll

Excluding DebugInfo this is the last patch for the initial
implementation of the IROutliner!

Reviewers: jroelofs, paquette

Differential Revision: https://reviews.llvm.org/D87314
This commit is contained in:
Andrew Litteken 2020-09-08 13:42:56 -05:00
parent 0d21e66014
commit 57a46914f5
3 changed files with 115 additions and 20 deletions

View File

@ -321,9 +321,14 @@ private:
// TODO: Handle specific intrinsics individually from those that can be
// handled.
bool IntrinsicInst(IntrinsicInst &II) { return false; }
// TODO: Handle CallInsts, there will need to be handling for special kinds
// of calls, as well as calls to intrinsics.
bool visitCallInst(CallInst &CI) { return false; }
// We only handle CallInsts that are not indirect, since we cannot guarantee
// that they have a name in these cases.
bool visitCallInst(CallInst &CI) {
Function *F = CI.getCalledFunction();
if (!F || CI.isIndirectCall() || !F->hasName())
return false;
return true;
}
// TODO: Handle FreezeInsts. Since a frozen value could be frozen inside
// the outlined region, and then returned as an output, this will have to be
// handled differently.

View File

@ -1,22 +1,21 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -S -verify -iroutliner -ir-outlining-no-cost < %s | FileCheck %s
; This test checks that we do not outline calls. Special calls, such as
; indirect or nameless calls require extra handling to ensure that there
; are no inconsistencies when outlining and consolidating regions.
; This test checks that we do not outline indirect calls. We cannot guarantee
; that we have the same name in these cases, so two indirect calls cannot
; be considered similar.
declare void @f1(i32*, i32*);
declare void @f2(i32*, i32*);
define void @outline_constants1() {
; CHECK-LABEL: @outline_constants1(
define void @function1(void()* %func) {
; 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: store i32 2, i32* [[A]], align 4
; CHECK-NEXT: store i32 3, i32* [[B]], align 4
; CHECK-NEXT: store i32 4, i32* [[C]], align 4
; CHECK-NEXT: call void @f1(i32* [[A]], i32* [[B]])
; CHECK-NEXT: call void @outlined_ir_func_1(i32* [[A]], i32* [[B]], i32* [[C]])
; CHECK-NEXT: call void [[FUNC:%.*]]()
; CHECK-NEXT: call void @outlined_ir_func_0(i32* [[A]], i32* [[B]], i32* [[C]])
; CHECK-NEXT: ret void
;
@ -27,23 +26,21 @@ entry:
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)
call void %func()
%al = load i32, i32* %a
%bl = load i32, i32* %b
%cl = load i32, i32* %c
ret void
}
define void @outline_constants2() {
; CHECK-LABEL: @outline_constants2(
define void @function2(void()* %func) {
; 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: store i32 2, i32* [[A]], align 4
; CHECK-NEXT: store i32 3, i32* [[B]], align 4
; CHECK-NEXT: store i32 4, i32* [[C]], align 4
; CHECK-NEXT: call void @f1(i32* [[A]], i32* [[B]])
; CHECK-NEXT: call void @outlined_ir_func_1(i32* [[A]], i32* [[B]], i32* [[C]])
; CHECK-NEXT: call void [[FUNC:%.*]]()
; CHECK-NEXT: call void @outlined_ir_func_0(i32* [[A]], i32* [[B]], i32* [[C]])
; CHECK-NEXT: ret void
;
@ -54,7 +51,7 @@ entry:
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)
call void %func()
%al = load i32, i32* %a
%bl = load i32, i32* %b
%cl = load i32, i32* %c

View File

@ -0,0 +1,93 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -S -verify -iroutliner < %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() {
; 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]])
; CHECK-NEXT: ret void
;
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() {
; 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]])
; CHECK-NEXT: ret void
;
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() {
; 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: store i32 2, i32* [[A]], align 4
; CHECK-NEXT: store i32 3, i32* [[B]], align 4
; CHECK-NEXT: store i32 4, i32* [[C]], align 4
; CHECK-NEXT: call void @f2(i32* [[A]], i32* [[B]])
; CHECK-NEXT: [[AL:%.*]] = load i32, i32* [[A]], align 4
; CHECK-NEXT: [[BL:%.*]] = load i32, i32* [[B]], align 4
; CHECK-NEXT: [[CL:%.*]] = load i32, i32* [[C]], align 4
; CHECK-NEXT: ret void
;
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: define internal void @outlined_ir_func_0(i32* [[ARG0:%.*]], i32* [[ARG1:%.*]], i32* [[ARG2:%.*]])
; CHECK: entry_to_outline:
; CHECK-NEXT: store i32 2, i32* [[ARG0]], align 4
; CHECK-NEXT: store i32 3, i32* [[ARG1]], align 4
; CHECK-NEXT: store i32 4, i32* [[ARG2]], align 4
; CHECK-NEXT: call void @f1(i32* [[ARG0]], i32* [[ARG1]])
; CHECK-NEXT: [[AL:%.*]] = load i32, i32* [[ARG0]], align 4
; CHECK-NEXT: [[BL:%.*]] = load i32, i32* [[ARG1]], align 4
; CHECK-NEXT: [[CL:%.*]] = load i32, i32* [[ARG2]], align 4