From 7b29f4854c91ab24394c6f453b80532efc7529e3 Mon Sep 17 00:00:00 2001 From: Svyatoslav Scherbina Date: Fri, 23 Dec 2016 10:41:53 +0700 Subject: [PATCH] backend: lower safe casts --- .../kotlin/backend/konan/KonanLower.kt | 3 + .../kotlin/backend/konan/KonanPhases.kt | 1 + .../kotlin/backend/konan/llvm/IrToBitcode.kt | 29 +--------- .../konan/lower/TypeOperatorLowering.kt | 56 +++++++++++++++++++ 4 files changed, 61 insertions(+), 28 deletions(-) create mode 100644 backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/TypeOperatorLowering.kt diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanLower.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanLower.kt index b31fd36d89f..ae7b3109e63 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanLower.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanLower.kt @@ -20,6 +20,9 @@ internal class KonanLower(val context: Context) { phaser.phase(KonanPhase.LOWER_BUILTIN_OPERATORS) { BuiltinOperatorLowering(context).runOnFilePostfix(irFile) } + phaser.phase(KonanPhase.LOWER_TYPE_OPERATORS) { + TypeOperatorLowering(context).runOnFilePostfix(irFile) + } phaser.phase(KonanPhase.LOWER_SHARED_VARIABLES) { SharedVariablesLowering(context).runOnFilePostfix(irFile) } diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanPhases.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanPhases.kt index ff3841afbed..bb0b9092ea9 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanPhases.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanPhases.kt @@ -9,6 +9,7 @@ enum class KonanPhase(val description: String, /* */ BACKEND("All backend"), /* ... */ LOWER("IR Lowering"), /* ... ... */ LOWER_BUILTIN_OPERATORS("BuiltIn Operators Lowering"), + /* ... ... */ LOWER_TYPE_OPERATORS("Type operators lowering"), /* ... ... */ LOWER_SHARED_VARIABLES("Shared Variable Lowering"), /* ... ... */ LOWER_LOCAL_FUNCTIONS("Local Function Lowering"), /* ... ... */ LOWER_CALLABLES("Callable references Lowering"), diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt index b7d5ceb1eaa..77f1381c9ce 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt @@ -1323,40 +1323,13 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid IrTypeOperator.IMPLICIT_CAST -> return evaluateExpression(value.argument) IrTypeOperator.IMPLICIT_NOTNULL -> TODO("${ir2string(value)}") IrTypeOperator.IMPLICIT_COERCION_TO_UNIT -> return evaluateExpression(value.argument) - IrTypeOperator.SAFE_CAST -> return evaluateSafeCast(value) + IrTypeOperator.SAFE_CAST -> throw IllegalStateException("safe cast wasn't lowered") IrTypeOperator.INSTANCEOF -> return evaluateInstanceOf(value) IrTypeOperator.NOT_INSTANCEOF -> return evaluateNotInstanceOf(value) } } - //-------------------------------------------------------------------------// - - private fun evaluateSafeCast(value: IrTypeOperatorCall): LLVMValueRef? { - val bbTrue = codegen.basicBlock() - val bbFalse = codegen.basicBlock() - val bbExit = codegen.basicBlock() - - val resultLlvmType = codegen.getLLVMType(value.type) - val result = codegen.vars.createAnonymousMutable(resultLlvmType) - - val condition = evaluateInstanceOf(value) - codegen.condBr(condition, bbTrue, bbFalse) - - codegen.positionAtEnd(bbTrue) - val castResult = evaluateExpression(value.argument) - codegen.vars.store(castResult!!, result) - codegen.br(bbExit) - - codegen.positionAtEnd(bbFalse) - val nullResult = LLVMConstNull(resultLlvmType)!! - codegen.vars.store(nullResult, result) - codegen.br(bbExit) - - codegen.positionAtEnd(bbExit) - return codegen.vars.load(result) - } - //-------------------------------------------------------------------------// // table of conversion with llvm for primitive types // to be used in replacement fo primitive.toX() calls with diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/TypeOperatorLowering.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/TypeOperatorLowering.kt new file mode 100644 index 00000000000..3c6b574f764 --- /dev/null +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/TypeOperatorLowering.kt @@ -0,0 +1,56 @@ +package org.jetbrains.kotlin.backend.konan.lower + +import org.jetbrains.kotlin.backend.common.FunctionLoweringPass +import org.jetbrains.kotlin.backend.common.lower.createFunctionIrGenerator +import org.jetbrains.kotlin.backend.common.lower.irBlock +import org.jetbrains.kotlin.backend.konan.Context +import org.jetbrains.kotlin.descriptors.FunctionDescriptor +import org.jetbrains.kotlin.ir.IrStatement +import org.jetbrains.kotlin.ir.builders.* +import org.jetbrains.kotlin.ir.declarations.IrFunction +import org.jetbrains.kotlin.ir.expressions.IrExpression +import org.jetbrains.kotlin.ir.expressions.IrTypeOperator +import org.jetbrains.kotlin.ir.expressions.IrTypeOperatorCall +import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid +import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid + +/** + * This lowering pass lowers some [IrTypeOperatorCall]s. + */ +internal class TypeOperatorLowering(val context: Context) : FunctionLoweringPass { + override fun lower(irFunction: IrFunction) { + val transformer = TypeOperatorTransformer(context, irFunction.descriptor) + irFunction.transformChildrenVoid(transformer) + } +} + + +private class TypeOperatorTransformer(val context: Context, val function: FunctionDescriptor) : IrElementTransformerVoid() { + + private val generator = context.createFunctionIrGenerator(function) + + override fun visitFunction(declaration: IrFunction): IrStatement { + // ignore inner functions during this pass + return declaration + } + + private fun lowerSafeCast(expression: IrTypeOperatorCall): IrExpression { + return generator.irBlock(expression) { + +irLet(expression.argument) { variable -> + irIfThenElse(expression.type, + condition = irIs(irGet(variable), expression.typeOperand), + thenPart = irImplicitCast(irGet(variable), expression.typeOperand), + elsePart = irNull()) + } + } + } + + override fun visitTypeOperator(expression: IrTypeOperatorCall): IrExpression { + expression.transformChildrenVoid(this) + + return when (expression.operator) { + IrTypeOperator.SAFE_CAST -> lowerSafeCast(expression) + else -> expression + } + } +} \ No newline at end of file