100c943a5SGuillaume Chatelet //===-- C++ code generation from NamedFunctionDescriptors -----------------===//
200c943a5SGuillaume Chatelet //
300c943a5SGuillaume Chatelet // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
400c943a5SGuillaume Chatelet // See https://llvm.org/LICENSE.txt for license information.
500c943a5SGuillaume Chatelet // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
600c943a5SGuillaume Chatelet //
700c943a5SGuillaume Chatelet //===----------------------------------------------------------------------===//
800c943a5SGuillaume Chatelet // This code is responsible for generating the "Implementation.cpp" file.
900c943a5SGuillaume Chatelet // The file is composed like this:
1000c943a5SGuillaume Chatelet //
1100c943a5SGuillaume Chatelet // 1. Includes
1200c943a5SGuillaume Chatelet // 2. Using statements to help readability.
1300c943a5SGuillaume Chatelet // 3. Source code for all the mem function implementations.
1400c943a5SGuillaume Chatelet // 4. The function to retrieve all the function descriptors with their name.
1500c943a5SGuillaume Chatelet //      llvm::ArrayRef<NamedFunctionDescriptor> getFunctionDescriptors();
1600c943a5SGuillaume Chatelet // 5. The functions for the benchmarking infrastructure:
1700c943a5SGuillaume Chatelet //      llvm::ArrayRef<MemcpyConfiguration> getMemcpyConfigurations();
1800c943a5SGuillaume Chatelet //      llvm::ArrayRef<MemcmpOrBcmpConfiguration> getMemcmpConfigurations();
1900c943a5SGuillaume Chatelet //      llvm::ArrayRef<MemcmpOrBcmpConfiguration> getBcmpConfigurations();
2000c943a5SGuillaume Chatelet //      llvm::ArrayRef<MemsetConfiguration> getMemsetConfigurations();
2100c943a5SGuillaume Chatelet //      llvm::ArrayRef<BzeroConfiguration> getBzeroConfigurations();
2200c943a5SGuillaume Chatelet //
2300c943a5SGuillaume Chatelet //
2400c943a5SGuillaume Chatelet // Sections 3, 4 and 5 are handled by the following namespaces:
2500c943a5SGuillaume Chatelet // - codegen::functions
2600c943a5SGuillaume Chatelet // - codegen::descriptors
2700c943a5SGuillaume Chatelet // - codegen::configurations
2800c943a5SGuillaume Chatelet //
2900c943a5SGuillaume Chatelet // The programming style is functionnal. In each of these namespace, the
3000c943a5SGuillaume Chatelet // original `NamedFunctionDescriptor` object is turned into a different type. We
3100c943a5SGuillaume Chatelet // make use of overloaded stream operators to format the resulting type into
3200c943a5SGuillaume Chatelet // either a function, a descriptor or a configuration. The entry point of each
3300c943a5SGuillaume Chatelet // namespace is the Serialize function.
3400c943a5SGuillaume Chatelet //
3500c943a5SGuillaume Chatelet // Note the code here is better understood by starting from the `Serialize`
3600c943a5SGuillaume Chatelet // function at the end of the file.
3700c943a5SGuillaume Chatelet 
3800c943a5SGuillaume Chatelet #include "automemcpy/CodeGen.h"
3900c943a5SGuillaume Chatelet #include <cassert>
4000c943a5SGuillaume Chatelet #include <llvm/ADT/Optional.h>
4100c943a5SGuillaume Chatelet #include <llvm/ADT/STLExtras.h>
4200c943a5SGuillaume Chatelet #include <llvm/ADT/StringSet.h>
4300c943a5SGuillaume Chatelet #include <llvm/Support/FormatVariadic.h>
4400c943a5SGuillaume Chatelet #include <llvm/Support/raw_ostream.h>
4500c943a5SGuillaume Chatelet #include <set>
4600c943a5SGuillaume Chatelet 
4700c943a5SGuillaume Chatelet namespace llvm {
4800c943a5SGuillaume Chatelet namespace automemcpy {
4900c943a5SGuillaume Chatelet namespace codegen {
5000c943a5SGuillaume Chatelet 
5100c943a5SGuillaume Chatelet // The indentation string.
5200c943a5SGuillaume Chatelet static constexpr StringRef kIndent = "  ";
5300c943a5SGuillaume Chatelet 
5400c943a5SGuillaume Chatelet // The codegen namespace handles the serialization of a NamedFunctionDescriptor
5500c943a5SGuillaume Chatelet // into source code for the function, the descriptor and the configuration.
5600c943a5SGuillaume Chatelet 
5700c943a5SGuillaume Chatelet namespace functions {
5800c943a5SGuillaume Chatelet 
5900c943a5SGuillaume Chatelet // This namespace turns a NamedFunctionDescriptor into an actual implementation.
6000c943a5SGuillaume Chatelet // -----------------------------------------------------------------------------
6100c943a5SGuillaume Chatelet // e.g.
6200c943a5SGuillaume Chatelet // static void memcpy_0xB20D4702493C397E(char *__restrict dst,
6300c943a5SGuillaume Chatelet //                                       const char *__restrict src,
6400c943a5SGuillaume Chatelet //                                       size_t size) {
6500c943a5SGuillaume Chatelet //   using namespace __llvm_libc::x86;
6600c943a5SGuillaume Chatelet //   if(size == 0) return;
671c92911eSMichael Jones //   if(size == 1) return copy<_1>(dst, src);
681c92911eSMichael Jones //   if(size < 4) return copy<HeadTail<_2>>(dst, src, size);
691c92911eSMichael Jones //   if(size < 8) return copy<HeadTail<_4>>(dst, src, size);
701c92911eSMichael Jones //   if(size < 16) return copy<HeadTail<_8>>(dst, src, size);
711c92911eSMichael Jones //   if(size < 32) return copy<HeadTail<_16>>(dst, src, size);
721c92911eSMichael Jones //   return copy<Accelerator>(dst, src, size);
7300c943a5SGuillaume Chatelet // }
7400c943a5SGuillaume Chatelet 
7500c943a5SGuillaume Chatelet // The `Serialize` method turns a `NamedFunctionDescriptor` into a
7600c943a5SGuillaume Chatelet // `FunctionImplementation` which holds all the information needed to produce
7700c943a5SGuillaume Chatelet // the C++ source code.
7800c943a5SGuillaume Chatelet 
7900c943a5SGuillaume Chatelet // An Element with its size (e.g. `_16` in the example above).
8000c943a5SGuillaume Chatelet struct ElementType {
8100c943a5SGuillaume Chatelet   size_t Size;
8200c943a5SGuillaume Chatelet };
8300c943a5SGuillaume Chatelet // The case `if(size == 0)` is encoded as a the Zero type.
8400c943a5SGuillaume Chatelet struct Zero {
8500c943a5SGuillaume Chatelet   StringRef DefaultReturnValue;
8600c943a5SGuillaume Chatelet };
8700c943a5SGuillaume Chatelet // An individual size `if(size == X)` is encoded as an Individual type.
8800c943a5SGuillaume Chatelet struct Individual {
8900c943a5SGuillaume Chatelet   size_t IfEq;
9000c943a5SGuillaume Chatelet   ElementType Element;
9100c943a5SGuillaume Chatelet };
9200c943a5SGuillaume Chatelet // An overlap strategy is encoded as an Overlap type.
9300c943a5SGuillaume Chatelet struct Overlap {
9400c943a5SGuillaume Chatelet   size_t IfLt;
9500c943a5SGuillaume Chatelet   ElementType Element;
9600c943a5SGuillaume Chatelet };
9700c943a5SGuillaume Chatelet // A loop strategy is encoded as a Loop type.
9800c943a5SGuillaume Chatelet struct Loop {
9900c943a5SGuillaume Chatelet   size_t IfLt;
10000c943a5SGuillaume Chatelet   ElementType Element;
10100c943a5SGuillaume Chatelet };
10200c943a5SGuillaume Chatelet // An aligned loop strategy is encoded as an AlignedLoop type.
10300c943a5SGuillaume Chatelet struct AlignedLoop {
10400c943a5SGuillaume Chatelet   size_t IfLt;
10500c943a5SGuillaume Chatelet   ElementType Element;
10600c943a5SGuillaume Chatelet   ElementType Alignment;
10700c943a5SGuillaume Chatelet   StringRef AlignTo;
10800c943a5SGuillaume Chatelet };
10900c943a5SGuillaume Chatelet // The accelerator strategy.
11000c943a5SGuillaume Chatelet struct Accelerator {
11100c943a5SGuillaume Chatelet   size_t IfLt;
11200c943a5SGuillaume Chatelet };
11300c943a5SGuillaume Chatelet // The Context stores data about the function type.
11400c943a5SGuillaume Chatelet struct Context {
11500c943a5SGuillaume Chatelet   StringRef FunctionReturnType; // e.g. void* or int
11600c943a5SGuillaume Chatelet   StringRef FunctionArgs;
1171c92911eSMichael Jones   StringRef ElementOp; // copy, three_way_compare, splat_set, ...
11800c943a5SGuillaume Chatelet   StringRef FixedSizeArgs;
11900c943a5SGuillaume Chatelet   StringRef RuntimeSizeArgs;
12000c943a5SGuillaume Chatelet   StringRef AlignArg1;
12100c943a5SGuillaume Chatelet   StringRef AlignArg2;
12200c943a5SGuillaume Chatelet   StringRef DefaultReturnValue;
12300c943a5SGuillaume Chatelet };
12400c943a5SGuillaume Chatelet // A detailed representation of the function implementation mapped from the
12500c943a5SGuillaume Chatelet // NamedFunctionDescriptor.
12600c943a5SGuillaume Chatelet struct FunctionImplementation {
12700c943a5SGuillaume Chatelet   Context Ctx;
12800c943a5SGuillaume Chatelet   StringRef Name;
12900c943a5SGuillaume Chatelet   std::vector<Individual> Individuals;
13000c943a5SGuillaume Chatelet   std::vector<Overlap> Overlaps;
13100c943a5SGuillaume Chatelet   Optional<Loop> Loop;
13200c943a5SGuillaume Chatelet   Optional<AlignedLoop> AlignedLoop;
13300c943a5SGuillaume Chatelet   Optional<Accelerator> Accelerator;
13400c943a5SGuillaume Chatelet   ElementTypeClass ElementClass;
13500c943a5SGuillaume Chatelet };
13600c943a5SGuillaume Chatelet 
13700c943a5SGuillaume Chatelet // Returns the Context for each FunctionType.
getCtx(FunctionType FT)13800c943a5SGuillaume Chatelet static Context getCtx(FunctionType FT) {
13900c943a5SGuillaume Chatelet   switch (FT) {
14000c943a5SGuillaume Chatelet   case FunctionType::MEMCPY:
14100c943a5SGuillaume Chatelet     return {"void",
14200c943a5SGuillaume Chatelet             "(char *__restrict dst, const char *__restrict src, size_t size)",
1431c92911eSMichael Jones             "copy",
14400c943a5SGuillaume Chatelet             "(dst, src)",
14500c943a5SGuillaume Chatelet             "(dst, src, size)",
14600c943a5SGuillaume Chatelet             "Arg::Dst",
14700c943a5SGuillaume Chatelet             "Arg::Src",
14800c943a5SGuillaume Chatelet             ""};
14900c943a5SGuillaume Chatelet   case FunctionType::MEMCMP:
15000c943a5SGuillaume Chatelet     return {"int",
15100c943a5SGuillaume Chatelet             "(const char * lhs, const char * rhs, size_t size)",
1521c92911eSMichael Jones             "three_way_compare",
15300c943a5SGuillaume Chatelet             "(lhs, rhs)",
15400c943a5SGuillaume Chatelet             "(lhs, rhs, size)",
15500c943a5SGuillaume Chatelet             "Arg::Lhs",
15600c943a5SGuillaume Chatelet             "Arg::Rhs",
15700c943a5SGuillaume Chatelet             "0"};
15800c943a5SGuillaume Chatelet   case FunctionType::MEMSET:
15900c943a5SGuillaume Chatelet     return {"void",
16000c943a5SGuillaume Chatelet             "(char * dst, int value, size_t size)",
1611c92911eSMichael Jones             "splat_set",
16200c943a5SGuillaume Chatelet             "(dst, value)",
16300c943a5SGuillaume Chatelet             "(dst, value, size)",
16400c943a5SGuillaume Chatelet             "Arg::Dst",
16500c943a5SGuillaume Chatelet             "Arg::Src",
16600c943a5SGuillaume Chatelet             ""};
16700c943a5SGuillaume Chatelet   case FunctionType::BZERO:
16800c943a5SGuillaume Chatelet     return {"void",           "(char * dst, size_t size)",
1691c92911eSMichael Jones             "splat_set",      "(dst, 0)",
17000c943a5SGuillaume Chatelet             "(dst, 0, size)", "Arg::Dst",
17100c943a5SGuillaume Chatelet             "Arg::Src",       ""};
17200c943a5SGuillaume Chatelet   default:
17300c943a5SGuillaume Chatelet     report_fatal_error("Not yet implemented");
17400c943a5SGuillaume Chatelet   }
17500c943a5SGuillaume Chatelet }
17600c943a5SGuillaume Chatelet 
getAligntoString(const Context & Ctx,const AlignArg & AlignTo)17700c943a5SGuillaume Chatelet static StringRef getAligntoString(const Context &Ctx, const AlignArg &AlignTo) {
17800c943a5SGuillaume Chatelet   switch (AlignTo) {
17900c943a5SGuillaume Chatelet   case AlignArg::_1:
18000c943a5SGuillaume Chatelet     return Ctx.AlignArg1;
18100c943a5SGuillaume Chatelet   case AlignArg::_2:
18200c943a5SGuillaume Chatelet     return Ctx.AlignArg2;
18300c943a5SGuillaume Chatelet   case AlignArg::ARRAY_SIZE:
18400c943a5SGuillaume Chatelet     report_fatal_error("logic error");
18500c943a5SGuillaume Chatelet   }
18600c943a5SGuillaume Chatelet }
18700c943a5SGuillaume Chatelet 
operator <<(raw_ostream & Stream,const ElementType & E)18800c943a5SGuillaume Chatelet static raw_ostream &operator<<(raw_ostream &Stream, const ElementType &E) {
18900c943a5SGuillaume Chatelet   return Stream << '_' << E.Size;
19000c943a5SGuillaume Chatelet }
operator <<(raw_ostream & Stream,const Individual & O)19100c943a5SGuillaume Chatelet static raw_ostream &operator<<(raw_ostream &Stream, const Individual &O) {
19200c943a5SGuillaume Chatelet   return Stream << O.Element;
19300c943a5SGuillaume Chatelet }
operator <<(raw_ostream & Stream,const Overlap & O)19400c943a5SGuillaume Chatelet static raw_ostream &operator<<(raw_ostream &Stream, const Overlap &O) {
19500c943a5SGuillaume Chatelet   return Stream << "HeadTail<" << O.Element << '>';
19600c943a5SGuillaume Chatelet }
operator <<(raw_ostream & Stream,const Loop & O)19700c943a5SGuillaume Chatelet static raw_ostream &operator<<(raw_ostream &Stream, const Loop &O) {
19800c943a5SGuillaume Chatelet   return Stream << "Loop<" << O.Element << '>';
19900c943a5SGuillaume Chatelet }
operator <<(raw_ostream & Stream,const AlignedLoop & O)20000c943a5SGuillaume Chatelet static raw_ostream &operator<<(raw_ostream &Stream, const AlignedLoop &O) {
20100c943a5SGuillaume Chatelet   return Stream << "Align<" << O.Alignment << ',' << O.AlignTo << ">::Then<"
20200c943a5SGuillaume Chatelet                 << Loop{O.IfLt, O.Element} << ">";
20300c943a5SGuillaume Chatelet }
operator <<(raw_ostream & Stream,const Accelerator & O)20400c943a5SGuillaume Chatelet static raw_ostream &operator<<(raw_ostream &Stream, const Accelerator &O) {
20500c943a5SGuillaume Chatelet   return Stream << "Accelerator";
20600c943a5SGuillaume Chatelet }
20700c943a5SGuillaume Chatelet 
20800c943a5SGuillaume Chatelet template <typename T> struct IfEq {
20900c943a5SGuillaume Chatelet   StringRef Op;
21000c943a5SGuillaume Chatelet   StringRef Args;
21100c943a5SGuillaume Chatelet   const T &Element;
21200c943a5SGuillaume Chatelet };
21300c943a5SGuillaume Chatelet 
21400c943a5SGuillaume Chatelet template <typename T> struct IfLt {
21500c943a5SGuillaume Chatelet   StringRef Op;
21600c943a5SGuillaume Chatelet   StringRef Args;
21700c943a5SGuillaume Chatelet   const T &Element;
21800c943a5SGuillaume Chatelet };
21900c943a5SGuillaume Chatelet 
operator <<(raw_ostream & Stream,const Zero & O)22000c943a5SGuillaume Chatelet static raw_ostream &operator<<(raw_ostream &Stream, const Zero &O) {
22100c943a5SGuillaume Chatelet   Stream << kIndent << "if(size == 0) return";
22200c943a5SGuillaume Chatelet   if (!O.DefaultReturnValue.empty())
22300c943a5SGuillaume Chatelet     Stream << ' ' << O.DefaultReturnValue;
22400c943a5SGuillaume Chatelet   return Stream << ";\n";
22500c943a5SGuillaume Chatelet }
22600c943a5SGuillaume Chatelet 
22700c943a5SGuillaume Chatelet template <typename T>
operator <<(raw_ostream & Stream,const IfEq<T> & O)22800c943a5SGuillaume Chatelet static raw_ostream &operator<<(raw_ostream &Stream, const IfEq<T> &O) {
22900c943a5SGuillaume Chatelet   return Stream << kIndent << "if(size == " << O.Element.IfEq << ") return "
23000c943a5SGuillaume Chatelet                 << O.Op << '<' << O.Element << '>' << O.Args << ";\n";
23100c943a5SGuillaume Chatelet }
23200c943a5SGuillaume Chatelet 
23300c943a5SGuillaume Chatelet template <typename T>
operator <<(raw_ostream & Stream,const IfLt<T> & O)23400c943a5SGuillaume Chatelet static raw_ostream &operator<<(raw_ostream &Stream, const IfLt<T> &O) {
23500c943a5SGuillaume Chatelet   Stream << kIndent;
23600c943a5SGuillaume Chatelet   if (O.Element.IfLt != kMaxSize)
23700c943a5SGuillaume Chatelet     Stream << "if(size < " << O.Element.IfLt << ") ";
23800c943a5SGuillaume Chatelet   return Stream << "return " << O.Op << '<' << O.Element << '>' << O.Args
23900c943a5SGuillaume Chatelet                 << ";\n";
24000c943a5SGuillaume Chatelet }
24100c943a5SGuillaume Chatelet 
operator <<(raw_ostream & Stream,const ElementTypeClass & Class)24200c943a5SGuillaume Chatelet static raw_ostream &operator<<(raw_ostream &Stream,
24300c943a5SGuillaume Chatelet                                const ElementTypeClass &Class) {
24400c943a5SGuillaume Chatelet   switch (Class) {
24500c943a5SGuillaume Chatelet   case ElementTypeClass::SCALAR:
24600c943a5SGuillaume Chatelet     return Stream << "scalar";
24700c943a5SGuillaume Chatelet   case ElementTypeClass::BUILTIN:
24800c943a5SGuillaume Chatelet     return Stream << "builtin";
24900c943a5SGuillaume Chatelet   case ElementTypeClass::NATIVE:
25000c943a5SGuillaume Chatelet     // FIXME: the framework should provide a `native` namespace that redirect to
25100c943a5SGuillaume Chatelet     // x86, arm or other architectures.
25200c943a5SGuillaume Chatelet     return Stream << "x86";
25300c943a5SGuillaume Chatelet   }
25400c943a5SGuillaume Chatelet }
25500c943a5SGuillaume Chatelet 
operator <<(raw_ostream & Stream,const FunctionImplementation & FI)25600c943a5SGuillaume Chatelet static raw_ostream &operator<<(raw_ostream &Stream,
25700c943a5SGuillaume Chatelet                                const FunctionImplementation &FI) {
25800c943a5SGuillaume Chatelet   const auto &Ctx = FI.Ctx;
25900c943a5SGuillaume Chatelet   Stream << "static " << Ctx.FunctionReturnType << ' ' << FI.Name
26000c943a5SGuillaume Chatelet          << Ctx.FunctionArgs << " {\n";
26100c943a5SGuillaume Chatelet   Stream << kIndent << "using namespace __llvm_libc::" << FI.ElementClass
26200c943a5SGuillaume Chatelet          << ";\n";
26300c943a5SGuillaume Chatelet   for (const auto &I : FI.Individuals)
26400c943a5SGuillaume Chatelet     if (I.Element.Size == 0)
26500c943a5SGuillaume Chatelet       Stream << Zero{Ctx.DefaultReturnValue};
26600c943a5SGuillaume Chatelet     else
26700c943a5SGuillaume Chatelet       Stream << IfEq<Individual>{Ctx.ElementOp, Ctx.FixedSizeArgs, I};
26800c943a5SGuillaume Chatelet   for (const auto &O : FI.Overlaps)
26900c943a5SGuillaume Chatelet     Stream << IfLt<Overlap>{Ctx.ElementOp, Ctx.RuntimeSizeArgs, O};
27000c943a5SGuillaume Chatelet   if (const auto &C = FI.Loop)
27100c943a5SGuillaume Chatelet     Stream << IfLt<Loop>{Ctx.ElementOp, Ctx.RuntimeSizeArgs, *C};
27200c943a5SGuillaume Chatelet   if (const auto &C = FI.AlignedLoop)
27300c943a5SGuillaume Chatelet     Stream << IfLt<AlignedLoop>{Ctx.ElementOp, Ctx.RuntimeSizeArgs, *C};
27400c943a5SGuillaume Chatelet   if (const auto &C = FI.Accelerator)
27500c943a5SGuillaume Chatelet     Stream << IfLt<Accelerator>{Ctx.ElementOp, Ctx.RuntimeSizeArgs, *C};
27600c943a5SGuillaume Chatelet   return Stream << "}\n";
27700c943a5SGuillaume Chatelet }
27800c943a5SGuillaume Chatelet 
27900c943a5SGuillaume Chatelet // Turns a `NamedFunctionDescriptor` into a `FunctionImplementation` unfolding
28000c943a5SGuillaume Chatelet // the contiguous and overlap region into several statements. The zero case is
28100c943a5SGuillaume Chatelet // also mapped to its own type.
28200c943a5SGuillaume Chatelet static FunctionImplementation
getImplementation(const NamedFunctionDescriptor & NamedFD)28300c943a5SGuillaume Chatelet getImplementation(const NamedFunctionDescriptor &NamedFD) {
28400c943a5SGuillaume Chatelet   const FunctionDescriptor &FD = NamedFD.Desc;
28500c943a5SGuillaume Chatelet   FunctionImplementation Impl;
28600c943a5SGuillaume Chatelet   Impl.Ctx = getCtx(FD.Type);
28700c943a5SGuillaume Chatelet   Impl.Name = NamedFD.Name;
28800c943a5SGuillaume Chatelet   Impl.ElementClass = FD.ElementClass;
28900c943a5SGuillaume Chatelet   if (auto C = FD.Contiguous)
29000c943a5SGuillaume Chatelet     for (size_t I = C->Span.Begin; I < C->Span.End; ++I)
29100c943a5SGuillaume Chatelet       Impl.Individuals.push_back(Individual{I, ElementType{I}});
29200c943a5SGuillaume Chatelet   if (auto C = FD.Overlap)
29300c943a5SGuillaume Chatelet     for (size_t I = C->Span.Begin; I < C->Span.End; I *= 2)
29400c943a5SGuillaume Chatelet       Impl.Overlaps.push_back(Overlap{2 * I, ElementType{I}});
29500c943a5SGuillaume Chatelet   if (const auto &L = FD.Loop)
29600c943a5SGuillaume Chatelet     Impl.Loop = Loop{L->Span.End, ElementType{L->BlockSize}};
29700c943a5SGuillaume Chatelet   if (const auto &AL = FD.AlignedLoop)
29800c943a5SGuillaume Chatelet     Impl.AlignedLoop = AlignedLoop{
29900c943a5SGuillaume Chatelet         AL->Loop.Span.End, ElementType{AL->Loop.BlockSize},
30000c943a5SGuillaume Chatelet         ElementType{AL->Alignment}, getAligntoString(Impl.Ctx, AL->AlignTo)};
30100c943a5SGuillaume Chatelet   if (const auto &A = FD.Accelerator)
30200c943a5SGuillaume Chatelet     Impl.Accelerator = Accelerator{A->Span.End};
30300c943a5SGuillaume Chatelet   return Impl;
30400c943a5SGuillaume Chatelet }
30500c943a5SGuillaume Chatelet 
Serialize(raw_ostream & Stream,ArrayRef<NamedFunctionDescriptor> Descriptors)30600c943a5SGuillaume Chatelet static void Serialize(raw_ostream &Stream,
30700c943a5SGuillaume Chatelet                       ArrayRef<NamedFunctionDescriptor> Descriptors) {
30800c943a5SGuillaume Chatelet 
30900c943a5SGuillaume Chatelet   for (const auto &FD : Descriptors)
31000c943a5SGuillaume Chatelet     Stream << getImplementation(FD);
31100c943a5SGuillaume Chatelet }
31200c943a5SGuillaume Chatelet 
31300c943a5SGuillaume Chatelet } // namespace functions
31400c943a5SGuillaume Chatelet 
31500c943a5SGuillaume Chatelet namespace descriptors {
31600c943a5SGuillaume Chatelet 
31700c943a5SGuillaume Chatelet // This namespace generates the getFunctionDescriptors function:
31800c943a5SGuillaume Chatelet // -------------------------------------------------------------
31900c943a5SGuillaume Chatelet // e.g.
32000c943a5SGuillaume Chatelet // ArrayRef<NamedFunctionDescriptor> getFunctionDescriptors() {
32100c943a5SGuillaume Chatelet //   static constexpr NamedFunctionDescriptor kDescriptors[] = {
32200c943a5SGuillaume Chatelet //     {"memcpy_0xE00E29EE73994E2B",{FunctionType::MEMCPY,llvm::None,llvm::None,llvm::None,llvm::None,Accelerator{{0,kMaxSize}},ElementTypeClass::NATIVE}},
32300c943a5SGuillaume Chatelet //     {"memcpy_0x8661D80472487AB5",{FunctionType::MEMCPY,Contiguous{{0,1}},llvm::None,llvm::None,llvm::None,Accelerator{{1,kMaxSize}},ElementTypeClass::NATIVE}},
32400c943a5SGuillaume Chatelet //     ...
32500c943a5SGuillaume Chatelet //   };
32600c943a5SGuillaume Chatelet //   return makeArrayRef(kDescriptors);
32700c943a5SGuillaume Chatelet // }
32800c943a5SGuillaume Chatelet 
operator <<(raw_ostream & Stream,const SizeSpan & SS)32900c943a5SGuillaume Chatelet static raw_ostream &operator<<(raw_ostream &Stream, const SizeSpan &SS) {
33000c943a5SGuillaume Chatelet   Stream << "{" << SS.Begin << ',';
33100c943a5SGuillaume Chatelet   if (SS.End == kMaxSize)
33200c943a5SGuillaume Chatelet     Stream << "kMaxSize";
33300c943a5SGuillaume Chatelet   else
33400c943a5SGuillaume Chatelet     Stream << SS.End;
33500c943a5SGuillaume Chatelet   return Stream << '}';
33600c943a5SGuillaume Chatelet }
operator <<(raw_ostream & Stream,const Contiguous & O)33700c943a5SGuillaume Chatelet static raw_ostream &operator<<(raw_ostream &Stream, const Contiguous &O) {
33800c943a5SGuillaume Chatelet   return Stream << "Contiguous{" << O.Span << '}';
33900c943a5SGuillaume Chatelet }
operator <<(raw_ostream & Stream,const Overlap & O)34000c943a5SGuillaume Chatelet static raw_ostream &operator<<(raw_ostream &Stream, const Overlap &O) {
34100c943a5SGuillaume Chatelet   return Stream << "Overlap{" << O.Span << '}';
34200c943a5SGuillaume Chatelet }
operator <<(raw_ostream & Stream,const Loop & O)34300c943a5SGuillaume Chatelet static raw_ostream &operator<<(raw_ostream &Stream, const Loop &O) {
34400c943a5SGuillaume Chatelet   return Stream << "Loop{" << O.Span << ',' << O.BlockSize << '}';
34500c943a5SGuillaume Chatelet }
operator <<(raw_ostream & Stream,const AlignArg & O)34600c943a5SGuillaume Chatelet static raw_ostream &operator<<(raw_ostream &Stream, const AlignArg &O) {
34700c943a5SGuillaume Chatelet   switch (O) {
34800c943a5SGuillaume Chatelet   case AlignArg::_1:
34900c943a5SGuillaume Chatelet     return Stream << "AlignArg::_1";
35000c943a5SGuillaume Chatelet   case AlignArg::_2:
35100c943a5SGuillaume Chatelet     return Stream << "AlignArg::_2";
35200c943a5SGuillaume Chatelet   case AlignArg::ARRAY_SIZE:
35300c943a5SGuillaume Chatelet     report_fatal_error("logic error");
35400c943a5SGuillaume Chatelet   }
35500c943a5SGuillaume Chatelet }
operator <<(raw_ostream & Stream,const AlignedLoop & O)35600c943a5SGuillaume Chatelet static raw_ostream &operator<<(raw_ostream &Stream, const AlignedLoop &O) {
35700c943a5SGuillaume Chatelet   return Stream << "AlignedLoop{" << O.Loop << ',' << O.Alignment << ','
35800c943a5SGuillaume Chatelet                 << O.AlignTo << '}';
35900c943a5SGuillaume Chatelet }
operator <<(raw_ostream & Stream,const Accelerator & O)36000c943a5SGuillaume Chatelet static raw_ostream &operator<<(raw_ostream &Stream, const Accelerator &O) {
36100c943a5SGuillaume Chatelet   return Stream << "Accelerator{" << O.Span << '}';
36200c943a5SGuillaume Chatelet }
operator <<(raw_ostream & Stream,const ElementTypeClass & O)36300c943a5SGuillaume Chatelet static raw_ostream &operator<<(raw_ostream &Stream, const ElementTypeClass &O) {
36400c943a5SGuillaume Chatelet   switch (O) {
36500c943a5SGuillaume Chatelet   case ElementTypeClass::SCALAR:
36600c943a5SGuillaume Chatelet     return Stream << "ElementTypeClass::SCALAR";
36700c943a5SGuillaume Chatelet   case ElementTypeClass::BUILTIN:
36800c943a5SGuillaume Chatelet     return Stream << "ElementTypeClass::BUILTIN";
36900c943a5SGuillaume Chatelet   case ElementTypeClass::NATIVE:
37000c943a5SGuillaume Chatelet     return Stream << "ElementTypeClass::NATIVE";
37100c943a5SGuillaume Chatelet   }
37200c943a5SGuillaume Chatelet }
operator <<(raw_ostream & Stream,const FunctionType & T)37300c943a5SGuillaume Chatelet static raw_ostream &operator<<(raw_ostream &Stream, const FunctionType &T) {
37400c943a5SGuillaume Chatelet   switch (T) {
37500c943a5SGuillaume Chatelet   case FunctionType::MEMCPY:
37600c943a5SGuillaume Chatelet     return Stream << "FunctionType::MEMCPY";
37700c943a5SGuillaume Chatelet   case FunctionType::MEMCMP:
37800c943a5SGuillaume Chatelet     return Stream << "FunctionType::MEMCMP";
37900c943a5SGuillaume Chatelet   case FunctionType::BCMP:
38000c943a5SGuillaume Chatelet     return Stream << "FunctionType::BCMP";
38100c943a5SGuillaume Chatelet   case FunctionType::MEMSET:
38200c943a5SGuillaume Chatelet     return Stream << "FunctionType::MEMSET";
38300c943a5SGuillaume Chatelet   case FunctionType::BZERO:
38400c943a5SGuillaume Chatelet     return Stream << "FunctionType::BZERO";
38500c943a5SGuillaume Chatelet   }
38600c943a5SGuillaume Chatelet }
38700c943a5SGuillaume Chatelet template <typename T>
operator <<(raw_ostream & Stream,const llvm::Optional<T> & MaybeT)38800c943a5SGuillaume Chatelet static raw_ostream &operator<<(raw_ostream &Stream,
38900c943a5SGuillaume Chatelet                                const llvm::Optional<T> &MaybeT) {
39000c943a5SGuillaume Chatelet   if (MaybeT)
39100c943a5SGuillaume Chatelet     return Stream << *MaybeT;
39200c943a5SGuillaume Chatelet   return Stream << "llvm::None";
39300c943a5SGuillaume Chatelet }
operator <<(raw_ostream & Stream,const FunctionDescriptor & FD)39400c943a5SGuillaume Chatelet static raw_ostream &operator<<(raw_ostream &Stream,
39500c943a5SGuillaume Chatelet                                const FunctionDescriptor &FD) {
39600c943a5SGuillaume Chatelet   return Stream << '{' << FD.Type << ',' << FD.Contiguous << ',' << FD.Overlap
39700c943a5SGuillaume Chatelet                 << ',' << FD.Loop << ',' << FD.AlignedLoop << ','
39800c943a5SGuillaume Chatelet                 << FD.Accelerator << ',' << FD.ElementClass << '}';
39900c943a5SGuillaume Chatelet }
operator <<(raw_ostream & Stream,const NamedFunctionDescriptor & NFD)40000c943a5SGuillaume Chatelet static raw_ostream &operator<<(raw_ostream &Stream,
40100c943a5SGuillaume Chatelet                                const NamedFunctionDescriptor &NFD) {
40200c943a5SGuillaume Chatelet   return Stream << '{' << '"' << NFD.Name << '"' << ',' << NFD.Desc << '}';
40300c943a5SGuillaume Chatelet }
40400c943a5SGuillaume Chatelet template <typename T>
operator <<(raw_ostream & Stream,const std::vector<T> & VectorT)40500c943a5SGuillaume Chatelet static raw_ostream &operator<<(raw_ostream &Stream,
40600c943a5SGuillaume Chatelet                                const std::vector<T> &VectorT) {
40700c943a5SGuillaume Chatelet   Stream << '{';
40800c943a5SGuillaume Chatelet   bool First = true;
40900c943a5SGuillaume Chatelet   for (const auto &Obj : VectorT) {
41000c943a5SGuillaume Chatelet     if (!First)
41100c943a5SGuillaume Chatelet       Stream << ',';
41200c943a5SGuillaume Chatelet     Stream << Obj;
41300c943a5SGuillaume Chatelet     First = false;
41400c943a5SGuillaume Chatelet   }
41500c943a5SGuillaume Chatelet   return Stream << '}';
41600c943a5SGuillaume Chatelet }
41700c943a5SGuillaume Chatelet 
Serialize(raw_ostream & Stream,ArrayRef<NamedFunctionDescriptor> Descriptors)41800c943a5SGuillaume Chatelet static void Serialize(raw_ostream &Stream,
41900c943a5SGuillaume Chatelet                       ArrayRef<NamedFunctionDescriptor> Descriptors) {
42000c943a5SGuillaume Chatelet   Stream << R"(ArrayRef<NamedFunctionDescriptor> getFunctionDescriptors() {
42100c943a5SGuillaume Chatelet   static constexpr NamedFunctionDescriptor kDescriptors[] = {
42200c943a5SGuillaume Chatelet )";
42300c943a5SGuillaume Chatelet   for (size_t I = 0, E = Descriptors.size(); I < E; ++I) {
42400c943a5SGuillaume Chatelet     Stream << kIndent << kIndent << Descriptors[I] << ",\n";
42500c943a5SGuillaume Chatelet   }
42600c943a5SGuillaume Chatelet   Stream << R"(  };
42700c943a5SGuillaume Chatelet   return makeArrayRef(kDescriptors);
42800c943a5SGuillaume Chatelet }
42900c943a5SGuillaume Chatelet )";
43000c943a5SGuillaume Chatelet }
43100c943a5SGuillaume Chatelet 
43200c943a5SGuillaume Chatelet } // namespace descriptors
43300c943a5SGuillaume Chatelet 
43400c943a5SGuillaume Chatelet namespace configurations {
43500c943a5SGuillaume Chatelet 
43600c943a5SGuillaume Chatelet // This namespace generates the getXXXConfigurations functions:
43700c943a5SGuillaume Chatelet // ------------------------------------------------------------
43800c943a5SGuillaume Chatelet // e.g.
43900c943a5SGuillaume Chatelet // llvm::ArrayRef<MemcpyConfiguration> getMemcpyConfigurations() {
44000c943a5SGuillaume Chatelet //   using namespace __llvm_libc;
44100c943a5SGuillaume Chatelet //   static constexpr MemcpyConfiguration kConfigurations[] = {
44200c943a5SGuillaume Chatelet //     {Wrap<memcpy_0xE00E29EE73994E2B>, "memcpy_0xE00E29EE73994E2B"},
44300c943a5SGuillaume Chatelet //     {Wrap<memcpy_0x8661D80472487AB5>, "memcpy_0x8661D80472487AB5"},
44400c943a5SGuillaume Chatelet //     ...
44500c943a5SGuillaume Chatelet //   };
44600c943a5SGuillaume Chatelet //   return llvm::makeArrayRef(kConfigurations);
44700c943a5SGuillaume Chatelet // }
44800c943a5SGuillaume Chatelet 
44900c943a5SGuillaume Chatelet // The `Wrap` template function is provided in the `Main` function below.
45000c943a5SGuillaume Chatelet // It is used to adapt the gnerated code to the prototype of the C function.
45100c943a5SGuillaume Chatelet // For instance, the generated code for a `memcpy` takes `char*` pointers and
45200c943a5SGuillaume Chatelet // returns nothing but the original C `memcpy` function take and returns `void*`
45300c943a5SGuillaume Chatelet // pointers.
45400c943a5SGuillaume Chatelet 
45500c943a5SGuillaume Chatelet struct FunctionName {
45600c943a5SGuillaume Chatelet   FunctionType ForType;
45700c943a5SGuillaume Chatelet };
45800c943a5SGuillaume Chatelet 
45900c943a5SGuillaume Chatelet struct ReturnType {
46000c943a5SGuillaume Chatelet   FunctionType ForType;
46100c943a5SGuillaume Chatelet };
46200c943a5SGuillaume Chatelet 
46300c943a5SGuillaume Chatelet struct Configuration {
46400c943a5SGuillaume Chatelet   FunctionName Name;
46500c943a5SGuillaume Chatelet   ReturnType Type;
46600c943a5SGuillaume Chatelet   std::vector<const NamedFunctionDescriptor *> Descriptors;
46700c943a5SGuillaume Chatelet };
46800c943a5SGuillaume Chatelet 
operator <<(raw_ostream & Stream,const FunctionName & FN)46900c943a5SGuillaume Chatelet static raw_ostream &operator<<(raw_ostream &Stream, const FunctionName &FN) {
47000c943a5SGuillaume Chatelet   switch (FN.ForType) {
47100c943a5SGuillaume Chatelet   case FunctionType::MEMCPY:
47200c943a5SGuillaume Chatelet     return Stream << "getMemcpyConfigurations";
47300c943a5SGuillaume Chatelet   case FunctionType::MEMCMP:
47400c943a5SGuillaume Chatelet     return Stream << "getMemcmpConfigurations";
47500c943a5SGuillaume Chatelet   case FunctionType::BCMP:
47600c943a5SGuillaume Chatelet     return Stream << "getBcmpConfigurations";
47700c943a5SGuillaume Chatelet   case FunctionType::MEMSET:
47800c943a5SGuillaume Chatelet     return Stream << "getMemsetConfigurations";
47900c943a5SGuillaume Chatelet   case FunctionType::BZERO:
48000c943a5SGuillaume Chatelet     return Stream << "getBzeroConfigurations";
48100c943a5SGuillaume Chatelet   }
48200c943a5SGuillaume Chatelet }
48300c943a5SGuillaume Chatelet 
operator <<(raw_ostream & Stream,const ReturnType & RT)48400c943a5SGuillaume Chatelet static raw_ostream &operator<<(raw_ostream &Stream, const ReturnType &RT) {
48500c943a5SGuillaume Chatelet   switch (RT.ForType) {
48600c943a5SGuillaume Chatelet   case FunctionType::MEMCPY:
48700c943a5SGuillaume Chatelet     return Stream << "MemcpyConfiguration";
48800c943a5SGuillaume Chatelet   case FunctionType::MEMCMP:
48900c943a5SGuillaume Chatelet   case FunctionType::BCMP:
49000c943a5SGuillaume Chatelet     return Stream << "MemcmpOrBcmpConfiguration";
49100c943a5SGuillaume Chatelet   case FunctionType::MEMSET:
49200c943a5SGuillaume Chatelet     return Stream << "MemsetConfiguration";
49300c943a5SGuillaume Chatelet   case FunctionType::BZERO:
49400c943a5SGuillaume Chatelet     return Stream << "BzeroConfiguration";
49500c943a5SGuillaume Chatelet   }
49600c943a5SGuillaume Chatelet }
49700c943a5SGuillaume Chatelet 
operator <<(raw_ostream & Stream,const NamedFunctionDescriptor * FD)49800c943a5SGuillaume Chatelet static raw_ostream &operator<<(raw_ostream &Stream,
49900c943a5SGuillaume Chatelet                                const NamedFunctionDescriptor *FD) {
50000c943a5SGuillaume Chatelet   return Stream << formatv("{Wrap<{0}>, \"{0}\"}", FD->Name);
50100c943a5SGuillaume Chatelet }
50200c943a5SGuillaume Chatelet 
50300c943a5SGuillaume Chatelet static raw_ostream &
operator <<(raw_ostream & Stream,const std::vector<const NamedFunctionDescriptor * > & Descriptors)50400c943a5SGuillaume Chatelet operator<<(raw_ostream &Stream,
50500c943a5SGuillaume Chatelet            const std::vector<const NamedFunctionDescriptor *> &Descriptors) {
50600c943a5SGuillaume Chatelet   for (size_t I = 0, E = Descriptors.size(); I < E; ++I)
50700c943a5SGuillaume Chatelet     Stream << kIndent << kIndent << Descriptors[I] << ",\n";
50800c943a5SGuillaume Chatelet   return Stream;
50900c943a5SGuillaume Chatelet }
51000c943a5SGuillaume Chatelet 
operator <<(raw_ostream & Stream,const Configuration & C)51100c943a5SGuillaume Chatelet static raw_ostream &operator<<(raw_ostream &Stream, const Configuration &C) {
51200c943a5SGuillaume Chatelet   Stream << "llvm::ArrayRef<" << C.Type << "> " << C.Name << "() {\n";
51300c943a5SGuillaume Chatelet   if (C.Descriptors.empty())
51400c943a5SGuillaume Chatelet     Stream << kIndent << "return {};\n";
51500c943a5SGuillaume Chatelet   else {
51600c943a5SGuillaume Chatelet     Stream << kIndent << "using namespace __llvm_libc;\n";
51700c943a5SGuillaume Chatelet     Stream << kIndent << "static constexpr " << C.Type
51800c943a5SGuillaume Chatelet            << " kConfigurations[] = {\n";
51900c943a5SGuillaume Chatelet     Stream << C.Descriptors;
52000c943a5SGuillaume Chatelet     Stream << kIndent << "};\n";
52100c943a5SGuillaume Chatelet     Stream << kIndent << "return llvm::makeArrayRef(kConfigurations);\n";
52200c943a5SGuillaume Chatelet   }
52300c943a5SGuillaume Chatelet   Stream << "}\n";
52400c943a5SGuillaume Chatelet   return Stream;
52500c943a5SGuillaume Chatelet }
52600c943a5SGuillaume Chatelet 
Serialize(raw_ostream & Stream,FunctionType FT,ArrayRef<NamedFunctionDescriptor> Descriptors)52700c943a5SGuillaume Chatelet static void Serialize(raw_ostream &Stream, FunctionType FT,
52800c943a5SGuillaume Chatelet                       ArrayRef<NamedFunctionDescriptor> Descriptors) {
52900c943a5SGuillaume Chatelet   Configuration Conf;
53000c943a5SGuillaume Chatelet   Conf.Name = {FT};
53100c943a5SGuillaume Chatelet   Conf.Type = {FT};
53200c943a5SGuillaume Chatelet   for (const auto &FD : Descriptors)
53300c943a5SGuillaume Chatelet     if (FD.Desc.Type == FT)
53400c943a5SGuillaume Chatelet       Conf.Descriptors.push_back(&FD);
53500c943a5SGuillaume Chatelet   Stream << Conf;
53600c943a5SGuillaume Chatelet }
53700c943a5SGuillaume Chatelet 
53800c943a5SGuillaume Chatelet } // namespace configurations
Serialize(raw_ostream & Stream,ArrayRef<NamedFunctionDescriptor> Descriptors)53900c943a5SGuillaume Chatelet static void Serialize(raw_ostream &Stream,
54000c943a5SGuillaume Chatelet                       ArrayRef<NamedFunctionDescriptor> Descriptors) {
54100c943a5SGuillaume Chatelet   Stream << "// This file is auto-generated by libc/benchmarks/automemcpy.\n";
54200c943a5SGuillaume Chatelet   Stream << "// Functions : " << Descriptors.size() << "\n";
54300c943a5SGuillaume Chatelet   Stream << "\n";
54400c943a5SGuillaume Chatelet   Stream << "#include \"LibcFunctionPrototypes.h\"\n";
54500c943a5SGuillaume Chatelet   Stream << "#include \"automemcpy/FunctionDescriptor.h\"\n";
54600c943a5SGuillaume Chatelet   Stream << "#include \"src/string/memory_utils/elements.h\"\n";
54700c943a5SGuillaume Chatelet   Stream << "\n";
54800c943a5SGuillaume Chatelet   Stream << "using llvm::libc_benchmarks::BzeroConfiguration;\n";
54900c943a5SGuillaume Chatelet   Stream << "using llvm::libc_benchmarks::MemcmpOrBcmpConfiguration;\n";
55000c943a5SGuillaume Chatelet   Stream << "using llvm::libc_benchmarks::MemcpyConfiguration;\n";
551de21f346SGuillaume Chatelet   Stream << "using llvm::libc_benchmarks::MemmoveConfiguration;\n";
55200c943a5SGuillaume Chatelet   Stream << "using llvm::libc_benchmarks::MemsetConfiguration;\n";
55300c943a5SGuillaume Chatelet   Stream << "\n";
55400c943a5SGuillaume Chatelet   Stream << "namespace __llvm_libc {\n";
55500c943a5SGuillaume Chatelet   Stream << "\n";
55600c943a5SGuillaume Chatelet   codegen::functions::Serialize(Stream, Descriptors);
55700c943a5SGuillaume Chatelet   Stream << "\n";
55800c943a5SGuillaume Chatelet   Stream << "} // namespace __llvm_libc\n";
55900c943a5SGuillaume Chatelet   Stream << "\n";
56000c943a5SGuillaume Chatelet   Stream << "namespace llvm {\n";
56100c943a5SGuillaume Chatelet   Stream << "namespace automemcpy {\n";
56200c943a5SGuillaume Chatelet   Stream << "\n";
56300c943a5SGuillaume Chatelet   codegen::descriptors::Serialize(Stream, Descriptors);
56400c943a5SGuillaume Chatelet   Stream << "\n";
56500c943a5SGuillaume Chatelet   Stream << "} // namespace automemcpy\n";
56600c943a5SGuillaume Chatelet   Stream << "} // namespace llvm\n";
56700c943a5SGuillaume Chatelet   Stream << "\n";
56800c943a5SGuillaume Chatelet   Stream << R"(
56900c943a5SGuillaume Chatelet using MemcpyStub = void (*)(char *__restrict, const char *__restrict, size_t);
57000c943a5SGuillaume Chatelet template <MemcpyStub Foo>
57100c943a5SGuillaume Chatelet void *Wrap(void *__restrict dst, const void *__restrict src, size_t size) {
57200c943a5SGuillaume Chatelet   Foo(reinterpret_cast<char *__restrict>(dst),
57300c943a5SGuillaume Chatelet       reinterpret_cast<const char *__restrict>(src), size);
57400c943a5SGuillaume Chatelet   return dst;
57500c943a5SGuillaume Chatelet }
57600c943a5SGuillaume Chatelet )";
57700c943a5SGuillaume Chatelet   codegen::configurations::Serialize(Stream, FunctionType::MEMCPY, Descriptors);
57800c943a5SGuillaume Chatelet   Stream << R"(
57900c943a5SGuillaume Chatelet using MemcmpStub = int (*)(const char *, const char *, size_t);
58000c943a5SGuillaume Chatelet template <MemcmpStub Foo>
58100c943a5SGuillaume Chatelet int Wrap(const void *lhs, const void *rhs, size_t size) {
58200c943a5SGuillaume Chatelet   return Foo(reinterpret_cast<const char *>(lhs),
58300c943a5SGuillaume Chatelet              reinterpret_cast<const char *>(rhs), size);
58400c943a5SGuillaume Chatelet }
58500c943a5SGuillaume Chatelet )";
58600c943a5SGuillaume Chatelet   codegen::configurations::Serialize(Stream, FunctionType::MEMCMP, Descriptors);
58700c943a5SGuillaume Chatelet   codegen::configurations::Serialize(Stream, FunctionType::BCMP, Descriptors);
58800c943a5SGuillaume Chatelet   Stream << R"(
58900c943a5SGuillaume Chatelet using MemsetStub = void (*)(char *, int, size_t);
59000c943a5SGuillaume Chatelet template <MemsetStub Foo> void *Wrap(void *dst, int value, size_t size) {
59100c943a5SGuillaume Chatelet   Foo(reinterpret_cast<char *>(dst), value, size);
59200c943a5SGuillaume Chatelet   return dst;
59300c943a5SGuillaume Chatelet }
59400c943a5SGuillaume Chatelet )";
59500c943a5SGuillaume Chatelet   codegen::configurations::Serialize(Stream, FunctionType::MEMSET, Descriptors);
59600c943a5SGuillaume Chatelet   Stream << R"(
59700c943a5SGuillaume Chatelet using BzeroStub = void (*)(char *, size_t);
59800c943a5SGuillaume Chatelet template <BzeroStub Foo> void Wrap(void *dst, size_t size) {
59900c943a5SGuillaume Chatelet   Foo(reinterpret_cast<char *>(dst), size);
60000c943a5SGuillaume Chatelet }
60100c943a5SGuillaume Chatelet )";
60200c943a5SGuillaume Chatelet   codegen::configurations::Serialize(Stream, FunctionType::BZERO, Descriptors);
603de21f346SGuillaume Chatelet   Stream << R"(
604de21f346SGuillaume Chatelet llvm::ArrayRef<MemmoveConfiguration> getMemmoveConfigurations() {
605de21f346SGuillaume Chatelet   return {};
606de21f346SGuillaume Chatelet }
607de21f346SGuillaume Chatelet )";
60800c943a5SGuillaume Chatelet   Stream << "// Functions : " << Descriptors.size() << "\n";
60900c943a5SGuillaume Chatelet }
61000c943a5SGuillaume Chatelet 
61100c943a5SGuillaume Chatelet } // namespace codegen
61200c943a5SGuillaume Chatelet 
61300c943a5SGuillaume Chatelet // Stores `VolatileStr` into a cache and returns a StringRef of the cached
61400c943a5SGuillaume Chatelet // version.
getInternalizedString(std::string VolatileStr)61500c943a5SGuillaume Chatelet StringRef getInternalizedString(std::string VolatileStr) {
616*48e0e6ceSGuillaume Chatelet   static llvm::StringSet StringCache;
61700c943a5SGuillaume Chatelet   return StringCache.insert(std::move(VolatileStr)).first->getKey();
61800c943a5SGuillaume Chatelet }
61900c943a5SGuillaume Chatelet 
getString(FunctionType FT)62000c943a5SGuillaume Chatelet static StringRef getString(FunctionType FT) {
62100c943a5SGuillaume Chatelet   switch (FT) {
62200c943a5SGuillaume Chatelet   case FunctionType::MEMCPY:
62300c943a5SGuillaume Chatelet     return "memcpy";
62400c943a5SGuillaume Chatelet   case FunctionType::MEMCMP:
62500c943a5SGuillaume Chatelet     return "memcmp";
62600c943a5SGuillaume Chatelet   case FunctionType::BCMP:
62700c943a5SGuillaume Chatelet     return "bcmp";
62800c943a5SGuillaume Chatelet   case FunctionType::MEMSET:
62900c943a5SGuillaume Chatelet     return "memset";
63000c943a5SGuillaume Chatelet   case FunctionType::BZERO:
63100c943a5SGuillaume Chatelet     return "bzero";
63200c943a5SGuillaume Chatelet   }
63300c943a5SGuillaume Chatelet }
63400c943a5SGuillaume Chatelet 
Serialize(raw_ostream & Stream,ArrayRef<FunctionDescriptor> Descriptors)63500c943a5SGuillaume Chatelet void Serialize(raw_ostream &Stream, ArrayRef<FunctionDescriptor> Descriptors) {
63600c943a5SGuillaume Chatelet   std::vector<NamedFunctionDescriptor> FunctionDescriptors;
63700c943a5SGuillaume Chatelet   FunctionDescriptors.reserve(Descriptors.size());
63800c943a5SGuillaume Chatelet   for (auto &FD : Descriptors) {
63900c943a5SGuillaume Chatelet     FunctionDescriptors.emplace_back();
64000c943a5SGuillaume Chatelet     FunctionDescriptors.back().Name = getInternalizedString(
64100c943a5SGuillaume Chatelet         formatv("{0}_{1:X16}", getString(FD.Type), FD.id()));
64200c943a5SGuillaume Chatelet     FunctionDescriptors.back().Desc = std::move(FD);
64300c943a5SGuillaume Chatelet   }
64400c943a5SGuillaume Chatelet   // Sort functions so they are easier to spot in the generated C++ file.
64500c943a5SGuillaume Chatelet   std::sort(FunctionDescriptors.begin(), FunctionDescriptors.end(),
64600c943a5SGuillaume Chatelet             [](const NamedFunctionDescriptor &A,
64700c943a5SGuillaume Chatelet                const NamedFunctionDescriptor &B) { return A.Desc < B.Desc; });
64800c943a5SGuillaume Chatelet   codegen::Serialize(Stream, FunctionDescriptors);
64900c943a5SGuillaume Chatelet }
65000c943a5SGuillaume Chatelet 
65100c943a5SGuillaume Chatelet } // namespace automemcpy
65200c943a5SGuillaume Chatelet } // namespace llvm
653