CODEGEN: Implemented support for "instanceOf", operations "Boolean" type implemented, operator NOT_INSTANCEOF implemented

for code
--------8<--------
> cat ../backend.native/tests/codegen/basics/check_type.kt
interface I
class A() : I {}
class B() {}

//-----------------------------------------------------------------------------//

fun isTypeOf(a: Any) : Boolean {
  return a is A
}

fun check_type(): Boolean {
  val a = A()
  return isTypeOf(a)
}

//-----------------------------------------------------------------------------//

fun isNotTypeOf(a: Any) : Boolean {
  return a !is A
}

fun check_not_type(): Boolean {
  val b = B()
  return isNotTypeOf(b)
}

//-----------------------------------------------------------------------------//

fun isTypeOfInterface(a: Any) : Boolean {
  return a is I
}

fun check_interface(): Boolean {
  val a = A()
  return isTypeOfInterface(a)
}
--------8<--------

translator generates:

--------8<--------
> llvm-dis-mp-3.8 ../backend.native/tests/codegen/basics/check_type.kt.bc -o -
; ModuleID = '../backend.native/tests/codegen/basics/check_type.kt.bc'
target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-apple-macosx10.12.0"

...
define i1 @"kfun:isTypeOf(Any)"(i8*) {
entry:
  %a = alloca i8*
  store i8* %0, i8** %a
  %tmp_1 = load i8*, i8** %a
  %tmp_2 = bitcast i8* %tmp_1 to %struct.ObjHeader*
  %tmp_3 = call i8 @IsInstance(%struct.ObjHeader* %tmp_2, %struct.TypeInfo* @"ktype:A")
  %tmp_0 = trunc i8 %tmp_3 to i1
  ret i1 %tmp_0
}
...
define i1 @"kfun:isNotTypeOf(Any)"(i8*) {
entry:
  %a = alloca i8*
  store i8* %0, i8** %a
  %tmp_2 = load i8*, i8** %a
  %tmp_3 = bitcast i8* %tmp_2 to %struct.ObjHeader*
  %tmp_4 = call i8 @IsInstance(%struct.ObjHeader* %tmp_3, %struct.TypeInfo* @"ktype:A")
  %tmp_1 = trunc i8 %tmp_4 to i1
  %tmp_0 = xor i1 %tmp_1, true
  ret i1 %tmp_0
}
...
define i1 @"kfun:isTypeOfInterface(Any)"(i8*) {
entry:
  %a = alloca i8*
  store i8* %0, i8** %a
  %tmp_1 = load i8*, i8** %a
  %tmp_2 = bitcast i8* %tmp_1 to %struct.ObjHeader*
  %tmp_3 = call i8 @IsInstance(%struct.ObjHeader* %tmp_2, %struct.TypeInfo* @"ktype:I")
  %tmp_0 = trunc i8 %tmp_3 to i1
  ret i1 %tmp_0
}

--------8<--------
This commit is contained in:
Konstantin Anisimov
2016-11-17 16:05:05 +03:00
committed by vvlevchenko
parent c1bb762417
commit d86b387f9c
3 changed files with 55 additions and 3 deletions
@@ -21,6 +21,7 @@ import org.jetbrains.kotlin.ir.visitors.acceptVoid
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.asSimpleType
fun emitLLVM(module: IrModuleFragment, runtimeFile: String, outFile: String) {
val llvmModule = LLVMModuleCreateWithName("out")!! // TODO: dispose
@@ -371,6 +372,21 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
return codegen.store(ret!!, variable)
}
//-------------------------------------------------------------------------//
private fun evaluateTypeOperator(tmpVariableName: String, value: IrTypeOperatorCall): LLVMOpaqueValue {
when (value.operator) {
IrTypeOperator.CAST -> return evaluateCast(tmpVariableName, value)
IrTypeOperator.IMPLICIT_CAST -> TODO()
IrTypeOperator.IMPLICIT_NOTNULL -> TODO()
IrTypeOperator.IMPLICIT_COERCION_TO_UNIT -> TODO()
IrTypeOperator.SAFE_CAST -> TODO()
IrTypeOperator.INSTANCEOF -> return evaluateInstanceOf(tmpVariableName, value)
IrTypeOperator.NOT_INSTANCEOF -> return evaluateNotInstanceOf(tmpVariableName, value)
}
}
//-------------------------------------------------------------------------//
// table of conversion with llvm for primitive types
// to be used in replacement fo primitive.toX() calls with
@@ -384,8 +400,8 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
// float | fptosi fptosi fptosi fptosi x fpext
// double | fptosi fptosi fptosi fptosi fptrunc x
private fun evaluateTypeOperator(tmpVariableName: String, value: IrTypeOperatorCall): LLVMOpaqueValue {
logger.log("evaluateTypeOperator : ${ir2string(value)}")
private fun evaluateCast(tmpVariableName: String, value: IrTypeOperatorCall): LLVMOpaqueValue {
logger.log("evaluateCast : ${ir2string(value)}")
assert(!KotlinBuiltIns.isPrimitiveType(value.type) && !KotlinBuiltIns.isPrimitiveType(value.argument.type))
val dstDescriptor = TypeUtils.getClassDescriptor(value.type) // Get class descriptor for dst type.
@@ -399,6 +415,28 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
//-------------------------------------------------------------------------//
private fun evaluateInstanceOf(tmpVariableName: String, value: IrTypeOperatorCall): LLVMOpaqueValue {
logger.log("evaluateInstanceOf : ${ir2string(value)}")
val dstDescriptor = TypeUtils.getClassDescriptor(value.typeOperand) // Get class descriptor for dst type.
val dstTypeInfo = codegen.typeInfoValue(dstDescriptor!!) // Get TypeInfo for dst type.
val srcArg = evaluateExpression(codegen.newVar(), value.argument)!! // Evaluate src expression.
val srcObjInfoPtr = codegen.bitcast(kObjHeaderPtr, srcArg, codegen.newVar()) // Cast src to ObjInfoPtr.
val args = listOf(srcObjInfoPtr, dstTypeInfo) // Create arg list.
val result = codegen.call(context.isInstanceFunction, args, codegen.newVar()) // Check if dst is subclass of src.
return LLVMBuildTrunc(context.llvmBuilder, result!!, kInt1, tmpVariableName)!! // Truncate result to boolean
}
//-------------------------------------------------------------------------//
private fun evaluateNotInstanceOf(tmpVariableName: String, value: IrTypeOperatorCall): LLVMOpaqueValue {
val instanceOfResult = evaluateInstanceOf(codegen.newVar(), value)
return LLVMBuildNot(context.llvmBuilder, instanceOfResult, tmpVariableName)!!
}
//-------------------------------------------------------------------------//
private fun evaluateGetField(value: IrGetField): LLVMOpaqueValue {
logger.log("evaluateGetField : ${ir2string(value)}")
if (value.descriptor.dispatchReceiverParameter != null) {
@@ -698,6 +736,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
private val kObjHeader = LLVMGetTypeByName(context.llvmModule, "struct.ObjHeader")!!
private val kObjHeaderPtr = pointerType(kObjHeader)!!
private val kTypeInfoPtr = pointerType(kTypeInfo)
private val kInt1 = LLVMInt1Type()
private val kInt8Ptr = pointerType(LLVMInt8Type())
private val kInt8PtrPtr = pointerType(kInt8Ptr)
+9 -1
View File
@@ -5,11 +5,19 @@
extern "C" {
//--- Boolean -----------------------------------------------------------------//
KBoolean Kotlin_Boolean_not (KBoolean a ) { return !a; }
KBoolean Kotlin_Boolean_and_Boolean (KBoolean a, KBoolean b) { return a && b; }
KBoolean Kotlin_Boolean_or_Boolean (KBoolean a, KBoolean b) { return a || b; }
KBoolean Kotlin_Boolean_xor_Boolean (KBoolean a, KBoolean b) { return a != b; }
KInt Kotlin_Boolean_compareTo_Boolean(KBoolean a, KBoolean b) { if (a == b) return 0; return (a < b) ? -1 : 1; }
//--- Char --------------------------------------------------------------------//
KInt Kotlin_Char_compareTo_Char (KChar a, KChar b) { if (a == b) return 0; return (a < b) ? -1 : 1; }
KChar Kotlin_Char_plus_Char (KChar a, KInt b) { return a + b; }
KChar Kotlin_Char_minus_Char (KChar a, KChar b) { return a - b; }
KInt Kotlin_Char_minus_Char (KChar a, KChar b) { return a - b; }
KChar Kotlin_Char_minus_Int (KChar a, KInt b) { return a - b; }
KChar Kotlin_Char_inc (KChar a ) { return a + 1; }
KChar Kotlin_Char_dec (KChar a ) { return a - 1; }
@@ -8,23 +8,28 @@ public final class Boolean : Comparable<Boolean> {
/**
* Returns the inverse of this boolean.
*/
@SymbolName("Kotlin_Boolean_not")
external public operator fun not(): Boolean
/**
* Performs a logical `and` operation between this Boolean and the [other] one.
*/
@SymbolName("Kotlin_Boolean_and_Boolean")
external public infix fun and(other: Boolean): Boolean
/**
* Performs a logical `or` operation between this Boolean and the [other] one.
*/
@SymbolName("Kotlin_Boolean_or_Boolean")
external public infix fun or(other: Boolean): Boolean
/**
* Performs a logical `xor` operation between this Boolean and the [other] one.
*/
@SymbolName("Kotlin_Boolean_xor_Boolean")
external public infix fun xor(other: Boolean): Boolean
@SymbolName("Kotlin_Boolean_compareTo_Boolean")
external public override fun compareTo(other: Boolean): Int
// Konan-specific.