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