Skip to content

Commit

Permalink
[SDAG] fix miscompile from merging stores of different sizes
Browse files Browse the repository at this point in the history
As shown in:
https://llvm.org/PR50623
...and the similar tests here, we were not accounting for
store merging of different sizes that do not cover the
entire range of the wide value to be stored.

This is the easy fix: just make sure that all of the
original stores are the same size, so when we calculate
the wide width, it's a simple N * M check.

This still allows all of the motivating optimizations from:
D86420 / 54a5dd4
D87112 / 7a06b16

We could enhance this code to track individual bytes and
allow merging multiple sizes.
  • Loading branch information
rotateright committed Jun 9, 2021
1 parent 206a66d commit dd763ac
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 13 deletions.
24 changes: 16 additions & 8 deletions llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7270,14 +7270,22 @@ SDValue DAGCombiner::mergeTruncStores(StoreSDNode *N) {
if (LegalOperations)
return SDValue();

// Collect all the stores in the chain.
SDValue Chain;
SmallVector<StoreSDNode *, 8> Stores;
for (StoreSDNode *Store = N; Store; Store = dyn_cast<StoreSDNode>(Chain)) {
// TODO: Allow unordered atomics when wider type is legal (see D66309)
EVT MemVT = Store->getMemoryVT();
if (!(MemVT == MVT::i8 || MemVT == MVT::i16 || MemVT == MVT::i32) ||
!Store->isSimple() || Store->isIndexed())
// We only handle merging simple stores of 1-4 bytes.
// TODO: Allow unordered atomics when wider type is legal (see D66309)
EVT MemVT = N->getMemoryVT();
if (!(MemVT == MVT::i8 || MemVT == MVT::i16 || MemVT == MVT::i32) ||
!N->isSimple() || N->isIndexed())
return SDValue();

// Collect all of the stores in the chain.
SDValue Chain = N->getChain();
SmallVector<StoreSDNode *, 8> Stores = {N};
while (auto *Store = dyn_cast<StoreSDNode>(Chain)) {
// All stores must be the same size to ensure that we are writing all of the
// bytes in the wide value.
// TODO: We could allow multiple sizes by tracking each stored byte.
if (Store->getMemoryVT() != MemVT || !Store->isSimple() ||
Store->isIndexed())
return SDValue();
Stores.push_back(Store);
Chain = Store->getChain();
Expand Down
11 changes: 6 additions & 5 deletions llvm/test/CodeGen/X86/stores-merging.ll
Original file line number Diff line number Diff line change
Expand Up @@ -614,14 +614,15 @@ define dso_local void @be_i64_to_i32_order(i64 %x, i32* %p0) {
}

; https://llvm.org/PR50623
; FIXME:
; It is a miscompile to merge the stores if we are not
; writing all of the bytes from the source value.

define void @merge_hole(i32 %x, i8* %p) {
; CHECK-LABEL: merge_hole:
; CHECK: # %bb.0:
; CHECK-NEXT: movl %edi, (%rsi)
; CHECK-NEXT: movb %dil, (%rsi)
; CHECK-NEXT: shrl $16, %edi
; CHECK-NEXT: movw %di, 2(%rsi)
; CHECK-NEXT: retq
%pcast = bitcast i8* %p to i16*
%p2 = getelementptr inbounds i16, i16* %pcast, i64 1
Expand Down Expand Up @@ -678,15 +679,15 @@ define void @merge_hole3(i32 %x, i8* %p) {
}

; Change offset.
; FIXME:
; It is a miscompile to merge the stores if we are not
; writing all of the bytes from the source value.

define void @merge_hole4(i32 %x, i8* %p) {
; CHECK-LABEL: merge_hole4:
; CHECK: # %bb.0:
; CHECK-NEXT: rorl $16, %edi
; CHECK-NEXT: movl %edi, (%rsi)
; CHECK-NEXT: movb %dil, 2(%rsi)
; CHECK-NEXT: shrl $16, %edi
; CHECK-NEXT: movw %di, (%rsi)
; CHECK-NEXT: retq
%pcast = bitcast i8* %p to i16*
%p2 = getelementptr inbounds i8, i8* %p, i64 2
Expand Down

0 comments on commit dd763ac

Please sign in to comment.