Issue: https://github.com/llvm/llvm-project/issues/54431 PHINodes that need to be generated to accommodate a PHINode outside the region due to different output paths need to have their own numbering to determine the number of output schemes required to properly handle all the outlined regions. This numbering was previously only determined by the order and values of the incoming values, as well as the parent block of the PHINode. This adds the incoming blocks to the calculation of a hash value for these PHINodes as well, and the supporting infrastructure to give each block in a region a corresponding canonical numbering. Reviewer: paquette Differential Revision: https://reviews.llvm.org/D122207
123 lines
4.2 KiB
LLVM
123 lines
4.2 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
|
|
|
|
; A PHINode defines the global value number of a split phi node for
|
|
; an exit paths based on the canonical number for the incoming values, and
|
|
; the canonical number for the basic block. This checks that we accurately
|
|
; capture a different numbering for the same incoming value but with different
|
|
; blocks.
|
|
|
|
define void @func1(i32 %0, i32 %1) local_unnamed_addr #0 {
|
|
bb1:
|
|
br label %bb5
|
|
|
|
bb2:
|
|
%a = add i32 %0, %1
|
|
%b = add i32 %0, %1
|
|
%c = icmp eq i32 %b, 1
|
|
br i1 %c, label %bb5, label %bb3
|
|
|
|
bb3:
|
|
%d = add i32 %0, %1
|
|
br label %bb5
|
|
|
|
bb4:
|
|
%e = sub i32 %0, %1
|
|
br label %bb2
|
|
|
|
bb5:
|
|
%f = phi i32 [ 0, %bb1 ], [ 1, %bb2 ], [ 1, %bb3 ]
|
|
ret void
|
|
}
|
|
|
|
define void @func2(i32 %0, i32 %1) local_unnamed_addr #0 {
|
|
bb1:
|
|
br label %bb5
|
|
|
|
bb2:
|
|
%a = sub i32 %0, %1
|
|
%b = add i32 %0, %1
|
|
%c = icmp eq i32 %b, 1
|
|
br i1 %c, label %bb5, label %bb3
|
|
|
|
bb3:
|
|
%d = add i32 %0, %1
|
|
br label %bb5
|
|
|
|
bb4:
|
|
%e = add i32 %0, %1
|
|
br label %bb2
|
|
|
|
bb5:
|
|
%f = phi i32 [ 0, %bb1 ], [ 1, %bb3 ], [ 1, %bb2 ]
|
|
ret void
|
|
}
|
|
; CHECK-LABEL: @func1(
|
|
; CHECK-NEXT: bb1:
|
|
; CHECK-NEXT: [[F_CE_LOC:%.*]] = alloca i32, align 4
|
|
; CHECK-NEXT: br label [[BB5:%.*]]
|
|
; CHECK: bb2:
|
|
; CHECK-NEXT: [[A:%.*]] = add i32 [[TMP0:%.*]], [[TMP1:%.*]]
|
|
; CHECK-NEXT: [[LT_CAST:%.*]] = bitcast i32* [[F_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 [[TMP0]], i32 [[TMP1]], i32* [[F_CE_LOC]], i32 0)
|
|
; CHECK-NEXT: [[F_CE_RELOAD:%.*]] = load i32, i32* [[F_CE_LOC]], align 4
|
|
; CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 -1, i8* [[LT_CAST]])
|
|
; CHECK-NEXT: br label [[BB5]]
|
|
; CHECK: bb4:
|
|
; CHECK-NEXT: [[E:%.*]] = sub i32 [[TMP0]], [[TMP1]]
|
|
; CHECK-NEXT: br label [[BB2:%.*]]
|
|
; CHECK: bb5:
|
|
; CHECK-NEXT: [[F:%.*]] = phi i32 [ 0, [[BB1:%.*]] ], [ [[F_CE_RELOAD]], [[BB2]] ]
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
;
|
|
; CHECK-LABEL: @func2(
|
|
; CHECK-NEXT: bb1:
|
|
; CHECK-NEXT: [[F_CE_LOC:%.*]] = alloca i32, align 4
|
|
; CHECK-NEXT: br label [[BB5:%.*]]
|
|
; CHECK: bb2:
|
|
; CHECK-NEXT: [[A:%.*]] = sub i32 [[TMP0:%.*]], [[TMP1:%.*]]
|
|
; CHECK-NEXT: [[LT_CAST:%.*]] = bitcast i32* [[F_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 [[TMP0]], i32 [[TMP1]], i32* [[F_CE_LOC]], i32 1)
|
|
; CHECK-NEXT: [[F_CE_RELOAD:%.*]] = load i32, i32* [[F_CE_LOC]], align 4
|
|
; CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 -1, i8* [[LT_CAST]])
|
|
; CHECK-NEXT: br label [[BB5]]
|
|
; CHECK: bb4:
|
|
; CHECK-NEXT: [[E:%.*]] = add i32 [[TMP0]], [[TMP1]]
|
|
; CHECK-NEXT: br label [[BB2:%.*]]
|
|
; CHECK: bb5:
|
|
; CHECK-NEXT: [[F:%.*]] = phi i32 [ 0, [[BB1:%.*]] ], [ [[F_CE_RELOAD]], [[BB2]] ]
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
;
|
|
; CHECK-LABEL: define internal void @outlined_ir_func_0(
|
|
; CHECK-NEXT: newFuncRoot:
|
|
; CHECK-NEXT: br label [[BB2_TO_OUTLINE:%.*]]
|
|
; CHECK: bb2_to_outline:
|
|
; CHECK-NEXT: [[B:%.*]] = add i32 [[TMP0:%.*]], [[TMP1:%.*]]
|
|
; CHECK-NEXT: [[C:%.*]] = icmp eq i32 [[B]], 1
|
|
; CHECK-NEXT: br i1 [[C]], label [[BB5_SPLIT:%.*]], label [[BB3:%.*]]
|
|
; CHECK: bb3:
|
|
; CHECK-NEXT: [[D:%.*]] = add i32 [[TMP0]], [[TMP1]]
|
|
; CHECK-NEXT: br label [[BB5_SPLIT]]
|
|
; CHECK: bb5.split:
|
|
; CHECK-NEXT: [[TMP4:%.*]] = phi i32 [ 1, [[BB3]] ], [ 1, [[BB2_TO_OUTLINE]] ]
|
|
; CHECK-NEXT: [[F_CE:%.*]] = phi i32 [ 1, [[BB2_TO_OUTLINE]] ], [ 1, [[BB3]] ]
|
|
; CHECK-NEXT: br label [[BB5_EXITSTUB:%.*]]
|
|
; CHECK: bb5.exitStub:
|
|
; CHECK-NEXT: switch i32 [[TMP3:%.*]], 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 [[F_CE]], i32* [[TMP2:%.*]], align 4
|
|
; CHECK-NEXT: br label [[FINAL_BLOCK_0]]
|
|
; CHECK: output_block_1_0:
|
|
; CHECK-NEXT: store i32 [[TMP4]], i32* [[TMP2]], align 4
|
|
; CHECK-NEXT: br label [[FINAL_BLOCK_0]]
|
|
; CHECK: final_block_0:
|
|
; CHECK-NEXT: ret void
|
|
;
|