summaryrefslogtreecommitdiffstats
path: root/llvm/test
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/test')
-rw-r--r--llvm/test/Transforms/HardwareLoops/ARM/calls.ll404
-rw-r--r--llvm/test/Transforms/HardwareLoops/ARM/counter.ll35
-rw-r--r--llvm/test/Transforms/HardwareLoops/ARM/do-rem.ll259
-rw-r--r--llvm/test/Transforms/HardwareLoops/ARM/fp-emulation.ll207
-rw-r--r--llvm/test/Transforms/HardwareLoops/ARM/simple-do.ll155
-rw-r--r--llvm/test/Transforms/HardwareLoops/ARM/structure.ll72
6 files changed, 1132 insertions, 0 deletions
diff --git a/llvm/test/Transforms/HardwareLoops/ARM/calls.ll b/llvm/test/Transforms/HardwareLoops/ARM/calls.ll
new file mode 100644
index 00000000000..f2fb8f4eda7
--- /dev/null
+++ b/llvm/test/Transforms/HardwareLoops/ARM/calls.ll
@@ -0,0 +1,404 @@
+; RUN: opt -mtriple=thumbv8.1m.main-arm-none-eabi -hardware-loops -disable-arm-loloops=false %s -S -o - | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-MAIN
+; RUN: opt -mtriple=thumbv8.1m.main-arm-none-eabi -mattr=+fullfp16 -hardware-loops -disable-arm-loloops=false %s -S -o - | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-FP
+; RUN: opt -mtriple=thumbv8.1m.main-arm-none-eabi -mattr=+fp-armv8,+fullfp16 -hardware-loops -disable-arm-loloops=false %s -S -o - | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-FP64
+; RUN: opt -mtriple=thumbv8.1m.main-arm-none-eabi -mattr=+mve -hardware-loops -disable-arm-loloops=false %s -S -o - | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-MVE
+; RUN: opt -mtriple=thumbv8.1m.main-arm-none-eabi -mattr=+mve.fp -hardware-loops -disable-arm-loloops=false %s -S -o - | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-MVEFP
+
+
+; CHECK-LABEL: skip_call
+; CHECK-NOT: call void @llvm.set.loop.iterations
+; CHECK-NOT: call i32 @llvm.loop.decrement
+
+define i32 @skip_call(i32 %n) {
+entry:
+ %cmp6 = icmp eq i32 %n, 0
+ br i1 %cmp6, label %while.end, label %while.body.preheader
+
+while.body.preheader:
+ br label %while.body
+
+while.body:
+ %i.08 = phi i32 [ %inc1, %while.body ], [ 0, %while.body.preheader ]
+ %res.07 = phi i32 [ %add, %while.body ], [ 0, %while.body.preheader ]
+ %call = tail call i32 bitcast (i32 (...)* @bar to i32 ()*)() #2
+ %add = add nsw i32 %call, %res.07
+ %inc1 = add nuw i32 %i.08, 1
+ %exitcond = icmp eq i32 %inc1, %n
+ br i1 %exitcond, label %while.end.loopexit, label %while.body
+
+while.end.loopexit:
+ br label %while.end
+
+while.end:
+ %res.0.lcssa = phi i32 [ 0, %entry ], [ %add, %while.end.loopexit ]
+ ret i32 %res.0.lcssa
+}
+
+; CHECK-LABEL: test_target_specific
+; CHECK: call void @llvm.set.loop.iterations.i32(i32 50)
+; CHECK: [[COUNT:%[^ ]+]] = phi i32 [ 50, %entry ], [ [[LOOP_DEC:%[^ ]+]], %loop ]
+; CHECK: [[LOOP_DEC]] = call i32 @llvm.loop.decrement.reg.i32.i32.i32(i32 [[COUNT]], i32 1)
+; CHECK: [[CMP:%[^ ]+]] = icmp ne i32 [[LOOP_DEC]], 0
+; CHECK: br i1 [[CMP]], label %loop, label %exit
+
+define i32 @test_target_specific(i32* %a, i32* %b) {
+entry:
+ br label %loop
+loop:
+ %acc = phi i32 [ 0, %entry ], [ %res, %loop ]
+ %count = phi i32 [ 0, %entry ], [ %count.next, %loop ]
+ %addr.a = getelementptr i32, i32* %a, i32 %count
+ %addr.b = getelementptr i32, i32* %b, i32 %count
+ %load.a = load i32, i32* %addr.a
+ %load.b = load i32, i32* %addr.b
+ %res = call i32 @llvm.arm.smlad(i32 %load.a, i32 %load.b, i32 %acc)
+ %count.next = add nuw i32 %count, 2
+ %cmp = icmp ne i32 %count.next, 100
+ br i1 %cmp, label %loop, label %exit
+exit:
+ ret i32 %res
+}
+
+; CHECK-LABEL: test_fabs_f16
+; CHECK-MAIN-NOT: call void @llvm.set.loop.iterations
+; CHECK-MVE-NOT: call void @llvm.set.loop.iterations
+; CHECK-FP: call void @llvm.set.loop.iterations.i32(i32 100)
+; CHECK-MVEFP: call void @llvm.set.loop.iterations.i32(i32 100)
+define void @test_fabs_f16(half* %a, half* %b) {
+entry:
+ br label %loop
+loop:
+ %count = phi i32 [ 0, %entry ], [ %count.next, %loop ]
+ %addr.a = getelementptr half, half* %a, i32 %count
+ %load.a = load half, half* %addr.a
+ %abs = call half @llvm.fabs.f16(half %load.a)
+ %addr.b = getelementptr half, half* %b, i32 %count
+ store half %abs, half *%addr.b
+ %count.next = add nuw i32 %count, 1
+ %cmp = icmp ne i32 %count.next, 100
+ br i1 %cmp, label %loop, label %exit
+exit:
+ ret void
+}
+
+; CHECK-LABEL: test_fabs
+; CHECK-MAIN-NOT: call void @llvm.set.loop.iterations
+; CHECK-MVE-NOT: call void @llvm.set.loop.iterations
+; CHECK-FP: call void @llvm.set.loop.iterations.i32(i32 100)
+; CHECK-MVEFP: call void @llvm.set.loop.iterations.i32(i32 100)
+define float @test_fabs(float* %a) {
+entry:
+ br label %loop
+loop:
+ %acc = phi float [ 0.0, %entry ], [ %res, %loop ]
+ %count = phi i32 [ 0, %entry ], [ %count.next, %loop ]
+ %addr.a = getelementptr float, float* %a, i32 %count
+ %load.a = load float, float* %addr.a
+ %abs = call float @llvm.fabs.f32(float %load.a)
+ %res = fadd float %abs, %acc
+ %count.next = add nuw i32 %count, 1
+ %cmp = icmp ne i32 %count.next, 100
+ br i1 %cmp, label %loop, label %exit
+exit:
+ ret float %res
+}
+
+; CHECK-LABEL: test_fabs_64
+; CHECK-MAIN-NOT: call void @llvm.set.loop.iterations
+; CHECK-MVE-NOT: call void @llvm.set.loop.iterations
+; CHECK-FP-NOT: call void @llvm.set.loop.iterations.i32(i32 100)
+; CHECK-FP64: void @llvm.set.loop.iterations.i32(i32 100)
+; CHECK-MVEFP-NOT: call void @llvm.set.loop.iterations.i32(i32 100)
+define void @test_fabs_64(double* %a, double* %b) {
+entry:
+ br label %loop
+loop:
+ %count = phi i32 [ 0, %entry ], [ %count.next, %loop ]
+ %addr.a = getelementptr double, double* %a, i32 %count
+ %load.a = load double, double* %addr.a
+ %abs = call double @llvm.fabs.f64(double %load.a)
+ %addr.b = getelementptr double, double* %b, i32 %count
+ store double %abs, double *%addr.b
+ %count.next = add nuw i32 %count, 1
+ %cmp = icmp ne i32 %count.next, 100
+ br i1 %cmp, label %loop, label %exit
+exit:
+ ret void
+}
+
+; CHECK-LABEL: test_fabs_vec
+; CHECK-MVE-NOT: call void @llvm.set.loop.iterations
+; CHECK-MVEFP: call void @llvm.set.loop.iterations.i32(i32 100)
+; CHECK-MVEFP: [[COUNT:%[^ ]+]] = phi i32 [ 100, %entry ], [ [[LOOP_DEC:%[^ ]+]], %loop ]
+; CHECK-MVEFP: [[LOOP_DEC]] = call i32 @llvm.loop.decrement.reg.i32.i32.i32(i32 [[COUNT]], i32 1)
+; CHECK-MVEFP: [[CMP:%[^ ]+]] = icmp ne i32 [[LOOP_DEC]], 0
+; CHECK-MVEFP: br i1 [[CMP]], label %loop, label %exit
+define <4 x float> @test_fabs_vec(<4 x float>* %a) {
+entry:
+ br label %loop
+loop:
+ %acc = phi <4 x float> [ zeroinitializer, %entry ], [ %res, %loop ]
+ %count = phi i32 [ 0, %entry ], [ %count.next, %loop ]
+ %addr.a = getelementptr <4 x float>, <4 x float>* %a, i32 %count
+ %load.a = load <4 x float>, <4 x float>* %addr.a
+ %abs = call <4 x float> @llvm.fabs.v4f32(<4 x float> %load.a)
+ %res = fadd <4 x float> %abs, %acc
+ %count.next = add nuw i32 %count, 1
+ %cmp = icmp ne i32 %count.next, 100
+ br i1 %cmp, label %loop, label %exit
+exit:
+ ret <4 x float> %res
+}
+
+; CHECK-LABEL: test_log
+; CHECK-NOT: call void @llvm.set.loop.iterations
+; CHECK-NOT: llvm.loop.decrement
+define float @test_log(float* %a) {
+entry:
+ br label %loop
+loop:
+ %acc = phi float [ 0.0, %entry ], [ %res, %loop ]
+ %count = phi i32 [ 0, %entry ], [ %count.next, %loop ]
+ %addr.a = getelementptr float, float* %a, i32 %count
+ %load.a = load float, float* %addr.a
+ %abs = call float @llvm.log.f32(float %load.a)
+ %res = fadd float %abs, %acc
+ %count.next = add nuw i32 %count, 1
+ %cmp = icmp ne i32 %count.next, 100
+ br i1 %cmp, label %loop, label %exit
+exit:
+ ret float %res
+}
+
+; CHECK-LABEL: test_sqrt_16
+; CHECK-MAIN-NOT: call void @llvm.set.loop.iterations
+; CHECK-MVE-NOT: call void @llvm.set.loop.iterations
+; CHECK-FP: call void @llvm.set.loop.iterations.i32(i32 100)
+; CHECK-MVEFP: call void @llvm.set.loop.iterations.i32(i32 100)
+; CHECK-FP64: call void @llvm.set.loop.iterations.i32(i32 100)
+define void @test_sqrt_16(half* %a, half* %b) {
+entry:
+ br label %loop
+loop:
+ %count = phi i32 [ 0, %entry ], [ %count.next, %loop ]
+ %addr.a = getelementptr half, half* %a, i32 %count
+ %load.a = load half, half* %addr.a
+ %sqrt = call half @llvm.sqrt.f16(half %load.a)
+ %addr.b = getelementptr half, half* %b, i32 %count
+ store half %sqrt, half *%addr.b
+ %count.next = add nuw i32 %count, 1
+ %cmp = icmp ne i32 %count.next, 100
+ br i1 %cmp, label %loop, label %exit
+exit:
+ ret void
+}
+; CHECK-LABEL: test_sqrt
+; CHECK-MAIN-NOT: call void @llvm.set.loop.iterations
+; CHECK-MVE-NOT: call void @llvm.set.loop.iterations
+; CHECK-FP: call void @llvm.set.loop.iterations
+; CHECK-MVEFP: call void @llvm.set.loop.iterations.i32(i32 100)
+; CHECK-MVEFP: [[COUNT:%[^ ]+]] = phi i32 [ 100, %entry ], [ [[LOOP_DEC:%[^ ]+]], %loop ]
+; CHECK-MVEFP: [[LOOP_DEC]] = call i32 @llvm.loop.decrement.reg.i32.i32.i32(i32 [[COUNT]], i32 1)
+; CHECK-MVEFP: [[CMP:%[^ ]+]] = icmp ne i32 [[LOOP_DEC]], 0
+; CHECK-MVEFP: br i1 [[CMP]], label %loop, label %exit
+define void @test_sqrt(float* %a, float* %b) {
+entry:
+ br label %loop
+loop:
+ %count = phi i32 [ 0, %entry ], [ %count.next, %loop ]
+ %addr.a = getelementptr float, float* %a, i32 %count
+ %load.a = load float, float* %addr.a
+ %sqrt = call float @llvm.sqrt.f32(float %load.a)
+ %addr.b = getelementptr float, float* %b, i32 %count
+ store float %sqrt, float* %addr.b
+ %count.next = add nuw i32 %count, 1
+ %cmp = icmp ne i32 %count.next, 100
+ br i1 %cmp, label %loop, label %exit
+exit:
+ ret void
+}
+
+; CHECK-LABEL: test_sqrt_64
+; CHECK-MAIN-NOT: call void @llvm.set.loop.iterations
+; CHECK-MVE-NOT: call void @llvm.set.loop.iterations
+; CHECK-FP-NOT: call void @llvm.set.loop.iterations.i32(i32 100)
+; CHECK-MVEFP-NOT: call void @llvm.set.loop.iterations.i32(i32 100)
+; CHECK-FP64: call void @llvm.set.loop.iterations.i32(i32 100)
+define void @test_sqrt_64(double* %a, double* %b) {
+entry:
+ br label %loop
+loop:
+ %count = phi i32 [ 0, %entry ], [ %count.next, %loop ]
+ %addr.a = getelementptr double, double* %a, i32 %count
+ %load.a = load double, double* %addr.a
+ %sqrt = call double @llvm.sqrt.f64(double %load.a)
+ %addr.b = getelementptr double, double* %b, i32 %count
+ store double %sqrt, double *%addr.b
+ %count.next = add nuw i32 %count, 1
+ %cmp = icmp ne i32 %count.next, 100
+ br i1 %cmp, label %loop, label %exit
+exit:
+ ret void
+}
+
+; CHECK-LABEL: test_sqrt_vec
+; CHECK-MAIN-NOT: call void @llvm.set.loop.iterations
+; CHECK-MVE-NOT: call void @llvm.set.loop.iterations
+; CHECK-FP: call void @llvm.set.loop.iterations.i32(i32 100)
+; CHECK-MVEFP: call void @llvm.set.loop.iterations.i32(i32 100)
+define void @test_sqrt_vec(<4 x float>* %a, <4 x float>* %b) {
+entry:
+ br label %loop
+loop:
+ %count = phi i32 [ 0, %entry ], [ %count.next, %loop ]
+ %addr.a = getelementptr <4 x float>, <4 x float>* %a, i32 %count
+ %load.a = load <4 x float>, <4 x float>* %addr.a
+ %sqrt = call <4 x float> @llvm.sqrt.v4f32(<4 x float> %load.a)
+ %addr.b = getelementptr <4 x float>, <4 x float>* %b, i32 %count
+ store <4 x float> %sqrt, <4 x float>* %addr.b
+ %count.next = add nuw i32 %count, 1
+ %cmp = icmp ne i32 %count.next, 100
+ br i1 %cmp, label %loop, label %exit
+exit:
+ ret void
+}
+
+; CHECK-LABEL: test_overflow
+; CHECK: call void @llvm.set.loop.iterations
+define i32 @test_overflow(i32* %a, i32* %b) {
+entry:
+ br label %loop
+loop:
+ %acc = phi i32 [ 0, %entry ], [ %res, %loop ]
+ %count = phi i32 [ 0, %entry ], [ %count.next, %loop ]
+ %addr.a = getelementptr i32, i32* %a, i32 %count
+ %addr.b = getelementptr i32, i32* %b, i32 %count
+ %load.a = load i32, i32* %addr.a
+ %load.b = load i32, i32* %addr.b
+ %sadd = call {i32, i1} @llvm.sadd.with.overflow.i32(i32 %load.a, i32 %load.b)
+ %res = extractvalue {i32, i1} %sadd, 0
+ %count.next = add nuw i32 %count, 1
+ %cmp = icmp ne i32 %count.next, 100
+ br i1 %cmp, label %loop, label %exit
+exit:
+ ret i32 %res
+}
+
+; TODO: We should be able to generate a qadd/sub
+; CHECK-LABEL: test_sat
+; CHECK: call void @llvm.set.loop.iterations.i32(i32 100)
+define i32 @test_sat(i32* %a, i32* %b) {
+entry:
+ br label %loop
+loop:
+ %acc = phi i32 [ 0, %entry ], [ %res, %loop ]
+ %count = phi i32 [ 0, %entry ], [ %count.next, %loop ]
+ %addr.a = getelementptr i32, i32* %a, i32 %count
+ %addr.b = getelementptr i32, i32* %b, i32 %count
+ %load.a = load i32, i32* %addr.a
+ %load.b = load i32, i32* %addr.b
+ %res = call i32 @llvm.sadd.sat.i32(i32 %load.a, i32 %load.b)
+ %count.next = add nuw i32 %count, 1
+ %cmp = icmp ne i32 %count.next, 100
+ br i1 %cmp, label %loop, label %exit
+exit:
+ ret i32 %res
+}
+
+; CHECK-LABEL: test_masked_i32
+; CHECK-NOT: call void @llvm.set.loop.iterations
+; CHECK-MVEFP: call void @llvm.set.loop.iterations
+; CHECK-MVE: call void @llvm.set.loop.iterations.i32(i32 100)
+; CHECK-MVE: [[COUNT:%[^ ]+]] = phi i32 [ 100, %entry ], [ [[LOOP_DEC:%[^ ]+]], %loop ]
+; CHECK-MVE: [[LOOP_DEC]] = call i32 @llvm.loop.decrement.reg.i32.i32.i32(i32 [[COUNT]], i32 1)
+; CHECK-MVE: [[CMP:%[^ ]+]] = icmp ne i32 [[LOOP_DEC]], 0
+; CHECK-MVE: br i1 [[CMP]], label %loop, label %exit
+define void @test_masked_i32(<4 x i1> %mask, <4 x i32>* %a, <4 x i32>* %b, <4 x i32>* %c, <4 x i32> %passthru) {
+entry:
+ br label %loop
+loop:
+ %count = phi i32 [ 0, %entry ], [ %count.next, %loop ]
+ %addr.a = getelementptr <4 x i32>, <4 x i32>* %a, i32 %count
+ %addr.b = getelementptr <4 x i32>, <4 x i32>* %b, i32 %count
+ %addr.c = getelementptr <4 x i32>, <4 x i32>* %c, i32 %count
+ %load.a = call <4 x i32> @llvm.masked.load.v4i32.p0v4i32(<4 x i32>* %addr.a, i32 4, <4 x i1> %mask, <4 x i32> %passthru)
+ %load.b = call <4 x i32> @llvm.masked.load.v4i32.p0v4i32(<4 x i32>* %addr.b, i32 4, <4 x i1> %mask, <4 x i32> %passthru)
+ %res = add <4 x i32> %load.a, %load.b
+ call void @llvm.masked.store.v4i32.p0v4i32(<4 x i32> %res, <4 x i32>* %addr.c, i32 4, <4 x i1> %mask)
+ %count.next = add nuw i32 %count, 1
+ %cmp = icmp ne i32 %count.next, 100
+ br i1 %cmp, label %loop, label %exit
+exit:
+ ret void
+}
+
+; CHECK-LABEL: test_masked_f32
+; CHECK-NOT: call void @llvm.set.loop.iterations
+; CHECK-MVEFP: call void @llvm.set.loop.iterations
+; CHECK-MVE: call void @llvm.set.loop.iterations.i32(i32 100)
+; CHECK-MVE: [[COUNT:%[^ ]+]] = phi i32 [ 100, %entry ], [ [[LOOP_DEC:%[^ ]+]], %loop ]
+; CHECK-MVE: [[LOOP_DEC]] = call i32 @llvm.loop.decrement.reg.i32.i32.i32(i32 [[COUNT]], i32 1)
+; CHECK-MVE: [[CMP:%[^ ]+]] = icmp ne i32 [[LOOP_DEC]], 0
+; CHECK-MVE: br i1 [[CMP]], label %loop, label %exit
+define void @test_masked_f32(<4 x i1> %mask, <4 x float>* %a, <4 x float>* %b, <4 x float>* %c, <4 x float> %passthru) {
+entry:
+ br label %loop
+loop:
+ %count = phi i32 [ 0, %entry ], [ %count.next, %loop ]
+ %addr.a = getelementptr <4 x float>, <4 x float>* %a, i32 %count
+ %addr.b = getelementptr <4 x float>, <4 x float>* %b, i32 %count
+ %addr.c = getelementptr <4 x float>, <4 x float>* %c, i32 %count
+ %load.a = call <4 x float> @llvm.masked.load.v4f32.p0v4f32(<4 x float>* %addr.a, i32 4, <4 x i1> %mask, <4 x float> %passthru)
+ %load.b = call <4 x float> @llvm.masked.load.v4f32.p0v4f32(<4 x float>* %addr.b, i32 4, <4 x i1> %mask, <4 x float> %passthru)
+ %res = fadd <4 x float> %load.a, %load.b
+ call void @llvm.masked.store.v4f32.p0v4f32(<4 x float> %res, <4 x float>* %addr.c, i32 4, <4 x i1> %mask)
+ %count.next = add nuw i32 %count, 1
+ %cmp = icmp ne i32 %count.next, 100
+ br i1 %cmp, label %loop, label %exit
+exit:
+ ret void
+}
+
+; CHECK-LABEL: test_gather_scatter
+; CHECK-NOT: call void @llvm.set.loop.iterations
+; CHECK-MVEFP: call void @llvm.set.loop.iterations
+; CHECK-MVE: call void @llvm.set.loop.iterations.i32(i32 100)
+; CHECK-MVE: [[COUNT:%[^ ]+]] = phi i32 [ 100, %entry ], [ [[LOOP_DEC:%[^ ]+]], %loop ]
+; CHECK-MVE: [[LOOP_DEC]] = call i32 @llvm.loop.decrement.reg.i32.i32.i32(i32 [[COUNT]], i32 1)
+; CHECK-MVE: [[CMP:%[^ ]+]] = icmp ne i32 [[LOOP_DEC]], 0
+; CHECK-MVE: br i1 [[CMP]], label %loop, label %exit
+define void @test_gather_scatter(<4 x i1> %mask, <4 x float*> %a, <4 x float*> %b, <4 x float*> %c, <4 x float> %passthru) {
+entry:
+ br label %loop
+loop:
+ %count = phi i32 [ 0, %entry ], [ %count.next, %loop ]
+ %load.a = call <4 x float> @llvm.masked.gather.v4f32.p0v4f32(<4 x float*> %a, i32 4, <4 x i1> %mask, <4 x float> %passthru)
+ %load.b = call <4 x float> @llvm.masked.gather.v4f32.p0v4f32(<4 x float*> %b, i32 4, <4 x i1> %mask, <4 x float> %passthru)
+ %res = fadd <4 x float> %load.a, %load.b
+ call void @llvm.masked.scatter.v4f32.p0v4f32(<4 x float> %res, <4 x float*> %c, i32 4, <4 x i1> %mask)
+ %count.next = add nuw i32 %count, 1
+ %cmp = icmp ne i32 %count.next, 100
+ br i1 %cmp, label %loop, label %exit
+exit:
+ ret void
+}
+
+declare i32 @bar(...) local_unnamed_addr #1
+declare i32 @llvm.arm.smlad(i32, i32, i32)
+declare half @llvm.fabs.f16(half)
+declare float @llvm.fabs.f32(float)
+declare double @llvm.fabs.f64(double)
+declare float @llvm.log.f32(float)
+declare <4 x float> @llvm.fabs.v4f32(<4 x float>)
+declare half @llvm.sqrt.f16(half)
+declare float @llvm.sqrt.f32(float)
+declare double @llvm.sqrt.f64(double)
+declare <4 x float> @llvm.sqrt.v4f32(<4 x float>)
+declare i32 @llvm.sadd.sat.i32(i32, i32)
+declare {i32, i1} @llvm.sadd.with.overflow.i32(i32, i32)
+declare <4 x i32> @llvm.masked.load.v4i32.p0v4i32(<4 x i32>*, i32, <4 x i1>, <4 x i32>)
+declare void @llvm.masked.store.v4i32.p0v4i32(<4 x i32>, <4 x i32>*, i32, <4 x i1>)
+declare <4 x float> @llvm.masked.load.v4f32.p0v4f32(<4 x float>*, i32, <4 x i1>, <4 x float>)
+declare void @llvm.masked.store.v4f32.p0v4f32(<4 x float>, <4 x float>*, i32, <4 x i1>)
+declare <4 x float> @llvm.masked.gather.v4f32.p0v4f32(<4 x float*>, i32, <4 x i1>, <4 x float>)
+declare void @llvm.masked.scatter.v4f32.p0v4f32(<4 x float>, <4 x float*>, i32, <4 x i1>)
diff --git a/llvm/test/Transforms/HardwareLoops/ARM/counter.ll b/llvm/test/Transforms/HardwareLoops/ARM/counter.ll
new file mode 100644
index 00000000000..bdd83d1234b
--- /dev/null
+++ b/llvm/test/Transforms/HardwareLoops/ARM/counter.ll
@@ -0,0 +1,35 @@
+; RUN: opt -mtriple=thumbv8.1m.main-arm-none-eabi -hardware-loops -disable-arm-loloops=false %s -o - | FileCheck %s
+
+@g = common local_unnamed_addr global i32* null, align 4
+
+; CHECK-LABEL: counter_too_large
+; CHECK-NOT: call void @llvm.set.loop.iterations
+; CHECK-NOT: call i32 @llvm.loop.decrement
+
+define i32 @counter_too_large(i64 %n) {
+entry:
+ %cmp7 = icmp eq i64 %n, 0
+ br i1 %cmp7, label %while.end, label %while.body.lr.ph
+
+while.body.lr.ph:
+ %0 = load i32*, i32** @g, align 4
+ br label %while.body
+
+while.body:
+ %i.09 = phi i64 [ 0, %while.body.lr.ph ], [ %inc1, %while.body ]
+ %res.08 = phi i32 [ 0, %while.body.lr.ph ], [ %add, %while.body ]
+ %idxprom = trunc i64 %i.09 to i32
+ %arrayidx = getelementptr inbounds i32, i32* %0, i32 %idxprom
+ %1 = load i32, i32* %arrayidx, align 4
+ %add = add nsw i32 %1, %res.08
+ %inc1 = add nuw i64 %i.09, 1
+ %cmp = icmp ult i64 %inc1, %n
+ br i1 %cmp, label %while.body, label %while.end.loopexit
+
+while.end.loopexit:
+ br label %while.end
+
+while.end:
+ %res.0.lcssa = phi i32 [ 0, %entry ], [ %add, %while.end.loopexit ]
+ ret i32 %res.0.lcssa
+}
diff --git a/llvm/test/Transforms/HardwareLoops/ARM/do-rem.ll b/llvm/test/Transforms/HardwareLoops/ARM/do-rem.ll
new file mode 100644
index 00000000000..074a1bb6c4c
--- /dev/null
+++ b/llvm/test/Transforms/HardwareLoops/ARM/do-rem.ll
@@ -0,0 +1,259 @@
+; RUN: opt -mtriple=thumbv8.1m.main-arm-none-eabi -hardware-loops -disable-arm-loloops=false %s -S -o - | FileCheck %s
+
+@g = common local_unnamed_addr global i32* null, align 4
+
+; CHECK-LABEL: do_with_i32_urem
+; CHECK: while.body.preheader:
+; CHECK: call void @llvm.set.loop.iterations.i32(i32 %n)
+; CHECK-NEXT: br label %while.body
+
+; CHECK: [[REM:%[^ ]+]] = phi i32 [ %n, %while.body.preheader ], [ [[LOOP_DEC:%[^ ]+]], %while.body ]
+; CHECK: [[LOOP_DEC]] = call i32 @llvm.loop.decrement.reg.i32.i32.i32(i32 [[REM]], i32 1)
+; CHECK: [[CMP:%[^ ]+]] = icmp ne i32 [[LOOP_DEC]], 0
+; CHECK: br i1 [[CMP]], label %while.body, label %while.end.loopexit
+
+define i32 @do_with_i32_urem(i32 %n) {
+entry:
+ %cmp7 = icmp eq i32 %n, 0
+ br i1 %cmp7, label %while.end, label %while.body.preheader
+
+while.body.preheader:
+ br label %while.body
+
+while.body:
+ %i.09 = phi i32 [ %inc1, %while.body ], [ 0, %while.body.preheader ]
+ %res.08 = phi i32 [ %add, %while.body ], [ 0, %while.body.preheader ]
+ %rem = urem i32 %i.09, 5
+ %add = add i32 %rem, %res.08
+ %inc1 = add nuw i32 %i.09, 1
+ %exitcond = icmp eq i32 %inc1, %n
+ br i1 %exitcond, label %while.end.loopexit, label %while.body
+
+while.end.loopexit:
+ br label %while.end
+
+while.end:
+ %res.0.lcssa = phi i32 [ 0, %entry ], [ %add, %while.end.loopexit ]
+ ret i32 %res.0.lcssa
+}
+
+; CHECK-LABEL: do_with_i32_srem
+; CHECK: while.body.preheader:
+; CHECK: call void @llvm.set.loop.iterations.i32(i32 %n)
+; CHECK-NEXT: br label %while.body
+
+; CHECK: [[REM:%[^ ]+]] = phi i32 [ %n, %while.body.preheader ], [ [[LOOP_DEC:%[^ ]+]], %while.body ]
+; CHECK: [[LOOP_DEC]] = call i32 @llvm.loop.decrement.reg.i32.i32.i32(i32 [[REM]], i32 1)
+; CHECK: [[CMP:%[^ ]+]] = icmp ne i32 [[LOOP_DEC]], 0
+; CHECK: br i1 [[CMP]], label %while.body, label %while.end.loopexit
+
+define i32 @do_with_i32_srem(i32 %n) {
+entry:
+ %cmp7 = icmp eq i32 %n, 0
+ br i1 %cmp7, label %while.end, label %while.body.preheader
+
+while.body.preheader:
+ br label %while.body
+
+while.body:
+ %i.09 = phi i32 [ %inc1, %while.body ], [ 0, %while.body.preheader ]
+ %res.08 = phi i32 [ %add, %while.body ], [ 0, %while.body.preheader ]
+ %rem = srem i32 %i.09, 5
+ %add = sub i32 %rem, %res.08
+ %inc1 = add nuw i32 %i.09, 1
+ %exitcond = icmp eq i32 %inc1, %n
+ br i1 %exitcond, label %while.end.loopexit, label %while.body
+
+while.end.loopexit:
+ br label %while.end
+
+while.end:
+ %res.0.lcssa = phi i32 [ 0, %entry ], [ %add, %while.end.loopexit ]
+ ret i32 %res.0.lcssa
+}
+
+; CHECK-LABEL: do_with_i32_udiv
+; CHECK: while.body.preheader:
+; CHECK: call void @llvm.set.loop.iterations.i32(i32 %n)
+; CHECK-NEXT: br label %while.body
+
+; CHECK: [[REM:%[^ ]+]] = phi i32 [ %n, %while.body.preheader ], [ [[LOOP_DEC:%[^ ]+]], %while.body ]
+; CHECK: [[LOOP_DEC]] = call i32 @llvm.loop.decrement.reg.i32.i32.i32(i32 [[REM]], i32 1)
+; CHECK: [[CMP:%[^ ]+]] = icmp ne i32 [[LOOP_DEC]], 0
+; CHECK: br i1 [[CMP]], label %while.body, label %while.end.loopexit
+
+define i32 @do_with_i32_udiv(i32 %n) {
+entry:
+ %cmp7 = icmp eq i32 %n, 0
+ br i1 %cmp7, label %while.end, label %while.body.preheader
+
+while.body.preheader:
+ br label %while.body
+
+while.body:
+ %i.09 = phi i32 [ %inc1, %while.body ], [ 0, %while.body.preheader ]
+ %res.08 = phi i32 [ %add, %while.body ], [ 0, %while.body.preheader ]
+ %rem = udiv i32 %i.09, 5
+ %add = add i32 %rem, %res.08
+ %inc1 = add nuw i32 %i.09, 1
+ %exitcond = icmp eq i32 %inc1, %n
+ br i1 %exitcond, label %while.end.loopexit, label %while.body
+
+while.end.loopexit:
+ br label %while.end
+
+while.end:
+ %res.0.lcssa = phi i32 [ 0, %entry ], [ %add, %while.end.loopexit ]
+ ret i32 %res.0.lcssa
+}
+
+; CHECK-LABEL: do_with_i32_sdiv
+; CHECK: while.body.preheader:
+; CHECK: call void @llvm.set.loop.iterations.i32(i32 %n)
+; CHECK-NEXT: br label %while.body
+
+; CHECK: [[REM:%[^ ]+]] = phi i32 [ %n, %while.body.preheader ], [ [[LOOP_DEC:%[^ ]+]], %while.body ]
+; CHECK: [[LOOP_DEC]] = call i32 @llvm.loop.decrement.reg.i32.i32.i32(i32 [[REM]], i32 1)
+; CHECK: [[CMP:%[^ ]+]] = icmp ne i32 [[LOOP_DEC]], 0
+; CHECK: br i1 [[CMP]], label %while.body, label %while.end.loopexit
+
+define i32 @do_with_i32_sdiv(i32 %n) {
+entry:
+ %cmp7 = icmp eq i32 %n, 0
+ br i1 %cmp7, label %while.end, label %while.body.preheader
+
+while.body.preheader:
+ br label %while.body
+
+while.body:
+ %i.09 = phi i32 [ %inc1, %while.body ], [ 0, %while.body.preheader ]
+ %res.08 = phi i32 [ %add, %while.body ], [ 0, %while.body.preheader ]
+ %rem = sdiv i32 %i.09, 5
+ %add = sub i32 %rem, %res.08
+ %inc1 = add nuw i32 %i.09, 1
+ %exitcond = icmp eq i32 %inc1, %n
+ br i1 %exitcond, label %while.end.loopexit, label %while.body
+
+while.end.loopexit:
+ br label %while.end
+
+while.end:
+ %res.0.lcssa = phi i32 [ 0, %entry ], [ %add, %while.end.loopexit ]
+ ret i32 %res.0.lcssa
+}
+
+; CHECK-LABEL: do_with_i64_urem
+; CHECK-NOT: llvm.set.loop.iterations
+; CHECK-NOT: llvm.loop.decrement
+define i64 @do_with_i64_urem(i32 %n) {
+entry:
+ %cmp7 = icmp eq i32 %n, 0
+ br i1 %cmp7, label %while.end, label %while.body.preheader
+
+while.body.preheader:
+ br label %while.body
+
+while.body:
+ %i.09 = phi i32 [ %inc1, %while.body ], [ 0, %while.body.preheader ]
+ %res.08 = phi i64 [ %add, %while.body ], [ 0, %while.body.preheader ]
+ %conv = zext i32 %i.09 to i64
+ %rem = urem i64 %conv, 5
+ %add = add i64 %rem, %res.08
+ %inc1 = add nuw i32 %i.09, 1
+ %exitcond = icmp eq i32 %inc1, %n
+ br i1 %exitcond, label %while.end.loopexit, label %while.body
+
+while.end.loopexit:
+ br label %while.end
+
+while.end:
+ %res.0.lcssa = phi i64 [ 0, %entry ], [ %add, %while.end.loopexit ]
+ ret i64 %res.0.lcssa
+}
+
+; CHECK-LABEL: do_with_i64_srem
+; CHECK-NOT: llvm.set.loop.iterations
+; CHECK-NOT: llvm.loop.decrement
+define i64 @do_with_i64_srem(i32 %n) {
+entry:
+ %cmp7 = icmp eq i32 %n, 0
+ br i1 %cmp7, label %while.end, label %while.body.preheader
+
+while.body.preheader:
+ br label %while.body
+
+while.body:
+ %i.09 = phi i32 [ %inc1, %while.body ], [ 0, %while.body.preheader ]
+ %res.08 = phi i64 [ %add, %while.body ], [ 0, %while.body.preheader ]
+ %conv = zext i32 %i.09 to i64
+ %rem = srem i64 %conv, 5
+ %add = sub i64 %rem, %res.08
+ %inc1 = add nuw i32 %i.09, 1
+ %exitcond = icmp eq i32 %inc1, %n
+ br i1 %exitcond, label %while.end.loopexit, label %while.body
+
+while.end.loopexit:
+ br label %while.end
+
+while.end:
+ %res.0.lcssa = phi i64 [ 0, %entry ], [ %add, %while.end.loopexit ]
+ ret i64 %res.0.lcssa
+}
+
+; CHECK-LABEL: do_with_i64_udiv
+; CHECK-NOT: llvm.set.loop.iterations
+; CHECK-NOT: llvm.loop.decrement
+define i64 @do_with_i64_udiv(i32 %n) {
+entry:
+ %cmp7 = icmp eq i32 %n, 0
+ br i1 %cmp7, label %while.end, label %while.body.preheader
+
+while.body.preheader:
+ br label %while.body
+
+while.body:
+ %i.09 = phi i32 [ %inc1, %while.body ], [ 0, %while.body.preheader ]
+ %res.08 = phi i64 [ %add, %while.body ], [ 0, %while.body.preheader ]
+ %conv = zext i32 %i.09 to i64
+ %rem = udiv i64 %conv, 5
+ %add = add i64 %rem, %res.08
+ %inc1 = add nuw i32 %i.09, 1
+ %exitcond = icmp eq i32 %inc1, %n
+ br i1 %exitcond, label %while.end.loopexit, label %while.body
+
+while.end.loopexit:
+ br label %while.end
+
+while.end:
+ %res.0.lcssa = phi i64 [ 0, %entry ], [ %add, %while.end.loopexit ]
+ ret i64 %res.0.lcssa
+}
+
+; CHECK-LABEL: do_with_i64_sdiv
+; CHECK-NOT: call void @llvm.set.loop.iterations
+; CHECK-NOT: call i32 @llvm.loop.decrement
+define i64 @do_with_i64_sdiv(i32 %n) {
+entry:
+ %cmp7 = icmp eq i32 %n, 0
+ br i1 %cmp7, label %while.end, label %while.body.preheader
+
+while.body.preheader:
+ br label %while.body
+
+while.body:
+ %i.09 = phi i32 [ %inc1, %while.body ], [ 0, %while.body.preheader ]
+ %res.08 = phi i64 [ %add, %while.body ], [ 0, %while.body.preheader ]
+ %conv = zext i32 %i.09 to i64
+ %rem = sdiv i64 %conv, 5
+ %add = sub i64 %rem, %res.08
+ %inc1 = add nuw i32 %i.09, 1
+ %exitcond = icmp eq i32 %inc1, %n
+ br i1 %exitcond, label %while.end.loopexit, label %while.body
+
+while.end.loopexit:
+ br label %while.end
+
+while.end:
+ %res.0.lcssa = phi i64 [ 0, %entry ], [ %add, %while.end.loopexit ]
+ ret i64 %res.0.lcssa
+}
diff --git a/llvm/test/Transforms/HardwareLoops/ARM/fp-emulation.ll b/llvm/test/Transforms/HardwareLoops/ARM/fp-emulation.ll
new file mode 100644
index 00000000000..8336b989ac7
--- /dev/null
+++ b/llvm/test/Transforms/HardwareLoops/ARM/fp-emulation.ll
@@ -0,0 +1,207 @@
+; RUN: opt -mtriple=thumbv8.1m.main-arm-none-eabi -mattr=+fp-armv8 -hardware-loops -disable-arm-loloops=false %s -S -o - | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-FP
+; RUN: opt -mtriple=thumbv8.1m.main-arm-none-eabi -mattr=+soft-float -hardware-loops -disable-arm-loloops=false %s -S -o - | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-SOFT
+
+; CHECK-LABEL: test_fptosi
+; CHECK: while.body.lr.ph:
+; CHECK-FP: [[CMP:%[^ ]+]] = icmp ugt i32 %n, 1
+; CHECK-FP: [[COUNT:%[^ ]+]] = select i1 [[CMP]], i32 %n, i32 1
+; CHECK-FP: call void @llvm.set.loop.iterations.i32(i32 [[COUNT]])
+; CHECK-FP-NEXT: br label %while.body
+
+; CHECK-FP: [[REM:%[^ ]+]] = phi i32 [ [[COUNT]], %while.body.lr.ph ], [ [[LOOP_DEC:%[^ ]+]], %if.end4 ]
+; CHECK-FP: [[LOOP_DEC]] = call i32 @llvm.loop.decrement.reg.i32.i32.i32(i32 [[REM]], i32 1)
+; CHECK-FP: [[CMP:%[^ ]+]] = icmp ne i32 [[LOOP_DEC]], 0
+; CHECK-FP: br i1 [[CMP]], label %while.body, label %cleanup.loopexit
+
+; CHECK-SOFT-NOT: call void @llvm.set.loop.iterations
+
+define void @test_fptosi(i32 %n, i32** %g, double** %d) {
+entry:
+ %n.off = add i32 %n, -1
+ %0 = icmp ult i32 %n.off, 500
+ br i1 %0, label %while.body.lr.ph, label %cleanup
+
+while.body.lr.ph:
+ %1 = load double*, double** %d, align 4
+ %2 = load i32*, i32** %g, align 4
+ br label %while.body
+
+while.body:
+ %i.012 = phi i32 [ 0, %while.body.lr.ph ], [ %inc, %if.end4 ]
+ %rem = urem i32 %i.012, 10
+ %tobool = icmp eq i32 %rem, 0
+ br i1 %tobool, label %if.end4, label %if.then2
+
+if.then2:
+ %arrayidx = getelementptr inbounds double, double* %1, i32 %i.012
+ %3 = load double, double* %arrayidx, align 8
+ %conv = fptosi double %3 to i32
+ %arrayidx3 = getelementptr inbounds i32, i32* %2, i32 %i.012
+ store i32 %conv, i32* %arrayidx3, align 4
+ br label %if.end4
+
+if.end4:
+ %inc = add nuw i32 %i.012, 1
+ %cmp1 = icmp ult i32 %inc, %n
+ br i1 %cmp1, label %while.body, label %cleanup.loopexit
+
+cleanup.loopexit:
+ br label %cleanup
+
+cleanup:
+ ret void
+}
+
+; CHECK-LABEL: test_fptoui
+; CHECK-FP: while.body.lr.ph:
+; CHECK-FP: [[CMP:%[^ ]+]] = icmp ugt i32 %n, 1
+; CHECK-FP: [[COUNT:%[^ ]+]] = select i1 [[CMP]], i32 %n, i32 1
+; CHECK-FP: call void @llvm.set.loop.iterations.i32(i32 [[COUNT]])
+; CHECK-FP-NEXT: br label %while.body
+
+; CHECK-FP: [[REM:%[^ ]+]] = phi i32 [ [[COUNT]], %while.body.lr.ph ], [ [[LOOP_DEC:%[^ ]+]], %if.end4 ]
+; CHECK-FP: [[LOOP_DEC]] = call i32 @llvm.loop.decrement.reg.i32.i32.i32(i32 [[REM]], i32 1)
+; CHECK-FP: [[CMP:%[^ ]+]] = icmp ne i32 [[LOOP_DEC]], 0
+; CHECK-FP: br i1 [[CMP]], label %while.body, label %cleanup.loopexit
+
+; CHECK-SOFT-NOT: call void @llvm.set.loop.iterations
+
+define void @test_fptoui(i32 %n, i32** %g, double** %d) {
+entry:
+ %n.off = add i32 %n, -1
+ %0 = icmp ult i32 %n.off, 500
+ br i1 %0, label %while.body.lr.ph, label %cleanup
+
+while.body.lr.ph:
+ %1 = load double*, double** %d, align 4
+ %2 = load i32*, i32** %g, align 4
+ br label %while.body
+
+while.body:
+ %i.012 = phi i32 [ 0, %while.body.lr.ph ], [ %inc, %if.end4 ]
+ %rem = urem i32 %i.012, 10
+ %tobool = icmp eq i32 %rem, 0
+ br i1 %tobool, label %if.end4, label %if.then2
+
+if.then2:
+ %arrayidx = getelementptr inbounds double, double* %1, i32 %i.012
+ %3 = load double, double* %arrayidx, align 8
+ %conv = fptoui double %3 to i32
+ %arrayidx3 = getelementptr inbounds i32, i32* %2, i32 %i.012
+ store i32 %conv, i32* %arrayidx3, align 4
+ br label %if.end4
+
+if.end4:
+ %inc = add nuw i32 %i.012, 1
+ %cmp1 = icmp ult i32 %inc, %n
+ br i1 %cmp1, label %while.body, label %cleanup.loopexit
+
+cleanup.loopexit:
+ br label %cleanup
+
+cleanup:
+ ret void
+}
+
+; CHECK-LABEL: load_store_float
+; CHECK: while.body.lr.ph:
+; CHECK: [[CMP:%[^ ]+]] = icmp ugt i32 %n, 1
+; CHECK: [[COUNT:%[^ ]+]] = select i1 [[CMP]], i32 %n, i32 1
+; CHECK: call void @llvm.set.loop.iterations.i32(i32 [[COUNT]])
+; CHECK-NEXT: br label %while.body
+
+; CHECK: [[REM:%[^ ]+]] = phi i32 [ [[COUNT]], %while.body.lr.ph ], [ [[LOOP_DEC:%[^ ]+]], %if.end4 ]
+; CHECK: [[LOOP_DEC]] = call i32 @llvm.loop.decrement.reg.i32.i32.i32(i32 [[REM]], i32 1)
+; CHECK: [[CMP:%[^ ]+]] = icmp ne i32 [[LOOP_DEC]], 0
+; CHECK: br i1 [[CMP]], label %while.body, label %cleanup.loopexit
+
+define void @load_store_float(i32 %n, double** %d, double** %g) {
+entry:
+ %n.off = add i32 %n, -1
+ %0 = icmp ult i32 %n.off, 500
+ br i1 %0, label %while.body.lr.ph, label %cleanup
+
+while.body.lr.ph:
+ %1 = load double*, double** %d, align 4
+ %2 = load double*, double** %g, align 4
+ br label %while.body
+
+while.body:
+ %i.012 = phi i32 [ 0, %while.body.lr.ph ], [ %inc, %if.end4 ]
+ %rem = urem i32 %i.012, 10
+ %tobool = icmp eq i32 %rem, 0
+ br i1 %tobool, label %if.end4, label %if.then2
+
+if.then2:
+ %arrayidx = getelementptr inbounds double, double* %1, i32 %i.012
+ %3 = load double, double* %arrayidx, align 8
+ %arrayidx3 = getelementptr inbounds double, double* %2, i32 %i.012
+ store double %3, double* %arrayidx3, align 8
+ br label %if.end4
+
+if.end4:
+ %inc = add nuw i32 %i.012, 1
+ %cmp1 = icmp ult i32 %inc, %n
+ br i1 %cmp1, label %while.body, label %cleanup.loopexit
+
+cleanup.loopexit:
+ br label %cleanup
+
+cleanup:
+ ret void
+}
+
+; CHECK-LABEL: fp_add
+; CHECK: while.body.lr.ph:
+
+; CHECK-SOFT-NOT: call void @llvm.set.loop.iterations
+
+; CHECK-FP: [[CMP:%[^ ]+]] = icmp ugt i32 %n, 1
+; CHECK-FP: [[COUNT:%[^ ]+]] = select i1 [[CMP]], i32 %n, i32 1
+; CHECK-FP: call void @llvm.set.loop.iterations.i32(i32 [[COUNT]])
+; CHECK: br label %while.body
+
+; CHECK-SOFT-NOT: call i32 @llvm.loop.decrement
+
+; CHECK-FP: [[REM:%[^ ]+]] = phi i32 [ [[COUNT]], %while.body.lr.ph ], [ [[LOOP_DEC:%[^ ]+]], %if.end4 ]
+; CHECK-FP: [[LOOP_DEC]] = call i32 @llvm.loop.decrement.reg.i32.i32.i32(i32 [[REM]], i32 1)
+; CHECK-FP: [[CMP:%[^ ]+]] = icmp ne i32 [[LOOP_DEC]], 0
+; CHECK-FP: br i1 [[CMP]], label %while.body, label %cleanup.loopexit
+
+define void @fp_add(i32 %n, float** %d, float** %g) {
+entry:
+ %n.off = add i32 %n, -1
+ %0 = icmp ult i32 %n.off, 500
+ br i1 %0, label %while.body.lr.ph, label %cleanup
+
+while.body.lr.ph:
+ %1 = load float*, float** %d, align 4
+ %2 = load float*, float** %g, align 4
+ br label %while.body
+
+while.body:
+ %i.012 = phi i32 [ 0, %while.body.lr.ph ], [ %inc, %if.end4 ]
+ %rem = urem i32 %i.012, 10
+ %tobool = icmp eq i32 %rem, 0
+ br i1 %tobool, label %if.end4, label %if.then2
+
+if.then2:
+ %arrayidx = getelementptr inbounds float, float* %1, i32 %i.012
+ %3 = load float, float* %arrayidx, align 4
+ %arrayidx3 = getelementptr inbounds float, float* %2, i32 %i.012
+ %4 = load float, float* %arrayidx3, align 4
+ %add = fadd float %3, %4
+ store float %add, float* %arrayidx3, align 4
+ br label %if.end4
+
+if.end4:
+ %inc = add nuw i32 %i.012, 1
+ %cmp1 = icmp ult i32 %inc, %n
+ br i1 %cmp1, label %while.body, label %cleanup.loopexit
+
+cleanup.loopexit:
+ br label %cleanup
+
+cleanup:
+ ret void
+}
diff --git a/llvm/test/Transforms/HardwareLoops/ARM/simple-do.ll b/llvm/test/Transforms/HardwareLoops/ARM/simple-do.ll
new file mode 100644
index 00000000000..41eb0712b41
--- /dev/null
+++ b/llvm/test/Transforms/HardwareLoops/ARM/simple-do.ll
@@ -0,0 +1,155 @@
+; RUN: opt -mtriple=thumbv8.1m.main-arm-none-eabi -hardware-loops -disable-arm-loloops=false %s -S -o - | FileCheck %s
+; RUN: opt -mtriple=thumbv8.1m.main-arm-none-eabi -hardware-loops -disable-arm-loloops=true %s -S -o - | FileCheck %s --check-prefix=DISABLED
+; RUN: opt -mtriple=thumbv8.1m.main-arm-none-eabi -mattr=-lob -hardware-loops %s -S -o - | FileCheck %s --check-prefix=DISABLED
+
+; DISABLED-NOT: llvm.set.loop.iterations
+; DISABLED-NOT: llvm.loop.decrement
+
+@g = common local_unnamed_addr global i32* null, align 4
+
+; CHECK-LABEL: do_copy
+; CHECK: call void @llvm.set.loop.iterations.i32(i32 %n)
+; CHECK: br label %while.body
+
+; CHECK: [[REM:%[^ ]+]] = phi i32 [ %n, %entry ], [ [[LOOP_DEC:%[^ ]+]], %while.body ]
+; CHECK: [[LOOP_DEC]] = call i32 @llvm.loop.decrement.reg.i32.i32.i32(i32 [[REM]], i32 1)
+; CHECK: [[CMP:%[^ ]+]] = icmp ne i32 [[LOOP_DEC]], 0
+; CHECK: br i1 [[CMP]], label %while.body, label %while.end
+define i32 @do_copy(i32 %n, i32* nocapture %p, i32* nocapture readonly %q) {
+entry:
+ br label %while.body
+
+while.body:
+ %q.addr.05 = phi i32* [ %incdec.ptr, %while.body ], [ %q, %entry ]
+ %p.addr.04 = phi i32* [ %incdec.ptr1, %while.body ], [ %p, %entry ]
+ %x.addr.03 = phi i32 [ %dec, %while.body ], [ %n, %entry ]
+ %dec = add nsw i32 %x.addr.03, -1
+ %incdec.ptr = getelementptr inbounds i32, i32* %q.addr.05, i32 1
+ %0 = load i32, i32* %q.addr.05, align 4
+ %incdec.ptr1 = getelementptr inbounds i32, i32* %p.addr.04, i32 1
+ store i32 %0, i32* %p.addr.04, align 4
+ %tobool = icmp eq i32 %dec, 0
+ br i1 %tobool, label %while.end, label %while.body
+
+while.end:
+ ret i32 0
+}
+
+; CHECK-LABEL: do_inc1
+; CHECK: while.body.lr.ph:
+; CHECK: call void @llvm.set.loop.iterations.i32(i32 %n)
+; CHECK-NEXT: br label %while.body
+
+; CHECK: [[REM:%[^ ]+]] = phi i32 [ %n, %while.body.lr.ph ], [ [[LOOP_DEC:%[^ ]+]], %while.body ]
+; CHECK: [[LOOP_DEC]] = call i32 @llvm.loop.decrement.reg.i32.i32.i32(i32 [[REM]], i32 1)
+; CHECK: [[CMP:%[^ ]+]] = icmp ne i32 [[LOOP_DEC]], 0
+; CHECK: br i1 [[CMP]], label %while.body, label %while.end.loopexit
+
+define i32 @do_inc1(i32 %n) {
+entry:
+ %cmp7 = icmp eq i32 %n, 0
+ br i1 %cmp7, label %while.end, label %while.body.lr.ph
+
+while.body.lr.ph:
+ %0 = load i32*, i32** @g, align 4
+ br label %while.body
+
+while.body:
+ %i.09 = phi i32 [ 0, %while.body.lr.ph ], [ %inc1, %while.body ]
+ %res.08 = phi i32 [ 0, %while.body.lr.ph ], [ %add, %while.body ]
+ %arrayidx = getelementptr inbounds i32, i32* %0, i32 %i.09
+ %1 = load i32, i32* %arrayidx, align 4
+ %add = add nsw i32 %1, %res.08
+ %inc1 = add nuw i32 %i.09, 1
+ %exitcond = icmp eq i32 %inc1, %n
+ br i1 %exitcond, label %while.end.loopexit, label %while.body
+
+while.end.loopexit:
+ br label %while.end
+
+while.end:
+ %res.0.lcssa = phi i32 [ 0, %entry ], [ %add, %while.end.loopexit ]
+ ret i32 %res.0.lcssa
+}
+
+; CHECK-LABEL: do_inc2
+; CHECK: while.body.lr.ph:
+; CHECK: [[ROUND:%[^ ]+]] = add i32 %n, -1
+; CHECK: [[HALVE:%[^ ]+]] = lshr i32 [[ROUND]], 1
+; CHECK: [[COUNT:%[^ ]+]] = add i32 [[HALVE]], 1
+; CHECK: call void @llvm.set.loop.iterations.i32(i32 [[COUNT]])
+; CHECK-NEXT: br label %while.body
+
+; CHECK: [[REM:%[^ ]+]] = phi i32 [ [[COUNT]], %while.body.lr.ph ], [ [[LOOP_DEC:%[^ ]+]], %while.body ]
+; CHECK: [[LOOP_DEC]] = call i32 @llvm.loop.decrement.reg.i32.i32.i32(i32 [[REM]], i32 1)
+; CHECK: [[CMP:%[^ ]+]] = icmp ne i32 [[LOOP_DEC]], 0
+; CHECK: br i1 [[CMP]], label %while.body, label %while.end.loopexit
+define i32 @do_inc2(i32 %n) {
+entry:
+ %cmp7 = icmp sgt i32 %n, 0
+ br i1 %cmp7, label %while.body.lr.ph, label %while.end
+
+while.body.lr.ph:
+ %0 = load i32*, i32** @g, align 4
+ br label %while.body
+
+while.body:
+ %i.09 = phi i32 [ 0, %while.body.lr.ph ], [ %add1, %while.body ]
+ %res.08 = phi i32 [ 0, %while.body.lr.ph ], [ %add, %while.body ]
+ %arrayidx = getelementptr inbounds i32, i32* %0, i32 %i.09
+ %1 = load i32, i32* %arrayidx, align 4
+ %add = add nsw i32 %1, %res.08
+ %add1 = add nuw nsw i32 %i.09, 2
+ %cmp = icmp slt i32 %add1, %n
+ br i1 %cmp, label %while.body, label %while.end.loopexit
+
+while.end.loopexit:
+ br label %while.end
+
+while.end:
+ %res.0.lcssa = phi i32 [ 0, %entry ], [ %add, %while.end.loopexit ]
+ ret i32 %res.0.lcssa
+}
+
+; CHECK-LABEL: do_dec2
+
+; CHECK: while.body.lr.ph:
+; CHECK: [[ROUND:%[^ ]+]] = add i32 %n, 1
+; CHECK: [[CMP:%[^ ]+]] = icmp slt i32 %n, 2
+; CHECK: [[SMIN:%[^ ]+]] = select i1 [[CMP]], i32 %n, i32 2
+; CHECK: [[SUB:%[^ ]+]] = sub i32 [[ROUND]], [[SMIN]]
+; CHECK: [[HALVE:%[^ ]+]] = lshr i32 [[SUB]], 1
+; CHECK: [[COUNT:%[^ ]+]] = add i32 [[HALVE]], 1
+; CHECK: call void @llvm.set.loop.iterations.i32(i32 [[COUNT]])
+; CHECK-NEXT: br label %while.body
+
+; CHECK: [[REM:%[^ ]+]] = phi i32 [ [[COUNT]], %while.body.lr.ph ], [ [[LOOP_DEC:%[^ ]+]], %while.body ]
+; CHECK: [[LOOP_DEC]] = call i32 @llvm.loop.decrement.reg.i32.i32.i32(i32 [[REM]], i32 1)
+; CHECK: [[CMP:%[^ ]+]] = icmp ne i32 [[LOOP_DEC]], 0
+; CHECK: br i1 [[CMP]], label %while.body, label %while.end.loopexit
+define i32 @do_dec2(i32 %n) {
+entry:
+ %cmp6 = icmp sgt i32 %n, 0
+ br i1 %cmp6, label %while.body.lr.ph, label %while.end
+
+while.body.lr.ph:
+ %0 = load i32*, i32** @g, align 4
+ br label %while.body
+
+while.body:
+ %i.08 = phi i32 [ %n, %while.body.lr.ph ], [ %sub, %while.body ]
+ %res.07 = phi i32 [ 0, %while.body.lr.ph ], [ %add, %while.body ]
+ %arrayidx = getelementptr inbounds i32, i32* %0, i32 %i.08
+ %1 = load i32, i32* %arrayidx, align 4
+ %add = add nsw i32 %1, %res.07
+ %sub = add nsw i32 %i.08, -2
+ %cmp = icmp sgt i32 %i.08, 2
+ br i1 %cmp, label %while.body, label %while.end.loopexit
+
+while.end.loopexit:
+ br label %while.end
+
+while.end:
+ %res.0.lcssa = phi i32 [ 0, %entry ], [ %add, %while.end.loopexit ]
+ ret i32 %res.0.lcssa
+}
diff --git a/llvm/test/Transforms/HardwareLoops/ARM/structure.ll b/llvm/test/Transforms/HardwareLoops/ARM/structure.ll
new file mode 100644
index 00000000000..e3fe762bb1d
--- /dev/null
+++ b/llvm/test/Transforms/HardwareLoops/ARM/structure.ll
@@ -0,0 +1,72 @@
+; RUN: opt -mtriple=thumbv8.1m.main-arm-none-eabi -hardware-loops -disable-arm-loloops=false %s -S -o - | FileCheck %s
+
+; CHECK-LABEL: early_exit
+; CHECK-NOT: llvm.set.loop.iterations
+; CHECK-NOT: llvm.loop.decrement
+define i32 @early_exit(i32* nocapture readonly %a, i32 %max, i32 %n) {
+entry:
+ br label %do.body
+
+do.body:
+ %i.0 = phi i32 [ 0, %entry ], [ %inc, %if.end ]
+ %arrayidx = getelementptr inbounds i32, i32* %a, i32 %i.0
+ %0 = load i32, i32* %arrayidx, align 4
+ %cmp = icmp sgt i32 %0, %max
+ br i1 %cmp, label %do.end, label %if.end
+
+if.end:
+ %inc = add nuw i32 %i.0, 1
+ %cmp1 = icmp ult i32 %inc, %n
+ br i1 %cmp1, label %do.body, label %if.end.do.end_crit_edge
+
+if.end.do.end_crit_edge:
+ %arrayidx2.phi.trans.insert = getelementptr inbounds i32, i32* %a, i32 %inc
+ %.pre = load i32, i32* %arrayidx2.phi.trans.insert, align 4
+ br label %do.end
+
+do.end:
+ %1 = phi i32 [ %.pre, %if.end.do.end_crit_edge ], [ %0, %do.body ]
+ ret i32 %1
+}
+
+; CHECK-LABEL: nested
+; CHECK-NOT: call void @llvm.set.loop.iterations.i32(i32 %N)
+; CHECK: br i1 %cmp20, label %while.end7, label %while.cond1.preheader.us
+
+; CHECK: call void @llvm.set.loop.iterations.i32(i32 %N)
+; CHECK: br label %while.body3.us
+
+; CHECK: [[REM:%[^ ]+]] = phi i32 [ %N, %while.cond1.preheader.us ], [ [[LOOP_DEC:%[^ ]+]], %while.body3.us ]
+; CHECK: [[LOOP_DEC]] = call i32 @llvm.loop.decrement.reg.i32.i32.i32(i32 [[REM]], i32 1)
+; CHECK: [[CMP:%[^ ]+]] = icmp ne i32 [[LOOP_DEC]], 0
+; CHECK: br i1 [[CMP]], label %while.body3.us, label %while.cond1.while.end_crit_edge.us
+
+; CHECK-NOT: [[LOOP_DEC1:%[^ ]+]] = call i1 @llvm.loop.decrement.i32(i32 1)
+; CHECK-NOT: br i1 [[LOOP_DEC1]], label %while.cond1.preheader.us, label %while.end7
+define void @nested(i32* nocapture %A, i32 %N) {
+entry:
+ %cmp20 = icmp eq i32 %N, 0
+ br i1 %cmp20, label %while.end7, label %while.cond1.preheader.us
+
+while.cond1.preheader.us:
+ %i.021.us = phi i32 [ %inc6.us, %while.cond1.while.end_crit_edge.us ], [ 0, %entry ]
+ %mul.us = mul i32 %i.021.us, %N
+ br label %while.body3.us
+
+while.body3.us:
+ %j.019.us = phi i32 [ 0, %while.cond1.preheader.us ], [ %inc.us, %while.body3.us ]
+ %add.us = add i32 %j.019.us, %mul.us
+ %arrayidx.us = getelementptr inbounds i32, i32* %A, i32 %add.us
+ store i32 %add.us, i32* %arrayidx.us, align 4
+ %inc.us = add nuw i32 %j.019.us, 1
+ %exitcond = icmp eq i32 %inc.us, %N
+ br i1 %exitcond, label %while.cond1.while.end_crit_edge.us, label %while.body3.us
+
+while.cond1.while.end_crit_edge.us:
+ %inc6.us = add nuw i32 %i.021.us, 1
+ %exitcond23 = icmp eq i32 %inc6.us, %N
+ br i1 %exitcond23, label %while.end7, label %while.cond1.preheader.us
+
+while.end7:
+ ret void
+}
OpenPOWER on IntegriCloud