[PATCH] D39875: [PPC] Change i32 constant in store instruction to i64

Guozhi Wei via Phabricator via llvm-commits llvm-commits at lists.llvm.org
Thu Nov 9 15:51:58 PST 2017


Carrot created this revision.

The motivated test case is:

struct S {

  long l;
  char c;
  short s;
  int i;

};

void foo(struct S *p) {

  p->l = 0;
  p->c = 0;
  p->s = 0;
  p->i = 0;

}

It is very common in constructors, llvm generates:

  li 4, 0
  li 5, 0          <=== this is not necessary, we could use r4 instead.
  stb 4, 0(3)
  sth 4, 2(3)
  stw 4, 4(3)
  std 5, 8(3)
  blr

It is because 8bit and 16bit types are not legal, they are promoted to 32bit, so all 8b/16b/32b stores reference Constant:i32<0>, constants are shared in LLVM IR, so they are naturally CSEd. 64bit store references Constant:i64<0>, it is of different type, so it is represented by a different constant node, and generate another constant construction instruction.

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.


https://reviews.llvm.org/D39875

Files:
  include/llvm/CodeGen/SelectionDAGNodes.h
  lib/Target/PowerPC/PPCISelLowering.cpp
  test/CodeGen/PowerPC/store-constant.ll


Index: test/CodeGen/PowerPC/store-constant.ll
===================================================================
--- test/CodeGen/PowerPC/store-constant.ll
+++ test/CodeGen/PowerPC/store-constant.ll
@@ -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)
+}
+
Index: lib/Target/PowerPC/PPCISelLowering.cpp
===================================================================
--- lib/Target/PowerPC/PPCISelLowering.cpp
+++ lib/Target/PowerPC/PPCISelLowering.cpp
@@ -12215,9 +12215,21 @@
                                 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.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() &&
Index: include/llvm/CodeGen/SelectionDAGNodes.h
===================================================================
--- include/llvm/CodeGen/SelectionDAGNodes.h
+++ include/llvm/CodeGen/SelectionDAGNodes.h
@@ -2015,6 +2015,7 @@
   /// 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); }


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D39875.122347.patch
Type: text/x-patch
Size: 3515 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20171109/eb74337a/attachment.bin>


More information about the llvm-commits mailing list