Support for built in types com parision implemented
for following code snipped:
---------------8<---------------
> cat ../backend.native/tests/codegen/function/eqeq.kt
fun eqeqB (a:Byte, b:Byte ) = a == b
fun eqeqS (a:Short, b:Short ) = a == b
fun eqeqI (a:Int, b:Int ) = a == b
fun eqeqL (a:Long, b:Long ) = a == b
fun eqeqF (a:Float, b:Float ) = a == b
fun eqeqD (a:Double, b:Double) = a == b
fun eqeqStr(a:String, b:String) = a == b
fun gtI (a:Int, b:Int ) = a > b
fun ltI (a:Int, b:Int ) = a > b
fun geI (a:Int, b:Int ) = a >= b
fun leI (a:Int, b:Int ) = a <= b
fun neI (a:Int, b:Int ) = a != b
fun gtF (a:Float, b:Float ) = a > b
fun ltF (a:Float, b:Float ) = a > b
fun geF (a:Float, b:Float ) = a >= b
fun leF (a:Float, b:Float ) = a <= b
fun neF (a:Float, b:Float ) = a != b
fun helloString() = "Hello"
fun goodbyeString() = "Goodbye"
---------------8<---------------
interesting cases here are '==' for primitive and objects and any < =< > >= and separatelly !=
---------------8<---------------
; ModuleID = '../backend.native/tests/codegen/function/eqeq.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:eqeqB(Byte;Byte)"(i8, i8) {
entry:
%a = alloca i8
store i8 %0, i8* %a
%b = alloca i8
store i8 %1, i8* %b
%tmp_1 = load i8, i8* %a
%tmp_2 = load i8, i8* %b
%tmp_0 = icmp eq i8 %tmp_1, %tmp_2 <- '==' for primitive
ret i1 %tmp_0
}
...
define i1 @"kfun:eqeqStr(String;String)"(i8*, i8*) {
entry:
%a = alloca i8*
store i8* %0, i8** %a
%b = alloca i8*
store i8* %1, i8** %b
%tmp_1 = load i8*, i8** %a
%tmp_2 = load i8*, i8** %b
%tmp_0 = call i1 @Kotlin_String_equals(i8* %tmp_1, i8* %tmp_2) <-- '==' for object
ret i1 %tmp_0
}
...
define i1 @"kfun:gtI(Int;Int)"(i32, i32) {
entry:
%a = alloca i32
store i32 %0, i32* %a
%b = alloca i32
store i32 %1, i32* %b
%tmp_2 = load i32, i32* %a
%tmp_3 = load i32, i32* %b
%tmp_1 = call i32 @Kotlin_Int_compareTo_Int(i32 %tmp_2, i32 %tmp_3) <-- '>' for primitive
%tmp_0 = icmp sgt i32 %tmp_1, 0 <--/
ret i1 %tmp_0
}
...
define i1 @"kfun:neI(Int;Int)"(i32, i32) {
entry:
%a = alloca i32
store i32 %0, i32* %a
%b = alloca i32
store i32 %1, i32* %b
%tmp_2 = load i32, i32* %a
%tmp_3 = load i32, i32* %b
%tmp_1 = icmp eq i32 %tmp_2, %tmp_3 <--- '!=' fro primitive
%tmp_0 = icmp ne i1 %tmp_1, true <--/
ret i1 %tmp_0
}
---------------8<---------------
This commit is contained in:
committed by
vvlevchenko
parent
04822dda69
commit
69b7cdb866
+5
@@ -127,6 +127,11 @@ internal class CodeGenerator(override val context:Context) : ContextUtils {
|
||||
|
||||
/* integers comparisons */
|
||||
fun icmpEq(arg0: LLVMOpaqueValue, arg1: LLVMOpaqueValue, result: String): LLVMOpaqueValue = LLVMBuildICmp(context.llvmBuilder, LLVMIntPredicate.LLVMIntEQ, arg0, arg1, result)!!
|
||||
fun icmpGt(arg0: LLVMOpaqueValue, arg1: LLVMOpaqueValue, result: String): LLVMOpaqueValue = LLVMBuildICmp(context.llvmBuilder, LLVMIntPredicate.LLVMIntSGT, arg0, arg1, result)!!
|
||||
fun icmpGe(arg0: LLVMOpaqueValue, arg1: LLVMOpaqueValue, result: String): LLVMOpaqueValue = LLVMBuildICmp(context.llvmBuilder, LLVMIntPredicate.LLVMIntSGE, arg0, arg1, result)!!
|
||||
fun icmpLt(arg0: LLVMOpaqueValue, arg1: LLVMOpaqueValue, result: String): LLVMOpaqueValue = LLVMBuildICmp(context.llvmBuilder, LLVMIntPredicate.LLVMIntSLT, arg0, arg1, result)!!
|
||||
fun icmpLe(arg0: LLVMOpaqueValue, arg1: LLVMOpaqueValue, result: String): LLVMOpaqueValue = LLVMBuildICmp(context.llvmBuilder, LLVMIntPredicate.LLVMIntSLE, arg0, arg1, result)!!
|
||||
fun icmpNe(arg0: LLVMOpaqueValue, arg1: LLVMOpaqueValue, result: String): LLVMOpaqueValue = LLVMBuildICmp(context.llvmBuilder, LLVMIntPredicate.LLVMIntNE, arg0, arg1, result)!!
|
||||
|
||||
/* floating-point comparisons */
|
||||
fun fcmpEq(arg0: LLVMOpaqueValue, arg1: LLVMOpaqueValue, result: String): LLVMOpaqueValue = LLVMBuildFCmp(context.llvmBuilder, LLVMRealPredicate.LLVMRealOEQ, arg0, arg1, result)!!
|
||||
|
||||
+42
-19
@@ -9,9 +9,11 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.impl.LazyClassReceiverParameterDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.descriptors.*
|
||||
import org.jetbrains.kotlin.ir.descriptors.IrBuiltinOperatorDescriptorBase
|
||||
import org.jetbrains.kotlin.ir.descriptors.IrTemporaryVariableDescriptor
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrBinaryPrimitiveImpl
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||
@@ -331,7 +333,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
if (value.descriptor.dispatchReceiverParameter != null) {
|
||||
if (value.descriptor.getter != null) {
|
||||
val tmpThis = codegen.load(codegen.thisVariable(), codegen.newVar())
|
||||
return evaluateSimpleFunctionCall(codegen.newVar(), value.descriptor.getter!!.original, mutableListOf(tmpThis))!!
|
||||
return evaluateSimpleFunctionCall(codegen.newVar(), value.descriptor.getter!!.original, listOf(tmpThis))!!
|
||||
} else {
|
||||
val thisPtr = codegen.load(codegen.thisVariable(), codegen.newVar())
|
||||
val typedPtr = codegen.bitcast(pointerType(codegen.classType(codegen.currentClass!!)), thisPtr, codegen.newVar())
|
||||
@@ -385,7 +387,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
|
||||
private fun evaluateSimpleFunctionCall(tmpVariableName: String, descriptor: FunctionDescriptor, args: MutableList<LLVMOpaqueValue?>): LLVMOpaqueValue? {
|
||||
private fun evaluateSimpleFunctionCall(tmpVariableName: String, descriptor: FunctionDescriptor, args: List<LLVMOpaqueValue?>): LLVMOpaqueValue? {
|
||||
//logger.log("evaluateSimpleFunctionCall : $tmpVariableName = ${ir2string(value)}")
|
||||
if (descriptor.isOverridable)
|
||||
return callVirtual(descriptor, args, tmpVariableName)
|
||||
@@ -395,7 +397,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
|
||||
private fun evaluateFunctionCall(tmpVariableName: String, callee: IrCall, args: MutableList<LLVMOpaqueValue?>): LLVMOpaqueValue? {
|
||||
private fun evaluateFunctionCall(tmpVariableName: String, callee: IrCall, args: List<LLVMOpaqueValue?>): LLVMOpaqueValue? {
|
||||
val descriptor:FunctionDescriptor = callee.descriptor as FunctionDescriptor
|
||||
when (descriptor) {
|
||||
is IrBuiltinOperatorDescriptorBase -> return evaluateOperatorCall (tmpVariableName, callee, args)
|
||||
@@ -406,7 +408,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
|
||||
private fun evaluateConstructorCall(variableName: String, callee: IrCall, args: MutableList<LLVMOpaqueValue?>): LLVMOpaqueValue? {
|
||||
private fun evaluateConstructorCall(variableName: String, callee: IrCall, args: List<LLVMOpaqueValue?>): LLVMOpaqueValue? {
|
||||
logger.log("evaluateConstructorCall : $variableName = ${ir2string(callee)}")
|
||||
memScoped {
|
||||
val containingClass = (callee.descriptor as ClassConstructorDescriptor).containingDeclaration
|
||||
@@ -414,9 +416,9 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
val allocHint = Int32(1).getLlvmValue()
|
||||
val thisValue = if (containingClass.isArray) {
|
||||
assert(args.size == 1 && LLVMTypeOf(args[0]) == LLVMInt32Type())
|
||||
codegen.call(context.allocArrayFunction, mutableListOf(typeInfo, allocHint, args[0]), variableName)
|
||||
codegen.call(context.allocArrayFunction, listOf(typeInfo, allocHint, args[0]), variableName)
|
||||
} else {
|
||||
codegen.call(context.allocInstanceFunction, mutableListOf(typeInfo, allocHint), variableName)
|
||||
codegen.call(context.allocInstanceFunction, listOf(typeInfo, allocHint), variableName)
|
||||
}
|
||||
val constructorParams: MutableList<LLVMOpaqueValue?> = mutableListOf()
|
||||
constructorParams += thisValue
|
||||
@@ -426,30 +428,51 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
private val EQEQ = Name.identifier("EQEQ")
|
||||
private val kEqeq = Name.identifier("EQEQ")
|
||||
private val kGt0 = Name.identifier("GT0")
|
||||
private val kGteq0 = Name.identifier("GTEQ0")
|
||||
private val kLt0 = Name.identifier("LT0")
|
||||
private val kLteq0 = Name.identifier("LTEQ0")
|
||||
private val kNot = Name.identifier("NOT")
|
||||
private val kImmZero = LLVMConstInt(LLVMInt32Type(), 0, 1)!!
|
||||
private val kTrue = LLVMConstInt(LLVMInt1Type(), 1, 1)!!
|
||||
private val kFalse = LLVMConstInt(LLVMInt1Type(), 0, 1)!!
|
||||
|
||||
private fun evaluateOperatorCall(tmpVariableName: String, callee: IrCall, args: MutableList<LLVMOpaqueValue?>): LLVMOpaqueValue {
|
||||
|
||||
private fun evaluateOperatorCall(tmpVariableName: String, callee: IrCall, args: List<LLVMOpaqueValue?>): LLVMOpaqueValue {
|
||||
logger.log("evaluateCall $tmpVariableName origin:$callee")
|
||||
val descriptor = callee.descriptor
|
||||
when (descriptor.name) {
|
||||
EQEQ -> return evaluateOperatorEqeq(callee as IrBinaryPrimitiveImpl, args[0]!!, args[1]!!, tmpVariableName)
|
||||
kEqeq -> return evaluateOperatorEqeq(callee as IrBinaryPrimitiveImpl, args[0]!!, args[1]!!, tmpVariableName)
|
||||
kGt0 -> return codegen.icmpGt(args[0]!!, kImmZero, tmpVariableName)
|
||||
kGteq0 -> return codegen.icmpGe(args[0]!!, kImmZero, tmpVariableName)
|
||||
kLt0 -> return codegen.icmpLt(args[0]!!, kImmZero, tmpVariableName)
|
||||
kLteq0 -> return codegen.icmpLe(args[0]!!, kImmZero, tmpVariableName)
|
||||
kNot -> return codegen.icmpNe(args[0]!!, kTrue, tmpVariableName)
|
||||
else -> {
|
||||
TODO()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
|
||||
private fun evaluateOperatorEqeq(callee: IrBinaryPrimitiveImpl, arg0: LLVMOpaqueValue, arg1: LLVMOpaqueValue, tmpVariableName: String):LLVMOpaqueValue {
|
||||
val operandType = callee.argument0.type
|
||||
assert(operandType == callee.argument1.type)
|
||||
val arg0Type = callee.argument0.type
|
||||
val isFp = KotlinBuiltIns.isDouble(arg0Type) || KotlinBuiltIns.isFloat(arg0Type)
|
||||
val isInt = KotlinBuiltIns.isPrimitiveType(arg0Type) && !isFp
|
||||
assert(arg0Type == callee.argument1.type)
|
||||
when {
|
||||
KotlinBuiltIns.isByte (operandType) -> return codegen.icmpEq(arg0, arg1, tmpVariableName)
|
||||
KotlinBuiltIns.isShort (operandType) -> return codegen.icmpEq(arg0, arg1, tmpVariableName)
|
||||
KotlinBuiltIns.isInt (operandType) -> return codegen.icmpEq(arg0, arg1, tmpVariableName)
|
||||
KotlinBuiltIns.isLong (operandType) -> return codegen.icmpEq(arg0, arg1, tmpVariableName)
|
||||
KotlinBuiltIns.isFloat (operandType) -> return codegen.fcmpEq(arg0, arg1, tmpVariableName)
|
||||
KotlinBuiltIns.isDouble(operandType) -> return codegen.fcmpEq(arg0, arg1, tmpVariableName)
|
||||
else -> TODO("ComplexType")
|
||||
isFp -> return codegen.fcmpEq(arg0, arg1, tmpVariableName)
|
||||
isInt -> return codegen.icmpEq(arg0, arg1, tmpVariableName)
|
||||
else -> {
|
||||
val functions = arg0Type.memberScope.getContributedFunctions(Name.identifier("equals"), NoLookupLocation.FROM_BACKEND).filter {
|
||||
it.valueParameters.size == 1 && KotlinBuiltIns.isAnyOrNullableAny(it.valueParameters[0].type)
|
||||
}
|
||||
assert(functions.size == 1)
|
||||
val descriptor = functions.first()
|
||||
return evaluateSimpleFunctionCall(tmpVariableName, descriptor, listOf(arg0, arg1))!!
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user