Skip to content
This repository was archived by the owner on Feb 5, 2019. It is now read-only.

Preserve nonnull metadata on Loads through SROA & mem2reg #90

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions include/llvm/Transforms/Utils/Local.h
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,19 @@ unsigned replaceDominatedUsesWith(Value *From, Value *To, DominatorTree &DT,
/// during lowering by the GC infrastructure.
bool callsGCLeafFunction(ImmutableCallSite CS);

/// Copy a nonnull metadata node to a new load instruction.
///
/// This handles mapping it to range metadata if the new load is an integer
/// load instead of a pointer load.
void copyNonnullMetadata(const LoadInst &OldLI, MDNode *N, LoadInst &NewLI);

/// Copy a range metadata node to a new load instruction.
///
/// This handles mapping it to nonnull metadata if the new load is a pointer
/// load instead of an integer load and the range doesn't cover null.
void copyRangeMetadata(const DataLayout &DL, const LoadInst &OldLI, MDNode *N,
LoadInst &NewLI);

//===----------------------------------------------------------------------===//
// Intrinsic pattern matching
//
Expand Down
28 changes: 2 additions & 26 deletions lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -471,21 +471,7 @@ static LoadInst *combineLoadToNewType(InstCombiner &IC, LoadInst &LI, Type *NewT
break;

case LLVMContext::MD_nonnull:
// This only directly applies if the new type is also a pointer.
if (NewTy->isPointerTy()) {
NewLoad->setMetadata(ID, N);
break;
}
// If it's integral now, translate it to !range metadata.
if (NewTy->isIntegerTy()) {
auto *ITy = cast<IntegerType>(NewTy);
auto *NullInt = ConstantExpr::getPtrToInt(
ConstantPointerNull::get(cast<PointerType>(Ptr->getType())), ITy);
auto *NonNullInt =
ConstantExpr::getAdd(NullInt, ConstantInt::get(ITy, 1));
NewLoad->setMetadata(LLVMContext::MD_range,
MDB.createRange(NonNullInt, NullInt));
}
copyNonnullMetadata(LI, N, *NewLoad);
break;
case LLVMContext::MD_align:
case LLVMContext::MD_dereferenceable:
Expand All @@ -495,17 +481,7 @@ static LoadInst *combineLoadToNewType(InstCombiner &IC, LoadInst &LI, Type *NewT
NewLoad->setMetadata(ID, N);
break;
case LLVMContext::MD_range:
// FIXME: It would be nice to propagate this in some way, but the type
// conversions make it hard.

// If it's a pointer now and the range does not contain 0, make it !nonnull.
if (NewTy->isPointerTy()) {
unsigned BitWidth = IC.getDataLayout().getTypeSizeInBits(NewTy);
if (!getConstantRangeFromMetadata(*N).contains(APInt(BitWidth, 0))) {
MDNode *NN = MDNode::get(LI.getContext(), None);
NewLoad->setMetadata(LLVMContext::MD_nonnull, NN);
}
}
copyRangeMetadata(IC.getDataLayout(), LI, N, *NewLoad);
break;
}
}
Expand Down
15 changes: 15 additions & 0 deletions lib/Transforms/Scalar/SROA.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2387,6 +2387,21 @@ class llvm::sroa::AllocaSliceRewriter
LI.isVolatile(), LI.getName());
if (LI.isVolatile())
NewLI->setAtomic(LI.getOrdering(), LI.getSynchScope());

// Any !nonnull metadata or !range metadata on the old load is also valid
// on the new load. This is even true in some cases even when the loads
// are different types, for example by mapping !nonnull metadata to
// !range metadata by modeling the null pointer constant converted to the
// integer type.
// FIXME: Add support for range metadata here. Currently the utilities
// for this don't propagate range metadata in trivial cases from one
// integer load to another, don't handle non-addrspace-0 null pointers
// correctly, and don't have any support for mapping ranges as the
// integer type becomes winder or narrower.
if (MDNode *N = LI.getMetadata(LLVMContext::MD_nonnull))
copyNonnullMetadata(LI, N, *NewLI);

// Try to preserve nonnull metadata
V = NewLI;

// If this is an integer load past the end of the slice (which means the
Expand Down
54 changes: 49 additions & 5 deletions lib/Transforms/Utils/Local.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include "llvm/Analysis/LazyValueInfo.h"
#include "llvm/Analysis/ValueTracking.h"
#include "llvm/IR/CFG.h"
#include "llvm/IR/ConstantRange.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DIBuilder.h"
#include "llvm/IR/DataLayout.h"
Expand Down Expand Up @@ -1069,7 +1070,7 @@ static bool LdStHasDebugValue(DILocalVariable *DIVar, DIExpression *DIExpr,
}

/// See if there is a dbg.value intrinsic for DIVar for the PHI node.
static bool PhiHasDebugValue(DILocalVariable *DIVar,
static bool PhiHasDebugValue(DILocalVariable *DIVar,
DIExpression *DIExpr,
PHINode *APN) {
// Since we can't guarantee that the original dbg.declare instrinsic
Expand Down Expand Up @@ -1152,7 +1153,7 @@ void llvm::ConvertDebugDeclareToDebugValue(DbgDeclareInst *DDI,
DbgValue->insertAfter(LI);
}

/// Inserts a llvm.dbg.value intrinsic after a phi
/// Inserts a llvm.dbg.value intrinsic after a phi
/// that has an associated llvm.dbg.decl intrinsic.
void llvm::ConvertDebugDeclareToDebugValue(DbgDeclareInst *DDI,
PHINode *APN, DIBuilder &Builder) {
Expand Down Expand Up @@ -1723,12 +1724,12 @@ void llvm::combineMetadata(Instruction *K, const Instruction *J,
// Preserve !invariant.group in K.
break;
case LLVMContext::MD_align:
K->setMetadata(Kind,
K->setMetadata(Kind,
MDNode::getMostGenericAlignmentOrDereferenceable(JMD, KMD));
break;
case LLVMContext::MD_dereferenceable:
case LLVMContext::MD_dereferenceable_or_null:
K->setMetadata(Kind,
K->setMetadata(Kind,
MDNode::getMostGenericAlignmentOrDereferenceable(JMD, KMD));
break;
}
Expand Down Expand Up @@ -1812,6 +1813,49 @@ bool llvm::callsGCLeafFunction(ImmutableCallSite CS) {
return false;
}

void llvm::copyNonnullMetadata(const LoadInst &OldLI, MDNode *N,
LoadInst &NewLI) {
auto *NewTy = NewLI.getType();

// This only directly applies if the new type is also a pointer.
if (NewTy->isPointerTy()) {
NewLI.setMetadata(LLVMContext::MD_nonnull, N);
return;
}

// The only other translation we can do is to integral loads with !range
// metadata.
if (!NewTy->isIntegerTy())
return;

MDBuilder MDB(NewLI.getContext());
const Value *Ptr = OldLI.getPointerOperand();
auto *ITy = cast<IntegerType>(NewTy);
auto *NullInt = ConstantExpr::getPtrToInt(
ConstantPointerNull::get(cast<PointerType>(Ptr->getType())), ITy);
auto *NonNullInt = ConstantExpr::getAdd(NullInt, ConstantInt::get(ITy, 1));
NewLI.setMetadata(LLVMContext::MD_range,
MDB.createRange(NonNullInt, NullInt));
}

void llvm::copyRangeMetadata(const DataLayout &DL, const LoadInst &OldLI,
MDNode *N, LoadInst &NewLI) {
auto *NewTy = NewLI.getType();

// Give up unless it is converted to a pointer where there is a single very
// valuable mapping we can do reliably.
// FIXME: It would be nice to propagate this in more ways, but the type
// conversions make it hard.
if (!NewTy->isPointerTy())
return;

unsigned BitWidth = DL.getTypeSizeInBits(NewTy);
if (!getConstantRangeFromMetadata(*N).contains(APInt(BitWidth, 0))) {
MDNode *NN = MDNode::get(OldLI.getContext(), None);
NewLI.setMetadata(LLVMContext::MD_nonnull, NN);
}
}

namespace {
/// A potential constituent of a bitreverse or bswap expression. See
/// collectBitParts for a fuller explanation.
Expand Down Expand Up @@ -1933,7 +1977,7 @@ collectBitParts(Value *V, bool MatchBSwaps, bool MatchBitReversals,
unsigned NumMaskedBits = AndMask.countPopulation();
if (!MatchBitReversals && NumMaskedBits % 8 != 0)
return Result;

auto &Res = collectBitParts(I->getOperand(0), MatchBSwaps,
MatchBitReversals, BPS);
if (!Res)
Expand Down
57 changes: 47 additions & 10 deletions lib/Transforms/Utils/PromoteMemoryToRegister.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,14 @@
//
//===----------------------------------------------------------------------===//

#include "llvm/Transforms/Utils/PromoteMemToReg.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Analysis/AliasSetTracker.h"
#include "llvm/Analysis/AssumptionCache.h"
#include "llvm/Analysis/InstructionSimplify.h"
#include "llvm/Analysis/IteratedDominanceFrontier.h"
#include "llvm/Analysis/ValueTracking.h"
Expand All @@ -38,6 +38,7 @@
#include "llvm/IR/Metadata.h"
#include "llvm/IR/Module.h"
#include "llvm/Transforms/Utils/Local.h"
#include "llvm/Transforms/Utils/PromoteMemToReg.h"
#include <algorithm>
using namespace llvm;

Expand Down Expand Up @@ -301,6 +302,18 @@ struct PromoteMem2Reg {

} // end of anonymous namespace

/// Given a LoadInst LI this adds assume(LI != null) after it.
static void addAssumeNonNull(AssumptionCache *AC, LoadInst *LI) {
Function *AssumeIntrinsic =
Intrinsic::getDeclaration(LI->getModule(), Intrinsic::assume);
ICmpInst *LoadNotNull = new ICmpInst(ICmpInst::ICMP_NE, LI,
Constant::getNullValue(LI->getType()));
LoadNotNull->insertAfter(LI);
CallInst *CI = CallInst::Create(AssumeIntrinsic, {LoadNotNull});
CI->insertAfter(LoadNotNull);
AC->registerAssumption(CI);
}

static void removeLifetimeIntrinsicUsers(AllocaInst *AI) {
// Knowing that this alloca is promotable, we know that it's safe to kill all
// instructions except for load and store.
Expand Down Expand Up @@ -334,9 +347,9 @@ static void removeLifetimeIntrinsicUsers(AllocaInst *AI) {
/// and thus must be phi-ed with undef. We fall back to the standard alloca
/// promotion algorithm in that case.
static bool rewriteSingleStoreAlloca(AllocaInst *AI, AllocaInfo &Info,
LargeBlockInfo &LBI,
DominatorTree &DT,
AliasSetTracker *AST) {
LargeBlockInfo &LBI, DominatorTree &DT,
AliasSetTracker *AST,
AssumptionCache *AC) {
StoreInst *OnlyStore = Info.OnlyStore;
bool StoringGlobalVal = !isa<Instruction>(OnlyStore->getOperand(0));
BasicBlock *StoreBB = OnlyStore->getParent();
Expand Down Expand Up @@ -387,6 +400,14 @@ static bool rewriteSingleStoreAlloca(AllocaInst *AI, AllocaInfo &Info,
// code.
if (ReplVal == LI)
ReplVal = UndefValue::get(LI->getType());

// If the load was marked as nonnull we don't want to lose
// that information when we erase this Load. So we preserve
// it with an assume.
if (AC && LI->getMetadata(LLVMContext::MD_nonnull) &&
!llvm::isKnownNonNullAt(ReplVal, LI, &DT))
addAssumeNonNull(AC, LI);

LI->replaceAllUsesWith(ReplVal);
if (AST && LI->getType()->isPointerTy())
AST->deleteValue(LI);
Expand Down Expand Up @@ -435,7 +456,9 @@ static bool rewriteSingleStoreAlloca(AllocaInst *AI, AllocaInfo &Info,
/// }
static bool promoteSingleBlockAlloca(AllocaInst *AI, const AllocaInfo &Info,
LargeBlockInfo &LBI,
AliasSetTracker *AST) {
AliasSetTracker *AST,
DominatorTree &DT,
AssumptionCache *AC) {
// The trickiest case to handle is when we have large blocks. Because of this,
// this code is optimized assuming that large blocks happen. This does not
// significantly pessimize the small block case. This uses LargeBlockInfo to
Expand Down Expand Up @@ -476,10 +499,17 @@ static bool promoteSingleBlockAlloca(AllocaInst *AI, const AllocaInfo &Info,
// There is no store before this load, bail out (load may be affected
// by the following stores - see main comment).
return false;
}
else
} else {
// Otherwise, there was a store before this load, the load takes its value.
LI->replaceAllUsesWith(std::prev(I)->second->getOperand(0));
// Note, if the load was marked as nonnull we don't want to lose that
// information when we erase it. So we preserve it with an assume.
Value *ReplVal = std::prev(I)->second->getOperand(0);
if (AC && LI->getMetadata(LLVMContext::MD_nonnull) &&
!llvm::isKnownNonNullAt(ReplVal, LI, &DT))
addAssumeNonNull(AC, LI);

LI->replaceAllUsesWith(ReplVal);
}

if (AST && LI->getType()->isPointerTy())
AST->deleteValue(LI);
Expand Down Expand Up @@ -553,7 +583,7 @@ void PromoteMem2Reg::run() {
// If there is only a single store to this value, replace any loads of
// it that are directly dominated by the definition with the value stored.
if (Info.DefiningBlocks.size() == 1) {
if (rewriteSingleStoreAlloca(AI, Info, LBI, DT, AST)) {
if (rewriteSingleStoreAlloca(AI, Info, LBI, DT, AST, AC)) {
// The alloca has been processed, move on.
RemoveFromAllocasList(AllocaNum);
++NumSingleStore;
Expand All @@ -564,7 +594,7 @@ void PromoteMem2Reg::run() {
// If the alloca is only read and written in one basic block, just perform a
// linear sweep over the block to eliminate it.
if (Info.OnlyUsedInOneBlock &&
promoteSingleBlockAlloca(AI, Info, LBI, AST)) {
promoteSingleBlockAlloca(AI, Info, LBI, AST, DT, AC)) {
// The alloca has been processed, move on.
RemoveFromAllocasList(AllocaNum);
continue;
Expand Down Expand Up @@ -940,6 +970,13 @@ void PromoteMem2Reg::RenamePass(BasicBlock *BB, BasicBlock *Pred,

Value *V = IncomingVals[AI->second];

// If the load was marked as nonnull we don't want to lose
// that information when we erase this Load. So we preserve
// it with an assume.
if (AC && LI->getMetadata(LLVMContext::MD_nonnull) &&
!llvm::isKnownNonNullAt(V, LI, &DT))
addAssumeNonNull(AC, LI);

// Anything using the load now uses the current value.
LI->replaceAllUsesWith(V);
if (AST && LI->getType()->isPointerTy())
Expand Down
Loading