; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 ; RUN: opt -p loop-idiom -S %s | FileCheck %s target datalayout = "e-m:e-i64:64-i128:128-f80:128-n8:16:32:64-S128-ni:1-p2:32:8:8:32-ni:2" declare void @foo() declare void @bar() define void @scev_expand_ptrtoint(i8 %x, ptr %start) { ; CHECK-LABEL: define void @scev_expand_ptrtoint( ; CHECK-SAME: i8 [[X:%.*]], ptr [[START:%.*]]) { ; CHECK-NEXT: [[ENTRY:.*]]: ; CHECK-NEXT: [[START1:%.*]] = ptrtoaddr ptr [[START]] to i64 ; CHECK-NEXT: br label %[[LOOP_1_HEADER:.*]] ; CHECK: [[LOOP_1_HEADER]]: ; CHECK-NEXT: [[PTR_IV_1:%.*]] = phi ptr [ [[START]], %[[ENTRY]] ], [ [[PTR_IV_1_NEXT:%.*]], %[[LOOP_1_LATCH:.*]] ] ; CHECK-NEXT: [[C:%.*]] = icmp ule i8 [[X]], 1 ; CHECK-NEXT: br i1 [[C]], label %[[LOOP_1_LATCH]], label %[[MIDDLE:.*]] ; CHECK: [[LOOP_1_LATCH]]: ; CHECK-NEXT: [[PTR_IV_1_NEXT]] = getelementptr i8, ptr [[PTR_IV_1]], i64 1 ; CHECK-NEXT: br label %[[LOOP_1_HEADER]] ; CHECK: [[MIDDLE]]: ; CHECK-NEXT: [[PTR_IV_1_LCSSA:%.*]] = phi ptr [ [[PTR_IV_1]], %[[LOOP_1_HEADER]] ] ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[X]], 0 ; CHECK-NEXT: [[CMP_EXT:%.*]] = zext i1 [[CMP]] to i64 ; CHECK-NEXT: [[GEP_START:%.*]] = getelementptr i8, ptr [[PTR_IV_1_LCSSA]], i64 [[CMP_EXT]] ; CHECK-NEXT: br label %[[LOOP_2_HEADER:.*]] ; CHECK: [[LOOP_2_HEADER]]: ; CHECK-NEXT: [[INDVAR:%.*]] = phi i64 [ [[INDVAR_NEXT:%.*]], %[[LOOP_2_LATCH:.*]] ], [ 0, %[[MIDDLE]] ] ; CHECK-NEXT: [[PTR_IV_2:%.*]] = phi ptr [ [[GEP_START]], %[[MIDDLE]] ], [ [[PTR_IV_2_NEXT:%.*]], %[[LOOP_2_LATCH]] ] ; CHECK-NEXT: switch i8 [[X]], label %[[LOOP_2_LATCH]] [ ; CHECK-NEXT: i8 1, label %[[LOOP_3_PREHEADER:.*]] ; CHECK-NEXT: i8 4, label %[[LOOP_3_PREHEADER]] ; CHECK-NEXT: ] ; CHECK: [[LOOP_3_PREHEADER]]: ; CHECK-NEXT: [[INDVAR_LCSSA:%.*]] = phi i64 [ [[INDVAR]], %[[LOOP_2_HEADER]] ], [ [[INDVAR]], %[[LOOP_2_HEADER]] ] ; CHECK-NEXT: [[PTR_IV_2_LCSSA:%.*]] = phi ptr [ [[PTR_IV_2]], %[[LOOP_2_HEADER]] ], [ [[PTR_IV_2]], %[[LOOP_2_HEADER]] ] ; CHECK-NEXT: [[TMP0:%.*]] = sub i64 1, [[START1]] ; CHECK-NEXT: [[TMP1:%.*]] = ptrtoaddr ptr [[PTR_IV_1_LCSSA]] to i64 ; CHECK-NEXT: [[TMP2:%.*]] = add i64 [[TMP1]], [[TMP0]] ; CHECK-NEXT: [[TMP4:%.*]] = add i64 [[CMP_EXT]], [[TMP2]] ; CHECK-NEXT: [[TMP5:%.*]] = add i64 [[INDVAR_LCSSA]], [[TMP4]] ; CHECK-NEXT: [[SCEVGEP:%.*]] = getelementptr i8, ptr [[START]], i64 [[TMP5]] ; CHECK-NEXT: [[STRLEN:%.*]] = call i64 @strlen(ptr [[SCEVGEP]]) ; CHECK-NEXT: br label %[[LOOP_3:.*]] ; CHECK: [[LOOP_2_LATCH]]: ; CHECK-NEXT: [[PTR_IV_2_NEXT]] = getelementptr i8, ptr [[PTR_IV_2]], i64 1 ; CHECK-NEXT: [[INDVAR_NEXT]] = add i64 [[INDVAR]], 1 ; CHECK-NEXT: br label %[[LOOP_2_HEADER]] ; CHECK: [[LOOP_3]]: ; CHECK-NEXT: [[IV_3:%.*]] = phi i64 [ [[IV_3_NEXT:%.*]], %[[LOOP_3]] ], [ 1, %[[LOOP_3_PREHEADER]] ] ; CHECK-NEXT: [[GEP:%.*]] = getelementptr i8, ptr [[PTR_IV_2_LCSSA]], i64 [[IV_3]] ; CHECK-NEXT: [[TMP6:%.*]] = load i8, ptr [[GEP]], align 1 ; CHECK-NEXT: [[EC:%.*]] = icmp eq i8 [[TMP6]], 0 ; CHECK-NEXT: [[IV_3_NEXT]] = add i64 [[IV_3]], 1 ; CHECK-NEXT: br i1 true, label %[[EXIT:.*]], label %[[LOOP_3]] ; CHECK: [[EXIT]]: ; CHECK-NEXT: ret void ; entry: br label %loop.1.header loop.1.header: %ptr.iv.1 = phi ptr [ %start, %entry ], [ %ptr.iv.1.next, %loop.1.latch ] %c = icmp ule i8 %x, 1 br i1 %c, label %loop.1.latch, label %middle loop.1.latch: %ptr.iv.1.next = getelementptr i8, ptr %ptr.iv.1, i64 1 br label %loop.1.header middle: %cmp = icmp eq i8 %x, 0 %cmp.ext = zext i1 %cmp to i64 %gep.start = getelementptr i8, ptr %ptr.iv.1, i64 %cmp.ext br label %loop.2.header loop.2.header: %ptr.iv.2 = phi ptr [ %gep.start, %middle ], [ %ptr.iv.2.next, %loop.2.latch ] switch i8 %x, label %loop.2.latch [ i8 1, label %loop.3 i8 4, label %loop.3 ] loop.2.latch: %ptr.iv.2.next = getelementptr i8, ptr %ptr.iv.2, i64 1 br label %loop.2.header loop.3: %iv.3 = phi i64 [ 1, %loop.2.header ], [ 1, %loop.2.header ], [ %iv.3.next, %loop.3 ] %gep = getelementptr i8, ptr %ptr.iv.2, i64 %iv.3 %1 = load i8, ptr %gep, align 1 %ec = icmp eq i8 %1, 0 %iv.3.next = add i64 %iv.3, 1 br i1 %ec, label %exit, label %loop.3 exit: ret void } declare i1 @cond() define ptr @test_lcssa_reuse_preserve_lcssa() { ; CHECK-LABEL: define ptr @test_lcssa_reuse_preserve_lcssa() { ; CHECK-NEXT: [[ENTRY:.*:]] ; CHECK-NEXT: br label %[[LOOP_0_HEADER:.*]] ; CHECK: [[LOOP_0_HEADER]]: ; CHECK-NEXT: br label %[[LOOP_1:.*]] ; CHECK: [[LOOP_1]]: ; CHECK-NEXT: [[IV_1:%.*]] = phi ptr [ null, %[[LOOP_0_HEADER]] ], [ [[IV_1_NEXT:%.*]], %[[LOOP_1]] ] ; CHECK-NEXT: [[IV_1_NEXT]] = getelementptr i8, ptr [[IV_1]], i64 1 ; CHECK-NEXT: [[EC_1:%.*]] = call i1 @cond() ; CHECK-NEXT: br i1 [[EC_1]], label %[[THEN:.*]], label %[[LOOP_1]] ; CHECK: [[THEN]]: ; CHECK-NEXT: [[IV_1_LCSSA1:%.*]] = phi ptr [ [[IV_1]], %[[LOOP_1]] ] ; CHECK-NEXT: [[C_2:%.*]] = call i1 @cond() ; CHECK-NEXT: br i1 [[C_2]], label %[[LOOP_2_PREHEADER:.*]], label %[[LOOP_0_LATCH:.*]] ; CHECK: [[LOOP_2_PREHEADER]]: ; CHECK-NEXT: [[IV_1_LCSSA:%.*]] = phi ptr [ [[IV_1_LCSSA1]], %[[THEN]] ] ; CHECK-NEXT: [[IV_1_LCSSA_LCSSA:%.*]] = phi ptr [ [[IV_1_LCSSA1]], %[[THEN]] ] ; CHECK-NEXT: [[STRLEN:%.*]] = call i64 @strlen(ptr null) ; CHECK-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr [[IV_1_LCSSA]], i64 1 ; CHECK-NEXT: [[SCEVGEP:%.*]] = getelementptr i8, ptr [[TMP0]], i64 [[STRLEN]] ; CHECK-NEXT: br label %[[LOOP_2:.*]] ; CHECK: [[LOOP_2]]: ; CHECK-NEXT: [[IV_2:%.*]] = phi ptr [ [[RES:%.*]], %[[LOOP_2]] ], [ [[IV_1_LCSSA_LCSSA]], %[[LOOP_2_PREHEADER]] ] ; CHECK-NEXT: [[RES]] = getelementptr i8, ptr [[IV_2]], i64 1 ; CHECK-NEXT: [[L:%.*]] = load i8, ptr [[IV_1_LCSSA_LCSSA]], align 1 ; CHECK-NEXT: [[EC_2:%.*]] = icmp eq i8 [[L]], 0 ; CHECK-NEXT: br i1 true, label %[[EXIT:.*]], label %[[LOOP_2]] ; CHECK: [[LOOP_0_LATCH]]: ; CHECK-NEXT: br label %[[LOOP_0_HEADER]] ; CHECK: [[EXIT]]: ; CHECK-NEXT: ret ptr [[SCEVGEP]] ; entry: br label %loop.0.header loop.0.header: br label %loop.1 loop.1: %iv.1 = phi ptr [ null, %loop.0.header ], [ %iv.1.next, %loop.1 ] %iv.1.next = getelementptr i8, ptr %iv.1, i64 1 %ec.1 = call i1 @cond() br i1 %ec.1, label %then, label %loop.1 then: %c.2 = call i1 @cond() br i1 %c.2, label %loop.2, label %loop.0.latch loop.2: %iv.2 = phi ptr [ %res, %loop.2 ], [ %iv.1, %then ] %res = getelementptr i8, ptr %iv.2, i64 1 %l = load i8, ptr %iv.1, align 1 %ec.2 = icmp eq i8 %l, 0 br i1 %ec.2, label %exit, label %loop.2 loop.0.latch: br label %loop.0.header exit: ret ptr %res } ; Test case for https://github.com/llvm/llvm-project/issues/155287. ; Make sure we don't crash when trying to construct a PtrToInt SCEV expression ; results in SCEVCouldNotCompute. define void @phi_ptr_addressspace_ptrtoint_fail(ptr addrspace(1) %arg) { ; CHECK-LABEL: define void @phi_ptr_addressspace_ptrtoint_fail( ; CHECK-SAME: ptr addrspace(1) [[ARG:%.*]]) { ; CHECK-NEXT: [[BB:.*]]: ; CHECK-NEXT: br label %[[LOOP_1:.*]] ; CHECK: [[LOOP_1]]: ; CHECK-NEXT: [[IV_1:%.*]] = phi i64 [ 0, %[[BB]] ], [ [[ADD5:%.*]], %[[LOOP_1]] ] ; CHECK-NEXT: [[ADD5]] = add i64 [[IV_1]], 1 ; CHECK-NEXT: [[GETELEMENTPTR:%.*]] = getelementptr i16, ptr addrspace(1) [[ARG]], i64 [[ADD5]] ; CHECK-NEXT: br i1 false, label %[[LOOP_1]], label %[[LOOP_2_PH:.*]] ; CHECK: [[LOOP_2_PH]]: ; CHECK-NEXT: [[IV_1_LCSSA1:%.*]] = phi i64 [ [[IV_1]], %[[LOOP_1]] ] ; CHECK-NEXT: [[IV_1_LCSSA:%.*]] = phi i64 [ [[IV_1]], %[[LOOP_1]] ] ; CHECK-NEXT: [[PHI:%.*]] = phi ptr addrspace(1) [ [[GETELEMENTPTR]], %[[LOOP_1]] ] ; CHECK-NEXT: [[TMP0:%.*]] = shl nuw nsw i64 [[IV_1_LCSSA1]], 2 ; CHECK-NEXT: [[SCEVGEP:%.*]] = getelementptr i8, ptr addrspace(1) [[ARG]], i64 [[TMP0]] ; CHECK-NEXT: call void @llvm.memset.p1.i64(ptr addrspace(1) align 4 [[SCEVGEP]], i8 0, i64 8, i1 false) ; CHECK-NEXT: br label %[[LOOP_2_HEADER:.*]] ; CHECK: [[LOOP_2_HEADER]]: ; CHECK-NEXT: [[IV_2:%.*]] = phi i64 [ [[IV_1_LCSSA]], %[[LOOP_2_PH]] ], [ [[IV_2_NEXT:%.*]], %[[LOOP_2_LATCH:.*]] ] ; CHECK-NEXT: [[GREP_ARG:%.*]] = getelementptr i32, ptr addrspace(1) [[ARG]], i64 [[IV_2]] ; CHECK-NEXT: [[EC:%.*]] = icmp ult i64 [[IV_2]], 1 ; CHECK-NEXT: br i1 [[EC]], label %[[LOOP_2_LATCH]], label %[[EXIT:.*]] ; CHECK: [[LOOP_2_LATCH]]: ; CHECK-NEXT: [[IV_2_NEXT]] = add i64 [[IV_2]], 1 ; CHECK-NEXT: br label %[[LOOP_2_HEADER]] ; CHECK: [[EXIT]]: ; CHECK-NEXT: ret void ; bb: br label %loop.1 loop.1: %iv.1 = phi i64 [ 0, %bb ], [ %add5, %loop.1] %add5 = add i64 %iv.1, 1 %getelementptr = getelementptr i16, ptr addrspace(1) %arg, i64 %add5 br i1 false, label %loop.1, label %loop.2.ph loop.2.ph: %phi = phi ptr addrspace(1) [ %getelementptr, %loop.1] br label %loop.2.header loop.2.header: %iv.2 = phi i64 [ %iv.1, %loop.2.ph ], [ %iv.2.next, %loop.2.latch ] %grep.arg = getelementptr i32, ptr addrspace(1) %arg, i64 %iv.2 store i32 0, ptr addrspace(1) %grep.arg, align 4 %ec = icmp ult i64 %iv.2, 1 br i1 %ec, label %loop.2.latch, label %exit loop.2.latch: %iv.2.next = add i64 %iv.2, 1 br label %loop.2.header exit: ret void } define void @expand_truncated_ptrtoint(ptr %A, ptr %B) { ; CHECK-LABEL: define void @expand_truncated_ptrtoint( ; CHECK-SAME: ptr [[A:%.*]], ptr [[B:%.*]]) { ; CHECK-NEXT: [[ENTRY:.*]]: ; CHECK-NEXT: [[A1:%.*]] = ptrtoint ptr [[A]] to i64 ; CHECK-NEXT: br label %[[LOOP_1:.*]] ; CHECK: [[LOOP_1]]: ; CHECK-NEXT: [[INDVAR:%.*]] = phi i32 [ [[INDVAR_NEXT:%.*]], %[[LOOP_1]] ], [ 0, %[[ENTRY]] ] ; CHECK-NEXT: [[P_0:%.*]] = phi ptr [ [[A]], %[[ENTRY]] ], [ [[P_0_NEXT:%.*]], %[[LOOP_1]] ] ; CHECK-NEXT: [[P_0_NEXT]] = getelementptr i8, ptr [[P_0]], i64 -1 ; CHECK-NEXT: call void @foo() ; CHECK-NEXT: [[INDVAR_NEXT]] = add i32 [[INDVAR]], 1 ; CHECK-NEXT: br i1 false, label %[[MIDDLE:.*]], label %[[LOOP_1]] ; CHECK: [[MIDDLE]]: ; CHECK-NEXT: [[INDVAR_LCSSA:%.*]] = phi i32 [ [[INDVAR]], %[[LOOP_1]] ] ; CHECK-NEXT: [[P_0_LCSSA:%.*]] = phi ptr [ [[P_0]], %[[LOOP_1]] ] ; CHECK-NEXT: [[P_0_TO_INT:%.*]] = ptrtoint ptr [[P_0_LCSSA]] to i64 ; CHECK-NEXT: [[TRUNC:%.*]] = trunc i64 [[P_0_TO_INT]] to i32 ; CHECK-NEXT: [[TMP0:%.*]] = zext i32 [[TRUNC]] to i64 ; CHECK-NEXT: [[TMP1:%.*]] = mul nsw i64 [[TMP0]], -1 ; CHECK-NEXT: [[SCEVGEP:%.*]] = getelementptr i8, ptr [[B]], i64 [[TMP1]] ; CHECK-NEXT: [[TMP2:%.*]] = trunc i64 [[A1]] to i32 ; CHECK-NEXT: [[TMP3:%.*]] = add i32 [[TMP2]], 1 ; CHECK-NEXT: [[TMP6:%.*]] = mul i32 [[INDVAR_LCSSA]], -1 ; CHECK-NEXT: [[TMP5:%.*]] = add i32 [[TMP6]], [[TMP3]] ; CHECK-NEXT: [[TMP4:%.*]] = zext i32 [[TMP5]] to i64 ; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr align 1 [[SCEVGEP]], i8 0, i64 [[TMP4]], i1 false) ; CHECK-NEXT: br label %[[LOOP_2:.*]] ; CHECK: [[LOOP_2]]: ; CHECK-NEXT: [[P_1:%.*]] = phi ptr [ [[B]], %[[MIDDLE]] ], [ [[P_1_NEXT:%.*]], %[[LOOP_2]] ] ; CHECK-NEXT: [[P_2:%.*]] = phi i32 [ [[TRUNC]], %[[MIDDLE]] ], [ [[P_2_NEXT:%.*]], %[[LOOP_2]] ] ; CHECK-NEXT: [[P_1_NEXT]] = getelementptr i8, ptr [[P_1]], i64 -1 ; CHECK-NEXT: [[P_2_NEXT]] = add i32 [[P_2]], -1 ; CHECK-NEXT: [[EC:%.*]] = icmp sgt i32 [[P_2]], 0 ; CHECK-NEXT: br i1 [[EC]], label %[[LOOP_2]], label %[[EXIT:.*]] ; CHECK: [[EXIT]]: ; CHECK-NEXT: ret void ; entry: br label %loop.1 loop.1: %p.0 = phi ptr [ %A, %entry ], [ %p.0.next, %loop.1 ] %p.0.next = getelementptr i8, ptr %p.0, i64 -1 call void @foo() br i1 false, label %middle, label %loop.1 middle: %p.0.to.int = ptrtoint ptr %p.0 to i64 %trunc = trunc i64 %p.0.to.int to i32 br label %loop.2 loop.2: %p.1 = phi ptr [ %B, %middle ], [ %p.1.next, %loop.2 ] %p.2 = phi i32 [ %trunc, %middle ], [ %p.2.next, %loop.2 ] %p.1.next = getelementptr i8, ptr %p.1, i64 -1 store i8 0, ptr %p.1, align 1 %p.2.next = add i32 %p.2, -1 %ec = icmp sgt i32 %p.2, 0 br i1 %ec, label %loop.2, label %exit exit: ret void }