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:
committed by
vvlevchenko
parent
c1bb762417
commit
d86b387f9c
+41
-2
@@ -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)
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user