1 /**
2 * Copyright (c) 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 #include "string_builder_utils.h"
17
18 namespace ark::compiler {
19
IsStringBuilderInstance(Inst * inst)20 bool IsStringBuilderInstance(Inst *inst)
21 {
22 if (inst->GetOpcode() != Opcode::NewObject) {
23 return false;
24 }
25
26 auto klass = GetObjectClass(inst->CastToNewObject());
27 if (klass == nullptr) {
28 return false;
29 }
30
31 auto runtime = inst->GetBasicBlock()->GetGraph()->GetRuntime();
32 return runtime->IsClassStringBuilder(klass);
33 }
34
IsMethodStringConcat(Inst * inst)35 bool IsMethodStringConcat(Inst *inst)
36 {
37 if (inst->GetOpcode() != Opcode::CallStatic && inst->GetOpcode() != Opcode::CallVirtual) {
38 return false;
39 }
40
41 auto call = static_cast<CallInst *>(inst);
42 if (call->IsInlined()) {
43 return false;
44 }
45
46 auto runtime = inst->GetBasicBlock()->GetGraph()->GetRuntime();
47 return runtime->IsMethodStringConcat(call->GetCallMethod());
48 }
49
IsMethodStringBuilderConstructorWithStringArg(Inst * inst)50 bool IsMethodStringBuilderConstructorWithStringArg(Inst *inst)
51 {
52 if (inst->GetOpcode() != Opcode::CallStatic) {
53 return false;
54 }
55
56 auto call = inst->CastToCallStatic();
57 if (call->IsInlined()) {
58 return false;
59 }
60
61 auto runtime = inst->GetBasicBlock()->GetGraph()->GetRuntime();
62 return runtime->IsMethodStringBuilderConstructorWithStringArg(call->GetCallMethod());
63 }
64
IsMethodStringBuilderConstructorWithCharArrayArg(Inst * inst)65 bool IsMethodStringBuilderConstructorWithCharArrayArg(Inst *inst)
66 {
67 if (inst->GetOpcode() != Opcode::CallStatic) {
68 return false;
69 }
70
71 auto call = inst->CastToCallStatic();
72 if (call->IsInlined()) {
73 return false;
74 }
75
76 auto runtime = inst->GetBasicBlock()->GetGraph()->GetRuntime();
77 return runtime->IsMethodStringBuilderConstructorWithCharArrayArg(call->GetCallMethod());
78 }
79
IsStringBuilderToString(Inst * inst)80 bool IsStringBuilderToString(Inst *inst)
81 {
82 auto runtime = inst->GetBasicBlock()->GetGraph()->GetRuntime();
83 if (inst->GetOpcode() == Opcode::CallStatic || inst->GetOpcode() == Opcode::CallVirtual) {
84 auto callInst = static_cast<CallInst *>(inst);
85 return !callInst->IsInlined() && runtime->IsMethodStringBuilderToString(callInst->GetCallMethod());
86 }
87 if (inst->IsIntrinsic()) {
88 auto intrinsic = inst->CastToIntrinsic();
89 return runtime->IsIntrinsicStringBuilderToString(intrinsic->GetIntrinsicId());
90 }
91 return false;
92 }
93
IsMethodStringBuilderDefaultConstructor(Inst * inst)94 bool IsMethodStringBuilderDefaultConstructor(Inst *inst)
95 {
96 if (inst->GetOpcode() != Opcode::CallStatic) {
97 return false;
98 }
99
100 auto call = inst->CastToCallStatic();
101 if (call->IsInlined()) {
102 return false;
103 }
104
105 auto runtime = inst->GetBasicBlock()->GetGraph()->GetRuntime();
106 return runtime->IsMethodStringBuilderDefaultConstructor(call->GetCallMethod());
107 }
108
InsertBeforeWithSaveState(Inst * inst,Inst * before)109 void InsertBeforeWithSaveState(Inst *inst, Inst *before)
110 {
111 if (inst->RequireState()) {
112 before->InsertBefore(inst->GetSaveState());
113 }
114 before->InsertBefore(inst);
115 }
116
InsertAfterWithSaveState(Inst * inst,Inst * after)117 void InsertAfterWithSaveState(Inst *inst, Inst *after)
118 {
119 after->InsertAfter(inst);
120 if (inst->RequireState()) {
121 after->InsertAfter(inst->GetSaveState());
122 }
123 }
124
InsertBeforeWithInputs(Inst * inst,Inst * before)125 void InsertBeforeWithInputs(Inst *inst, Inst *before)
126 {
127 for (auto &input : inst->GetInputs()) {
128 auto inputInst = input.GetInst();
129 if (inputInst->GetBasicBlock() == nullptr) {
130 InsertBeforeWithInputs(inputInst, before);
131 }
132 }
133
134 if (inst->GetBasicBlock() == nullptr) {
135 before->InsertBefore(inst);
136 }
137 }
138
HasInput(Inst * inst,const FindInputPredicate & predicate)139 bool HasInput(Inst *inst, const FindInputPredicate &predicate)
140 {
141 // Check if any instruction input satisfy predicate
142
143 auto found = std::find_if(inst->GetInputs().begin(), inst->GetInputs().end(), predicate);
144 return found != inst->GetInputs().end();
145 }
146
HasInputPhiRecursively(Inst * inst,Marker visited,const FindInputPredicate & predicate)147 bool HasInputPhiRecursively(Inst *inst, Marker visited, const FindInputPredicate &predicate)
148 {
149 // Check if any instruction input satisfy predicate
150 // All Phi-instruction inputs are checked recursively
151
152 if (HasInput(inst, predicate)) {
153 return true;
154 }
155
156 inst->SetMarker(visited);
157
158 for (auto &input : inst->GetInputs()) {
159 auto inputInst = input.GetInst();
160 if (!inputInst->IsPhi()) {
161 continue;
162 }
163 if (inputInst->IsMarked(visited)) {
164 continue;
165 }
166 if (HasInputPhiRecursively(inputInst, visited, predicate)) {
167 return true;
168 }
169 }
170
171 return false;
172 }
173
ResetInputMarkersRecursively(Inst * inst,Marker visited)174 void ResetInputMarkersRecursively(Inst *inst, Marker visited)
175 {
176 // Reset marker for an instruction and all it's inputs recursively
177
178 if (inst->IsMarked(visited)) {
179 inst->ResetMarker(visited);
180
181 for (auto &input : inst->GetInputs()) {
182 auto inputInst = input.GetInst();
183 if (inputInst->IsMarked(visited)) {
184 ResetInputMarkersRecursively(inputInst, visited);
185 }
186 }
187 }
188 }
189
HasUser(Inst * inst,const FindUserPredicate & predicate)190 bool HasUser(Inst *inst, const FindUserPredicate &predicate)
191 {
192 // Check if instruction is used in a context defined by predicate
193
194 auto found = std::find_if(inst->GetUsers().begin(), inst->GetUsers().end(), predicate);
195 return found != inst->GetUsers().end();
196 }
197
HasUserPhiRecursively(Inst * inst,Marker visited,const FindUserPredicate & predicate)198 bool HasUserPhiRecursively(Inst *inst, Marker visited, const FindUserPredicate &predicate)
199 {
200 // Check if instruction is used in a context defined by predicate
201 // All Phi-instruction users are checked recursively
202
203 if (HasUser(inst, predicate)) {
204 return true;
205 }
206
207 inst->SetMarker(visited);
208
209 for (auto &user : inst->GetUsers()) {
210 auto userInst = user.GetInst();
211 if (!userInst->IsPhi()) {
212 continue;
213 }
214 if (userInst->IsMarked(visited)) {
215 continue;
216 }
217 if (HasUserPhiRecursively(userInst, visited, predicate)) {
218 return true;
219 }
220 }
221
222 return false;
223 }
224
ResetUserMarkersRecursively(Inst * inst,Marker visited)225 void ResetUserMarkersRecursively(Inst *inst, Marker visited)
226 {
227 // Reset marker for an instruction and all it's users recursively
228
229 if (inst->IsMarked(visited)) {
230 inst->ResetMarker(visited);
231
232 for (auto &user : inst->GetUsers()) {
233 auto userInst = user.GetInst();
234 if (userInst->IsMarked(visited)) {
235 ResetUserMarkersRecursively(userInst, visited);
236 }
237 }
238 }
239 }
240
SkipSingleUserCheckInstruction(Inst * inst)241 Inst *SkipSingleUserCheckInstruction(Inst *inst)
242 {
243 if (inst->IsCheck() && inst->HasSingleUser()) {
244 inst = inst->GetUsers().Front().GetInst();
245 }
246 return inst;
247 }
248
249 } // namespace ark::compiler
250