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