• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #ifndef COMPILER_OPTIMIZER_CODEGEN_TARGET_ASM_PRINTER_H
17 #define COMPILER_OPTIMIZER_CODEGEN_TARGET_ASM_PRINTER_H
18 
19 #include "encode.h"
20 #include "compiler/optimizer/code_generator/callconv.h"
21 #include "registers_description.h"
22 
23 #ifdef PANDA_COMPILER_TARGET_AARCH32
24 #include "aarch32/target.h"
25 #endif
26 
27 #ifdef PANDA_COMPILER_TARGET_AARCH64
28 #include "aarch64/target.h"
29 #endif
30 
31 #ifdef PANDA_COMPILER_TARGET_X86_64
32 #include "amd64/target.h"
33 #else
34 namespace amd64 {
35 class [[maybe_unused]] Amd64Encoder;
36 }  // namespace amd64
37 #endif
38 
39 #include <iostream>
40 #include <string>
41 
42 namespace ark::compiler {
43 
44 template <class T>
45 class PrinterLabelHolder final : public LabelHolder {
46 public:
47     using LabelType = std::string;
PrinterLabelHolder(Encoder * enc)48     explicit PrinterLabelHolder(Encoder *enc) : LabelHolder(enc), labels_(enc->GetAllocator()->Adapter()) {};
49 
50     NO_MOVE_SEMANTIC(PrinterLabelHolder);
51     NO_COPY_SEMANTIC(PrinterLabelHolder);
52     ~PrinterLabelHolder() override = default;
53 
CreateLabel()54     LabelId CreateLabel() override
55     {
56         // Create unnammed label
57         ++id_;
58         auto label = LabelType(std::to_string(id_ - 1));
59         labels_[id_ - 1] = label;
60         ASSERT(labels_.size() == id_);
61         return id_ - 1;
62     }
63 
CreateLabel(const LabelType & str)64     LabelId CreateLabel(const LabelType &str)
65     {
66         // Create nammed label
67         ++id_;
68         labels_[id_ - 1] = str;
69         ASSERT(labels_.size() == id_);
70         return id_ - 1;
71     }
72 
CreateLabels(LabelId size)73     void CreateLabels(LabelId size) override
74     {
75         for (LabelId i = 0; i <= size; ++i) {
76             CreateLabel();
77         }
78     }
79 
80     void BindLabel(LabelId id) override;
81 
GetLabel(LabelId id)82     LabelType *GetLabel(LabelId id)
83     {
84         ASSERT(labels_.size() > id);
85         return &labels_[id];
86     }
87 
Size()88     LabelId Size() override
89     {
90         return labels_.size();
91     }
92 
93 private:
94     ArenaMap<LabelId, LabelType> labels_;
95     LabelId id_ {0};
96     friend T;
97 };  // Aarch32LabelHolder
98 
99 template <class T>
100 class AssemblyPrinter final : public Encoder {
101     // Do not inherited from T, because need save `final` on them
102 public:
103     explicit AssemblyPrinter(ArenaAllocator *aa, T *enc);
104 
~AssemblyPrinter()105     ~AssemblyPrinter() override
106     {
107         enc_->~Encoder();
108     }
109 
110     NO_COPY_SEMANTIC(AssemblyPrinter);
111     NO_MOVE_SEMANTIC(AssemblyPrinter);
112 
InitMasm()113     bool InitMasm() override
114     {
115         return enc_->InitMasm();
116     }
117 
118     // DUMMY
Finalize()119     void Finalize() override
120     {
121         enc_->Finalize();
122     }
123 
SetStream(std::ostream * str)124     void SetStream(std::ostream *str)
125     {
126         str_ = str;
127     }
128 
GetStream()129     std::ostream *GetStream()
130     {
131         return str_;
132     }
133 
GetResult()134     bool GetResult() const override
135     {
136         return Encoder::GetResult() && enc_->GetResult();
137     }
138 
EmitFunctionName(const void * funcName)139     void EmitFunctionName(const void *funcName)
140     {
141         auto *name = reinterpret_cast<const char *>(funcName);
142         *str_ << ".global " << name << std::endl;
143         *str_ << ".type " << name << ", %function" << std::endl;
144         *str_ << name << ":" << std::endl;
145     }
146 
GetLabels()147     LabelHolder *GetLabels() const override
148     {
149         return labels_;
150     };
151 
GetLabelAddress(LabelHolder::LabelId label)152     size_t GetLabelAddress(LabelHolder::LabelId label) override
153     {
154         return enc_->GetLabelAddress(label);
155     }
156 
LabelHasLinks(LabelHolder::LabelId label)157     bool LabelHasLinks(LabelHolder::LabelId label) override
158     {
159         return enc_->LabelHasLinks(label);
160     }
161 
162     // Next interfaces used for create wrappers
163 
GetEncoder()164     T *GetEncoder()
165     {
166         return reinterpret_cast<T *>(enc_);
167     }
168 
GetCursorOffset()169     size_t GetCursorOffset() const override
170     {
171         return enc_->GetCursorOffset();
172     }
173 
PreWork()174     void PreWork() {}
175 
PostWork()176     void PostWork() {}
177 
Disasm(size_t from,size_t to)178     void Disasm(size_t from, size_t to)
179     {
180         for (uint32_t i = from; i < to;) {
181             auto tmp = i;
182             i = enc_->DisasmInstr(*str_, i, -1);
183             if (i == tmp) {
184                 enc_->SetFalseResult();
185                 return;
186             }
187             *str_ << std::endl;
188         }
189     }
190 
191 // Define default math operations
192 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
193 #define UNARY_OPERATION(opc)                    \
194     void Encode##opc(Reg dst, Reg src) override \
195     {                                           \
196         ASSERT(str_ != nullptr);                \
197         auto curr_cursor = GetCursorOffset();   \
198         PreWork();                              \
199         enc_->Encode##opc(dst, src);            \
200         PostWork();                             \
201         Disasm(curr_cursor, GetCursorOffset()); \
202     }
203 
204 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
205 #define BINARY_OPERATION(opc)                              \
206     void Encode##opc(Reg dst, Reg src0, Reg src1) override \
207     {                                                      \
208         ASSERT(str_ != nullptr);                           \
209         auto curr_cursor = enc_->GetCursorOffset();        \
210         PreWork();                                         \
211         enc_->Encode##opc(dst, src0, src1);                \
212         PostWork();                                        \
213         Disasm(curr_cursor, enc_->GetCursorOffset());      \
214     }
215 
216 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
217 #define BINARY_SHIFTED_REGISTER_OPERATION(opc)            \
218     void Encode##opc(Reg dst, Reg src, Shift sh) override \
219     {                                                     \
220         ASSERT(str_ != nullptr);                          \
221         auto curr_cursor = enc_->GetCursorOffset();       \
222         PreWork();                                        \
223         enc_->Encode##opc(dst, src, sh);                  \
224         PostWork();                                       \
225         Disasm(curr_cursor, enc_->GetCursorOffset());     \
226     }
227 
228 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
229 #define INST_DEF(OPCODE, MACRO) MACRO(OPCODE)
230 
231     ENCODE_MATH_LIST(INST_DEF)
232     ENCODE_INST_WITH_SHIFTED_OPERAND(INST_DEF)
233 
234 #undef UNARY_OPERATION
235 #undef BINARY_OPERATION
236 #undef BINARY_SHIFTED_REGISTER_OPERATION
237 
238 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
239 #define BINARY_OPERATION(opc)                            \
240     void Encode##opc(Reg dst, Reg src, Imm imm) override \
241     {                                                    \
242         ASSERT(str_ != nullptr);                         \
243         auto curr_cursor = enc_->GetCursorOffset();      \
244         PreWork();                                       \
245         enc_->Encode##opc(dst, src, imm);                \
246         PostWork();                                      \
247         Disasm(curr_cursor, enc_->GetCursorOffset());    \
248     }
249 
250     ENCODE_MATH_BINARY_OP_LIST(INST_DEF)
251 
252 #undef BINARY_OPERATION
253 #undef INST_DEF
254 
255 // Call by reg+offset or MemRef - default encode
256 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
257 #define ENCODE_INST_ADDITIONAL_ZERO_ARG(DEF) \
258     DEF(EncodeReturn)                        \
259     DEF(EncodeAbort)
260 
261 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
262 #define DEF_ZERO_PARAM_OPERATION(opc)                 \
263     void opc() override                               \
264     {                                                 \
265         ASSERT(str_ != nullptr);                      \
266         auto curr_cursor = enc_->GetCursorOffset();   \
267         PreWork();                                    \
268         enc_->opc();                                  \
269         PostWork();                                   \
270         Disasm(curr_cursor, enc_->GetCursorOffset()); \
271     }
272 
273     ENCODE_INST_ADDITIONAL_ZERO_ARG(DEF_ZERO_PARAM_OPERATION)
274 
275 // Call by reg+offset - no needed, because unusable:
276 //     * MakeCallAot(intptr_t, offset)
277 //     * MakeCallByOffset(intptr_t, offset)
278 
279 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
280 #define ENCODE_INST_ADDITIONAL_ONE_ARG(DEF) DEF(MakeCall, MemRef, entryPoint)
281 
282 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
283 #define DEF_ONE_PARAM_OPERATION(opc, type, param)     \
284     void opc(type param) override                     \
285     {                                                 \
286         ASSERT(str_ != nullptr);                      \
287         auto curr_cursor = enc_->GetCursorOffset();   \
288         PreWork();                                    \
289         enc_->opc(param);                             \
290         PostWork();                                   \
291         Disasm(curr_cursor, enc_->GetCursorOffset()); \
292     }
293 
294     ENCODE_INST_ADDITIONAL_ONE_ARG(DEF_ONE_PARAM_OPERATION)
295 
296     // Aot Table - unusable:
297     //   * MakeLoadAotTable(intptr_t, offset, Reg, reg)
298 
299 #undef ENCODE_INST_ADDITIONAL_ZERO_ARG
300 #undef DEF_ZERO_PARAM_OPERATION
301 #undef ENCODE_INST_ADDITIONAL_ONE_ARG
302 #undef DEF_ONE_PARAM_OPERATION
303 
304     // Special cases - call read from
305     void MakeCall(const void *entryPoint) override;
306 
307 private:
308     Encoder *enc_;
309     std::ostream *str_ {nullptr};
310     LabelHolder *labels_ {nullptr};
311 };
312 
313 // T - CallConv-origin class
314 // E - Encoder-printer class
315 template <class T, class E>
316 class PrinterCallingConvention : public T {
317     // CallingConvention call virtual methods inside (example - Begin call GeneratePrologue)
318     // That's why not all methods must be rewrited
319 
320 public:
PrinterCallingConvention(ArenaAllocator * allocator,E * enc,RegistersDescription * descr,CallConvMode mode)321     PrinterCallingConvention(ArenaAllocator *allocator, E *enc, RegistersDescription *descr, CallConvMode mode)
322         : T(allocator, enc->GetEncoder(), descr, mode), printer_(enc) {};
323 
324     NO_MOVE_SEMANTIC(PrinterCallingConvention);
325     NO_COPY_SEMANTIC(PrinterCallingConvention);
326 
327     ~PrinterCallingConvention() override = default;
328 
GetEncoder()329     Encoder *GetEncoder() const
330     {
331         return CallingConvention::GetEncoder();
332     }
333 
PreWork()334     void PreWork()
335     {
336         cursor_ = printer_->GetCursorOffset();
337         printer_->PreWork();
338     }
339 
PostWork()340     void PostWork()
341     {
342         printer_->PostWork();
343         size_t endCursor = printer_->GetCursorOffset();
344         if (endCursor == cursor_) {
345             return;
346         }
347         printer_->Disasm(cursor_, endCursor);
348     }
349 
GeneratePrologue(const FrameInfo & frameInfo)350     void GeneratePrologue(const FrameInfo &frameInfo) override
351     {
352         PreWork();
353         T::GeneratePrologue(frameInfo);
354         PostWork();
355     }
GenerateEpilogue(const FrameInfo & frameInfo,std::function<void ()> postJob)356     void GenerateEpilogue(const FrameInfo &frameInfo, std::function<void()> postJob) override
357     {
358         PreWork();
359         T::GenerateEpilogue(frameInfo, postJob);
360         PostWork();
361     }
362 
363     // Copy register to return register
364     // Interfaces after finalize code
GetCodeEntry()365     void *GetCodeEntry() override
366     {
367         PreWork();
368         auto tmp = T::GetCodeEntry();
369         PostWork();
370         return tmp;
371     }
372     // Get return register
GetCodeSize()373     uint32_t GetCodeSize() override
374     {
375         PreWork();
376         auto tmp = T::GetCodeSize();
377         PostWork();
378         return tmp;
379     }
380     // Calculating information about parameters and save regs_offset registers for special needs
GetParameterInfo(uint8_t regsOffset)381     ParameterInfo *GetParameterInfo(uint8_t regsOffset) override
382     {
383         PreWork();
384         auto tmp = T::GetParameterInfo(regsOffset);
385         PostWork();
386         return tmp;
387     }
388 
389 private:
390     E *printer_;
391     size_t cursor_ {0};
392 };
393 
394 #ifdef PANDA_COMPILER_TARGET_AARCH32
395 namespace aarch32 {
396 using Aarch32Assembly = AssemblyPrinter<Aarch32Encoder>;
397 using Aarch32AssemblyLabelHolder = PrinterLabelHolder<Aarch32Encoder>;
398 }  // namespace aarch32
399 #endif
400 
401 #ifdef PANDA_COMPILER_TARGET_AARCH64
402 namespace aarch64 {
403 using Aarch64Assembly = AssemblyPrinter<Aarch64Encoder>;
404 using Aarch64AssemblyLabelHolder = PrinterLabelHolder<Aarch64Encoder>;
405 }  // namespace aarch64
406 #endif
407 
408 #ifdef PANDA_COMPILER_TARGET_X86_64
409 namespace amd64 {
410 using Amd64Assembly = AssemblyPrinter<Amd64Encoder>;
411 using Amd64AssemblyLabelHolder = PrinterLabelHolder<Amd64Encoder>;
412 }  // namespace amd64
413 #endif
414 
415 }  // namespace ark::compiler
416 
417 #endif  // COMPILER_OPTIMIZER_CODEGEN_TARGET_ASM_PRINTER_H
418