xref: /aosp_15_r20/art/compiler/optimizing/instruction_simplifier_test.cc (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker  * Copyright (C) 2021 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker  *
4*795d594fSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker  *
8*795d594fSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker  *
10*795d594fSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker  * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker  */
16*795d594fSAndroid Build Coastguard Worker 
17*795d594fSAndroid Build Coastguard Worker #include "instruction_simplifier.h"
18*795d594fSAndroid Build Coastguard Worker 
19*795d594fSAndroid Build Coastguard Worker #include <initializer_list>
20*795d594fSAndroid Build Coastguard Worker #include <tuple>
21*795d594fSAndroid Build Coastguard Worker 
22*795d594fSAndroid Build Coastguard Worker #include "gtest/gtest.h"
23*795d594fSAndroid Build Coastguard Worker 
24*795d594fSAndroid Build Coastguard Worker #include "class_root-inl.h"
25*795d594fSAndroid Build Coastguard Worker #include "nodes.h"
26*795d594fSAndroid Build Coastguard Worker #include "optimizing/data_type.h"
27*795d594fSAndroid Build Coastguard Worker #include "optimizing_unit_test.h"
28*795d594fSAndroid Build Coastguard Worker 
29*795d594fSAndroid Build Coastguard Worker namespace art HIDDEN {
30*795d594fSAndroid Build Coastguard Worker 
31*795d594fSAndroid Build Coastguard Worker namespace mirror {
32*795d594fSAndroid Build Coastguard Worker class ClassExt;
33*795d594fSAndroid Build Coastguard Worker class Throwable;
34*795d594fSAndroid Build Coastguard Worker }  // namespace mirror
35*795d594fSAndroid Build Coastguard Worker 
36*795d594fSAndroid Build Coastguard Worker static constexpr bool kDebugSimplifierTests = false;
37*795d594fSAndroid Build Coastguard Worker 
38*795d594fSAndroid Build Coastguard Worker template<typename SuperClass>
39*795d594fSAndroid Build Coastguard Worker class InstructionSimplifierTestBase : public SuperClass, public OptimizingUnitTestHelper {
40*795d594fSAndroid Build Coastguard Worker  public:
InstructionSimplifierTestBase()41*795d594fSAndroid Build Coastguard Worker   InstructionSimplifierTestBase() {
42*795d594fSAndroid Build Coastguard Worker     this->use_boot_image_ = true;  // Make the Runtime creation cheaper.
43*795d594fSAndroid Build Coastguard Worker   }
44*795d594fSAndroid Build Coastguard Worker 
SetUp()45*795d594fSAndroid Build Coastguard Worker   void SetUp() override {
46*795d594fSAndroid Build Coastguard Worker     SuperClass::SetUp();
47*795d594fSAndroid Build Coastguard Worker     gLogVerbosity.compiler = true;
48*795d594fSAndroid Build Coastguard Worker   }
49*795d594fSAndroid Build Coastguard Worker 
TearDown()50*795d594fSAndroid Build Coastguard Worker   void TearDown() override {
51*795d594fSAndroid Build Coastguard Worker     SuperClass::TearDown();
52*795d594fSAndroid Build Coastguard Worker     gLogVerbosity.compiler = false;
53*795d594fSAndroid Build Coastguard Worker   }
54*795d594fSAndroid Build Coastguard Worker 
PerformSimplification()55*795d594fSAndroid Build Coastguard Worker   void PerformSimplification() {
56*795d594fSAndroid Build Coastguard Worker     if (kDebugSimplifierTests) {
57*795d594fSAndroid Build Coastguard Worker       graph_->Dump(LOG_STREAM(INFO) << "Pre simplification ", /* codegen_= */ nullptr);
58*795d594fSAndroid Build Coastguard Worker     }
59*795d594fSAndroid Build Coastguard Worker     graph_->ClearDominanceInformation();
60*795d594fSAndroid Build Coastguard Worker     graph_->BuildDominatorTree();
61*795d594fSAndroid Build Coastguard Worker     InstructionSimplifier simp(graph_, /*codegen=*/nullptr);
62*795d594fSAndroid Build Coastguard Worker     simp.Run();
63*795d594fSAndroid Build Coastguard Worker     if (kDebugSimplifierTests) {
64*795d594fSAndroid Build Coastguard Worker       graph_->Dump(LOG_STREAM(INFO) << "Post simplify ", /* codegen_= */ nullptr);
65*795d594fSAndroid Build Coastguard Worker     }
66*795d594fSAndroid Build Coastguard Worker   }
67*795d594fSAndroid Build Coastguard Worker };
68*795d594fSAndroid Build Coastguard Worker 
69*795d594fSAndroid Build Coastguard Worker class InstructionSimplifierTest : public InstructionSimplifierTestBase<CommonCompilerTest> {};
70*795d594fSAndroid Build Coastguard Worker 
71*795d594fSAndroid Build Coastguard Worker // Various configs we can use for testing. Currently used in PartialComparison tests.
72*795d594fSAndroid Build Coastguard Worker enum class InstanceOfKind {
73*795d594fSAndroid Build Coastguard Worker   kSelf,
74*795d594fSAndroid Build Coastguard Worker   kUnrelatedLoaded,
75*795d594fSAndroid Build Coastguard Worker   kUnrelatedUnloaded,
76*795d594fSAndroid Build Coastguard Worker   kSupertype,
77*795d594fSAndroid Build Coastguard Worker };
78*795d594fSAndroid Build Coastguard Worker 
operator <<(std::ostream & os,const InstanceOfKind & comp)79*795d594fSAndroid Build Coastguard Worker std::ostream& operator<<(std::ostream& os, const InstanceOfKind& comp) {
80*795d594fSAndroid Build Coastguard Worker   switch (comp) {
81*795d594fSAndroid Build Coastguard Worker     case InstanceOfKind::kSupertype:
82*795d594fSAndroid Build Coastguard Worker       return os << "kSupertype";
83*795d594fSAndroid Build Coastguard Worker     case InstanceOfKind::kSelf:
84*795d594fSAndroid Build Coastguard Worker       return os << "kSelf";
85*795d594fSAndroid Build Coastguard Worker     case InstanceOfKind::kUnrelatedLoaded:
86*795d594fSAndroid Build Coastguard Worker       return os << "kUnrelatedLoaded";
87*795d594fSAndroid Build Coastguard Worker     case InstanceOfKind::kUnrelatedUnloaded:
88*795d594fSAndroid Build Coastguard Worker       return os << "kUnrelatedUnloaded";
89*795d594fSAndroid Build Coastguard Worker   }
90*795d594fSAndroid Build Coastguard Worker }
91*795d594fSAndroid Build Coastguard Worker 
92*795d594fSAndroid Build Coastguard Worker class InstanceOfInstructionSimplifierTestGroup
93*795d594fSAndroid Build Coastguard Worker     : public InstructionSimplifierTestBase<CommonCompilerTestWithParam<InstanceOfKind>> {
94*795d594fSAndroid Build Coastguard Worker  public:
GetConstantResult() const95*795d594fSAndroid Build Coastguard Worker   bool GetConstantResult() const {
96*795d594fSAndroid Build Coastguard Worker     switch (GetParam()) {
97*795d594fSAndroid Build Coastguard Worker       case InstanceOfKind::kSupertype:
98*795d594fSAndroid Build Coastguard Worker       case InstanceOfKind::kSelf:
99*795d594fSAndroid Build Coastguard Worker         return true;
100*795d594fSAndroid Build Coastguard Worker       case InstanceOfKind::kUnrelatedLoaded:
101*795d594fSAndroid Build Coastguard Worker       case InstanceOfKind::kUnrelatedUnloaded:
102*795d594fSAndroid Build Coastguard Worker         return false;
103*795d594fSAndroid Build Coastguard Worker     }
104*795d594fSAndroid Build Coastguard Worker   }
105*795d594fSAndroid Build Coastguard Worker 
GetLoadClasses(HBasicBlock * block,VariableSizedHandleScope * vshs)106*795d594fSAndroid Build Coastguard Worker   std::pair<HLoadClass*, HLoadClass*> GetLoadClasses(HBasicBlock* block,
107*795d594fSAndroid Build Coastguard Worker                                                      VariableSizedHandleScope* vshs)
108*795d594fSAndroid Build Coastguard Worker       REQUIRES_SHARED(Locks::mutator_lock_) {
109*795d594fSAndroid Build Coastguard Worker     InstanceOfKind kind = GetParam();
110*795d594fSAndroid Build Coastguard Worker     // New inst always needs to have a valid rti since we dcheck that.
111*795d594fSAndroid Build Coastguard Worker     HLoadClass* new_inst = MakeLoadClass(
112*795d594fSAndroid Build Coastguard Worker         block,
113*795d594fSAndroid Build Coastguard Worker         /* ti= */ std::nullopt,
114*795d594fSAndroid Build Coastguard Worker         vshs->NewHandle<mirror::Class>(GetClassRoot<mirror::ClassExt>()));
115*795d594fSAndroid Build Coastguard Worker     new_inst->SetValidLoadedClassRTI();
116*795d594fSAndroid Build Coastguard Worker     if (kind == InstanceOfKind::kSelf) {
117*795d594fSAndroid Build Coastguard Worker       return {new_inst, new_inst};
118*795d594fSAndroid Build Coastguard Worker     }
119*795d594fSAndroid Build Coastguard Worker     if (kind == InstanceOfKind::kUnrelatedUnloaded) {
120*795d594fSAndroid Build Coastguard Worker       HLoadClass* target_class = MakeLoadClass(block);
121*795d594fSAndroid Build Coastguard Worker       EXPECT_FALSE(target_class->GetLoadedClassRTI().IsValid());
122*795d594fSAndroid Build Coastguard Worker       return {new_inst, target_class};
123*795d594fSAndroid Build Coastguard Worker     }
124*795d594fSAndroid Build Coastguard Worker     // Force both classes to be a real classes.
125*795d594fSAndroid Build Coastguard Worker     // For simplicity we use class-roots as the types. The new-inst will always
126*795d594fSAndroid Build Coastguard Worker     // be a ClassExt, unrelated-loaded will always be Throwable and super will
127*795d594fSAndroid Build Coastguard Worker     // always be Object
128*795d594fSAndroid Build Coastguard Worker     HLoadClass* target_class = MakeLoadClass(
129*795d594fSAndroid Build Coastguard Worker         block,
130*795d594fSAndroid Build Coastguard Worker         /* ti= */ std::nullopt,
131*795d594fSAndroid Build Coastguard Worker         vshs->NewHandle<mirror::Class>(kind == InstanceOfKind::kSupertype ?
132*795d594fSAndroid Build Coastguard Worker                                            GetClassRoot<mirror::Object>() :
133*795d594fSAndroid Build Coastguard Worker                                            GetClassRoot<mirror::Throwable>()));
134*795d594fSAndroid Build Coastguard Worker     target_class->SetValidLoadedClassRTI();
135*795d594fSAndroid Build Coastguard Worker     EXPECT_TRUE(target_class->GetLoadedClassRTI().IsValid());
136*795d594fSAndroid Build Coastguard Worker     return {new_inst, target_class};
137*795d594fSAndroid Build Coastguard Worker   }
138*795d594fSAndroid Build Coastguard Worker };
139*795d594fSAndroid Build Coastguard Worker 
140*795d594fSAndroid Build Coastguard Worker // // ENTRY
141*795d594fSAndroid Build Coastguard Worker // obj = new Obj();
142*795d594fSAndroid Build Coastguard Worker // // Make sure this graph isn't broken
143*795d594fSAndroid Build Coastguard Worker // if (obj instanceof <other>) {
144*795d594fSAndroid Build Coastguard Worker //   // LEFT
145*795d594fSAndroid Build Coastguard Worker // } else {
146*795d594fSAndroid Build Coastguard Worker //   // RIGHT
147*795d594fSAndroid Build Coastguard Worker // }
148*795d594fSAndroid Build Coastguard Worker // EXIT
149*795d594fSAndroid Build Coastguard Worker // return obj.field
TEST_P(InstanceOfInstructionSimplifierTestGroup,ExactClassInstanceOfOther)150*795d594fSAndroid Build Coastguard Worker TEST_P(InstanceOfInstructionSimplifierTestGroup, ExactClassInstanceOfOther) {
151*795d594fSAndroid Build Coastguard Worker   ScopedObjectAccess soa(Thread::Current());
152*795d594fSAndroid Build Coastguard Worker   VariableSizedHandleScope vshs(soa.Self());
153*795d594fSAndroid Build Coastguard Worker   HBasicBlock* breturn = InitEntryMainExitGraph(/*handles=*/&vshs);
154*795d594fSAndroid Build Coastguard Worker   auto [if_block, left, right] = CreateDiamondPattern(breturn);
155*795d594fSAndroid Build Coastguard Worker   EnsurePredecessorOrder(breturn, {left, right});
156*795d594fSAndroid Build Coastguard Worker 
157*795d594fSAndroid Build Coastguard Worker   HInstruction* test_res = graph_->GetIntConstant(GetConstantResult() ? 1 : 0);
158*795d594fSAndroid Build Coastguard Worker 
159*795d594fSAndroid Build Coastguard Worker   auto [new_inst_klass, target_klass] = GetLoadClasses(if_block, &vshs);
160*795d594fSAndroid Build Coastguard Worker   HInstruction* new_inst = MakeNewInstance(if_block, new_inst_klass);
161*795d594fSAndroid Build Coastguard Worker   new_inst->SetReferenceTypeInfo(
162*795d594fSAndroid Build Coastguard Worker       ReferenceTypeInfo::Create(new_inst_klass->GetClass(), /*is_exact=*/true));
163*795d594fSAndroid Build Coastguard Worker   HInstanceOf* instance_of = new (GetAllocator()) HInstanceOf(new_inst,
164*795d594fSAndroid Build Coastguard Worker                                                               target_klass,
165*795d594fSAndroid Build Coastguard Worker                                                               TypeCheckKind::kClassHierarchyCheck,
166*795d594fSAndroid Build Coastguard Worker                                                               target_klass->GetClass(),
167*795d594fSAndroid Build Coastguard Worker                                                               0u,
168*795d594fSAndroid Build Coastguard Worker                                                               GetAllocator(),
169*795d594fSAndroid Build Coastguard Worker                                                               nullptr,
170*795d594fSAndroid Build Coastguard Worker                                                               nullptr);
171*795d594fSAndroid Build Coastguard Worker   if (target_klass->GetLoadedClassRTI().IsValid()) {
172*795d594fSAndroid Build Coastguard Worker     instance_of->SetValidTargetClassRTI();
173*795d594fSAndroid Build Coastguard Worker   }
174*795d594fSAndroid Build Coastguard Worker   if_block->AddInstruction(instance_of);
175*795d594fSAndroid Build Coastguard Worker   HIf* if_inst = MakeIf(if_block, instance_of);
176*795d594fSAndroid Build Coastguard Worker 
177*795d594fSAndroid Build Coastguard Worker   HInstruction* read_bottom =
178*795d594fSAndroid Build Coastguard Worker       MakeIFieldGet(breturn, new_inst, DataType::Type::kInt32, MemberOffset(32));
179*795d594fSAndroid Build Coastguard Worker   MakeReturn(breturn, read_bottom);
180*795d594fSAndroid Build Coastguard Worker 
181*795d594fSAndroid Build Coastguard Worker   PerformSimplification();
182*795d594fSAndroid Build Coastguard Worker 
183*795d594fSAndroid Build Coastguard Worker   if (!GetConstantResult() || GetParam() == InstanceOfKind::kSelf) {
184*795d594fSAndroid Build Coastguard Worker     EXPECT_INS_RETAINED(target_klass);
185*795d594fSAndroid Build Coastguard Worker   } else {
186*795d594fSAndroid Build Coastguard Worker     EXPECT_INS_REMOVED(target_klass);
187*795d594fSAndroid Build Coastguard Worker   }
188*795d594fSAndroid Build Coastguard Worker   EXPECT_INS_REMOVED(instance_of);
189*795d594fSAndroid Build Coastguard Worker   EXPECT_INS_EQ(if_inst->InputAt(0), test_res);
190*795d594fSAndroid Build Coastguard Worker }
191*795d594fSAndroid Build Coastguard Worker 
192*795d594fSAndroid Build Coastguard Worker // // ENTRY
193*795d594fSAndroid Build Coastguard Worker // obj = new Obj();
194*795d594fSAndroid Build Coastguard Worker // (<other>)obj;
195*795d594fSAndroid Build Coastguard Worker // // Make sure this graph isn't broken
196*795d594fSAndroid Build Coastguard Worker // EXIT
197*795d594fSAndroid Build Coastguard Worker // return obj
TEST_P(InstanceOfInstructionSimplifierTestGroup,ExactClassCheckCastOther)198*795d594fSAndroid Build Coastguard Worker TEST_P(InstanceOfInstructionSimplifierTestGroup, ExactClassCheckCastOther) {
199*795d594fSAndroid Build Coastguard Worker   ScopedObjectAccess soa(Thread::Current());
200*795d594fSAndroid Build Coastguard Worker   VariableSizedHandleScope vshs(soa.Self());
201*795d594fSAndroid Build Coastguard Worker   HBasicBlock* main = InitEntryMainExitGraph(/*handles=*/&vshs);
202*795d594fSAndroid Build Coastguard Worker 
203*795d594fSAndroid Build Coastguard Worker   auto [new_inst_klass, target_klass] = GetLoadClasses(main, &vshs);
204*795d594fSAndroid Build Coastguard Worker   HInstruction* new_inst = MakeNewInstance(main, new_inst_klass);
205*795d594fSAndroid Build Coastguard Worker   new_inst->SetReferenceTypeInfo(
206*795d594fSAndroid Build Coastguard Worker       ReferenceTypeInfo::Create(new_inst_klass->GetClass(), /*is_exact=*/true));
207*795d594fSAndroid Build Coastguard Worker   HCheckCast* check_cast = new (GetAllocator()) HCheckCast(new_inst,
208*795d594fSAndroid Build Coastguard Worker                                                            target_klass,
209*795d594fSAndroid Build Coastguard Worker                                                            TypeCheckKind::kClassHierarchyCheck,
210*795d594fSAndroid Build Coastguard Worker                                                            target_klass->GetClass(),
211*795d594fSAndroid Build Coastguard Worker                                                            0u,
212*795d594fSAndroid Build Coastguard Worker                                                            GetAllocator(),
213*795d594fSAndroid Build Coastguard Worker                                                            nullptr,
214*795d594fSAndroid Build Coastguard Worker                                                            nullptr);
215*795d594fSAndroid Build Coastguard Worker   if (target_klass->GetLoadedClassRTI().IsValid()) {
216*795d594fSAndroid Build Coastguard Worker     check_cast->SetValidTargetClassRTI();
217*795d594fSAndroid Build Coastguard Worker   }
218*795d594fSAndroid Build Coastguard Worker   main->AddInstruction(check_cast);
219*795d594fSAndroid Build Coastguard Worker   MakeReturn(main, new_inst);
220*795d594fSAndroid Build Coastguard Worker 
221*795d594fSAndroid Build Coastguard Worker   PerformSimplification();
222*795d594fSAndroid Build Coastguard Worker 
223*795d594fSAndroid Build Coastguard Worker   if (!GetConstantResult() || GetParam() == InstanceOfKind::kSelf) {
224*795d594fSAndroid Build Coastguard Worker     EXPECT_INS_RETAINED(target_klass);
225*795d594fSAndroid Build Coastguard Worker   } else {
226*795d594fSAndroid Build Coastguard Worker     EXPECT_INS_REMOVED(target_klass);
227*795d594fSAndroid Build Coastguard Worker   }
228*795d594fSAndroid Build Coastguard Worker   if (GetConstantResult()) {
229*795d594fSAndroid Build Coastguard Worker     EXPECT_INS_REMOVED(check_cast);
230*795d594fSAndroid Build Coastguard Worker   } else {
231*795d594fSAndroid Build Coastguard Worker     EXPECT_INS_RETAINED(check_cast);
232*795d594fSAndroid Build Coastguard Worker   }
233*795d594fSAndroid Build Coastguard Worker }
234*795d594fSAndroid Build Coastguard Worker 
235*795d594fSAndroid Build Coastguard Worker INSTANTIATE_TEST_SUITE_P(InstructionSimplifierTest,
236*795d594fSAndroid Build Coastguard Worker                          InstanceOfInstructionSimplifierTestGroup,
237*795d594fSAndroid Build Coastguard Worker                          testing::Values(InstanceOfKind::kSelf,
238*795d594fSAndroid Build Coastguard Worker                                          InstanceOfKind::kUnrelatedLoaded,
239*795d594fSAndroid Build Coastguard Worker                                          InstanceOfKind::kUnrelatedUnloaded,
240*795d594fSAndroid Build Coastguard Worker                                          InstanceOfKind::kSupertype));
241*795d594fSAndroid Build Coastguard Worker 
242*795d594fSAndroid Build Coastguard Worker }  // namespace art
243