blob: 1f38a73653a21a358b75234d002f8e5eed7844cf [file] [log] [blame]
///////////////////////////////////////////////////////////////////////////////
// //
// HLPreprocess.cpp //
// Copyright (C) Microsoft Corporation. All rights reserved. //
// This file is distributed under the University of Illinois Open Source //
// License. See LICENSE.TXT for details. //
// //
// Preprocess HLModule after inline. //
// //
///////////////////////////////////////////////////////////////////////////////
#include "llvm/IR/Function.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/Module.h"
#include "dxc/HLSL/DxilGenerationPass.h"
using namespace llvm;
///////////////////////////////////////////////////////////////////////////////
// HLPreprocess.
// Inliner will create stacksave stackstore if there are allocas inside block
// other than entry block. HLPreprocess will remove stacksave and stackstore and
// put all allocas inside entry block.
//
namespace {
class HLPreprocess : public ModulePass {
public:
static char ID; // Pass identification, replacement for typeid
explicit HLPreprocess() : ModulePass(ID) {}
StringRef getPassName() const override {
return "Preprocess HLModule after inline";
}
bool runOnModule(Module &M) override {
bool bUpdated = false;
// Remove stacksave and stackstore.
// Get the two intrinsics we care about.
Function *StackSave = Intrinsic::getDeclaration(&M, Intrinsic::stacksave);
Function *StackRestore =
Intrinsic::getDeclaration(&M, Intrinsic::stackrestore);
// If has user, remove user first.
if (!StackSave->user_empty() || !StackRestore->user_empty()) {
for (auto it = StackRestore->user_begin();
it != StackRestore->user_end();) {
Instruction *I = cast<Instruction>(*(it++));
I->eraseFromParent();
}
for (auto it = StackSave->user_begin(); it != StackSave->user_end();) {
Instruction *I = cast<Instruction>(*(it++));
I->eraseFromParent();
}
bUpdated = true;
}
StackSave->eraseFromParent();
StackRestore->eraseFromParent();
// If stacksave/store is present, it means alloca not in the
// entry block. However, there could be other cases where allocas
// could be present in the non-entry blocks.
// Therefore, always go through all non-entry blocks and
// make sure all allocas are moved to the entry block.
for (Function &F : M.functions()) {
bUpdated |= MoveAllocasToEntryBlock(&F);
}
return bUpdated;
}
private:
bool MoveAllocasToEntryBlock(Function *F);
};
char HLPreprocess::ID = 0;
// Make sure all allocas are in entry block.
bool HLPreprocess::MoveAllocasToEntryBlock(Function *F) {
bool changed = false;
if (F->getBasicBlockList().size() < 2)
return changed;
BasicBlock &Entry = F->getEntryBlock();
IRBuilder<> Builder(Entry.getFirstInsertionPt());
for (auto bb = F->begin(); bb != F->end(); bb++) {
BasicBlock *BB = bb;
if (BB == &Entry)
continue;
for (auto it = BB->begin(); it != BB->end();) {
Instruction *I = (it++);
if (isa<AllocaInst>(I)) {
I->removeFromParent();
Builder.Insert(I);
changed = true;
}
}
}
return changed;
}
} // namespace
ModulePass *llvm::createHLPreprocessPass() { return new HLPreprocess(); }
INITIALIZE_PASS(HLPreprocess, "hl-preprocess",
"Preprocess HLModule after inline", false, false)