}
template<typename T>
-void HGraphBuilder::If_22t(const Instruction& instruction, int32_t dex_offset, bool is_not) {
+void HGraphBuilder::If_22t(const Instruction& instruction, int32_t dex_offset) {
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);
+ T* comparison = new (arena_) T(first, second);
+ current_block_->AddInstruction(comparison);
+ HInstruction* ifinst = new (arena_) HIf(comparison);
+ current_block_->AddInstruction(ifinst);
+ HBasicBlock* target = FindBlockStartingAt(dex_offset + instruction.GetTargetOffset());
+ DCHECK(target != nullptr);
+ current_block_->AddSuccessor(target);
+ target = FindBlockStartingAt(dex_offset + instruction.SizeInCodeUnits());
+ DCHECK(target != nullptr);
+ current_block_->AddSuccessor(target);
+ current_block_ = nullptr;
+}
+
+template<typename T>
+void HGraphBuilder::If_21t(const Instruction& instruction, int32_t dex_offset) {
+ HInstruction* value = LoadLocal(instruction.VRegA(), Primitive::kPrimInt);
+ T* comparison = new (arena_) T(value, GetIntConstant(0));
+ current_block_->AddInstruction(comparison);
+ HInstruction* ifinst = new (arena_) HIf(comparison);
+ current_block_->AddInstruction(ifinst);
+ HBasicBlock* target = FindBlockStartingAt(dex_offset + instruction.GetTargetOffset());
DCHECK(target != nullptr);
current_block_->AddSuccessor(target);
target = FindBlockStartingAt(dex_offset + instruction.SizeInCodeUnits());
break;
}
+ case Instruction::CONST: {
+ int32_t register_index = instruction.VRegA();
+ HIntConstant* constant = GetIntConstant(instruction.VRegB_31i());
+ UpdateLocal(register_index, constant);
+ break;
+ }
+
+ case Instruction::CONST_HIGH16: {
+ int32_t register_index = instruction.VRegA();
+ HIntConstant* constant = GetIntConstant(instruction.VRegB_21h() << 16);
+ UpdateLocal(register_index, constant);
+ break;
+ }
+
case Instruction::CONST_WIDE_16: {
int32_t register_index = instruction.VRegA();
- HLongConstant* constant = GetLongConstant(instruction.VRegB_21s());
+ // Get 16 bits of constant value, sign extended to 64 bits.
+ int64_t value = instruction.VRegB_21s();
+ value <<= 48;
+ value >>= 48;
+ HLongConstant* constant = GetLongConstant(value);
UpdateLocal(register_index, constant);
break;
}
case Instruction::CONST_WIDE_32: {
int32_t register_index = instruction.VRegA();
- HLongConstant* constant = GetLongConstant(instruction.VRegB_31i());
+ // Get 32 bits of constant value, sign extended to 64 bits.
+ int64_t value = instruction.VRegB_31i();
+ value <<= 32;
+ value >>= 32;
+ HLongConstant* constant = GetLongConstant(value);
UpdateLocal(register_index, constant);
break;
}
break;
}
- case Instruction::MOVE: {
+ case Instruction::CONST_WIDE_HIGH16: {
+ int32_t register_index = instruction.VRegA();
+ int64_t value = static_cast<int64_t>(instruction.VRegB_21h()) << 48;
+ HLongConstant* constant = GetLongConstant(value);
+ UpdateLocal(register_index, constant);
+ break;
+ }
+
+ // TODO: these instructions are also used to move floating point values, so what is
+ // the type (int or float)?
+ case Instruction::MOVE:
+ case Instruction::MOVE_FROM16:
+ case Instruction::MOVE_16: {
HInstruction* value = LoadLocal(instruction.VRegB(), Primitive::kPrimInt);
UpdateLocal(instruction.VRegA(), value);
break;
}
- case Instruction::RETURN_VOID: {
- BuildReturn(instruction, Primitive::kPrimVoid);
+ // TODO: these instructions are also used to move floating point values, so what is
+ // the type (long or double)?
+ case Instruction::MOVE_WIDE:
+ case Instruction::MOVE_WIDE_FROM16:
+ case Instruction::MOVE_WIDE_16: {
+ HInstruction* value = LoadLocal(instruction.VRegB(), Primitive::kPrimLong);
+ UpdateLocal(instruction.VRegA(), value);
break;
}
- case Instruction::IF_EQ: {
- If_22t<HEqual>(instruction, dex_offset, false);
+ case Instruction::MOVE_OBJECT:
+ case Instruction::MOVE_OBJECT_16:
+ case Instruction::MOVE_OBJECT_FROM16: {
+ HInstruction* value = LoadLocal(instruction.VRegB(), Primitive::kPrimNot);
+ UpdateLocal(instruction.VRegA(), value);
break;
}
- case Instruction::IF_NE: {
- If_22t<HEqual>(instruction, dex_offset, true);
+ case Instruction::RETURN_VOID: {
+ BuildReturn(instruction, Primitive::kPrimVoid);
break;
}
+#define IF_XX(comparison, cond) \
+ case Instruction::IF_##cond: If_22t<comparison>(instruction, dex_offset); break; \
+ case Instruction::IF_##cond##Z: If_21t<comparison>(instruction, dex_offset); break
+
+ IF_XX(HEqual, EQ);
+ IF_XX(HNotEqual, NE);
+ IF_XX(HLessThan, LT);
+ IF_XX(HLessThanOrEqual, LE);
+ IF_XX(HGreaterThan, GT);
+ IF_XX(HGreaterThanOrEqual, GE);
+
case Instruction::GOTO:
case Instruction::GOTO_16:
case Instruction::GOTO_32: {
}
case Instruction::MOVE_RESULT:
- case Instruction::MOVE_RESULT_WIDE: {
+ case Instruction::MOVE_RESULT_WIDE:
+ case Instruction::MOVE_RESULT_OBJECT:
UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction());
break;
- }
case Instruction::NOP:
break;
#include "primitive.h"
#include "utils/allocation.h"
#include "utils/growable_array.h"
+#include "nodes.h"
namespace art {
-class ArenaAllocator;
class Instruction;
-class HBasicBlock;
-class HGraph;
-class HIntConstant;
-class HLongConstant;
-class HInstruction;
-class HLocal;
class HGraphBuilder : public ValueObject {
public:
template<typename T>
void Binop_22s(const Instruction& instruction, bool reverse);
- template<typename T> void If_22t(const Instruction& instruction, int32_t dex_offset, bool is_not);
+ template<typename T>
+ void If_22t(const Instruction& instruction, int32_t dex_offset);
+
+ template<typename T>
+ void If_21t(const Instruction& instruction, int32_t dex_offset);
void BuildReturn(const Instruction& instruction, Primitive::Type type);
namespace arm {
+
+inline Condition ARMCondition(IfCondition cond) {
+ switch (cond) {
+ case kCondEQ: return EQ;
+ case kCondNE: return NE;
+ case kCondLT: return LT;
+ case kCondLE: return LE;
+ case kCondGT: return GT;
+ case kCondGE: return GE;
+ default:
+ LOG(FATAL) << "Unknown if condition";
+ }
+ return EQ; // Unreachable.
+}
+
+inline Condition ARMOppositeCondition(IfCondition cond) {
+ switch (cond) {
+ case kCondEQ: return NE;
+ case kCondNE: return EQ;
+ case kCondLT: return GE;
+ case kCondLE: return GT;
+ case kCondGT: return LE;
+ case kCondGE: return LT;
+ default:
+ LOG(FATAL) << "Unknown if condition";
+ }
+ return EQ; // Unreachable.
+}
+
static constexpr int kNumberOfPushedRegistersAtEntry = 1;
static constexpr int kCurrentMethodStackOffset = 0;
void LocationsBuilderARM::VisitIf(HIf* if_instr) {
LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(if_instr);
- locations->SetInAt(0, Location::RequiresRegister());
+ locations->SetInAt(0, Location::Any());
if_instr->SetLocations(locations);
}
void InstructionCodeGeneratorARM::VisitIf(HIf* if_instr) {
- // TODO: Generate the input as a condition, instead of materializing in a register.
- __ cmp(if_instr->GetLocations()->InAt(0).AsArm().AsCoreRegister(), ShifterOperand(0));
- __ b(codegen_->GetLabelOf(if_instr->IfFalseSuccessor()), EQ);
- if (!codegen_->GoesToNextBlock(if_instr->GetBlock(), if_instr->IfTrueSuccessor())) {
- __ b(codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
+ HInstruction* cond = if_instr->InputAt(0);
+ DCHECK(cond->IsCondition());
+ HCondition* condition = cond->AsCondition();
+ if (condition->NeedsMaterialization()) {
+ // Condition has been materialized, compare the output to 0
+ if (!if_instr->GetLocations()->InAt(0).IsRegister()) {
+ LOG(FATAL) << "Materialized condition is not in an ARM register";
+ }
+ __ cmp(if_instr->GetLocations()->InAt(0).AsArm().AsCoreRegister(),
+ ShifterOperand(0));
+ __ b(codegen_->GetLabelOf(if_instr->IfTrueSuccessor()), EQ);
+ } else {
+ // Condition has not been materialized, use its inputs as the comparison and its
+ // condition as the branch condition.
+ __ cmp(condition->GetLocations()->InAt(0).AsArm().AsCoreRegister(),
+ ShifterOperand(condition->GetLocations()->InAt(1).AsArm().AsCoreRegister()));
+ __ b(codegen_->GetLabelOf(if_instr->IfTrueSuccessor()),
+ ARMCondition(condition->GetCondition()));
+ }
+ if (!codegen_->GoesToNextBlock(if_instr->GetBlock(), if_instr->IfFalseSuccessor())) {
+ __ b(codegen_->GetLabelOf(if_instr->IfFalseSuccessor()));
}
}
-void LocationsBuilderARM::VisitEqual(HEqual* equal) {
- LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(equal);
+
+void LocationsBuilderARM::VisitCondition(HCondition* comp) {
+ LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(comp);
locations->SetInAt(0, Location::RequiresRegister());
locations->SetInAt(1, Location::RequiresRegister());
locations->SetOut(Location::RequiresRegister());
- equal->SetLocations(locations);
+ comp->SetLocations(locations);
+}
+
+void InstructionCodeGeneratorARM::VisitCondition(HCondition* comp) {
+ if (comp->NeedsMaterialization()) {
+ LocationSummary* locations = comp->GetLocations();
+ __ cmp(locations->InAt(0).AsArm().AsCoreRegister(),
+ ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister()));
+ __ it(ARMCondition(comp->GetCondition()), kItElse);
+ __ mov(locations->Out().AsArm().AsCoreRegister(), ShifterOperand(1),
+ ARMCondition(comp->GetCondition()));
+ __ mov(locations->Out().AsArm().AsCoreRegister(), ShifterOperand(0),
+ ARMOppositeCondition(comp->GetCondition()));
+ }
+}
+
+void LocationsBuilderARM::VisitEqual(HEqual* comp) {
+ VisitCondition(comp);
+}
+
+void InstructionCodeGeneratorARM::VisitEqual(HEqual* comp) {
+ VisitCondition(comp);
+}
+
+void LocationsBuilderARM::VisitNotEqual(HNotEqual* comp) {
+ VisitCondition(comp);
+}
+
+void InstructionCodeGeneratorARM::VisitNotEqual(HNotEqual* comp) {
+ VisitCondition(comp);
+}
+
+void LocationsBuilderARM::VisitLessThan(HLessThan* comp) {
+ VisitCondition(comp);
+}
+
+void InstructionCodeGeneratorARM::VisitLessThan(HLessThan* comp) {
+ VisitCondition(comp);
+}
+
+void LocationsBuilderARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
+ VisitCondition(comp);
+}
+
+void InstructionCodeGeneratorARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
+ VisitCondition(comp);
+}
+
+void LocationsBuilderARM::VisitGreaterThan(HGreaterThan* comp) {
+ VisitCondition(comp);
+}
+
+void InstructionCodeGeneratorARM::VisitGreaterThan(HGreaterThan* comp) {
+ VisitCondition(comp);
+}
+
+void LocationsBuilderARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
+ VisitCondition(comp);
}
-void InstructionCodeGeneratorARM::VisitEqual(HEqual* equal) {
- LocationSummary* locations = equal->GetLocations();
- __ teq(locations->InAt(0).AsArm().AsCoreRegister(),
- ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister()));
- __ mov(locations->Out().AsArm().AsCoreRegister(), ShifterOperand(1), EQ);
- __ mov(locations->Out().AsArm().AsCoreRegister(), ShifterOperand(0), NE);
+void InstructionCodeGeneratorARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
+ VisitCondition(comp);
}
void LocationsBuilderARM::VisitLocal(HLocal* local) {
#include "code_generator.h"
#include "nodes.h"
#include "parallel_move_resolver.h"
-#include "utils/arm/assembler_arm32.h"
+#include "utils/arm/assembler_thumb2.h"
namespace art {
namespace arm {
LocationsBuilderARM location_builder_;
InstructionCodeGeneratorARM instruction_visitor_;
ParallelMoveResolverARM move_resolver_;
- Arm32Assembler assembler_;
+ Thumb2Assembler assembler_;
DISALLOW_COPY_AND_ASSIGN(CodeGeneratorARM);
};
namespace x86 {
+inline Condition X86Condition(IfCondition cond) {
+ switch (cond) {
+ case kCondEQ: return kEqual;
+ case kCondNE: return kNotEqual;
+ case kCondLT: return kLess;
+ case kCondLE: return kLessEqual;
+ case kCondGT: return kGreater;
+ case kCondGE: return kGreaterEqual;
+ default:
+ LOG(FATAL) << "Unknown if condition";
+ }
+ return kEqual;
+}
+
static constexpr int kNumberOfPushedRegistersAtEntry = 1;
static constexpr int kCurrentMethodStackOffset = 0;
}
void InstructionCodeGeneratorX86::VisitIf(HIf* if_instr) {
- // TODO: Generate the input as a condition, instead of materializing in a register.
- Location location = if_instr->GetLocations()->InAt(0);
- if (location.IsRegister()) {
- __ cmpl(location.AsX86().AsCpuRegister(), Immediate(0));
+ HInstruction* cond = if_instr->InputAt(0);
+ DCHECK(cond->IsCondition());
+ HCondition* condition = cond->AsCondition();
+ if (condition->NeedsMaterialization()) {
+ // Materialized condition, compare against 0
+ Location lhs = if_instr->GetLocations()->InAt(0);
+ if (lhs.IsRegister()) {
+ __ cmpl(lhs.AsX86().AsCpuRegister(), Immediate(0));
+ } else {
+ __ cmpl(Address(ESP, lhs.GetStackIndex()), Immediate(0));
+ }
+ __ j(kEqual, codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
} else {
- __ cmpl(Address(ESP, location.GetStackIndex()), Immediate(0));
+ Location lhs = condition->GetLocations()->InAt(0);
+ Location rhs = condition->GetLocations()->InAt(1);
+ // LHS is guaranteed to be in a register (see LocationsBuilderX86::VisitCondition).
+ if (rhs.IsRegister()) {
+ __ cmpl(lhs.AsX86().AsCpuRegister(), rhs.AsX86().AsCpuRegister());
+ } else {
+ __ cmpl(lhs.AsX86().AsCpuRegister(), Address(ESP, rhs.GetStackIndex()));
+ }
+ __ j(X86Condition(condition->GetCondition()),
+ codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
}
- __ j(kEqual, codegen_->GetLabelOf(if_instr->IfFalseSuccessor()));
- if (!codegen_->GoesToNextBlock(if_instr->GetBlock(), if_instr->IfTrueSuccessor())) {
- __ jmp(codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
+ if (!codegen_->GoesToNextBlock(if_instr->GetBlock(), if_instr->IfFalseSuccessor())) {
+ __ jmp(codegen_->GetLabelOf(if_instr->IfFalseSuccessor()));
}
}
void InstructionCodeGeneratorX86::VisitStoreLocal(HStoreLocal* store) {
}
-void LocationsBuilderX86::VisitEqual(HEqual* equal) {
- LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(equal);
+void LocationsBuilderX86::VisitCondition(HCondition* comp) {
+ LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(comp);
locations->SetInAt(0, Location::RequiresRegister());
locations->SetInAt(1, Location::Any());
locations->SetOut(Location::SameAsFirstInput());
- equal->SetLocations(locations);
+ comp->SetLocations(locations);
}
-void InstructionCodeGeneratorX86::VisitEqual(HEqual* equal) {
- LocationSummary* locations = equal->GetLocations();
- if (locations->InAt(1).IsRegister()) {
- __ cmpl(locations->InAt(0).AsX86().AsCpuRegister(),
- locations->InAt(1).AsX86().AsCpuRegister());
- } else {
- __ cmpl(locations->InAt(0).AsX86().AsCpuRegister(),
- Address(ESP, locations->InAt(1).GetStackIndex()));
+void InstructionCodeGeneratorX86::VisitCondition(HCondition* comp) {
+ if (comp->NeedsMaterialization()) {
+ LocationSummary* locations = comp->GetLocations();
+ if (locations->InAt(1).IsRegister()) {
+ __ cmpl(locations->InAt(0).AsX86().AsCpuRegister(),
+ locations->InAt(1).AsX86().AsCpuRegister());
+ } else {
+ __ cmpl(locations->InAt(0).AsX86().AsCpuRegister(),
+ Address(ESP, locations->InAt(1).GetStackIndex()));
+ }
+ __ setb(X86Condition(comp->GetCondition()), locations->Out().AsX86().AsCpuRegister());
}
- __ setb(kEqual, locations->Out().AsX86().AsCpuRegister());
+}
+
+void LocationsBuilderX86::VisitEqual(HEqual* comp) {
+ VisitCondition(comp);
+}
+
+void InstructionCodeGeneratorX86::VisitEqual(HEqual* comp) {
+ VisitCondition(comp);
+}
+
+void LocationsBuilderX86::VisitNotEqual(HNotEqual* comp) {
+ VisitCondition(comp);
+}
+
+void InstructionCodeGeneratorX86::VisitNotEqual(HNotEqual* comp) {
+ VisitCondition(comp);
+}
+
+void LocationsBuilderX86::VisitLessThan(HLessThan* comp) {
+ VisitCondition(comp);
+}
+
+void InstructionCodeGeneratorX86::VisitLessThan(HLessThan* comp) {
+ VisitCondition(comp);
+}
+
+void LocationsBuilderX86::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
+ VisitCondition(comp);
+}
+
+void InstructionCodeGeneratorX86::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
+ VisitCondition(comp);
+}
+
+void LocationsBuilderX86::VisitGreaterThan(HGreaterThan* comp) {
+ VisitCondition(comp);
+}
+
+void InstructionCodeGeneratorX86::VisitGreaterThan(HGreaterThan* comp) {
+ VisitCondition(comp);
+}
+
+void LocationsBuilderX86::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
+ VisitCondition(comp);
+}
+
+void InstructionCodeGeneratorX86::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
+ VisitCondition(comp);
}
void LocationsBuilderX86::VisitIntConstant(HIntConstant* constant) {
namespace x86_64 {
+inline Condition X86_64Condition(IfCondition cond) {
+ switch (cond) {
+ case kCondEQ: return kEqual;
+ case kCondNE: return kNotEqual;
+ case kCondLT: return kLess;
+ case kCondLE: return kLessEqual;
+ case kCondGT: return kGreater;
+ case kCondGE: return kGreaterEqual;
+ default:
+ LOG(FATAL) << "Unknown if condition";
+ }
+ return kEqual;
+}
+
// Some x86_64 instructions require a register to be available as temp.
static constexpr Register TMP = R11;
void LocationsBuilderX86_64::VisitIf(HIf* if_instr) {
LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(if_instr);
- locations->SetInAt(0, Location::RequiresRegister());
+ locations->SetInAt(0, Location::Any());
if_instr->SetLocations(locations);
}
void InstructionCodeGeneratorX86_64::VisitIf(HIf* if_instr) {
- // TODO: Generate the input as a condition, instead of materializing in a register.
- __ cmpl(if_instr->GetLocations()->InAt(0).AsX86_64().AsCpuRegister(), Immediate(0));
- __ j(kEqual, codegen_->GetLabelOf(if_instr->IfFalseSuccessor()));
- if (!codegen_->GoesToNextBlock(if_instr->GetBlock(), if_instr->IfTrueSuccessor())) {
- __ jmp(codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
+ HInstruction* cond = if_instr->InputAt(0);
+ DCHECK(cond->IsCondition());
+ HCondition* condition = cond->AsCondition();
+ if (condition->NeedsMaterialization()) {
+ // Materialized condition, compare against 0.
+ Location lhs = if_instr->GetLocations()->InAt(0);
+ if (lhs.IsRegister()) {
+ __ cmpl(lhs.AsX86_64().AsCpuRegister(), Immediate(0));
+ } else {
+ __ cmpl(Address(CpuRegister(RSP), lhs.GetStackIndex()), Immediate(0));
+ }
+ __ j(kEqual, codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
+ } else {
+ Location lhs = condition->GetLocations()->InAt(0);
+ Location rhs = condition->GetLocations()->InAt(1);
+ __ cmpl(lhs.AsX86_64().AsCpuRegister(), rhs.AsX86_64().AsCpuRegister());
+ __ j(X86_64Condition(condition->GetCondition()),
+ codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
+ }
+ if (!codegen_->GoesToNextBlock(if_instr->GetBlock(), if_instr->IfFalseSuccessor())) {
+ __ jmp(codegen_->GetLabelOf(if_instr->IfFalseSuccessor()));
}
}
void InstructionCodeGeneratorX86_64::VisitStoreLocal(HStoreLocal* store) {
}
-void LocationsBuilderX86_64::VisitEqual(HEqual* equal) {
- LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(equal);
+void LocationsBuilderX86_64::VisitCondition(HCondition* comp) {
+ LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(comp);
locations->SetInAt(0, Location::RequiresRegister());
locations->SetInAt(1, Location::RequiresRegister());
locations->SetOut(Location::SameAsFirstInput());
- equal->SetLocations(locations);
+ comp->SetLocations(locations);
+}
+
+void InstructionCodeGeneratorX86_64::VisitCondition(HCondition* comp) {
+ if (comp->NeedsMaterialization()) {
+ __ cmpq(comp->GetLocations()->InAt(0).AsX86_64().AsCpuRegister(),
+ comp->GetLocations()->InAt(1).AsX86_64().AsCpuRegister());
+ __ setcc(X86_64Condition(comp->GetCondition()),
+ comp->GetLocations()->Out().AsX86_64().AsCpuRegister());
+ }
+}
+
+void LocationsBuilderX86_64::VisitEqual(HEqual* comp) {
+ VisitCondition(comp);
+}
+
+void InstructionCodeGeneratorX86_64::VisitEqual(HEqual* comp) {
+ VisitCondition(comp);
+}
+
+void LocationsBuilderX86_64::VisitNotEqual(HNotEqual* comp) {
+ VisitCondition(comp);
+}
+
+void InstructionCodeGeneratorX86_64::VisitNotEqual(HNotEqual* comp) {
+ VisitCondition(comp);
+}
+
+void LocationsBuilderX86_64::VisitLessThan(HLessThan* comp) {
+ VisitCondition(comp);
+}
+
+void InstructionCodeGeneratorX86_64::VisitLessThan(HLessThan* comp) {
+ VisitCondition(comp);
+}
+
+void LocationsBuilderX86_64::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
+ VisitCondition(comp);
+}
+
+void InstructionCodeGeneratorX86_64::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
+ VisitCondition(comp);
+}
+
+void LocationsBuilderX86_64::VisitGreaterThan(HGreaterThan* comp) {
+ VisitCondition(comp);
+}
+
+void InstructionCodeGeneratorX86_64::VisitGreaterThan(HGreaterThan* comp) {
+ VisitCondition(comp);
+}
+
+void LocationsBuilderX86_64::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
+ VisitCondition(comp);
}
-void InstructionCodeGeneratorX86_64::VisitEqual(HEqual* equal) {
- __ cmpq(equal->GetLocations()->InAt(0).AsX86_64().AsCpuRegister(),
- equal->GetLocations()->InAt(1).AsX86_64().AsCpuRegister());
- __ setcc(kEqual, equal->GetLocations()->Out().AsX86_64().AsCpuRegister());
+void InstructionCodeGeneratorX86_64::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
+ VisitCondition(comp);
}
void LocationsBuilderX86_64::VisitIntConstant(HIntConstant* constant) {
static void Run(const InternalCodeAllocator& allocator, bool has_result, int32_t expected) {
typedef int32_t (*fptr)();
CommonCompilerTest::MakeExecutable(allocator.GetMemory(), allocator.GetSize());
- int32_t result = reinterpret_cast<fptr>(allocator.GetMemory())();
+ fptr f = reinterpret_cast<fptr>(allocator.GetMemory());
+#if defined(__arm__)
+ // For thumb we need the bottom bit set.
+ f = reinterpret_cast<fptr>(reinterpret_cast<uintptr_t>(f) + 1);
+#endif
+ int32_t result = f();
if (has_result) {
CHECK_EQ(result, expected);
}
graph->AddBlock(if_block);
HInstruction* instr = new (allocator) HIntConstant(4);
if_block->AddInstruction(instr);
- instr = new (allocator) HIf(instr);
+ HInstruction* equal = new (allocator) HEqual(instr, instr);
+ if_block->AddInstruction(equal);
+ instr = new (allocator) HIf(equal);
if_block->AddInstruction(instr);
return if_block;
}
}
}
+
+bool HCondition::NeedsMaterialization() const {
+ if (!HasOnlyOneUse()) {
+ return true;
+ }
+ HUseListNode<HInstruction>* uses = GetUses();
+ HInstruction* user = uses->GetUser();
+ if (!user->IsIf()) {
+ return true;
+ }
+
+ // TODO: should we allow intervening instructions with no side-effect between this condition
+ // and the If instruction?
+ if (GetNext() != user) {
+ return true;
+ }
+ return false;
+}
+
} // namespace art
static const int kDefaultNumberOfPredecessors = 2;
static const int kDefaultNumberOfBackEdges = 1;
+enum IfCondition {
+ kCondEQ,
+ kCondNE,
+ kCondLT,
+ kCondLE,
+ kCondGT,
+ kCondGE,
+};
+
class HInstructionList {
public:
HInstructionList() : first_instruction_(nullptr), last_instruction_(nullptr) {}
maximum_number_of_out_vregs_(0),
number_of_vregs_(0),
number_of_in_vregs_(0),
- current_instruction_id_(0) { }
+ current_instruction_id_(0) {}
ArenaAllocator* GetArena() const { return arena_; }
const GrowableArray<HBasicBlock*>& GetBlocks() const { return blocks_; }
#define FOR_EACH_INSTRUCTION(M) \
M(Add) \
+ M(Condition) \
M(Equal) \
+ M(NotEqual) \
+ M(LessThan) \
+ M(LessThanOrEqual) \
+ M(GreaterThan) \
+ M(GreaterThanOrEqual) \
M(Exit) \
M(Goto) \
M(If) \
M(StoreLocal) \
M(Sub) \
+
#define FORWARD_DECLARATION(type) class H##type;
FOR_EACH_INSTRUCTION(FORWARD_DECLARATION)
#undef FORWARD_DECLARATION
class HUseListNode : public ArenaObject {
public:
HUseListNode(T* user, size_t index, HUseListNode* tail)
- : user_(user), index_(index), tail_(tail) { }
+ : user_(user), index_(index), tail_(tail) {}
HUseListNode* GetTail() const { return tail_; }
T* GetUser() const { return user_; }
live_interval_(nullptr),
lifetime_position_(kNoLifetime) {}
- virtual ~HInstruction() { }
+ virtual ~HInstruction() {}
HInstruction* GetNext() const { return next_; }
HInstruction* GetPrevious() const { return previous_; }
void ReplaceWith(HInstruction* instruction);
+ bool HasOnlyOneUse() const {
+ return uses_ != nullptr && uses_->GetTail() == nullptr;
+ }
+
#define INSTRUCTION_TYPE_CHECK(type) \
bool Is##type() { return (As##type() != nullptr); } \
virtual H##type* As##type() { return nullptr; }
class HInputIterator : public ValueObject {
public:
- explicit HInputIterator(HInstruction* instruction) : instruction_(instruction), index_(0) { }
+ explicit HInputIterator(HInstruction* instruction) : instruction_(instruction), index_(0) {}
bool Done() const { return index_ == instruction_->InputCount(); }
HInstruction* Current() const { return instruction_->InputAt(index_); }
template<typename T, intptr_t N>
class EmbeddedArray {
public:
- EmbeddedArray() : elements_() { }
+ EmbeddedArray() : elements_() {}
intptr_t GetLength() const { return N; }
template<intptr_t N>
class HTemplateInstruction: public HInstruction {
public:
- HTemplateInstruction<N>() : inputs_() { }
- virtual ~HTemplateInstruction() { }
+ HTemplateInstruction<N>() : inputs_() {}
+ virtual ~HTemplateInstruction() {}
virtual size_t InputCount() const { return N; }
virtual HInstruction* InputAt(size_t i) const { return inputs_[i]; }
friend class SsaBuilder;
};
+template<intptr_t N>
+class HExpression: public HTemplateInstruction<N> {
+ public:
+ explicit HExpression<N>(Primitive::Type type) : type_(type) {}
+ virtual ~HExpression() {}
+
+ virtual Primitive::Type GetType() const { return type_; }
+
+ private:
+ const Primitive::Type type_;
+};
+
// Represents dex's RETURN_VOID opcode. A HReturnVoid is a control flow
// instruction that branches to the exit block.
class HReturnVoid : public HTemplateInstruction<0> {
DISALLOW_COPY_AND_ASSIGN(HGoto);
};
+
// Conditional branch. A block ending with an HIf instruction must have
// two successors.
class HIf : public HTemplateInstruction<1> {
DECLARE_INSTRUCTION(If);
+ virtual bool IsIfInstruction() const { return true; }
+
private:
DISALLOW_COPY_AND_ASSIGN(HIf);
};
-class HBinaryOperation : public HTemplateInstruction<2> {
+class HBinaryOperation : public HExpression<2> {
public:
HBinaryOperation(Primitive::Type result_type,
HInstruction* left,
- HInstruction* right) : result_type_(result_type) {
+ HInstruction* right) : HExpression(result_type) {
SetRawInputAt(0, left);
SetRawInputAt(1, right);
}
HInstruction* GetLeft() const { return InputAt(0); }
HInstruction* GetRight() const { return InputAt(1); }
- Primitive::Type GetResultType() const { return result_type_; }
+ Primitive::Type GetResultType() const { return GetType(); }
virtual bool IsCommutative() { return false; }
- virtual Primitive::Type GetType() const { return GetResultType(); }
private:
- const Primitive::Type result_type_;
-
DISALLOW_COPY_AND_ASSIGN(HBinaryOperation);
};
-
-// Instruction to check if two inputs are equal to each other.
-class HEqual : public HBinaryOperation {
+class HCondition : public HBinaryOperation {
public:
- HEqual(HInstruction* first, HInstruction* second)
+ HCondition(HInstruction* first, HInstruction* second)
: HBinaryOperation(Primitive::kPrimBoolean, first, second) {}
virtual bool IsCommutative() { return true; }
+ bool NeedsMaterialization() const;
- virtual Primitive::Type GetType() const { return Primitive::kPrimBoolean; }
+ DECLARE_INSTRUCTION(Condition);
+
+ virtual IfCondition GetCondition() const = 0;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(HCondition);
+};
+
+// Instruction to check if two inputs are equal to each other.
+class HEqual : public HCondition {
+ public:
+ HEqual(HInstruction* first, HInstruction* second)
+ : HCondition(first, second) {}
DECLARE_INSTRUCTION(Equal);
+ virtual IfCondition GetCondition() const {
+ return kCondEQ;
+ }
+
private:
DISALLOW_COPY_AND_ASSIGN(HEqual);
};
+class HNotEqual : public HCondition {
+ public:
+ HNotEqual(HInstruction* first, HInstruction* second)
+ : HCondition(first, second) {}
+
+ DECLARE_INSTRUCTION(NotEqual);
+
+ virtual IfCondition GetCondition() const {
+ return kCondNE;
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(HNotEqual);
+};
+
+class HLessThan : public HCondition {
+ public:
+ HLessThan(HInstruction* first, HInstruction* second)
+ : HCondition(first, second) {}
+
+ DECLARE_INSTRUCTION(LessThan);
+
+ virtual IfCondition GetCondition() const {
+ return kCondLT;
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(HLessThan);
+};
+
+class HLessThanOrEqual : public HCondition {
+ public:
+ HLessThanOrEqual(HInstruction* first, HInstruction* second)
+ : HCondition(first, second) {}
+
+ DECLARE_INSTRUCTION(LessThanOrEqual);
+
+ virtual IfCondition GetCondition() const {
+ return kCondLE;
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(HLessThanOrEqual);
+};
+
+class HGreaterThan : public HCondition {
+ public:
+ HGreaterThan(HInstruction* first, HInstruction* second)
+ : HCondition(first, second) {}
+
+ DECLARE_INSTRUCTION(GreaterThan);
+
+ virtual IfCondition GetCondition() const {
+ return kCondGT;
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(HGreaterThan);
+};
+
+class HGreaterThanOrEqual : public HCondition {
+ public:
+ HGreaterThanOrEqual(HInstruction* first, HInstruction* second)
+ : HCondition(first, second) {}
+
+ DECLARE_INSTRUCTION(GreaterThanOrEqual);
+
+ virtual IfCondition GetCondition() const {
+ return kCondGE;
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(HGreaterThanOrEqual);
+};
+
+
// A local in the graph. Corresponds to a Dex register.
class HLocal : public HTemplateInstruction<0> {
public:
- explicit HLocal(uint16_t reg_number) : reg_number_(reg_number) { }
+ explicit HLocal(uint16_t reg_number) : reg_number_(reg_number) {}
DECLARE_INSTRUCTION(Local);
};
// Load a given local. The local is an input of this instruction.
-class HLoadLocal : public HTemplateInstruction<1> {
+class HLoadLocal : public HExpression<1> {
public:
- explicit HLoadLocal(HLocal* local, Primitive::Type type) : type_(type) {
+ explicit HLoadLocal(HLocal* local, Primitive::Type type) : HExpression(type) {
SetRawInputAt(0, local);
}
- virtual Primitive::Type GetType() const { return type_; }
-
HLocal* GetLocal() const { return reinterpret_cast<HLocal*>(InputAt(0)); }
DECLARE_INSTRUCTION(LoadLocal);
private:
- const Primitive::Type type_;
-
DISALLOW_COPY_AND_ASSIGN(HLoadLocal);
};
// Constants of the type int. Those can be from Dex instructions, or
// synthesized (for example with the if-eqz instruction).
-class HIntConstant : public HTemplateInstruction<0> {
+class HIntConstant : public HExpression<0> {
public:
- explicit HIntConstant(int32_t value) : value_(value) { }
+ explicit HIntConstant(int32_t value) : HExpression(Primitive::kPrimInt), value_(value) {}
int32_t GetValue() const { return value_; }
- virtual Primitive::Type GetType() const { return Primitive::kPrimInt; }
DECLARE_INSTRUCTION(IntConstant);
DISALLOW_COPY_AND_ASSIGN(HIntConstant);
};
-class HLongConstant : public HTemplateInstruction<0> {
+class HLongConstant : public HExpression<0> {
public:
- explicit HLongConstant(int64_t value) : value_(value) { }
+ explicit HLongConstant(int64_t value) : HExpression(Primitive::kPrimLong), value_(value) {}
int64_t GetValue() const { return value_; }
DISALLOW_COPY_AND_ASSIGN(HInvokeStatic);
};
-class HNewInstance : public HTemplateInstruction<0> {
+class HNewInstance : public HExpression<0> {
public:
- HNewInstance(uint32_t dex_pc, uint16_t type_index) : dex_pc_(dex_pc), type_index_(type_index) {}
+ HNewInstance(uint32_t dex_pc, uint16_t type_index) : HExpression(Primitive::kPrimNot),
+ dex_pc_(dex_pc), type_index_(type_index) {}
uint32_t GetDexPc() const { return dex_pc_; }
uint16_t GetTypeIndex() const { return type_index_; }
- virtual Primitive::Type GetType() const { return Primitive::kPrimNot; }
-
// Calls runtime so needs an environment.
virtual bool NeedsEnvironment() const { return true; }
// The value of a parameter in this method. Its location depends on
// the calling convention.
-class HParameterValue : public HTemplateInstruction<0> {
+class HParameterValue : public HExpression<0> {
public:
HParameterValue(uint8_t index, Primitive::Type parameter_type)
- : index_(index), parameter_type_(parameter_type) {}
+ : HExpression(parameter_type), index_(index) {}
uint8_t GetIndex() const { return index_; }
- virtual Primitive::Type GetType() const { return parameter_type_; }
-
DECLARE_INSTRUCTION(ParameterValue);
private:
// than HGraph::number_of_in_vregs_;
const uint8_t index_;
- const Primitive::Type parameter_type_;
-
DISALLOW_COPY_AND_ASSIGN(HParameterValue);
};
-class HNot : public HTemplateInstruction<1> {
+class HNot : public HExpression<1> {
public:
- explicit HNot(HInstruction* input) {
+ explicit HNot(HInstruction* input) : HExpression(Primitive::kPrimBoolean) {
SetRawInputAt(0, input);
}
- virtual Primitive::Type GetType() const { return Primitive::kPrimBoolean; }
-
DECLARE_INSTRUCTION(Not);
private:
class HGraphVisitor : public ValueObject {
public:
- explicit HGraphVisitor(HGraph* graph) : graph_(graph) { }
- virtual ~HGraphVisitor() { }
+ explicit HGraphVisitor(HGraph* graph) : graph_(graph) {}
+ virtual ~HGraphVisitor() {}
- virtual void VisitInstruction(HInstruction* instruction) { }
+ virtual void VisitInstruction(HInstruction* instruction) {}
virtual void VisitBasicBlock(HBasicBlock* block);
void VisitInsertionOrder();
}
InstructionSet instruction_set = GetCompilerDriver()->GetInstructionSet();
- // The optimizing compiler currently does not have a Thumb2 assembler.
- if (instruction_set == kThumb2) {
- instruction_set = kArm;
- }
CodeGenerator* codegen = CodeGenerator::Create(&arena, graph, instruction_set);
if (codegen == nullptr) {
if (shouldCompile) {
interval->AddRange(start, end);
}
+// TODO: make the register allocator understand instructions like HCondition
+// that may not need to be materialized. It doesn't need to allocate any
+// registers for it.
void RegisterAllocator::AllocateRegistersInternal() {
number_of_registers_ = processing_core_registers_
? codegen_->GetNumberOfCoreRegisters()
++reg;
}
CHECK_LT(reg, 16);
- CHECK(am == DB_W); // Only writeback is supported.
+ CHECK(am == IA_W); // Only writeback is supported.
ldr(static_cast<Register>(reg), Address(base, kRegisterSize, Address::PostIndex), cond);
} else {
EmitMultiMemOp(cond, am, true, base, regs);
++reg;
}
CHECK_LT(reg, 16);
- CHECK(am == IA || am == IA_W);
- Address::Mode strmode = am == IA ? Address::PreIndex : Address::Offset;
+ CHECK(am == DB || am == DB_W);
+ Address::Mode strmode = am == DB_W ? Address::PreIndex : Address::Offset;
str(static_cast<Register>(reg), Address(base, -kRegisterSize, strmode), cond);
} else {
EmitMultiMemOp(cond, am, false, base, regs);
if (imm > (1 << 9)) { // 9 bit immediate.
return true;
}
+ return false; // 16 bit good.
} else if (opcode == ADD && rd != SP && rn == SP) { // 10 bit immediate.
if (imm > (1 << 10)) {
return true;
uint32_t op = (instruction >> 21) & 0xf;
opcode = kDataProcessingOperations[op];
bool implicit_s = ((op & ~3) == 8); // TST, TEQ, CMP, and CMN.
- if (implicit_s) {
- // Rd is unused (and not shown), and we don't show the 's' suffix either.
- } else {
+ bool is_mov = op == 0b1101 || op == 0b1111;
+ if (is_mov) {
+ // Show only Rd and Rm.
if (s) {
- suffixes += 's';
- }
- args << ArmRegister(instruction, 12) << ", ";
- }
- if (i) {
- args << ArmRegister(instruction, 16) << ", " << ShiftedImmediate(instruction);
+ suffixes += 's';
+ }
+ args << ArmRegister(instruction, 12) << ", ";
+ if (i) {
+ args << ShiftedImmediate(instruction);
+ } else {
+ // TODO: Shifted register.
+ args << ArmRegister(instruction, 16) << ", " << ArmRegister(instruction, 0);
+ }
} else {
- args << Rm(instruction);
+ if (implicit_s) {
+ // Rd is unused (and not shown), and we don't show the 's' suffix either.
+ } else {
+ if (s) {
+ suffixes += 's';
+ }
+ args << ArmRegister(instruction, 12) << ", ";
+ }
+ if (i) {
+ args << ArmRegister(instruction, 16) << ", " << ShiftedImmediate(instruction);
+ } else {
+ // TODO: Shifted register.
+ args << ArmRegister(instruction, 16) << ", " << ArmRegister(instruction, 0);
+ }
}
}
break;
int32_t imm32 = (imm8 << 24) >> 24; // sign-extend imm8
if (Rn.r == 13 && P == 1 && U == 0 && W == 1 && imm32 == 4) {
opcode << "push";
- args << Rt;
+ args << "{" << Rt << "}";
} else if (Rn.r == 15 || (P == 0 && W == 0)) {
opcode << "UNDEFINED";
} else {
}
args << "]";
} else {
- // LDRT Rt, [Rn, #imm8] - 111 11 00 00 101 nnnn tttt 1110iiiiiiii
- uint32_t imm8 = instr & 0xFF;
- opcode << "ldrt";
- args << Rt << ", [" << Rn << ", #" << imm8 << "]";
+ bool p = (instr & (1 << 10)) != 0;
+ bool w = (instr & (1 << 8)) != 0;
+ bool u = (instr & (1 << 9)) != 0;
+ if (p && u && !w) {
+ // LDRT Rt, [Rn, #imm8] - 111 11 00 00 101 nnnn tttt 1110iiiiiiii
+ uint32_t imm8 = instr & 0xFF;
+ opcode << "ldrt";
+ args << Rt << ", [" << Rn << ", #" << imm8 << "]";
+ } else if (Rn.r == 13 && !p && u && w && (instr & 0xff) == 4) {
+ // POP
+ opcode << "pop";
+ args << "{" << Rt << "}";
+ } else {
+ bool wback = !p || w;
+ uint32_t offset = (instr & 0xff);
+ opcode << "ldr.w";
+ args << Rt << ",";
+ if (p && !wback) {
+ args << "[" << Rn << ", #" << offset << "]";
+ } else if (p && wback) {
+ args << "[" << Rn << ", #" << offset << "]!";
+ } else if (!p && wback) {
+ args << "[" << Rn << "], #" << offset;
+ } else {
+ LOG(FATAL) << p << " " << w;
+ }
+ }
}
break;
}