[K/N] Eliminate frame creation in some cases

This commit is contained in:
Pavel Kunyavskiy
2022-02-04 16:22:11 +03:00
committed by Space
parent d8b1992fde
commit b575d98272
5 changed files with 157 additions and 119 deletions
@@ -458,7 +458,8 @@ internal abstract class FunctionGenerationContext(
var returnType: LLVMTypeRef? = LLVMGetReturnType(getFunctionType(function))
val constructedClass: IrClass?
get() = (irFunction as? IrConstructor)?.constructedClass
private var returnSlot: LLVMValueRef? = null
var returnSlot: LLVMValueRef? = null
private set
private var slotsPhi: LLVMValueRef? = null
private val frameOverlaySlotCount =
(LLVMStoreSizeOfType(llvmTargetData, runtime.frameOverlayType) / runtime.pointerSize).toInt()
@@ -585,10 +586,10 @@ internal abstract class FunctionGenerationContext(
return result
}
fun loadSlot(address: LLVMValueRef, isVar: Boolean, name: String = ""): LLVMValueRef {
fun loadSlot(address: LLVMValueRef, isVar: Boolean, resultSlot: LLVMValueRef? = null, name: String = ""): LLVMValueRef {
val value = LLVMBuildLoad(builder, address, name)!!
if (isObjectRef(value) && isVar) {
val slot = alloca(LLVMTypeOf(value), variableLocation = null)
val slot = resultSlot ?: alloca(LLVMTypeOf(value), variableLocation = null)
storeStackRef(value, slot)
}
return value
@@ -672,14 +673,17 @@ internal abstract class FunctionGenerationContext(
fun call(llvmCallable: LlvmCallable, args: List<LLVMValueRef>,
resultLifetime: Lifetime = Lifetime.IRRELEVANT,
exceptionHandler: ExceptionHandler = ExceptionHandler.None,
verbatim: Boolean = false): LLVMValueRef =
call(llvmCallable.llvmValue, args, resultLifetime, exceptionHandler, verbatim, llvmCallable.attributeProvider)
verbatim: Boolean = false,
resultSlot: LLVMValueRef? = null,
): LLVMValueRef =
call(llvmCallable.llvmValue, args, resultLifetime, exceptionHandler, verbatim, llvmCallable.attributeProvider, resultSlot)
fun call(llvmFunction: LLVMValueRef, args: List<LLVMValueRef>,
resultLifetime: Lifetime = Lifetime.IRRELEVANT,
exceptionHandler: ExceptionHandler = ExceptionHandler.None,
verbatim: Boolean = false,
attributeProvider: LlvmFunctionAttributeProvider? = null
attributeProvider: LlvmFunctionAttributeProvider? = null,
resultSlot: LLVMValueRef? = null
): LLVMValueRef {
val callArgs = if (verbatim || !isObjectReturn(llvmFunction.type)) {
args
@@ -687,7 +691,7 @@ internal abstract class FunctionGenerationContext(
// If function returns an object - create slot for the returned value or give local arena.
// This allows appropriate rootset accounting by just looking at the stack slots,
// along with ability to allocate in appropriate arena.
val resultSlot = when (resultLifetime.slotType) {
val realResultSlot = resultSlot ?: when (resultLifetime.slotType) {
SlotType.STACK -> {
localAllocs++
// Case of local call. Use memory allocated on stack.
@@ -705,7 +709,7 @@ internal abstract class FunctionGenerationContext(
else -> throw Error("Incorrect slot type: ${resultLifetime.slotType}")
}
args + resultSlot
args + realResultSlot
}
return callRaw(llvmFunction, callArgs, exceptionHandler, attributeProvider)
}
@@ -772,29 +776,30 @@ internal abstract class FunctionGenerationContext(
}
}
fun allocInstance(typeInfo: LLVMValueRef, lifetime: Lifetime): LLVMValueRef =
call(context.llvm.allocInstanceFunction, listOf(typeInfo), lifetime)
fun allocInstance(typeInfo: LLVMValueRef, lifetime: Lifetime, resultSlot: LLVMValueRef?): LLVMValueRef =
call(context.llvm.allocInstanceFunction, listOf(typeInfo), lifetime, resultSlot = resultSlot)
fun allocInstance(irClass: IrClass, lifetime: Lifetime, stackLocalsManager: StackLocalsManager) =
fun allocInstance(irClass: IrClass, lifetime: Lifetime, stackLocalsManager: StackLocalsManager, resultSlot: LLVMValueRef?) =
if (lifetime == Lifetime.STACK)
stackLocalsManager.alloc(irClass,
// In case the allocation is not from the root scope, fields must be cleaned up explicitly,
// as the object might be being reused.
cleanFieldsExplicitly = stackLocalsManager != this.stackLocalsManager)
else
allocInstance(codegen.typeInfoForAllocation(irClass), lifetime)
allocInstance(codegen.typeInfoForAllocation(irClass), lifetime, resultSlot)
fun allocArray(
irClass: IrClass,
count: LLVMValueRef,
lifetime: Lifetime,
exceptionHandler: ExceptionHandler
exceptionHandler: ExceptionHandler,
resultSlot: LLVMValueRef? = null
): LLVMValueRef {
val typeInfo = codegen.typeInfoValue(irClass)
return if (lifetime == Lifetime.STACK) {
stackLocalsManager.allocArray(irClass, count)
} else {
call(context.llvm.allocArrayFunction, listOf(typeInfo, count), lifetime, exceptionHandler)
call(context.llvm.allocArrayFunction, listOf(typeInfo, count), lifetime, exceptionHandler, resultSlot = resultSlot)
}
}
@@ -1235,7 +1240,8 @@ internal abstract class FunctionGenerationContext(
}
fun getObjectValue(irClass: IrClass, exceptionHandler: ExceptionHandler,
startLocationInfo: LocationInfo?, endLocationInfo: LocationInfo? = null
startLocationInfo: LocationInfo?, endLocationInfo: LocationInfo? = null,
resultSlot: LLVMValueRef? = null
): LLVMValueRef {
// TODO: could be processed the same way as other stateless objects.
if (irClass.isUnit()) {
@@ -1327,7 +1333,7 @@ internal abstract class FunctionGenerationContext(
context.llvm.initThreadLocalSingleton
}
val args = listOf(objectPtr, typeInfo, ctor)
val newValue = call(initFunction, args, Lifetime.GLOBAL, exceptionHandler)
val newValue = call(initFunction, args, Lifetime.GLOBAL, exceptionHandler, resultSlot = resultSlot)
val bbInitResult = currentBlock
br(bbExit)
@@ -114,11 +114,12 @@ internal interface IntrinsicGeneratorEnvironment {
fun calculateLifetime(element: IrElement): Lifetime
fun evaluateCall(function: IrFunction, args: List<LLVMValueRef>, resultLifetime: Lifetime, superClass: IrClass? = null): LLVMValueRef
fun evaluateCall(function: IrFunction, args: List<LLVMValueRef>, resultLifetime: Lifetime,
superClass: IrClass? = null, resultSlot: LLVMValueRef? = null): LLVMValueRef
fun evaluateExplicitArgs(expression: IrFunctionAccessExpression): List<LLVMValueRef>
fun evaluateExpression(value: IrExpression): LLVMValueRef
fun evaluateExpression(value: IrExpression, resultSlot: LLVMValueRef?): LLVMValueRef
}
internal fun tryGetIntrinsicType(callSite: IrFunctionAccessExpression): IntrinsicType? =
@@ -158,7 +159,7 @@ internal class IntrinsicGenerator(private val environment: IntrinsicGeneratorEnv
* So this method looks at [callSite] and if it is call to "special" intrinsic
* processes it. Otherwise it returns null.
*/
fun tryEvaluateSpecialCall(callSite: IrFunctionAccessExpression): LLVMValueRef? {
fun tryEvaluateSpecialCall(callSite: IrFunctionAccessExpression, resultSlot: LLVMValueRef?): LLVMValueRef? {
val function = callSite.symbol.owner
if (!function.isTypedIntrinsic) {
return null
@@ -175,34 +176,35 @@ internal class IntrinsicGenerator(private val environment: IntrinsicGeneratorEnv
}
IntrinsicType.INIT_INSTANCE -> {
val initializer = callSite.getValueArgument(1) as IrConstructorCall
val thiz = environment.evaluateExpression(callSite.getValueArgument(0)!!)
val thiz = environment.evaluateExpression(callSite.getValueArgument(0)!!, null)
environment.evaluateCall(
initializer.symbol.owner,
listOf(thiz) + environment.evaluateExplicitArgs(initializer),
environment.calculateLifetime(initializer)
environment.calculateLifetime(initializer),
)
codegen.theUnitInstanceRef.llvm
}
IntrinsicType.COROUTINE_LAUNCHPAD -> {
val suspendFunctionCall = callSite.getValueArgument(0) as IrCall
val continuation = environment.evaluateExpression(callSite.getValueArgument(1)!!)
val continuation = environment.evaluateExpression(callSite.getValueArgument(1)!!, null)
val suspendFunction = suspendFunctionCall.symbol.owner
assert(suspendFunction.isSuspend) { "Call to a suspend function expected but was ${suspendFunction.dump()}" }
environment.evaluateCall(suspendFunction,
environment.evaluateExplicitArgs(suspendFunctionCall) + listOf(continuation),
environment.calculateLifetime(suspendFunctionCall),
suspendFunction.parent as? IrClass // Call non-virtually.
suspendFunction.parent as? IrClass, // Call non-virtually.
resultSlot,
)
}
else -> null
}
}
fun evaluateCall(callSite: IrCall, args: List<LLVMValueRef>): LLVMValueRef =
environment.functionGenerationContext.evaluateCall(callSite, args)
fun evaluateCall(callSite: IrCall, args: List<LLVMValueRef>, resultSlot: LLVMValueRef?): LLVMValueRef =
environment.functionGenerationContext.evaluateCall(callSite, args, resultSlot)
// Assuming that we checked for `TypedIntrinsic` annotation presence.
private fun FunctionGenerationContext.evaluateCall(callSite: IrCall, args: List<LLVMValueRef>): LLVMValueRef =
private fun FunctionGenerationContext.evaluateCall(callSite: IrCall, args: List<LLVMValueRef>, resultSlot: LLVMValueRef?): LLVMValueRef =
when (val intrinsicType = getIntrinsicType(callSite)) {
IntrinsicType.PLUS -> emitPlus(args)
IntrinsicType.MINUS -> emitMinus(args)
@@ -246,7 +248,7 @@ internal class IntrinsicGenerator(private val environment: IntrinsicGeneratorEnv
IntrinsicType.INTEROP_READ_PRIMITIVE -> emitReadPrimitive(callSite, args)
IntrinsicType.INTEROP_WRITE_PRIMITIVE -> emitWritePrimitive(callSite, args)
IntrinsicType.INTEROP_GET_POINTER_SIZE -> emitGetPointerSize()
IntrinsicType.CREATE_UNINITIALIZED_INSTANCE -> emitCreateUninitializedInstance(callSite)
IntrinsicType.CREATE_UNINITIALIZED_INSTANCE -> emitCreateUninitializedInstance(callSite, resultSlot)
IntrinsicType.INTEROP_NATIVE_PTR_TO_LONG -> emitNativePtrToLong(callSite, args)
IntrinsicType.INTEROP_NATIVE_PTR_PLUS_LONG -> emitNativePtrPlusLong(args)
IntrinsicType.INTEROP_GET_NATIVE_NULL_PTR -> emitGetNativeNullPtr()
@@ -322,11 +324,11 @@ internal class IntrinsicGenerator(private val environment: IntrinsicGeneratorEnv
}
}
private fun FunctionGenerationContext.emitCreateUninitializedInstance(callSite: IrCall): LLVMValueRef {
private fun FunctionGenerationContext.emitCreateUninitializedInstance(callSite: IrCall, resultSlot: LLVMValueRef?): LLVMValueRef {
val typeParameterT = context.ir.symbols.createUninitializedInstance.descriptor.typeParameters[0]
val enumClass = callSite.getTypeArgument(typeParameterT)!!
val enumIrClass = enumClass.getClass()!!
return allocInstance(enumIrClass, environment.calculateLifetime(callSite), environment.stackLocalsManager)
return allocInstance(enumIrClass, environment.calculateLifetime(callSite), environment.stackLocalsManager, resultSlot)
}
private fun FunctionGenerationContext.emitGetPointerSize(): LLVMValueRef =
@@ -135,6 +135,8 @@ private interface CodeContext {
*/
fun genReturn(target: IrSymbolOwner, value: LLVMValueRef?)
fun getReturnSlot(target: IrSymbolOwner) : LLVMValueRef?
fun genBreak(destination: IrBreak)
fun genContinue(destination: IrContinue)
@@ -159,7 +161,7 @@ private interface CodeContext {
*
* @return the requested value
*/
fun genGetValue(value: IrValueDeclaration): LLVMValueRef
fun genGetValue(value: IrValueDeclaration, resultSlot: LLVMValueRef?): LLVMValueRef
/**
* Returns owning function scope.
@@ -230,14 +232,14 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
override val stackLocalsManager: StackLocalsManager
get() = currentCodeContext.stackLocalsManager
override fun evaluateCall(function: IrFunction, args: List<LLVMValueRef>, resultLifetime: Lifetime, superClass: IrClass?) =
evaluateSimpleFunctionCall(function, args, resultLifetime, superClass)
override fun evaluateCall(function: IrFunction, args: List<LLVMValueRef>, resultLifetime: Lifetime, superClass: IrClass?, resultSlot: LLVMValueRef?) =
evaluateSimpleFunctionCall(function, args, resultLifetime, superClass, resultSlot)
override fun evaluateExplicitArgs(expression: IrFunctionAccessExpression): List<LLVMValueRef> =
this@CodeGeneratorVisitor.evaluateExplicitArgs(expression)
override fun evaluateExpression(value: IrExpression): LLVMValueRef =
this@CodeGeneratorVisitor.evaluateExpression(value)
override fun evaluateExpression(value: IrExpression, resultSlot: LLVMValueRef?): LLVMValueRef =
this@CodeGeneratorVisitor.evaluateExpression(value, resultSlot)
}
private val intrinsicGenerator = IntrinsicGenerator(intrinsicGeneratorEnvironment)
@@ -252,6 +254,8 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
override fun genReturn(target: IrSymbolOwner, value: LLVMValueRef?) = unsupported(target)
override fun getReturnSlot(target: IrSymbolOwner): LLVMValueRef? = unsupported(target)
override fun genBreak(destination: IrBreak) = unsupported()
override fun genContinue(destination: IrContinue) = unsupported()
@@ -264,7 +268,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
override fun getDeclaredValue(value: IrValueDeclaration) = -1
override fun genGetValue(value: IrValueDeclaration) = unsupported(value)
override fun genGetValue(value: IrValueDeclaration, resultSlot: LLVMValueRef?) = unsupported(value)
override fun functionScope(): CodeContext? = null
@@ -516,7 +520,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
.filter { it.storageKind(context) == FieldStorageKind.THREAD_LOCAL }
.forEach { initThreadLocalField(it) }
context.llvm.initializersGenerationState.moduleThreadLocalInitializers.forEach {
evaluateSimpleFunctionCall(it, emptyList(), Lifetime.IRRELEVANT)
evaluateSimpleFunctionCall(it, emptyList(), Lifetime.IRRELEVANT, null)
}
ret(null)
}
@@ -666,12 +670,12 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
return if (index < 0) super.getDeclaredValue(value) else index
}
override fun genGetValue(value: IrValueDeclaration): LLVMValueRef {
override fun genGetValue(value: IrValueDeclaration, resultSlot: LLVMValueRef?): LLVMValueRef {
val index = functionGenerationContext.vars.indexOf(value)
if (index < 0) {
return super.genGetValue(value)
return super.genGetValue(value, resultSlot)
} else {
return functionGenerationContext.vars.load(index)
return functionGenerationContext.vars.load(index, resultSlot)
}
}
}
@@ -701,12 +705,12 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
}
}
override fun genGetValue(value: IrValueDeclaration): LLVMValueRef {
override fun genGetValue(value: IrValueDeclaration, resultSlot: LLVMValueRef?): LLVMValueRef {
val index = functionGenerationContext.vars.indexOf(value)
if (index < 0) {
return super.genGetValue(value)
return super.genGetValue(value, resultSlot)
} else {
return functionGenerationContext.vars.load(index)
return functionGenerationContext.vars.load(index, resultSlot)
}
}
}
@@ -740,6 +744,14 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
}
}
override fun getReturnSlot(target: IrSymbolOwner) : LLVMValueRef? {
return if (declaration == null || target == declaration) {
functionGenerationContext.returnSlot
} else {
super.getReturnSlot(target)
}
}
override val exceptionHandler: ExceptionHandler
get() = ExceptionHandler.Caller
@@ -844,7 +856,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
callDirect(context.ir.symbols.throwIllegalStateExceptionWithMessage.owner,
listOf(context.llvm.staticData.kotlinStringLiteral(
"unsupported call of reified inlined function `${declaration.fqNameForIrSerialization}`").llvm),
Lifetime.IRRELEVANT)
Lifetime.IRRELEVANT, null)
return@usingVariableScope
}
when (body) {
@@ -970,37 +982,37 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
//-------------------------------------------------------------------------//
private fun evaluateExpression(value: IrExpression): LLVMValueRef {
private fun evaluateExpression(value: IrExpression, resultSlot: LLVMValueRef? = null): LLVMValueRef {
updateBuilderDebugLocation(value)
recordCoverage(value)
when (value) {
is IrTypeOperatorCall -> return evaluateTypeOperator (value)
is IrCall -> return evaluateCall (value)
is IrTypeOperatorCall -> return evaluateTypeOperator (value, resultSlot)
is IrCall -> return evaluateCall (value, resultSlot)
is IrDelegatingConstructorCall ->
return evaluateCall (value)
is IrConstructorCall -> return evaluateCall (value)
return evaluateCall (value, resultSlot)
is IrConstructorCall -> return evaluateCall (value, resultSlot)
is IrInstanceInitializerCall ->
return evaluateInstanceInitializerCall(value)
is IrGetValue -> return evaluateGetValue (value)
is IrGetValue -> return evaluateGetValue (value, resultSlot)
is IrSetValue -> return evaluateSetValue (value)
is IrGetField -> return evaluateGetField (value)
is IrGetField -> return evaluateGetField (value, resultSlot)
is IrSetField -> return evaluateSetField (value)
is IrConst<*> -> return evaluateConst (value).llvm
is IrReturn -> return evaluateReturn (value)
is IrWhen -> return evaluateWhen (value)
is IrWhen -> return evaluateWhen (value, resultSlot)
is IrThrow -> return evaluateThrow (value)
is IrTry -> return evaluateTry (value)
is IrReturnableBlock -> return evaluateReturnableBlock (value)
is IrContainerExpression -> return evaluateContainerExpression (value)
is IrReturnableBlock -> return evaluateReturnableBlock (value, resultSlot)
is IrContainerExpression -> return evaluateContainerExpression (value, resultSlot)
is IrWhileLoop -> return evaluateWhileLoop (value)
is IrDoWhileLoop -> return evaluateDoWhileLoop (value)
is IrVararg -> return evaluateVararg (value)
is IrBreak -> return evaluateBreak (value)
is IrContinue -> return evaluateContinue (value)
is IrGetObjectValue -> return evaluateGetObjectValue (value)
is IrGetObjectValue -> return evaluateGetObjectValue (value, resultSlot)
is IrFunctionReference -> return evaluateFunctionReference (value)
is IrSuspendableExpression ->
return evaluateSuspendableExpression (value)
return evaluateSuspendableExpression (value, resultSlot)
is IrSuspensionPoint -> return evaluateSuspensionPoint (value)
is IrClassReference -> return evaluateClassReference (value)
is IrConstantValue -> return evaluateConstantValue (value).llvm
@@ -1022,12 +1034,13 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
//-------------------------------------------------------------------------//
private fun evaluateGetObjectValue(value: IrGetObjectValue): LLVMValueRef =
private fun evaluateGetObjectValue(value: IrGetObjectValue, resultSlot: LLVMValueRef?): LLVMValueRef =
functionGenerationContext.getObjectValue(
value.symbol.owner,
currentCodeContext.exceptionHandler,
value.startLocation,
value.endLocation
value.endLocation,
resultSlot
)
@@ -1286,7 +1299,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
}
}
private fun evaluateWhen(expression: IrWhen): LLVMValueRef {
private fun evaluateWhen(expression: IrWhen, resultSlot: LLVMValueRef?): LLVMValueRef {
context.log{"evaluateWhen : ${ir2string(expression)}"}
val whenEmittingContext = WhenEmittingContext(expression)
@@ -1297,7 +1310,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
null
else
functionGenerationContext.basicBlock("when_next", it.startLocation, it.endLocation)
generateWhenCase(whenEmittingContext, it, bbNext)
generateWhenCase(whenEmittingContext, it, bbNext, resultSlot)
}
if (whenEmittingContext.bbExit.isInitialized())
@@ -1320,15 +1333,15 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
}
}
private fun generateWhenCase(whenEmittingContext: WhenEmittingContext, branch: IrBranch, bbNext: LLVMBasicBlockRef?) {
private fun generateWhenCase(whenEmittingContext: WhenEmittingContext, branch: IrBranch, bbNext: LLVMBasicBlockRef?, resultSlot: LLVMValueRef?) {
val brResult = if (branch.isUnconditional())
evaluateExpression(branch.result)
evaluateExpression(branch.result, resultSlot)
else {
val bbCase = functionGenerationContext.basicBlock("when_case", branch.startLocation, branch.endLocation)
val condition = evaluateExpression(branch.condition)
functionGenerationContext.condBr(condition, bbCase, bbNext ?: whenEmittingContext.bbExit.value)
functionGenerationContext.positionAtEnd(bbCase)
evaluateExpression(branch.result)
evaluateExpression(branch.result, resultSlot)
}
if (!functionGenerationContext.isAfterTerminator()) {
if (whenEmittingContext.needsPhi)
@@ -1392,15 +1405,21 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
//-------------------------------------------------------------------------//
private fun evaluateGetValue(value: IrGetValue): LLVMValueRef {
private fun evaluateGetValue(value: IrGetValue, resultSlot: LLVMValueRef?): LLVMValueRef {
context.log{"evaluateGetValue : ${ir2string(value)}"}
return currentCodeContext.genGetValue(value.symbol.owner)
return currentCodeContext.genGetValue(value.symbol.owner, resultSlot)
}
//-------------------------------------------------------------------------//
private fun evaluateSetValue(value: IrSetValue): LLVMValueRef {
context.log{"evaluateSetValue : ${ir2string(value)}"}
/*
* Probably, here returnSlot optimization can be done, for not creating extra slot and reuse slot for a variable.
* On the other side, eliminating extra slot is not so profitable, as eliminating all slots in a function,
* while removing this slot is dangerous, as it needs to be accurate with setting variable inside expression.
* So optimization was not implemented here for now.
*/
val result = evaluateExpression(value.value)
val variable = currentCodeContext.getDeclaredValue(value.symbol.owner)
functionGenerationContext.vars.store(result, variable)
@@ -1467,11 +1486,11 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
//-------------------------------------------------------------------------//
private fun evaluateTypeOperator(value: IrTypeOperatorCall): LLVMValueRef {
private fun evaluateTypeOperator(value: IrTypeOperatorCall, resultSlot: LLVMValueRef?): LLVMValueRef {
return when (value.operator) {
IrTypeOperator.CAST -> evaluateCast(value)
IrTypeOperator.CAST -> evaluateCast(value, resultSlot)
IrTypeOperator.IMPLICIT_INTEGER_COERCION -> evaluateIntegerCoercion(value)
IrTypeOperator.IMPLICIT_CAST -> evaluateExpression(value.argument)
IrTypeOperator.IMPLICIT_CAST -> evaluateExpression(value.argument, resultSlot)
IrTypeOperator.IMPLICIT_NOTNULL -> TODO(ir2string(value))
IrTypeOperator.IMPLICIT_COERCION_TO_UNIT -> {
evaluateExpression(value.argument)
@@ -1530,12 +1549,12 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
// float | fptosi fptosi fptosi fptosi x fpext
// double | fptosi fptosi fptosi fptosi fptrunc x
private fun evaluateCast(value: IrTypeOperatorCall): LLVMValueRef {
private fun evaluateCast(value: IrTypeOperatorCall, resultSlot: LLVMValueRef?): LLVMValueRef {
context.log{"evaluateCast : ${ir2string(value)}"}
val dstClass = value.typeOperand.getClass()
?: error("No class for ${value.typeOperand.render()} from \n${functionGenerationContext.irFunction?.render()}")
val srcArg = evaluateExpression(value.argument)
val srcArg = evaluateExpression(value.argument, resultSlot)
assert(srcArg.type == codegen.kObjHeaderPtr)
with(functionGenerationContext) {
@@ -1544,14 +1563,16 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
callDirect(
context.ir.symbols.throwTypeCastException.owner,
emptyList(),
Lifetime.GLOBAL
Lifetime.GLOBAL,
null
)
} else {
val dstTypeInfo = functionGenerationContext.bitcast(kInt8Ptr, codegen.typeInfoValue(dstClass))
callDirect(
context.ir.symbols.throwClassCastException.owner,
listOf(srcArg, dstTypeInfo),
Lifetime.GLOBAL
Lifetime.GLOBAL,
null
)
}
}
@@ -1628,7 +1649,8 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
val objCObject = callDirect(
context.ir.symbols.interopObjCObjectRawValueGetter.owner,
listOf(obj),
Lifetime.IRRELEVANT
Lifetime.IRRELEVANT,
null
)
return if (dstClass.isObjCClass()) {
@@ -1689,12 +1711,12 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
//-------------------------------------------------------------------------//
private fun evaluateGetField(value: IrGetField): LLVMValueRef {
private fun evaluateGetField(value: IrGetField, resultSlot: LLVMValueRef?): LLVMValueRef {
context.log { "evaluateGetField : ${ir2string(value)}" }
return if (!value.symbol.owner.isStatic) {
val thisPtr = evaluateExpression(value.receiver!!)
functionGenerationContext.loadSlot(
fieldPtrOfClass(thisPtr, value.symbol.owner), !value.symbol.owner.isFinal)
fieldPtrOfClass(thisPtr, value.symbol.owner), !value.symbol.owner.isFinal, resultSlot)
} else {
assert(value.receiver == null)
if (value.symbol.owner.correspondingPropertySymbol?.owner?.isConst == true) {
@@ -1706,7 +1728,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
val ptr = context.llvmDeclarations.forStaticField(value.symbol.owner).storageAddressAccess.getAddress(
functionGenerationContext
)
functionGenerationContext.loadSlot(ptr, !value.symbol.owner.isFinal)
functionGenerationContext.loadSlot(ptr, !value.symbol.owner.isFinal, resultSlot)
}
}.also {
if (value.type.classifierOrNull?.isClassWithFqName(vectorType) == true)
@@ -1912,17 +1934,15 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
private fun evaluateReturn(expression: IrReturn): LLVMValueRef {
context.log{"evaluateReturn : ${ir2string(expression)}"}
val value = expression.value
val evaluated = evaluateExpression(value)
val target = expression.returnTargetSymbol.owner
val evaluated = evaluateExpression(value, currentCodeContext.getReturnSlot(target))
currentCodeContext.genReturn(target, evaluated)
return codegen.kNothingFakeValue
}
//-------------------------------------------------------------------------//
private inner class ReturnableBlockScope(val returnableBlock: IrReturnableBlock) :
private inner class ReturnableBlockScope(val returnableBlock: IrReturnableBlock, val resultSlot: LLVMValueRef?) :
FileScope(returnableBlock.inlineFunctionSymbol?.owner?.let {
context.specialDeclarationsFactory.loweredInlineFunctions[it]?.irFile ?: it.fileOrNull
}
@@ -1970,6 +1990,14 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
}
}
override fun getReturnSlot(target: IrSymbolOwner) : LLVMValueRef? {
return if (target == returnableBlock) {
resultSlot
} else {
super.getReturnSlot(target)
}
}
override fun returnableBlockScope(): CodeContext? = this
override fun location(offset: Int): LocationInfo? {
@@ -2028,10 +2056,10 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
}
//-------------------------------------------------------------------------//
private fun evaluateReturnableBlock(value: IrReturnableBlock): LLVMValueRef {
private fun evaluateReturnableBlock(value: IrReturnableBlock, resultSlot: LLVMValueRef?): LLVMValueRef {
context.log{"evaluateReturnableBlock : ${value.statements.forEach { ir2string(it) }}"}
val returnableBlockScope = ReturnableBlockScope(value)
val returnableBlockScope = ReturnableBlockScope(value, resultSlot)
generateDebugTrambolineIf("inline", value)
using(returnableBlockScope) {
using(VariableScope()) {
@@ -2058,7 +2086,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
//-------------------------------------------------------------------------//
private fun evaluateContainerExpression(value: IrContainerExpression): LLVMValueRef {
private fun evaluateContainerExpression(value: IrContainerExpression, resultSlot: LLVMValueRef?): LLVMValueRef {
context.log{"evaluateContainerExpression : ${value.statements.forEach { ir2string(it) }}"}
val scope = if (value.isTransparentScope) {
@@ -2073,7 +2101,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
}
value.statements.lastOrNull()?.let {
if (it is IrExpression) {
return evaluateExpression(it)
return evaluateExpression(it, resultSlot)
} else {
generateStatement(it)
}
@@ -2090,18 +2118,18 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
}
//-------------------------------------------------------------------------//
private fun evaluateCall(value: IrFunctionAccessExpression): LLVMValueRef {
private fun evaluateCall(value: IrFunctionAccessExpression, resultSlot: LLVMValueRef?): LLVMValueRef {
context.log{"evaluateCall : ${ir2string(value)}"}
intrinsicGenerator.tryEvaluateSpecialCall(value)?.let { return it }
intrinsicGenerator.tryEvaluateSpecialCall(value, resultSlot)?.let { return it }
val args = evaluateExplicitArgs(value)
updateBuilderDebugLocation(value)
return when (value) {
is IrDelegatingConstructorCall -> delegatingConstructorCall(value.symbol.owner, args)
is IrConstructorCall -> evaluateConstructorCall(value, args)
else -> evaluateFunctionCall(value as IrCall, args, resultLifetime(value))
is IrConstructorCall -> evaluateConstructorCall(value, args, resultSlot)
else -> evaluateFunctionCall(value as IrCall, args, resultLifetime(value), resultSlot)
}
}
@@ -2247,7 +2275,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
// Suspend call from non-suspend function - must be [invokeSuspend].
assert ((caller as IrSimpleFunction).overrides(context.ir.symbols.invokeSuspendFunction.owner),
{ "Expected 'BaseContinuationImpl.invokeSuspend' but was '$caller'" })
currentCodeContext.genGetValue(caller.dispatchReceiverParameter!!)
currentCodeContext.genGetValue(caller.dispatchReceiverParameter!!, null)
}
}
@@ -2296,7 +2324,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
}
}
private fun evaluateSuspendableExpression(expression: IrSuspendableExpression): LLVMValueRef {
private fun evaluateSuspendableExpression(expression: IrSuspendableExpression, resultSlot: LLVMValueRef?): LLVMValueRef {
val suspensionPointId = evaluateExpression(expression.suspensionPointId)
val bbStart = functionGenerationContext.basicBlock("start", expression.result.startLocation)
val bbDispatch = functionGenerationContext.basicBlock("dispatch", expression.suspensionPointId.startLocation)
@@ -2306,7 +2334,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
functionGenerationContext.condBr(functionGenerationContext.icmpEq(suspensionPointId, kNullInt8Ptr), bbStart, bbDispatch)
functionGenerationContext.positionAtEnd(bbStart)
val result = evaluateExpression(expression.result)
val result = evaluateExpression(expression.result, resultSlot)
functionGenerationContext.appendingTo(bbDispatch) {
if (context.config.indirectBranchesAreAllowed)
@@ -2327,14 +2355,14 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
private inner class SuspensionPointScope(val suspensionPointId: IrVariable,
val bbResume: LLVMBasicBlockRef,
val bbResumeId: Int): InnerScopeImpl() {
override fun genGetValue(value: IrValueDeclaration): LLVMValueRef {
override fun genGetValue(value: IrValueDeclaration, resultSlot: LLVMValueRef?): LLVMValueRef {
if (value == suspensionPointId) {
return if (context.config.indirectBranchesAreAllowed)
functionGenerationContext.blockAddress(bbResume)
else
functionGenerationContext.intToPtr(Int32(bbResumeId + 1).llvm, int8TypePtr)
}
return super.genGetValue(value)
return super.genGetValue(value, resultSlot)
}
}
@@ -2367,19 +2395,19 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
//-------------------------------------------------------------------------//
private fun evaluateFunctionCall(callee: IrCall, args: List<LLVMValueRef>,
resultLifetime: Lifetime): LLVMValueRef {
resultLifetime: Lifetime, resultSlot: LLVMValueRef?): LLVMValueRef {
val function = callee.symbol.owner
val argsWithContinuationIfNeeded = if (function.isSuspend)
args + getContinuation()
else args
return when {
function.isTypedIntrinsic -> intrinsicGenerator.evaluateCall(callee, args)
function.isTypedIntrinsic -> intrinsicGenerator.evaluateCall(callee, args, resultSlot)
function.isBuiltInOperator -> evaluateOperatorCall(callee, argsWithContinuationIfNeeded)
function.origin == DECLARATION_ORIGIN_FILE_GLOBAL_INITIALIZER -> evaluateFileGlobalInitializerCall(function)
function.origin == DECLARATION_ORIGIN_FILE_THREAD_LOCAL_INITIALIZER -> evaluateFileThreadLocalInitializerCall(function)
function.origin == DECLARATION_ORIGIN_FILE_STANDALONE_THREAD_LOCAL_INITIALIZER -> evaluateFileStandaloneThreadLocalInitializerCall(function)
else -> evaluateSimpleFunctionCall(function, argsWithContinuationIfNeeded, resultLifetime, callee.superQualifierSymbol?.owner)
else -> evaluateSimpleFunctionCall(function, argsWithContinuationIfNeeded, resultLifetime, callee.superQualifierSymbol?.owner, resultSlot)
}
}
@@ -2452,12 +2480,12 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
private fun evaluateSimpleFunctionCall(
function: IrFunction, args: List<LLVMValueRef>,
resultLifetime: Lifetime, superClass: IrClass? = null): LLVMValueRef {
resultLifetime: Lifetime, superClass: IrClass? = null, resultSlot: LLVMValueRef? = null): LLVMValueRef {
//context.log{"evaluateSimpleFunctionCall : $tmpVariableName = ${ir2string(value)}"}
if (superClass == null && function is IrSimpleFunction && function.isOverridable)
return callVirtual(function, args, resultLifetime)
return callVirtual(function, args, resultLifetime, resultSlot)
else
return callDirect(function, args, resultLifetime)
return callDirect(function, args, resultLifetime, resultSlot)
}
//-------------------------------------------------------------------------//
@@ -2465,7 +2493,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
return lifetimes.getOrElse(callee) { /* TODO: make IRRELEVANT */ Lifetime.GLOBAL }
}
private fun evaluateConstructorCall(callee: IrConstructorCall, args: List<LLVMValueRef>): LLVMValueRef {
private fun evaluateConstructorCall(callee: IrConstructorCall, args: List<LLVMValueRef>, resultSlot: LLVMValueRef?): LLVMValueRef {
context.log{"evaluateConstructorCall : ${ir2string(callee)}"}
return memScoped {
val constructedClass = callee.symbol.owner.constructedClass
@@ -2473,19 +2501,19 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
constructedClass.isArray -> {
assert(args.isNotEmpty() && args[0].type == int32Type)
functionGenerationContext.allocArray(constructedClass, args[0],
resultLifetime(callee), currentCodeContext.exceptionHandler)
resultLifetime(callee), currentCodeContext.exceptionHandler, resultSlot = resultSlot)
}
constructedClass == context.ir.symbols.string.owner -> {
// TODO: consider returning the empty string literal instead.
assert(args.isEmpty())
functionGenerationContext.allocArray(constructedClass, count = kImmZero,
lifetime = resultLifetime(callee), exceptionHandler = currentCodeContext.exceptionHandler)
lifetime = resultLifetime(callee), exceptionHandler = currentCodeContext.exceptionHandler, resultSlot = resultSlot)
}
constructedClass.isObjCClass() -> error("Call should've been lowered: ${callee.dump()}")
else -> functionGenerationContext.allocInstance(constructedClass, resultLifetime(callee),
currentCodeContext.stackLocalsManager)
currentCodeContext.stackLocalsManager, resultSlot = resultSlot)
}
evaluateSimpleFunctionCall(callee.symbol.owner,
listOf(thisValue) + args, Lifetime.IRRELEVANT /* constructor doesn't return anything */)
@@ -2571,7 +2599,8 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
callDirect(
context.ir.symbols.throwIllegalArgumentExceptionWithMessage.owner,
args,
Lifetime.GLOBAL
Lifetime.GLOBAL,
null
)
}
else -> TODO(function.name.toString())
@@ -2583,16 +2612,16 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
//-------------------------------------------------------------------------//
fun callDirect(function: IrFunction, args: List<LLVMValueRef>, resultLifetime: Lifetime): LLVMValueRef {
fun callDirect(function: IrFunction, args: List<LLVMValueRef>, resultLifetime: Lifetime, resultSlot: LLVMValueRef?): LLVMValueRef {
val functionDeclarations = codegen.llvmFunction(function.target)
return call(function, functionDeclarations, args, resultLifetime)
return call(function, functionDeclarations, args, resultLifetime, resultSlot)
}
//-------------------------------------------------------------------------//
fun callVirtual(function: IrFunction, args: List<LLVMValueRef>, resultLifetime: Lifetime): LLVMValueRef {
fun callVirtual(function: IrFunction, args: List<LLVMValueRef>, resultLifetime: Lifetime, resultSlot: LLVMValueRef?): LLVMValueRef {
val functionDeclarations = functionGenerationContext.lookupVirtualImpl(args.first(), function)
return call(function, functionDeclarations, args, resultLifetime)
return call(function, functionDeclarations, args, resultLifetime, resultSlot)
}
//-------------------------------------------------------------------------//
@@ -2610,7 +2639,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
}
private fun call(function: IrFunction, llvmCallable: LlvmCallable, args: List<LLVMValueRef>,
resultLifetime: Lifetime): LLVMValueRef {
resultLifetime: Lifetime, resultSlot: LLVMValueRef?): LLVMValueRef {
check(!function.isTypedIntrinsic)
val needsNativeThreadState = function.needsNativeThreadState
@@ -2627,7 +2656,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
functionGenerationContext.switchThreadState(ThreadState.Native)
}
val result = call(llvmCallable, args, resultLifetime, exceptionHandler)
val result = call(llvmCallable, args, resultLifetime, exceptionHandler, resultSlot)
when {
!function.isSuspend && function.returnType.isNothing() ->
@@ -2647,8 +2676,9 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
function: LlvmCallable, args: List<LLVMValueRef>,
resultLifetime: Lifetime = Lifetime.IRRELEVANT,
exceptionHandler: ExceptionHandler = currentCodeContext.exceptionHandler,
resultSlot: LLVMValueRef? = null
): LLVMValueRef {
return functionGenerationContext.call(function, args, resultLifetime, exceptionHandler)
return functionGenerationContext.call(function, args, resultLifetime, exceptionHandler, resultSlot = resultSlot)
}
//-------------------------------------------------------------------------//
@@ -2656,7 +2686,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
private fun delegatingConstructorCall(constructor: IrConstructor, args: List<LLVMValueRef>): LLVMValueRef {
val constructedClass = functionGenerationContext.constructedClass!!
val thisPtr = currentCodeContext.genGetValue(constructedClass.thisReceiver!!)
val thisPtr = currentCodeContext.genGetValue(constructedClass.thisReceiver!!, null)
if (constructor.constructedClass.isExternalObjCClass() || constructor.constructedClass.isAny()) {
assert(args.isEmpty())
@@ -2672,7 +2702,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
}
return callDirect(constructor, listOf(thisPtrArg) + args,
Lifetime.IRRELEVANT /* no value returned */)
Lifetime.IRRELEVANT /* no value returned */, null)
}
//-------------------------------------------------------------------------//
@@ -18,13 +18,13 @@ internal fun IrElement.needDebugInfo(context: Context) = context.shouldContainDe
internal class VariableManager(val functionGenerationContext: FunctionGenerationContext) {
internal interface Record {
fun load() : LLVMValueRef
fun load(resultSlot: LLVMValueRef?) : LLVMValueRef
fun store(value: LLVMValueRef)
fun address() : LLVMValueRef
}
inner class SlotRecord(val address: LLVMValueRef, val refSlot: Boolean, val isVar: Boolean) : Record {
override fun load() : LLVMValueRef = functionGenerationContext.loadSlot(address, isVar)
override fun load(resultSlot: LLVMValueRef?) : LLVMValueRef = functionGenerationContext.loadSlot(address, isVar, resultSlot)
override fun store(value: LLVMValueRef) {
functionGenerationContext.storeAny(value, address, true)
}
@@ -33,14 +33,14 @@ internal class VariableManager(val functionGenerationContext: FunctionGeneration
}
inner class ParameterRecord(val address: LLVMValueRef, val refSlot: Boolean) : Record {
override fun load(): LLVMValueRef = functionGenerationContext.loadSlot(address, false)
override fun load(resultSlot: LLVMValueRef?): LLVMValueRef = functionGenerationContext.loadSlot(address, false, resultSlot)
override fun store(value: LLVMValueRef) = functionGenerationContext.store(value, address)
override fun address() : LLVMValueRef = this.address
override fun toString() = (if (refSlot) "refslot" else "slot") + " for ${address}"
}
class ValueRecord(val value: LLVMValueRef, val name: Name) : Record {
override fun load() : LLVMValueRef = value
override fun load(resultSlot: LLVMValueRef?) : LLVMValueRef = value
override fun store(value: LLVMValueRef) = throw Error("writing to immutable: ${name}")
override fun address() : LLVMValueRef = throw Error("no address for: ${name}")
override fun toString() = "value of ${value} from ${name}"
@@ -135,8 +135,8 @@ internal class VariableManager(val functionGenerationContext: FunctionGeneration
return variables[index].address()
}
fun load(index: Int): LLVMValueRef {
return variables[index].load()
fun load(index: Int, resultSlot: LLVMValueRef?): LLVMValueRef {
return variables[index].load(resultSlot)
}
fun store(value: LLVMValueRef, index: Int) {
@@ -100,7 +100,7 @@ internal fun ObjCExportCodeGeneratorBase.generateBlockToKotlinFunctionConverter(
val retainedBlockPtr = callFromBridge(retainBlock, listOf(blockPtr))
val result = if (useSeparateHolder) {
val result = allocInstance(typeInfo.llvm, Lifetime.RETURN_VALUE)
val result = allocInstance(typeInfo.llvm, Lifetime.RETURN_VALUE, null)
val bodyPtr = bitcast(pointerType(bodyType), result)
val holder = allocInstanceWithAssociatedObject(
symbols.interopForeignObjCObject.owner.typeInfoPtr,