Skip to content

Commit

Permalink
Revert "Reapply [SimplifyCFG][LICM] Preserve nonnull, range and align…
Browse files Browse the repository at this point in the history
… metadata when speculating"

This reverts commit 6f7e5c0.

Seems to expose a miscompile in rust, possibly exposing a bug in LLVM
somewhere. Investigation thread over at:
https://rust-lang.zulipchat.com/#narrow/stream/187780-t-compiler.2Fwg-llvm/topic/LLVM.20D146629.20breakage
  • Loading branch information
krasimirgg committed Apr 19, 2023
1 parent efd64c2 commit bf7f6b4
Show file tree
Hide file tree
Showing 8 changed files with 22 additions and 42 deletions.
7 changes: 1 addition & 6 deletions llvm/include/llvm/IR/Instruction.h
Expand Up @@ -401,16 +401,11 @@ class Instruction : public User,
}

/// This function drops non-debug unknown metadata (through
/// dropUnknownNonDebugMetadata). For calls, it also drops parameter and
/// dropUnknownNonDebugMetadata). For calls, it also drops parameter and
/// return attributes that can cause undefined behaviour. Both of these should
/// be done by passes which move instructions in IR.
void dropUBImplyingAttrsAndUnknownMetadata(ArrayRef<unsigned> KnownIDs = {});

/// Drop any attributes or metadata that can cause immediate undefined
/// behavior. Retain other attributes/metadata on a best-effort basis.
/// This should be used when speculating instructions.
void dropUBImplyingAttrsAndMetadata();

/// Determine whether the exact flag is set.
bool isExact() const LLVM_READONLY;

Expand Down
10 changes: 0 additions & 10 deletions llvm/lib/IR/Instruction.cpp
Expand Up @@ -243,16 +243,6 @@ void Instruction::dropUBImplyingAttrsAndUnknownMetadata(
CB->removeRetAttrs(UBImplyingAttributes);
}

void Instruction::dropUBImplyingAttrsAndMetadata() {
// !annotation metadata does not impact semantics.
// !range, !nonnull and !align produce poison, so they are safe to speculate.
// !noundef and various AA metadata must be dropped, as it generally produces
// immediate undefined behavior.
unsigned KnownIDs[] = {LLVMContext::MD_annotation, LLVMContext::MD_range,
LLVMContext::MD_nonnull, LLVMContext::MD_align};
dropUBImplyingAttrsAndUnknownMetadata(KnownIDs);
}

bool Instruction::isExact() const {
return cast<PossiblyExactOperator>(this)->isExact();
}
Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/Transforms/Scalar/LICM.cpp
Expand Up @@ -1757,7 +1757,7 @@ static void hoist(Instruction &I, const DominatorTree *DT, const Loop *CurLoop,
// time in isGuaranteedToExecute if we don't actually have anything to
// drop. It is a compile time optimization, not required for correctness.
!SafetyInfo->isGuaranteedToExecute(I, DT, CurLoop))
I.dropUBImplyingAttrsAndMetadata();
I.dropUBImplyingAttrsAndUnknownMetadata();

if (isa<PHINode>(I))
// Move the new node to the end of the phi list in the destination block.
Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/Transforms/Scalar/SROA.cpp
Expand Up @@ -1696,7 +1696,7 @@ static void rewriteMemOpOfSelect(SelectInst &SI, T &I,
else
++NumStoresPredicated;
} else {
CondMemOp.dropUBImplyingAttrsAndMetadata();
CondMemOp.dropUBImplyingAttrsAndUnknownMetadata();
++NumLoadsSpeculated;
}
CondMemOp.insertBefore(NewMemOpBB->getTerminator());
Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/Transforms/Utils/Local.cpp
Expand Up @@ -2990,7 +2990,7 @@ void llvm::hoistAllInstructionsInto(BasicBlock *DomBlock, Instruction *InsertPt,

for (BasicBlock::iterator II = BB->begin(), IE = BB->end(); II != IE;) {
Instruction *I = &*II;
I->dropUBImplyingAttrsAndMetadata();
I->dropUBImplyingAttrsAndUnknownMetadata();
if (I->isUsedByMetadata())
dropDebugUsers(*I);
if (I->isDebugOrPseudoInst()) {
Expand Down
14 changes: 9 additions & 5 deletions llvm/lib/Transforms/Utils/SimplifyCFG.cpp
Expand Up @@ -1117,12 +1117,16 @@ static void CloneInstructionsIntoPredecessorBlockAndUpdateSSAUses(
RF_NoModuleLevelChanges | RF_IgnoreMissingLocals);
VMap[&BonusInst] = NewBonusInst;

// If we speculated an instruction, we need to drop any metadata that may
// result in undefined behavior, as the metadata might have been valid
// If we moved a load, we cannot any longer claim any knowledge about
// its potential value. The previous information might have been valid
// only given the branch precondition.
// For an analogous reason, we must also drop all the metadata whose
// semantics we don't understand. We *can* preserve !annotation, because
// it is tied to the instruction itself, not the value or position.
// Similarly strip attributes on call parameters that may cause UB in
// location the call is moved to.
NewBonusInst->dropUBImplyingAttrsAndMetadata();
NewBonusInst->dropUBImplyingAttrsAndUnknownMetadata(
LLVMContext::MD_annotation);

NewBonusInst->insertInto(PredBlock, PTI->getIterator());
NewBonusInst->takeName(&BonusInst);
Expand Down Expand Up @@ -3010,7 +3014,7 @@ bool SimplifyCFGOpt::SpeculativelyExecuteBB(BranchInst *BI, BasicBlock *ThenBB,
}

// Metadata can be dependent on the condition we are hoisting above.
// Strip all UB-implying metadata on the instruction. Drop the debug loc
// Conservatively strip all metadata on the instruction. Drop the debug loc
// to avoid making it appear as if the condition is a constant, which would
// be misleading while debugging.
// Similarly strip attributes that maybe dependent on condition we are
Expand All @@ -3021,7 +3025,7 @@ bool SimplifyCFGOpt::SpeculativelyExecuteBB(BranchInst *BI, BasicBlock *ThenBB,
if (!isa<DbgAssignIntrinsic>(&I))
I.setDebugLoc(DebugLoc());
}
I.dropUBImplyingAttrsAndMetadata();
I.dropUBImplyingAttrsAndUnknownMetadata();

// Drop ephemeral values.
if (EphTracker.contains(&I)) {
Expand Down
9 changes: 3 additions & 6 deletions llvm/test/Transforms/LICM/hoist-metadata.ll
Expand Up @@ -3,7 +3,6 @@

declare void @foo(...) memory(none)

; We can preserve all metadata on instructions that are guaranteed to execute.
define void @test_unconditional(i1 %c, ptr dereferenceable(8) align 8 %p) {
; CHECK-LABEL: define void @test_unconditional
; CHECK-SAME: (i1 [[C:%.*]], ptr align 8 dereferenceable(8) [[P:%.*]]) {
Expand All @@ -30,14 +29,12 @@ exit:
ret void
}

; We cannot preserve UB-implying metadata on instructions that are speculated.
; However, we can preserve poison-implying metadata.
define void @test_conditional(i1 %c, i1 %c2, ptr dereferenceable(8) align 8 %p) {
; CHECK-LABEL: define void @test_conditional
; CHECK-SAME: (i1 [[C:%.*]], i1 [[C2:%.*]], ptr align 8 dereferenceable(8) [[P:%.*]]) {
; CHECK-NEXT: [[V1:%.*]] = load i32, ptr [[P]], align 4, !range [[RNG0]]
; CHECK-NEXT: [[V2:%.*]] = load ptr, ptr [[P]], align 8, !nonnull !1
; CHECK-NEXT: [[V3:%.*]] = load ptr, ptr [[P]], align 8, !align !2
; CHECK-NEXT: [[V1:%.*]] = load i32, ptr [[P]], align 4
; CHECK-NEXT: [[V2:%.*]] = load ptr, ptr [[P]], align 8
; CHECK-NEXT: [[V3:%.*]] = load ptr, ptr [[P]], align 8
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: br i1 [[C]], label [[IF:%.*]], label [[LATCH:%.*]]
Expand Down
18 changes: 6 additions & 12 deletions llvm/test/Transforms/SimplifyCFG/hoist-with-metadata.ll
Expand Up @@ -97,11 +97,10 @@ out:
ret void
}

; !range violation only returns poison, and is thus safe to speculate.
define i32 @speculate_range(i1 %c, ptr dereferenceable(8) align 8 %p) {
; CHECK-LABEL: @speculate_range(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[V:%.*]] = load i32, ptr [[P:%.*]], align 4, !range [[RNG3:![0-9]+]]
; CHECK-NEXT: [[V:%.*]] = load i32, ptr [[P:%.*]], align 4
; CHECK-NEXT: [[SPEC_SELECT:%.*]] = select i1 [[C:%.*]], i32 [[V]], i32 0
; CHECK-NEXT: ret i32 [[SPEC_SELECT]]
;
Expand All @@ -117,12 +116,10 @@ join:
ret i32 %phi
}

; !nonnull is safe to speculate, but !noundef is not, as the latter causes
; immediate undefined behavior.
define ptr @speculate_nonnull(i1 %c, ptr dereferenceable(8) align 8 %p) {
; CHECK-LABEL: @speculate_nonnull(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[V:%.*]] = load ptr, ptr [[P:%.*]], align 8, !nonnull !1
; CHECK-NEXT: [[V:%.*]] = load ptr, ptr [[P:%.*]], align 8
; CHECK-NEXT: [[SPEC_SELECT:%.*]] = select i1 [[C:%.*]], ptr [[V]], ptr null
; CHECK-NEXT: ret ptr [[SPEC_SELECT]]
;
Expand All @@ -138,12 +135,11 @@ join:
ret ptr %phi
}

; !align is safe to speculate, but !dereferenceable is not, as the latter causes
; immediate undefined behavior.

define ptr @speculate_align(i1 %c, ptr dereferenceable(8) align 8 %p) {
; CHECK-LABEL: @speculate_align(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[V:%.*]] = load ptr, ptr [[P:%.*]], align 8, !align !4
; CHECK-NEXT: [[V:%.*]] = load ptr, ptr [[P:%.*]], align 8
; CHECK-NEXT: [[SPEC_SELECT:%.*]] = select i1 [[C:%.*]], ptr [[V]], ptr null
; CHECK-NEXT: ret ptr [[SPEC_SELECT]]
;
Expand All @@ -162,7 +158,7 @@ join:
define void @hoist_fpmath(i1 %c, double %x) {
; CHECK-LABEL: @hoist_fpmath(
; CHECK-NEXT: if:
; CHECK-NEXT: [[T:%.*]] = fadd double [[X:%.*]], 1.000000e+00, !fpmath !5
; CHECK-NEXT: [[T:%.*]] = fadd double [[X:%.*]], 1.000000e+00, !fpmath !3
; CHECK-NEXT: ret void
;
if:
Expand All @@ -184,7 +180,5 @@ out:
; CHECK: [[RNG0]] = !{i8 0, i8 1, i8 3, i8 5}
; CHECK: [[META1:![0-9]+]] = !{}
; CHECK: [[META2:![0-9]+]] = !{i64 10}
; CHECK: [[RNG3]] = !{i32 0, i32 10}
; CHECK: [[META4:![0-9]+]] = !{i64 4}
; CHECK: [[META5:![0-9]+]] = !{float 2.500000e+00}
; CHECK: [[META3:![0-9]+]] = !{float 2.500000e+00}
;.

0 comments on commit bf7f6b4

Please sign in to comment.