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_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 VisitLoadUndefined([[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 272 #include "visitor.inc" 273 CheckCommonTypes(Inst * inst1,Inst * inst2)274 static bool CheckCommonTypes(Inst *inst1, Inst *inst2) 275 { 276 if (inst1->GetBasicBlock()->GetGraph()->IsDynamicMethod() && 277 (inst1->GetType() == DataType::ANY || inst2->GetType() == DataType::ANY)) { 278 return true; 279 } 280 DataType::Type type1 = inst1->GetType(); 281 DataType::Type type2 = inst2->GetType(); 282 return DataType::GetCommonType(type1) == DataType::GetCommonType(type2); 283 } 284 285 static void CheckBinaryOperationTypes([[maybe_unused]] GraphVisitor *v, Inst *inst, bool isInt = false) 286 { 287 [[maybe_unused]] auto op1 = inst->GetInputs()[0].GetInst(); 288 [[maybe_unused]] auto op2 = inst->GetInputs()[1].GetInst(); 289 290 if (inst->GetOpcode() == Opcode::Div || inst->GetOpcode() == Opcode::Mod) { 291 if (op2->GetOpcode() == Opcode::ZeroCheck) { 292 op2 = op2->GetInput(0).GetInst(); 293 } 294 } 295 296 if (isInt) { 297 CHECKER_DO_IF_NOT_VISITOR( 298 v, DataType::GetCommonType(inst->GetType()) == DataType::INT64, 299 (std::cerr << "Binary instruction type is not a integer", inst->Dump(&std::cerr))); 300 } 301 302 CHECKER_DO_IF_NOT_VISITOR( 303 v, DataType::IsTypeNumeric(op1->GetType()), 304 (std::cerr << "Binary instruction 1st operand type is not a numeric", inst->Dump(&std::cerr))); 305 CHECKER_DO_IF_NOT_VISITOR( 306 v, DataType::IsTypeNumeric(op2->GetType()), 307 (std::cerr << "Binary instruction 2nd operand type is not a numeric", inst->Dump(&std::cerr))); 308 CHECKER_DO_IF_NOT_VISITOR(v, DataType::IsTypeNumeric(inst->GetType()), 309 (std::cerr << "Binary instruction type is not a numeric", inst->Dump(&std::cerr))); 310 311 CHECKER_DO_IF_NOT_VISITOR(v, CheckCommonTypes(op1, op2), 312 (std::cerr << "Types of binary instruction operands are not compatible\n", 313 op1->Dump(&std::cerr), op2->Dump(&std::cerr), inst->Dump(&std::cerr))); 314 CHECKER_DO_IF_NOT_VISITOR( 315 v, CheckCommonTypes(inst, op1), 316 (std::cerr << "Types of binary instruction result and its operands are not compatible\n", 317 inst->Dump(&std::cerr))); 318 } 319 CheckBinaryOverflowOperation(GraphVisitor * v,IfInst * inst)320 static void CheckBinaryOverflowOperation(GraphVisitor *v, IfInst *inst) 321 { 322 // Overflow instruction are used only in dynamic methods. 323 // But ASSERT wasn't added because the instructions checks in codegen_test.cpp with default method 324 // NOTE(pishin) add an ASSERT after add assembly tests tests and remove the test from codegen_test.cpp 325 [[maybe_unused]] auto cc = inst->GetCc(); 326 CHECKER_DO_IF_NOT_VISITOR(v, (cc == CC_EQ || cc == CC_NE), 327 (std::cerr << "overflow instruction are used only CC_EQ or CC_NE")); 328 CheckBinaryOperationTypes(v, inst, true); 329 CHECKER_DO_IF_NOT_VISITOR(v, !DataType::IsLessInt32(inst->GetType()), 330 (std::cerr << "overflow instruction have INT32 or INT64 types")); 331 } 332 CheckBinaryOperationWithShiftedOperandTypes(GraphVisitor * v,Inst * inst,bool rorSupported)333 static void CheckBinaryOperationWithShiftedOperandTypes(GraphVisitor *v, Inst *inst, 334 [[maybe_unused]] bool rorSupported) 335 { 336 CheckBinaryOperationTypes(v, inst, true); 337 [[maybe_unused]] auto instWShift = static_cast<BinaryShiftedRegisterOperation *>(inst); 338 CHECKER_DO_IF_NOT_VISITOR(v, 339 instWShift->GetShiftType() != ShiftType::INVALID_SHIFT && 340 (rorSupported || instWShift->GetShiftType() != ShiftType::ROR), 341 (std::cerr << "Operation has invalid shift type\n", inst->Dump(&std::cerr))); 342 } 343 CheckUnaryOperationTypes(GraphVisitor * v,Inst * inst)344 static void CheckUnaryOperationTypes([[maybe_unused]] GraphVisitor *v, Inst *inst) 345 { 346 [[maybe_unused]] auto op = inst->GetInput(0).GetInst(); 347 CHECKER_DO_IF_NOT_VISITOR( 348 v, CheckCommonTypes(inst, op), 349 (std::cerr << "Types of unary instruction result and its operand are not compatible\n", 350 inst->Dump(&std::cerr), op->Dump(&std::cerr))); 351 } 352 353 static void CheckTernaryOperationTypes([[maybe_unused]] GraphVisitor *v, Inst *inst, bool isInt = false) 354 { 355 [[maybe_unused]] auto op1 = inst->GetInputs()[0].GetInst(); 356 [[maybe_unused]] auto op2 = inst->GetInputs()[1].GetInst(); 357 [[maybe_unused]] auto op3 = inst->GetInputs()[1].GetInst(); 358 359 if (isInt) { 360 CHECKER_DO_IF_NOT_VISITOR( 361 v, DataType::GetCommonType(inst->GetType()) == DataType::INT64, 362 (std::cerr << "Ternary instruction type is not a integer", inst->Dump(&std::cerr))); 363 } 364 365 CHECKER_DO_IF_NOT_VISITOR( 366 v, DataType::IsTypeNumeric(op1->GetType()), 367 (std::cerr << "Ternary instruction 1st operand type is not a numeric", inst->Dump(&std::cerr))); 368 CHECKER_DO_IF_NOT_VISITOR( 369 v, DataType::IsTypeNumeric(op2->GetType()), 370 (std::cerr << "Ternary instruction 2nd operand type is not a numeric", inst->Dump(&std::cerr))); 371 CHECKER_DO_IF_NOT_VISITOR( 372 v, DataType::IsTypeNumeric(op3->GetType()), 373 (std::cerr << "Ternary instruction 2nd operand type is not a numeric", inst->Dump(&std::cerr))); 374 CHECKER_DO_IF_NOT_VISITOR(v, DataType::IsTypeNumeric(inst->GetType()), 375 (std::cerr << "Ternary instruction type is not a numeric", inst->Dump(&std::cerr))); 376 377 CHECKER_DO_IF_NOT_VISITOR(v, CheckCommonTypes(op1, op2) && CheckCommonTypes(op2, op3), 378 (std::cerr << "Types of ternary instruction operands are not compatible\n", 379 op1->Dump(&std::cerr), op2->Dump(&std::cerr), op3->Dump(&std::cerr), 380 inst->Dump(&std::cerr))); 381 CHECKER_DO_IF_NOT_VISITOR( 382 v, CheckCommonTypes(inst, op1), 383 (std::cerr << "Types of ternary instruction result and its operands are not compatible\n", 384 inst->Dump(&std::cerr))); 385 } 386 387 static void CheckMemoryInstruction([[maybe_unused]] GraphVisitor *v, [[maybe_unused]] Inst *inst, 388 [[maybe_unused]] bool needBarrier = false) 389 { 390 CHECKER_DO_IF_NOT_VISITOR(v, 391 DataType::IsTypeNumeric(inst->GetType()) || inst->GetType() == DataType::REFERENCE || 392 inst->GetType() == DataType::ANY, 393 (std::cerr << "Memory instruction has wrong type\n", inst->Dump(&std::cerr))); 394 if (inst->IsStore() && (inst->GetInputType(0) != DataType::POINTER) && (inst->GetType() == DataType::ANY)) { 395 CHECKER_DO_IF_NOT_VISITOR(v, needBarrier, 396 (std::cerr << "This store should have barrier:\n", inst->Dump(&std::cerr))); 397 } 398 } 399 CheckObjectTypeDynamic(GraphVisitor * v,Inst * inst,ObjectType type,uint32_t typeId)400 static void CheckObjectTypeDynamic([[maybe_unused]] GraphVisitor *v, Inst *inst, ObjectType type, 401 [[maybe_unused]] uint32_t typeId) 402 { 403 // IrToc use LoadObject and StoreObject with ObjectType::MEM_OBJECT for dynamic 404 // We can inline intrinsics with the instruction under the option --compiler-inline-full-intrinsics=true 405 if (!g_options.IsCompilerInlineFullIntrinsics()) { 406 CHECKER_DO_IF_NOT_VISITOR( 407 v, type != ObjectType::MEM_OBJECT && type != ObjectType::MEM_STATIC, 408 (std::cerr << "The object type isn't supported for dynamic\n", inst->Dump(&std::cerr))); 409 } 410 if (type == ObjectType::MEM_DYN_CLASS) { 411 CHECKER_DO_IF_NOT_VISITOR( 412 v, typeId == TypeIdMixin::MEM_DYN_CLASS_ID, 413 (std::cerr << "The object type_id for MEM_DYN_CLASS is incorrect\n", inst->Dump(&std::cerr))); 414 } else if (type == ObjectType::MEM_DYN_PROPS) { 415 CHECKER_DO_IF_NOT_VISITOR( 416 v, typeId == TypeIdMixin::MEM_DYN_PROPS_ID, 417 (std::cerr << "The object type_id for MEM_DYN_PROPS is incorrect\n", inst->Dump(&std::cerr))); 418 } else if (type == ObjectType::MEM_DYN_PROTO_HOLDER) { 419 CHECKER_DO_IF_NOT_VISITOR( 420 v, typeId == TypeIdMixin::MEM_DYN_PROTO_HOLDER_ID, 421 (std::cerr << "The object type_id for MEM_DYN_PROTO_HOLDER is incorrect\n", inst->Dump(&std::cerr))); 422 } else if (type == ObjectType::MEM_DYN_PROTO_CELL) { 423 [[maybe_unused]] Inst *objInst = inst->GetInput(0).GetInst(); 424 CHECKER_DO_IF_NOT_VISITOR( 425 v, typeId == TypeIdMixin::MEM_DYN_PROTO_CELL_ID, 426 (std::cerr << "The object type_id for MEM_DYN_PROTO_CELL is incorrect\n", inst->Dump(&std::cerr))); 427 } else if (type == ObjectType::MEM_DYN_CHANGE_FIELD) { 428 [[maybe_unused]] Inst *objInst = inst->GetInput(0).GetInst(); 429 CHECKER_DO_IF_NOT_VISITOR( 430 v, typeId == TypeIdMixin::MEM_DYN_CHANGE_FIELD_ID, 431 (std::cerr << "The object type_id for MEM_DYN_CHANGE_FIELD is incorrect\n", inst->Dump(&std::cerr))); 432 } else if (type == ObjectType::MEM_DYN_GLOBAL) { 433 CHECKER_DO_IF_NOT_VISITOR( 434 v, typeId == TypeIdMixin::MEM_DYN_GLOBAL_ID, 435 (std::cerr << "The object type_id for MEM_DYN_GLOBAL is incorrect\n", inst->Dump(&std::cerr))); 436 } else if (type == ObjectType::MEM_DYN_HCLASS) { 437 CHECKER_DO_IF_NOT_VISITOR( 438 v, typeId == TypeIdMixin::MEM_DYN_HCLASS_ID, 439 (std::cerr << "The object type_id for MEM_DYN_HCLASS is incorrect\n", inst->Dump(&std::cerr))); 440 } else { 441 CHECKER_DO_IF_NOT_VISITOR( 442 v, 443 typeId != TypeIdMixin::MEM_DYN_GLOBAL_ID && typeId != TypeIdMixin::MEM_DYN_CLASS_ID && 444 typeId != TypeIdMixin::MEM_DYN_PROPS_ID, 445 (std::cerr << "The object type_id for MEM_DYN_GLOBAL is incorrect\n", inst->Dump(&std::cerr))); 446 } 447 } 448 CheckObjectType(GraphVisitor * v,Inst * inst,ObjectType type,uint32_t typeId)449 static void CheckObjectType([[maybe_unused]] GraphVisitor *v, Inst *inst, ObjectType type, 450 [[maybe_unused]] uint32_t typeId) 451 { 452 auto graph = inst->GetBasicBlock()->GetGraph(); 453 if (!graph->SupportManagedCode()) { 454 return; 455 } 456 if (graph->IsDynamicMethod()) { 457 CheckObjectTypeDynamic(v, inst, type, typeId); 458 } else { 459 CHECKER_DO_IF_NOT_VISITOR( 460 v, type == ObjectType::MEM_OBJECT || type == ObjectType::MEM_STATIC, 461 (std::cerr << "The object type isn't supported for static\n", inst->Dump(&std::cerr))); 462 } 463 } 464 CheckContrlFlowInst(GraphVisitor * v,Inst * inst)465 static void CheckContrlFlowInst([[maybe_unused]] GraphVisitor *v, Inst *inst) 466 { 467 auto block = inst->GetBasicBlock(); 468 [[maybe_unused]] auto lastInst = *block->AllInstsSafeReverse().begin(); 469 CHECKER_DO_IF_NOT_VISITOR( 470 v, (lastInst == inst), 471 (std::cerr << "Control flow instruction must be last instruction in block\n CF instruction:\n", 472 inst->Dump(&std::cerr), std::cerr << "\n last instruction:\n", lastInst->Dump(&std::cerr))); 473 CHECKER_DO_IF_NOT_VISITOR(v, inst->GetUsers().Empty(), 474 (std::cerr << "Control flow instruction has users\n", inst->Dump(&std::cerr))); 475 } 476 CheckThrows(GraphVisitor * v,Inst * inst,std::initializer_list<Opcode> opcs)477 static void CheckThrows([[maybe_unused]] GraphVisitor *v, [[maybe_unused]] Inst *inst, 478 [[maybe_unused]] std::initializer_list<Opcode> opcs) 479 { 480 #ifdef COMPILER_DEBUG_CHECKS 481 const auto &inputs = inst->GetInputs(); 482 auto ssInput = [&inst](const auto &input) { 483 return input.GetInst()->GetOpcode() == Opcode::SaveState || 484 (input.GetInst()->GetOpcode() == Opcode::SaveStateDeoptimize && inst->CanDeoptimize()); 485 }; 486 bool hasSaveState = std::find_if(inputs.begin(), inputs.end(), ssInput) != inputs.end(); 487 488 bool hasOpc = true; 489 for (auto &node : inst->GetUsers()) { 490 auto opc = node.GetInst()->GetOpcode(); 491 hasOpc &= std::find(opcs.begin(), opcs.end(), opc) != opcs.end(); 492 } 493 494 CHECKER_DO_IF_NOT_VISITOR( 495 v, !inst->HasUsers() || hasOpc, 496 (inst->Dump(&std::cerr), 497 std::cerr << "Throw inst doesn't have any users from the list:" << opcs << std::endl)); 498 CHECKER_DO_IF_NOT_VISITOR(v, hasSaveState, 499 (inst->Dump(&std::cerr), std::cerr << "Throw inst without SaveState" << std::endl)); 500 #endif 501 } 502 CheckSaveStateInput(GraphVisitor * v,Inst * inst)503 static void CheckSaveStateInput([[maybe_unused]] GraphVisitor *v, [[maybe_unused]] Inst *inst) 504 { 505 CHECKER_DO_IF_NOT_VISITOR( 506 v, 507 inst->GetInputsCount() != 0 && 508 inst->GetInput(inst->GetInputsCount() - 1).GetInst()->GetOpcode() == Opcode::SaveState, 509 (std::cerr << "Instruction must have SaveState as last input:\n", inst->Dump(&std::cerr))); 510 } 511 GetPassName()512 std::string GetPassName() const 513 { 514 return passName_; 515 } 516 IncrementNullPtrInstCounterAndGet()517 int IncrementNullPtrInstCounterAndGet() 518 { 519 return ++nullPtrInstCounter_; 520 } 521 IncrementLoadUndefinedInstCounterAndGet()522 int IncrementLoadUndefinedInstCounterAndGet() 523 { 524 return ++loadUndefinedInstCounter_; 525 } 526 527 void PrintFailedMethodAndPass() const; 528 static void PrintFailedMethodAndPassVisitor(GraphVisitor *v); 529 530 private: 531 Graph *graph_; 532 ArenaAllocator allocator_ {SpaceType::SPACE_TYPE_COMPILER, nullptr, true}; 533 ArenaAllocator localAllocator_ {SpaceType::SPACE_TYPE_COMPILER, nullptr, true}; 534 int nullPtrInstCounter_ = 0; 535 int loadUndefinedInstCounter_ = 0; 536 std::string passName_; 537 bool success_ {true}; 538 }; 539 } // namespace ark::compiler 540 541 #undef CHECKER_DO_IF_NOT_VISITOR 542 543 #endif // COMPILER_OPTIMIZER_IR_GRAPH_CHECKER_H 544