<div dir="ltr">Fixed in r208448 by adding a triple with an OS in it.</div><div class="gmail_extra"><br><br><div class="gmail_quote">On Fri, May 9, 2014 at 2:50 PM, Reid Kleckner <span dir="ltr"><<a href="mailto:rnk@google.com" target="_blank">rnk@google.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr">This test is failing for me locally and on Takumi's bot:<div><a href="http://bb.pgr.jp/builders/ninja-x64-msvc-RA-centos6/builds/2593/steps/test_all/logs/LLVM%20%3A%3A%20CodeGen__ARM__intrinsics-overflow.ll" target="_blank">http://bb.pgr.jp/builders/ninja-x64-msvc-RA-centos6/builds/2593/steps/test_all/logs/LLVM%20%3A%3A%20CodeGen__ARM__intrinsics-overflow.ll</a><br>

<div><div><br></div><div>-- Testing: 10688 tests, 32 threads --</div><div>FAIL: LLVM :: CodeGen/ARM/intrinsics-overflow.ll (1128 of 10688)</div><div>******************** TEST 'LLVM :: CodeGen/ARM/intrinsics-overflow.ll' FAILED ********************</div>

<div>Script:</div><div>--</div><div>D:/src/llvm/build/./bin\llc.EXE < D:\src\llvm\test\CodeGen\ARM\intrinsics-overflow.ll -march=arm -mcpu=generic | D:/src/llvm/build/./bin\FileCheck.EXE D:\src\llvm\test\CodeGen\ARM\intrinsics-overflow.ll</div>

<div>--</div><div>Exit Code: 2</div><div><br></div><div>Command Output (stdout):</div><div>--</div><div>Command 0: "D:/src/llvm/build/./bin\llc.EXE" "-march=arm" "-mcpu=generic"</div><div>Command 0 Result: 1</div>

<div>Command 0 Output:</div><div><br></div><div><br></div><div>Command 0 Stderr:</div><div>LLVM ERROR: CPU: 'generic' does not support ARM mode execution!</div><div>Stack dump:</div><div>0.      Program arguments: D:/src/llvm/build/./bin\llc.EXE -march=arm -mcpu=generic</div>

<div><br></div><div><br></div><div>Command 1: "D:/src/llvm/build/./bin\FileCheck.EXE" "D:\src\llvm\test\CodeGen\ARM\intrinsics-overflow.ll"</div><div>Command 1 Result: 2</div><div>Command 1 Output:</div>

<div><br></div><div><br></div><div>Command 1 Stderr:</div><div>FileCheck error: '-' is empty.</div><div><br></div><div><br></div><div><br></div><div>--</div><div><br></div></div></div></div><div class="HOEnZb"><div class="h5">
<div class="gmail_extra">
<br><br><div class="gmail_quote">On Fri, May 9, 2014 at 10:02 AM, Louis Gerbarg <span dir="ltr"><<a href="mailto:lgg@apple.com" target="_blank">lgg@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: louis<br>
Date: Fri May  9 12:02:49 2014<br>
New Revision: 208435<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=208435&view=rev" target="_blank">http://llvm.org/viewvc/llvm-project?rev=208435&view=rev</a><br>
Log:<br>
Add custom lowering for add/sub with overflow intrinsics to ARM<br>
<br>
This patch adds support to ARM for custom lowering of the<br>
llvm.{u|s}add.with.overflow.i32 intrinsics for i32/i64. This is particularly useful<br>
for handling idiomatic saturating math functions as generated by<br>
InstCombineCompare.<br>
<br>
Test cases included.<br>
<br>
rdar://14853450<br>
<br>
Added:<br>
    llvm/trunk/test/CodeGen/ARM/intrinsics-overflow.ll<br>
Modified:<br>
    llvm/trunk/lib/Target/ARM/ARMISelLowering.cpp<br>
    llvm/trunk/lib/Target/ARM/ARMISelLowering.h<br>
<br>
Modified: llvm/trunk/lib/Target/ARM/ARMISelLowering.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMISelLowering.cpp?rev=208435&r1=208434&r2=208435&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMISelLowering.cpp?rev=208435&r1=208434&r2=208435&view=diff</a><br>


==============================================================================<br>
--- llvm/trunk/lib/Target/ARM/ARMISelLowering.cpp (original)<br>
+++ llvm/trunk/lib/Target/ARM/ARMISelLowering.cpp Fri May  9 12:02:49 2014<br>
@@ -639,6 +639,11 @@ ARMTargetLowering::ARMTargetLowering(Tar<br>
     }<br>
   }<br>
<br>
+  setOperationAction(ISD::SADDO, MVT::i32, Custom);<br>
+  setOperationAction(ISD::UADDO, MVT::i32, Custom);<br>
+  setOperationAction(ISD::SSUBO, MVT::i32, Custom);<br>
+  setOperationAction(ISD::USUBO, MVT::i32, Custom);<br>
+<br>
   // i64 operation support.<br>
   setOperationAction(ISD::MUL,     MVT::i64, Expand);<br>
   setOperationAction(ISD::MULHU,   MVT::i32, Expand);<br>
@@ -3222,11 +3227,96 @@ ARMTargetLowering::duplicateCmp(SDValue<br>
   return DAG.getNode(ARMISD::FMSTAT, DL, MVT::Glue, Cmp);<br>
 }<br>
<br>
+std::pair<SDValue, SDValue><br>
+ARMTargetLowering::getARMXALUOOp(SDValue Op, SelectionDAG &DAG,<br>
+                                 SDValue &ARMcc) const {<br>
+  assert(Op.getValueType() == MVT::i32 &&  "Unsupported value type");<br>
+<br>
+  SDValue Value, OverflowCmp;<br>
+  SDValue LHS = Op.getOperand(0);<br>
+  SDValue RHS = Op.getOperand(1);<br>
+<br>
+<br>
+  // FIXME: We are currently always generating CMPs because we don't support<br>
+  // generating CMN through the backend. This is not as good as the natural<br>
+  // CMP case because it causes a register dependency and cannot be folded<br>
+  // later.<br>
+<br>
+  switch (Op.getOpcode()) {<br>
+  default:<br>
+    llvm_unreachable("Unknown overflow instruction!");<br>
+  case ISD::SADDO:<br>
+    ARMcc = DAG.getConstant(ARMCC::VC, MVT::i32);<br>
+    Value = DAG.getNode(ISD::ADD, SDLoc(Op), Op.getValueType(), LHS, RHS);<br>
+    OverflowCmp = DAG.getNode(ARMISD::CMP, SDLoc(Op), MVT::Glue, Value, LHS);<br>
+    break;<br>
+  case ISD::UADDO:<br>
+    ARMcc = DAG.getConstant(ARMCC::HS, MVT::i32);<br>
+    Value = DAG.getNode(ISD::ADD, SDLoc(Op), Op.getValueType(), LHS, RHS);<br>
+    OverflowCmp = DAG.getNode(ARMISD::CMP, SDLoc(Op), MVT::Glue, Value, LHS);<br>
+    break;<br>
+  case ISD::SSUBO:<br>
+    ARMcc = DAG.getConstant(ARMCC::VC, MVT::i32);<br>
+    Value = DAG.getNode(ISD::SUB, SDLoc(Op), Op.getValueType(), LHS, RHS);<br>
+    OverflowCmp = DAG.getNode(ARMISD::CMP, SDLoc(Op), MVT::Glue, LHS, RHS);<br>
+    break;<br>
+  case ISD::USUBO:<br>
+    ARMcc = DAG.getConstant(ARMCC::HS, MVT::i32);<br>
+    Value = DAG.getNode(ISD::SUB, SDLoc(Op), Op.getValueType(), LHS, RHS);<br>
+    OverflowCmp = DAG.getNode(ARMISD::CMP, SDLoc(Op), MVT::Glue, LHS, RHS);<br>
+    break;<br>
+  } // switch (...)<br>
+<br>
+  return std::make_pair(Value, OverflowCmp);<br>
+}<br>
+<br>
+<br>
+SDValue<br>
+ARMTargetLowering::LowerXALUO(SDValue Op, SelectionDAG &DAG) const {<br>
+  // Let legalize expand this if it isn't a legal type yet.<br>
+  if (!DAG.getTargetLoweringInfo().isTypeLegal(Op.getValueType()))<br>
+    return SDValue();<br>
+<br>
+  SDValue Value, OverflowCmp;<br>
+  SDValue ARMcc;<br>
+  std::tie(Value, OverflowCmp) = getARMXALUOOp(Op, DAG, ARMcc);<br>
+  SDValue CCR = DAG.getRegister(ARM::CPSR, MVT::i32);<br>
+  // We use 0 and 1 as false and true values.<br>
+  SDValue TVal = DAG.getConstant(1, MVT::i32);<br>
+  SDValue FVal = DAG.getConstant(0, MVT::i32);<br>
+  EVT VT = Op.getValueType();<br>
+<br>
+  SDValue Overflow = DAG.getNode(ARMISD::CMOV, SDLoc(Op), VT, TVal, FVal,<br>
+                                 ARMcc, CCR, OverflowCmp);<br>
+<br>
+  SDVTList VTs = DAG.getVTList(Op.getValueType(), MVT::i32);<br>
+  return DAG.getNode(ISD::MERGE_VALUES, SDLoc(Op), VTs, Value, Overflow);<br>
+}<br>
+<br>
+<br>
 SDValue ARMTargetLowering::LowerSELECT(SDValue Op, SelectionDAG &DAG) const {<br>
   SDValue Cond = Op.getOperand(0);<br>
   SDValue SelectTrue = Op.getOperand(1);<br>
   SDValue SelectFalse = Op.getOperand(2);<br>
   SDLoc dl(Op);<br>
+  unsigned Opc = Cond.getOpcode();<br>
+<br>
+  if (Cond.getResNo() == 1 &&<br>
+      (Opc == ISD::SADDO || Opc == ISD::UADDO || Opc == ISD::SSUBO ||<br>
+       Opc == ISD::USUBO)) {<br>
+    if (!DAG.getTargetLoweringInfo().isTypeLegal(Cond->getValueType(0)))<br>
+      return SDValue();<br>
+<br>
+    SDValue Value, OverflowCmp;<br>
+    SDValue ARMcc;<br>
+    std::tie(Value, OverflowCmp) = getARMXALUOOp(Cond, DAG, ARMcc);<br>
+    SDValue CCR = DAG.getRegister(ARM::CPSR, MVT::i32);<br>
+    EVT VT = Op.getValueType();<br>
+<br>
+    return DAG.getNode(ARMISD::CMOV, SDLoc(Op), VT, SelectTrue, SelectFalse,<br>
+                       ARMcc, CCR, OverflowCmp);<br>
+<br>
+  }<br>
<br>
   // Convert:<br>
   //<br>
@@ -6139,6 +6229,11 @@ SDValue ARMTargetLowering::LowerOperatio<br>
   case ISD::ADDE:<br>
   case ISD::SUBC:<br>
   case ISD::SUBE:          return LowerADDC_ADDE_SUBC_SUBE(Op, DAG);<br>
+  case ISD::SADDO:<br>
+  case ISD::UADDO:<br>
+  case ISD::SSUBO:<br>
+  case ISD::USUBO:<br>
+    return LowerXALUO(Op, DAG);<br>
   case ISD::ATOMIC_LOAD:<br>
   case ISD::ATOMIC_STORE:  return LowerAtomicLoadStore(Op, DAG);<br>
   case ISD::FSINCOS:       return LowerFSINCOS(Op, DAG);<br>
<br>
Modified: llvm/trunk/lib/Target/ARM/ARMISelLowering.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMISelLowering.h?rev=208435&r1=208434&r2=208435&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMISelLowering.h?rev=208435&r1=208434&r2=208435&view=diff</a><br>


==============================================================================<br>
--- llvm/trunk/lib/Target/ARM/ARMISelLowering.h (original)<br>
+++ llvm/trunk/lib/Target/ARM/ARMISelLowering.h Fri May  9 12:02:49 2014<br>
@@ -416,6 +416,7 @@ namespace llvm {<br>
     void addTypeForNEON(MVT VT, MVT PromotedLdStVT, MVT PromotedBitwiseVT);<br>
     void addDRTypeForNEON(MVT VT);<br>
     void addQRTypeForNEON(MVT VT);<br>
+    std::pair<SDValue, SDValue> getARMXALUOOp(SDValue Op, SelectionDAG &DAG, SDValue &ARMcc) const;<br>
<br>
     typedef SmallVector<std::pair<unsigned, SDValue>, 8> RegsToPassVector;<br>
     void PassF64ArgInRegs(SDLoc dl, SelectionDAG &DAG,<br>
@@ -453,6 +454,7 @@ namespace llvm {<br>
                                  TLSModel::Model model) const;<br>
     SDValue LowerGLOBAL_OFFSET_TABLE(SDValue Op, SelectionDAG &DAG) const;<br>
     SDValue LowerBR_JT(SDValue Op, SelectionDAG &DAG) const;<br>
+    SDValue LowerXALUO(SDValue Op, SelectionDAG &DAG) const;<br>
     SDValue LowerSELECT(SDValue Op, SelectionDAG &DAG) const;<br>
     SDValue LowerSELECT_CC(SDValue Op, SelectionDAG &DAG) const;<br>
     SDValue LowerBR_CC(SDValue Op, SelectionDAG &DAG) const;<br>
<br>
Added: llvm/trunk/test/CodeGen/ARM/intrinsics-overflow.ll<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/ARM/intrinsics-overflow.ll?rev=208435&view=auto" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/ARM/intrinsics-overflow.ll?rev=208435&view=auto</a><br>


==============================================================================<br>
--- llvm/trunk/test/CodeGen/ARM/intrinsics-overflow.ll (added)<br>
+++ llvm/trunk/test/CodeGen/ARM/intrinsics-overflow.ll Fri May  9 12:02:49 2014<br>
@@ -0,0 +1,57 @@<br>
+; RUN: llc < %s -march=arm -mcpu=generic | FileCheck %s<br>
+<br>
+define i32 @uadd_overflow(i32 %a, i32 %b) #0 {<br>
+  %sadd = tail call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 %a, i32 %b)<br>
+  %1 = extractvalue { i32, i1 } %sadd, 1<br>
+  %2 = zext i1 %1 to i32<br>
+  ret i32 %2<br>
+<br>
+  ; CHECK-LABEL: uadd_overflow:<br>
+  ; CHECK: add r[[R2:[0-9]+]], r[[R0:[0-9]+]], r[[R1:[0-9]+]]<br>
+  ; CHECK: mov r[[R1]], #1<br>
+  ; CHECK: cmp r[[R2]], r[[R0]]<br>
+  ; CHECK: movhs r[[R1]], #0<br>
+}<br>
+<br>
+<br>
+define i32 @sadd_overflow(i32 %a, i32 %b) #0 {<br>
+  %sadd = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %a, i32 %b)<br>
+  %1 = extractvalue { i32, i1 } %sadd, 1<br>
+  %2 = zext i1 %1 to i32<br>
+  ret i32 %2<br>
+<br>
+  ; CHECK-LABEL: sadd_overflow:<br>
+  ; CHECK: add r[[R2:[0-9]+]], r[[R0:[0-9]+]], r[[R1:[0-9]+]]<br>
+  ; CHECK: mov r[[R1]], #1<br>
+  ; CHECK: cmp r[[R2]], r[[R0]]<br>
+  ; CHECK: movvc r[[R1]], #0<br>
+}<br>
+<br>
+define i32 @usub_overflow(i32 %a, i32 %b) #0 {<br>
+  %sadd = tail call { i32, i1 } @llvm.usub.with.overflow.i32(i32 %a, i32 %b)<br>
+  %1 = extractvalue { i32, i1 } %sadd, 1<br>
+  %2 = zext i1 %1 to i32<br>
+  ret i32 %2<br>
+<br>
+  ; CHECK-LABEL: usub_overflow:<br>
+  ; CHECK: mov r[[R2]], #1<br>
+  ; CHECK: cmp r[[R0]], r[[R1]]<br>
+  ; CHECK: movhs r[[R2]], #0<br>
+}<br>
+<br>
+define i32 @ssub_overflow(i32 %a, i32 %b) #0 {<br>
+  %sadd = tail call { i32, i1 } @llvm.ssub.with.overflow.i32(i32 %a, i32 %b)<br>
+  %1 = extractvalue { i32, i1 } %sadd, 1<br>
+  %2 = zext i1 %1 to i32<br>
+  ret i32 %2<br>
+<br>
+  ; CHECK-LABEL: ssub_overflow:<br>
+  ; CHECK: mov r[[R2]], #1<br>
+  ; CHECK: cmp r[[R0]], r[[R1]]<br>
+  ; CHECK: movvc r[[R2]], #0<br>
+}<br>
+<br>
+declare { i32, i1 } @llvm.uadd.with.overflow.i32(i32, i32) #1<br>
+declare { i32, i1 } @llvm.sadd.with.overflow.i32(i32, i32) #2<br>
+declare { i32, i1 } @llvm.usub.with.overflow.i32(i32, i32) #3<br>
+declare { i32, i1 } @llvm.ssub.with.overflow.i32(i32, i32) #4<br>
<br>
<br>
_______________________________________________<br>
llvm-commits mailing list<br>
<a href="mailto:llvm-commits@cs.uiuc.edu" target="_blank">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>
</div></div></blockquote></div><br></div>