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 COMPILER_OPTIMIZER_IR_GRAPH_CHECKER_H 17 #define COMPILER_OPTIMIZER_IR_GRAPH_CHECKER_H 18 19 #include "compiler_options.h" 20 #include "graph.h" 21 #include "graph_visitor.h" 22 #include "graph_checker_macros.h" 23 #include "optimizer/analysis/dominators_tree.h" 24 #include "optimizer/analysis/rpo.h" 25 #include "optimizer/analysis/loop_analyzer.h" 26 #include "optimizer/code_generator/registers_description.h" 27 #include "optimizer/optimizations/cleanup.h" 28 #include "optimizer/optimizations/memory_coalescing.h" 29 #include <iostream> 30 31 // CC-OFFNXT(G.PRE.02) should be with define 32 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 33 #define CHECKER_DO_IF_NOT_VISITOR(visitor, cond, func) \ 34 CHECKER_DO_IF_NOT_VISITOR_INTERNAL(visitor, GraphChecker *, cond, func) 35 36 namespace ark::compiler { 37 inline std::ostream &operator<<(std::ostream &os, const std::initializer_list<Opcode> &opcs) 38 { 39 os << "[ "; 40 for (auto opc : opcs) { 41 os << GetOpcodeString(opc) << " "; 42 } 43 os << "]"; 44 return os; 45 } 46 47 class GraphChecker : public GraphVisitor { 48 public: 49 explicit GraphChecker(Graph *graph, const char *passName); 50 PANDA_PUBLIC_API explicit GraphChecker(Graph *graph); 51 ~GraphChecker()52 ~GraphChecker() override 53 { 54 GetGraph()->GetPassManager()->SetCheckMode(false); 55 } 56 57 NO_COPY_SEMANTIC(GraphChecker); 58 NO_MOVE_SEMANTIC(GraphChecker); 59 60 PANDA_PUBLIC_API bool Check(); 61 GetStatus()62 bool GetStatus() const 63 { 64 return success_; 65 } 66 SetStatus(bool status)67 void SetStatus(bool status) 68 { 69 success_ = status; 70 } 71 72 private: 73 void PreCloneChecks(Graph *graph); 74 void UserInputCheck(Graph *graph); 75 void CheckBlock(BasicBlock *block); 76 void CheckDomTree(); 77 void CheckLoopAnalysis(); 78 void CheckStartBlock(); 79 void CheckEndBlock(); 80 void CheckControlFlow(BasicBlock *block); 81 void CheckDataFlow(BasicBlock *block); 82 void CheckUserOfInt32(BasicBlock *block, Inst *inst, User &user); 83 void CheckInstUsers(Inst *inst, [[maybe_unused]] BasicBlock *block); 84 void CheckPhiInputs(Inst *phiInst); 85 void CheckInstsRegisters(BasicBlock *block); 86 void CheckPhisRegisters(BasicBlock *block); 87 void CheckNoLowLevel(BasicBlock *block); 88 void CheckLoops(); 89 void CheckGraph(); 90 bool HasOuterInfiniteLoop(); 91 bool CheckInstHasInput(Inst *inst, Inst *input); 92 bool CheckInstHasUser(Inst *inst, Inst *user); 93 void CheckCallReturnInlined(); 94 void CheckSaveStateCaller(SaveStateInst *savestate); 95 bool FindCaller(Inst *caller, BasicBlock *domBlock, ArenaStack<Inst *> *inlinedCalls); 96 void CheckSpillFillHolder(Inst *inst); 97 bool CheckInstRegUsageSaved(const Inst *inst, Register reg) const; 98 void MarkBlocksInLoop(Loop *loop, Marker mrk); 99 bool CheckBlockHasPredecessor(BasicBlock *block, BasicBlock *predecessor); 100 bool CheckBlockHasSuccessor(BasicBlock *block, BasicBlock *successor); 101 bool BlockContainsInstruction(BasicBlock *block, Opcode opcode); 102 void CheckLoopHasSafePoint(Loop *loop); 103 void CheckBlockEdges(const BasicBlock &block); 104 void CheckTryBeginBlock(const BasicBlock &block); 105 void CheckJump(const BasicBlock &block); 106 bool IsTryCatchDomination(const BasicBlock *inputBlock, const BasicBlock *userBlock) const; 107 void CheckInputType(Inst *inst); 108 #ifdef COMPILER_DEBUG_CHECKS 109 bool NeedCheckSaveState(); 110 void PrepareUsers(Inst *inst, ArenaVector<User *> *users); 111 bool IsPhiSafeToSkipObjectCheck(Inst *inst, Marker visited); 112 bool IsPhiUserSafeToSkipObjectCheck(Inst *inst, Marker visited); 113 void CheckSaveStateInputs(Inst *inst, ArenaVector<User *> *users); 114 #endif // COMPILER_DEBUG_CHECKS 115 void CheckSaveStateInputs(); 116 void CheckSaveStatesWithRuntimeCallUsers(); 117 void CheckSaveStatesWithRuntimeCallUsers(BasicBlock *block, SaveStateInst *ss); 118 void CheckSaveStateOsrRec(const Inst *inst, const Inst *user, BasicBlock *block, Marker visited); 119 GetGraph()120 Graph *GetGraph() const 121 { 122 return graph_; 123 } 124 GetAllocator()125 ArenaAllocator *GetAllocator() 126 { 127 return &allocator_; 128 } 129 GetLocalAllocator()130 ArenaAllocator *GetLocalAllocator() 131 { 132 return &localAllocator_; 133 } 134 GetBlocksToVisit()135 const ArenaVector<BasicBlock *> &GetBlocksToVisit() const override 136 { 137 return GetGraph()->GetBlocksRPO(); 138 } 139 140 /* 141 * Visitors to check instructions types 142 */ 143 static PANDA_PUBLIC_API void VisitMov([[maybe_unused]] GraphVisitor *v, Inst *inst); 144 static PANDA_PUBLIC_API void VisitNeg([[maybe_unused]] GraphVisitor *v, Inst *inst); 145 static PANDA_PUBLIC_API void VisitAbs([[maybe_unused]] GraphVisitor *v, Inst *inst); 146 static PANDA_PUBLIC_API void VisitSqrt([[maybe_unused]] GraphVisitor *v, Inst *inst); 147 static PANDA_PUBLIC_API void VisitAddI([[maybe_unused]] GraphVisitor *v, Inst *inst); 148 static PANDA_PUBLIC_API void VisitSubI([[maybe_unused]] GraphVisitor *v, Inst *inst); 149 static PANDA_PUBLIC_API void VisitMulI([[maybe_unused]] GraphVisitor *v, Inst *inst); 150 static PANDA_PUBLIC_API void VisitDivI([[maybe_unused]] GraphVisitor *v, Inst *inst); 151 static PANDA_PUBLIC_API void VisitModI([[maybe_unused]] GraphVisitor *v, Inst *inst); 152 static PANDA_PUBLIC_API void VisitAndI([[maybe_unused]] GraphVisitor *v, Inst *inst); 153 static PANDA_PUBLIC_API void VisitOrI([[maybe_unused]] GraphVisitor *v, Inst *inst); 154 static PANDA_PUBLIC_API void VisitXorI([[maybe_unused]] GraphVisitor *v, Inst *inst); 155 static PANDA_PUBLIC_API void VisitShlI([[maybe_unused]] GraphVisitor *v, Inst *inst); 156 static PANDA_PUBLIC_API void VisitShrI([[maybe_unused]] GraphVisitor *v, Inst *inst); 157 static PANDA_PUBLIC_API void VisitAShlI([[maybe_unused]] GraphVisitor *v, Inst *inst); 158 static PANDA_PUBLIC_API void VisitNot([[maybe_unused]] GraphVisitor *v, Inst *inst); 159 static PANDA_PUBLIC_API void VisitAdd([[maybe_unused]] GraphVisitor *v, Inst *inst); 160 static PANDA_PUBLIC_API void VisitSub([[maybe_unused]] GraphVisitor *v, Inst *inst); 161 static PANDA_PUBLIC_API void VisitMul([[maybe_unused]] GraphVisitor *v, Inst *inst); 162 static PANDA_PUBLIC_API void VisitDiv([[maybe_unused]] GraphVisitor *v, Inst *inst); 163 static PANDA_PUBLIC_API void VisitMod([[maybe_unused]] GraphVisitor *v, Inst *inst); 164 static PANDA_PUBLIC_API void VisitMin([[maybe_unused]] GraphVisitor *v, Inst *inst); 165 static PANDA_PUBLIC_API void VisitMax([[maybe_unused]] GraphVisitor *v, Inst *inst); 166 static PANDA_PUBLIC_API void VisitShl([[maybe_unused]] GraphVisitor *v, Inst *inst); 167 static PANDA_PUBLIC_API void VisitShr([[maybe_unused]] GraphVisitor *v, Inst *inst); 168 static PANDA_PUBLIC_API void VisitAShr([[maybe_unused]] GraphVisitor *v, Inst *inst); 169 static PANDA_PUBLIC_API void VisitAnd([[maybe_unused]] GraphVisitor *v, Inst *inst); 170 static PANDA_PUBLIC_API void VisitOr([[maybe_unused]] GraphVisitor *v, Inst *inst); 171 static PANDA_PUBLIC_API void VisitXor([[maybe_unused]] GraphVisitor *v, Inst *inst); 172 static PANDA_PUBLIC_API void VisitLoadArray([[maybe_unused]] GraphVisitor *v, Inst *inst); 173 static PANDA_PUBLIC_API void VisitLoadArrayI([[maybe_unused]] GraphVisitor *v, Inst *inst); 174 static PANDA_PUBLIC_API void VisitLoadArrayPair([[maybe_unused]] GraphVisitor *v, Inst *inst); 175 static PANDA_PUBLIC_API void VisitLoadObjectPair([[maybe_unused]] GraphVisitor *v, Inst *inst); 176 static PANDA_PUBLIC_API void VisitLoadArrayPairI([[maybe_unused]] GraphVisitor *v, Inst *inst); 177 static PANDA_PUBLIC_API void VisitLoadPairPart([[maybe_unused]] GraphVisitor *v, Inst *inst); 178 static PANDA_PUBLIC_API void VisitStore([[maybe_unused]] GraphVisitor *v, Inst *inst); 179 static PANDA_PUBLIC_API void VisitStoreI([[maybe_unused]] GraphVisitor *v, Inst *inst); 180 static PANDA_PUBLIC_API void VisitStoreArrayPair([[maybe_unused]] GraphVisitor *v, Inst *inst); 181 static PANDA_PUBLIC_API void VisitStoreObjectPair([[maybe_unused]] GraphVisitor *v, Inst *inst); 182 static PANDA_PUBLIC_API void VisitStoreArrayPairI([[maybe_unused]] GraphVisitor *v, Inst *inst); 183 static PANDA_PUBLIC_API void VisitStoreArray([[maybe_unused]] GraphVisitor *v, Inst *inst); 184 static PANDA_PUBLIC_API void VisitStoreArrayI([[maybe_unused]] GraphVisitor *v, Inst *inst); 185 static PANDA_PUBLIC_API void VisitStoreStatic([[maybe_unused]] GraphVisitor *v, Inst *inst); 186 static PANDA_PUBLIC_API void VisitUnresolvedStoreStatic([[maybe_unused]] GraphVisitor *v, Inst *inst); 187 static PANDA_PUBLIC_API void VisitStoreObject([[maybe_unused]] GraphVisitor *v, Inst *inst); 188 static PANDA_PUBLIC_API void VisitStoreObjectDynamic([[maybe_unused]] GraphVisitor *v, Inst *inst); 189 static PANDA_PUBLIC_API void VisitStoreResolvedObjectField([[maybe_unused]] GraphVisitor *v, Inst *inst); 190 static PANDA_PUBLIC_API void VisitFillConstArray([[maybe_unused]] GraphVisitor *v, Inst *inst); 191 static PANDA_PUBLIC_API void VisitStoreResolvedObjectFieldStatic([[maybe_unused]] GraphVisitor *v, Inst *inst); 192 static PANDA_PUBLIC_API void VisitLoadStatic([[maybe_unused]] GraphVisitor *v, Inst *inst); 193 static PANDA_PUBLIC_API void VisitLoadClass([[maybe_unused]] GraphVisitor *v, Inst *inst); 194 static PANDA_PUBLIC_API void VisitLoadAndInitClass([[maybe_unused]] GraphVisitor *v, Inst *inst); 195 static PANDA_PUBLIC_API void VisitUnresolvedLoadAndInitClass([[maybe_unused]] GraphVisitor *v, Inst *inst); 196 static PANDA_PUBLIC_API void VisitGetInstanceClass([[maybe_unused]] GraphVisitor *v, Inst *inst); 197 static PANDA_PUBLIC_API void VisitNewObject([[maybe_unused]] GraphVisitor *v, Inst *inst); 198 static PANDA_PUBLIC_API void VisitInitObject([[maybe_unused]] GraphVisitor *v, [[maybe_unused]] Inst *inst); 199 static PANDA_PUBLIC_API void VisitInitClass([[maybe_unused]] GraphVisitor *v, [[maybe_unused]] Inst *inst); 200 static PANDA_PUBLIC_API void VisitIntrinsic([[maybe_unused]] GraphVisitor *v, [[maybe_unused]] Inst *inst); 201 static PANDA_PUBLIC_API void VisitLoadRuntimeClass([[maybe_unused]] GraphVisitor *v, [[maybe_unused]] Inst *inst); 202 static PANDA_PUBLIC_API void VisitLoadObject([[maybe_unused]] GraphVisitor *v, Inst *inst); 203 static PANDA_PUBLIC_API void VisitConstant([[maybe_unused]] GraphVisitor *v, [[maybe_unused]] Inst *inst); 204 static PANDA_PUBLIC_API void VisitNullPtr([[maybe_unused]] GraphVisitor *v, [[maybe_unused]] Inst *inst); 205 static PANDA_PUBLIC_API void VisitLoadUniqueObject([[maybe_unused]] GraphVisitor *v, [[maybe_unused]] Inst *inst); 206 static PANDA_PUBLIC_API void VisitPhi([[maybe_unused]] GraphVisitor *v, Inst *inst); 207 static PANDA_PUBLIC_API void VisitParameter([[maybe_unused]] GraphVisitor *v, [[maybe_unused]] Inst *inst); 208 static PANDA_PUBLIC_API void VisitCompare([[maybe_unused]] GraphVisitor *v, Inst *inst); 209 static PANDA_PUBLIC_API void VisitCast([[maybe_unused]] GraphVisitor *v, Inst *inst); 210 static PANDA_PUBLIC_API void VisitCmp([[maybe_unused]] GraphVisitor *v, Inst *inst); 211 static PANDA_PUBLIC_API void VisitMonitor([[maybe_unused]] GraphVisitor *v, Inst *inst); 212 static PANDA_PUBLIC_API void VisitReturn([[maybe_unused]] GraphVisitor *v, Inst *inst); 213 static PANDA_PUBLIC_API void VisitReturnVoid([[maybe_unused]] GraphVisitor *v, Inst *inst); 214 static PANDA_PUBLIC_API void VisitNullCheck([[maybe_unused]] GraphVisitor *v, Inst *inst); 215 static PANDA_PUBLIC_API void VisitBoundsCheck([[maybe_unused]] GraphVisitor *v, Inst *inst); 216 static PANDA_PUBLIC_API void VisitBoundsCheckI([[maybe_unused]] GraphVisitor *v, [[maybe_unused]] Inst *inst); 217 static PANDA_PUBLIC_API void VisitRefTypeCheck([[maybe_unused]] GraphVisitor *v, Inst *inst); 218 static PANDA_PUBLIC_API void VisitNegativeCheck([[maybe_unused]] GraphVisitor *v, Inst *inst); 219 static PANDA_PUBLIC_API void VisitNotPositiveCheck([[maybe_unused]] GraphVisitor *v, Inst *inst); 220 static PANDA_PUBLIC_API void VisitZeroCheck([[maybe_unused]] GraphVisitor *v, Inst *inst); 221 static PANDA_PUBLIC_API void VisitDeoptimizeIf([[maybe_unused]] GraphVisitor *v, Inst *inst); 222 static PANDA_PUBLIC_API void VisitLenArray([[maybe_unused]] GraphVisitor *v, Inst *inst); 223 static PANDA_PUBLIC_API void VisitCallVirtual([[maybe_unused]] GraphVisitor *v, Inst *inst); 224 static PANDA_PUBLIC_API void VisitCallDynamic([[maybe_unused]] GraphVisitor *v, [[maybe_unused]] Inst *inst); 225 static PANDA_PUBLIC_API void VisitSaveState([[maybe_unused]] GraphVisitor *v, [[maybe_unused]] Inst *inst); 226 static PANDA_PUBLIC_API void VisitSafePoint([[maybe_unused]] GraphVisitor *v, [[maybe_unused]] Inst *inst); 227 static PANDA_PUBLIC_API void VisitSaveStateOsr([[maybe_unused]] GraphVisitor *v, [[maybe_unused]] Inst *inst); 228 static PANDA_PUBLIC_API void VisitThrow([[maybe_unused]] GraphVisitor *v, [[maybe_unused]] Inst *inst); 229 static PANDA_PUBLIC_API void VisitCheckCast([[maybe_unused]] GraphVisitor *v, [[maybe_unused]] Inst *inst); 230 static PANDA_PUBLIC_API void VisitIsInstance([[maybe_unused]] GraphVisitor *v, [[maybe_unused]] Inst *inst); 231 static PANDA_PUBLIC_API void VisitSelect([[maybe_unused]] GraphVisitor *v, [[maybe_unused]] Inst *inst); 232 static PANDA_PUBLIC_API void VisitSelectWithReference([[maybe_unused]] GraphVisitor *v, 233 [[maybe_unused]] Inst *inst); 234 static PANDA_PUBLIC_API void VisitSelectImm([[maybe_unused]] GraphVisitor *v, [[maybe_unused]] Inst *inst); 235 static PANDA_PUBLIC_API void VisitSelectImmWithReference([[maybe_unused]] GraphVisitor *v, 236 [[maybe_unused]] Inst *inst); 237 static PANDA_PUBLIC_API void VisitSelectImmNotReference([[maybe_unused]] GraphVisitor *v, 238 [[maybe_unused]] Inst *inst); 239 static PANDA_PUBLIC_API void VisitIf([[maybe_unused]] GraphVisitor *v, Inst *inst); 240 static PANDA_PUBLIC_API void VisitIfImm([[maybe_unused]] GraphVisitor *v, Inst *inst); 241 static PANDA_PUBLIC_API void VisitTry([[maybe_unused]] GraphVisitor *v, Inst *inst); 242 static PANDA_PUBLIC_API void VisitNOP([[maybe_unused]] GraphVisitor *v, [[maybe_unused]] Inst *inst); 243 static PANDA_PUBLIC_API void VisitAndNot([[maybe_unused]] GraphVisitor *v, Inst *inst); 244 static PANDA_PUBLIC_API void VisitOrNot([[maybe_unused]] GraphVisitor *v, Inst *inst); 245 static PANDA_PUBLIC_API void VisitXorNot([[maybe_unused]] GraphVisitor *v, Inst *inst); 246 static PANDA_PUBLIC_API void VisitMNeg([[maybe_unused]] GraphVisitor *v, Inst *inst); 247 static PANDA_PUBLIC_API void VisitMAdd([[maybe_unused]] GraphVisitor *v, Inst *inst); 248 static PANDA_PUBLIC_API void VisitMSub([[maybe_unused]] GraphVisitor *v, Inst *inst); 249 static PANDA_PUBLIC_API void VisitAddSR(GraphVisitor *v, Inst *inst); 250 static PANDA_PUBLIC_API void VisitSubSR(GraphVisitor *v, Inst *inst); 251 static PANDA_PUBLIC_API void VisitAndSR(GraphVisitor *v, Inst *inst); 252 static PANDA_PUBLIC_API void VisitOrSR(GraphVisitor *v, Inst *inst); 253 static PANDA_PUBLIC_API void VisitXorSR(GraphVisitor *v, Inst *inst); 254 static PANDA_PUBLIC_API void VisitAndNotSR(GraphVisitor *v, Inst *inst); 255 static PANDA_PUBLIC_API void VisitOrNotSR(GraphVisitor *v, Inst *inst); 256 static PANDA_PUBLIC_API void VisitXorNotSR(GraphVisitor *v, Inst *inst); 257 static PANDA_PUBLIC_API void VisitNegSR([[maybe_unused]] GraphVisitor *v, [[maybe_unused]] Inst *inst); 258 static PANDA_PUBLIC_API void VisitCompareAnyType(GraphVisitor *v, Inst *inst); 259 static PANDA_PUBLIC_API void VisitCastAnyTypeValue(GraphVisitor *v, Inst *inst); 260 static PANDA_PUBLIC_API void VisitCastValueToAnyType(GraphVisitor *v, Inst *inst); 261 static PANDA_PUBLIC_API void VisitAnyTypeCheck(GraphVisitor *v, Inst *inst); 262 static PANDA_PUBLIC_API void VisitHclassCheck(GraphVisitor *v, Inst *inst); 263 static PANDA_PUBLIC_API void VisitBitcast(GraphVisitor *v, Inst *inst); 264 static PANDA_PUBLIC_API void VisitAddOverflow([[maybe_unused]] GraphVisitor *v, Inst *inst); 265 static PANDA_PUBLIC_API void VisitSubOverflow([[maybe_unused]] GraphVisitor *v, Inst *inst); 266 static PANDA_PUBLIC_API void VisitLoadString(GraphVisitor *v, Inst *inst); 267 static PANDA_PUBLIC_API void VisitLoadType(GraphVisitor *v, Inst *inst); 268 static PANDA_PUBLIC_API void VisitLoadUnresolvedType(GraphVisitor *v, Inst *inst); 269 static PANDA_PUBLIC_API void VisitLoadFromConstantPool(GraphVisitor *v, Inst *inst); 270 static PANDA_PUBLIC_API void VisitLoadImmediate([[maybe_unused]] GraphVisitor *v, Inst *inst); 271 static PANDA_PUBLIC_API void VisitCallNative(GraphVisitor *v, Inst *inst); 272 273 #include "visitor.inc" 274 CheckCommonTypes(Inst * inst1,Inst * inst2)275 static bool CheckCommonTypes(Inst *inst1, Inst *inst2) 276 { 277 if (inst1->GetBasicBlock()->GetGraph()->IsDynamicMethod() && 278 (inst1->GetType() == DataType::ANY || inst2->GetType() == DataType::ANY)) { 279 return true; 280 } 281 DataType::Type type1 = inst1->GetType(); 282 DataType::Type type2 = inst2->GetType(); 283 return DataType::GetCommonType(type1) == DataType::GetCommonType(type2); 284 } 285 286 static void CheckBinaryOperationTypes([[maybe_unused]] GraphVisitor *v, Inst *inst, bool isInt = false) 287 { 288 [[maybe_unused]] auto op1 = inst->GetInputs()[0].GetInst(); 289 [[maybe_unused]] auto op2 = inst->GetInputs()[1].GetInst(); 290 291 if (inst->GetOpcode() == Opcode::Div || inst->GetOpcode() == Opcode::Mod) { 292 if (op2->GetOpcode() == Opcode::ZeroCheck) { 293 op2 = op2->GetInput(0).GetInst(); 294 } 295 } 296 297 if (isInt) { 298 CHECKER_DO_IF_NOT_VISITOR( 299 v, DataType::GetCommonType(inst->GetType()) == DataType::INT64, 300 (std::cerr << "Binary instruction type is not a integer", inst->Dump(&std::cerr))); 301 } 302 303 CHECKER_DO_IF_NOT_VISITOR( 304 v, DataType::IsTypeNumeric(op1->GetType()), 305 (std::cerr << "Binary instruction 1st operand type is not a numeric", inst->Dump(&std::cerr))); 306 CHECKER_DO_IF_NOT_VISITOR( 307 v, DataType::IsTypeNumeric(op2->GetType()), 308 (std::cerr << "Binary instruction 2nd operand type is not a numeric", inst->Dump(&std::cerr))); 309 CHECKER_DO_IF_NOT_VISITOR(v, DataType::IsTypeNumeric(inst->GetType()), 310 (std::cerr << "Binary instruction type is not a numeric", inst->Dump(&std::cerr))); 311 312 CHECKER_DO_IF_NOT_VISITOR(v, CheckCommonTypes(op1, op2), 313 (std::cerr << "Types of binary instruction operands are not compatible\n", 314 op1->Dump(&std::cerr), op2->Dump(&std::cerr), inst->Dump(&std::cerr))); 315 CHECKER_DO_IF_NOT_VISITOR( 316 v, CheckCommonTypes(inst, op1), 317 (std::cerr << "Types of binary instruction result and its operands are not compatible\n", 318 inst->Dump(&std::cerr))); 319 } 320 CheckBinaryOverflowOperation(GraphVisitor * v,IfInst * inst)321 static void CheckBinaryOverflowOperation(GraphVisitor *v, IfInst *inst) 322 { 323 // Overflow instruction are used only in dynamic methods. 324 // But ASSERT wasn't added because the instructions checks in codegen_test.cpp with default method 325 // NOTE(pishin) add an ASSERT after add assembly tests tests and remove the test from codegen_test.cpp 326 [[maybe_unused]] auto cc = inst->GetCc(); 327 CHECKER_DO_IF_NOT_VISITOR(v, (cc == CC_EQ || cc == CC_NE), 328 (std::cerr << "overflow instruction are used only CC_EQ or CC_NE")); 329 CheckBinaryOperationTypes(v, inst, true); 330 CHECKER_DO_IF_NOT_VISITOR(v, !DataType::IsLessInt32(inst->GetType()), 331 (std::cerr << "overflow instruction have INT32 or INT64 types")); 332 } 333 CheckBinaryOperationWithShiftedOperandTypes(GraphVisitor * v,Inst * inst,bool rorSupported)334 static void CheckBinaryOperationWithShiftedOperandTypes(GraphVisitor *v, Inst *inst, 335 [[maybe_unused]] bool rorSupported) 336 { 337 CheckBinaryOperationTypes(v, inst, true); 338 [[maybe_unused]] auto instWShift = static_cast<BinaryShiftedRegisterOperation *>(inst); 339 CHECKER_DO_IF_NOT_VISITOR(v, 340 instWShift->GetShiftType() != ShiftType::INVALID_SHIFT && 341 (rorSupported || instWShift->GetShiftType() != ShiftType::ROR), 342 (std::cerr << "Operation has invalid shift type\n", inst->Dump(&std::cerr))); 343 } 344 CheckUnaryOperationTypes(GraphVisitor * v,Inst * inst)345 static void CheckUnaryOperationTypes([[maybe_unused]] GraphVisitor *v, Inst *inst) 346 { 347 [[maybe_unused]] auto op = inst->GetInput(0).GetInst(); 348 CHECKER_DO_IF_NOT_VISITOR( 349 v, CheckCommonTypes(inst, op), 350 (std::cerr << "Types of unary instruction result and its operand are not compatible\n", 351 inst->Dump(&std::cerr), op->Dump(&std::cerr))); 352 } 353 354 static void CheckTernaryOperationTypes([[maybe_unused]] GraphVisitor *v, Inst *inst, bool isInt = false) 355 { 356 [[maybe_unused]] auto op1 = inst->GetInputs()[0].GetInst(); 357 [[maybe_unused]] auto op2 = inst->GetInputs()[1].GetInst(); 358 [[maybe_unused]] auto op3 = inst->GetInputs()[1].GetInst(); 359 360 if (isInt) { 361 CHECKER_DO_IF_NOT_VISITOR( 362 v, DataType::GetCommonType(inst->GetType()) == DataType::INT64, 363 (std::cerr << "Ternary instruction type is not a integer", inst->Dump(&std::cerr))); 364 } 365 366 CHECKER_DO_IF_NOT_VISITOR( 367 v, DataType::IsTypeNumeric(op1->GetType()), 368 (std::cerr << "Ternary instruction 1st operand type is not a numeric", inst->Dump(&std::cerr))); 369 CHECKER_DO_IF_NOT_VISITOR( 370 v, DataType::IsTypeNumeric(op2->GetType()), 371 (std::cerr << "Ternary instruction 2nd operand type is not a numeric", inst->Dump(&std::cerr))); 372 CHECKER_DO_IF_NOT_VISITOR( 373 v, DataType::IsTypeNumeric(op3->GetType()), 374 (std::cerr << "Ternary instruction 2nd operand type is not a numeric", inst->Dump(&std::cerr))); 375 CHECKER_DO_IF_NOT_VISITOR(v, DataType::IsTypeNumeric(inst->GetType()), 376 (std::cerr << "Ternary instruction type is not a numeric", inst->Dump(&std::cerr))); 377 378 CHECKER_DO_IF_NOT_VISITOR(v, CheckCommonTypes(op1, op2) && CheckCommonTypes(op2, op3), 379 (std::cerr << "Types of ternary instruction operands are not compatible\n", 380 op1->Dump(&std::cerr), op2->Dump(&std::cerr), op3->Dump(&std::cerr), 381 inst->Dump(&std::cerr))); 382 CHECKER_DO_IF_NOT_VISITOR( 383 v, CheckCommonTypes(inst, op1), 384 (std::cerr << "Types of ternary instruction result and its operands are not compatible\n", 385 inst->Dump(&std::cerr))); 386 } 387 388 static void CheckMemoryInstruction([[maybe_unused]] GraphVisitor *v, [[maybe_unused]] Inst *inst, 389 [[maybe_unused]] bool needBarrier = false) 390 { 391 CHECKER_DO_IF_NOT_VISITOR(v, 392 DataType::IsTypeNumeric(inst->GetType()) || inst->GetType() == DataType::REFERENCE || 393 inst->GetType() == DataType::ANY, 394 (std::cerr << "Memory instruction has wrong type\n", inst->Dump(&std::cerr))); 395 if (inst->IsStore() && (inst->GetInputType(0) != DataType::POINTER) && (inst->GetType() == DataType::ANY)) { 396 CHECKER_DO_IF_NOT_VISITOR(v, needBarrier, 397 (std::cerr << "This store should have barrier:\n", inst->Dump(&std::cerr))); 398 } 399 } 400 CheckObjectTypeDynamic(GraphVisitor * v,Inst * inst,ObjectType type,uint32_t typeId)401 static void CheckObjectTypeDynamic([[maybe_unused]] GraphVisitor *v, Inst *inst, ObjectType type, 402 [[maybe_unused]] uint32_t typeId) 403 { 404 // IrToc use LoadObject and StoreObject with ObjectType::MEM_OBJECT for dynamic 405 // We can inline intrinsics with the instruction under the option --compiler-inline-full-intrinsics=true 406 if (!g_options.IsCompilerInlineFullIntrinsics()) { 407 CHECKER_DO_IF_NOT_VISITOR( 408 v, type != ObjectType::MEM_OBJECT && type != ObjectType::MEM_STATIC, 409 (std::cerr << "The object type isn't supported for dynamic\n", inst->Dump(&std::cerr))); 410 } 411 if (type == ObjectType::MEM_DYN_CLASS) { 412 CHECKER_DO_IF_NOT_VISITOR( 413 v, typeId == TypeIdMixin::MEM_DYN_CLASS_ID, 414 (std::cerr << "The object type_id for MEM_DYN_CLASS is incorrect\n", inst->Dump(&std::cerr))); 415 } else if (type == ObjectType::MEM_DYN_PROPS) { 416 CHECKER_DO_IF_NOT_VISITOR( 417 v, typeId == TypeIdMixin::MEM_DYN_PROPS_ID, 418 (std::cerr << "The object type_id for MEM_DYN_PROPS is incorrect\n", inst->Dump(&std::cerr))); 419 } else if (type == ObjectType::MEM_DYN_PROTO_HOLDER) { 420 CHECKER_DO_IF_NOT_VISITOR( 421 v, typeId == TypeIdMixin::MEM_DYN_PROTO_HOLDER_ID, 422 (std::cerr << "The object type_id for MEM_DYN_PROTO_HOLDER is incorrect\n", inst->Dump(&std::cerr))); 423 } else if (type == ObjectType::MEM_DYN_PROTO_CELL) { 424 [[maybe_unused]] Inst *objInst = inst->GetInput(0).GetInst(); 425 CHECKER_DO_IF_NOT_VISITOR( 426 v, typeId == TypeIdMixin::MEM_DYN_PROTO_CELL_ID, 427 (std::cerr << "The object type_id for MEM_DYN_PROTO_CELL is incorrect\n", inst->Dump(&std::cerr))); 428 } else if (type == ObjectType::MEM_DYN_CHANGE_FIELD) { 429 [[maybe_unused]] Inst *objInst = inst->GetInput(0).GetInst(); 430 CHECKER_DO_IF_NOT_VISITOR( 431 v, typeId == TypeIdMixin::MEM_DYN_CHANGE_FIELD_ID, 432 (std::cerr << "The object type_id for MEM_DYN_CHANGE_FIELD is incorrect\n", inst->Dump(&std::cerr))); 433 } else if (type == ObjectType::MEM_DYN_GLOBAL) { 434 CHECKER_DO_IF_NOT_VISITOR( 435 v, typeId == TypeIdMixin::MEM_DYN_GLOBAL_ID, 436 (std::cerr << "The object type_id for MEM_DYN_GLOBAL is incorrect\n", inst->Dump(&std::cerr))); 437 } else if (type == ObjectType::MEM_DYN_HCLASS) { 438 CHECKER_DO_IF_NOT_VISITOR( 439 v, typeId == TypeIdMixin::MEM_DYN_HCLASS_ID, 440 (std::cerr << "The object type_id for MEM_DYN_HCLASS is incorrect\n", inst->Dump(&std::cerr))); 441 } else { 442 CHECKER_DO_IF_NOT_VISITOR( 443 v, 444 typeId != TypeIdMixin::MEM_DYN_GLOBAL_ID && typeId != TypeIdMixin::MEM_DYN_CLASS_ID && 445 typeId != TypeIdMixin::MEM_DYN_PROPS_ID, 446 (std::cerr << "The object type_id for MEM_DYN_GLOBAL is incorrect\n", inst->Dump(&std::cerr))); 447 } 448 } 449 CheckObjectType(GraphVisitor * v,Inst * inst,ObjectType type,uint32_t typeId)450 static void CheckObjectType([[maybe_unused]] GraphVisitor *v, Inst *inst, ObjectType type, 451 [[maybe_unused]] uint32_t typeId) 452 { 453 auto graph = inst->GetBasicBlock()->GetGraph(); 454 if (!graph->SupportManagedCode()) { 455 return; 456 } 457 if (graph->IsDynamicMethod()) { 458 CheckObjectTypeDynamic(v, inst, type, typeId); 459 } else { 460 CHECKER_DO_IF_NOT_VISITOR( 461 v, type == ObjectType::MEM_OBJECT || type == ObjectType::MEM_STATIC, 462 (std::cerr << "The object type isn't supported for static\n", inst->Dump(&std::cerr))); 463 } 464 } 465 CheckContrlFlowInst(GraphVisitor * v,Inst * inst)466 static void CheckContrlFlowInst([[maybe_unused]] GraphVisitor *v, Inst *inst) 467 { 468 auto block = inst->GetBasicBlock(); 469 [[maybe_unused]] auto lastInst = *block->AllInstsSafeReverse().begin(); 470 CHECKER_DO_IF_NOT_VISITOR( 471 v, (lastInst == inst), 472 (std::cerr << "Control flow instruction must be last instruction in block\n CF instruction:\n", 473 inst->Dump(&std::cerr), std::cerr << "\n last instruction:\n", lastInst->Dump(&std::cerr))); 474 CHECKER_DO_IF_NOT_VISITOR(v, inst->GetUsers().Empty(), 475 (std::cerr << "Control flow instruction has users\n", inst->Dump(&std::cerr))); 476 } 477 CheckThrows(GraphVisitor * v,Inst * inst,std::initializer_list<Opcode> opcs)478 static void CheckThrows([[maybe_unused]] GraphVisitor *v, [[maybe_unused]] Inst *inst, 479 [[maybe_unused]] std::initializer_list<Opcode> opcs) 480 { 481 #ifdef COMPILER_DEBUG_CHECKS 482 const auto &inputs = inst->GetInputs(); 483 auto ssInput = [&inst](const auto &input) { 484 return input.GetInst()->GetOpcode() == Opcode::SaveState || 485 (input.GetInst()->GetOpcode() == Opcode::SaveStateDeoptimize && inst->CanDeoptimize()); 486 }; 487 bool hasSaveState = std::find_if(inputs.begin(), inputs.end(), ssInput) != inputs.end(); 488 489 bool hasOpc = true; 490 for (auto &node : inst->GetUsers()) { 491 auto opc = node.GetInst()->GetOpcode(); 492 hasOpc &= std::find(opcs.begin(), opcs.end(), opc) != opcs.end(); 493 } 494 495 CHECKER_DO_IF_NOT_VISITOR( 496 v, !inst->HasUsers() || hasOpc, 497 (inst->Dump(&std::cerr), 498 std::cerr << "Throw inst doesn't have any users from the list:" << opcs << std::endl)); 499 CHECKER_DO_IF_NOT_VISITOR(v, hasSaveState, 500 (inst->Dump(&std::cerr), std::cerr << "Throw inst without SaveState" << std::endl)); 501 #endif 502 } 503 CheckSaveStateInput(GraphVisitor * v,Inst * inst)504 static void CheckSaveStateInput([[maybe_unused]] GraphVisitor *v, [[maybe_unused]] Inst *inst) 505 { 506 CHECKER_DO_IF_NOT_VISITOR( 507 v, 508 inst->GetInputsCount() != 0 && 509 inst->GetInput(inst->GetInputsCount() - 1).GetInst()->GetOpcode() == Opcode::SaveState, 510 (std::cerr << "Instruction must have SaveState as last input:\n", inst->Dump(&std::cerr))); 511 } 512 GetPassName()513 std::string GetPassName() const 514 { 515 return passName_; 516 } 517 IncrementNullPtrInstCounterAndGet()518 int IncrementNullPtrInstCounterAndGet() 519 { 520 return ++nullPtrInstCounter_; 521 } 522 IncrementLoadUniqueObjectInstCounterAndGet()523 int IncrementLoadUniqueObjectInstCounterAndGet() 524 { 525 return ++loadUniqueObjectInstCounter_; 526 } 527 528 void PrintFailedMethodAndPass() const; 529 static void PrintFailedMethodAndPassVisitor(GraphVisitor *v); 530 531 private: 532 Graph *graph_; 533 ArenaAllocator allocator_ {SpaceType::SPACE_TYPE_COMPILER, nullptr, true}; 534 ArenaAllocator localAllocator_ {SpaceType::SPACE_TYPE_COMPILER, nullptr, true}; 535 int nullPtrInstCounter_ = 0; 536 int loadUniqueObjectInstCounter_ = 0; 537 std::string passName_; 538 bool success_ {true}; 539 }; 540 } // namespace ark::compiler 541 542 #undef CHECKER_DO_IF_NOT_VISITOR 543 544 #endif // COMPILER_OPTIMIZER_IR_GRAPH_CHECKER_H 545