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