1 //===-- Automemcpy CodeGen Test -------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "automemcpy/CodeGen.h"
10 #include "automemcpy/RandomFunctionGenerator.h"
11 #include "gmock/gmock.h"
12 #include "gtest/gtest.h"
13 
14 using testing::AllOf;
15 using testing::AnyOf;
16 using testing::ElementsAre;
17 using testing::Ge;
18 using testing::Gt;
19 using testing::Le;
20 using testing::Lt;
21 
22 namespace llvm {
23 namespace automemcpy {
24 namespace {
25 
26 TEST(Automemcpy, Codegen) {
27   static constexpr FunctionDescriptor kDescriptors[] = {
28       {FunctionType::MEMCPY, llvm::None, llvm::None, llvm::None, llvm::None,
29        Accelerator{{0, kMaxSize}}, ElementTypeClass::NATIVE},
30       {FunctionType::MEMCPY, Contiguous{{0, 4}}, Overlap{{4, 256}},
31        Loop{{256, kMaxSize}, 64}, llvm::None, llvm::None,
32        ElementTypeClass::NATIVE},
33       {FunctionType::MEMCMP, Contiguous{{0, 2}}, Overlap{{2, 64}}, llvm::None,
34        AlignedLoop{Loop{{64, kMaxSize}, 16}, 16, AlignArg::_1}, llvm::None,
35        ElementTypeClass::NATIVE},
36       {FunctionType::MEMSET, Contiguous{{0, 2}}, Overlap{{2, 256}}, llvm::None,
37        AlignedLoop{Loop{{256, kMaxSize}, 32}, 16, AlignArg::_1}, llvm::None,
38        ElementTypeClass::NATIVE},
39       {FunctionType::MEMSET, Contiguous{{0, 2}}, Overlap{{2, 256}}, llvm::None,
40        AlignedLoop{Loop{{256, kMaxSize}, 32}, 32, AlignArg::_1}, llvm::None,
41        ElementTypeClass::NATIVE},
42       {FunctionType::BZERO, Contiguous{{0, 4}}, Overlap{{4, 128}}, llvm::None,
43        AlignedLoop{Loop{{128, kMaxSize}, 32}, 32, AlignArg::_1}, llvm::None,
44        ElementTypeClass::NATIVE},
45   };
46 
47   std::string Output;
48   raw_string_ostream OutputStream(Output);
49   Serialize(OutputStream, kDescriptors);
50 
51   EXPECT_STREQ(OutputStream.str().c_str(),
52                R"(// This file is auto-generated by libc/benchmarks/automemcpy.
53 // Functions : 6
54 
55 #include "LibcFunctionPrototypes.h"
56 #include "automemcpy/FunctionDescriptor.h"
57 #include "src/string/memory_utils/elements.h"
58 
59 using llvm::libc_benchmarks::BzeroConfiguration;
60 using llvm::libc_benchmarks::MemcmpOrBcmpConfiguration;
61 using llvm::libc_benchmarks::MemcpyConfiguration;
62 using llvm::libc_benchmarks::MemsetConfiguration;
63 
64 namespace __llvm_libc {
65 
66 static void memcpy_0xE00E29EE73994E2B(char *__restrict dst, const char *__restrict src, size_t size) {
67   using namespace __llvm_libc::x86;
68   return Copy<Accelerator>(dst, src, size);
69 }
70 static void memcpy_0x7381B60C7BE75EF9(char *__restrict dst, const char *__restrict src, size_t size) {
71   using namespace __llvm_libc::x86;
72   if(size == 0) return;
73   if(size == 1) return Copy<_1>(dst, src);
74   if(size == 2) return Copy<_2>(dst, src);
75   if(size == 3) return Copy<_3>(dst, src);
76   if(size < 8) return Copy<HeadTail<_4>>(dst, src, size);
77   if(size < 16) return Copy<HeadTail<_8>>(dst, src, size);
78   if(size < 32) return Copy<HeadTail<_16>>(dst, src, size);
79   if(size < 64) return Copy<HeadTail<_32>>(dst, src, size);
80   if(size < 128) return Copy<HeadTail<_64>>(dst, src, size);
81   if(size < 256) return Copy<HeadTail<_128>>(dst, src, size);
82   return Copy<Loop<_64>>(dst, src, size);
83 }
84 static int memcmp_0x348D7BA6DB0EE033(const char * lhs, const char * rhs, size_t size) {
85   using namespace __llvm_libc::x86;
86   if(size == 0) return 0;
87   if(size == 1) return ThreeWayCompare<_1>(lhs, rhs);
88   if(size < 4) return ThreeWayCompare<HeadTail<_2>>(lhs, rhs, size);
89   if(size < 8) return ThreeWayCompare<HeadTail<_4>>(lhs, rhs, size);
90   if(size < 16) return ThreeWayCompare<HeadTail<_8>>(lhs, rhs, size);
91   if(size < 32) return ThreeWayCompare<HeadTail<_16>>(lhs, rhs, size);
92   if(size < 64) return ThreeWayCompare<HeadTail<_32>>(lhs, rhs, size);
93   return ThreeWayCompare<Align<_16,Arg::Lhs>::Then<Loop<_16>>>(lhs, rhs, size);
94 }
95 static void memset_0x71E761699B999863(char * dst, int value, size_t size) {
96   using namespace __llvm_libc::x86;
97   if(size == 0) return;
98   if(size == 1) return SplatSet<_1>(dst, value);
99   if(size < 4) return SplatSet<HeadTail<_2>>(dst, value, size);
100   if(size < 8) return SplatSet<HeadTail<_4>>(dst, value, size);
101   if(size < 16) return SplatSet<HeadTail<_8>>(dst, value, size);
102   if(size < 32) return SplatSet<HeadTail<_16>>(dst, value, size);
103   if(size < 64) return SplatSet<HeadTail<_32>>(dst, value, size);
104   if(size < 128) return SplatSet<HeadTail<_64>>(dst, value, size);
105   if(size < 256) return SplatSet<HeadTail<_128>>(dst, value, size);
106   return SplatSet<Align<_16,Arg::Dst>::Then<Loop<_32>>>(dst, value, size);
107 }
108 static void memset_0x3DF0F44E2ED6A50F(char * dst, int value, size_t size) {
109   using namespace __llvm_libc::x86;
110   if(size == 0) return;
111   if(size == 1) return SplatSet<_1>(dst, value);
112   if(size < 4) return SplatSet<HeadTail<_2>>(dst, value, size);
113   if(size < 8) return SplatSet<HeadTail<_4>>(dst, value, size);
114   if(size < 16) return SplatSet<HeadTail<_8>>(dst, value, size);
115   if(size < 32) return SplatSet<HeadTail<_16>>(dst, value, size);
116   if(size < 64) return SplatSet<HeadTail<_32>>(dst, value, size);
117   if(size < 128) return SplatSet<HeadTail<_64>>(dst, value, size);
118   if(size < 256) return SplatSet<HeadTail<_128>>(dst, value, size);
119   return SplatSet<Align<_32,Arg::Dst>::Then<Loop<_32>>>(dst, value, size);
120 }
121 static void bzero_0x475977492C218AD4(char * dst, size_t size) {
122   using namespace __llvm_libc::x86;
123   if(size == 0) return;
124   if(size == 1) return SplatSet<_1>(dst, 0);
125   if(size == 2) return SplatSet<_2>(dst, 0);
126   if(size == 3) return SplatSet<_3>(dst, 0);
127   if(size < 8) return SplatSet<HeadTail<_4>>(dst, 0, size);
128   if(size < 16) return SplatSet<HeadTail<_8>>(dst, 0, size);
129   if(size < 32) return SplatSet<HeadTail<_16>>(dst, 0, size);
130   if(size < 64) return SplatSet<HeadTail<_32>>(dst, 0, size);
131   if(size < 128) return SplatSet<HeadTail<_64>>(dst, 0, size);
132   return SplatSet<Align<_32,Arg::Dst>::Then<Loop<_32>>>(dst, 0, size);
133 }
134 
135 } // namespace __llvm_libc
136 
137 namespace llvm {
138 namespace automemcpy {
139 
140 ArrayRef<NamedFunctionDescriptor> getFunctionDescriptors() {
141   static constexpr NamedFunctionDescriptor kDescriptors[] = {
142     {"memcpy_0xE00E29EE73994E2B",{FunctionType::MEMCPY,llvm::None,llvm::None,llvm::None,llvm::None,Accelerator{{0,kMaxSize}},ElementTypeClass::NATIVE}},
143     {"memcpy_0x7381B60C7BE75EF9",{FunctionType::MEMCPY,Contiguous{{0,4}},Overlap{{4,256}},Loop{{256,kMaxSize},64},llvm::None,llvm::None,ElementTypeClass::NATIVE}},
144     {"memcmp_0x348D7BA6DB0EE033",{FunctionType::MEMCMP,Contiguous{{0,2}},Overlap{{2,64}},llvm::None,AlignedLoop{Loop{{64,kMaxSize},16},16,AlignArg::_1},llvm::None,ElementTypeClass::NATIVE}},
145     {"memset_0x71E761699B999863",{FunctionType::MEMSET,Contiguous{{0,2}},Overlap{{2,256}},llvm::None,AlignedLoop{Loop{{256,kMaxSize},32},16,AlignArg::_1},llvm::None,ElementTypeClass::NATIVE}},
146     {"memset_0x3DF0F44E2ED6A50F",{FunctionType::MEMSET,Contiguous{{0,2}},Overlap{{2,256}},llvm::None,AlignedLoop{Loop{{256,kMaxSize},32},32,AlignArg::_1},llvm::None,ElementTypeClass::NATIVE}},
147     {"bzero_0x475977492C218AD4",{FunctionType::BZERO,Contiguous{{0,4}},Overlap{{4,128}},llvm::None,AlignedLoop{Loop{{128,kMaxSize},32},32,AlignArg::_1},llvm::None,ElementTypeClass::NATIVE}},
148   };
149   return makeArrayRef(kDescriptors);
150 }
151 
152 } // namespace automemcpy
153 } // namespace llvm
154 
155 
156 using MemcpyStub = void (*)(char *__restrict, const char *__restrict, size_t);
157 template <MemcpyStub Foo>
158 void *Wrap(void *__restrict dst, const void *__restrict src, size_t size) {
159   Foo(reinterpret_cast<char *__restrict>(dst),
160       reinterpret_cast<const char *__restrict>(src), size);
161   return dst;
162 }
163 llvm::ArrayRef<MemcpyConfiguration> getMemcpyConfigurations() {
164   using namespace __llvm_libc;
165   static constexpr MemcpyConfiguration kConfigurations[] = {
166     {Wrap<memcpy_0xE00E29EE73994E2B>, "memcpy_0xE00E29EE73994E2B"},
167     {Wrap<memcpy_0x7381B60C7BE75EF9>, "memcpy_0x7381B60C7BE75EF9"},
168   };
169   return llvm::makeArrayRef(kConfigurations);
170 }
171 
172 using MemcmpStub = int (*)(const char *, const char *, size_t);
173 template <MemcmpStub Foo>
174 int Wrap(const void *lhs, const void *rhs, size_t size) {
175   return Foo(reinterpret_cast<const char *>(lhs),
176              reinterpret_cast<const char *>(rhs), size);
177 }
178 llvm::ArrayRef<MemcmpOrBcmpConfiguration> getMemcmpConfigurations() {
179   using namespace __llvm_libc;
180   static constexpr MemcmpOrBcmpConfiguration kConfigurations[] = {
181     {Wrap<memcmp_0x348D7BA6DB0EE033>, "memcmp_0x348D7BA6DB0EE033"},
182   };
183   return llvm::makeArrayRef(kConfigurations);
184 }
185 llvm::ArrayRef<MemcmpOrBcmpConfiguration> getBcmpConfigurations() {
186   return {};
187 }
188 
189 using MemsetStub = void (*)(char *, int, size_t);
190 template <MemsetStub Foo> void *Wrap(void *dst, int value, size_t size) {
191   Foo(reinterpret_cast<char *>(dst), value, size);
192   return dst;
193 }
194 llvm::ArrayRef<MemsetConfiguration> getMemsetConfigurations() {
195   using namespace __llvm_libc;
196   static constexpr MemsetConfiguration kConfigurations[] = {
197     {Wrap<memset_0x71E761699B999863>, "memset_0x71E761699B999863"},
198     {Wrap<memset_0x3DF0F44E2ED6A50F>, "memset_0x3DF0F44E2ED6A50F"},
199   };
200   return llvm::makeArrayRef(kConfigurations);
201 }
202 
203 using BzeroStub = void (*)(char *, size_t);
204 template <BzeroStub Foo> void Wrap(void *dst, size_t size) {
205   Foo(reinterpret_cast<char *>(dst), size);
206 }
207 llvm::ArrayRef<BzeroConfiguration> getBzeroConfigurations() {
208   using namespace __llvm_libc;
209   static constexpr BzeroConfiguration kConfigurations[] = {
210     {Wrap<bzero_0x475977492C218AD4>, "bzero_0x475977492C218AD4"},
211   };
212   return llvm::makeArrayRef(kConfigurations);
213 }
214 // Functions : 6
215 )");
216 }
217 } // namespace
218 } // namespace automemcpy
219 } // namespace llvm
220