[libc] This adds the strcmp (string compare) implementation.
Reviewed-by: sivachandra
Differential Revision: https://reviews.llvm.org/D82134
GitOrigin-RevId: 05e1612c4345353680752bad23eb52eba3ab51a3
diff --git a/config/linux/x86_64/entrypoints.txt b/config/linux/x86_64/entrypoints.txt
index 656ccdd..a783663 100644
--- a/config/linux/x86_64/entrypoints.txt
+++ b/config/linux/x86_64/entrypoints.txt
@@ -26,6 +26,7 @@
libc.src.string.strcpy
libc.src.string.strcat
libc.src.string.strlen
+ libc.src.string.strcmp
# sys/mman.h entrypoints
libc.src.sys.mman.mmap
diff --git a/src/string/CMakeLists.txt b/src/string/CMakeLists.txt
index dee547b..51456e8 100644
--- a/src/string/CMakeLists.txt
+++ b/src/string/CMakeLists.txt
@@ -34,6 +34,16 @@
libc.include.string
)
+add_entrypoint_object(
+ strcmp
+ SRCS
+ strcmp.cpp
+ HDRS
+ strcmp.h
+ DEPENDS
+ libc.include.string
+)
+
# Helper to define a function with multiple implementations
# - Computes flags to satisfy required/rejected features and arch,
# - Declares an entry point,
diff --git a/src/string/strcmp.cpp b/src/string/strcmp.cpp
new file mode 100644
index 0000000..4ef7a77
--- /dev/null
+++ b/src/string/strcmp.cpp
@@ -0,0 +1,23 @@
+//===-- Implementation of strcmp ------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/string/strcmp.h"
+
+#include "src/__support/common.h"
+
+namespace __llvm_libc {
+
+// TODO: Look at benefits for comparing words at a time.
+int LLVM_LIBC_ENTRYPOINT(strcmp)(const char *left, const char *right) {
+ for (; *left && *left == *right; ++left, ++right)
+ ;
+ return *reinterpret_cast<const unsigned char *>(left) -
+ *reinterpret_cast<const unsigned char *>(right);
+}
+
+} // namespace __llvm_libc
diff --git a/src/string/strcmp.h b/src/string/strcmp.h
new file mode 100644
index 0000000..a45f2d5
--- /dev/null
+++ b/src/string/strcmp.h
@@ -0,0 +1,18 @@
+//===-- Implementation header for strcmp ------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_STRING_STRCMP_H
+#define LLVM_LIBC_SRC_STRING_STRCMP_H
+
+namespace __llvm_libc {
+
+int strcmp(const char *left, const char *right);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_STRING_STRCMP_H
diff --git a/test/src/string/CMakeLists.txt b/test/src/string/CMakeLists.txt
index abe0652..992cebe 100644
--- a/test/src/string/CMakeLists.txt
+++ b/test/src/string/CMakeLists.txt
@@ -32,6 +32,16 @@
libc.src.string.strlen
)
+add_libc_unittest(
+ strcmp_test
+ SUITE
+ libc_string_unittests
+ SRCS
+ strcmp_test.cpp
+ DEPENDS
+ libc.src.string.strcmp
+)
+
# Tests all implementations that can run on the host.
function(add_libc_multi_impl_test name)
get_property(fq_implementations GLOBAL PROPERTY ${name}_implementations)
diff --git a/test/src/string/strcmp_test.cpp b/test/src/string/strcmp_test.cpp
new file mode 100644
index 0000000..18e20a2
--- /dev/null
+++ b/test/src/string/strcmp_test.cpp
@@ -0,0 +1,97 @@
+//===-- Unittests for strcmp ----------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/string/strcmp.h"
+#include "utils/UnitTest/Test.h"
+
+TEST(StrCmpTest, EmptyStringsShouldReturnZero) {
+ const char *s1 = "";
+ const char *s2 = "";
+ int result = __llvm_libc::strcmp(s1, s2);
+ ASSERT_EQ(result, 0);
+
+ // Verify operands reversed.
+ result = __llvm_libc::strcmp(s2, s1);
+ ASSERT_EQ(result, 0);
+}
+
+TEST(StrCmpTest, EmptyStringShouldNotEqualNonEmptyString) {
+ const char *empty = "";
+ const char *s2 = "abc";
+ int result = __llvm_libc::strcmp(empty, s2);
+ // This should be '\0' - 'a' = -97
+ ASSERT_EQ(result, -97);
+
+ // Similar case if empty string is second argument.
+ const char *s3 = "123";
+ result = __llvm_libc::strcmp(s3, empty);
+ // This should be '1' - '\0' = 49
+ ASSERT_EQ(result, 49);
+}
+
+TEST(StrCmpTest, EqualStringsShouldReturnZero) {
+ const char *s1 = "abc";
+ const char *s2 = "abc";
+ int result = __llvm_libc::strcmp(s1, s2);
+ ASSERT_EQ(result, 0);
+
+ // Verify operands reversed.
+ result = __llvm_libc::strcmp(s2, s1);
+ ASSERT_EQ(result, 0);
+}
+
+TEST(StrCmpTest, ShouldReturnResultOfFirstDifference) {
+ const char *s1 = "___B42__";
+ const char *s2 = "___C55__";
+ int result = __llvm_libc::strcmp(s1, s2);
+ // This should return 'B' - 'C' = -1.
+ ASSERT_EQ(result, -1);
+
+ // Verify operands reversed.
+ result = __llvm_libc::strcmp(s2, s1);
+ // This should return 'C' - 'B' = 1.
+ ASSERT_EQ(result, 1);
+}
+
+TEST(StrCmpTest, CapitalizedLetterShouldNotBeEqual) {
+ const char *s1 = "abcd";
+ const char *s2 = "abCd";
+ int result = __llvm_libc::strcmp(s1, s2);
+ // 'c' - 'C' = 32.
+ ASSERT_EQ(result, 32);
+
+ // Verify operands reversed.
+ result = __llvm_libc::strcmp(s2, s1);
+ // 'C' - 'c' = -32.
+ ASSERT_EQ(result, -32);
+}
+
+TEST(StrCmpTest, UnequalLengthStringsShouldNotReturnZero) {
+ const char *s1 = "abc";
+ const char *s2 = "abcd";
+ int result = __llvm_libc::strcmp(s1, s2);
+ // '\0' - 'd' = -100.
+ ASSERT_EQ(result, -100);
+
+ // Verify operands reversed.
+ result = __llvm_libc::strcmp(s2, s1);
+ // 'd' - '\0' = 100.
+ ASSERT_EQ(result, 100);
+}
+
+TEST(StrCmpTest, StringArgumentSwapChangesSign) {
+ const char *a = "a";
+ const char *b = "b";
+ int result = __llvm_libc::strcmp(b, a);
+ // 'b' - 'a' = 1.
+ ASSERT_EQ(result, 1);
+
+ result = __llvm_libc::strcmp(a, b);
+ // 'a' - 'b' = -1.
+ ASSERT_EQ(result, -1);
+}