236 lines
7.1 KiB
LLVM
236 lines
7.1 KiB
LLVM
|
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
|
||
|
; RUN: opt -S -passes=licm < %s | FileCheck %s --check-prefixes=CHECK,MT
|
||
|
; RUN: opt -S -passes=licm -licm-force-thread-model-single < %s | FileCheck %s --check-prefixes=CHECK,ST
|
||
|
|
||
|
@g = external global i32
|
||
|
@c = external constant i32
|
||
|
|
||
|
declare void @capture(ptr)
|
||
|
|
||
|
; Even in single-thread mode, can only perform load-only promotion for globals,
|
||
|
; because we might not have provenance to write to the global. See
|
||
|
; promote_global_noalias for an example of the issue.
|
||
|
define void @promote_global(i1 %c, i1 %c2) {
|
||
|
; CHECK-LABEL: @promote_global(
|
||
|
; CHECK-NEXT: entry:
|
||
|
; CHECK-NEXT: [[G_PROMOTED:%.*]] = load i32, ptr @g, align 4
|
||
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
||
|
; CHECK: loop:
|
||
|
; CHECK-NEXT: [[V_INC2:%.*]] = phi i32 [ [[V_INC1:%.*]], [[LATCH:%.*]] ], [ [[G_PROMOTED]], [[ENTRY:%.*]] ]
|
||
|
; CHECK-NEXT: br i1 [[C:%.*]], label [[IF:%.*]], label [[LATCH]]
|
||
|
; CHECK: if:
|
||
|
; CHECK-NEXT: [[V_INC:%.*]] = add i32 [[V_INC2]], 1
|
||
|
; CHECK-NEXT: store i32 [[V_INC]], ptr @g, align 4
|
||
|
; CHECK-NEXT: br label [[LATCH]]
|
||
|
; CHECK: latch:
|
||
|
; CHECK-NEXT: [[V_INC1]] = phi i32 [ [[V_INC]], [[IF]] ], [ [[V_INC2]], [[LOOP]] ]
|
||
|
; CHECK-NEXT: br i1 [[C2:%.*]], label [[EXIT:%.*]], label [[LOOP]]
|
||
|
; CHECK: exit:
|
||
|
; CHECK-NEXT: ret void
|
||
|
;
|
||
|
entry:
|
||
|
br label %loop
|
||
|
|
||
|
loop:
|
||
|
br i1 %c, label %if, label %latch
|
||
|
|
||
|
if:
|
||
|
%v = load i32, ptr @g
|
||
|
%v.inc = add i32 %v, 1
|
||
|
store i32 %v.inc, ptr @g
|
||
|
br label %latch
|
||
|
|
||
|
latch:
|
||
|
br i1 %c2, label %exit, label %loop
|
||
|
|
||
|
exit:
|
||
|
ret void
|
||
|
}
|
||
|
|
||
|
; The store can never be promoted here, because the global is constant, and
|
||
|
; the store could trap.
|
||
|
define void @promote_constant_global(i1 %c, i1 %c2) {
|
||
|
; CHECK-LABEL: @promote_constant_global(
|
||
|
; CHECK-NEXT: entry:
|
||
|
; CHECK-NEXT: [[V:%.*]] = load i32, ptr @c, align 4
|
||
|
; CHECK-NEXT: [[V_INC:%.*]] = add i32 [[V]], 1
|
||
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
||
|
; CHECK: loop:
|
||
|
; CHECK-NEXT: br i1 [[C:%.*]], label [[IF:%.*]], label [[LATCH:%.*]]
|
||
|
; CHECK: if:
|
||
|
; CHECK-NEXT: store i32 [[V_INC]], ptr @c, align 4
|
||
|
; CHECK-NEXT: br label [[LATCH]]
|
||
|
; CHECK: latch:
|
||
|
; CHECK-NEXT: br i1 [[C2:%.*]], label [[EXIT:%.*]], label [[LOOP]]
|
||
|
; CHECK: exit:
|
||
|
; CHECK-NEXT: ret void
|
||
|
;
|
||
|
entry:
|
||
|
br label %loop
|
||
|
|
||
|
loop:
|
||
|
br i1 %c, label %if, label %latch
|
||
|
|
||
|
if:
|
||
|
%v = load i32, ptr @c
|
||
|
%v.inc = add i32 %v, 1
|
||
|
store i32 %v.inc, ptr @c
|
||
|
br label %latch
|
||
|
|
||
|
latch:
|
||
|
br i1 %c2, label %exit, label %loop
|
||
|
|
||
|
exit:
|
||
|
ret void
|
||
|
}
|
||
|
|
||
|
; if %c is false and %ptr == @g, then this should store 42 to the pointer.
|
||
|
; However, if we perform load+store promotion, then we would instead store the
|
||
|
; original value of the global.
|
||
|
define void @promote_global_noalias(i1 %c, i1 %c2, ptr noalias %ptr) {
|
||
|
; CHECK-LABEL: @promote_global_noalias(
|
||
|
; CHECK-NEXT: entry:
|
||
|
; CHECK-NEXT: [[G_PROMOTED:%.*]] = load i32, ptr @g, align 4
|
||
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
||
|
; CHECK: loop:
|
||
|
; CHECK-NEXT: [[V_INC2:%.*]] = phi i32 [ [[V_INC1:%.*]], [[LATCH:%.*]] ], [ [[G_PROMOTED]], [[ENTRY:%.*]] ]
|
||
|
; CHECK-NEXT: br i1 [[C:%.*]], label [[IF:%.*]], label [[ELSE:%.*]]
|
||
|
; CHECK: if:
|
||
|
; CHECK-NEXT: [[V_INC:%.*]] = add i32 [[V_INC2]], 1
|
||
|
; CHECK-NEXT: store i32 [[V_INC]], ptr @g, align 4
|
||
|
; CHECK-NEXT: br label [[LATCH]]
|
||
|
; CHECK: else:
|
||
|
; CHECK-NEXT: store i32 42, ptr [[PTR:%.*]], align 4
|
||
|
; CHECK-NEXT: br label [[LATCH]]
|
||
|
; CHECK: latch:
|
||
|
; CHECK-NEXT: [[V_INC1]] = phi i32 [ [[V_INC2]], [[ELSE]] ], [ [[V_INC]], [[IF]] ]
|
||
|
; CHECK-NEXT: br i1 [[C2:%.*]], label [[EXIT:%.*]], label [[LOOP]]
|
||
|
; CHECK: exit:
|
||
|
; CHECK-NEXT: ret void
|
||
|
;
|
||
|
entry:
|
||
|
br label %loop
|
||
|
|
||
|
loop:
|
||
|
br i1 %c, label %if, label %else
|
||
|
|
||
|
if:
|
||
|
%v = load i32, ptr @g
|
||
|
%v.inc = add i32 %v, 1
|
||
|
store i32 %v.inc, ptr @g
|
||
|
br label %latch
|
||
|
|
||
|
else:
|
||
|
store i32 42, ptr %ptr
|
||
|
br label %latch
|
||
|
|
||
|
latch:
|
||
|
br i1 %c2, label %exit, label %loop
|
||
|
|
||
|
exit:
|
||
|
ret void
|
||
|
}
|
||
|
|
||
|
; In single-thread mode both loads and stores can be promoted. In multi-thread
|
||
|
; mode only loads can be promoted, as a different thread might write to the
|
||
|
; captured alloca.
|
||
|
define void @promote_captured_alloca(i1 %c, i1 %c2) {
|
||
|
; MT-LABEL: @promote_captured_alloca(
|
||
|
; MT-NEXT: entry:
|
||
|
; MT-NEXT: [[A:%.*]] = alloca i32, align 4
|
||
|
; MT-NEXT: call void @capture(ptr [[A]])
|
||
|
; MT-NEXT: [[A_PROMOTED:%.*]] = load i32, ptr [[A]], align 4
|
||
|
; MT-NEXT: br label [[LOOP:%.*]]
|
||
|
; MT: loop:
|
||
|
; MT-NEXT: [[V_INC2:%.*]] = phi i32 [ [[V_INC1:%.*]], [[LATCH:%.*]] ], [ [[A_PROMOTED]], [[ENTRY:%.*]] ]
|
||
|
; MT-NEXT: br i1 [[C:%.*]], label [[IF:%.*]], label [[LATCH]]
|
||
|
; MT: if:
|
||
|
; MT-NEXT: [[V_INC:%.*]] = add i32 [[V_INC2]], 1
|
||
|
; MT-NEXT: store i32 [[V_INC]], ptr [[A]], align 4
|
||
|
; MT-NEXT: br label [[LATCH]]
|
||
|
; MT: latch:
|
||
|
; MT-NEXT: [[V_INC1]] = phi i32 [ [[V_INC]], [[IF]] ], [ [[V_INC2]], [[LOOP]] ]
|
||
|
; MT-NEXT: br i1 [[C2:%.*]], label [[EXIT:%.*]], label [[LOOP]]
|
||
|
; MT: exit:
|
||
|
; MT-NEXT: ret void
|
||
|
;
|
||
|
; ST-LABEL: @promote_captured_alloca(
|
||
|
; ST-NEXT: entry:
|
||
|
; ST-NEXT: [[A:%.*]] = alloca i32, align 4
|
||
|
; ST-NEXT: call void @capture(ptr [[A]])
|
||
|
; ST-NEXT: [[A_PROMOTED:%.*]] = load i32, ptr [[A]], align 4
|
||
|
; ST-NEXT: br label [[LOOP:%.*]]
|
||
|
; ST: loop:
|
||
|
; ST-NEXT: [[V_INC2:%.*]] = phi i32 [ [[V_INC1:%.*]], [[LATCH:%.*]] ], [ [[A_PROMOTED]], [[ENTRY:%.*]] ]
|
||
|
; ST-NEXT: br i1 [[C:%.*]], label [[IF:%.*]], label [[LATCH]]
|
||
|
; ST: if:
|
||
|
; ST-NEXT: [[V_INC:%.*]] = add i32 [[V_INC2]], 1
|
||
|
; ST-NEXT: br label [[LATCH]]
|
||
|
; ST: latch:
|
||
|
; ST-NEXT: [[V_INC1]] = phi i32 [ [[V_INC]], [[IF]] ], [ [[V_INC2]], [[LOOP]] ]
|
||
|
; ST-NEXT: br i1 [[C2:%.*]], label [[EXIT:%.*]], label [[LOOP]]
|
||
|
; ST: exit:
|
||
|
; ST-NEXT: [[V_INC1_LCSSA:%.*]] = phi i32 [ [[V_INC1]], [[LATCH]] ]
|
||
|
; ST-NEXT: store i32 [[V_INC1_LCSSA]], ptr [[A]], align 4
|
||
|
; ST-NEXT: ret void
|
||
|
;
|
||
|
entry:
|
||
|
%a = alloca i32
|
||
|
call void @capture(ptr %a)
|
||
|
br label %loop
|
||
|
|
||
|
loop:
|
||
|
br i1 %c, label %if, label %latch
|
||
|
|
||
|
if:
|
||
|
%v = load i32, ptr %a
|
||
|
%v.inc = add i32 %v, 1
|
||
|
store i32 %v.inc, ptr %a
|
||
|
br label %latch
|
||
|
|
||
|
latch:
|
||
|
br i1 %c2, label %exit, label %loop
|
||
|
|
||
|
exit:
|
||
|
ret void
|
||
|
}
|
||
|
|
||
|
; The store cannot be promoted here, because we do not know whether the
|
||
|
; argument memory is writable.
|
||
|
define void @promote_arg(ptr noalias dereferenceable(4) align 4 %arg, i1 %c, i1 %c2) {
|
||
|
; CHECK-LABEL: @promote_arg(
|
||
|
; CHECK-NEXT: entry:
|
||
|
; CHECK-NEXT: [[ARG_PROMOTED:%.*]] = load i32, ptr [[ARG:%.*]], align 4
|
||
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
||
|
; CHECK: loop:
|
||
|
; CHECK-NEXT: [[V_INC2:%.*]] = phi i32 [ [[V_INC1:%.*]], [[LATCH:%.*]] ], [ [[ARG_PROMOTED]], [[ENTRY:%.*]] ]
|
||
|
; CHECK-NEXT: br i1 [[C:%.*]], label [[IF:%.*]], label [[LATCH]]
|
||
|
; CHECK: if:
|
||
|
; CHECK-NEXT: [[V_INC:%.*]] = add i32 [[V_INC2]], 1
|
||
|
; CHECK-NEXT: store i32 [[V_INC]], ptr [[ARG]], align 4
|
||
|
; CHECK-NEXT: br label [[LATCH]]
|
||
|
; CHECK: latch:
|
||
|
; CHECK-NEXT: [[V_INC1]] = phi i32 [ [[V_INC]], [[IF]] ], [ [[V_INC2]], [[LOOP]] ]
|
||
|
; CHECK-NEXT: br i1 [[C2:%.*]], label [[EXIT:%.*]], label [[LOOP]]
|
||
|
; CHECK: exit:
|
||
|
; CHECK-NEXT: ret void
|
||
|
;
|
||
|
entry:
|
||
|
br label %loop
|
||
|
|
||
|
loop:
|
||
|
br i1 %c, label %if, label %latch
|
||
|
|
||
|
if:
|
||
|
%v = load i32, ptr %arg
|
||
|
%v.inc = add i32 %v, 1
|
||
|
store i32 %v.inc, ptr %arg
|
||
|
br label %latch
|
||
|
|
||
|
latch:
|
||
|
br i1 %c2, label %exit, label %loop
|
||
|
|
||
|
exit:
|
||
|
ret void
|
||
|
}
|