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_ANALYSIS_H
17 #define COMPILER_OPTIMIZER_IR_ANALYSIS_H
18
19 #include "graph.h"
20
21 #include <optional>
22
23 namespace ark::compiler {
24
25 /// The file contains small analysis functions which can be used in different passes
26 class Inst;
27 class BasicBlock;
28 // returns Store value, for StoreArrayPair and StoreArrayPairI saved not last store value in second_value
29 Inst *InstStoredValue(Inst *inst, Inst **secondValue);
30 Inst *InstStoredValue(Inst *inst);
31
32 template <typename T = Inst>
33 bool HasOsrEntryBetween(T *dominate, T *current);
34 bool HasTryBlockBetween(Inst *dominateInst, Inst *inst);
35 bool IsSuitableForImplicitNullCheck(const Inst *inst);
36 bool IsInstNotNull(const Inst *inst);
37 bool CheckFcmpInputs(Inst *input0, Inst *input1);
38 bool CheckFcmpWithConstInput(Inst *input0, Inst *input1);
39 int64_t GetPowerOfTwo(uint64_t n);
40 bool CanRemoveOverflowCheck(Inst *inst, Marker marker);
41 bool IsCastAllowedInBytecode(const Inst *inst);
42 bool IsInputTypeMismatch(Inst *inst, int32_t inputIndex, Arch arch);
43 bool ApplyForCastJoin(Inst *cast, Inst *input, Inst *origInst, Arch arch);
44 SaveStateInst *CopySaveState(Graph *graph, SaveStateInst *inst);
45 std::optional<bool> IsIfInverted(BasicBlock *phiBlock, IfImmInst *ifImm);
46 bool CheckArrayFieldObject(RuntimeInterface::ArrayField kind, Inst *inst);
47 bool CheckArrayField(RuntimeInterface::ArrayField kind, Inst *inst, Inst *&arrayOriginRef);
48
49 // If object input has known class, return pointer to the class, else returns nullptr
50 RuntimeInterface::ClassPtr GetClassPtrForObject(Inst *inst, size_t inputNum = 0);
51 RuntimeInterface::ClassPtr GetObjectClass(Inst *inst);
52 RuntimeInterface::ClassPtr GetClass(Inst *inst);
53
IsInstInDifferentBlocks(Inst * i1,Inst * i2)54 inline bool IsInstInDifferentBlocks(Inst *i1, Inst *i2)
55 {
56 return i1->GetBasicBlock() != i2->GetBasicBlock();
57 }
58
InstHasPseudoInputs(Inst * inst)59 inline bool InstHasPseudoInputs(Inst *inst)
60 {
61 return inst->GetOpcode() == Opcode::WrapObjectNative;
62 }
63
64 // This function bypass all blocks and delete 'SaveStateOSR' if the block is no longer the header of the loop
65 void CleanupGraphSaveStateOSR(Graph *graph);
66
67 class IsSaveState;
68 class IsSaveStateCanTriggerGc;
69 // returns true is there is SaveState/SafePoint between instructions
70 template <typename T = IsSaveState>
71 bool HasSaveStateBetween(Inst *domInst, Inst *inst);
72
73 bool IsSaveStateForGc(const Inst *inst);
74
75 /**
76 * Functions below are using for create bridge in SaveStates between source instruction and target instruction.
77 * It use in GVN etc. It inserts `source` instruction into `SaveStates` on each path between `source` and
78 * `target` instructions to save the object in case GC is triggered on this path.
79 * Instructions on how to use it: compiler/docs/bridges.md
80 */
81 class SaveStateBridgesBuilder {
82 public:
83 ArenaVector<Inst *> *SearchMissingObjInSaveStates(Graph *graph, Inst *source, Inst *target,
84 Inst *stopSearch = nullptr, BasicBlock *targetBlock = nullptr);
85 void CreateBridgeInSS(Inst *source);
86 void SearchAndCreateMissingObjInSaveState(Graph *graph, Inst *source, Inst *target, Inst *stopSearchInst = nullptr,
87 BasicBlock *targetBlock = nullptr);
88 void FixInstUsageInSS(Graph *graph, Inst *inst);
89 void FixSaveStatesInBB(BasicBlock *block);
90 void FixPhisWithCheckInputs(BasicBlock *block);
91 void DumpBridges(std::ostream &out, Inst *source);
92
93 private:
94 void SearchSSOnWay(BasicBlock *block, Inst *startFrom, Inst *sourceInst, Marker visited, Inst *stopSearch);
95 bool IsSaveStateForGc(Inst *inst);
96 void ProcessSSUserPreds(Graph *graph, Inst *inst, Inst *targetInst);
97 void SearchInSaveStateAndFillBridgeVector(Inst *inst, Inst *searchedInst);
98 void FixUsageInstInOtherBB(BasicBlock *block, Inst *inst);
99 void FixUsagePhiInBB(BasicBlock *block, Inst *inst);
100 void DeleteUnrealObjInSaveState(Inst *ss);
101 /**
102 * Pointer to moved out to class for reduce memory usage in each pair of equal instructions.
103 * When using functions, it looks like we work as if every time get a new vector,
104 * but one vector is always used and cleaned before use.
105 */
106 ArenaVector<Inst *> *bridges_ {nullptr};
107 };
108
109 class InstAppender {
110 public:
block_(block)111 explicit InstAppender(BasicBlock *block, Inst *insertAfter = nullptr) : block_(block), prev_(insertAfter) {}
112 ~InstAppender() = default;
113 DEFAULT_MOVE_SEMANTIC(InstAppender);
114 NO_COPY_SEMANTIC(InstAppender);
115
116 void Append(Inst *inst);
117 void Append(std::initializer_list<Inst *> instructions);
118
119 private:
120 BasicBlock *block_;
121 Inst *prev_ {nullptr};
122 };
123
124 bool StoreValueCanBeObject(Inst *inst);
125
126 bool IsConditionEqual(const Inst *inst0, const Inst *inst1, bool inverted);
127
128 } // namespace ark::compiler
129
130 #endif // COMPILER_OPTIMIZER_IR_ANALYSIS_H
131