[DAGCombine] Truncate BUILD_VECTOR operators if necessary when constant folding vectors
authorSilviu Baranga <silviu.baranga@arm.com>
Thu, 10 Sep 2015 10:34:34 +0000 (10:34 +0000)
committerSilviu Baranga <silviu.baranga@arm.com>
Thu, 10 Sep 2015 10:34:34 +0000 (10:34 +0000)
Summary:
The BUILD_VECTOR node will truncate its operators to match the
type. We need to take this into account when constant folding -
we need to perform a truncation before constant folding the elements.
This is because the upper bits can change the result, depending on
the operation type (for example this is the case for min/max).

This change also adds a regression test.

Reviewers: jmolloy

Subscribers: jmolloy, llvm-commits

Differential Revision: http://reviews.llvm.org/D12697

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

lib/CodeGen/SelectionDAG/DAGCombiner.cpp
test/CodeGen/AArch64/aarch64-smax-constantfold.ll [new file with mode: 0644]

index 755edee1c6c17a129d97da2ed0059ef9d3969871..f81da723e69321fbba2c127b4ee3de02adad0094 100644 (file)
@@ -13325,20 +13325,34 @@ SDValue DAGCombiner::SimplifyVBinOp(SDNode *N) {
 
       EVT VT = LHSOp.getValueType();
       EVT RVT = RHSOp.getValueType();
-      if (RVT != VT) {
-        // Integer BUILD_VECTOR operands may have types larger than the element
-        // size (e.g., when the element type is not legal).  Prior to type
-        // legalization, the types may not match between the two BUILD_VECTORS.
-        // Truncate one of the operands to make them match.
-        if (RVT.getSizeInBits() > VT.getSizeInBits()) {
-          RHSOp = DAG.getNode(ISD::TRUNCATE, SDLoc(N), VT, RHSOp);
-        } else {
-          LHSOp = DAG.getNode(ISD::TRUNCATE, SDLoc(N), RVT, LHSOp);
-          VT = RVT;
-        }
+      EVT ST = VT;
+
+      if (RVT.getSizeInBits() < VT.getSizeInBits())
+        ST = RVT;
+
+      // Integer BUILD_VECTOR operands may have types larger than the element
+      // size (e.g., when the element type is not legal).  Prior to type
+      // legalization, the types may not match between the two BUILD_VECTORS.
+      // Truncate the operands to make them match.
+      if (VT.getSizeInBits() != LHS.getValueType().getScalarSizeInBits()) {
+        EVT ScalarT = LHS.getValueType().getScalarType();
+        LHSOp = DAG.getNode(ISD::TRUNCATE, SDLoc(N), ScalarT, LHSOp);
+        VT = LHSOp.getValueType();
       }
+      if (RVT.getSizeInBits() != RHS.getValueType().getScalarSizeInBits()) {
+        EVT ScalarT = RHS.getValueType().getScalarType();
+        RHSOp = DAG.getNode(ISD::TRUNCATE, SDLoc(N), ScalarT, RHSOp);
+        RVT = RHSOp.getValueType();
+      }
+
       SDValue FoldOp = DAG.getNode(N->getOpcode(), SDLoc(LHS), VT,
                                    LHSOp, RHSOp);
+
+      // We need the resulting constant to be legal if we are in a phase after
+      // legalization, so zero extend to the smallest operand type if required.
+      if (ST != VT && Level != BeforeLegalizeTypes)
+        FoldOp = DAG.getNode(ISD::ANY_EXTEND, SDLoc(LHS), ST, FoldOp);
+
       if (FoldOp.getOpcode() != ISD::UNDEF &&
           FoldOp.getOpcode() != ISD::Constant &&
           FoldOp.getOpcode() != ISD::ConstantFP)
diff --git a/test/CodeGen/AArch64/aarch64-smax-constantfold.ll b/test/CodeGen/AArch64/aarch64-smax-constantfold.ll
new file mode 100644 (file)
index 0000000..0e5b59f
--- /dev/null
@@ -0,0 +1,12 @@
+; RUN: llc -mtriple=aarch64-none-linux-gnu < %s -o -| FileCheck %s
+
+; Function Attrs: nounwind readnone
+declare <4 x i16> @llvm.aarch64.neon.smax.v4i16(<4 x i16>, <4 x i16>)
+
+; CHECK-LABEL: test
+define <4 x i16> @test() {
+entry:
+; CHECK: movi  d{{[0-9]+}}, #0000000000000000
+  %0 = tail call <4 x i16> @llvm.aarch64.neon.smax.v4i16(<4 x i16> <i16 -1, i16 -1, i16 -1, i16 -1>, <4 x i16> zeroinitializer)
+  ret <4 x i16> %0
+}