diff options
Diffstat (limited to 'compiler/optimizing/builder.cc')
-rw-r--r-- | compiler/optimizing/builder.cc | 393 |
1 files changed, 311 insertions, 82 deletions
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc index 05548761e0..1efdd389d8 100644 --- a/compiler/optimizing/builder.cc +++ b/compiler/optimizing/builder.cc @@ -25,7 +25,8 @@ namespace art { -void HGraphBuilder::InitializeLocals(int count) { +void HGraphBuilder::InitializeLocals(uint16_t count) { + graph_->SetNumberOfVRegs(count); locals_.SetSize(count); for (int i = 0; i < count; i++) { HLocal* local = new (arena_) HLocal(i); @@ -34,15 +35,81 @@ void HGraphBuilder::InitializeLocals(int count) { } } +bool HGraphBuilder::InitializeParameters(uint16_t number_of_parameters) { + // dex_compilation_unit_ is null only when unit testing. + if (dex_compilation_unit_ == nullptr) { + return true; + } + + graph_->SetNumberOfInVRegs(number_of_parameters); + const char* shorty = dex_compilation_unit_->GetShorty(); + int locals_index = locals_.Size() - number_of_parameters; + int parameter_index = 0; + + if (!dex_compilation_unit_->IsStatic()) { + // Add the implicit 'this' argument, not expressed in the signature. + HParameterValue* parameter = + new (arena_) HParameterValue(parameter_index++, Primitive::kPrimNot); + entry_block_->AddInstruction(parameter); + HLocal* local = GetLocalAt(locals_index++); + entry_block_->AddInstruction(new (arena_) HStoreLocal(local, parameter)); + number_of_parameters--; + } + + uint32_t pos = 1; + for (int i = 0; i < number_of_parameters; i++) { + switch (shorty[pos++]) { + case 'F': + case 'D': { + return false; + } + + default: { + // integer and reference parameters. + HParameterValue* parameter = + new (arena_) HParameterValue(parameter_index++, Primitive::GetType(shorty[pos - 1])); + entry_block_->AddInstruction(parameter); + HLocal* local = GetLocalAt(locals_index++); + // Store the parameter value in the local that the dex code will use + // to reference that parameter. + entry_block_->AddInstruction(new (arena_) HStoreLocal(local, parameter)); + if (parameter->GetType() == Primitive::kPrimLong) { + i++; + locals_index++; + parameter_index++; + } + break; + } + } + } + return true; +} + static bool CanHandleCodeItem(const DexFile::CodeItem& code_item) { if (code_item.tries_size_ > 0) { return false; - } else if (code_item.ins_size_ > 0) { - return false; } return true; } +template<typename T> +void HGraphBuilder::If_22t(const Instruction& instruction, int32_t dex_offset, bool is_not) { + HInstruction* first = LoadLocal(instruction.VRegA(), Primitive::kPrimInt); + HInstruction* second = LoadLocal(instruction.VRegB(), Primitive::kPrimInt); + current_block_->AddInstruction(new (arena_) T(first, second)); + if (is_not) { + current_block_->AddInstruction(new (arena_) HNot(current_block_->GetLastInstruction())); + } + current_block_->AddInstruction(new (arena_) HIf(current_block_->GetLastInstruction())); + HBasicBlock* target = FindBlockStartingAt(instruction.GetTargetOffset() + dex_offset); + DCHECK(target != nullptr); + current_block_->AddSuccessor(target); + target = FindBlockStartingAt(dex_offset + instruction.SizeInCodeUnits()); + DCHECK(target != nullptr); + current_block_->AddSuccessor(target); + current_block_ = nullptr; +} + HGraph* HGraphBuilder::BuildGraph(const DexFile::CodeItem& code_item) { if (!CanHandleCodeItem(code_item)) { return nullptr; @@ -66,6 +133,10 @@ HGraph* HGraphBuilder::BuildGraph(const DexFile::CodeItem& code_item) { // start a new block, and create these blocks. ComputeBranchTargets(code_ptr, code_end); + if (!InitializeParameters(code_item.ins_size_)) { + return nullptr; + } + size_t dex_offset = 0; while (code_ptr < code_end) { // Update the current block if dex_offset starts a new block. @@ -139,6 +210,112 @@ HBasicBlock* HGraphBuilder::FindBlockStartingAt(int32_t index) const { return branch_targets_.Get(index); } +template<typename T> +void HGraphBuilder::Binop_32x(const Instruction& instruction, Primitive::Type type) { + HInstruction* first = LoadLocal(instruction.VRegB(), type); + HInstruction* second = LoadLocal(instruction.VRegC(), type); + current_block_->AddInstruction(new (arena_) T(type, first, second)); + UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction()); +} + +template<typename T> +void HGraphBuilder::Binop_12x(const Instruction& instruction, Primitive::Type type) { + HInstruction* first = LoadLocal(instruction.VRegA(), type); + HInstruction* second = LoadLocal(instruction.VRegB(), type); + current_block_->AddInstruction(new (arena_) T(type, first, second)); + UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction()); +} + +template<typename T> +void HGraphBuilder::Binop_22s(const Instruction& instruction, bool reverse) { + HInstruction* first = LoadLocal(instruction.VRegB(), Primitive::kPrimInt); + HInstruction* second = GetIntConstant(instruction.VRegC_22s()); + if (reverse) { + std::swap(first, second); + } + current_block_->AddInstruction(new (arena_) T(Primitive::kPrimInt, first, second)); + UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction()); +} + +template<typename T> +void HGraphBuilder::Binop_22b(const Instruction& instruction, bool reverse) { + HInstruction* first = LoadLocal(instruction.VRegB(), Primitive::kPrimInt); + HInstruction* second = GetIntConstant(instruction.VRegC_22b()); + if (reverse) { + std::swap(first, second); + } + current_block_->AddInstruction(new (arena_) T(Primitive::kPrimInt, first, second)); + UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction()); +} + +void HGraphBuilder::BuildReturn(const Instruction& instruction, Primitive::Type type) { + if (type == Primitive::kPrimVoid) { + current_block_->AddInstruction(new (arena_) HReturnVoid()); + } else { + HInstruction* value = LoadLocal(instruction.VRegA(), type); + current_block_->AddInstruction(new (arena_) HReturn(value)); + } + current_block_->AddSuccessor(exit_block_); + current_block_ = nullptr; +} + +bool HGraphBuilder::BuildInvoke(const Instruction& instruction, + uint32_t dex_offset, + uint32_t method_idx, + uint32_t number_of_vreg_arguments, + bool is_range, + uint32_t* args, + uint32_t register_index) { + const DexFile::MethodId& method_id = dex_file_->GetMethodId(method_idx); + const DexFile::ProtoId& proto_id = dex_file_->GetProtoId(method_id.proto_idx_); + const char* descriptor = dex_file_->StringDataByIdx(proto_id.shorty_idx_); + Primitive::Type return_type = Primitive::GetType(descriptor[0]); + bool is_instance_call = + instruction.Opcode() != Instruction::INVOKE_STATIC + && instruction.Opcode() != Instruction::INVOKE_STATIC_RANGE; + const size_t number_of_arguments = strlen(descriptor) - (is_instance_call ? 0 : 1); + + // Treat invoke-direct like static calls for now. + HInvoke* invoke = new (arena_) HInvokeStatic( + arena_, number_of_arguments, return_type, dex_offset, method_idx); + + size_t start_index = 0; + if (is_instance_call) { + HInstruction* arg = LoadLocal(is_range ? register_index : args[0], Primitive::kPrimNot); + invoke->SetArgumentAt(0, arg); + start_index = 1; + } + + uint32_t descriptor_index = 1; + uint32_t argument_index = start_index; + for (size_t i = start_index; i < number_of_vreg_arguments; i++, argument_index++) { + Primitive::Type type = Primitive::GetType(descriptor[descriptor_index++]); + switch (type) { + case Primitive::kPrimFloat: + case Primitive::kPrimDouble: + return false; + + default: { + if (!is_range && type == Primitive::kPrimLong && args[i] + 1 != args[i + 1]) { + LOG(WARNING) << "Non sequential register pair in " << dex_compilation_unit_->GetSymbol() + << " at " << dex_offset; + // We do not implement non sequential register pair. + return false; + } + HInstruction* arg = LoadLocal(is_range ? register_index + i : args[i], type); + invoke->SetArgumentAt(argument_index, arg); + if (type == Primitive::kPrimLong) { + i++; + } + } + } + } + + DCHECK_EQ(argument_index, number_of_arguments); + current_block_->AddInstruction(invoke); + return true; +} + bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, int32_t dex_offset) { if (current_block_ == nullptr) { return true; // Dead code @@ -147,30 +324,57 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, int32_ switch (instruction.Opcode()) { case Instruction::CONST_4: { int32_t register_index = instruction.VRegA(); - HIntConstant* constant = GetConstant(instruction.VRegB_11n()); + HIntConstant* constant = GetIntConstant(instruction.VRegB_11n()); + UpdateLocal(register_index, constant); + break; + } + + case Instruction::CONST_16: { + int32_t register_index = instruction.VRegA(); + HIntConstant* constant = GetIntConstant(instruction.VRegB_21s()); UpdateLocal(register_index, constant); break; } + case Instruction::CONST_WIDE_16: { + int32_t register_index = instruction.VRegA(); + HLongConstant* constant = GetLongConstant(instruction.VRegB_21s()); + UpdateLocal(register_index, constant); + break; + } + + case Instruction::CONST_WIDE_32: { + int32_t register_index = instruction.VRegA(); + HLongConstant* constant = GetLongConstant(instruction.VRegB_31i()); + UpdateLocal(register_index, constant); + break; + } + + case Instruction::CONST_WIDE: { + int32_t register_index = instruction.VRegA(); + HLongConstant* constant = GetLongConstant(instruction.VRegB_51l()); + UpdateLocal(register_index, constant); + break; + } + + case Instruction::MOVE: { + HInstruction* value = LoadLocal(instruction.VRegB(), Primitive::kPrimInt); + UpdateLocal(instruction.VRegA(), value); + break; + } + case Instruction::RETURN_VOID: { - current_block_->AddInstruction(new (arena_) HReturnVoid()); - current_block_->AddSuccessor(exit_block_); - current_block_ = nullptr; + BuildReturn(instruction, Primitive::kPrimVoid); break; } case Instruction::IF_EQ: { - HInstruction* first = LoadLocal(instruction.VRegA()); - HInstruction* second = LoadLocal(instruction.VRegB()); - current_block_->AddInstruction(new (arena_) HEqual(first, second)); - current_block_->AddInstruction(new (arena_) HIf(current_block_->GetLastInstruction())); - HBasicBlock* target = FindBlockStartingAt(instruction.GetTargetOffset() + dex_offset); - DCHECK(target != nullptr); - current_block_->AddSuccessor(target); - target = FindBlockStartingAt(dex_offset + instruction.SizeInCodeUnits()); - DCHECK(target != nullptr); - current_block_->AddSuccessor(target); - current_block_ = nullptr; + If_22t<HEqual>(instruction, dex_offset, false); + break; + } + + case Instruction::IF_NE: { + If_22t<HEqual>(instruction, dex_offset, true); break; } @@ -186,93 +390,112 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, int32_ } case Instruction::RETURN: { - HInstruction* value = LoadLocal(instruction.VRegA()); - current_block_->AddInstruction(new (arena_) HReturn(value)); - current_block_->AddSuccessor(exit_block_); - current_block_ = nullptr; + BuildReturn(instruction, Primitive::kPrimInt); break; } - case Instruction::INVOKE_STATIC: { - uint32_t method_idx = instruction.VRegB_35c(); - const DexFile::MethodId& method_id = dex_file_->GetMethodId(method_idx); - uint32_t return_type_idx = dex_file_->GetProtoId(method_id.proto_idx_).return_type_idx_; - const char* descriptor = dex_file_->StringByTypeIdx(return_type_idx); - const size_t number_of_arguments = instruction.VRegA_35c(); - - if (Primitive::GetType(descriptor[0]) != Primitive::kPrimVoid) { - return false; - } + case Instruction::RETURN_OBJECT: { + BuildReturn(instruction, Primitive::kPrimNot); + break; + } - HInvokeStatic* invoke = new (arena_) HInvokeStatic( - arena_, number_of_arguments, dex_offset, method_idx); + case Instruction::RETURN_WIDE: { + BuildReturn(instruction, Primitive::kPrimLong); + break; + } + case Instruction::INVOKE_STATIC: + case Instruction::INVOKE_DIRECT: { + uint32_t method_idx = instruction.VRegB_35c(); + uint32_t number_of_vreg_arguments = instruction.VRegA_35c(); uint32_t args[5]; instruction.GetArgs(args); - - for (size_t i = 0; i < number_of_arguments; i++) { - HInstruction* arg = LoadLocal(args[i]); - HInstruction* push = new (arena_) HPushArgument(arg, i); - current_block_->AddInstruction(push); - invoke->SetArgumentAt(i, push); + if (!BuildInvoke(instruction, dex_offset, method_idx, number_of_vreg_arguments, false, args, -1)) { + return false; } - - current_block_->AddInstruction(invoke); break; } - case Instruction::INVOKE_STATIC_RANGE: { + case Instruction::INVOKE_STATIC_RANGE: + case Instruction::INVOKE_DIRECT_RANGE: { uint32_t method_idx = instruction.VRegB_3rc(); - const DexFile::MethodId& method_id = dex_file_->GetMethodId(method_idx); - uint32_t return_type_idx = dex_file_->GetProtoId(method_id.proto_idx_).return_type_idx_; - const char* descriptor = dex_file_->StringByTypeIdx(return_type_idx); - const size_t number_of_arguments = instruction.VRegA_3rc(); - - if (Primitive::GetType(descriptor[0]) != Primitive::kPrimVoid) { + uint32_t number_of_vreg_arguments = instruction.VRegA_3rc(); + uint32_t register_index = instruction.VRegC(); + if (!BuildInvoke(instruction, dex_offset, method_idx, + number_of_vreg_arguments, true, nullptr, register_index)) { return false; } - - HInvokeStatic* invoke = new (arena_) HInvokeStatic( - arena_, number_of_arguments, dex_offset, method_idx); - int32_t register_index = instruction.VRegC(); - for (size_t i = 0; i < number_of_arguments; i++) { - HInstruction* arg = LoadLocal(register_index + i); - HInstruction* push = new (arena_) HPushArgument(arg, i); - current_block_->AddInstruction(push); - invoke->SetArgumentAt(i, push); - } - current_block_->AddInstruction(invoke); break; } case Instruction::ADD_INT: { - HInstruction* first = LoadLocal(instruction.VRegB()); - HInstruction* second = LoadLocal(instruction.VRegC()); - current_block_->AddInstruction(new (arena_) HAdd(Primitive::kPrimInt, first, second)); - UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction()); + Binop_32x<HAdd>(instruction, Primitive::kPrimInt); + break; + } + + case Instruction::ADD_LONG: { + Binop_32x<HAdd>(instruction, Primitive::kPrimLong); + break; + } + + case Instruction::SUB_INT: { + Binop_32x<HSub>(instruction, Primitive::kPrimInt); + break; + } + + case Instruction::SUB_LONG: { + Binop_32x<HSub>(instruction, Primitive::kPrimLong); break; } case Instruction::ADD_INT_2ADDR: { - HInstruction* first = LoadLocal(instruction.VRegA()); - HInstruction* second = LoadLocal(instruction.VRegB()); - current_block_->AddInstruction(new (arena_) HAdd(Primitive::kPrimInt, first, second)); - UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction()); + Binop_12x<HAdd>(instruction, Primitive::kPrimInt); + break; + } + + case Instruction::ADD_LONG_2ADDR: { + Binop_12x<HAdd>(instruction, Primitive::kPrimLong); + break; + } + + case Instruction::SUB_INT_2ADDR: { + Binop_12x<HSub>(instruction, Primitive::kPrimInt); + break; + } + + case Instruction::SUB_LONG_2ADDR: { + Binop_12x<HSub>(instruction, Primitive::kPrimLong); break; } case Instruction::ADD_INT_LIT16: { - HInstruction* first = LoadLocal(instruction.VRegB()); - HInstruction* second = GetConstant(instruction.VRegC_22s()); - current_block_->AddInstruction(new (arena_) HAdd(Primitive::kPrimInt, first, second)); - UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction()); + Binop_22s<HAdd>(instruction, false); + break; + } + + case Instruction::RSUB_INT: { + Binop_22s<HSub>(instruction, true); break; } case Instruction::ADD_INT_LIT8: { - HInstruction* first = LoadLocal(instruction.VRegB()); - HInstruction* second = GetConstant(instruction.VRegC_22b()); - current_block_->AddInstruction(new (arena_) HAdd(Primitive::kPrimInt, first, second)); + Binop_22b<HAdd>(instruction, false); + break; + } + + case Instruction::RSUB_INT_LIT8: { + Binop_22b<HSub>(instruction, true); + break; + } + + case Instruction::NEW_INSTANCE: { + current_block_->AddInstruction( + new (arena_) HNewInstance(dex_offset, instruction.VRegB_21c())); + UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction()); + break; + } + + case Instruction::MOVE_RESULT_WIDE: { UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction()); break; } @@ -286,7 +509,7 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, int32_ return true; } -HIntConstant* HGraphBuilder::GetConstant0() { +HIntConstant* HGraphBuilder::GetIntConstant0() { if (constant0_ != nullptr) { return constant0_; } @@ -295,7 +518,7 @@ HIntConstant* HGraphBuilder::GetConstant0() { return constant0_; } -HIntConstant* HGraphBuilder::GetConstant1() { +HIntConstant* HGraphBuilder::GetIntConstant1() { if (constant1_ != nullptr) { return constant1_; } @@ -304,10 +527,10 @@ HIntConstant* HGraphBuilder::GetConstant1() { return constant1_; } -HIntConstant* HGraphBuilder::GetConstant(int constant) { +HIntConstant* HGraphBuilder::GetIntConstant(int32_t constant) { switch (constant) { - case 0: return GetConstant0(); - case 1: return GetConstant1(); + case 0: return GetIntConstant0(); + case 1: return GetIntConstant1(); default: { HIntConstant* instruction = new (arena_) HIntConstant(constant); entry_block_->AddInstruction(instruction); @@ -316,6 +539,12 @@ HIntConstant* HGraphBuilder::GetConstant(int constant) { } } +HLongConstant* HGraphBuilder::GetLongConstant(int64_t constant) { + HLongConstant* instruction = new (arena_) HLongConstant(constant); + entry_block_->AddInstruction(instruction); + return instruction; +} + HLocal* HGraphBuilder::GetLocalAt(int register_index) const { return locals_.Get(register_index); } @@ -325,9 +554,9 @@ void HGraphBuilder::UpdateLocal(int register_index, HInstruction* instruction) c current_block_->AddInstruction(new (arena_) HStoreLocal(local, instruction)); } -HInstruction* HGraphBuilder::LoadLocal(int register_index) const { +HInstruction* HGraphBuilder::LoadLocal(int register_index, Primitive::Type type) const { HLocal* local = GetLocalAt(register_index); - current_block_->AddInstruction(new (arena_) HLoadLocal(local)); + current_block_->AddInstruction(new (arena_) HLoadLocal(local, type)); return current_block_->GetLastInstruction(); } |