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
99 lines
3.7 KiB
LLVM
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
|
|
;
|