• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2022 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 panda::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 * func_name)139     void EmitFunctionName(const void *func_name)
140     {
141         auto *name = reinterpret_cast<const char *>(func_name);
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 UnaryOperation(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         auto encoded_curr_cursor = GetCursorOffset(); \
202         Disasm(curr_cursor, encoded_curr_cursor);     \
203     }
204 
205 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
206 #define BinaryOperation(opc)                                \
207     void Encode##opc(Reg dst, Reg src0, Reg src1) override  \
208     {                                                       \
209         ASSERT(str_ != nullptr);                            \
210         auto curr_cursor = enc_->GetCursorOffset();         \
211         PreWork();                                          \
212         enc_->Encode##opc(dst, src0, src1);                 \
213         PostWork();                                         \
214         auto encoded_curr_cursor = enc_->GetCursorOffset(); \
215         Disasm(curr_cursor, encoded_curr_cursor);           \
216     }                                                       \
217     void Encode##opc(Reg dst, Reg src, Imm imm) override    \
218     {                                                       \
219         ASSERT(str_ != nullptr);                            \
220         auto curr_cursor = enc_->GetCursorOffset();         \
221         PreWork();                                          \
222         enc_->Encode##opc(dst, src, imm);                   \
223         PostWork();                                         \
224         auto encoded_curr_cursor = enc_->GetCursorOffset(); \
225         Disasm(curr_cursor, encoded_curr_cursor);           \
226     }
227 
228 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
229 #define BinaryShiftedRegisterOperation(opc)                 \
230     void Encode##opc(Reg dst, Reg src, Shift sh) override   \
231     {                                                       \
232         ASSERT(str_ != nullptr);                            \
233         auto curr_cursor = enc_->GetCursorOffset();         \
234         PreWork();                                          \
235         enc_->Encode##opc(dst, src, sh);                    \
236         PostWork();                                         \
237         auto encoded_curr_cursor = enc_->GetCursorOffset(); \
238         Disasm(curr_cursor, encoded_curr_cursor);           \
239     }
240 
241 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
242 #define INST_DEF(OPCODE, TYPE) TYPE(OPCODE)
243 
244     ENCODE_MATH_LIST(INST_DEF)
245 
246     ENCODE_INST_WITH_SHIFTED_OPERAND(INST_DEF)
247 
248 #undef UnaryOperation
249 #undef BinaryOperation
250 #undef BinaryShiftedRegisterOperation
251 #undef INST_DEF
252 
253 // Call by reg+offset or MemRef - default encode
254 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
255 #define ENCODE_INST_ADDITIONAL_ZERO_ARG(DEF) \
256     DEF(EncodeReturn)                        \
257     DEF(EncodeAbort)
258 
259 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
260 #define DefZeroParamOperation(opc)                          \
261     void opc() override                                     \
262     {                                                       \
263         ASSERT(str_ != nullptr);                            \
264         auto curr_cursor = enc_->GetCursorOffset();         \
265         PreWork();                                          \
266         enc_->opc();                                        \
267         PostWork();                                         \
268         auto encoded_curr_cursor = enc_->GetCursorOffset(); \
269         Disasm(curr_cursor, encoded_curr_cursor);           \
270     }
271 
272     ENCODE_INST_ADDITIONAL_ZERO_ARG(DefZeroParamOperation)
273 
274 // Call by reg+offset - no needed, because unusable:
275 //     * MakeCallAot(intptr_t, offset)
276 //     * MakeCallByOffset(intptr_t, offset)
277 
278 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
279 #define ENCODE_INST_ADDITIONAL_ONE_ARG(DEF) DEF(MakeCall, MemRef, entry_point)
280 
281 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
282 #define DefOneParamOperation(opc, type, param)              \
283     void opc(type param) override                           \
284     {                                                       \
285         ASSERT(str_ != nullptr);                            \
286         auto curr_cursor = enc_->GetCursorOffset();         \
287         PreWork();                                          \
288         enc_->opc(param);                                   \
289         PostWork();                                         \
290         auto encoded_curr_cursor = enc_->GetCursorOffset(); \
291         Disasm(curr_cursor, encoded_curr_cursor);           \
292     }
293 
294     ENCODE_INST_ADDITIONAL_ONE_ARG(DefOneParamOperation)
295 
296     // Aot Table - unusable:
297     //   * MakeLoadAotTable(intptr_t, offset, Reg, reg)
298 
299 #undef ENCODE_INST_ADDITIONAL_ZERO_ARG
300 #undef DefZeroParamOperation
301 #undef ENCODE_INST_ADDITIONAL_ONE_ARG
302 #undef DefOneParamOperation
303 
304     // Special cases - call read from
305     void MakeCall(const void *entry_point) 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 end_cursor = printer_->GetCursorOffset();
344         if (end_cursor == cursor_) {
345             return;
346         }
347         printer_->Disasm(cursor_, end_cursor);
348     }
349 
GeneratePrologue(const FrameInfo & frame_info)350     void GeneratePrologue(const FrameInfo &frame_info) override
351     {
352         PreWork();
353         T::GeneratePrologue(frame_info);
354         PostWork();
355     }
GenerateEpilogue(const FrameInfo & frame_info,std::function<void ()> post_job)356     void GenerateEpilogue(const FrameInfo &frame_info, std::function<void()> post_job) override
357     {
358         PreWork();
359         T::GenerateEpilogue(frame_info, post_job);
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 regs_offset)381     ParameterInfo *GetParameterInfo(uint8_t regs_offset) override
382     {
383         PreWork();
384         auto tmp = T::GetParameterInfo(regs_offset);
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 panda::compiler
416 
417 #endif  // COMPILER_OPTIMIZER_CODEGEN_TARGET_ASM_PRINTER_H
418