<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=us-ascii">
<style type="text/css" style="display:none;"> P {margin-top:0;margin-bottom:0;} </style>
</head>
<body dir="ltr">
<div style="font-family: Calibri, Arial, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
Thanks Hans, sorry I've been on holiday. I think it's triggering an underlying bug, so I'll look into a proper fix today.</div>
<div style="font-family: Calibri, Arial, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
<br>
</div>
<div style="font-family: Calibri, Arial, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
Sam</div>
<div style="font-family: Calibri, Arial, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
<br>
</div>
<div id="Signature">
<div id="divtagdefaultwrapper" dir="ltr" style="font-size:12pt; color:rgb(0,0,0); background-color:rgb(255,255,255); font-family:Calibri,Arial,Helvetica,sans-serif,EmojiFont,"Apple Color Emoji","Segoe UI Emoji",NotoColorEmoji,"Segoe UI Symbol","Android Emoji",EmojiSymbols,EmojiFont,"Apple Color Emoji","Segoe UI Emoji",NotoColorEmoji,"Segoe UI Symbol","Android Emoji",EmojiSymbols">
<p style="margin-top: 0px; margin-bottom: 0px;"></p>
<p style="margin-top: 0px; margin-bottom: 0px;font-family:"Times New Roman""><span style="font-family:Calibri,Helvetica,sans-serif">Sam Parker</span></p>
<span style="font-family:Calibri,Helvetica,sans-serif"></span>
<p style="margin-top: 0px; margin-bottom: 0px;font-family:"Times New Roman""><span style="font-family:Calibri,Helvetica,sans-serif">Compilation Tools Engineer | Arm</span></p>
<span style="font-family:Calibri,Helvetica,sans-serif"></span>
<p style="margin-top: 0px; margin-bottom: 0px;font-family:"Times New Roman""><span style="font-family:Calibri,Helvetica,sans-serif">. . . . . . . . . . . . . . . . . . . . . . . . . . .</span></p>
<span style="font-family:Calibri,Helvetica,sans-serif"></span>
<p style="margin-top: 0px; margin-bottom: 0px;font-family:"Times New Roman""><span style="font-family:Calibri,Helvetica,sans-serif">Arm.com</span></p>
<p style="margin-top: 0px; margin-bottom: 0px;"></p>
</div>
</div>
<div id="appendonsend"></div>
<hr style="display:inline-block;width:98%" tabindex="-1">
<div id="divRplyFwdMsg" dir="ltr"><font face="Calibri, sans-serif" style="font-size:11pt" color="#000000"><b>From:</b> Hans Wennborg <hans@chromium.org><br>
<b>Sent:</b> 21 August 2019 14:09<br>
<b>To:</b> Sam Parker <Sam.Parker@arm.com><br>
<b>Cc:</b> llvm-commits <llvm-commits@lists.llvm.org><br>
<b>Subject:</b> Re: [llvm] r367389 - [ARM][ParallelDSP] Convert to function pass</font>
<div> </div>
</div>
<div class="BodyFragment"><font size="2"><span style="font-size:11pt;">
<div class="PlainText">It does look like a miscompile. Filed<br>
<a href="https://bugs.llvm.org/show_bug.cgi?id=43073">https://bugs.llvm.org/show_bug.cgi?id=43073</a><br>
<br>
On Mon, Aug 19, 2019 at 6:06 PM Hans Wennborg <hans@chromium.org> wrote:<br>
><br>
> Just a heads up that we bisected a regression in Chromium (really<br>
> WebRTC) to this revision:<br>
> <a href="https://bugs.chromium.org/p/webrtc/issues/detail?id=10887">https://bugs.chromium.org/p/webrtc/issues/detail?id=10887</a><br>
><br>
> We still don't know what's wrong, and the problem could lie in the<br>
> WebRTC code, but I wanted to give a heads up that this affected our<br>
> code.<br>
><br>
> On Wed, Jul 31, 2019 at 9:31 AM Sam Parker via llvm-commits<br>
> <llvm-commits@lists.llvm.org> wrote:<br>
> ><br>
> > Author: sam_parker<br>
> > Date: Wed Jul 31 00:32:03 2019<br>
> > New Revision: 367389<br>
> ><br>
> > URL: <a href="http://llvm.org/viewvc/llvm-project?rev=367389&view=rev">http://llvm.org/viewvc/llvm-project?rev=367389&view=rev</a><br>
> > Log:<br>
> > [ARM][ParallelDSP] Convert to function pass<br>
> ><br>
> > Run across a whole function, visiting each basic block one at a time.<br>
> ><br>
> > Differential Revision: <a href="https://reviews.llvm.org/D65324">https://reviews.llvm.org/D65324</a><br>
> ><br>
> > Added:<br>
> >     llvm/trunk/test/CodeGen/ARM/ParallelDSP/blocks.ll<br>
> > Modified:<br>
> >     llvm/trunk/lib/Target/ARM/ARMParallelDSP.cpp<br>
> >     llvm/trunk/test/CodeGen/ARM/O3-pipeline.ll<br>
> >     llvm/trunk/test/CodeGen/ARM/ParallelDSP/smlad12.ll<br>
> ><br>
> > Modified: llvm/trunk/lib/Target/ARM/ARMParallelDSP.cpp<br>
> > URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMParallelDSP.cpp?rev=367389&r1=367388&r2=367389&view=diff">
http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMParallelDSP.cpp?rev=367389&r1=367388&r2=367389&view=diff</a><br>
> > ==============================================================================<br>
> > --- llvm/trunk/lib/Target/ARM/ARMParallelDSP.cpp (original)<br>
> > +++ llvm/trunk/lib/Target/ARM/ARMParallelDSP.cpp Wed Jul 31 00:32:03 2019<br>
> > @@ -1,4 +1,4 @@<br>
> > -//===- ParallelDSP.cpp - Parallel DSP Pass --------------------------------===//<br>
> > +//===- ARMParallelDSP.cpp - Parallel DSP Pass -----------------------------===//<br>
> >  //<br>
> >  // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.<br>
> >  // See <a href="https://llvm.org/LICENSE.txt">https://llvm.org/LICENSE.txt</a> for license information.<br>
> > @@ -18,13 +18,10 @@<br>
> >  #include "llvm/ADT/SmallPtrSet.h"<br>
> >  #include "llvm/Analysis/AliasAnalysis.h"<br>
> >  #include "llvm/Analysis/LoopAccessAnalysis.h"<br>
> > -#include "llvm/Analysis/LoopPass.h"<br>
> > -#include "llvm/Analysis/LoopInfo.h"<br>
> >  #include "llvm/IR/Instructions.h"<br>
> >  #include "llvm/IR/NoFolder.h"<br>
> >  #include "llvm/Transforms/Scalar.h"<br>
> >  #include "llvm/Transforms/Utils/BasicBlockUtils.h"<br>
> > -#include "llvm/Transforms/Utils/LoopUtils.h"<br>
> >  #include "llvm/Pass.h"<br>
> >  #include "llvm/PassRegistry.h"<br>
> >  #include "llvm/PassSupport.h"<br>
> > @@ -156,13 +153,11 @@ namespace {<br>
> >      }<br>
> >    };<br>
> ><br>
> > -  class ARMParallelDSP : public LoopPass {<br>
> > +  class ARMParallelDSP : public FunctionPass {<br>
> >      ScalarEvolution   *SE;<br>
> >      AliasAnalysis     *AA;<br>
> >      TargetLibraryInfo *TLI;<br>
> >      DominatorTree     *DT;<br>
> > -    LoopInfo          *LI;<br>
> > -    Loop              *L;<br>
> >      const DataLayout  *DL;<br>
> >      Module            *M;<br>
> >      std::map<LoadInst*, LoadInst*> LoadPairs;<br>
> > @@ -184,63 +179,38 @@ namespace {<br>
> >      /// products to a 32-bit accumulate operand. Optionally, the instruction can<br>
> >      /// exchange the halfwords of the second operand before performing the<br>
> >      /// arithmetic.<br>
> > -    bool MatchSMLAD(Loop *L);<br>
> > +    bool MatchSMLAD(Function &F);<br>
> ><br>
> >    public:<br>
> >      static char ID;<br>
> ><br>
> > -    ARMParallelDSP() : LoopPass(ID) { }<br>
> > -<br>
> > -    bool doInitialization(Loop *L, LPPassManager &LPM) override {<br>
> > -      LoadPairs.clear();<br>
> > -      WideLoads.clear();<br>
> > -      return true;<br>
> > -    }<br>
> > +    ARMParallelDSP() : FunctionPass(ID) { }<br>
> ><br>
> >      void getAnalysisUsage(AnalysisUsage &AU) const override {<br>
> > -      LoopPass::getAnalysisUsage(AU);<br>
> > +      FunctionPass::getAnalysisUsage(AU);<br>
> >        AU.addRequired<AssumptionCacheTracker>();<br>
> >        AU.addRequired<ScalarEvolutionWrapperPass>();<br>
> >        AU.addRequired<AAResultsWrapperPass>();<br>
> >        AU.addRequired<TargetLibraryInfoWrapperPass>();<br>
> > -      AU.addRequired<LoopInfoWrapperPass>();<br>
> >        AU.addRequired<DominatorTreeWrapperPass>();<br>
> >        AU.addRequired<TargetPassConfig>();<br>
> > -      AU.addPreserved<LoopInfoWrapperPass>();<br>
> > +      AU.addPreserved<ScalarEvolutionWrapperPass>();<br>
> > +      AU.addPreserved<GlobalsAAWrapperPass>();<br>
> >        AU.setPreservesCFG();<br>
> >      }<br>
> ><br>
> > -    bool runOnLoop(Loop *TheLoop, LPPassManager &) override {<br>
> > +    bool runOnFunction(Function &F) override {<br>
> >        if (DisableParallelDSP)<br>
> >          return false;<br>
> > -      if (skipLoop(TheLoop))<br>
> > +      if (skipFunction(F))<br>
> >          return false;<br>
> ><br>
> > -      L = TheLoop;<br>
> >        SE = &getAnalysis<ScalarEvolutionWrapperPass>().getSE();<br>
> >        AA = &getAnalysis<AAResultsWrapperPass>().getAAResults();<br>
> >        TLI = &getAnalysis<TargetLibraryInfoWrapperPass>().getTLI();<br>
> >        DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree();<br>
> > -      LI = &getAnalysis<LoopInfoWrapperPass>().getLoopInfo();<br>
> >        auto &TPC = getAnalysis<TargetPassConfig>();<br>
> ><br>
> > -      BasicBlock *Header = TheLoop->getHeader();<br>
> > -      if (!Header)<br>
> > -        return false;<br>
> > -<br>
> > -      // TODO: We assume the loop header and latch to be the same block.<br>
> > -      // This is not a fundamental restriction, but lifting this would just<br>
> > -      // require more work to do the transformation and then patch up the CFG.<br>
> > -      if (Header != TheLoop->getLoopLatch()) {<br>
> > -        LLVM_DEBUG(dbgs() << "The loop header is not the loop latch: not "<br>
> > -                             "running pass ARMParallelDSP\n");<br>
> > -        return false;<br>
> > -      }<br>
> > -<br>
> > -      if (!TheLoop->getLoopPreheader())<br>
> > -        InsertPreheaderForLoop(L, DT, LI, nullptr, true);<br>
> > -<br>
> > -      Function &F = *Header->getParent();<br>
> >        M = F.getParent();<br>
> >        DL = &M->getDataLayout();<br>
> ><br>
> > @@ -265,17 +235,10 @@ namespace {<br>
> >          return false;<br>
> >        }<br>
> ><br>
> > -      LoopAccessInfo LAI(L, SE, TLI, AA, DT, LI);<br>
> > -<br>
> >        LLVM_DEBUG(dbgs() << "\n== Parallel DSP pass ==\n");<br>
> >        LLVM_DEBUG(dbgs() << " - " << F.getName() << "\n\n");<br>
> ><br>
> > -      if (!RecordMemoryOps(Header)) {<br>
> > -        LLVM_DEBUG(dbgs() << " - No sequential loads found.\n");<br>
> > -        return false;<br>
> > -      }<br>
> > -<br>
> > -      bool Changes = MatchSMLAD(L);<br>
> > +      bool Changes = MatchSMLAD(F);<br>
> >        return Changes;<br>
> >      }<br>
> >    };<br>
> > @@ -337,6 +300,8 @@ bool ARMParallelDSP::IsNarrowSequence(Va<br>
> >  bool ARMParallelDSP::RecordMemoryOps(BasicBlock *BB) {<br>
> >    SmallVector<LoadInst*, 8> Loads;<br>
> >    SmallVector<Instruction*, 8> Writes;<br>
> > +  LoadPairs.clear();<br>
> > +  WideLoads.clear();<br>
> ><br>
> >    // Collect loads and instruction that may write to memory. For now we only<br>
> >    // record loads which are simple, sign-extended and have a single user.<br>
> > @@ -415,7 +380,7 @@ bool ARMParallelDSP::RecordMemoryOps(Bas<br>
> >    return LoadPairs.size() > 1;<br>
> >  }<br>
> ><br>
> > -// Loop Pass that needs to identify integer add/sub reductions of 16-bit vector<br>
> > +// The pass needs to identify integer add/sub reductions of 16-bit vector<br>
> >  // multiplications.<br>
> >  // To use SMLAD:<br>
> >  // 1) we first need to find integer add then look for this pattern:<br>
> > @@ -446,13 +411,13 @@ bool ARMParallelDSP::RecordMemoryOps(Bas<br>
> >  // If loop invariants are used instead of loads, these need to be packed<br>
> >  // before the loop begins.<br>
> >  //<br>
> > -bool ARMParallelDSP::MatchSMLAD(Loop *L) {<br>
> > +bool ARMParallelDSP::MatchSMLAD(Function &F) {<br>
> >    // Search recursively back through the operands to find a tree of values that<br>
> >    // form a multiply-accumulate chain. The search records the Add and Mul<br>
> >    // instructions that form the reduction and allows us to find a single value<br>
> >    // to be used as the initial input to the accumlator.<br>
> > -  std::function<bool(Value*, Reduction&)> Search = [&]<br>
> > -    (Value *V, Reduction &R) -> bool {<br>
> > +  std::function<bool(Value*, BasicBlock*, Reduction&)> Search = [&]<br>
> > +    (Value *V, BasicBlock *BB, Reduction &R) -> bool {<br>
> ><br>
> >      // If we find a non-instruction, try to use it as the initial accumulator<br>
> >      // value. This may have already been found during the search in which case<br>
> > @@ -461,6 +426,9 @@ bool ARMParallelDSP::MatchSMLAD(Loop *L)<br>
> >      if (!I)<br>
> >        return R.InsertAcc(V);<br>
> ><br>
> > +    if (I->getParent() != BB)<br>
> > +      return false;<br>
> > +<br>
> >      switch (I->getOpcode()) {<br>
> >      default:<br>
> >        break;<br>
> > @@ -471,8 +439,8 @@ bool ARMParallelDSP::MatchSMLAD(Loop *L)<br>
> >        // Adds should be adding together two muls, or another add and a mul to<br>
> >        // be within the mac chain. One of the operands may also be the<br>
> >        // accumulator value at which point we should stop searching.<br>
> > -      bool ValidLHS = Search(I->getOperand(0), R);<br>
> > -      bool ValidRHS = Search(I->getOperand(1), R);<br>
> > +      bool ValidLHS = Search(I->getOperand(0), BB, R);<br>
> > +      bool ValidRHS = Search(I->getOperand(1), BB, R);<br>
> >        if (!ValidLHS && !ValidLHS)<br>
> >          return false;<br>
> >        else if (ValidLHS && ValidRHS) {<br>
> > @@ -498,36 +466,40 @@ bool ARMParallelDSP::MatchSMLAD(Loop *L)<br>
> >        return false;<br>
> >      }<br>
> >      case Instruction::SExt:<br>
> > -      return Search(I->getOperand(0), R);<br>
> > +      return Search(I->getOperand(0), BB, R);<br>
> >      }<br>
> >      return false;<br>
> >    };<br>
> ><br>
> >    bool Changed = false;<br>
> > -  SmallPtrSet<Instruction*, 4> AllAdds;<br>
> > -  BasicBlock *Latch = L->getLoopLatch();<br>
> ><br>
> > -  for (Instruction &I : reverse(*Latch)) {<br>
> > -    if (I.getOpcode() != Instruction::Add)<br>
> > +  for (auto &BB : F) {<br>
> > +    SmallPtrSet<Instruction*, 4> AllAdds;<br>
> > +    if (!RecordMemoryOps(&BB))<br>
> >        continue;<br>
> ><br>
> > -    if (AllAdds.count(&I))<br>
> > -      continue;<br>
> > +    for (Instruction &I : reverse(BB)) {<br>
> > +      if (I.getOpcode() != Instruction::Add)<br>
> > +        continue;<br>
> ><br>
> > -    const auto *Ty = I.getType();<br>
> > -    if (!Ty->isIntegerTy(32) && !Ty->isIntegerTy(64))<br>
> > -      continue;<br>
> > +      if (AllAdds.count(&I))<br>
> > +        continue;<br>
> ><br>
> > -    Reduction R(&I);<br>
> > -    if (!Search(&I, R))<br>
> > -      continue;<br>
> > +      const auto *Ty = I.getType();<br>
> > +      if (!Ty->isIntegerTy(32) && !Ty->isIntegerTy(64))<br>
> > +        continue;<br>
> ><br>
> > -    if (!CreateParallelPairs(R))<br>
> > -      continue;<br>
> > +      Reduction R(&I);<br>
> > +      if (!Search(&I, &BB, R))<br>
> > +        continue;<br>
> ><br>
> > -    InsertParallelMACs(R);<br>
> > -    Changed = true;<br>
> > -    AllAdds.insert(R.getAdds().begin(), R.getAdds().end());<br>
> > +      if (!CreateParallelPairs(R))<br>
> > +        continue;<br>
> > +<br>
> > +      InsertParallelMACs(R);<br>
> > +      Changed = true;<br>
> > +      AllAdds.insert(R.getAdds().begin(), R.getAdds().end());<br>
> > +    }<br>
> >    }<br>
> ><br>
> >    return Changed;<br>
> > @@ -745,6 +717,6 @@ Pass *llvm::createARMParallelDSPPass() {<br>
> >  char ARMParallelDSP::ID = 0;<br>
> ><br>
> >  INITIALIZE_PASS_BEGIN(ARMParallelDSP, "arm-parallel-dsp",<br>
> > -                "Transform loops to use DSP intrinsics", false, false)<br>
> > +                "Transform functions to use DSP intrinsics", false, false)<br>
> >  INITIALIZE_PASS_END(ARMParallelDSP, "arm-parallel-dsp",<br>
> > -                "Transform loops to use DSP intrinsics", false, false)<br>
> > +                "Transform functions to use DSP intrinsics", false, false)<br>
> ><br>
> > Modified: llvm/trunk/test/CodeGen/ARM/O3-pipeline.ll<br>
> > URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/ARM/O3-pipeline.ll?rev=367389&r1=367388&r2=367389&view=diff">
http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/ARM/O3-pipeline.ll?rev=367389&r1=367388&r2=367389&view=diff</a><br>
> > ==============================================================================<br>
> > --- llvm/trunk/test/CodeGen/ARM/O3-pipeline.ll (original)<br>
> > +++ llvm/trunk/test/CodeGen/ARM/O3-pipeline.ll Wed Jul 31 00:32:03 2019<br>
> > @@ -37,8 +37,7 @@<br>
> >  ; CHECK-NEXT:      Scalar Evolution Analysis<br>
> >  ; CHECK-NEXT:      Basic Alias Analysis (stateless AA impl)<br>
> >  ; CHECK-NEXT:      Function Alias Analysis Results<br>
> > -; CHECK-NEXT:      Loop Pass Manager<br>
> > -; CHECK-NEXT:        Transform loops to use DSP intrinsics<br>
> > +; CHECK-NEXT:      Transform functions to use DSP intrinsics<br>
> >  ; CHECK-NEXT:      Interleaved Access Pass<br>
> >  ; CHECK-NEXT:      ARM IR optimizations<br>
> >  ; CHECK-NEXT:      Dominator Tree Construction<br>
> ><br>
> > Added: llvm/trunk/test/CodeGen/ARM/ParallelDSP/blocks.ll<br>
> > URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/ARM/ParallelDSP/blocks.ll?rev=367389&view=auto">
http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/ARM/ParallelDSP/blocks.ll?rev=367389&view=auto</a><br>
> > ==============================================================================<br>
> > --- llvm/trunk/test/CodeGen/ARM/ParallelDSP/blocks.ll (added)<br>
> > +++ llvm/trunk/test/CodeGen/ARM/ParallelDSP/blocks.ll Wed Jul 31 00:32:03 2019<br>
> > @@ -0,0 +1,79 @@<br>
> > +; RUN: opt -arm-parallel-dsp -mtriple=armv7-a -S %s -o - | FileCheck %s<br>
> > +<br>
> > +; CHECK-LABEL: single_block<br>
> > +; CHECK: [[CAST_A:%[^ ]+]] = bitcast i16* %a to i32*<br>
> > +; CHECK: [[A:%[^ ]+]] = load i32, i32* [[CAST_A]]<br>
> > +; CHECK: [[CAST_B:%[^ ]+]] = bitcast i16* %b to i32*<br>
> > +; CHECK: [[B:%[^ ]+]] = load i32, i32* [[CAST_B]]<br>
> > +; CHECK  call i32 @llvm.arm.smlad(i32 [[A]], i32 [[B]], i32 %acc)<br>
> > +define i32 @single_block(i16* %a, i16* %b, i32 %acc) {<br>
> > +entry:<br>
> > +  %ld.a.0 = load i16, i16* %a<br>
> > +  %sext.a.0 = sext i16 %ld.a.0 to i32<br>
> > +  %ld.b.0 = load i16, i16* %b<br>
> > +  %sext.b.0 = sext i16 %ld.b.0 to i32<br>
> > +  %mul.0 = mul i32 %sext.a.0, %sext.b.0<br>
> > +  %addr.a.1 = getelementptr i16, i16* %a, i32 1<br>
> > +  %addr.b.1 = getelementptr i16, i16* %b, i32 1<br>
> > +  %ld.a.1 = load i16, i16* %addr.a.1<br>
> > +  %sext.a.1 = sext i16 %ld.a.1 to i32<br>
> > +  %ld.b.1 = load i16, i16* %addr.b.1<br>
> > +  %sext.b.1 = sext i16 %ld.b.1 to i32<br>
> > +  %mul.1 = mul i32 %sext.a.1, %sext.b.1<br>
> > +  %add = add i32 %mul.0, %mul.1<br>
> > +  %res = add i32 %add, %acc<br>
> > +  ret i32 %res<br>
> > +}<br>
> > +<br>
> > +; CHECK-LABEL: multi_block<br>
> > +; CHECK: [[CAST_A:%[^ ]+]] = bitcast i16* %a to i32*<br>
> > +; CHECK: [[A:%[^ ]+]] = load i32, i32* [[CAST_A]]<br>
> > +; CHECK: [[CAST_B:%[^ ]+]] = bitcast i16* %b to i32*<br>
> > +; CHECK: [[B:%[^ ]+]] = load i32, i32* [[CAST_B]]<br>
> > +; CHECK  call i32 @llvm.arm.smlad(i32 [[A]], i32 [[B]], i32 0)<br>
> > +define i32 @multi_block(i16* %a, i16* %b, i32 %acc) {<br>
> > +entry:<br>
> > +  %ld.a.0 = load i16, i16* %a<br>
> > +  %sext.a.0 = sext i16 %ld.a.0 to i32<br>
> > +  %ld.b.0 = load i16, i16* %b<br>
> > +  %sext.b.0 = sext i16 %ld.b.0 to i32<br>
> > +  %mul.0 = mul i32 %sext.a.0, %sext.b.0<br>
> > +  %addr.a.1 = getelementptr i16, i16* %a, i32 1<br>
> > +  %addr.b.1 = getelementptr i16, i16* %b, i32 1<br>
> > +  %ld.a.1 = load i16, i16* %addr.a.1<br>
> > +  %sext.a.1 = sext i16 %ld.a.1 to i32<br>
> > +  %ld.b.1 = load i16, i16* %addr.b.1<br>
> > +  %sext.b.1 = sext i16 %ld.b.1 to i32<br>
> > +  %mul.1 = mul i32 %sext.a.1, %sext.b.1<br>
> > +  %add = add i32 %mul.0, %mul.1<br>
> > +  br label %bb.1<br>
> > +<br>
> > +bb.1:<br>
> > +  %res = add i32 %add, %acc<br>
> > +  ret i32 %res<br>
> > +}<br>
> > +<br>
> > +; CHECK-LABEL: multi_block_1<br>
> > +; CHECK-NOT: call i32 @llvm.arm.smlad<br>
> > +define i32 @multi_block_1(i16* %a, i16* %b, i32 %acc) {<br>
> > +entry:<br>
> > +  %ld.a.0 = load i16, i16* %a<br>
> > +  %sext.a.0 = sext i16 %ld.a.0 to i32<br>
> > +  %ld.b.0 = load i16, i16* %b<br>
> > +  %sext.b.0 = sext i16 %ld.b.0 to i32<br>
> > +  %mul.0 = mul i32 %sext.a.0, %sext.b.0<br>
> > +  br label %bb.1<br>
> > +<br>
> > +bb.1:<br>
> > +  %addr.a.1 = getelementptr i16, i16* %a, i32 1<br>
> > +  %addr.b.1 = getelementptr i16, i16* %b, i32 1<br>
> > +  %ld.a.1 = load i16, i16* %addr.a.1<br>
> > +  %sext.a.1 = sext i16 %ld.a.1 to i32<br>
> > +  %ld.b.1 = load i16, i16* %addr.b.1<br>
> > +  %sext.b.1 = sext i16 %ld.b.1 to i32<br>
> > +  %mul.1 = mul i32 %sext.a.1, %sext.b.1<br>
> > +  %add = add i32 %mul.0, %mul.1<br>
> > +  %res = add i32 %add, %acc<br>
> > +  ret i32 %res<br>
> > +}<br>
> > +<br>
> ><br>
> > Modified: llvm/trunk/test/CodeGen/ARM/ParallelDSP/smlad12.ll<br>
> > URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/ARM/ParallelDSP/smlad12.ll?rev=367389&r1=367388&r2=367389&view=diff">
http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/ARM/ParallelDSP/smlad12.ll?rev=367389&r1=367388&r2=367389&view=diff</a><br>
> > ==============================================================================<br>
> > --- llvm/trunk/test/CodeGen/ARM/ParallelDSP/smlad12.ll (original)<br>
> > +++ llvm/trunk/test/CodeGen/ARM/ParallelDSP/smlad12.ll Wed Jul 31 00:32:03 2019<br>
> > @@ -2,7 +2,7 @@<br>
> >  ;<br>
> >  ; The loop header is not the loop latch.<br>
> >  ;<br>
> > -; CHECK-NOT:  call i32 @llvm.arm.smlad<br>
> > +; CHECK:  call i32 @llvm.arm.smlad<br>
> >  ;<br>
> >  define dso_local i32 @test(i32 %arg, i32* nocapture readnone %arg1, i16* nocapture readonly %arg2, i16* nocapture readonly %arg3) {<br>
> >  entry:<br>
> ><br>
> ><br>
> > _______________________________________________<br>
> > llvm-commits mailing list<br>
> > llvm-commits@lists.llvm.org<br>
> > <a href="https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits">https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits</a><br>
</div>
</span></font></div>
</body>
</html>