-
-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: use llvm new pass manager api #352
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,8 @@ | ||
/* | ||
Some LLVM passes helpful for | ||
integrating immix with LLVM | ||
*/ | ||
|
||
#include "llvm/IR/PassManager.h" | ||
#include "llvm/IR/IRBuilder.h" | ||
#include "llvm/Transforms/Utils/ModuleUtils.h" | ||
|
@@ -9,50 +14,85 @@ | |
using namespace llvm; | ||
namespace | ||
{ | ||
struct Immix : public ModulePass | ||
void immixPassLogic(Module &M); | ||
// The new pass manager plugin | ||
class ImmixPass : public PassInfoMixin<ImmixPass> | ||
{ | ||
static char ID; | ||
Immix() : ModulePass(ID) {} | ||
|
||
public: | ||
PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM); | ||
}; | ||
PreservedAnalyses ImmixPass::run(Module &M, ModuleAnalysisManager &AM) | ||
{ | ||
immixPassLogic(M); | ||
return PreservedAnalyses::all(); | ||
} | ||
|
||
/* | ||
This pass helps integrate immix with LLVM. | ||
|
||
It does the following: | ||
- Sets the GC name to "plimmix" for all functions | ||
- Adds a call to immix_gc_init in the global constructor | ||
- Adds a global variable declaration for the module stack map | ||
|
||
However, it does not generate the stack map. This is done by the | ||
immix compiler plugin. | ||
|
||
Also note that mauch more work is needed to get immix working with | ||
LLVM. Besides the pass, you need to: | ||
- Implement visit functions for all complex types | ||
- insert stack roots for all heap pointers | ||
- replace all malloc calls with immix::alloc | ||
... | ||
*/ | ||
void immixPassLogic(Module &M) | ||
{ | ||
for (auto FB = M.functions().begin(), FE = M.functions().end(); FB != FE; ++FB) | ||
{ | ||
Function *FV = &*FB; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. just curious, why not use |
||
FV->setGC("plimmix"); | ||
} | ||
// auto gc_init_c = M.getOrInsertFunction("__gc_init_stackmap", Type::getVoidTy(M.getContext())); | ||
auto immix_init_c = M.getOrInsertFunction("immix_gc_init", Type::getVoidTy(M.getContext()), PointerType::get(IntegerType::get(M.getContext(), 8), 0)); | ||
auto immix_init_f = cast<Function>(immix_init_c.getCallee()); | ||
immix_init_f->setLinkage(GlobalValue::LinkageTypes::ExternalLinkage); | ||
SmallVector<Type *, 1> argTypes; | ||
argTypes.push_back(PointerType::get(IntegerType::get(M.getContext(), 8), 0)); | ||
std::string symbol; | ||
symbol += "_IMMIX_GC_MAP_"; | ||
symbol += M.getSourceFileName(); | ||
auto g = M.getOrInsertGlobal(symbol, Type::getInt8Ty(M.getContext())); | ||
GlobalVariable *g_c = cast<GlobalVariable>(g); | ||
g_c->setLinkage(GlobalValue::LinkageTypes::ExternalWeakLinkage); | ||
// auto g = M.getNamedGlobal(symbol); | ||
SmallVector<Value *, 1> assertArgs; | ||
assertArgs.push_back(g); | ||
Function *gc_init_f; | ||
std::tie(gc_init_f, std::ignore) = createSanitizerCtorAndInitFunctions(M, "__gc_init_stackmap", "immix_gc_init", argTypes, assertArgs); | ||
gc_init_f->setLinkage(GlobalValue::LinkageTypes::InternalLinkage); | ||
// appendToCompilerUsed(M, gc_init_f); | ||
appendToGlobalCtors(M, gc_init_f, 1000); | ||
} | ||
|
||
// The old pass manager plugin | ||
struct ImmixLegacy : public ModulePass | ||
{ | ||
static char ID; | ||
ImmixLegacy() : ModulePass(ID) {} | ||
|
||
bool runOnModule(Module &M) override | ||
{ | ||
for (auto FB = M.functions().begin(), FE = M.functions().end(); FB != FE; ++FB) | ||
{ | ||
Function *FV = &*FB; | ||
FV->setGC("plimmix"); | ||
} | ||
// auto gc_init_c = M.getOrInsertFunction("__gc_init_stackmap", Type::getVoidTy(M.getContext())); | ||
auto immix_init_c = M.getOrInsertFunction("immix_gc_init", Type::getVoidTy(M.getContext()), PointerType::get(IntegerType::get(M.getContext(), 8), 0)); | ||
auto immix_init_f = cast<Function>(immix_init_c.getCallee()); | ||
immix_init_f->setLinkage(GlobalValue::LinkageTypes::ExternalLinkage); | ||
SmallVector<Type *, 1> argTypes; | ||
argTypes.push_back(PointerType::get(IntegerType::get(M.getContext(), 8), 0)); | ||
std::string symbol; | ||
symbol += "_IMMIX_GC_MAP_"; | ||
symbol += M.getSourceFileName(); | ||
auto g = M.getOrInsertGlobal(symbol, Type::getInt8Ty(M.getContext())); | ||
GlobalVariable *g_c = cast<GlobalVariable>(g); | ||
g_c->setLinkage(GlobalValue::LinkageTypes::ExternalWeakLinkage); | ||
// auto g = M.getNamedGlobal(symbol); | ||
SmallVector<Value *, 1> assertArgs; | ||
assertArgs.push_back(g); | ||
Function *gc_init_f; | ||
std::tie(gc_init_f, std::ignore) = createSanitizerCtorAndInitFunctions(M, "__gc_init_stackmap", "immix_gc_init", argTypes, assertArgs); | ||
gc_init_f->setLinkage(GlobalValue::LinkageTypes::InternalLinkage); | ||
// appendToCompilerUsed(M, gc_init_f); | ||
appendToGlobalCtors(M, gc_init_f, 1000); | ||
immixPassLogic(M); | ||
|
||
return true; | ||
} | ||
}; | ||
} | ||
char Immix::ID = 0; | ||
static RegisterPass<Immix> X("plimmix", "plimmix gc Pass", | ||
false /* Only looks at CFG */, | ||
false /* Analysis Pass */); | ||
|
||
// static llvm::RegisterStandardPasses Y( | ||
// llvm::PassManagerBuilder::EP_EarlyAsPossible, | ||
// [](const llvm::PassManagerBuilder &Builder, | ||
// llvm::legacy::PassManagerBase &PM) | ||
// { PM.add(new Immix()); }); | ||
|
||
// char ImmixPass::ID = 0; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. unused comment |
||
char ImmixLegacy::ID = 0; | ||
static RegisterPass<ImmixLegacy> X("plimmix", "plimmix gc Pass", | ||
false /* Only looks at CFG */, | ||
false /* Analysis Pass */); |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -144,6 +144,7 @@ pub struct LLVMBuilder<'a, 'ctx> { | |
optimized: Arc<RefCell<bool>>, | ||
used: Arc<RefCell<Vec<FunctionValue<'ctx>>>>, | ||
difile: Cell<DIFile<'ctx>>, | ||
optlevel: OptimizationLevel, | ||
} | ||
|
||
pub fn get_target_machine(level: OptimizationLevel) -> TargetMachine { | ||
|
@@ -184,6 +185,7 @@ impl<'a, 'ctx> LLVMBuilder<'a, 'ctx> { | |
dibuilder: &'a DebugInfoBuilder<'ctx>, | ||
diunit: &'a DICompileUnit<'ctx>, | ||
tm: &'a TargetMachine, | ||
opt: OptimizationLevel, | ||
) -> Self { | ||
module.set_triple(&TargetMachine::get_default_triple()); | ||
Self { | ||
|
@@ -204,6 +206,7 @@ impl<'a, 'ctx> LLVMBuilder<'a, 'ctx> { | |
optimized: Arc::new(RefCell::new(false)), | ||
used: Default::default(), | ||
difile: Cell::new(diunit.get_file()), | ||
optlevel: opt, | ||
} | ||
} | ||
fn alloc_raw( | ||
|
@@ -1513,24 +1516,27 @@ impl<'a, 'ctx> LLVMBuilder<'a, 'ctx> { | |
.add_global(used_arr.get_type(), None, "llvm.used"); | ||
used_global.set_linkage(Linkage::Appending); | ||
used_global.set_initializer(&used_arr); | ||
|
||
if crate::ast::jit_config::IS_JIT.load(std::sync::atomic::Ordering::Relaxed) { | ||
// jit is using shadow stack, skip immix pass | ||
self.module.get_functions().for_each(|f| { | ||
f.set_gc("shadow-stack"); | ||
}); | ||
} else { | ||
extern "C" { | ||
fn add_module_pass(ptr: *mut u8); | ||
// fn add_module_pass(ptr: *mut u8); | ||
fn run_module_pass(m: *mut u8, tm: i32); | ||
} | ||
let ptr = unsafe { llvm_sys::core::LLVMCreatePassManager() }; | ||
let mpm: inkwell::passes::PassManager<Module> = | ||
unsafe { inkwell::passes::PassManager::new(ptr) }; | ||
|
||
// let ptr = unsafe { llvm_sys::core::LLVMCreatePassManager() }; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. remove unused comments. |
||
// let mpm: inkwell::passes::PassManager<Module> = | ||
// unsafe { inkwell::passes::PassManager::new(ptr) }; | ||
|
||
// unsafe { | ||
// add_module_pass(ptr as _); | ||
// }; | ||
// mpm.run_on(self.module); | ||
unsafe { | ||
add_module_pass(ptr as _); | ||
}; | ||
mpm.run_on(self.module); | ||
run_module_pass(self.module.as_mut_ptr() as _, self.optlevel as i32); | ||
} | ||
} | ||
*self.optimized.borrow_mut() = true; | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could add a comment about
run_module_pass
to explain: