1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
|
//===--- 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
var changed = false
for block in function.blocks {
if let condBr = block.terminator as? CondBranchInst {
changed = fold(condBranch: condBr, context) || changed
}
}
if changed {
_ = context.removeDeadBlocks(in: function)
}
}
private func fold(condBranch: CondBranchInst, _ context: FunctionPassContext) -> Bool {
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 false
}
let builder = Builder(before: condBranch, context)
builder.createBranch(to: literalValue == 0 ? condBranch.falseBlock : condBranch.trueBlock)
context.erase(instruction: condBranch)
return true
}
|