Skip to content

Commit c7ebd9f

Browse files
author
Akshay Deodhar
committed
removes segfault caused by wrong object destruction order, adds global optimizations, toy JIT
1 parent db7aab2 commit c7ebd9f

3 files changed

Lines changed: 149 additions & 18 deletions

File tree

KaleidoscopeJIT.h

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
//===- KaleidoscopeJIT.h - A simple JIT for Kaleidoscope --------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// Contains a simple JIT definition for use in the kaleidoscope tutorials.
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef LLVM_EXECUTIONENGINE_ORC_KALEIDOSCOPEJIT_H
14+
#define LLVM_EXECUTIONENGINE_ORC_KALEIDOSCOPEJIT_H
15+
16+
#include "llvm/ADT/StringRef.h"
17+
#include "llvm/ExecutionEngine/JITSymbol.h"
18+
#include "llvm/ExecutionEngine/Orc/CompileUtils.h"
19+
#include "llvm/ExecutionEngine/Orc/Core.h"
20+
#include "llvm/ExecutionEngine/Orc/ExecutionUtils.h"
21+
#include "llvm/ExecutionEngine/Orc/ExecutorProcessControl.h"
22+
#include "llvm/ExecutionEngine/Orc/IRCompileLayer.h"
23+
#include "llvm/ExecutionEngine/Orc/JITTargetMachineBuilder.h"
24+
#include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h"
25+
#include "llvm/ExecutionEngine/SectionMemoryManager.h"
26+
#include "llvm/IR/DataLayout.h"
27+
#include "llvm/IR/LLVMContext.h"
28+
#include <memory>
29+
30+
namespace llvm {
31+
namespace orc {
32+
33+
class KaleidoscopeJIT {
34+
private:
35+
std::unique_ptr<ExecutionSession> ES;
36+
37+
DataLayout DL;
38+
MangleAndInterner Mangle;
39+
40+
RTDyldObjectLinkingLayer ObjectLayer;
41+
IRCompileLayer CompileLayer;
42+
43+
JITDylib &MainJD;
44+
45+
public:
46+
KaleidoscopeJIT(std::unique_ptr<ExecutionSession> ES,
47+
JITTargetMachineBuilder JTMB, DataLayout DL)
48+
: ES(std::move(ES)), DL(std::move(DL)), Mangle(*this->ES, this->DL),
49+
ObjectLayer(*this->ES,
50+
[]() { return std::make_unique<SectionMemoryManager>(); }),
51+
CompileLayer(*this->ES, ObjectLayer,
52+
std::make_unique<ConcurrentIRCompiler>(std::move(JTMB))),
53+
MainJD(this->ES->createBareJITDylib("<main>")) {
54+
MainJD.addGenerator(
55+
cantFail(DynamicLibrarySearchGenerator::GetForCurrentProcess(
56+
DL.getGlobalPrefix())));
57+
}
58+
59+
~KaleidoscopeJIT() {
60+
if (auto Err = ES->endSession())
61+
ES->reportError(std::move(Err));
62+
}
63+
64+
static Expected<std::unique_ptr<KaleidoscopeJIT>> Create() {
65+
auto EPC = SelfExecutorProcessControl::Create();
66+
if (!EPC)
67+
return EPC.takeError();
68+
69+
auto ES = std::make_unique<ExecutionSession>(std::move(*EPC));
70+
71+
JITTargetMachineBuilder JTMB(
72+
ES->getExecutorProcessControl().getTargetTriple());
73+
74+
auto DL = JTMB.getDefaultDataLayoutForTarget();
75+
if (!DL)
76+
return DL.takeError();
77+
78+
return std::make_unique<KaleidoscopeJIT>(std::move(ES), std::move(JTMB),
79+
std::move(*DL));
80+
}
81+
82+
const DataLayout &getDataLayout() const { return DL; }
83+
84+
JITDylib &getMainJITDylib() { return MainJD; }
85+
86+
Error addModule(ThreadSafeModule TSM, ResourceTrackerSP RT = nullptr) {
87+
if (!RT)
88+
RT = MainJD.getDefaultResourceTracker();
89+
return CompileLayer.add(RT, std::move(TSM));
90+
}
91+
92+
Expected<JITEvaluatedSymbol> lookup(StringRef Name) {
93+
return ES->lookup({&MainJD}, Mangle(Name.str()));
94+
}
95+
};
96+
97+
} // end namespace orc
98+
} // end namespace llvm
99+
100+
#endif // LLVM_EXECUTIONENGINE_ORC_KALEIDOSCOPEJIT_H

Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
kaleidoscope: kaleidoscope.cpp
2-
clang++ -g3 -Wall kaleidoscope.cpp `llvm-config --cxxflags --ldflags --system-libs --libs core` -o kaleidoscope
2+
clang++ -g3 -Wall kaleidoscope.cpp `llvm-config --cxxflags --ldflags --system-libs --libs core orcjit native` -o kaleidoscope
33

44
theirkaleidoscope: theirkaleidoscope.cpp
5-
clang++ -g3 -Wall theirkaleidoscope.cpp `llvm-config --cxxflags --ldflags --system-libs --libs core` -o theirkaleidoscope
5+
clang++ -g3 -Wall theirkaleidoscope.cpp `llvm-config --cxxflags --ldflags --system-libs --libs core orcjit native` -o theirkaleidoscope
66

77
test: kaleidoscope fib.k
88
cat fib.k | ./kaleidoscope

kaleidoscope.cpp

Lines changed: 47 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,15 @@
66
#include "llvm/IR/Function.h"
77
#include "llvm/IR/IRBuilder.h"
88
#include "llvm/IR/LLVMContext.h"
9+
#include "llvm/IR/LegacyPassManager.h"
910
#include "llvm/IR/Module.h"
1011
#include "llvm/IR/Type.h"
1112
#include "llvm/IR/Verifier.h"
13+
#include "llvm/Support/TargetSelect.h"
14+
#include "llvm/Target/TargetMachine.h"
15+
#include "llvm/Transforms/InstCombine/InstCombine.h"
16+
#include "llvm/Transforms/Scalar.h"
17+
#include "llvm/Transforms/Scalar/GVN.h"
1218
#include <iostream>
1319
#include <string>
1420
#include <vector>
@@ -18,6 +24,7 @@
1824
#include <cstdio>
1925
#include <cstdlib>
2026
#include <unordered_map>
27+
#include "./KaleidoscopeJIT.h"
2128

2229
using namespace llvm;
2330

@@ -107,9 +114,10 @@ static int gettok(void){
107114

108115

109116
// State variables
110-
static std::unique_ptr<IRBuilder<>> Builder; // for creating instructions, constants, etc
111-
static std::unique_ptr<Module> TheModule; // to hold blocks, definitions? (TODO), TODO: why does this have to be a pointer?
112117
static std::unique_ptr<LLVMContext> TheContext;
118+
static std::unique_ptr<Module> TheModule; // to hold blocks, definitions? (TODO), TODO: why does this have to be a pointer?
119+
static std::unique_ptr<IRBuilder<>> Builder; // for creating instructions, constants, etc
120+
static std::unique_ptr<legacy::FunctionPassManager> TheFPM; // Function pass manager
113121
static std::unordered_map<std::string, Value *> Symbols; // Maps names inside function context to LLVM "values"
114122

115123

@@ -679,12 +687,6 @@ Value* VariableExprAST::codegen() {
679687
// Generates code for function call, returns `Value` of function call
680688
Value* CallExprAST::codegen() {
681689

682-
// Generate code for arguments, and get their values
683-
std::vector<Value *> Argvec;
684-
for (const auto& arg: Args) {
685-
Argvec.push_back(arg->codegen());
686-
}
687-
688690
// Obtain function with name `Callee` from Module
689691
Function *func = TheModule->getFunction(Callee);
690692
if (!func) {
@@ -699,16 +701,24 @@ Value* CallExprAST::codegen() {
699701
);
700702
}
701703

704+
// Generate code for arguments, and get their values
705+
std::vector<Value *> Argvec;
706+
for (const auto& arg: Args) {
707+
Argvec.push_back(arg->codegen());
708+
}
709+
710+
711+
702712
// TODO: why do I need to provide TheContext to getDoubleTy?
703-
std::vector<Type *> ArgTypes = std::vector<Type *>(Args.size(), Builder->getDoubleTy());
713+
//std::vector<Type *> ArgTypes = std::vector<Type *>(Args.size(), Builder->getDoubleTy());
704714

705715
// Create type for call
706716
// TODO: this is not needed: CreateCall can be called without a type
707717
// Why is this so? Is it because the function does not take variable arguments?
708718
//FunctionType *func_type = FunctionType::get(Builder->getDoubleTy(), ArgTypes, false);
709719

710720
// Create call
711-
return Builder->CreateCall(func, Argvec, Callee);
721+
return Builder->CreateCall(func, Argvec, "call");
712722
}
713723

714724
Value* BinaryExprAST::codegen() {
@@ -742,6 +752,7 @@ Value* BinaryExprAST::codegen() {
742752
return Builder->CreateUIToFP(L, Builder->getDoubleTy(), "booltofp");
743753
default:
744754
return LogErrorV("Invalid Operator");
755+
break;
745756
}
746757
}
747758

@@ -797,6 +808,9 @@ Function* FunctionAST::codegen() {
797808
// TODO: What if this check fails? Do I still continue?
798809
verifyFunction(*func);
799810

811+
// Run passes on function
812+
TheFPM->run(*func);
813+
800814
return func;
801815
}
802816

@@ -873,15 +887,32 @@ static void HandleTopLevelExpression() {
873887
}
874888
}
875889

876-
static void InitializeModule() {
890+
static void InitializeModuleAndPassManager() {
877891
TheContext = std::make_unique<LLVMContext>();
878892
TheModule = std::make_unique<Module>("kaleidoscope", *TheContext);
893+
// Why .get? Ahh- I want to pass a pointer. What about uniqueness?
894+
TheFPM = std::make_unique<legacy::FunctionPassManager>(TheModule.get());
879895
Builder = std::make_unique<IRBuilder<>>(*TheContext);
896+
897+
// Peephole optimizations
898+
TheFPM->add(createInstructionCombiningPass());
899+
900+
// ?
901+
TheFPM->add(createReassociatePass());
902+
903+
// Global value numbering-> common subexpression elimination. Global is actually per-function
904+
TheFPM->add(createGVNPass());
905+
906+
// Dead code elimination pass;
907+
TheFPM->add(createCFGSimplificationPass());
908+
909+
// Run initalizers for all passes added to pass manager
910+
TheFPM->doInitialization();
880911
}
881912

882913
// top = definition | expression | external | ;
883914
static void MainLoop() {
884-
while(1) {
915+
while(true) {
885916
fprintf(stderr, "ready>");
886917
switch (CurTok) {
887918
case tok_eof:
@@ -940,13 +971,13 @@ int main(void) {
940971
BinopPrecedence['*'] = 40;
941972
BinopPrecedence['/'] = 40;
942973

943-
#if IRGEN
944-
InitializeModule();
945-
#endif
946-
947974
fprintf(stderr, "ready>");
948975
getNextToken();
949976

977+
#if IRGEN
978+
InitializeModuleAndPassManager();
979+
#endif
980+
950981
MainLoop();
951982
//oldmain();
952983

0 commit comments

Comments
 (0)