Skip to content

Commit

Permalink
Use noalias on StackValues (#704)
Browse files Browse the repository at this point in the history
Co-authored-by: Philipp Schuster <[email protected]>
  • Loading branch information
serkm and phischu authored Dec 4, 2024
1 parent 4e6d325 commit 1c7179a
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 51 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -72,12 +72,12 @@ ${indentedLines(instructions.map(show).mkString("\n"))}
C.abort(s"tail call to non-void function returning: $tpe")

case Load(result, tpe, LocalReference(PointerType(), name)) =>
s"${localName(result)} = load ${show(tpe)}, ${show(LocalReference(PointerType(), name))}"
s"${localName(result)} = load ${show(tpe)}, ${show(LocalReference(PointerType(), name))}, !noalias !2"
case Load(_, _, operand) => C.abort(s"WIP: loading anything but local references not yet implemented: $operand")

// TODO [jfrech, 2022-07-26] Why does `Load` explicitly check for a local reference and `Store` does not?
case Store(address, value) =>
s"store ${show(value)}, ${show(address)}"
s"store ${show(value)}, ${show(address)}, !noalias !2"

case GetElementPtr(result, tpe, ptr @ LocalReference(_, name), i :: is) =>
s"${localName(result)} = getelementptr ${show(tpe)}, ${show(ptr)}, i64 $i" + is.map(", i32 " + _).mkString
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -217,8 +217,7 @@ object Transformer {
emit(Call(name, Ccc(), referenceType, newReference, List(getStack())))

shareValues(environment, freeVariables(rest));
pushEnvironmentOnto(getStack(), environment);
pushReturnAddressOnto(getStack(), returnAddressName, sharer, eraser);
pushFrameOnto(getStack(), environment, returnAddressName, sharer, eraser);

transform(rest)

Expand Down Expand Up @@ -262,6 +261,7 @@ object Transformer {
val parameters = frame.parameters.map { case machine.Variable(name, tpe) => Parameter(transform(tpe), name) }
defineLabel(returnAddressName, parameters) {
emit(Comment(s"pushFrame / return address, ${frameEnvironment.length} free variables"))
emit(Call("", Ccc(), VoidType(), ConstantGlobal("assumeFrameHeaderWasPopped"), List(getStack())))
popEnvironmentFrom(getStack(), frameEnvironment);
// eraseValues(frameEnvironment, frameEnvironment) (unnecessary)
eraseValues(frame.parameters, freeVariables(frame.body))
Expand All @@ -273,8 +273,7 @@ object Transformer {
val eraser = getEraser(frameEnvironment, StackFrameEraser)

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

transform(rest)

Expand Down Expand Up @@ -318,8 +317,7 @@ object Transformer {

shareValues(frameEnvironment, freeVariables(rest));

pushEnvironmentOnto(getStack(), frameEnvironment);
pushReturnAddressOnto(getStack(), returnAddressName, sharer, eraser);
pushFrameOnto(getStack(), frameEnvironment, returnAddressName, sharer, eraser);

transform(rest)

Expand Down Expand Up @@ -582,15 +580,24 @@ object Transformer {
}
}

def pushEnvironmentOnto(stack: Operand, environment: machine.Environment)(using ModuleContext, FunctionContext, BlockContext): Unit = {
if (environment.isEmpty) {
()
} else {
val stackPointer = LocalReference(stackPointerType, freshName("stackPointer"));
val size = ConstantInt(environmentSize(environment));
emit(Call(stackPointer.name, Ccc(), stackPointer.tpe, stackAllocate, List(stack, size)));
storeEnvironmentAt(stackPointer, environment);
}
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);
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 @@ -671,25 +678,6 @@ object Transformer {
}.map(emit)
}

def pushReturnAddressOnto(stack: Operand, returnAddressName: String, sharer: Operand, eraser: Operand)(using ModuleContext, FunctionContext, BlockContext): Unit = {

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

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

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

def popReturnAddressFrom(stack: Operand, returnAddressName: String)(using ModuleContext, FunctionContext, BlockContext): Unit = {

val stackPointer = LocalReference(stackPointerType, freshName("stackPointer"));
Expand Down
57 changes: 42 additions & 15 deletions libraries/llvm/rts.ll
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ declare double @llvm.ceil.f64(double)
declare double @llvm.floor.f64(double)
declare void @print(i64)
declare void @exit(i64)
declare void @llvm.assume(i1)


; Prompts
Expand Down Expand Up @@ -258,20 +259,19 @@ define private %StackPointer @stackAllocate(%Stack %stack, i64 %n) {
%stackPointer_pointer = getelementptr %StackValue, %Stack %stack, i64 0, i32 1, i32 0
%limit_pointer = getelementptr %StackValue, %Stack %stack, i64 0, i32 1, i32 2

%currentStackPointer = load %StackPointer, ptr %stackPointer_pointer
%limit = load %Limit, ptr %limit_pointer

%currentStackPointer = load %StackPointer, ptr %stackPointer_pointer, !alias.scope !2
%limit = load %Limit, ptr %limit_pointer, !alias.scope !2
%nextStackPointer = getelementptr i8, %StackPointer %currentStackPointer, i64 %n
%isInside = icmp ule %StackPointer %nextStackPointer, %limit
br i1 %isInside, label %continue, label %realloc

continue:
store %StackPointer %nextStackPointer, ptr %stackPointer_pointer
store %StackPointer %nextStackPointer, ptr %stackPointer_pointer, !alias.scope !2
ret %StackPointer %currentStackPointer

realloc:
%base_pointer = getelementptr %StackValue, %Stack %stack, i64 0, i32 1, i32 1
%base = load %Base, ptr %base_pointer
%base = load %Base, ptr %base_pointer, !alias.scope !2

%intStackPointer = ptrtoint %StackPointer %currentStackPointer to i64
%intBase = ptrtoint %Base %base to i64
Expand All @@ -285,31 +285,48 @@ realloc:
%newStackPointer = getelementptr i8, %Base %newBase, i64 %size
%newNextStackPointer = getelementptr i8, %StackPointer %newStackPointer, i64 %n

store %StackPointer %newNextStackPointer, ptr %stackPointer_pointer
store %Base %newBase, ptr %base_pointer
store %Limit %newLimit, ptr %limit_pointer
store %StackPointer %newNextStackPointer, ptr %stackPointer_pointer, !alias.scope !2
store %Base %newBase, ptr %base_pointer, !alias.scope !2
store %Limit %newLimit, ptr %limit_pointer, !alias.scope !2

ret %StackPointer %newStackPointer
}

define private %StackPointer @stackDeallocate(%Stack %stack, i64 %n) {
%stackPointer_pointer = getelementptr %StackValue, %Stack %stack, i64 0, i32 1, i32 0
%stackPointer = load %StackPointer, ptr %stackPointer_pointer
%stackPointer = load %StackPointer, ptr %stackPointer_pointer, !alias.scope !2

%limit_pointer = getelementptr %StackValue, %Stack %stack, i64 0, i32 1, i32 2
%limit = load %Limit, ptr %limit_pointer, !alias.scope !2
%isInside = icmp ule %StackPointer %stackPointer, %limit
call void @llvm.assume(i1 %isInside)

%o = sub i64 0, %n
%newStackPointer = getelementptr i8, %StackPointer %stackPointer, i64 %o
store %StackPointer %newStackPointer, ptr %stackPointer_pointer
store %StackPointer %newStackPointer, ptr %stackPointer_pointer, !alias.scope !2

ret %StackPointer %newStackPointer
}

define i64 @nextPowerOfTwo(i64 %x) {
define private i64 @nextPowerOfTwo(i64 %x) {
%leadingZeros = call i64 @llvm.ctlz.i64(i64 %x, i1 false)
%numBits = sub i64 64, %leadingZeros
%result = shl i64 1, %numBits
ret i64 %result
}

define private void @assumeFrameHeaderWasPopped(%Stack %stack) alwaysinline {
%stackPointer_pointer = getelementptr %StackValue, %Stack %stack, i64 0, i32 1, i32 0
%stackPointer = load %StackPointer, ptr %stackPointer_pointer, !alias.scope !2
%oldStackPointer = getelementptr %FrameHeader, %StackPointer %stackPointer, i64 1

%limit_pointer = getelementptr %StackValue, %Stack %stack, i64 0, i32 1, i32 2
%limit = load %Limit, ptr %limit_pointer, !alias.scope !2
%isInside = icmp ule %StackPointer %oldStackPointer, %limit
call void @llvm.assume(i1 %isInside)
ret void
}

; Meta-stack management

define private %Memory @newMemory() {
Expand Down Expand Up @@ -374,7 +391,7 @@ update:
ret void
}

define void @displace(%Stack %stack, %Stack %end) {
define private void @displace(%Stack %stack, %Stack %end) {
%prompt_pointer = getelementptr %StackValue, %Stack %stack, i64 0, i32 2
%next_pointer = getelementptr %StackValue, %Stack %stack, i64 0, i32 3
%prompt = load %Prompt, ptr %prompt_pointer
Expand All @@ -393,7 +410,7 @@ continue:
ret void
}

define %Stack @resume(%Resumption %resumption, %Stack %oldStack) {
define private %Stack @resume(%Resumption %resumption, %Stack %oldStack) {
%uniqueResumption = call %Resumption @uniqueStack(%Resumption %resumption)
%rest_pointer = getelementptr %StackValue, %Resumption %uniqueResumption, i64 0, i32 3
%start = load %Stack, ptr %rest_pointer
Expand Down Expand Up @@ -423,7 +440,7 @@ define private void @eraseMemory(%Memory %memory) {
ret void
}

define void @erasePrompt(%Prompt %prompt) alwaysinline {
define private void @erasePrompt(%Prompt %prompt) alwaysinline {
%referenceCount_pointer = getelementptr %PromptValue, %Prompt %prompt, i64 0, i32 0
%referenceCount = load %ReferenceCount, ptr %referenceCount_pointer
switch %ReferenceCount %referenceCount, label %decrement [%ReferenceCount 0, label %free]
Expand All @@ -438,7 +455,7 @@ free:
ret void
}

define void @sharePrompt(%Prompt %prompt) alwaysinline {
define private void @sharePrompt(%Prompt %prompt) alwaysinline {
%referenceCount_pointer = getelementptr %PromptValue, %Prompt %prompt, i64 0, i32 0
%referenceCount = load %ReferenceCount, ptr %referenceCount_pointer
%newReferenceCount = add %ReferenceCount %referenceCount, 1
Expand Down Expand Up @@ -755,3 +772,13 @@ define void @run_Pos(%Neg %f, %Pos %argument) {
tail call tailcc %Pos %functionPointer(%Object %object, %Evidence 0, %Pos %argument, %Stack %stack)
ret void
}


; Scope domains
!0 = !{!"types"}

; Scopes
!1 = !{!"stackValues", !0}

; Scope lists
!2 = !{!1}

0 comments on commit 1c7179a

Please sign in to comment.