; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 2 ; RUN: opt < %s -passes=infer-alignment -S | FileCheck %s ; ------------------------------------------------------------------------------ ; Simple test ; ------------------------------------------------------------------------------ define void @simple_forwardpropagate(ptr %a) { ; CHECK-LABEL: define void @simple_forwardpropagate ; CHECK-SAME: (ptr [[A:%.*]]) { ; CHECK-NEXT: [[PTRINT:%.*]] = ptrtoint ptr [[A]] to i64 ; CHECK-NEXT: [[MASKEDPTR:%.*]] = and i64 [[PTRINT]], 31 ; CHECK-NEXT: [[MASKCOND:%.*]] = icmp eq i64 [[MASKEDPTR]], 0 ; CHECK-NEXT: tail call void @llvm.assume(i1 [[MASKCOND]]) ; CHECK-NEXT: [[LOAD_A:%.*]] = load i32, ptr [[A]], align 32 ; CHECK-NEXT: store i32 345, ptr [[A]], align 32 ; CHECK-NEXT: ret void ; %ptrint = ptrtoint ptr %a to i64 %maskedptr = and i64 %ptrint, 31 %maskcond = icmp eq i64 %maskedptr, 0 tail call void @llvm.assume(i1 %maskcond) %load.a = load i32, ptr %a, align 4 store i32 345, ptr %a, align 4 ret void } define void @simple_backpropagate(ptr %a) { ; CHECK-LABEL: define void @simple_backpropagate ; CHECK-SAME: (ptr [[A:%.*]]) { ; CHECK-NEXT: [[LOAD_A:%.*]] = load i32, ptr [[A]], align 32 ; CHECK-NEXT: store i32 345, ptr [[A]], align 32 ; CHECK-NEXT: [[PTRINT:%.*]] = ptrtoint ptr [[A]] to i64 ; CHECK-NEXT: [[MASKEDPTR:%.*]] = and i64 [[PTRINT]], 31 ; CHECK-NEXT: [[MASKCOND:%.*]] = icmp eq i64 [[MASKEDPTR]], 0 ; CHECK-NEXT: tail call void @llvm.assume(i1 [[MASKCOND]]) ; CHECK-NEXT: ret void ; %load.a = load i32, ptr %a, align 4 store i32 345, ptr %a, align 4 %ptrint = ptrtoint ptr %a to i64 %maskedptr = and i64 %ptrint, 31 %maskcond = icmp eq i64 %maskedptr, 0 tail call void @llvm.assume(i1 %maskcond) ret void } define void @simple_forwardpropagate_bundle(ptr %a) { ; CHECK-LABEL: define void @simple_forwardpropagate_bundle ; CHECK-SAME: (ptr [[A:%.*]]) { ; CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr [[A]], i32 32) ] ; CHECK-NEXT: [[LOAD_A:%.*]] = load i32, ptr [[A]], align 32 ; CHECK-NEXT: store i32 345, ptr [[A]], align 32 ; CHECK-NEXT: ret void ; call void @llvm.assume(i1 true) ["align"(ptr %a, i32 32)] %load.a = load i32, ptr %a, align 4 store i32 345, ptr %a, align 4 ret void } define void @simple_backpropagate_bundle(ptr %a) { ; CHECK-LABEL: define void @simple_backpropagate_bundle ; CHECK-SAME: (ptr [[A:%.*]]) { ; CHECK-NEXT: [[LOAD_A:%.*]] = load i32, ptr [[A]], align 32 ; CHECK-NEXT: store i32 345, ptr [[A]], align 32 ; CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr [[A]], i32 32) ] ; CHECK-NEXT: ret void ; %load.a = load i32, ptr %a, align 4 store i32 345, ptr %a, align 4 call void @llvm.assume(i1 true) ["align"(ptr %a, i32 32)] ret void } ; ------------------------------------------------------------------------------ ; Complex test ; ------------------------------------------------------------------------------ define void @loop_forwardpropagate(ptr %a, ptr %b) { ; CHECK-LABEL: define void @loop_forwardpropagate ; CHECK-SAME: (ptr [[A:%.*]], ptr [[B:%.*]]) { ; CHECK-NEXT: entry: ; CHECK-NEXT: [[PTRINT:%.*]] = ptrtoint ptr [[A]] to i64 ; CHECK-NEXT: [[MASKEDPTR:%.*]] = and i64 [[PTRINT]], 63 ; CHECK-NEXT: [[MASKCOND:%.*]] = icmp eq i64 [[MASKEDPTR]], 0 ; CHECK-NEXT: tail call void @llvm.assume(i1 [[MASKCOND]]) ; CHECK-NEXT: [[PTRINT2:%.*]] = ptrtoint ptr [[B]] to i64 ; CHECK-NEXT: [[MASKEDPTR2:%.*]] = and i64 [[PTRINT2]], 63 ; CHECK-NEXT: [[MASKEDCOND2:%.*]] = icmp eq i64 [[MASKEDPTR2]], 0 ; CHECK-NEXT: tail call void @llvm.assume(i1 [[MASKEDCOND2]]) ; CHECK-NEXT: br label [[FOR_BODY:%.*]] ; CHECK: for.body: ; CHECK-NEXT: [[I:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[I_NEXT:%.*]], [[FOR_BODY]] ] ; CHECK-NEXT: [[GEP_B:%.*]] = getelementptr inbounds i32, ptr [[B]], i64 [[I]] ; CHECK-NEXT: [[LOAD_B:%.*]] = load i32, ptr [[GEP_B]], align 64 ; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[LOAD_B]], 1 ; CHECK-NEXT: [[GEP_A:%.*]] = getelementptr inbounds i32, ptr [[A]], i64 [[I]] ; CHECK-NEXT: store i32 [[ADD]], ptr [[GEP_A]], align 64 ; CHECK-NEXT: [[I_NEXT]] = add nuw nsw i64 [[I]], 16 ; CHECK-NEXT: [[CMP:%.*]] = icmp slt i64 [[I_NEXT]], 1648 ; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_END:%.*]] ; CHECK: for.end: ; CHECK-NEXT: ret void ; entry: %ptrint = ptrtoint ptr %a to i64 %maskedptr = and i64 %ptrint, 63 %maskcond = icmp eq i64 %maskedptr, 0 tail call void @llvm.assume(i1 %maskcond) %ptrint2 = ptrtoint ptr %b to i64 %maskedptr2 = and i64 %ptrint2, 63 %maskedcond2 = icmp eq i64 %maskedptr2, 0 tail call void @llvm.assume(i1 %maskedcond2) br label %for.body for.body: %i = phi i64 [ 0, %entry ], [ %i.next, %for.body ] %gep.b = getelementptr inbounds i32, ptr %b, i64 %i %load.b = load i32, ptr %gep.b, align 4 %add = add nsw i32 %load.b, 1 %gep.a = getelementptr inbounds i32, ptr %a, i64 %i store i32 %add, ptr %gep.a, align 4 %i.next = add nuw nsw i64 %i, 16 %cmp = icmp slt i64 %i.next, 1648 br i1 %cmp, label %for.body, label %for.end for.end: ret void } define void @loop_forwardpropagate_bundle(ptr %a, ptr %b) { ; CHECK-LABEL: define void @loop_forwardpropagate_bundle ; CHECK-SAME: (ptr [[A:%.*]], ptr [[B:%.*]]) { ; CHECK-NEXT: entry: ; CHECK-NEXT: tail call void @llvm.assume(i1 true) [ "align"(ptr [[A]], i32 64) ] ; CHECK-NEXT: tail call void @llvm.assume(i1 true) [ "align"(ptr [[B]], i32 64) ] ; CHECK-NEXT: br label [[FOR_BODY:%.*]] ; CHECK: for.body: ; CHECK-NEXT: [[I:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[I_NEXT:%.*]], [[FOR_BODY]] ] ; CHECK-NEXT: [[GEP_B:%.*]] = getelementptr inbounds i32, ptr [[B]], i64 [[I]] ; CHECK-NEXT: [[LOAD_B:%.*]] = load i32, ptr [[GEP_B]], align 64 ; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[LOAD_B]], 1 ; CHECK-NEXT: [[GEP_A:%.*]] = getelementptr inbounds i32, ptr [[A]], i64 [[I]] ; CHECK-NEXT: store i32 [[ADD]], ptr [[GEP_A]], align 64 ; CHECK-NEXT: [[I_NEXT]] = add nuw nsw i64 [[I]], 16 ; CHECK-NEXT: [[CMP:%.*]] = icmp slt i64 [[I_NEXT]], 1648 ; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_END:%.*]] ; CHECK: for.end: ; CHECK-NEXT: ret void ; entry: tail call void @llvm.assume(i1 true) ["align"(ptr %a, i32 64)] tail call void @llvm.assume(i1 true) ["align"(ptr %b, i32 64)] br label %for.body for.body: %i = phi i64 [ 0, %entry ], [ %i.next, %for.body ] %gep.b = getelementptr inbounds i32, ptr %b, i64 %i %load.b = load i32, ptr %gep.b, align 4 %add = add nsw i32 %load.b, 1 %gep.a = getelementptr inbounds i32, ptr %a, i64 %i store i32 %add, ptr %gep.a, align 4 %i.next = add nuw nsw i64 %i, 16 %cmp = icmp slt i64 %i.next, 1648 br i1 %cmp, label %for.body, label %for.end for.end: ret void } ; Check that assume is propagated backwards through all ; operations that are `isGuaranteedToTransferExecutionToSuccessor` ; (it should reach the load and mark it as `align 32`). define void @complex_backpropagate(ptr %a, ptr %b, ptr %c) { ; CHECK-LABEL: define void @complex_backpropagate ; CHECK-SAME: (ptr [[A:%.*]], ptr [[B:%.*]], ptr [[C:%.*]]) { ; CHECK-NEXT: [[ALLOCA:%.*]] = alloca i64, align 8 ; CHECK-NEXT: [[LOAD_A:%.*]] = load i32, ptr [[A]], align 32 ; CHECK-NEXT: [[LOAD_B:%.*]] = load i32, ptr [[B]], align 4 ; CHECK-NEXT: store i32 [[LOAD_B]], ptr [[A]], align 32 ; CHECK-NEXT: [[OBJ_SIZE:%.*]] = call i64 @llvm.objectsize.i64.p0(ptr [[C]], i1 false, i1 false, i1 false) ; CHECK-NEXT: store i64 [[OBJ_SIZE]], ptr [[ALLOCA]], align 8 ; CHECK-NEXT: [[PTRINT:%.*]] = ptrtoint ptr [[A]] to i64 ; CHECK-NEXT: [[MASKEDPTR:%.*]] = and i64 [[PTRINT]], 31 ; CHECK-NEXT: [[MASKCOND:%.*]] = icmp eq i64 [[MASKEDPTR]], 0 ; CHECK-NEXT: tail call void @llvm.assume(i1 [[MASKCOND]]) ; CHECK-NEXT: ret void ; %alloca = alloca i64 %load.a = load i32, ptr %a, align 4 %load.b = load i32, ptr %b store i32 %load.b, ptr %a %obj.size = call i64 @llvm.objectsize.i64.p0(ptr %c, i1 false) store i64 %obj.size, ptr %alloca %ptrint = ptrtoint ptr %a to i64 %maskedptr = and i64 %ptrint, 31 %maskcond = icmp eq i64 %maskedptr, 0 tail call void @llvm.assume(i1 %maskcond) ret void } define void @complex_backpropagate_bundle(ptr %a, ptr %b, ptr %c) { ; CHECK-LABEL: define void @complex_backpropagate_bundle ; CHECK-SAME: (ptr [[A:%.*]], ptr [[B:%.*]], ptr [[C:%.*]]) { ; CHECK-NEXT: [[ALLOCA:%.*]] = alloca i64, align 8 ; CHECK-NEXT: [[LOAD_A:%.*]] = load i32, ptr [[A]], align 32 ; CHECK-NEXT: [[LOAD_B:%.*]] = load i32, ptr [[B]], align 4 ; CHECK-NEXT: store i32 [[LOAD_B]], ptr [[A]], align 32 ; CHECK-NEXT: [[OBJ_SIZE:%.*]] = call i64 @llvm.objectsize.i64.p0(ptr [[C]], i1 false, i1 false, i1 false) ; CHECK-NEXT: store i64 [[OBJ_SIZE]], ptr [[ALLOCA]], align 8 ; CHECK-NEXT: tail call void @llvm.assume(i1 true) [ "align"(ptr [[A]], i32 32) ] ; CHECK-NEXT: ret void ; %alloca = alloca i64 %load.a = load i32, ptr %a, align 4 %load.b = load i32, ptr %b store i32 %load.b, ptr %a %obj.size = call i64 @llvm.objectsize.i64.p0(ptr %c, i1 false) store i64 %obj.size, ptr %alloca tail call void @llvm.assume(i1 true) ["align"(ptr %a, i32 32)] ret void } declare i64 @llvm.objectsize.i64.p0(ptr, i1) declare void @llvm.assume(i1)