GlobalISel: support overflow arithmetic intrinsics.

Unsigned addition and subtraction can reuse the instructions created to
legalize large width operations (i.e. both produce and consume a carry flag).
Signed operations and multiplies get a dedicated op-with-overflow instruction.

Once this is produced the two values are combined into a struct register (which
will almost always be merged with a corresponding G_EXTRACT as part of
legalization).

llvm-svn: 279278
diff --git a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
index a7b6d20..ac95b82 100644
--- a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
@@ -204,6 +204,41 @@
   return true;
 }
 
+bool IRTranslator::translateKnownIntrinsic(const CallInst &CI,
+                                           Intrinsic::ID ID) {
+  unsigned Op = 0;
+  switch (ID) {
+  default: return false;
+  case Intrinsic::uadd_with_overflow: Op = TargetOpcode::G_UADDE; break;
+  case Intrinsic::sadd_with_overflow: Op = TargetOpcode::G_SADDO; break;
+  case Intrinsic::usub_with_overflow: Op = TargetOpcode::G_USUBE; break;
+  case Intrinsic::ssub_with_overflow: Op = TargetOpcode::G_SSUBO; break;
+  case Intrinsic::umul_with_overflow: Op = TargetOpcode::G_UMULO; break;
+  case Intrinsic::smul_with_overflow: Op = TargetOpcode::G_SMULO; break;
+  }
+
+  LLT Ty{*CI.getOperand(0)->getType()};
+  LLT s1 = LLT::scalar(1);
+  unsigned Width = Ty.getSizeInBits();
+  unsigned Res = MRI->createGenericVirtualRegister(Width);
+  unsigned Overflow = MRI->createGenericVirtualRegister(1);
+  auto MIB = MIRBuilder.buildInstr(Op, {Ty, s1})
+                 .addDef(Res)
+                 .addDef(Overflow)
+                 .addUse(getOrCreateVReg(*CI.getOperand(0)))
+                 .addUse(getOrCreateVReg(*CI.getOperand(1)));
+
+  if (Op == TargetOpcode::G_UADDE || Op == TargetOpcode::G_USUBE) {
+    unsigned Zero = MRI->createGenericVirtualRegister(1);
+    EntryBuilder.buildConstant(s1, Zero, 0);
+    MIB.addUse(Zero);
+  }
+
+  MIRBuilder.buildSequence(LLT{*CI.getType(), DL}, getOrCreateVReg(CI), Res, 0,
+                           Overflow, Width);
+  return true;
+}
+
 bool IRTranslator::translateCall(const User &U) {
   const CallInst &CI = cast<CallInst>(U);
   auto TII = MIRBuilder.getMF().getTarget().getIntrinsicInfo();
@@ -227,6 +262,9 @@
 
   assert(ID != Intrinsic::not_intrinsic && "unknown intrinsic");
 
+  if (translateKnownIntrinsic(CI, ID))
+    return true;
+
   // Need types (starting with return) & args.
   SmallVector<LLT, 4> Tys;
   Tys.emplace_back(*CI.getType());
diff --git a/llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp b/llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp
index 70a2441..92dbab0 100644
--- a/llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp
@@ -124,11 +124,11 @@
       .addMemOperand(&MMO);
 }
 
-MachineInstrBuilder MachineIRBuilder::buildAdde(LLT Ty, unsigned Res,
-                                                unsigned CarryOut, unsigned Op0,
-                                                unsigned Op1,
-                                                unsigned CarryIn) {
-  return buildInstr(TargetOpcode::G_ADDE, Ty)
+MachineInstrBuilder MachineIRBuilder::buildUAdde(LLT Ty, unsigned Res,
+                                                 unsigned CarryOut,
+                                                 unsigned Op0, unsigned Op1,
+                                                 unsigned CarryIn) {
+  return buildInstr(TargetOpcode::G_UADDE, Ty)
       .addDef(Res)
       .addDef(CarryOut)
       .addUse(Op0)
@@ -157,12 +157,18 @@
   return MIB;
 }
 
-MachineInstrBuilder MachineIRBuilder::buildSequence(LLT Ty, unsigned Res,
-                                              ArrayRef<unsigned> Ops) {
+MachineInstrBuilder
+MachineIRBuilder::buildSequence(LLT Ty, unsigned Res,
+                                ArrayRef<unsigned> Ops,
+                                ArrayRef<unsigned> Indexes) {
+  assert(Ops.size() == Indexes.size() && "incompatible args");
+
   MachineInstrBuilder MIB = buildInstr(TargetOpcode::G_SEQUENCE, Ty);
   MIB.addDef(Res);
-  for (auto Op : Ops)
-    MIB.addUse(Op);
+  for (unsigned i = 0; i < Ops.size(); ++i) {
+    MIB.addUse(Ops[i]);
+    MIB.addImm(Indexes[i]);
+  }
   return MIB;
 }
 
diff --git a/llvm/lib/CodeGen/GlobalISel/MachineLegalizeHelper.cpp b/llvm/lib/CodeGen/GlobalISel/MachineLegalizeHelper.cpp
index 01d87d1..d999fbe8 100644
--- a/llvm/lib/CodeGen/GlobalISel/MachineLegalizeHelper.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/MachineLegalizeHelper.cpp
@@ -71,7 +71,7 @@
 
     MIRBuilder.setInstr(MI);
 
-    SmallVector<unsigned, 2> Src1Regs, Src2Regs, DstRegs;
+    SmallVector<unsigned, 2> Src1Regs, Src2Regs, DstRegs, Indexes;
     extractParts(MI.getOperand(1).getReg(), NarrowTy, NumParts, Src1Regs);
     extractParts(MI.getOperand(2).getReg(), NarrowTy, NumParts, Src2Regs);
 
@@ -82,13 +82,15 @@
       unsigned DstReg = MRI.createGenericVirtualRegister(NarrowSize);
       unsigned CarryOut = MRI.createGenericVirtualRegister(1);
 
-      MIRBuilder.buildAdde(NarrowTy, DstReg, CarryOut, Src1Regs[i], Src2Regs[i],
-                           CarryIn);
+      MIRBuilder.buildUAdde(NarrowTy, DstReg, CarryOut, Src1Regs[i],
+                            Src2Regs[i], CarryIn);
 
       DstRegs.push_back(DstReg);
+      Indexes.push_back(i * NarrowSize);
       CarryIn = CarryOut;
     }
-    MIRBuilder.buildSequence(MI.getType(), MI.getOperand(0).getReg(), DstRegs);
+    MIRBuilder.buildSequence(MI.getType(), MI.getOperand(0).getReg(), DstRegs,
+                             Indexes);
     MI.eraseFromParent();
     return Legalized;
   }
@@ -140,7 +142,7 @@
 
     MIRBuilder.setInstr(MI);
 
-    SmallVector<unsigned, 2> Src1Regs, Src2Regs, DstRegs;
+    SmallVector<unsigned, 2> Src1Regs, Src2Regs, DstRegs, Indexes;
     extractParts(MI.getOperand(1).getReg(), NarrowTy, NumParts, Src1Regs);
     extractParts(MI.getOperand(2).getReg(), NarrowTy, NumParts, Src2Regs);
 
@@ -148,9 +150,11 @@
       unsigned DstReg = MRI.createGenericVirtualRegister(NarrowSize);
       MIRBuilder.buildAdd(NarrowTy, DstReg, Src1Regs[i], Src2Regs[i]);
       DstRegs.push_back(DstReg);
+      Indexes.push_back(i * NarrowSize);
     }
 
-    MIRBuilder.buildSequence(MI.getType(), MI.getOperand(0).getReg(), DstRegs);
+    MIRBuilder.buildSequence(MI.getType(), MI.getOperand(0).getReg(), DstRegs,
+                             Indexes);
     MI.eraseFromParent();
     return Legalized;
   }