diff options
Diffstat (limited to 'src/compiler/codegen/gen_common.cc')
| -rw-r--r-- | src/compiler/codegen/gen_common.cc | 340 |
1 files changed, 66 insertions, 274 deletions
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); |