| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6 | |
| ; RUN: opt -S -mtriple=amdgcn-amd-amdhsa -passes="loop-simplify,simplifycfg<no-keep-loops>,loop-unroll" < %s | FileCheck %s --check-prefix=UNROLL | |
| ; RUN: opt -S -mtriple=amdgcn-amd-amdhsa -passes="loop-simplify,simplifycfg<no-keep-loops>,loop-vectorize" < %s | FileCheck %s --check-prefix=VECTORIZE | |
| ; SimplifyCFG without canonical loops folds the unique backedge block inserted | |
| ; by LoopSimplify. The loop unroller and the vectorizer re-simplify the loop | |
| ; and must not separate it into a nested loop on a target with branch | |
| ; divergence either. | |
| define i32 @continue_loop(i32 %n, ptr %p) { | |
| ; UNROLL-LABEL: define i32 @continue_loop( | |
| ; UNROLL-SAME: i32 [[N:%.*]], ptr [[P:%.*]]) { | |
| ; UNROLL-NEXT: [[ENTRY:.*]]: | |
| ; UNROLL-NEXT: [[TID:%.*]] = call i32 @llvm.amdgcn.workitem.id.x() | |
| ; UNROLL-NEXT: br label %[[HEADER:.*]] | |
| ; UNROLL: [[HEADER]]: | |
| ; UNROLL-NEXT: [[I:%.*]] = phi i32 [ 0, %[[ENTRY]] ], [ [[I_NEXT:%.*]], %[[HEADER_BACKEDGE:.*]] ] | |
| ; UNROLL-NEXT: [[ACC:%.*]] = phi i32 [ 0, %[[ENTRY]] ], [ [[ACC_BE:%.*]], %[[HEADER_BACKEDGE]] ] | |
| ; UNROLL-NEXT: [[I_NEXT]] = add i32 [[I]], 1 | |
| ; UNROLL-NEXT: [[GEP:%.*]] = getelementptr i32, ptr [[P]], i32 [[I]] | |
| ; UNROLL-NEXT: [[V:%.*]] = load i32, ptr [[GEP]], align 4 | |
| ; UNROLL-NEXT: [[BITS:%.*]] = lshr i32 [[V]], [[TID]] | |
| ; UNROLL-NEXT: [[BIT:%.*]] = and i32 [[BITS]], 1 | |
| ; UNROLL-NEXT: [[IS_ZERO:%.*]] = icmp eq i32 [[BIT]], 0 | |
| ; UNROLL-NEXT: br i1 [[IS_ZERO]], label %[[CONTINUE:.*]], label %[[UPDATE:.*]] | |
| ; UNROLL: [[CONTINUE]]: | |
| ; UNROLL-NEXT: [[C1:%.*]] = icmp slt i32 [[I_NEXT]], [[N]] | |
| ; UNROLL-NEXT: br i1 [[C1]], label %[[HEADER_BACKEDGE]], label %[[EXIT:.*]] | |
| ; UNROLL: [[HEADER_BACKEDGE]]: | |
| ; UNROLL-NEXT: [[ACC_BE]] = phi i32 [ [[ACC]], %[[CONTINUE]] ], [ [[ACC_NEXT:%.*]], %[[UPDATE]] ] | |
| ; UNROLL-NEXT: br label %[[HEADER]] | |
| ; UNROLL: [[UPDATE]]: | |
| ; UNROLL-NEXT: [[ACC_NEXT]] = add i32 [[ACC]], [[V]] | |
| ; UNROLL-NEXT: [[C2:%.*]] = icmp slt i32 [[I_NEXT]], [[N]] | |
| ; UNROLL-NEXT: br i1 [[C2]], label %[[HEADER_BACKEDGE]], label %[[EXIT]] | |
| ; UNROLL: [[EXIT]]: | |
| ; UNROLL-NEXT: [[R:%.*]] = phi i32 [ [[ACC]], %[[CONTINUE]] ], [ [[ACC_NEXT]], %[[UPDATE]] ] | |
| ; UNROLL-NEXT: ret i32 [[R]] | |
| ; | |
| ; VECTORIZE-LABEL: define i32 @continue_loop( | |
| ; VECTORIZE-SAME: i32 [[N:%.*]], ptr [[P:%.*]]) { | |
| ; VECTORIZE-NEXT: [[ENTRY:.*]]: | |
| ; VECTORIZE-NEXT: [[TID:%.*]] = call i32 @llvm.amdgcn.workitem.id.x() | |
| ; VECTORIZE-NEXT: br label %[[HEADER:.*]] | |
| ; VECTORIZE: [[HEADER]]: | |
| ; VECTORIZE-NEXT: [[I:%.*]] = phi i32 [ 0, %[[ENTRY]] ], [ [[I_NEXT:%.*]], %[[HEADER_BACKEDGE:.*]] ] | |
| ; VECTORIZE-NEXT: [[ACC:%.*]] = phi i32 [ 0, %[[ENTRY]] ], [ [[ACC_BE:%.*]], %[[HEADER_BACKEDGE]] ] | |
| ; VECTORIZE-NEXT: [[I_NEXT]] = add i32 [[I]], 1 | |
| ; VECTORIZE-NEXT: [[GEP:%.*]] = getelementptr i32, ptr [[P]], i32 [[I]] | |
| ; VECTORIZE-NEXT: [[V:%.*]] = load i32, ptr [[GEP]], align 4 | |
| ; VECTORIZE-NEXT: [[BITS:%.*]] = lshr i32 [[V]], [[TID]] | |
| ; VECTORIZE-NEXT: [[BIT:%.*]] = and i32 [[BITS]], 1 | |
| ; VECTORIZE-NEXT: [[IS_ZERO:%.*]] = icmp eq i32 [[BIT]], 0 | |
| ; VECTORIZE-NEXT: br i1 [[IS_ZERO]], label %[[CONTINUE:.*]], label %[[UPDATE:.*]] | |
| ; VECTORIZE: [[CONTINUE]]: | |
| ; VECTORIZE-NEXT: [[C1:%.*]] = icmp slt i32 [[I_NEXT]], [[N]] | |
| ; VECTORIZE-NEXT: br i1 [[C1]], label %[[HEADER_BACKEDGE]], label %[[EXIT:.*]] | |
| ; VECTORIZE: [[HEADER_BACKEDGE]]: | |
| ; VECTORIZE-NEXT: [[ACC_BE]] = phi i32 [ [[ACC]], %[[CONTINUE]] ], [ [[ACC_NEXT:%.*]], %[[UPDATE]] ] | |
| ; VECTORIZE-NEXT: br label %[[HEADER]] | |
| ; VECTORIZE: [[UPDATE]]: | |
| ; VECTORIZE-NEXT: [[ACC_NEXT]] = add i32 [[ACC]], [[V]] | |
| ; VECTORIZE-NEXT: [[C2:%.*]] = icmp slt i32 [[I_NEXT]], [[N]] | |
| ; VECTORIZE-NEXT: br i1 [[C2]], label %[[HEADER_BACKEDGE]], label %[[EXIT]] | |
| ; VECTORIZE: [[EXIT]]: | |
| ; VECTORIZE-NEXT: [[R:%.*]] = phi i32 [ [[ACC]], %[[CONTINUE]] ], [ [[ACC_NEXT]], %[[UPDATE]] ] | |
| ; VECTORIZE-NEXT: ret i32 [[R]] | |
| ; | |
| entry: | |
| %tid = call i32 @llvm.amdgcn.workitem.id.x() | |
| br label %header | |
| header: | |
| %i = phi i32 [ 0, %entry ], [ %i.next, %continue ], [ %i.next, %update ] | |
| %acc = phi i32 [ 0, %entry ], [ %acc, %continue ], [ %acc.next, %update ] | |
| %i.next = add i32 %i, 1 | |
| %gep = getelementptr i32, ptr %p, i32 %i | |
| %v = load i32, ptr %gep, align 4 | |
| %bits = lshr i32 %v, %tid | |
| %bit = and i32 %bits, 1 | |
| %is.zero = icmp eq i32 %bit, 0 | |
| br i1 %is.zero, label %continue, label %update | |
| continue: | |
| %c1 = icmp slt i32 %i.next, %n | |
| br i1 %c1, label %header, label %exit | |
| update: | |
| %acc.next = add i32 %acc, %v | |
| %c2 = icmp slt i32 %i.next, %n | |
| br i1 %c2, label %header, label %exit | |
| exit: | |
| %r = phi i32 [ %acc, %continue ], [ %acc.next, %update ] | |
| ret i32 %r | |
| } | |
| declare i32 @llvm.amdgcn.workitem.id.x() |