Bug type: miscompilation
Component: SimplifyCFG
Bug location: llvm/lib/Transforms/Utils/SimplifyCFG.cpp: isSafeToSpeculateStore
Issue title: coalescing of redundant vector stores isn't preserving alignment correctly
Labels: miscompilation
llvm:transforms
Reported by: regehr

https://alive2.llvm.org/ce/z/-qQphe

optimizing this code:
```llvm
define i32 @f(ptr %0, i1 %1) {
  store <2 x i64> zeroinitializer, ptr %0, align 8
  br i1 %1, label %4, label %3

3:                                                ; preds = %2
  store <2 x i64> zeroinitializer, ptr %0, align 16
  br label %4

4:                                                ; preds = %3, %2
  ret i32 0
}
```

is mostly doing what we expect, but the coalesced store should retain the smaller alignnment value of the two, not the larger:
```lllvm
define noundef i32 @f(ptr nocapture writeonly %0, i1 %1) local_unnamed_addr #0 {
  store <2 x i64> zeroinitializer, ptr %0, align 16
  ret i32 0
}

attributes #0 = { mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write) }
```

cc @nunoplopes @hatsunespica

Comments: author: nikic
body: The issue is introduced by SimplifyCFG: https://alive2.llvm.org/ce/z/zf-j74
author: nikic
body: Specifically this is isSafeToSpeculateStore(), which looks for a preceding store to check whether it is safe to speculate, but fails to check alignment.

Fix patch:
commit 883887493c882d656d5da100ee637a348e81357c
Author: Nikita Popov <npopov@redhat.com>
Date:   Tue Apr 23 12:36:35 2024 +0900

    [SimplifyCFG] Check alignment when speculating stores
    
    When speculating a store based on a preceding load/store, we need
    to ensure that the speculated store does not have a higher
    alignment (which might only be guaranteed by the branch condition).
    
    There are various ways in which this could be strengthened (we
    could get or enforce the alignment), but for now just do the
    simple check against the preceding load/store.
    
    Fixes https://github.com/llvm/llvm-project/issues/89672.

diff --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
index da3eb229c041..0826d748ba0d 100644
--- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
+++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
@@ -2888,7 +2888,8 @@ static Value *isSafeToSpeculateStore(Instruction *I, BasicBlock *BrBB,
       // simple, to avoid introducing a spurious non-atomic write after an
       // atomic write.
       if (SI->getPointerOperand() == StorePtr &&
-          SI->getValueOperand()->getType() == StoreTy && SI->isSimple())
+          SI->getValueOperand()->getType() == StoreTy && SI->isSimple() &&
+          SI->getAlign() >= StoreToHoist->getAlign())
         // Found the previous store, return its value operand.
         return SI->getValueOperand();
       return nullptr; // Unknown store.
@@ -2896,7 +2897,7 @@ static Value *isSafeToSpeculateStore(Instruction *I, BasicBlock *BrBB,
 
     if (auto *LI = dyn_cast<LoadInst>(&CurI)) {
       if (LI->getPointerOperand() == StorePtr && LI->getType() == StoreTy &&
-          LI->isSimple()) {
+          LI->isSimple() && LI->getAlign() >= StoreToHoist->getAlign()) {
         // Local objects (created by an `alloca` instruction) are always
         // writable, so once we are past a read from a location it is valid to
         // also write to that same location.


Regression tests:
file: llvm/test/Transforms/SimplifyCFG/speculate-store.ll
commands: opt -passes=simplifycfg -simplifycfg-require-and-preserve-domtree=1 -S < %s
tests: test_name: wrong_align_store
test_body: define void @wrong_align_store(ptr %A, i32 %B, i32 %C, i32 %D) {
entry:
  store i32 %B, ptr %A, align 4
  %cmp = icmp sgt i32 %D, 42
  br i1 %cmp, label %if.then, label %ret.end

if.then:                                          ; preds = %entry
  store i32 %C, ptr %A, align 8
  br label %ret.end

ret.end:                                          ; preds = %if.then, %entry
  ret void
}

test_name: wrong_align_load
test_body: define void @wrong_align_load(i32 %C, i32 %D) {
entry:
  %A = alloca i32, align 4
  %0 = load i32, ptr %A, align 4
  %cmp = icmp sgt i32 %D, 42
  br i1 %cmp, label %if.then, label %ret.end

if.then:                                          ; preds = %entry
  store i32 %C, ptr %A, align 8
  br label %ret.end

ret.end:                                          ; preds = %if.then, %entry
  ret void
}