Fold comparison of __builtin_object_size expression with -1 for non-const size
authorSiddhesh Poyarekar <siddhesh@redhat.com>
Tue, 22 Dec 2020 09:51:41 +0000 (10:51 +0100)
committerserge-sans-paille <sguelton@redhat.com>
Tue, 22 Dec 2020 09:56:31 +0000 (10:56 +0100)
When __builtin_dynamic_object_size returns a non-constant expression, it cannot
be -1 since that is an invalid return value for object size. However since
passes running after the substitution don't know this, they are unable to
optimize away the comparison and hence the comparison and branch stays in there.
This change generates an appropriate call to llvm.assume to help the optimizer
folding the test.

glibc is considering adopting __builtin_dynamic_object_size for additional
protection[1] and this change will help reduce branching overhead in fortified
implementations of all of the functions that don't have the __builtin___*_chk
type builtins, e.g. __ppoll_chk.

Also remove the test limit-max-iterations.ll because it was deemed unnecessary
during review.

[1] https://sourceware.org/pipermail/libc-alpha/2020-November/120191.html

Differential Revision: https://reviews.llvm.org/D93015

llvm/lib/Analysis/MemoryBuiltins.cpp
llvm/test/Transforms/InstCombine/builtin-dynamic-object-size.ll
llvm/test/Transforms/InstCombine/limit-max-iterations.ll [deleted file]

index cbb54e8..5d82d9d 100644 (file)
@@ -566,8 +566,16 @@ Value *llvm::lowerObjectSizeCall(IntrinsicInst *ObjectSize,
       Value *UseZero =
           Builder.CreateICmpULT(SizeOffsetPair.first, SizeOffsetPair.second);
       ResultSize = Builder.CreateZExtOrTrunc(ResultSize, ResultType);
-      return Builder.CreateSelect(UseZero, ConstantInt::get(ResultType, 0),
-                                  ResultSize);
+      Value *Ret = Builder.CreateSelect(
+          UseZero, ConstantInt::get(ResultType, 0), ResultSize);
+
+      // The non-constant size expression cannot evaluate to -1.
+      if (!isa<Constant>(SizeOffsetPair.first) ||
+          !isa<Constant>(SizeOffsetPair.second))
+        Builder.CreateAssumption(
+            Builder.CreateICmpNE(Ret, ConstantInt::get(ResultType, -1)));
+
+      return Ret;
     }
   }
 
index 4093a12..91c9d3c 100644 (file)
@@ -14,7 +14,7 @@ entry:
 
 ; CHECK:      define i64 @weird_identity_but_ok(i64 %sz)
 ; CHECK-NEXT: entry:
-; CHECK-NEXT:   ret i64 %sz
+; CHECK:   ret i64 %sz
 ; CHECK-NEXT: }
 
 define i64 @phis_are_neat(i1 %which) {
@@ -101,6 +101,57 @@ for.end:                                          ; preds = %for.body, %entry
 ; CHECK:   define void @f()
 ; CHECK:     call i64 @llvm.objectsize.i64.p0i8(
 
+define void @bdos_cmpm1(i64 %alloc) {
+entry:
+  %obj = call i8* @malloc(i64 %alloc)
+  %objsize = call i64 @llvm.objectsize.i64.p0i8(i8* %obj, i1 0, i1 0, i1 1)
+  %cmp.not = icmp eq i64 %objsize, -1
+  br i1 %cmp.not, label %if.else, label %if.then
+
+if.then:
+  call void @fortified_chk(i8* %obj, i64 %objsize)
+  br label %if.end
+
+if.else:
+  call void @unfortified(i8* %obj, i64 %objsize)
+  br label %if.end
+
+if.end:                                           ; preds = %if.else, %if.then
+  ret void
+}
+
+; CHECK:  define void @bdos_cmpm1(
+; CHECK:    [[TMP:%.*]] = icmp ne i64 %alloc, -1
+; CHECK-NEXT:    call void @llvm.assume(i1 [[TMP]])
+; CHECK-NEXT:    br i1 false, label %if.else, label %if.then
+; CHECK:    call void @fortified_chk(i8* %obj, i64 %alloc)
+
+define void @bdos_cmpm1_expr(i64 %alloc, i64 %part) {
+entry:
+  %sz = udiv i64 %alloc, %part
+  %obj = call i8* @malloc(i64 %sz)
+  %objsize = call i64 @llvm.objectsize.i64.p0i8(i8* %obj, i1 0, i1 0, i1 1)
+  %cmp.not = icmp eq i64 %objsize, -1
+  br i1 %cmp.not, label %if.else, label %if.then
+
+if.then:
+  call void @fortified_chk(i8* %obj, i64 %objsize)
+  br label %if.end
+
+if.else:
+  call void @unfortified(i8* %obj, i64 %objsize)
+  br label %if.end
+
+if.end:                                           ; preds = %if.else, %if.then
+  ret void
+}
+
+; CHECK:  define void @bdos_cmpm1_expr(
+; CHECK:    [[TMP:%.*]] = icmp ne i64 [[SZ:%.*]], -1
+; CHECK-NEXT:    call void @llvm.assume(i1 [[TMP]])
+; CHECK-NEXT:    br i1 false, label %if.else, label %if.then
+; CHECK:    call void @fortified_chk(i8* %obj, i64 [[SZ]])
+
 declare void @bury(i32) local_unnamed_addr #2
 
 ; Function Attrs: nounwind allocsize(0)
@@ -113,3 +164,7 @@ declare void @free(i8* nocapture)
 
 ; Function Attrs: nounwind readnone speculatable
 declare i64 @llvm.objectsize.i64.p0i8(i8*, i1, i1, i1)
+
+declare void @fortified_chk(i8*, i64)
+
+declare void @unfortified(i8*, i64)
diff --git a/llvm/test/Transforms/InstCombine/limit-max-iterations.ll b/llvm/test/Transforms/InstCombine/limit-max-iterations.ll
deleted file mode 100644 (file)
index a29166c..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt < %s -instcombine --instcombine-max-iterations=0 -S | FileCheck %s --check-prefix=ZERO
-; RUN: opt < %s -instcombine --instcombine-max-iterations=1 -S | FileCheck %s --check-prefix=ONE
-; RUN: opt < %s -instcombine -S | FileCheck %s --check-prefix=FIXPOINT
-; RUN: not --crash opt < %s -instcombine -S --instcombine-infinite-loop-threshold=2 2>&1 | FileCheck %s --check-prefix=LOOP
-
-; Based on builtin-dynamic-object-size.ll. This requires multiple iterations of
-; InstCombine to reach a fixpoint.
-
-define i64 @weird_identity_but_ok(i64 %sz) {
-; ZERO-LABEL: @weird_identity_but_ok(
-; ZERO-NEXT:  entry:
-; ZERO-NEXT:    [[CALL:%.*]] = tail call i8* @malloc(i64 [[SZ:%.*]])
-; ZERO-NEXT:    [[CALC_SIZE:%.*]] = tail call i64 @llvm.objectsize.i64.p0i8(i8* [[CALL]], i1 false, i1 true, i1 true)
-; ZERO-NEXT:    tail call void @free(i8* [[CALL]])
-; ZERO-NEXT:    ret i64 [[CALC_SIZE]]
-;
-; ONE-LABEL: @weird_identity_but_ok(
-; ONE-NEXT:  entry:
-; ONE-NEXT:    [[TMP0:%.*]] = sub i64 [[SZ:%.*]], 0
-; ONE-NEXT:    [[TMP1:%.*]] = icmp ult i64 [[SZ]], 0
-; ONE-NEXT:    [[TMP2:%.*]] = select i1 [[TMP1]], i64 0, i64 [[TMP0]]
-; ONE-NEXT:    ret i64 [[TMP2]]
-;
-; FIXPOINT-LABEL: @weird_identity_but_ok(
-; FIXPOINT-NEXT:  entry:
-; FIXPOINT-NEXT:    ret i64 [[SZ:%.*]]
-;
-; LOOP: LLVM ERROR: Instruction Combining seems stuck in an infinite loop after 2 iterations.
-entry:
-  %call = tail call i8* @malloc(i64 %sz)
-  %calc_size = tail call i64 @llvm.objectsize.i64.p0i8(i8* %call, i1 false, i1 true, i1 true)
-  tail call void @free(i8* %call)
-  ret i64 %calc_size
-}
-
-declare i64 @llvm.objectsize.i64.p0i8(i8*, i1, i1, i1)
-declare i8* @malloc(i64)
-declare void @free(i8*)