Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

&str.slice is bloated #16625

Closed
huonw opened this issue Aug 20, 2014 · 8 comments
Closed

&str.slice is bloated #16625

huonw opened this issue Aug 20, 2014 · 8 comments
Labels
I-slow Issue: Problems and improvements with respect to performance of generated code.

Comments

@huonw
Copy link
Member

huonw commented Aug 20, 2014

#![crate_type = "lib"]
pub fn slice(x: &str, a: uint, b: uint) -> &str {
    x.slice(a, b)
}

with -O becomes

; Function Attrs: uwtable
define void @_ZN5slice20ha62b7cd23f98de21daaE(%str_slice* noalias nocapture sret dereferenceable(16), %str_slice* noalias nocapture dereferenceable(16), i64, i64) unnamed_addr #0 {
entry-block:
  %4 = alloca %str_slice, align 8
  %5 = alloca %"struct.core::fmt::Argument<[]>[#3]", align 8
  %__args.i.i = alloca %"struct.core::fmt::Arguments<[]>[#3]", align 8
  %6 = alloca %str_slice, align 8
  %7 = alloca %"struct.core::fmt::Argument<[]>[#3]", align 8
  %__args7.i.i = alloca %"struct.core::fmt::Arguments<[]>[#3]", align 8
  %begin.i = alloca i64, align 8
  %end.i = alloca i64, align 8
  %8 = alloca [3 x %"struct.core::fmt::Argument<[]>[#3]"], align 8
  %__args.i = alloca %"struct.core::fmt::Arguments<[]>[#3]", align 8
  %.sub.i = getelementptr inbounds [3 x %"struct.core::fmt::Argument<[]>[#3]"]* %8, i64 0, i64 0
  %9 = bitcast i64* %begin.i to i8*
  call void @llvm.lifetime.start(i64 8, i8* %9)
  store i64 %2, i64* %begin.i, align 8
  %10 = bitcast i64* %end.i to i8*
  call void @llvm.lifetime.start(i64 8, i8* %10)
  store i64 %3, i64* %end.i, align 8
  %.sroa.3.0..sroa_idx4.i.i.i = getelementptr inbounds %str_slice* %1, i64 0, i32 1
  %.sroa.3.0.copyload.i.i.i = load i64* %.sroa.3.0..sroa_idx4.i.i.i, align 8
  %11 = icmp eq i64 %.sroa.3.0.copyload.i.i.i, %2
  br i1 %11, label %before_rhs.i, label %next-block.i.i

next-block.i.i:                                   ; preds = %entry-block
  %12 = icmp ult i64 %.sroa.3.0.copyload.i.i.i, %2
  br i1 %12, label %then-block-54-.i, label %next-block1.i.i

next-block1.i.i:                                  ; preds = %next-block.i.i
  %13 = icmp ugt i64 %.sroa.3.0.copyload.i.i.i, %2
  br i1 %13, label %"_ZN3str39_$BP$$x27a$x20str.StrSlice$LT$$x27a$GT$16is_char_boundary20h77e6472c98e21760edaE.exit.i", label %cond.i.i, !prof !0

cond.i.i:                                         ; preds = %next-block1.i.i
  tail call void @_ZN7failure17fail_bounds_check20hb6567e7af36a3c08KykE({ %str_slice, i64 }* noalias nocapture readonly dereferenceable(24) @const, i64 %2, i64 %.sroa.3.0.copyload.i.i.i)
  unreachable

"_ZN3str39_$BP$$x27a$x20str.StrSlice$LT$$x27a$GT$16is_char_boundary20h77e6472c98e21760edaE.exit.i": ; preds = %next-block1.i.i
  %.sroa.0.0..sroa_idx.i.i = getelementptr inbounds %str_slice* %1, i64 0, i32 0
  %.sroa.0.0.copyload.i.i = load i8** %.sroa.0.0..sroa_idx.i.i, align 8
  %14 = getelementptr inbounds i8* %.sroa.0.0.copyload.i.i, i64 %2
  %15 = load i8* %14, align 1
  %16 = icmp sgt i8 %15, -1
  %17 = icmp ugt i8 %15, -65
  %..i.i = or i1 %16, %17
  br i1 %..i.i, label %before_rhs.i, label %then-block-54-.i

join.i:                                           ; preds = %next-block1.i15.i
  %.sroa.0.0..sroa_idx.i16.i = getelementptr inbounds %str_slice* %1, i64 0, i32 0
  %.sroa.0.0.copyload.i17.i = load i8** %.sroa.0.0..sroa_idx.i16.i, align 8
  %18 = getelementptr inbounds i8* %.sroa.0.0.copyload.i17.i, i64 %3
  %19 = load i8* %18, align 1
  %20 = icmp sgt i8 %19, -1
  %21 = icmp ugt i8 %19, -65
  %..i18.i = or i1 %20, %21
  br i1 %..i18.i, label %next-block.i, label %then-block-54-.i

before_rhs.i:                                     ; preds = %"_ZN3str39_$BP$$x27a$x20str.StrSlice$LT$$x27a$GT$16is_char_boundary20h77e6472c98e21760edaE.exit.i", %entry-block
  %22 = icmp eq i64 %.sroa.3.0.copyload.i.i.i, %3
  br i1 %22, label %before_rhs.next-block_crit_edge.i, label %next-block.i14.i

before_rhs.next-block_crit_edge.i:                ; preds = %before_rhs.i
  %arg.sroa.0.0..sroa_idx.phi.trans.insert.i = getelementptr inbounds %str_slice* %1, i64 0, i32 0
  %arg.sroa.0.0.copyload.pre.i = load i8** %arg.sroa.0.0..sroa_idx.phi.trans.insert.i, align 8
  br label %next-block.i

next-block.i14.i:                                 ; preds = %before_rhs.i
  %23 = icmp ult i64 %.sroa.3.0.copyload.i.i.i, %3
  br i1 %23, label %then-block-54-.i, label %next-block1.i15.i

next-block1.i15.i:                                ; preds = %next-block.i14.i
  %24 = icmp ugt i64 %.sroa.3.0.copyload.i.i.i, %3
  br i1 %24, label %join.i, label %cond.i20.i, !prof !0

cond.i20.i:                                       ; preds = %next-block1.i15.i
  tail call void @_ZN7failure17fail_bounds_check20hb6567e7af36a3c08KykE({ %str_slice, i64 }* noalias nocapture readonly dereferenceable(24) @const, i64 %3, i64 %.sroa.3.0.copyload.i.i.i)
  unreachable

then-block-54-.i:                                 ; preds = %next-block.i14.i, %join.i, %"_ZN3str39_$BP$$x27a$x20str.StrSlice$LT$$x27a$GT$16is_char_boundary20h77e6472c98e21760edaE.exit.i", %next-block.i.i
  %25 = bitcast [3 x %"struct.core::fmt::Argument<[]>[#3]"]* %8 to i8*
  call void @llvm.lifetime.start(i64 16, i8* %25)
  %26 = getelementptr inbounds [3 x %"struct.core::fmt::Argument<[]>[#3]"]* %8, i64 0, i64 0, i32 0
  store %"enum.core::result::Result<[(), core::fmt::FormatError]>[#3]" (%"enum.core::fmt::Void<[]>[#3]"*, %"struct.core::fmt::Formatter<[]>[#3]"*)* bitcast (%"enum.core::result::Result<[(), core::fmt::FormatError]>[#3]" (i64*, %"struct.core::fmt::Formatter<[]>[#3]"*)* @_ZN3fmt11secret_show20h2484714462526658409E to %"enum.core::result::Result<[(), core::fmt::FormatError]>[#3]" (%"enum.core::fmt::Void<[]>[#3]"*, %"struct.core::fmt::Formatter<[]>[#3]"*)*), %"enum.core::result::Result<[(), core::fmt::FormatError]>[#3]" (%"enum.core::fmt::Void<[]>[#3]"*, %"struct.core::fmt::Formatter<[]>[#3]"*)** %26, align 8
  %27 = getelementptr inbounds [3 x %"struct.core::fmt::Argument<[]>[#3]"]* %8, i64 0, i64 0, i32 1
  %.c.i.i = bitcast i64* %begin.i to %"enum.core::fmt::Void<[]>[#3]"*
  store %"enum.core::fmt::Void<[]>[#3]"* %.c.i.i, %"enum.core::fmt::Void<[]>[#3]"** %27, align 8
  %28 = getelementptr inbounds [3 x %"struct.core::fmt::Argument<[]>[#3]"]* %8, i64 0, i64 1, i32 0
  store %"enum.core::result::Result<[(), core::fmt::FormatError]>[#3]" (%"enum.core::fmt::Void<[]>[#3]"*, %"struct.core::fmt::Formatter<[]>[#3]"*)* bitcast (%"enum.core::result::Result<[(), core::fmt::FormatError]>[#3]" (i64*, %"struct.core::fmt::Formatter<[]>[#3]"*)* @_ZN3fmt11secret_show20h2484714462526658409E to %"enum.core::result::Result<[(), core::fmt::FormatError]>[#3]" (%"enum.core::fmt::Void<[]>[#3]"*, %"struct.core::fmt::Formatter<[]>[#3]"*)*), %"enum.core::result::Result<[(), core::fmt::FormatError]>[#3]" (%"enum.core::fmt::Void<[]>[#3]"*, %"struct.core::fmt::Formatter<[]>[#3]"*)** %28, align 8
  %29 = getelementptr inbounds [3 x %"struct.core::fmt::Argument<[]>[#3]"]* %8, i64 0, i64 1, i32 1
  %.c.i25.i = bitcast i64* %end.i to %"enum.core::fmt::Void<[]>[#3]"*
  store %"enum.core::fmt::Void<[]>[#3]"* %.c.i25.i, %"enum.core::fmt::Void<[]>[#3]"** %29, align 8
  %30 = getelementptr inbounds [3 x %"struct.core::fmt::Argument<[]>[#3]"]* %8, i64 0, i64 2, i32 0
  store %"enum.core::result::Result<[(), core::fmt::FormatError]>[#3]" (%"enum.core::fmt::Void<[]>[#3]"*, %"struct.core::fmt::Formatter<[]>[#3]"*)* bitcast (%"enum.core::result::Result<[(), core::fmt::FormatError]>[#3]" (%str_slice*, %"struct.core::fmt::Formatter<[]>[#3]"*)* @_ZN3fmt11secret_show20h1520870893265926329E to %"enum.core::result::Result<[(), core::fmt::FormatError]>[#3]" (%"enum.core::fmt::Void<[]>[#3]"*, %"struct.core::fmt::Formatter<[]>[#3]"*)*), %"enum.core::result::Result<[(), core::fmt::FormatError]>[#3]" (%"enum.core::fmt::Void<[]>[#3]"*, %"struct.core::fmt::Formatter<[]>[#3]"*)** %30, align 8
  %31 = getelementptr inbounds [3 x %"struct.core::fmt::Argument<[]>[#3]"]* %8, i64 0, i64 2, i32 1
  %.c.i26.i = bitcast %str_slice* %1 to %"enum.core::fmt::Void<[]>[#3]"*
  store %"enum.core::fmt::Void<[]>[#3]"* %.c.i26.i, %"enum.core::fmt::Void<[]>[#3]"** %31, align 8
  %32 = bitcast %"struct.core::fmt::Arguments<[]>[#3]"* %__args.i to i8*
  call void @llvm.lifetime.start(i64 32, i8* %32)
  %__adjust.sroa.0.0..sroa_idx.i = getelementptr inbounds %"struct.core::fmt::Arguments<[]>[#3]"* %__args.i, i64 0, i32 0, i32 0
  store %"enum.core::fmt::rt::Piece<[]>[#3]"* bitcast ({ { i8, %str_slice, [48 x i8] }, { i8, { { i8, [15 x i8] }, { i32, i8, i64, { i8, [15 x i8] }, { i8, [15 x i8] } } }, [0 x i8] }, { i8, %str_slice, [48 x i8] }, { i8, { { i8, [15 x i8] }, { i32, i8, i64, { i8, [15 x i8] }, { i8, [15 x i8] } } }, [0 x i8] }, { i8, %str_slice, [48 x i8] }, { i8, { { i8, [15 x i8] }, { i32, i8, i64, { i8, [15 x i8] }, { i8, [15 x i8] } } }, [0 x i8] }, { i8, %str_slice, [48 x i8] } }* @"_ZN3str39_$BP$$x27a$x20str.StrSlice$LT$$x27a$GT$5slice15__STATIC_FMTSTR20hecbbb0a2a6789145mDrE" to %"enum.core::fmt::rt::Piece<[]>[#3]"*), %"enum.core::fmt::rt::Piece<[]>[#3]"** %__adjust.sroa.0.0..sroa_idx.i, align 8
  %__adjust.sroa.4.0..sroa_idx34.i = getelementptr inbounds %"struct.core::fmt::Arguments<[]>[#3]"* %__args.i, i64 0, i32 0, i32 1
  store i64 7, i64* %__adjust.sroa.4.0..sroa_idx34.i, align 8
  %__adjust.sroa.0.0..sroa_idx.i27.i = getelementptr inbounds %"struct.core::fmt::Arguments<[]>[#3]"* %__args.i, i64 0, i32 1, i32 0
  store %"struct.core::fmt::Argument<[]>[#3]"* %.sub.i, %"struct.core::fmt::Argument<[]>[#3]"** %__adjust.sroa.0.0..sroa_idx.i27.i, align 8
  %__adjust.sroa.3.0..sroa_idx1.i.i = getelementptr inbounds %"struct.core::fmt::Arguments<[]>[#3]"* %__args.i, i64 0, i32 1, i32 1
  store i64 3, i64* %__adjust.sroa.3.0..sroa_idx1.i.i, align 8
  call void @_ZN7failure12begin_unwind20hd0af3f4657afff41yAkE(%"struct.core::fmt::Arguments<[]>[#3]"* noalias nocapture readonly dereferenceable(32) %__args.i, { %str_slice, i64 }* noalias nocapture readonly dereferenceable(24) @"_ZN3str39_$BP$$x27a$x20str.StrSlice$LT$$x27a$GT$5slice8_run_fmt10_FILE_LINE20h4965d27d95ea2255QCrE")
  unreachable

next-block.i:                                     ; preds = %before_rhs.next-block_crit_edge.i, %join.i
  %arg.sroa.0.0.copyload.i = phi i8* [ %arg.sroa.0.0.copyload.pre.i, %before_rhs.next-block_crit_edge.i ], [ %.sroa.0.0.copyload.i17.i, %join.i ]
  %33 = icmp ult i64 %3, %2
  br i1 %33, label %then-block-583-.i.i, label %next-block.i24.i

then-block-583-.i.i:                              ; preds = %next-block.i
  %34 = bitcast %str_slice* %4 to i8*
  call void @llvm.lifetime.start(i64 16, i8* %34)
  %35 = getelementptr inbounds %str_slice* %4, i64 0, i32 0
  store i8* getelementptr inbounds ([30 x i8]* @str1159, i64 0, i64 0), i8** %35, align 8
  %36 = getelementptr inbounds %str_slice* %4, i64 0, i32 1
  store i64 30, i64* %36, align 8
  %37 = bitcast %"struct.core::fmt::Argument<[]>[#3]"* %5 to i8*
  call void @llvm.lifetime.start(i64 16, i8* %37)
  %38 = getelementptr inbounds %"struct.core::fmt::Argument<[]>[#3]"* %5, i64 0, i32 0
  store %"enum.core::result::Result<[(), core::fmt::FormatError]>[#3]" (%"enum.core::fmt::Void<[]>[#3]"*, %"struct.core::fmt::Formatter<[]>[#3]"*)* bitcast (%"enum.core::result::Result<[(), core::fmt::FormatError]>[#3]" (%str_slice*, %"struct.core::fmt::Formatter<[]>[#3]"*)* @_ZN3fmt11secret_show20h8865777717318847987E to %"enum.core::result::Result<[(), core::fmt::FormatError]>[#3]" (%"enum.core::fmt::Void<[]>[#3]"*, %"struct.core::fmt::Formatter<[]>[#3]"*)*), %"enum.core::result::Result<[(), core::fmt::FormatError]>[#3]" (%"enum.core::fmt::Void<[]>[#3]"*, %"struct.core::fmt::Formatter<[]>[#3]"*)** %38, align 8
  %39 = getelementptr inbounds %"struct.core::fmt::Argument<[]>[#3]"* %5, i64 0, i32 1
  %.c.i.i.i = bitcast %str_slice* %4 to %"enum.core::fmt::Void<[]>[#3]"*
  store %"enum.core::fmt::Void<[]>[#3]"* %.c.i.i.i, %"enum.core::fmt::Void<[]>[#3]"** %39, align 8
  %40 = bitcast %"struct.core::fmt::Arguments<[]>[#3]"* %__args.i.i to i8*
  call void @llvm.lifetime.start(i64 32, i8* %40)
  %__adjust.sroa.0.0..sroa_idx.i.i = getelementptr inbounds %"struct.core::fmt::Arguments<[]>[#3]"* %__args.i.i, i64 0, i32 0, i32 0
  store %"enum.core::fmt::rt::Piece<[]>[#3]"* bitcast ({ { i8, { { i8, [15 x i8] }, { i32, i8, i64, { i8, [15 x i8] }, { i8, [15 x i8] } } }, [0 x i8] } }* @_ZN3str3raw11slice_bytes15__STATIC_FMTSTR20hf82a49d95a7811fb4irE to %"enum.core::fmt::rt::Piece<[]>[#3]"*), %"enum.core::fmt::rt::Piece<[]>[#3]"** %__adjust.sroa.0.0..sroa_idx.i.i, align 8
  %__adjust.sroa.4.0..sroa_idx37.i.i = getelementptr inbounds %"struct.core::fmt::Arguments<[]>[#3]"* %__args.i.i, i64 0, i32 0, i32 1
  store i64 1, i64* %__adjust.sroa.4.0..sroa_idx37.i.i, align 8
  %__adjust.sroa.0.0..sroa_idx.i.i.i = getelementptr inbounds %"struct.core::fmt::Arguments<[]>[#3]"* %__args.i.i, i64 0, i32 1, i32 0
  store %"struct.core::fmt::Argument<[]>[#3]"* %5, %"struct.core::fmt::Argument<[]>[#3]"** %__adjust.sroa.0.0..sroa_idx.i.i.i, align 8
  %__adjust.sroa.3.0..sroa_idx1.i.i.i = getelementptr inbounds %"struct.core::fmt::Arguments<[]>[#3]"* %__args.i.i, i64 0, i32 1, i32 1
  store i64 1, i64* %__adjust.sroa.3.0..sroa_idx1.i.i.i, align 8
  call void @_ZN7failure12begin_unwind20hd0af3f4657afff41yAkE(%"struct.core::fmt::Arguments<[]>[#3]"* noalias nocapture readonly dereferenceable(32) %__args.i.i, { %str_slice, i64 }* noalias nocapture readonly dereferenceable(24) @_ZN3str3raw11slice_bytes8_run_fmt10_FILE_LINE20h4965d27d95ea2255ghrE)
  unreachable

next-block.i24.i:                                 ; preds = %next-block.i
  %41 = icmp ult i64 %.sroa.3.0.copyload.i.i.i, %3
  br i1 %41, label %then-block-670-.i.i, label %"_ZN3str39_$BP$$x27a$x20str.StrSlice$LT$$x27a$GT$5slice20he30e5671c97c5789AaaE.exit"

then-block-670-.i.i:                              ; preds = %next-block.i24.i
  %42 = bitcast %str_slice* %6 to i8*
  call void @llvm.lifetime.start(i64 16, i8* %42)
  %43 = getelementptr inbounds %str_slice* %6, i64 0, i32 0
  store i8* getelementptr inbounds ([32 x i8]* @str1160, i64 0, i64 0), i8** %43, align 8
  %44 = getelementptr inbounds %str_slice* %6, i64 0, i32 1
  store i64 32, i64* %44, align 8
  %45 = bitcast %"struct.core::fmt::Argument<[]>[#3]"* %7 to i8*
  call void @llvm.lifetime.start(i64 16, i8* %45)
  %46 = getelementptr inbounds %"struct.core::fmt::Argument<[]>[#3]"* %7, i64 0, i32 0
  store %"enum.core::result::Result<[(), core::fmt::FormatError]>[#3]" (%"enum.core::fmt::Void<[]>[#3]"*, %"struct.core::fmt::Formatter<[]>[#3]"*)* bitcast (%"enum.core::result::Result<[(), core::fmt::FormatError]>[#3]" (%str_slice*, %"struct.core::fmt::Formatter<[]>[#3]"*)* @_ZN3fmt11secret_show20h8865777717318847987E to %"enum.core::result::Result<[(), core::fmt::FormatError]>[#3]" (%"enum.core::fmt::Void<[]>[#3]"*, %"struct.core::fmt::Formatter<[]>[#3]"*)*), %"enum.core::result::Result<[(), core::fmt::FormatError]>[#3]" (%"enum.core::fmt::Void<[]>[#3]"*, %"struct.core::fmt::Formatter<[]>[#3]"*)** %46, align 8
  %47 = getelementptr inbounds %"struct.core::fmt::Argument<[]>[#3]"* %7, i64 0, i32 1
  %.c.i25.i.i = bitcast %str_slice* %6 to %"enum.core::fmt::Void<[]>[#3]"*
  store %"enum.core::fmt::Void<[]>[#3]"* %.c.i25.i.i, %"enum.core::fmt::Void<[]>[#3]"** %47, align 8
  %48 = bitcast %"struct.core::fmt::Arguments<[]>[#3]"* %__args7.i.i to i8*
  call void @llvm.lifetime.start(i64 32, i8* %48)
  %__adjust8.sroa.0.0..sroa_idx.i.i = getelementptr inbounds %"struct.core::fmt::Arguments<[]>[#3]"* %__args7.i.i, i64 0, i32 0, i32 0
  store %"enum.core::fmt::rt::Piece<[]>[#3]"* bitcast ({ { i8, { { i8, [15 x i8] }, { i32, i8, i64, { i8, [15 x i8] }, { i8, [15 x i8] } } }, [0 x i8] } }* @_ZN3str3raw11slice_bytes15__STATIC_FMTSTR20hf82a49d95a7811fb4irE to %"enum.core::fmt::rt::Piece<[]>[#3]"*), %"enum.core::fmt::rt::Piece<[]>[#3]"** %__adjust8.sroa.0.0..sroa_idx.i.i, align 8
  %__adjust8.sroa.4.0..sroa_idx32.i.i = getelementptr inbounds %"struct.core::fmt::Arguments<[]>[#3]"* %__args7.i.i, i64 0, i32 0, i32 1
  store i64 1, i64* %__adjust8.sroa.4.0..sroa_idx32.i.i, align 8
  %__adjust.sroa.0.0..sroa_idx.i23.i.i = getelementptr inbounds %"struct.core::fmt::Arguments<[]>[#3]"* %__args7.i.i, i64 0, i32 1, i32 0
  store %"struct.core::fmt::Argument<[]>[#3]"* %7, %"struct.core::fmt::Argument<[]>[#3]"** %__adjust.sroa.0.0..sroa_idx.i23.i.i, align 8
  %__adjust.sroa.3.0..sroa_idx1.i24.i.i = getelementptr inbounds %"struct.core::fmt::Arguments<[]>[#3]"* %__args7.i.i, i64 0, i32 1, i32 1
  store i64 1, i64* %__adjust.sroa.3.0..sroa_idx1.i24.i.i, align 8
  call void @_ZN7failure12begin_unwind20hd0af3f4657afff41yAkE(%"struct.core::fmt::Arguments<[]>[#3]"* noalias nocapture readonly dereferenceable(32) %__args7.i.i, { %str_slice, i64 }* noalias nocapture readonly dereferenceable(24) @_ZN3str3raw11slice_bytes8_run_fmt10_FILE_LINE20h4965d27d95ea2255FirE)
  unreachable

"_ZN3str39_$BP$$x27a$x20str.StrSlice$LT$$x27a$GT$5slice20he30e5671c97c5789AaaE.exit": ; preds = %next-block.i24.i
  %49 = getelementptr inbounds %str_slice* %0, i64 0, i32 0
  %50 = getelementptr inbounds i8* %arg.sroa.0.0.copyload.i, i64 %2
  store i8* %50, i8** %49, align 8
  %51 = getelementptr inbounds %str_slice* %0, i64 0, i32 1
  %52 = sub i64 %3, %2
  store i64 %52, i64* %51, align 8
  call void @llvm.lifetime.end(i64 8, i8* %10)
  call void @llvm.lifetime.end(i64 8, i8* %9)
  %53 = bitcast %str_slice* %1 to i8*
  tail call void @llvm.lifetime.end(i64 16, i8* %53)
  ret void
}

The worst part is there's five separate sites that unwind (each unreachable is just after an unwinding function) due to various assertions and bounds-checks. (&[].slice is mildly better.)

@huonw huonw added the I-slow label Aug 20, 2014
@thestinger
Copy link
Contributor

This is the cost of the fail!() macro. Instead, we should call a function (fail("foo")) and let backtraces handle reporting the location of the error.

@huonw
Copy link
Member Author

huonw commented Aug 20, 2014

It's also the cost of doing significantly more work than necessary:

  • bounds checks, neither (there is two is_char_boundary calls) are eliminated, although this looks a bit like an LLVM bug, since the two length comparisons above it cover the OOB case, and it's even touching the same variables in the IR:

      %11 = icmp eq i64 %.sroa.3.0.copyload.i.i.i, %2
      br i1 %11, label %before_rhs.i, label %next-block.i.i
    
    next-block.i.i:                                   ; preds = %entry-block
      %12 = icmp ult i64 %.sroa.3.0.copyload.i.i.i, %2
      br i1 %12, label %then-block-54-.i, label %next-block1.i.i
    
    next-block1.i.i:                                  ; preds = %next-block.i.i
      %13 = icmp ugt i64 %.sroa.3.0.copyload.i.i.i, %2 ; impossible to fail!
  • an assert! that is impossible to trigger due to bounds checking in is_char_boundary.

It should be possible to at least reduce it to 2 unwinding (one for the character boundaries, one for start <= end), or even 1 if we're willing to lump everything together.

@thestinger
Copy link
Contributor

The intricate details of the error handling aren't really important, because there's no reason for it to be inlined everywhere. It should be a function call passing a string literal. Using macros to report error locations doesn't work anyway because you don't get any context beyond the fact that a very low-level function like slice failed. You already need backtraces and those don't bloat all of the code.

@pcwalton
Copy link
Contributor

I think the problem is not the error location (that can be fixed if it's not already) but the fact that there's string formatting going on. Asserts should never have string formatting.

@bluss
Copy link
Member

bluss commented Aug 20, 2014

Do .slice_from and .slice_to optimize out the checks for their respective fixed endpoints? If not, that's a possible improvement in the same area.

@bluss
Copy link
Member

bluss commented Aug 21, 2014

fail!("assertion failed: {:s}", stringify!($cond)) should be easy to fix. Replace with
fail!(concat!("assertion failed: ", stringify!($cond)))

bors added a commit that referenced this issue Aug 24, 2014
These are somewhat stop-gap solutions to address #16625 

core: Separate failure formatting in str methods slice, slice_to, slice_from

Use a separate inline-never function to format failure message for
str::slice() errors.

Using strcat's idea, this makes sure no formatting code from failure is
inlined when str::slice() is inlined. The number of `unreachable` being
inlined when usingi `.slice()` drops from 5 to just 1.



The testcase:

```
#![crate_type = "lib"]
pub fn slice(x: &str, a: uint, b: uint) -> &str {
    x.slice(a, b)
}
```

shrinks from 16.9 kB to 3.3 kB llvm IR, and the number of `unreachable` drops from 5 to 1.
bors added a commit that referenced this issue Aug 24, 2014

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
With no custom message, we should just use concat! + stringify! for
`assert!(expr)` to avoid the string formatting code path.

Inspired by issue #16625
@bluss
Copy link
Member

bluss commented Aug 24, 2014

This issue has been resolved by resolving the example given, but what is the follow up, what is the more general issue? Would allowing a format-free assert! code path help (issue #16700)? Should we extend the pattern of using a "cold" function to perform elaborate error reporting?

@alexcrichton
Copy link
Member

I would not like to propagate the #[inline(never)] + #[cold] pattern except where absolutely necessary as it is in general indicative of a more subtle underlying problem than a fix that should only happen locally.

This specific issue has been addressed, however, so I'm going to close this. More targeted follow up issues can be opened and addressed separately.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
I-slow Issue: Problems and improvements with respect to performance of generated code.
Projects
None yet
Development

No branches or pull requests

5 participants