[K/N] Replace invokes with combination of calls and branch instructions

This commit is contained in:
Elena Lepilkina
2021-05-20 17:19:40 +03:00
committed by Space
parent 0be5602363
commit 2320eb8b44
@@ -228,6 +228,8 @@ internal class StackLocalsManagerImpl(
private val stackLocals = mutableListOf<StackLocal>() private val stackLocals = mutableListOf<StackLocal>()
fun isEmpty() = stackLocals.isEmpty()
override fun alloc(irClass: IrClass, cleanFieldsExplicitly: Boolean): LLVMValueRef = with(functionGenerationContext) { override fun alloc(irClass: IrClass, cleanFieldsExplicitly: Boolean): LLVMValueRef = with(functionGenerationContext) {
val type = context.llvmDeclarations.forClass(irClass).bodyType val type = context.llvmDeclarations.forClass(irClass).bodyType
val stackLocal = appendingTo(bbInitStackLocals) { val stackLocal = appendingTo(bbInitStackLocals) {
@@ -386,6 +388,11 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
val stackLocalsManager = StackLocalsManagerImpl(this, stackLocalsInitBb) val stackLocalsManager = StackLocalsManagerImpl(this, stackLocalsInitBb)
data class FunctionInvokeInformation(val invokeInstruction: LLVMValueRef, val llvmFunction: LLVMValueRef, val rargs: CValues<CPointerVar<LLVMOpaqueValue>>,
val argsNumber: Int, val success: LLVMBasicBlockRef)
private val invokeInstructions = mutableListOf<FunctionInvokeInformation>()
/** /**
* TODO: consider merging this with [ExceptionHandler]. * TODO: consider merging this with [ExceptionHandler].
*/ */
@@ -610,7 +617,13 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
val endLocation = position?.end val endLocation = position?.end
val success = basicBlock("call_success", endLocation) val success = basicBlock("call_success", endLocation)
val result = LLVMBuildInvoke(builder, llvmFunction, rargs, args.size, success, unwind, "")!! val result = LLVMBuildInvoke(builder, llvmFunction, rargs, args.size, success, unwind, "")!!
// Store invoke instruction and its success block in reverse order.
// Reverse order allows save arguments valid during all work with invokes
// because other invokes processed before can be inside arguments list.
if (exceptionHandler == ExceptionHandler.Caller)
invokeInstructions.add(0, FunctionInvokeInformation(result, llvmFunction, rargs, args.size, success))
positionAtEnd(success) positionAtEnd(success)
return result return result
} }
} }
@@ -1358,41 +1371,60 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
} }
} }
appendingTo(cleanupLandingpad) { val shouldHaveCleanupLandingpad = forwardingForeignExceptionsTerminatedWith != null ||
val landingpad = gxxLandingpad(numClauses = 0) needSlots ||
LLVMSetCleanup(landingpad, 1) !stackLocalsManager.isEmpty() ||
(context.memoryModel == MemoryModel.EXPERIMENTAL && irFunction?.origin == CBridgeOrigin.C_TO_KOTLIN_BRIDGE)
forwardingForeignExceptionsTerminatedWith?.let { terminator -> if (shouldHaveCleanupLandingpad) {
// Catch all but Kotlin exceptions. appendingTo(cleanupLandingpad) {
val clause = ConstArray(int8TypePtr, listOf(kotlinExceptionRtti)) val landingpad = gxxLandingpad(numClauses = 0)
LLVMAddClause(landingpad, clause.llvm) LLVMSetCleanup(landingpad, 1)
val bbCleanup = basicBlock("forwardException", position()?.end) forwardingForeignExceptionsTerminatedWith?.let { terminator ->
val bbUnexpected = basicBlock("unexpectedException", position()?.end) // Catch all but Kotlin exceptions.
val clause = ConstArray(int8TypePtr, listOf(kotlinExceptionRtti))
LLVMAddClause(landingpad, clause.llvm)
val selector = extractValue(landingpad, 1) val bbCleanup = basicBlock("forwardException", position()?.end)
condBr( val bbUnexpected = basicBlock("unexpectedException", position()?.end)
icmpLt(selector, Int32(0).llvm),
bbUnexpected,
bbCleanup
)
appendingTo(bbUnexpected) { val selector = extractValue(landingpad, 1)
val exceptionRecord = extractValue(landingpad, 0) condBr(
icmpLt(selector, Int32(0).llvm),
bbUnexpected,
bbCleanup
)
val beginCatch = context.llvm.cxaBeginCatchFunction appendingTo(bbUnexpected) {
// So `terminator` is called from C++ catch block: val exceptionRecord = extractValue(landingpad, 0)
call(beginCatch, listOf(exceptionRecord))
call(terminator, emptyList()) val beginCatch = context.llvm.cxaBeginCatchFunction
unreachable() // So `terminator` is called from C++ catch block:
call(beginCatch, listOf(exceptionRecord))
call(terminator, emptyList())
unreachable()
}
positionAtEnd(bbCleanup)
} }
positionAtEnd(bbCleanup) releaseVars()
handleEpilogueForExperimentalMM(context.llvm.Kotlin_mm_safePointExceptionUnwind)
LLVMBuildResume(builder, landingpad)
} }
} else {
releaseVars() // Replace invokes with calls and branches.
handleEpilogueForExperimentalMM(context.llvm.Kotlin_mm_safePointExceptionUnwind) invokeInstructions.forEach { functionInvokeInfo ->
LLVMBuildResume(builder, landingpad) positionBefore(functionInvokeInfo.invokeInstruction)
val newResult = LLVMBuildCall(builder, functionInvokeInfo.llvmFunction, functionInvokeInfo.rargs,
functionInvokeInfo.argsNumber, "")
// Have to generate `br` instruction because of current scheme of debug info.
br(functionInvokeInfo.success)
LLVMReplaceAllUsesWith(functionInvokeInfo.invokeInstruction, newResult)
LLVMInstructionEraseFromParent(functionInvokeInfo.invokeInstruction)
}
LLVMDeleteBasicBlock(cleanupLandingpad)
} }
returns.clear() returns.clear()
@@ -1468,6 +1500,12 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
isAfterTerminator = lastInstr != null && (LLVMIsATerminatorInst(lastInstr) != null) isAfterTerminator = lastInstr != null && (LLVMIsATerminatorInst(lastInstr) != null)
} }
fun positionBefore(instruction: LLVMValueRef) {
LLVMPositionBuilderBefore(builder, instruction)
val previousInstr = LLVMGetPreviousInstruction(instruction)
isAfterTerminator = previousInstr != null && (LLVMIsATerminatorInst(previousInstr) != null)
}
fun dispose() { fun dispose() {
LLVMDisposeBuilder(builder) LLVMDisposeBuilder(builder)
} }
@@ -1504,6 +1542,8 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
fun positionAtEnd(bbLabel: LLVMBasicBlockRef) = currentPositionHolder.positionAtEnd(bbLabel) fun positionAtEnd(bbLabel: LLVMBasicBlockRef) = currentPositionHolder.positionAtEnd(bbLabel)
fun positionBefore(instruction: LLVMValueRef) = currentPositionHolder.positionBefore(instruction)
inline private fun <R> preservingPosition(code: () -> R): R { inline private fun <R> preservingPosition(code: () -> R): R {
val oldPositionHolder = currentPositionHolder val oldPositionHolder = currentPositionHolder
val newPositionHolder = PositionHolder() val newPositionHolder = PositionHolder()