|
@@ -0,0 +1,105 @@
|
|
|
|
+///////////////////////////////////////////////////////////////////////////////
|
|
|
|
+// //
|
|
|
|
+// 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/Module.h"
|
|
|
|
+#include "llvm/IR/IRBuilder.h"
|
|
|
|
+#include "llvm/IR/Intrinsics.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) {}
|
|
|
|
+
|
|
|
|
+ const char *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();
|
|
|
|
+ // Has stacksave/store mean alloca not in entry block.
|
|
|
|
+ if (bUpdated) {
|
|
|
|
+ // Make sure all allocas are in entry block.
|
|
|
|
+ for (Function &F : M.functions()) {
|
|
|
|
+ MoveAllocasToEntryBlock(&F);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return bUpdated;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+private:
|
|
|
|
+ void MoveAllocasToEntryBlock(Function *F);
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+char HLPreprocess::ID = 0;
|
|
|
|
+
|
|
|
|
+// Make sure all allocas are in entry block.
|
|
|
|
+void HLPreprocess::MoveAllocasToEntryBlock(Function *F) {
|
|
|
|
+ if (F->getBasicBlockList().size() < 2)
|
|
|
|
+ return;
|
|
|
|
+ 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);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+} // namespace
|
|
|
|
+
|
|
|
|
+ModulePass *llvm::createHLPreprocessPass() { return new HLPreprocess(); }
|
|
|
|
+
|
|
|
|
+INITIALIZE_PASS(HLPreprocess, "hl-preprocess",
|
|
|
|
+ "Preprocess HLModule after inline", false, false)
|