From 2320eb8b449e295b368680d5e8ec3ad8c2648901 Mon Sep 17 00:00:00 2001 From: Elena Lepilkina Date: Thu, 20 May 2021 17:19:40 +0300 Subject: [PATCH] [K/N] Replace invokes with combination of calls and branch instructions --- .../backend/konan/llvm/CodeGenerator.kt | 94 +++++++++++++------ 1 file changed, 67 insertions(+), 27 deletions(-) diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/CodeGenerator.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/CodeGenerator.kt index 4fceb42cc32..6577b7a3d50 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/CodeGenerator.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/CodeGenerator.kt @@ -228,6 +228,8 @@ internal class StackLocalsManagerImpl( private val stackLocals = mutableListOf() + fun isEmpty() = stackLocals.isEmpty() + override fun alloc(irClass: IrClass, cleanFieldsExplicitly: Boolean): LLVMValueRef = with(functionGenerationContext) { val type = context.llvmDeclarations.forClass(irClass).bodyType val stackLocal = appendingTo(bbInitStackLocals) { @@ -386,6 +388,11 @@ internal class FunctionGenerationContext(val function: LLVMValueRef, val stackLocalsManager = StackLocalsManagerImpl(this, stackLocalsInitBb) + data class FunctionInvokeInformation(val invokeInstruction: LLVMValueRef, val llvmFunction: LLVMValueRef, val rargs: CValues>, + val argsNumber: Int, val success: LLVMBasicBlockRef) + + private val invokeInstructions = mutableListOf() + /** * TODO: consider merging this with [ExceptionHandler]. */ @@ -610,7 +617,13 @@ internal class FunctionGenerationContext(val function: LLVMValueRef, val endLocation = position?.end val success = basicBlock("call_success", endLocation) 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) + return result } } @@ -1358,41 +1371,60 @@ internal class FunctionGenerationContext(val function: LLVMValueRef, } } - appendingTo(cleanupLandingpad) { - val landingpad = gxxLandingpad(numClauses = 0) - LLVMSetCleanup(landingpad, 1) + val shouldHaveCleanupLandingpad = forwardingForeignExceptionsTerminatedWith != null || + needSlots || + !stackLocalsManager.isEmpty() || + (context.memoryModel == MemoryModel.EXPERIMENTAL && irFunction?.origin == CBridgeOrigin.C_TO_KOTLIN_BRIDGE) - forwardingForeignExceptionsTerminatedWith?.let { terminator -> - // Catch all but Kotlin exceptions. - val clause = ConstArray(int8TypePtr, listOf(kotlinExceptionRtti)) - LLVMAddClause(landingpad, clause.llvm) + if (shouldHaveCleanupLandingpad) { + appendingTo(cleanupLandingpad) { + val landingpad = gxxLandingpad(numClauses = 0) + LLVMSetCleanup(landingpad, 1) - val bbCleanup = basicBlock("forwardException", position()?.end) - val bbUnexpected = basicBlock("unexpectedException", position()?.end) + forwardingForeignExceptionsTerminatedWith?.let { terminator -> + // Catch all but Kotlin exceptions. + val clause = ConstArray(int8TypePtr, listOf(kotlinExceptionRtti)) + LLVMAddClause(landingpad, clause.llvm) - val selector = extractValue(landingpad, 1) - condBr( - icmpLt(selector, Int32(0).llvm), - bbUnexpected, - bbCleanup - ) + val bbCleanup = basicBlock("forwardException", position()?.end) + val bbUnexpected = basicBlock("unexpectedException", position()?.end) - appendingTo(bbUnexpected) { - val exceptionRecord = extractValue(landingpad, 0) + val selector = extractValue(landingpad, 1) + condBr( + icmpLt(selector, Int32(0).llvm), + bbUnexpected, + bbCleanup + ) - val beginCatch = context.llvm.cxaBeginCatchFunction - // So `terminator` is called from C++ catch block: - call(beginCatch, listOf(exceptionRecord)) - call(terminator, emptyList()) - unreachable() + appendingTo(bbUnexpected) { + val exceptionRecord = extractValue(landingpad, 0) + + val beginCatch = context.llvm.cxaBeginCatchFunction + // 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) } - - releaseVars() - handleEpilogueForExperimentalMM(context.llvm.Kotlin_mm_safePointExceptionUnwind) - LLVMBuildResume(builder, landingpad) + } else { + // Replace invokes with calls and branches. + invokeInstructions.forEach { functionInvokeInfo -> + 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() @@ -1468,6 +1500,12 @@ internal class FunctionGenerationContext(val function: LLVMValueRef, 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() { LLVMDisposeBuilder(builder) } @@ -1504,6 +1542,8 @@ internal class FunctionGenerationContext(val function: LLVMValueRef, fun positionAtEnd(bbLabel: LLVMBasicBlockRef) = currentPositionHolder.positionAtEnd(bbLabel) + fun positionBefore(instruction: LLVMValueRef) = currentPositionHolder.positionBefore(instruction) + inline private fun preservingPosition(code: () -> R): R { val oldPositionHolder = currentPositionHolder val newPositionHolder = PositionHolder()