• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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