[ARM][ParallelDSP] Change search for muls
rL369567 reverted a couple of recent changes made to ARMParallelDSP
because of a miscompilation error: PR43073.
The issue stemmed from an underlying bug that was caused by adding
muls into a reduction before it was proved that they could be executed
in parallel with another mul.
Most of the changes here are from the previously reverted commits.
The additional changes have been made area:
1) The Search function now doesn't insert any muls into the Reduction
object. That now happens once the search has successfully finished.
2) For any muls added into the reduction but that weren't paired, we
accumulate their values as an input into the smlad.
Differential Revision: https://reviews.llvm.org/D66660
llvm-svn: 370171
diff --git a/llvm/test/CodeGen/ARM/ParallelDSP/blocks.ll b/llvm/test/CodeGen/ARM/ParallelDSP/blocks.ll
new file mode 100644
index 0000000..d9dbd96
--- /dev/null
+++ b/llvm/test/CodeGen/ARM/ParallelDSP/blocks.ll
@@ -0,0 +1,79 @@
+; RUN: opt -arm-parallel-dsp -mtriple=armv7-a -S %s -o - | FileCheck %s
+
+; CHECK-LABEL: single_block
+; CHECK: [[CAST_A:%[^ ]+]] = bitcast i16* %a to i32*
+; CHECK: [[A:%[^ ]+]] = load i32, i32* [[CAST_A]]
+; CHECK: [[CAST_B:%[^ ]+]] = bitcast i16* %b to i32*
+; CHECK: [[B:%[^ ]+]] = load i32, i32* [[CAST_B]]
+; CHECK: call i32 @llvm.arm.smlad(i32 [[A]], i32 [[B]], i32 %acc)
+define i32 @single_block(i16* %a, i16* %b, i32 %acc) {
+entry:
+ %ld.a.0 = load i16, i16* %a
+ %sext.a.0 = sext i16 %ld.a.0 to i32
+ %ld.b.0 = load i16, i16* %b
+ %sext.b.0 = sext i16 %ld.b.0 to i32
+ %mul.0 = mul i32 %sext.a.0, %sext.b.0
+ %addr.a.1 = getelementptr i16, i16* %a, i32 1
+ %addr.b.1 = getelementptr i16, i16* %b, i32 1
+ %ld.a.1 = load i16, i16* %addr.a.1
+ %sext.a.1 = sext i16 %ld.a.1 to i32
+ %ld.b.1 = load i16, i16* %addr.b.1
+ %sext.b.1 = sext i16 %ld.b.1 to i32
+ %mul.1 = mul i32 %sext.a.1, %sext.b.1
+ %add = add i32 %mul.0, %mul.1
+ %res = add i32 %add, %acc
+ ret i32 %res
+}
+
+; CHECK-LABEL: multi_block
+; CHECK: [[CAST_A:%[^ ]+]] = bitcast i16* %a to i32*
+; CHECK: [[A:%[^ ]+]] = load i32, i32* [[CAST_A]]
+; CHECK: [[CAST_B:%[^ ]+]] = bitcast i16* %b to i32*
+; CHECK: [[B:%[^ ]+]] = load i32, i32* [[CAST_B]]
+; CHECK: call i32 @llvm.arm.smlad(i32 [[A]], i32 [[B]], i32 0)
+define i32 @multi_block(i16* %a, i16* %b, i32 %acc) {
+entry:
+ %ld.a.0 = load i16, i16* %a
+ %sext.a.0 = sext i16 %ld.a.0 to i32
+ %ld.b.0 = load i16, i16* %b
+ %sext.b.0 = sext i16 %ld.b.0 to i32
+ %mul.0 = mul i32 %sext.a.0, %sext.b.0
+ %addr.a.1 = getelementptr i16, i16* %a, i32 1
+ %addr.b.1 = getelementptr i16, i16* %b, i32 1
+ %ld.a.1 = load i16, i16* %addr.a.1
+ %sext.a.1 = sext i16 %ld.a.1 to i32
+ %ld.b.1 = load i16, i16* %addr.b.1
+ %sext.b.1 = sext i16 %ld.b.1 to i32
+ %mul.1 = mul i32 %sext.a.1, %sext.b.1
+ %add = add i32 %mul.0, %mul.1
+ br label %bb.1
+
+bb.1:
+ %res = add i32 %add, %acc
+ ret i32 %res
+}
+
+; CHECK-LABEL: multi_block_1
+; CHECK-NOT: call i32 @llvm.arm.smlad
+define i32 @multi_block_1(i16* %a, i16* %b, i32 %acc) {
+entry:
+ %ld.a.0 = load i16, i16* %a
+ %sext.a.0 = sext i16 %ld.a.0 to i32
+ %ld.b.0 = load i16, i16* %b
+ %sext.b.0 = sext i16 %ld.b.0 to i32
+ %mul.0 = mul i32 %sext.a.0, %sext.b.0
+ br label %bb.1
+
+bb.1:
+ %addr.a.1 = getelementptr i16, i16* %a, i32 1
+ %addr.b.1 = getelementptr i16, i16* %b, i32 1
+ %ld.a.1 = load i16, i16* %addr.a.1
+ %sext.a.1 = sext i16 %ld.a.1 to i32
+ %ld.b.1 = load i16, i16* %addr.b.1
+ %sext.b.1 = sext i16 %ld.b.1 to i32
+ %mul.1 = mul i32 %sext.a.1, %sext.b.1
+ %add = add i32 %mul.0, %mul.1
+ %res = add i32 %add, %acc
+ ret i32 %res
+}
+
diff --git a/llvm/test/CodeGen/ARM/ParallelDSP/exchange.ll b/llvm/test/CodeGen/ARM/ParallelDSP/exchange.ll
new file mode 100644
index 0000000..c072df4
--- /dev/null
+++ b/llvm/test/CodeGen/ARM/ParallelDSP/exchange.ll
@@ -0,0 +1,329 @@
+; RUN: opt -arm-parallel-dsp -mtriple=armv7-a -S %s -o - | FileCheck %s
+
+; CHECK-LABEL: exchange_1
+; CHECK: [[CAST_A:%[^ ]+]] = bitcast i16* %a to i32*
+; CHECK: [[LD_A:%[^ ]+]] = load i32, i32* [[CAST_A]]
+; CHECK: [[CAST_B:%[^ ]+]] = bitcast i16* %b to i32*
+; CHECK: [[LD_B:%[^ ]+]] = load i32, i32* [[CAST_B]]
+; CHECK: call i32 @llvm.arm.smladx(i32 [[LD_A]], i32 [[LD_B]]
+define i32 @exchange_1(i16* %a, i16* %b, i32 %acc) {
+entry:
+ %addr.a.1 = getelementptr i16, i16* %a, i32 1
+ %addr.b.1 = getelementptr i16, i16* %b, i32 1
+ %ld.a.0 = load i16, i16* %a
+ %sext.a.0 = sext i16 %ld.a.0 to i32
+ %ld.b.0 = load i16, i16* %b
+ %ld.a.1 = load i16, i16* %addr.a.1
+ %ld.b.1 = load i16, i16* %addr.b.1
+ %sext.a.1 = sext i16 %ld.a.1 to i32
+ %sext.b.1 = sext i16 %ld.b.1 to i32
+ %sext.b.0 = sext i16 %ld.b.0 to i32
+ %mul.0 = mul i32 %sext.a.0, %sext.b.1
+ %mul.1 = mul i32 %sext.a.1, %sext.b.0
+ %add = add i32 %mul.0, %mul.1
+ %res = add i32 %add, %acc
+ ret i32 %res
+}
+
+; CHECK-LABEL: exchange_2
+; CHECK: [[CAST_A:%[^ ]+]] = bitcast i16* %a to i32*
+; CHECK: [[LD_A:%[^ ]+]] = load i32, i32* [[CAST_A]]
+; CHECK: [[CAST_B:%[^ ]+]] = bitcast i16* %b to i32*
+; CHECK: [[LD_B:%[^ ]+]] = load i32, i32* [[CAST_B]]
+; CHECK: call i32 @llvm.arm.smladx(i32 [[LD_A]], i32 [[LD_B]]
+define i32 @exchange_2(i16* %a, i16* %b, i32 %acc) {
+entry:
+ %addr.a.1 = getelementptr i16, i16* %a, i32 1
+ %addr.b.1 = getelementptr i16, i16* %b, i32 1
+ %ld.a.0 = load i16, i16* %a
+ %sext.a.0 = sext i16 %ld.a.0 to i32
+ %ld.b.0 = load i16, i16* %b
+ %ld.a.1 = load i16, i16* %addr.a.1
+ %ld.b.1 = load i16, i16* %addr.b.1
+ %sext.a.1 = sext i16 %ld.a.1 to i32
+ %sext.b.1 = sext i16 %ld.b.1 to i32
+ %sext.b.0 = sext i16 %ld.b.0 to i32
+ %mul.0 = mul i32 %sext.b.1, %sext.a.0
+ %mul.1 = mul i32 %sext.b.0, %sext.a.1
+ %add = add i32 %mul.0, %mul.1
+ %res = add i32 %add, %acc
+ ret i32 %res
+}
+
+; CHECK-LABEL: exchange_3
+; CHECK: [[CAST_A:%[^ ]+]] = bitcast i16* %a to i32*
+; CHECK: [[LD_A:%[^ ]+]] = load i32, i32* [[CAST_A]]
+; CHECK: [[CAST_B:%[^ ]+]] = bitcast i16* %b to i32*
+; CHECK: [[LD_B:%[^ ]+]] = load i32, i32* [[CAST_B]]
+; CHECK: call i32 @llvm.arm.smladx(i32 [[LD_B]], i32 [[LD_A]]
+define i32 @exchange_3(i16* %a, i16* %b, i32 %acc) {
+entry:
+ %addr.a.1 = getelementptr i16, i16* %a, i32 1
+ %addr.b.1 = getelementptr i16, i16* %b, i32 1
+ %ld.a.0 = load i16, i16* %a
+ %sext.a.0 = sext i16 %ld.a.0 to i32
+ %ld.b.0 = load i16, i16* %b
+ %ld.a.1 = load i16, i16* %addr.a.1
+ %ld.b.1 = load i16, i16* %addr.b.1
+ %sext.a.1 = sext i16 %ld.a.1 to i32
+ %sext.b.1 = sext i16 %ld.b.1 to i32
+ %sext.b.0 = sext i16 %ld.b.0 to i32
+ %mul.0 = mul i32 %sext.a.0, %sext.b.1
+ %mul.1 = mul i32 %sext.a.1, %sext.b.0
+ %add = add i32 %mul.1, %mul.0
+ %res = add i32 %add, %acc
+ ret i32 %res
+}
+
+; CHECK-LABEL: exchange_4
+; CHECK: [[CAST_A:%[^ ]+]] = bitcast i16* %a to i32*
+; CHECK: [[LD_A:%[^ ]+]] = load i32, i32* [[CAST_A]]
+; CHECK: [[CAST_B:%[^ ]+]] = bitcast i16* %b to i32*
+; CHECK: [[LD_B:%[^ ]+]] = load i32, i32* [[CAST_B]]
+; CHECK: call i32 @llvm.arm.smladx(i32 [[LD_B]], i32 [[LD_A]]
+define i32 @exchange_4(i16* %a, i16* %b, i32 %acc) {
+entry:
+ %addr.a.1 = getelementptr i16, i16* %a, i32 1
+ %addr.b.1 = getelementptr i16, i16* %b, i32 1
+ %ld.a.0 = load i16, i16* %a
+ %sext.a.0 = sext i16 %ld.a.0 to i32
+ %ld.b.0 = load i16, i16* %b
+ %ld.a.1 = load i16, i16* %addr.a.1
+ %ld.b.1 = load i16, i16* %addr.b.1
+ %sext.a.1 = sext i16 %ld.a.1 to i32
+ %sext.b.1 = sext i16 %ld.b.1 to i32
+ %sext.b.0 = sext i16 %ld.b.0 to i32
+ %mul.0 = mul i32 %sext.b.1, %sext.a.0
+ %mul.1 = mul i32 %sext.b.0, %sext.a.1
+ %add = add i32 %mul.1, %mul.0
+ %res = add i32 %add, %acc
+ ret i32 %res
+}
+
+; CHECK-LABEL: exchange_multi_use_1
+; CHECK: [[CAST_A:%[^ ]+]] = bitcast i16* %a to i32*
+; CHECK: [[LD_A:%[^ ]+]] = load i32, i32* [[CAST_A]]
+; CHECK: [[CAST_B:%[^ ]+]] = bitcast i16* %b to i32*
+; CHECK: [[LD_B:%[^ ]+]] = load i32, i32* [[CAST_B]]
+; CHECK: [[GEP:%[^ ]+]] = getelementptr i16, i16* %a, i32 2
+; CHECK: [[CAST_A_2:%[^ ]+]] = bitcast i16* [[GEP]] to i32*
+; CHECK: [[LD_A_2:%[^ ]+]] = load i32, i32* [[CAST_A_2]]
+; CHECK: [[X:%[^ ]+]] = call i32 @llvm.arm.smladx(i32 [[LD_A]], i32 [[LD_B]], i32 %acc
+; CHECK: call i32 @llvm.arm.smlad(i32 [[LD_A_2]], i32 [[LD_B]], i32 [[X]])
+define i32 @exchange_multi_use_1(i16* %a, i16* %b, i32 %acc) {
+entry:
+ %addr.a.1 = getelementptr i16, i16* %a, i32 1
+ %addr.b.1 = getelementptr i16, i16* %b, i32 1
+ %ld.a.0 = load i16, i16* %a
+ %sext.a.0 = sext i16 %ld.a.0 to i32
+ %ld.b.0 = load i16, i16* %b
+ %ld.a.1 = load i16, i16* %addr.a.1
+ %ld.b.1 = load i16, i16* %addr.b.1
+ %sext.a.1 = sext i16 %ld.a.1 to i32
+ %sext.b.1 = sext i16 %ld.b.1 to i32
+ %sext.b.0 = sext i16 %ld.b.0 to i32
+ %mul.0 = mul i32 %sext.a.0, %sext.b.1
+ %mul.1 = mul i32 %sext.a.1, %sext.b.0
+ %add = add i32 %mul.0, %mul.1
+ %addr.a.2 = getelementptr i16, i16* %a, i32 2
+ %addr.a.3 = getelementptr i16, i16* %a, i32 3
+ %ld.a.2 = load i16, i16* %addr.a.2
+ %ld.a.3 = load i16, i16* %addr.a.3
+ %sext.a.2 = sext i16 %ld.a.2 to i32
+ %sext.a.3 = sext i16 %ld.a.3 to i32
+ %mul.2 = mul i32 %sext.a.3, %sext.b.1
+ %mul.3 = mul i32 %sext.a.2, %sext.b.0
+ %add.1 = add i32 %mul.2, %mul.3
+ %add.2 = add i32 %add, %add.1
+ %res = add i32 %add.2, %acc
+ ret i32 %res
+}
+
+; CHECK-LABEL: exchange_multi_use_2
+; CHECK: [[CAST_A:%[^ ]+]] = bitcast i16* %a to i32*
+; CHECK: [[LD_A:%[^ ]+]] = load i32, i32* [[CAST_A]]
+; CHECK: [[CAST_B:%[^ ]+]] = bitcast i16* %b to i32*
+; CHECK: [[LD_B:%[^ ]+]] = load i32, i32* [[CAST_B]]
+; CHECK: [[GEP:%[^ ]+]] = getelementptr i16, i16* %a, i32 2
+; CHECK: [[CAST_A_2:%[^ ]+]] = bitcast i16* [[GEP]] to i32*
+; CHECK: [[LD_A_2:%[^ ]+]] = load i32, i32* [[CAST_A_2]]
+; CHECK: [[X:%[^ ]+]] = call i32 @llvm.arm.smlad(i32 [[LD_A]], i32 [[LD_B]], i32 %acc
+; CHECK: call i32 @llvm.arm.smladx(i32 [[LD_B]], i32 [[LD_A_2]], i32 [[X]])
+define i32 @exchange_multi_use_2(i16* %a, i16* %b, i32 %acc) {
+entry:
+ %addr.a.1 = getelementptr i16, i16* %a, i32 1
+ %addr.b.1 = getelementptr i16, i16* %b, i32 1
+ %ld.a.0 = load i16, i16* %a
+ %sext.a.0 = sext i16 %ld.a.0 to i32
+ %ld.b.0 = load i16, i16* %b
+ %ld.a.1 = load i16, i16* %addr.a.1
+ %ld.b.1 = load i16, i16* %addr.b.1
+ %sext.a.1 = sext i16 %ld.a.1 to i32
+ %sext.b.1 = sext i16 %ld.b.1 to i32
+ %sext.b.0 = sext i16 %ld.b.0 to i32
+ %mul.0 = mul i32 %sext.a.0, %sext.b.0
+ %mul.1 = mul i32 %sext.a.1, %sext.b.1
+ %add = add i32 %mul.0, %mul.1
+ %addr.a.2 = getelementptr i16, i16* %a, i32 2
+ %addr.a.3 = getelementptr i16, i16* %a, i32 3
+ %ld.a.2 = load i16, i16* %addr.a.2
+ %ld.a.3 = load i16, i16* %addr.a.3
+ %sext.a.2 = sext i16 %ld.a.2 to i32
+ %sext.a.3 = sext i16 %ld.a.3 to i32
+ %mul.2 = mul i32 %sext.b.0, %sext.a.3
+ %mul.3 = mul i32 %sext.b.1, %sext.a.2
+ %add.1 = add i32 %mul.2, %mul.3
+ %add.2 = add i32 %add, %add.1
+ %res = add i32 %add.2, %acc
+ ret i32 %res
+}
+
+; TODO: Why aren't two intrinsics generated?
+; CHECK-LABEL: exchange_multi_use_3
+; CHECK: [[CAST_B:%[^ ]+]] = bitcast i16* %b to i32*
+; CHECK: [[LD_B:%[^ ]+]] = load i32, i32* [[CAST_B]]
+; CHECK: [[GEP:%[^ ]+]] = getelementptr i16, i16* %a, i32 2
+; CHECK: [[CAST_A_2:%[^ ]+]] = bitcast i16* [[GEP]] to i32*
+; CHECK: [[LD_A_2:%[^ ]+]] = load i32, i32* [[CAST_A_2]]
+; CHECK-NOT: call i32 @llvm.arm.smlad
+; CHECK: [[X:%[^ ]+]] = call i32 @llvm.arm.smladx(i32 [[LD_B]], i32 [[LD_A_2]], i32 0
+define i32 @exchange_multi_use_3(i16* %a, i16* %b, i32 %acc) {
+entry:
+ %addr.a.1 = getelementptr i16, i16* %a, i32 1
+ %addr.b.1 = getelementptr i16, i16* %b, i32 1
+ %ld.a.0 = load i16, i16* %a
+ %sext.a.0 = sext i16 %ld.a.0 to i32
+ %ld.b.0 = load i16, i16* %b
+ %ld.a.1 = load i16, i16* %addr.a.1
+ %ld.b.1 = load i16, i16* %addr.b.1
+ %sext.a.1 = sext i16 %ld.a.1 to i32
+ %sext.b.1 = sext i16 %ld.b.1 to i32
+ %sext.b.0 = sext i16 %ld.b.0 to i32
+ %addr.a.2 = getelementptr i16, i16* %a, i32 2
+ %addr.a.3 = getelementptr i16, i16* %a, i32 3
+ %ld.a.2 = load i16, i16* %addr.a.2
+ %ld.a.3 = load i16, i16* %addr.a.3
+ %sext.a.2 = sext i16 %ld.a.2 to i32
+ %sext.a.3 = sext i16 %ld.a.3 to i32
+ %mul.2 = mul i32 %sext.b.0, %sext.a.3
+ %mul.3 = mul i32 %sext.b.1, %sext.a.2
+ %mul.0 = mul i32 %sext.a.0, %sext.b.0
+ %mul.1 = mul i32 %sext.a.1, %sext.b.1
+ %add = add i32 %mul.0, %mul.1
+ %add.1 = add i32 %mul.2, %mul.3
+ %sub = sub i32 %add, %add.1
+ %res = add i32 %acc, %sub
+ ret i32 %res
+}
+
+; TODO: Why isn't smladx generated too?
+; CHECK-LABEL: exchange_multi_use_4
+; CHECK: [[CAST_A:%[^ ]+]] = bitcast i16* %a to i32*
+; CHECK: [[LD_A:%[^ ]+]] = load i32, i32* [[CAST_A]]
+; CHECK: [[CAST_B:%[^ ]+]] = bitcast i16* %b to i32*
+; CHECK: [[LD_B:%[^ ]+]] = load i32, i32* [[CAST_B]]
+; CHECK: [[X:%[^ ]+]] = call i32 @llvm.arm.smlad(i32 [[LD_A]], i32 [[LD_B]], i32 0
+; CHECK-NOT: call i32 @llvm.arm.smlad
+define i32 @exchange_multi_use_4(i16* %a, i16* %b, i32 %acc) {
+entry:
+ %addr.a.1 = getelementptr i16, i16* %a, i32 1
+ %addr.b.1 = getelementptr i16, i16* %b, i32 1
+ %ld.a.0 = load i16, i16* %a
+ %sext.a.0 = sext i16 %ld.a.0 to i32
+ %ld.b.0 = load i16, i16* %b
+ %ld.a.1 = load i16, i16* %addr.a.1
+ %ld.b.1 = load i16, i16* %addr.b.1
+ %sext.a.1 = sext i16 %ld.a.1 to i32
+ %sext.b.1 = sext i16 %ld.b.1 to i32
+ %sext.b.0 = sext i16 %ld.b.0 to i32
+ %addr.a.2 = getelementptr i16, i16* %a, i32 2
+ %addr.a.3 = getelementptr i16, i16* %a, i32 3
+ %ld.a.2 = load i16, i16* %addr.a.2
+ %ld.a.3 = load i16, i16* %addr.a.3
+ %sext.a.2 = sext i16 %ld.a.2 to i32
+ %sext.a.3 = sext i16 %ld.a.3 to i32
+ %mul.2 = mul i32 %sext.b.0, %sext.a.3
+ %mul.3 = mul i32 %sext.b.1, %sext.a.2
+ %mul.0 = mul i32 %sext.a.0, %sext.b.0
+ %mul.1 = mul i32 %sext.a.1, %sext.b.1
+ %add.1 = add i32 %mul.2, %mul.3
+ %add = add i32 %mul.0, %mul.1
+ %sub = sub i32 %add, %add.1
+ %res = add i32 %acc, %sub
+ ret i32 %res
+}
+
+; CHECK-LABEL: exchange_swap
+; CHECK: [[CAST_A:%[^ ]+]] = bitcast i16* %a to i32*
+; CHECK: [[LD_A:%[^ ]+]] = load i32, i32* [[CAST_A]]
+; CHECK: [[CAST_B:%[^ ]+]] = bitcast i16* %b to i32*
+; CHECK: [[LD_B:%[^ ]+]] = load i32, i32* [[CAST_B]]
+; CHECK: call i32 @llvm.arm.smladx(i32 [[LD_B]], i32 [[LD_A]]
+define i32 @exchange_swap(i16* %a, i16* %b, i32 %acc) {
+entry:
+ %addr.a.1 = getelementptr i16, i16* %a, i32 1
+ %addr.b.1 = getelementptr i16, i16* %b, i32 1
+ %ld.a.0 = load i16, i16* %a
+ %sext.a.0 = sext i16 %ld.a.0 to i32
+ %ld.b.0 = load i16, i16* %b
+ %ld.a.1 = load i16, i16* %addr.a.1
+ %ld.b.1 = load i16, i16* %addr.b.1
+ %sext.a.1 = sext i16 %ld.a.1 to i32
+ %sext.b.1 = sext i16 %ld.b.1 to i32
+ %sext.b.0 = sext i16 %ld.b.0 to i32
+ %mul.0 = mul i32 %sext.a.1, %sext.b.0
+ %mul.1 = mul i32 %sext.a.0, %sext.b.1
+ %add = add i32 %mul.0, %mul.1
+ %res = add i32 %add, %acc
+ ret i32 %res
+}
+
+; CHECK-LABEL: exchange_swap_2
+; CHECK: [[CAST_A:%[^ ]+]] = bitcast i16* %a to i32*
+; CHECK: [[LD_A:%[^ ]+]] = load i32, i32* [[CAST_A]]
+; CHECK: [[CAST_B:%[^ ]+]] = bitcast i16* %b to i32*
+; CHECK: [[LD_B:%[^ ]+]] = load i32, i32* [[CAST_B]]
+; CHECK: call i32 @llvm.arm.smladx(i32 [[LD_A]], i32 [[LD_B]]
+define i32 @exchange_swap_2(i16* %a, i16* %b, i32 %acc) {
+entry:
+ %addr.a.1 = getelementptr i16, i16* %a, i32 1
+ %addr.b.1 = getelementptr i16, i16* %b, i32 1
+ %ld.a.0 = load i16, i16* %a
+ %sext.a.0 = sext i16 %ld.a.0 to i32
+ %ld.b.0 = load i16, i16* %b
+ %ld.a.1 = load i16, i16* %addr.a.1
+ %ld.b.1 = load i16, i16* %addr.b.1
+ %sext.a.1 = sext i16 %ld.a.1 to i32
+ %sext.b.1 = sext i16 %ld.b.1 to i32
+ %sext.b.0 = sext i16 %ld.b.0 to i32
+ %mul.0 = mul i32 %sext.a.1, %sext.b.0
+ %mul.1 = mul i32 %sext.a.0, %sext.b.1
+ %add = add i32 %mul.1, %mul.0
+ %res = add i32 %add, %acc
+ ret i32 %res
+}
+
+; CHECK-LABEL: exchange_swap_3
+; CHECK: [[CAST_A:%[^ ]+]] = bitcast i16* %a to i32*
+; CHECK: [[LD_A:%[^ ]+]] = load i32, i32* [[CAST_A]]
+; CHECK: [[CAST_B:%[^ ]+]] = bitcast i16* %b to i32*
+; CHECK: [[LD_B:%[^ ]+]] = load i32, i32* [[CAST_B]]
+; CHECK: call i32 @llvm.arm.smladx(i32 [[LD_A]], i32 [[LD_B]]
+define i32 @exchange_swap_3(i16* %a, i16* %b, i32 %acc) {
+entry:
+ %addr.a.1 = getelementptr i16, i16* %a, i32 1
+ %addr.b.1 = getelementptr i16, i16* %b, i32 1
+ %ld.a.0 = load i16, i16* %a
+ %sext.a.0 = sext i16 %ld.a.0 to i32
+ %ld.b.0 = load i16, i16* %b
+ %ld.a.1 = load i16, i16* %addr.a.1
+ %ld.b.1 = load i16, i16* %addr.b.1
+ %sext.a.1 = sext i16 %ld.a.1 to i32
+ %sext.b.1 = sext i16 %ld.b.1 to i32
+ %sext.b.0 = sext i16 %ld.b.0 to i32
+ %mul.0 = mul i32 %sext.b.0, %sext.a.1
+ %mul.1 = mul i32 %sext.b.1, %sext.a.0
+ %add = add i32 %mul.1, %mul.0
+ %res = add i32 %add, %acc
+ ret i32 %res
+}
diff --git a/llvm/test/CodeGen/ARM/ParallelDSP/overlapping.ll b/llvm/test/CodeGen/ARM/ParallelDSP/overlapping.ll
new file mode 100644
index 0000000..a071ec3
--- /dev/null
+++ b/llvm/test/CodeGen/ARM/ParallelDSP/overlapping.ll
@@ -0,0 +1,172 @@
+; RUN: opt -arm-parallel-dsp -mtriple=armv7-a -S %s -o - | FileCheck %s
+
+; CHECK-LABEL: overlap_1
+; CHECK: [[ADDR_A_1:%[^ ]+]] = getelementptr i16, i16* %a, i32 1
+; CHECK: [[ADDR_B_1:%[^ ]+]] = getelementptr i16, i16* %b, i32 1
+; CHECK: [[CAST_A:%[^ ]+]] = bitcast i16* %a to i32*
+; CHECK: [[LD_A:%[^ ]+]] = load i32, i32* [[CAST_A]]
+; CHECK: [[CAST_B:%[^ ]+]] = bitcast i16* %b to i32*
+; CHECK: [[LD_B:%[^ ]+]] = load i32, i32* [[CAST_B]]
+; CHECK: [[CAST_A_1:%[^ ]+]] = bitcast i16* [[ADDR_A_1]] to i32*
+; CHECK: [[LD_A_1:%[^ ]+]] = load i32, i32* [[CAST_A_1]]
+; CHECK: [[CAST_B_1:%[^ ]+]] = bitcast i16* [[ADDR_B_1]] to i32*
+; CHECK: [[LD_B_1:%[^ ]+]] = load i32, i32* [[CAST_B_1]]
+; CHECK: [[ACC:%[^ ]+]] = call i32 @llvm.arm.smlad(i32 [[LD_A_1]], i32 [[LD_B_1]], i32 %acc)
+; CHECK: [[RES:%[^ ]+]] = call i32 @llvm.arm.smlad(i32 [[LD_A]], i32 [[LD_B]], i32 [[ACC]])
+; CHECK: ret i32 [[RES]]
+define i32 @overlap_1(i16* %a, i16* %b, i32 %acc) {
+entry:
+ %addr.a.1 = getelementptr i16, i16* %a, i32 1
+ %addr.b.1 = getelementptr i16, i16* %b, i32 1
+ %ld.a.0 = load i16, i16* %a
+ %sext.a.0 = sext i16 %ld.a.0 to i32
+ %ld.b.0 = load i16, i16* %b
+ %ld.a.1 = load i16, i16* %addr.a.1
+ %ld.b.1 = load i16, i16* %addr.b.1
+ %sext.a.1 = sext i16 %ld.a.1 to i32
+ %sext.b.1 = sext i16 %ld.b.1 to i32
+ %sext.b.0 = sext i16 %ld.b.0 to i32
+ %mul.0 = mul i32 %sext.a.0, %sext.b.0
+ %mul.1 = mul i32 %sext.a.1, %sext.b.1
+ %addr.a.2 = getelementptr i16, i16* %a, i32 2
+ %addr.b.2 = getelementptr i16, i16* %b, i32 2
+ %ld.a.2 = load i16, i16* %addr.a.2
+ %ld.b.2 = load i16, i16* %addr.b.2
+ %sext.a.2 = sext i16 %ld.a.2 to i32
+ %sext.b.2 = sext i16 %ld.b.2 to i32
+ %mul.2 = mul i32 %sext.a.2, %sext.b.2
+ %add = add i32 %mul.0, %mul.1
+ %add.1 = add i32 %mul.1, %mul.2
+ %add.2 = add i32 %add.1, %add
+ %res = add i32 %add.2, %acc
+ ret i32 %res
+}
+
+; CHECK-LABEL: overlap_2
+; CHECK: [[ADDR_A_1:%[^ ]+]] = getelementptr i16, i16* %a, i32 1
+; CHECK: [[ADDR_B_1:%[^ ]+]] = getelementptr i16, i16* %b, i32 1
+; CHECK: [[CAST_A:%[^ ]+]] = bitcast i16* %a to i32*
+; CHECK: [[LD_A:%[^ ]+]] = load i32, i32* [[CAST_A]]
+; CHECK: [[CAST_B:%[^ ]+]] = bitcast i16* %b to i32*
+; CHECK: [[LD_B:%[^ ]+]] = load i32, i32* [[CAST_B]]
+; CHECK: [[ACC1:%[^ ]+]] = add i32 %mul.1, %acc
+; CHECK: [[ACC2:%[^ ]+]] = add i32 %mul.2, [[ACC1]]
+; CHECK: [[RES:%[^ ]+]] = call i32 @llvm.arm.smlad(i32 [[LD_A]], i32 [[LD_B]], i32 [[ACC2]])
+; CHECK: ret i32 [[RES]]
+define i32 @overlap_2(i16* %a, i16* %b, i32 %acc) {
+entry:
+ %addr.a.1 = getelementptr i16, i16* %a, i32 1
+ %addr.b.1 = getelementptr i16, i16* %b, i32 1
+ %ld.a.0 = load i16, i16* %a
+ %sext.a.0 = sext i16 %ld.a.0 to i32
+ %ld.b.0 = load i16, i16* %b
+ %ld.a.1 = load i16, i16* %addr.a.1
+ %ld.b.1 = load i16, i16* %addr.b.1
+ %sext.a.1 = sext i16 %ld.a.1 to i32
+ %sext.b.1 = sext i16 %ld.b.1 to i32
+ %sext.b.0 = sext i16 %ld.b.0 to i32
+ %mul.0 = mul i32 %sext.a.0, %sext.b.0
+ %mul.1 = mul i32 %sext.a.1, %sext.b.1
+ %addr.a.2 = getelementptr i16, i16* %a, i32 2
+ %addr.b.2 = getelementptr i16, i16* %b, i32 2
+ %ld.a.2 = load i16, i16* %addr.a.2
+ %ld.b.2 = load i16, i16* %addr.b.2
+ %sext.a.2 = sext i16 %ld.a.2 to i32
+ %sext.b.2 = sext i16 %ld.b.2 to i32
+ %mul.2 = mul i32 %sext.b.2, %sext.a.2
+ %add = add i32 %mul.0, %mul.1
+ %add.1 = add i32 %mul.1, %mul.2
+ %add.2 = add i32 %add, %add.1
+ %res = add i32 %add.2, %acc
+ ret i32 %res
+}
+
+; CHECK-LABEL: overlap_3
+; CHECK: [[GEP_B:%[^ ]+]] = getelementptr i16, i16* %b, i32 1
+; CHECK: [[CAST_A:%[^ ]+]] = bitcast i16* %a to i32*
+; CHECK: [[LD_A:%[^ ]+]] = load i32, i32* [[CAST_A]]
+; CHECK: [[CAST_B:%[^ ]+]] = bitcast i16* %b to i32*
+; CHECK: [[LD_B:%[^ ]+]] = load i32, i32* [[CAST_B]]
+; CHECK: [[CAST_B_1:%[^ ]+]] = bitcast i16* [[GEP_B]] to i32*
+; CHECK: [[LD_B_1:%[^ ]+]] = load i32, i32* [[CAST_B_1]]
+; CHECK: [[GEP_A:%[^ ]+]] = getelementptr i16, i16* %a, i32 2
+; CHECK: [[CAST_A_2:%[^ ]+]] = bitcast i16* [[GEP_A]] to i32*
+; CHECK: [[LD_A_2:%[^ ]+]] = load i32, i32* [[CAST_A_2]]
+; CHECK: [[SMLAD:%[^ ]+]] = call i32 @llvm.arm.smlad(i32 [[LD_A_2]], i32 [[LD_B_1]], i32 %acc)
+; CHECK: call i32 @llvm.arm.smlad(i32 [[LD_A]], i32 [[LD_B]], i32 [[SMLAD]])
+define i32 @overlap_3(i16* %a, i16* %b, i32 %acc) {
+entry:
+ %addr.a.1 = getelementptr i16, i16* %a, i32 1
+ %addr.b.1 = getelementptr i16, i16* %b, i32 1
+ %ld.a.0 = load i16, i16* %a
+ %sext.a.0 = sext i16 %ld.a.0 to i32
+ %ld.b.0 = load i16, i16* %b
+ %ld.a.1 = load i16, i16* %addr.a.1
+ %ld.b.1 = load i16, i16* %addr.b.1
+ %sext.a.1 = sext i16 %ld.a.1 to i32
+ %sext.b.1 = sext i16 %ld.b.1 to i32
+ %sext.b.0 = sext i16 %ld.b.0 to i32
+ %mul.0 = mul i32 %sext.a.0, %sext.b.0
+ %mul.1 = mul i32 %sext.a.1, %sext.b.1
+ %addr.a.2 = getelementptr i16, i16* %a, i32 2
+ %addr.b.2 = getelementptr i16, i16* %b, i32 2
+ %addr.a.3 = getelementptr i16, i16* %a, i32 3
+ %ld.a.2 = load i16, i16* %addr.a.2
+ %ld.b.2 = load i16, i16* %addr.b.2
+ %ld.a.3 = load i16, i16* %addr.a.3
+ %sext.a.2 = sext i16 %ld.a.2 to i32
+ %sext.b.2 = sext i16 %ld.b.2 to i32
+ %sext.a.3 = sext i16 %ld.a.3 to i32
+ %mul.2 = mul i32 %sext.a.2, %sext.b.1
+ %mul.3 = mul i32 %sext.a.3, %sext.b.2
+ %add = add i32 %mul.0, %mul.1
+ %add.1 = add i32 %mul.2, %mul.3
+ %add.2 = add i32 %add.1, %add
+ %res = add i32 %add.2, %acc
+ ret i32 %res
+}
+
+; CHECK-LABEL: overlap_4
+; CHECK: [[GEP_B:%[^ ]+]] = getelementptr i16, i16* %b, i32 1
+; CHECK: [[CAST_A:%[^ ]+]] = bitcast i16* %a to i32*
+; CHECK: [[LD_A:%[^ ]+]] = load i32, i32* [[CAST_A]]
+; CHECK: [[CAST_B:%[^ ]+]] = bitcast i16* %b to i32*
+; CHECK: [[LD_B:%[^ ]+]] = load i32, i32* [[CAST_B]]
+; CHECK: [[CAST_B_1:%[^ ]+]] = bitcast i16* [[GEP_B]] to i32*
+; CHECK: [[LD_B_1:%[^ ]+]] = load i32, i32* [[CAST_B_1]]
+; CHECK: [[GEP_A:%[^ ]+]] = getelementptr i16, i16* %a, i32 2
+; CHECK: [[CAST_A_2:%[^ ]+]] = bitcast i16* [[GEP_A]] to i32*
+; CHECK: [[LD_A_2:%[^ ]+]] = load i32, i32* [[CAST_A_2]]
+; CHECK: [[SMLAD:%[^ ]+]] = call i32 @llvm.arm.smladx(i32 [[LD_A_2]], i32 [[LD_B_1]], i32 %acc)
+; CHECK: call i32 @llvm.arm.smlad(i32 [[LD_A]], i32 [[LD_B]], i32 [[SMLAD]])
+define i32 @overlap_4(i16* %a, i16* %b, i32 %acc) {
+entry:
+ %addr.a.1 = getelementptr i16, i16* %a, i32 1
+ %addr.b.1 = getelementptr i16, i16* %b, i32 1
+ %ld.a.0 = load i16, i16* %a
+ %sext.a.0 = sext i16 %ld.a.0 to i32
+ %ld.b.0 = load i16, i16* %b
+ %ld.a.1 = load i16, i16* %addr.a.1
+ %ld.b.1 = load i16, i16* %addr.b.1
+ %sext.a.1 = sext i16 %ld.a.1 to i32
+ %sext.b.1 = sext i16 %ld.b.1 to i32
+ %sext.b.0 = sext i16 %ld.b.0 to i32
+ %mul.0 = mul i32 %sext.a.0, %sext.b.0
+ %mul.1 = mul i32 %sext.a.1, %sext.b.1
+ %addr.a.2 = getelementptr i16, i16* %a, i32 2
+ %addr.b.2 = getelementptr i16, i16* %b, i32 2
+ %addr.a.3 = getelementptr i16, i16* %a, i32 3
+ %ld.a.2 = load i16, i16* %addr.a.2
+ %ld.b.2 = load i16, i16* %addr.b.2
+ %ld.a.3 = load i16, i16* %addr.a.3
+ %sext.a.2 = sext i16 %ld.a.2 to i32
+ %sext.b.2 = sext i16 %ld.b.2 to i32
+ %sext.a.3 = sext i16 %ld.a.3 to i32
+ %mul.2 = mul i32 %sext.b.2, %sext.a.2
+ %mul.3 = mul i32 %sext.b.1, %sext.a.3
+ %add = add i32 %mul.0, %mul.1
+ %add.1 = add i32 %mul.2, %mul.3
+ %add.2 = add i32 %add.1, %add
+ %res = add i32 %add.2, %acc
+ ret i32 %res
+}
diff --git a/llvm/test/CodeGen/ARM/ParallelDSP/pr42729.ll b/llvm/test/CodeGen/ARM/ParallelDSP/pr42729.ll
index e422ead..9f032cd 100644
--- a/llvm/test/CodeGen/ARM/ParallelDSP/pr42729.ll
+++ b/llvm/test/CodeGen/ARM/ParallelDSP/pr42729.ll
@@ -9,7 +9,7 @@
; CHECK: [[GEP16:%[^ ]+]] = getelementptr i16, i16* [[CAST_GEP8]], i32 6
; CHECK: [[CAST_GEP16:%[^ ]+]] = bitcast i16* [[GEP16]] to i32*
; CHECK: [[LOAD_UNDEF:%[^ ]+]] = load i32, i32* [[CAST_GEP16]], align 2
-; CHECK: call i32 @llvm.arm.smladx(i32 [[LOAD_A]], i32 [[LOAD_UNDEF]], i32 undef)
+; CHECK: call i32 @llvm.arm.smladx(i32 [[LOAD_UNDEF]], i32 [[LOAD_A]], i32 undef)
define void @undef_no_return(i16* %a) {
entry:
%incdec.ptr21 = getelementptr inbounds i16, i16* %a, i32 3
@@ -48,7 +48,7 @@
; CHECK: [[GEP16:%[^ ]+]] = getelementptr i16, i16* [[CAST_GEP8]], i32 %iv
; CHECK: [[CAST_GEP16:%[^ ]+]] = bitcast i16* [[GEP16]] to i32*
; CHECK: [[LOAD_B:%[^ ]+]] = load i32, i32* [[CAST_GEP16]], align 2
-; CHECK: [[ACC_NEXT]] = call i32 @llvm.arm.smladx(i32 [[LOAD_A]], i32 [[LOAD_B]], i32 [[ACC]])
+; CHECK: [[ACC_NEXT]] = call i32 @llvm.arm.smladx(i32 [[LOAD_B]], i32 [[LOAD_A]], i32 [[ACC]])
define i32 @return(i16* %a, i8* %b, i32 %N) {
entry:
%incdec.ptr21 = getelementptr inbounds i16, i16* %a, i32 3
diff --git a/llvm/test/CodeGen/ARM/ParallelDSP/pr43073.ll b/llvm/test/CodeGen/ARM/ParallelDSP/pr43073.ll
new file mode 100644
index 0000000..a2f4745
--- /dev/null
+++ b/llvm/test/CodeGen/ARM/ParallelDSP/pr43073.ll
@@ -0,0 +1,145 @@
+; RUN: opt -mtriple=thumbv7-unknown-linux-gnueabihf -arm-parallel-dsp -dce %s -S -o - | FileCheck %s
+
+; CHECK-LABEL: first_mul_invalid
+; CHECK: [[ADDR_IN_MINUS_1:%[^ ]+]] = getelementptr inbounds i16, i16* %in, i32 -1
+; CHECK: [[LD_IN_MINUS_1:%[^ ]+]] = load i16, i16* [[ADDR_IN_MINUS_1]], align 2
+; CHECK: [[IN_MINUS_1:%[^ ]+]] = sext i16 [[LD_IN_MINUS_1]] to i32
+; CHECK: [[ADDR_B_PLUS_1:%[^ ]+]] = getelementptr inbounds i16, i16* %b, i32 1
+; CHECK: [[LD_B_PLUS_1:%[^ ]+]] = load i16, i16* [[ADDR_B_PLUS_1]], align 2
+; CHECK: [[B_PLUS_1:%[^ ]+]] = sext i16 [[LD_B_PLUS_1]] to i32
+; CHECK: [[MUL0:%[^ ]+]] = mul nsw i32 [[B_PLUS_1]], [[IN_MINUS_1]]
+; CHECK: [[ADD0:%[^ ]+]] = add i32 [[MUL0]], %call
+; CHECK: [[ADDR_IN_MINUS_3:%[^ ]+]] = getelementptr inbounds i16, i16* %in, i32 -3
+; CHECK: [[CAST_ADDR_IN_MINUS_3:%[^ ]+]] = bitcast i16* [[ADDR_IN_MINUS_3]] to i32*
+; CHECK: [[IN_MINUS_3:%[^ ]+]] = load i32, i32* [[CAST_ADDR_IN_MINUS_3]], align 2
+; CHECK: [[ADDR_B_PLUS_2:%[^ ]+]] = getelementptr inbounds i16, i16* %b, i32 2
+; CHECK: [[CAST_ADDR_B_PLUS_2:%[^ ]+]] = bitcast i16* [[ADDR_B_PLUS_2]] to i32*
+; CHECK: [[B_PLUS_2:%[^ ]+]] = load i32, i32* [[CAST_ADDR_B_PLUS_2]], align 2
+; CHECK: [[ADDR_IN_MINUS_5:%[^ ]+]] = getelementptr inbounds i16, i16* %in, i32 -5
+; CHECK: [[CAST_ADDR_IN_MINUS_5:%[^ ]+]] = bitcast i16* [[ADDR_IN_MINUS_5]] to i32*
+; CHECK: [[IN_MINUS_5:%[^ ]+]] = load i32, i32* [[CAST_ADDR_IN_MINUS_5]], align 2
+; CHECK: [[ADDR_B_PLUS_4:%[^ ]+]] = getelementptr inbounds i16, i16* %b, i32 4
+; CHECK: [[CAST_ADDR_B_PLUS_4:%[^ ]+]] = bitcast i16* [[ADDR_B_PLUS_4]] to i32*
+; CHECK: [[B_PLUS_4:%[^ ]+]] = load i32, i32* [[CAST_ADDR_B_PLUS_4]], align 2
+; CHECK: [[ACC:%[^ ]+]] = call i32 @llvm.arm.smladx(i32 [[IN_MINUS_5]], i32 [[B_PLUS_4]], i32 [[ADD0]])
+; CHECK: [[RES:%[^ ]+]] = call i32 @llvm.arm.smladx(i32 [[IN_MINUS_3]], i32 [[B_PLUS_2]], i32 [[ACC]])
+; CHECK: ret i32 [[RES]]
+define i32 @first_mul_invalid(i16* nocapture readonly %in, i16* nocapture readonly %b) {
+entry:
+ %0 = load i16, i16* %in, align 2
+ %conv = sext i16 %0 to i32
+ %1 = load i16, i16* %b, align 2
+ %conv2 = sext i16 %1 to i32
+ %call = tail call i32 @bar(i32 %conv, i32 %conv2)
+ %arrayidx3 = getelementptr inbounds i16, i16* %in, i32 -1
+ %2 = load i16, i16* %arrayidx3, align 2
+ %conv4 = sext i16 %2 to i32
+ %arrayidx5 = getelementptr inbounds i16, i16* %b, i32 1
+ %3 = load i16, i16* %arrayidx5, align 2
+ %conv6 = sext i16 %3 to i32
+ %mul = mul nsw i32 %conv6, %conv4
+ %add = add i32 %mul, %call
+ %arrayidx7 = getelementptr inbounds i16, i16* %in, i32 -2
+ %4 = load i16, i16* %arrayidx7, align 2
+ %conv8 = sext i16 %4 to i32
+ %arrayidx9 = getelementptr inbounds i16, i16* %b, i32 2
+ %5 = load i16, i16* %arrayidx9, align 2
+ %conv10 = sext i16 %5 to i32
+ %mul11 = mul nsw i32 %conv10, %conv8
+ %add12 = add i32 %add, %mul11
+ %arrayidx13 = getelementptr inbounds i16, i16* %in, i32 -3
+ %6 = load i16, i16* %arrayidx13, align 2
+ %conv14 = sext i16 %6 to i32
+ %arrayidx15 = getelementptr inbounds i16, i16* %b, i32 3
+ %7 = load i16, i16* %arrayidx15, align 2
+ %conv16 = sext i16 %7 to i32
+ %mul17 = mul nsw i32 %conv16, %conv14
+ %add18 = add i32 %add12, %mul17
+ %arrayidx19 = getelementptr inbounds i16, i16* %in, i32 -4
+ %8 = load i16, i16* %arrayidx19, align 2
+ %conv20 = sext i16 %8 to i32
+ %arrayidx21 = getelementptr inbounds i16, i16* %b, i32 4
+ %9 = load i16, i16* %arrayidx21, align 2
+ %conv22 = sext i16 %9 to i32
+ %mul23 = mul nsw i32 %conv22, %conv20
+ %add24 = add i32 %add18, %mul23
+ %arrayidx25 = getelementptr inbounds i16, i16* %in, i32 -5
+ %10 = load i16, i16* %arrayidx25, align 2
+ %conv26 = sext i16 %10 to i32
+ %arrayidx27 = getelementptr inbounds i16, i16* %b, i32 5
+ %11 = load i16, i16* %arrayidx27, align 2
+ %conv28 = sext i16 %11 to i32
+ %mul29 = mul nsw i32 %conv28, %conv26
+ %add30 = add i32 %add24, %mul29
+ ret i32 %add30
+}
+
+; CHECK-LABEL: with_no_acc_input
+; CHECK: [[ADDR_IN_MINUS_1:%[^ ]+]] = getelementptr inbounds i16, i16* %in, i32 -1
+; CHECK: [[LD_IN_MINUS_1:%[^ ]+]] = load i16, i16* [[ADDR_IN_MINUS_1]], align 2
+; CHECK: [[IN_MINUS_1:%[^ ]+]] = sext i16 [[LD_IN_MINUS_1]] to i32
+; CHECK: [[ADDR_B_PLUS_1:%[^ ]+]] = getelementptr inbounds i16, i16* %b, i32 1
+; CHECK: [[LD_B_PLUS_1:%[^ ]+]] = load i16, i16* [[ADDR_B_PLUS_1]], align 2
+; CHECK: [[B_PLUS_1:%[^ ]+]] = sext i16 [[LD_B_PLUS_1]] to i32
+; CHECK: [[MUL0:%[^ ]+]] = mul nsw i32 [[B_PLUS_1]], [[IN_MINUS_1]]
+; CHECK: [[ADDR_IN_MINUS_3:%[^ ]+]] = getelementptr inbounds i16, i16* %in, i32 -3
+; CHECK: [[CAST_ADDR_IN_MINUS_3:%[^ ]+]] = bitcast i16* [[ADDR_IN_MINUS_3]] to i32*
+; CHECK: [[IN_MINUS_3:%[^ ]+]] = load i32, i32* [[CAST_ADDR_IN_MINUS_3]], align 2
+; CHECK: [[ADDR_B_PLUS_2:%[^ ]+]] = getelementptr inbounds i16, i16* %b, i32 2
+; CHECK: [[CAST_ADDR_B_PLUS_2:%[^ ]+]] = bitcast i16* [[ADDR_B_PLUS_2]] to i32*
+; CHECK: [[B_PLUS_2:%[^ ]+]] = load i32, i32* [[CAST_ADDR_B_PLUS_2]], align 2
+; CHECK: [[ADDR_IN_MINUS_5:%[^ ]+]] = getelementptr inbounds i16, i16* %in, i32 -5
+; CHECK: [[CAST_ADDR_IN_MINUS_5:%[^ ]+]] = bitcast i16* [[ADDR_IN_MINUS_5]] to i32*
+; CHECK: [[IN_MINUS_5:%[^ ]+]] = load i32, i32* [[CAST_ADDR_IN_MINUS_5]], align 2
+; CHECK: [[ADDR_B_PLUS_4:%[^ ]+]] = getelementptr inbounds i16, i16* %b, i32 4
+; CHECK: [[CAST_ADDR_B_PLUS_4:%[^ ]+]] = bitcast i16* [[ADDR_B_PLUS_4]] to i32*
+; CHECK: [[B_PLUS_4:%[^ ]+]] = load i32, i32* [[CAST_ADDR_B_PLUS_4]], align 2
+; CHECK: [[ACC:%[^ ]+]] = call i32 @llvm.arm.smladx(i32 [[IN_MINUS_5]], i32 [[B_PLUS_4]], i32 [[MUL0]])
+; CHECK: [[RES:%[^ ]+]] = call i32 @llvm.arm.smladx(i32 [[IN_MINUS_3]], i32 [[B_PLUS_2]], i32 [[ACC]])
+; CHECK: ret i32 [[RES]]
+define i32 @with_no_acc_input(i16* nocapture readonly %in, i16* nocapture readonly %b) {
+entry:
+ %arrayidx3 = getelementptr inbounds i16, i16* %in, i32 -1
+ %ld.2 = load i16, i16* %arrayidx3, align 2
+ %conv4 = sext i16 %ld.2 to i32
+ %arrayidx5 = getelementptr inbounds i16, i16* %b, i32 1
+ %ld.3 = load i16, i16* %arrayidx5, align 2
+ %conv6 = sext i16 %ld.3 to i32
+ %mul = mul nsw i32 %conv6, %conv4
+ %arrayidx7 = getelementptr inbounds i16, i16* %in, i32 -2
+ %ld.4 = load i16, i16* %arrayidx7, align 2
+ %conv8 = sext i16 %ld.4 to i32
+ %arrayidx9 = getelementptr inbounds i16, i16* %b, i32 2
+ %ld.5 = load i16, i16* %arrayidx9, align 2
+ %conv10 = sext i16 %ld.5 to i32
+ %mul11 = mul nsw i32 %conv10, %conv8
+ %add12 = add i32 %mul, %mul11
+ %arrayidx13 = getelementptr inbounds i16, i16* %in, i32 -3
+ %ld.6 = load i16, i16* %arrayidx13, align 2
+ %conv14 = sext i16 %ld.6 to i32
+ %arrayidx15 = getelementptr inbounds i16, i16* %b, i32 3
+ %ld.7 = load i16, i16* %arrayidx15, align 2
+ %conv16 = sext i16 %ld.7 to i32
+ %mul17 = mul nsw i32 %conv16, %conv14
+ %add18 = add i32 %add12, %mul17
+ %arrayidx19 = getelementptr inbounds i16, i16* %in, i32 -4
+ %ld.8 = load i16, i16* %arrayidx19, align 2
+ %conv20 = sext i16 %ld.8 to i32
+ %arrayidx21 = getelementptr inbounds i16, i16* %b, i32 4
+ %ld.9 = load i16, i16* %arrayidx21, align 2
+ %conv22 = sext i16 %ld.9 to i32
+ %mul23 = mul nsw i32 %conv22, %conv20
+ %add24 = add i32 %add18, %mul23
+ %arrayidx25 = getelementptr inbounds i16, i16* %in, i32 -5
+ %ld.10 = load i16, i16* %arrayidx25, align 2
+ %conv26 = sext i16 %ld.10 to i32
+ %arrayidx27 = getelementptr inbounds i16, i16* %b, i32 5
+ %ld.11 = load i16, i16* %arrayidx27, align 2
+ %conv28 = sext i16 %ld.11 to i32
+ %mul29 = mul nsw i32 %conv28, %conv26
+ %add30 = add i32 %add24, %mul29
+ ret i32 %add30
+}
+
+declare dso_local i32 @bar(i32, i32) local_unnamed_addr
+
diff --git a/llvm/test/CodeGen/ARM/ParallelDSP/smlad11.ll b/llvm/test/CodeGen/ARM/ParallelDSP/smlad11.ll
index b17106e..22744be 100644
--- a/llvm/test/CodeGen/ARM/ParallelDSP/smlad11.ll
+++ b/llvm/test/CodeGen/ARM/ParallelDSP/smlad11.ll
@@ -12,8 +12,8 @@
; CHECK: [[V9:%[0-9]+]] = load i32, i32* [[V8]], align 2
; CHECK: [[V13:%[0-9]+]] = bitcast i16* %arrayidx17 to i32*
; CHECK: [[V14:%[0-9]+]] = load i32, i32* [[V13]], align 2
-; CHECK: [[V12:%[0-9]+]] = call i32 @llvm.arm.smlad(i32 [[V9]], i32 [[V11]], i32 %mac1{{\.}}054)
-; CHECK: [[V17:%[0-9]+]] = call i32 @llvm.arm.smlad(i32 [[V14]], i32 [[V16]], i32 [[V12]])
+; CHECK: [[V12:%[0-9]+]] = call i32 @llvm.arm.smlad(i32 [[V14]], i32 [[V16]], i32 %mac1{{\.}}054)
+; CHECK: [[V17:%[0-9]+]] = call i32 @llvm.arm.smlad(i32 [[V9]], i32 [[V11]], i32 [[V12]])
;
; And we don't want to see a 3rd smlad:
; CHECK-NOT: call i32 @llvm.arm.smlad
diff --git a/llvm/test/CodeGen/ARM/ParallelDSP/smlad12.ll b/llvm/test/CodeGen/ARM/ParallelDSP/smlad12.ll
index d4e09ca..637fc3d3 100644
--- a/llvm/test/CodeGen/ARM/ParallelDSP/smlad12.ll
+++ b/llvm/test/CodeGen/ARM/ParallelDSP/smlad12.ll
@@ -2,7 +2,7 @@
;
; The loop header is not the loop latch.
;
-; CHECK-NOT: call i32 @llvm.arm.smlad
+; CHECK: call i32 @llvm.arm.smlad
;
define dso_local i32 @test(i32 %arg, i32* nocapture readnone %arg1, i16* nocapture readonly %arg2, i16* nocapture readonly %arg3) {
entry:
diff --git a/llvm/test/CodeGen/ARM/ParallelDSP/smlaldx-2.ll b/llvm/test/CodeGen/ARM/ParallelDSP/smlaldx-2.ll
index 971c85f..07cc1b4 100644
--- a/llvm/test/CodeGen/ARM/ParallelDSP/smlaldx-2.ll
+++ b/llvm/test/CodeGen/ARM/ParallelDSP/smlaldx-2.ll
@@ -195,8 +195,8 @@
; CHECK: [[PIN1_CAST:%[^ ]+]] = bitcast i16* [[PIN1]] to i32*
; CHECK: [[IN1:%[^ ]+]] = load i32, i32* [[PIN1_CAST]], align 2
-; CHECK: [[ACC1:%[^ ]+]] = call i64 @llvm.arm.smlaldx(i32 [[IN2]], i32 [[IN1_2]], i64 [[ACC0]])
-; CHECK: [[ACC2]] = call i64 @llvm.arm.smlaldx(i32 [[IN1]], i32 [[IN2_2]], i64 [[ACC1]])
+; CHECK: [[ACC1:%[^ ]+]] = call i64 @llvm.arm.smlaldx(i32 [[IN2_2]], i32 [[IN1]], i64 [[ACC0]])
+; CHECK: [[ACC2]] = call i64 @llvm.arm.smlaldx(i32 [[IN2]], i32 [[IN1_2]], i64 [[ACC1]])
; CHECK: [[PIN1_NEXT]] = getelementptr i16, i16* [[PIN1]], i32 4
; CHECK: [[PIN2_NEXT]] = getelementptr i16, i16* [[PIN2]], i32 -4