1 /* 2 * Copyright (c) 2021-2025 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 PANDA_INST_BUILDER_H 17 #define PANDA_INST_BUILDER_H 18 19 #include "compiler_options.h" 20 #include "optimizer/ir/graph.h" 21 #include "optimizer/ir/basicblock.h" 22 #include "optimizer/analysis/loop_analyzer.h" 23 #include "code_info/vreg_info.h" 24 #include "code_data_accessor.h" 25 #include "file_items.h" 26 #include "compiler_logger.h" 27 28 #include "bytecode_instruction.h" 29 30 namespace ark::compiler { 31 constexpr int64_t INVALID_OFFSET = std::numeric_limits<int64_t>::max(); 32 33 class InstBuilder { 34 public: 35 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 36 #define ENV_IDX(ENV_TYPE) /* CC-OFFNXT(G.PRE.02, G.PRE.09) namespace member, code generation */ \ 37 static constexpr uint8_t ENV_TYPE##_IDX = VRegInfo::VRegType::ENV_TYPE - VRegInfo::VRegType::ENV_BEGIN; 38 VREGS_ENV_TYPE_DEFS(ENV_IDX) 39 #undef ENV_IDX 40 41 InstBuilder(Graph *graph, RuntimeInterface::MethodPtr method, CallInst *callerInst, uint32_t inliningDepth); 42 43 NO_COPY_SEMANTIC(InstBuilder); 44 NO_MOVE_SEMANTIC(InstBuilder); ~InstBuilder()45 ~InstBuilder() 46 { 47 GetGraph()->EraseMarker(noTypeMarker_); 48 GetGraph()->EraseMarker(visitedBlockMarker_); 49 } 50 51 /** 52 * Content of this function is auto generated from inst_builder.erb and is located in inst_builder_gen.cpp file 53 * @param instruction Pointer to bytecode instruction 54 */ 55 void BuildInstruction(const BytecodeInstruction *instruction); 56 57 void InitEnv(BasicBlock *bb); 58 IsFailed()59 bool IsFailed() const 60 { 61 return failed_; 62 } 63 64 /// Return jump offset for instruction `inst`, 0 if it is not jump instruction. 65 static int64_t GetInstructionJumpOffset(const BytecodeInstruction *inst); 66 67 void SetCurrentBlock(BasicBlock *bb); 68 GetCurrentBlock()69 BasicBlock *GetCurrentBlock() const 70 { 71 return currentBb_; 72 } 73 74 void Prepare(bool isInlinedGraph); 75 76 void FixType(PhiInst *inst, BasicBlock *bb); 77 void FixType(Inst *inst); 78 void FixInstructions(); 79 void ResolveConstants(); 80 void SplitConstant(ConstantInst *constInst); 81 82 static void RemoveNotDominateInputs(SaveStateInst *saveState); 83 84 size_t GetPc(const uint8_t *instPtr) const; 85 CreateSafePoint(BasicBlock * bb)86 auto CreateSafePoint(BasicBlock *bb) 87 { 88 #ifndef NDEBUG 89 ResetSafepointDistance(); 90 #endif 91 return CreateSaveState(Opcode::SafePoint, bb->GetGuestPc()); 92 } 93 CreateSaveStateOsr(BasicBlock * bb)94 auto CreateSaveStateOsr(BasicBlock *bb) 95 { 96 return CreateSaveState(Opcode::SaveStateOsr, bb->GetGuestPc()); 97 } 98 CreateSaveStateDeoptimize(uint32_t pc)99 auto CreateSaveStateDeoptimize(uint32_t pc) 100 { 101 return CreateSaveState(Opcode::SaveStateDeoptimize, pc); 102 } 103 104 void UpdateDefs(); 105 bool UpdateDefsForPreds(size_t vreg, std::optional<Inst *> &value); 106 GetCurrentDefs()107 const auto &GetCurrentDefs() 108 { 109 ASSERT(currentDefs_ != nullptr); 110 return *currentDefs_; 111 } 112 IsInBootContext()113 bool IsInBootContext() 114 { 115 auto method = static_cast<ark::Method *>(GetGraph()->GetMethod()); 116 return method->GetClass()->GetLoadContext()->IsBootContext(); 117 } 118 119 void AddCatchPhiInputs(const ArenaUnorderedSet<BasicBlock *> &catchHandlers, const InstVector &defs, 120 Inst *throwableInst); 121 122 SaveStateInst *CreateSaveState(Opcode opc, size_t pc); 123 124 static void SetParamSpillFill(Graph *graph, ParameterInst *paramInst, size_t numArgs, size_t i, 125 DataType::Type type); 126 127 #ifndef NDEBUG 128 void TryInsertSafepoint(BasicBlock *bb = nullptr, bool insertSP = false) 129 { 130 auto curBb = bb != nullptr ? bb : currentBb_; 131 if (GetGraph()->IsBytecodeOptimizer() || curBb->IsOsrEntry() || 132 !g_options.IsCompilerEnforceSafepointPlacement()) { 133 return; 134 } 135 if ((curBb->GetLastInst() == nullptr || curBb->GetLastInst()->GetOpcode() != Opcode::SafePoint) && 136 (insertSP || --safepointDistance_ <= 0)) { 137 auto *sp = CreateSafePoint(curBb); 138 currentBb_->AppendInst(sp); 139 #ifdef PANDA_COMPILER_DEBUG_INFO 140 if (sp->GetPc() != INVALID_PC) { 141 sp->SetCurrentMethod(method_); 142 } 143 #endif 144 COMPILER_LOG(DEBUG, IR_BUILDER) << *sp; 145 } 146 } 147 #endif 148 149 protected: 150 template <typename T> AddInstruction(T inst)151 void AddInstruction(T inst) 152 { 153 ASSERT(currentBb_); 154 currentBb_->AppendInst(inst); 155 #ifdef PANDA_COMPILER_DEBUG_INFO 156 if (inst->GetPc() != INVALID_PC) { 157 inst->SetCurrentMethod(method_); 158 } 159 #endif 160 COMPILER_LOG(DEBUG, IR_BUILDER) << *inst; 161 } 162 163 template <typename T, typename... Ts> AddInstruction(T inst,Ts...insts)164 void AddInstruction(T inst, Ts... insts) 165 { 166 AddInstruction(inst); 167 AddInstruction(insts...); 168 } 169 170 void UpdateDefinition(size_t vreg, Inst *inst); 171 void UpdateDefinitionAcc(Inst *inst); 172 void UpdateDefinitionLexEnv(Inst *inst); 173 Inst *GetDefinition(size_t vreg); 174 Inst *GetDefinitionAcc(); 175 Inst *GetEnvDefinition(uint8_t envIdx); 176 177 void BuildCastToAnyString(const BytecodeInstruction *bcInst); 178 GetGraph()179 Graph *GetGraph() 180 { 181 return graph_; 182 } 183 GetGraph()184 const Graph *GetGraph() const 185 { 186 return graph_; 187 } 188 GetRuntime()189 const RuntimeInterface *GetRuntime() const 190 { 191 return runtime_; 192 } 193 GetRuntime()194 RuntimeInterface *GetRuntime() 195 { 196 return runtime_; 197 } 198 GetMethod()199 RuntimeInterface::MethodPtr GetMethod() const 200 { 201 return method_; 202 } 203 204 /// Get count of arguments for the method specified by id 205 size_t GetMethodArgumentsCount(uintptr_t id) const; 206 207 private: 208 void SyncWithGraph(); 209 210 void UpdateDefsForCatch(); 211 void UpdateDefsForLoopHead(); 212 GetVRegsCount()213 size_t GetVRegsCount() const 214 { 215 return vregsAndArgsCount_ + 1 + GetGraph()->GetEnvCount(); 216 } 217 SetCallNativeFlags(CallInst * callInst,RuntimeInterface::MethodPtr method)218 void SetCallNativeFlags(CallInst *callInst, RuntimeInterface::MethodPtr method) const 219 { 220 bool isNativeApi = method != nullptr && GetRuntime()->IsMethodNativeApi(method); 221 callInst->SetIsNative(isNativeApi); 222 callInst->SetCanNativeException(isNativeApi && GetRuntime()->HasNativeException(method)); 223 } 224 225 ConstantInst *FindOrCreate32BitConstant(uint32_t value); 226 ConstantInst *FindOrCreateConstant(uint64_t value); 227 ConstantInst *FindOrCreateAnyConstant(DataType::Any value); 228 ConstantInst *FindOrCreateDoubleConstant(double value); 229 ConstantInst *FindOrCreateFloatConstant(float value); 230 231 enum SaveStateType { 232 CHECK = 0, // side_exit = true, move_to_side_exit = true 233 CALL, // side_exit = false, move_to_side_exit = false 234 VIRT_CALL // side_exit = true, move_to_side_exit = false 235 }; 236 237 ClassInst *CreateLoadAndInitClassGeneric(uint32_t classId, size_t pc); 238 CreateCast(Inst * input,DataType::Type type,DataType::Type operandsType,size_t pc)239 Inst *CreateCast(Inst *input, DataType::Type type, DataType::Type operandsType, size_t pc) 240 { 241 auto cast = GetGraph()->CreateInstCast(type, pc, input, operandsType); 242 if (!input->HasType()) { 243 input->SetType(operandsType); 244 } 245 return cast; 246 } 247 CreateNewObjectInst(size_t pc,uint32_t typeId,SaveStateInst * saveState,Inst * initClass)248 NewObjectInst *CreateNewObjectInst(size_t pc, uint32_t typeId, SaveStateInst *saveState, Inst *initClass) 249 { 250 auto newObj = graph_->CreateInstNewObject(DataType::REFERENCE, pc, initClass, saveState, 251 TypeIdMixin {typeId, graph_->GetMethod()}); 252 return newObj; 253 } 254 255 template <Opcode OPCODE, bool IS_RANGE, bool ACC_READ, bool HAS_SAVE_STATE = true> 256 class BuildCallHelper { 257 public: 258 BuildCallHelper(const BytecodeInstruction *bcInst, InstBuilder *builder, Inst *additionalInput = nullptr); 259 260 bool TryBuildIntrinsic(); 261 void BuildIntrinsic(); 262 void BuildDefaultIntrinsic(RuntimeInterface::IntrinsicId intrinsicId, bool isVirtual); 263 void BuildDefaultStaticIntrinsic(RuntimeInterface::IntrinsicId intrinsicId); 264 void BuildDefaultVirtualCallIntrinsic(RuntimeInterface::IntrinsicId intrinsicId); 265 void BuildMonitorIntrinsic(bool isEnter); 266 267 void BuildStaticCallIntrinsic(RuntimeInterface::IntrinsicId intrinsicId); 268 void BuildVirtualCallIntrinsic(RuntimeInterface::IntrinsicId intrinsicId); 269 270 void AddCallInstruction(); 271 void BuildCallInst(uint32_t classId); 272 void BuildCallStaticInst(uint32_t classId); 273 void BuildInitClassInstForCallStatic(uint32_t classId); 274 275 void BuildCallVirtualInst(); 276 void SetCallArgs(Inst *additionalInput = nullptr); 277 uint32_t GetClassId(); GetGraph()278 auto GetGraph() 279 { 280 return builder_->GetGraph(); 281 } GetRuntime()282 auto GetRuntime() 283 { 284 return builder_->GetRuntime(); 285 } GetMethod()286 auto GetMethod() 287 { 288 return builder_->GetMethod(); 289 } Builder()290 auto Builder() 291 { 292 return builder_; 293 } 294 295 private: 296 InstBuilder *builder_ {}; 297 const BytecodeInstruction *bcInst_ {}; 298 RuntimeInterface::MethodPtr method_ {}; 299 uint32_t methodId_ {}; 300 uint32_t pc_ {}; 301 InputTypesMixin<DynamicInputsInst> *call_ {}; 302 Inst *resolver_ {}; 303 Inst *nullCheck_ {}; 304 SaveStateInst *saveState_ {}; 305 bool hasImplicitArg_ {}; 306 }; 307 Inst *GetArgDefinition(const BytecodeInstruction *bcInst, size_t idx, bool accRead, bool isRange = false); 308 Inst *GetArgDefinitionRange(const BytecodeInstruction *bcInst, size_t idx); 309 template <bool IS_VIRTUAL> 310 void AddArgNullcheckIfNeeded(RuntimeInterface::IntrinsicId intrinsic, Inst *inst, Inst *saveState, size_t bcAddr); 311 void BuildMonitor(const BytecodeInstruction *bcInst, Inst *def, bool isEnter); 312 Inst *BuildFloatInst(const BytecodeInstruction *bcInst); 313 template <bool IS_RANGE, bool ACC_READ> 314 void BuildIntrinsic(const BytecodeInstruction *bcInst, bool isRange, bool accRead); 315 template <bool IS_RANGE, bool ACC_READ> 316 void BuildDefaultIntrinsic(bool isVirtual, const BytecodeInstruction *bcInst); 317 void BuildAbsIntrinsic(const BytecodeInstruction *bcInst, bool accRead); 318 template <Opcode OPCODE> 319 void BuildBinaryOperationIntrinsic(const BytecodeInstruction *bcInst, bool accRead); 320 void BuildSqrtIntrinsic(const BytecodeInstruction *bcInst, bool accRead); 321 void BuildIsNanIntrinsic(const BytecodeInstruction *bcInst, bool accRead); 322 void BuildStringLengthIntrinsic(const BytecodeInstruction *bcInst, bool accRead); 323 void BuildStringIsEmptyIntrinsic(const BytecodeInstruction *bcInst, bool accRead); 324 void BuildCharIsUpperCaseIntrinsic(const BytecodeInstruction *bcInst, bool accRead); 325 void BuildCharToUpperCaseIntrinsic(const BytecodeInstruction *bcInst, bool accRead); 326 void BuildCharIsLowerCaseIntrinsic(const BytecodeInstruction *bcInst, bool accRead); 327 void BuildCharToLowerCaseIntrinsic(const BytecodeInstruction *bcInst, bool accRead); 328 void BuildMonitorIntrinsic(const BytecodeInstruction *bcInst, bool isEnter, bool accRead); 329 virtual void BuildThrow(const BytecodeInstruction *bcInst); 330 void BuildLenArray(const BytecodeInstruction *bcInst); 331 virtual void BuildNewArray(const BytecodeInstruction *bcInst); 332 virtual void BuildNewObject(const BytecodeInstruction *bcInst); 333 virtual void BuildLoadConstArray(const BytecodeInstruction *bcInst); 334 void BuildLoadConstStringArray(const BytecodeInstruction *bcInst); 335 template <typename T> 336 void BuildUnfoldLoadConstArray(const BytecodeInstruction *bcInst, DataType::Type type, 337 const pandasm::LiteralArray &litArray); 338 template <typename T> 339 void BuildUnfoldLoadConstPrimitiveArray(const BytecodeInstruction *bcInst, DataType::Type type, 340 const pandasm::LiteralArray &litArray, NewArrayInst *arrayInst); 341 template <typename T> 342 void BuildUnfoldLoadConstStringArray(const BytecodeInstruction *bcInst, DataType::Type type, 343 const pandasm::LiteralArray &litArray, NewArrayInst *arrayInst); 344 void BuildInitString(const BytecodeInstruction *bcInst); 345 virtual void BuildInitObject(const BytecodeInstruction *bcInst, bool isRange); 346 CallInst *BuildCallStaticForInitObject(const BytecodeInstruction *bcInst, uint32_t methodId, Inst **resolver); 347 void BuildMultiDimensionalArrayObject(const BytecodeInstruction *bcInst, bool isRange); 348 void BuildInitObjectMultiDimensionalArray(const BytecodeInstruction *bcInst, bool isRange); 349 template <bool IS_ACC_WRITE> 350 void BuildLoadObject(const BytecodeInstruction *bcInst, DataType::Type type); 351 template <bool IS_ACC_READ> 352 void BuildStoreObject(const BytecodeInstruction *bcInst, DataType::Type type); 353 Inst *BuildStoreObjectInst(const BytecodeInstruction *bcInst, DataType::Type type, RuntimeInterface::FieldPtr field, 354 uint32_t fieldId, Inst **resolveInst); 355 virtual void BuildLoadStatic(const BytecodeInstruction *bcInst, DataType::Type type); 356 Inst *BuildLoadStaticInst(size_t pc, DataType::Type type, uint32_t typeId, Inst *saveState); 357 virtual void BuildStoreStatic(const BytecodeInstruction *bcInst, DataType::Type type); 358 Inst *BuildStoreStaticInst(const BytecodeInstruction *bcInst, DataType::Type type, uint32_t typeId, 359 Inst *storeInput, Inst *saveState); 360 virtual void BuildCheckCast(const BytecodeInstruction *bcInst); 361 virtual void BuildIsInstance(const BytecodeInstruction *bcInst); 362 Inst *BuildLoadClass(RuntimeInterface::IdType typeId, size_t pc, Inst *saveState); 363 virtual void BuildLoadArray(const BytecodeInstruction *bcInst, DataType::Type type); 364 virtual void BuildStoreArray(const BytecodeInstruction *bcInst, DataType::Type type); 365 template <bool CREATE_REF_CHECK> 366 void BuildStoreArrayInst(const BytecodeInstruction *bcInst, DataType::Type type, Inst *arrayRef, Inst *index, 367 Inst *value); 368 std::tuple<SaveStateInst *, Inst *, LengthMethodInst *, BoundsCheckInst *> BuildChecksBeforeArray( 369 size_t pc, Inst *arrayRef, bool withNullcheck = true); 370 template <Opcode OPCODE> 371 void BuildLoadFromPool(const BytecodeInstruction *bcInst); 372 void BuildCastToAnyNumber(const BytecodeInstruction *bcInst); 373 AnyTypeCheckInst *BuildAnyTypeCheckInst(size_t bcAddr, Inst *input, Inst *saveState, 374 AnyBaseType type = AnyBaseType::UNDEFINED_TYPE); 375 void InitAnyTypeCheckInst(AnyTypeCheckInst *anyCheck, bool typeWasProfiled = false, 376 profiling::AnyInputType allowedInputType = {}) 377 { 378 anyCheck->SetAllowedInputType(allowedInputType); 379 anyCheck->SetIsTypeWasProfiled(typeWasProfiled); 380 } 381 382 bool TryBuildStringCharAtIntrinsic(const BytecodeInstruction *bcInst, bool accRead); 383 #include "inst_builder_extensions.inl.h" 384 GetClassId()385 auto GetClassId() const 386 { 387 return classId_; 388 } 389 GetNoTypeMarker()390 Marker GetNoTypeMarker() const 391 { 392 return noTypeMarker_; 393 } 394 GetVisitedBlockMarker()395 Marker GetVisitedBlockMarker() const 396 { 397 return visitedBlockMarker_; 398 } 399 ForceUnresolved()400 bool ForceUnresolved() const 401 { 402 #ifndef NDEBUG 403 return g_options.IsCompilerForceUnresolved() && !graph_->IsBytecodeOptimizer(); 404 #else 405 return false; 406 #endif 407 } 408 409 void SetTypeRec(Inst *inst, DataType::Type type); 410 411 /// Convert Panda bytecode type to COMPILER IR type 412 static DataType::Type ConvertPbcType(panda_file::Type type); 413 414 /// Get return type of the method specified by id 415 DataType::Type GetMethodReturnType(uintptr_t id) const; 416 /// Get type of argument of the method specified by id 417 DataType::Type GetMethodArgumentType(uintptr_t id, size_t index) const; 418 /// Get return type of currently compiling method 419 DataType::Type GetCurrentMethodReturnType() const; 420 /// Get type of argument of currently compiling method 421 DataType::Type GetCurrentMethodArgumentType(size_t index) const; 422 /// Get count of arguments of currently compiling method 423 size_t GetCurrentMethodArgumentsCount() const; 424 425 template <bool IS_STATIC> 426 bool IsInConstructor() const; 427 428 #ifndef PANDA_ETS_INTEROP_JS TryBuildInteropCall(const BytecodeInstruction * bcInst,bool isRange,bool accRead)429 bool TryBuildInteropCall([[maybe_unused]] const BytecodeInstruction *bcInst, [[maybe_unused]] bool isRange, 430 [[maybe_unused]] bool accRead) 431 { 432 return false; 433 } 434 #endif 435 436 #ifndef NDEBUG ResetSafepointDistance()437 void ResetSafepointDistance() 438 { 439 safepointDistance_ = static_cast<int32_t>(g_options.GetCompilerSafepointDistanceLimit()); 440 } 441 #endif 442 443 private: 444 static constexpr size_t ONE_FOR_OBJECT = 1; 445 static constexpr size_t ONE_FOR_SSTATE = 1; 446 447 Graph *graph_ {nullptr}; 448 RuntimeInterface *runtime_ {nullptr}; 449 BasicBlock *currentBb_ {nullptr}; 450 451 RuntimeInterface::MethodProfile methodProfile_ {}; 452 453 // Definitions vector of currently processed basic block 454 InstVector *currentDefs_ {nullptr}; 455 // Result of LoadFromConstantPool which will be added to SaveState inputs 456 Inst *additionalDef_ {nullptr}; 457 // Contains definitions of the virtual registers in all basic blocks 458 ArenaVector<InstVector> defs_; 459 460 RuntimeInterface::MethodPtr method_ {nullptr}; 461 // Set to true if builder failed to build IR 462 bool failed_ {false}; 463 // Number of virtual registers and method arguments 464 const size_t vregsAndArgsCount_; 465 // Marker for instructions with undefined type in the building phase 466 Marker noTypeMarker_; 467 Marker visitedBlockMarker_; 468 469 // Pointer to start position of bytecode instructions buffer 470 const uint8_t *instructionsBuf_ {nullptr}; 471 472 CallInst *callerInst_ {nullptr}; 473 uint32_t inliningDepth_ {0}; 474 size_t classId_; 475 #ifndef NDEBUG 476 int32_t safepointDistance_ {0}; 477 #endif 478 #include "intrinsics_ir_build.inl.h" 479 }; 480 } // namespace ark::compiler 481 482 #endif // PANDA_INST_BUILDER_H 483