/* -*- mode: objc; coding: utf-8 -*- */
/* Toilet Lisp, a Common Lisp subset for the Étoilé runtime.
* Copyright (C) 2008 Matthias Andreas Benkard.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#import "MLKCompiledClosure.h"
#import "MLKDynamicContext.h"
#import "MLKLexicalContext-MLKLLVMCompilation.h"
#import "MLKLLVMCompiler.h"
#import "MLKRoot.h"
#import "MLKPackage.h"
#import "globals.h"
#import "llvm_context.h"
#import "util.h"
#import
#import
#import
#import
#ifdef __OBJC_GC__
#import
#endif
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
//#include
#include
#include
#include
#include // InlineFunction
#include
#include
#include
#include
#include
#ifdef MACOSX
#include
#if defined(OBJC_API_VERSION) && OBJC_API_VERSION >= 2
#include
#endif
#endif
using namespace llvm;
using namespace std;
static ExecutionEngine *execution_engine;
static llvm::Module *module;
static IRBuilder* builder;
static FunctionPassManager *fpm;
static Constant
*createGlobalStringPtr (const char *string)
{
Constant *(indices[2]);
indices[0] = indices[1] = ConstantInt::get (Int32Ty, 0);
Constant *str = ConstantDataArray::getString (*llvm_context, string, true);
Constant *str2 = new GlobalVariable (*module,
str->getType(),
true,
GlobalValue::InternalLinkage,
str,
"");
// ArrayRef aindices(indices, 2);
// Constant *ptr = ConstantExpr::getGetElementPtr (str2, aindices, false);
Constant *ptr = ConstantExpr::getGetElementPtr (str2, indices, false);
return ptr;
}
@implementation MLKLLVMCompiler
+(void) load
{
if (!MLKDefaultCompiler)
{
MLKDefaultCompiler = self;
MLKLoadCompilesP = YES;
}
// GNU ld optimises the MLKLLVMCompilation category on
// MLKLexicalContext away unless we do this. Man, the crappiness of
// this Unix stuff is amazing...
MLKDummyUseLLVMLexicalContext = nil;
}
+(void) initialize
{
llvm_context = new LLVMContext();
//const Type* IntPtrTy = IntegerType::getInt32Ty(C);
Int8Ty = IntegerType::getInt8Ty(*llvm_context);
Int16Ty = IntegerType::getInt16Ty(*llvm_context);
Int32Ty = IntegerType::getInt32Ty(*llvm_context);
Int64Ty = IntegerType::getInt64Ty(*llvm_context);
//const Type* VoidTy = TypeBuilder::get(llvm_context);
VoidTy = Type::getVoidTy(*llvm_context);
VoidPointerTy = PointerType::get(Int8Ty, 0);
PointerPointerTy = PointerType::get(VoidPointerTy, 0);
builder = new IRBuilder(*llvm_context);
module = new llvm::Module ("MLKLLVMModule", *llvm_context);
LLVMLinkInInterpreter();
LLVMLinkInJIT();
InitializeNativeTarget();
std::string error;
//execution_engine = ExecutionEngine::create (module, true, &error);
execution_engine = ExecutionEngine::create (module, false, &error);
assert(execution_engine);
fpm = new FunctionPassManager (module);
//FIXME gone in 3.2??
// fpm->add (new TargetData (*execution_engine->getTargetData()));
//fpm->add (new TargetData (module));
fpm->add (createScalarReplAggregatesPass());
fpm->add (createInstructionCombiningPass());
fpm->add (createReassociatePass());
fpm->add (createGVNPass());
// fpm->add (createVerifierPass());
//fpm->add (createLowerSetJmpPass());
//fpm->add (createRaiseAllocationsPass());
fpm->add (createCFGSimplificationPass());
fpm->add (createPromoteMemoryToRegisterPass());
//fpm->add (createGlobalOptimizerPass());
//fpm->add (createGlobalDCEPass());
//fpm->add (createFunctionInliningPass());
// Utilities.
// fpm->add (createUnifyFunctionExitNodesPass());
}
+(id) compile:(id)object
inContext:(MLKLexicalContext *)context
{
NSAutoreleasePool *pool;
pool = [[NSAutoreleasePool alloc] init];
Value *v = NULL;
BasicBlock *block;
FunctionType *function_type = FunctionType::get (VoidPointerTy,
false);
Function *function = Function::Create (function_type,
Function::ExternalLinkage,
"",
module);
id lambdaForm;
//id (*fn)();
MLKForm *form = [MLKForm formWithObject:object
inContext:context
forCompiler:self];
[self markVariablesForHeapAllocationInForm:form];
//NSLog(@"Compiling form: %@", MLKPrintToString(object));
block = BasicBlock::Create (*llvm_context, "entry", function);
builder->SetInsertPoint (block);
v = [self processForm:form];
builder->CreateRet (v);
verifyFunction (*function);
//NSLog(@"Running FPM...");
fpm->run (*function);
function->dump(); //!
//module->dump();
//NSLog (@"%p", fn);
LRELEASE (pool);
//NSLog (@"Code compiled.");
#if 1
// JIT-compile.
vector nogenericargs;
lambdaForm = (id)execution_engine->runFunction (function, nogenericargs).PointerVal;
//id (*fn)() = (id (*)()) execution_engine->getPointerToFunction (function);
// Execute.
//lambdaForm = fn();
// FIXME: Free machine code when appropriate. (I.e. now? But this crashes after a LOAD.)
//execution_engine->freeMachineCodeForFunction (function);
#else
Interpreter *i = Interpreter::create (module);
lambdaForm = i->runFunction (function)->PointerVal;
#endif
//NSLog (@"Function: %p / %p", function, execution_engine->getPointerToFunction (function));
//NSLog (@"Executed: %p", fn);
//NSLog (@"Closure built: %p", lambdaForm);
return lambdaForm;
}
+(void) processTopLevelForm:(id)object
{
[self processTopLevelForm:object
inMode:not_compile_time_mode];
}
+(void) processTopLevelForm:(id)object
inMode:(enum MLKProcessingMode)mode
{
//FIXME
// If PROGN, do this... If EVAL-WHEN, do that...
}
+(id) eval:(id)object
{
return [self compile:object
inContext:[MLKLexicalContext globalContext]];
}
+(Value *) processForm:(MLKForm *)form
{
return [form processForLLVMWithMultiValue:NULL];
}
+(void) markVariablesForHeapAllocationInForm:(MLKForm *)form
{
NSArray *subforms = [form subforms];
unsigned int i;
for (i = 0; i < [subforms count]; i++)
{
MLKForm *subform = [subforms objectAtIndex:i];
[self markVariablesForHeapAllocationInForm:subform];
if ([subform isKindOfClass:[MLKSimpleLambdaForm class]]
|| [subform isKindOfClass:[MLKLambdaForm class]])
{
NSArray *freeVariables = [[subform freeVariables] allObjects];
unsigned int j;
for (j = 0; j < [freeVariables count]; j++)
{
id variable = [freeVariables objectAtIndex:j];
[[subform context] setVariableHeapAllocation:YES
forSymbol:variable];
}
}
}
}
+(Value *) insertSelectorLookup:(NSString *)name
{
Constant *function =
module->getOrInsertFunction (
#ifdef __NEXT_RUNTIME__
"sel_getUid",
#else
"sel_get_uid",
#endif
VoidPointerTy,
VoidPointerTy,
NULL);
Constant *nameptr = createGlobalStringPtr ([name UTF8String]);
return builder->CreateCall (function, nameptr, "selector");
}
+(Value *) insertMethodCall:(NSString *)messageName
onObject:(Value *)object
withArgumentVector:(vector *)argv
{
return [self insertMethodCall:messageName
onObject:object
withArgumentVector:argv
name:@""];
}
+(Value *) insertVoidMethodCall:(NSString *)messageName
onObject:(Value *)object
withArgumentVector:(vector *)argv
{
return [self insertMethodCall:messageName
onObject:object
withArgumentVector:argv
name:@""
returnType:(VoidTy)];
}
+(Value *) insertMethodCall:(NSString *)messageName
onObject:(Value *)object
withArgumentVector:(vector *)argv
name:(NSString *)name
{
return [self insertMethodCall:messageName
onObject:object
withArgumentVector:argv
name:@""
returnType:VoidPointerTy];
}
+(Value *) insertMethodCall:(NSString *)messageName
onObject:(Value *)object
withArgumentVector:(vector *)argv
name:(NSString *)name
returnType:(Type *)returnType
{
vector argtypes (2, VoidPointerTy);
FunctionType *ftype = FunctionType::get (returnType, argtypes, true);
Value *sel = [self insertSelectorLookup:messageName];
#ifdef __NEXT_RUNTIME__
Constant *function =
module->getOrInsertFunction ("objc_msgSend", ftype);
#else
vector lookup_argtypes (2, VoidPointerTy);
FunctionType *lookup_ftype = FunctionType::get (PointerType::get (ftype, 0),
lookup_argtypes,
false);
Constant *lookup_function =
module->getOrInsertFunction ("objc_msg_lookup", lookup_ftype);
Value *function =
builder->CreateCall2 (lookup_function, object, sel, "method_impl");
#endif
// XXX The following doesn't work. Why?
// deque argd (*argv);
// argd.push_front (sel);
// argd.push_front (object);
vector argd;
argd.push_back (object);
argd.push_back (sel);
vector::iterator e;
for (e = argv->begin(); e != argv->end(); e++)
argd.push_back (*e);
return builder->CreateCall (function, argd);
}
+(Value *) insertMethodCall:(NSString *)messageName
onObject:(Value *)object
withName:(NSString *)name
{
vector argv;
return [self insertMethodCall:messageName
onObject:object
withArgumentVector:&argv
name:name];
}
+(Value *) insertMethodCall:(NSString *)messageName
onObject:(Value *)object
{
return [self insertMethodCall:messageName
onObject:object
withName:@""];
}
+(Value *) insertClassLookup:(NSString *)className
{
Constant *function =
module->getOrInsertFunction (
#ifdef __NEXT_RUNTIME__
"objc_getClass",
#else
"objc_get_class",
#endif
VoidPointerTy,
VoidPointerTy,
NULL);
const char *cname = [className UTF8String];
// Value *nameptr = builder->CreateGlobalStringPtr (cname, "");
Constant *nameptr = createGlobalStringPtr (cname);
return builder->CreateCall (function, nameptr, cname);
}
+(void) insertTrace:(NSString *)message
{
Constant *function =
module->getOrInsertFunction ("puts",
Int32Ty,
VoidPointerTy,
NULL);
builder->CreateCall (function, createGlobalStringPtr ([message UTF8String]));
}
+(void) insertPointerTrace:(Value *)pointerValue
{
Constant *function =
module->getOrInsertFunction ("printf",
Int32Ty,
VoidPointerTy,
VoidPointerTy,
NULL);
builder->CreateCall2 (function,
createGlobalStringPtr ("%p\n"),
builder->CreateBitCast (pointerValue, VoidPointerTy));
}
@end
@implementation MLKForm (MLKLLVMCompilation)
-(Value *) processForLLVMWithMultiValue:(Value *)multiValue
{
#if 0
[_compiler insertTrace:
[NSString stringWithFormat:
@"Executing: %@", MLKPrintToString(_form)]];
#endif
Value *result = [self reallyProcessForLLVMWithMultiValue:multiValue];
#if 0
[_compiler insertTrace:
[NSString stringWithFormat:
@"Done: %@", MLKPrintToString(_form)]];
#endif
return result;
}
-(Value *) reallyProcessForLLVMWithMultiValue:(Value *)multiValue
{
NSLog (@"WARNING: Unrecognised form type: %@", self);
return NULL;
}
@end
@implementation MLKProgNForm (MLKLLVMCompilation)
-(Value *) reallyProcessForLLVMWithMultiValue:(Value *)multiValue
{
NSEnumerator *e = [_bodyForms objectEnumerator];
MLKForm *form;
Value *value = ConstantPointerNull::get (VoidPointerTy);
unsigned int i;
i = 0;
while ((form = [e nextObject]))
{
i++;
if (i == [_bodyForms count])
value = [form processForLLVMWithMultiValue:multiValue];
else
value = [form processForLLVMWithMultiValue:NULL];
}
return value;
}
@end
@implementation MLKSimpleLoopForm (MLKLLVMCompilation)
-(Value *) reallyProcessForLLVMWithMultiValue:(Value *)multiValue
{
NSEnumerator *e = [_bodyForms objectEnumerator];
MLKForm *form;
Function *function = builder->GetInsertBlock()->getParent();
BasicBlock *loopBlock = BasicBlock::Create (*llvm_context, "loop", function);
BasicBlock *joinBlock = BasicBlock::Create (*llvm_context, "after_loop");
builder->CreateBr (loopBlock);
builder->SetInsertPoint (loopBlock);
while ((form = [e nextObject]))
{
[form processForLLVMWithMultiValue:NULL];
}
builder->CreateBr (loopBlock);
builder->SetInsertPoint (joinBlock);
function->getBasicBlockList().push_back (joinBlock);
builder->CreateUnreachable ();
return ConstantPointerNull::get (VoidPointerTy);;
}
@end
@implementation MLKSymbolForm (MLKLLVMCompilation)
-(Value *) reallyProcessForLLVMWithMultiValue:(Value *)multiValue
{
Value *value;
//NSLog (@"Symbol: %@", MLKPrintToString (_form));
//[_compiler insertTrace:[NSString stringWithFormat:@"Symbol: %@", _form]];
if (![_context variableIsLexical:_form])
{
//[_compiler insertTrace:@"Dynamic."];
Value *mlkdynamiccontext = [_compiler insertClassLookup:@"MLKDynamicContext"];
Value *dynctx = [_compiler insertMethodCall:@"currentContext"
onObject:mlkdynamiccontext];
LRETAIN (_form); // FIXME: release
Value *symbolV = builder->CreateIntToPtr (ConstantInt::get(Int64Ty,
(uint64_t)_form,
false),
VoidPointerTy);
vector args (1, symbolV);
value = [_compiler insertMethodCall:@"valueForSymbol:"
onObject:dynctx
withArgumentVector:&args];
}
else if ([_context variableIsGlobal:_form])
{
//[_compiler insertTrace:@"Global."];
Value *binding = builder->Insert ([_context globalBindingValueForSymbol:_form]);
value = [_compiler insertMethodCall:@"value" onObject:binding];
}
else if ([_context variableHeapAllocationForSymbol:_form])
{
Value *binding = [_context bindingValueForSymbol:_form];
value = [_compiler insertMethodCall:@"value" onObject:binding];
}
else
{
value = builder->CreateLoad ([_context valueValueForSymbol:_form],
[MLKPrintToString(_form) UTF8String]);
}
return value;
}
@end
@implementation MLKFunctionCallForm (MLKLLVMCompilation)
-(Value *) reallyProcessForLLVMWithMultiValue:(Value *)multiValue
{
Value *functionPtr;
Value *closureDataPtr;
vector args;
if (![_context symbolNamesFunction:_head])
{
NSLog (@"Compiler: Don't know function %@", MLKPrintToString(_head));
// XXX Issue a style warning.
}
const char *built_in_name;
if ((built_in_name = toilet_built_in_function_name(_head)))
{
//vector argtypes (2, VoidPointerTy);
vector argtypes (2 + [_argumentForms count] + 1, VoidPointerTy);
argtypes[1] = PointerPointerTy;
FunctionType *ftype = FunctionType::get (VoidPointerTy, argtypes, false);
functionPtr =
module->getOrInsertFunction (built_in_name, ftype);
closureDataPtr = ConstantPointerNull::get (VoidPointerTy);
}
else if ([_context functionIsGlobal:_head])
{
Value *functionCell;
Value *closureDataCell;
functionCell = builder->Insert ([_context functionCellValueForSymbol:_head]);
functionPtr = builder->CreateLoad (functionCell);
closureDataCell = builder->Insert ([_context closureDataPointerValueForSymbol:_head]);
closureDataPtr = builder->CreateLoad (closureDataCell);
}
else
{
Value *binding = [_context functionBindingValueForSymbol:_head];
// It's important for closure to be an i8* because we need to calculate
// the GEP offset in terms of bytes.
Value *closure = builder->CreateBitCast ([_compiler insertMethodCall:@"value" onObject:binding], VoidPointerTy);
#if defined(OBJC_API_VERSION) && OBJC_API_VERSION >= 2
ptrdiff_t code_offset = ivar_getOffset (class_getInstanceVariable ([MLKCompiledClosure class], "m_code"));
ptrdiff_t data_offset = ivar_getOffset (class_getInstanceVariable ([MLKCompiledClosure class], "m_data"));
#else
ptrdiff_t code_offset = offsetof (MLKCompiledClosure, m_code);
ptrdiff_t data_offset = offsetof (MLKCompiledClosure, m_data);
#endif
Constant *code_offset_value = ConstantInt::get (Int32Ty, code_offset, false);
Constant *data_offset_value = ConstantInt::get (Int32Ty, data_offset, false);
Value *codeptr = builder->CreateGEP (closure, code_offset_value);
Value *dataptr = builder->CreateGEP (closure, data_offset_value);
codeptr = builder->CreateBitCast (codeptr, PointerPointerTy, "closure_code_ptr");
dataptr = builder->CreateBitCast (codeptr, PointerPointerTy, "closure_data_ptr");
Value *code = builder->CreateLoad (codeptr, "closure_code");
Value *data = builder->CreateLoad (dataptr, "closure_data");
std::vector types (2, PointerPointerTy);
functionPtr = builder->CreateBitCast (code, PointerType::get(FunctionType::get(VoidPointerTy,
types,
true),
0));
closureDataPtr = builder->CreateBitCast (data, PointerPointerTy);
}
//[_compiler insertTrace:[NSString stringWithFormat:@"Call: %@", MLKPrintToString(_head)]];
//[_compiler insertPointerTrace:functionPtr];
args.push_back (closureDataPtr);
if (multiValue)
args.push_back (multiValue);
else
args.push_back (ConstantPointerNull::get (PointerPointerTy));
NSEnumerator *e = [_argumentForms objectEnumerator];
MLKForm *form;
while ((form = [e nextObject]))
{
args.push_back ([form processForLLVMWithMultiValue:NULL]);
}
//GlobalVariable *endmarker = module->getGlobalVariable ("MLKEndOfArgumentsMarker", false);
//endmarker->setConstant (true);
//GlobalVariable *endmarker = new GlobalVariable (VoidPointerTy, true, GlobalValue::ExternalWeakLinkage);
Value *endmarker = builder->CreateIntToPtr (ConstantInt::get(Int64Ty,
(uint64_t)MLKEndOfArgumentsMarker,
false),
VoidPointerTy);
args.push_back (endmarker);
// If the pointer output here is different from the one above,
// there's some stack smashing going on.
//[_compiler insertTrace:[NSString stringWithFormat:@"Now calling: %@.", MLKPrintToString(_head)]];
//[_compiler insertPointerTrace:functionPtr];
CallInst *call = builder->CreateCall(functionPtr,
args,
[MLKPrintToString(_head) UTF8String]);
call->setCallingConv(CallingConv::C);
call->setTailCall(true);
// XXX
if ([_context functionIsInline:_head])
{
// FIXME: What to do here?
//InlineFunction (call);
}
//[_compiler insertTrace:[NSString stringWithFormat:@"%@ done.", MLKPrintToString(_head)]];
return call;
}
@end
static void
build_simple_function_definition (MLKBodyForm *processed_form,
id _lambdaListName,
Function*& function,
Value*& closure_data,
intptr_t& closure_data_size)
{
NSArray *_bodyForms = [processed_form bodyForms];
MLKLexicalContext *_bodyContext = [processed_form bodyContext];
MLKLexicalContext *_context = [processed_form context];
id _compiler = [MLKLLVMCompiler class];
vector argtypes (2, PointerPointerTy);
FunctionType *ftype = FunctionType::get (VoidPointerTy, argtypes, true);
function = Function::Create (ftype,
Function::InternalLinkage,
"a_lisp_closure_body",
module);
Function::arg_iterator args = function->arg_begin();
Value *closure_data_arg = args++;
closure_data_arg->setName ("closure_data");
Value *functionMultiValue = args++;
functionMultiValue->setName ("function_multiple_value_return_pointer");
BasicBlock *outerBlock = builder->GetInsertBlock ();
BasicBlock *initBlock = BasicBlock::Create (*llvm_context, "init_function", function);
BasicBlock *loopBlock = BasicBlock::Create (*llvm_context, "load_args");
BasicBlock *loopInitBlock = BasicBlock::Create (*llvm_context, "load_args_prelude");
BasicBlock *joinBlock = BasicBlock::Create (*llvm_context, "function_body");
BasicBlock *lambdaListNewBlock = BasicBlock::Create (*llvm_context, "lambda_list_new");
BasicBlock *lambdaListUpdateBlock = BasicBlock::Create (*llvm_context, "lambda_list_update");
// ***** HANDLE CLOSURE VARIABLES *****
builder->SetInsertPoint (outerBlock);
NSArray *freeVariables = [[processed_form freeVariables] allObjects];
closure_data = builder->CreateAlloca (VoidPointerTy,
ConstantInt::get(Int32Ty,
(uint32_t)[freeVariables count],
false));
closure_data_size = 0;
unsigned int i;
for (i = 0; i < [freeVariables count]; i++)
{
// FIXME: We assume heap allocation for all closure variables.
MLKSymbol *symbol = [freeVariables objectAtIndex:i];
if (![_context variableIsGlobal:symbol])
{
Constant *position = ConstantInt::get(Int32Ty, closure_data_size, false);
// Fill in the closure data array.
builder->SetInsertPoint (outerBlock);
Value *binding = [_context bindingValueForSymbol:symbol];
Value *closure_value_ptr = builder->CreateGEP (closure_data, position);
builder->CreateStore (binding, closure_value_ptr);
// Access the closure data array from within the closure.
builder->SetInsertPoint (initBlock);
Value *local_closure_value_ptr = builder->CreateGEP (closure_data_arg,
position);
Value *local_closure_value = builder->CreateLoad (local_closure_value_ptr,
[MLKPrintToString(symbol) UTF8String]);
[_bodyContext locallySetBindingValue:local_closure_value
forSymbol:symbol];
closure_data_size++;
}
}
// ***** HANDLE ARGUMENTS *****
builder->SetInsertPoint (initBlock);
Value *endmarker = builder->CreateIntToPtr (ConstantInt::get(Int64Ty,
(uint64_t)MLKEndOfArgumentsMarker,
false),
PointerType::get(Int8Ty, 0));
Value *ap = builder->CreateAlloca (VoidPointerTy, NULL, "ap");
Value *ap2 = builder->CreateBitCast (ap, VoidPointerTy);
builder->CreateCall (module->getOrInsertFunction ("llvm.va_start",
VoidTy,
VoidPointerTy,
NULL),
ap2);
Value *mlkcons = [_compiler insertClassLookup:@"MLKCons"];
// FIXME: Heap-allocate if appropriate.
Value *lambdaList = builder->CreateAlloca (VoidPointerTy, NULL, "lambda_list");
Value *lambdaListTail = builder->CreateAlloca (VoidPointerTy, NULL, "lambda_list_tail");
builder->CreateStore (ConstantPointerNull::get (VoidPointerTy), lambdaList);
builder->CreateStore (ConstantPointerNull::get (VoidPointerTy), lambdaListTail);
builder->CreateBr (loopInitBlock);
builder->SetInsertPoint (loopInitBlock);
function->getBasicBlockList().push_back (loopInitBlock);
Value *arg = builder->CreateVAArg (ap, VoidPointerTy, "arg");
Value *cond = builder->CreateICmpEQ (arg, endmarker);
builder->CreateCondBr (cond, joinBlock, loopBlock);
builder->SetInsertPoint (loopBlock);
function->getBasicBlockList().push_back (loopBlock);
builder->CreateCondBr (builder->CreateICmpEQ (builder->CreateLoad (lambdaList),
ConstantPointerNull::get (VoidPointerTy)),
lambdaListNewBlock,
lambdaListUpdateBlock);
builder->SetInsertPoint (lambdaListNewBlock);
function->getBasicBlockList().push_back (lambdaListNewBlock);
vector argv (1, arg);
argv.push_back (ConstantPointerNull::get (VoidPointerTy));
Value *newLambdaList = [_compiler insertMethodCall:@"cons:with:"
onObject:mlkcons
withArgumentVector:&argv];
builder->CreateStore (newLambdaList, lambdaList);
builder->CreateStore (newLambdaList, lambdaListTail);
builder->CreateBr (loopInitBlock);
builder->SetInsertPoint (lambdaListUpdateBlock);
function->getBasicBlockList().push_back (lambdaListUpdateBlock);
Value *newCons = [_compiler insertMethodCall:@"cons:with:"
onObject:mlkcons
withArgumentVector:&argv];
vector setcdr_argv (1, newCons);
[_compiler insertVoidMethodCall:@"setCdr:"
onObject:builder->CreateLoad(lambdaListTail)
withArgumentVector:&setcdr_argv];
builder->CreateStore (newCons, lambdaListTail);
builder->CreateBr (loopInitBlock);
builder->SetInsertPoint (joinBlock);
function->getBasicBlockList().push_back (joinBlock);
builder->CreateCall (module->getOrInsertFunction ("llvm.va_end",
VoidTy,
VoidPointerTy,
NULL),
ap2);
if ([_bodyContext variableHeapAllocationForSymbol:_lambdaListName])
{
Value *mlkbinding = [_compiler insertClassLookup:@"MLKBinding"];
Value *currentLambdaList = builder->CreateLoad (lambdaList);
vector args (1, currentLambdaList);
Value *lambdaBinding = [_compiler insertMethodCall:@"bindingWithValue:"
onObject:mlkbinding
withArgumentVector:&args];
[_bodyContext setBindingValue:lambdaBinding
forSymbol:_lambdaListName];
}
else
[_bodyContext setValueValue:lambdaList forSymbol:_lambdaListName];
NSEnumerator *e = [_bodyForms objectEnumerator];
MLKForm *form;
Value *value = NULL;
if ([_bodyForms count] == 0)
{
//NSLog (@"%LAMBDA: No body.");
value = ConstantPointerNull::get (VoidPointerTy);
}
i = 0;
while ((form = [e nextObject]))
{
i++;
if (i == [_bodyForms count])
value = [form processForLLVMWithMultiValue:functionMultiValue];
else
value = [form processForLLVMWithMultiValue:NULL];
}
builder->CreateRet (value);
//function->dump();
//NSLog (@"Verify...");
verifyFunction (*function);
//NSLog (@"Optimise...");
fpm->run (*function);
//NSLog (@"Assemble...");
// Explicit assembly is needed in order to allow libffi to call
// the function.
execution_engine->getPointerToFunction (function);
//NSLog (@"Done.");
//function->dump();
//function->viewCFG();
//NSLog (@"Function built.");
builder->SetInsertPoint (outerBlock);
}
@implementation MLKSimpleLambdaForm (MLKLLVMCompilation)
-(Value *) reallyProcessForLLVMWithMultiValue:(Value *)multiValue
{
intptr_t closure_data_size;
Function *function;
Value *closure_data;
build_simple_function_definition (self, _lambdaListName, function, closure_data, closure_data_size);
vector argv;
argv.push_back (function);
argv.push_back (builder->CreateBitCast (closure_data, VoidPointerTy));
argv.push_back (builder->CreateIntToPtr (ConstantInt::get(Int32Ty,
closure_data_size,
false),
VoidPointerTy));
Value *mlkcompiledclosure = [_compiler
insertClassLookup:@"MLKCompiledClosure"];
Value *closure =
[_compiler insertMethodCall:@"closureWithCode:data:length:"
onObject:mlkcompiledclosure
withArgumentVector:&argv];
return closure;
}
@end
@implementation MLKLetForm (MLKLLVMCompilation)
-(Value *) reallyProcessForLLVMWithMultiValue:(Value *)multiValue
{
NSEnumerator *e = [_variableBindingForms objectEnumerator];
Value *value = ConstantPointerNull::get (VoidPointerTy);
MLKForm *form;
MLKVariableBindingForm *binding_form;
while ((binding_form = [e nextObject]))
{
Value *binding_value = [[binding_form valueForm] processForLLVMWithMultiValue:NULL];
if ([_bodyContext variableHeapAllocationForSymbol:[binding_form name]])
{
Value *mlkbinding = [_compiler insertClassLookup:@"MLKBinding"];
vector args (1, binding_value);
Value *binding = [_compiler insertMethodCall:@"bindingWithValue:"
onObject:mlkbinding
withArgumentVector:&args];
[_bodyContext setBindingValue:binding
forSymbol:[binding_form name]];
}
else
{
Value *binding_variable = builder->CreateAlloca (VoidPointerTy,
NULL,
[(MLKPrintToString([binding_form name]))
UTF8String]);
builder->CreateStore (binding_value, binding_variable);
[_bodyContext setValueValue:binding_variable
forSymbol:[binding_form name]];
}
}
unsigned int i = 0;
e = [_bodyForms objectEnumerator];
while ((form = [e nextObject]))
{
i++;
if (i == [_bodyForms count])
value = [form processForLLVMWithMultiValue:multiValue];
else
value = [form processForLLVMWithMultiValue:NULL];
}
return value;
}
@end
@implementation MLKSimpleFletForm (MLKLLVMCompilation)
-(Value *) reallyProcessForLLVMWithMultiValue:(Value *)multiValue
{
NSEnumerator *e = [_functionBindingForms objectEnumerator];
Value *value = ConstantPointerNull::get (VoidPointerTy);
MLKForm *form;
MLKSimpleFunctionBindingForm *binding_form;
unsigned int i;
while ((binding_form = [e nextObject]))
{
intptr_t closure_data_size;
Function *function;
Value *closure_data;
build_simple_function_definition (binding_form, [binding_form lambdaListName], function, closure_data, closure_data_size);
vector argv;
argv.push_back (function);
argv.push_back (builder->CreateBitCast (closure_data, VoidPointerTy));
argv.push_back (builder->CreateIntToPtr (ConstantInt::get(Int32Ty,
closure_data_size,
false),
VoidPointerTy));
Value *mlkcompiledclosure = [_compiler
insertClassLookup:@"MLKCompiledClosure"];
Value *closure =
[_compiler insertMethodCall:@"closureWithCode:data:length:"
onObject:mlkcompiledclosure
withArgumentVector:&argv];
Value *binding_value = closure;
Value *mlkbinding = [_compiler insertClassLookup:@"MLKBinding"];
vector args (1, binding_value);
Value *binding = [_compiler insertMethodCall:@"bindingWithValue:"
onObject:mlkbinding
withArgumentVector:&args];
[_bodyContext setFunctionBindingValue:binding
forSymbol:[binding_form name]];
}
i = 0;
e = [_bodyForms objectEnumerator];
while ((form = [e nextObject]))
{
i++;
if (i == [_bodyForms count])
value = [form processForLLVMWithMultiValue:multiValue];
else
value = [form processForLLVMWithMultiValue:NULL];
}
return value;
}
@end
@implementation MLKQuoteForm (MLKLLVMCompilation)
-(Value *) reallyProcessForLLVMWithMultiValue:(Value *)multiValue
{
// FIXME: When to release _quotedData? At the same time the code is
// released, probably...
// FIXME: In garbage-collected code, _quotedData will be deleted even
// though it is referenced by compiled code!
LRETAIN (_quotedData);
#ifdef __OBJC_GC__
if (_quotedData && MLKInstanceP (_quotedData))
[[NSGarbageCollector defaultCollector] disableCollectorForPointer:_quotedData];
#endif
return builder->CreateIntToPtr (ConstantInt::get(Int64Ty,
(uint64_t)_quotedData,
false),
VoidPointerTy);
}
@end
@implementation MLKSelfEvaluatingForm (MLKLLVMCompilation)
-(Value *) reallyProcessForLLVMWithMultiValue:(Value *)multiValue
{
// FIXME: When to release _form? At the same time the code is
// released, probably...
// FIXME: In garbage-collected code, _form will be deleted even
// though it is referenced by compiled code!
LRETAIN (_form);
#ifdef __OBJC_GC__
if (_form && MLKInstanceP (_form))
[[NSGarbageCollector defaultCollector] disableCollectorForPointer:_form];
#endif
return builder->CreateIntToPtr (ConstantInt::get(Int64Ty,
(uint64_t)_form,
false),
VoidPointerTy);
}
@end
@implementation MLKIfForm (MLKLLVMCompilation)
-(Value *) reallyProcessForLLVMWithMultiValue:(Value *)multiValue
{
Function *function = builder->GetInsertBlock()->getParent();
BasicBlock *thenBlock = BasicBlock::Create (*llvm_context, "if_then", function);
BasicBlock *elseBlock = BasicBlock::Create (*llvm_context, "if_else");
BasicBlock *joinBlock = BasicBlock::Create (*llvm_context, "if_join");
Value *test = builder->CreateICmpNE ([_conditionForm processForLLVMWithMultiValue:NULL],
ConstantPointerNull::get (VoidPointerTy));
Value *value = builder->CreateAlloca (VoidPointerTy, NULL, "if_result");
builder->CreateCondBr (test, thenBlock, elseBlock);
builder->SetInsertPoint (thenBlock);
builder->CreateStore ([_consequentForm processForLLVMWithMultiValue:multiValue], value);
builder->CreateBr (joinBlock);
builder->SetInsertPoint (elseBlock);
function->getBasicBlockList().push_back (elseBlock);
builder->CreateStore ([_alternativeForm processForLLVMWithMultiValue:multiValue], value);
builder->CreateBr (joinBlock);
builder->SetInsertPoint (joinBlock);
function->getBasicBlockList().push_back (joinBlock);
return builder->CreateLoad (value);
}
@end
@implementation MLKSetQForm (MLKLLVMCompilation)
-(Value *) reallyProcessForLLVMWithMultiValue:(Value *)multiValue
{
NSEnumerator *var_e, *value_e;
MLKForm *valueForm;
Value *value = ConstantPointerNull::get (VoidPointerTy);
id variable;
var_e = [_variables objectEnumerator];
value_e = [_valueForms objectEnumerator];
while ((valueForm = [value_e nextObject]))
{
variable = [var_e nextObject];
value = [valueForm processForLLVMWithMultiValue:NULL];
if (![_context variableIsLexical:variable])
{
Value *mlkdynamiccontext = [_compiler insertClassLookup:@"MLKDynamicContext"];
Value *dynctx = [_compiler insertMethodCall:@"currentContext"
onObject:mlkdynamiccontext];
LRETAIN (variable); // FIXME: release
#ifdef __OBJC_GC__
// FIXME: proper memory management
if (variable && MLKInstanceP (variable))
[[NSGarbageCollector defaultCollector] disableCollectorForPointer:variable];
#endif
Value *symbolV = builder->CreateIntToPtr (ConstantInt::get(Int64Ty,
(uint64_t)variable,
false),
VoidPointerTy);
vector args;
args.push_back (symbolV);
Value *binding = [_compiler insertMethodCall:@"bindingForSymbol:"
onObject:dynctx
withArgumentVector:&args];
// Test whether the binding is non-null. If so, set its value, else create a new one.
Function *function = builder->GetInsertBlock()->getParent();
BasicBlock *setBlock = BasicBlock::Create (*llvm_context, "setq_set_existing_dynamic_binding", function);
BasicBlock *makeNewBlock = BasicBlock::Create (*llvm_context, "setq_make_new_dynamic_binding");
BasicBlock *joinBlock = BasicBlock::Create (*llvm_context, "setq_join");
Value *test = builder->CreateICmpNE (binding, ConstantPointerNull::get (VoidPointerTy));
//Value *value = builder->CreateAlloca (VoidPointerTy, NULL, "if_result");
builder->CreateCondBr (test, setBlock, makeNewBlock);
builder->SetInsertPoint (setBlock);
args[0] = value;
[_compiler insertMethodCall:@"setValue:"
onObject:binding
withArgumentVector:&args];
builder->CreateBr (joinBlock);
builder->SetInsertPoint (makeNewBlock);
function->getBasicBlockList().push_back (makeNewBlock);
Value *globalctx = [_compiler insertMethodCall:@"globalContext"
onObject:mlkdynamiccontext];
args[0] = value;
args.push_back (symbolV);
[_compiler insertMethodCall:@"addValue:forSymbol:"
onObject:globalctx
withArgumentVector:&args];
builder->CreateBr (joinBlock);
builder->SetInsertPoint (joinBlock);
function->getBasicBlockList().push_back (joinBlock);
}
else if ([_context variableIsGlobal:variable])
{
Value *binding = builder->Insert ([_context globalBindingValueForSymbol:variable]);
vector args (1, value);
[_compiler insertVoidMethodCall:@"setValue:"
onObject:binding
withArgumentVector:&args];
}
else if ([_context variableHeapAllocationForSymbol:variable])
{
Value *binding = [_context bindingValueForSymbol:variable];
vector args (1, value);
[_compiler insertVoidMethodCall:@"setValue:"
onObject:binding
withArgumentVector:&args];
}
else
{
builder->CreateStore (value, [_context valueValueForSymbol:variable]);
}
}
return value;
}
@end
@implementation MLKInPackageForm (MLKLLVMCompilation)
-(Value *) reallyProcessForLLVMWithMultiValue:(Value *)multiValue
{
id package = [MLKPackage findPackage:stringify(_packageDesignator)];
[[MLKDynamicContext currentContext]
setValue:package
forSymbol:[[MLKPackage findPackage:@"COMMON-LISP"]
intern:@"*PACKAGE*"]];
return builder->CreateIntToPtr (ConstantInt::get(Int64Ty,
(uint64_t)package,
false),
VoidPointerTy);
}
@end
@implementation MLKSimpleFunctionForm (MLKLLVMCompilation)
-(Value *) reallyProcessForLLVMWithMultiValue:(Value *)multiValue
{
if ([_context functionIsGlobal:_functionName])
{
Value *mlklexicalenvironment = [_compiler insertClassLookup:@"MLKLexicalEnvironment"];
Value *env = [_compiler insertMethodCall:@"globalEnvironment"
onObject:mlklexicalenvironment];
LRETAIN (_functionName); // FIXME: release
#ifdef __OBJC_GC__
// FIXME: proper memory management
if (_functionName && MLKInstanceP (_functionName))
[[NSGarbageCollector defaultCollector] disableCollectorForPointer:_functionName];
#endif
Value *symbolV = builder->CreateIntToPtr (ConstantInt::get(Int64Ty,
(uint64_t)_functionName,
false),
VoidPointerTy);
vector args;
args.push_back (symbolV);
Value *fun = [_compiler insertMethodCall:@"functionForSymbol:"
onObject:env
withArgumentVector:&args];
return fun;
}
else
{
Value *binding = [_context functionBindingValueForSymbol:_functionName];
Value *closure = builder->CreateBitCast ([_compiler insertMethodCall:@"value" onObject:binding], VoidPointerTy);
return closure;
}
}
@end
@implementation MLKLambdaFunctionForm (MLKLLVMCompilation)
-(Value *) reallyProcessForLLVMWithMultiValue:(Value *)multiValue
{
return [_lambdaForm processForLLVMWithMultiValue:multiValue];
}
@end
@implementation MLKMultipleValueListForm (MLKLLVMCompilation)
-(Value *) reallyProcessForLLVMWithMultiValue:(Value *)multiValue
{
Value *endmarker = builder->CreateIntToPtr (ConstantInt::get(Int64Ty,
(uint64_t)MLKEndOfArgumentsMarker,
false),
VoidPointerTy);
Value *multi_tmp = builder->CreateAlloca (VoidPointerTy, NULL);
builder->CreateStore (endmarker, multi_tmp);
Value *value = [_listForm processForLLVMWithMultiValue:multi_tmp];
Value *return_value = builder->CreateAlloca (VoidPointerTy, NULL);
Function *function = builder->GetInsertBlock()->getParent();
BasicBlock *singleValueBlock = BasicBlock::Create (*llvm_context, "single_value_block", function);
BasicBlock *multipleValueBlock = BasicBlock::Create (*llvm_context, "multiple_value_block");
BasicBlock *joinBlock = BasicBlock::Create (*llvm_context, "join_block");
Value *multi_tmp_content = builder->CreateLoad (multi_tmp);
Value *isSingleValue = builder->CreateICmpEQ (multi_tmp_content, endmarker);
builder->CreateCondBr (isSingleValue, singleValueBlock, multipleValueBlock);
builder->SetInsertPoint (singleValueBlock);
Value *mlkcons = [_compiler insertClassLookup:@"MLKCons"];
vector argv;
argv.push_back (value);
argv.push_back (ConstantPointerNull::get (VoidPointerTy));
Value *newList = [_compiler insertMethodCall:@"cons:with:"
onObject:mlkcons
withArgumentVector:&argv];
builder->CreateStore (newList, return_value);
builder->CreateBr (joinBlock);
function->getBasicBlockList().push_back (multipleValueBlock);
builder->SetInsertPoint (multipleValueBlock);
builder->CreateStore (multi_tmp_content, return_value);
builder->CreateBr (joinBlock);
function->getBasicBlockList().push_back (joinBlock);
builder->SetInsertPoint (joinBlock);
return builder->CreateLoad (return_value);
}
@end