1 /**
2 * Copyright 2021 Huawei Technologies Co., Ltd
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #ifndef MINDSPORE_LITE_MICRO_CODER_OPCODERS_SERIALIZERS_SERIALIZER_H_
18 #define MINDSPORE_LITE_MICRO_CODER_OPCODERS_SERIALIZERS_SERIALIZER_H_
19
20 #include <vector>
21 #include <string>
22 #include <sstream>
23 #include "coder/allocator/allocator.h"
24 #include "coder/opcoders/serializers/nnacl_serializer/nnacl_stream_utils.h"
25
26 namespace mindspore::lite::micro {
27
28 /*
29 * convert array T[] to string
30 * std::ostream &operator<<(std::ostream &, const ::T &) must exist
31 * arr shouldn't be pointer, T* is not valid
32 * example:
33 * int arr[] = {1, 2, 3};
34 * ToString(arr);
35 * the code above would produce:
36 * "{1, 2, 3}"
37 */
38 template <typename T, unsigned int N>
ToString(const T (& arr)[N])39 std::string ToString(const T (&arr)[N]) {
40 std::stringstream code;
41 int n = N;
42 while (n > 0 && arr[n - 1] == 0) {
43 n--;
44 }
45 code << "{";
46 for (int i = 0; i < n - 1; ++i) {
47 code << arr[i] << ", ";
48 }
49 if (n > 0) {
50 code << arr[n - 1];
51 }
52 code << "}";
53 return code.str();
54 }
55
56 class Serializer {
57 public:
58 Serializer() = default;
59 virtual ~Serializer() = default;
60
61 /*
62 * Code function call to generated code
63 * First parameter is the function name, the rest are the parameters of the function
64 * example:
65 * CodeFunction("function", "foo", "bar", "foobar", 42);
66 * the code above would produce:
67 * "function("foo", "bar", "foobar", 42);\n"
68 */
69 template <typename... PARAMETERS>
CodeFunction(const std::string & name,PARAMETERS...parameters)70 void CodeFunction(const std::string &name, PARAMETERS... parameters) {
71 code << name << "(";
72 GenCode(parameters...);
73 code << ");\n";
74 }
75
76 /*
77 * Code function call to generated code, with checking the return code
78 * First parameter is the function name, the rest are the parameters of the function
79 * example:
80 * CodeFunctionWithCheck("function", "foo", "bar", "foobar", 42);
81 * the code above would produce:
82 * """
83 * if(function("foo", "bar", "foobar", 42) != 0) {\n
84 * return -1;
85 * }
86 * """
87 */
88 template <typename... PARAMETERS>
CodeFunctionWithCheck(const std::string & name,PARAMETERS...parameters)89 void CodeFunctionWithCheck(const std::string &name, PARAMETERS... parameters) {
90 code << "if(" << name << "(";
91 GenCode(parameters...);
92 code << ") != RET_OK) {\n";
93 code << " return RET_ERROR;\n";
94 code << "}\n";
95 }
96
97 /*
98 * helper function for coding
99 * example:
100 * int bar[] = {1 ,3, 2};
101 * CodeArray("bar", bar, 3);
102 * the code above would produce:
103 * "int bar[3] = {1 ,3, 2};\n"
104 */
105 template <typename T>
106 void CodeArray(const std::string &name, T *data, int length, bool is_const = true) {
107 std::string type = GetVariableTypeName<T>();
108 if (is_const) {
109 code << "const " << type << " " << name << "[" << length << "] = {";
110 } else {
111 code << type << " " << name << "[" << length << "] = {";
112 }
113 for (int i = 0; i < length - 1; ++i) {
114 code << data[i] << ", ";
115 }
116 if (length > 0) {
117 code << data[length - 1];
118 }
119 code << "};\n";
120 }
121
122 template <typename T>
CodeMallocExpression(T t,size_t size)123 void CodeMallocExpression(T t, size_t size) {
124 if (size == 0) {
125 MS_LOG(ERROR) << "CodeMallocExpression size is zero";
126 exit(1);
127 }
128 GenCode(t);
129 code << " = malloc(" << size << ");\n";
130 code << "if (";
131 GenCode(t);
132 code << " == NULL) {\n";
133 code << " return RET_ERROR;\n";
134 code << "}\n";
135 }
136
precision(std::streamsize size)137 std::streamsize precision(std::streamsize size) {
138 std::streamsize old = code.precision(size);
139 return old;
140 }
141
str()142 std::string str() const { return code.str(); }
143
144 template <typename T>
145 Serializer &operator<<(T t) {
146 code << t;
147 return *this;
148 }
149
150 /*
151 * helper function for CodeStruct
152 * all parameters should be
153 * example:
154 * given:
155 * typedef struct Foo {
156 * int array[5];
157 * int *pointer;
158 * int count;
159 * } Foo;
160 * int pointer[] = {1 ,3, 2, 42};
161 * Foo foo = {{1, 2, 3}, pointer, 4};
162 * the CodeStruct should be written as:
163 * CodeStruct(const string &name, const Foo &foo) {
164 * CodeArray("pointer_gen", foo.pointer, foo.count);
165 * CodeBaseStruct("Foo", "foo_gen", ToString(foo.array), "pointer_gen", foo.count);
166 * }
167 * the code above would produce:
168 * "int pointer_gen[4] = {1 ,3, 2, 42};\n
169 * const Foo foo_gen = {{1, 2, 3}, pointer_gen, 4};\n"
170 */
171 template <bool immutable = true, typename... PARAMETERS>
CodeBaseStruct(const std::string & type,const std::string & name,PARAMETERS...parameters)172 void CodeBaseStruct(const std::string &type, const std::string &name, PARAMETERS... parameters) {
173 if constexpr (immutable) {
174 code << "const " << type << " " << name << " = {";
175 } else {
176 code << type << " " << name << " = {";
177 }
178 GenCode(parameters...);
179 code << "};\n";
180 }
181
182 protected:
183 std::ostringstream code;
184
185 private:
186 /*
187 * function GenCode(Args... args)
188 * Convert all parameters to string, and join connect them with comma ", "
189 * example:
190 * GenCode(true, false, static_cast<int8_t>(12), static_cast<uint8_t>(57), 'c', 5567);
191 * the code above would produce:
192 * "true, false, 12, 57, c, 5567"
193 */
194 template <typename T, typename... REST>
GenCode(T t,REST...args)195 void GenCode(T t, REST... args) {
196 GenCode(t);
197 code << ", ";
198 GenCode(args...);
199 }
200 template <typename T>
GenCode(T t)201 void GenCode(T t) {
202 code << t;
203 }
204
205 /*
206 * Convert pointer to string when it's in MemoryAllocator (and it should be)
207 * if t is not in the table of MemoryAllocator, it would return empty string ""
208 * then the coder would generate something like
209 * {foo, , bar}
210 * and make the generated code
211 * not compilable rather than generating code like
212 * {foo, 0x7ffed0cd377c, bar}
213 * which would bring the hard coded address to the runtime and make it harder to debug
214 *
215 * if t is nullptr, "NULL" would be coded to generated code because some pointer might
216 * be nullptr in some cases and we want to code it.
217 * In this function, passing nullptr **would not** be regarded as a bug or mistake
218 */
219 template <typename T>
GenCode(T * t)220 void GenCode(T *t) {
221 if (t == nullptr) {
222 code << "NULL";
223 } else {
224 std::string name = MemoryAllocator::GetInstance()->GetRuntimeAddr(t, true);
225 if (name.empty()) {
226 MS_LOG(ERROR) << "pointer is not allocated by the allocator";
227 exit(1);
228 }
229 code << name;
230 }
231 }
232
233 // std::boolalpha converts bool to string literals {"true", "false"} instead of {1, 0}
GenCode(bool t)234 void GenCode(bool t) { code << std::boolalpha << t; }
GenCode(int8_t t)235 void GenCode(int8_t t) { code << std::to_string(t); }
GenCode(uint8_t t)236 void GenCode(uint8_t t) { code << std::to_string(t); }
GenCode(decltype (nullptr)t)237 void GenCode(decltype(nullptr) t) { code << "NULL"; }
GenCode(const char * t)238 void GenCode(const char *t) { code << t; }
GenCode(LiteDataType t)239 void GenCode(LiteDataType t) { code << "(LiteDataType)" << t; }
240 };
241 } // namespace mindspore::lite::micro
242 #endif // MINDSPORE_LITE_MICRO_CODER_SERIALIZERS_SERIALIZER_H_
243