1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals smart 2; RUN: opt -S -passes=instcombine,simplifycfg < %s 2>&1 | FileCheck %s 3 4declare void @llvm.assume(i1 noundef) 5 6define void @f1(ptr %a) { 7; CHECK-LABEL: @f1( 8; CHECK-NEXT: entry: 9; CHECK-NEXT: [[PTR:%.*]] = getelementptr inbounds nuw i8, ptr [[A:%.*]], i64 4 10; CHECK-NEXT: [[TMP0:%.*]] = ptrtoint ptr [[PTR]] to i64 11; CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 3 12; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 0 13; CHECK-NEXT: br i1 [[TMP2]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] 14; CHECK: if.then: 15; CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr [[PTR]], i64 4) ] 16; CHECK-NEXT: store i32 4, ptr [[PTR]], align 4 17; CHECK-NEXT: br label [[IF_END]] 18; CHECK: if.end: 19; CHECK-NEXT: ret void 20; 21entry: 22 %ptr = getelementptr inbounds i8, ptr %a, i64 4 23 %0 = ptrtoint ptr %ptr to i64 24 %1 = and i64 %0, 3 25 %2 = icmp eq i64 %1, 0 26 br i1 %2, label %if.then, label %if.end 27 28if.then: ; preds = %entry 29 call void @llvm.assume(i1 true) [ "align"(ptr %ptr, i64 4) ] 30 %3 = ptrtoint ptr %ptr to i64 31 %4 = and i64 %3, 3 32 %5 = icmp eq i64 %4, 0 33 br i1 %5, label %if.then1, label %if.else1 34 35if.then1: ; preds = %if.then 36 store i32 4, ptr %ptr, align 4 37 br label %if.end 38 39if.else1: ; preds = %if.then 40 store i8 1, ptr %ptr, align 1 41 br label %if.end 42 43if.end: ; preds = %if.then1, %if.else1, %entry 44 ret void 45} 46 47; TODO: We could fold away the branch "br i1 %3, ..." by either using a GEP or make getKnowledgeValidInContext aware the alignment bundle offset, and the improvement of value tracking of GEP. 48 49define void @f2(ptr %a) { 50; CHECK-LABEL: @f2( 51; CHECK-NEXT: entry: 52; CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr [[A:%.*]], i64 32, i32 24) ] 53; CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds nuw i8, ptr [[A]], i64 8 54; CHECK-NEXT: [[TMP1:%.*]] = ptrtoint ptr [[TMP0]] to i64 55; CHECK-NEXT: [[TMP2:%.*]] = and i64 [[TMP1]], 8 56; CHECK-NEXT: [[TMP3:%.*]] = icmp eq i64 [[TMP2]], 0 57; CHECK-NEXT: br i1 [[TMP3]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]] 58; CHECK: if.then: 59; CHECK-NEXT: store i64 16, ptr [[TMP0]], align 4 60; CHECK-NEXT: br label [[IF_END:%.*]] 61; CHECK: if.else: 62; CHECK-NEXT: store i8 1, ptr [[TMP0]], align 1 63; CHECK-NEXT: br label [[IF_END]] 64; CHECK: if.end: 65; CHECK-NEXT: ret void 66; 67entry: 68 call void @llvm.assume(i1 true) [ "align"(ptr %a, i64 32, i32 24) ] 69 %0 = getelementptr inbounds i8, ptr %a, i64 8 70 %1 = ptrtoint ptr %0 to i64 71 %2 = and i64 %1, 15 72 %3 = icmp eq i64 %2, 0 73 br i1 %3, label %if.then, label %if.else 74 75if.then: ; preds = %entry 76 store i64 16, ptr %0, align 4 77 br label %if.end 78 79if.else: ; preds = %entry 80 store i8 1, ptr %0, align 1 81 br label %if.end 82 83if.end: ; preds = %if.else, %if.then 84 ret void 85} 86 87define void @f3(i64 %a, ptr %b) { 88; CHECK-LABEL: @f3( 89; CHECK-NEXT: [[C:%.*]] = ptrtoint ptr [[B:%.*]] to i64 90; CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr [[B]], i64 4294967296) ] 91; CHECK-NEXT: [[D:%.*]] = add i64 [[A:%.*]], [[C]] 92; CHECK-NEXT: call void @g(i64 [[D]]) 93; CHECK-NEXT: ret void 94; 95 %c = ptrtoint ptr %b to i64 96 call void @llvm.assume(i1 true) [ "align"(ptr %b, i64 4294967296) ] 97 %d = add i64 %a, %c 98 call void @g(i64 %d) 99 ret void 100} 101 102declare void @g(i64) 103 104define i8 @assume_align_zero(ptr %p) { 105; CHECK-LABEL: @assume_align_zero( 106; CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr [[P:%.*]], i64 0) ] 107; CHECK-NEXT: [[V:%.*]] = load i8, ptr [[P]], align 1 108; CHECK-NEXT: ret i8 [[V]] 109; 110 call void @llvm.assume(i1 true) [ "align"(ptr %p, i64 0) ] 111 %v = load i8, ptr %p 112 ret i8 %v 113} 114 115define i8 @assume_align_non_pow2(ptr %p) { 116; CHECK-LABEL: @assume_align_non_pow2( 117; CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr [[P:%.*]], i64 123) ] 118; CHECK-NEXT: [[V:%.*]] = load i8, ptr [[P]], align 1 119; CHECK-NEXT: ret i8 [[V]] 120; 121 call void @llvm.assume(i1 true) [ "align"(ptr %p, i64 123) ] 122 %v = load i8, ptr %p 123 ret i8 %v 124} 125 126; TODO: Can fold alignment assumption into !align metadata on load. 127define ptr @fold_assume_align_pow2_of_loaded_pointer_into_align_metadata(ptr %p) { 128; CHECK-LABEL: @fold_assume_align_pow2_of_loaded_pointer_into_align_metadata( 129; CHECK-NEXT: [[P2:%.*]] = load ptr, ptr [[P:%.*]], align 8 130; CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr [[P2]], i64 8) ] 131; CHECK-NEXT: ret ptr [[P2]] 132; 133 %p2 = load ptr, ptr %p 134 call void @llvm.assume(i1 true) [ "align"(ptr %p2, i64 8) ] 135 ret ptr %p2 136} 137 138define ptr @dont_fold_assume_align_pow2_of_loaded_pointer_into_align_metadata_due_to_call(ptr %p) { 139; CHECK-LABEL: @dont_fold_assume_align_pow2_of_loaded_pointer_into_align_metadata_due_to_call( 140; CHECK-NEXT: [[P2:%.*]] = load ptr, ptr [[P:%.*]], align 8 141; CHECK-NEXT: call void @g(i64 0) 142; CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr [[P2]], i64 8) ] 143; CHECK-NEXT: ret ptr [[P2]] 144; 145 %p2 = load ptr, ptr %p 146 call void @g(i64 0) 147 call void @llvm.assume(i1 true) [ "align"(ptr %p2, i64 8) ] 148 ret ptr %p2 149} 150 151; !align must have a power-of-2 alignment. 152define ptr @dont_fold_assume_align_non_pow2_of_loaded_pointer_into_align_metadata(ptr %p) { 153; CHECK-LABEL: @dont_fold_assume_align_non_pow2_of_loaded_pointer_into_align_metadata( 154; CHECK-NEXT: [[P2:%.*]] = load ptr, ptr [[P:%.*]], align 8 155; CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr [[P2]], i64 13) ] 156; CHECK-NEXT: ret ptr [[P2]] 157; 158 %p2 = load ptr, ptr %p 159 call void @llvm.assume(i1 true) [ "align"(ptr %p2, i64 13) ] 160 ret ptr %p2 161} 162 163; !align must have a power-of-2 alignment. 164define ptr @dont_fold_assume_align_zero_of_loaded_pointer_into_align_metadata(ptr %p) { 165; CHECK-LABEL: @dont_fold_assume_align_zero_of_loaded_pointer_into_align_metadata( 166; CHECK-NEXT: [[P2:%.*]] = load ptr, ptr [[P:%.*]], align 8 167; CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr [[P2]], i64 0) ] 168; CHECK-NEXT: ret ptr [[P2]] 169; 170 %p2 = load ptr, ptr %p 171 call void @llvm.assume(i1 true) [ "align"(ptr %p2, i64 0) ] 172 ret ptr %p2 173} 174 175define ptr @redundant_assume_align_1(ptr %p) { 176; CHECK-LABEL: @redundant_assume_align_1( 177; CHECK-NEXT: [[P2:%.*]] = load ptr, ptr [[P:%.*]], align 8 178; CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr [[P2]], i32 1) ] 179; CHECK-NEXT: call void @foo(ptr [[P2]]) 180; CHECK-NEXT: ret ptr [[P2]] 181; 182 %p2 = load ptr, ptr %p 183 call void @llvm.assume(i1 true) [ "align"(ptr %p2, i32 1) ] 184 call void @foo(ptr %p2) 185 ret ptr %p2 186} 187 188 189define ptr @redundant_assume_align_8_via_align_metadata(ptr %p) { 190; CHECK-LABEL: @redundant_assume_align_8_via_align_metadata( 191; CHECK-NEXT: [[P2:%.*]] = load ptr, ptr [[P:%.*]], align 8, !align [[META0:![0-9]+]] 192; CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr [[P2]], i32 8) ] 193; CHECK-NEXT: call void @foo(ptr [[P2]]) 194; CHECK-NEXT: ret ptr [[P2]] 195; 196 %p2 = load ptr, ptr %p, !align !{i64 8} 197 call void @llvm.assume(i1 true) [ "align"(ptr %p2, i32 8) ] 198 call void @foo(ptr %p2) 199 ret ptr %p2 200} 201 202define ptr @assume_align_16_via_align_metadata(ptr %p) { 203; CHECK-LABEL: @assume_align_16_via_align_metadata( 204; CHECK-NEXT: [[P2:%.*]] = load ptr, ptr [[P:%.*]], align 8, !align [[META0]] 205; CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr [[P2]], i32 16) ] 206; CHECK-NEXT: call void @foo(ptr [[P2]]) 207; CHECK-NEXT: ret ptr [[P2]] 208; 209 %p2 = load ptr, ptr %p, !align !{i64 8} 210 call void @llvm.assume(i1 true) [ "align"(ptr %p2, i32 16) ] 211 call void @foo(ptr %p2) 212 ret ptr %p2 213} 214 215define ptr @redundant_assume_align_8_via_align_attribute(ptr align 8 %p) { 216; CHECK-LABEL: @redundant_assume_align_8_via_align_attribute( 217; CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr [[P:%.*]], i32 8) ] 218; CHECK-NEXT: call void @foo(ptr [[P]]) 219; CHECK-NEXT: ret ptr [[P]] 220; 221 call void @llvm.assume(i1 true) [ "align"(ptr %p, i32 8) ] 222 call void @foo(ptr %p) 223 ret ptr %p 224} 225 226define ptr @assume_align_16_via_align_attribute(ptr align 8 %p) { 227; CHECK-LABEL: @assume_align_16_via_align_attribute( 228; CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr [[P:%.*]], i32 16) ] 229; CHECK-NEXT: call void @foo(ptr [[P]]) 230; CHECK-NEXT: ret ptr [[P]] 231; 232 call void @llvm.assume(i1 true) [ "align"(ptr %p, i32 16) ] 233 call void @foo(ptr %p) 234 ret ptr %p 235} 236 237define ptr @redundant_assume_align_8_via_asume(ptr %p) { 238; CHECK-LABEL: @redundant_assume_align_8_via_asume( 239; CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr [[P:%.*]], i32 16) ] 240; CHECK-NEXT: call void @foo(ptr [[P]]) 241; CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr [[P]], i32 8) ] 242; CHECK-NEXT: call void @foo(ptr [[P]]) 243; CHECK-NEXT: ret ptr [[P]] 244; 245 call void @llvm.assume(i1 true) [ "align"(ptr %p, i32 16) ] 246 call void @foo(ptr %p) 247 call void @llvm.assume(i1 true) [ "align"(ptr %p, i32 8) ] 248 call void @foo(ptr %p) 249 ret ptr %p 250} 251 252declare void @foo(ptr) 253;. 254; CHECK: [[META0]] = !{i64 8} 255;. 256