Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Store sharer and eraser in function prefix #768

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,13 @@ object PrettyPrinter {
definitions.map(show).mkString("\n\n")

def show(definition: Definition)(using C: Context): LLVMString = definition match {
case Function(callingConvention, returnType, name, parameters, basicBlocks) =>
case Function(callingConvention, returnType, name, parameters, Some(prefix), basicBlocks) =>
s"""
define ${show(callingConvention)} ${show(returnType)} ${globalName(name)}(${commaSeparated(parameters.map(show))}) prefix ${show(prefix)} {
${indentedLines(basicBlocks.map(show).mkString)}
}
"""
case Function(callingConvention, returnType, name, parameters, None, basicBlocks) =>
s"""
define ${show(callingConvention)} ${show(returnType)} ${globalName(name)}(${commaSeparated(parameters.map(show))}) {
${indentedLines(basicBlocks.map(show).mkString)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,10 @@ object Transformer {

val transitionJump = Call("_", Tailcc(false), VoidType(), ConstantGlobal("effektMainTailcc"), List())
val transitionBlock = BasicBlock("transition", List(transitionJump), RetVoid())
val transitionFunction = Function(Ccc(), VoidType(), "effektMain", List(), List(transitionBlock))
val transitionFunction = Function(Ccc(), VoidType(), "effektMain", List(), None, List(transitionBlock))

val entryBlock = BasicBlock("entry", instructions, terminator)
val effektMain = Function(Tailcc(true), VoidType(), "effektMainTailcc", List(), entryBlock :: basicBlocks)
val effektMain = Function(Tailcc(true), VoidType(), "effektMainTailcc", List(), None, entryBlock :: basicBlocks)
declarations.map(transform) ++ definitions :+ transitionFunction :+ effektMain
}

Expand Down Expand Up @@ -155,10 +155,12 @@ object Transformer {
val closureEnvironment = freeVariables(clauses).toList;
emit(Comment(s"new ${variable.name}, ${clauses.length} clauses, ${closureEnvironment.size} free variables"))

val clauseNames = clauses.map { clause =>
val clauseName = freshName(variable.name + "_clause");
val names = List.range(0, clauses.length).map(i => freshName(variable.name + i))
val vtable = ConstantArray(PointerType(), names.drop(1).reverse.map(ConstantGlobal(_))) // these are indexed in reverse
val clauseNames = clauses.zip(names).map { (clause, clauseName) =>
val parameters = clause.parameters.map { case machine.Variable(name, tpe) => Parameter(transform(tpe), name) }
defineLabel(clauseName, Parameter(objectType, "closure") +: parameters) {
val prefix = if (clause == clauses.head) then Some(vtable) else None
defineLabel(clauseName, Parameter(objectType, "closure") +: parameters, prefix) {
emit(Comment(s"new ${clauseName}, ${clause.parameters.length} parameters"))
consumeObject(LocalReference(objectType, "closure"), closureEnvironment, freeVariables(clause));
eraseValues(clause.parameters, freeVariables(clause.body));
Expand All @@ -167,13 +169,10 @@ object Transformer {
ConstantGlobal(clauseName)
}

val vtableName = freshName("vtable")
emit(GlobalConstant(vtableName, ConstantArray(methodType, clauseNames)))

val vtable = produceObject("closure", closureEnvironment, freeVariables(rest));
val environment = produceObject("closure", closureEnvironment, freeVariables(rest));
val temporaryName = freshName("vtable_temporary");
emit(InsertValue(temporaryName, ConstantAggregateZero(negativeType), ConstantGlobal(vtableName), 0));
emit(InsertValue(variable.name, LocalReference(negativeType, temporaryName), vtable, 1));
emit(InsertValue(temporaryName, ConstantAggregateZero(negativeType), names.headOption.map(ConstantGlobal(_)).getOrElse(ConstantNull(PointerType())), 0));
emit(InsertValue(variable.name, LocalReference(negativeType, temporaryName), environment, 1));

eraseValues(List(variable), freeVariables(rest));
transform(rest)
Expand All @@ -182,26 +181,34 @@ object Transformer {
emit(Comment(s"invoke ${value.name}, tag ${tag}, ${values.length} values"))
shareValues(value :: values, Set());

val vtableName = freshName("vtable");
val function0 = freshName("function0Pointer");
val objectName = freshName("closure");
val pointerName = freshName("functionPointer_pointer");
val functionName = freshName("functionPointer");
val arguments = values.map(transform)

emit(ExtractValue(vtableName, transform(value), 0));
emit(ExtractValue(function0, transform(value), 0));
emit(ExtractValue(objectName, transform(value), 1));
emit(GetElementPtr(pointerName, methodType, LocalReference(PointerType(), vtableName), List(tag)))
emit(Load(functionName, methodType, LocalReference(PointerType(), pointerName)))
emit(callLabel(LocalReference(methodType, functionName), LocalReference(objectType, objectName) +: arguments))
if (tag == 0) {
emit(callLabel(LocalReference(methodType, function0), LocalReference(objectType, objectName) +: arguments))
}
else {
emit(GetElementPtr(pointerName, methodType, LocalReference(PointerType(), function0), List(-tag)))
emit(Load(functionName, methodType, LocalReference(PointerType(), pointerName)))
emit(callLabel(LocalReference(methodType, functionName), LocalReference(objectType, objectName) +: arguments))
}
RetVoid()

case machine.Var(ref @ machine.Variable(name, machine.Type.Reference(tpe)), init, retType, rest) =>
val environment = List(init)
val sharer = getSharer(environment, StackFrameSharer)
val eraser = getEraser(environment, StackFrameEraser)

val returnAddressName = freshName("returnAddress")
val returnType = transform(retType)
val returnValue = freshName("returnValue")
val parameters = List(Parameter(returnType, returnValue))
defineLabel(returnAddressName, parameters) {
defineLabel(returnAddressName, parameters, Some(ConstantArray(PointerType(), List(sharer, eraser)))) {
emit(Comment(s"var $name / return address"))
popEnvironmentFrom(getStack(), environment)
eraseValue(init)
Expand All @@ -211,9 +218,6 @@ object Transformer {
RetVoid()
}

val sharer = getSharer(environment, StackFrameSharer)
val eraser = getEraser(environment, StackFrameEraser)

emit(Call(name, Ccc(), referenceType, newReference, List(getStack())))

shareValues(environment, freeVariables(rest));
Expand Down Expand Up @@ -257,9 +261,12 @@ object Transformer {
case machine.PushFrame(frame, rest) =>
val frameEnvironment = freeVariables(frame).toList;

val sharer = getSharer(frameEnvironment, StackFrameSharer)
val eraser = getEraser(frameEnvironment, StackFrameEraser)

val returnAddressName = freshName("returnAddress");
val parameters = frame.parameters.map { case machine.Variable(name, tpe) => Parameter(transform(tpe), name) }
defineLabel(returnAddressName, parameters) {
defineLabel(returnAddressName, parameters, Some(ConstantArray(PointerType(), List(sharer, eraser)))) {
emit(Comment(s"pushFrame / return address, ${frameEnvironment.length} free variables"))
emit(Call("", Ccc(), VoidType(), ConstantGlobal("assumeFrameHeaderWasPopped"), List(getStack())))
popEnvironmentFrom(getStack(), frameEnvironment);
Expand All @@ -269,9 +276,6 @@ object Transformer {
transform(frame.body);
}

val sharer = getSharer(frameEnvironment, StackFrameSharer)
val eraser = getEraser(frameEnvironment, StackFrameEraser)

shareValues(frameEnvironment, freeVariables(rest));
pushFrameOnto(getStack(), frameEnvironment, returnAddressName, sharer, eraser);

Expand All @@ -297,9 +301,12 @@ object Transformer {

val frameEnvironment = freeVariables(frame).toList;

val sharer = getSharer(frameEnvironment, StackSharer)
val eraser = getEraser(frameEnvironment, StackEraser)

val returnAddressName = freshName("returnAddress");
val parameters = frame.parameters.map { case machine.Variable(name, tpe) => Parameter(transform(tpe), name) }
defineLabel(returnAddressName, parameters) {
defineLabel(returnAddressName, parameters, Some(ConstantArray(PointerType(), List(sharer, eraser)))) {
emit(Comment(s"Reset / return address, ${frameEnvironment.length} free variables"))
popEnvironmentFrom(getStack(), frameEnvironment);
// eraseValues(frameEnvironment, frameEnvironment) (unnecessary)
Expand All @@ -312,9 +319,6 @@ object Transformer {
transform(frame.body);
}

val sharer = getSharer(frameEnvironment, StackSharer)
val eraser = getEraser(frameEnvironment, StackEraser)

shareValues(frameEnvironment, freeVariables(rest));

pushFrameOnto(getStack(), frameEnvironment, returnAddressName, sharer, eraser);
Expand Down Expand Up @@ -435,7 +439,7 @@ object Transformer {
case machine.Type.Reference(_) => 16
}

def defineFunction(name: String, parameters: List[Parameter])(prog: (FunctionContext, BlockContext) ?=> Terminator): ModuleContext ?=> Unit = {
def defineFunction(name: String, parameters: List[Parameter], prefix: Option[Operand] = None)(prog: (FunctionContext, BlockContext) ?=> Terminator): ModuleContext ?=> Unit = {
implicit val FC = FunctionContext();
implicit val BC = BlockContext();

Expand All @@ -445,12 +449,12 @@ object Transformer {
val instructions = BC.instructions; BC.instructions = null;

val entryBlock = BasicBlock("entry", instructions, terminator);
val function = Function(Ccc(), VoidType(), name, parameters, entryBlock :: basicBlocks);
val function = Function(Ccc(), VoidType(), name, parameters, prefix, entryBlock :: basicBlocks);

emit(function)
}

def defineLabel(name: String, parameters: List[Parameter])(prog: (FunctionContext, BlockContext) ?=> Terminator): ModuleContext ?=> Unit = {
def defineLabel(name: String, parameters: List[Parameter], prefix: Option[Operand] = None)(prog: (FunctionContext, BlockContext) ?=> Terminator): ModuleContext ?=> Unit = {
implicit val FC = FunctionContext();
implicit val BC = BlockContext();

Expand All @@ -460,7 +464,7 @@ object Transformer {
val instructions = BC.instructions; BC.instructions = null;

val entryBlock = BasicBlock("entry", instructions, terminator);
val function = Function(Tailcc(true), VoidType(), name, parameters :+ Parameter(stackType, "stack"), entryBlock :: basicBlocks);
val function = Function(Tailcc(true), VoidType(), name, parameters :+ Parameter(stackType, "stack"), prefix, entryBlock :: basicBlocks);

emit(function)
}
Expand Down Expand Up @@ -583,22 +587,16 @@ object Transformer {

def pushFrameOnto(stack: Operand, environment: machine.Environment, returnAddressName: String, sharer: Operand, eraser: Operand)(using ModuleContext, FunctionContext, BlockContext) = {
val stackPointer = LocalReference(stackPointerType, freshName("stackPointer"));
val size = ConstantInt(environmentSize(environment) + 24);
val size = ConstantInt(environmentSize(environment) + 8);
emit(Call(stackPointer.name, Ccc(), stackPointer.tpe, stackAllocate, List(stack, size)));

val frameType = StructureType(List(environmentType(environment), frameHeaderType));
storeEnvironmentAt(stackPointer, environment);

val returnAddressPointer = LocalReference(PointerType(), freshName("returnAddress_pointer"));
emit(GetElementPtr(returnAddressPointer.name, frameType, stackPointer, List(0, 1, 0)));
val sharerPointer = LocalReference(PointerType(), freshName("sharer_pointer"));
emit(GetElementPtr(sharerPointer.name, frameType, stackPointer, List(0, 1, 1)));
val eraserPointer = LocalReference(PointerType(), freshName("eraser_pointer"));
emit(GetElementPtr(eraserPointer.name, frameType, stackPointer, List(0, 1, 2)));

emit(Store(returnAddressPointer, ConstantGlobal(returnAddressName)));
emit(Store(sharerPointer, sharer));
emit(Store(eraserPointer, eraser));
}

def popEnvironmentFrom(stack: Operand, environment: machine.Environment)(using ModuleContext, FunctionContext, BlockContext): Unit = {
Expand Down Expand Up @@ -683,7 +681,7 @@ object Transformer {

val stackPointer = LocalReference(stackPointerType, freshName("stackPointer"));
// TODO properly find size
val size = ConstantInt(24);
val size = ConstantInt(8);
emit(Call(stackPointer.name, Ccc(), stackPointer.tpe, stackDeallocate, List(stack, size)));

val returnAddressPointer = LocalReference(PointerType(), freshName("returnAddress_pointer"));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ package llvm
* see: https://hackage.haskell.org/package/llvm-hs-pure-9.0.0/docs/LLVM-AST.html#t:Definition
*/
enum Definition {
case Function(callingConvention: CallingConvention, returnType: Type, name: String, parameters: List[Parameter], basicBlocks: List[BasicBlock])
case Function(callingConvention: CallingConvention, returnType: Type, name: String, parameters: List[Parameter], prefix: Option[Operand], basicBlocks: List[BasicBlock])
case VerbatimFunction(callingConvention: CallingConvention, returnType: Type, name: String, parameters: List[Parameter], body: String)
case Verbatim(content: String)
case GlobalConstant(name: String, initializer: Operand) // initializer should be constant
Expand Down
30 changes: 12 additions & 18 deletions libraries/llvm/rts.ll
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@
%Base = type %StackPointer
%Limit = type %StackPointer
%ReturnAddress = type ptr
%FrameHeader = type { %ReturnAddress, %Sharer, %Eraser }
%FrameHeader = type { %ReturnAddress }

; Pointers for a heap allocated stack
%Memory = type { %StackPointer, %Base, %Limit }
Expand Down Expand Up @@ -502,10 +502,6 @@ define private %Stack @underflowStack(%Stack %stack) {
ret %Stack %rest
}

define private void @nop(%Stack %stack) {
ret void
}

define private %Memory @copyMemory(%Memory %memory) alwaysinline {
%stackPointer = extractvalue %Memory %memory, 0
%base = extractvalue %Memory %memory, 1
Expand Down Expand Up @@ -658,23 +654,25 @@ done:

define private void @shareFrames(%StackPointer %stackPointer) alwaysinline {
%newStackPointer = getelementptr %FrameHeader, %StackPointer %stackPointer, i64 -1
%stackSharer = getelementptr %FrameHeader, %StackPointer %newStackPointer, i64 0, i32 1
%sharer = load %Sharer, ptr %stackSharer
%returnAdress = load %ReturnAddress, ptr %newStackPointer
%sharer_pointer = getelementptr ptr, ptr %returnAdress, i64 -2
%sharer = load %Sharer, ptr %sharer_pointer
tail call void %sharer(%StackPointer %newStackPointer)
ret void
}

define private void @eraseFrames(%StackPointer %stackPointer) alwaysinline {
%newStackPointer = getelementptr %FrameHeader, %StackPointer %stackPointer, i64 -1
%stackEraser = getelementptr %FrameHeader, %StackPointer %newStackPointer, i64 0, i32 2
%eraser = load %Eraser, ptr %stackEraser
%returnAdress = load %ReturnAddress, ptr %newStackPointer
%eraser_pointer = getelementptr ptr, ptr %returnAdress, i64 -1
%eraser = load %Eraser, ptr %eraser_pointer
tail call void %eraser(%StackPointer %newStackPointer)
ret void
}

; RTS initialization

define private tailcc void @topLevel(%Pos %val, %Stack %stack) {
define private tailcc void @topLevel(%Pos %val, %Stack %stack) prefix { %Sharer, %Eraser } { %Sharer @topLevelSharer, %Eraser @topLevelEraser } {
%rest = call %Stack @underflowStack(%Stack %stack)
; rest holds global variables
call void @eraseStack(%Stack %rest)
Expand All @@ -693,19 +691,19 @@ define private void @topLevelEraser(%Environment %environment) {

@global = private global { i64, %Stack } { i64 0, %Stack null }

define private void @nop(%Stack %stack) prefix { %Sharer, %Eraser } { %Sharer @nop, %Eraser @free } {
ret void
}

define private %Stack @withEmptyStack() {
%globals = call %Stack @reset(%Stack null)

%globalsStackPointer_pointer = getelementptr %StackValue, %Stack %globals, i64 0, i32 1, i32 0
%globalsStackPointer = load %StackPointer, ptr %globalsStackPointer_pointer

%returnAddressPointer.0 = getelementptr %FrameHeader, %StackPointer %globalsStackPointer, i64 0, i32 0
%sharerPointer.0 = getelementptr %FrameHeader, %StackPointer %globalsStackPointer, i64 0, i32 1
%eraserPointer.0 = getelementptr %FrameHeader, %StackPointer %globalsStackPointer, i64 0, i32 2

store ptr @nop, ptr %returnAddressPointer.0
store ptr @nop, ptr %sharerPointer.0
store ptr @free, ptr %eraserPointer.0

%globalsStackPointer_2 = getelementptr %FrameHeader, %StackPointer %globalsStackPointer, i64 1
store %StackPointer %globalsStackPointer_2, ptr %globalsStackPointer_pointer
Expand All @@ -719,12 +717,8 @@ define private %Stack @withEmptyStack() {
%stackPointer = load %StackPointer, ptr %stackStackPointer

%returnAddressPointer = getelementptr %FrameHeader, %StackPointer %stackPointer, i64 0, i32 0
%sharerPointer = getelementptr %FrameHeader, %StackPointer %stackPointer, i64 0, i32 1
%eraserPointer = getelementptr %FrameHeader, %StackPointer %stackPointer, i64 0, i32 2

store %ReturnAddress @topLevel, ptr %returnAddressPointer
store %Sharer @topLevelSharer, ptr %sharerPointer
store %Eraser @topLevelEraser, ptr %eraserPointer

%stackPointer_2 = getelementptr %FrameHeader, %StackPointer %stackPointer, i64 1
store %StackPointer %stackPointer_2, ptr %stackStackPointer
Expand Down
Loading