Allow X86 QBE to be extended
Enhancements and updates to allow X86Mir2LIR Backend to be subclassed
for experimentation. Add virtual in a whole bunch of places, and make
some other changes to get this to work.
Change-Id: I0980a19bc5d5725f91660f98c95f1f51c17ee9b6
Signed-off-by: Mark Mendell <mark.p.mendell@intel.com>
diff --git a/compiler/dex/quick/x86/codegen_x86.h b/compiler/dex/quick/x86/codegen_x86.h
index 52c870b..e717638 100644
--- a/compiler/dex/quick/x86/codegen_x86.h
+++ b/compiler/dex/quick/x86/codegen_x86.h
@@ -22,7 +22,7 @@
namespace art {
-class X86Mir2Lir FINAL : public Mir2Lir {
+class X86Mir2Lir : public Mir2Lir {
public:
X86Mir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena, bool gen64bit);
@@ -175,8 +175,8 @@
* @param op The DEX opcode for the operation.
* @param is_commutative The sources can be swapped if needed.
*/
- void GenLongArith(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2,
- Instruction::Code op, bool is_commutative);
+ virtual void GenLongArith(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2,
+ Instruction::Code op, bool is_commutative);
/**
* @brief Generate a two operand long arithmetic operation.
@@ -192,7 +192,7 @@
* @param rl_src The other operand. May be in a register or in memory.
* @param op The DEX opcode for the operation.
*/
- void GenLongRegOrMemOp(RegLocation rl_dest, RegLocation rl_src, Instruction::Code op);
+ virtual void GenLongRegOrMemOp(RegLocation rl_dest, RegLocation rl_src, Instruction::Code op);
/**
* @brief Implement instanceof a final class with x86 specific code.
@@ -265,6 +265,12 @@
bool InexpensiveConstantDouble(int64_t value);
/*
+ * @brief Should try to optimize for two address instructions?
+ * @return true if we try to avoid generating three operand instructions.
+ */
+ virtual bool GenerateTwoOperandInstructions() const { return true; }
+
+ /*
* @brief x86 specific codegen for int operations.
* @param opcode Operation to perform.
* @param rl_dest Destination for the result.
@@ -304,7 +310,7 @@
* @param type How the method will be invoked.
* @returns Call instruction
*/
- LIR * CallWithLinkerFixup(const MethodReference& target_method, InvokeType type);
+ virtual LIR * CallWithLinkerFixup(const MethodReference& target_method, InvokeType type);
/*
* @brief Handle x86 specific literals
@@ -323,7 +329,7 @@
*/
std::vector<uint8_t>* ReturnCallFrameInformation();
- private:
+ protected:
size_t ComputeSize(const X86EncodingMap* entry, int base, int displacement, bool has_sib);
void EmitPrefix(const X86EncodingMap* entry);
void EmitOpcode(const X86EncodingMap* entry);
@@ -398,6 +404,12 @@
static bool ProvidesFullMemoryBarrier(X86OpCode opcode);
/*
+ * @brief Ensure that a temporary register is byte addressable.
+ * @returns a temporary guarenteed to be byte addressable.
+ */
+ virtual RegStorage AllocateByteRegister();
+
+ /*
* @brief generate inline code for fast case of Strng.indexOf.
* @param info Call parameters
* @param zero_based 'true' if the index into the string is 0.
@@ -533,7 +545,7 @@
* @param rl_src The source of the long.
* @param is_double 'true' if dealing with double, 'false' for float.
*/
- void GenLongToFP(RegLocation rl_dest, RegLocation rl_src, bool is_double);
+ virtual void GenLongToFP(RegLocation rl_dest, RegLocation rl_src, bool is_double);
/*
* @brief Perform MIR analysis before compiling method.
@@ -579,7 +591,7 @@
* @param bb Basic block containing instruction.
* @param mir Instruction to analyze.
*/
- void AnalyzeMIR(int opcode, BasicBlock * bb, MIR *mir);
+ virtual void AnalyzeMIR(int opcode, BasicBlock * bb, MIR *mir);
/*
* @brief Analyze one MIR float/double instruction
diff --git a/compiler/dex/quick/x86/int_x86.cc b/compiler/dex/quick/x86/int_x86.cc
index 71a3962..a6ccc99 100644
--- a/compiler/dex/quick/x86/int_x86.cc
+++ b/compiler/dex/quick/x86/int_x86.cc
@@ -1292,8 +1292,12 @@
case Instruction::AND_LONG_2ADDR:
case Instruction::OR_LONG_2ADDR:
case Instruction::XOR_LONG_2ADDR:
- GenLongArith(rl_dest, rl_src2, op);
- return;
+ if (GenerateTwoOperandInstructions()) {
+ GenLongArith(rl_dest, rl_src2, op);
+ return;
+ }
+ break;
+
default:
break;
}
@@ -1532,7 +1536,7 @@
RegLocation X86Mir2Lir::GenShiftImmOpLong(Instruction::Code opcode, RegLocation rl_dest,
RegLocation rl_src, int shift_amount) {
- RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
+ RegLocation rl_result = EvalLocWide(rl_dest, kCoreReg, true);
switch (opcode) {
case Instruction::SHL_LONG:
case Instruction::SHL_LONG_2ADDR:
@@ -1641,7 +1645,11 @@
case Instruction::XOR_LONG_2ADDR:
case Instruction::AND_LONG_2ADDR:
if (rl_src2.is_const) {
- GenLongImm(rl_dest, rl_src2, opcode);
+ if (GenerateTwoOperandInstructions()) {
+ GenLongImm(rl_dest, rl_src2, opcode);
+ } else {
+ GenLongLongImm(rl_dest, rl_src1, rl_src2, opcode);
+ }
} else {
DCHECK(rl_src1.is_const);
GenLongLongImm(rl_dest, rl_src2, rl_src1, opcode);
@@ -1869,7 +1877,7 @@
// SETcc only works with EAX..EDX.
if (result_reg == object.reg || result_reg.GetRegNum() >= rs_rX86_SP.GetRegNum()) {
- result_reg = AllocTypedTemp(false, kCoreReg);
+ result_reg = AllocateByteRegister();
DCHECK_LT(result_reg.GetRegNum(), rs_rX86_SP.GetRegNum());
}
@@ -2110,12 +2118,16 @@
LOG(FATAL) << "Invalid word arith op: " << opcode;
}
- // Can we convert to a two address instruction?
+ // Can we convert to a two address instruction?
if (!is_two_addr &&
(mir_graph_->SRegToVReg(rl_dest.s_reg_low) ==
mir_graph_->SRegToVReg(rl_lhs.s_reg_low))) {
- is_two_addr = true;
- }
+ is_two_addr = true;
+ }
+
+ if (!GenerateTwoOperandInstructions()) {
+ is_two_addr = false;
+ }
// Get the div/rem stuff out of the way.
if (is_div_rem) {
@@ -2212,6 +2224,8 @@
if (mir_graph_->SRegToVReg(rl_dest.s_reg_low) == mir_graph_->SRegToVReg(rl_lhs.s_reg_low)) {
rl_lhs = LoadValue(rl_lhs, kCoreReg);
rl_result = EvalLoc(rl_dest, kCoreReg, true);
+ // No-op if these are the same.
+ OpRegCopy(rl_result.reg, rl_lhs.reg);
} else {
rl_result = EvalLoc(rl_dest, kCoreReg, true);
LoadValueDirect(rl_lhs, rl_result.reg);
diff --git a/compiler/dex/quick/x86/target_x86.cc b/compiler/dex/quick/x86/target_x86.cc
index 8f06791..9ddeb68 100644
--- a/compiler/dex/quick/x86/target_x86.cc
+++ b/compiler/dex/quick/x86/target_x86.cc
@@ -423,6 +423,10 @@
UNIMPLEMENTED(FATAL) << "MarkPreservedDouble";
}
+RegStorage X86Mir2Lir::AllocateByteRegister() {
+ return AllocTypedTemp(false, kCoreReg);
+}
+
/* Clobber all regs that might be used by an external C call */
void X86Mir2Lir::ClobberCallerSave() {
Clobber(rs_rAX);
diff --git a/compiler/dex/quick/x86/utility_x86.cc b/compiler/dex/quick/x86/utility_x86.cc
index e9592a6..fed31c1 100644
--- a/compiler/dex/quick/x86/utility_x86.cc
+++ b/compiler/dex/quick/x86/utility_x86.cc
@@ -161,6 +161,22 @@
case kOpMul:
opcode = byte_imm ? kX86Imul32RRI8 : kX86Imul32RRI;
return NewLIR3(opcode, r_dest_src1.GetReg(), r_dest_src1.GetReg(), value);
+ case kOp2Byte:
+ opcode = kX86Mov32RI;
+ value = static_cast<int8_t>(value);
+ break;
+ case kOp2Short:
+ opcode = kX86Mov32RI;
+ value = static_cast<int16_t>(value);
+ break;
+ case kOp2Char:
+ opcode = kX86Mov32RI;
+ value = static_cast<uint16_t>(value);
+ break;
+ case kOpNeg:
+ opcode = kX86Mov32RI;
+ value = -value;
+ break;
default:
LOG(FATAL) << "Bad case in OpRegImm " << op;
}
@@ -523,7 +539,7 @@
int32_t val_hi = High32Bits(value);
int32_t low_reg_val = r_dest.IsPair() ? r_dest.GetLowReg() : r_dest.GetReg();
LIR *res;
- bool is_fp = RegStorage::IsFloat(low_reg_val);
+ bool is_fp = r_dest.IsFloat();
// TODO: clean this up once we fully recognize 64-bit storage containers.
if (is_fp) {
if (value == 0) {