<div dir="ltr"><div>This change seems to have broken the build of compiler-rt:</div><div><br></div><a href="http://llvm.org/bugs/show_bug.cgi?id=19503">http://llvm.org/bugs/show_bug.cgi?id=19503</a><br></div><div class="gmail_extra">
<br><br><div class="gmail_quote">On Mon, Apr 21, 2014 at 12:34 PM, Yi Jiang <span dir="ltr"><<a href="mailto:yjiang@apple.com" target="_blank">yjiang@apple.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
Author: yjiang<br>
Date: Mon Apr 21 14:34:27 2014<br>
New Revision: 206774<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=206774&view=rev" target="_blank">http://llvm.org/viewvc/llvm-project?rev=206774&view=rev</a><br>
Log:<br>
ARM64: Combine shifts and uses from different basic block to bit-extract instruction<br>
<br>
Modified:<br>
    llvm/trunk/include/llvm/Target/TargetLowering.h<br>
    llvm/trunk/lib/CodeGen/CodeGenPrepare.cpp<br>
    llvm/trunk/lib/Target/ARM64/ARM64ISelDAGToDAG.cpp<br>
    llvm/trunk/lib/Target/ARM64/ARM64ISelLowering.cpp<br>
    llvm/trunk/test/CodeGen/ARM64/bitfield-extract.ll<br>
<br>
Modified: llvm/trunk/include/llvm/Target/TargetLowering.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Target/TargetLowering.h?rev=206774&r1=206773&r2=206774&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Target/TargetLowering.h?rev=206774&r1=206773&r2=206774&view=diff</a><br>

==============================================================================<br>
--- llvm/trunk/include/llvm/Target/TargetLowering.h (original)<br>
+++ llvm/trunk/include/llvm/Target/TargetLowering.h Mon Apr 21 14:34:27 2014<br>
@@ -182,6 +182,9 @@ public:<br>
     return HasMultipleConditionRegisters;<br>
   }<br>
<br>
+  /// Return true if the target has BitExtract instructions.<br>
+  bool hasExtractBitsInsn() const { return HasExtractBitsInsn; }<br>
+<br>
   /// Return true if a vector of the given type should be split<br>
   /// (TypeSplitVector) instead of promoted (TypePromoteInteger) during type<br>
   /// legalization.<br>
@@ -1010,6 +1013,14 @@ protected:<br>
     HasMultipleConditionRegisters = hasManyRegs;<br>
   }<br>
<br>
+  /// Tells the code generator that the target has BitExtract instructions.<br>
+  /// The code generator will aggressively sink "shift"s into the blocks of<br>
+  /// their users if the users will generate "and" instructions which can be<br>
+  /// combined with "shift" to BitExtract instructions.<br>
+  void setHasExtractBitsInsn(bool hasExtractInsn = true) {<br>
+    HasExtractBitsInsn = hasExtractInsn;<br>
+  }<br>
+<br>
   /// Tells the code generator not to expand sequence of operations into a<br>
   /// separate sequences that increases the amount of flow control.<br>
   void setJumpIsExpensive(bool isExpensive = true) {<br>
@@ -1436,6 +1447,12 @@ private:<br>
   /// the blocks of their users.<br>
   bool HasMultipleConditionRegisters;<br>
<br>
+  /// Tells the code generator that the target has BitExtract instructions.<br>
+  /// The code generator will aggressively sink "shift"s into the blocks of<br>
+  /// their users if the users will generate "and" instructions which can be<br>
+  /// combined with "shift" to BitExtract instructions.<br>
+  bool HasExtractBitsInsn;<br>
+<br>
   /// Tells the code generator not to expand integer divides by constants into a<br>
   /// sequence of muls, adds, and shifts.  This is a hack until a real cost<br>
   /// model is in place.  If we ever optimize for size, this will be set to true<br>
<br>
Modified: llvm/trunk/lib/CodeGen/CodeGenPrepare.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/CodeGenPrepare.cpp?rev=206774&r1=206773&r2=206774&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/CodeGenPrepare.cpp?rev=206774&r1=206773&r2=206774&view=diff</a><br>

==============================================================================<br>
--- llvm/trunk/lib/CodeGen/CodeGenPrepare.cpp (original)<br>
+++ llvm/trunk/lib/CodeGen/CodeGenPrepare.cpp Mon Apr 21 14:34:27 2014<br>
@@ -628,6 +628,187 @@ static bool OptimizeCmpExpression(CmpIns<br>
   return MadeChange;<br>
 }<br>
<br>
+/// isExtractBitsCandidateUse - Check if the candidates could<br>
+/// be combined with shift instruction, which includes:<br>
+/// 1. Truncate instruction<br>
+/// 2. And instruction and the imm is a mask of the low bits:<br>
+/// imm & (imm+1) == 0<br>
+bool isExtractBitsCandidateUse(Instruction *User) {<br>
+  if (!isa<TruncInst>(User)) {<br>
+    if (User->getOpcode() != Instruction::And ||<br>
+        !isa<ConstantInt>(User->getOperand(1)))<br>
+      return false;<br>
+<br>
+    unsigned Cimm = dyn_cast<ConstantInt>(User->getOperand(1))->getZExtValue();<br>
+<br>
+    if (Cimm & (Cimm + 1))<br>
+      return false;<br>
+  }<br>
+  return true;<br>
+}<br>
+<br>
+/// SinkShiftAndTruncate - sink both shift and truncate instruction<br>
+/// to the use of truncate's BB.<br>
+bool<br>
+SinkShiftAndTruncate(BinaryOperator *ShiftI, Instruction *User, ConstantInt *CI,<br>
+                     DenseMap<BasicBlock *, BinaryOperator *> &InsertedShifts,<br>
+                     const TargetLowering &TLI) {<br>
+  BasicBlock *UserBB = User->getParent();<br>
+  DenseMap<BasicBlock *, CastInst *> InsertedTruncs;<br>
+  TruncInst *TruncI = dyn_cast<TruncInst>(User);<br>
+  bool MadeChange = false;<br>
+<br>
+  for (Value::user_iterator TruncUI = TruncI->user_begin(),<br>
+                            TruncE = TruncI->user_end();<br>
+       TruncUI != TruncE;) {<br>
+<br>
+    Use &TruncTheUse = TruncUI.getUse();<br>
+    Instruction *TruncUser = cast<Instruction>(*TruncUI);<br>
+    // Preincrement use iterator so we don't invalidate it.<br>
+<br>
+    ++TruncUI;<br>
+<br>
+    int ISDOpcode = TLI.InstructionOpcodeToISD(TruncUser->getOpcode());<br>
+    if (!ISDOpcode)<br>
+      continue;<br>
+<br>
+    // If the use is actually a legal node, there will not be an implicit<br>
+    // truncate.<br>
+    if (TLI.isOperationLegalOrCustom(ISDOpcode,<br>
+                                     EVT::getEVT(TruncUser->getType())))<br>
+      continue;<br>
+<br>
+    // Don't bother for PHI nodes.<br>
+    if (isa<PHINode>(TruncUser))<br>
+      continue;<br>
+<br>
+    BasicBlock *TruncUserBB = TruncUser->getParent();<br>
+<br>
+    if (UserBB == TruncUserBB)<br>
+      continue;<br>
+<br>
+    BinaryOperator *&InsertedShift = InsertedShifts[TruncUserBB];<br>
+    CastInst *&InsertedTrunc = InsertedTruncs[TruncUserBB];<br>
+<br>
+    if (!InsertedShift && !InsertedTrunc) {<br>
+      BasicBlock::iterator InsertPt = TruncUserBB->getFirstInsertionPt();<br>
+      // Sink the shift<br>
+      if (ShiftI->getOpcode() == Instruction::AShr)<br>
+        InsertedShift =<br>
+            BinaryOperator::CreateAShr(ShiftI->getOperand(0), CI, "", InsertPt);<br>
+      else<br>
+        InsertedShift =<br>
+            BinaryOperator::CreateLShr(ShiftI->getOperand(0), CI, "", InsertPt);<br>
+<br>
+      // Sink the trunc<br>
+      BasicBlock::iterator TruncInsertPt = TruncUserBB->getFirstInsertionPt();<br>
+      TruncInsertPt++;<br>
+<br>
+      InsertedTrunc = CastInst::Create(TruncI->getOpcode(), InsertedShift,<br>
+                                       TruncI->getType(), "", TruncInsertPt);<br>
+<br>
+      MadeChange = true;<br>
+<br>
+      TruncTheUse = InsertedTrunc;<br>
+    }<br>
+  }<br>
+  return MadeChange;<br>
+}<br>
+<br>
+/// OptimizeExtractBits - sink the shift *right* instruction into user blocks if<br>
+/// the uses could potentially be combined with this shift instruction and<br>
+/// generate BitExtract instruction. It will only be applied if the architecture<br>
+/// supports BitExtract instruction. Here is an example:<br>
+/// BB1:<br>
+///   %x.extract.shift = lshr i64 %arg1, 32<br>
+/// BB2:<br>
+///   %x.extract.trunc = trunc i64 %x.extract.shift to i16<br>
+/// ==><br>
+///<br>
+/// BB2:<br>
+///   %x.extract.shift.1 = lshr i64 %arg1, 32<br>
+///   %x.extract.trunc = trunc i64 %x.extract.shift.1 to i16<br>
+///<br>
+/// CodeGen will recoginze the pattern in BB2 and generate BitExtract<br>
+/// instruction.<br>
+/// Return true if any changes are made.<br>
+static bool OptimizeExtractBits(BinaryOperator *ShiftI, ConstantInt *CI,<br>
+                                const TargetLowering &TLI) {<br>
+  BasicBlock *DefBB = ShiftI->getParent();<br>
+<br>
+  /// Only insert instructions in each block once.<br>
+  DenseMap<BasicBlock *, BinaryOperator *> InsertedShifts;<br>
+<br>
+  bool shiftIsLegal = TLI.isTypeLegal(TLI.getValueType(ShiftI->getType()));<br>
+<br>
+  bool MadeChange = false;<br>
+  for (Value::user_iterator UI = ShiftI->user_begin(), E = ShiftI->user_end();<br>
+       UI != E;) {<br>
+    Use &TheUse = UI.getUse();<br>
+    Instruction *User = cast<Instruction>(*UI);<br>
+    // Preincrement use iterator so we don't invalidate it.<br>
+    ++UI;<br>
+<br>
+    // Don't bother for PHI nodes.<br>
+    if (isa<PHINode>(User))<br>
+      continue;<br>
+<br>
+    if (!isExtractBitsCandidateUse(User))<br>
+      continue;<br>
+<br>
+    BasicBlock *UserBB = User->getParent();<br>
+<br>
+    if (UserBB == DefBB) {<br>
+      // If the shift and truncate instruction are in the same BB. The use of<br>
+      // the truncate(TruncUse) may still introduce another truncate if not<br>
+      // legal. In this case, we would like to sink both shift and truncate<br>
+      // instruction to the BB of TruncUse.<br>
+      // for example:<br>
+      // BB1:<br>
+      // i64 shift.result = lshr i64 opnd, imm<br>
+      // trunc.result = trunc shift.result to i16<br>
+      //<br>
+      // BB2:<br>
+      //   ----> We will have an implicit truncate here if the architecture does<br>
+      //   not have i16 compare.<br>
+      // cmp i16 trunc.result, opnd2<br>
+      //<br>
+      if (isa<TruncInst>(User) && shiftIsLegal<br>
+          // If the type of the truncate is legal, no trucate will be<br>
+          // introduced in other basic blocks.<br>
+          && (!TLI.isTypeLegal(TLI.getValueType(User->getType()))))<br>
+        MadeChange =<br>
+            SinkShiftAndTruncate(ShiftI, User, CI, InsertedShifts, TLI);<br>
+<br>
+      continue;<br>
+    }<br>
+    // If we have already inserted a shift into this block, use it.<br>
+    BinaryOperator *&InsertedShift = InsertedShifts[UserBB];<br>
+<br>
+    if (!InsertedShift) {<br>
+      BasicBlock::iterator InsertPt = UserBB->getFirstInsertionPt();<br>
+<br>
+      if (ShiftI->getOpcode() == Instruction::AShr)<br>
+        InsertedShift =<br>
+            BinaryOperator::CreateAShr(ShiftI->getOperand(0), CI, "", InsertPt);<br>
+      else<br>
+        InsertedShift =<br>
+            BinaryOperator::CreateLShr(ShiftI->getOperand(0), CI, "", InsertPt);<br>
+<br>
+      MadeChange = true;<br>
+    }<br>
+<br>
+    // Replace a use of the shift with a use of the new shift.<br>
+    TheUse = InsertedShift;<br>
+  }<br>
+<br>
+  // If we removed all uses, nuke the shift.<br>
+  if (ShiftI->use_empty())<br>
+    ShiftI->eraseFromParent();<br>
+<br>
+  return MadeChange;<br>
+}<br>
+<br>
 namespace {<br>
 class CodeGenPrepareFortifiedLibCalls : public SimplifyFortifiedLibCalls {<br>
 protected:<br>
@@ -3225,6 +3406,17 @@ bool CodeGenPrepare::OptimizeInst(Instru<br>
     return false;<br>
   }<br>
<br>
+  BinaryOperator *BinOp = dyn_cast<BinaryOperator>(I);<br>
+<br>
+  if (BinOp && (BinOp->getOpcode() == Instruction::AShr ||<br>
+                BinOp->getOpcode() == Instruction::LShr)) {<br>
+    ConstantInt *CI = dyn_cast<ConstantInt>(BinOp->getOperand(1));<br>
+    if (TLI && CI && TLI->hasExtractBitsInsn())<br>
+      return OptimizeExtractBits(BinOp, CI, *TLI);<br>
+<br>
+    return false;<br>
+  }<br>
+<br>
   if (GetElementPtrInst *GEPI = dyn_cast<GetElementPtrInst>(I)) {<br>
     if (GEPI->hasAllZeroIndices()) {<br>
       /// The GEP operand must be a pointer, so must its result -> BitCast<br>
<br>
Modified: llvm/trunk/lib/Target/ARM64/ARM64ISelDAGToDAG.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM64/ARM64ISelDAGToDAG.cpp?rev=206774&r1=206773&r2=206774&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM64/ARM64ISelDAGToDAG.cpp?rev=206774&r1=206773&r2=206774&view=diff</a><br>

==============================================================================<br>
--- llvm/trunk/lib/Target/ARM64/ARM64ISelDAGToDAG.cpp (original)<br>
+++ llvm/trunk/lib/Target/ARM64/ARM64ISelDAGToDAG.cpp Mon Apr 21 14:34:27 2014<br>
@@ -1183,6 +1183,14 @@ static bool isBitfieldExtractOpFromAnd(S<br>
     // Make sure to clamp the MSB so that we preserve the semantics of the<br>
     // original operations.<br>
     ClampMSB = true;<br>
+  } else if (VT == MVT::i32 && Op0->getOpcode() == ISD::TRUNCATE &&<br>
+             isOpcWithIntImmediate(Op0->getOperand(0).getNode(), ISD::SRL,<br>
+                                   Srl_imm)) {<br>
+    // If the shift result was truncated, we can still combine them.<br>
+    Opd0 = Op0->getOperand(0).getOperand(0);<br>
+<br>
+    // Use the type of SRL node.<br>
+    VT = Opd0->getValueType(0);<br>
   } else if (isOpcWithIntImmediate(Op0, ISD::SRL, Srl_imm)) {<br>
     Opd0 = Op0->getOperand(0);<br>
   } else if (BiggerPattern) {<br>
@@ -1277,8 +1285,19 @@ static bool isBitfieldExtractOpFromShr(S<br>
<br>
   // we're looking for a shift of a shift<br>
   uint64_t Shl_imm = 0;<br>
+  uint64_t Trunc_bits = 0;<br>
   if (isOpcWithIntImmediate(N->getOperand(0).getNode(), ISD::SHL, Shl_imm)) {<br>
     Opd0 = N->getOperand(0).getOperand(0);<br>
+  } else if (VT == MVT::i32 && N->getOpcode() == ISD::SRL &&<br>
+             N->getOperand(0).getNode()->getOpcode() == ISD::TRUNCATE) {<br>
+    // We are looking for a shift of truncate. Truncate from i64 to i32 could<br>
+    // be considered as setting high 32 bits as zero. Our strategy here is to<br>
+    // always generate 64bit UBFM. This consistency will help the CSE pass<br>
+    // later find more redundancy.<br>
+    Opd0 = N->getOperand(0).getOperand(0);<br>
+    Trunc_bits = Opd0->getValueType(0).getSizeInBits() - VT.getSizeInBits();<br>
+    VT = Opd0->getValueType(0);<br>
+    assert(VT == MVT::i64 && "the promoted type should be i64");<br>
   } else if (BiggerPattern) {<br>
     // Let's pretend a 0 shift left has been performed.<br>
     // FIXME: Currently we limit this to the bigger pattern case,<br>
@@ -1295,7 +1314,7 @@ static bool isBitfieldExtractOpFromShr(S<br>
   assert(Srl_imm > 0 && Srl_imm < VT.getSizeInBits() &&<br>
          "bad amount in shift node!");<br>
   // Note: The width operand is encoded as width-1.<br>
-  unsigned Width = VT.getSizeInBits() - Srl_imm - 1;<br>
+  unsigned Width = VT.getSizeInBits() - Trunc_bits - Srl_imm - 1;<br>
   int sLSB = Srl_imm - Shl_imm;<br>
   if (sLSB < 0)<br>
     return false;<br>
@@ -1354,8 +1373,23 @@ SDNode *ARM64DAGToDAGISel::SelectBitfiel<br>
     return NULL;<br>
<br>
   EVT VT = N->getValueType(0);<br>
-  SDValue Ops[] = { Opd0, CurDAG->getTargetConstant(LSB, VT),<br>
-                    CurDAG->getTargetConstant(MSB, VT) };<br>
+<br>
+  // If the bit extract operation is 64bit but the original type is 32bit, we<br>
+  // need to add one EXTRACT_SUBREG.<br>
+  if ((Opc == ARM64::SBFMXri || Opc == ARM64::UBFMXri) && VT == MVT::i32) {<br>
+    SDValue Ops64[] = {Opd0, CurDAG->getTargetConstant(LSB, MVT::i64),<br>
+                       CurDAG->getTargetConstant(MSB, MVT::i64)};<br>
+<br>
+    SDNode *BFM = CurDAG->getMachineNode(Opc, SDLoc(N), MVT::i64, Ops64);<br>
+    SDValue SubReg = CurDAG->getTargetConstant(ARM64::sub_32, MVT::i32);<br>
+    MachineSDNode *Node =<br>
+        CurDAG->getMachineNode(TargetOpcode::EXTRACT_SUBREG, SDLoc(N), MVT::i32,<br>
+                               SDValue(BFM, 0), SubReg);<br>
+    return Node;<br>
+  }<br>
+<br>
+  SDValue Ops[] = {Opd0, CurDAG->getTargetConstant(LSB, VT),<br>
+                   CurDAG->getTargetConstant(MSB, VT)};<br>
   return CurDAG->SelectNodeTo(N, Opc, VT, Ops, 3);<br>
 }<br>
<br>
<br>
Modified: llvm/trunk/lib/Target/ARM64/ARM64ISelLowering.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM64/ARM64ISelLowering.cpp?rev=206774&r1=206773&r2=206774&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM64/ARM64ISelLowering.cpp?rev=206774&r1=206773&r2=206774&view=diff</a><br>

==============================================================================<br>
--- llvm/trunk/lib/Target/ARM64/ARM64ISelLowering.cpp (original)<br>
+++ llvm/trunk/lib/Target/ARM64/ARM64ISelLowering.cpp Mon Apr 21 14:34:27 2014<br>
@@ -438,6 +438,8 @@ ARM64TargetLowering::ARM64TargetLowering<br>
   setDivIsWellDefined(true);<br>
<br>
   RequireStrictAlign = StrictAlign;<br>
+<br>
+  setHasExtractBitsInsn(true);<br>
 }<br>
<br>
 void ARM64TargetLowering::addTypeForNEON(EVT VT, EVT PromotedBitwiseVT) {<br>
<br>
Modified: llvm/trunk/test/CodeGen/ARM64/bitfield-extract.ll<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/ARM64/bitfield-extract.ll?rev=206774&r1=206773&r2=206774&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/ARM64/bitfield-extract.ll?rev=206774&r1=206773&r2=206774&view=diff</a><br>

==============================================================================<br>
--- llvm/trunk/test/CodeGen/ARM64/bitfield-extract.ll (original)<br>
+++ llvm/trunk/test/CodeGen/ARM64/bitfield-extract.ll Mon Apr 21 14:34:27 2014<br>
@@ -1,3 +1,4 @@<br>
+; RUN: opt -codegenprepare -mtriple=arm64-apple=ios -S -o - %s | FileCheck --check-prefix=OPT %s<br>
 ; RUN: llc < %s -march=arm64 | FileCheck %s<br>
 %struct.X = type { i8, i8, [2 x i8] }<br>
 %struct.Y = type { i32, i8 }<br>
@@ -404,3 +405,75 @@ define i64 @fct18(i32 %xor72) nounwind s<br>
   %result = and i64 %conv82, 255<br>
   ret i64 %result<br>
 }<br>
+<br>
+; Using the access to the global array to keep the instruction and control flow.<br>
+@first_ones = external global [65536 x i8]<br>
+<br>
+; Function Attrs: nounwind readonly ssp<br>
+define i32 @fct19(i64 %arg1) nounwind readonly ssp  {<br>
+; CHECK-LABEL: fct19:<br>
+entry:<br>
+  %x.sroa.1.0.extract.shift = lshr i64 %arg1, 16<br>
+  %x.sroa.1.0.extract.trunc = trunc i64 %x.sroa.1.0.extract.shift to i16<br>
+  %x.sroa.3.0.extract.shift = lshr i64 %arg1, 32<br>
+  %x.sroa.5.0.extract.shift = lshr i64 %arg1, 48<br>
+  %tobool = icmp eq i64 %x.sroa.5.0.extract.shift, 0<br>
+  br i1 %tobool, label %if.end, label %if.then<br>
+<br>
+if.then:                                          ; preds = %entry<br>
+  %arrayidx3 = getelementptr inbounds [65536 x i8]* @first_ones, i64 0, i64 %x.sroa.5.0.extract.shift<br>
+  %0 = load i8* %arrayidx3, align 1<br>
+  %conv = zext i8 %0 to i32<br>
+  br label %return<br>
+<br>
+; OPT-LABEL: if.end<br>
+if.end:                                           ; preds = %entry<br>
+; OPT: lshr<br>
+; CHECK: ubfm  [[REG1:x[0-9]+]], [[REG2:x[0-9]+]], #32, #47<br>
+  %x.sroa.3.0.extract.trunc = trunc i64 %x.sroa.3.0.extract.shift to i16<br>
+  %tobool6 = icmp eq i16 %x.sroa.3.0.extract.trunc, 0<br>
+; CHECK: cbz<br>
+  br i1 %tobool6, label %if.end13, label %if.then7<br>
+<br>
+; OPT-LABEL: if.then7<br>
+if.then7:                                         ; preds = %if.end<br>
+; OPT: lshr<br>
+; "and" should be combined to "ubfm" while "ubfm" should be removed by cse.<br>
+; So neither of them should be in the assemble code.<br>
+; CHECK-NOT: and<br>
+; CHECK-NOT: ubfm<br>
+  %idxprom10 = and i64 %x.sroa.3.0.extract.shift, 65535<br>
+  %arrayidx11 = getelementptr inbounds [65536 x i8]* @first_ones, i64 0, i64 %idxprom10<br>
+  %1 = load i8* %arrayidx11, align 1<br>
+  %conv12 = zext i8 %1 to i32<br>
+  %add = add nsw i32 %conv12, 16<br>
+  br label %return<br>
+<br>
+; OPT-LABEL: if.end13<br>
+if.end13:                                         ; preds = %if.end<br>
+; OPT: lshr<br>
+; OPT: trunc<br>
+; CHECK: ubfm  [[REG3:x[0-9]+]], [[REG4:x[0-9]+]], #16, #31<br>
+  %tobool16 = icmp eq i16 %x.sroa.1.0.extract.trunc, 0<br>
+; CHECK: cbz<br>
+  br i1 %tobool16, label %return, label %if.then17<br>
+<br>
+; OPT-LABEL: if.then17<br>
+if.then17:                                        ; preds = %if.end13<br>
+; OPT: lshr<br>
+; "and" should be combined to "ubfm" while "ubfm" should be removed by cse.<br>
+; So neither of them should be in the assemble code.<br>
+; CHECK-NOT: and<br>
+; CHECK-NOT: ubfm<br>
+  %idxprom20 = and i64 %x.sroa.1.0.extract.shift, 65535<br>
+  %arrayidx21 = getelementptr inbounds [65536 x i8]* @first_ones, i64 0, i64 %idxprom20<br>
+  %2 = load i8* %arrayidx21, align 1<br>
+  %conv22 = zext i8 %2 to i32<br>
+  %add23 = add nsw i32 %conv22, 32<br>
+  br label %return<br>
+<br>
+return:                                           ; preds = %if.end13, %if.then17, %if.then7, %if.then<br>
+; CHECK: ret<br>
+  %retval.0 = phi i32 [ %conv, %if.then ], [ %add, %if.then7 ], [ %add23, %if.then17 ], [ 64, %if.end13 ]<br>
+  ret i32 %retval.0<br>
+}<br>
<br>
<br>
_______________________________________________<br>
llvm-commits mailing list<br>
<a href="mailto:llvm-commits@cs.uiuc.edu">llvm-commits@cs.uiuc.edu</a><br>
<a href="http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits" target="_blank">http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits</a><br>
</blockquote></div><br></div>