[libc] Add [l|ll]abs implementation.

Implement abs, labs and llabs with template.

Reviewed By: sivachandra

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

GitOrigin-RevId: 1fd32dcb294e16781fcfcf1a468180d00cf1e3ca
diff --git a/config/linux/aarch64/entrypoints.txt b/config/linux/aarch64/entrypoints.txt
index 3a3b050..534a4bd 100644
--- a/config/linux/aarch64/entrypoints.txt
+++ b/config/linux/aarch64/entrypoints.txt
@@ -18,6 +18,11 @@
     # errno.h entrypoints
     libc.src.errno.__errno_location
 
+    # stdlib.h entrypoints
+    libc.src.stdlib.abs
+    libc.src.stdlib.labs
+    libc.src.stdlib.llabs
+
     # string.h entrypoints
     libc.src.string.bzero
     libc.src.string.memchr
diff --git a/config/linux/x86_64/entrypoints.txt b/config/linux/x86_64/entrypoints.txt
index 2b461c4..4cae553 100644
--- a/config/linux/x86_64/entrypoints.txt
+++ b/config/linux/x86_64/entrypoints.txt
@@ -41,6 +41,9 @@
     # stdlib.h entrypoints
     libc.src.stdlib._Exit
     libc.src.stdlib.abort
+    libc.src.stdlib.abs
+    libc.src.stdlib.labs
+    libc.src.stdlib.llabs
 
     # string.h entrypoints
     libc.src.string.bzero
diff --git a/spec/spec.td b/spec/spec.td
index 29c11a9..9a31d85 100644
--- a/spec/spec.td
+++ b/spec/spec.td
@@ -42,6 +42,8 @@
 def FloatType : NamedType<"float">;
 def DoubleType : NamedType<"double">;
 def LongDoubleType : NamedType<"long double">;
+def LongLongType : NamedType<"long long">;
+def LongType : NamedType<"long">;
 def CharType : NamedType<"char">;
 
 // Common types
diff --git a/spec/stdc.td b/spec/stdc.td
index 70cc260..051e0a8 100644
--- a/spec/stdc.td
+++ b/spec/stdc.td
@@ -400,6 +400,9 @@
       [], // Enumerations
       [
           FunctionSpec<"abort", RetValSpec<NoReturn>, [ArgSpec<VoidType>]>,
+          FunctionSpec<"abs", RetValSpec<IntType>, [ArgSpec<IntType>]>,
+          FunctionSpec<"labs", RetValSpec<LongType>, [ArgSpec<LongType>]>,
+          FunctionSpec<"llabs", RetValSpec<LongLongType>, [ArgSpec<LongLongType>]>,
           FunctionSpec<"_Exit", RetValSpec<NoReturn>, [ArgSpec<IntType>]>,
       ]
   >;
diff --git a/src/stdlib/CMakeLists.txt b/src/stdlib/CMakeLists.txt
index 50b7421..a599d8a 100644
--- a/src/stdlib/CMakeLists.txt
+++ b/src/stdlib/CMakeLists.txt
@@ -2,6 +2,12 @@
   add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS})
 endif()
 
+add_header_library(
+  abs_utils
+  HDRS
+    abs_utils.h
+)
+
 add_entrypoint_object(
   _Exit
   ALIAS
@@ -20,3 +26,33 @@
     libc.src.signal.raise
     ._Exit
 )
+
+add_entrypoint_object(
+  abs
+  SRCS
+    abs.cpp
+  HDRS
+    abs.h
+  DEPENDS
+    .abs_utils
+)
+
+add_entrypoint_object(
+  labs
+  SRCS
+    labs.cpp
+  HDRS
+    labs.h
+  DEPENDS
+    .abs_utils
+)
+
+add_entrypoint_object(
+  llabs
+  SRCS
+    llabs.cpp
+  HDRS
+    llabs.h
+  DEPENDS
+    .abs_utils
+)
diff --git a/src/stdlib/abs.cpp b/src/stdlib/abs.cpp
new file mode 100644
index 0000000..74c47cd
--- /dev/null
+++ b/src/stdlib/abs.cpp
@@ -0,0 +1,20 @@
+//===-- Implementation of abs ---------------------------------------------===//
+//
+// 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/stdlib/abs.h"
+#include "src/__support/common.h"
+#include "src/stdlib/abs_utils.h"
+
+namespace __llvm_libc {
+
+int LLVM_LIBC_ENTRYPOINT(abs)(int n) {
+  // integer_abs from abs_utils.h.
+  return integer_abs(n);
+}
+
+} // namespace __llvm_libc
diff --git a/src/stdlib/abs.h b/src/stdlib/abs.h
new file mode 100644
index 0000000..42ef7f8
--- /dev/null
+++ b/src/stdlib/abs.h
@@ -0,0 +1,18 @@
+//===-- Implementation header for abs ---------------------------*- 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_STDLIB_ABS_H
+#define LLVM_LIBC_SRC_STDLIB_ABS_H
+
+namespace __llvm_libc {
+
+int abs(int n);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_STDLIB_ABS_H
diff --git a/src/stdlib/abs_utils.h b/src/stdlib/abs_utils.h
new file mode 100644
index 0000000..c0943fe
--- /dev/null
+++ b/src/stdlib/abs_utils.h
@@ -0,0 +1,22 @@
+//===-- Utils for abs and friends -------------------------------*- 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_STDLIB_ABS_UTILS_H
+#define LLVM_LIBC_SRC_STDLIB_ABS_UTILS_H
+
+namespace __llvm_libc {
+
+template <typename T> static inline T integer_abs(T n) {
+  if (n < 0)
+    return -n;
+  return n;
+}
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_STDLIB_ABS_UTILS_H
diff --git a/src/stdlib/labs.cpp b/src/stdlib/labs.cpp
new file mode 100644
index 0000000..427cb9d
--- /dev/null
+++ b/src/stdlib/labs.cpp
@@ -0,0 +1,20 @@
+//===-- Implementation of labs --------------------------------------------===//
+//
+// 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/stdlib/labs.h"
+#include "src/__support/common.h"
+#include "src/stdlib/abs_utils.h"
+
+namespace __llvm_libc {
+
+long LLVM_LIBC_ENTRYPOINT(labs)(long n) {
+  // integer_abs from abs_utils.h.
+  return integer_abs(n);
+}
+
+} // namespace __llvm_libc
diff --git a/src/stdlib/labs.h b/src/stdlib/labs.h
new file mode 100644
index 0000000..0f0ea99
--- /dev/null
+++ b/src/stdlib/labs.h
@@ -0,0 +1,18 @@
+//===-- Implementation header for labs --------------------------*- 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_STDLIB_LABS_H
+#define LLVM_LIBC_SRC_STDLIB_LABS_H
+
+namespace __llvm_libc {
+
+long labs(long n);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_STDLIB_LABS_H
diff --git a/src/stdlib/llabs.cpp b/src/stdlib/llabs.cpp
new file mode 100644
index 0000000..8878ce4
--- /dev/null
+++ b/src/stdlib/llabs.cpp
@@ -0,0 +1,20 @@
+//===-- Implementation of llabs -------------------------------------------===//
+//
+// 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/stdlib/llabs.h"
+#include "src/__support/common.h"
+#include "src/stdlib/abs_utils.h"
+
+namespace __llvm_libc {
+
+long long LLVM_LIBC_ENTRYPOINT(llabs)(long long n) {
+  // integer_abs from abs_utils.h.
+  return integer_abs(n);
+}
+
+} // namespace __llvm_libc
diff --git a/src/stdlib/llabs.h b/src/stdlib/llabs.h
new file mode 100644
index 0000000..f173431
--- /dev/null
+++ b/src/stdlib/llabs.h
@@ -0,0 +1,18 @@
+//===-- Implementation header for llabs -------------------------*- 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_STDLIB_LLABS_H
+#define LLVM_LIBC_SRC_STDLIB_LLABS_H
+
+namespace __llvm_libc {
+
+long long llabs(long long n);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_STDLIB_LLABS_H
diff --git a/test/src/stdlib/CMakeLists.txt b/test/src/stdlib/CMakeLists.txt
index 06adaa2..e5cb04a 100644
--- a/test/src/stdlib/CMakeLists.txt
+++ b/test/src/stdlib/CMakeLists.txt
@@ -24,3 +24,33 @@
     libc.src.stdlib._Exit
     libc.src.signal.raise
 )
+
+add_libc_unittest(
+  abs_test
+  SUITE
+    libc_stdlib_unittests
+  SRCS
+    abs_test.cpp
+  DEPENDS
+    libc.src.stdlib.abs
+)
+
+add_libc_unittest(
+  labs_test
+  SUITE
+    libc_stdlib_unittests
+  SRCS
+    labs_test.cpp
+  DEPENDS
+    libc.src.stdlib.labs
+)
+
+add_libc_unittest(
+  llabs_test
+  SUITE
+    libc_stdlib_unittests
+  SRCS
+    llabs_test.cpp
+  DEPENDS
+    libc.src.stdlib.llabs
+)
diff --git a/test/src/stdlib/abs_test.cpp b/test/src/stdlib/abs_test.cpp
new file mode 100644
index 0000000..6f1a46e
--- /dev/null
+++ b/test/src/stdlib/abs_test.cpp
@@ -0,0 +1,16 @@
+//===-- Unittests for abs -------------------------------------------------===//
+//
+// 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/stdlib/abs.h"
+#include "utils/UnitTest/Test.h"
+
+TEST(AbsTest, Zero) { EXPECT_EQ(__llvm_libc::abs(0), 0); }
+
+TEST(AbsTest, Positive) { EXPECT_EQ(__llvm_libc::abs(1), 1); }
+
+TEST(AbsTest, Negative) { EXPECT_EQ(__llvm_libc::abs(-1), 1); }
diff --git a/test/src/stdlib/labs_test.cpp b/test/src/stdlib/labs_test.cpp
new file mode 100644
index 0000000..cd81425
--- /dev/null
+++ b/test/src/stdlib/labs_test.cpp
@@ -0,0 +1,16 @@
+//===-- Unittests for labs ------------------------------------------------===//
+//
+// 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/stdlib/labs.h"
+#include "utils/UnitTest/Test.h"
+
+TEST(LabsTest, Zero) { EXPECT_EQ(__llvm_libc::labs(0l), 0l); }
+
+TEST(LabsTest, Positive) { EXPECT_EQ(__llvm_libc::labs(1l), 1l); }
+
+TEST(LabsTest, Negative) { EXPECT_EQ(__llvm_libc::labs(-1l), 1l); }
diff --git a/test/src/stdlib/llabs_test.cpp b/test/src/stdlib/llabs_test.cpp
new file mode 100644
index 0000000..4b5fde9
--- /dev/null
+++ b/test/src/stdlib/llabs_test.cpp
@@ -0,0 +1,16 @@
+//===-- Unittests for llabs -----------------------------------------------===//
+//
+// 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/stdlib/llabs.h"
+#include "utils/UnitTest/Test.h"
+
+TEST(LlabsTest, Zero) { EXPECT_EQ(__llvm_libc::llabs(0ll), 0ll); }
+
+TEST(LlabsTest, Positive) { EXPECT_EQ(__llvm_libc::llabs(1ll), 1ll); }
+
+TEST(LlabsTest, Negative) { EXPECT_EQ(__llvm_libc::llabs(-1ll), 1ll); }