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;
}