Disable non-required MIR opts with optimize(none)

Co-authored-by: Waffle Lapkin <waffle.lapkin@gmail.com>
This commit is contained in:
clubby789 2024-12-09 19:34:51 +00:00
parent cd848c9f3e
commit 7a9661d768
57 changed files with 319 additions and 10 deletions

View file

@ -46,6 +46,12 @@ pub enum OptimizeAttr {
Size,
}
impl OptimizeAttr {
pub fn do_not_optimize(&self) -> bool {
matches!(self, Self::DoNotOptimize)
}
}
#[derive(Clone, Debug, Encodable, Decodable)]
pub enum DiagnosticAttribute {
// tidy-alphabetical-start

View file

@ -116,4 +116,8 @@ impl<'tcx> crate::MirPass<'tcx> for AbortUnwindingCalls {
// We may have invalidated some `cleanup` blocks so clean those up now.
super::simplify::remove_dead_blocks(body);
}
fn is_required(&self) -> bool {
true
}
}

View file

@ -75,4 +75,8 @@ impl<'tcx> crate::MirPass<'tcx> for AddCallGuards {
body.basic_blocks_mut().extend(new_blocks);
}
fn is_required(&self) -> bool {
true
}
}

View file

@ -68,6 +68,10 @@ impl<'tcx> crate::MirPass<'tcx> for AddMovesForPackedDrops {
patch.apply(body);
}
fn is_required(&self) -> bool {
true
}
}
fn add_move_for_packed_drop<'tcx>(

View file

@ -176,4 +176,8 @@ impl<'tcx> crate::MirPass<'tcx> for AddRetag {
}
}
}
fn is_required(&self) -> bool {
true
}
}

View file

@ -61,4 +61,8 @@ impl<'tcx> crate::MirPass<'tcx> for Subtyper {
}
checker.patcher.apply(body);
}
fn is_required(&self) -> bool {
true
}
}

View file

@ -60,6 +60,10 @@ impl<'tcx> crate::MirPass<'tcx> for CheckAlignment {
}
}
}
fn is_required(&self) -> bool {
true
}
}
struct PointerFinder<'a, 'tcx> {

View file

@ -72,4 +72,8 @@ impl<'tcx> crate::MirPass<'tcx> for CleanupPostBorrowck {
decl.user_ty = None;
}
}
fn is_required(&self) -> bool {
true
}
}

View file

@ -56,6 +56,10 @@ impl<'tcx> crate::MirPass<'tcx> for CopyProp {
crate::simplify::remove_unused_definitions(body);
}
}
fn is_required(&self) -> bool {
false
}
}
/// `SsaLocals` computed equivalence classes between locals considering copy/move assignments.

View file

@ -1688,6 +1688,10 @@ impl<'tcx> crate::MirPass<'tcx> for StateTransform {
// Run derefer to fix Derefs that are not in the first place
deref_finder(tcx, body);
}
fn is_required(&self) -> bool {
true
}
}
/// Looks for any assignments between locals (e.g., `_4 = _5`) that will both be converted to fields

View file

@ -61,6 +61,10 @@ impl<'tcx> crate::MirPass<'tcx> for InstrumentCoverage {
instrument_function_for_coverage(tcx, mir_body);
}
fn is_required(&self) -> bool {
false
}
}
fn instrument_function_for_coverage<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mut mir::Body<'tcx>) {

View file

@ -69,7 +69,7 @@ fn cross_crate_inlinable(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
// Don't do any inference if codegen optimizations are disabled and also MIR inlining is not
// enabled. This ensures that we do inference even if someone only passes -Zinline-mir,
// which is less confusing than having to also enable -Copt-level=1.
let inliner_will_run = pm::should_run_pass(tcx, &inline::Inline)
let inliner_will_run = pm::should_run_pass(tcx, &inline::Inline, pm::Optimizations::Allowed)
|| inline::ForceInline::should_run_pass_for_callee(tcx, def_id.to_def_id());
if matches!(tcx.sess.opts.optimize, OptLevel::No) && !inliner_will_run {
return false;

View file

@ -36,6 +36,10 @@ impl<'tcx> crate::MirPass<'tcx> for CtfeLimit {
);
}
}
fn is_required(&self) -> bool {
true
}
}
fn has_back_edge(

View file

@ -71,6 +71,10 @@ impl<'tcx> crate::MirPass<'tcx> for DataflowConstProp {
let mut patch = visitor.patch;
debug_span!("patch").in_scope(|| patch.visit_body_preserves_cfg(body));
}
fn is_required(&self) -> bool {
false
}
}
// Note: Currently, places that have their reference taken cannot be tracked. Although this would

View file

@ -147,4 +147,8 @@ impl<'tcx> crate::MirPass<'tcx> for DeadStoreElimination {
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
eliminate(tcx, body);
}
fn is_required(&self) -> bool {
false
}
}

View file

@ -31,6 +31,10 @@ impl<'tcx> crate::MirPass<'tcx> for DeduplicateBlocks {
simplify_cfg(body);
}
}
fn is_required(&self) -> bool {
false
}
}
struct OptApplier<'tcx> {

View file

@ -81,4 +81,8 @@ impl<'tcx> crate::MirPass<'tcx> for Derefer {
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
deref_finder(tcx, body);
}
fn is_required(&self) -> bool {
true
}
}

View file

@ -240,6 +240,10 @@ impl<'tcx> crate::MirPass<'tcx> for DestinationPropagation {
trace!(round_count);
}
fn is_required(&self) -> bool {
false
}
}
#[derive(Debug, Default)]

View file

@ -15,6 +15,10 @@ impl<'tcx> crate::MirPass<'tcx> for Marker {
}
fn run_pass(&self, _tcx: TyCtxt<'tcx>, _body: &mut Body<'tcx>) {}
fn is_required(&self) -> bool {
false
}
}
pub fn emit_mir(tcx: TyCtxt<'_>) -> io::Result<()> {

View file

@ -227,6 +227,10 @@ impl<'tcx> crate::MirPass<'tcx> for EarlyOtherwiseBranch {
simplify_cfg(body);
}
}
fn is_required(&self) -> bool {
false
}
}
#[derive(Debug)]

View file

@ -150,4 +150,8 @@ impl<'tcx> crate::MirPass<'tcx> for ElaborateBoxDerefs {
}
}
}
fn is_required(&self) -> bool {
true
}
}

View file

@ -88,6 +88,10 @@ impl<'tcx> crate::MirPass<'tcx> for ElaborateDrops {
elaborate_patch.apply(body);
deref_finder(tcx, body);
}
fn is_required(&self) -> bool {
true
}
}
/// Records unwind edges which are known to be unreachable, because they are in `drop` terminators

View file

@ -163,6 +163,10 @@ impl<'tcx> crate::MirPass<'tcx> for GVN {
// statements.
StorageRemover { tcx, reused_locals: state.reused_locals }.visit_body_preserves_cfg(body);
}
fn is_required(&self) -> bool {
false
}
}
newtype_index! {

View file

@ -53,4 +53,8 @@ impl<'tcx> MirPass<'tcx> for ImpossiblePredicates {
body.local_decls.raw.truncate(body.arg_count + 1);
}
}
fn is_required(&self) -> bool {
true
}
}

View file

@ -66,6 +66,10 @@ impl<'tcx> crate::MirPass<'tcx> for Inline {
deref_finder(tcx, body);
}
}
fn is_required(&self) -> bool {
false
}
}
pub struct ForceInline;
@ -85,6 +89,10 @@ impl<'tcx> crate::MirPass<'tcx> for ForceInline {
false
}
fn is_required(&self) -> bool {
true
}
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
let span = trace_span!("force_inline", body = %tcx.def_path_str(body.source.def_id()));
let _guard = span.enter();

View file

@ -62,6 +62,10 @@ impl<'tcx> crate::MirPass<'tcx> for InstSimplify {
simplify_duplicate_switch_targets(block.terminator.as_mut().unwrap());
}
}
fn is_required(&self) -> bool {
false
}
}
struct InstSimplifyContext<'a, 'tcx> {

View file

@ -105,6 +105,10 @@ impl<'tcx> crate::MirPass<'tcx> for JumpThreading {
}
OpportunitySet::new(body, opportunities).apply(body);
}
fn is_required(&self) -> bool {
false
}
}
#[derive(Debug)]

View file

@ -200,6 +200,10 @@ impl<'tcx> crate::MirPass<'tcx> for EnumSizeOpt {
});
}
}
fn is_required(&self) -> bool {
false
}
}
impl EnumSizeOpt {

View file

@ -388,6 +388,7 @@ fn mir_built(tcx: TyCtxt<'_>, def: LocalDefId) -> &Steal<Body<'_>> {
&Lint(sanity_check::SanityCheck),
],
None,
pm::Optimizations::Allowed,
);
tcx.alloc_steal_mir(body)
}
@ -440,6 +441,7 @@ fn mir_promoted(
&mut body,
&[&promote_pass, &simplify::SimplifyCfg::PromoteConsts, &coverage::InstrumentCoverage],
Some(MirPhase::Analysis(AnalysisPhase::Initial)),
pm::Optimizations::Allowed,
);
lint_tail_expr_drop_order::run_lint(tcx, def, &body);
@ -473,7 +475,7 @@ fn inner_mir_for_ctfe(tcx: TyCtxt<'_>, def: LocalDefId) -> Body<'_> {
};
let mut body = remap_mir_for_const_eval_select(tcx, body, hir::Constness::Const);
pm::run_passes(tcx, &mut body, &[&ctfe_limit::CtfeLimit], None);
pm::run_passes(tcx, &mut body, &[&ctfe_limit::CtfeLimit], None, pm::Optimizations::Allowed);
body
}
@ -493,7 +495,7 @@ fn mir_drops_elaborated_and_const_checked(tcx: TyCtxt<'_>, def: LocalDefId) -> &
let is_fn_like = tcx.def_kind(def).is_fn_like();
if is_fn_like {
// Do not compute the mir call graph without said call graph actually being used.
if pm::should_run_pass(tcx, &inline::Inline)
if pm::should_run_pass(tcx, &inline::Inline, pm::Optimizations::Allowed)
|| inline::ForceInline::should_run_pass_for_callee(tcx, def.to_def_id())
{
tcx.ensure_with_value().mir_inliner_callees(ty::InstanceKind::Item(def.to_def_id()));
@ -533,6 +535,7 @@ pub fn run_analysis_to_runtime_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'
&Lint(post_drop_elaboration::CheckLiveDrops),
],
None,
pm::Optimizations::Allowed,
);
}
@ -557,7 +560,13 @@ fn run_analysis_cleanup_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
&deref_separator::Derefer,
];
pm::run_passes(tcx, body, passes, Some(MirPhase::Analysis(AnalysisPhase::PostCleanup)));
pm::run_passes(
tcx,
body,
passes,
Some(MirPhase::Analysis(AnalysisPhase::PostCleanup)),
pm::Optimizations::Allowed,
);
}
/// Returns the sequence of passes that lowers analysis to runtime MIR.
@ -597,7 +606,13 @@ fn run_runtime_cleanup_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
&simplify::SimplifyCfg::PreOptimizations,
];
pm::run_passes(tcx, body, passes, Some(MirPhase::Runtime(RuntimePhase::PostCleanup)));
pm::run_passes(
tcx,
body,
passes,
Some(MirPhase::Runtime(RuntimePhase::PostCleanup)),
pm::Optimizations::Allowed,
);
// Clear this by anticipation. Optimizations and runtime MIR have no reason to look
// into this information, which is meant for borrowck diagnostics.
@ -611,6 +626,15 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
WithMinOptLevel(1, x)
}
let def_id = body.source.def_id();
let optimizations = if tcx.def_kind(def_id).has_codegen_attrs()
&& tcx.codegen_fn_attrs(def_id).optimize.do_not_optimize()
{
pm::Optimizations::Suppressed
} else {
pm::Optimizations::Allowed
};
// The main optimizations that we do on MIR.
pm::run_passes(
tcx,
@ -683,6 +707,7 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
&dump_mir::Marker("PreCodegen"),
],
Some(MirPhase::Runtime(RuntimePhase::Optimized)),
optimizations,
);
}

View file

@ -325,4 +325,8 @@ impl<'tcx> crate::MirPass<'tcx> for LowerIntrinsics {
}
}
}
fn is_required(&self) -> bool {
true
}
}

View file

@ -26,6 +26,10 @@ impl<'tcx> crate::MirPass<'tcx> for LowerSliceLenCalls {
lower_slice_len_call(block, slice_len_fn_item_def_id);
}
}
fn is_required(&self) -> bool {
false
}
}
fn lower_slice_len_call<'tcx>(block: &mut BasicBlockData<'tcx>, slice_len_fn_item_def_id: DefId) {

View file

@ -49,6 +49,10 @@ impl<'tcx> crate::MirPass<'tcx> for MatchBranchSimplification {
simplify_cfg(body);
}
}
fn is_required(&self) -> bool {
false
}
}
trait SimplifyMatch<'tcx> {

View file

@ -27,6 +27,10 @@ impl<'tcx> crate::MirPass<'tcx> for MentionedItems {
visitor.visit_body(body);
body.set_mentioned_items(visitor.mentioned_items);
}
fn is_required(&self) -> bool {
true
}
}
// This visitor is carefully in sync with the one in `rustc_monomorphize::collector`. We are

View file

@ -36,4 +36,8 @@ impl<'tcx> crate::MirPass<'tcx> for MultipleReturnTerminators {
simplify::remove_dead_blocks(body)
}
fn is_required(&self) -> bool {
false
}
}

View file

@ -71,6 +71,10 @@ impl<'tcx> crate::MirPass<'tcx> for RenameReturnPlace {
// The return place is always mutable.
ret_decl.mutability = Mutability::Mut;
}
fn is_required(&self) -> bool {
false
}
}
/// MIR that is eligible for the NRVO must fulfill two conditions:

View file

@ -90,6 +90,11 @@ pub(super) trait MirPass<'tcx> {
fn is_mir_dump_enabled(&self) -> bool {
true
}
/// Returns `true` if this pass must be run (i.e. it is required for soundness).
/// For passes which are strictly optimizations, this should return `false`.
/// If this is `false`, `#[optimize(none)]` will disable the pass.
fn is_required(&self) -> bool;
}
/// Just like `MirPass`, except it cannot mutate `Body`, and MIR dumping is
@ -134,6 +139,10 @@ where
fn is_mir_dump_enabled(&self) -> bool {
false
}
fn is_required(&self) -> bool {
true
}
}
pub(super) struct WithMinOptLevel<T>(pub u32, pub T);
@ -153,6 +162,19 @@ where
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
self.1.run_pass(tcx, body)
}
fn is_required(&self) -> bool {
self.1.is_required()
}
}
/// Whether to allow non-[required] optimizations
///
/// [required]: MirPass::is_required
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub(crate) enum Optimizations {
Suppressed,
Allowed,
}
/// Run the sequence of passes without validating the MIR after each pass. The MIR is still
@ -163,7 +185,7 @@ pub(super) fn run_passes_no_validate<'tcx>(
passes: &[&dyn MirPass<'tcx>],
phase_change: Option<MirPhase>,
) {
run_passes_inner(tcx, body, passes, phase_change, false);
run_passes_inner(tcx, body, passes, phase_change, false, Optimizations::Allowed);
}
/// The optional `phase_change` is applied after executing all the passes, if present
@ -172,11 +194,16 @@ pub(super) fn run_passes<'tcx>(
body: &mut Body<'tcx>,
passes: &[&dyn MirPass<'tcx>],
phase_change: Option<MirPhase>,
optimizations: Optimizations,
) {
run_passes_inner(tcx, body, passes, phase_change, true);
run_passes_inner(tcx, body, passes, phase_change, true, optimizations);
}
pub(super) fn should_run_pass<'tcx, P>(tcx: TyCtxt<'tcx>, pass: &P) -> bool
pub(super) fn should_run_pass<'tcx, P>(
tcx: TyCtxt<'tcx>,
pass: &P,
optimizations: Optimizations,
) -> bool
where
P: MirPass<'tcx> + ?Sized,
{
@ -196,7 +223,8 @@ where
);
*polarity
});
overridden.unwrap_or_else(|| pass.is_enabled(tcx.sess))
let suppressed = !pass.is_required() && matches!(optimizations, Optimizations::Suppressed);
overridden.unwrap_or_else(|| !suppressed && pass.is_enabled(tcx.sess))
}
fn run_passes_inner<'tcx>(
@ -205,6 +233,7 @@ fn run_passes_inner<'tcx>(
passes: &[&dyn MirPass<'tcx>],
phase_change: Option<MirPhase>,
validate_each: bool,
optimizations: Optimizations,
) {
let overridden_passes = &tcx.sess.opts.unstable_opts.mir_enable_passes;
trace!(?overridden_passes);
@ -243,7 +272,7 @@ fn run_passes_inner<'tcx>(
for pass in passes {
let name = pass.name();
if !should_run_pass(tcx, *pass) {
if !should_run_pass(tcx, *pass, optimizations) {
continue;
};

View file

@ -15,6 +15,10 @@ impl<'tcx> crate::MirPass<'tcx> for PostAnalysisNormalize {
let typing_env = ty::TypingEnv::post_analysis(tcx, body.source.def_id());
PostAnalysisNormalizeVisitor { tcx, typing_env }.visit_body_preserves_cfg(body);
}
fn is_required(&self) -> bool {
true
}
}
struct PostAnalysisNormalizeVisitor<'tcx> {

View file

@ -35,6 +35,10 @@ impl<'tcx> crate::MirPass<'tcx> for ReorderBasicBlocks {
permute(body.basic_blocks.as_mut(), &updater.map);
}
fn is_required(&self) -> bool {
false
}
}
/// Rearranges the locals into *use* order.
@ -85,6 +89,10 @@ impl<'tcx> crate::MirPass<'tcx> for ReorderLocals {
permute(&mut body.local_decls, &updater.map);
}
fn is_required(&self) -> bool {
false
}
}
fn permute<I: rustc_index::Idx + Ord, T>(data: &mut IndexVec<I, T>, map: &IndexSlice<I, I>) {

View file

@ -61,6 +61,10 @@ impl<'tcx> crate::MirPass<'tcx> for PromoteTemps<'tcx> {
let promoted = promote_candidates(body, tcx, temps, promotable_candidates);
self.promoted_fragments.set(promoted);
}
fn is_required(&self) -> bool {
true
}
}
/// State of a temporary during collection and promotion.

View file

@ -81,6 +81,10 @@ impl<'tcx> crate::MirPass<'tcx> for ReferencePropagation {
debug!(def_id = ?body.source.def_id());
while propagate_ssa(tcx, body) {}
}
fn is_required(&self) -> bool {
false
}
}
fn propagate_ssa<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) -> bool {

View file

@ -74,6 +74,10 @@ impl<'tcx> crate::MirPass<'tcx> for RemoveNoopLandingPads {
debug!("removed {:?} jumps and {:?} landing pads", jumps_folded, landing_pads_removed);
}
fn is_required(&self) -> bool {
true
}
}
impl RemoveNoopLandingPads {

View file

@ -20,4 +20,8 @@ impl<'tcx> crate::MirPass<'tcx> for RemovePlaceMention {
})
}
}
fn is_required(&self) -> bool {
true
}
}

View file

@ -22,4 +22,8 @@ impl<'tcx> crate::MirPass<'tcx> for RemoveStorageMarkers {
})
}
}
fn is_required(&self) -> bool {
true
}
}

View file

@ -62,6 +62,10 @@ impl<'tcx> crate::MirPass<'tcx> for RemoveUninitDrops {
block.terminator_mut().kind = TerminatorKind::Goto { target: *target };
}
}
fn is_required(&self) -> bool {
true
}
}
fn is_needs_drop_and_init<'tcx>(

View file

@ -38,4 +38,8 @@ impl<'tcx> crate::MirPass<'tcx> for RemoveUnneededDrops {
simplify_cfg(body);
}
}
fn is_required(&self) -> bool {
true
}
}

View file

@ -27,6 +27,10 @@ impl<'tcx> crate::MirPass<'tcx> for RemoveZsts {
replacer.visit_basic_block_data(bb, data);
}
}
fn is_required(&self) -> bool {
true
}
}
struct Replacer<'a, 'tcx> {

View file

@ -119,6 +119,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceKind<'tcx>) -> Body<
&add_call_guards::CriticalCallEdges,
],
Some(MirPhase::Runtime(RuntimePhase::Optimized)),
pm::Optimizations::Allowed,
);
return body;

View file

@ -83,6 +83,10 @@ impl<'tcx> crate::MirPass<'tcx> for SimplifyCfg {
debug!("SimplifyCfg({:?}) - simplifying {:?}", self.name(), body.source);
simplify_cfg(body);
}
fn is_required(&self) -> bool {
false
}
}
struct CfgSimplifier<'a, 'tcx> {
@ -405,6 +409,10 @@ impl<'tcx> crate::MirPass<'tcx> for SimplifyLocals {
body.local_decls.shrink_to_fit();
}
}
fn is_required(&self) -> bool {
false
}
}
pub(super) fn remove_unused_definitions<'tcx>(body: &mut Body<'tcx>) {

View file

@ -60,4 +60,8 @@ impl<'tcx> crate::MirPass<'tcx> for SimplifyConstCondition {
};
}
}
fn is_required(&self) -> bool {
false
}
}

View file

@ -140,6 +140,10 @@ impl<'tcx> crate::MirPass<'tcx> for SimplifyComparisonIntegral {
body.basic_blocks_mut()[idx].statements.insert(0, stmt);
}
}
fn is_required(&self) -> bool {
false
}
}
struct OptimizationFinder<'a, 'tcx> {

View file

@ -81,6 +81,10 @@ impl<'tcx> crate::MirPass<'tcx> for SingleUseConsts {
}
}
}
fn is_required(&self) -> bool {
true
}
}
#[derive(Copy, Clone, Debug)]

View file

@ -48,6 +48,10 @@ impl<'tcx> crate::MirPass<'tcx> for ScalarReplacementOfAggregates {
}
}
}
fn is_required(&self) -> bool {
false
}
}
/// Identify all locals that are not eligible for SROA.

View file

@ -31,4 +31,8 @@ impl<'tcx> crate::MirPass<'tcx> for StripDebugInfo {
)
});
}
fn is_required(&self) -> bool {
true
}
}

View file

@ -208,4 +208,8 @@ impl<'tcx> crate::MirPass<'tcx> for UnreachableEnumBranching {
patch.apply(body);
}
fn is_required(&self) -> bool {
false
}
}

View file

@ -52,6 +52,10 @@ impl crate::MirPass<'_> for UnreachablePropagation {
body.basic_blocks_mut()[bb].statements.clear();
}
}
fn is_required(&self) -> bool {
false
}
}
/// Return whether the current terminator is fully unreachable.

View file

@ -91,6 +91,10 @@ impl<'tcx> crate::MirPass<'tcx> for Validator {
}
}
}
fn is_required(&self) -> bool {
true
}
}
struct CfgChecker<'a, 'tcx> {

View file

@ -0,0 +1,32 @@
//@ revisions: NO-OPT SPEED-OPT
//@[NO-OPT] compile-flags: -Copt-level=0
//@[SPEED-OPT] compile-flags: -Copt-level=3 -Coverflow-checks=y
#![feature(optimize_attribute)]
#[optimize(none)]
pub fn add_noopt() -> i32 {
// CHECK-LABEL: fn add_noopt(
// CHECK: AddWithOverflow(const 1_i32, const 2_i32);
// CHECK-NEXT: assert
1 + 2
}
#[optimize(none)]
pub fn const_branch() -> i32 {
// CHECK-LABEL: fn const_branch(
// CHECK: switchInt(const true) -> [0: [[FALSE:bb[0-9]+]], otherwise: [[TRUE:bb[0-9]+]]];
// CHECK-NEXT: }
// CHECK: [[FALSE]]: {
// CHECK-NEXT: _0 = const 0
// CHECK-NEXT: goto
// CHECK-NEXT: }
// CHECK: [[TRUE]]: {
// CHECK-NEXT: _0 = const 1
// CHECK-NEXT: goto
// CHECK-NEXT: }
if true { 1 } else { 0 }
}
fn main() {}