GlobalISel: legalize sdiv and srem operations.
authorTim Northover <tnorthover@apple.com>
Fri, 26 Aug 2016 17:46:13 +0000 (17:46 +0000)
committerTim Northover <tnorthover@apple.com>
Fri, 26 Aug 2016 17:46:13 +0000 (17:46 +0000)
llvm-svn: 279842

llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h
llvm/include/llvm/CodeGen/GlobalISel/MachineLegalizeHelper.h
llvm/include/llvm/CodeGen/GlobalISel/MachineLegalizer.h
llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp
llvm/lib/CodeGen/GlobalISel/MachineLegalizeHelper.cpp
llvm/lib/CodeGen/GlobalISel/MachineLegalizer.cpp
llvm/lib/Target/AArch64/AArch64MachineLegalizer.cpp
llvm/test/CodeGen/AArch64/GlobalISel/legalize-rem.mir [new file with mode: 0644]
llvm/unittests/CodeGen/GlobalISel/MachineLegalizerTest.cpp

index c990ebe..24ab286 100644 (file)
@@ -144,6 +144,28 @@ public:
   MachineInstrBuilder buildAdd(LLT Ty, unsigned Res, unsigned Op0,
                                 unsigned Op1);
 
+  /// Build and insert \p Res<def> = 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<def> = 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<def>, \p CarryOut = G_UADDE \p Tys \p Op0, \p Op1,
   /// \p CarryIn
   ///
index d2b1d88..c3ba735 100644 (file)
@@ -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,
index 439f2ae..c6f453c 100644 (file)
@@ -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.
index dfa252d..76555f9 100644 (file)
@@ -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);
 }
index 401f29a..ec59c83 100644 (file)
@@ -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:
@@ -269,6 +271,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) {
   assert(TypeIdx == 0 && "don't know how to handle secondary types yet");
index 873288e..c6ee362 100644 (file)
@@ -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,
index 0c9addf..681d137 100644 (file)
@@ -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/llvm/test/CodeGen/AArch64/GlobalISel/legalize-rem.mir b/llvm/test/CodeGen/AArch64/GlobalISel/legalize-rem.mir
new file mode 100644 (file)
index 0000000..cfd0958
--- /dev/null
@@ -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
+
+...
index 946f3b4..f7544af 100644 (file)
@@ -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;