408 lines · plain
1; RUN: opt -mtriple=thumbv8.1m.main-none-none-eabi -passes=hardware-loops %s -S -o - | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-MAIN2; RUN: opt -mtriple=thumbv8.1m.main-none-none-eabi -mattr=+fullfp16 -passes=hardware-loops %s -S -o - | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-FP3; RUN: opt -mtriple=thumbv8.1m.main-none-none-eabi -mattr=+fp-armv8,+fullfp16 -passes=hardware-loops %s -S -o - | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-FP644; RUN: opt -mtriple=thumbv8.1m.main-none-none-eabi -mattr=+mve -passes=hardware-loops %s -S -o - | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-MVE5; RUN: opt -mtriple=thumbv8.1m.main-none-none-eabi -mattr=+mve.fp -passes=hardware-loops %s -S -o - | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-MVEFP6; RUN: opt -mtriple=thumbv8.1m.main-none-none-eabi -passes=hardware-loops -disable-arm-loloops=true %s -S -o - | FileCheck %s --check-prefix=DISABLED7 8; DISABLED-NOT: call i32 @llvm.loop.decrement9 10; CHECK-LABEL: skip_call11; CHECK-NOT: call i32 @llvm.start.loop.iterations12; CHECK-NOT: call i32 @llvm.loop.decrement13 14define i32 @skip_call(i32 %n) {15entry:16 %cmp6 = icmp eq i32 %n, 017 br i1 %cmp6, label %while.end, label %while.body.preheader18 19while.body.preheader:20 br label %while.body21 22while.body:23 %i.08 = phi i32 [ %inc1, %while.body ], [ 0, %while.body.preheader ]24 %res.07 = phi i32 [ %add, %while.body ], [ 0, %while.body.preheader ]25 %call = tail call i32 @bar() #226 %add = add nsw i32 %call, %res.0727 %inc1 = add nuw i32 %i.08, 128 %exitcond = icmp eq i32 %inc1, %n29 br i1 %exitcond, label %while.end.loopexit, label %while.body30 31while.end.loopexit:32 br label %while.end33 34while.end:35 %res.0.lcssa = phi i32 [ 0, %entry ], [ %add, %while.end.loopexit ]36 ret i32 %res.0.lcssa37}38 39; CHECK-LABEL: test_target_specific40; CHECK: [[X:%[^ ]+]] = call i32 @llvm.start.loop.iterations.i32(i32 50)41; CHECK: [[COUNT:%[^ ]+]] = phi i32 [ [[X]], %entry ], [ [[LOOP_DEC:%[^ ]+]], %loop ]42; CHECK: [[LOOP_DEC]] = call i32 @llvm.loop.decrement.reg.i32(i32 [[COUNT]], i32 1)43; CHECK: [[CMP:%[^ ]+]] = icmp ne i32 [[LOOP_DEC]], 044; CHECK: br i1 [[CMP]], label %loop, label %exit45 46define i32 @test_target_specific(ptr %a, ptr %b) {47entry:48 br label %loop49loop:50 %acc = phi i32 [ 0, %entry ], [ %res, %loop ]51 %count = phi i32 [ 0, %entry ], [ %count.next, %loop ]52 %addr.a = getelementptr i32, ptr %a, i32 %count53 %addr.b = getelementptr i32, ptr %b, i32 %count54 %load.a = load i32, ptr %addr.a55 %load.b = load i32, ptr %addr.b56 %res = call i32 @llvm.arm.smlad(i32 %load.a, i32 %load.b, i32 %acc)57 %count.next = add nuw i32 %count, 258 %cmp = icmp ne i32 %count.next, 10059 br i1 %cmp, label %loop, label %exit60exit:61 ret i32 %res62}63 64; CHECK-LABEL: test_fabs_f1665; CHECK-MAIN-NOT: call i32 @llvm.start.loop.iterations66; CHECK-MVE-NOT: call i32 @llvm.start.loop.iterations67; CHECK-FP: call i32 @llvm.start.loop.iterations.i32(i32 100)68; CHECK-MVEFP: call i32 @llvm.start.loop.iterations.i32(i32 100)69define void @test_fabs_f16(ptr %a, ptr %b) {70entry:71 br label %loop72loop:73 %count = phi i32 [ 0, %entry ], [ %count.next, %loop ]74 %addr.a = getelementptr half, ptr %a, i32 %count75 %load.a = load half, ptr %addr.a76 %abs = call half @llvm.fabs.f16(half %load.a)77 %addr.b = getelementptr half, ptr %b, i32 %count78 store half %abs, ptr %addr.b79 %count.next = add nuw i32 %count, 180 %cmp = icmp ne i32 %count.next, 10081 br i1 %cmp, label %loop, label %exit82exit:83 ret void84}85 86; CHECK-LABEL: test_fabs87; CHECK-MAIN-NOT: call i32 @llvm.start.loop.iterations88; CHECK-MVE-NOT: call i32 @llvm.start.loop.iterations89; CHECK-FP: call i32 @llvm.start.loop.iterations.i32(i32 100)90; CHECK-MVEFP: call i32 @llvm.start.loop.iterations.i32(i32 100)91 92define float @test_fabs(ptr %a) {93entry:94 br label %loop95loop:96 %acc = phi float [ 0.0, %entry ], [ %res, %loop ]97 %count = phi i32 [ 0, %entry ], [ %count.next, %loop ]98 %addr.a = getelementptr float, ptr %a, i32 %count99 %load.a = load float, ptr %addr.a100 %abs = call float @llvm.fabs.f32(float %load.a)101 %res = fadd float %abs, %acc102 %count.next = add nuw i32 %count, 1103 %cmp = icmp ne i32 %count.next, 100104 br i1 %cmp, label %loop, label %exit105exit:106 ret float %res107}108 109; CHECK-LABEL: test_fabs_64110; CHECK-MAIN-NOT: call i32 @llvm.start.loop.iterations111; CHECK-MVE-NOT: call i32 @llvm.start.loop.iterations112; CHECK-FP-NOT: call i32 @llvm.start.loop.iterations.i32(i32 100)113; CHECK-FP64: call i32 @llvm.start.loop.iterations.i32(i32 100)114; CHECK-MVEFP-NOT: call i32 @llvm.start.loop.iterations.i32(i32 100)115define void @test_fabs_64(ptr %a, ptr %b) {116entry:117 br label %loop118loop:119 %count = phi i32 [ 0, %entry ], [ %count.next, %loop ]120 %addr.a = getelementptr double, ptr %a, i32 %count121 %load.a = load double, ptr %addr.a122 %abs = call double @llvm.fabs.f64(double %load.a)123 %addr.b = getelementptr double, ptr %b, i32 %count124 store double %abs, ptr %addr.b125 %count.next = add nuw i32 %count, 1126 %cmp = icmp ne i32 %count.next, 100127 br i1 %cmp, label %loop, label %exit128exit:129 ret void130}131 132; CHECK-LABEL: test_fabs_vec133; CHECK-MVE-NOT: call i32 @llvm.start.loop.iterations134; CHECK-MVEFP: [[X:%[^ ]+]] = call i32 @llvm.start.loop.iterations.i32(i32 100)135; CHECK-MVEFP: [[COUNT:%[^ ]+]] = phi i32 [ [[X]], %entry ], [ [[LOOP_DEC:%[^ ]+]], %loop ]136; CHECK-MVEFP: [[LOOP_DEC]] = call i32 @llvm.loop.decrement.reg.i32(i32 [[COUNT]], i32 1)137; CHECK-MVEFP: [[CMP:%[^ ]+]] = icmp ne i32 [[LOOP_DEC]], 0138; CHECK-MVEFP: br i1 [[CMP]], label %loop, label %exit139define <4 x float> @test_fabs_vec(ptr %a) {140entry:141 br label %loop142loop:143 %acc = phi <4 x float> [ zeroinitializer, %entry ], [ %res, %loop ]144 %count = phi i32 [ 0, %entry ], [ %count.next, %loop ]145 %addr.a = getelementptr <4 x float>, ptr %a, i32 %count146 %load.a = load <4 x float>, ptr %addr.a147 %abs = call <4 x float> @llvm.fabs.v4f32(<4 x float> %load.a)148 %res = fadd <4 x float> %abs, %acc149 %count.next = add nuw i32 %count, 1150 %cmp = icmp ne i32 %count.next, 100151 br i1 %cmp, label %loop, label %exit152exit:153 ret <4 x float> %res154}155 156; CHECK-LABEL: test_log157; CHECK-NOT: call i32 @llvm.start.loop.iterations158; CHECK-NOT: llvm.loop.decrement159define float @test_log(ptr %a) {160entry:161 br label %loop162loop:163 %acc = phi float [ 0.0, %entry ], [ %res, %loop ]164 %count = phi i32 [ 0, %entry ], [ %count.next, %loop ]165 %addr.a = getelementptr float, ptr %a, i32 %count166 %load.a = load float, ptr %addr.a167 %abs = call float @llvm.log.f32(float %load.a)168 %res = fadd float %abs, %acc169 %count.next = add nuw i32 %count, 1170 %cmp = icmp ne i32 %count.next, 100171 br i1 %cmp, label %loop, label %exit172exit:173 ret float %res174}175 176; CHECK-LABEL: test_sqrt_16177; CHECK-MAIN-NOT: call i32 @llvm.start.loop.iterations178; CHECK-MVE-NOT: call i32 @llvm.start.loop.iterations179; CHECK-FP: call i32 @llvm.start.loop.iterations.i32(i32 100)180; CHECK-MVEFP: call i32 @llvm.start.loop.iterations.i32(i32 100)181; CHECK-FP64: call i32 @llvm.start.loop.iterations.i32(i32 100)182define void @test_sqrt_16(ptr %a, ptr %b) {183entry:184 br label %loop185loop:186 %count = phi i32 [ 0, %entry ], [ %count.next, %loop ]187 %addr.a = getelementptr half, ptr %a, i32 %count188 %load.a = load half, ptr %addr.a189 %sqrt = call half @llvm.sqrt.f16(half %load.a)190 %addr.b = getelementptr half, ptr %b, i32 %count191 store half %sqrt, ptr %addr.b192 %count.next = add nuw i32 %count, 1193 %cmp = icmp ne i32 %count.next, 100194 br i1 %cmp, label %loop, label %exit195exit:196 ret void197}198; CHECK-LABEL: test_sqrt199; CHECK-MAIN-NOT: call i32 @llvm.start.loop.iterations200; CHECK-MVE-NOT: call i32 @llvm.start.loop.iterations201; CHECK-FP: call i32 @llvm.start.loop.iterations202; CHECK-MVEFP: [[X:%[^ ]+]] = call i32 @llvm.start.loop.iterations.i32(i32 100)203; CHECK-MVEFP: [[COUNT:%[^ ]+]] = phi i32 [ [[X]], %entry ], [ [[LOOP_DEC:%[^ ]+]], %loop ]204; CHECK-MVEFP: [[LOOP_DEC]] = call i32 @llvm.loop.decrement.reg.i32(i32 [[COUNT]], i32 1)205; CHECK-MVEFP: [[CMP:%[^ ]+]] = icmp ne i32 [[LOOP_DEC]], 0206; CHECK-MVEFP: br i1 [[CMP]], label %loop, label %exit207define void @test_sqrt(ptr %a, ptr %b) {208entry:209 br label %loop210loop:211 %count = phi i32 [ 0, %entry ], [ %count.next, %loop ]212 %addr.a = getelementptr float, ptr %a, i32 %count213 %load.a = load float, ptr %addr.a214 %sqrt = call float @llvm.sqrt.f32(float %load.a)215 %addr.b = getelementptr float, ptr %b, i32 %count216 store float %sqrt, ptr %addr.b217 %count.next = add nuw i32 %count, 1218 %cmp = icmp ne i32 %count.next, 100219 br i1 %cmp, label %loop, label %exit220exit:221 ret void222}223 224; CHECK-LABEL: test_sqrt_64225; CHECK-MAIN-NOT: call i32 @llvm.start.loop.iterations226; CHECK-MVE-NOT: call i32 @llvm.start.loop.iterations227; CHECK-FP-NOT: call i32 @llvm.start.loop.iterations.i32(i32 100)228; CHECK-MVEFP-NOT: call i32 @llvm.start.loop.iterations.i32(i32 100)229; CHECK-FP64: call i32 @llvm.start.loop.iterations.i32(i32 100)230define void @test_sqrt_64(ptr %a, ptr %b) {231entry:232 br label %loop233loop:234 %count = phi i32 [ 0, %entry ], [ %count.next, %loop ]235 %addr.a = getelementptr double, ptr %a, i32 %count236 %load.a = load double, ptr %addr.a237 %sqrt = call double @llvm.sqrt.f64(double %load.a)238 %addr.b = getelementptr double, ptr %b, i32 %count239 store double %sqrt, ptr %addr.b240 %count.next = add nuw i32 %count, 1241 %cmp = icmp ne i32 %count.next, 100242 br i1 %cmp, label %loop, label %exit243exit:244 ret void245}246 247; CHECK-LABEL: test_sqrt_vec248; CHECK-MAIN-NOT: call i32 @llvm.start.loop.iterations249; CHECK-MVE-NOT: call i32 @llvm.start.loop.iterations250; CHECK-FP: call i32 @llvm.start.loop.iterations.i32(i32 100)251; CHECK-MVEFP: call i32 @llvm.start.loop.iterations.i32(i32 100)252define void @test_sqrt_vec(ptr %a, ptr %b) {253entry:254 br label %loop255loop:256 %count = phi i32 [ 0, %entry ], [ %count.next, %loop ]257 %addr.a = getelementptr <4 x float>, ptr %a, i32 %count258 %load.a = load <4 x float>, ptr %addr.a259 %sqrt = call <4 x float> @llvm.sqrt.v4f32(<4 x float> %load.a)260 %addr.b = getelementptr <4 x float>, ptr %b, i32 %count261 store <4 x float> %sqrt, ptr %addr.b262 %count.next = add nuw i32 %count, 1263 %cmp = icmp ne i32 %count.next, 100264 br i1 %cmp, label %loop, label %exit265exit:266 ret void267}268 269; CHECK-LABEL: test_overflow270; CHECK: call i32 @llvm.start.loop.iterations271define i32 @test_overflow(ptr %a, ptr %b) {272entry:273 br label %loop274loop:275 %acc = phi i32 [ 0, %entry ], [ %res, %loop ]276 %count = phi i32 [ 0, %entry ], [ %count.next, %loop ]277 %addr.a = getelementptr i32, ptr %a, i32 %count278 %addr.b = getelementptr i32, ptr %b, i32 %count279 %load.a = load i32, ptr %addr.a280 %load.b = load i32, ptr %addr.b281 %sadd = call {i32, i1} @llvm.sadd.with.overflow.i32(i32 %load.a, i32 %load.b)282 %res = extractvalue {i32, i1} %sadd, 0283 %count.next = add nuw i32 %count, 1284 %cmp = icmp ne i32 %count.next, 100285 br i1 %cmp, label %loop, label %exit286exit:287 ret i32 %res288}289 290; TODO: We should be able to generate a qadd/sub291; CHECK-LABEL: test_sat292; CHECK: call i32 @llvm.start.loop.iterations.i32(i32 100)293define i32 @test_sat(ptr %a, ptr %b) {294entry:295 br label %loop296loop:297 %acc = phi i32 [ 0, %entry ], [ %res, %loop ]298 %count = phi i32 [ 0, %entry ], [ %count.next, %loop ]299 %addr.a = getelementptr i32, ptr %a, i32 %count300 %addr.b = getelementptr i32, ptr %b, i32 %count301 %load.a = load i32, ptr %addr.a302 %load.b = load i32, ptr %addr.b303 %res = call i32 @llvm.sadd.sat.i32(i32 %load.a, i32 %load.b)304 %count.next = add nuw i32 %count, 1305 %cmp = icmp ne i32 %count.next, 100306 br i1 %cmp, label %loop, label %exit307exit:308 ret i32 %res309}310 311; CHECK-LABEL: test_masked_i32312; CHECK-NOT: call i32 @llvm.start.loop.iterations313; CHECK-MVEFP: call i32 @llvm.start.loop.iterations314; CHECK-MVE: [[X:%[^ ]+]] = call i32 @llvm.start.loop.iterations.i32(i32 100)315; CHECK-MVE: [[COUNT:%[^ ]+]] = phi i32 [ [[X]], %entry ], [ [[LOOP_DEC:%[^ ]+]], %loop ]316; CHECK-MVE: [[LOOP_DEC]] = call i32 @llvm.loop.decrement.reg.i32(i32 [[COUNT]], i32 1)317; CHECK-MVE: [[CMP:%[^ ]+]] = icmp ne i32 [[LOOP_DEC]], 0318; CHECK-MVE: br i1 [[CMP]], label %loop, label %exit319define arm_aapcs_vfpcc void @test_masked_i32(<4 x i1> %mask, ptr %a, ptr %b, ptr %c, <4 x i32> %passthru) {320entry:321 br label %loop322loop:323 %count = phi i32 [ 0, %entry ], [ %count.next, %loop ]324 %addr.a = getelementptr <4 x i32>, ptr %a, i32 %count325 %addr.b = getelementptr <4 x i32>, ptr %b, i32 %count326 %addr.c = getelementptr <4 x i32>, ptr %c, i32 %count327 %load.a = call <4 x i32> @llvm.masked.load.v4i32.p0(ptr %addr.a, i32 4, <4 x i1> %mask, <4 x i32> %passthru)328 %load.b = call <4 x i32> @llvm.masked.load.v4i32.p0(ptr %addr.b, i32 4, <4 x i1> %mask, <4 x i32> %passthru)329 %res = add <4 x i32> %load.a, %load.b330 call void @llvm.masked.store.v4i32.p0(<4 x i32> %res, ptr %addr.c, i32 4, <4 x i1> %mask)331 %count.next = add nuw i32 %count, 1332 %cmp = icmp ne i32 %count.next, 100333 br i1 %cmp, label %loop, label %exit334exit:335 ret void336}337 338; CHECK-LABEL: test_masked_f32339; CHECK-NOT: call i32 @llvm.start.loop.iterations340; CHECK-MVEFP: call i32 @llvm.start.loop.iterations341; CHECK-MVE: [[X:%[^ ]+]] = call i32 @llvm.start.loop.iterations.i32(i32 100)342; CHECK-MVE: [[COUNT:%[^ ]+]] = phi i32 [ [[X]], %entry ], [ [[LOOP_DEC:%[^ ]+]], %loop ]343; CHECK-MVE: [[LOOP_DEC]] = call i32 @llvm.loop.decrement.reg.i32(i32 [[COUNT]], i32 1)344; CHECK-MVE: [[CMP:%[^ ]+]] = icmp ne i32 [[LOOP_DEC]], 0345; CHECK-MVE: br i1 [[CMP]], label %loop, label %exit346define arm_aapcs_vfpcc void @test_masked_f32(<4 x i1> %mask, ptr %a, ptr %b, ptr %c, <4 x float> %passthru) {347entry:348 br label %loop349loop:350 %count = phi i32 [ 0, %entry ], [ %count.next, %loop ]351 %addr.a = getelementptr <4 x float>, ptr %a, i32 %count352 %addr.b = getelementptr <4 x float>, ptr %b, i32 %count353 %addr.c = getelementptr <4 x float>, ptr %c, i32 %count354 %load.a = call <4 x float> @llvm.masked.load.v4f32.p0(ptr %addr.a, i32 4, <4 x i1> %mask, <4 x float> %passthru)355 %load.b = call <4 x float> @llvm.masked.load.v4f32.p0(ptr %addr.b, i32 4, <4 x i1> %mask, <4 x float> %passthru)356 %res = fadd <4 x float> %load.a, %load.b357 call void @llvm.masked.store.v4f32.p0(<4 x float> %res, ptr %addr.c, i32 4, <4 x i1> %mask)358 %count.next = add nuw i32 %count, 1359 %cmp = icmp ne i32 %count.next, 100360 br i1 %cmp, label %loop, label %exit361exit:362 ret void363}364 365; CHECK-LABEL: test_gather_scatter366; CHECK-NOT: call i32 @llvm.start.loop.iterations367; CHECK-MVEFP: call i32 @llvm.start.loop.iterations368; CHECK-MVE: [[X:%[^ ]+]] = call i32 @llvm.start.loop.iterations.i32(i32 100)369; CHECK-MVE: [[COUNT:%[^ ]+]] = phi i32 [ [[X]], %entry ], [ [[LOOP_DEC:%[^ ]+]], %loop ]370; CHECK-MVE: [[LOOP_DEC]] = call i32 @llvm.loop.decrement.reg.i32(i32 [[COUNT]], i32 1)371; CHECK-MVE: [[CMP:%[^ ]+]] = icmp ne i32 [[LOOP_DEC]], 0372; CHECK-MVE: br i1 [[CMP]], label %loop, label %exit373define arm_aapcs_vfpcc void @test_gather_scatter(<4 x i1> %mask, <4 x ptr> %a, <4 x ptr> %b, <4 x ptr> %c, <4 x float> %passthru) {374entry:375 br label %loop376loop:377 %count = phi i32 [ 0, %entry ], [ %count.next, %loop ]378 %load.a = call <4 x float> @llvm.masked.gather.v4f32.p0(<4 x ptr> %a, i32 4, <4 x i1> %mask, <4 x float> %passthru)379 %load.b = call <4 x float> @llvm.masked.gather.v4f32.p0(<4 x ptr> %b, i32 4, <4 x i1> %mask, <4 x float> %passthru)380 %res = fadd <4 x float> %load.a, %load.b381 call void @llvm.masked.scatter.v4f32.p0(<4 x float> %res, <4 x ptr> %c, i32 4, <4 x i1> %mask)382 %count.next = add nuw i32 %count, 1383 %cmp = icmp ne i32 %count.next, 100384 br i1 %cmp, label %loop, label %exit385exit:386 ret void387}388 389declare i32 @bar(...) local_unnamed_addr #1390declare i32 @llvm.arm.smlad(i32, i32, i32)391declare half @llvm.fabs.f16(half)392declare float @llvm.fabs.f32(float)393declare double @llvm.fabs.f64(double)394declare float @llvm.log.f32(float)395declare <4 x float> @llvm.fabs.v4f32(<4 x float>)396declare half @llvm.sqrt.f16(half)397declare float @llvm.sqrt.f32(float)398declare double @llvm.sqrt.f64(double)399declare <4 x float> @llvm.sqrt.v4f32(<4 x float>)400declare i32 @llvm.sadd.sat.i32(i32, i32)401declare {i32, i1} @llvm.sadd.with.overflow.i32(i32, i32)402declare <4 x i32> @llvm.masked.load.v4i32.p0(ptr, i32, <4 x i1>, <4 x i32>)403declare void @llvm.masked.store.v4i32.p0(<4 x i32>, ptr, i32, <4 x i1>)404declare <4 x float> @llvm.masked.load.v4f32.p0(ptr, i32, <4 x i1>, <4 x float>)405declare void @llvm.masked.store.v4f32.p0(<4 x float>, ptr, i32, <4 x i1>)406declare <4 x float> @llvm.masked.gather.v4f32.p0(<4 x ptr>, i32, <4 x i1>, <4 x float>)407declare void @llvm.masked.scatter.v4f32.p0(<4 x float>, <4 x ptr>, i32, <4 x i1>)408