Skip to content

Option::map_or generates a bunch of garbage IR #46758

Closed
@arielb1

Description

@arielb1

See e.g.

fn main() {
    let x = Some("hello".to_owned());
    x.map_or(0, |_| 1);
}

Which generates this initial IR:

; <core::option::Option<T>>::map_or
; Function Attrs: inlinehint uwtable
define internal i32 @"_ZN38_$LT$core..option..Option$LT$T$GT$$GT$6map_or17hf55f2f906b05703eE"(%"core::option::Option<alloc::string::String>"* noalias nocapture dereferenceable(24) %self, i32 %default) unnamed_addr #0 personality i32 (i32, i32, i64, %"unwind::libunwind::_Unwind_Exception"*, %"unwind::libunwind::_Unwind_Context"*)* @rust_eh_personality {
start:
  %personalityslot = alloca { i8*, i32 }, align 8
  %_12 = alloca i8, align 1
  %_11 = alloca i8, align 1
  %_10 = alloca i8, align 1
  %_8 = alloca %"alloc::string::String", align 8
  %_7 = alloca { [0 x i8], %"alloc::string::String", [0 x i8] }, align 8
  %t = alloca %"alloc::string::String", align 8
  %_0 = alloca i32, align 4
  store i8 0, i8* %_12
  store i8 0, i8* %_10
  store i8 0, i8* %_11
  store i8 1, i8* %_10
  store i8 1, i8* %_11
  store i8 1, i8* %_12
  %0 = bitcast %"core::option::Option<alloc::string::String>"* %self to {}**
  %1 = load {}*, {}** %0
  %2 = icmp eq {}* %1, null
  %3 = select i1 %2, i64 0, i64 1
  switch i64 %3, label %bb3 [
    i64 0, label %bb2
    i64 1, label %bb4
  ]

bb1:                                              ; preds = %bb11, %bb10, %bb12
  %4 = bitcast { i8*, i32 }* %personalityslot to i8**
  %5 = load i8*, i8** %4
  %6 = getelementptr inbounds { i8*, i32 }, { i8*, i32 }* %personalityslot, i32 0, i32 1
  %7 = load i32, i32* %6
  %8 = insertvalue { i8*, i32 } undef, i8* %5, 0
  %9 = insertvalue { i8*, i32 } %8, i32 %7, 1
  resume { i8*, i32 } %9

bb2:                                              ; preds = %start
  store i8 0, i8* %_11
  store i32 %default, i32* %_0
  br label %bb5

bb3:                                              ; preds = %start
  unreachable

bb4:                                              ; preds = %start
  store i8 0, i8* %_10
  %10 = bitcast %"core::option::Option<alloc::string::String>"* %self to %"core::option::Option<alloc::string::String>::Some"*
  %11 = bitcast %"core::option::Option<alloc::string::String>::Some"* %10 to %"alloc::string::String"*
  %12 = bitcast %"alloc::string::String"* %11 to i8*
  %13 = bitcast %"alloc::string::String"* %t to i8*
  call void @llvm.memcpy.p0i8.p0i8.i64(i8* %13, i8* %12, i64 24, i32 8, i1 false)
  store i8 0, i8* %_12
  %14 = bitcast %"alloc::string::String"* %t to i8*
  %15 = bitcast %"alloc::string::String"* %_8 to i8*
  call void @llvm.memcpy.p0i8.p0i8.i64(i8* %15, i8* %14, i64 24, i32 8, i1 false)
  %16 = bitcast { [0 x i8], %"alloc::string::String", [0 x i8] }* %_7 to %"alloc::string::String"*
  %17 = bitcast %"alloc::string::String"* %_8 to i8*
  %18 = bitcast %"alloc::string::String"* %16 to i8*
  call void @llvm.memcpy.p0i8.p0i8.i64(i8* %18, i8* %17, i64 24, i32 8, i1 false)
  %19 = bitcast { [0 x i8], %"alloc::string::String", [0 x i8] }* %_7 to %"alloc::string::String"*
; invoke map_example::main::{{closure}}
  %20 = invoke i32 @"_ZN11map_example4main28_$u7b$$u7b$closure$u7d$$u7d$17h0799836f5ea6b921E"(%"alloc::string::String"* noalias nocapture dereferenceable(24) %19)
          to label %bb7 unwind label %cleanup

bb5:                                              ; preds = %bb2, %bb7
  %21 = load i8, i8* %_12, !range !1
  %22 = trunc i8 %21 to i1
  br i1 %22, label %bb15, label %bb8

bb6:                                              ; preds = %bb13, %bb14
  %23 = bitcast %"core::option::Option<alloc::string::String>"* %self to {}**
  %24 = load {}*, {}** %23
  %25 = icmp eq {}* %24, null
  %26 = select i1 %25, i64 0, i64 1
  switch i64 %26, label %bb12 [
    i64 1, label %bb10
  ]

bb7:                                              ; preds = %bb4
  store i32 %20, i32* %_0
  br label %bb5

bb8:                                              ; preds = %bb15, %bb5
  %27 = load i8, i8* %_11, !range !1
  %28 = trunc i8 %27 to i1
  br i1 %28, label %bb16, label %bb9

bb9:                                              ; preds = %bb16, %bb8
  %29 = bitcast %"core::option::Option<alloc::string::String>"* %self to {}**
  %30 = load {}*, {}** %29
  %31 = icmp eq {}* %30, null
  %32 = select i1 %31, i64 0, i64 1
  switch i64 %32, label %bb20 [
    i64 1, label %bb18
  ]


bb10:                                             ; preds = %bb6
  %33 = load i8, i8* %_10, !range !1
  %34 = trunc i8 %33 to i1
  br i1 %34, label %bb11, label %bb1

bb11:                                             ; preds = %bb10
  store i8 0, i8* %_10
  %35 = bitcast %"core::option::Option<alloc::string::String>"* %self to %"core::option::Option<alloc::string::String>::Some"*
  %36 = bitcast %"core::option::Option<alloc::string::String>::Some"* %35 to %"alloc::string::String"*
; call core::ptr::drop_in_place
  call void @_ZN4core3ptr13drop_in_place17h5aaf0cb4e5af22beE(%"alloc::string::String"* %36) #8
  br label %bb1

bb12:                                             ; preds = %bb6
; call core::ptr::drop_in_place
  call void @_ZN4core3ptr13drop_in_place17h85c4ff3726432e4eE(%"core::option::Option<alloc::string::String>"* %self) #8
  br label %bb1

bb13:                                             ; preds = %bb14
  store i8 0, i8* %_11
  br label %bb6

bb14:                                             ; preds = %cleanup
  %37 = load i8, i8* %_11, !range !1
  %38 = trunc i8 %37 to i1
  br i1 %38, label %bb13, label %bb6

bb15:                                             ; preds = %bb5
  store i8 0, i8* %_12
  br label %bb8

bb16:                                             ; preds = %bb8
  store i8 0, i8* %_11
  br label %bb9

bb17:                                             ; preds = %bb19, %bb18, %bb20
  %39 = load i32, i32* %_0
  ret i32 %39

bb18:                                             ; preds = %bb9
  %40 = load i8, i8* %_10, !range !1
  %41 = trunc i8 %40 to i1
  br i1 %41, label %bb19, label %bb17

bb19:                                             ; preds = %bb18
  store i8 0, i8* %_10
  %42 = bitcast %"core::option::Option<alloc::string::String>"* %self to %"core::option::Option<alloc::string::String>::Some"*
  %43 = bitcast %"core::option::Option<alloc::string::String>::Some"* %42 to %"alloc::string::String"*
; call core::ptr::drop_in_place
  call void @_ZN4core3ptr13drop_in_place17h5aaf0cb4e5af22beE(%"alloc::string::String"* %43)
  br label %bb17

bb20:                                             ; preds = %bb9
; call core::ptr::drop_in_place
  call void @_ZN4core3ptr13drop_in_place17h85c4ff3726432e4eE(%"core::option::Option<alloc::string::String>"* %self)
  br label %bb17

cleanup:                                          ; preds = %bb4
  %44 = landingpad { i8*, i32 }
          cleanup
  %45 = extractvalue { i8*, i32 } %44, 0
  %46 = extractvalue { i8*, i32 } %44, 1
  %47 = getelementptr inbounds { i8*, i32 }, { i8*, i32 }* %personalityslot, i32 0, i32 0
  store i8* %45, i8** %47
  %48 = getelementptr inbounds { i8*, i32 }, { i8*, i32 }* %personalityslot, i32 0, i32 1
  store i32 %46, i32* %48
  br label %bb14

Which is quite a bit of IR for such a little function:

    pub fn map_or<U, F: FnOnce(T) -> U>(self, default: U, f: F) -> U {
        match self {
            Some(t) => f(t),
            None => default,
        }
    }

I suspect #46525 might be involved in causing drop elaboration to go crazy

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-MIRArea: Mid-level IR (MIR) - https://blog.rust-lang.org/2016/04/19/MIR.htmlA-codegenArea: Code generationC-enhancementCategory: An issue proposing an enhancement or a PR with one.C-optimizationCategory: An issue highlighting optimization opportunities or PRs implementing suchI-compiletimeIssue: Problems and improvements with respect to compile times.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions