1 /**
2 * Copyright (c) 2021-2022 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 "compiler/optimizer/optimizations/peepholes.h"
17 #include "compiler/optimizer/ir/analysis.h"
18 #include "compiler/optimizer/ir/runtime_interface.h"
19
20 namespace panda::compiler {
PeepholeStringEquals(GraphVisitor * v,IntrinsicInst * intrinsic)21 bool Peepholes::PeepholeStringEquals([[maybe_unused]] GraphVisitor *v, IntrinsicInst *intrinsic)
22 {
23 // Replaces
24 // Intrinsic.StdCoreStringEquals arg, NullPtr
25 // with
26 // Compare EQ ref arg, NullPtr
27
28 auto input0 = intrinsic->GetInput(0).GetInst();
29 auto input1 = intrinsic->GetInput(1).GetInst();
30 if (input0->IsNullPtr() || input1->IsNullPtr()) {
31 auto bb = intrinsic->GetBasicBlock();
32 auto graph = bb->GetGraph();
33
34 auto compare = graph->CreateInst(Opcode::Compare)->CastToCompare();
35 compare->SetCc(ConditionCode::CC_EQ);
36 compare->SetType(intrinsic->GetType());
37 ASSERT(input0->GetType() == input1->GetType());
38 compare->SetOperandsType(input0->GetType());
39
40 compare->SetInput(0, input0);
41 compare->SetInput(1, input1);
42 bb->InsertAfter(compare, intrinsic);
43 intrinsic->ReplaceUsers(compare);
44
45 return true;
46 }
47
48 return false;
49 }
50
GetStringFromLength(Inst * inst)51 Inst *GetStringFromLength(Inst *inst)
52 {
53 Inst *lenArray = inst;
54 if (inst->GetBasicBlock()->GetGraph()->GetRuntime()->IsCompressedStringsEnabled()) {
55 if (inst->GetOpcode() != Opcode::Shr || inst->GetType() != DataType::INT32) {
56 return nullptr;
57 }
58 auto input1 = inst->GetInput(1).GetInst();
59 if (!input1->IsConst() || input1->CastToConstant()->GetRawValue() != 1) {
60 return nullptr;
61 }
62 lenArray = inst->GetInput(0).GetInst();
63 }
64
65 if (lenArray->GetOpcode() != Opcode::LenArray || !lenArray->CastToLenArray()->IsString()) {
66 return nullptr;
67 }
68 return lenArray->GetDataFlowInput(0);
69 }
70
PeepholeStringSubstring(GraphVisitor * v,IntrinsicInst * intrinsic)71 bool Peepholes::PeepholeStringSubstring([[maybe_unused]] GraphVisitor *v, IntrinsicInst *intrinsic)
72 {
73 // Replaces
74 // string
75 // Intrinsic.StdCoreStringSubstring string, 0, string.Length -> .....
76 // with
77 // string -> .....
78
79 auto string = intrinsic->GetDataFlowInput(0);
80 auto begin = intrinsic->GetInput(1).GetInst();
81 auto end = intrinsic->GetInput(2).GetInst();
82 if (!begin->IsConst() || begin->GetType() != DataType::INT64) {
83 return false;
84 }
85 if (static_cast<int64_t>(begin->CastToConstant()->GetRawValue()) > 0) {
86 return false;
87 }
88 if (GetStringFromLength(end) != string) {
89 return false;
90 }
91 intrinsic->ReplaceUsers(string);
92 intrinsic->ClearFlag(inst_flags::NO_DCE);
93
94 return true;
95 }
96
97 template <bool IS_STORE>
TryInsertFieldInst(IntrinsicInst * intrinsic,RuntimeInterface::ClassPtr klassPtr,RuntimeInterface::FieldPtr rawField,size_t fieldId)98 bool TryInsertFieldInst(IntrinsicInst *intrinsic, RuntimeInterface::ClassPtr klassPtr,
99 RuntimeInterface::FieldPtr rawField, size_t fieldId)
100 {
101 auto graph = intrinsic->GetBasicBlock()->GetGraph();
102 auto runtime = graph->GetRuntime();
103 auto field = runtime->ResolveLookUpField(rawField, klassPtr);
104 if (field == nullptr) {
105 return false;
106 }
107 Inst *memObj;
108 auto type = intrinsic->GetType();
109 auto pc = intrinsic->GetPc();
110 if constexpr (IS_STORE) {
111 auto storeField = graph->CreateInstStoreObject(type, pc);
112 storeField->SetTypeId(fieldId);
113 storeField->SetMethod(intrinsic->GetMethod());
114 storeField->SetObjField(field);
115 if (runtime->IsFieldVolatile(field)) {
116 storeField->SetVolatile(true);
117 }
118 if (type == DataType::REFERENCE) {
119 storeField->SetNeedBarrier(true);
120 }
121 storeField->SetInput(1, intrinsic->GetInput(1).GetInst());
122 memObj = storeField;
123 } else {
124 auto loadField = graph->CreateInstLoadObject(type, pc);
125 loadField->SetTypeId(fieldId);
126 loadField->SetMethod(intrinsic->GetMethod());
127 loadField->SetObjField(field);
128 if (runtime->IsFieldVolatile(field)) {
129 loadField->SetVolatile(true);
130 }
131 memObj = loadField;
132 intrinsic->ReplaceUsers(loadField);
133 }
134 memObj->SetInput(0, intrinsic->GetInput(0).GetInst());
135 intrinsic->InsertAfter(memObj);
136
137 intrinsic->ClearFlag(inst_flags::NO_DCE);
138 return true;
139 }
140
141 template <bool IS_STORE>
TryInsertCallInst(IntrinsicInst * intrinsic,RuntimeInterface::ClassPtr klassPtr,RuntimeInterface::FieldPtr rawField)142 bool TryInsertCallInst(IntrinsicInst *intrinsic, RuntimeInterface::ClassPtr klassPtr,
143 RuntimeInterface::FieldPtr rawField)
144 {
145 auto graph = intrinsic->GetBasicBlock()->GetGraph();
146 auto runtime = graph->GetRuntime();
147 auto method = runtime->ResolveLookUpCall(rawField, klassPtr, IS_STORE);
148 if (method == nullptr) {
149 return false;
150 }
151 auto type = IS_STORE ? DataType::VOID : intrinsic->GetType();
152 auto pc = intrinsic->GetPc();
153
154 auto call = graph->CreateInstCallVirtual(type, pc, runtime->GetMethodId(method));
155 call->SetCallMethod(method);
156 size_t numInputs = IS_STORE ? 3 : 2;
157 call->ReserveInputs(numInputs);
158 call->AllocateInputTypes(graph->GetAllocator(), numInputs);
159 for (size_t i = 0; i < numInputs; ++i) {
160 call->AppendInputAndType(intrinsic->GetInput(i).GetInst(), intrinsic->GetInputType(i));
161 }
162 intrinsic->InsertAfter(call);
163 intrinsic->ReplaceUsers(call);
164 intrinsic->ClearFlag(inst_flags::NO_DCE);
165 return true;
166 }
167
PeepholeLdObjByName(GraphVisitor * v,IntrinsicInst * intrinsic)168 bool Peepholes::PeepholeLdObjByName(GraphVisitor *v, IntrinsicInst *intrinsic)
169 {
170 auto klassPtr = GetClassPtrForObject(intrinsic);
171 if (klassPtr == nullptr) {
172 return false;
173 }
174 auto graph = intrinsic->GetBasicBlock()->GetGraph();
175 auto method = intrinsic->GetMethod();
176 auto runtime = graph->GetRuntime();
177 auto fieldId = intrinsic->GetImm(0);
178 auto rawField = runtime->ResolveField(method, fieldId, !graph->IsAotMode(), nullptr);
179 ASSERT(rawField != nullptr);
180
181 if (TryInsertFieldInst<false>(intrinsic, klassPtr, rawField, fieldId)) {
182 PEEPHOLE_IS_APPLIED(static_cast<Peepholes *>(v), intrinsic);
183 return true;
184 }
185 if (TryInsertCallInst<false>(intrinsic, klassPtr, rawField)) {
186 PEEPHOLE_IS_APPLIED(static_cast<Peepholes *>(v), intrinsic);
187 return true;
188 }
189 return false;
190 }
191
PeepholeStObjByName(GraphVisitor * v,IntrinsicInst * intrinsic)192 bool Peepholes::PeepholeStObjByName(GraphVisitor *v, IntrinsicInst *intrinsic)
193 {
194 auto klassPtr = GetClassPtrForObject(intrinsic);
195 if (klassPtr == nullptr) {
196 return false;
197 }
198 auto graph = intrinsic->GetBasicBlock()->GetGraph();
199 auto method = intrinsic->GetMethod();
200 auto runtime = graph->GetRuntime();
201 auto fieldId = intrinsic->GetImm(0);
202 auto rawField = runtime->ResolveField(method, fieldId, !graph->IsAotMode(), nullptr);
203 ASSERT(rawField != nullptr);
204
205 if (TryInsertFieldInst<true>(intrinsic, klassPtr, rawField, fieldId)) {
206 PEEPHOLE_IS_APPLIED(static_cast<Peepholes *>(v), intrinsic);
207 return true;
208 }
209 if (TryInsertCallInst<true>(intrinsic, klassPtr, rawField)) {
210 PEEPHOLE_IS_APPLIED(static_cast<Peepholes *>(v), intrinsic);
211 return true;
212 }
213 return false;
214 }
215
216 } // namespace panda::compiler