[Sparc] Added software multiplication/division feature
authorJames Y Knight <jyknight@google.com>
Tue, 18 Jul 2017 19:08:38 +0000 (19:08 +0000)
committerJames Y Knight <jyknight@google.com>
Tue, 18 Jul 2017 19:08:38 +0000 (19:08 +0000)
Added a feature to the Sparc back-end that replaces the integer multiply and
divide instructions with calls to .mul/.sdiv/.udiv. This is a step towards
having full v7 support.

Patch by: Eric Kedaigle
Differential Revision: https://reviews.llvm.org/D35500

llvm-svn: 308343

llvm/lib/Target/Sparc/Sparc.td
llvm/lib/Target/Sparc/SparcISelLowering.cpp
llvm/lib/Target/Sparc/SparcInstrInfo.td
llvm/lib/Target/Sparc/SparcSubtarget.h
llvm/test/CodeGen/SPARC/soft-mul-div.ll [new file with mode: 0644]

index 11004c5..91cab00 100644 (file)
@@ -20,6 +20,10 @@ include "llvm/Target/Target.td"
 // SPARC Subtarget features.
 //
 
+def FeatureSoftMulDiv
+  : SubtargetFeature<"soft-mul-div", "UseSoftMulDiv", "true",
+                     "Use software emulation for integer multiply and divide">;
+
 def FeatureV9
   : SubtargetFeature<"v9", "IsV9", "true",
                      "Enable SPARC-V9 instructions">;
@@ -75,7 +79,7 @@ class Proc<string Name, list<SubtargetFeature> Features>
  : Processor<Name, NoItineraries, Features>;
 
 def : Proc<"generic",         []>;
-def : Proc<"v7",              []>;
+def : Proc<"v7",              [FeatureSoftMulDiv]>;
 def : Proc<"v8",              []>;
 def : Proc<"supersparc",      []>;
 def : Proc<"sparclite",       []>;
index 9e7e3c6..6767a59 100644 (file)
@@ -1689,6 +1689,19 @@ SparcTargetLowering::SparcTargetLowering(const TargetMachine &TM,
   setOperationAction(ISD::MULHS,     MVT::i32, Expand);
   setOperationAction(ISD::MUL,       MVT::i32, Expand);
 
+  if (Subtarget->useSoftMulDiv()) {
+    // .umul works for both signed and unsigned
+    setOperationAction(ISD::SMUL_LOHI, MVT::i32, Expand);
+    setOperationAction(ISD::UMUL_LOHI, MVT::i32, Expand);
+    setLibcallName(RTLIB::MUL_I32, ".umul");
+
+    setOperationAction(ISD::SDIV, MVT::i32, Expand);
+    setLibcallName(RTLIB::SDIV_I32, ".div");
+
+    setOperationAction(ISD::UDIV, MVT::i32, Expand);
+    setLibcallName(RTLIB::UDIV_I32, ".udiv");
+  }
+
   if (Subtarget->is64Bit()) {
     setOperationAction(ISD::UMUL_LOHI, MVT::i64, Expand);
     setOperationAction(ISD::SMUL_LOHI, MVT::i64, Expand);
index ae45c8b..3194ad4 100644 (file)
@@ -27,6 +27,9 @@ def Is32Bit : Predicate<"!Subtarget->is64Bit()">;
 // True when generating 64-bit code. This also implies HasV9.
 def Is64Bit : Predicate<"Subtarget->is64Bit()">;
 
+def UseSoftMulDiv : Predicate<"Subtarget->useSoftMulDiv()">,
+              AssemblerPredicate<"FeatureSoftMulDiv">;
+
 // HasV9 - This predicate is true when the target processor supports V9
 // instructions.  Note that the machine may be running in 32-bit mode.
 def HasV9   : Predicate<"Subtarget->isV9()">,
index fa42da4..d181399 100644 (file)
@@ -32,6 +32,7 @@ class StringRef;
 class SparcSubtarget : public SparcGenSubtargetInfo {
   Triple TargetTriple;
   virtual void anchor();
+  bool UseSoftMulDiv;
   bool IsV9;
   bool IsLeon;
   bool V8DeprecatedInsts;
@@ -76,6 +77,7 @@ public:
 
   bool enableMachineScheduler() const override;
 
+  bool useSoftMulDiv() const { return UseSoftMulDiv; }
   bool isV9() const { return IsV9; }
   bool isLeon() const { return IsLeon; }
   bool isVIS() const { return IsVIS; }
diff --git a/llvm/test/CodeGen/SPARC/soft-mul-div.ll b/llvm/test/CodeGen/SPARC/soft-mul-div.ll
new file mode 100644 (file)
index 0000000..7c453dd
--- /dev/null
@@ -0,0 +1,65 @@
+; RUN: llc -march=sparc -mcpu=v7 -O0 < %s | FileCheck %s
+
+define i32 @test_mul32(i32 %a, i32 %b) #0 {
+    ; CHECK-LABEL: test_mul32
+    ; CHECK:       call .umul
+    %m = mul i32 %a, %b
+    ret i32 %m
+}
+
+define i16 @test_mul16(i16 %a, i16 %b) #0 {
+    ; CHECK-LABEL: test_mul16
+    ; CHECK:       call .umul
+    %m = mul i16 %a, %b
+    ret i16 %m
+}
+
+define i8 @test_mul8(i8 %a, i8 %b) #0 {
+    ; CHECK-LABEL: test_mul8
+    ; CHECK:       call .umul
+    %m = mul i8 %a, %b
+    ret i8 %m
+}
+
+define i32 @test_sdiv32(i32 %a, i32 %b) #0 {
+    ; CHECK-LABEL: test_sdiv32
+    ; CHECK:       call .div
+    %d = sdiv i32 %a, %b
+    ret i32 %d
+}
+
+define i16 @test_sdiv16(i16 %a, i16 %b) #0 {
+    ; CHECK-LABEL: test_sdiv16
+    ; CHECK:       call .div
+    %d = sdiv i16 %a, %b
+    ret i16 %d
+}
+
+define i8 @test_sdiv8(i8 %a, i8 %b) #0 {
+    ; CHECK-LABEL: test_sdiv8
+    ; CHECK:       call .div
+    %d = sdiv i8 %a, %b
+    ret i8 %d
+}
+
+define i32 @test_udiv32(i32 %a, i32 %b) #0 {
+    ; CHECK-LABEL: test_udiv32
+    ; CHECK:       call .udiv
+    %d = udiv i32 %a, %b
+    ret i32 %d
+}
+
+define i16 @test_udiv16(i16 %a, i16 %b) #0 {
+    ; CHECK-LABEL: test_udiv16
+    ; CHECK:       call .udiv
+    %d = udiv i16 %a, %b
+    ret i16 %d
+}
+
+define i8 @test_udiv8(i8 %a, i8 %b) #0 {
+    ; CHECK-LABEL: test_udiv8
+    ; CHECK:       call .udiv
+    %d = udiv i8 %a, %b
+    ret i8 %d
+}
+