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 <array>
17 #include "optimizer/ir/basicblock.h"
18 #include "optimizer/analysis/alias_analysis.h"
19 #include "optimizer/analysis/bounds_analysis.h"
20 #include "lowering.h"
21
22 namespace panda::compiler {
VisitIfImm(GraphVisitor * v,Inst * inst)23 void Lowering::VisitIfImm([[maybe_unused]] GraphVisitor *v, Inst *inst)
24 {
25 ASSERT(inst->GetOpcode() == Opcode::IfImm);
26 LowerIf(inst->CastToIfImm());
27 }
28
29 // Ask encoder whether Constant can be an immediate for Compare
ConstantFitsCompareImm(Inst * cst,uint32_t size,ConditionCode cc)30 bool Lowering::ConstantFitsCompareImm(Inst *cst, uint32_t size, ConditionCode cc)
31 {
32 ASSERT(cst->GetOpcode() == Opcode::Constant);
33 if (DataType::IsFloatType(cst->GetType())) {
34 return false;
35 }
36 int64_t val = cst->CastToConstant()->GetRawValue();
37 return (size == HALF_SIZE) && (val == 0);
38 }
39
LowerCastValueToAnyTypeWithConst(Inst * inst)40 bool Lowering::LowerCastValueToAnyTypeWithConst(Inst *inst)
41 {
42 auto graph = inst->GetBasicBlock()->GetGraph();
43 auto any_type = inst->CastToCastValueToAnyType()->GetAnyType();
44 auto base_type = AnyBaseTypeToDataType(any_type);
45 if (!IsTypeNumeric(base_type) || base_type == DataType::POINTER) {
46 return false;
47 }
48 auto input_inst = inst->GetInput(0).GetInst();
49 if (!input_inst->IsConst()) {
50 return false;
51 }
52 auto imm = input_inst->CastToConstant()->GetRawValue();
53 auto pack_imm = graph->GetRuntime()->GetPackConstantByPrimitiveType(any_type, imm);
54 auto any_const = inst->GetBasicBlock()->GetGraph()->FindOrCreateConstant(DataType::Any(pack_imm));
55 inst->ReplaceUsers(any_const);
56 return true;
57 }
58
59 // We'd like to swap only to make second operand immediate
BetterToSwapCompareInputs(Inst * cmp)60 bool Lowering::BetterToSwapCompareInputs(Inst *cmp)
61 {
62 ASSERT(cmp->GetOpcode() == Opcode::Compare);
63 auto in0 = cmp->GetInput(0).GetInst();
64 auto in1 = cmp->GetInput(1).GetInst();
65 if (DataType::IsFloatType(in0->GetType())) {
66 return false;
67 }
68
69 if (in0->IsConst()) {
70 if (in1->IsConst()) {
71 DataType::Type type = cmp->CastToCompare()->GetOperandsType();
72 uint32_t size = (type == DataType::UINT64 || type == DataType::INT64) ? WORD_SIZE : HALF_SIZE;
73 auto cc = cmp->CastToCompare()->GetCc();
74 return ConstantFitsCompareImm(in0, size, cc) && !ConstantFitsCompareImm(in1, size, cc);
75 }
76 return true;
77 }
78 return false;
79 }
80
81 // Optimize order of input arguments for decreasing using accumulator (Bytecodeoptimizer only).
OptimizeIfInput(compiler::Inst * if_inst)82 void Lowering::OptimizeIfInput(compiler::Inst *if_inst)
83 {
84 ASSERT(if_inst->GetOpcode() == compiler::Opcode::If);
85 compiler::Inst *input_0 = if_inst->GetInput(0).GetInst();
86 compiler::Inst *input_1 = if_inst->GetInput(1).GetInst();
87
88 if (input_0->IsDominate(input_1)) {
89 if_inst->SetInput(0, input_1);
90 if_inst->SetInput(1, input_0);
91 // And change CC
92 auto cc = if_inst->CastToIf()->GetCc();
93 cc = SwapOperandsConditionCode(cc);
94 if_inst->CastToIf()->SetCc(cc);
95 }
96 }
97
LowerIf(IfImmInst * inst)98 void Lowering::LowerIf(IfImmInst *inst)
99 {
100 auto graph = inst->GetBasicBlock()->GetGraph();
101 ASSERT(inst->GetCc() == ConditionCode::CC_NE || inst->GetCc() == ConditionCode::CC_EQ);
102 ASSERT(inst->GetImm() == 0);
103 if (inst->GetOperandsType() != DataType::BOOL) {
104 ASSERT(!graph->SupportManagedCode() || graph->IsDynamicMethod());
105 return;
106 }
107 auto input = inst->GetInput(0).GetInst();
108 if (input->GetOpcode() != Opcode::Compare) {
109 return;
110 }
111 // Check, that inst have only IfImm user
112 for (auto &user : input->GetUsers()) {
113 if (user.GetInst()->GetOpcode() != Opcode::IfImm) {
114 return;
115 }
116 }
117 // Try put constant in second input
118 if (BetterToSwapCompareInputs(input)) {
119 // Swap inputs
120 auto in0 = input->GetInput(0).GetInst();
121 auto in1 = input->GetInput(1).GetInst();
122 input->SetInput(0, in1);
123 input->SetInput(1, in0);
124 // And change CC
125 auto cc = input->CastToCompare()->GetCc();
126 cc = SwapOperandsConditionCode(cc);
127 input->CastToCompare()->SetCc(cc);
128 }
129 auto cst = input->GetInput(1).GetInst();
130 DataType::Type type = input->CastToCompare()->GetOperandsType();
131 uint32_t size = (type == DataType::UINT64 || type == DataType::INT64) ? WORD_SIZE : HALF_SIZE;
132 auto cc = input->CastToCompare()->GetCc();
133 // IfImm can be inverted
134 if (inst->GetCc() == ConditionCode::CC_EQ && inst->GetImm() == 0) {
135 cc = GetInverseConditionCode(cc);
136 }
137
138 if (cst->IsConst() && ConstantFitsCompareImm(cst, size, cc)) {
139 // In-place change for IfImm
140 InPlaceLowerIfImm(inst, input, cst, cc);
141 } else {
142 // New instruction
143 auto replace = graph->CreateInstIf(DataType::NO_TYPE, inst->GetPc(), cc);
144 replace->SetMethod(inst->GetMethod());
145 replace->SetOperandsType(input->CastToCompare()->GetOperandsType());
146 replace->SetInput(0, input->GetInput(0).GetInst());
147 replace->SetInput(1, input->GetInput(1).GetInst());
148 // Replace IfImm instruction immediately because it's not removable by DCE
149 inst->RemoveInputs();
150 inst->GetBasicBlock()->ReplaceInst(inst, replace);
151 graph->GetEventWriter().EventLowering(GetOpcodeString(inst->GetOpcode()), inst->GetId(), inst->GetPc());
152 if (graph->IsBytecodeOptimizer()) {
153 OptimizeIfInput(replace);
154 }
155 COMPILER_LOG(DEBUG, LOWERING) << "Lowering is applied for " << GetOpcodeString(inst->GetOpcode());
156 }
157 }
158
InPlaceLowerIfImm(IfImmInst * inst,Inst * input,Inst * cst,ConditionCode cc)159 void Lowering::InPlaceLowerIfImm(IfImmInst *inst, Inst *input, Inst *cst, ConditionCode cc)
160 {
161 inst->SetOperandsType(input->CastToCompare()->GetOperandsType());
162 auto new_input = input->GetInput(0).GetInst();
163 inst->SetInput(0, new_input);
164
165 uint64_t val = cst->CastToConstant()->GetRawValue();
166 inst->SetImm(val);
167 inst->SetCc(cc);
168 inst->GetBasicBlock()->GetGraph()->GetEventWriter().EventLowering(GetOpcodeString(inst->GetOpcode()), inst->GetId(),
169 inst->GetPc());
170 COMPILER_LOG(DEBUG, LOWERING) << "Lowering is applied for " << GetOpcodeString(inst->GetOpcode());
171 }
172
InvalidateAnalyses()173 void Lowering::InvalidateAnalyses()
174 {
175 GetGraph()->InvalidateAnalysis<BoundsAnalysis>();
176 GetGraph()->InvalidateAnalysis<AliasAnalysis>();
177 }
178
RunImpl()179 bool Lowering::RunImpl()
180 {
181 VisitGraph();
182 return true;
183 }
184 } // namespace panda::compiler
185