1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes 2; RUN: opt -S -passes=argpromotion < %s | FileCheck %s 3 4define internal i32 @callee_must_exec(ptr %p) { 5; CHECK-LABEL: define {{[^@]+}}@callee_must_exec 6; CHECK-SAME: (i32 [[P_0_VAL:%.*]]) { 7; CHECK-NEXT: ret i32 [[P_0_VAL]] 8; 9 %x = load i32, ptr %p, align 16 10 ret i32 %x 11} 12 13define void @caller_must_exec(ptr %p) { 14; CHECK-LABEL: define {{[^@]+}}@caller_must_exec 15; CHECK-SAME: (ptr [[P:%.*]]) { 16; CHECK-NEXT: [[P_VAL:%.*]] = load i32, ptr [[P]], align 16 17; CHECK-NEXT: [[TMP1:%.*]] = call i32 @callee_must_exec(i32 [[P_VAL]]) 18; CHECK-NEXT: ret void 19; 20 call i32 @callee_must_exec(ptr %p) 21 ret void 22} 23 24define internal i32 @callee_guaranteed_aligned_1(i1 %c, ptr %p) { 25; CHECK-LABEL: define {{[^@]+}}@callee_guaranteed_aligned_1 26; CHECK-SAME: (i1 [[C:%.*]], i32 [[P_0_VAL:%.*]]) { 27; CHECK-NEXT: br i1 [[C]], label [[IF:%.*]], label [[ELSE:%.*]] 28; CHECK: if: 29; CHECK-NEXT: ret i32 [[P_0_VAL]] 30; CHECK: else: 31; CHECK-NEXT: ret i32 -1 32; 33 br i1 %c, label %if, label %else 34 35if: 36 %x = load i32, ptr %p, align 16 37 ret i32 %x 38 39else: 40 ret i32 -1 41} 42 43define void @caller_guaranteed_aligned_1(i1 %c, ptr align 16 dereferenceable(4) %p) { 44; CHECK-LABEL: define {{[^@]+}}@caller_guaranteed_aligned_1 45; CHECK-SAME: (i1 [[C:%.*]], ptr align 16 dereferenceable(4) [[P:%.*]]) { 46; CHECK-NEXT: [[P_VAL:%.*]] = load i32, ptr [[P]], align 16 47; CHECK-NEXT: [[TMP1:%.*]] = call i32 @callee_guaranteed_aligned_1(i1 [[C]], i32 [[P_VAL]]) 48; CHECK-NEXT: ret void 49; 50 call i32 @callee_guaranteed_aligned_1(i1 %c, ptr %p) 51 ret void 52} 53 54define internal i32 @callee_guaranteed_aligned_2(i1 %c, ptr align 16 dereferenceable(4) %p) { 55; CHECK-LABEL: define {{[^@]+}}@callee_guaranteed_aligned_2 56; CHECK-SAME: (i1 [[C:%.*]], i32 [[P_0_VAL:%.*]]) { 57; CHECK-NEXT: br i1 [[C]], label [[IF:%.*]], label [[ELSE:%.*]] 58; CHECK: if: 59; CHECK-NEXT: ret i32 [[P_0_VAL]] 60; CHECK: else: 61; CHECK-NEXT: ret i32 -1 62; 63 br i1 %c, label %if, label %else 64 65if: 66 %x = load i32, ptr %p, align 16 67 ret i32 %x 68 69else: 70 ret i32 -1 71} 72 73define void @caller_guaranteed_aligned_2(i1 %c, ptr %p) { 74; CHECK-LABEL: define {{[^@]+}}@caller_guaranteed_aligned_2 75; CHECK-SAME: (i1 [[C:%.*]], ptr [[P:%.*]]) { 76; CHECK-NEXT: [[P_VAL:%.*]] = load i32, ptr [[P]], align 16 77; CHECK-NEXT: [[TMP1:%.*]] = call i32 @callee_guaranteed_aligned_2(i1 [[C]], i32 [[P_VAL]]) 78; CHECK-NEXT: ret void 79; 80 call i32 @callee_guaranteed_aligned_2(i1 %c, ptr %p) 81 ret void 82} 83 84; We have seen the offset before but with a lower alignment 85define internal i32 @callee_guaranteed_aligned_3(i1 %c, ptr align 16 dereferenceable(4) %p) { 86; CHECK-LABEL: define {{[^@]+}}@callee_guaranteed_aligned_3 87; CHECK-SAME: (i1 [[C:%.*]], i32 [[P_0_VAL:%.*]]) { 88; CHECK-NEXT: br i1 [[C]], label [[IF:%.*]], label [[ELSE:%.*]] 89; CHECK: if: 90; CHECK-NEXT: ret i32 [[P_0_VAL]] 91; CHECK: else: 92; CHECK-NEXT: ret i32 -1 93; 94 %x = load i32, ptr %p, align 8 95 br i1 %c, label %if, label %else 96 97if: 98 %y = load i32, ptr %p, align 16 99 ret i32 %y 100 101else: 102 ret i32 -1 103} 104 105define void @caller_guaranteed_aligned_3(i1 %c, ptr %p) { 106; CHECK-LABEL: define {{[^@]+}}@caller_guaranteed_aligned_3 107; CHECK-SAME: (i1 [[C:%.*]], ptr [[P:%.*]]) { 108; CHECK-NEXT: [[P_VAL:%.*]] = load i32, ptr [[P]], align 16 109; CHECK-NEXT: [[TMP1:%.*]] = call i32 @callee_guaranteed_aligned_3(i1 [[C]], i32 [[P_VAL]]) 110; CHECK-NEXT: ret void 111; 112 call i32 @callee_guaranteed_aligned_3(i1 %c, ptr %p) 113 ret void 114} 115 116; We have seen the offset before but with a lower alignment, the guaranteed 117; alignment is insufficient and the argument should not be promoted. 118define internal i32 @callee_guaranteed_insufficient_aligned(i1 %c, ptr align 8 dereferenceable(4) %p) { 119; CHECK-LABEL: define {{[^@]+}}@callee_guaranteed_insufficient_aligned 120; CHECK-SAME: (i1 [[C:%.*]], ptr align 8 dereferenceable(4) [[P:%.*]]) { 121; CHECK-NEXT: [[X:%.*]] = load i32, ptr [[P]], align 8 122; CHECK-NEXT: br i1 [[C]], label [[IF:%.*]], label [[ELSE:%.*]] 123; CHECK: if: 124; CHECK-NEXT: [[Y:%.*]] = load i32, ptr [[P]], align 16 125; CHECK-NEXT: ret i32 [[Y]] 126; CHECK: else: 127; CHECK-NEXT: ret i32 -1 128; 129 %x = load i32, ptr %p, align 8 130 br i1 %c, label %if, label %else 131 132if: 133 %y = load i32, ptr %p, align 16 134 ret i32 %y 135 136else: 137 ret i32 -1 138} 139 140define void @caller_guaranteed_insufficient_aligned(i1 %c, ptr %p) { 141; CHECK-LABEL: define {{[^@]+}}@caller_guaranteed_insufficient_aligned 142; CHECK-SAME: (i1 [[C:%.*]], ptr [[P:%.*]]) { 143; CHECK-NEXT: [[TMP1:%.*]] = call i32 @callee_guaranteed_insufficient_aligned(i1 [[C]], ptr [[P]]) 144; CHECK-NEXT: ret void 145; 146 call i32 @callee_guaranteed_insufficient_aligned(i1 %c, ptr %p) 147 ret void 148} 149 150; This should not be promoted, as the caller only guarantees that the 151; pointer is dereferenceable, not that it is aligned. 152define internal i32 @callee_not_guaranteed_aligned(i1 %c, ptr %p) { 153; CHECK-LABEL: define {{[^@]+}}@callee_not_guaranteed_aligned 154; CHECK-SAME: (i1 [[C:%.*]], ptr [[P:%.*]]) { 155; CHECK-NEXT: br i1 [[C]], label [[IF:%.*]], label [[ELSE:%.*]] 156; CHECK: if: 157; CHECK-NEXT: [[X:%.*]] = load i32, ptr [[P]], align 16 158; CHECK-NEXT: ret i32 [[X]] 159; CHECK: else: 160; CHECK-NEXT: ret i32 -1 161; 162 br i1 %c, label %if, label %else 163 164if: 165 %x = load i32, ptr %p, align 16 166 ret i32 %x 167 168else: 169 ret i32 -1 170} 171 172define void @caller_not_guaranteed_aligned(i1 %c, ptr dereferenceable(4) %p) { 173; CHECK-LABEL: define {{[^@]+}}@caller_not_guaranteed_aligned 174; CHECK-SAME: (i1 [[C:%.*]], ptr dereferenceable(4) [[P:%.*]]) { 175; CHECK-NEXT: [[TMP1:%.*]] = call i32 @callee_not_guaranteed_aligned(i1 [[C]], ptr [[P]]) 176; CHECK-NEXT: ret void 177; 178 call i32 @callee_not_guaranteed_aligned(i1 %c, ptr %p) 179 ret void 180} 181