| //===-- Automemcpy CodeGen Test -------------------------------------------===// |
| // |
| // 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 "automemcpy/CodeGen.h" |
| #include "automemcpy/RandomFunctionGenerator.h" |
| #include "gmock/gmock.h" |
| #include "gtest/gtest.h" |
| #include <optional> |
| |
| using testing::AllOf; |
| using testing::AnyOf; |
| using testing::ElementsAre; |
| using testing::Ge; |
| using testing::Gt; |
| using testing::Le; |
| using testing::Lt; |
| |
| namespace llvm { |
| namespace automemcpy { |
| namespace { |
| |
| TEST(Automemcpy, Codegen) { |
| static constexpr FunctionDescriptor kDescriptors[] = { |
| {FunctionType::MEMCPY, std::nullopt, std::nullopt, std::nullopt, std::nullopt, |
| Accelerator{{0, kMaxSize}}, ElementTypeClass::NATIVE}, |
| {FunctionType::MEMCPY, Contiguous{{0, 4}}, Overlap{{4, 256}}, |
| Loop{{256, kMaxSize}, 64}, std::nullopt, std::nullopt, |
| ElementTypeClass::NATIVE}, |
| {FunctionType::MEMCMP, Contiguous{{0, 2}}, Overlap{{2, 64}}, std::nullopt, |
| AlignedLoop{Loop{{64, kMaxSize}, 16}, 16, AlignArg::_1}, std::nullopt, |
| ElementTypeClass::NATIVE}, |
| {FunctionType::MEMSET, Contiguous{{0, 2}}, Overlap{{2, 256}}, std::nullopt, |
| AlignedLoop{Loop{{256, kMaxSize}, 32}, 16, AlignArg::_1}, std::nullopt, |
| ElementTypeClass::NATIVE}, |
| {FunctionType::MEMSET, Contiguous{{0, 2}}, Overlap{{2, 256}}, std::nullopt, |
| AlignedLoop{Loop{{256, kMaxSize}, 32}, 32, AlignArg::_1}, std::nullopt, |
| ElementTypeClass::NATIVE}, |
| {FunctionType::BZERO, Contiguous{{0, 4}}, Overlap{{4, 128}}, std::nullopt, |
| AlignedLoop{Loop{{128, kMaxSize}, 32}, 32, AlignArg::_1}, std::nullopt, |
| ElementTypeClass::NATIVE}, |
| }; |
| |
| std::string Output; |
| raw_string_ostream OutputStream(Output); |
| Serialize(OutputStream, kDescriptors); |
| |
| EXPECT_STREQ(OutputStream.str().c_str(), |
| R"(// This file is auto-generated by libc/benchmarks/automemcpy. |
| // Functions : 6 |
| |
| #include "LibcFunctionPrototypes.h" |
| #include "automemcpy/FunctionDescriptor.h" |
| #include "src/string/memory_utils/elements.h" |
| |
| using llvm::libc_benchmarks::BzeroConfiguration; |
| using llvm::libc_benchmarks::MemcmpOrBcmpConfiguration; |
| using llvm::libc_benchmarks::MemcpyConfiguration; |
| using llvm::libc_benchmarks::MemmoveConfiguration; |
| using llvm::libc_benchmarks::MemsetConfiguration; |
| |
| namespace LIBC_NAMESPACE { |
| |
| static void memcpy_0xE00E29EE73994E2B(char *__restrict dst, const char *__restrict src, size_t size) { |
| using namespace LIBC_NAMESPACE::x86; |
| return copy<Accelerator>(dst, src, size); |
| } |
| static void memcpy_0x7381B60C7BE75EF9(char *__restrict dst, const char *__restrict src, size_t size) { |
| using namespace LIBC_NAMESPACE::x86; |
| if(size == 0) return; |
| if(size == 1) return copy<_1>(dst, src); |
| if(size == 2) return copy<_2>(dst, src); |
| if(size == 3) return copy<_3>(dst, src); |
| if(size < 8) return copy<HeadTail<_4>>(dst, src, size); |
| if(size < 16) return copy<HeadTail<_8>>(dst, src, size); |
| if(size < 32) return copy<HeadTail<_16>>(dst, src, size); |
| if(size < 64) return copy<HeadTail<_32>>(dst, src, size); |
| if(size < 128) return copy<HeadTail<_64>>(dst, src, size); |
| if(size < 256) return copy<HeadTail<_128>>(dst, src, size); |
| return copy<Loop<_64>>(dst, src, size); |
| } |
| static int memcmp_0x348D7BA6DB0EE033(const char * lhs, const char * rhs, size_t size) { |
| using namespace LIBC_NAMESPACE::x86; |
| if(size == 0) return 0; |
| if(size == 1) return three_way_compare<_1>(lhs, rhs); |
| if(size < 4) return three_way_compare<HeadTail<_2>>(lhs, rhs, size); |
| if(size < 8) return three_way_compare<HeadTail<_4>>(lhs, rhs, size); |
| if(size < 16) return three_way_compare<HeadTail<_8>>(lhs, rhs, size); |
| if(size < 32) return three_way_compare<HeadTail<_16>>(lhs, rhs, size); |
| if(size < 64) return three_way_compare<HeadTail<_32>>(lhs, rhs, size); |
| return three_way_compare<Align<_16,Arg::Lhs>::Then<Loop<_16>>>(lhs, rhs, size); |
| } |
| static void memset_0x71E761699B999863(char * dst, int value, size_t size) { |
| using namespace LIBC_NAMESPACE::x86; |
| if(size == 0) return; |
| if(size == 1) return splat_set<_1>(dst, value); |
| if(size < 4) return splat_set<HeadTail<_2>>(dst, value, size); |
| if(size < 8) return splat_set<HeadTail<_4>>(dst, value, size); |
| if(size < 16) return splat_set<HeadTail<_8>>(dst, value, size); |
| if(size < 32) return splat_set<HeadTail<_16>>(dst, value, size); |
| if(size < 64) return splat_set<HeadTail<_32>>(dst, value, size); |
| if(size < 128) return splat_set<HeadTail<_64>>(dst, value, size); |
| if(size < 256) return splat_set<HeadTail<_128>>(dst, value, size); |
| return splat_set<Align<_16,Arg::Dst>::Then<Loop<_32>>>(dst, value, size); |
| } |
| static void memset_0x3DF0F44E2ED6A50F(char * dst, int value, size_t size) { |
| using namespace LIBC_NAMESPACE::x86; |
| if(size == 0) return; |
| if(size == 1) return splat_set<_1>(dst, value); |
| if(size < 4) return splat_set<HeadTail<_2>>(dst, value, size); |
| if(size < 8) return splat_set<HeadTail<_4>>(dst, value, size); |
| if(size < 16) return splat_set<HeadTail<_8>>(dst, value, size); |
| if(size < 32) return splat_set<HeadTail<_16>>(dst, value, size); |
| if(size < 64) return splat_set<HeadTail<_32>>(dst, value, size); |
| if(size < 128) return splat_set<HeadTail<_64>>(dst, value, size); |
| if(size < 256) return splat_set<HeadTail<_128>>(dst, value, size); |
| return splat_set<Align<_32,Arg::Dst>::Then<Loop<_32>>>(dst, value, size); |
| } |
| static void bzero_0x475977492C218AD4(char * dst, size_t size) { |
| using namespace LIBC_NAMESPACE::x86; |
| if(size == 0) return; |
| if(size == 1) return splat_set<_1>(dst, 0); |
| if(size == 2) return splat_set<_2>(dst, 0); |
| if(size == 3) return splat_set<_3>(dst, 0); |
| if(size < 8) return splat_set<HeadTail<_4>>(dst, 0, size); |
| if(size < 16) return splat_set<HeadTail<_8>>(dst, 0, size); |
| if(size < 32) return splat_set<HeadTail<_16>>(dst, 0, size); |
| if(size < 64) return splat_set<HeadTail<_32>>(dst, 0, size); |
| if(size < 128) return splat_set<HeadTail<_64>>(dst, 0, size); |
| return splat_set<Align<_32,Arg::Dst>::Then<Loop<_32>>>(dst, 0, size); |
| } |
| |
| } // namespace LIBC_NAMESPACE |
| |
| namespace llvm { |
| namespace automemcpy { |
| |
| ArrayRef<NamedFunctionDescriptor> getFunctionDescriptors() { |
| static constexpr NamedFunctionDescriptor kDescriptors[] = { |
| {"memcpy_0xE00E29EE73994E2B",{FunctionType::MEMCPY,std::nullopt,std::nullopt,std::nullopt,std::nullopt,Accelerator{{0,kMaxSize}},ElementTypeClass::NATIVE}}, |
| {"memcpy_0x7381B60C7BE75EF9",{FunctionType::MEMCPY,Contiguous{{0,4}},Overlap{{4,256}},Loop{{256,kMaxSize},64},std::nullopt,std::nullopt,ElementTypeClass::NATIVE}}, |
| {"memcmp_0x348D7BA6DB0EE033",{FunctionType::MEMCMP,Contiguous{{0,2}},Overlap{{2,64}},std::nullopt,AlignedLoop{Loop{{64,kMaxSize},16},16,AlignArg::_1},std::nullopt,ElementTypeClass::NATIVE}}, |
| {"memset_0x71E761699B999863",{FunctionType::MEMSET,Contiguous{{0,2}},Overlap{{2,256}},std::nullopt,AlignedLoop{Loop{{256,kMaxSize},32},16,AlignArg::_1},std::nullopt,ElementTypeClass::NATIVE}}, |
| {"memset_0x3DF0F44E2ED6A50F",{FunctionType::MEMSET,Contiguous{{0,2}},Overlap{{2,256}},std::nullopt,AlignedLoop{Loop{{256,kMaxSize},32},32,AlignArg::_1},std::nullopt,ElementTypeClass::NATIVE}}, |
| {"bzero_0x475977492C218AD4",{FunctionType::BZERO,Contiguous{{0,4}},Overlap{{4,128}},std::nullopt,AlignedLoop{Loop{{128,kMaxSize},32},32,AlignArg::_1},std::nullopt,ElementTypeClass::NATIVE}}, |
| }; |
| return ArrayRef(kDescriptors); |
| } |
| |
| } // namespace automemcpy |
| } // namespace llvm |
| |
| |
| using MemcpyStub = void (*)(char *__restrict, const char *__restrict, size_t); |
| template <MemcpyStub Foo> |
| void *Wrap(void *__restrict dst, const void *__restrict src, size_t size) { |
| Foo(reinterpret_cast<char *__restrict>(dst), |
| reinterpret_cast<const char *__restrict>(src), size); |
| return dst; |
| } |
| llvm::ArrayRef<MemcpyConfiguration> getMemcpyConfigurations() { |
| using namespace LIBC_NAMESPACE; |
| static constexpr MemcpyConfiguration kConfigurations[] = { |
| {Wrap<memcpy_0xE00E29EE73994E2B>, "memcpy_0xE00E29EE73994E2B"}, |
| {Wrap<memcpy_0x7381B60C7BE75EF9>, "memcpy_0x7381B60C7BE75EF9"}, |
| }; |
| return llvm::ArrayRef(kConfigurations); |
| } |
| |
| using MemcmpStub = int (*)(const char *, const char *, size_t); |
| template <MemcmpStub Foo> |
| int Wrap(const void *lhs, const void *rhs, size_t size) { |
| return Foo(reinterpret_cast<const char *>(lhs), |
| reinterpret_cast<const char *>(rhs), size); |
| } |
| llvm::ArrayRef<MemcmpOrBcmpConfiguration> getMemcmpConfigurations() { |
| using namespace LIBC_NAMESPACE; |
| static constexpr MemcmpOrBcmpConfiguration kConfigurations[] = { |
| {Wrap<memcmp_0x348D7BA6DB0EE033>, "memcmp_0x348D7BA6DB0EE033"}, |
| }; |
| return llvm::ArrayRef(kConfigurations); |
| } |
| llvm::ArrayRef<MemcmpOrBcmpConfiguration> getBcmpConfigurations() { |
| return {}; |
| } |
| |
| using MemsetStub = void (*)(char *, int, size_t); |
| template <MemsetStub Foo> void *Wrap(void *dst, int value, size_t size) { |
| Foo(reinterpret_cast<char *>(dst), value, size); |
| return dst; |
| } |
| llvm::ArrayRef<MemsetConfiguration> getMemsetConfigurations() { |
| using namespace LIBC_NAMESPACE; |
| static constexpr MemsetConfiguration kConfigurations[] = { |
| {Wrap<memset_0x71E761699B999863>, "memset_0x71E761699B999863"}, |
| {Wrap<memset_0x3DF0F44E2ED6A50F>, "memset_0x3DF0F44E2ED6A50F"}, |
| }; |
| return llvm::ArrayRef(kConfigurations); |
| } |
| |
| using BzeroStub = void (*)(char *, size_t); |
| template <BzeroStub Foo> void Wrap(void *dst, size_t size) { |
| Foo(reinterpret_cast<char *>(dst), size); |
| } |
| llvm::ArrayRef<BzeroConfiguration> getBzeroConfigurations() { |
| using namespace LIBC_NAMESPACE; |
| static constexpr BzeroConfiguration kConfigurations[] = { |
| {Wrap<bzero_0x475977492C218AD4>, "bzero_0x475977492C218AD4"}, |
| }; |
| return llvm::ArrayRef(kConfigurations); |
| } |
| |
| llvm::ArrayRef<MemmoveConfiguration> getMemmoveConfigurations() { |
| return {}; |
| } |
| // Functions : 6 |
| )"); |
| } |
| } // namespace |
| } // namespace automemcpy |
| } // namespace llvm |