diff options
Diffstat (limited to 'src/compiler/codegen')
| -rw-r--r-- | src/compiler/codegen/arm/codegen_arm.h | 8 | ||||
| -rw-r--r-- | src/compiler/codegen/arm/int_arm.cc | 200 | ||||
| -rw-r--r-- | src/compiler/codegen/arm/utility_arm.cc | 20 | ||||
| -rw-r--r-- | src/compiler/codegen/codegen.h | 14 | ||||
| -rw-r--r-- | src/compiler/codegen/codegen_util.cc | 23 | ||||
| -rw-r--r-- | src/compiler/codegen/codegen_util.h | 1 | ||||
| -rw-r--r-- | src/compiler/codegen/gen_common.cc | 340 | ||||
| -rw-r--r-- | src/compiler/codegen/gen_invoke.cc | 5 | ||||
| -rw-r--r-- | src/compiler/codegen/gen_loadstore.cc | 6 | ||||
| -rw-r--r-- | src/compiler/codegen/mips/codegen_mips.h | 8 | ||||
| -rw-r--r-- | src/compiler/codegen/mips/int_mips.cc | 203 | ||||
| -rw-r--r-- | src/compiler/codegen/mips/utility_mips.cc | 19 | ||||
| -rw-r--r-- | src/compiler/codegen/mir_to_lir.cc | 79 | ||||
| -rw-r--r-- | src/compiler/codegen/ralloc_util.cc | 10 | ||||
| -rw-r--r-- | src/compiler/codegen/x86/codegen_x86.h | 8 | ||||
| -rw-r--r-- | src/compiler/codegen/x86/int_x86.cc | 144 | ||||
| -rw-r--r-- | src/compiler/codegen/x86/utility_x86.cc | 10 |
17 files changed, 775 insertions, 323 deletions
diff --git a/src/compiler/codegen/arm/codegen_arm.h b/src/compiler/codegen/arm/codegen_arm.h index f085a19b3f..ca39e5a46b 100644 --- a/src/compiler/codegen/arm/codegen_arm.h +++ b/src/compiler/codegen/arm/codegen_arm.h @@ -39,7 +39,6 @@ class ArmCodegen : public Codegen { virtual LIR* LoadConstantNoClobber(CompilationUnit* cu, int r_dest, int value); virtual LIR* LoadConstantValueWide(CompilationUnit* cu, int r_dest_lo, int r_dest_hi, int val_lo, int val_hi); - virtual void LoadPair(CompilationUnit* cu, int base, int low_reg, int high_reg); virtual LIR* StoreBaseDisp(CompilationUnit* cu, int rBase, int displacement, int r_src, OpSize size); virtual LIR* StoreBaseDispWide(CompilationUnit* cu, int rBase, int displacement, int r_src_lo, @@ -90,6 +89,12 @@ class ArmCodegen : public Codegen { virtual bool IsUnconditionalBranch(LIR* lir); // Required for target - Dalvik-level generators. + virtual void GenArrayObjPut(CompilationUnit* cu, int opt_flags, RegLocation rl_array, + RegLocation rl_index, RegLocation rl_src, int scale); + virtual void GenArrayGet(CompilationUnit* cu, int opt_flags, OpSize size, RegLocation rl_array, + RegLocation rl_index, RegLocation rl_dest, int scale); + virtual void GenArrayPut(CompilationUnit* cu, int opt_flags, OpSize size, RegLocation rl_array, + RegLocation rl_index, RegLocation rl_src, int scale); virtual bool GenAddLong(CompilationUnit* cu, RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2); virtual bool GenAndLong(CompilationUnit* cu, RegLocation rl_dest, RegLocation rl_src1, @@ -191,6 +196,7 @@ class ArmCodegen : public Codegen { static int EncodeShift(int code, int amount); static int ModifiedImmediate(uint32_t value); static ArmConditionCode ArmConditionEncoding(ConditionCode code); + bool InexpensiveConstant(int reg, int value); }; } // namespace art diff --git a/src/compiler/codegen/arm/int_arm.cc b/src/compiler/codegen/arm/int_arm.cc index 0a6abd216e..e86f379694 100644 --- a/src/compiler/codegen/arm/int_arm.cc +++ b/src/compiler/codegen/arm/int_arm.cc @@ -558,4 +558,204 @@ bool ArmCodegen::GenXorLong(CompilationUnit* cu, RegLocation rl_dest, RegLocatio return false; } +/* + * Generate array load + */ +void ArmCodegen::GenArrayGet(CompilationUnit* cu, int opt_flags, OpSize size, RegLocation rl_array, + RegLocation rl_index, RegLocation rl_dest, int scale) +{ + RegisterClass reg_class = oat_reg_class_by_size(size); + int len_offset = Array::LengthOffset().Int32Value(); + int data_offset; + RegLocation rl_result; + rl_array = LoadValue(cu, rl_array, kCoreReg); + rl_index = LoadValue(cu, rl_index, kCoreReg); + + if (rl_dest.wide) { + data_offset = Array::DataOffset(sizeof(int64_t)).Int32Value(); + } else { + data_offset = Array::DataOffset(sizeof(int32_t)).Int32Value(); + } + + /* null object? */ + GenNullCheck(cu, rl_array.s_reg_low, rl_array.low_reg, opt_flags); + + bool needs_range_check = (!(opt_flags & MIR_IGNORE_RANGE_CHECK)); + int reg_len = INVALID_REG; + if (needs_range_check) { + reg_len = AllocTemp(cu); + /* Get len */ + LoadWordDisp(cu, rl_array.low_reg, len_offset, reg_len); + } + if (rl_dest.wide || rl_dest.fp) { + // No special indexed operation, lea + load w/ displacement + int reg_ptr = AllocTemp(cu); + OpRegRegRegShift(cu, kOpAdd, reg_ptr, rl_array.low_reg, rl_index.low_reg, + EncodeShift(kArmLsl, scale)); + FreeTemp(cu, rl_index.low_reg); + rl_result = EvalLoc(cu, rl_dest, reg_class, true); + + if (needs_range_check) { + // TODO: change kCondCS to a more meaningful name, is the sense of + // carry-set/clear flipped? + GenRegRegCheck(cu, kCondCs, rl_index.low_reg, reg_len, kThrowArrayBounds); + FreeTemp(cu, reg_len); + } + if (rl_dest.wide) { + LoadBaseDispWide(cu, reg_ptr, data_offset, rl_result.low_reg, rl_result.high_reg, INVALID_SREG); + FreeTemp(cu, reg_ptr); + StoreValueWide(cu, rl_dest, rl_result); + } else { + LoadBaseDisp(cu, reg_ptr, data_offset, rl_result.low_reg, size, INVALID_SREG); + FreeTemp(cu, reg_ptr); + StoreValue(cu, rl_dest, rl_result); + } + } else { + // Offset base, then use indexed load + int reg_ptr = AllocTemp(cu); + OpRegRegImm(cu, kOpAdd, reg_ptr, rl_array.low_reg, data_offset); + FreeTemp(cu, rl_array.low_reg); + rl_result = EvalLoc(cu, rl_dest, reg_class, true); + + if (needs_range_check) { + // TODO: change kCondCS to a more meaningful name, is the sense of + // carry-set/clear flipped? + GenRegRegCheck(cu, kCondCs, rl_index.low_reg, reg_len, kThrowArrayBounds); + FreeTemp(cu, reg_len); + } + LoadBaseIndexed(cu, reg_ptr, rl_index.low_reg, rl_result.low_reg, scale, size); + FreeTemp(cu, reg_ptr); + StoreValue(cu, rl_dest, rl_result); + } +} + +/* + * Generate array store + * + */ +void ArmCodegen::GenArrayPut(CompilationUnit* cu, int opt_flags, OpSize size, RegLocation rl_array, + RegLocation rl_index, RegLocation rl_src, int scale) +{ + RegisterClass reg_class = oat_reg_class_by_size(size); + int len_offset = Array::LengthOffset().Int32Value(); + int data_offset; + + if (size == kLong || size == kDouble) { + data_offset = Array::DataOffset(sizeof(int64_t)).Int32Value(); + } else { + data_offset = Array::DataOffset(sizeof(int32_t)).Int32Value(); + } + + rl_array = LoadValue(cu, rl_array, kCoreReg); + rl_index = LoadValue(cu, rl_index, kCoreReg); + int reg_ptr = INVALID_REG; + if (IsTemp(cu, rl_array.low_reg)) { + Clobber(cu, rl_array.low_reg); + reg_ptr = rl_array.low_reg; + } else { + reg_ptr = AllocTemp(cu); + } + + /* null object? */ + GenNullCheck(cu, rl_array.s_reg_low, rl_array.low_reg, opt_flags); + + bool needs_range_check = (!(opt_flags & MIR_IGNORE_RANGE_CHECK)); + int reg_len = INVALID_REG; + if (needs_range_check) { + reg_len = AllocTemp(cu); + //NOTE: max live temps(4) here. + /* Get len */ + LoadWordDisp(cu, rl_array.low_reg, len_offset, reg_len); + } + /* at this point, reg_ptr points to array, 2 live temps */ + if (rl_src.wide || rl_src.fp) { + if (rl_src.wide) { + rl_src = LoadValueWide(cu, rl_src, reg_class); + } else { + rl_src = LoadValue(cu, rl_src, reg_class); + } + OpRegRegRegShift(cu, kOpAdd, reg_ptr, rl_array.low_reg, rl_index.low_reg, + EncodeShift(kArmLsl, scale)); + if (needs_range_check) { + GenRegRegCheck(cu, kCondCs, rl_index.low_reg, reg_len, kThrowArrayBounds); + FreeTemp(cu, reg_len); + } + if (rl_src.wide) { + StoreBaseDispWide(cu, reg_ptr, data_offset, rl_src.low_reg, rl_src.high_reg); + } else { + StoreBaseDisp(cu, reg_ptr, data_offset, rl_src.low_reg, size); + } + } else { + /* reg_ptr -> array data */ + OpRegRegImm(cu, kOpAdd, reg_ptr, rl_array.low_reg, data_offset); + rl_src = LoadValue(cu, rl_src, reg_class); + if (needs_range_check) { + GenRegRegCheck(cu, kCondCs, rl_index.low_reg, reg_len, kThrowArrayBounds); + FreeTemp(cu, reg_len); + } + StoreBaseIndexed(cu, reg_ptr, rl_index.low_reg, rl_src.low_reg, + scale, size); + } + FreeTemp(cu, reg_ptr); +} + +/* + * Generate array store + * + */ +void ArmCodegen::GenArrayObjPut(CompilationUnit* cu, int opt_flags, RegLocation rl_array, + RegLocation rl_index, RegLocation rl_src, int scale) +{ + int len_offset = Array::LengthOffset().Int32Value(); + int data_offset = Array::DataOffset(sizeof(Object*)).Int32Value(); + + FlushAllRegs(cu); // Use explicit registers + LockCallTemps(cu); + + int r_value = TargetReg(kArg0); // Register holding value + int r_array_class = TargetReg(kArg1); // Register holding array's Class + int r_array = TargetReg(kArg2); // Register holding array + int r_index = TargetReg(kArg3); // Register holding index into array + + LoadValueDirectFixed(cu, rl_array, r_array); // Grab array + LoadValueDirectFixed(cu, rl_src, r_value); // Grab value + LoadValueDirectFixed(cu, rl_index, r_index); // Grab index + + GenNullCheck(cu, rl_array.s_reg_low, r_array, opt_flags); // NPE? + + // Store of null? + LIR* null_value_check = OpCmpImmBranch(cu, kCondEq, r_value, 0, NULL); + + // Get the array's class. + LoadWordDisp(cu, r_array, Object::ClassOffset().Int32Value(), r_array_class); + CallRuntimeHelperRegReg(cu, ENTRYPOINT_OFFSET(pCanPutArrayElementFromCode), r_value, + r_array_class, true); + // Redo LoadValues in case they didn't survive the call. + LoadValueDirectFixed(cu, rl_array, r_array); // Reload array + LoadValueDirectFixed(cu, rl_index, r_index); // Reload index + LoadValueDirectFixed(cu, rl_src, r_value); // Reload value + r_array_class = INVALID_REG; + + // Branch here if value to be stored == null + LIR* target = NewLIR0(cu, kPseudoTargetLabel); + null_value_check->target = target; + + bool needs_range_check = (!(opt_flags & MIR_IGNORE_RANGE_CHECK)); + int reg_len = INVALID_REG; + if (needs_range_check) { + reg_len = TargetReg(kArg1); + LoadWordDisp(cu, r_array, len_offset, reg_len); // Get len + } + /* r_ptr -> array data */ + int r_ptr = AllocTemp(cu); + OpRegRegImm(cu, kOpAdd, r_ptr, r_array, data_offset); + if (needs_range_check) { + GenRegRegCheck(cu, kCondCs, r_index, reg_len, kThrowArrayBounds); + } + StoreBaseIndexed(cu, r_ptr, r_index, r_value, scale, kWord); + FreeTemp(cu, r_ptr); + FreeTemp(cu, r_index); + MarkGCCard(cu, r_value, r_array); +} + } // namespace art diff --git a/src/compiler/codegen/arm/utility_arm.cc b/src/compiler/codegen/arm/utility_arm.cc index 7f37bea1af..5c25eee87a 100644 --- a/src/compiler/codegen/arm/utility_arm.cc +++ b/src/compiler/codegen/arm/utility_arm.cc @@ -126,6 +126,21 @@ int ArmCodegen::ModifiedImmediate(uint32_t value) return value | ((0x8 + z_leading) << 7); /* [01000..11111]:bcdefgh */ } +bool ArmCodegen::InexpensiveConstant(int reg, int value) +{ + bool res = false; + if (ARM_FPREG(reg)) { + res = (EncodeImmSingle(value) >= 0); + } else { + if (ARM_LOWREG(reg) && (value >= 0) && (IsUint(8, value))) { + res = true; + } else { + res = (ModifiedImmediate(value) >= 0) || (ModifiedImmediate(~value) >= 0); + } + } + return res; +} + /* * Load a immediate using a shortcut if possible; otherwise * grab from the per-translation literal pool. @@ -1011,11 +1026,6 @@ LIR* ArmCodegen::StoreBaseDispWide(CompilationUnit* cu, int rBase, int displacem return StoreBaseDispBody(cu, rBase, displacement, r_src_lo, r_src_hi, kLong); } -void ArmCodegen::LoadPair(CompilationUnit* cu, int base, int low_reg, int high_reg) -{ - LoadBaseDispWide(cu, base, 0, low_reg, high_reg, INVALID_SREG); -} - LIR* ArmCodegen::OpFpRegCopy(CompilationUnit* cu, int r_dest, int r_src) { int opcode; diff --git a/src/compiler/codegen/codegen.h b/src/compiler/codegen/codegen.h index e512803258..7a85ce8d30 100644 --- a/src/compiler/codegen/codegen.h +++ b/src/compiler/codegen/codegen.h @@ -135,12 +135,6 @@ class Codegen { void GenInstanceof(CompilationUnit* cu, uint32_t type_idx, RegLocation rl_dest, RegLocation rl_src); void GenCheckCast(CompilationUnit* cu, uint32_t type_idx, RegLocation rl_src); - void GenArrayObjPut(CompilationUnit* cu, int opt_flags, RegLocation rl_array, - RegLocation rl_index, RegLocation rl_src, int scale); - void GenArrayGet(CompilationUnit* cu, int opt_flags, OpSize size, RegLocation rl_array, - RegLocation rl_index, RegLocation rl_dest, int scale); - void GenArrayPut(CompilationUnit* cu, int opt_flags, OpSize size, RegLocation rl_array, - RegLocation rl_index, RegLocation rl_src, int scale); void GenLong3Addr(CompilationUnit* cu, OpKind first_op, OpKind second_op, RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2); bool GenShiftOpLong(CompilationUnit* cu, Instruction::Code opcode, RegLocation rl_dest, @@ -245,7 +239,6 @@ class Codegen { virtual LIR* LoadConstantNoClobber(CompilationUnit* cu, int r_dest, int value) = 0; virtual LIR* LoadConstantValueWide(CompilationUnit* cu, int r_dest_lo, int r_dest_hi, int val_lo, int val_hi) = 0; - virtual void LoadPair(CompilationUnit* cu, int base, int low_reg, int high_reg) = 0; virtual LIR* StoreBaseDisp(CompilationUnit* cu, int rBase, int displacement, int r_src, OpSize size) = 0; virtual LIR* StoreBaseDispWide(CompilationUnit* cu, int rBase, int displacement, int r_src_lo, @@ -350,6 +343,12 @@ class Codegen { RegLocation rl_src) = 0; virtual void GenSpecialCase(CompilationUnit* cu, BasicBlock* bb, MIR* mir, SpecialCaseHandler special_case) = 0; + virtual void GenArrayObjPut(CompilationUnit* cu, int opt_flags, RegLocation rl_array, + RegLocation rl_index, RegLocation rl_src, int scale) = 0; + virtual void GenArrayGet(CompilationUnit* cu, int opt_flags, OpSize size, RegLocation rl_array, + RegLocation rl_index, RegLocation rl_dest, int scale) = 0; + virtual void GenArrayPut(CompilationUnit* cu, int opt_flags, OpSize size, RegLocation rl_array, + RegLocation rl_index, RegLocation rl_src, int scale) = 0; // Required for target - single operation generators. virtual LIR* OpUnconditionalBranch(CompilationUnit* cu, LIR* target) = 0; @@ -382,6 +381,7 @@ class Codegen { virtual void OpRegCopyWide(CompilationUnit* cu, int dest_lo, int dest_hi, int src_lo, int src_hi) = 0; virtual void OpTlsCmp(CompilationUnit* cu, int offset, int val) = 0; + virtual bool InexpensiveConstant(int reg, int value) = 0; // Temp workaround void Workaround7250540(CompilationUnit* cu, RegLocation rl_dest, int value); diff --git a/src/compiler/codegen/codegen_util.cc b/src/compiler/codegen/codegen_util.cc index bab5cd98c5..77a2269aaf 100644 --- a/src/compiler/codegen/codegen_util.cc +++ b/src/compiler/codegen/codegen_util.cc @@ -1074,4 +1074,27 @@ LIR* MarkBoundary(CompilationUnit* cu, int offset, const char* inst_str) return res; } +bool EvaluateBranch(Instruction::Code opcode, int32_t src1, int32_t src2) +{ + bool is_taken; + switch (opcode) { + case Instruction::IF_EQ: is_taken = (src1 == src2); break; + case Instruction::IF_NE: is_taken = (src1 != src2); break; + case Instruction::IF_LT: is_taken = (src1 < src2); break; + case Instruction::IF_GE: is_taken = (src1 >= src2); break; + case Instruction::IF_GT: is_taken = (src1 > src2); break; + case Instruction::IF_LE: is_taken = (src1 <= src2); break; + case Instruction::IF_EQZ: is_taken = (src1 == 0); break; + case Instruction::IF_NEZ: is_taken = (src1 != 0); break; + case Instruction::IF_LTZ: is_taken = (src1 < 0); break; + case Instruction::IF_GEZ: is_taken = (src1 >= 0); break; + case Instruction::IF_GTZ: is_taken = (src1 > 0); break; + case Instruction::IF_LEZ: is_taken = (src1 <= 0); break; + default: + LOG(FATAL) << "Unexpected opcode " << opcode; + is_taken = false; + } + return is_taken; +} + } // namespace art diff --git a/src/compiler/codegen/codegen_util.h b/src/compiler/codegen/codegen_util.h index 6a9b6cdb1f..3bb4291767 100644 --- a/src/compiler/codegen/codegen_util.h +++ b/src/compiler/codegen/codegen_util.h @@ -51,6 +51,7 @@ void DumpSparseSwitchTable(const uint16_t* table); void DumpPackedSwitchTable(const uint16_t* table); LIR* MarkBoundary(CompilationUnit* cu, int offset, const char* inst_str); void NopLIR(LIR* lir); +bool EvaluateBranch(Instruction::Code opcode, int src1, int src2); } // namespace art diff --git a/src/compiler/codegen/gen_common.cc b/src/compiler/codegen/gen_common.cc index db99a306e1..275aee5a68 100644 --- a/src/compiler/codegen/gen_common.cc +++ b/src/compiler/codegen/gen_common.cc @@ -89,13 +89,28 @@ LIR* Codegen::GenRegRegCheck(CompilationUnit* cu, ConditionCode c_code, int reg1 return branch; } +// Convert relation of src1/src2 to src2/src1 +ConditionCode FlipComparisonOrder(ConditionCode before) { + ConditionCode res; + switch (before) { + case kCondEq: res = kCondEq; break; + case kCondNe: res = kCondNe; break; + case kCondLt: res = kCondGt; break; + case kCondGt: res = kCondLt; break; + case kCondLe: res = kCondGe; break; + case kCondGe: res = kCondLe; break; + default: + res = static_cast<ConditionCode>(0); + LOG(FATAL) << "Unexpected ccode " << before; + } + return res; +} + void Codegen::GenCompareAndBranch(CompilationUnit* cu, Instruction::Code opcode, RegLocation rl_src1, RegLocation rl_src2, LIR* taken, LIR* fall_through) { ConditionCode cond; - rl_src1 = LoadValue(cu, rl_src1, kCoreReg); - rl_src2 = LoadValue(cu, rl_src2, kCoreReg); switch (opcode) { case Instruction::IF_EQ: cond = kCondEq; @@ -119,6 +134,29 @@ void Codegen::GenCompareAndBranch(CompilationUnit* cu, Instruction::Code opcode, cond = static_cast<ConditionCode>(0); LOG(FATAL) << "Unexpected opcode " << opcode; } + + // Normalize such that if either operand is constant, src2 will be constant + if (rl_src1.is_const) { + RegLocation rl_temp = rl_src1; + rl_src1 = rl_src2; + rl_src2 = rl_temp; + cond = FlipComparisonOrder(cond); + } + + rl_src1 = LoadValue(cu, rl_src1, kCoreReg); + // Is this really an immediate comparison? + if (rl_src2.is_const) { + int immval = cu->constant_values[rl_src2.orig_sreg]; + // If it's already live in a register or not easily materialized, just keep going + RegLocation rl_temp = UpdateLoc(cu, rl_src2); + if ((rl_temp.location == kLocDalvikFrame) && InexpensiveConstant(rl_src1.low_reg, immval)) { + // OK - convert this to a compare immediate and branch + OpCmpImmBranch(cu, cond, rl_src1.low_reg, immval, taken); + OpUnconditionalBranch(cu, fall_through); + return; + } + } + rl_src2 = LoadValue(cu, rl_src2, kCoreReg); OpCmpBranch(cu, cond, rl_src1.low_reg, rl_src2.low_reg, taken); OpUnconditionalBranch(cu, fall_through); } @@ -151,12 +189,7 @@ void Codegen::GenCompareZeroAndBranch(CompilationUnit* cu, Instruction::Code opc cond = static_cast<ConditionCode>(0); LOG(FATAL) << "Unexpected opcode " << opcode; } - if (cu->instruction_set == kThumb2) { - OpRegImm(cu, kOpCmp, rl_src.low_reg, 0); - OpCondBranch(cu, cond, taken); - } else { - OpCmpImmBranch(cu, cond, rl_src.low_reg, 0, taken); - } + OpCmpImmBranch(cu, cond, rl_src.low_reg, 0, taken); OpUnconditionalBranch(cu, fall_through); } @@ -668,7 +701,7 @@ void Codegen::GenIGet(CompilationUnit* cu, uint32_t field_idx, int opt_flags, Op int reg_ptr = AllocTemp(cu); OpRegRegImm(cu, kOpAdd, reg_ptr, rl_obj.low_reg, field_offset); rl_result = EvalLoc(cu, rl_dest, reg_class, true); - LoadPair(cu, reg_ptr, rl_result.low_reg, rl_result.high_reg); + LoadBaseDispWide(cu, reg_ptr, 0, rl_result.low_reg, rl_result.high_reg, INVALID_SREG); if (is_volatile) { GenMemBarrier(cu, kLoadLoad); } @@ -1056,270 +1089,6 @@ void Codegen::GenCheckCast(CompilationUnit* cu, uint32_t type_idx, RegLocation r branch2->target = target; } -/* - * Generate array store - * - */ -void Codegen::GenArrayObjPut(CompilationUnit* cu, int opt_flags, RegLocation rl_array, - RegLocation rl_index, RegLocation rl_src, int scale) -{ - int len_offset = Array::LengthOffset().Int32Value(); - int data_offset = Array::DataOffset(sizeof(Object*)).Int32Value(); - - FlushAllRegs(cu); // Use explicit registers - LockCallTemps(cu); - - int r_value = TargetReg(kArg0); // Register holding value - int r_array_class = TargetReg(kArg1); // Register holding array's Class - int r_array = TargetReg(kArg2); // Register holding array - int r_index = TargetReg(kArg3); // Register holding index into array - - LoadValueDirectFixed(cu, rl_array, r_array); // Grab array - LoadValueDirectFixed(cu, rl_src, r_value); // Grab value - LoadValueDirectFixed(cu, rl_index, r_index); // Grab index - - GenNullCheck(cu, rl_array.s_reg_low, r_array, opt_flags); // NPE? - - // Store of null? - LIR* null_value_check = OpCmpImmBranch(cu, kCondEq, r_value, 0, NULL); - - // Get the array's class. - LoadWordDisp(cu, r_array, Object::ClassOffset().Int32Value(), r_array_class); - CallRuntimeHelperRegReg(cu, ENTRYPOINT_OFFSET(pCanPutArrayElementFromCode), r_value, - r_array_class, true); - // Redo LoadValues in case they didn't survive the call. - LoadValueDirectFixed(cu, rl_array, r_array); // Reload array - LoadValueDirectFixed(cu, rl_index, r_index); // Reload index - LoadValueDirectFixed(cu, rl_src, r_value); // Reload value - r_array_class = INVALID_REG; - - // Branch here if value to be stored == null - LIR* target = NewLIR0(cu, kPseudoTargetLabel); - null_value_check->target = target; - - if (cu->instruction_set == kX86) { - // make an extra temp available for card mark below - FreeTemp(cu, TargetReg(kArg1)); - if (!(opt_flags & MIR_IGNORE_RANGE_CHECK)) { - /* if (rl_index >= [rl_array + len_offset]) goto kThrowArrayBounds */ - GenRegMemCheck(cu, kCondUge, r_index, r_array, len_offset, kThrowArrayBounds); - } - StoreBaseIndexedDisp(cu, r_array, r_index, scale, - data_offset, r_value, INVALID_REG, kWord, INVALID_SREG); - } else { - bool needs_range_check = (!(opt_flags & MIR_IGNORE_RANGE_CHECK)); - int reg_len = INVALID_REG; - if (needs_range_check) { - reg_len = TargetReg(kArg1); - LoadWordDisp(cu, r_array, len_offset, reg_len); // Get len - } - /* r_ptr -> array data */ - int r_ptr = AllocTemp(cu); - OpRegRegImm(cu, kOpAdd, r_ptr, r_array, data_offset); - if (needs_range_check) { - GenRegRegCheck(cu, kCondCs, r_index, reg_len, kThrowArrayBounds); - } - StoreBaseIndexed(cu, r_ptr, r_index, r_value, scale, kWord); - FreeTemp(cu, r_ptr); - } - FreeTemp(cu, r_index); - MarkGCCard(cu, r_value, r_array); -} - -/* - * Generate array load - */ -void Codegen::GenArrayGet(CompilationUnit* cu, int opt_flags, OpSize size, RegLocation rl_array, - RegLocation rl_index, RegLocation rl_dest, int scale) -{ - RegisterClass reg_class = oat_reg_class_by_size(size); - int len_offset = Array::LengthOffset().Int32Value(); - int data_offset; - RegLocation rl_result; - rl_array = LoadValue(cu, rl_array, kCoreReg); - rl_index = LoadValue(cu, rl_index, kCoreReg); - - if (size == kLong || size == kDouble) { - data_offset = Array::DataOffset(sizeof(int64_t)).Int32Value(); - } else { - data_offset = Array::DataOffset(sizeof(int32_t)).Int32Value(); - } - - /* null object? */ - GenNullCheck(cu, rl_array.s_reg_low, rl_array.low_reg, opt_flags); - - if (cu->instruction_set == kX86) { - if (!(opt_flags & MIR_IGNORE_RANGE_CHECK)) { - /* if (rl_index >= [rl_array + len_offset]) goto kThrowArrayBounds */ - GenRegMemCheck(cu, kCondUge, rl_index.low_reg, rl_array.low_reg, - len_offset, kThrowArrayBounds); - } - if ((size == kLong) || (size == kDouble)) { - int reg_addr = AllocTemp(cu); - OpLea(cu, reg_addr, rl_array.low_reg, rl_index.low_reg, scale, data_offset); - FreeTemp(cu, rl_array.low_reg); - FreeTemp(cu, rl_index.low_reg); - rl_result = EvalLoc(cu, rl_dest, reg_class, true); - LoadBaseIndexedDisp(cu, reg_addr, INVALID_REG, 0, 0, rl_result.low_reg, - rl_result.high_reg, size, INVALID_SREG); - StoreValueWide(cu, rl_dest, rl_result); - } else { - rl_result = EvalLoc(cu, rl_dest, reg_class, true); - - LoadBaseIndexedDisp(cu, rl_array.low_reg, rl_index.low_reg, scale, - data_offset, rl_result.low_reg, INVALID_REG, size, - INVALID_SREG); - - StoreValue(cu, rl_dest, rl_result); - } - } else { - int reg_ptr = AllocTemp(cu); - bool needs_range_check = (!(opt_flags & MIR_IGNORE_RANGE_CHECK)); - int reg_len = INVALID_REG; - if (needs_range_check) { - reg_len = AllocTemp(cu); - /* Get len */ - LoadWordDisp(cu, rl_array.low_reg, len_offset, reg_len); - } - /* reg_ptr -> array data */ - OpRegRegImm(cu, kOpAdd, reg_ptr, rl_array.low_reg, data_offset); - FreeTemp(cu, rl_array.low_reg); - if ((size == kLong) || (size == kDouble)) { - if (scale) { - int r_new_index = AllocTemp(cu); - OpRegRegImm(cu, kOpLsl, r_new_index, rl_index.low_reg, scale); - OpRegReg(cu, kOpAdd, reg_ptr, r_new_index); - FreeTemp(cu, r_new_index); - } else { - OpRegReg(cu, kOpAdd, reg_ptr, rl_index.low_reg); - } - FreeTemp(cu, rl_index.low_reg); - rl_result = EvalLoc(cu, rl_dest, reg_class, true); - - if (needs_range_check) { - // TODO: change kCondCS to a more meaningful name, is the sense of - // carry-set/clear flipped? - GenRegRegCheck(cu, kCondCs, rl_index.low_reg, reg_len, kThrowArrayBounds); - FreeTemp(cu, reg_len); - } - LoadPair(cu, reg_ptr, rl_result.low_reg, rl_result.high_reg); - - FreeTemp(cu, reg_ptr); - StoreValueWide(cu, rl_dest, rl_result); - } else { - rl_result = EvalLoc(cu, rl_dest, reg_class, true); - - if (needs_range_check) { - // TODO: change kCondCS to a more meaningful name, is the sense of - // carry-set/clear flipped? - GenRegRegCheck(cu, kCondCs, rl_index.low_reg, reg_len, kThrowArrayBounds); - FreeTemp(cu, reg_len); - } - LoadBaseIndexed(cu, reg_ptr, rl_index.low_reg, rl_result.low_reg, scale, size); - - FreeTemp(cu, reg_ptr); - StoreValue(cu, rl_dest, rl_result); - } - } -} - -/* - * Generate array store - * - */ -void Codegen::GenArrayPut(CompilationUnit* cu, int opt_flags, OpSize size, RegLocation rl_array, - RegLocation rl_index, RegLocation rl_src, int scale) -{ - RegisterClass reg_class = oat_reg_class_by_size(size); - int len_offset = Array::LengthOffset().Int32Value(); - int data_offset; - - if (size == kLong || size == kDouble) { - data_offset = Array::DataOffset(sizeof(int64_t)).Int32Value(); - } else { - data_offset = Array::DataOffset(sizeof(int32_t)).Int32Value(); - } - - rl_array = LoadValue(cu, rl_array, kCoreReg); - rl_index = LoadValue(cu, rl_index, kCoreReg); - int reg_ptr = INVALID_REG; - if (cu->instruction_set != kX86) { - if (IsTemp(cu, rl_array.low_reg)) { - Clobber(cu, rl_array.low_reg); - reg_ptr = rl_array.low_reg; - } else { - reg_ptr = AllocTemp(cu); - OpRegCopy(cu, reg_ptr, rl_array.low_reg); - } - } - - /* null object? */ - GenNullCheck(cu, rl_array.s_reg_low, rl_array.low_reg, opt_flags); - - if (cu->instruction_set == kX86) { - if (!(opt_flags & MIR_IGNORE_RANGE_CHECK)) { - /* if (rl_index >= [rl_array + len_offset]) goto kThrowArrayBounds */ - GenRegMemCheck(cu, kCondUge, rl_index.low_reg, rl_array.low_reg, len_offset, kThrowArrayBounds); - } - if ((size == kLong) || (size == kDouble)) { - rl_src = LoadValueWide(cu, rl_src, reg_class); - } else { - rl_src = LoadValue(cu, rl_src, reg_class); - } - // If the src reg can't be byte accessed, move it to a temp first. - if ((size == kSignedByte || size == kUnsignedByte) && rl_src.low_reg >= 4) { - int temp = AllocTemp(cu); - OpRegCopy(cu, temp, rl_src.low_reg); - StoreBaseIndexedDisp(cu, rl_array.low_reg, rl_index.low_reg, scale, data_offset, temp, - INVALID_REG, size, INVALID_SREG); - } else { - StoreBaseIndexedDisp(cu, rl_array.low_reg, rl_index.low_reg, scale, data_offset, rl_src.low_reg, - rl_src.high_reg, size, INVALID_SREG); - } - } else { - bool needs_range_check = (!(opt_flags & MIR_IGNORE_RANGE_CHECK)); - int reg_len = INVALID_REG; - if (needs_range_check) { - reg_len = AllocTemp(cu); - //NOTE: max live temps(4) here. - /* Get len */ - LoadWordDisp(cu, rl_array.low_reg, len_offset, reg_len); - } - /* reg_ptr -> array data */ - OpRegImm(cu, kOpAdd, reg_ptr, data_offset); - /* at this point, reg_ptr points to array, 2 live temps */ - if ((size == kLong) || (size == kDouble)) { - //TUNING: specific wide routine that can handle fp regs - if (scale) { - int r_new_index = AllocTemp(cu); - OpRegRegImm(cu, kOpLsl, r_new_index, rl_index.low_reg, scale); - OpRegReg(cu, kOpAdd, reg_ptr, r_new_index); - FreeTemp(cu, r_new_index); - } else { - OpRegReg(cu, kOpAdd, reg_ptr, rl_index.low_reg); - } - rl_src = LoadValueWide(cu, rl_src, reg_class); - - if (needs_range_check) { - GenRegRegCheck(cu, kCondCs, rl_index.low_reg, reg_len, kThrowArrayBounds); - FreeTemp(cu, reg_len); - } - - StoreBaseDispWide(cu, reg_ptr, 0, rl_src.low_reg, rl_src.high_reg); - - FreeTemp(cu, reg_ptr); - } else { - rl_src = LoadValue(cu, rl_src, reg_class); - if (needs_range_check) { - GenRegRegCheck(cu, kCondCs, rl_index.low_reg, reg_len, kThrowArrayBounds); - FreeTemp(cu, reg_len); - } - StoreBaseIndexed(cu, reg_ptr, rl_index.low_reg, rl_src.low_reg, - scale, size); - } - } -} - void Codegen::GenLong3Addr(CompilationUnit* cu, OpKind first_op, OpKind second_op, RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2) { @@ -1683,10 +1452,18 @@ bool Codegen::GenArithOpIntLit(CompilationUnit* cu, Instruction::Code opcode, break; } + case Instruction::SUB_INT: + case Instruction::SUB_INT_2ADDR: + lit = -lit; + // Intended fallthrough + case Instruction::ADD_INT: + case Instruction::ADD_INT_2ADDR: case Instruction::ADD_INT_LIT8: case Instruction::ADD_INT_LIT16: op = kOpAdd; break; + case Instruction::MUL_INT: + case Instruction::MUL_INT_2ADDR: case Instruction::MUL_INT_LIT8: case Instruction::MUL_INT_LIT16: { if (HandleEasyMultiply(cu, rl_src, rl_dest, lit)) { @@ -1695,39 +1472,52 @@ bool Codegen::GenArithOpIntLit(CompilationUnit* cu, Instruction::Code opcode, op = kOpMul; break; } + case Instruction::AND_INT: + case Instruction::AND_INT_2ADDR: case Instruction::AND_INT_LIT8: case Instruction::AND_INT_LIT16: op = kOpAnd; break; + case Instruction::OR_INT: + case Instruction::OR_INT_2ADDR: case Instruction::OR_INT_LIT8: case Instruction::OR_INT_LIT16: op = kOpOr; break; + case Instruction::XOR_INT: + case Instruction::XOR_INT_2ADDR: case Instruction::XOR_INT_LIT8: case Instruction::XOR_INT_LIT16: op = kOpXor; break; case Instruction::SHL_INT_LIT8: case Instruction::SHL_INT: + case Instruction::SHL_INT_2ADDR: lit &= 31; shift_op = true; op = kOpLsl; break; case Instruction::SHR_INT_LIT8: case Instruction::SHR_INT: + case Instruction::SHR_INT_2ADDR: lit &= 31; shift_op = true; op = kOpAsr; break; case Instruction::USHR_INT_LIT8: case Instruction::USHR_INT: + case Instruction::USHR_INT_2ADDR: lit &= 31; shift_op = true; op = kOpLsr; break; + case Instruction::DIV_INT: + case Instruction::DIV_INT_2ADDR: case Instruction::DIV_INT_LIT8: case Instruction::DIV_INT_LIT16: + case Instruction::REM_INT: + case Instruction::REM_INT_2ADDR: case Instruction::REM_INT_LIT8: case Instruction::REM_INT_LIT16: { if (lit == 0) { @@ -1738,6 +1528,8 @@ bool Codegen::GenArithOpIntLit(CompilationUnit* cu, Instruction::Code opcode, return false; } if ((opcode == Instruction::DIV_INT_LIT8) || + (opcode == Instruction::DIV_INT) || + (opcode == Instruction::DIV_INT_2ADDR) || (opcode == Instruction::DIV_INT_LIT16)) { is_div = true; } else { @@ -1762,7 +1554,7 @@ bool Codegen::GenArithOpIntLit(CompilationUnit* cu, Instruction::Code opcode, break; } default: - return true; + LOG(FATAL) << "Unexpected opcode " << opcode; } rl_src = LoadValue(cu, rl_src, kCoreReg); rl_result = EvalLoc(cu, rl_dest, kCoreReg, true); diff --git a/src/compiler/codegen/gen_invoke.cc b/src/compiler/codegen/gen_invoke.cc index ebc1a986ca..f35415259f 100644 --- a/src/compiler/codegen/gen_invoke.cc +++ b/src/compiler/codegen/gen_invoke.cc @@ -602,7 +602,10 @@ static int LoadArgRegs(CompilationUnit* cu, CallInfo* info, int call_state, next_reg++; next_arg++; } else { - rl_arg.wide = false; + if (rl_arg.wide) { + rl_arg.wide = false; + rl_arg.is_const = false; + } cg->LoadValueDirectFixed(cu, rl_arg, next_reg); } call_state = next_call_insn(cu, info, call_state, dex_idx, method_idx, diff --git a/src/compiler/codegen/gen_loadstore.cc b/src/compiler/codegen/gen_loadstore.cc index fe08caa72c..eec74af2da 100644 --- a/src/compiler/codegen/gen_loadstore.cc +++ b/src/compiler/codegen/gen_loadstore.cc @@ -92,7 +92,11 @@ void Codegen::LoadValueDirect(CompilationUnit* cu, RegLocation rl_src, int r_des } else { DCHECK((rl_src.location == kLocDalvikFrame) || (rl_src.location == kLocCompilerTemp)); - LoadWordDisp(cu, TargetReg(kSp), SRegOffset(cu, rl_src.s_reg_low), r_dest); + if (rl_src.is_const && InexpensiveConstant(r_dest, cu->constant_values[rl_src.orig_sreg])) { + LoadConstantNoClobber(cu, r_dest, cu->constant_values[rl_src.orig_sreg]); + } else { + LoadWordDisp(cu, TargetReg(kSp), SRegOffset(cu, rl_src.s_reg_low), r_dest); + } } } diff --git a/src/compiler/codegen/mips/codegen_mips.h b/src/compiler/codegen/mips/codegen_mips.h index aaa03c053d..4178f2eb12 100644 --- a/src/compiler/codegen/mips/codegen_mips.h +++ b/src/compiler/codegen/mips/codegen_mips.h @@ -39,7 +39,6 @@ class MipsCodegen : public Codegen { virtual LIR* LoadConstantNoClobber(CompilationUnit* cu, int r_dest, int value); virtual LIR* LoadConstantValueWide(CompilationUnit* cu, int r_dest_lo, int r_dest_hi, int val_lo, int val_hi); - virtual void LoadPair(CompilationUnit* cu, int base, int low_reg, int high_reg); virtual LIR* StoreBaseDisp(CompilationUnit* cu, int rBase, int displacement, int r_src, OpSize size); virtual LIR* StoreBaseDispWide(CompilationUnit* cu, int rBase, int displacement, int r_src_lo, @@ -90,6 +89,12 @@ class MipsCodegen : public Codegen { virtual bool IsUnconditionalBranch(LIR* lir); // Required for target - Dalvik-level generators. + virtual void GenArrayObjPut(CompilationUnit* cu, int opt_flags, RegLocation rl_array, + RegLocation rl_index, RegLocation rl_src, int scale); + virtual void GenArrayGet(CompilationUnit* cu, int opt_flags, OpSize size, RegLocation rl_array, + RegLocation rl_index, RegLocation rl_dest, int scale); + virtual void GenArrayPut(CompilationUnit* cu, int opt_flags, OpSize size, RegLocation rl_array, + RegLocation rl_index, RegLocation rl_src, int scale); virtual bool GenAddLong(CompilationUnit* cu, RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2); virtual bool GenAndLong(CompilationUnit* cu, RegLocation rl_dest, RegLocation rl_src1, @@ -184,6 +189,7 @@ class MipsCodegen : public Codegen { void SpillCoreRegs(CompilationUnit* cu); void UnSpillCoreRegs(CompilationUnit* cu); static const MipsEncodingMap EncodingMap[kMipsLast]; + bool InexpensiveConstant(int reg, int value); }; } // namespace art diff --git a/src/compiler/codegen/mips/int_mips.cc b/src/compiler/codegen/mips/int_mips.cc index bb36dc1450..e2a5a02ccb 100644 --- a/src/compiler/codegen/mips/int_mips.cc +++ b/src/compiler/codegen/mips/int_mips.cc @@ -432,4 +432,207 @@ bool MipsCodegen::GenXorLong(CompilationUnit* cu, RegLocation rl_dest, RegLocati return false; } +/* + * Generate array load + */ +void MipsCodegen::GenArrayGet(CompilationUnit* cu, int opt_flags, OpSize size, RegLocation rl_array, + RegLocation rl_index, RegLocation rl_dest, int scale) +{ + RegisterClass reg_class = oat_reg_class_by_size(size); + int len_offset = Array::LengthOffset().Int32Value(); + int data_offset; + RegLocation rl_result; + rl_array = LoadValue(cu, rl_array, kCoreReg); + rl_index = LoadValue(cu, rl_index, kCoreReg); + + if (size == kLong || size == kDouble) { + data_offset = Array::DataOffset(sizeof(int64_t)).Int32Value(); + } else { + data_offset = Array::DataOffset(sizeof(int32_t)).Int32Value(); + } + + /* null object? */ + GenNullCheck(cu, rl_array.s_reg_low, rl_array.low_reg, opt_flags); + + int reg_ptr = AllocTemp(cu); + bool needs_range_check = (!(opt_flags & MIR_IGNORE_RANGE_CHECK)); + int reg_len = INVALID_REG; + if (needs_range_check) { + reg_len = AllocTemp(cu); + /* Get len */ + LoadWordDisp(cu, rl_array.low_reg, len_offset, reg_len); + } + /* reg_ptr -> array data */ + OpRegRegImm(cu, kOpAdd, reg_ptr, rl_array.low_reg, data_offset); + FreeTemp(cu, rl_array.low_reg); + if ((size == kLong) || (size == kDouble)) { + if (scale) { + int r_new_index = AllocTemp(cu); + OpRegRegImm(cu, kOpLsl, r_new_index, rl_index.low_reg, scale); + OpRegReg(cu, kOpAdd, reg_ptr, r_new_index); + FreeTemp(cu, r_new_index); + } else { + OpRegReg(cu, kOpAdd, reg_ptr, rl_index.low_reg); + } + FreeTemp(cu, rl_index.low_reg); + rl_result = EvalLoc(cu, rl_dest, reg_class, true); + + if (needs_range_check) { + // TODO: change kCondCS to a more meaningful name, is the sense of + // carry-set/clear flipped? + GenRegRegCheck(cu, kCondCs, rl_index.low_reg, reg_len, kThrowArrayBounds); + FreeTemp(cu, reg_len); + } + LoadBaseDispWide(cu, reg_ptr, 0, rl_result.low_reg, rl_result.high_reg, INVALID_SREG); + + FreeTemp(cu, reg_ptr); + StoreValueWide(cu, rl_dest, rl_result); + } else { + rl_result = EvalLoc(cu, rl_dest, reg_class, true); + + if (needs_range_check) { + // TODO: change kCondCS to a more meaningful name, is the sense of + // carry-set/clear flipped? + GenRegRegCheck(cu, kCondCs, rl_index.low_reg, reg_len, kThrowArrayBounds); + FreeTemp(cu, reg_len); + } + LoadBaseIndexed(cu, reg_ptr, rl_index.low_reg, rl_result.low_reg, scale, size); + + FreeTemp(cu, reg_ptr); + StoreValue(cu, rl_dest, rl_result); + } +} + +/* + * Generate array store + * + */ +void MipsCodegen::GenArrayPut(CompilationUnit* cu, int opt_flags, OpSize size, RegLocation rl_array, + RegLocation rl_index, RegLocation rl_src, int scale) +{ + RegisterClass reg_class = oat_reg_class_by_size(size); + int len_offset = Array::LengthOffset().Int32Value(); + int data_offset; + + if (size == kLong || size == kDouble) { + data_offset = Array::DataOffset(sizeof(int64_t)).Int32Value(); + } else { + data_offset = Array::DataOffset(sizeof(int32_t)).Int32Value(); + } + + rl_array = LoadValue(cu, rl_array, kCoreReg); + rl_index = LoadValue(cu, rl_index, kCoreReg); + int reg_ptr = INVALID_REG; + if (IsTemp(cu, rl_array.low_reg)) { + Clobber(cu, rl_array.low_reg); + reg_ptr = rl_array.low_reg; + } else { + reg_ptr = AllocTemp(cu); + OpRegCopy(cu, reg_ptr, rl_array.low_reg); + } + + /* null object? */ + GenNullCheck(cu, rl_array.s_reg_low, rl_array.low_reg, opt_flags); + + bool needs_range_check = (!(opt_flags & MIR_IGNORE_RANGE_CHECK)); + int reg_len = INVALID_REG; + if (needs_range_check) { + reg_len = AllocTemp(cu); + //NOTE: max live temps(4) here. + /* Get len */ + LoadWordDisp(cu, rl_array.low_reg, len_offset, reg_len); + } + /* reg_ptr -> array data */ + OpRegImm(cu, kOpAdd, reg_ptr, data_offset); + /* at this point, reg_ptr points to array, 2 live temps */ + if ((size == kLong) || (size == kDouble)) { + //TUNING: specific wide routine that can handle fp regs + if (scale) { + int r_new_index = AllocTemp(cu); + OpRegRegImm(cu, kOpLsl, r_new_index, rl_index.low_reg, scale); + OpRegReg(cu, kOpAdd, reg_ptr, r_new_index); + FreeTemp(cu, r_new_index); + } else { + OpRegReg(cu, kOpAdd, reg_ptr, rl_index.low_reg); + } + rl_src = LoadValueWide(cu, rl_src, reg_class); + + if (needs_range_check) { + GenRegRegCheck(cu, kCondCs, rl_index.low_reg, reg_len, kThrowArrayBounds); + FreeTemp(cu, reg_len); + } + + StoreBaseDispWide(cu, reg_ptr, 0, rl_src.low_reg, rl_src.high_reg); + + FreeTemp(cu, reg_ptr); + } else { + rl_src = LoadValue(cu, rl_src, reg_class); + if (needs_range_check) { + GenRegRegCheck(cu, kCondCs, rl_index.low_reg, reg_len, kThrowArrayBounds); + FreeTemp(cu, reg_len); + } + StoreBaseIndexed(cu, reg_ptr, rl_index.low_reg, rl_src.low_reg, + scale, size); + } +} + +/* + * Generate array store + * + */ +void MipsCodegen::GenArrayObjPut(CompilationUnit* cu, int opt_flags, RegLocation rl_array, + RegLocation rl_index, RegLocation rl_src, int scale) +{ + int len_offset = Array::LengthOffset().Int32Value(); + int data_offset = Array::DataOffset(sizeof(Object*)).Int32Value(); + + FlushAllRegs(cu); // Use explicit registers + LockCallTemps(cu); + + int r_value = TargetReg(kArg0); // Register holding value + int r_array_class = TargetReg(kArg1); // Register holding array's Class + int r_array = TargetReg(kArg2); // Register holding array + int r_index = TargetReg(kArg3); // Register holding index into array + + LoadValueDirectFixed(cu, rl_array, r_array); // Grab array + LoadValueDirectFixed(cu, rl_src, r_value); // Grab value + LoadValueDirectFixed(cu, rl_index, r_index); // Grab index + + GenNullCheck(cu, rl_array.s_reg_low, r_array, opt_flags); // NPE? + + // Store of null? + LIR* null_value_check = OpCmpImmBranch(cu, kCondEq, r_value, 0, NULL); + + // Get the array's class. + LoadWordDisp(cu, r_array, Object::ClassOffset().Int32Value(), r_array_class); + CallRuntimeHelperRegReg(cu, ENTRYPOINT_OFFSET(pCanPutArrayElementFromCode), r_value, + r_array_class, true); + // Redo LoadValues in case they didn't survive the call. + LoadValueDirectFixed(cu, rl_array, r_array); // Reload array + LoadValueDirectFixed(cu, rl_index, r_index); // Reload index + LoadValueDirectFixed(cu, rl_src, r_value); // Reload value + r_array_class = INVALID_REG; + + // Branch here if value to be stored == null + LIR* target = NewLIR0(cu, kPseudoTargetLabel); + null_value_check->target = target; + + bool needs_range_check = (!(opt_flags & MIR_IGNORE_RANGE_CHECK)); + int reg_len = INVALID_REG; + if (needs_range_check) { + reg_len = TargetReg(kArg1); + LoadWordDisp(cu, r_array, len_offset, reg_len); // Get len + } + /* r_ptr -> array data */ + int r_ptr = AllocTemp(cu); + OpRegRegImm(cu, kOpAdd, r_ptr, r_array, data_offset); + if (needs_range_check) { + GenRegRegCheck(cu, kCondCs, r_index, reg_len, kThrowArrayBounds); + } + StoreBaseIndexed(cu, r_ptr, r_index, r_value, scale, kWord); + FreeTemp(cu, r_ptr); + FreeTemp(cu, r_index); + MarkGCCard(cu, r_value, r_array); +} + } // namespace art diff --git a/src/compiler/codegen/mips/utility_mips.cc b/src/compiler/codegen/mips/utility_mips.cc index 44d75d1b58..4d4be7600b 100644 --- a/src/compiler/codegen/mips/utility_mips.cc +++ b/src/compiler/codegen/mips/utility_mips.cc @@ -52,6 +52,19 @@ LIR* MipsCodegen::OpFpRegCopy(CompilationUnit *cu, int r_dest, int r_src) return res; } +bool MipsCodegen::InexpensiveConstant(int reg, int value) +{ + bool res = false; + if (value == 0) { + res = true; + } else if (IsUint(16, value)) { + res = true; + } else if ((value < 0) && (value >= -32768)) { + res = true; + } + return res; +} + /* * Load a immediate using a shortcut if possible; otherwise * grab from the per-translation literal pool. If target is @@ -640,12 +653,6 @@ LIR* MipsCodegen::StoreBaseDispWide(CompilationUnit *cu, int rBase, int displace return StoreBaseDispBody(cu, rBase, displacement, r_src_lo, r_src_hi, kLong); } -void MipsCodegen::LoadPair(CompilationUnit *cu, int base, int low_reg, int high_reg) -{ - LoadWordDisp(cu, base, LOWORD_OFFSET , low_reg); - LoadWordDisp(cu, base, HIWORD_OFFSET , high_reg); -} - LIR* MipsCodegen::OpThreadMem(CompilationUnit* cu, OpKind op, int thread_offset) { LOG(FATAL) << "Unexpected use of OpThreadMem for MIPS"; diff --git a/src/compiler/codegen/mir_to_lir.cc b/src/compiler/codegen/mir_to_lir.cc index 6ec7edbf1f..acdeafe32c 100644 --- a/src/compiler/codegen/mir_to_lir.cc +++ b/src/compiler/codegen/mir_to_lir.cc @@ -278,11 +278,22 @@ static bool CompileDalvikInstruction(CompilationUnit* cu, MIR* mir, BasicBlock* LIR* fall_through = &label_list[bb->fall_through->id]; bool backward_branch; backward_branch = (bb->taken->start_offset <= mir->offset); - if (backward_branch) { - cg->GenSuspendTest(cu, opt_flags); + // Result known at compile time? + if (rl_src[0].is_const && rl_src[1].is_const) { + bool is_taken = EvaluateBranch(opcode, cu->constant_values[rl_src[0].orig_sreg], + cu->constant_values[rl_src[1].orig_sreg]); + if (is_taken && backward_branch) { + cg->GenSuspendTest(cu, opt_flags); + } + int id = is_taken ? bb->taken->id : bb->fall_through->id; + cg->OpUnconditionalBranch(cu, &label_list[id]); + } else { + if (backward_branch) { + cg->GenSuspendTest(cu, opt_flags); + } + cg->GenCompareAndBranch(cu, opcode, rl_src[0], rl_src[1], taken, + fall_through); } - cg->GenCompareAndBranch(cu, opcode, rl_src[0], rl_src[1], taken, - fall_through); break; } @@ -296,10 +307,20 @@ static bool CompileDalvikInstruction(CompilationUnit* cu, MIR* mir, BasicBlock* LIR* fall_through = &label_list[bb->fall_through->id]; bool backward_branch; backward_branch = (bb->taken->start_offset <= mir->offset); - if (backward_branch) { - cg->GenSuspendTest(cu, opt_flags); + // Result known at compile time? + if (rl_src[0].is_const) { + bool is_taken = EvaluateBranch(opcode, cu->constant_values[rl_src[0].orig_sreg], 0); + if (is_taken && backward_branch) { + cg->GenSuspendTest(cu, opt_flags); + } + int id = is_taken ? bb->taken->id : bb->fall_through->id; + cg->OpUnconditionalBranch(cu, &label_list[id]); + } else { + if (backward_branch) { + cg->GenSuspendTest(cu, opt_flags); + } + cg->GenCompareZeroAndBranch(cu, opcode, rl_src[0], taken, fall_through); } - cg->GenCompareZeroAndBranch(cu, opcode, rl_src[0], taken, fall_through); break; } @@ -504,29 +525,49 @@ static bool CompileDalvikInstruction(CompilationUnit* cu, MIR* mir, BasicBlock* cg->GenConversion(cu, opcode, rl_dest, rl_src[0]); break; + case Instruction::ADD_INT: - case Instruction::SUB_INT: + case Instruction::ADD_INT_2ADDR: case Instruction::MUL_INT: - case Instruction::DIV_INT: - case Instruction::REM_INT: + case Instruction::MUL_INT_2ADDR: case Instruction::AND_INT: + case Instruction::AND_INT_2ADDR: case Instruction::OR_INT: + case Instruction::OR_INT_2ADDR: case Instruction::XOR_INT: - case Instruction::SHL_INT: - case Instruction::SHR_INT: - case Instruction::USHR_INT: - case Instruction::ADD_INT_2ADDR: + case Instruction::XOR_INT_2ADDR: + if (rl_src[0].is_const && + cu->cg->InexpensiveConstant(0, cu->constant_values[rl_src[0].orig_sreg])) { + cg->GenArithOpIntLit(cu, opcode, rl_dest, rl_src[1], + cu->constant_values[rl_src[0].orig_sreg]); + } else if (rl_src[1].is_const && + cu->cg->InexpensiveConstant(0, cu->constant_values[rl_src[1].orig_sreg])) { + cg->GenArithOpIntLit(cu, opcode, rl_dest, rl_src[0], + cu->constant_values[rl_src[1].orig_sreg]); + } else { + cg->GenArithOpInt(cu, opcode, rl_dest, rl_src[0], rl_src[1]); + } + break; + + case Instruction::SUB_INT: case Instruction::SUB_INT_2ADDR: - case Instruction::MUL_INT_2ADDR: + case Instruction::DIV_INT: case Instruction::DIV_INT_2ADDR: + case Instruction::REM_INT: case Instruction::REM_INT_2ADDR: - case Instruction::AND_INT_2ADDR: - case Instruction::OR_INT_2ADDR: - case Instruction::XOR_INT_2ADDR: + case Instruction::SHL_INT: case Instruction::SHL_INT_2ADDR: + case Instruction::SHR_INT: case Instruction::SHR_INT_2ADDR: + case Instruction::USHR_INT: case Instruction::USHR_INT_2ADDR: - cg->GenArithOpInt(cu, opcode, rl_dest, rl_src[0], rl_src[1]); + if (rl_src[1].is_const && + cu->cg->InexpensiveConstant(0, cu->constant_values[rl_src[1].orig_sreg])) { + cg->GenArithOpIntLit(cu, opcode, rl_dest, rl_src[0], + cu->constant_values[rl_src[1].orig_sreg]); + } else { + cg->GenArithOpInt(cu, opcode, rl_dest, rl_src[0], rl_src[1]); + } break; case Instruction::ADD_LONG: diff --git a/src/compiler/codegen/ralloc_util.cc b/src/compiler/codegen/ralloc_util.cc index 1a3a4137d8..accf676fd7 100644 --- a/src/compiler/codegen/ralloc_util.cc +++ b/src/compiler/codegen/ralloc_util.cc @@ -1091,12 +1091,18 @@ static void CountRefs(CompilationUnit *cu, BasicBlock* bb, RefCounts* core_count RegLocation loc = cu->reg_location[i]; RefCounts* counts = loc.fp ? fp_counts : core_counts; int p_map_idx = SRegToPMap(cu, loc.s_reg_low); + int sample_reg = loc.fp ? cu->reg_pool->FPRegs[0].reg : cu->reg_pool->core_regs[0].reg; + bool simple_immediate = loc.is_const && + !cu->cg->InexpensiveConstant(sample_reg, cu->constant_values[loc.orig_sreg]); if (loc.defined) { - counts[p_map_idx].count += cu->use_counts.elem_list[i]; + // Don't count easily regenerated immediates + if (!simple_immediate) { + counts[p_map_idx].count += cu->use_counts.elem_list[i]; + } } if (loc.wide) { if (loc.defined) { - if (loc.fp) { + if (loc.fp && !simple_immediate) { counts[p_map_idx].double_start = true; counts[p_map_idx+1].count += cu->use_counts.elem_list[i+1]; } diff --git a/src/compiler/codegen/x86/codegen_x86.h b/src/compiler/codegen/x86/codegen_x86.h index 4ef186a221..f467e83770 100644 --- a/src/compiler/codegen/x86/codegen_x86.h +++ b/src/compiler/codegen/x86/codegen_x86.h @@ -40,7 +40,6 @@ class X86Codegen : public Codegen { virtual LIR* LoadConstantNoClobber(CompilationUnit* cu, int r_dest, int value); virtual LIR* LoadConstantValueWide(CompilationUnit* cu, int r_dest_lo, int r_dest_hi, int val_lo, int val_hi); - virtual void LoadPair(CompilationUnit* cu, int base, int low_reg, int high_reg); virtual LIR* StoreBaseDisp(CompilationUnit* cu, int rBase, int displacement, int r_src, OpSize size); virtual LIR* StoreBaseDispWide(CompilationUnit* cu, int rBase, int displacement, int r_src_lo, @@ -91,6 +90,12 @@ class X86Codegen : public Codegen { virtual bool IsUnconditionalBranch(LIR* lir); // Required for target - Dalvik-level generators. + virtual void GenArrayObjPut(CompilationUnit* cu, int opt_flags, RegLocation rl_array, + RegLocation rl_index, RegLocation rl_src, int scale); + virtual void GenArrayGet(CompilationUnit* cu, int opt_flags, OpSize size, RegLocation rl_array, + RegLocation rl_index, RegLocation rl_dest, int scale); + virtual void GenArrayPut(CompilationUnit* cu, int opt_flags, OpSize size, RegLocation rl_array, + RegLocation rl_index, RegLocation rl_src, int scale); virtual bool GenAddLong(CompilationUnit* cu, RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2); virtual bool GenAndLong(CompilationUnit* cu, RegLocation rl_dest, RegLocation rl_src1, @@ -182,6 +187,7 @@ class X86Codegen : public Codegen { void SpillCoreRegs(CompilationUnit* cu); void UnSpillCoreRegs(CompilationUnit* cu); static const X86EncodingMap EncodingMap[kX86Last]; + bool InexpensiveConstant(int reg, int value); }; } // namespace art diff --git a/src/compiler/codegen/x86/int_x86.cc b/src/compiler/codegen/x86/int_x86.cc index bd3a7fa456..0f1fc53925 100644 --- a/src/compiler/codegen/x86/int_x86.cc +++ b/src/compiler/codegen/x86/int_x86.cc @@ -439,4 +439,148 @@ void X86Codegen::OpRegThreadMem(CompilationUnit* cu, OpKind op, int r_dest, int NewLIR2(cu, opcode, r_dest, thread_offset); } +/* + * Generate array load + */ +void X86Codegen::GenArrayGet(CompilationUnit* cu, int opt_flags, OpSize size, RegLocation rl_array, + RegLocation rl_index, RegLocation rl_dest, int scale) +{ + RegisterClass reg_class = oat_reg_class_by_size(size); + int len_offset = Array::LengthOffset().Int32Value(); + int data_offset; + RegLocation rl_result; + rl_array = LoadValue(cu, rl_array, kCoreReg); + rl_index = LoadValue(cu, rl_index, kCoreReg); + + if (size == kLong || size == kDouble) { + data_offset = Array::DataOffset(sizeof(int64_t)).Int32Value(); + } else { + data_offset = Array::DataOffset(sizeof(int32_t)).Int32Value(); + } + + /* null object? */ + GenNullCheck(cu, rl_array.s_reg_low, rl_array.low_reg, opt_flags); + + if (!(opt_flags & MIR_IGNORE_RANGE_CHECK)) { + /* if (rl_index >= [rl_array + len_offset]) goto kThrowArrayBounds */ + GenRegMemCheck(cu, kCondUge, rl_index.low_reg, rl_array.low_reg, + len_offset, kThrowArrayBounds); + } + if ((size == kLong) || (size == kDouble)) { + int reg_addr = AllocTemp(cu); + OpLea(cu, reg_addr, rl_array.low_reg, rl_index.low_reg, scale, data_offset); + FreeTemp(cu, rl_array.low_reg); + FreeTemp(cu, rl_index.low_reg); + rl_result = EvalLoc(cu, rl_dest, reg_class, true); + LoadBaseIndexedDisp(cu, reg_addr, INVALID_REG, 0, 0, rl_result.low_reg, + rl_result.high_reg, size, INVALID_SREG); + StoreValueWide(cu, rl_dest, rl_result); + } else { + rl_result = EvalLoc(cu, rl_dest, reg_class, true); + + LoadBaseIndexedDisp(cu, rl_array.low_reg, rl_index.low_reg, scale, + data_offset, rl_result.low_reg, INVALID_REG, size, + INVALID_SREG); + + StoreValue(cu, rl_dest, rl_result); + } +} + +/* + * Generate array store + * + */ +void X86Codegen::GenArrayPut(CompilationUnit* cu, int opt_flags, OpSize size, RegLocation rl_array, + RegLocation rl_index, RegLocation rl_src, int scale) +{ + RegisterClass reg_class = oat_reg_class_by_size(size); + int len_offset = Array::LengthOffset().Int32Value(); + int data_offset; + + if (size == kLong || size == kDouble) { + data_offset = Array::DataOffset(sizeof(int64_t)).Int32Value(); + } else { + data_offset = Array::DataOffset(sizeof(int32_t)).Int32Value(); + } + + rl_array = LoadValue(cu, rl_array, kCoreReg); + rl_index = LoadValue(cu, rl_index, kCoreReg); + + /* null object? */ + GenNullCheck(cu, rl_array.s_reg_low, rl_array.low_reg, opt_flags); + + if (!(opt_flags & MIR_IGNORE_RANGE_CHECK)) { + /* if (rl_index >= [rl_array + len_offset]) goto kThrowArrayBounds */ + GenRegMemCheck(cu, kCondUge, rl_index.low_reg, rl_array.low_reg, len_offset, kThrowArrayBounds); + } + if ((size == kLong) || (size == kDouble)) { + rl_src = LoadValueWide(cu, rl_src, reg_class); + } else { + rl_src = LoadValue(cu, rl_src, reg_class); + } + // If the src reg can't be byte accessed, move it to a temp first. + if ((size == kSignedByte || size == kUnsignedByte) && rl_src.low_reg >= 4) { + int temp = AllocTemp(cu); + OpRegCopy(cu, temp, rl_src.low_reg); + StoreBaseIndexedDisp(cu, rl_array.low_reg, rl_index.low_reg, scale, data_offset, temp, + INVALID_REG, size, INVALID_SREG); + } else { + StoreBaseIndexedDisp(cu, rl_array.low_reg, rl_index.low_reg, scale, data_offset, rl_src.low_reg, + rl_src.high_reg, size, INVALID_SREG); + } +} + +/* + * Generate array store + * + */ +void X86Codegen::GenArrayObjPut(CompilationUnit* cu, int opt_flags, RegLocation rl_array, + RegLocation rl_index, RegLocation rl_src, int scale) +{ + int len_offset = Array::LengthOffset().Int32Value(); + int data_offset = Array::DataOffset(sizeof(Object*)).Int32Value(); + + FlushAllRegs(cu); // Use explicit registers + LockCallTemps(cu); + + int r_value = TargetReg(kArg0); // Register holding value + int r_array_class = TargetReg(kArg1); // Register holding array's Class + int r_array = TargetReg(kArg2); // Register holding array + int r_index = TargetReg(kArg3); // Register holding index into array + + LoadValueDirectFixed(cu, rl_array, r_array); // Grab array + LoadValueDirectFixed(cu, rl_src, r_value); // Grab value + LoadValueDirectFixed(cu, rl_index, r_index); // Grab index + + GenNullCheck(cu, rl_array.s_reg_low, r_array, opt_flags); // NPE? + + // Store of null? + LIR* null_value_check = OpCmpImmBranch(cu, kCondEq, r_value, 0, NULL); + + // Get the array's class. + LoadWordDisp(cu, r_array, Object::ClassOffset().Int32Value(), r_array_class); + CallRuntimeHelperRegReg(cu, ENTRYPOINT_OFFSET(pCanPutArrayElementFromCode), r_value, + r_array_class, true); + // Redo LoadValues in case they didn't survive the call. + LoadValueDirectFixed(cu, rl_array, r_array); // Reload array + LoadValueDirectFixed(cu, rl_index, r_index); // Reload index + LoadValueDirectFixed(cu, rl_src, r_value); // Reload value + r_array_class = INVALID_REG; + + // Branch here if value to be stored == null + LIR* target = NewLIR0(cu, kPseudoTargetLabel); + null_value_check->target = target; + + // make an extra temp available for card mark below + FreeTemp(cu, TargetReg(kArg1)); + if (!(opt_flags & MIR_IGNORE_RANGE_CHECK)) { + /* if (rl_index >= [rl_array + len_offset]) goto kThrowArrayBounds */ + GenRegMemCheck(cu, kCondUge, r_index, r_array, len_offset, kThrowArrayBounds); + } + StoreBaseIndexedDisp(cu, r_array, r_index, scale, + data_offset, r_value, INVALID_REG, kWord, INVALID_SREG); + FreeTemp(cu, r_index); + MarkGCCard(cu, r_value, r_array); +} + } // namespace art diff --git a/src/compiler/codegen/x86/utility_x86.cc b/src/compiler/codegen/x86/utility_x86.cc index bdbc54767f..ce55b4bf22 100644 --- a/src/compiler/codegen/x86/utility_x86.cc +++ b/src/compiler/codegen/x86/utility_x86.cc @@ -50,6 +50,11 @@ LIR* X86Codegen::OpFpRegCopy(CompilationUnit *cu, int r_dest, int r_src) return res; } +bool X86Codegen::InexpensiveConstant(int reg, int value) +{ + return true; +} + /* * Load a immediate using a shortcut if possible; otherwise * grab from the per-translation literal pool. If target is @@ -559,9 +564,4 @@ LIR* X86Codegen::StoreBaseDispWide(CompilationUnit *cu, int rBase, int displacem r_src_lo, r_src_hi, kLong, INVALID_SREG); } -void X86Codegen::LoadPair(CompilationUnit *cu, int base, int low_reg, int high_reg) -{ - LoadBaseDispWide(cu, base, 0, low_reg, high_reg, INVALID_SREG); -} - } // namespace art |