diff --git a/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h b/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h index c990ebe49ac..24ab286b51f 100644 --- a/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h +++ b/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h @@ -144,6 +144,28 @@ public: MachineInstrBuilder buildAdd(LLT Ty, unsigned Res, unsigned Op0, unsigned Op1); + /// Build and insert \p Res = G_SUB \p Ty \p Op0, \p Op1 + /// + /// G_SUB sets \p Res to the sum of integer parameters \p Op0 and \p Op1, + /// truncated to their width. + /// + /// \pre setBasicBlock or setMI must have been called. + /// + /// \return a MachineInstrBuilder for the newly created instruction. + MachineInstrBuilder buildSub(LLT Ty, unsigned Res, unsigned Op0, + unsigned Op1); + + /// Build and insert \p Res = G_MUL \p Ty \p Op0, \p Op1 + /// + /// G_MUL sets \p Res to the sum of integer parameters \p Op0 and \p Op1, + /// truncated to their width. + /// + /// \pre setBasicBlock or setMI must have been called. + /// + /// \return a MachineInstrBuilder for the newly created instruction. + MachineInstrBuilder buildMul(LLT Ty, unsigned Res, unsigned Op0, + unsigned Op1); + /// Build and insert \p Res, \p CarryOut = G_UADDE \p Tys \p Op0, \p Op1, /// \p CarryIn /// diff --git a/include/llvm/CodeGen/GlobalISel/MachineLegalizeHelper.h b/include/llvm/CodeGen/GlobalISel/MachineLegalizeHelper.h index d2b1d88d530..c3ba7354282 100644 --- a/include/llvm/CodeGen/GlobalISel/MachineLegalizeHelper.h +++ b/include/llvm/CodeGen/GlobalISel/MachineLegalizeHelper.h @@ -70,6 +70,10 @@ public: /// precision, ignoring the unused bits). LegalizeResult widenScalar(MachineInstr &MI, unsigned TypeIdx, LLT WideTy); + /// Legalize an instruction by splitting it into simpler parts, hopefully + /// understood by the target. + LegalizeResult lower(MachineInstr &MI, unsigned TypeIdx, LLT Ty); + /// Legalize a vector instruction by splitting into multiple components, each /// acting on the same scalar type as the original but with fewer elements. LegalizeResult fewerElementsVector(MachineInstr &MI, unsigned TypeIdx, diff --git a/include/llvm/CodeGen/GlobalISel/MachineLegalizer.h b/include/llvm/CodeGen/GlobalISel/MachineLegalizer.h index 439f2aeae40..c6f453c795e 100644 --- a/include/llvm/CodeGen/GlobalISel/MachineLegalizer.h +++ b/include/llvm/CodeGen/GlobalISel/MachineLegalizer.h @@ -87,6 +87,10 @@ public: /// the first two results. MoreElements, + /// The operation itself must be expressed in terms of simpler actions on + /// this target. E.g. a SREM replaced by an SDIV and subtraction. + Lower, + /// The operation should be implemented as a call to some kind of runtime /// support library. For example this usually happens on machines that don't /// support floating-point operations natively. diff --git a/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp b/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp index dfa252d0b62..76555f99c58 100644 --- a/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp +++ b/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp @@ -99,6 +99,22 @@ MachineInstrBuilder MachineIRBuilder::buildAdd(LLT Ty, unsigned Res, .addUse(Op1); } +MachineInstrBuilder MachineIRBuilder::buildSub(LLT Ty, unsigned Res, + unsigned Op0, unsigned Op1) { + return buildInstr(TargetOpcode::G_SUB, Ty) + .addDef(Res) + .addUse(Op0) + .addUse(Op1); +} + +MachineInstrBuilder MachineIRBuilder::buildMul(LLT Ty, unsigned Res, + unsigned Op0, unsigned Op1) { + return buildInstr(TargetOpcode::G_MUL, Ty) + .addDef(Res) + .addUse(Op0) + .addUse(Op1); +} + MachineInstrBuilder MachineIRBuilder::buildBr(MachineBasicBlock &Dest) { return buildInstr(TargetOpcode::G_BR, LLT::unsized()).addMBB(&Dest); } diff --git a/lib/CodeGen/GlobalISel/MachineLegalizeHelper.cpp b/lib/CodeGen/GlobalISel/MachineLegalizeHelper.cpp index 401f29a6ddc..ec59c834296 100644 --- a/lib/CodeGen/GlobalISel/MachineLegalizeHelper.cpp +++ b/lib/CodeGen/GlobalISel/MachineLegalizeHelper.cpp @@ -42,6 +42,8 @@ MachineLegalizeHelper::legalizeInstrStep(MachineInstr &MI, return narrowScalar(MI, std::get<1>(Action), std::get<2>(Action)); case MachineLegalizer::WidenScalar: return widenScalar(MI, std::get<1>(Action), std::get<2>(Action)); + case MachineLegalizer::Lower: + return lower(MI, std::get<1>(Action), std::get<2>(Action)); case MachineLegalizer::FewerElements: return fewerElementsVector(MI, std::get<1>(Action), std::get<2>(Action)); default: @@ -268,6 +270,33 @@ MachineLegalizeHelper::widenScalar(MachineInstr &MI, unsigned TypeIdx, } } +MachineLegalizeHelper::LegalizeResult +MachineLegalizeHelper::lower(MachineInstr &MI, unsigned TypeIdx, LLT Ty) { + using namespace TargetOpcode; + unsigned Size = Ty.getSizeInBits(); + MIRBuilder.setInstr(MI); + + switch(MI.getOpcode()) { + default: + return UnableToLegalize; + case TargetOpcode::G_SREM: + case TargetOpcode::G_UREM: { + unsigned QuotReg = MRI.createGenericVirtualRegister(Size); + MIRBuilder.buildInstr(MI.getOpcode() == G_SREM ? G_SDIV : G_UDIV, Ty) + .addDef(QuotReg) + .addUse(MI.getOperand(1).getReg()) + .addUse(MI.getOperand(2).getReg()); + + unsigned ProdReg = MRI.createGenericVirtualRegister(Size); + MIRBuilder.buildMul(Ty, ProdReg, QuotReg, MI.getOperand(2).getReg()); + MIRBuilder.buildSub(Ty, MI.getOperand(0).getReg(), + MI.getOperand(1).getReg(), ProdReg); + MI.eraseFromParent(); + return Legalized; + } + } +} + MachineLegalizeHelper::LegalizeResult MachineLegalizeHelper::fewerElementsVector(MachineInstr &MI, unsigned TypeIdx, LLT NarrowTy) { diff --git a/lib/CodeGen/GlobalISel/MachineLegalizer.cpp b/lib/CodeGen/GlobalISel/MachineLegalizer.cpp index 873288ee42c..c6ee362c63f 100644 --- a/lib/CodeGen/GlobalISel/MachineLegalizer.cpp +++ b/lib/CodeGen/GlobalISel/MachineLegalizer.cpp @@ -126,6 +126,7 @@ LLT MachineLegalizer::findLegalType(const InstrAspect &Aspect, default: llvm_unreachable("Cannot find legal type"); case Legal: + case Lower: return Aspect.Type; case NarrowScalar: { return findLegalType(Aspect, diff --git a/lib/Target/AArch64/AArch64MachineLegalizer.cpp b/lib/Target/AArch64/AArch64MachineLegalizer.cpp index 0c9addf83ba..681d1378ca2 100644 --- a/lib/Target/AArch64/AArch64MachineLegalizer.cpp +++ b/lib/Target/AArch64/AArch64MachineLegalizer.cpp @@ -51,6 +51,10 @@ AArch64MachineLegalizer::AArch64MachineLegalizer() { setAction({BinOp, Ty}, WidenScalar); } + for (auto BinOp : { G_SREM, G_UREM }) + for (auto Ty : { s1, s8, s16, s32, s64 }) + setAction({BinOp, Ty}, Lower); + for (auto Op : { G_UADDE, G_USUBE, G_SADDO, G_SSUBO, G_SMULO, G_UMULO }) { for (auto Ty : { s32, s64 }) setAction({Op, Ty}, Legal); diff --git a/test/CodeGen/AArch64/GlobalISel/legalize-rem.mir b/test/CodeGen/AArch64/GlobalISel/legalize-rem.mir new file mode 100644 index 00000000000..cfd0958dae3 --- /dev/null +++ b/test/CodeGen/AArch64/GlobalISel/legalize-rem.mir @@ -0,0 +1,52 @@ +# RUN: llc -O0 -run-pass=legalize-mir -global-isel %s -o - 2>&1 | FileCheck %s + +--- | + target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128" + target triple = "aarch64-apple-ios" + define void @test_rem() { + entry: + ret void + } +... + +--- +name: test_rem +registers: + - { id: 0, class: _ } + - { id: 1, class: _ } + - { id: 2, class: _ } + - { id: 3, class: _ } + - { id: 4, class: _ } + - { id: 5, class: _ } + - { id: 6, class: _ } + - { id: 7, class: _ } + - { id: 8, class: _ } +body: | + bb.0.entry: + liveins: %x0, %x1, %x2, %x3 + + ; CHECK: [[QUOT:%[0-9]+]](64) = G_UDIV s64 %0, %1 + ; CHECK: [[PROD:%[0-9]+]](64) = G_MUL s64 [[QUOT]], %1 + ; CHECK: [[RES:%[0-9]+]](64) = G_SUB s64 %0, [[PROD]] + %0(64) = COPY %x0 + %1(64) = COPY %x1 + %2(64) = G_UREM s64 %0, %1 + + ; CHECK: [[QUOT:%[0-9]+]](32) = G_SDIV s32 %3, %4 + ; CHECK: [[PROD:%[0-9]+]](32) = G_MUL s32 [[QUOT]], %4 + ; CHECK: [[RES:%[0-9]+]](32) = G_SUB s32 %3, [[PROD]] + %3(32) = G_TRUNC { s32, s64 } %0 + %4(32) = G_TRUNC { s32, s64 } %1 + %5(32) = G_SREM s32 %3, %4 + + ; CHECK: [[LHS32:%[0-9]+]](32) = G_SEXT { s32, s8 } %6 + ; CHECK: [[RHS32:%[0-9]+]](32) = G_SEXT { s32, s8 } %7 + ; CHECK: [[QUOT32:%[0-9]+]](32) = G_SDIV s32 [[LHS32]], [[RHS32]] + ; CHECK: [[QUOT:%[0-9]+]](8) = G_TRUNC { s8, s32 } [[QUOT32]] + ; CHECK: [[PROD:%[0-9]+]](8) = G_MUL s8 [[QUOT]], %7 + ; CHECK: [[RES:%[0-9]+]](8) = G_SUB s8 %6, [[PROD]] + %6(8) = G_TRUNC { s8, s64 } %0 + %7(8) = G_TRUNC { s8, s64 } %1 + %8(8) = G_SREM s8 %6, %7 + +... diff --git a/unittests/CodeGen/GlobalISel/MachineLegalizerTest.cpp b/unittests/CodeGen/GlobalISel/MachineLegalizerTest.cpp index 946f3b4c0c9..f7544af25b4 100644 --- a/unittests/CodeGen/GlobalISel/MachineLegalizerTest.cpp +++ b/unittests/CodeGen/GlobalISel/MachineLegalizerTest.cpp @@ -13,6 +13,7 @@ using namespace llvm; using llvm::MachineLegalizer::LegalizeAction::Legal; +using llvm::MachineLegalizer::LegalizeAction::Lower; using llvm::MachineLegalizer::LegalizeAction::NarrowScalar; using llvm::MachineLegalizer::LegalizeAction::WidenScalar; using llvm::MachineLegalizer::LegalizeAction::FewerElements; @@ -26,6 +27,7 @@ namespace llvm { std::ostream & operator<<(std::ostream &OS, const llvm::MachineLegalizer::LegalizeAction Act) { switch (Act) { + case Lower: OS << "Lower"; break; case Legal: OS << "Legal"; break; case NarrowScalar: OS << "NarrowScalar"; break; case WidenScalar: OS << "WidenScalar"; break;