[PPC] Change i32 constant in store instruction to i64
authorGuozhi Wei <carrot@google.com>
Thu, 16 Nov 2017 18:27:34 +0000 (18:27 +0000)
committerGuozhi Wei <carrot@google.com>
Thu, 16 Nov 2017 18:27:34 +0000 (18:27 +0000)
This patch changes all i32 constant in store instruction to i64 with truncation, to increase the chance that the referenced constant can be shared with other i64 constant.

Differential Revision: https://reviews.llvm.org/D39352

llvm-svn: 318436

llvm/include/llvm/CodeGen/SelectionDAGNodes.h
llvm/lib/Target/PowerPC/PPCISelLowering.cpp
llvm/test/CodeGen/PowerPC/store-constant.ll [new file with mode: 0644]

index d119423..7de2e76 100644 (file)
@@ -2015,6 +2015,9 @@ public:
   /// For integers this is the same as doing a TRUNCATE and storing the result.
   /// For floats, it is the same as doing an FP_ROUND and storing the result.
   bool isTruncatingStore() const { return StoreSDNodeBits.IsTruncating; }
+  void setTruncatingStore(bool Truncating) {
+    StoreSDNodeBits.IsTruncating = Truncating;
+  }
 
   const SDValue &getValue() const { return getOperand(1); }
   const SDValue &getBasePtr() const { return getOperand(2); }
index 3c3657e..cab17fb 100644 (file)
@@ -12223,9 +12223,24 @@ SDValue PPCTargetLowering::PerformDAGCombine(SDNode *N,
                                 cast<StoreSDNode>(N)->getMemOperand());
     }
 
+    // STORE Constant:i32<0>  ->  STORE<trunc to i32> Constant:i64<0>
+    // So it can increase the chance of CSE constant construction.
+    EVT VT = N->getOperand(1).getValueType();
+    if (Subtarget.isPPC64() && !DCI.isBeforeLegalize() &&
+        isa<ConstantSDNode>(N->getOperand(1)) && VT == MVT::i32) {
+      SDValue Const64 = DAG.getConstant(N->getConstantOperandVal(1), dl,
+                                        MVT::i64);
+      // DAG.getTruncStore() can't be used here because it doesn't accept
+      // the general (base + offset) addressing mode.
+      // So we use UpdateNodeOperands and setTruncatingStore instead.
+      DAG.UpdateNodeOperands(N, N->getOperand(0), Const64, N->getOperand(2),
+                             N->getOperand(3));
+      cast<StoreSDNode>(N)->setTruncatingStore(true);
+      return SDValue(N, 0);
+    }
+
     // For little endian, VSX stores require generating xxswapd/lxvd2x.
     // Not needed on ISA 3.0 based CPUs since we have a non-permuting store.
-    EVT VT = N->getOperand(1).getValueType();
     if (VT.isSimple()) {
       MVT StoreVT = VT.getSimpleVT();
       if (Subtarget.needsSwapsForVSXMemOps() &&
diff --git a/llvm/test/CodeGen/PowerPC/store-constant.ll b/llvm/test/CodeGen/PowerPC/store-constant.ll
new file mode 100644 (file)
index 0000000..d17d1ba
--- /dev/null
@@ -0,0 +1,44 @@
+; RUN: llc < %s -mtriple=powerpc64-unknown-linux-gnu -mcpu=pwr8 -verify-machineinstrs | FileCheck %s
+
+; Test the same constant can be used by different stores.
+
+%struct.S = type { i64, i8, i16, i32 }
+
+define void @foo(%struct.S* %p) {
+  %l4 = bitcast %struct.S* %p to i64*
+  store i64 0, i64* %l4, align 8
+  %c = getelementptr %struct.S, %struct.S* %p, i64 0, i32 1
+  store i8 0, i8* %c, align 8
+  %s = getelementptr %struct.S, %struct.S* %p, i64 0, i32 2
+  store i16 0, i16* %s, align 2
+  %i = getelementptr %struct.S, %struct.S* %p, i64 0, i32 3
+  store i32 0, i32* %i, align 4
+  ret void
+
+; CHECK-LABEL: @foo
+; CHECK:       li 4, 0
+; CHECK:       stb 4, 8(3)
+; CHECK:       std 4, 0(3)
+; CHECK:       sth 4, 10(3)
+; CHECK:       stw 4, 12(3)
+}
+
+define void @bar(%struct.S* %p) {
+  %i = getelementptr %struct.S, %struct.S* %p, i64 0, i32 3
+  store i32 2, i32* %i, align 4
+  %s = getelementptr %struct.S, %struct.S* %p, i64 0, i32 2
+  store i16 2, i16* %s, align 2
+  %c = getelementptr %struct.S, %struct.S* %p, i64 0, i32 1
+  store i8 2, i8* %c, align 8
+  %l4 = bitcast %struct.S* %p to i64*
+  store i64 2, i64* %l4, align 8
+  ret void
+
+; CHECK-LABEL: @bar
+; CHECK:       li 4, 2
+; CHECK:       stw 4, 12(3)
+; CHECK:       sth 4, 10(3)
+; CHECK:       std 4, 0(3)
+; CHECK:       stb 4, 8(3)
+}
+