summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--compiler/dex/mir_graph.h2
-rw-r--r--compiler/dex/quick/x86/assemble_x86.cc11
-rw-r--r--compiler/dex/quick/x86/call_x86.cc30
-rw-r--r--compiler/dex/quick/x86/codegen_x86.h55
-rw-r--r--compiler/dex/quick/x86/target_x86.cc8
-rw-r--r--compiler/dex/quick/x86/utility_x86.cc141
6 files changed, 241 insertions, 6 deletions
diff --git a/compiler/dex/mir_graph.h b/compiler/dex/mir_graph.h
index debcb5c..f8706c4 100644
--- a/compiler/dex/mir_graph.h
+++ b/compiler/dex/mir_graph.h
@@ -647,7 +647,7 @@ class MIRGraph {
}
RegLocation GetRegLocation(int index) {
- DCHECK((index >= 0) && (index > num_ssa_regs_));
+ DCHECK((index >= 0) && (index < num_ssa_regs_));
return reg_location_[index];
}
diff --git a/compiler/dex/quick/x86/assemble_x86.cc b/compiler/dex/quick/x86/assemble_x86.cc
index 916bc7a..3058b0c 100644
--- a/compiler/dex/quick/x86/assemble_x86.cc
+++ b/compiler/dex/quick/x86/assemble_x86.cc
@@ -1154,6 +1154,17 @@ AssemblerStatus X86Mir2Lir::AssembleInstructions(CodeOffset start_addr) {
break;
}
default:
+ if (lir->flags.fixup == kFixupLoad) {
+ LIR *target_lir = lir->target;
+ DCHECK(target_lir != NULL);
+ CodeOffset target = target_lir->offset;
+ lir->operands[2] = target;
+ int newSize = GetInsnSize(lir);
+ if (newSize != lir->flags.size) {
+ lir->flags.size = newSize;
+ res = kRetryAll;
+ }
+ }
break;
}
}
diff --git a/compiler/dex/quick/x86/call_x86.cc b/compiler/dex/quick/x86/call_x86.cc
index 4267b5b..93875c9 100644
--- a/compiler/dex/quick/x86/call_x86.cc
+++ b/compiler/dex/quick/x86/call_x86.cc
@@ -84,10 +84,19 @@ void X86Mir2Lir::GenPackedSwitch(MIR* mir, DexOffset table_offset,
// Get the switch value
rl_src = LoadValue(rl_src, kCoreReg);
- int start_of_method_reg = AllocTemp();
- // Materialize a pointer to the switch table
// NewLIR0(kX86Bkpt);
- NewLIR1(kX86StartOfMethod, start_of_method_reg);
+
+ // Materialize a pointer to the switch table
+ int start_of_method_reg;
+ if (base_of_code_ != nullptr) {
+ // We can use the saved value.
+ RegLocation rl_method = mir_graph_->GetRegLocation(base_of_code_->s_reg_low);
+ rl_method = LoadValue(rl_method, kCoreReg);
+ start_of_method_reg = rl_method.low_reg;
+ } else {
+ start_of_method_reg = AllocTemp();
+ NewLIR1(kX86StartOfMethod, start_of_method_reg);
+ }
int low_key = s4FromSwitchData(&table[2]);
int keyReg;
// Remove the bias, if necessary
@@ -142,7 +151,13 @@ void X86Mir2Lir::GenFillArrayData(DexOffset table_offset, RegLocation rl_src) {
FlushAllRegs(); /* Everything to home location */
LoadValueDirectFixed(rl_src, rX86_ARG0);
// Materialize a pointer to the fill data image
- NewLIR1(kX86StartOfMethod, rX86_ARG2);
+ if (base_of_code_ != nullptr) {
+ // We can use the saved value.
+ RegLocation rl_method = mir_graph_->GetRegLocation(base_of_code_->s_reg_low);
+ LoadValueDirect(rl_method, rX86_ARG2);
+ } else {
+ NewLIR1(kX86StartOfMethod, rX86_ARG2);
+ }
NewLIR2(kX86PcRelAdr, rX86_ARG1, WrapPointer(tab_rec));
NewLIR2(kX86Add32RR, rX86_ARG1, rX86_ARG2);
CallRuntimeHelperRegReg(QUICK_ENTRYPOINT_OFFSET(pHandleFillArrayData), rX86_ARG0,
@@ -211,6 +226,13 @@ void X86Mir2Lir::GenEntrySequence(RegLocation* ArgLocs, RegLocation rl_method) {
FlushIns(ArgLocs, rl_method);
+ if (base_of_code_ != nullptr) {
+ // We have been asked to save the address of the method start for later use.
+ NewLIR1(kX86StartOfMethod, rX86_ARG0);
+ int displacement = SRegOffset(base_of_code_->s_reg_low);
+ StoreBaseDisp(rX86_SP, displacement, rX86_ARG0, kWord);
+ }
+
FreeTemp(rX86_ARG0);
FreeTemp(rX86_ARG1);
FreeTemp(rX86_ARG2);
diff --git a/compiler/dex/quick/x86/codegen_x86.h b/compiler/dex/quick/x86/codegen_x86.h
index a864117..6896504 100644
--- a/compiler/dex/quick/x86/codegen_x86.h
+++ b/compiler/dex/quick/x86/codegen_x86.h
@@ -407,6 +407,61 @@ class X86Mir2Lir : public Mir2Lir {
* @returns 'true' if the operation can proceed without needing temporary regs.
*/
bool IsOperationSafeWithoutTemps(RegLocation rl_lhs, RegLocation rl_rhs);
+
+ /*
+ * @brief Perform MIR analysis before compiling method.
+ * @note Invokes Mir2LiR::Materialize after analysis.
+ */
+ void Materialize();
+
+ /*
+ * @brief Analyze MIR before generating code, to prepare for the code generation.
+ */
+ void AnalyzeMIR();
+
+ /*
+ * @brief Analyze one basic block.
+ * @param bb Basic block to analyze.
+ */
+ void AnalyzeBB(BasicBlock * bb);
+
+ /*
+ * @brief Analyze one extended MIR instruction
+ * @param opcode MIR instruction opcode.
+ * @param bb Basic block containing instruction.
+ * @param mir Extended instruction to analyze.
+ */
+ void AnalyzeExtendedMIR(int opcode, BasicBlock * bb, MIR *mir);
+
+ /*
+ * @brief Analyze one MIR instruction
+ * @param opcode MIR instruction opcode.
+ * @param bb Basic block containing instruction.
+ * @param mir Instruction to analyze.
+ */
+ void AnalyzeMIR(int opcode, BasicBlock * bb, MIR *mir);
+
+ /*
+ * @brief Analyze one MIR float/double instruction
+ * @param opcode MIR instruction opcode.
+ * @param bb Basic block containing instruction.
+ * @param mir Instruction to analyze.
+ */
+ void AnalyzeFPInstruction(int opcode, BasicBlock * bb, MIR *mir);
+
+ /*
+ * @brief Analyze one use of a double operand.
+ * @param rl_use Double RegLocation for the operand.
+ */
+ void AnalyzeDoubleUse(RegLocation rl_use);
+
+ // Information derived from analysis of MIR
+
+ // Have we decided to compute a ptr to code and store in temporary VR?
+ bool store_method_addr_;
+
+ // The compiler temporary for the code address of the method.
+ CompilerTemp *base_of_code_;
};
} // namespace art
diff --git a/compiler/dex/quick/x86/target_x86.cc b/compiler/dex/quick/x86/target_x86.cc
index f223548..a347d8b 100644
--- a/compiler/dex/quick/x86/target_x86.cc
+++ b/compiler/dex/quick/x86/target_x86.cc
@@ -808,4 +808,12 @@ void X86Mir2Lir::DumpRegLocation(RegLocation loc) {
<< ", orig: " << loc.orig_sreg;
}
+void X86Mir2Lir::Materialize() {
+ // A good place to put the analysis before starting.
+ AnalyzeMIR();
+
+ // Now continue with regular code generation.
+ Mir2Lir::Materialize();
+}
+
} // namespace art
diff --git a/compiler/dex/quick/x86/utility_x86.cc b/compiler/dex/quick/x86/utility_x86.cc
index a77e921..18c5ca8 100644
--- a/compiler/dex/quick/x86/utility_x86.cc
+++ b/compiler/dex/quick/x86/utility_x86.cc
@@ -16,6 +16,7 @@
#include "codegen_x86.h"
#include "dex/quick/mir_to_lir-inl.h"
+#include "dex/dataflow_iterator-inl.h"
#include "x86_lir.h"
namespace art {
@@ -61,7 +62,7 @@ bool X86Mir2Lir::InexpensiveConstantLong(int64_t value) {
}
bool X86Mir2Lir::InexpensiveConstantDouble(int64_t value) {
- return false; // TUNING
+ return value == 0;
}
/*
@@ -394,6 +395,27 @@ LIR* X86Mir2Lir::LoadConstantWide(int r_dest_lo, int r_dest_hi, int64_t value) {
DCHECK_EQ(r_dest_lo, r_dest_hi);
if (value == 0) {
return NewLIR2(kX86XorpsRR, r_dest_lo, r_dest_lo);
+ } else if (base_of_code_ != nullptr) {
+ // We will load the value from the literal area.
+ LIR* data_target = ScanLiteralPoolWide(literal_list_, val_lo, val_hi);
+ if (data_target == NULL) {
+ data_target = AddWideData(&literal_list_, val_lo, val_hi);
+ }
+
+ // Address the start of the method
+ RegLocation rl_method = mir_graph_->GetRegLocation(base_of_code_->s_reg_low);
+ rl_method = LoadValue(rl_method, kCoreReg);
+
+ // Load the proper value from the literal area.
+ // We don't know the proper offset for the value, so pick one that will force
+ // 4 byte offset. We will fix this up in the assembler later to have the right
+ // value.
+ res = LoadBaseDisp(rl_method.low_reg, 256 /* bogus */, r_dest_lo, kDouble, INVALID_SREG);
+ res->target = data_target;
+ res->flags.fixup = kFixupLoad;
+ SetMemRefType(res, true, kLiteral);
+ // Redo after we assign target to ensure size is correct.
+ SetupResourceMasks(res);
} else {
if (val_lo == 0) {
res = NewLIR2(kX86XorpsRR, r_dest_lo, r_dest_lo);
@@ -662,4 +684,121 @@ LIR* X86Mir2Lir::OpCmpMemImmBranch(ConditionCode cond, int temp_reg, int base_re
return branch;
}
+void X86Mir2Lir::AnalyzeMIR() {
+ // Assume we don't need a pointer to the base of the code.
+ cu_->NewTimingSplit("X86 MIR Analysis");
+ store_method_addr_ = false;
+
+ // Walk the MIR looking for interesting items.
+ PreOrderDfsIterator iter(mir_graph_);
+ BasicBlock* curr_bb = iter.Next();
+ while (curr_bb != NULL) {
+ AnalyzeBB(curr_bb);
+ curr_bb = iter.Next();
+ }
+
+ // Did we need a pointer to the method code?
+ if (store_method_addr_) {
+ base_of_code_ = mir_graph_->GetNewCompilerTemp(kCompilerTempVR, false);
+ } else {
+ base_of_code_ = nullptr;
+ }
+}
+
+void X86Mir2Lir::AnalyzeBB(BasicBlock * bb) {
+ if (bb->block_type == kDead) {
+ // Ignore dead blocks
+ return;
+ }
+
+ for (MIR *mir = bb->first_mir_insn; mir != NULL; mir = mir->next) {
+ int opcode = mir->dalvikInsn.opcode;
+ if (opcode >= kMirOpFirst) {
+ AnalyzeExtendedMIR(opcode, bb, mir);
+ } else {
+ AnalyzeMIR(opcode, bb, mir);
+ }
+ }
+}
+
+
+void X86Mir2Lir::AnalyzeExtendedMIR(int opcode, BasicBlock * bb, MIR *mir) {
+ switch (opcode) {
+ // Instructions referencing doubles.
+ case kMirOpFusedCmplDouble:
+ case kMirOpFusedCmpgDouble:
+ AnalyzeFPInstruction(opcode, bb, mir);
+ break;
+ default:
+ // Ignore the rest.
+ break;
+ }
+}
+
+void X86Mir2Lir::AnalyzeMIR(int opcode, BasicBlock * bb, MIR *mir) {
+ // Looking for
+ // - Do we need a pointer to the code (used for packed switches and double lits)?
+
+ switch (opcode) {
+ // Instructions referencing doubles.
+ case Instruction::CMPL_DOUBLE:
+ case Instruction::CMPG_DOUBLE:
+ case Instruction::NEG_DOUBLE:
+ case Instruction::ADD_DOUBLE:
+ case Instruction::SUB_DOUBLE:
+ case Instruction::MUL_DOUBLE:
+ case Instruction::DIV_DOUBLE:
+ case Instruction::REM_DOUBLE:
+ case Instruction::ADD_DOUBLE_2ADDR:
+ case Instruction::SUB_DOUBLE_2ADDR:
+ case Instruction::MUL_DOUBLE_2ADDR:
+ case Instruction::DIV_DOUBLE_2ADDR:
+ case Instruction::REM_DOUBLE_2ADDR:
+ AnalyzeFPInstruction(opcode, bb, mir);
+ break;
+ // Packed switches and array fills need a pointer to the base of the method.
+ case Instruction::FILL_ARRAY_DATA:
+ case Instruction::PACKED_SWITCH:
+ store_method_addr_ = true;
+ break;
+ default:
+ // Other instructions are not interesting yet.
+ break;
+ }
+}
+
+void X86Mir2Lir::AnalyzeFPInstruction(int opcode, BasicBlock * bb, MIR *mir) {
+ // Look at all the uses, and see if they are double constants.
+ uint64_t attrs = mir_graph_->oat_data_flow_attributes_[opcode];
+ int next_sreg = 0;
+ if (attrs & DF_UA) {
+ if (attrs & DF_A_WIDE) {
+ AnalyzeDoubleUse(mir_graph_->GetSrcWide(mir, next_sreg));
+ next_sreg += 2;
+ } else {
+ next_sreg++;
+ }
+ }
+ if (attrs & DF_UB) {
+ if (attrs & DF_B_WIDE) {
+ AnalyzeDoubleUse(mir_graph_->GetSrcWide(mir, next_sreg));
+ next_sreg += 2;
+ } else {
+ next_sreg++;
+ }
+ }
+ if (attrs & DF_UC) {
+ if (attrs & DF_C_WIDE) {
+ AnalyzeDoubleUse(mir_graph_->GetSrcWide(mir, next_sreg));
+ }
+ }
+}
+
+void X86Mir2Lir::AnalyzeDoubleUse(RegLocation use) {
+ // If this is a double literal, we will want it in the literal pool.
+ if (use.is_const) {
+ store_method_addr_ = true;
+ }
+}
+
} // namespace art