]> granicus.if.org Git - llvm/commitdiff
[ARM] Add new target feature to fuse literal generation
authorEvandro Menezes <e.menezes@samsung.com>
Fri, 27 Jul 2018 18:16:47 +0000 (18:16 +0000)
committerEvandro Menezes <e.menezes@samsung.com>
Fri, 27 Jul 2018 18:16:47 +0000 (18:16 +0000)
This feature enables the fusion of such operations on Cortex A57 and Cortex
A72, as recommended in their Software Optimisation Guides, sections 4.14 and
4.11, respectively.

Differential revision: https://reviews.llvm.org/D49563

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@338147 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Target/ARM/ARM.td
lib/Target/ARM/ARMMacroFusion.cpp
lib/Target/ARM/ARMSubtarget.h
test/CodeGen/ARM/misched-fusion-lit.ll [new file with mode: 0644]

index 742b355188948becdb82bebc87905a582a53b96b..2e62a07904188004b718afea8d1acdeaaf173183 100644 (file)
@@ -141,6 +141,10 @@ def FeatureFPAO           : SubtargetFeature<"fpao", "HasFPAO", "true",
 def FeatureFuseAES        : SubtargetFeature<"fuse-aes", "HasFuseAES", "true",
                                              "CPU fuses AES crypto operations">;
 
+// Fast execution of bottom and top halves of literal generation
+def FeatureFuseLiterals   : SubtargetFeature<"fuse-literals", "HasFuseLiterals", "true",
+                                             "CPU fuses literal generation operations">;
+
 // The way of reading thread pointer                                             
 def FeatureReadTp :  SubtargetFeature<"read-tp-hard", "ReadTPHard", "true",
                                       "Reading thread pointer from register">;
index f2dc650a6f3ea94d8724423d3f366f2b5286890a..d11fe9d5c502dccfc575c0a00432010eb0072cb8 100644 (file)
 
 namespace llvm {
 
+// Fuse AES crypto encoding or decoding.
+static bool isAESPair(const MachineInstr *FirstMI,
+                      const MachineInstr &SecondMI) {
+  // Assume the 1st instr to be a wildcard if it is unspecified.
+  unsigned FirstOpcode =
+      FirstMI ? FirstMI->getOpcode()
+              : static_cast<unsigned>(ARM::INSTRUCTION_LIST_END);
+  unsigned SecondOpcode = SecondMI.getOpcode();
+
+  switch(SecondOpcode) {
+  // AES encode.
+  case ARM::AESMC :
+    return FirstOpcode == ARM::AESE ||
+           FirstOpcode == ARM::INSTRUCTION_LIST_END;
+  // AES decode.
+  case ARM::AESIMC:
+    return FirstOpcode == ARM::AESD ||
+           FirstOpcode == ARM::INSTRUCTION_LIST_END;
+  }
+
+  return false;
+}
+
+// Fuse literal generation.
+static bool isLiteralsPair(const MachineInstr *FirstMI,
+                           const MachineInstr &SecondMI) {
+  // Assume the 1st instr to be a wildcard if it is unspecified.
+  unsigned FirstOpcode =
+      FirstMI ? FirstMI->getOpcode()
+              : static_cast<unsigned>(ARM::INSTRUCTION_LIST_END);
+  unsigned SecondOpcode = SecondMI.getOpcode();
+
+  // 32 bit immediate.
+  if ((FirstOpcode == ARM::INSTRUCTION_LIST_END ||
+       FirstOpcode == ARM::MOVi16) &&
+      SecondOpcode == ARM::MOVTi16)
+    return true;
+
+  return false;
+}
+
 /// Check if the instr pair, FirstMI and SecondMI, should be fused
 /// together. Given SecondMI, when FirstMI is unspecified, then check if
 /// SecondMI may be part of a fused pair at all.
@@ -28,24 +69,10 @@ static bool shouldScheduleAdjacent(const TargetInstrInfo &TII,
                                    const MachineInstr &SecondMI) {
   const ARMSubtarget &ST = static_cast<const ARMSubtarget&>(TSI);
 
-  // Assume wildcards for unspecified instrs.
-  unsigned FirstOpcode =
-    FirstMI ? FirstMI->getOpcode()
-            : static_cast<unsigned>(ARM::INSTRUCTION_LIST_END);
-  unsigned SecondOpcode = SecondMI.getOpcode();
-
-  if (ST.hasFuseAES())
-    // Fuse AES crypto operations.
-    switch(SecondOpcode) {
-    // AES encode.
-    case ARM::AESMC :
-      return FirstOpcode == ARM::AESE ||
-             FirstOpcode == ARM::INSTRUCTION_LIST_END;
-    // AES decode.
-    case ARM::AESIMC:
-      return FirstOpcode == ARM::AESD ||
-             FirstOpcode == ARM::INSTRUCTION_LIST_END;
-    }
+  if (ST.hasFuseAES() && isAESPair(FirstMI, SecondMI))
+    return true;
+  if (ST.hasFuseLiterals() && isLiteralsPair(FirstMI, SecondMI))
+    return true;
 
   return false;
 }
index 165077926c88bda521b3764cceed2a74084ef1d0..74aee9a8ed38bb2af8eb34c4956a4cec85e3ca5c 100644 (file)
@@ -327,6 +327,10 @@ protected:
   /// pairs faster.
   bool HasFuseAES = false;
 
+  /// HasFuseLiterals - if true, processor executes back to back
+  /// bottom and top halves of literal generation faster.
+  bool HasFuseLiterals = false;
+
   /// If true, if conversion may decide to leave some instructions unpredicated.
   bool IsProfitableToUnpredicate = false;
 
@@ -616,8 +620,9 @@ public:
   bool hasFullFP16() const { return HasFullFP16; }
 
   bool hasFuseAES() const { return HasFuseAES; }
+  bool hasFuseLiterals() const { return HasFuseLiterals; }
   /// Return true if the CPU supports any kind of instruction fusion.
-  bool hasFusion() const { return hasFuseAES(); }
+  bool hasFusion() const { return hasFuseAES() || hasFuseLiterals(); }
 
   const Triple &getTargetTriple() const { return TargetTriple; }
 
diff --git a/test/CodeGen/ARM/misched-fusion-lit.ll b/test/CodeGen/ARM/misched-fusion-lit.ll
new file mode 100644 (file)
index 0000000..cfc4356
--- /dev/null
@@ -0,0 +1,39 @@
+; RUN: llc %s -o - -mtriple=armv8-unknown -mattr=-fuse-literals,+use-misched | FileCheck %s --check-prefix=CHECK --check-prefix=CHECKDONT
+; RUN: llc %s -o - -mtriple=armv8-unknown -mattr=+fuse-literals,+use-misched | FileCheck %s --check-prefix=CHECK --check-prefix=CHECKFUSE
+
+@g = common global i32* zeroinitializer
+
+define i32* @litp(i32 %a, i32 %b) {
+entry:
+  %add = add nsw i32 %b, %a
+  %ptr = getelementptr i32, i32* bitcast (i32* (i32, i32)* @litp to i32*), i32 %add
+  %res = getelementptr i32, i32* bitcast (i32** @g to i32*), i32 %add
+  store i32* %ptr, i32** @g, align 4
+  ret i32* %res
+
+; CHECK-LABEL: litp:
+; CHECK:          movw [[R:r[0-9]+]], :lower16:litp
+; CHECKDONT-NEXT: movw [[S:r[0-9]+]], :lower16:g
+; CHECKFUSE-NEXT: movt [[R]], :upper16:litp
+; CHECKFUSE-NEXT: movw [[S:r[0-9]+]], :lower16:g
+; CHECKFUSE-NEXT: movt [[S]], :upper16:g
+}
+
+define i32 @liti(i32 %a, i32 %b) {
+entry:
+  %adda = add i32 %a, -262095121
+  %add1 = add i32 %adda, %b
+  %addb = add i32 %b, 121110837
+  %add2 = add i32 %addb, %a
+  store i32 %add1, i32* bitcast (i32** @g to i32*), align 4
+  ret i32 %add2
+
+; CHECK-LABEL: liti:
+; CHECK:          movw [[R:r[0-9]+]], #309
+; CHECKDONT-NEXT: add {{r[0-9]+}}, {{r[0-9]+}}, {{r[0-9]+}}
+; CHECKFUSE-NEXT: movt [[R]], #1848
+; CHECKFUSE:      movw [[S:r[0-9]+]], :lower16:g
+; CHECKFUSE-NEXT: movt [[S]], :upper16:g
+; CHECKFUSE-NEXT: movw [[T:r[0-9]+]], #48879
+; CHECKFUSE-NEXT: movt [[T]], #61536
+}