llvm-project/llvm/test/Transforms/IROutliner/exit-block-phi-node-value-attribution.ll
Andrew Litteken c79ab1065e [IROutliner] Separate split PHI nodes from multiple exits by different outlinable regions.
The IR Outliner is supposed to extract the outputs contained in an external phi node and place them into a phi node contained within the outlined function. However, when the output values of two outlined functions with two different output sets are contained within the same phi node, they are counted as the same exit path when first analyzed. In reality, these create two different phi nodes, creating an inconsistency, resulting in a mismatch in the expected number of output paths and a crash.  This fixes that counting when analyzing the outputs by also analyzing the incoming blocks rather than just the incoming values.

Reviewer: paquette

Differential Revision: https://reviews.llvm.org/D121313
2022-03-14 14:56:59 -05:00

99 lines
3.7 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
; Make sure that each outlined region only analyzes on the incoming values in exit
; block phi nodes that come from the outlined region. Without this, more incoming
; values from the phi node would be considered if the incoming value is
; included in the outlined region. This is particularly likely to happen for
; constants.
define void @f1() {
bb1:
%0 = add i32 1, 2
%1 = add i32 3, 4
%2 = add i32 5, 6
%3 = add i32 7, 8
br label %bb5
bb2:
%4 = mul i32 5, 4
br label %bb5
placeholder:
%a = sub i32 5, 4
br label %bb5
bb3:
%5 = add i32 1, 2
%6 = add i32 3, 4
%7 = add i32 5, 6
%8 = add i32 7, 8
br label %bb5
bb4:
%9 = mul i32 5, 4
br label %bb5
placeholder1:
%b = add i32 5, 4
ret void
bb5:
%phinode = phi i32 [5, %placeholder], [5, %bb1], [5, %bb2], [4, %bb3], [4, %bb4]
ret void
}
; CHECK-LABEL: @f1(
; CHECK-NEXT: bb1:
; CHECK-NEXT: [[PHINODE_CE_LOC1:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[PHINODE_CE_LOC:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[LT_CAST:%.*]] = bitcast i32* [[PHINODE_CE_LOC]] to i8*
; CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 -1, i8* [[LT_CAST]])
; CHECK-NEXT: call void @outlined_ir_func_0(i32* [[PHINODE_CE_LOC]], i32 0)
; CHECK-NEXT: [[PHINODE_CE_RELOAD:%.*]] = load i32, i32* [[PHINODE_CE_LOC]], align 4
; CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 -1, i8* [[LT_CAST]])
; CHECK-NEXT: br label [[BB5:%.*]]
; CHECK: placeholder:
; CHECK-NEXT: [[A:%.*]] = sub i32 5, 4
; CHECK-NEXT: br label [[BB5]]
; CHECK: bb3:
; CHECK-NEXT: [[LT_CAST3:%.*]] = bitcast i32* [[PHINODE_CE_LOC1]] to i8*
; CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 -1, i8* [[LT_CAST3]])
; CHECK-NEXT: call void @outlined_ir_func_0(i32* [[PHINODE_CE_LOC1]], i32 1)
; CHECK-NEXT: [[PHINODE_CE_RELOAD2:%.*]] = load i32, i32* [[PHINODE_CE_LOC1]], align 4
; CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 -1, i8* [[LT_CAST3]])
; CHECK-NEXT: br label [[BB5]]
; CHECK: placeholder1:
; CHECK-NEXT: [[B:%.*]] = add i32 5, 4
; CHECK-NEXT: ret void
; CHECK: bb5:
; CHECK-NEXT: [[PHINODE:%.*]] = phi i32 [ 5, [[PLACEHOLDER:%.*]] ], [ [[PHINODE_CE_RELOAD]], [[BB1:%.*]] ], [ [[PHINODE_CE_RELOAD2]], [[BB3:%.*]] ]
; CHECK-NEXT: ret void
;
;
; CHECK-LABEL: define internal void @outlined_ir_func_0(
; CHECK-NEXT: newFuncRoot:
; CHECK-NEXT: br label [[BB1_TO_OUTLINE:%.*]]
; CHECK: bb1_to_outline:
; CHECK-NEXT: [[TMP2:%.*]] = add i32 1, 2
; CHECK-NEXT: [[TMP3:%.*]] = add i32 3, 4
; CHECK-NEXT: [[TMP4:%.*]] = add i32 5, 6
; CHECK-NEXT: [[TMP5:%.*]] = add i32 7, 8
; CHECK-NEXT: br label [[BB5_SPLIT:%.*]]
; CHECK: bb2:
; CHECK-NEXT: [[TMP6:%.*]] = mul i32 5, 4
; CHECK-NEXT: br label [[BB5_SPLIT]]
; CHECK: bb5.split:
; CHECK-NEXT: [[TMP7:%.*]] = phi i32 [ 4, [[BB1_TO_OUTLINE]] ], [ 4, [[BB2:%.*]] ]
; CHECK-NEXT: [[PHINODE_CE:%.*]] = phi i32 [ 5, [[BB1_TO_OUTLINE]] ], [ 5, [[BB2]] ]
; CHECK-NEXT: br label [[BB5_EXITSTUB:%.*]]
; CHECK: bb5.exitStub:
; CHECK-NEXT: switch i32 [[TMP1:%.*]], label [[FINAL_BLOCK_0:%.*]] [
; CHECK-NEXT: i32 0, label [[OUTPUT_BLOCK_0_0:%.*]]
; CHECK-NEXT: i32 1, label [[OUTPUT_BLOCK_1_0:%.*]]
; CHECK-NEXT: ]
; CHECK: output_block_0_0:
; CHECK-NEXT: store i32 [[PHINODE_CE]], i32* [[TMP0:%.*]], align 4
; CHECK-NEXT: br label [[FINAL_BLOCK_0]]
; CHECK: output_block_1_0:
; CHECK-NEXT: store i32 [[TMP7]], i32* [[TMP0]], align 4
; CHECK-NEXT: br label [[FINAL_BLOCK_0]]
; CHECK: final_block_0:
; CHECK-NEXT: ret void
;