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. #68

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
10 changes: 10 additions & 0 deletions include/llvm/IR/Instruction.h
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,16 @@ class Instruction : public User,
void setMetadata(unsigned KindID, MDNode *Node);
void setMetadata(StringRef Kind, MDNode *Node);

/// Copy metadata from \p SrcInst to this instruction. \p WL, if not empty,
/// specifies the list of meta data that needs to be copied. If \p WL is
/// empty, all meta data will be copied.
void copyMetadata(const Instruction &SrcInst, ArrayRef<unsigned> WL = {});

/// If the instruction has "branch_weights" MD_prof metadata and the MDNode
/// has three operands (including name string), swap the order of the
/// metadata.
void swapProfMetadata();

/// Drop all unknown metadata except for debug locations.
/// @{
/// Passes are required to drop metadata they don't understand. This is a
Expand Down
54 changes: 43 additions & 11 deletions lib/IR/Instruction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
//
//===----------------------------------------------------------------------===//

#include "llvm/ADT/DenseSet.h"
#include "llvm/IR/Instruction.h"
#include "llvm/IR/CallSite.h"
#include "llvm/IR/Constants.h"
Expand Down Expand Up @@ -627,6 +628,47 @@ Instruction *Instruction::cloneImpl() const {
llvm_unreachable("Subclass of Instruction failed to implement cloneImpl");
}

void Instruction::swapProfMetadata() {
MDNode *ProfileData = getMetadata(LLVMContext::MD_prof);
if (!ProfileData || ProfileData->getNumOperands() != 3 ||
!isa<MDString>(ProfileData->getOperand(0)))
return;

MDString *MDName = cast<MDString>(ProfileData->getOperand(0));
if (MDName->getString() != "branch_weights")
return;

// The first operand is the name. Fetch them backwards and build a new one.
Metadata *Ops[] = {ProfileData->getOperand(0), ProfileData->getOperand(2),
ProfileData->getOperand(1)};
setMetadata(LLVMContext::MD_prof,
MDNode::get(ProfileData->getContext(), Ops));
}

/// Copy meta data from \p SrcInst to this instruction. If WL is empty, all
/// data will be copied, otherwise only ones specified in WL will be copied.
void Instruction::copyMetadata(const Instruction &SrcInst,
ArrayRef<unsigned> WL) {
if (!SrcInst.hasMetadata())
return;

DenseSet<unsigned> WLS;
for (unsigned M : WL)
WLS.insert(M);

// Otherwise, enumerate and copy over metadata from the old instruction to the
// new one.
SmallVector<std::pair<unsigned, MDNode *>, 4> TheMDs;
SrcInst.getAllMetadataOtherThanDebugLoc(TheMDs);
for (const auto &MD : TheMDs) {
if (WL.empty() || WLS.count(MD.first))
setMetadata(MD.first, MD.second);
}
if (WL.empty() || WLS.count(LLVMContext::MD_dbg))
setDebugLoc(SrcInst.getDebugLoc());
return;
}

Instruction *Instruction::clone() const {
Instruction *New = nullptr;
switch (getOpcode()) {
Expand All @@ -641,16 +683,6 @@ Instruction *Instruction::clone() const {
}

New->SubclassOptionalData = SubclassOptionalData;
if (!hasMetadata())
return New;

// Otherwise, enumerate and copy over metadata from the old instruction to the
// new one.
SmallVector<std::pair<unsigned, MDNode *>, 4> TheMDs;
getAllMetadataOtherThanDebugLoc(TheMDs);
for (const auto &MD : TheMDs)
New->setMetadata(MD.first, MD.second);

New->setDebugLoc(getDebugLoc());
New->copyMetadata(*this);
return New;
}
10 changes: 1 addition & 9 deletions lib/IR/Instructions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1209,15 +1209,7 @@ void BranchInst::swapSuccessors() {

// Update profile metadata if present and it matches our structural
// expectations.
MDNode *ProfileData = getMetadata(LLVMContext::MD_prof);
if (!ProfileData || ProfileData->getNumOperands() != 3)
return;

// The first operand is the name. Fetch them backwards and build a new one.
Metadata *Ops[] = {ProfileData->getOperand(0), ProfileData->getOperand(2),
ProfileData->getOperand(1)};
setMetadata(LLVMContext::MD_prof,
MDNode::get(ProfileData->getContext(), Ops));
swapProfMetadata();
}

BasicBlock *BranchInst::getSuccessorV(unsigned idx) const {
Expand Down
45 changes: 8 additions & 37 deletions lib/Transforms/Scalar/LoopUnswitch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -742,42 +742,6 @@ static Loop *CloneLoop(Loop *L, Loop *PL, ValueToValueMapTy &VM,
return &New;
}

static void copyMetadata(Instruction *DstInst, const Instruction *SrcInst,
bool Swapped) {
if (!SrcInst || !SrcInst->hasMetadata())
return;

SmallVector<std::pair<unsigned, MDNode *>, 4> MDs;
SrcInst->getAllMetadata(MDs);
for (auto &MD : MDs) {
switch (MD.first) {
default:
break;
case LLVMContext::MD_prof:
if (Swapped && MD.second->getNumOperands() == 3 &&
isa<MDString>(MD.second->getOperand(0))) {
MDString *MDName = cast<MDString>(MD.second->getOperand(0));
if (MDName->getString() == "branch_weights") {
auto *ValT = cast_or_null<ConstantAsMetadata>(
MD.second->getOperand(1))->getValue();
auto *ValF = cast_or_null<ConstantAsMetadata>(
MD.second->getOperand(2))->getValue();
assert(ValT && ValF && "Invalid Operands of branch_weights");
auto NewMD =
MDBuilder(DstInst->getParent()->getContext())
.createBranchWeights(cast<ConstantInt>(ValF)->getZExtValue(),
cast<ConstantInt>(ValT)->getZExtValue());
MD.second = NewMD;
}
}
// fallthrough.
case LLVMContext::MD_make_implicit:
case LLVMContext::MD_dbg:
DstInst->setMetadata(MD.first, MD.second);
}
}
}

/// Emit a conditional branch on two values if LIC == Val, branch to TrueDst,
/// otherwise branch to FalseDest. Insert the code immediately before InsertPt.
void LoopUnswitch::EmitPreheaderBranchOnCondition(Value *LIC, Constant *Val,
Expand All @@ -800,7 +764,14 @@ void LoopUnswitch::EmitPreheaderBranchOnCondition(Value *LIC, Constant *Val,

// Insert the new branch.
BranchInst *BI = BranchInst::Create(TrueDest, FalseDest, BranchVal, InsertPt);
copyMetadata(BI, TI, Swapped);
if (TI) {
// FIXME: check why white list is needed here:
ArrayRef<unsigned> WL = {LLVMContext::MD_dbg, LLVMContext::MD_prof,
LLVMContext::MD_make_implicit};
BI->copyMetadata(*TI, WL);
if (Swapped)
BI->swapProfMetadata();
}

// If either edge is critical, split it. This helps preserve LoopSimplify
// form for enclosing loops.
Expand Down
4 changes: 4 additions & 0 deletions lib/Transforms/Scalar/SROA.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2390,6 +2390,10 @@ class llvm::sroa::AllocaSliceRewriter
LI.isVolatile(), LI.getName());
if (LI.isVolatile())
NewLI->setAtomic(LI.getOrdering(), LI.getSynchScope());

// Try to preserve nonnull metadata
if (TargetTy->isPointerTy())
NewLI->copyMetadata(LI, LLVMContext::MD_nonnull);
V = NewLI;

// If this is an integer load past the end of the slice (which means the
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 @@ -938,6 +968,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