mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Add a new mandatory BooleanLiteralFolding pass which constant folds conditional branches with boolean literals as operands.
```
%1 = integer_literal -1
%2 = apply %bool_init(%1) // Bool.init(_builtinBooleanLiteral:)
%3 = struct_extract %2, #Bool._value
cond_br %3, bb1, bb2
```
->
```
...
br bb1
```
This pass is intended to run before DefiniteInitialization, where mandatory inlining and constant folding didn't run, yet (which would perform this kind of optimization).
This optimization is required to let DefiniteInitialization handle boolean literals correctly.
For example in infinite loops:
```
init() {
while true { // DI need to know that there is no loop exit from this while-statement
if some_condition {
member_field = init_value
break
}
}
}
```
71 lines
2.3 KiB
Swift
71 lines
2.3 KiB
Swift
//===--- BooleanLiteralFolding.swift ---------------------------------------==//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2024 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See https://swift.org/LICENSE.txt for license information
|
|
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
import SIL
|
|
|
|
/// Constant folds conditional branches with boolean literals as operands.
|
|
///
|
|
/// ```
|
|
/// %1 = integer_literal -1
|
|
/// %2 = apply %bool_init(%1) // Bool.init(_builtinBooleanLiteral:)
|
|
/// %3 = struct_extract %2, #Bool._value
|
|
/// cond_br %3, bb1, bb2
|
|
/// ```
|
|
/// ->
|
|
/// ```
|
|
/// ...
|
|
/// br bb1
|
|
/// ```
|
|
///
|
|
/// This pass is intended to run before DefiniteInitialization, where mandatory inlining and
|
|
/// constant folding didn't run, yet (which would perform this kind of optimization).
|
|
///
|
|
/// This optimization is required to let DefiniteInitialization handle boolean literals correctly.
|
|
/// For example in infinite loops:
|
|
///
|
|
/// ```
|
|
/// init() {
|
|
/// while true { // DI need to know that there is no loop exit from this while-statement
|
|
/// if some_condition {
|
|
/// member_field = init_value
|
|
/// break
|
|
/// }
|
|
/// }
|
|
/// }
|
|
/// ```
|
|
///
|
|
let booleanLiteralFolding = FunctionPass(name: "boolean-literal-folding") {
|
|
(function: Function, context: FunctionPassContext) in
|
|
|
|
for block in function.blocks {
|
|
if let condBr = block.terminator as? CondBranchInst {
|
|
fold(condBranch: condBr, context)
|
|
}
|
|
}
|
|
}
|
|
|
|
private func fold(condBranch: CondBranchInst, _ context: FunctionPassContext) {
|
|
guard let structExtract = condBranch.condition as? StructExtractInst,
|
|
let initApply = structExtract.struct as? ApplyInst,
|
|
initApply.hasSemanticsAttribute("bool.literal_init"),
|
|
initApply.arguments.count == 2,
|
|
let literal = initApply.arguments[0] as? IntegerLiteralInst,
|
|
let literalValue = literal.value else
|
|
{
|
|
return
|
|
}
|
|
|
|
let builder = Builder(before: condBranch, context)
|
|
builder.createBranch(to: literalValue == 0 ? condBranch.falseBlock : condBranch.trueBlock)
|
|
context.erase(instruction: condBranch)
|
|
}
|