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