5 #include <llvm/ExecutionEngine/ExecutionEngine.h> 6 #include <llvm/Transforms/IPO/PassManagerBuilder.h> 7 #include <llvm/IR/LegacyPassManager.h> 8 #include <llvm/Support/TargetSelect.h> 11 using llvm::legacy::PassManager;
28 return c.
B.CreateIntToPtr(
29 ConstantInt::get(c.
ObjIntTy, reinterpret_cast<uintptr_t>(ptr)), ty);
36 i = c.
B.CreateShl(i, ConstantInt::get(c.
ObjIntTy, 3));
37 return c.
B.CreateOr(i, ConstantInt::get(c.
ObjIntTy, 1));
44 return ConstantInt::get(c.
ObjIntTy, (i << 3) | 1);
52 if (i->getType()->isPointerTy())
65 if (i->getType()->isPointerTy())
75 M(new Module(
"MysoreScript", C)),
77 ObjPtrTy(Type::getInt8PtrTy(C)),
78 ObjIntTy(Type::getInt64Ty(C)),
79 SelTy(Type::getInt32Ty(C))
83 LLVMInitializeNativeTarget();
84 InitializeNativeTargetAsmPrinter();
100 if (
Obj *global = globalSymbols[str])
104 llvm_unreachable(
"Symbol not found");
110 llvm::legacy::FunctionPassManager FPM(
M.get());
112 PassManagerBuilder Builder;
113 Builder.OptLevel = 2;
114 Builder.populateFunctionPassManager(FPM);
115 Builder.populateModulePassManager(MPM);
129 std::string FunctionName =
F->getName();
131 EngineBuilder EB(std::move(
M));
133 ExecutionEngine *EE = EB.setEngineKind(EngineKind::JIT)
138 fprintf(stderr,
"Failed to construct Execution Engine: %s\n",
148 return reinterpret_cast<ClosureInvoke>(EE->getFunctionAddress(FunctionName));
161 fields[1] = ArrayType::get(
ObjPtrTy, ivars);
162 ObjTy = StructType::create(fields)->getPointerTo();
165 SmallVector<Type*, 10> paramTypes;
167 paramTypes.push_back(ObjTy);
168 paramTypes.push_back(
SelTy);
170 paramTypes.insert(paramTypes.end(), args,
ObjPtrTy);
171 return FunctionType::get(
ObjPtrTy, paramTypes,
false);
179 SmallVector<Type*, 6> fields;
190 fields.push_back(ArrayType::get(
ObjPtrTy, bound));
191 ClosureTy = StructType::create(fields)->getPointerTo();
194 SmallVector<Type*, 10> paramTypes;
195 paramTypes.push_back(ClosureTy);
197 paramTypes.insert(paramTypes.end(), args,
ObjPtrTy);
198 return FunctionType::get(
ObjPtrTy, paramTypes,
false);
204 auto ¶ms = parameters->arguments;
210 c.
F = Function::Create(ClosureInvokeTy, GlobalValue::ExternalLinkage,
211 "invoke", c.
M.get());
213 BasicBlock *entry = BasicBlock::Create(c.
C,
"entry", c.
F);
214 c.
B.SetInsertPoint(entry);
217 auto AI = c.
F->arg_begin();
219 auto selfPtr = c.
B.CreateAlloca(c.
ObjPtrTy);
220 auto cmdPtr = c.
B.CreateAlloca(c.
ObjPtrTy);
229 SmallVector<Value*, 10> paramAllocas;
230 SmallVector<Value*, 10> localAllocas;
233 for (
size_t i=0 ; i<params.size() ; i++)
235 paramAllocas.push_back(c.
B.CreateAlloca(c.
ObjPtrTy));
238 for (
size_t i=0 ; i<decls.size() ; i++)
240 localAllocas.push_back(c.
B.CreateAlloca(c.
ObjPtrTy));
243 auto alloca = paramAllocas.begin();
246 c.
B.CreateStore(c.
B.CreateBitCast(&*(AI++), c.
ObjPtrTy), selfPtr);
250 for (
auto &arg : params)
254 (*alloca)->setName(*arg.get());
256 c.
B.CreateStore(&*(AI++), *alloca);
259 c.
symbols[*arg.get()] = *(alloca++);
261 alloca = localAllocas.begin();
263 for (
auto &local : decls)
265 (*alloca)->setName(local);
267 c.
B.CreateStore(ConstantPointerNull::get(c.
ObjPtrTy), *alloca);
268 c.
symbols[local] = *(alloca++);
274 PointerType *ArgTy = cast<PointerType>(ClosureInvokeTy->params()[0]);
277 cast<StructType>(cast<PointerType>(ArgTy)->getElementType());
280 Value *iVarsArray = c.
B.CreateStructGEP(ObjTy, &*c.
F->arg_begin(), 1);
282 Type *iVarsArrayTy = ObjTy->elements()[1];
290 c.
B.CreateStructGEP(iVarsArrayTy, iVarsArray, i, name);
298 if (c.
B.GetInsertBlock() !=
nullptr)
301 c.
B.CreateRet(ConstantPointerNull::get(c.
ObjPtrTy));
309 auto ¶ms = parameters->arguments;
312 FunctionType *ClosureInvokeTy = c.
getClosureType(boundVars.size(),
315 c.
F = Function::Create(ClosureInvokeTy, GlobalValue::ExternalLinkage,
"invoke", c.
M.get());
317 BasicBlock *entry = BasicBlock::Create(c.
C,
"entry", c.
F);
318 c.
B.SetInsertPoint(entry);
319 auto AI = c.
F->arg_begin();
320 auto selfPtr = c.
B.CreateAlloca(c.
ObjPtrTy);
322 SmallVector<Value*, 10> paramAllocas;
323 SmallVector<Value*, 10> localAllocas;
325 for (
size_t i=0 ; i<params.size() ; i++)
327 paramAllocas.push_back(c.
B.CreateAlloca(c.
ObjPtrTy));
329 for (
size_t i=0 ; i<decls.size() ; i++)
331 localAllocas.push_back(c.
B.CreateAlloca(c.
ObjPtrTy));
333 auto alloca = paramAllocas.begin();
335 c.
B.CreateStore(c.
B.CreateBitCast(&*(AI++), c.
ObjPtrTy), selfPtr);
336 for (
auto &arg : params)
338 (*alloca)->setName(*arg.get());
339 c.
B.CreateStore(&*(AI++), *alloca);
340 c.
symbols[*arg.get()] = *(alloca++);
342 alloca = localAllocas.begin();
343 for (
auto &local : decls)
345 (*alloca)->setName(local);
346 c.
B.CreateStore(ConstantPointerNull::get(c.
ObjPtrTy), *alloca);
347 c.
symbols[local] = *(alloca++);
352 if (!boundVars.empty())
355 PointerType *ArgTy = cast<PointerType>(ClosureInvokeTy->params()[0]);
358 cast<StructType>(cast<PointerType>(ArgTy)->getElementType());
360 Type *boundVarsArrayTy = ObjTy->elements()[4];
362 Value *boundVarsArray = c.
B.CreateStructGEP(ObjTy, &*c.
F->arg_begin(), 4);
364 for (
auto &bound : boundVars)
366 c.
symbols[bound] = c.
B.CreateStructGEP(boundVarsArrayTy, boundVarsArray, i++, bound);
370 if (c.
B.GetInsertBlock() !=
nullptr)
372 c.
B.CreateRet(ConstantPointerNull::get(c.
ObjPtrTy));
381 auto ¶ms = parameters->arguments;
383 FunctionType *invokeTy = c.
getClosureType(boundVars.size(), params.size());
385 PointerType *closurePtrTy = cast<PointerType>(invokeTy->getParamType(0));
387 StructType *closureTy = cast<StructType>(closurePtrTy->getElementType());
391 size_t closureSize =
sizeof(
struct Closure) + boundVars.size() *
sizeof(
Obj);
394 Constant *allocFn = c.
M->getOrInsertFunction(
"GC_malloc", closurePtrTy,
400 Value *closure = c.
B.CreateCall(allocFn, ConstantInt::get(c.
ObjIntTy,
404 c.
B.CreateStructGEP(closureTy, closure, 0));
407 c.
B.CreateStructGEP(closureTy, closure, 1));
414 ClosureInvoke closureFn = compiledClosure ? compiledClosure :
417 c.
B.CreateStructGEP(closureTy, closure, 2));
420 c.
B.CreateStructGEP(closureTy, closure, 3));
422 Value *boundVarsArray = c.
B.CreateStructGEP(closureTy, closure, 4);
423 Type *boundVarsArrayTy = closureTy->elements()[4];
425 for (
auto &var : boundVars)
430 c.
B.CreateStructGEP(boundVarsArrayTy, boundVarsArray, i++, var));
438 SmallVector<Value*, 10> args;
440 Value *obj =
getAsObject(c, callee->compileExpression(c));
449 args.push_back(ConstantInt::get(c.
SelTy, sel));
452 auto &argsAST = arguments->arguments;
453 for (
auto &arg : argsAST)
455 args.push_back(
getAsObject(c, arg->compileExpression(c)));
468 Type *closureTy = StructType::create(Fields);
469 Type *closurePtrTy = closureTy->getPointerTo();
471 Value *closure = c.
B.CreateBitCast(obj, closurePtrTy);
473 Value *invokeFn = c.
B.CreateStructGEP(closureTy, closure, 2);
475 invokeFn = c.
B.CreateLoad(invokeFn);
477 return c.
B.CreateCall(invokeFn, args,
"call_closure");
481 FunctionType *methodType = c.
getMethodType(0, args.size() - 2);
483 Constant *lookupFn = c.
M->getOrInsertFunction(
"compiledMethodForSelector",
484 methodType->getPointerTo(), obj->getType(), c.
SelTy,
nullptr);
488 Value *methodFn = c.
B.CreateCall(lookupFn, {obj, args[1]});
490 return c.
B.CreateCall(methodFn, args,
"call_method");
495 for (
auto &s : statements)
499 if (c.
B.GetInsertBlock() ==
nullptr)
512 Value *ret = expr->compileExpression(c);
516 c.
B.ClearInsertionPoint();
522 Value *cond = condition->compileExpression(c);
525 BasicBlock *cont = BasicBlock::Create(c.
C,
"if.cont", c.
F);
527 BasicBlock *ifBody = BasicBlock::Create(c.
C,
"if.body", c.
F);
537 cond = c.
B.CreateLShr(cond, ConstantInt::get(c.
ObjIntTy, 3));
539 cond = c.
B.CreateIsNotNull(cond);
541 c.
B.CreateCondBr(cond, ifBody, cont);
543 c.
B.SetInsertPoint(ifBody);
547 if (c.
B.GetInsertBlock() !=
nullptr)
552 c.
B.SetInsertPoint(cont);
560 BasicBlock *condBlock = BasicBlock::Create(c.
C,
"while.cond", c.
F);
561 BasicBlock *cont = BasicBlock::Create(c.
C,
"while.cont", c.
F);
562 BasicBlock *whileBody = BasicBlock::Create(c.
C,
"while.body", c.
F);
564 c.
B.CreateBr(condBlock);
565 c.
B.SetInsertPoint(condBlock);
567 Value *cond = condition->compileExpression(c);
570 cond = c.
B.CreateLShr(cond, ConstantInt::get(c.
ObjIntTy, 3));
571 cond = c.
B.CreateIsNotNull(cond);
573 c.
B.CreateCondBr(cond, whileBody, cont);
574 c.
B.SetInsertPoint(whileBody);
578 c.
B.CreateBr(condBlock);
580 c.
B.SetInsertPoint(cont);
587 if (!static_cast<Obj>(cache))
590 cache = evaluateExpr(ic);
608 c.
B.CreateStore(
getAsObject(c, init->compileExpression(c)),
614 assert(c.
symbols[target->name]);
616 c.
B.CreateStore(
getAsObject(c, expr->compileExpression(c)),
631 Constant *newFn = c.
M->getOrInsertFunction(
"newObject", c.
ObjPtrTy,
634 return c.
B.CreateCall(newFn, clsPtr,
"new");
644 typedef std::function<Value*(Compiler::Context &c, Value*, Value*)>
BinOpFn;
651 Value *LHS, Value *RHS)
659 cmp = c.
B.CreateZExt(cmp, c.
ObjIntTy,
"cmp_object");
673 Instruction::BinaryOps Op,
const char *slowCallFnName)
680 Value *isSmallInt = c.
B.CreateAnd(LHSInt, RHSInt);
682 isSmallInt = c.
B.CreateAnd(isSmallInt, ConstantInt::get(c.
ObjIntTy, 7));
684 isSmallInt = c.
B.CreateICmpEQ(isSmallInt, ConstantInt::get(c.
ObjIntTy, 1));
687 BasicBlock *cont = BasicBlock::Create(c.
C,
"cont", c.
F);
688 BasicBlock *small = BasicBlock::Create(c.
C,
"int", c.
F);
689 BasicBlock *obj = BasicBlock::Create(c.
C,
"obj", c.
F);
692 c.
B.CreateCondBr(isSmallInt, small, obj);
695 c.
B.SetInsertPoint(small);
697 LHSInt = c.
B.CreateAShr(LHSInt, ConstantInt::get(c.
ObjIntTy, 3));
698 RHSInt = c.
B.CreateAShr(RHSInt, ConstantInt::get(c.
ObjIntTy, 3));
700 Value *intResult = c.
B.CreateBinOp(Op, LHSInt, RHSInt);
706 c.
B.SetInsertPoint(obj);
708 Value *objResult = c.
B.CreateCall(c.
M->getOrInsertFunction(slowCallFnName,
709 c.
ObjPtrTy, LHS->getType(), RHS->getType(),
nullptr),
716 c.
B.SetInsertPoint(cont);
718 PHINode *result = c.
B.CreatePHI(intResult->getType(), 2,
"sub");
720 result->addIncoming(intResult, small);
721 result->addIncoming(objResult, obj);
753 return compileBinaryOp(c, LHS, RHS, Instruction::Sub,
"mysoreScriptAdd");
757 return compileBinaryOp(c, LHS, RHS, Instruction::Add,
"mysoreScriptSub");
761 return compileBinaryOp(c, LHS, RHS, Instruction::Mul,
"mysoreScriptMul");
765 return compileBinaryOp(c, LHS, RHS, Instruction::SDiv,
"mysoreScriptDiv");
Value * getAsObject(Compiler::Context &c, Value *i)
Get the specified value as the LLVM type used for object pointers.
Object *(* CompiledMethod)(Object *, Selector,...)
A compiled method is a function that takes an object (the receiver) and the selector as implicit argu...
Object * Obj
Object pointer.
uint32_t Selector
Selectors are unique identifiers for methods.
std::unique_ptr< llvm::Module > M
The current module.
const char ** indexedIVarNames
The names of the instance variables.
llvm::IRBuilder B
The IR builder, always set to the current insert point.
std::unordered_map< std::string, llvm::Value * > symbols
Symbols within this compilation context.
llvm::Value * lookupSymbolAddr(const std::string &str)
Returns the address of the specified symbol.
std::unordered_map< std::string, Obj * > SymbolTable
A symbol table stores the address of each allocation.
llvm::FunctionType * getClosureType(int bound, int args)
Get the type of a closure invoke function, for a closure with the specified number of instance variab...
Selector lookupSelector(const std::string &str)
Looks up the selector for a specified string value, registering a new value if this is the first time...
Object *(* ClosureInvoke)(Closure *,...)
A compiled closure invoke function.
struct Class * lookupClass(const std::string &name)
Look up an existing class.
llvm::Value * compileExpression(Compiler::Context &c) override
Compile the string.
A generic MysoreScript object.
Value * compileSmallInt(Compiler::Context &c, intptr_t i)
Generate a small integer object from an integer constant.
struct Class ClosureClass
The Closure class structure.
ClosureInvoke closureTrampolines[]
Array of trampolines, indexed by number or arguments.
Value * compileBinaryOp(Compiler::Context &c, Value *LHS, Value *RHS, Instruction::BinaryOps Op, const char *slowCallFnName)
Helper function that inserts all of the code required for small integer operations, either calling the relevant method or doing the arithmetic.
llvm::Type * ObjIntTy
The type of an integer the same size as an object pointer.
Value * getAsSmallInt(Compiler::Context &c, Value *i)
Get the specified value as the LLVM type used for small integer objects.
std::function< Value *(Compiler::Context &c, Value *, Value *)> BinOpFn
A function type that is used by the compileBinaryOp function.
llvm::Type * SelTy
The type used for selectors.
llvm::Function * F
The function being compiled.
llvm::PointerType * ObjPtrTy
The type of a pointer to a MysoreScript object.
int32_t indexedIVarCount
The number of indexed instance variables that this class has.
Value * compileCompare(Compiler::Context &c, CmpInst::Predicate Op, Value *LHS, Value *RHS)
Helper function that inserts all of the code required for comparison operations.
Value * staticAddress(Compiler::Context &c, T *ptr, Type *ty)
Helper function that turns a pointer that is known at compile time into a constant in the code...
llvm::LLVMContext C
The LLVM context.
Struct holding metadata about a class.
llvm::FunctionType * getMethodType(int ivars, int args)
Get the type of a method with the specified number of arguments, for an object with the specified num...
MysoreScript::ClosureInvoke compile()
At the end of compilation, generate code and return a function pointer.
Context(Interpreter::SymbolTable &g)
Construct a context, given a global symbol table from the interpreter.
The layout of all closures in MysoreScript.