[llvm] 57a4691 - [IRSim][IROutliner] Allowing call instructions to be outlined.

Andrew Litteken via llvm-commits llvm-commits at lists.llvm.org
Thu Dec 31 21:30:05 PST 2020


Author: Andrew Litteken
Date: 2020-12-31T23:01:29-06:00
New Revision: 57a46914f5c1efbdc130dc7a06f8d5b45d606f8d

URL: https://github.com/llvm/llvm-project/commit/57a46914f5c1efbdc130dc7a06f8d5b45d606f8d
DIFF: https://github.com/llvm/llvm-project/commit/57a46914f5c1efbdc130dc7a06f8d5b45d606f8d.diff

LOG: [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

Added: 
    llvm/test/Transforms/IROutliner/illegal-indirect-calls.ll
    llvm/test/Transforms/IROutliner/outlining-calls.ll

Modified: 
    llvm/include/llvm/Transforms/IPO/IROutliner.h

Removed: 
    llvm/test/Transforms/IROutliner/illegal-calls.ll


################################################################################
diff  --git a/llvm/include/llvm/Transforms/IPO/IROutliner.h b/llvm/include/llvm/Transforms/IPO/IROutliner.h
index fef02b18b7c3..0346803e9ad7 100644
--- a/llvm/include/llvm/Transforms/IPO/IROutliner.h
+++ b/llvm/include/llvm/Transforms/IPO/IROutliner.h
@@ -321,9 +321,14 @@ class IROutliner {
     // 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 
diff erently.

diff  --git a/llvm/test/Transforms/IROutliner/illegal-calls.ll b/llvm/test/Transforms/IROutliner/illegal-indirect-calls.ll
similarity index 60%
rename from llvm/test/Transforms/IROutliner/illegal-calls.ll
rename to llvm/test/Transforms/IROutliner/illegal-indirect-calls.ll
index 18d37c2f4dc0..513fa60dc625 100644
--- a/llvm/test/Transforms/IROutliner/illegal-calls.ll
+++ b/llvm/test/Transforms/IROutliner/illegal-indirect-calls.ll
@@ -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

diff  --git a/llvm/test/Transforms/IROutliner/outlining-calls.ll b/llvm/test/Transforms/IROutliner/outlining-calls.ll
new file mode 100644
index 000000000000..c19ff28cc25a
--- /dev/null
+++ b/llvm/test/Transforms/IROutliner/outlining-calls.ll
@@ -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


        


More information about the llvm-commits mailing list