| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py |
| ; RUN: opt -passes=sink -S < %s | FileCheck %s |
| |
| ; Loads marked invariant can be sunk across critical edges. |
| |
| define <4 x float> @invariant_load(ptr %in, i32 %s) { |
| ; CHECK-LABEL: @invariant_load( |
| ; CHECK-NEXT: main_body: |
| ; CHECK-NEXT: [[C:%.*]] = icmp eq i32 [[S:%.*]], 0 |
| ; CHECK-NEXT: br i1 [[C]], label [[BLOCK:%.*]], label [[END:%.*]] |
| ; CHECK: block: |
| ; CHECK-NEXT: [[Z:%.*]] = add i32 [[S]], 1 |
| ; CHECK-NEXT: br label [[END]] |
| ; CHECK: end: |
| ; CHECK-NEXT: [[V:%.*]] = load <4 x float>, ptr [[IN:%.*]], align 16, !invariant.load [[META0:![0-9]+]] |
| ; CHECK-NEXT: ret <4 x float> [[V]] |
| ; |
| main_body: |
| %v = load <4 x float>, ptr %in, !invariant.load !0 |
| %c = icmp eq i32 %s, 0 |
| br i1 %c, label %block, label %end |
| block: |
| %z = add i32 %s, 1 |
| br label %end |
| end: |
| ret <4 x float> %v |
| } |
| |
| ; Loads that aren't marked invariant but used in one branch |
| ; can be sunk to that branch. |
| |
| define void @invariant_load_use_in_br(ptr %p, i1 %cond) { |
| ; CHECK-LABEL: @invariant_load_use_in_br( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: br i1 [[COND:%.*]], label [[TRUE_BR:%.*]], label [[FALSE_BR:%.*]] |
| ; CHECK: true.br: |
| ; CHECK-NEXT: call void @fn() |
| ; CHECK-NEXT: br label [[EXIT:%.*]] |
| ; CHECK: false.br: |
| ; CHECK-NEXT: [[VAL:%.*]] = load i32, ptr [[P:%.*]], align 4 |
| ; CHECK-NEXT: call void @fn(i32 [[VAL]]) |
| ; CHECK-NEXT: br label [[EXIT]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| %val = load i32, ptr %p |
| br i1 %cond, label %true.br, label %false.br |
| true.br: |
| call void @fn() |
| br label %exit |
| false.br: |
| call void @fn(i32 %val) |
| br label %exit |
| exit: |
| ret void |
| } |
| |
| ; TODO: Invariant loads marked with metadata can be sunk past calls. |
| |
| define void @invariant_load_metadata_call(ptr %p, i1 %cond) { |
| ; CHECK-LABEL: @invariant_load_metadata_call( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[VAL:%.*]] = load i32, ptr [[P:%.*]], align 4, !invariant.load [[META0]] |
| ; CHECK-NEXT: call void @fn() |
| ; CHECK-NEXT: br i1 [[COND:%.*]], label [[TRUE_BR:%.*]], label [[FALSE_BR:%.*]] |
| ; CHECK: true.br: |
| ; CHECK-NEXT: call void @fn() |
| ; CHECK-NEXT: br label [[EXIT:%.*]] |
| ; CHECK: false.br: |
| ; CHECK-NEXT: call void @fn(i32 [[VAL]]) |
| ; CHECK-NEXT: br label [[EXIT]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| %val = load i32, ptr %p, !invariant.load !0 |
| call void @fn() |
| br i1 %cond, label %true.br, label %false.br |
| true.br: |
| call void @fn() |
| br label %exit |
| false.br: |
| call void @fn(i32 %val) |
| br label %exit |
| exit: |
| ret void |
| } |
| |
| declare void @fn() |
| |
| !0 = !{} |