Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions backend-v2/bridge/Exceptions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -687,6 +687,17 @@ throwNoMatchingOverloadException_C(const char *className,
RT_boxPtr(::String_createDynamicStr(ss.str().c_str())), RT_boxNil());
}

extern "C" [[noreturn]] void
throwNoMatchingConstructorException_C(const char *className,
int arity) {
std::stringstream ss;
ss << "No matching constructor found for " << className << " with arity " << arity;
throw rt::LanguageException(
"NoMatchingConstructorException",
RT_boxPtr(::String_createDynamicStr(ss.str().c_str())), RT_boxNil());
}


extern "C" void throwLanguageException_C(const char *name, RTValue message,
RTValue payload) {
throw rt::LanguageException(name, message, payload);
Expand Down
4 changes: 4 additions & 0 deletions backend-v2/bridge/Exceptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,10 @@ extern "C" [[noreturn]] void
throwNoMatchingOverloadException_C(const char *className,
const char *methodName);

extern "C" [[noreturn]] void
throwNoMatchingConstructorException_C(const char *className,
int arity);

extern "C" String *exceptionToString_C(void *exception);
extern "C" void *createException_C(const char *className, String *message,
RTValue payload);
Expand Down
8 changes: 8 additions & 0 deletions backend-v2/codegen/CodeGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -181,8 +181,15 @@ llvm::Function *CodeGen::generateBaselineMethod(
[](unsigned char c) { return !std::isalnum(c); }, '_');
funcName += sanitized + "_";
}
funcName += "arity_" + std::to_string(method.fixedarity()) + "_";
if (method.isvariadic()) {
funcName += "variadic_";
}
funcName += generateRandomHex(16);

std::string savedSuggestedFunctionName = suggestedFunctionName;
suggestedFunctionName = "";

// Create the function with baseline signature: (Frame*, Arg0, Arg1, Arg2,
// Arg3, Arg4) -> RTValue
Function *F =
Expand Down Expand Up @@ -351,6 +358,7 @@ llvm::Function *CodeGen::generateBaselineMethod(
variableTypesBindingsStack.pop();

verifyFunction(*F);
suggestedFunctionName = savedSuggestedFunctionName;
return F;
}

Expand Down
16 changes: 9 additions & 7 deletions backend-v2/codegen/invoke/InvokeManager.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#include "InvokeManager.h"
#include "../../tools/RandomID.h"
#include "../../bridge/Exceptions.h"
#include "../../tools/EdnParser.h"
#include "../../tools/RandomID.h"
#include "../../types/ConstantBigInteger.h"
#include "../../types/ConstantBool.h"
#include "../../types/ConstantDouble.h"
Expand Down Expand Up @@ -343,9 +343,9 @@ TypedValue InvokeManager::invokeRuntime(
}
}

return TypedValue(
retValType ? *retValType : ObjectTypeSet::all(),
invokeRaw(fname, functionType, argVals, guard, consumesArgs, extraCleanup));
return TypedValue(retValType ? *retValType : ObjectTypeSet::all(),
invokeRaw(fname, functionType, argVals, guard, consumesArgs,
extraCleanup));
}

TypedValue InvokeManager::generateRawMethodCall(
Expand Down Expand Up @@ -397,7 +397,8 @@ TypedValue InvokeManager::generateRawMethodCall(
? static_cast<llvm::Value *>(&*currentFn->arg_begin())
: static_cast<llvm::Value *>(
ConstantPointerNull::get(cast<PointerType>(types.ptrTy)));
builder.CreateStore(currentFrame, types.getFrameLeafFramePtr(builder, framePtr));
builder.CreateStore(currentFrame,
types.getFrameLeafFramePtr(builder, framePtr));
builder.CreateStore(methodPtr, types.getFrameMethodPtr(builder, framePtr));
builder.CreateStore(valueEncoder.box(self).value,
types.getFrameSelfPtr(builder, framePtr));
Expand Down Expand Up @@ -478,8 +479,9 @@ TypedValue InvokeManager::generateRawMethodCall(
return TypedValue(ObjectTypeSet::dynamicType(), res);
}

llvm::Value *InvokeManager::generateICLookup(
llvm::Value *currentVal, size_t argCount, CleanupChainGuard *guard) {
llvm::Value *InvokeManager::generateICLookup(llvm::Value *currentVal,
size_t argCount,
CleanupChainGuard *guard) {
auto &TheContext = theModule.getContext();
llvm::Function *currentFn = builder.GetInsertBlock()->getParent();

Expand Down
4 changes: 2 additions & 2 deletions backend-v2/codegen/invoke/InvokeManager_InstanceCall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ TypedValue InvokeManager::generateDynamicInstanceCall(
// 1. Get current instance type
TypedValue boxedInstance = valueEncoder.box(instance);
FunctionType *getTypeSig =
FunctionType::get(types.i64Ty, {types.RT_valueTy}, false);
FunctionType::get(types.wordTy, {types.RT_valueTy}, false);
FunctionCallee getTypeFunc =
theModule.getOrInsertFunction("getType", getTypeSig);
Value *currentTypeIdent =
Expand Down Expand Up @@ -380,7 +380,7 @@ TypedValue InvokeManager::generateDeterminedInstanceCall(
Value *targetVal =
ConstantInt::get(this->types.i32Ty, (uint32_t)target);
Value *isType =
this->builder.CreateICmpEQ(argRuntimeTypes[i], targetVal);
this->builder.CreateICmpEQ(this->builder.CreateTrunc(argRuntimeTypes[i], this->types.i32Ty), targetVal);

if (match) {
match = this->builder.CreateAnd(match, isType);
Expand Down
19 changes: 11 additions & 8 deletions backend-v2/codegen/invoke/InvokeManager_Math.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -483,11 +483,16 @@ void registerMathIntrinsics(InvokeManager &mgr) {
const std::string &errorMessage) {
return [&mgr, &theModule, &types, llvmIntrinsic, errorMessage](
llvm::IRBuilder<> &b, std::vector<llvm::Value *> args) {
Function *fn = Intrinsic::getOrInsertDeclaration(
&theModule,
llvmIntrinsic == "sadd" ? Intrinsic::sadd_with_overflow
: Intrinsic::ssub_with_overflow,
{b.getInt32Ty()});
Intrinsic::ID id = Intrinsic::not_intrinsic;
if (llvmIntrinsic == "sadd")
id = Intrinsic::sadd_with_overflow;
else if (llvmIntrinsic == "ssub")
id = Intrinsic::ssub_with_overflow;
else if (llvmIntrinsic == "smul")
id = Intrinsic::smul_with_overflow;

Function *fn =
Intrinsic::getOrInsertDeclaration(&theModule, id, {b.getInt32Ty()});
Value *resStruct = b.CreateCall(fn, args);
Value *res = b.CreateExtractValue(resStruct, {0});
Value *overflow = b.CreateExtractValue(resStruct, {1});
Expand Down Expand Up @@ -524,9 +529,7 @@ void registerMathIntrinsics(InvokeManager &mgr) {
intrinsics["FMul"] = [](auto &b, auto args) {
return b.CreateFMul(args[0], args[1]);
};
intrinsics["Mul"] = [](auto &b, auto args) {
return b.CreateMul(args[0], args[1]);
};
intrinsics["Mul"] = createCheckedOp("smul", "Integer overflow");
intrinsics["FDiv"] = [](auto &b, auto args) {
return b.CreateFDiv(args[0], args[1]);
};
Expand Down
135 changes: 123 additions & 12 deletions backend-v2/codegen/ops/NewNode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,16 +46,15 @@ TypedValue CodeGen::codegen(const Node &node, const NewNode &subnode,
"Class " + className + " does not have compiler metadata", node);
}

// 3. Find matching constructor by arity
const IntrinsicDescription *bestMatch = nullptr;
// 3. Find matching constructors by arity
std::vector<const IntrinsicDescription *> versions;
for (const auto &ctor : ext->constructors) {
if ((int32_t)ctor.argTypes.size() == subnode.args_size()) {
bestMatch = &ctor;
break;
versions.push_back(&ctor);
}
}

if (!bestMatch) {
if (versions.empty()) {
throwCodeGenerationException("Class " + className +
" does not have a constructor of arity " +
to_string(subnode.args_size()),
Expand All @@ -64,24 +63,136 @@ TypedValue CodeGen::codegen(const Node &node, const NewNode &subnode,

// 4. Codegen arguments
std::vector<TypedValue> args;
bool allDetermined = true;
for (int i = 0; i < subnode.args_size(); i++) {
auto t = codegen(subnode.args(i), ObjectTypeSet::all());
if (!t.type.isDetermined())
allDetermined = false;
args.push_back(t);
guard.push(t);
}

std::vector<TypedValue> unboxedArgs;
for (size_t i = 0; i < args.size(); i++) {
if (!bestMatch->argTypes[i].isBoxedType()) {
unboxedArgs.push_back(this->valueEncoder.unbox(args[i]));
} else {
unboxedArgs.push_back(this->valueEncoder.box(args[i]));
const IntrinsicDescription *bestMatch = nullptr;
if (allDetermined) {
// Exact match trial
for (const auto *ctor : versions) {
bool match = true;
for (size_t i = 0; i < args.size(); i++) {
if (args[i].type.restriction(ctor->argTypes[i]).isEmpty()) {
match = false;
break;
}
}
if (match) {
bestMatch = ctor;
break;
}
}
}

if (bestMatch) {
std::vector<TypedValue> unboxedArgs;
for (size_t i = 0; i < args.size(); i++) {
if (!bestMatch->argTypes[i].isBoxedType()) {
unboxedArgs.push_back(this->valueEncoder.unbox(args[i]));
} else {
unboxedArgs.push_back(this->valueEncoder.box(args[i]));
}
}
return this->invokeManager.generateIntrinsic(*bestMatch, unboxedArgs,
&guard);
}

// No exact compile-time match -> Dynamic Dispatch or specialized trials
Function *currentFn = this->Builder.GetInsertBlock()->getParent();
BasicBlock *mergeBB =
BasicBlock::Create(this->TheContext, "new_dispatch_merge", currentFn);

struct DispatchCase {
BasicBlock *block;
TypedValue value;
};
std::vector<DispatchCase> cases;
std::vector<Value *> argRuntimeTypes(args.size(), nullptr);

for (const auto *fid : versions) {
BasicBlock *thenBB =
BasicBlock::Create(this->TheContext, "new_specialised", currentFn);
BasicBlock *nextBB =
BasicBlock::Create(this->TheContext, "new_specialised_next", currentFn);

Value *match = nullptr;
for (size_t i = 0; i < args.size(); i++) {
if (fid->argTypes[i].isDetermined()) {
if (!argRuntimeTypes[i]) {
TypedValue boxed = this->valueEncoder.box(args[i]);
FunctionType *getTypeSig = FunctionType::get(
this->types.wordTy, {this->types.RT_valueTy}, false);
argRuntimeTypes[i] = this->invokeManager.invokeRaw(
"getType", getTypeSig, {boxed.value}, &guard, true);
}

uint32_t targetTypeID = fid->argTypes[i].determinedType();
Value *targetVal =
ConstantInt::get(this->types.i32Ty, (uint32_t)targetTypeID);
Value *isType = this->Builder.CreateICmpEQ(
this->Builder.CreateTrunc(argRuntimeTypes[i], this->types.i32Ty),
targetVal);

if (match)
match = this->Builder.CreateAnd(match, isType);
else
match = isType;
}
}

if (!match)
match = this->Builder.getTrue();

this->Builder.CreateCondBr(match, thenBB, nextBB);
this->Builder.SetInsertPoint(thenBB);

std::vector<TypedValue> specializedArgs;
for (size_t i = 0; i < args.size(); i++) {
if (fid->argTypes[i].isDetermined()) {
TypedValue valToUnbox = args[i];
if (valToUnbox.type.isBoxedType()) {
valToUnbox = TypedValue(fid->argTypes[i].boxed(), valToUnbox.value);
}
llvm::Value *unboxedVal = this->valueEncoder.unbox(valToUnbox).value;
specializedArgs.push_back(TypedValue(fid->argTypes[i], unboxedVal));
} else {
specializedArgs.push_back(this->valueEncoder.box(args[i]));
}
}

TypedValue res =
this->invokeManager.generateIntrinsic(*fid, specializedArgs, &guard);
TypedValue boxedRes = this->valueEncoder.box(res);
cases.push_back({this->Builder.GetInsertBlock(), boxedRes});
this->Builder.CreateBr(mergeBB);
this->Builder.SetInsertPoint(nextBB);
}

return this->invokeManager.generateIntrinsic(*bestMatch, unboxedArgs, &guard);
// Fallback -> No matching constructor found at runtime
Value *clsName = this->Builder.CreateGlobalString(className, "new_fail_class");
FunctionType *fnTy = FunctionType::get(
this->types.voidTy, {this->types.ptrTy, this->types.i32Ty}, false);
this->invokeManager.invokeRaw(
"throwNoMatchingConstructorException_C", fnTy,
{clsName, ConstantInt::get(this->types.i32Ty, subnode.args_size())});
this->Builder.CreateUnreachable();

this->Builder.SetInsertPoint(mergeBB);
PHINode *phi = Builder.CreatePHI(types.RT_valueTy, cases.size(), "new_phi");
for (auto &c : cases) {
phi->addIncoming(c.value.value, c.block);
}

return TypedValue(ObjectTypeSet((objectType)cls->registerId), phi);
}


ObjectTypeSet CodeGen::getType(const Node &node, const NewNode &subnode,
const ObjectTypeSet &typeRestrictions) {
auto classTypeSet = getType(subnode.class_(), ObjectTypeSet::all());
Expand Down
45 changes: 13 additions & 32 deletions backend-v2/codegen/ops/StaticCallNode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -167,19 +167,18 @@ TypedValue CodeGen::codegen(const Node &node, const StaticCallNode &subnode,
if (fid->argTypes[i].isDetermined()) {
if (!argRuntimeTypes[i]) {
TypedValue boxed = this->valueEncoder.box(args[i]);
ObjectTypeSet retType(integerType, false);
std::vector<ObjectTypeSet> pArgTypes = {ObjectTypeSet::dynamicType()};
std::vector<TypedValue> pArgVals = {boxed};
TypedValue typeVal = this->invokeManager.invokeRuntime(
"getType", &retType, pArgTypes, pArgVals);
argRuntimeTypes[i] = typeVal.value;
FunctionType *getTypeSig = FunctionType::get(
this->types.wordTy, {this->types.RT_valueTy}, false);
argRuntimeTypes[i] = this->invokeManager.invokeRaw(
"getType", getTypeSig, {boxed.value}, &guard, true);
}

uint32_t target = fid->argTypes[i].determinedType();
uint32_t targetID = fid->argTypes[i].determinedType();
Value *targetVal =
ConstantInt::get(this->types.i32Ty, (uint32_t)target);
Value *isType =
this->Builder.CreateICmpEQ(argRuntimeTypes[i], targetVal);
ConstantInt::get(this->types.i32Ty, (uint32_t)targetID);
Value *isType = this->Builder.CreateICmpEQ(
this->Builder.CreateTrunc(argRuntimeTypes[i], this->types.i32Ty),
targetVal);

if (match) {
match = this->Builder.CreateAnd(match, isType);
Expand All @@ -199,29 +198,11 @@ TypedValue CodeGen::codegen(const Node &node, const StaticCallNode &subnode,
std::vector<TypedValue> specializedArgs;
for (size_t i = 0; i < args.size(); i++) {
if (fid->argTypes[i].isDetermined()) {
uint32_t target = fid->argTypes[i].determinedType();
llvm::Value *unboxedVal = nullptr;
if (target == integerType)
unboxedVal = this->valueEncoder.unboxInt32(args[i]).value;
else if (target == doubleType)
unboxedVal = this->valueEncoder.unboxDouble(args[i]).value;
else if (target == booleanType)
unboxedVal = this->valueEncoder.unboxBool(args[i]).value;
else if (target == stringType || target == persistentListType ||
target == persistentVectorType || target == bigIntegerType ||
target == ratioType || target == keywordType ||
target == symbolType || target == functionType ||
target == classType || target == persistentArrayMapType ||
target == varType || target == exceptionType ||
target == bridgedObjectType) {
unboxedVal = this->valueEncoder.unboxPointer(args[i]).value;
} else if (target == nilType) {
unboxedVal = args[i].value;
} else {
unboxedVal = this->valueEncoder.unbox(args[i]).value;
TypedValue valToUnbox = args[i];
if (valToUnbox.type.isBoxedType()) {
valToUnbox = TypedValue(fid->argTypes[i].boxed(), valToUnbox.value);
}
// CRITICAL: Set the verified type so InvokeManager doesn't complain
specializedArgs.push_back(TypedValue(fid->argTypes[i], unboxedVal));
specializedArgs.push_back(this->valueEncoder.unbox(valToUnbox));
} else {
specializedArgs.push_back(this->valueEncoder.box(args[i]));
}
Expand Down
2 changes: 2 additions & 0 deletions backend-v2/jit/JITEngine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,8 @@ void JITEngine::registerRuntimeSymbols() {
runtimeSymbols.insert(absoluteSymbol("equals", (void *)::equals));
runtimeSymbols.insert(absoluteSymbol("hash", (void *)::hash));
runtimeSymbols.insert(absoluteSymbol("toString", (void *)toString));
runtimeSymbols.insert(
absoluteSymbol("identical_managed", (void *)identical_managed));
runtimeSymbols.insert(
absoluteSymbol("equals_managed", (void *)equals_managed));

Expand Down
Loading
Loading