1#include "../include/KaleidoscopeJIT.h"
2#include "llvm/ADT/APFloat.h"
3#include "llvm/ADT/STLExtras.h"
4#include "llvm/IR/BasicBlock.h"
5#include "llvm/IR/Constants.h"
6#include "llvm/IR/DerivedTypes.h"
7#include "llvm/IR/Function.h"
8#include "llvm/IR/IRBuilder.h"
9#include "llvm/IR/LLVMContext.h"
10#include "llvm/IR/Module.h"
11#include "llvm/IR/PassManager.h"
12#include "llvm/IR/Type.h"
13#include "llvm/IR/Verifier.h"
14#include "llvm/Passes/PassBuilder.h"
15#include "llvm/Passes/StandardInstrumentations.h"
16#include "llvm/Support/TargetSelect.h"
17#include "llvm/Target/TargetMachine.h"
18#include "llvm/Transforms/InstCombine/InstCombine.h"
19#include "llvm/Transforms/Scalar.h"
20#include "llvm/Transforms/Scalar/GVN.h"
21#include "llvm/Transforms/Scalar/Reassociate.h"
22#include "llvm/Transforms/Scalar/SimplifyCFG.h"
23#include <algorithm>
24#include <cassert>
25#include <cctype>
26#include <cstdint>
27#include <cstdio>
28#include <cstdlib>
29#include <map>
30#include <memory>
31#include <string>
32#include <vector>
33
34using namespace llvm;
35using namespace llvm::orc;
36
37//===----------------------------------------------------------------------===//
38// Lexer
39//===----------------------------------------------------------------------===//
40
41// The lexer returns tokens [0-255] if it is an unknown character, otherwise one
42// of these for known things.
43enum Token {
44 tok_eof = -1,
45
46 // commands
47 tok_def = -2,
48 tok_extern = -3,
49
50 // primary
51 tok_identifier = -4,
52 tok_number = -5
53};
54
55static std::string IdentifierStr; // Filled in if tok_identifier
56static double NumVal; // Filled in if tok_number
57
58/// gettok - Return the next token from standard input.
59static int gettok() {
60 static int LastChar = ' ';
61
62 // Skip any whitespace.
63 while (isspace(LastChar))
64 LastChar = getchar();
65
66 if (isalpha(LastChar)) { // identifier: [a-zA-Z][a-zA-Z0-9]*
67 IdentifierStr = LastChar;
68 while (isalnum((LastChar = getchar())))
69 IdentifierStr += LastChar;
70
71 if (IdentifierStr == "def")
72 return tok_def;
73 if (IdentifierStr == "extern")
74 return tok_extern;
75 return tok_identifier;
76 }
77
78 if (isdigit(LastChar) || LastChar == '.') { // Number: [0-9.]+
79 std::string NumStr;
80 do {
81 NumStr += LastChar;
82 LastChar = getchar();
83 } while (isdigit(LastChar) || LastChar == '.');
84
85 NumVal = strtod(nptr: NumStr.c_str(), endptr: nullptr);
86 return tok_number;
87 }
88
89 if (LastChar == '#') {
90 // Comment until end of line.
91 do
92 LastChar = getchar();
93 while (LastChar != EOF && LastChar != '\n' && LastChar != '\r');
94
95 if (LastChar != EOF)
96 return gettok();
97 }
98
99 // Check for end of file. Don't eat the EOF.
100 if (LastChar == EOF)
101 return tok_eof;
102
103 // Otherwise, just return the character as its ascii value.
104 int ThisChar = LastChar;
105 LastChar = getchar();
106 return ThisChar;
107}
108
109//===----------------------------------------------------------------------===//
110// Abstract Syntax Tree (aka Parse Tree)
111//===----------------------------------------------------------------------===//
112
113namespace {
114
115/// ExprAST - Base class for all expression nodes.
116class ExprAST {
117public:
118 virtual ~ExprAST() = default;
119
120 virtual Value *codegen() = 0;
121};
122
123/// NumberExprAST - Expression class for numeric literals like "1.0".
124class NumberExprAST : public ExprAST {
125 double Val;
126
127public:
128 NumberExprAST(double Val) : Val(Val) {}
129
130 Value *codegen() override;
131};
132
133/// VariableExprAST - Expression class for referencing a variable, like "a".
134class VariableExprAST : public ExprAST {
135 std::string Name;
136
137public:
138 VariableExprAST(const std::string &Name) : Name(Name) {}
139
140 Value *codegen() override;
141};
142
143/// BinaryExprAST - Expression class for a binary operator.
144class BinaryExprAST : public ExprAST {
145 char Op;
146 std::unique_ptr<ExprAST> LHS, RHS;
147
148public:
149 BinaryExprAST(char Op, std::unique_ptr<ExprAST> LHS,
150 std::unique_ptr<ExprAST> RHS)
151 : Op(Op), LHS(std::move(LHS)), RHS(std::move(RHS)) {}
152
153 Value *codegen() override;
154};
155
156/// CallExprAST - Expression class for function calls.
157class CallExprAST : public ExprAST {
158 std::string Callee;
159 std::vector<std::unique_ptr<ExprAST>> Args;
160
161public:
162 CallExprAST(const std::string &Callee,
163 std::vector<std::unique_ptr<ExprAST>> Args)
164 : Callee(Callee), Args(std::move(Args)) {}
165
166 Value *codegen() override;
167};
168
169/// PrototypeAST - This class represents the "prototype" for a function,
170/// which captures its name, and its argument names (thus implicitly the number
171/// of arguments the function takes).
172class PrototypeAST {
173 std::string Name;
174 std::vector<std::string> Args;
175
176public:
177 PrototypeAST(const std::string &Name, std::vector<std::string> Args)
178 : Name(Name), Args(std::move(Args)) {}
179
180 Function *codegen();
181 const std::string &getName() const { return Name; }
182};
183
184/// FunctionAST - This class represents a function definition itself.
185class FunctionAST {
186 std::unique_ptr<PrototypeAST> Proto;
187 std::unique_ptr<ExprAST> Body;
188
189public:
190 FunctionAST(std::unique_ptr<PrototypeAST> Proto,
191 std::unique_ptr<ExprAST> Body)
192 : Proto(std::move(Proto)), Body(std::move(Body)) {}
193
194 Function *codegen();
195};
196
197} // end anonymous namespace
198
199//===----------------------------------------------------------------------===//
200// Parser
201//===----------------------------------------------------------------------===//
202
203/// CurTok/getNextToken - Provide a simple token buffer. CurTok is the current
204/// token the parser is looking at. getNextToken reads another token from the
205/// lexer and updates CurTok with its results.
206static int CurTok;
207static int getNextToken() { return CurTok = gettok(); }
208
209/// BinopPrecedence - This holds the precedence for each binary operator that is
210/// defined.
211static std::map<char, int> BinopPrecedence;
212
213/// GetTokPrecedence - Get the precedence of the pending binary operator token.
214static int GetTokPrecedence() {
215 if (!isascii(c: CurTok))
216 return -1;
217
218 // Make sure it's a declared binop.
219 int TokPrec = BinopPrecedence[CurTok];
220 if (TokPrec <= 0)
221 return -1;
222 return TokPrec;
223}
224
225/// LogError* - These are little helper functions for error handling.
226std::unique_ptr<ExprAST> LogError(const char *Str) {
227 fprintf(stderr, format: "Error: %s\n", Str);
228 return nullptr;
229}
230
231std::unique_ptr<PrototypeAST> LogErrorP(const char *Str) {
232 LogError(Str);
233 return nullptr;
234}
235
236static std::unique_ptr<ExprAST> ParseExpression();
237
238/// numberexpr ::= number
239static std::unique_ptr<ExprAST> ParseNumberExpr() {
240 auto Result = std::make_unique<NumberExprAST>(args&: NumVal);
241 getNextToken(); // consume the number
242 return std::move(Result);
243}
244
245/// parenexpr ::= '(' expression ')'
246static std::unique_ptr<ExprAST> ParseParenExpr() {
247 getNextToken(); // eat (.
248 auto V = ParseExpression();
249 if (!V)
250 return nullptr;
251
252 if (CurTok != ')')
253 return LogError(Str: "expected ')'");
254 getNextToken(); // eat ).
255 return V;
256}
257
258/// identifierexpr
259/// ::= identifier
260/// ::= identifier '(' expression* ')'
261static std::unique_ptr<ExprAST> ParseIdentifierExpr() {
262 std::string IdName = IdentifierStr;
263
264 getNextToken(); // eat identifier.
265
266 if (CurTok != '(') // Simple variable ref.
267 return std::make_unique<VariableExprAST>(args&: IdName);
268
269 // Call.
270 getNextToken(); // eat (
271 std::vector<std::unique_ptr<ExprAST>> Args;
272 if (CurTok != ')') {
273 while (true) {
274 if (auto Arg = ParseExpression())
275 Args.push_back(x: std::move(Arg));
276 else
277 return nullptr;
278
279 if (CurTok == ')')
280 break;
281
282 if (CurTok != ',')
283 return LogError(Str: "Expected ')' or ',' in argument list");
284 getNextToken();
285 }
286 }
287
288 // Eat the ')'.
289 getNextToken();
290
291 return std::make_unique<CallExprAST>(args&: IdName, args: std::move(Args));
292}
293
294/// primary
295/// ::= identifierexpr
296/// ::= numberexpr
297/// ::= parenexpr
298static std::unique_ptr<ExprAST> ParsePrimary() {
299 switch (CurTok) {
300 default:
301 return LogError(Str: "unknown token when expecting an expression");
302 case tok_identifier:
303 return ParseIdentifierExpr();
304 case tok_number:
305 return ParseNumberExpr();
306 case '(':
307 return ParseParenExpr();
308 }
309}
310
311/// binoprhs
312/// ::= ('+' primary)*
313static std::unique_ptr<ExprAST> ParseBinOpRHS(int ExprPrec,
314 std::unique_ptr<ExprAST> LHS) {
315 // If this is a binop, find its precedence.
316 while (true) {
317 int TokPrec = GetTokPrecedence();
318
319 // If this is a binop that binds at least as tightly as the current binop,
320 // consume it, otherwise we are done.
321 if (TokPrec < ExprPrec)
322 return LHS;
323
324 // Okay, we know this is a binop.
325 int BinOp = CurTok;
326 getNextToken(); // eat binop
327
328 // Parse the primary expression after the binary operator.
329 auto RHS = ParsePrimary();
330 if (!RHS)
331 return nullptr;
332
333 // If BinOp binds less tightly with RHS than the operator after RHS, let
334 // the pending operator take RHS as its LHS.
335 int NextPrec = GetTokPrecedence();
336 if (TokPrec < NextPrec) {
337 RHS = ParseBinOpRHS(ExprPrec: TokPrec + 1, LHS: std::move(RHS));
338 if (!RHS)
339 return nullptr;
340 }
341
342 // Merge LHS/RHS.
343 LHS =
344 std::make_unique<BinaryExprAST>(args&: BinOp, args: std::move(LHS), args: std::move(RHS));
345 }
346}
347
348/// expression
349/// ::= primary binoprhs
350///
351static std::unique_ptr<ExprAST> ParseExpression() {
352 auto LHS = ParsePrimary();
353 if (!LHS)
354 return nullptr;
355
356 return ParseBinOpRHS(ExprPrec: 0, LHS: std::move(LHS));
357}
358
359/// prototype
360/// ::= id '(' id* ')'
361static std::unique_ptr<PrototypeAST> ParsePrototype() {
362 if (CurTok != tok_identifier)
363 return LogErrorP(Str: "Expected function name in prototype");
364
365 std::string FnName = IdentifierStr;
366 getNextToken();
367
368 if (CurTok != '(')
369 return LogErrorP(Str: "Expected '(' in prototype");
370
371 std::vector<std::string> ArgNames;
372 while (getNextToken() == tok_identifier)
373 ArgNames.push_back(x: IdentifierStr);
374 if (CurTok != ')')
375 return LogErrorP(Str: "Expected ')' in prototype");
376
377 // success.
378 getNextToken(); // eat ')'.
379
380 return std::make_unique<PrototypeAST>(args&: FnName, args: std::move(ArgNames));
381}
382
383/// definition ::= 'def' prototype expression
384static std::unique_ptr<FunctionAST> ParseDefinition() {
385 getNextToken(); // eat def.
386 auto Proto = ParsePrototype();
387 if (!Proto)
388 return nullptr;
389
390 if (auto E = ParseExpression())
391 return std::make_unique<FunctionAST>(args: std::move(Proto), args: std::move(E));
392 return nullptr;
393}
394
395/// toplevelexpr ::= expression
396static std::unique_ptr<FunctionAST> ParseTopLevelExpr() {
397 if (auto E = ParseExpression()) {
398 // Make an anonymous proto.
399 auto Proto = std::make_unique<PrototypeAST>(args: "__anon_expr",
400 args: std::vector<std::string>());
401 return std::make_unique<FunctionAST>(args: std::move(Proto), args: std::move(E));
402 }
403 return nullptr;
404}
405
406/// external ::= 'extern' prototype
407static std::unique_ptr<PrototypeAST> ParseExtern() {
408 getNextToken(); // eat extern.
409 return ParsePrototype();
410}
411
412//===----------------------------------------------------------------------===//
413// Code Generation
414//===----------------------------------------------------------------------===//
415
416static std::unique_ptr<LLVMContext> TheContext;
417static std::unique_ptr<Module> TheModule;
418static std::unique_ptr<IRBuilder<>> Builder;
419static std::map<std::string, Value *> NamedValues;
420static std::unique_ptr<KaleidoscopeJIT> TheJIT;
421static std::unique_ptr<FunctionPassManager> TheFPM;
422static std::unique_ptr<LoopAnalysisManager> TheLAM;
423static std::unique_ptr<FunctionAnalysisManager> TheFAM;
424static std::unique_ptr<CGSCCAnalysisManager> TheCGAM;
425static std::unique_ptr<ModuleAnalysisManager> TheMAM;
426static std::unique_ptr<PassInstrumentationCallbacks> ThePIC;
427static std::unique_ptr<StandardInstrumentations> TheSI;
428static std::map<std::string, std::unique_ptr<PrototypeAST>> FunctionProtos;
429static ExitOnError ExitOnErr;
430
431Value *LogErrorV(const char *Str) {
432 LogError(Str);
433 return nullptr;
434}
435
436Function *getFunction(std::string Name) {
437 // First, see if the function has already been added to the current module.
438 if (auto *F = TheModule->getFunction(Name))
439 return F;
440
441 // If not, check whether we can codegen the declaration from some existing
442 // prototype.
443 auto FI = FunctionProtos.find(x: Name);
444 if (FI != FunctionProtos.end())
445 return FI->second->codegen();
446
447 // If no existing prototype exists, return null.
448 return nullptr;
449}
450
451Value *NumberExprAST::codegen() {
452 return ConstantFP::get(Context&: *TheContext, V: APFloat(Val));
453}
454
455Value *VariableExprAST::codegen() {
456 // Look this variable up in the function.
457 Value *V = NamedValues[Name];
458 if (!V)
459 return LogErrorV(Str: "Unknown variable name");
460 return V;
461}
462
463Value *BinaryExprAST::codegen() {
464 Value *L = LHS->codegen();
465 Value *R = RHS->codegen();
466 if (!L || !R)
467 return nullptr;
468
469 switch (Op) {
470 case '+':
471 return Builder->CreateFAdd(L, R, Name: "addtmp");
472 case '-':
473 return Builder->CreateFSub(L, R, Name: "subtmp");
474 case '*':
475 return Builder->CreateFMul(L, R, Name: "multmp");
476 case '<':
477 L = Builder->CreateFCmpULT(LHS: L, RHS: R, Name: "cmptmp");
478 // Convert bool 0/1 to double 0.0 or 1.0
479 return Builder->CreateUIToFP(V: L, DestTy: Type::getDoubleTy(C&: *TheContext), Name: "booltmp");
480 default:
481 return LogErrorV(Str: "invalid binary operator");
482 }
483}
484
485Value *CallExprAST::codegen() {
486 // Look up the name in the global module table.
487 Function *CalleeF = getFunction(Name: Callee);
488 if (!CalleeF)
489 return LogErrorV(Str: "Unknown function referenced");
490
491 // If argument mismatch error.
492 if (CalleeF->arg_size() != Args.size())
493 return LogErrorV(Str: "Incorrect # arguments passed");
494
495 std::vector<Value *> ArgsV;
496 for (unsigned i = 0, e = Args.size(); i != e; ++i) {
497 ArgsV.push_back(x: Args[i]->codegen());
498 if (!ArgsV.back())
499 return nullptr;
500 }
501
502 return Builder->CreateCall(Callee: CalleeF, Args: ArgsV, Name: "calltmp");
503}
504
505Function *PrototypeAST::codegen() {
506 // Make the function type: double(double,double) etc.
507 std::vector<Type *> Doubles(Args.size(), Type::getDoubleTy(C&: *TheContext));
508 FunctionType *FT =
509 FunctionType::get(Result: Type::getDoubleTy(C&: *TheContext), Params: Doubles, isVarArg: false);
510
511 Function *F =
512 Function::Create(Ty: FT, Linkage: Function::ExternalLinkage, N: Name, M: TheModule.get());
513
514 // Set names for all arguments.
515 unsigned Idx = 0;
516 for (auto &Arg : F->args())
517 Arg.setName(Args[Idx++]);
518
519 return F;
520}
521
522Function *FunctionAST::codegen() {
523 // Transfer ownership of the prototype to the FunctionProtos map, but keep a
524 // reference to it for use below.
525 auto &P = *Proto;
526 FunctionProtos[Proto->getName()] = std::move(Proto);
527 Function *TheFunction = getFunction(Name: P.getName());
528 if (!TheFunction)
529 return nullptr;
530
531 // Create a new basic block to start insertion into.
532 BasicBlock *BB = BasicBlock::Create(Context&: *TheContext, Name: "entry", Parent: TheFunction);
533 Builder->SetInsertPoint(BB);
534
535 // Record the function arguments in the NamedValues map.
536 NamedValues.clear();
537 for (auto &Arg : TheFunction->args())
538 NamedValues[std::string(Arg.getName())] = &Arg;
539
540 if (Value *RetVal = Body->codegen()) {
541 // Finish off the function.
542 Builder->CreateRet(V: RetVal);
543
544 // Validate the generated code, checking for consistency.
545 verifyFunction(F: *TheFunction);
546
547 // Run the optimizer on the function.
548 TheFPM->run(IR&: *TheFunction, AM&: *TheFAM);
549
550 return TheFunction;
551 }
552
553 // Error reading body, remove function.
554 TheFunction->eraseFromParent();
555 return nullptr;
556}
557
558//===----------------------------------------------------------------------===//
559// Top-Level parsing and JIT Driver
560//===----------------------------------------------------------------------===//
561
562static void InitializeModuleAndManagers() {
563 // Open a new context and module.
564 TheContext = std::make_unique<LLVMContext>();
565 TheModule = std::make_unique<Module>(args: "KaleidoscopeJIT", args&: *TheContext);
566 TheModule->setDataLayout(TheJIT->getDataLayout());
567
568 // Create a new builder for the module.
569 Builder = std::make_unique<IRBuilder<>>(args&: *TheContext);
570
571 // Create new pass and analysis managers.
572 TheFPM = std::make_unique<FunctionPassManager>();
573 TheLAM = std::make_unique<LoopAnalysisManager>();
574 TheFAM = std::make_unique<FunctionAnalysisManager>();
575 TheCGAM = std::make_unique<CGSCCAnalysisManager>();
576 TheMAM = std::make_unique<ModuleAnalysisManager>();
577 ThePIC = std::make_unique<PassInstrumentationCallbacks>();
578 TheSI = std::make_unique<StandardInstrumentations>(args&: *TheContext,
579 /*DebugLogging*/ args: true);
580 TheSI->registerCallbacks(PIC&: *ThePIC, MAM: TheMAM.get());
581
582 // Add transform passes.
583 // Do simple "peephole" optimizations and bit-twiddling optzns.
584 TheFPM->addPass(Pass: InstCombinePass());
585 // Reassociate expressions.
586 TheFPM->addPass(Pass: ReassociatePass());
587 // Eliminate Common SubExpressions.
588 TheFPM->addPass(Pass: GVNPass());
589 // Simplify the control flow graph (deleting unreachable blocks, etc).
590 TheFPM->addPass(Pass: SimplifyCFGPass());
591
592 // Register analysis passes used in these transform passes.
593 PassBuilder PB;
594 PB.registerModuleAnalyses(MAM&: *TheMAM);
595 PB.registerFunctionAnalyses(FAM&: *TheFAM);
596 PB.crossRegisterProxies(LAM&: *TheLAM, FAM&: *TheFAM, CGAM&: *TheCGAM, MAM&: *TheMAM);
597}
598
599static void HandleDefinition() {
600 if (auto FnAST = ParseDefinition()) {
601 if (auto *FnIR = FnAST->codegen()) {
602 fprintf(stderr, format: "Read function definition:");
603 FnIR->print(OS&: errs());
604 fprintf(stderr, format: "\n");
605 ExitOnErr(TheJIT->addModule(
606 TSM: ThreadSafeModule(std::move(TheModule), std::move(TheContext))));
607 InitializeModuleAndManagers();
608 }
609 } else {
610 // Skip token for error recovery.
611 getNextToken();
612 }
613}
614
615static void HandleExtern() {
616 if (auto ProtoAST = ParseExtern()) {
617 if (auto *FnIR = ProtoAST->codegen()) {
618 fprintf(stderr, format: "Read extern: ");
619 FnIR->print(OS&: errs());
620 fprintf(stderr, format: "\n");
621 FunctionProtos[ProtoAST->getName()] = std::move(ProtoAST);
622 }
623 } else {
624 // Skip token for error recovery.
625 getNextToken();
626 }
627}
628
629static void HandleTopLevelExpression() {
630 // Evaluate a top-level expression into an anonymous function.
631 if (auto FnAST = ParseTopLevelExpr()) {
632 if (FnAST->codegen()) {
633 // Create a ResourceTracker to track JIT'd memory allocated to our
634 // anonymous expression -- that way we can free it after executing.
635 auto RT = TheJIT->getMainJITDylib().createResourceTracker();
636
637 auto TSM = ThreadSafeModule(std::move(TheModule), std::move(TheContext));
638 ExitOnErr(TheJIT->addModule(TSM: std::move(TSM), RT));
639 InitializeModuleAndManagers();
640
641 // Search the JIT for the __anon_expr symbol.
642 auto ExprSymbol = ExitOnErr(TheJIT->lookup(Name: "__anon_expr"));
643
644 // Get the symbol's address and cast it to the right type (takes no
645 // arguments, returns a double) so we can call it as a native function.
646 double (*FP)() = ExprSymbol.getAddress().toPtr<double (*)()>();
647 fprintf(stderr, format: "Evaluated to %f\n", FP());
648
649 // Delete the anonymous expression module from the JIT.
650 ExitOnErr(RT->remove());
651 }
652 } else {
653 // Skip token for error recovery.
654 getNextToken();
655 }
656}
657
658/// top ::= definition | external | expression | ';'
659static void MainLoop() {
660 while (true) {
661 fprintf(stderr, format: "ready> ");
662 switch (CurTok) {
663 case tok_eof:
664 return;
665 case ';': // ignore top-level semicolons.
666 getNextToken();
667 break;
668 case tok_def:
669 HandleDefinition();
670 break;
671 case tok_extern:
672 HandleExtern();
673 break;
674 default:
675 HandleTopLevelExpression();
676 break;
677 }
678 }
679}
680
681//===----------------------------------------------------------------------===//
682// "Library" functions that can be "extern'd" from user code.
683//===----------------------------------------------------------------------===//
684
685#ifdef _WIN32
686#define DLLEXPORT __declspec(dllexport)
687#else
688#define DLLEXPORT
689#endif
690
691/// putchard - putchar that takes a double and returns 0.
692extern "C" DLLEXPORT double putchard(double X) {
693 fputc(c: (char)X, stderr);
694 return 0;
695}
696
697/// printd - printf that takes a double prints it as "%f\n", returning 0.
698extern "C" DLLEXPORT double printd(double X) {
699 fprintf(stderr, format: "%f\n", X);
700 return 0;
701}
702
703//===----------------------------------------------------------------------===//
704// Main driver code.
705//===----------------------------------------------------------------------===//
706
707int main() {
708 InitializeNativeTarget();
709 InitializeNativeTargetAsmPrinter();
710 InitializeNativeTargetAsmParser();
711
712 // Install standard binary operators.
713 // 1 is lowest precedence.
714 BinopPrecedence['<'] = 10;
715 BinopPrecedence['+'] = 20;
716 BinopPrecedence['-'] = 20;
717 BinopPrecedence['*'] = 40; // highest.
718
719 // Prime the first token.
720 fprintf(stderr, format: "ready> ");
721 getNextToken();
722
723 TheJIT = ExitOnErr(KaleidoscopeJIT::Create());
724
725 InitializeModuleAndManagers();
726
727 // Run the main "interpreter loop" now.
728 MainLoop();
729
730 return 0;
731}
732

source code of llvm/examples/Kaleidoscope/Chapter4/toy.cpp