[libcxx-commits] [PATCH] D59999: Make it easier for the compiler to optimize `operator==(string, char*)`.

Samuel Benzaquen via Phabricator via libcxx-commits libcxx-commits at lists.llvm.org
Fri Mar 29 13:53:13 PDT 2019


sbenza added a comment.

Maybe the generated code would be better if `basic_string::compare` was being inlined, but the compiler chose not to do it. `char_traits::compare`, on the other hand is much smaller and easier to inline.

IR examples before and after this change: https://gcc.godbolt.org/z/0N90W2

For something like str=="".
Before:

  define dso_local zeroext i1 @_Z5EmptyRKNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE(%"class.std::__1::basic_string"* dereferenceable(24)) local_unnamed_addr #0 personality i32 (...)* @__gxx_personality_v0 !dbg !918 {
    call void @llvm.dbg.value(metadata %"class.std::__1::basic_string"* %0, metadata !927, metadata !DIExpression()), !dbg !928
    call void @llvm.dbg.value(metadata %"class.std::__1::basic_string"* %0, metadata !929, metadata !DIExpression()) #4, !dbg !1031
    call void @llvm.dbg.value(metadata i8* getelementptr inbounds ([1 x i8], [1 x i8]* @.str, i64 0, i64 0), metadata !936, metadata !DIExpression()) #4, !dbg !1033
    call void @llvm.dbg.value(metadata i64 0, metadata !937, metadata !DIExpression()) #4, !dbg !1034
    call void @llvm.dbg.value(metadata %"class.std::__1::basic_string"* %0, metadata !1035, metadata !DIExpression()) #4, !dbg !1152
    call void @llvm.dbg.value(metadata %"class.std::__1::basic_string"* %0, metadata !1155, metadata !DIExpression()) #4, !dbg !1161
    %2 = bitcast %"class.std::__1::basic_string"* %0 to i8*, !dbg !1163
    %3 = load i8, i8* %2, align 8, !dbg !1163, !tbaa !1164
    %4 = and i8 %3, 1, !dbg !1167
    %5 = icmp eq i8 %4, 0, !dbg !1168
    %6 = getelementptr inbounds %"class.std::__1::basic_string", %"class.std::__1::basic_string"* %0, i64 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 1, !dbg !1169
    %7 = load i64, i64* %6, align 8, !dbg !1169
    %8 = lshr i8 %3, 1, !dbg !1169
    %9 = zext i8 %8 to i64, !dbg !1169
    %10 = select i1 %5, i64 %9, i64 %7, !dbg !1169
    %11 = icmp eq i64 %10, 0, !dbg !1170
    br i1 %11, label %12, label %19, !dbg !1171
  
  12:                                               ; preds = %1
    %13 = invoke i32 @_ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE7compareEmmPKcm(%"class.std::__1::basic_string"* nonnull %0, i64 0, i64 -1, i8* getelementptr inbounds ([1 x i8], [1 x i8]* @.str, i64 0, i64 0), i64 0)
            to label %14 unwind label %16, !dbg !1172
  
  14:                                               ; preds = %12
    %15 = icmp eq i32 %13, 0, !dbg !1173
    br label %19, !dbg !1174
  
  16:                                               ; preds = %12
    %17 = landingpad { i8*, i32 }
            catch i8* null, !dbg !1175
    %18 = extractvalue { i8*, i32 } %17, 0, !dbg !1175
    tail call void @__clang_call_terminate(i8* %18) #5, !dbg !1175
    unreachable, !dbg !1175
  
  19:                                               ; preds = %1, %14
    %20 = phi i1 [ %15, %14 ], [ false, %1 ], !dbg !1176
    ret i1 %20, !dbg !1177
  }

After:

  define dso_local zeroext i1 @_Z5EmptyRKNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE(%"class.std::__1::basic_string"* nocapture readonly dereferenceable(24)) local_unnamed_addr #0 !dbg !918 {
    call void @llvm.dbg.value(metadata %"class.std::__1::basic_string"* %0, metadata !927, metadata !DIExpression()), !dbg !928
    call void @llvm.dbg.value(metadata %"class.std::__1::basic_string"* %0, metadata !929, metadata !DIExpression()) #3, !dbg !1031
    call void @llvm.dbg.value(metadata i64 0, metadata !937, metadata !DIExpression()) #3, !dbg !1033
    call void @llvm.dbg.value(metadata %"class.std::__1::basic_string"* %0, metadata !1034, metadata !DIExpression()) #3, !dbg !1151
    call void @llvm.dbg.value(metadata %"class.std::__1::basic_string"* %0, metadata !1154, metadata !DIExpression()) #3, !dbg !1160
    %2 = bitcast %"class.std::__1::basic_string"* %0 to i8*, !dbg !1162
    %3 = load i8, i8* %2, align 8, !dbg !1162, !tbaa !1163
    %4 = and i8 %3, 1, !dbg !1166
    %5 = icmp eq i8 %4, 0, !dbg !1167
    %6 = getelementptr inbounds %"class.std::__1::basic_string", %"class.std::__1::basic_string"* %0, i64 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 1, !dbg !1168
    %7 = load i64, i64* %6, align 8, !dbg !1168
    %8 = lshr i8 %3, 1, !dbg !1168
    %9 = zext i8 %8 to i64, !dbg !1168
    %10 = select i1 %5, i64 %9, i64 %7, !dbg !1168
    %11 = icmp eq i64 %10, 0, !dbg !1169
    ret i1 %11, !dbg !1170
  }

Other simple comparisons like str=="ABCDEFG" get better too. (see link above).

I'm adding a few more benchmarks in https://reviews.llvm.org/D59781 that show the improvement.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D59999/new/

https://reviews.llvm.org/D59999





More information about the libcxx-commits mailing list