forked from cosmonaut/wraith-lang
1929 lines
57 KiB
C
1929 lines
57 KiB
C
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include <llvm-c/Analysis.h>
|
|
#include <llvm-c/BitWriter.h>
|
|
#include <llvm-c/Core.h>
|
|
#include <llvm-c/Object.h>
|
|
#include <llvm-c/Target.h>
|
|
#include <llvm-c/TargetMachine.h>
|
|
#include <llvm-c/Transforms/InstCombine.h>
|
|
#include <llvm-c/Transforms/PassManagerBuilder.h>
|
|
#include <llvm-c/Transforms/Scalar.h>
|
|
#include <llvm-c/Transforms/Utils.h>
|
|
|
|
#include "ast.h"
|
|
#include "util.h"
|
|
|
|
typedef struct LocalVariable
|
|
{
|
|
char *name;
|
|
LLVMValueRef pointer;
|
|
LLVMValueRef value;
|
|
} LocalVariable;
|
|
|
|
typedef struct LocalGenericType
|
|
{
|
|
char *name;
|
|
TypeTag *concreteTypeTag;
|
|
LLVMTypeRef type;
|
|
} LocalGenericType;
|
|
|
|
typedef struct FunctionArgument
|
|
{
|
|
char *name;
|
|
LLVMValueRef value;
|
|
} FunctionArgument;
|
|
|
|
typedef struct ScopeFrame
|
|
{
|
|
LocalVariable *localVariables;
|
|
uint32_t localVariableCount;
|
|
|
|
LocalGenericType *genericTypes;
|
|
uint32_t genericTypeCount;
|
|
} ScopeFrame;
|
|
|
|
typedef struct Scope
|
|
{
|
|
ScopeFrame *scopeStack;
|
|
uint32_t scopeStackCount;
|
|
} Scope;
|
|
|
|
Scope *scope;
|
|
|
|
typedef struct StructTypeField
|
|
{
|
|
char *name;
|
|
uint32_t index;
|
|
} StructTypeField;
|
|
|
|
typedef struct StructTypeFunction
|
|
{
|
|
char *name;
|
|
LLVMValueRef function;
|
|
LLVMTypeRef returnType;
|
|
uint8_t isStatic;
|
|
} StructTypeFunction;
|
|
|
|
typedef struct MonomorphizedGenericFunctionHashEntry
|
|
{
|
|
uint64_t key;
|
|
TypeTag **types;
|
|
uint32_t typeCount;
|
|
StructTypeFunction function;
|
|
} MonomorphizedGenericFunctionHashEntry;
|
|
|
|
typedef struct MonomorphizedGenericFunctionHashArray
|
|
{
|
|
MonomorphizedGenericFunctionHashEntry *elements;
|
|
uint32_t count;
|
|
} MonomorphizedGenericFunctionHashArray;
|
|
|
|
#define NUM_MONOMORPHIZED_HASH_BUCKETS 1031
|
|
|
|
typedef struct StructTypeGenericFunction
|
|
{
|
|
char *parentStructName;
|
|
LLVMTypeRef parentStructPointerType;
|
|
char *name;
|
|
Node *functionDeclarationNode;
|
|
uint8_t isStatic;
|
|
MonomorphizedGenericFunctionHashArray
|
|
monomorphizedFunctions[NUM_MONOMORPHIZED_HASH_BUCKETS];
|
|
} StructTypeGenericFunction;
|
|
|
|
typedef struct StructTypeDeclaration
|
|
{
|
|
char *name;
|
|
LLVMTypeRef structType;
|
|
LLVMTypeRef structPointerType;
|
|
StructTypeField *fields;
|
|
uint32_t fieldCount;
|
|
|
|
StructTypeFunction *functions;
|
|
uint32_t functionCount;
|
|
|
|
StructTypeGenericFunction *genericFunctions;
|
|
uint32_t genericFunctionCount;
|
|
} StructTypeDeclaration;
|
|
|
|
StructTypeDeclaration *structTypeDeclarations;
|
|
uint32_t structTypeDeclarationCount;
|
|
|
|
/* FUNCTION FORWARD DECLARATIONS */
|
|
static LLVMBasicBlockRef CompileStatement(
|
|
LLVMModuleRef module,
|
|
LLVMBuilderRef builder,
|
|
LLVMValueRef function,
|
|
Node *statement);
|
|
|
|
static LLVMValueRef CompileExpression(
|
|
LLVMModuleRef module,
|
|
LLVMBuilderRef builder,
|
|
Node *expression);
|
|
|
|
static Scope *CreateScope()
|
|
{
|
|
Scope *scope = malloc(sizeof(Scope));
|
|
|
|
scope->scopeStack = malloc(sizeof(ScopeFrame));
|
|
scope->scopeStack[0].localVariableCount = 0;
|
|
scope->scopeStack[0].localVariables = NULL;
|
|
scope->scopeStack[0].genericTypeCount = 0;
|
|
scope->scopeStack[0].genericTypes = NULL;
|
|
scope->scopeStackCount = 1;
|
|
|
|
return scope;
|
|
}
|
|
|
|
static void PushScopeFrame(Scope *scope)
|
|
{
|
|
uint32_t index = scope->scopeStackCount;
|
|
scope->scopeStack = realloc(
|
|
scope->scopeStack,
|
|
sizeof(ScopeFrame) * (scope->scopeStackCount + 1));
|
|
scope->scopeStack[index].localVariableCount = 0;
|
|
scope->scopeStack[index].localVariables = NULL;
|
|
scope->scopeStack[index].genericTypeCount = 0;
|
|
scope->scopeStack[index].genericTypes = NULL;
|
|
|
|
scope->scopeStackCount += 1;
|
|
}
|
|
|
|
static void PopScopeFrame(Scope *scope)
|
|
{
|
|
uint32_t i;
|
|
uint32_t index = scope->scopeStackCount - 1;
|
|
|
|
if (scope->scopeStack[index].localVariables != NULL)
|
|
{
|
|
for (i = 0; i < scope->scopeStack[index].localVariableCount; i += 1)
|
|
{
|
|
free(scope->scopeStack[index].localVariables[i].name);
|
|
}
|
|
free(scope->scopeStack[index].localVariables);
|
|
}
|
|
|
|
if (scope->scopeStack[index].genericTypes != NULL)
|
|
{
|
|
for (i = 0; i < scope->scopeStack[index].genericTypeCount; i += 1)
|
|
{
|
|
free(scope->scopeStack[index].genericTypes[i].name);
|
|
}
|
|
free(scope->scopeStack[index].genericTypes);
|
|
}
|
|
|
|
scope->scopeStackCount -= 1;
|
|
|
|
scope->scopeStack =
|
|
realloc(scope->scopeStack, sizeof(ScopeFrame) * scope->scopeStackCount);
|
|
}
|
|
|
|
static LLVMTypeRef WraithTypeToLLVMType(PrimitiveType type)
|
|
{
|
|
switch (type)
|
|
{
|
|
case Int:
|
|
return LLVMInt64Type();
|
|
|
|
case UInt:
|
|
return LLVMInt64Type();
|
|
|
|
case Bool:
|
|
return LLVMInt1Type();
|
|
|
|
case Void:
|
|
return LLVMVoidType();
|
|
}
|
|
|
|
fprintf(stderr, "Unrecognized type!");
|
|
return NULL;
|
|
}
|
|
|
|
static LocalGenericType *LookupGenericType(char *name)
|
|
{
|
|
int32_t i, j;
|
|
|
|
for (i = scope->scopeStackCount - 1; i >= 0; i -= 1)
|
|
{
|
|
for (j = 0; j < scope->scopeStack[i].genericTypeCount; j += 1)
|
|
{
|
|
if (strcmp(scope->scopeStack[i].genericTypes[j].name, name) == 0)
|
|
{
|
|
return &scope->scopeStack[i].genericTypes[j];
|
|
}
|
|
}
|
|
}
|
|
|
|
fprintf(stderr, "Could not find resolved generic type!\n");
|
|
return NULL;
|
|
}
|
|
|
|
static LLVMTypeRef LookupCustomType(char *name)
|
|
{
|
|
int32_t i;
|
|
|
|
for (i = 0; i < structTypeDeclarationCount; i += 1)
|
|
{
|
|
if (strcmp(structTypeDeclarations[i].name, name) == 0)
|
|
{
|
|
return structTypeDeclarations[i].structType;
|
|
}
|
|
}
|
|
|
|
fprintf(stderr, "Could not find struct type!\n");
|
|
return NULL;
|
|
}
|
|
|
|
static LLVMTypeRef ResolveType(TypeTag *typeTag)
|
|
{
|
|
if (typeTag->type == Primitive)
|
|
{
|
|
return WraithTypeToLLVMType(typeTag->value.primitiveType);
|
|
}
|
|
else if (typeTag->type == Custom)
|
|
{
|
|
return LookupCustomType(typeTag->value.customType);
|
|
}
|
|
else if (typeTag->type == Reference)
|
|
{
|
|
return LLVMPointerType(ResolveType(typeTag->value.referenceType), 0);
|
|
}
|
|
else if (typeTag->type == Generic)
|
|
{
|
|
return LookupGenericType(typeTag->value.genericType)->type;
|
|
}
|
|
else
|
|
{
|
|
fprintf(stderr, "Unknown type node!\n");
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
static void AddLocalVariable(
|
|
Scope *scope,
|
|
LLVMValueRef pointer, /* can be NULL */
|
|
LLVMValueRef value, /* can be NULL */
|
|
char *name)
|
|
{
|
|
ScopeFrame *scopeFrame = &scope->scopeStack[scope->scopeStackCount - 1];
|
|
uint32_t index = scopeFrame->localVariableCount;
|
|
|
|
scopeFrame->localVariables = realloc(
|
|
scopeFrame->localVariables,
|
|
sizeof(LocalVariable) * (scopeFrame->localVariableCount + 1));
|
|
scopeFrame->localVariables[index].name = strdup(name);
|
|
scopeFrame->localVariables[index].pointer = pointer;
|
|
scopeFrame->localVariables[index].value = value;
|
|
|
|
scopeFrame->localVariableCount += 1;
|
|
}
|
|
|
|
static void AddGenericVariable(Scope *scope, TypeTag *typeTag, char *name)
|
|
{
|
|
ScopeFrame *scopeFrame = &scope->scopeStack[scope->scopeStackCount - 1];
|
|
uint32_t index = scopeFrame->genericTypeCount;
|
|
|
|
scopeFrame->genericTypes = realloc(
|
|
scopeFrame->genericTypes,
|
|
sizeof(LocalGenericType) * (scopeFrame->genericTypeCount + 1));
|
|
scopeFrame->genericTypes[index].name = strdup(name);
|
|
scopeFrame->genericTypes[index].concreteTypeTag = typeTag;
|
|
scopeFrame->genericTypes[index].type = ResolveType(typeTag);
|
|
|
|
scopeFrame->genericTypeCount += 1;
|
|
}
|
|
|
|
static void AddStructVariablesToScope(
|
|
LLVMBuilderRef builder,
|
|
LLVMValueRef structPointer)
|
|
{
|
|
uint32_t i, j;
|
|
|
|
for (i = 0; i < structTypeDeclarationCount; i += 1)
|
|
{
|
|
if (structTypeDeclarations[i].structPointerType ==
|
|
LLVMTypeOf(structPointer))
|
|
{
|
|
for (j = 0; j < structTypeDeclarations[i].fieldCount; j += 1)
|
|
{
|
|
char *ptrName =
|
|
strdup(structTypeDeclarations[i].fields[j].name);
|
|
strcat(ptrName, "_ptr");
|
|
LLVMValueRef elementPointer = LLVMBuildStructGEP(
|
|
builder,
|
|
structPointer,
|
|
structTypeDeclarations[i].fields[j].index,
|
|
ptrName);
|
|
free(ptrName);
|
|
|
|
AddLocalVariable(
|
|
scope,
|
|
elementPointer,
|
|
NULL,
|
|
structTypeDeclarations[i].fields[j].name);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static LLVMTypeRef FindStructType(char *name)
|
|
{
|
|
uint32_t i;
|
|
|
|
for (i = 0; i < structTypeDeclarationCount; i += 1)
|
|
{
|
|
if (strcmp(structTypeDeclarations[i].name, name) == 0)
|
|
{
|
|
return structTypeDeclarations[i].structType;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static LLVMValueRef FindStructFieldPointer(
|
|
LLVMBuilderRef builder,
|
|
LLVMValueRef structPointer,
|
|
char *name)
|
|
{
|
|
int32_t i, j;
|
|
|
|
LLVMTypeRef structPointerType = LLVMTypeOf(structPointer);
|
|
|
|
for (i = 0; i < structTypeDeclarationCount; i += 1)
|
|
{
|
|
if (structTypeDeclarations[i].structPointerType == structPointerType)
|
|
{
|
|
for (j = 0; j < structTypeDeclarations[i].fieldCount; j += 1)
|
|
{
|
|
if (strcmp(structTypeDeclarations[i].fields[j].name, name) == 0)
|
|
{
|
|
char *ptrName = strdup(name);
|
|
strcat(ptrName, "_ptr");
|
|
return LLVMBuildStructGEP(
|
|
builder,
|
|
structPointer,
|
|
structTypeDeclarations[i].fields[j].index,
|
|
ptrName);
|
|
free(ptrName);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
printf("Failed to find struct field pointer!");
|
|
return NULL;
|
|
}
|
|
|
|
static LLVMValueRef FindVariablePointer(char *name)
|
|
{
|
|
int32_t i, j;
|
|
|
|
for (i = scope->scopeStackCount - 1; i >= 0; i -= 1)
|
|
{
|
|
for (j = 0; j < scope->scopeStack[i].localVariableCount; j += 1)
|
|
{
|
|
if (strcmp(scope->scopeStack[i].localVariables[j].name, name) == 0)
|
|
{
|
|
return scope->scopeStack[i].localVariables[j].pointer;
|
|
}
|
|
}
|
|
}
|
|
|
|
printf("Failed to find variable pointer!");
|
|
return NULL;
|
|
}
|
|
|
|
static LLVMValueRef FindVariableValue(LLVMBuilderRef builder, char *name)
|
|
{
|
|
int32_t i, j;
|
|
|
|
for (i = scope->scopeStackCount - 1; i >= 0; i -= 1)
|
|
{
|
|
for (j = 0; j < scope->scopeStack[i].localVariableCount; j += 1)
|
|
{
|
|
if (strcmp(scope->scopeStack[i].localVariables[j].name, name) == 0)
|
|
{
|
|
if (scope->scopeStack[i].localVariables[j].value != NULL)
|
|
{
|
|
return scope->scopeStack[i].localVariables[j].value;
|
|
}
|
|
else
|
|
{
|
|
return LLVMBuildLoad(
|
|
builder,
|
|
scope->scopeStack[i].localVariables[j].pointer,
|
|
name);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
printf("Failed to find variable value!");
|
|
return NULL;
|
|
}
|
|
|
|
static void AddStructDeclaration(
|
|
LLVMTypeRef wStructType,
|
|
LLVMTypeRef wStructPointerType,
|
|
char *name,
|
|
Node **fieldDeclarations,
|
|
uint32_t fieldDeclarationCount)
|
|
{
|
|
uint32_t i;
|
|
uint32_t index = structTypeDeclarationCount;
|
|
structTypeDeclarations = realloc(
|
|
structTypeDeclarations,
|
|
sizeof(StructTypeDeclaration) * (structTypeDeclarationCount + 1));
|
|
structTypeDeclarations[index].structType = wStructType;
|
|
structTypeDeclarations[index].structPointerType = wStructPointerType;
|
|
structTypeDeclarations[index].name = strdup(name);
|
|
structTypeDeclarations[index].fields = NULL;
|
|
structTypeDeclarations[index].fieldCount = 0;
|
|
structTypeDeclarations[index].functions = NULL;
|
|
structTypeDeclarations[index].functionCount = 0;
|
|
structTypeDeclarations[index].genericFunctions = NULL;
|
|
structTypeDeclarations[index].genericFunctionCount = 0;
|
|
|
|
for (i = 0; i < fieldDeclarationCount; i += 1)
|
|
{
|
|
structTypeDeclarations[index].fields = realloc(
|
|
structTypeDeclarations[index].fields,
|
|
sizeof(StructTypeField) *
|
|
(structTypeDeclarations[index].fieldCount + 1));
|
|
structTypeDeclarations[index].fields[i].name = strdup(
|
|
fieldDeclarations[i]->declaration.identifier->identifier.name);
|
|
structTypeDeclarations[index].fields[i].index = i;
|
|
structTypeDeclarations[index].fieldCount += 1;
|
|
}
|
|
|
|
structTypeDeclarationCount += 1;
|
|
}
|
|
|
|
/* FIXME: pass the declaration itself */
|
|
static void DeclareStructFunction(
|
|
LLVMTypeRef wStructPointerType,
|
|
LLVMValueRef function,
|
|
LLVMTypeRef returnType,
|
|
uint8_t isStatic,
|
|
char *name)
|
|
{
|
|
uint32_t i, index;
|
|
|
|
for (i = 0; i < structTypeDeclarationCount; i += 1)
|
|
{
|
|
if (structTypeDeclarations[i].structPointerType == wStructPointerType)
|
|
{
|
|
index = structTypeDeclarations[i].functionCount;
|
|
structTypeDeclarations[i].functions = realloc(
|
|
structTypeDeclarations[i].functions,
|
|
sizeof(StructTypeFunction) *
|
|
(structTypeDeclarations[i].functionCount + 1));
|
|
structTypeDeclarations[i].functions[index].name = strdup(name);
|
|
structTypeDeclarations[i].functions[index].function = function;
|
|
structTypeDeclarations[i].functions[index].returnType = returnType;
|
|
structTypeDeclarations[i].functions[index].isStatic = isStatic;
|
|
structTypeDeclarations[i].functionCount += 1;
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
fprintf(stderr, "Could not find struct type for function!\n");
|
|
}
|
|
|
|
/* FIXME: pass the declaration itself */
|
|
static void DeclareGenericStructFunction(
|
|
LLVMTypeRef wStructPointerType,
|
|
Node *functionDeclarationNode,
|
|
uint8_t isStatic,
|
|
char *parentStructName,
|
|
char *name)
|
|
{
|
|
uint32_t i, j, index;
|
|
|
|
for (i = 0; i < structTypeDeclarationCount; i += 1)
|
|
{
|
|
if (structTypeDeclarations[i].structPointerType == wStructPointerType)
|
|
{
|
|
index = structTypeDeclarations[i].genericFunctionCount;
|
|
structTypeDeclarations[i].genericFunctions = realloc(
|
|
structTypeDeclarations[i].genericFunctions,
|
|
sizeof(StructTypeGenericFunction) *
|
|
(structTypeDeclarations[i].genericFunctionCount + 1));
|
|
structTypeDeclarations[i].genericFunctions[index].name =
|
|
strdup(name);
|
|
structTypeDeclarations[i].genericFunctions[index].parentStructName =
|
|
parentStructName;
|
|
structTypeDeclarations[i].structPointerType = wStructPointerType;
|
|
structTypeDeclarations[i]
|
|
.genericFunctions[index]
|
|
.functionDeclarationNode = functionDeclarationNode;
|
|
structTypeDeclarations[i].genericFunctions[index].isStatic =
|
|
isStatic;
|
|
|
|
for (j = 0; j < NUM_MONOMORPHIZED_HASH_BUCKETS; j += 1)
|
|
{
|
|
structTypeDeclarations[i]
|
|
.genericFunctions[index]
|
|
.monomorphizedFunctions[j]
|
|
.elements = NULL;
|
|
structTypeDeclarations[i]
|
|
.genericFunctions[index]
|
|
.monomorphizedFunctions[j]
|
|
.count = 0;
|
|
}
|
|
|
|
structTypeDeclarations[i].genericFunctionCount += 1;
|
|
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
static inline uint64_t HashTypeTags(TypeTag **tags, uint32_t count)
|
|
{
|
|
const uint64_t HASH_FACTOR = 97;
|
|
uint64_t result = 1;
|
|
uint32_t i;
|
|
|
|
for (i = 0; i < count; i += 1)
|
|
{
|
|
result *= HASH_FACTOR + str_hash(TypeTagToString(tags[i]));
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/* FIXME: lots of duplication with non-generic function compile */
|
|
static StructTypeFunction CompileGenericFunction(
|
|
LLVMModuleRef module,
|
|
char *parentStructName,
|
|
LLVMTypeRef wStructPointerType,
|
|
TypeTag **resolvedGenericArgumentTypes,
|
|
uint32_t genericArgumentTypeCount,
|
|
Node *functionDeclaration)
|
|
{
|
|
uint32_t i;
|
|
uint8_t hasReturn = 0;
|
|
uint8_t isStatic = 0;
|
|
Node *functionSignature =
|
|
functionDeclaration->functionDeclaration.functionSignature;
|
|
Node *functionBody = functionDeclaration->functionDeclaration.functionBody;
|
|
uint32_t argumentCount = functionSignature->functionSignature.arguments
|
|
->functionSignatureArguments.count;
|
|
LLVMTypeRef paramTypes[argumentCount + 1];
|
|
uint32_t paramIndex = 0;
|
|
LLVMTypeRef returnType;
|
|
|
|
PushScopeFrame(scope);
|
|
|
|
for (i = 0; i < genericArgumentTypeCount; i += 1)
|
|
{
|
|
AddGenericVariable(
|
|
scope,
|
|
resolvedGenericArgumentTypes[i],
|
|
functionDeclaration->functionDeclaration.functionSignature
|
|
->functionSignature.genericArguments->genericArguments
|
|
.arguments[i]
|
|
->genericArgument.identifier->identifier.name);
|
|
}
|
|
|
|
if (functionSignature->functionSignature.modifiers->functionModifiers
|
|
.count > 0)
|
|
{
|
|
for (i = 0; i < functionSignature->functionSignature.modifiers
|
|
->functionModifiers.count;
|
|
i += 1)
|
|
{
|
|
if (functionSignature->functionSignature.modifiers
|
|
->functionModifiers.sequence[i]
|
|
->syntaxKind == StaticModifier)
|
|
{
|
|
isStatic = 1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
char *functionName = strdup(parentStructName);
|
|
strcat(functionName, "_");
|
|
strcat(
|
|
functionName,
|
|
functionSignature->functionSignature.identifier->identifier.name);
|
|
|
|
for (i = 0; i < genericArgumentTypeCount; i += 1)
|
|
{
|
|
strcat(functionName, TypeTagToString(resolvedGenericArgumentTypes[i]));
|
|
}
|
|
|
|
if (!isStatic)
|
|
{
|
|
paramTypes[paramIndex] = wStructPointerType;
|
|
paramIndex += 1;
|
|
}
|
|
|
|
for (i = 0; i < functionSignature->functionSignature.arguments
|
|
->functionSignatureArguments.count;
|
|
i += 1)
|
|
{
|
|
paramTypes[paramIndex] =
|
|
ResolveType(functionSignature->functionSignature.arguments
|
|
->functionSignatureArguments.sequence[i]
|
|
->declaration.identifier->typeTag);
|
|
|
|
paramIndex += 1;
|
|
}
|
|
|
|
returnType =
|
|
ResolveType(functionSignature->functionSignature.identifier->typeTag);
|
|
|
|
LLVMTypeRef functionType =
|
|
LLVMFunctionType(returnType, paramTypes, paramIndex, 0);
|
|
|
|
LLVMValueRef function = LLVMAddFunction(module, functionName, functionType);
|
|
|
|
LLVMBasicBlockRef entry = LLVMAppendBasicBlock(function, "entry");
|
|
LLVMBuilderRef builder = LLVMCreateBuilder();
|
|
LLVMPositionBuilderAtEnd(builder, entry);
|
|
|
|
if (!isStatic)
|
|
{
|
|
LLVMValueRef wStructPointer = LLVMGetParam(function, 0);
|
|
AddStructVariablesToScope(builder, wStructPointer);
|
|
}
|
|
|
|
for (i = 0; i < functionSignature->functionSignature.arguments
|
|
->functionSignatureArguments.count;
|
|
i += 1)
|
|
{
|
|
char *ptrName = strdup(functionSignature->functionSignature.arguments
|
|
->functionSignatureArguments.sequence[i]
|
|
->declaration.identifier->identifier.name);
|
|
strcat(ptrName, "_ptr");
|
|
LLVMValueRef argument = LLVMGetParam(function, i + !isStatic);
|
|
LLVMValueRef argumentCopy =
|
|
LLVMBuildAlloca(builder, LLVMTypeOf(argument), ptrName);
|
|
LLVMBuildStore(builder, argument, argumentCopy);
|
|
free(ptrName);
|
|
AddLocalVariable(
|
|
scope,
|
|
argumentCopy,
|
|
NULL,
|
|
functionSignature->functionSignature.arguments
|
|
->functionSignatureArguments.sequence[i]
|
|
->declaration.identifier->identifier.name);
|
|
}
|
|
|
|
for (i = 0; i < functionBody->statementSequence.count; i += 1)
|
|
{
|
|
CompileStatement(
|
|
module,
|
|
builder,
|
|
function,
|
|
functionBody->statementSequence.sequence[i]);
|
|
}
|
|
|
|
hasReturn =
|
|
LLVMGetBasicBlockTerminator(LLVMGetLastBasicBlock(function)) != NULL;
|
|
|
|
if (LLVMGetTypeKind(returnType) == LLVMVoidTypeKind && !hasReturn)
|
|
{
|
|
LLVMBuildRetVoid(builder);
|
|
}
|
|
else if (LLVMGetTypeKind(returnType) != LLVMVoidTypeKind && !hasReturn)
|
|
{
|
|
fprintf(stderr, "Return statement not provided!");
|
|
}
|
|
|
|
LLVMDisposeBuilder(builder);
|
|
PopScopeFrame(scope);
|
|
free(functionName);
|
|
|
|
StructTypeFunction structTypeFunction;
|
|
structTypeFunction.name = strdup(
|
|
functionSignature->functionSignature.identifier->identifier.name);
|
|
structTypeFunction.function = function;
|
|
structTypeFunction.returnType = returnType;
|
|
structTypeFunction.isStatic = isStatic;
|
|
|
|
return structTypeFunction;
|
|
}
|
|
|
|
static LLVMValueRef LookupGenericFunction(
|
|
LLVMModuleRef module,
|
|
StructTypeGenericFunction *genericFunction,
|
|
TypeTag **argumentTypes,
|
|
uint32_t argumentCount,
|
|
LLVMTypeRef *pReturnType,
|
|
uint8_t *pStatic)
|
|
{
|
|
uint32_t i, j;
|
|
uint64_t typeHash;
|
|
uint8_t match = 0;
|
|
uint32_t genericArgumentTypeCount =
|
|
genericFunction->functionDeclarationNode->functionDeclaration
|
|
.functionSignature->functionSignature.genericArguments
|
|
->genericArguments.count;
|
|
TypeTag *resolvedGenericArgumentTypes[genericArgumentTypeCount];
|
|
|
|
for (i = 0; i < genericArgumentTypeCount; i += 1)
|
|
{
|
|
for (j = 0;
|
|
j < genericFunction->functionDeclarationNode->functionDeclaration
|
|
.functionSignature->functionSignature.arguments
|
|
->functionSignatureArguments.count;
|
|
j += 1)
|
|
{
|
|
if (genericFunction->functionDeclarationNode->functionDeclaration
|
|
.functionSignature->functionSignature.arguments
|
|
->functionSignatureArguments.sequence[j]
|
|
->declaration.identifier->typeTag->type == Generic &&
|
|
strcmp(
|
|
genericFunction->functionDeclarationNode
|
|
->functionDeclaration.functionSignature
|
|
->functionSignature.arguments
|
|
->functionSignatureArguments.sequence[j]
|
|
->declaration.identifier->typeTag->value.genericType,
|
|
genericFunction->functionDeclarationNode
|
|
->functionDeclaration.functionSignature
|
|
->functionSignature.genericArguments->genericArguments
|
|
.arguments[i]
|
|
->genericArgument.identifier->identifier.name) == 0)
|
|
{
|
|
resolvedGenericArgumentTypes[i] = argumentTypes[j];
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Concretize generics if we are compiling nested generic functions */
|
|
for (i = 0; i < genericArgumentTypeCount; i += 1)
|
|
{
|
|
if (resolvedGenericArgumentTypes[i]->type == Generic)
|
|
{
|
|
resolvedGenericArgumentTypes[i] =
|
|
LookupGenericType(
|
|
resolvedGenericArgumentTypes[i]->value.genericType)
|
|
->concreteTypeTag;
|
|
}
|
|
}
|
|
|
|
typeHash =
|
|
HashTypeTags(resolvedGenericArgumentTypes, genericArgumentTypeCount);
|
|
|
|
MonomorphizedGenericFunctionHashArray *hashArray =
|
|
&genericFunction->monomorphizedFunctions
|
|
[typeHash % NUM_MONOMORPHIZED_HASH_BUCKETS];
|
|
|
|
MonomorphizedGenericFunctionHashEntry *hashEntry = NULL;
|
|
for (i = 0; i < hashArray->count; i += 1)
|
|
{
|
|
match = 1;
|
|
|
|
for (j = 0; j < hashArray->elements[i].typeCount; j += 1)
|
|
{
|
|
if (hashArray->elements[i].types[j] !=
|
|
resolvedGenericArgumentTypes[j])
|
|
{
|
|
match = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (match)
|
|
{
|
|
hashEntry = &hashArray->elements[i];
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (hashEntry == NULL)
|
|
{
|
|
StructTypeFunction function = CompileGenericFunction(
|
|
module,
|
|
genericFunction->parentStructName,
|
|
genericFunction->parentStructPointerType,
|
|
resolvedGenericArgumentTypes,
|
|
genericArgumentTypeCount,
|
|
genericFunction->functionDeclarationNode);
|
|
|
|
/* TODO: add to hash */
|
|
hashArray->elements = realloc(
|
|
hashArray->elements,
|
|
sizeof(MonomorphizedGenericFunctionHashEntry) *
|
|
(hashArray->count + 1));
|
|
hashArray->elements[hashArray->count].key = typeHash;
|
|
hashArray->elements[hashArray->count].types =
|
|
malloc(sizeof(TypeTag *) * genericArgumentTypeCount);
|
|
hashArray->elements[hashArray->count].typeCount =
|
|
genericArgumentTypeCount;
|
|
hashArray->elements[hashArray->count].function = function;
|
|
for (i = 0; i < genericArgumentTypeCount; i += 1)
|
|
{
|
|
hashArray->elements[hashArray->count].types[i] =
|
|
resolvedGenericArgumentTypes[i];
|
|
}
|
|
hashArray->count += 1;
|
|
|
|
hashEntry = &hashArray->elements[hashArray->count - 1];
|
|
}
|
|
|
|
*pReturnType = hashEntry->function.returnType;
|
|
*pStatic = genericFunction->isStatic;
|
|
|
|
return hashEntry->function.function;
|
|
}
|
|
|
|
static LLVMValueRef LookupFunctionByType(
|
|
LLVMModuleRef module,
|
|
LLVMTypeRef structType,
|
|
char *name,
|
|
TypeTag **argumentTypes,
|
|
uint32_t argumentCount,
|
|
LLVMTypeRef *pReturnType,
|
|
uint8_t *pStatic)
|
|
{
|
|
uint32_t i, j;
|
|
|
|
for (i = 0; i < structTypeDeclarationCount; i += 1)
|
|
{
|
|
if (structTypeDeclarations[i].structType == structType)
|
|
{
|
|
for (j = 0; j < structTypeDeclarations[i].functionCount; j += 1)
|
|
{
|
|
if (strcmp(structTypeDeclarations[i].functions[j].name, name) ==
|
|
0)
|
|
{
|
|
*pReturnType =
|
|
structTypeDeclarations[i].functions[j].returnType;
|
|
*pStatic = structTypeDeclarations[i].functions[j].isStatic;
|
|
return structTypeDeclarations[i].functions[j].function;
|
|
}
|
|
}
|
|
|
|
for (j = 0; j < structTypeDeclarations[i].genericFunctionCount;
|
|
j += 1)
|
|
{
|
|
if (strcmp(
|
|
structTypeDeclarations[i].genericFunctions[j].name,
|
|
name) == 0)
|
|
{
|
|
return LookupGenericFunction(
|
|
module,
|
|
&structTypeDeclarations[i].genericFunctions[j],
|
|
argumentTypes,
|
|
argumentCount,
|
|
pReturnType,
|
|
pStatic);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
fprintf(stderr, "Could not find struct function!\n");
|
|
return NULL;
|
|
}
|
|
|
|
static LLVMValueRef LookupFunctionByPointerType(
|
|
LLVMModuleRef module,
|
|
LLVMTypeRef structPointerType,
|
|
char *name,
|
|
TypeTag **argumentTypes,
|
|
uint32_t argumentCount,
|
|
LLVMTypeRef *pReturnType,
|
|
uint8_t *pStatic)
|
|
{
|
|
uint32_t i, j;
|
|
|
|
for (i = 0; i < structTypeDeclarationCount; i += 1)
|
|
{
|
|
if (structTypeDeclarations[i].structPointerType == structPointerType)
|
|
{
|
|
for (j = 0; j < structTypeDeclarations[i].functionCount; j += 1)
|
|
{
|
|
if (strcmp(structTypeDeclarations[i].functions[j].name, name) ==
|
|
0)
|
|
{
|
|
*pReturnType =
|
|
structTypeDeclarations[i].functions[j].returnType;
|
|
*pStatic = structTypeDeclarations[i].functions[j].isStatic;
|
|
return structTypeDeclarations[i].functions[j].function;
|
|
}
|
|
}
|
|
|
|
for (j = 0; j < structTypeDeclarations[i].genericFunctionCount;
|
|
j += 1)
|
|
{
|
|
if (strcmp(
|
|
structTypeDeclarations[i].genericFunctions[j].name,
|
|
name) == 0)
|
|
{
|
|
return LookupGenericFunction(
|
|
module,
|
|
&structTypeDeclarations[i].genericFunctions[j],
|
|
argumentTypes,
|
|
argumentCount,
|
|
pReturnType,
|
|
pStatic);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
fprintf(stderr, "Could not find struct function!\n");
|
|
return NULL;
|
|
}
|
|
|
|
static LLVMValueRef LookupFunctionByInstance(
|
|
LLVMModuleRef module,
|
|
LLVMValueRef structPointer,
|
|
char *name,
|
|
TypeTag **argumentTypes,
|
|
uint32_t argumentCount,
|
|
LLVMTypeRef *pReturnType,
|
|
uint8_t *pStatic)
|
|
{
|
|
return LookupFunctionByPointerType(
|
|
module,
|
|
LLVMTypeOf(structPointer),
|
|
name,
|
|
argumentTypes,
|
|
argumentCount,
|
|
pReturnType,
|
|
pStatic);
|
|
}
|
|
|
|
static LLVMValueRef CompileNumber(Node *numberExpression)
|
|
{
|
|
return LLVMConstInt(LLVMInt64Type(), numberExpression->number.value, 0);
|
|
}
|
|
|
|
static LLVMValueRef CompileString(
|
|
LLVMBuilderRef builder,
|
|
Node *stringExpression)
|
|
{
|
|
return LLVMBuildGlobalStringPtr(
|
|
builder,
|
|
stringExpression->stringLiteral.string,
|
|
"stringConstant");
|
|
}
|
|
|
|
static LLVMValueRef CompileBinaryExpression(
|
|
LLVMModuleRef module,
|
|
LLVMBuilderRef builder,
|
|
Node *binaryExpression)
|
|
{
|
|
LLVMValueRef left = CompileExpression(
|
|
module,
|
|
builder,
|
|
binaryExpression->binaryExpression.left);
|
|
|
|
LLVMValueRef right = CompileExpression(
|
|
module,
|
|
builder,
|
|
binaryExpression->binaryExpression.right);
|
|
|
|
switch (binaryExpression->binaryExpression.operator)
|
|
{
|
|
case Add:
|
|
return LLVMBuildAdd(builder, left, right, "addResult");
|
|
|
|
case Subtract:
|
|
return LLVMBuildSub(builder, left, right, "subtractResult");
|
|
|
|
case Multiply:
|
|
return LLVMBuildMul(builder, left, right, "multiplyResult");
|
|
|
|
/* FIXME: need type information for comparison */
|
|
case LessThan:
|
|
return LLVMBuildICmp(
|
|
builder,
|
|
LLVMIntSLT,
|
|
left,
|
|
right,
|
|
"lessThanResult");
|
|
|
|
case GreaterThan:
|
|
return LLVMBuildICmp(
|
|
builder,
|
|
LLVMIntSGT,
|
|
left,
|
|
right,
|
|
"greaterThanResult");
|
|
|
|
case Mod:
|
|
return LLVMBuildSRem(builder, left, right, "modResult");
|
|
|
|
case Equal:
|
|
return LLVMBuildICmp(builder, LLVMIntEQ, left, right, "equalResult");
|
|
|
|
case LogicalOr:
|
|
return LLVMBuildOr(builder, left, right, "orResult");
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/* FIXME THIS IS ALL BROKEN */
|
|
static LLVMValueRef CompileFunctionCallExpression(
|
|
LLVMModuleRef module,
|
|
LLVMBuilderRef builder,
|
|
Node *functionCallExpression)
|
|
{
|
|
uint32_t i;
|
|
uint32_t argumentCount = 0;
|
|
LLVMValueRef args
|
|
[functionCallExpression->functionCallExpression.argumentSequence
|
|
->functionArgumentSequence.count +
|
|
1];
|
|
TypeTag
|
|
*argumentTypes[functionCallExpression->functionCallExpression
|
|
.argumentSequence->functionArgumentSequence.count];
|
|
LLVMValueRef function;
|
|
uint8_t isStatic;
|
|
LLVMValueRef structInstance;
|
|
LLVMTypeRef functionReturnType;
|
|
char *returnName = "";
|
|
|
|
for (i = 0; i < functionCallExpression->functionCallExpression
|
|
.argumentSequence->functionArgumentSequence.count;
|
|
i += 1)
|
|
{
|
|
argumentTypes[i] =
|
|
functionCallExpression->functionCallExpression.argumentSequence
|
|
->functionArgumentSequence.sequence[i]
|
|
->typeTag;
|
|
|
|
argumentCount += 1;
|
|
}
|
|
|
|
/* FIXME: this needs to be recursive on access chains */
|
|
/* FIXME: this needs to be able to call same-struct functions implicitly
|
|
*/
|
|
if (functionCallExpression->functionCallExpression.identifier->syntaxKind ==
|
|
AccessExpression)
|
|
{
|
|
LLVMTypeRef typeReference = FindStructType(
|
|
functionCallExpression->functionCallExpression.identifier
|
|
->accessExpression.accessee->identifier.name);
|
|
|
|
if (typeReference != NULL)
|
|
{
|
|
function = LookupFunctionByType(
|
|
module,
|
|
typeReference,
|
|
functionCallExpression->functionCallExpression.identifier
|
|
->accessExpression.accessor->identifier.name,
|
|
argumentTypes,
|
|
argumentCount,
|
|
&functionReturnType,
|
|
&isStatic);
|
|
}
|
|
else
|
|
{
|
|
structInstance = FindVariablePointer(
|
|
functionCallExpression->functionCallExpression.identifier
|
|
->accessExpression.accessee->identifier.name);
|
|
function = LookupFunctionByInstance(
|
|
module,
|
|
structInstance,
|
|
functionCallExpression->functionCallExpression.identifier
|
|
->accessExpression.accessor->identifier.name,
|
|
argumentTypes,
|
|
argumentCount,
|
|
&functionReturnType,
|
|
&isStatic);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
fprintf(stderr, "Failed to find function!\n");
|
|
return NULL;
|
|
}
|
|
|
|
argumentCount = 0;
|
|
|
|
if (!isStatic)
|
|
{
|
|
args[argumentCount] = structInstance;
|
|
argumentCount += 1;
|
|
}
|
|
|
|
for (i = 0; i < functionCallExpression->functionCallExpression
|
|
.argumentSequence->functionArgumentSequence.count;
|
|
i += 1)
|
|
{
|
|
args[argumentCount] = CompileExpression(
|
|
module,
|
|
builder,
|
|
functionCallExpression->functionCallExpression.argumentSequence
|
|
->functionArgumentSequence.sequence[i]);
|
|
argumentCount += 1;
|
|
}
|
|
|
|
if (LLVMGetTypeKind(functionReturnType) != LLVMVoidTypeKind)
|
|
{
|
|
returnName = "callReturn";
|
|
}
|
|
|
|
return LLVMBuildCall(builder, function, args, argumentCount, returnName);
|
|
}
|
|
|
|
static LLVMValueRef CompileAccessExpressionForStore(
|
|
LLVMBuilderRef builder,
|
|
Node *accessExpression)
|
|
{
|
|
LLVMValueRef accesseeValue = FindVariablePointer(
|
|
accessExpression->accessExpression.accessee->identifier.name);
|
|
return FindStructFieldPointer(
|
|
builder,
|
|
accesseeValue,
|
|
accessExpression->accessExpression.accessor->identifier.name);
|
|
}
|
|
|
|
static LLVMValueRef CompileAccessExpression(
|
|
LLVMBuilderRef builder,
|
|
Node *accessExpression)
|
|
{
|
|
LLVMValueRef accesseeValue = FindVariablePointer(
|
|
accessExpression->accessExpression.accessee->identifier.name);
|
|
LLVMValueRef access = FindStructFieldPointer(
|
|
builder,
|
|
accesseeValue,
|
|
accessExpression->accessExpression.accessor->identifier.name);
|
|
return LLVMBuildLoad(
|
|
builder,
|
|
access,
|
|
accessExpression->accessExpression.accessor->identifier.name);
|
|
}
|
|
|
|
static LLVMValueRef CompileAllocExpression(
|
|
LLVMBuilderRef builder,
|
|
Node *allocExpression)
|
|
{
|
|
LLVMTypeRef type = ResolveType(allocExpression->typeTag);
|
|
return LLVMBuildMalloc(builder, type, "allocation");
|
|
}
|
|
|
|
static LLVMValueRef CompileExpression(
|
|
LLVMModuleRef module,
|
|
LLVMBuilderRef builder,
|
|
Node *expression)
|
|
{
|
|
switch (expression->syntaxKind)
|
|
{
|
|
case AccessExpression:
|
|
return CompileAccessExpression(builder, expression);
|
|
|
|
case AllocExpression:
|
|
return CompileAllocExpression(builder, expression);
|
|
|
|
case BinaryExpression:
|
|
return CompileBinaryExpression(module, builder, expression);
|
|
|
|
case FunctionCallExpression:
|
|
return CompileFunctionCallExpression(module, builder, expression);
|
|
|
|
case Identifier:
|
|
return FindVariableValue(builder, expression->identifier.name);
|
|
|
|
case Number:
|
|
return CompileNumber(expression);
|
|
|
|
case StringLiteral:
|
|
return CompileString(builder, expression);
|
|
}
|
|
|
|
fprintf(stderr, "Unknown expression kind!\n");
|
|
return NULL;
|
|
}
|
|
|
|
static LLVMBasicBlockRef CompileReturn(
|
|
LLVMModuleRef module,
|
|
LLVMBuilderRef builder,
|
|
LLVMValueRef function,
|
|
Node *returnStatemement)
|
|
{
|
|
LLVMValueRef expression = CompileExpression(
|
|
module,
|
|
builder,
|
|
returnStatemement->returnStatement.expression);
|
|
LLVMBuildRet(builder, expression);
|
|
return LLVMGetLastBasicBlock(function);
|
|
}
|
|
|
|
static LLVMBasicBlockRef CompileReturnVoid(
|
|
LLVMBuilderRef builder,
|
|
LLVMValueRef function)
|
|
{
|
|
LLVMBuildRetVoid(builder);
|
|
return LLVMGetLastBasicBlock(function);
|
|
}
|
|
|
|
/* FIXME: path for reference types */
|
|
static LLVMValueRef CompileFunctionVariableDeclaration(
|
|
LLVMBuilderRef builder,
|
|
LLVMValueRef function,
|
|
Node *variableDeclaration)
|
|
{
|
|
LLVMValueRef variable;
|
|
char *variableName =
|
|
variableDeclaration->declaration.identifier->identifier.name;
|
|
char *ptrName = strdup(variableName);
|
|
strcat(ptrName, "_ptr");
|
|
|
|
variable = LLVMBuildAlloca(
|
|
builder,
|
|
ResolveType(variableDeclaration->declaration.identifier->typeTag),
|
|
ptrName);
|
|
|
|
free(ptrName);
|
|
|
|
AddLocalVariable(scope, variable, NULL, variableName);
|
|
|
|
return variable;
|
|
}
|
|
|
|
static LLVMBasicBlockRef CompileAssignment(
|
|
LLVMModuleRef module,
|
|
LLVMBuilderRef builder,
|
|
LLVMValueRef function,
|
|
Node *assignmentStatement)
|
|
{
|
|
LLVMValueRef result = CompileExpression(
|
|
module,
|
|
builder,
|
|
assignmentStatement->assignmentStatement.right);
|
|
LLVMValueRef identifier;
|
|
if (assignmentStatement->assignmentStatement.left->syntaxKind ==
|
|
AccessExpression)
|
|
{
|
|
identifier = CompileAccessExpressionForStore(
|
|
builder,
|
|
assignmentStatement->assignmentStatement.left);
|
|
}
|
|
else if (
|
|
assignmentStatement->assignmentStatement.left->syntaxKind == Identifier)
|
|
{
|
|
identifier = FindVariablePointer(
|
|
assignmentStatement->assignmentStatement.left->identifier.name);
|
|
}
|
|
else if (
|
|
assignmentStatement->assignmentStatement.left->syntaxKind ==
|
|
Declaration)
|
|
{
|
|
identifier = CompileFunctionVariableDeclaration(
|
|
builder,
|
|
function,
|
|
assignmentStatement->assignmentStatement.left);
|
|
}
|
|
else
|
|
{
|
|
printf("Identifier not found!");
|
|
return LLVMGetLastBasicBlock(function);
|
|
}
|
|
|
|
LLVMBuildStore(builder, result, identifier);
|
|
|
|
return LLVMGetLastBasicBlock(function);
|
|
}
|
|
|
|
static LLVMBasicBlockRef CompileIfStatement(
|
|
LLVMModuleRef module,
|
|
LLVMBuilderRef builder,
|
|
LLVMValueRef function,
|
|
Node *ifStatement)
|
|
{
|
|
uint32_t i;
|
|
LLVMValueRef conditional =
|
|
CompileExpression(module, builder, ifStatement->ifStatement.expression);
|
|
|
|
LLVMBasicBlockRef block = LLVMAppendBasicBlock(function, "ifBlock");
|
|
LLVMBasicBlockRef afterCond = LLVMAppendBasicBlock(function, "afterCond");
|
|
|
|
LLVMBuildCondBr(builder, conditional, block, afterCond);
|
|
|
|
LLVMPositionBuilderAtEnd(builder, block);
|
|
|
|
for (i = 0;
|
|
i <
|
|
ifStatement->ifStatement.statementSequence->statementSequence.count;
|
|
i += 1)
|
|
{
|
|
CompileStatement(
|
|
module,
|
|
builder,
|
|
function,
|
|
ifStatement->ifStatement.statementSequence->statementSequence
|
|
.sequence[i]);
|
|
}
|
|
|
|
LLVMBuildBr(builder, afterCond);
|
|
LLVMPositionBuilderAtEnd(builder, afterCond);
|
|
|
|
return afterCond;
|
|
}
|
|
|
|
static LLVMBasicBlockRef CompileIfElseStatement(
|
|
LLVMModuleRef module,
|
|
LLVMBuilderRef builder,
|
|
LLVMValueRef function,
|
|
Node *ifElseStatement)
|
|
{
|
|
uint32_t i;
|
|
LLVMValueRef conditional = CompileExpression(
|
|
module,
|
|
builder,
|
|
ifElseStatement->ifElseStatement.ifStatement->ifStatement.expression);
|
|
|
|
LLVMBasicBlockRef ifBlock = LLVMAppendBasicBlock(function, "ifBlock");
|
|
LLVMBasicBlockRef elseBlock = LLVMAppendBasicBlock(function, "elseBlock");
|
|
LLVMBasicBlockRef afterCond = LLVMAppendBasicBlock(function, "afterCond");
|
|
|
|
LLVMBuildCondBr(builder, conditional, ifBlock, elseBlock);
|
|
|
|
LLVMPositionBuilderAtEnd(builder, ifBlock);
|
|
|
|
for (i = 0; i < ifElseStatement->ifElseStatement.ifStatement->ifStatement
|
|
.statementSequence->statementSequence.count;
|
|
i += 1)
|
|
{
|
|
CompileStatement(
|
|
module,
|
|
builder,
|
|
function,
|
|
ifElseStatement->ifElseStatement.ifStatement->ifStatement
|
|
.statementSequence->statementSequence.sequence[i]);
|
|
}
|
|
|
|
LLVMBuildBr(builder, afterCond);
|
|
|
|
LLVMPositionBuilderAtEnd(builder, elseBlock);
|
|
|
|
if (ifElseStatement->ifElseStatement.elseStatement->syntaxKind ==
|
|
StatementSequence)
|
|
{
|
|
for (i = 0; i < ifElseStatement->ifElseStatement.elseStatement
|
|
->statementSequence.count;
|
|
i += 1)
|
|
{
|
|
CompileStatement(
|
|
module,
|
|
builder,
|
|
function,
|
|
ifElseStatement->ifElseStatement.elseStatement
|
|
->statementSequence.sequence[i]);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CompileStatement(
|
|
module,
|
|
builder,
|
|
function,
|
|
ifElseStatement->ifElseStatement.elseStatement);
|
|
}
|
|
|
|
LLVMBuildBr(builder, afterCond);
|
|
LLVMPositionBuilderAtEnd(builder, afterCond);
|
|
|
|
return afterCond;
|
|
}
|
|
|
|
static LLVMBasicBlockRef CompileForLoopStatement(
|
|
LLVMModuleRef module,
|
|
LLVMBuilderRef builder,
|
|
LLVMValueRef function,
|
|
Node *forLoopStatement)
|
|
{
|
|
uint32_t i;
|
|
LLVMBasicBlockRef entryBlock = LLVMAppendBasicBlock(function, "loopEntry");
|
|
LLVMBasicBlockRef checkBlock = LLVMAppendBasicBlock(function, "loopCheck");
|
|
LLVMBasicBlockRef bodyBlock = LLVMAppendBasicBlock(function, "loopBody");
|
|
LLVMBasicBlockRef afterLoopBlock =
|
|
LLVMAppendBasicBlock(function, "afterLoop");
|
|
char *iteratorVariableName = forLoopStatement->forLoop.declaration
|
|
->declaration.identifier->identifier.name;
|
|
LLVMTypeRef iteratorVariableType = ResolveType(
|
|
forLoopStatement->forLoop.declaration->declaration.identifier->typeTag);
|
|
|
|
PushScopeFrame(scope);
|
|
|
|
LLVMBuildBr(builder, entryBlock);
|
|
|
|
LLVMPositionBuilderAtEnd(builder, entryBlock);
|
|
LLVMBuildBr(builder, checkBlock);
|
|
|
|
LLVMPositionBuilderAtEnd(builder, checkBlock);
|
|
LLVMValueRef iteratorValue =
|
|
LLVMBuildPhi(builder, iteratorVariableType, iteratorVariableName);
|
|
AddLocalVariable(scope, NULL, iteratorValue, iteratorVariableName);
|
|
|
|
LLVMPositionBuilderAtEnd(builder, bodyBlock);
|
|
LLVMValueRef nextValue = LLVMBuildAdd(
|
|
builder,
|
|
iteratorValue,
|
|
LLVMConstInt(
|
|
iteratorVariableType,
|
|
1,
|
|
0), /* FIXME: add custom increment value */
|
|
"next");
|
|
|
|
LLVMPositionBuilderAtEnd(builder, checkBlock);
|
|
|
|
LLVMValueRef iteratorEndValue =
|
|
CompileNumber(forLoopStatement->forLoop.endNumber);
|
|
LLVMValueRef comparison = LLVMBuildICmp(
|
|
builder,
|
|
LLVMIntULE,
|
|
iteratorValue,
|
|
iteratorEndValue,
|
|
"iteratorCompare");
|
|
|
|
LLVMBuildCondBr(builder, comparison, bodyBlock, afterLoopBlock);
|
|
|
|
LLVMPositionBuilderAtEnd(builder, bodyBlock);
|
|
|
|
LLVMBasicBlockRef lastBlock;
|
|
for (i = 0;
|
|
i <
|
|
forLoopStatement->forLoop.statementSequence->statementSequence.count;
|
|
i += 1)
|
|
{
|
|
lastBlock = CompileStatement(
|
|
module,
|
|
builder,
|
|
function,
|
|
forLoopStatement->forLoop.statementSequence->statementSequence
|
|
.sequence[i]);
|
|
}
|
|
|
|
LLVMBuildBr(builder, checkBlock);
|
|
|
|
LLVMPositionBuilderBefore(builder, LLVMGetFirstInstruction(checkBlock));
|
|
|
|
LLVMValueRef incomingValues[2];
|
|
incomingValues[0] = CompileNumber(forLoopStatement->forLoop.startNumber);
|
|
incomingValues[1] = nextValue;
|
|
|
|
LLVMBasicBlockRef incomingBlocks[2];
|
|
incomingBlocks[0] = entryBlock;
|
|
incomingBlocks[1] = lastBlock;
|
|
|
|
LLVMAddIncoming(iteratorValue, incomingValues, incomingBlocks, 2);
|
|
|
|
LLVMPositionBuilderAtEnd(builder, afterLoopBlock);
|
|
|
|
PopScopeFrame(scope);
|
|
|
|
return afterLoopBlock;
|
|
}
|
|
|
|
static LLVMBasicBlockRef CompileStatement(
|
|
LLVMModuleRef module,
|
|
LLVMBuilderRef builder,
|
|
LLVMValueRef function,
|
|
Node *statement)
|
|
{
|
|
switch (statement->syntaxKind)
|
|
{
|
|
case Assignment:
|
|
return CompileAssignment(module, builder, function, statement);
|
|
|
|
case Declaration:
|
|
CompileFunctionVariableDeclaration(builder, function, statement);
|
|
return LLVMGetLastBasicBlock(function);
|
|
|
|
case ForLoop:
|
|
return CompileForLoopStatement(module, builder, function, statement);
|
|
|
|
case FunctionCallExpression:
|
|
CompileFunctionCallExpression(module, builder, statement);
|
|
return LLVMGetLastBasicBlock(function);
|
|
|
|
case IfStatement:
|
|
return CompileIfStatement(module, builder, function, statement);
|
|
|
|
case IfElseStatement:
|
|
return CompileIfElseStatement(module, builder, function, statement);
|
|
|
|
case Return:
|
|
return CompileReturn(module, builder, function, statement);
|
|
|
|
case ReturnVoid:
|
|
return CompileReturnVoid(builder, function);
|
|
}
|
|
|
|
fprintf(stderr, "Unknown statement kind!\n");
|
|
return NULL;
|
|
}
|
|
|
|
static void CompileFunction(
|
|
LLVMModuleRef module,
|
|
char *parentStructName,
|
|
LLVMTypeRef wStructPointerType,
|
|
Node *functionDeclaration)
|
|
{
|
|
uint32_t i;
|
|
uint8_t hasReturn = 0;
|
|
uint8_t isStatic = 0;
|
|
Node *functionSignature =
|
|
functionDeclaration->functionDeclaration.functionSignature;
|
|
Node *functionBody = functionDeclaration->functionDeclaration.functionBody;
|
|
uint32_t argumentCount = functionSignature->functionSignature.arguments
|
|
->functionSignatureArguments.count;
|
|
LLVMTypeRef paramTypes[argumentCount + 1];
|
|
uint32_t paramIndex = 0;
|
|
|
|
if (functionSignature->functionSignature.modifiers->functionModifiers
|
|
.count > 0)
|
|
{
|
|
for (i = 0; i < functionSignature->functionSignature.modifiers
|
|
->functionModifiers.count;
|
|
i += 1)
|
|
{
|
|
if (functionSignature->functionSignature.modifiers
|
|
->functionModifiers.sequence[i]
|
|
->syntaxKind == StaticModifier)
|
|
{
|
|
isStatic = 1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
char *functionName = strdup(parentStructName);
|
|
strcat(functionName, "_");
|
|
strcat(
|
|
functionName,
|
|
functionSignature->functionSignature.identifier->identifier.name);
|
|
|
|
if (functionSignature->functionSignature.genericArguments->genericArguments
|
|
.count == 0)
|
|
{
|
|
PushScopeFrame(scope);
|
|
|
|
if (!isStatic)
|
|
{
|
|
paramTypes[paramIndex] = wStructPointerType;
|
|
paramIndex += 1;
|
|
}
|
|
|
|
for (i = 0; i < functionSignature->functionSignature.arguments
|
|
->functionSignatureArguments.count;
|
|
i += 1)
|
|
{
|
|
paramTypes[paramIndex] =
|
|
ResolveType(functionSignature->functionSignature.arguments
|
|
->functionSignatureArguments.sequence[i]
|
|
->declaration.identifier->typeTag);
|
|
paramIndex += 1;
|
|
}
|
|
|
|
LLVMTypeRef returnType = ResolveType(
|
|
functionSignature->functionSignature.identifier->typeTag);
|
|
LLVMTypeRef functionType =
|
|
LLVMFunctionType(returnType, paramTypes, paramIndex, 0);
|
|
|
|
LLVMValueRef function =
|
|
LLVMAddFunction(module, functionName, functionType);
|
|
|
|
DeclareStructFunction(
|
|
wStructPointerType,
|
|
function,
|
|
returnType,
|
|
isStatic,
|
|
functionSignature->functionSignature.identifier->identifier.name);
|
|
|
|
LLVMBasicBlockRef entry = LLVMAppendBasicBlock(function, "entry");
|
|
LLVMBuilderRef builder = LLVMCreateBuilder();
|
|
LLVMPositionBuilderAtEnd(builder, entry);
|
|
|
|
if (!isStatic)
|
|
{
|
|
LLVMValueRef wStructPointer = LLVMGetParam(function, 0);
|
|
AddStructVariablesToScope(builder, wStructPointer);
|
|
}
|
|
|
|
for (i = 0; i < functionSignature->functionSignature.arguments
|
|
->functionSignatureArguments.count;
|
|
i += 1)
|
|
{
|
|
char *ptrName =
|
|
strdup(functionSignature->functionSignature.arguments
|
|
->functionSignatureArguments.sequence[i]
|
|
->declaration.identifier->identifier.name);
|
|
strcat(ptrName, "_ptr");
|
|
LLVMValueRef argument = LLVMGetParam(function, i + !isStatic);
|
|
LLVMValueRef argumentCopy =
|
|
LLVMBuildAlloca(builder, LLVMTypeOf(argument), ptrName);
|
|
LLVMBuildStore(builder, argument, argumentCopy);
|
|
free(ptrName);
|
|
AddLocalVariable(
|
|
scope,
|
|
argumentCopy,
|
|
NULL,
|
|
functionSignature->functionSignature.arguments
|
|
->functionSignatureArguments.sequence[i]
|
|
->declaration.identifier->identifier.name);
|
|
}
|
|
|
|
for (i = 0; i < functionBody->statementSequence.count; i += 1)
|
|
{
|
|
CompileStatement(
|
|
module,
|
|
builder,
|
|
function,
|
|
functionBody->statementSequence.sequence[i]);
|
|
}
|
|
|
|
hasReturn = LLVMGetBasicBlockTerminator(
|
|
LLVMGetLastBasicBlock(function)) != NULL;
|
|
|
|
if (LLVMGetTypeKind(returnType) == LLVMVoidTypeKind && !hasReturn)
|
|
{
|
|
LLVMBuildRetVoid(builder);
|
|
}
|
|
else if (LLVMGetTypeKind(returnType) != LLVMVoidTypeKind && !hasReturn)
|
|
{
|
|
fprintf(stderr, "Return statement not provided!");
|
|
}
|
|
|
|
LLVMDisposeBuilder(builder);
|
|
|
|
PopScopeFrame(scope);
|
|
}
|
|
else
|
|
{
|
|
DeclareGenericStructFunction(
|
|
wStructPointerType,
|
|
functionDeclaration,
|
|
isStatic,
|
|
parentStructName,
|
|
functionSignature->functionSignature.identifier->identifier.name);
|
|
}
|
|
|
|
free(functionName);
|
|
}
|
|
|
|
static void CompileStruct(
|
|
LLVMModuleRef module,
|
|
LLVMContextRef context,
|
|
Node *node)
|
|
{
|
|
uint32_t i;
|
|
uint32_t fieldCount = 0;
|
|
uint32_t declarationCount =
|
|
node->structDeclaration.declarationSequence->declarationSequence.count;
|
|
uint8_t packed = 1;
|
|
LLVMTypeRef types[declarationCount];
|
|
Node *currentDeclarationNode;
|
|
Node *fieldDeclarations[declarationCount];
|
|
char *structName = node->structDeclaration.identifier->identifier.name;
|
|
|
|
PushScopeFrame(scope);
|
|
|
|
LLVMTypeRef wStructType = LLVMStructCreateNamed(context, structName);
|
|
LLVMTypeRef wStructPointerType = LLVMPointerType(
|
|
wStructType,
|
|
0); /* FIXME: is this address space correct? */
|
|
|
|
/* first, build the structure definition */
|
|
for (i = 0; i < declarationCount; i += 1)
|
|
{
|
|
currentDeclarationNode = node->structDeclaration.declarationSequence
|
|
->declarationSequence.sequence[i];
|
|
|
|
switch (currentDeclarationNode->syntaxKind)
|
|
{
|
|
case Declaration: /* this is badly named */
|
|
types[fieldCount] = ResolveType(
|
|
currentDeclarationNode->declaration.identifier->typeTag);
|
|
fieldDeclarations[fieldCount] = currentDeclarationNode;
|
|
fieldCount += 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
LLVMStructSetBody(wStructType, types, fieldCount, packed);
|
|
AddStructDeclaration(
|
|
wStructType,
|
|
wStructPointerType,
|
|
structName,
|
|
fieldDeclarations,
|
|
fieldCount);
|
|
|
|
/* now we can wire up the functions */
|
|
for (i = 0; i < declarationCount; i += 1)
|
|
{
|
|
currentDeclarationNode = node->structDeclaration.declarationSequence
|
|
->declarationSequence.sequence[i];
|
|
|
|
switch (currentDeclarationNode->syntaxKind)
|
|
{
|
|
case FunctionDeclaration:
|
|
CompileFunction(
|
|
module,
|
|
structName,
|
|
wStructPointerType,
|
|
currentDeclarationNode);
|
|
break;
|
|
}
|
|
}
|
|
|
|
PopScopeFrame(scope);
|
|
}
|
|
|
|
static void Compile(
|
|
LLVMModuleRef module,
|
|
LLVMContextRef context,
|
|
Node *declarationSequenceNode)
|
|
{
|
|
uint32_t i;
|
|
|
|
for (i = 0; i < declarationSequenceNode->declarationSequence.count; i += 1)
|
|
{
|
|
if (declarationSequenceNode->declarationSequence.sequence[i]
|
|
->syntaxKind == StructDeclaration)
|
|
{
|
|
CompileStruct(
|
|
module,
|
|
context,
|
|
declarationSequenceNode->declarationSequence.sequence[i]);
|
|
}
|
|
else
|
|
{
|
|
fprintf(
|
|
stderr,
|
|
"top level declarations that are not structs are "
|
|
"forbidden!\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
/* TODO: move this to some kind of standard library file? */
|
|
static void RegisterLibraryFunctions(
|
|
LLVMModuleRef module,
|
|
LLVMContextRef context)
|
|
{
|
|
LLVMTypeRef structType = LLVMStructCreateNamed(context, "Console");
|
|
LLVMTypeRef structPointerType = LLVMPointerType(structType, 0);
|
|
AddStructDeclaration(structType, structPointerType, "Console", NULL, 0);
|
|
|
|
LLVMTypeRef printfArg = LLVMPointerType(LLVMInt8Type(), 0);
|
|
LLVMTypeRef printfFunctionType =
|
|
LLVMFunctionType(LLVMInt32Type(), &printfArg, 1, 1);
|
|
LLVMValueRef printfFunction =
|
|
LLVMAddFunction(module, "printf", printfFunctionType);
|
|
LLVMSetLinkage(printfFunction, LLVMExternalLinkage);
|
|
|
|
LLVMTypeRef printLineFunctionType =
|
|
LLVMFunctionType(LLVMInt32Type(), &printfArg, 1, 1);
|
|
LLVMValueRef printLineFunction =
|
|
LLVMAddFunction(module, "printLine", printLineFunctionType);
|
|
|
|
LLVMBuilderRef builder = LLVMCreateBuilder();
|
|
LLVMBasicBlockRef entry = LLVMAppendBasicBlock(printLineFunction, "entry");
|
|
LLVMPositionBuilderAtEnd(builder, entry);
|
|
|
|
LLVMValueRef newLine = LLVMBuildGlobalStringPtr(builder, "\n", "newline");
|
|
|
|
LLVMValueRef printParams[LLVMCountParams(printLineFunction)];
|
|
LLVMGetParams(printLineFunction, printParams);
|
|
LLVMValueRef stringPrint = LLVMBuildCall(
|
|
builder,
|
|
printfFunction,
|
|
printParams,
|
|
LLVMCountParams(printLineFunction),
|
|
"printfCall");
|
|
LLVMValueRef newlinePrint =
|
|
LLVMBuildCall(builder, printfFunction, &newLine, 1, "printNewLine");
|
|
LLVMBuildRet(
|
|
builder,
|
|
LLVMBuildAnd(builder, stringPrint, newlinePrint, "and"));
|
|
|
|
DeclareStructFunction(
|
|
structPointerType,
|
|
printLineFunction,
|
|
LLVMInt8Type(),
|
|
1,
|
|
"PrintLine");
|
|
}
|
|
|
|
int Codegen(Node *node, uint32_t optimizationLevel)
|
|
{
|
|
scope = CreateScope();
|
|
|
|
structTypeDeclarations = NULL;
|
|
structTypeDeclarationCount = 0;
|
|
|
|
LLVMModuleRef module = LLVMModuleCreateWithName("my_module");
|
|
LLVMContextRef context = LLVMGetGlobalContext();
|
|
|
|
RegisterLibraryFunctions(module, context);
|
|
|
|
Compile(module, context, node);
|
|
|
|
/* add main call */
|
|
LLVMBuilderRef builder = LLVMCreateBuilder();
|
|
|
|
LLVMTypeRef mainFunctionType =
|
|
LLVMFunctionType(LLVMInt64Type(), NULL, 0, 0);
|
|
LLVMValueRef mainFunction =
|
|
LLVMAddFunction(module, "main", mainFunctionType);
|
|
LLVMBasicBlockRef entry = LLVMAppendBasicBlock(mainFunction, "entry");
|
|
LLVMPositionBuilderAtEnd(builder, entry);
|
|
|
|
LLVMValueRef wraithMainFunction =
|
|
LLVMGetNamedFunction(module, "Program_Main");
|
|
|
|
LLVMValueRef mainResult =
|
|
LLVMBuildCall(builder, wraithMainFunction, NULL, 0, "result");
|
|
LLVMBuildRet(builder, mainResult);
|
|
|
|
LLVMDisposeBuilder(builder);
|
|
|
|
/* verify */
|
|
char *error = NULL;
|
|
|
|
if (LLVMVerifyModule(module, LLVMAbortProcessAction, &error) != 0)
|
|
{
|
|
fprintf(stderr, "%s\n", error);
|
|
LLVMDisposeMessage(error);
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
/* prepare to emit assembly */
|
|
LLVMInitializeNativeTarget();
|
|
LLVMInitializeAllTargetInfos();
|
|
LLVMInitializeAllTargets();
|
|
LLVMInitializeAllTargetMCs();
|
|
LLVMInitializeAllAsmParsers();
|
|
LLVMInitializeAllAsmPrinters();
|
|
|
|
LLVMSetTarget(module, LLVM_DEFAULT_TARGET_TRIPLE);
|
|
LLVMTargetRef target;
|
|
if (LLVMGetTargetFromTriple(LLVM_DEFAULT_TARGET_TRIPLE, &target, &error) !=
|
|
0)
|
|
{
|
|
fprintf(stderr, "Failed to get target!\n");
|
|
fprintf(stderr, "%s\n", error);
|
|
LLVMDisposeMessage(error);
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
LLVMPassManagerRef passManager = LLVMCreatePassManager();
|
|
|
|
LLVMPassManagerBuilderRef passManagerBuilder =
|
|
LLVMPassManagerBuilderCreate();
|
|
LLVMPassManagerBuilderSetOptLevel(passManagerBuilder, optimizationLevel);
|
|
LLVMPassManagerBuilderPopulateModulePassManager(
|
|
passManagerBuilder,
|
|
passManager);
|
|
|
|
LLVMRunPassManager(passManager, module);
|
|
|
|
if (LLVMWriteBitcodeToFile(module, "test.bc") != 0)
|
|
{
|
|
fprintf(stderr, "error writing bitcode to file\n");
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
char *cpu = "generic";
|
|
char *features = "";
|
|
|
|
LLVMTargetMachineRef targetMachine = LLVMCreateTargetMachine(
|
|
target,
|
|
LLVM_DEFAULT_TARGET_TRIPLE,
|
|
cpu,
|
|
features,
|
|
LLVMCodeGenLevelDefault,
|
|
LLVMRelocDefault,
|
|
LLVMCodeModelDefault);
|
|
|
|
if (LLVMTargetMachineEmitToFile(
|
|
targetMachine,
|
|
module,
|
|
"test.o",
|
|
LLVMObjectFile,
|
|
&error) != 0)
|
|
{
|
|
fprintf(stderr, "Failed to emit machine code!\n");
|
|
fprintf(stderr, "%s\n", error);
|
|
LLVMDisposeMessage(error);
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
LLVMDisposeMessage(error);
|
|
LLVMDisposeTargetMachine(targetMachine);
|
|
LLVMPassManagerBuilderDispose(passManagerBuilder);
|
|
LLVMDisposePassManager(passManager);
|
|
LLVMDisposeModule(module);
|
|
|
|
return EXIT_SUCCESS;
|
|
}
|