Index: lib/CodeGen/SelectionDAG/DAGCombiner.cpp =================================================================== --- lib/CodeGen/SelectionDAG/DAGCombiner.cpp +++ lib/CodeGen/SelectionDAG/DAGCombiner.cpp @@ -12678,7 +12678,11 @@ SDValue Val = St->getValue(); StoreInt <<= ElementSizeBits; if (ConstantSDNode *C = dyn_cast(Val)) { - StoreInt |= C->getAPIntValue().zextOrTrunc(SizeInBits); + // Since the store may be truncating, the stored immediate must be + // truncated to the width of the element. + APInt CElt(ElementSizeBits, + C->getAPIntValue().zextOrTrunc(ElementSizeBits).getZExtValue()); + StoreInt |= CElt.zextOrTrunc(SizeInBits); } else if (ConstantFPSDNode *C = dyn_cast(Val)) { StoreInt |= C->getValueAPF().bitcastToAPInt().zextOrTrunc(SizeInBits); } else { Index: test/CodeGen/SystemZ/DAGCombiner_stores.ll =================================================================== --- /dev/null +++ test/CodeGen/SystemZ/DAGCombiner_stores.ll @@ -0,0 +1,327 @@ +; RUN: llc -mtriple=s390x-linux-gnu -mcpu=zEC12 < %s | FileCheck %s +; +; This (reduced csmith) test case stores a lot of 16 bit constant -7 values +; to adjacent locations, which the DAGCombiner will merge to wider stores. It +; was discovered that the result of combining two or four such stores +; resulted incorrectly in stores of 32-bit / 64-bit constants of value +; -7. The correct constant then is not -7, but consists of two or four i16 -7 +; elements. +; +; CHECK-NOT: mvghi {{.*}} -7 +; CHECK-NOT: mvhi {{.*}} -7 + +@0 = internal unnamed_addr global i16 1, align 2 +@1 = internal unnamed_addr global [10 x [7 x i16]] [[7 x i16] [i16 1, i16 -6729, i16 0, i16 0, i16 -6729, i16 1, i16 -4591], [7 x i16] [i16 -26203, i16 -6729, i16 9, i16 -4591, i16 0, i16 0, i16 0], [7 x i16] [i16 0, i16 0, i16 -10191, i16 0, i16 0, i16 -17444, i16 -26203], [7 x i16] [i16 22368, i16 -6729, i16 0, i16 1, i16 0, i16 -26203, i16 0], [7 x i16] [i16 1, i16 0, i16 0, i16 1, i16 0, i16 1, i16 22368], [7 x i16] [i16 22368, i16 1, i16 0, i16 1, i16 0, i16 0, i16 1], [7 x i16] [i16 0, i16 -26203, i16 0, i16 1, i16 0, i16 -6729, i16 22368], [7 x i16] [i16 -26203, i16 -17444, i16 0, i16 0, i16 -10191, i16 0, i16 0], [7 x i16] [i16 0, i16 0, i16 0, i16 -4591, i16 9, i16 -6729, i16 -26203], [7 x i16] [i16 -4591, i16 0, i16 0, i16 -6729, i16 -6729, i16 0, i16 0]], align 2 +@2 = private unnamed_addr constant [12 x i8] c"g_112[i][j]\00", align 2 +@3 = private unnamed_addr constant [9 x i8] c"g_653[i]\00", align 2 +@4 = internal unnamed_addr global i32 -1, align 4 +@5 = internal unnamed_addr global [256 x i32] zeroinitializer, align 4 +@6 = private unnamed_addr constant [36 x i8] c"...checksum after hashing %s : %lX\0A\00", align 2 +@7 = private unnamed_addr constant [15 x i8] c"checksum = %X\0A\00", align 2 + +; Function Attrs: nounwind +define signext i32 @main(i32 signext, i8** nocapture readonly) local_unnamed_addr #0 { + %3 = icmp eq i32 %0, 2 + br i1 %3, label %4, label %20 + +;