[llvm] [llvm][SimplifyLibCalls] Add option 'AllowMemcmpToBcmpTransform' (PR #82304)

Youngsuk Kim via llvm-commits llvm-commits at lists.llvm.org
Mon Feb 19 19:59:46 PST 2024


https://github.com/JOE1994 created https://github.com/llvm/llvm-project/pull/82304

Add command line option `AllowMemcmpToBcmpTransform` that controls whether the optimizer is allowed to make the following transform:

    memcmp(x, y, Len) == 0 -> bcmp(x, y, Len) == 0

The `bcmp` function was removed in the POSIX.1-2008 standard. The optimizer's default behavior of replacing a call to `memcmp` with `bcmp` without user's acknowledgement can cause inconvenience to users as in #40380 .

Other than 'llvm libc', major libc implementations (glibc, musl, newlib, uClibc, etc.) either alias `bcmp` to `memcmp`, define `bcmp` as a tail call to `memcmp`, or don't define `bcmp` by default. Therefore, the above transformation won't bring benefits to majority of users.

With the new option `AllowMemcmpToBcmpTransforms`, the optimizer will attempt the above transformation only when the user explicitly enables the option.

Closes #73218

>From 44512dbc222323e0a786c6fada0df1982a9e8b6d Mon Sep 17 00:00:00 2001
From: Youngsuk Kim <youngsuk.kim at hpe.com>
Date: Mon, 19 Feb 2024 20:26:45 -0600
Subject: [PATCH] [llvm][SimplifyLibCalls] Add option
 'AllowMemcmpToBcmpTransform'

Add command line option `AllowMemcmpToBcmpTransform` that controls whether
the optimizer is allowed to make the following transform:

    memcmp(x, y, Len) == 0 -> bcmp(x, y, Len) == 0

The `bcmp` function was removed in the POSIX.1-2008 standard. The optimizer's
default behavior of replacing a call to `memcmp` with `bcmp` without user's
acknowledgement can cause inconvenience to users as in #40380 .

Other than 'llvm libc', major libc implementations (glibc, musl, newlib,
uClibc, etc.) either alias `bcmp` to `memcmp`, define `bcmp` as a tail call to
`memcmp`, or don't define `bcmp` by default. Therefore, the above
transformation won't bring benefits to majority of users.

With the new option `AllowMemcmpToBcmpTransforms`, the optimizer will attempt
the above transformation only when the user explicitly enables the option.

Closes #73218
---
 llvm/docs/ReleaseNotes.rst                               | 4 ++++
 llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp           | 9 ++++++++-
 llvm/test/Transforms/InstCombine/memcmp-1.ll             | 2 +-
 .../Transforms/InstCombine/simplify-libcalls-inreg.ll    | 4 ++--
 llvm/test/Transforms/InstCombine/strcmp-1.ll             | 2 +-
 5 files changed, 16 insertions(+), 5 deletions(-)

diff --git a/llvm/docs/ReleaseNotes.rst b/llvm/docs/ReleaseNotes.rst
index 5be00d9d5a5899..cba9475b829180 100644
--- a/llvm/docs/ReleaseNotes.rst
+++ b/llvm/docs/ReleaseNotes.rst
@@ -152,6 +152,10 @@ Changes to Sanitizers
 Other Changes
 -------------
 
+* The optimizer will no longer try to transform `memcmp(x, y, Len) == 0` to
+  `bcmp(x, y, Len) == 0` unless the command line option
+  `allow-memcmp-to-bcmp-transform` is enabled (off by default).
+
 External Open Source Projects Using LLVM 19
 ===========================================
 
diff --git a/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp b/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp
index 26a34aa99e1b87..66d2f53c16d8ce 100644
--- a/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp
+++ b/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp
@@ -85,6 +85,13 @@ static cl::opt<unsigned, false, HotColdHintParser> HotNewHintValue(
     "hot-new-hint-value", cl::Hidden, cl::init(254),
     cl::desc("Value to pass to hot/cold operator new for hot allocation"));
 
+// Allow transforming `memcmp(x, y, Len) == 0` to `bcmp(x, y, Len) == 0`.
+// Note: `bcmp` was removed from the POSIX.1-2008 standard.
+static cl::opt<bool> AllowMemcmpToBcmpTransform(
+    "allow-memcmp-to-bcmp-transform", cl::Hidden, cl::init(false),
+    cl::desc(
+        "Allow transforming memcmp calls to bcmp calls if deemed beneficial"));
+
 //===----------------------------------------------------------------------===//
 // Helper Functions
 //===----------------------------------------------------------------------===//
@@ -1596,7 +1603,7 @@ Value *LibCallSimplifier::optimizeMemCmp(CallInst *CI, IRBuilderBase &B) {
   // memcmp(x, y, Len) == 0 -> bcmp(x, y, Len) == 0
   // bcmp can be more efficient than memcmp because it only has to know that
   // there is a difference, not how different one is to the other.
-  if (isLibFuncEmittable(M, TLI, LibFunc_bcmp) &&
+  if (AllowMemcmpToBcmpTransform && isLibFuncEmittable(M, TLI, LibFunc_bcmp) &&
       isOnlyUsedInZeroEqualityComparison(CI)) {
     Value *LHS = CI->getArgOperand(0);
     Value *RHS = CI->getArgOperand(1);
diff --git a/llvm/test/Transforms/InstCombine/memcmp-1.ll b/llvm/test/Transforms/InstCombine/memcmp-1.ll
index 054896647b5188..3eb74725c537cc 100644
--- a/llvm/test/Transforms/InstCombine/memcmp-1.ll
+++ b/llvm/test/Transforms/InstCombine/memcmp-1.ll
@@ -1,7 +1,7 @@
 ; Test that the memcmp library call simplifier works correctly.
 ;
 ; RUN: opt < %s -passes=instcombine -S | FileCheck --check-prefix=CHECK --check-prefix=NOBCMP %s
-; RUN: opt < %s -passes=instcombine -mtriple=x86_64-unknown-linux-gnu -S | FileCheck --check-prefix=CHECK --check-prefix=BCMP %s
+; RUN: opt < %s -passes=instcombine -mtriple=x86_64-unknown-linux-gnu -S -allow-memcmp-to-bcmp-transform | FileCheck --check-prefix=CHECK --check-prefix=BCMP %s
 
 target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128-n8:16:32:64"
 
diff --git a/llvm/test/Transforms/InstCombine/simplify-libcalls-inreg.ll b/llvm/test/Transforms/InstCombine/simplify-libcalls-inreg.ll
index 8bbd972ef6e0fa..320cb9eac8dc0e 100644
--- a/llvm/test/Transforms/InstCombine/simplify-libcalls-inreg.ll
+++ b/llvm/test/Transforms/InstCombine/simplify-libcalls-inreg.ll
@@ -15,8 +15,8 @@ declare i32 @__sprintf_chk(ptr, i32, i32, ptr, ...)
 @b = common global [60 x i8] zeroinitializer, align 1
 @h = constant [2 x i8] c"h\00"
 
-; CHECK:     declare i32 @bcmp(ptr inreg nocapture, ptr inreg nocapture, i32 inreg)
-; CHECK-NOT: declare i32 @bcmp(ptr nocapture, ptr nocapture, i32)
+; CHECK:     declare i32 @memcmp(ptr inreg nocapture noundef, ptr inreg nocapture noundef, i32 inreg noundef)
+; CHECK-NOT: declare i32 @memcmp(ptr nocapture noundef, ptr nocapture noundef, i32)
 
 define i32 @baz(ptr inreg noundef %s2, i32 inreg noundef %n){
   %call = call ptr @foo()
diff --git a/llvm/test/Transforms/InstCombine/strcmp-1.ll b/llvm/test/Transforms/InstCombine/strcmp-1.ll
index 0dff891171fe1e..4acfbaf4a48af8 100644
--- a/llvm/test/Transforms/InstCombine/strcmp-1.ll
+++ b/llvm/test/Transforms/InstCombine/strcmp-1.ll
@@ -1,7 +1,7 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
 ; Test that the strcmp library call simplifier works correctly.
 ; RUN: opt < %s -passes=instcombine -S | FileCheck %s --check-prefix=NOBCMP
-; RUN: opt < %s -passes=instcombine -mtriple=unknown-unknown-linux-gnu -S | FileCheck %s --check-prefix=BCMP
+; RUN: opt < %s -passes=instcombine -mtriple=unknown-unknown-linux-gnu -S -allow-memcmp-to-bcmp-transform | FileCheck %s --check-prefix=BCMP
 
 target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128"
 



More information about the llvm-commits mailing list