Fix basic blocks order for WHEN expression

Merge-request: KT-MR-6833
Merged-by: Vladimir Sukharev <Vladimir.Sukharev@jetbrains.com>
This commit is contained in:
Vladimir Sukharev
2022-08-11 08:27:06 +00:00
committed by Space
parent 4aad666d3c
commit 9f2cdb0130
7 changed files with 106 additions and 75 deletions
@@ -1283,12 +1283,16 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
* }
* we cannot determine if the result of when is assigned or not.
*/
private inner class WhenEmittingContext(val expression: IrWhen) {
private inner class WhenEmittingContext(val expression: IrWhen, val lastBBOfWhenCases: LLVMBasicBlockRef) {
val needsPhi = expression.branches.last().isUnconditional() && !expression.type.isUnit()
val llvmType = codegen.getLLVMType(expression.type)
val bbExit = lazy { functionGenerationContext.basicBlock("when_exit", expression.endLocation) }
val bbExit = lazy {
// bbExit must be positioned after all blocks of WHEN construct
functionGenerationContext.appendingTo(lastBBOfWhenCases) {
functionGenerationContext.basicBlock("when_exit", expression.endLocation)
}
}
val resultPhi = lazy {
functionGenerationContext.appendingTo(bbExit.value) {
functionGenerationContext.phi(llvmType)
@@ -1296,19 +1300,35 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
}
}
/** For WHEN { COND1 -> CASE1, COND2 -> CASE2, ELSE -> UNCONDITIONAL }
* the following sequence of basic blocks is generated:
* -- if COND1
* -- CASE1
* -- NEXT1(if COND2)
* -- CASE2
* -- NEXT2 (UNCONDITIONAL)
* -- EXIT
*/
private fun evaluateWhen(expression: IrWhen, resultSlot: LLVMValueRef?): LLVMValueRef {
context.log{"evaluateWhen : ${ir2string(expression)}"}
val whenEmittingContext = WhenEmittingContext(expression)
generateDebugTrambolineIf("when", expression)
expression.branches.forEach {
val bbNext = if (it == expression.branches.last())
null
else
functionGenerationContext.basicBlock("when_next", it.startLocation, it.endLocation)
generateWhenCase(whenEmittingContext, it, bbNext, resultSlot)
// First, generate all empty basic blocks for conditions and variants
val bbOfFirstConditionCheck = functionGenerationContext.currentBlock
val branchInfos: List<BranchCaseNextInfo> = expression.branches.map {
// Carefully create empty basic blocks and position them one after another
val bbCase = if (it.isUnconditional()) null else
functionGenerationContext.basicBlock("when_case", it.startLocation, it.endLocation).apply { functionGenerationContext.positionAtEnd(this) }
val bbNext = if (it.isUnconditional() || it == expression.branches.last()) null else
functionGenerationContext.basicBlock("when_next", it.startLocation, it.endLocation).apply { functionGenerationContext.positionAtEnd(this) }
BranchCaseNextInfo(it, bbCase, bbNext, resultSlot)
}
// Now, exit basic block can be positioned after all blocks of WHEN expression
val whenEmittingContext = WhenEmittingContext(expression, lastBBOfWhenCases = functionGenerationContext.currentBlock)
functionGenerationContext.positionAtEnd(bbOfFirstConditionCheck)
branchInfos.forEach { generateWhenCase(whenEmittingContext, it) }
if (whenEmittingContext.bbExit.isInitialized())
functionGenerationContext.positionAtEnd(whenEmittingContext.bbExit.value)
@@ -1330,25 +1350,26 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
}
}
private fun generateWhenCase(whenEmittingContext: WhenEmittingContext, branch: IrBranch, bbNext: LLVMBasicBlockRef?, resultSlot: LLVMValueRef?) {
val brResult = if (branch.isUnconditional())
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, resultSlot)
}
if (!functionGenerationContext.isAfterTerminator()) {
if (whenEmittingContext.needsPhi)
functionGenerationContext.assignPhis(whenEmittingContext.resultPhi.value to brResult)
functionGenerationContext.br(whenEmittingContext.bbExit.value)
}
if (bbNext != null)
functionGenerationContext.positionAtEnd(bbNext)
}
private data class BranchCaseNextInfo(val branch: IrBranch, val bbCase: LLVMBasicBlockRef?, val bbNext: LLVMBasicBlockRef?,
val resultSlot: LLVMValueRef?)
private fun generateWhenCase(whenEmittingContext: WhenEmittingContext, branchCaseNextInfo: BranchCaseNextInfo) {
with(branchCaseNextInfo) {
if (!branch.isUnconditional()) {
val condition = evaluateExpression(branch.condition)
functionGenerationContext.condBr(condition, bbCase, bbNext ?: whenEmittingContext.bbExit.value)
functionGenerationContext.positionAtEnd(bbCase!!)
}
val brResult = evaluateExpression(branch.result, resultSlot)
if (!functionGenerationContext.isAfterTerminator()) {
if (whenEmittingContext.needsPhi)
functionGenerationContext.assignPhis(whenEmittingContext.resultPhi.value to brResult)
functionGenerationContext.br(whenEmittingContext.bbExit.value)
}
if (bbNext != null)
functionGenerationContext.positionAtEnd(bbNext)
}
}
//-------------------------------------------------------------------------//
private fun evaluateWhileLoop(loop: IrWhileLoop): LLVMValueRef {
@@ -6151,6 +6151,10 @@ fileCheckTest("filecheck_smoke0") {
annotatedSource = project.file('filecheck/smoke0.kt')
}
fileCheckTest("filecheck_when") {
annotatedSource = project.file('filecheck/when.kt')
}
if (HostManager.@Companion.hostIsMac) {
fileCheckTest("filecheck_force_arm_instruction_set") {
enabled = enabled && cacheTesting == null
@@ -7,16 +7,14 @@ package codegen.stringConcatenationTypeNarrowing.kt53119_append_generated
import kotlin.test.*
// CHECK-LABEL: define %struct.ObjHeader* @"kfun:codegen.stringConcatenationTypeNarrowing.kt53119_append_generated#maybeAnyMaybeAny
// CHECK: %struct.ObjHeader* @"kfun:kotlin.text.StringBuilder#append(kotlin.String?)
// CHECK: %struct.ObjHeader* @"kfun:kotlin.text.StringBuilder#append(kotlin.String)
// CHECK: %struct.ObjHeader* @"kfun:kotlin.text.StringBuilder#append(kotlin.String?)
// CHECK-NOT: %struct.ObjHeader* @"kfun:kotlin.text.StringBuilder#append
// CHECK: %struct.ObjHeader* @"kfun:codegen.stringConcatenationTypeNarrowing.kt53119_append_generated.Foo#toString(){}kotlin.String"
// CHECK-NOT: %struct.ObjHeader* @"kfun:kotlin.text.StringBuilder#append
// CHECK: %struct.ObjHeader* @"kfun:codegen.stringConcatenationTypeNarrowing.kt53119_append_generated.Foo#toString(){}kotlin.String"
// CHECK-NOT: Foo#toString(){}kotlin.String"
// CHECK: %struct.ObjHeader* @"kfun:kotlin.text.StringBuilder#append(kotlin.String?)
// CHECK: %struct.ObjHeader* @"kfun:kotlin.text.StringBuilder#append(kotlin.String)
// CHECK-NOT: %struct.ObjHeader* @"kfun:kotlin.text.StringBuilder#append
// CHECK: %struct.ObjHeader* @"kfun:codegen.stringConcatenationTypeNarrowing.kt53119_append_generated.Foo#toString(){}kotlin.String"
// CHECK: %struct.ObjHeader* @"kfun:kotlin.text.StringBuilder#append(kotlin.String?)
// CHECK-NOT: %struct.ObjHeader* @"kfun:kotlin.text.StringBuilder#append
// CHECK: ret %struct.ObjHeader*
@@ -26,14 +24,13 @@ fun maybeAnyMaybeAny(maybeAny1: Any?, maybeAny2: Any?): String {
}
// CHECK-LABEL: define %struct.ObjHeader* @"kfun:codegen.stringConcatenationTypeNarrowing.kt53119_append_generated#maybeAnyMaybeString
// CHECK: %struct.ObjHeader* @"kfun:codegen.stringConcatenationTypeNarrowing.kt53119_append_generated.Foo#toString(){}kotlin.String"
// CHECK-NOT: Foo#toString(){}kotlin.String"
// CHECK: %struct.ObjHeader* @"kfun:kotlin.text.StringBuilder#append(kotlin.String?)
// CHECK: %struct.ObjHeader* @"kfun:kotlin.text.StringBuilder#append(kotlin.String)
// CHECK: %struct.ObjHeader* @"kfun:kotlin.text.StringBuilder#append(kotlin.String?)
// CHECK-NOT: %struct.ObjHeader* @"kfun:kotlin.text.StringBuilder#append
// CHECK: %struct.ObjHeader* @"kfun:codegen.stringConcatenationTypeNarrowing.kt53119_append_generated.Foo#toString(){}kotlin.String"
// CHECK-NOT: Foo#toString(){}kotlin.String"
// CHECK-NOT: %struct.ObjHeader* @"kfun:kotlin.text.StringBuilder#append
// CHECK: ret %struct.ObjHeader*
@@ -42,14 +39,13 @@ fun maybeAnyMaybeString(maybeAny1: Any?, maybeString2: String?): String {
}
// CHECK-LABEL: define %struct.ObjHeader* @"kfun:codegen.stringConcatenationTypeNarrowing.kt53119_append_generated#maybeAnyString
// CHECK: %struct.ObjHeader* @"kfun:codegen.stringConcatenationTypeNarrowing.kt53119_append_generated.Foo#toString(){}kotlin.String"
// CHECK-NOT: Foo#toString(){}kotlin.String"
// CHECK: %struct.ObjHeader* @"kfun:kotlin.text.StringBuilder#append(kotlin.String?)
// CHECK: %struct.ObjHeader* @"kfun:kotlin.text.StringBuilder#append(kotlin.String)
// CHECK: %struct.ObjHeader* @"kfun:kotlin.text.StringBuilder#append(kotlin.String)
// CHECK-NOT: %struct.ObjHeader* @"kfun:kotlin.text.StringBuilder#append
// CHECK: %struct.ObjHeader* @"kfun:codegen.stringConcatenationTypeNarrowing.kt53119_append_generated.Foo#toString(){}kotlin.String"
// CHECK-NOT: Foo#toString(){}kotlin.String"
// CHECK-NOT: %struct.ObjHeader* @"kfun:kotlin.text.StringBuilder#append
// CHECK: ret %struct.ObjHeader*
@@ -60,6 +56,8 @@ fun maybeAnyString(maybeAny1: Any?, string: String): String {
data class Foo(val bar: Int)
// CHECK-LABEL: define %struct.ObjHeader* @"kfun:codegen.stringConcatenationTypeNarrowing.kt53119_append_generated#maybeAnyFoo
// CHECK: %struct.ObjHeader* @"kfun:codegen.stringConcatenationTypeNarrowing.kt53119_append_generated.Foo#toString(){}kotlin.String"
// CHECK-NOT: Foo#toString(){}kotlin.String"
// CHECK: %struct.ObjHeader* @"kfun:kotlin.text.StringBuilder#append(kotlin.String?)
// CHECK: %struct.ObjHeader* @"kfun:kotlin.text.StringBuilder#append(kotlin.String)
// CHECK-NOT: %struct.ObjHeader* @"kfun:kotlin.text.StringBuilder#append
@@ -68,9 +66,6 @@ data class Foo(val bar: Int)
// CHECK: %struct.ObjHeader* @"kfun:kotlin.text.StringBuilder#append(kotlin.String?)
// CHECK-NOT: %struct.ObjHeader* @"kfun:kotlin.text.StringBuilder#append
// CHECK: %struct.ObjHeader* @"kfun:codegen.stringConcatenationTypeNarrowing.kt53119_append_generated.Foo#toString(){}kotlin.String"
// CHECK-NOT: Foo#toString(){}kotlin.String"
// CHECK-NOT: %struct.ObjHeader* @"kfun:kotlin.text.StringBuilder#append
// CHECK: ret %struct.ObjHeader*
@@ -78,14 +73,15 @@ fun maybeAnyFoo(maybeAny: Any?, foo: Foo): String {
return "$maybeAny,$foo"
}
// CHECK-LABEL: define %struct.ObjHeader* @"kfun:codegen.stringConcatenationTypeNarrowing.kt53119_append_generated#maybeAnyMaybeFoo
// CHECK: %struct.ObjHeader* @"kfun:codegen.stringConcatenationTypeNarrowing.kt53119_append_generated.Foo#toString(){}kotlin.String"
// CHECK-NOT: Foo#toString(){}kotlin.String"
// CHECK: %struct.ObjHeader* @"kfun:kotlin.text.StringBuilder#append(kotlin.String?)
// CHECK: %struct.ObjHeader* @"kfun:kotlin.text.StringBuilder#append(kotlin.String)
// CHECK: %struct.ObjHeader* @"kfun:codegen.stringConcatenationTypeNarrowing.kt53119_append_generated.Foo#toString(){}kotlin.String"
// CHECK-NOT: Foo#toString(){}kotlin.String"
// CHECK: %struct.ObjHeader* @"kfun:kotlin.text.StringBuilder#append(kotlin.String?)
// CHECK-NOT: %struct.ObjHeader* @"kfun:kotlin.text.StringBuilder#append
// CHECK: %struct.ObjHeader* @"kfun:codegen.stringConcatenationTypeNarrowing.kt53119_append_generated.Foo#toString(){}kotlin.String"
// CHECK: %struct.ObjHeader* @"kfun:codegen.stringConcatenationTypeNarrowing.kt53119_append_generated.Foo#toString(){}kotlin.String"
// CHECK-NOT: Foo#toString(){}kotlin.String"
// CHECK-NOT: %struct.ObjHeader* @"kfun:kotlin.text.StringBuilder#append
// CHECK: ret %struct.ObjHeader*
@@ -7,11 +7,9 @@ package codegen.stringConcatenationTypeNarrowing.kt53119_append_manual
import kotlin.test.*
// CHECK-LABEL: define %struct.ObjHeader* @"kfun:codegen.stringConcatenationTypeNarrowing.kt53119_append_manual#appendMaybeAny(kotlin.Any?)
// CHECK: %struct.ObjHeader* @"kfun:kotlin.text.StringBuilder#append(kotlin.String?)
// CHECK-NOT: %struct.ObjHeader* @"kfun:kotlin.text.StringBuilder#append
// CHECK: %struct.ObjHeader* @"kfun:codegen.stringConcatenationTypeNarrowing.kt53119_append_manual.Foo#toString(){}kotlin.String"
// CHECK-NOT: Foo#toString(){}kotlin.String"
// CHECK: %struct.ObjHeader* @"kfun:kotlin.text.StringBuilder#append(kotlin.String?)
// CHECK-NOT: %struct.ObjHeader* @"kfun:kotlin.text.StringBuilder#append
// CHECK: ret %struct.ObjHeader*
@@ -9,17 +9,15 @@ import kotlin.test.*
// CHECK-LABEL: define %struct.ObjHeader* @"kfun:codegen.stringConcatenationTypeNarrowing.kt53119_plus_extension#manualPlusExtensionAny
// CHECK-NOT: kfun:kotlin.String#plus(kotlin.Any?)
// CHECK: call %struct.ObjHeader* @"kfun:codegen.stringConcatenationTypeNarrowing.kt53119_plus_extension.Foo#toString(){}kotlin.String"
// CHECK-NOT: Foo#toString(){}kotlin.String"
// CHECK: call %struct.ObjHeader* @Kotlin_String_plusImpl
// CHECK-NOT: call %struct.ObjHeader* @Kotlin_String_plusImpl
// CHECK-NOT: kfun:kotlin.String#plus(kotlin.Any?)
// CHECK-NOT: call %struct.ObjHeader* @"kfun:kotlin.String#toString(){}kotlin.String"
// CHECK: call %struct.ObjHeader* @"kfun:codegen.stringConcatenationTypeNarrowing.kt53119_plus_extension.Foo#toString(){}kotlin.String"
// CHECK-NOT: call %struct.ObjHeader* @"kfun:kotlin.String#toString(){}kotlin.String"
// CHECK-NOT: Foo#toString(){}kotlin.String"
// CHECK-NOT: call %struct.ObjHeader* @Kotlin_String_plusImpl
// CHECK-NOT: kfun:kotlin.String#plus(kotlin.Any?)
// CHECK: ret %struct.ObjHeader*
@@ -43,16 +41,12 @@ fun manualPlusExtensionString(maybeStr: String?, str: String): kotlin.String =
// CHECK-LABEL: define %struct.ObjHeader* @"kfun:codegen.stringConcatenationTypeNarrowing.kt53119_plus_extension#generatedPlusExtensionAny
// CHECK-NOT: kfun:kotlin#plus__at__kotlin.String?(kotlin.Any?)
// CHECK: call %struct.ObjHeader* @"kfun:codegen.stringConcatenationTypeNarrowing.kt53119_plus_extension.Foo#toString(){}kotlin.String"
// CHECK-NOT: Foo#toString(){}kotlin.String"
// CHECK: call %struct.ObjHeader* @Kotlin_String_plusImpl
// CHECK-NOT: call %struct.ObjHeader* @Kotlin_String_plusImpl
// CHECK-NOT: kfun:kotlin#plus__at__kotlin.String?(kotlin.Any?)
// CHECK: call %struct.ObjHeader* @"kfun:codegen.stringConcatenationTypeNarrowing.kt53119_plus_extension.Foo#toString(){}kotlin.String"
// CHECK-NOT: Foo#toString(){}kotlin.String"
// CHECK-NOT: call %struct.ObjHeader* @"kfun:kotlin.String#toString(){}kotlin.String"
// CHECK-NOT: kfun:kotlin#plus__at__kotlin.String?(kotlin.Any?)
// CHECK-NOT: call %struct.ObjHeader* @Kotlin_String_plusImpl
// CHECK: ret %struct.ObjHeader*
@@ -98,14 +92,12 @@ fun generatedPlusExtensionFoo(maybeStr: String?, foo: Foo): String {
// CHECK-LABEL: define %struct.ObjHeader* @"kfun:codegen.stringConcatenationTypeNarrowing.kt53119_plus_extension#generatedPlusExtensionMaybeFoo
// CHECK-NOT: kfun:kotlin.String#plus(kotlin.Any?)
// CHECK: call %struct.ObjHeader* @"kfun:codegen.stringConcatenationTypeNarrowing.kt53119_plus_extension.Foo#toString(){}kotlin.String"
// CHECK-NOT: Foo#toString(){}kotlin.String
// CHECK: call %struct.ObjHeader* @Kotlin_String_plusImpl
// CHECK-NOT: call %struct.ObjHeader* @Kotlin_String_plusImpl
// CHECK-NOT: call %struct.ObjHeader* @"kfun:kotlin.String#toString(){}kotlin.String"
// CHECK: call %struct.ObjHeader* @"kfun:codegen.stringConcatenationTypeNarrowing.kt53119_plus_extension.Foo#toString(){}kotlin.String"
// CHECK-NOT: Foo#toString(){}kotlin.String
// CHECK-NOT: call %struct.ObjHeader* @"kfun:kotlin.String#toString(){}kotlin.String"
// CHECK-NOT: kfun:kotlin.String#plus(kotlin.Any?)
// CHECK: ret %struct.ObjHeader*
@@ -9,11 +9,9 @@ import kotlin.test.*
// CHECK-LABEL: define %struct.ObjHeader* @"kfun:codegen.stringConcatenationTypeNarrowing.kt53119_plus_member#manualPlusMemberAny
// CHECK-NOT: kfun:kotlin.String#plus(kotlin.Any?)
// CHECK: call %struct.ObjHeader* @Kotlin_String_plusImpl
// CHECK-NOT: kfun:kotlin.String#plus(kotlin.Any?)
// CHECK: call %struct.ObjHeader* @"kfun:codegen.stringConcatenationTypeNarrowing.kt53119_plus_member.Foo#toString(){}kotlin.String"
// CHECK-NOT: Foo#toString(){}kotlin.String"
// CHECK: call %struct.ObjHeader* @Kotlin_String_plusImpl
// CHECK-NOT: kfun:kotlin.String#plus(kotlin.Any?)
// CHECK: ret %struct.ObjHeader*
@@ -37,12 +35,9 @@ fun manualPlusMemberString(str1: String, str2: String): kotlin.String =
// CHECK-LABEL: define %struct.ObjHeader* @"kfun:codegen.stringConcatenationTypeNarrowing.kt53119_plus_member#generatedPlusMemberAny
// CHECK-NOT: kfun:kotlin.String#plus(kotlin.Any?)
// CHECK: call %struct.ObjHeader* @Kotlin_String_plusImpl
// CHECK-NOT: kfun:kotlin.String#plus(kotlin.Any?)
// CHECK: call %struct.ObjHeader* @"kfun:codegen.stringConcatenationTypeNarrowing.kt53119_plus_member.Foo#toString(){}kotlin.String"
// CHECK-NOT: Foo#toString(){}kotlin.String"
// CHECK: call %struct.ObjHeader* @Kotlin_String_plusImpl
// CHECK-NOT: kfun:kotlin.String#plus(kotlin.Any?)
// CHECK: ret %struct.ObjHeader*
@@ -86,9 +81,10 @@ fun manualPlusMemberFoo(str1: String, foo: Foo): kotlin.String =
// CHECK call %struct.ObjHeader* @"kfun:codegen.stringConcatenationTypeNarrowing.kt53119_plus_member.Foo#toString(){}kotlin.String"
// CHECK-NOT Foo#toString(){}kotlin.String
// CHECK: call %struct.ObjHeader* @Kotlin_String_plusImpl
// CHECK: call %struct.ObjHeader* @"kfun:codegen.stringConcatenationTypeNarrowing.kt53119_plus_member.Foo#toString
// CHECK-NOT: Foo#toString(){}kotlin.String"
// CHECK-NOT: kfun:kotlin.String#plus(kotlin.Any?)
// CHECK: call %struct.ObjHeader* @Kotlin_String_plusImpl
// CHECK-NOT: Foo#toString(){}kotlin.String"
// CHECK: ret %struct.ObjHeader*
@@ -0,0 +1,24 @@
/*
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
var i = 1
fun main() {
println(when(i) {
0 -> 10
1 -> 11
2 -> 12
else -> 13
})
}
// CHECK-LABEL: define void @"kfun:#main(){}"()
// CHECK: when_case
// CHECK: when_next
// CHECK: when_case1
// CHECK: when_next2
// CHECK: when_case3
// CHECK: when_next4
// CHECK: when_exit
// CHECK: call void @"kfun:kotlin.io#println(kotlin.Any?)
// CHECK: ret void