diff --git a/llvm/include/llvm/Transforms/IPO/IROutliner.h b/llvm/include/llvm/Transforms/IPO/IROutliner.h --- a/llvm/include/llvm/Transforms/IPO/IROutliner.h +++ b/llvm/include/llvm/Transforms/IPO/IROutliner.h @@ -318,8 +318,6 @@ // analyzed for similarity as it has no bearing on the outcome of the // program. bool visitDbgInfoIntrinsic(DbgInfoIntrinsic &DII) { return true; } - // TODO: Handle GetElementPtrInsts - bool visitGetElementPtrInst(GetElementPtrInst &GEPI) { return false; } // TODO: Handle specific intrinsics individually from those that can be // handled. bool IntrinsicInst(IntrinsicInst &II) { return false; } diff --git a/llvm/test/Transforms/IROutliner/illegal-gep.ll b/llvm/test/Transforms/IROutliner/illegal-gep.ll deleted file mode 100644 --- a/llvm/test/Transforms/IROutliner/illegal-gep.ll +++ /dev/null @@ -1,50 +0,0 @@ -; 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 to make sure that we do not outline getelementptr -; instructions since we must make extra checks on the final operands. - -%struct.RT = type { i8, [10 x [20 x i32]], i8 } -%struct.ST = type { i32, double, %struct.RT } - -define void @function1(%struct.ST* %s, i64 %t) { -; CHECK-LABEL: @function1( -; CHECK-NEXT: entry: -; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4 -; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4 -; CHECK-NEXT: store i32 2, i32* [[A]], align 4 -; CHECK-NEXT: store i32 3, i32* [[B]], align 4 -; CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[STRUCT_ST:%.*]], %struct.ST* [[S:%.*]], i64 1 -; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds [[STRUCT_ST]], %struct.ST* [[S]], i64 [[T:%.*]] -; CHECK-NEXT: ret void -; -entry: - %a = alloca i32, align 4 - %b = alloca i32, align 4 - store i32 2, i32* %a, align 4 - store i32 3, i32* %b, align 4 - %0 = getelementptr inbounds %struct.ST, %struct.ST* %s, i64 1 - %1 = getelementptr inbounds %struct.ST, %struct.ST* %s, i64 %t - ret void -} - -define void @function2(%struct.ST* %s, i64 %t) { -; CHECK-LABEL: @function2( -; CHECK-NEXT: entry: -; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4 -; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4 -; CHECK-NEXT: store i32 2, i32* [[A]], align 4 -; CHECK-NEXT: store i32 3, i32* [[B]], align 4 -; CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[STRUCT_ST:%.*]], %struct.ST* [[S:%.*]], i64 1 -; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds [[STRUCT_ST]], %struct.ST* [[S]], i64 [[T:%.*]] -; CHECK-NEXT: ret void -; -entry: - %a = alloca i32, align 4 - %b = alloca i32, align 4 - store i32 2, i32* %a, align 4 - store i32 3, i32* %b, align 4 - %0 = getelementptr inbounds %struct.ST, %struct.ST* %s, i64 1 - %1 = getelementptr inbounds %struct.ST, %struct.ST* %s, i64 %t - ret void -} diff --git a/llvm/test/Transforms/IROutliner/outlining-gep.ll b/llvm/test/Transforms/IROutliner/outlining-gep.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/IROutliner/outlining-gep.ll @@ -0,0 +1,68 @@ +; 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 to make sure that we outline getelementptr instructions only +; when all the operands after the first are the exact same. In this case, we +; outline from the first two functions, but not the third. + +%struct.RT = type { i8, [10 x [20 x i32]], i8 } +%struct.ST = type { i32, double, %struct.RT } + +define void @function1(%struct.ST* %s, i64 %t) { +; CHECK-LABEL: @function1( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4 +; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4 +; CHECK-NEXT: call void @outlined_ir_func_0(i32* [[A]], i32* [[B]], %struct.ST* [[S:%.*]], i64 [[T:%.*]]) +; CHECK-NEXT: ret void +; +entry: + %a = alloca i32, align 4 + %b = alloca i32, align 4 + store i32 2, i32* %a, align 4 + store i32 3, i32* %b, align 4 + %0 = getelementptr inbounds %struct.ST, %struct.ST* %s, i64 %t, i32 1 + ret void +} + +define void @function2(%struct.ST* %s, i64 %t) { +; CHECK-LABEL: @function2( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4 +; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4 +; CHECK-NEXT: call void @outlined_ir_func_0(i32* [[A]], i32* [[B]], %struct.ST* [[S:%.*]], i64 [[T:%.*]]) +; CHECK-NEXT: ret void +; +entry: + %a = alloca i32, align 4 + %b = alloca i32, align 4 + store i32 2, i32* %a, align 4 + store i32 3, i32* %b, align 4 + %0 = getelementptr inbounds %struct.ST, %struct.ST* %s, i64 %t, i32 1 + ret void +} + +define void @function3(%struct.ST* %s, i64 %t) { +; CHECK-LABEL: @function3( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4 +; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4 +; CHECK-NEXT: store i32 2, i32* [[A]], align 4 +; CHECK-NEXT: store i32 3, i32* [[B]], align 4 +; CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[STRUCT_ST:%.*]], %struct.ST* [[S:%.*]], i64 [[T:%.*]], i32 0 +; CHECK-NEXT: ret void +; +entry: + %a = alloca i32, align 4 + %b = alloca i32, align 4 + store i32 2, i32* %a, align 4 + store i32 3, i32* %b, align 4 + %0 = getelementptr inbounds %struct.ST, %struct.ST* %s, i64 %t, i32 0 + ret void +} + +; CHECK: define internal void @outlined_ir_func_0(i32* [[ARG0:%.*]], i32* [[ARG1:%.*]], %struct.ST* [[ARG2:%.*]], i64 [[ARG3:%.*]]) +; CHECK: entry_to_outline: +; CHECK-NEXT: store i32 2, i32* [[ARG0]], align 4 +; CHECK-NEXT: store i32 3, i32* [[ARG1]], align 4 +; CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds %struct.ST, %struct.ST* [[ARG2]], i64 [[ARG3]], i32 1