Rewrote when clause code generation
This commit is contained in:
+57
-66
@@ -1108,43 +1108,69 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
|||||||
* }
|
* }
|
||||||
* we cannot determine if the result of when is assigned or not.
|
* we cannot determine if the result of when is assigned or not.
|
||||||
*/
|
*/
|
||||||
private fun evaluateWhen(expression: IrWhen): LLVMValueRef {
|
private inner class WhenEmittingContext(val expression: IrWhen) {
|
||||||
context.log{"evaluateWhen : ${ir2string(expression)}"}
|
val needsPhi = isUnconditional(expression.branches.last()) && !expression.type.isUnit()
|
||||||
var bbExit: LLVMBasicBlockRef? = null // By default "when" does not have "exit".
|
|
||||||
val isUnit = expression.type.isUnit()
|
|
||||||
val isNothing = expression.type.isNothing()
|
|
||||||
|
|
||||||
// We may not cover all cases if IrWhen is used as statement.
|
|
||||||
val coverAllCases = isUnconditional(expression.branches.last())
|
|
||||||
|
|
||||||
// "When" has exit block if:
|
|
||||||
// its type is not Nothing - we must place phi in the exit block
|
|
||||||
// or it doesn't cover all cases - we may fall through all of them and must create exit block to continue.
|
|
||||||
if (!isNothing || !coverAllCases) // If "when" has "exit".
|
|
||||||
bbExit = functionGenerationContext.basicBlock("when_exit", expression.startLocation) // Create basic block to process "exit".
|
|
||||||
|
|
||||||
val llvmType = codegen.getLLVMType(expression.type)
|
val llvmType = codegen.getLLVMType(expression.type)
|
||||||
val resultPhi = if (isUnit || isNothing || !coverAllCases) null else
|
|
||||||
functionGenerationContext.appendingTo(bbExit!!) {
|
val bbExit = lazy { functionGenerationContext.basicBlock("when_exit", expression.startLocation) }
|
||||||
|
|
||||||
|
val resultPhi = lazy {
|
||||||
|
functionGenerationContext.appendingTo(bbExit.value) {
|
||||||
functionGenerationContext.phi(llvmType)
|
functionGenerationContext.phi(llvmType)
|
||||||
}
|
}
|
||||||
|
|
||||||
expression.branches.forEach { // Iterate through "when" branches (clauses).
|
|
||||||
var bbNext = bbExit // For last clause bbNext coincides with bbExit.
|
|
||||||
if (it != expression.branches.last()) // If it is not last clause.
|
|
||||||
bbNext = functionGenerationContext.basicBlock("when_next", it.startLocation) // Create new basic block for next clause.
|
|
||||||
generateWhenCase(resultPhi, it, bbNext, bbExit) // Generate code for current clause.
|
|
||||||
}
|
|
||||||
|
|
||||||
return when {
|
|
||||||
// FIXME: remove the hacks.
|
|
||||||
isUnit -> functionGenerationContext.theUnitInstanceRef.llvm
|
|
||||||
isNothing -> functionGenerationContext.kNothingFakeValue
|
|
||||||
!coverAllCases -> LLVMGetUndef(llvmType)!!
|
|
||||||
else -> resultPhi!!
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun evaluateWhen(expression: IrWhen): LLVMValueRef {
|
||||||
|
context.log{"evaluateWhen : ${ir2string(expression)}"}
|
||||||
|
|
||||||
|
val whenEmittingContext = WhenEmittingContext(expression)
|
||||||
|
|
||||||
|
expression.branches.forEach {
|
||||||
|
val bbNext = if (it == expression.branches.last())
|
||||||
|
null
|
||||||
|
else
|
||||||
|
functionGenerationContext.basicBlock("when_next", it.startLocation)
|
||||||
|
generateWhenCase(whenEmittingContext, it, bbNext)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (whenEmittingContext.bbExit.isInitialized())
|
||||||
|
functionGenerationContext.positionAtEnd(whenEmittingContext.bbExit.value)
|
||||||
|
|
||||||
|
return when {
|
||||||
|
expression.type.isUnit() -> functionGenerationContext.theUnitInstanceRef.llvm
|
||||||
|
expression.type.isNothing() -> functionGenerationContext.kNothingFakeValue
|
||||||
|
whenEmittingContext.resultPhi.isInitialized() -> whenEmittingContext.resultPhi.value
|
||||||
|
else -> LLVMGetUndef(whenEmittingContext.llvmType)!!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun generateWhenCase(whenEmittingContext: WhenEmittingContext, branch: IrBranch, bbNext: LLVMBasicBlockRef?) {
|
||||||
|
val brResult = if (isUnconditional(branch))
|
||||||
|
evaluateExpression(branch.result)
|
||||||
|
else {
|
||||||
|
val bbCase = functionGenerationContext.basicBlock("when_case", branch.startLocation)
|
||||||
|
val condition = evaluateExpression(branch.condition)
|
||||||
|
functionGenerationContext.condBr(condition, bbCase, bbNext ?: whenEmittingContext.bbExit.value)
|
||||||
|
functionGenerationContext.positionAtEnd(bbCase)
|
||||||
|
evaluateExpression(branch.result)
|
||||||
|
}
|
||||||
|
if (!functionGenerationContext.isAfterTerminator()) {
|
||||||
|
if (whenEmittingContext.needsPhi)
|
||||||
|
functionGenerationContext.assignPhis(whenEmittingContext.resultPhi.value to brResult)
|
||||||
|
functionGenerationContext.br(whenEmittingContext.bbExit.value)
|
||||||
|
}
|
||||||
|
if (bbNext != null)
|
||||||
|
functionGenerationContext.positionAtEnd(bbNext)
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------//
|
||||||
|
// Checks if the branch is unconditional
|
||||||
|
|
||||||
|
private fun isUnconditional(branch: IrBranch): Boolean =
|
||||||
|
branch.condition is IrConst<*> // If branch condition is constant.
|
||||||
|
&& (branch.condition as IrConst<*>).value as Boolean // If condition is "true"
|
||||||
|
|
||||||
//-------------------------------------------------------------------------//
|
//-------------------------------------------------------------------------//
|
||||||
|
|
||||||
private fun evaluateWhileLoop(loop: IrWhileLoop): LLVMValueRef {
|
private fun evaluateWhileLoop(loop: IrWhileLoop): LLVMValueRef {
|
||||||
@@ -2502,41 +2528,6 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
|||||||
|
|
||||||
//-------------------------------------------------------------------------//
|
//-------------------------------------------------------------------------//
|
||||||
|
|
||||||
private fun generateWhenCase(resultPhi: LLVMValueRef?, branch: IrBranch,
|
|
||||||
bbNext: LLVMBasicBlockRef?, bbExit: LLVMBasicBlockRef?) {
|
|
||||||
val branchResult = branch.result
|
|
||||||
val brResult = if (isUnconditional(branch)) { // It is the "else" clause.
|
|
||||||
evaluateExpression(branchResult) // Generate clause body.
|
|
||||||
} else { // It is conditional clause.
|
|
||||||
val bbCase = functionGenerationContext.basicBlock("when_case", branch.startLocation) // Create block for clause body.
|
|
||||||
val condition = evaluateExpression(branch.condition) // Generate cmp instruction.
|
|
||||||
functionGenerationContext.condBr(condition, bbCase, bbNext) // Conditional branch depending on cmp result.
|
|
||||||
functionGenerationContext.positionAtEnd(bbCase) // Switch generation to block for clause body.
|
|
||||||
evaluateExpression(branch.result) // Generate clause body.
|
|
||||||
}
|
|
||||||
if (!functionGenerationContext.isAfterTerminator()) {
|
|
||||||
if (resultPhi != null)
|
|
||||||
functionGenerationContext.assignPhis(resultPhi to brResult)
|
|
||||||
if (bbExit != null)
|
|
||||||
functionGenerationContext.br(bbExit)
|
|
||||||
else
|
|
||||||
functionGenerationContext.unreachable()
|
|
||||||
}
|
|
||||||
if (bbNext != null) // Switch generation to next or exit.
|
|
||||||
functionGenerationContext.positionAtEnd(bbNext)
|
|
||||||
else if (bbExit != null)
|
|
||||||
functionGenerationContext.positionAtEnd(bbExit)
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------------------------------------------//
|
|
||||||
// Checks if the branch is unconditional
|
|
||||||
|
|
||||||
private fun isUnconditional(branch: IrBranch): Boolean =
|
|
||||||
branch.condition is IrConst<*> // If branch condition is constant.
|
|
||||||
&& (branch.condition as IrConst<*>).value as Boolean // If condition is "true"
|
|
||||||
|
|
||||||
//-------------------------------------------------------------------------//
|
|
||||||
|
|
||||||
fun callDirect(descriptor: FunctionDescriptor, args: List<LLVMValueRef>,
|
fun callDirect(descriptor: FunctionDescriptor, args: List<LLVMValueRef>,
|
||||||
resultLifetime: Lifetime): LLVMValueRef {
|
resultLifetime: Lifetime): LLVMValueRef {
|
||||||
val realDescriptor = descriptor.target
|
val realDescriptor = descriptor.target
|
||||||
|
|||||||
Reference in New Issue
Block a user