diff options
Diffstat (limited to 'compiler')
59 files changed, 4623 insertions, 439 deletions
diff --git a/compiler/Android.mk b/compiler/Android.mk index 4eb9ff58f3..b17cd52fad 100644 --- a/compiler/Android.mk +++ b/compiler/Android.mk @@ -69,6 +69,7 @@ LIBART_COMPILER_SRC_FILES := \ jni/quick/arm64/calling_convention_arm64.cc \ jni/quick/mips/calling_convention_mips.cc \ jni/quick/x86/calling_convention_x86.cc \ + jni/quick/x86_64/calling_convention_x86_64.cc \ jni/quick/calling_convention.cc \ jni/quick/jni_compiler.cc \ optimizing/builder.cc \ @@ -89,6 +90,8 @@ LIBART_COMPILER_SRC_FILES := \ utils/mips/managed_register_mips.cc \ utils/x86/assembler_x86.cc \ utils/x86/managed_register_x86.cc \ + utils/x86_64/assembler_x86_64.cc \ + utils/x86_64/managed_register_x86_64.cc \ utils/scoped_arena_allocator.cc \ buffered_output_stream.cc \ compilers.cc \ diff --git a/compiler/compiled_method.cc b/compiler/compiled_method.cc index 344f3ef745..8e013c1ece 100644 --- a/compiler/compiled_method.cc +++ b/compiler/compiled_method.cc @@ -105,6 +105,7 @@ size_t CompiledCode::CodeDelta() const { case kArm64: case kMips: case kX86: + case kX86_64: return 0; case kThumb2: { // +1 to set the low-order bit so a BLX will switch to Thumb mode @@ -123,6 +124,7 @@ const void* CompiledCode::CodePointer(const void* code_pointer, case kArm64: case kMips: case kX86: + case kX86_64: return code_pointer; case kThumb2: { uintptr_t address = reinterpret_cast<uintptr_t>(code_pointer); diff --git a/compiler/dex/compiler_enums.h b/compiler/dex/compiler_enums.h index eb4a3367bb..964a222c05 100644 --- a/compiler/dex/compiler_enums.h +++ b/compiler/dex/compiler_enums.h @@ -417,7 +417,7 @@ std::ostream& operator<<(std::ostream& os, const SelectInstructionKind& kind); enum FixupKind { kFixupNone, kFixupLabel, // For labels we just adjust the offset. - kFixupLoad, // Mostly for imediates. + kFixupLoad, // Mostly for immediates. kFixupVLoad, // FP load which *may* be pc-relative. kFixupCBxZ, // Cbz, Cbnz. kFixupPushPop, // Not really pc relative, but changes size based on args. diff --git a/compiler/dex/frontend.cc b/compiler/dex/frontend.cc index 64fa685c19..3f122de623 100644 --- a/compiler/dex/frontend.cc +++ b/compiler/dex/frontend.cc @@ -287,9 +287,7 @@ static CompiledMethod* CompileMethod(CompilerDriver& driver, } cu.EndTiming(); - driver.GetTimingsLogger()->Start(); driver.GetTimingsLogger()->AddLogger(cu.timings); - driver.GetTimingsLogger()->End(); return result; } diff --git a/compiler/dex/quick/arm/assemble_arm.cc b/compiler/dex/quick/arm/assemble_arm.cc index caf84d9bba..7955d6cd3f 100644 --- a/compiler/dex/quick/arm/assemble_arm.cc +++ b/compiler/dex/quick/arm/assemble_arm.cc @@ -1062,134 +1062,142 @@ void ArmMir2Lir::InsertFixupBefore(LIR* prev_lir, LIR* orig_lir, LIR* new_lir) { */ #define PADDING_MOV_R5_R5 0x1C2D -void ArmMir2Lir::EncodeLIR(LIR* lir) { - int opcode = lir->opcode; - if (IsPseudoLirOp(opcode)) { - if (UNLIKELY(opcode == kPseudoPseudoAlign4)) { - // Note: size for this opcode will be either 0 or 2 depending on final alignment. - lir->u.a.bytes[0] = (PADDING_MOV_R5_R5 & 0xff); - lir->u.a.bytes[1] = ((PADDING_MOV_R5_R5 >> 8) & 0xff); - lir->flags.size = (lir->offset & 0x2); - } - } else if (LIKELY(!lir->flags.is_nop)) { - const ArmEncodingMap *encoder = &EncodingMap[lir->opcode]; - uint32_t bits = encoder->skeleton; - for (int i = 0; i < 4; i++) { - uint32_t operand; - uint32_t value; - operand = lir->operands[i]; - ArmEncodingKind kind = encoder->field_loc[i].kind; - if (LIKELY(kind == kFmtBitBlt)) { - value = (operand << encoder->field_loc[i].start) & - ((1 << (encoder->field_loc[i].end + 1)) - 1); - bits |= value; - } else { - switch (encoder->field_loc[i].kind) { - case kFmtSkip: - break; // Nothing to do, but continue to next. - case kFmtUnused: - i = 4; // Done, break out of the enclosing loop. - break; - case kFmtFPImm: - value = ((operand & 0xF0) >> 4) << encoder->field_loc[i].end; - value |= (operand & 0x0F) << encoder->field_loc[i].start; - bits |= value; - break; - case kFmtBrOffset: - value = ((operand & 0x80000) >> 19) << 26; - value |= ((operand & 0x40000) >> 18) << 11; - value |= ((operand & 0x20000) >> 17) << 13; - value |= ((operand & 0x1f800) >> 11) << 16; - value |= (operand & 0x007ff); - bits |= value; - break; - case kFmtShift5: - value = ((operand & 0x1c) >> 2) << 12; - value |= (operand & 0x03) << 6; - bits |= value; - break; - case kFmtShift: - value = ((operand & 0x70) >> 4) << 12; - value |= (operand & 0x0f) << 4; - bits |= value; - break; - case kFmtBWidth: - value = operand - 1; - bits |= value; - break; - case kFmtLsb: - value = ((operand & 0x1c) >> 2) << 12; - value |= (operand & 0x03) << 6; - bits |= value; - break; - case kFmtImm6: - value = ((operand & 0x20) >> 5) << 9; - value |= (operand & 0x1f) << 3; - bits |= value; - break; - case kFmtDfp: { - DCHECK(ARM_DOUBLEREG(operand)); - DCHECK_EQ((operand & 0x1), 0U); - uint32_t reg_name = (operand & ARM_FP_REG_MASK) >> 1; - /* Snag the 1-bit slice and position it */ - value = ((reg_name & 0x10) >> 4) << encoder->field_loc[i].end; - /* Extract and position the 4-bit slice */ - value |= (reg_name & 0x0f) << encoder->field_loc[i].start; - bits |= value; - break; +uint8_t* ArmMir2Lir::EncodeLIRs(uint8_t* write_pos, LIR* lir) { + for (; lir != NULL; lir = NEXT_LIR(lir)) { + if (!lir->flags.is_nop) { + int opcode = lir->opcode; + if (IsPseudoLirOp(opcode)) { + if (UNLIKELY(opcode == kPseudoPseudoAlign4)) { + // Note: size for this opcode will be either 0 or 2 depending on final alignment. + if (lir->offset & 0x2) { + write_pos[0] = (PADDING_MOV_R5_R5 & 0xff); + write_pos[1] = ((PADDING_MOV_R5_R5 >> 8) & 0xff); + write_pos += 2; } - case kFmtSfp: - DCHECK(ARM_SINGLEREG(operand)); - /* Snag the 1-bit slice and position it */ - value = (operand & 0x1) << encoder->field_loc[i].end; - /* Extract and position the 4-bit slice */ - value |= ((operand & 0x1e) >> 1) << encoder->field_loc[i].start; - bits |= value; - break; - case kFmtImm12: - case kFmtModImm: - value = ((operand & 0x800) >> 11) << 26; - value |= ((operand & 0x700) >> 8) << 12; - value |= operand & 0x0ff; - bits |= value; - break; - case kFmtImm16: - value = ((operand & 0x0800) >> 11) << 26; - value |= ((operand & 0xf000) >> 12) << 16; - value |= ((operand & 0x0700) >> 8) << 12; - value |= operand & 0x0ff; - bits |= value; - break; - case kFmtOff24: { - uint32_t signbit = (operand >> 31) & 0x1; - uint32_t i1 = (operand >> 22) & 0x1; - uint32_t i2 = (operand >> 21) & 0x1; - uint32_t imm10 = (operand >> 11) & 0x03ff; - uint32_t imm11 = operand & 0x07ff; - uint32_t j1 = (i1 ^ signbit) ? 0 : 1; - uint32_t j2 = (i2 ^ signbit) ? 0 : 1; - value = (signbit << 26) | (j1 << 13) | (j2 << 11) | (imm10 << 16) | - imm11; + } + } else if (LIKELY(!lir->flags.is_nop)) { + const ArmEncodingMap *encoder = &EncodingMap[lir->opcode]; + uint32_t bits = encoder->skeleton; + for (int i = 0; i < 4; i++) { + uint32_t operand; + uint32_t value; + operand = lir->operands[i]; + ArmEncodingKind kind = encoder->field_loc[i].kind; + if (LIKELY(kind == kFmtBitBlt)) { + value = (operand << encoder->field_loc[i].start) & + ((1 << (encoder->field_loc[i].end + 1)) - 1); bits |= value; + } else { + switch (encoder->field_loc[i].kind) { + case kFmtSkip: + break; // Nothing to do, but continue to next. + case kFmtUnused: + i = 4; // Done, break out of the enclosing loop. + break; + case kFmtFPImm: + value = ((operand & 0xF0) >> 4) << encoder->field_loc[i].end; + value |= (operand & 0x0F) << encoder->field_loc[i].start; + bits |= value; + break; + case kFmtBrOffset: + value = ((operand & 0x80000) >> 19) << 26; + value |= ((operand & 0x40000) >> 18) << 11; + value |= ((operand & 0x20000) >> 17) << 13; + value |= ((operand & 0x1f800) >> 11) << 16; + value |= (operand & 0x007ff); + bits |= value; + break; + case kFmtShift5: + value = ((operand & 0x1c) >> 2) << 12; + value |= (operand & 0x03) << 6; + bits |= value; + break; + case kFmtShift: + value = ((operand & 0x70) >> 4) << 12; + value |= (operand & 0x0f) << 4; + bits |= value; + break; + case kFmtBWidth: + value = operand - 1; + bits |= value; + break; + case kFmtLsb: + value = ((operand & 0x1c) >> 2) << 12; + value |= (operand & 0x03) << 6; + bits |= value; + break; + case kFmtImm6: + value = ((operand & 0x20) >> 5) << 9; + value |= (operand & 0x1f) << 3; + bits |= value; + break; + case kFmtDfp: { + DCHECK(ARM_DOUBLEREG(operand)); + DCHECK_EQ((operand & 0x1), 0U); + uint32_t reg_name = (operand & ARM_FP_REG_MASK) >> 1; + /* Snag the 1-bit slice and position it */ + value = ((reg_name & 0x10) >> 4) << encoder->field_loc[i].end; + /* Extract and position the 4-bit slice */ + value |= (reg_name & 0x0f) << encoder->field_loc[i].start; + bits |= value; + break; + } + case kFmtSfp: + DCHECK(ARM_SINGLEREG(operand)); + /* Snag the 1-bit slice and position it */ + value = (operand & 0x1) << encoder->field_loc[i].end; + /* Extract and position the 4-bit slice */ + value |= ((operand & 0x1e) >> 1) << encoder->field_loc[i].start; + bits |= value; + break; + case kFmtImm12: + case kFmtModImm: + value = ((operand & 0x800) >> 11) << 26; + value |= ((operand & 0x700) >> 8) << 12; + value |= operand & 0x0ff; + bits |= value; + break; + case kFmtImm16: + value = ((operand & 0x0800) >> 11) << 26; + value |= ((operand & 0xf000) >> 12) << 16; + value |= ((operand & 0x0700) >> 8) << 12; + value |= operand & 0x0ff; + bits |= value; + break; + case kFmtOff24: { + uint32_t signbit = (operand >> 31) & 0x1; + uint32_t i1 = (operand >> 22) & 0x1; + uint32_t i2 = (operand >> 21) & 0x1; + uint32_t imm10 = (operand >> 11) & 0x03ff; + uint32_t imm11 = operand & 0x07ff; + uint32_t j1 = (i1 ^ signbit) ? 0 : 1; + uint32_t j2 = (i2 ^ signbit) ? 0 : 1; + value = (signbit << 26) | (j1 << 13) | (j2 << 11) | (imm10 << 16) | + imm11; + bits |= value; + } + break; + default: + LOG(FATAL) << "Bad fmt:" << encoder->field_loc[i].kind; } - break; - default: - LOG(FATAL) << "Bad fmt:" << encoder->field_loc[i].kind; + } + } + if (encoder->size == 4) { + write_pos[0] = ((bits >> 16) & 0xff); + write_pos[1] = ((bits >> 24) & 0xff); + write_pos[2] = (bits & 0xff); + write_pos[3] = ((bits >> 8) & 0xff); + write_pos += 4; + } else { + DCHECK_EQ(encoder->size, 2); + write_pos[0] = (bits & 0xff); + write_pos[1] = ((bits >> 8) & 0xff); + write_pos += 2; } } } - if (encoder->size == 4) { - lir->u.a.bytes[0] = ((bits >> 16) & 0xff); - lir->u.a.bytes[1] = ((bits >> 24) & 0xff); - lir->u.a.bytes[2] = (bits & 0xff); - lir->u.a.bytes[3] = ((bits >> 8) & 0xff); - } else { - DCHECK_EQ(encoder->size, 2); - lir->u.a.bytes[0] = (bits & 0xff); - lir->u.a.bytes[1] = ((bits >> 8) & 0xff); - } - lir->flags.size = encoder->size; } + return write_pos; } // Assemble the LIR into binary instruction format. @@ -1198,7 +1206,7 @@ void ArmMir2Lir::AssembleLIR() { LIR* prev_lir; cu_->NewTimingSplit("Assemble"); int assembler_retries = 0; - CodeOffset starting_offset = EncodeRange(first_lir_insn_, last_lir_insn_, 0); + CodeOffset starting_offset = LinkFixupInsns(first_lir_insn_, last_lir_insn_, 0); data_offset_ = (starting_offset + 0x3) & ~0x3; int32_t offset_adjustment; AssignDataOffsets(); @@ -1304,8 +1312,6 @@ void ArmMir2Lir::AssembleLIR() { lir->operands[2] = 0; lir->operands[1] = base_reg; } - // Must redo encoding here - won't ever revisit this node. - EncodeLIR(lir); prev_lir = new_adr; // Continue scan with new_adr; lir = new_adr->u.a.pcrel_next; res = kRetryAll; @@ -1346,9 +1352,8 @@ void ArmMir2Lir::AssembleLIR() { /* operand[0] is src1 in both cb[n]z & CmpRI8 */ lir->operands[1] = 0; lir->target = 0; - EncodeLIR(lir); // NOTE: sets flags.size. + lir->flags.size = EncodingMap[lir->opcode].size; // Add back the new size. - DCHECK_EQ(lir->flags.size, static_cast<uint32_t>(EncodingMap[lir->opcode].size)); offset_adjustment += lir->flags.size; // Set up the new following inst. new_inst->offset = lir->offset + lir->flags.size; @@ -1570,20 +1575,6 @@ void ArmMir2Lir::AssembleLIR() { default: LOG(FATAL) << "Unexpected case " << lir->flags.fixup; } - /* - * If one of the pc-relative instructions expanded we'll have - * to make another pass. Don't bother to fully assemble the - * instruction. - */ - if (res == kSuccess) { - EncodeLIR(lir); - if (assembler_retries == 0) { - // Go ahead and fix up the code buffer image. - for (int i = 0; i < lir->flags.size; i++) { - code_buffer_[lir->offset + i] = lir->u.a.bytes[i]; - } - } - } prev_lir = lir; lir = lir->u.a.pcrel_next; } @@ -1602,21 +1593,15 @@ void ArmMir2Lir::AssembleLIR() { } } - // Rebuild the CodeBuffer if we had to retry; otherwise it should be good as-is. - if (assembler_retries != 0) { - code_buffer_.clear(); - for (LIR* lir = first_lir_insn_; lir != NULL; lir = NEXT_LIR(lir)) { - if (lir->flags.is_nop) { - continue; - } else { - for (int i = 0; i < lir->flags.size; i++) { - code_buffer_.push_back(lir->u.a.bytes[i]); - } - } - } - } + // Build the CodeBuffer. + DCHECK_LE(data_offset_, total_size_); + code_buffer_.reserve(total_size_); + code_buffer_.resize(starting_offset); + uint8_t* write_pos = &code_buffer_[0]; + write_pos = EncodeLIRs(write_pos, first_lir_insn_); + DCHECK_EQ(static_cast<CodeOffset>(write_pos - &code_buffer_[0]), starting_offset); - data_offset_ = (code_buffer_.size() + 0x3) & ~0x3; + DCHECK_EQ(data_offset_, (code_buffer_.size() + 0x3) & ~0x3); // Install literals InstallLiteralPools(); @@ -1641,19 +1626,11 @@ int ArmMir2Lir::GetInsnSize(LIR* lir) { } // Encode instruction bit pattern and assign offsets. -uint32_t ArmMir2Lir::EncodeRange(LIR* head_lir, LIR* tail_lir, uint32_t offset) { +uint32_t ArmMir2Lir::LinkFixupInsns(LIR* head_lir, LIR* tail_lir, uint32_t offset) { LIR* end_lir = tail_lir->next; - /* - * A significant percentage of methods can be assembled in a single pass. We'll - * go ahead and build the code image here, leaving holes for pc-relative fixup - * codes. If the code size changes during that pass, we'll have to throw away - * this work - but if not, we're ready to go. - */ - code_buffer_.reserve(estimated_native_code_size_ + 256); // Add a little slop. LIR* last_fixup = NULL; for (LIR* lir = head_lir; lir != end_lir; lir = NEXT_LIR(lir)) { - lir->offset = offset; if (!lir->flags.is_nop) { if (lir->flags.fixup != kFixupNone) { if (!IsPseudoLirOp(lir->opcode)) { @@ -1675,11 +1652,7 @@ uint32_t ArmMir2Lir::EncodeRange(LIR* head_lir, LIR* tail_lir, uint32_t offset) last_fixup->u.a.pcrel_next = lir; } last_fixup = lir; - } else { - EncodeLIR(lir); - } - for (int i = 0; i < lir->flags.size; i++) { - code_buffer_.push_back(lir->u.a.bytes[i]); + lir->offset = offset; } offset += lir->flags.size; } diff --git a/compiler/dex/quick/arm/codegen_arm.h b/compiler/dex/quick/arm/codegen_arm.h index 6df341bd93..8bfdb6af2c 100644 --- a/compiler/dex/quick/arm/codegen_arm.h +++ b/compiler/dex/quick/arm/codegen_arm.h @@ -22,14 +22,13 @@ namespace art { -class ArmMir2Lir FINAL : public Mir2Lir { +class ArmMir2Lir : public Mir2Lir { public: ArmMir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena); // Required for target - codegen helpers. bool SmallLiteralDivRem(Instruction::Code dalvik_opcode, bool is_div, RegLocation rl_src, RegLocation rl_dest, int lit); - bool EasyMultiply(RegLocation rl_src, RegLocation rl_dest, int lit) OVERRIDE; LIR* CheckSuspendUsingLoad() OVERRIDE; RegStorage LoadHelper(ThreadOffset offset); LIR* LoadBaseDisp(RegStorage r_base, int displacement, RegStorage r_dest, OpSize size, @@ -78,10 +77,10 @@ class ArmMir2Lir FINAL : public Mir2Lir { // Required for target - miscellaneous. void AssembleLIR(); - uint32_t EncodeRange(LIR* head_lir, LIR* tail_lir, uint32_t starting_offset); + uint32_t LinkFixupInsns(LIR* head_lir, LIR* tail_lir, CodeOffset offset); int AssignInsnOffsets(); void AssignOffsets(); - void EncodeLIR(LIR* lir); + static uint8_t* EncodeLIRs(uint8_t* write_pos, LIR* lir); void DumpResourceMask(LIR* lir, uint64_t mask, const char* prefix); void SetupTargetResourceMasks(LIR* lir, uint64_t flags); const char* GetTargetInstFmt(int opcode); @@ -182,9 +181,8 @@ class ArmMir2Lir FINAL : public Mir2Lir { LIR* LoadBaseDispBody(RegStorage r_base, int displacement, RegStorage r_dest, OpSize size, int s_reg); LIR* StoreBaseDispBody(RegStorage r_base, int displacement, RegStorage r_src, OpSize size); - LIR* OpRegRegRegShift(OpKind op, RegStorage r_dest, RegStorage r_src1, RegStorage r_src2, - int shift); - LIR* OpRegRegShift(OpKind op, RegStorage r_dest_src1, RegStorage r_src2, int shift); + LIR* OpRegRegRegShift(OpKind op, int r_dest, int r_src1, int r_src2, int shift); + LIR* OpRegRegShift(OpKind op, int r_dest_src1, int r_src2, int shift); static const ArmEncodingMap EncodingMap[kArmLast]; int EncodeShift(int code, int amount); int ModifiedImmediate(uint32_t value); @@ -204,13 +202,6 @@ class ArmMir2Lir FINAL : public Mir2Lir { RegLocation GenDivRem(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2, bool is_div, bool check_zero); RegLocation GenDivRemLit(RegLocation rl_dest, RegLocation rl_src1, int lit, bool is_div); - typedef struct { - OpKind op; - uint32_t shift; - } EasyMultiplyOp; - bool GetEasyMultiplyOp(int lit, EasyMultiplyOp* op); - bool GetEasyMultiplyTwoOps(int lit, EasyMultiplyOp* ops); - void GenEasyMultiplyTwoOps(RegStorage r_dest, RegStorage r_src, EasyMultiplyOp* ops); }; } // namespace art diff --git a/compiler/dex/quick/arm/int_arm.cc b/compiler/dex/quick/arm/int_arm.cc index 964c2fb893..46db466136 100644 --- a/compiler/dex/quick/arm/int_arm.cc +++ b/compiler/dex/quick/arm/int_arm.cc @@ -425,6 +425,10 @@ bool ArmMir2Lir::SmallLiteralDivRem(Instruction::Code dalvik_opcode, bool is_div if (pattern == DivideNone) { return false; } + // Tuning: add rem patterns + if (!is_div) { + return false; + } RegStorage r_magic = AllocTemp(); LoadConstant(r_magic, magic_table[lit].magic); @@ -435,136 +439,23 @@ bool ArmMir2Lir::SmallLiteralDivRem(Instruction::Code dalvik_opcode, bool is_div NewLIR4(kThumb2Smull, r_lo.GetReg(), r_hi.GetReg(), r_magic.GetReg(), rl_src.reg.GetReg()); switch (pattern) { case Divide3: - OpRegRegRegShift(kOpSub, rl_result.reg, r_hi, rl_src.reg, EncodeShift(kArmAsr, 31)); + OpRegRegRegShift(kOpSub, rl_result.reg.GetReg(), r_hi.GetReg(), + rl_src.reg.GetReg(), EncodeShift(kArmAsr, 31)); break; case Divide5: OpRegRegImm(kOpAsr, r_lo, rl_src.reg, 31); - OpRegRegRegShift(kOpRsub, rl_result.reg, r_lo, r_hi, - EncodeShift(kArmAsr, magic_table[lit].shift)); + OpRegRegRegShift(kOpRsub, rl_result.reg.GetReg(), r_lo.GetReg(), r_hi.GetReg(), + EncodeShift(kArmAsr, magic_table[lit].shift)); break; case Divide7: OpRegReg(kOpAdd, r_hi, rl_src.reg); OpRegRegImm(kOpAsr, r_lo, rl_src.reg, 31); - OpRegRegRegShift(kOpRsub, rl_result.reg, r_lo, r_hi, - EncodeShift(kArmAsr, magic_table[lit].shift)); + OpRegRegRegShift(kOpRsub, rl_result.reg.GetReg(), r_lo.GetReg(), r_hi.GetReg(), + EncodeShift(kArmAsr, magic_table[lit].shift)); break; default: LOG(FATAL) << "Unexpected pattern: " << pattern; } - - if (!is_div) { - RegStorage tmp1 = r_lo; - EasyMultiplyOp ops[2]; - - bool canEasyMultiply = GetEasyMultiplyTwoOps(lit, ops); - DCHECK_NE(canEasyMultiply, false); - - GenEasyMultiplyTwoOps(tmp1, rl_result.reg, ops); - OpRegRegReg(kOpSub, rl_result.reg, rl_src.reg, tmp1); - } - - StoreValue(rl_dest, rl_result); - return true; -} - -// Try to convert *lit to 1 RegRegRegShift/RegRegShift form. -bool ArmMir2Lir::GetEasyMultiplyOp(int lit, ArmMir2Lir::EasyMultiplyOp* op) { - if (IsPowerOfTwo(lit)) { - op->op = kOpLsl; - op->shift = LowestSetBit(lit); - return true; - } - - if (IsPowerOfTwo(lit - 1)) { - op->op = kOpAdd; - op->shift = LowestSetBit(lit - 1); - return true; - } - - if (IsPowerOfTwo(lit + 1)) { - op->op = kOpRsub; - op->shift = LowestSetBit(lit + 1); - return true; - } - - op->op = kOpInvalid; - return false; -} - -// Try to convert *lit to 1~2 RegRegRegShift/RegRegShift forms. -bool ArmMir2Lir::GetEasyMultiplyTwoOps(int lit, EasyMultiplyOp* ops) { - GetEasyMultiplyOp(lit, &ops[0]); - if (GetEasyMultiplyOp(lit, &ops[0])) { - ops[1].op = kOpInvalid; - return true; - } - - int lit1 = lit; - uint32_t shift = LowestSetBit(lit1); - if (GetEasyMultiplyOp(lit1 >> shift, &ops[0])) { - ops[1].op = kOpLsl; - ops[1].shift = shift; - return true; - } - - lit1 = lit - 1; - shift = LowestSetBit(lit1); - if (GetEasyMultiplyOp(lit1 >> shift, &ops[0])) { - ops[1].op = kOpAdd; - ops[1].shift = shift; - return true; - } - - lit1 = lit + 1; - shift = LowestSetBit(lit1); - if (GetEasyMultiplyOp(lit1 >> shift, &ops[0])) { - ops[1].op = kOpRsub; - ops[1].shift = shift; - return true; - } - - return false; -} - -void ArmMir2Lir::GenEasyMultiplyTwoOps(RegStorage r_dest, RegStorage r_src, EasyMultiplyOp* ops) { - // dest = ( src << shift1) + [ src | -src | 0 ] - // dest = (dest << shift2) + [ src | -src | 0 ] - for (int i = 0; i < 2; i++) { - RegStorage r_src2; - if (i == 0) { - r_src2 = r_src; - } else { - r_src2 = r_dest; - } - switch (ops[i].op) { - case kOpLsl: - OpRegRegImm(kOpLsl, r_dest, r_src2, ops[i].shift); - break; - case kOpAdd: - OpRegRegRegShift(kOpAdd, r_dest, r_src, r_src2, EncodeShift(kArmLsl, ops[i].shift)); - break; - case kOpRsub: - OpRegRegRegShift(kOpRsub, r_dest, r_src, r_src2, EncodeShift(kArmLsl, ops[i].shift)); - break; - default: - DCHECK_NE(i, 0); - DCHECK_EQ(ops[i].op, kOpInvalid); - break; - } - } -} - -bool ArmMir2Lir::EasyMultiply(RegLocation rl_src, RegLocation rl_dest, int lit) { - EasyMultiplyOp ops[2]; - - if (!GetEasyMultiplyTwoOps(lit, ops)) { - return false; - } - - rl_src = LoadValue(rl_src, kCoreReg); - RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true); - - GenEasyMultiplyTwoOps(rl_result.reg, rl_src.reg, ops); StoreValue(rl_dest, rl_result); return true; } @@ -861,7 +752,7 @@ LIR* ArmMir2Lir::OpVstm(RegStorage r_base, int count) { void ArmMir2Lir::GenMultiplyByTwoBitMultiplier(RegLocation rl_src, RegLocation rl_result, int lit, int first_bit, int second_bit) { - OpRegRegRegShift(kOpAdd, rl_result.reg, rl_src.reg, rl_src.reg, + OpRegRegRegShift(kOpAdd, rl_result.reg.GetReg(), rl_src.reg.GetReg(), rl_src.reg.GetReg(), EncodeShift(kArmLsl, second_bit - first_bit)); if (first_bit != 0) { OpRegRegImm(kOpLsl, rl_result.reg, rl_result.reg, first_bit); @@ -1007,7 +898,8 @@ void ArmMir2Lir::GenMulLong(Instruction::Code opcode, RegLocation rl_dest, NewLIR3(kThumb2MulRRR, tmp1.GetReg(), rl_src1.reg.GetLowReg(), rl_src1.reg.GetHighReg()); NewLIR4(kThumb2Umull, res_lo.GetReg(), res_hi.GetReg(), rl_src1.reg.GetLowReg(), rl_src1.reg.GetLowReg()); - OpRegRegRegShift(kOpAdd, res_hi, res_hi, tmp1, EncodeShift(kArmLsl, 1)); + OpRegRegRegShift(kOpAdd, res_hi.GetReg(), res_hi.GetReg(), tmp1.GetReg(), + EncodeShift(kArmLsl, 1)); } else { NewLIR3(kThumb2MulRRR, tmp1.GetReg(), rl_src2.reg.GetLowReg(), rl_src1.reg.GetHighReg()); if (reg_status == 2) { @@ -1117,7 +1009,8 @@ void ArmMir2Lir::GenArrayGet(int opt_flags, OpSize size, RegLocation rl_array, } else { // No special indexed operation, lea + load w/ displacement reg_ptr = AllocTemp(); - OpRegRegRegShift(kOpAdd, reg_ptr, rl_array.reg, rl_index.reg, EncodeShift(kArmLsl, scale)); + OpRegRegRegShift(kOpAdd, reg_ptr.GetReg(), rl_array.reg.GetReg(), rl_index.reg.GetReg(), + EncodeShift(kArmLsl, scale)); FreeTemp(rl_index.reg.GetReg()); } rl_result = EvalLoc(rl_dest, reg_class, true); @@ -1224,7 +1117,8 @@ void ArmMir2Lir::GenArrayPut(int opt_flags, OpSize size, RegLocation rl_array, rl_src = LoadValue(rl_src, reg_class); } if (!constant_index) { - OpRegRegRegShift(kOpAdd, reg_ptr, rl_array.reg, rl_index.reg, EncodeShift(kArmLsl, scale)); + OpRegRegRegShift(kOpAdd, reg_ptr.GetReg(), rl_array.reg.GetReg(), rl_index.reg.GetReg(), + EncodeShift(kArmLsl, scale)); } if (needs_range_check) { if (constant_index) { @@ -1289,7 +1183,7 @@ void ArmMir2Lir::GenShiftImmOpLong(Instruction::Code opcode, LoadConstant(rl_result.reg.GetLow(), 0); } else { OpRegRegImm(kOpLsl, rl_result.reg.GetHigh(), rl_src.reg.GetHigh(), shift_amount); - OpRegRegRegShift(kOpOr, rl_result.reg.GetHigh(), rl_result.reg.GetHigh(), rl_src.reg.GetLow(), + OpRegRegRegShift(kOpOr, rl_result.reg.GetHighReg(), rl_result.reg.GetHighReg(), rl_src.reg.GetLowReg(), EncodeShift(kArmLsr, 32 - shift_amount)); OpRegRegImm(kOpLsl, rl_result.reg.GetLow(), rl_src.reg.GetLow(), shift_amount); } @@ -1305,7 +1199,7 @@ void ArmMir2Lir::GenShiftImmOpLong(Instruction::Code opcode, } else { RegStorage t_reg = AllocTemp(); OpRegRegImm(kOpLsr, t_reg, rl_src.reg.GetLow(), shift_amount); - OpRegRegRegShift(kOpOr, rl_result.reg.GetLow(), t_reg, rl_src.reg.GetHigh(), + OpRegRegRegShift(kOpOr, rl_result.reg.GetLowReg(), t_reg.GetReg(), rl_src.reg.GetHighReg(), EncodeShift(kArmLsl, 32 - shift_amount)); FreeTemp(t_reg); OpRegRegImm(kOpAsr, rl_result.reg.GetHigh(), rl_src.reg.GetHigh(), shift_amount); @@ -1322,7 +1216,7 @@ void ArmMir2Lir::GenShiftImmOpLong(Instruction::Code opcode, } else { RegStorage t_reg = AllocTemp(); OpRegRegImm(kOpLsr, t_reg, rl_src.reg.GetLow(), shift_amount); - OpRegRegRegShift(kOpOr, rl_result.reg.GetLow(), t_reg, rl_src.reg.GetHigh(), + OpRegRegRegShift(kOpOr, rl_result.reg.GetLowReg(), t_reg.GetReg(), rl_src.reg.GetHighReg(), EncodeShift(kArmLsl, 32 - shift_amount)); FreeTemp(t_reg); OpRegRegImm(kOpLsr, rl_result.reg.GetHigh(), rl_src.reg.GetHigh(), shift_amount); diff --git a/compiler/dex/quick/arm/utility_arm.cc b/compiler/dex/quick/arm/utility_arm.cc index cf90fb1b52..1ec0a2c65d 100644 --- a/compiler/dex/quick/arm/utility_arm.cc +++ b/compiler/dex/quick/arm/utility_arm.cc @@ -234,10 +234,9 @@ LIR* ArmMir2Lir::OpReg(OpKind op, RegStorage r_dest_src) { return NewLIR1(opcode, r_dest_src.GetReg()); } -LIR* ArmMir2Lir::OpRegRegShift(OpKind op, RegStorage r_dest_src1, RegStorage r_src2, +LIR* ArmMir2Lir::OpRegRegShift(OpKind op, int r_dest_src1, int r_src2, int shift) { - bool thumb_form = - ((shift == 0) && ARM_LOWREG(r_dest_src1.GetReg()) && ARM_LOWREG(r_src2.GetReg())); + bool thumb_form = ((shift == 0) && ARM_LOWREG(r_dest_src1) && ARM_LOWREG(r_src2)); ArmOpcode opcode = kThumbBkpt; switch (op) { case kOpAdc: @@ -256,9 +255,9 @@ LIR* ArmMir2Lir::OpRegRegShift(OpKind op, RegStorage r_dest_src1, RegStorage r_s case kOpCmp: if (thumb_form) opcode = kThumbCmpRR; - else if ((shift == 0) && !ARM_LOWREG(r_dest_src1.GetReg()) && !ARM_LOWREG(r_src2.GetReg())) + else if ((shift == 0) && !ARM_LOWREG(r_dest_src1) && !ARM_LOWREG(r_src2)) opcode = kThumbCmpHH; - else if ((shift == 0) && ARM_LOWREG(r_dest_src1.GetReg())) + else if ((shift == 0) && ARM_LOWREG(r_dest_src1)) opcode = kThumbCmpLH; else if (shift == 0) opcode = kThumbCmpHL; @@ -270,11 +269,11 @@ LIR* ArmMir2Lir::OpRegRegShift(OpKind op, RegStorage r_dest_src1, RegStorage r_s break; case kOpMov: DCHECK_EQ(shift, 0); - if (ARM_LOWREG(r_dest_src1.GetReg()) && ARM_LOWREG(r_src2.GetReg())) + if (ARM_LOWREG(r_dest_src1) && ARM_LOWREG(r_src2)) opcode = kThumbMovRR; - else if (!ARM_LOWREG(r_dest_src1.GetReg()) && !ARM_LOWREG(r_src2.GetReg())) + else if (!ARM_LOWREG(r_dest_src1) && !ARM_LOWREG(r_src2)) opcode = kThumbMovRR_H2H; - else if (ARM_LOWREG(r_dest_src1.GetReg())) + else if (ARM_LOWREG(r_dest_src1)) opcode = kThumbMovRR_H2L; else opcode = kThumbMovRR_L2H; @@ -325,7 +324,7 @@ LIR* ArmMir2Lir::OpRegRegShift(OpKind op, RegStorage r_dest_src1, RegStorage r_s DCHECK_EQ(shift, 0); if (!thumb_form) { // Binary, but rm is encoded twice. - return NewLIR3(kThumb2RevRR, r_dest_src1.GetReg(), r_src2.GetReg(), r_src2.GetReg()); + return NewLIR3(kThumb2RevRR, r_dest_src1, r_src2, r_src2); } opcode = kThumbRev; break; @@ -333,34 +332,34 @@ LIR* ArmMir2Lir::OpRegRegShift(OpKind op, RegStorage r_dest_src1, RegStorage r_s DCHECK_EQ(shift, 0); if (!thumb_form) { // Binary, but rm is encoded twice. - return NewLIR3(kThumb2RevshRR, r_dest_src1.GetReg(), r_src2.GetReg(), r_src2.GetReg()); + return NewLIR3(kThumb2RevshRR, r_dest_src1, r_src2, r_src2); } opcode = kThumbRevsh; break; case kOp2Byte: DCHECK_EQ(shift, 0); - return NewLIR4(kThumb2Sbfx, r_dest_src1.GetReg(), r_src2.GetReg(), 0, 8); + return NewLIR4(kThumb2Sbfx, r_dest_src1, r_src2, 0, 8); case kOp2Short: DCHECK_EQ(shift, 0); - return NewLIR4(kThumb2Sbfx, r_dest_src1.GetReg(), r_src2.GetReg(), 0, 16); + return NewLIR4(kThumb2Sbfx, r_dest_src1, r_src2, 0, 16); case kOp2Char: DCHECK_EQ(shift, 0); - return NewLIR4(kThumb2Ubfx, r_dest_src1.GetReg(), r_src2.GetReg(), 0, 16); + return NewLIR4(kThumb2Ubfx, r_dest_src1, r_src2, 0, 16); default: LOG(FATAL) << "Bad opcode: " << op; break; } DCHECK(!IsPseudoLirOp(opcode)); if (EncodingMap[opcode].flags & IS_BINARY_OP) { - return NewLIR2(opcode, r_dest_src1.GetReg(), r_src2.GetReg()); + return NewLIR2(opcode, r_dest_src1, r_src2); } else if (EncodingMap[opcode].flags & IS_TERTIARY_OP) { if (EncodingMap[opcode].field_loc[2].kind == kFmtShift) { - return NewLIR3(opcode, r_dest_src1.GetReg(), r_src2.GetReg(), shift); + return NewLIR3(opcode, r_dest_src1, r_src2, shift); } else { - return NewLIR3(opcode, r_dest_src1.GetReg(), r_dest_src1.GetReg(), r_src2.GetReg()); + return NewLIR3(opcode, r_dest_src1, r_dest_src1, r_src2); } } else if (EncodingMap[opcode].flags & IS_QUAD_OP) { - return NewLIR4(opcode, r_dest_src1.GetReg(), r_dest_src1.GetReg(), r_src2.GetReg(), shift); + return NewLIR4(opcode, r_dest_src1, r_dest_src1, r_src2, shift); } else { LOG(FATAL) << "Unexpected encoding operand count"; return NULL; @@ -368,7 +367,7 @@ LIR* ArmMir2Lir::OpRegRegShift(OpKind op, RegStorage r_dest_src1, RegStorage r_s } LIR* ArmMir2Lir::OpRegReg(OpKind op, RegStorage r_dest_src1, RegStorage r_src2) { - return OpRegRegShift(op, r_dest_src1, r_src2, 0); + return OpRegRegShift(op, r_dest_src1.GetReg(), r_src2.GetReg(), 0); } LIR* ArmMir2Lir::OpMovRegMem(RegStorage r_dest, RegStorage r_base, int offset, MoveType move_type) { @@ -386,11 +385,11 @@ LIR* ArmMir2Lir::OpCondRegReg(OpKind op, ConditionCode cc, RegStorage r_dest, Re return NULL; } -LIR* ArmMir2Lir::OpRegRegRegShift(OpKind op, RegStorage r_dest, RegStorage r_src1, - RegStorage r_src2, int shift) { +LIR* ArmMir2Lir::OpRegRegRegShift(OpKind op, int r_dest, int r_src1, + int r_src2, int shift) { ArmOpcode opcode = kThumbBkpt; - bool thumb_form = (shift == 0) && ARM_LOWREG(r_dest.GetReg()) && ARM_LOWREG(r_src1.GetReg()) && - ARM_LOWREG(r_src2.GetReg()); + bool thumb_form = (shift == 0) && ARM_LOWREG(r_dest) && ARM_LOWREG(r_src1) && + ARM_LOWREG(r_src2); switch (op) { case kOpAdd: opcode = (thumb_form) ? kThumbAddRRR : kThumb2AddRRR; @@ -449,15 +448,15 @@ LIR* ArmMir2Lir::OpRegRegRegShift(OpKind op, RegStorage r_dest, RegStorage r_src } DCHECK(!IsPseudoLirOp(opcode)); if (EncodingMap[opcode].flags & IS_QUAD_OP) { - return NewLIR4(opcode, r_dest.GetReg(), r_src1.GetReg(), r_src2.GetReg(), shift); + return NewLIR4(opcode, r_dest, r_src1, r_src2, shift); } else { DCHECK(EncodingMap[opcode].flags & IS_TERTIARY_OP); - return NewLIR3(opcode, r_dest.GetReg(), r_src1.GetReg(), r_src2.GetReg()); + return NewLIR3(opcode, r_dest, r_src1, r_src2); } } LIR* ArmMir2Lir::OpRegRegReg(OpKind op, RegStorage r_dest, RegStorage r_src1, RegStorage r_src2) { - return OpRegRegRegShift(op, r_dest, r_src1, r_src2, 0); + return OpRegRegRegShift(op, r_dest.GetReg(), r_src1.GetReg(), r_src2.GetReg(), 0); } LIR* ArmMir2Lir::OpRegRegImm(OpKind op, RegStorage r_dest, RegStorage r_src1, int value) { diff --git a/compiler/dex/quick/gen_common.cc b/compiler/dex/quick/gen_common.cc index b23e10f288..2afa5ca815 100644 --- a/compiler/dex/quick/gen_common.cc +++ b/compiler/dex/quick/gen_common.cc @@ -1626,31 +1626,14 @@ bool Mir2Lir::HandleEasyDivRem(Instruction::Code dalvik_opcode, bool is_div, // Returns true if it added instructions to 'cu' to multiply 'rl_src' by 'lit' // and store the result in 'rl_dest'. bool Mir2Lir::HandleEasyMultiply(RegLocation rl_src, RegLocation rl_dest, int lit) { - if (lit < 0) { - return false; - } - if (lit == 0) { - RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true); - LoadConstant(rl_result.reg, 0); - StoreValue(rl_dest, rl_result); - return true; - } - if (lit == 1) { - rl_src = LoadValue(rl_src, kCoreReg); - RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true); - OpRegCopy(rl_result.reg, rl_src.reg); - StoreValue(rl_dest, rl_result); - return true; - } - // There is RegRegRegShift on Arm, so check for more special cases - if (cu_->instruction_set == kThumb2) { - return EasyMultiply(rl_src, rl_dest, lit); - } // Can we simplify this multiplication? bool power_of_two = false; bool pop_count_le2 = false; bool power_of_two_minus_one = false; - if (IsPowerOfTwo(lit)) { + if (lit < 2) { + // Avoid special cases. + return false; + } else if (IsPowerOfTwo(lit)) { power_of_two = true; } else if (IsPopCountLE2(lit)) { pop_count_le2 = true; diff --git a/compiler/dex/quick/mips/codegen_mips.h b/compiler/dex/quick/mips/codegen_mips.h index 0ef43b3197..bc1ad02ce8 100644 --- a/compiler/dex/quick/mips/codegen_mips.h +++ b/compiler/dex/quick/mips/codegen_mips.h @@ -22,14 +22,13 @@ namespace art { -class MipsMir2Lir FINAL : public Mir2Lir { +class MipsMir2Lir : public Mir2Lir { public: MipsMir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena); // Required for target - codegen utilities. bool SmallLiteralDivRem(Instruction::Code dalvik_opcode, bool is_div, RegLocation rl_src, RegLocation rl_dest, int lit); - bool EasyMultiply(RegLocation rl_src, RegLocation rl_dest, int lit) OVERRIDE; LIR* CheckSuspendUsingLoad() OVERRIDE; RegStorage LoadHelper(ThreadOffset offset); LIR* LoadBaseDisp(int r_base, int displacement, int r_dest, OpSize size, int s_reg); diff --git a/compiler/dex/quick/mips/int_mips.cc b/compiler/dex/quick/mips/int_mips.cc index 270d895194..dfe8b35277 100644 --- a/compiler/dex/quick/mips/int_mips.cc +++ b/compiler/dex/quick/mips/int_mips.cc @@ -368,11 +368,6 @@ bool MipsMir2Lir::SmallLiteralDivRem(Instruction::Code dalvik_opcode, bool is_di return false; } -bool MipsMir2Lir::EasyMultiply(RegLocation rl_src, RegLocation rl_dest, int lit) { - LOG(FATAL) << "Unexpected use of easyMultiply in Mips"; - return false; -} - LIR* MipsMir2Lir::OpIT(ConditionCode cond, const char* guide) { LOG(FATAL) << "Unexpected use of OpIT in Mips"; return NULL; diff --git a/compiler/dex/quick/mir_to_lir.h b/compiler/dex/quick/mir_to_lir.h index 946adc5e8a..8614151698 100644 --- a/compiler/dex/quick/mir_to_lir.h +++ b/compiler/dex/quick/mir_to_lir.h @@ -131,7 +131,6 @@ struct UseDefMasks { struct AssemblyInfo { LIR* pcrel_next; // Chain of LIR nodes needing pc relative fixups. - uint8_t bytes[16]; // Encoded instruction bytes. }; struct LIR { @@ -151,7 +150,7 @@ struct LIR { } flags; union { UseDefMasks m; // Use & Def masks used during optimization. - AssemblyInfo a; // Instruction encoding used during assembly phase. + AssemblyInfo a; // Instruction info used during assembly phase. } u; int32_t operands[5]; // [0..4] = [dest, src1, src2, extra, extra2]. }; @@ -340,7 +339,7 @@ class Mir2Lir : public Backend { return code_buffer_.size() / sizeof(code_buffer_[0]); } - bool IsPseudoLirOp(int opcode) { + static bool IsPseudoLirOp(int opcode) { return (opcode < 0); } @@ -811,7 +810,6 @@ class Mir2Lir : public Backend { // Required for target - codegen helpers. virtual bool SmallLiteralDivRem(Instruction::Code dalvik_opcode, bool is_div, RegLocation rl_src, RegLocation rl_dest, int lit) = 0; - virtual bool EasyMultiply(RegLocation rl_src, RegLocation rl_dest, int lit) = 0; virtual LIR* CheckSuspendUsingLoad() = 0; virtual RegStorage LoadHelper(ThreadOffset offset) = 0; virtual LIR* LoadBaseDisp(RegStorage r_base, int displacement, RegStorage r_dest, OpSize size, diff --git a/compiler/dex/quick/ralloc_util.cc b/compiler/dex/quick/ralloc_util.cc index 137d5eb61e..39783a21ea 100644 --- a/compiler/dex/quick/ralloc_util.cc +++ b/compiler/dex/quick/ralloc_util.cc @@ -743,11 +743,15 @@ void Mir2Lir::MarkInUse(RegStorage reg) { void Mir2Lir::CopyRegInfo(int new_reg, int old_reg) { RegisterInfo* new_info = GetRegInfo(new_reg); RegisterInfo* old_info = GetRegInfo(old_reg); - // Target temp status must not change + // Target temp, live, dirty status must not change bool is_temp = new_info->is_temp; + bool live = new_info->live; + bool dirty = new_info->dirty; *new_info = *old_info; - // Restore target's temp status + // Restore target's temp, live, dirty status new_info->is_temp = is_temp; + new_info->live = live; + new_info->dirty = dirty; new_info->reg = new_reg; } diff --git a/compiler/dex/quick/x86/codegen_x86.h b/compiler/dex/quick/x86/codegen_x86.h index 4c495a16c9..6d427e7bcf 100644 --- a/compiler/dex/quick/x86/codegen_x86.h +++ b/compiler/dex/quick/x86/codegen_x86.h @@ -22,14 +22,13 @@ namespace art { -class X86Mir2Lir FINAL : public Mir2Lir { +class X86Mir2Lir : public Mir2Lir { public: X86Mir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena); // Required for target - codegen helpers. bool SmallLiteralDivRem(Instruction::Code dalvik_opcode, bool is_div, RegLocation rl_src, RegLocation rl_dest, int lit); - bool EasyMultiply(RegLocation rl_src, RegLocation rl_dest, int lit) OVERRIDE; LIR* CheckSuspendUsingLoad() OVERRIDE; RegStorage LoadHelper(ThreadOffset offset); LIR* LoadBaseDisp(RegStorage r_base, int displacement, RegStorage r_dest, OpSize size, diff --git a/compiler/dex/quick/x86/int_x86.cc b/compiler/dex/quick/x86/int_x86.cc index 5ef7060731..851f4481a6 100644 --- a/compiler/dex/quick/x86/int_x86.cc +++ b/compiler/dex/quick/x86/int_x86.cc @@ -909,11 +909,6 @@ bool X86Mir2Lir::SmallLiteralDivRem(Instruction::Code dalvik_opcode, bool is_div return false; } -bool X86Mir2Lir::EasyMultiply(RegLocation rl_src, RegLocation rl_dest, int lit) { - LOG(FATAL) << "Unexpected use of easyMultiply in x86"; - return false; -} - LIR* X86Mir2Lir::OpIT(ConditionCode cond, const char* guide) { LOG(FATAL) << "Unexpected use of OpIT in x86"; return NULL; @@ -1184,10 +1179,14 @@ void X86Mir2Lir::GenLongArith(RegLocation rl_dest, RegLocation rl_src, Instructi LIR *lir = NewLIR3(x86op, r_base, displacement + LOWORD_OFFSET, rl_src.reg.GetLowReg()); AnnotateDalvikRegAccess(lir, (displacement + LOWORD_OFFSET) >> 2, + true /* is_load */, true /* is64bit */); + AnnotateDalvikRegAccess(lir, (displacement + LOWORD_OFFSET) >> 2, false /* is_load */, true /* is64bit */); x86op = GetOpcode(op, rl_dest, rl_src, true); lir = NewLIR3(x86op, r_base, displacement + HIWORD_OFFSET, rl_src.reg.GetHighReg()); AnnotateDalvikRegAccess(lir, (displacement + HIWORD_OFFSET) >> 2, + true /* is_load */, true /* is64bit */); + AnnotateDalvikRegAccess(lir, (displacement + HIWORD_OFFSET) >> 2, false /* is_load */, true /* is64bit */); FreeTemp(rl_src.reg); } @@ -1684,12 +1683,16 @@ void X86Mir2Lir::GenLongImm(RegLocation rl_dest, RegLocation rl_src, Instruction X86OpCode x86op = GetOpcode(op, rl_dest, false, val_lo); LIR *lir = NewLIR3(x86op, r_base, displacement + LOWORD_OFFSET, val_lo); AnnotateDalvikRegAccess(lir, (displacement + LOWORD_OFFSET) >> 2, + true /* is_load */, true /* is64bit */); + AnnotateDalvikRegAccess(lir, (displacement + LOWORD_OFFSET) >> 2, false /* is_load */, true /* is64bit */); } if (!IsNoOp(op, val_hi)) { X86OpCode x86op = GetOpcode(op, rl_dest, true, val_hi); LIR *lir = NewLIR3(x86op, r_base, displacement + HIWORD_OFFSET, val_hi); AnnotateDalvikRegAccess(lir, (displacement + HIWORD_OFFSET) >> 2, + true /* is_load */, true /* is64bit */); + AnnotateDalvikRegAccess(lir, (displacement + HIWORD_OFFSET) >> 2, false /* is_load */, true /* is64bit */); } return; diff --git a/compiler/dex/quick/x86/utility_x86.cc b/compiler/dex/quick/x86/utility_x86.cc index 013c40b99d..bb5d387bd5 100644 --- a/compiler/dex/quick/x86/utility_x86.cc +++ b/compiler/dex/quick/x86/utility_x86.cc @@ -368,6 +368,7 @@ LIR* X86Mir2Lir::OpMemReg(OpKind op, RegLocation rl_dest, int r_value) { break; } LIR *l = NewLIR3(opcode, rX86_SP, displacement, r_value); + AnnotateDalvikRegAccess(l, displacement >> 2, true /* is_load */, false /* is_64bit */); AnnotateDalvikRegAccess(l, displacement >> 2, false /* is_load */, false /* is_64bit */); return l; } diff --git a/compiler/jni/quick/arm/calling_convention_arm.cc b/compiler/jni/quick/arm/calling_convention_arm.cc index 78f403c2e8..28b438e198 100644 --- a/compiler/jni/quick/arm/calling_convention_arm.cc +++ b/compiler/jni/quick/arm/calling_convention_arm.cc @@ -85,7 +85,7 @@ FrameOffset ArmManagedRuntimeCallingConvention::CurrentParamStackOffset() { return result; } -const std::vector<ManagedRegister>& ArmManagedRuntimeCallingConvention::EntrySpills() { +const ManagedRegisterEntrySpills& ArmManagedRuntimeCallingConvention::EntrySpills() { // We spill the argument registers on ARM to free them up for scratch use, we then assume // all arguments are on the stack. if (entry_spills_.size() == 0) { diff --git a/compiler/jni/quick/arm/calling_convention_arm.h b/compiler/jni/quick/arm/calling_convention_arm.h index fc2d8570fe..96bbb7e94f 100644 --- a/compiler/jni/quick/arm/calling_convention_arm.h +++ b/compiler/jni/quick/arm/calling_convention_arm.h @@ -36,10 +36,10 @@ class ArmManagedRuntimeCallingConvention FINAL : public ManagedRuntimeCallingCon bool IsCurrentParamOnStack() OVERRIDE; ManagedRegister CurrentParamRegister() OVERRIDE; FrameOffset CurrentParamStackOffset() OVERRIDE; - const std::vector<ManagedRegister>& EntrySpills() OVERRIDE; + const ManagedRegisterEntrySpills& EntrySpills() OVERRIDE; private: - std::vector<ManagedRegister> entry_spills_; + ManagedRegisterEntrySpills entry_spills_; DISALLOW_COPY_AND_ASSIGN(ArmManagedRuntimeCallingConvention); }; diff --git a/compiler/jni/quick/arm64/calling_convention_arm64.cc b/compiler/jni/quick/arm64/calling_convention_arm64.cc index c4d0d451c0..ff899b75e9 100644 --- a/compiler/jni/quick/arm64/calling_convention_arm64.cc +++ b/compiler/jni/quick/arm64/calling_convention_arm64.cc @@ -85,7 +85,7 @@ FrameOffset Arm64ManagedRuntimeCallingConvention::CurrentParamStackOffset() { return result; } -const std::vector<ManagedRegister>& Arm64ManagedRuntimeCallingConvention::EntrySpills() { +const ManagedRegisterEntrySpills& Arm64ManagedRuntimeCallingConvention::EntrySpills() { // We spill the argument registers on ARM64 to free them up for scratch use, we then assume // all arguments are on the stack. if (entry_spills_.size() == 0) { diff --git a/compiler/jni/quick/arm64/calling_convention_arm64.h b/compiler/jni/quick/arm64/calling_convention_arm64.h index 2dcf1af71c..7e3383065d 100644 --- a/compiler/jni/quick/arm64/calling_convention_arm64.h +++ b/compiler/jni/quick/arm64/calling_convention_arm64.h @@ -36,10 +36,10 @@ class Arm64ManagedRuntimeCallingConvention FINAL : public ManagedRuntimeCallingC bool IsCurrentParamOnStack() OVERRIDE; ManagedRegister CurrentParamRegister() OVERRIDE; FrameOffset CurrentParamStackOffset() OVERRIDE; - const std::vector<ManagedRegister>& EntrySpills() OVERRIDE; + const ManagedRegisterEntrySpills& EntrySpills() OVERRIDE; private: - std::vector<ManagedRegister> entry_spills_; + ManagedRegisterEntrySpills entry_spills_; DISALLOW_COPY_AND_ASSIGN(Arm64ManagedRuntimeCallingConvention); }; diff --git a/compiler/jni/quick/calling_convention.cc b/compiler/jni/quick/calling_convention.cc index 5856df4bc1..043bceae17 100644 --- a/compiler/jni/quick/calling_convention.cc +++ b/compiler/jni/quick/calling_convention.cc @@ -21,6 +21,7 @@ #include "jni/quick/arm64/calling_convention_arm64.h" #include "jni/quick/mips/calling_convention_mips.h" #include "jni/quick/x86/calling_convention_x86.h" +#include "jni/quick/x86_64/calling_convention_x86_64.h" #include "utils.h" namespace art { @@ -44,6 +45,8 @@ ManagedRuntimeCallingConvention* ManagedRuntimeCallingConvention::Create( return new mips::MipsManagedRuntimeCallingConvention(is_static, is_synchronized, shorty); case kX86: return new x86::X86ManagedRuntimeCallingConvention(is_static, is_synchronized, shorty); + case kX86_64: + return new x86_64::X86_64ManagedRuntimeCallingConvention(is_static, is_synchronized, shorty); default: LOG(FATAL) << "Unknown InstructionSet: " << instruction_set; return NULL; @@ -61,6 +64,9 @@ void ManagedRuntimeCallingConvention::Next() { itr_longs_and_doubles_++; itr_slots_++; } + if (IsParamAFloatOrDouble(itr_args_)) { + itr_float_and_doubles_++; + } if (IsCurrentParamAReference()) { itr_refs_++; } @@ -85,6 +91,10 @@ bool ManagedRuntimeCallingConvention::IsCurrentParamAReference() { return IsParamAReference(itr_args_); } +bool ManagedRuntimeCallingConvention::IsCurrentParamAFloatOrDouble() { + return IsParamAFloatOrDouble(itr_args_); +} + // JNI calling convention JniCallingConvention* JniCallingConvention::Create(bool is_static, bool is_synchronized, @@ -100,6 +110,8 @@ JniCallingConvention* JniCallingConvention::Create(bool is_static, bool is_synch return new mips::MipsJniCallingConvention(is_static, is_synchronized, shorty); case kX86: return new x86::X86JniCallingConvention(is_static, is_synchronized, shorty); + case kX86_64: + return new x86_64::X86_64JniCallingConvention(is_static, is_synchronized, shorty); default: LOG(FATAL) << "Unknown InstructionSet: " << instruction_set; return NULL; @@ -111,9 +123,8 @@ size_t JniCallingConvention::ReferenceCount() const { } FrameOffset JniCallingConvention::SavedLocalReferenceCookieOffset() const { - size_t start_of_sirt = SirtNumRefsOffset().Int32Value() + kPointerSize; - size_t references_size = kPointerSize * ReferenceCount(); // size excluding header - return FrameOffset(start_of_sirt + references_size); + size_t references_size = kSirtPointerSize * ReferenceCount(); // size excluding header + return FrameOffset(SirtReferencesOffset().Int32Value() + references_size); } FrameOffset JniCallingConvention::ReturnValueSaveLocation() const { @@ -139,6 +150,9 @@ void JniCallingConvention::Next() { itr_slots_++; } } + if (IsCurrentParamAFloatOrDouble()) { + itr_float_and_doubles_++; + } if (IsCurrentParamAReference()) { itr_refs_++; } @@ -159,14 +173,25 @@ bool JniCallingConvention::IsCurrentParamAReference() { } } +bool JniCallingConvention::IsCurrentParamAFloatOrDouble() { + switch (itr_args_) { + case kJniEnv: + return false; // JNIEnv* + case kObjectOrClass: + return false; // jobject or jclass + default: { + int arg_pos = itr_args_ - NumberOfExtraArgumentsForJni(); + return IsParamAFloatOrDouble(arg_pos); + } + } +} + // Return position of SIRT entry holding reference at the current iterator // position FrameOffset JniCallingConvention::CurrentParamSirtEntryOffset() { CHECK(IsCurrentParamAReference()); CHECK_LT(SirtLinkOffset(), SirtNumRefsOffset()); - // Address of 1st SIRT entry - int result = SirtNumRefsOffset().Int32Value() + kPointerSize; - result += itr_refs_ * kPointerSize; + int result = SirtReferencesOffset().Int32Value() + itr_refs_ * kSirtPointerSize; CHECK_GT(result, SirtNumRefsOffset().Int32Value()); return FrameOffset(result); } diff --git a/compiler/jni/quick/calling_convention.h b/compiler/jni/quick/calling_convention.h index f2b7fd9a4a..fe3d1cd551 100644 --- a/compiler/jni/quick/calling_convention.h +++ b/compiler/jni/quick/calling_convention.h @@ -60,23 +60,35 @@ class CallingConvention { itr_args_ = 0; itr_refs_ = 0; itr_longs_and_doubles_ = 0; + itr_float_and_doubles_ = 0; } virtual ~CallingConvention() {} protected: CallingConvention(bool is_static, bool is_synchronized, const char* shorty) - : displacement_(0), is_static_(is_static), is_synchronized_(is_synchronized), + : displacement_(0), kSirtPointerSize(sizeof(StackReference<mirror::Object>)), is_static_(is_static), is_synchronized_(is_synchronized), shorty_(shorty) { num_args_ = (is_static ? 0 : 1) + strlen(shorty) - 1; num_ref_args_ = is_static ? 0 : 1; // The implicit this pointer. + num_float_or_double_args_ = 0; num_long_or_double_args_ = 0; for (size_t i = 1; i < strlen(shorty); i++) { char ch = shorty_[i]; - if (ch == 'L') { + switch (ch) { + case 'L': num_ref_args_++; - } else if ((ch == 'D') || (ch == 'J')) { + break; + case 'J': num_long_or_double_args_++; + break; + case 'D': + num_long_or_double_args_++; + num_float_or_double_args_++; + break; + case 'F': + num_float_or_double_args_++; + break; } } } @@ -97,6 +109,16 @@ class CallingConvention { char ch = shorty_[param]; return (ch == 'J' || ch == 'D'); } + bool IsParamAFloatOrDouble(unsigned int param) const { + DCHECK_LT(param, NumArgs()); + if (IsStatic()) { + param++; // 0th argument must skip return value at start of the shorty + } else if (param == 0) { + return false; // this argument + } + char ch = shorty_[param]; + return (ch == 'F' || ch == 'D'); + } bool IsParamAReference(unsigned int param) const { DCHECK_LT(param, NumArgs()); if (IsStatic()) { @@ -112,6 +134,9 @@ class CallingConvention { size_t NumLongOrDoubleArgs() const { return num_long_or_double_args_; } + size_t NumFloatOrDoubleArgs() const { + return num_float_or_double_args_; + } size_t NumReferenceArgs() const { return num_ref_args_; } @@ -141,8 +166,11 @@ class CallingConvention { unsigned int itr_args_; // Number of longs and doubles seen along argument list unsigned int itr_longs_and_doubles_; + // Number of float and doubles seen along argument list + unsigned int itr_float_and_doubles_; // Space for frames below this on the stack FrameOffset displacement_; + size_t kSirtPointerSize; private: const bool is_static_; @@ -150,6 +178,7 @@ class CallingConvention { std::string shorty_; size_t num_args_; size_t num_ref_args_; + size_t num_float_or_double_args_; size_t num_long_or_double_args_; }; @@ -174,6 +203,7 @@ class ManagedRuntimeCallingConvention : public CallingConvention { bool HasNext(); void Next(); bool IsCurrentParamAReference(); + bool IsCurrentParamAFloatOrDouble(); bool IsCurrentArgExplicit(); // ie a non-implict argument such as this bool IsCurrentArgPossiblyNull(); size_t CurrentParamSize(); @@ -185,7 +215,7 @@ class ManagedRuntimeCallingConvention : public CallingConvention { virtual ~ManagedRuntimeCallingConvention() {} // Registers to spill to caller's out registers on entry. - virtual const std::vector<ManagedRegister>& EntrySpills() = 0; + virtual const ManagedRegisterEntrySpills& EntrySpills() = 0; protected: ManagedRuntimeCallingConvention(bool is_static, bool is_synchronized, const char* shorty) @@ -241,6 +271,7 @@ class JniCallingConvention : public CallingConvention { bool HasNext(); virtual void Next(); bool IsCurrentParamAReference(); + bool IsCurrentParamAFloatOrDouble(); size_t CurrentParamSize(); virtual bool IsCurrentParamInRegister() = 0; virtual bool IsCurrentParamOnStack() = 0; @@ -255,13 +286,21 @@ class JniCallingConvention : public CallingConvention { return FrameOffset(displacement_.Int32Value() + kPointerSize); // above Method* } + + FrameOffset SirtLinkOffset() const { + return FrameOffset(SirtOffset().Int32Value() + + StackIndirectReferenceTable::LinkOffset()); + } + FrameOffset SirtNumRefsOffset() const { return FrameOffset(SirtOffset().Int32Value() + StackIndirectReferenceTable::NumberOfReferencesOffset()); } - FrameOffset SirtLinkOffset() const { - return FrameOffset(SirtOffset().Int32Value() + - StackIndirectReferenceTable::LinkOffset()); + + FrameOffset SirtReferencesOffset() const { + // The StackIndirectReferenceTable::number_of_references_ type is uint32_t + return FrameOffset(SirtNumRefsOffset().Int32Value() + + sizeof(uint32_t)); } virtual ~JniCallingConvention() {} diff --git a/compiler/jni/quick/jni_compiler.cc b/compiler/jni/quick/jni_compiler.cc index 1c9aed83c3..c89bc40fda 100644 --- a/compiler/jni/quick/jni_compiler.cc +++ b/compiler/jni/quick/jni_compiler.cc @@ -271,7 +271,7 @@ CompiledMethod* ArtJniCompileMethodInternal(CompilerDriver& compiler, mr_conv->InterproceduralScratchRegister()); // 10. Fix differences in result widths. - if (instruction_set == kX86) { + if (instruction_set == kX86 || instruction_set == kX86_64) { if (main_jni_conv->GetReturnType() == Primitive::kPrimByte || main_jni_conv->GetReturnType() == Primitive::kPrimShort) { __ SignExtend(main_jni_conv->ReturnRegister(), diff --git a/compiler/jni/quick/mips/calling_convention_mips.cc b/compiler/jni/quick/mips/calling_convention_mips.cc index 0a48500380..ea39d6009c 100644 --- a/compiler/jni/quick/mips/calling_convention_mips.cc +++ b/compiler/jni/quick/mips/calling_convention_mips.cc @@ -85,7 +85,7 @@ FrameOffset MipsManagedRuntimeCallingConvention::CurrentParamStackOffset() { return result; } -const std::vector<ManagedRegister>& MipsManagedRuntimeCallingConvention::EntrySpills() { +const ManagedRegisterEntrySpills& MipsManagedRuntimeCallingConvention::EntrySpills() { // We spill the argument registers on MIPS to free them up for scratch use, we then assume // all arguments are on the stack. if (entry_spills_.size() == 0) { diff --git a/compiler/jni/quick/mips/calling_convention_mips.h b/compiler/jni/quick/mips/calling_convention_mips.h index 445f453943..1a9053a9dd 100644 --- a/compiler/jni/quick/mips/calling_convention_mips.h +++ b/compiler/jni/quick/mips/calling_convention_mips.h @@ -35,10 +35,10 @@ class MipsManagedRuntimeCallingConvention FINAL : public ManagedRuntimeCallingCo bool IsCurrentParamOnStack() OVERRIDE; ManagedRegister CurrentParamRegister() OVERRIDE; FrameOffset CurrentParamStackOffset() OVERRIDE; - const std::vector<ManagedRegister>& EntrySpills() OVERRIDE; + const ManagedRegisterEntrySpills& EntrySpills() OVERRIDE; private: - std::vector<ManagedRegister> entry_spills_; + ManagedRegisterEntrySpills entry_spills_; DISALLOW_COPY_AND_ASSIGN(MipsManagedRuntimeCallingConvention); }; diff --git a/compiler/jni/quick/x86/calling_convention_x86.cc b/compiler/jni/quick/x86/calling_convention_x86.cc index 8b5c86d683..8d22fe6632 100644 --- a/compiler/jni/quick/x86/calling_convention_x86.cc +++ b/compiler/jni/quick/x86/calling_convention_x86.cc @@ -90,7 +90,7 @@ FrameOffset X86ManagedRuntimeCallingConvention::CurrentParamStackOffset() { (itr_slots_ * kPointerSize)); // offset into in args } -const std::vector<ManagedRegister>& X86ManagedRuntimeCallingConvention::EntrySpills() { +const ManagedRegisterEntrySpills& X86ManagedRuntimeCallingConvention::EntrySpills() { // We spill the argument registers on X86 to free them up for scratch use, we then assume // all arguments are on the stack. if (entry_spills_.size() == 0) { diff --git a/compiler/jni/quick/x86/calling_convention_x86.h b/compiler/jni/quick/x86/calling_convention_x86.h index e814c7e531..2dab059919 100644 --- a/compiler/jni/quick/x86/calling_convention_x86.h +++ b/compiler/jni/quick/x86/calling_convention_x86.h @@ -37,9 +37,9 @@ class X86ManagedRuntimeCallingConvention FINAL : public ManagedRuntimeCallingCon bool IsCurrentParamOnStack() OVERRIDE; ManagedRegister CurrentParamRegister() OVERRIDE; FrameOffset CurrentParamStackOffset() OVERRIDE; - const std::vector<ManagedRegister>& EntrySpills() OVERRIDE; + const ManagedRegisterEntrySpills& EntrySpills() OVERRIDE; private: - std::vector<ManagedRegister> entry_spills_; + ManagedRegisterEntrySpills entry_spills_; DISALLOW_COPY_AND_ASSIGN(X86ManagedRuntimeCallingConvention); }; diff --git a/compiler/jni/quick/x86_64/calling_convention_x86_64.cc b/compiler/jni/quick/x86_64/calling_convention_x86_64.cc new file mode 100644 index 0000000000..8ebea4630e --- /dev/null +++ b/compiler/jni/quick/x86_64/calling_convention_x86_64.cc @@ -0,0 +1,203 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "calling_convention_x86_64.h" + +#include "base/logging.h" +#include "utils/x86_64/managed_register_x86_64.h" +#include "utils.h" + +namespace art { +namespace x86_64 { + +// Calling convention + +ManagedRegister X86_64ManagedRuntimeCallingConvention::InterproceduralScratchRegister() { + return X86_64ManagedRegister::FromCpuRegister(RAX); +} + +ManagedRegister X86_64JniCallingConvention::InterproceduralScratchRegister() { + return X86_64ManagedRegister::FromCpuRegister(RAX); +} + +ManagedRegister X86_64JniCallingConvention::ReturnScratchRegister() const { + return ManagedRegister::NoRegister(); // No free regs, so assembler uses push/pop +} + +static ManagedRegister ReturnRegisterForShorty(const char* shorty, bool jni) { + if (shorty[0] == 'F' || shorty[0] == 'D') { + return X86_64ManagedRegister::FromXmmRegister(_XMM0); + } else if (shorty[0] == 'J') { + return X86_64ManagedRegister::FromCpuRegister(RAX); + } else if (shorty[0] == 'V') { + return ManagedRegister::NoRegister(); + } else { + return X86_64ManagedRegister::FromCpuRegister(RAX); + } +} + +ManagedRegister X86_64ManagedRuntimeCallingConvention::ReturnRegister() { + return ReturnRegisterForShorty(GetShorty(), false); +} + +ManagedRegister X86_64JniCallingConvention::ReturnRegister() { + return ReturnRegisterForShorty(GetShorty(), true); +} + +ManagedRegister X86_64JniCallingConvention::IntReturnRegister() { + return X86_64ManagedRegister::FromCpuRegister(RAX); +} + +// Managed runtime calling convention + +ManagedRegister X86_64ManagedRuntimeCallingConvention::MethodRegister() { + return X86_64ManagedRegister::FromCpuRegister(RDI); +} + +bool X86_64ManagedRuntimeCallingConvention::IsCurrentParamInRegister() { + return !IsCurrentParamOnStack(); +} + +bool X86_64ManagedRuntimeCallingConvention::IsCurrentParamOnStack() { + // We assume all parameters are on stack, args coming via registers are spilled as entry_spills + return true; +} + +ManagedRegister X86_64ManagedRuntimeCallingConvention::CurrentParamRegister() { + ManagedRegister res = ManagedRegister::NoRegister(); + if (!IsCurrentParamAFloatOrDouble()) { + switch (itr_args_ - itr_float_and_doubles_) { + case 0: res = X86_64ManagedRegister::FromCpuRegister(RSI); break; + case 1: res = X86_64ManagedRegister::FromCpuRegister(RDX); break; + case 2: res = X86_64ManagedRegister::FromCpuRegister(RCX); break; + case 3: res = X86_64ManagedRegister::FromCpuRegister(R8); break; + case 4: res = X86_64ManagedRegister::FromCpuRegister(R9); break; + } + } else if (itr_float_and_doubles_ < 8) { + // First eight float parameters are passed via XMM0..XMM7 + res = X86_64ManagedRegister::FromXmmRegister( + static_cast<XmmRegister>(_XMM0 + itr_float_and_doubles_)); + } + return res; +} + +FrameOffset X86_64ManagedRuntimeCallingConvention::CurrentParamStackOffset() { + return FrameOffset(displacement_.Int32Value() + // displacement + kPointerSize + // Method* + (itr_slots_ * sizeof(uint32_t))); // offset into in args +} + +const ManagedRegisterEntrySpills& X86_64ManagedRuntimeCallingConvention::EntrySpills() { + // We spill the argument registers on X86 to free them up for scratch use, we then assume + // all arguments are on the stack. + if (entry_spills_.size() == 0) { + ResetIterator(FrameOffset(0)); + while (HasNext()) { + ManagedRegister in_reg = CurrentParamRegister(); + if (!in_reg.IsNoRegister()) { + int32_t size = IsParamALongOrDouble(itr_args_)? 8 : 4; + int32_t spill_offset = CurrentParamStackOffset().Uint32Value(); + ManagedRegisterSpill spill(in_reg, size, spill_offset); + entry_spills_.push_back(spill); + } + Next(); + } + } + return entry_spills_; +} + +// JNI calling convention + +X86_64JniCallingConvention::X86_64JniCallingConvention(bool is_static, bool is_synchronized, + const char* shorty) + : JniCallingConvention(is_static, is_synchronized, shorty) { + callee_save_regs_.push_back(X86_64ManagedRegister::FromCpuRegister(RBX)); + callee_save_regs_.push_back(X86_64ManagedRegister::FromCpuRegister(RBP)); + callee_save_regs_.push_back(X86_64ManagedRegister::FromCpuRegister(R12)); + callee_save_regs_.push_back(X86_64ManagedRegister::FromCpuRegister(R13)); + callee_save_regs_.push_back(X86_64ManagedRegister::FromCpuRegister(R14)); + callee_save_regs_.push_back(X86_64ManagedRegister::FromCpuRegister(R15)); +} + +uint32_t X86_64JniCallingConvention::CoreSpillMask() const { + return 1 << RBX | 1 << RBP | 1 << R12 | 1 << R13 | 1 << R14 | 1 << R15 | 1 << R13 | 1 << kNumberOfCpuRegisters; +} + +size_t X86_64JniCallingConvention::FrameSize() { + // Method*, return address and callee save area size, local reference segment state + size_t frame_data_size = (3 + CalleeSaveRegisters().size()) * kPointerSize; + // References plus link_ (pointer) and number_of_references_ (uint32_t) for SIRT header + size_t sirt_size = kPointerSize + sizeof(uint32_t) + ReferenceCount()*kSirtPointerSize; + // Plus return value spill area size + return RoundUp(frame_data_size + sirt_size + SizeOfReturnValue(), kStackAlignment); +} + +size_t X86_64JniCallingConvention::OutArgSize() { + return RoundUp(NumberOfOutgoingStackArgs() * kPointerSize, kStackAlignment); +} + +bool X86_64JniCallingConvention::IsCurrentParamInRegister() { + return !IsCurrentParamOnStack(); +} + +bool X86_64JniCallingConvention::IsCurrentParamOnStack() { + return CurrentParamRegister().IsNoRegister(); +} + +ManagedRegister X86_64JniCallingConvention::CurrentParamRegister() { + ManagedRegister res = ManagedRegister::NoRegister(); + if (!IsCurrentParamAFloatOrDouble()) { + switch (itr_args_ - itr_float_and_doubles_) { + case 0: res = X86_64ManagedRegister::FromCpuRegister(RDI); break; + case 1: res = X86_64ManagedRegister::FromCpuRegister(RSI); break; + case 2: res = X86_64ManagedRegister::FromCpuRegister(RDX); break; + case 3: res = X86_64ManagedRegister::FromCpuRegister(RCX); break; + case 4: res = X86_64ManagedRegister::FromCpuRegister(R8); break; + case 5: res = X86_64ManagedRegister::FromCpuRegister(R9); break; + } + } else if (itr_float_and_doubles_ < 8) { + // First eight float parameters are passed via XMM0..XMM7 + res = X86_64ManagedRegister::FromXmmRegister( + static_cast<XmmRegister>(_XMM0 + itr_float_and_doubles_)); + } + return res; +} + +FrameOffset X86_64JniCallingConvention::CurrentParamStackOffset() { + size_t offset = itr_args_ + - std::min(8U, itr_float_and_doubles_) // Float arguments passed through Xmm0..Xmm7 + - std::min(6U, itr_args_ - itr_float_and_doubles_); // Integer arguments passed through GPR + return FrameOffset(displacement_.Int32Value() - OutArgSize() + (offset * kPointerSize)); +} + +size_t X86_64JniCallingConvention::NumberOfOutgoingStackArgs() { + size_t static_args = IsStatic() ? 1 : 0; // count jclass + // regular argument parameters and this + size_t param_args = NumArgs() + NumLongOrDoubleArgs(); + // count JNIEnv* and return pc (pushed after Method*) + size_t total_args = static_args + param_args + 2; + + // Float arguments passed through Xmm0..Xmm7 + // Other (integer) arguments passed through GPR (RDI, RSI, RDX, RCX, R8, R9) + size_t total_stack_args = total_args + - std::min(8U, static_cast<unsigned int>(NumFloatOrDoubleArgs())) + - std::min(6U, static_cast<unsigned int>(NumArgs() - NumFloatOrDoubleArgs())); + + return total_stack_args; +} + +} // namespace x86_64 +} // namespace art diff --git a/compiler/jni/quick/x86_64/calling_convention_x86_64.h b/compiler/jni/quick/x86_64/calling_convention_x86_64.h new file mode 100644 index 0000000000..d7f77626c3 --- /dev/null +++ b/compiler/jni/quick/x86_64/calling_convention_x86_64.h @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ART_COMPILER_JNI_QUICK_X86_64_CALLING_CONVENTION_X86_64_H_ +#define ART_COMPILER_JNI_QUICK_X86_64_CALLING_CONVENTION_X86_64_H_ + +#include "jni/quick/calling_convention.h" + +namespace art { +namespace x86_64 { + +class X86_64ManagedRuntimeCallingConvention FINAL : public ManagedRuntimeCallingConvention { + public: + explicit X86_64ManagedRuntimeCallingConvention(bool is_static, bool is_synchronized, + const char* shorty) + : ManagedRuntimeCallingConvention(is_static, is_synchronized, shorty) {} + ~X86_64ManagedRuntimeCallingConvention() OVERRIDE {} + // Calling convention + ManagedRegister ReturnRegister() OVERRIDE; + ManagedRegister InterproceduralScratchRegister() OVERRIDE; + // Managed runtime calling convention + ManagedRegister MethodRegister() OVERRIDE; + bool IsCurrentParamInRegister() OVERRIDE; + bool IsCurrentParamOnStack() OVERRIDE; + ManagedRegister CurrentParamRegister() OVERRIDE; + FrameOffset CurrentParamStackOffset() OVERRIDE; + const ManagedRegisterEntrySpills& EntrySpills() OVERRIDE; + private: + ManagedRegisterEntrySpills entry_spills_; + DISALLOW_COPY_AND_ASSIGN(X86_64ManagedRuntimeCallingConvention); +}; + +class X86_64JniCallingConvention FINAL : public JniCallingConvention { + public: + explicit X86_64JniCallingConvention(bool is_static, bool is_synchronized, const char* shorty); + ~X86_64JniCallingConvention() OVERRIDE {} + // Calling convention + ManagedRegister ReturnRegister() OVERRIDE; + ManagedRegister IntReturnRegister() OVERRIDE; + ManagedRegister InterproceduralScratchRegister() OVERRIDE; + // JNI calling convention + size_t FrameSize() OVERRIDE; + size_t OutArgSize() OVERRIDE; + const std::vector<ManagedRegister>& CalleeSaveRegisters() const OVERRIDE { + return callee_save_regs_; + } + ManagedRegister ReturnScratchRegister() const OVERRIDE; + uint32_t CoreSpillMask() const OVERRIDE; + uint32_t FpSpillMask() const OVERRIDE { + return 0; + } + bool IsCurrentParamInRegister() OVERRIDE; + bool IsCurrentParamOnStack() OVERRIDE; + ManagedRegister CurrentParamRegister() OVERRIDE; + FrameOffset CurrentParamStackOffset() OVERRIDE; + + protected: + size_t NumberOfOutgoingStackArgs() OVERRIDE; + + private: + // TODO: these values aren't unique and can be shared amongst instances + std::vector<ManagedRegister> callee_save_regs_; + + DISALLOW_COPY_AND_ASSIGN(X86_64JniCallingConvention); +}; + +} // namespace x86_64 +} // namespace art + +#endif // ART_COMPILER_JNI_QUICK_X86_64_CALLING_CONVENTION_X86_64_H_ diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc index 39535e953b..64ecdb5c24 100644 --- a/compiler/optimizing/builder.cc +++ b/compiler/optimizing/builder.cc @@ -16,10 +16,12 @@ */ #include "dex_file.h" +#include "dex_file-inl.h" #include "dex_instruction.h" #include "dex_instruction-inl.h" #include "builder.h" #include "nodes.h" +#include "primitive.h" namespace art { @@ -192,6 +194,55 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, int32_ break; } + case Instruction::INVOKE_STATIC: { + uint32_t method_idx = instruction.VRegB_35c(); + const DexFile::MethodId& method_id = dex_file_->GetMethodId(method_idx); + uint32_t return_type_idx = dex_file_->GetProtoId(method_id.proto_idx_).return_type_idx_; + const char* descriptor = dex_file_->StringByTypeIdx(return_type_idx); + const size_t number_of_arguments = instruction.VRegA_35c(); + if (number_of_arguments != 0) { + return false; + } + if (Primitive::GetType(descriptor[0]) != Primitive::kPrimVoid) { + return false; + } + current_block_->AddInstruction(new (arena_) HInvokeStatic( + arena_, number_of_arguments, dex_offset, method_idx)); + break; + } + + case Instruction::ADD_INT: { + HInstruction* first = LoadLocal(instruction.VRegB()); + HInstruction* second = LoadLocal(instruction.VRegC()); + current_block_->AddInstruction(new (arena_) HAdd(Primitive::kPrimInt, first, second)); + UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction()); + break; + } + + case Instruction::ADD_INT_2ADDR: { + HInstruction* first = LoadLocal(instruction.VRegA()); + HInstruction* second = LoadLocal(instruction.VRegB()); + current_block_->AddInstruction(new (arena_) HAdd(Primitive::kPrimInt, first, second)); + UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction()); + break; + } + + case Instruction::ADD_INT_LIT16: { + HInstruction* first = LoadLocal(instruction.VRegB()); + HInstruction* second = GetConstant(instruction.VRegC_22s()); + current_block_->AddInstruction(new (arena_) HAdd(Primitive::kPrimInt, first, second)); + UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction()); + break; + } + + case Instruction::ADD_INT_LIT8: { + HInstruction* first = LoadLocal(instruction.VRegB()); + HInstruction* second = GetConstant(instruction.VRegC_22b()); + current_block_->AddInstruction(new (arena_) HAdd(Primitive::kPrimInt, first, second)); + UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction()); + break; + } + case Instruction::NOP: break; diff --git a/compiler/optimizing/builder.h b/compiler/optimizing/builder.h index fff83a1205..46ca9aabd7 100644 --- a/compiler/optimizing/builder.h +++ b/compiler/optimizing/builder.h @@ -18,6 +18,7 @@ #define ART_COMPILER_OPTIMIZING_BUILDER_H_ #include "dex_file.h" +#include "driver/dex_compilation_unit.h" #include "utils/allocation.h" #include "utils/growable_array.h" @@ -33,7 +34,9 @@ class HLocal; class HGraphBuilder : public ValueObject { public: - explicit HGraphBuilder(ArenaAllocator* arena) + HGraphBuilder(ArenaAllocator* arena, + const DexCompilationUnit* dex_compilation_unit = nullptr, + const DexFile* dex_file = nullptr) : arena_(arena), branch_targets_(arena, 0), locals_(arena, 0), @@ -42,7 +45,9 @@ class HGraphBuilder : public ValueObject { current_block_(nullptr), graph_(nullptr), constant0_(nullptr), - constant1_(nullptr) { } + constant1_(nullptr), + dex_file_(dex_file), + dex_compilation_unit_(dex_compilation_unit) { } HGraph* BuildGraph(const DexFile::CodeItem& code); @@ -83,6 +88,9 @@ class HGraphBuilder : public ValueObject { HIntConstant* constant0_; HIntConstant* constant1_; + const DexFile* const dex_file_; + const DexCompilationUnit* const dex_compilation_unit_; + DISALLOW_COPY_AND_ASSIGN(HGraphBuilder); }; diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc index bb6ac84a9f..b86665b9ee 100644 --- a/compiler/optimizing/code_generator.cc +++ b/compiler/optimizing/code_generator.cc @@ -21,8 +21,11 @@ #include "dex/verified_method.h" #include "driver/dex_compilation_unit.h" #include "gc_map_builder.h" +#include "leb128.h" +#include "mapping_table.h" #include "utils/assembler.h" #include "verifier/dex_gc_map.h" +#include "vmap_table.h" namespace art { @@ -120,8 +123,95 @@ void CodeGenerator::BuildNativeGCMap( dex_compilation_unit.GetVerifiedMethod()->GetDexGcMap(); verifier::DexPcToReferenceMap dex_gc_map(&(gc_map_raw)[0]); - GcMapBuilder builder(data, 0, 0, dex_gc_map.RegWidth()); + uint32_t max_native_offset = 0; + for (size_t i = 0; i < pc_infos_.Size(); i++) { + uint32_t native_offset = pc_infos_.Get(i).native_pc; + if (native_offset > max_native_offset) { + max_native_offset = native_offset; + } + } + + GcMapBuilder builder(data, pc_infos_.Size(), max_native_offset, dex_gc_map.RegWidth()); + for (size_t i = 0; i < pc_infos_.Size(); i++) { + struct PcInfo pc_info = pc_infos_.Get(i); + uint32_t native_offset = pc_info.native_pc; + uint32_t dex_pc = pc_info.dex_pc; + const uint8_t* references = dex_gc_map.FindBitMap(dex_pc, false); + CHECK(references != NULL) << "Missing ref for dex pc 0x" << std::hex << dex_pc; + builder.AddEntry(native_offset, references); + } } +void CodeGenerator::BuildMappingTable(std::vector<uint8_t>* data) const { + uint32_t pc2dex_data_size = 0u; + uint32_t pc2dex_entries = pc_infos_.Size(); + uint32_t pc2dex_offset = 0u; + int32_t pc2dex_dalvik_offset = 0; + uint32_t dex2pc_data_size = 0u; + uint32_t dex2pc_entries = 0u; + + // We currently only have pc2dex entries. + for (size_t i = 0; i < pc2dex_entries; i++) { + struct PcInfo pc_info = pc_infos_.Get(i); + pc2dex_data_size += UnsignedLeb128Size(pc_info.native_pc - pc2dex_offset); + pc2dex_data_size += SignedLeb128Size(pc_info.dex_pc - pc2dex_dalvik_offset); + pc2dex_offset = pc_info.native_pc; + pc2dex_dalvik_offset = pc_info.dex_pc; + } + + uint32_t total_entries = pc2dex_entries + dex2pc_entries; + uint32_t hdr_data_size = UnsignedLeb128Size(total_entries) + UnsignedLeb128Size(pc2dex_entries); + uint32_t data_size = hdr_data_size + pc2dex_data_size + dex2pc_data_size; + data->resize(data_size); + + uint8_t* data_ptr = &(*data)[0]; + uint8_t* write_pos = data_ptr; + write_pos = EncodeUnsignedLeb128(write_pos, total_entries); + write_pos = EncodeUnsignedLeb128(write_pos, pc2dex_entries); + DCHECK_EQ(static_cast<size_t>(write_pos - data_ptr), hdr_data_size); + uint8_t* write_pos2 = write_pos + pc2dex_data_size; + + pc2dex_offset = 0u; + pc2dex_dalvik_offset = 0u; + for (size_t i = 0; i < pc2dex_entries; i++) { + struct PcInfo pc_info = pc_infos_.Get(i); + DCHECK(pc2dex_offset <= pc_info.native_pc); + write_pos = EncodeUnsignedLeb128(write_pos, pc_info.native_pc - pc2dex_offset); + write_pos = EncodeSignedLeb128(write_pos, pc_info.dex_pc - pc2dex_dalvik_offset); + pc2dex_offset = pc_info.native_pc; + pc2dex_dalvik_offset = pc_info.dex_pc; + } + DCHECK_EQ(static_cast<size_t>(write_pos - data_ptr), hdr_data_size + pc2dex_data_size); + DCHECK_EQ(static_cast<size_t>(write_pos2 - data_ptr), data_size); + + if (kIsDebugBuild) { + // Verify the encoded table holds the expected data. + MappingTable table(data_ptr); + CHECK_EQ(table.TotalSize(), total_entries); + CHECK_EQ(table.PcToDexSize(), pc2dex_entries); + auto it = table.PcToDexBegin(); + auto it2 = table.DexToPcBegin(); + for (size_t i = 0; i < pc2dex_entries; i++) { + struct PcInfo pc_info = pc_infos_.Get(i); + CHECK_EQ(pc_info.native_pc, it.NativePcOffset()); + CHECK_EQ(pc_info.dex_pc, it.DexPc()); + ++it; + } + CHECK(it == table.PcToDexEnd()); + CHECK(it2 == table.DexToPcEnd()); + } +} + +void CodeGenerator::BuildVMapTable(std::vector<uint8_t>* data) const { + Leb128EncodingVector vmap_encoder; + size_t size = 1 + 1 /* marker */ + 0; + vmap_encoder.Reserve(size + 1u); // All values are likely to be one byte in ULEB128 (<128). + vmap_encoder.PushBackUnsigned(size); + // We're currently always saving the frame pointer, so set it in the table as a temporary. + vmap_encoder.PushBackUnsigned(kVRegTempBaseReg + VmapTable::kEntryAdjustment); + vmap_encoder.PushBackUnsigned(VmapTable::kAdjustedFpMarker); + + *data = vmap_encoder.GetData(); +} } // namespace art diff --git a/compiler/optimizing/code_generator.h b/compiler/optimizing/code_generator.h index 63f8cbf429..24dcab6131 100644 --- a/compiler/optimizing/code_generator.h +++ b/compiler/optimizing/code_generator.h @@ -38,6 +38,11 @@ class CodeAllocator { DISALLOW_COPY_AND_ASSIGN(CodeAllocator); }; +struct PcInfo { + uint32_t dex_pc; + uintptr_t native_pc; +}; + /** * A Location is an abstraction over the potential location * of an instruction. It could be in register or stack. @@ -81,7 +86,8 @@ class Location : public ValueObject { class LocationSummary : public ArenaObject { public: explicit LocationSummary(HInstruction* instruction) - : inputs(instruction->GetBlock()->GetGraph()->GetArena(), instruction->InputCount()) { + : inputs(instruction->GetBlock()->GetGraph()->GetArena(), instruction->InputCount()), + temps(instruction->GetBlock()->GetGraph()->GetArena(), 0) { inputs.SetSize(instruction->InputCount()); for (int i = 0; i < instruction->InputCount(); i++) { inputs.Put(i, Location()); @@ -100,10 +106,19 @@ class LocationSummary : public ArenaObject { output = Location(location); } + void AddTemp(Location location) { + temps.Add(location); + } + + Location GetTemp(uint32_t at) const { + return temps.Get(at); + } + Location Out() const { return output; } private: GrowableArray<Location> inputs; + GrowableArray<Location> temps; Location output; DISALLOW_COPY_AND_ASSIGN(LocationSummary); @@ -134,9 +149,17 @@ class CodeGenerator : public ArenaObject { uint32_t GetFrameSize() const { return frame_size_; } void SetFrameSize(uint32_t size) { frame_size_ = size; } + uint32_t GetCoreSpillMask() const { return core_spill_mask_; } + + void RecordPcInfo(uint32_t dex_pc) { + struct PcInfo pc_info; + pc_info.dex_pc = dex_pc; + pc_info.native_pc = GetAssembler()->CodeSize(); + pc_infos_.Add(pc_info); + } - void BuildMappingTable(std::vector<uint8_t>* vector) const { } - void BuildVMapTable(std::vector<uint8_t>* vector) const { } + void BuildMappingTable(std::vector<uint8_t>* vector) const; + void BuildVMapTable(std::vector<uint8_t>* vector) const; void BuildNativeGCMap( std::vector<uint8_t>* vector, const DexCompilationUnit& dex_compilation_unit) const; @@ -144,23 +167,26 @@ class CodeGenerator : public ArenaObject { explicit CodeGenerator(HGraph* graph) : frame_size_(0), graph_(graph), - block_labels_(graph->GetArena(), 0) { + block_labels_(graph->GetArena(), 0), + pc_infos_(graph->GetArena(), 32) { block_labels_.SetSize(graph->GetBlocks()->Size()); } ~CodeGenerator() { } + // Frame size required for this method. + uint32_t frame_size_; + uint32_t core_spill_mask_; + private: void InitLocations(HInstruction* instruction); void CompileBlock(HBasicBlock* block); void CompileEntryBlock(); - // Frame size required for this method. - uint32_t frame_size_; - HGraph* const graph_; // Labels for each block that will be compiled. GrowableArray<Label> block_labels_; + GrowableArray<PcInfo> pc_infos_; DISALLOW_COPY_AND_ASSIGN(CodeGenerator); }; diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc index 04bdc34de7..68c997bf5f 100644 --- a/compiler/optimizing/code_generator_arm.cc +++ b/compiler/optimizing/code_generator_arm.cc @@ -18,17 +18,27 @@ #include "utils/assembler.h" #include "utils/arm/assembler_arm.h" +#include "mirror/array.h" +#include "mirror/art_method.h" + #define __ reinterpret_cast<ArmAssembler*>(GetAssembler())-> namespace art { namespace arm { void CodeGeneratorARM::GenerateFrameEntry() { + core_spill_mask_ |= (1 << LR); + // We're currently always using FP, which is callee-saved in Quick. + core_spill_mask_ |= (1 << FP); + __ PushList((1 << FP) | (1 << LR)); __ mov(FP, ShifterOperand(SP)); - if (GetFrameSize() != 0) { - __ AddConstant(SP, -GetFrameSize()); - } + + // Add the current ART method to the frame size, the return pc, and FP. + SetFrameSize(RoundUp(GetFrameSize() + 3 * kWordSize, kStackAlignment)); + // PC and FP have already been pushed on the stack. + __ AddConstant(SP, -(GetFrameSize() - 2 * kWordSize)); + __ str(R0, Address(SP, 0)); } void CodeGeneratorARM::GenerateFrameExit() { @@ -173,5 +183,71 @@ void InstructionCodeGeneratorARM::VisitReturn(HReturn* ret) { codegen_->GenerateFrameExit(); } +void LocationsBuilderARM::VisitInvokeStatic(HInvokeStatic* invoke) { + LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(invoke); + CHECK_EQ(invoke->InputCount(), 0); + locations->AddTemp(Location(R0)); + invoke->SetLocations(locations); +} + +void InstructionCodeGeneratorARM::LoadCurrentMethod(Register reg) { + __ ldr(reg, Address(SP, 0)); +} + +void InstructionCodeGeneratorARM::VisitInvokeStatic(HInvokeStatic* invoke) { + Register temp = invoke->GetLocations()->GetTemp(0).reg<Register>(); + size_t index_in_cache = mirror::Array::DataOffset(sizeof(mirror::Object*)).Int32Value() + + invoke->GetIndexInDexCache() * kWordSize; + + // TODO: Implement all kinds of calls: + // 1) boot -> boot + // 2) app -> boot + // 3) app -> app + // + // Currently we implement the app -> app logic, which looks up in the resolve cache. + + // temp = method; + LoadCurrentMethod(temp); + // temp = temp->dex_cache_resolved_methods_; + __ ldr(temp, Address(temp, mirror::ArtMethod::DexCacheResolvedMethodsOffset().Int32Value())); + // temp = temp[index_in_cache] + __ ldr(temp, Address(temp, index_in_cache)); + // LR = temp[offset_of_quick_compiled_code] + __ ldr(LR, Address(temp, + mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value())); + // LR() + __ blx(LR); + + codegen_->RecordPcInfo(invoke->GetDexPc()); +} + +void LocationsBuilderARM::VisitAdd(HAdd* add) { + LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(add); + switch (add->GetResultType()) { + case Primitive::kPrimInt: { + locations->SetInAt(0, Location(R0)); + locations->SetInAt(1, Location(R1)); + locations->SetOut(Location(R0)); + break; + } + default: + LOG(FATAL) << "Unimplemented"; + } + add->SetLocations(locations); +} + +void InstructionCodeGeneratorARM::VisitAdd(HAdd* add) { + LocationSummary* locations = add->GetLocations(); + switch (add->GetResultType()) { + case Primitive::kPrimInt: + __ add(locations->Out().reg<Register>(), + locations->InAt(0).reg<Register>(), + ShifterOperand(locations->InAt(1).reg<Register>())); + break; + default: + LOG(FATAL) << "Unimplemented"; + } +} + } // namespace arm } // namespace art diff --git a/compiler/optimizing/code_generator_arm.h b/compiler/optimizing/code_generator_arm.h index 52a7bf45c7..7a2835d026 100644 --- a/compiler/optimizing/code_generator_arm.h +++ b/compiler/optimizing/code_generator_arm.h @@ -58,6 +58,7 @@ class InstructionCodeGeneratorARM : public HGraphVisitor { #undef DECLARE_VISIT_INSTRUCTION Assembler* GetAssembler() const { return assembler_; } + void LoadCurrentMethod(Register reg); private: Assembler* const assembler_; diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc index c4bda5645e..1764486e57 100644 --- a/compiler/optimizing/code_generator_x86.cc +++ b/compiler/optimizing/code_generator_x86.cc @@ -18,18 +18,28 @@ #include "utils/assembler.h" #include "utils/x86/assembler_x86.h" +#include "mirror/array.h" +#include "mirror/art_method.h" + #define __ reinterpret_cast<X86Assembler*>(GetAssembler())-> namespace art { namespace x86 { void CodeGeneratorX86::GenerateFrameEntry() { + // Create a fake register to mimic Quick. + static const int kFakeReturnRegister = 8; + core_spill_mask_ |= (1 << kFakeReturnRegister); + // We're currently always using EBP, which is callee-saved in Quick. + core_spill_mask_ |= (1 << EBP); + __ pushl(EBP); __ movl(EBP, ESP); - - if (GetFrameSize() != 0) { - __ subl(ESP, Immediate(GetFrameSize())); - } + // Add the current ART method to the frame size, the return pc, and EBP. + SetFrameSize(RoundUp(GetFrameSize() + 3 * kWordSize, kStackAlignment)); + // The PC and EBP have already been pushed on the stack. + __ subl(ESP, Immediate(GetFrameSize() - 2 * kWordSize)); + __ movl(Address(ESP, 0), EAX); } void CodeGeneratorX86::GenerateFrameExit() { @@ -45,6 +55,10 @@ void CodeGeneratorX86::Push(HInstruction* instruction, Location location) { __ pushl(location.reg<Register>()); } +void InstructionCodeGeneratorX86::LoadCurrentMethod(Register reg) { + __ movl(reg, Address(ESP, 0)); +} + void CodeGeneratorX86::Move(HInstruction* instruction, Location location) { HIntConstant* constant = instruction->AsIntConstant(); if (constant != nullptr) { @@ -110,7 +124,8 @@ void LocationsBuilderX86::VisitLoadLocal(HLoadLocal* local) { static int32_t GetStackSlot(HLocal* local) { // We are currently using EBP to access locals, so the offset must be negative. - return (local->GetRegNumber() + 1) * -kWordSize; + // +1 for going backwards, +1 for the method pointer. + return (local->GetRegNumber() + 2) * -kWordSize; } void InstructionCodeGeneratorX86::VisitLoadLocal(HLoadLocal* load) { @@ -172,5 +187,63 @@ void InstructionCodeGeneratorX86::VisitReturn(HReturn* ret) { __ ret(); } +void LocationsBuilderX86::VisitInvokeStatic(HInvokeStatic* invoke) { + LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(invoke); + CHECK_EQ(invoke->InputCount(), 0); + locations->AddTemp(Location(EAX)); + invoke->SetLocations(locations); +} + +void InstructionCodeGeneratorX86::VisitInvokeStatic(HInvokeStatic* invoke) { + Register temp = invoke->GetLocations()->GetTemp(0).reg<Register>(); + size_t index_in_cache = mirror::Array::DataOffset(sizeof(mirror::Object*)).Int32Value() + + invoke->GetIndexInDexCache() * kWordSize; + + // TODO: Implement all kinds of calls: + // 1) boot -> boot + // 2) app -> boot + // 3) app -> app + // + // Currently we implement the app -> app logic, which looks up in the resolve cache. + + // temp = method; + LoadCurrentMethod(temp); + // temp = temp->dex_cache_resolved_methods_; + __ movl(temp, Address(temp, mirror::ArtMethod::DexCacheResolvedMethodsOffset().Int32Value())); + // temp = temp[index_in_cache] + __ movl(temp, Address(temp, index_in_cache)); + // (temp + offset_of_quick_compiled_code)() + __ call(Address(temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value())); + + codegen_->RecordPcInfo(invoke->GetDexPc()); +} + +void LocationsBuilderX86::VisitAdd(HAdd* add) { + LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(add); + switch (add->GetResultType()) { + case Primitive::kPrimInt: { + locations->SetInAt(0, Location(EAX)); + locations->SetInAt(1, Location(ECX)); + locations->SetOut(Location(EAX)); + break; + } + default: + LOG(FATAL) << "Unimplemented"; + } + add->SetLocations(locations); +} + +void InstructionCodeGeneratorX86::VisitAdd(HAdd* add) { + LocationSummary* locations = add->GetLocations(); + switch (add->GetResultType()) { + case Primitive::kPrimInt: + DCHECK_EQ(locations->InAt(0).reg<Register>(), locations->Out().reg<Register>()); + __ addl(locations->InAt(0).reg<Register>(), locations->InAt(1).reg<Register>()); + break; + default: + LOG(FATAL) << "Unimplemented"; + } +} + } // namespace x86 } // namespace art diff --git a/compiler/optimizing/code_generator_x86.h b/compiler/optimizing/code_generator_x86.h index ad2a06143a..505237bd55 100644 --- a/compiler/optimizing/code_generator_x86.h +++ b/compiler/optimizing/code_generator_x86.h @@ -57,6 +57,8 @@ class InstructionCodeGeneratorX86 : public HGraphVisitor { #undef DECLARE_VISIT_INSTRUCTION + void LoadCurrentMethod(Register reg); + Assembler* GetAssembler() const { return assembler_; } private: diff --git a/compiler/optimizing/codegen_test.cc b/compiler/optimizing/codegen_test.cc index ff743d8ed3..d40990e86b 100644 --- a/compiler/optimizing/codegen_test.cc +++ b/compiler/optimizing/codegen_test.cc @@ -196,4 +196,42 @@ TEST(CodegenTest, ReturnIf2) { TestCode(data, true, 0); } +TEST(CodegenTest, ReturnAdd1) { + const uint16_t data[] = TWO_REGISTERS_CODE_ITEM( + Instruction::CONST_4 | 3 << 12 | 0, + Instruction::CONST_4 | 4 << 12 | 1 << 8, + Instruction::ADD_INT, 1 << 8 | 0, + Instruction::RETURN); + + TestCode(data, true, 7); +} + +TEST(CodegenTest, ReturnAdd2) { + const uint16_t data[] = TWO_REGISTERS_CODE_ITEM( + Instruction::CONST_4 | 3 << 12 | 0, + Instruction::CONST_4 | 4 << 12 | 1 << 8, + Instruction::ADD_INT_2ADDR | 1 << 12, + Instruction::RETURN); + + TestCode(data, true, 7); +} + +TEST(CodegenTest, ReturnAdd3) { + const uint16_t data[] = ONE_REGISTER_CODE_ITEM( + Instruction::CONST_4 | 4 << 12 | 0 << 8, + Instruction::ADD_INT_LIT8, 3 << 8 | 0, + Instruction::RETURN); + + TestCode(data, true, 7); +} + +TEST(CodegenTest, ReturnAdd4) { + const uint16_t data[] = ONE_REGISTER_CODE_ITEM( + Instruction::CONST_4 | 4 << 12 | 0 << 8, + Instruction::ADD_INT_LIT16, 3, + Instruction::RETURN); + + TestCode(data, true, 7); +} + } // namespace art diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h index e74ed827ec..fc67486267 100644 --- a/compiler/optimizing/nodes.h +++ b/compiler/optimizing/nodes.h @@ -180,11 +180,13 @@ class HBasicBlock : public ArenaObject { }; #define FOR_EACH_INSTRUCTION(M) \ + M(Add) \ M(Equal) \ M(Exit) \ M(Goto) \ M(If) \ M(IntConstant) \ + M(InvokeStatic) \ M(LoadLocal) \ M(Local) \ M(Return) \ @@ -476,14 +478,36 @@ class HIf : public HTemplateInstruction<1> { DISALLOW_COPY_AND_ASSIGN(HIf); }; -// Instruction to check if two inputs are equal to each other. -class HEqual : public HTemplateInstruction<2> { +class HBinaryOperation : public HTemplateInstruction<2> { public: - HEqual(HInstruction* first, HInstruction* second) { - SetRawInputAt(0, first); - SetRawInputAt(1, second); + HBinaryOperation(Primitive::Type result_type, + HInstruction* left, + HInstruction* right) : result_type_(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_; } + + virtual bool IsCommutative() { return false; } + + 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 { + public: + HEqual(HInstruction* first, HInstruction* second) + : HBinaryOperation(Primitive::kPrimBoolean, first, second) {} + + virtual bool IsCommutative() { return true; } + DECLARE_INSTRUCTION(Equal) private: @@ -554,6 +578,55 @@ class HIntConstant : public HTemplateInstruction<0> { DISALLOW_COPY_AND_ASSIGN(HIntConstant); }; +class HInvoke : public HInstruction { + public: + HInvoke(ArenaAllocator* arena, uint32_t number_of_arguments, int32_t dex_pc) + : inputs_(arena, number_of_arguments), + dex_pc_(dex_pc) { + inputs_.SetSize(number_of_arguments); + } + + virtual intptr_t InputCount() const { return inputs_.Size(); } + virtual HInstruction* InputAt(intptr_t i) const { return inputs_.Get(i); } + + int32_t GetDexPc() const { return dex_pc_; } + + protected: + GrowableArray<HInstruction*> inputs_; + const int32_t dex_pc_; + + private: + DISALLOW_COPY_AND_ASSIGN(HInvoke); +}; + +class HInvokeStatic : public HInvoke { + public: + HInvokeStatic(ArenaAllocator* arena, uint32_t number_of_arguments, int32_t dex_pc, int32_t index_in_dex_cache) + : HInvoke(arena, number_of_arguments, dex_pc), index_in_dex_cache_(index_in_dex_cache) { } + + uint32_t GetIndexInDexCache() const { return index_in_dex_cache_; } + + DECLARE_INSTRUCTION(InvokeStatic) + + private: + uint32_t index_in_dex_cache_; + + DISALLOW_COPY_AND_ASSIGN(HInvokeStatic); +}; + +class HAdd : public HBinaryOperation { + public: + HAdd(Primitive::Type result_type, HInstruction* left, HInstruction* right) + : HBinaryOperation(result_type, left, right) {} + + virtual bool IsCommutative() { return true; } + + DECLARE_INSTRUCTION(Add); + + private: + DISALLOW_COPY_AND_ASSIGN(HAdd); +}; + class HGraphVisitor : public ValueObject { public: explicit HGraphVisitor(HGraph* graph) : graph_(graph) { } diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc index 334b185b44..d19c40c291 100644 --- a/compiler/optimizing/optimizing_compiler.cc +++ b/compiler/optimizing/optimizing_compiler.cc @@ -62,17 +62,31 @@ CompiledMethod* OptimizingCompiler::TryCompile(CompilerDriver& driver, nullptr, class_loader, art::Runtime::Current()->GetClassLinker(), dex_file, code_item, class_def_idx, method_idx, access_flags, driver.GetVerifiedMethod(&dex_file, method_idx)); + // For testing purposes, we put a special marker on method names that should be compiled + // with this compiler. This makes sure we're not regressing. + bool shouldCompile = dex_compilation_unit.GetSymbol().find("00024opt_00024") != std::string::npos; + ArenaPool pool; ArenaAllocator arena(&pool); - HGraphBuilder builder(&arena); + HGraphBuilder builder(&arena, &dex_compilation_unit, &dex_file); HGraph* graph = builder.BuildGraph(*code_item); if (graph == nullptr) { + if (shouldCompile) { + LOG(FATAL) << "Could not build graph in optimizing compiler"; + } return nullptr; } InstructionSet instruction_set = driver.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) { + LOG(FATAL) << "Could not find code generator for optimizing compiler"; + } return nullptr; } @@ -90,7 +104,7 @@ CompiledMethod* OptimizingCompiler::TryCompile(CompilerDriver& driver, instruction_set, allocator.GetMemory(), codegen->GetFrameSize(), - 0, /* GPR spill mask, unused */ + codegen->GetCoreSpillMask(), 0, /* FPR spill mask, unused */ mapping_table, vmap_table, diff --git a/compiler/utils/arm/assembler_arm.cc b/compiler/utils/arm/assembler_arm.cc index dbd078a81c..872a5571f5 100644 --- a/compiler/utils/arm/assembler_arm.cc +++ b/compiler/utils/arm/assembler_arm.cc @@ -1438,7 +1438,7 @@ void ArmAssembler::Rrx(Register rd, Register rm, Condition cond) { void ArmAssembler::BuildFrame(size_t frame_size, ManagedRegister method_reg, const std::vector<ManagedRegister>& callee_save_regs, - const std::vector<ManagedRegister>& entry_spills) { + const ManagedRegisterEntrySpills& entry_spills) { CHECK_ALIGNED(frame_size, kStackAlignment); CHECK_EQ(R0, method_reg.AsArm().AsCoreRegister()); diff --git a/compiler/utils/arm/assembler_arm.h b/compiler/utils/arm/assembler_arm.h index 757a8a2e99..bb9207cadb 100644 --- a/compiler/utils/arm/assembler_arm.h +++ b/compiler/utils/arm/assembler_arm.h @@ -440,7 +440,7 @@ class ArmAssembler : public Assembler { // Emit code that will create an activation on the stack virtual void BuildFrame(size_t frame_size, ManagedRegister method_reg, const std::vector<ManagedRegister>& callee_save_regs, - const std::vector<ManagedRegister>& entry_spills); + const ManagedRegisterEntrySpills& entry_spills); // Emit code that will remove an activation from the stack virtual void RemoveFrame(size_t frame_size, diff --git a/compiler/utils/arm64/assembler_arm64.cc b/compiler/utils/arm64/assembler_arm64.cc index 00ce923517..f8b91d7a40 100644 --- a/compiler/utils/arm64/assembler_arm64.cc +++ b/compiler/utils/arm64/assembler_arm64.cc @@ -577,7 +577,7 @@ void Arm64Assembler::EmitExceptionPoll(Arm64Exception *exception) { void Arm64Assembler::BuildFrame(size_t frame_size, ManagedRegister method_reg, const std::vector<ManagedRegister>& callee_save_regs, - const std::vector<ManagedRegister>& entry_spills) { + const ManagedRegisterEntrySpills& entry_spills) { CHECK_ALIGNED(frame_size, kStackAlignment); CHECK(X0 == method_reg.AsArm64().AsCoreRegister()); diff --git a/compiler/utils/arm64/assembler_arm64.h b/compiler/utils/arm64/assembler_arm64.h index 1c47e7757d..44eb6ff33a 100644 --- a/compiler/utils/arm64/assembler_arm64.h +++ b/compiler/utils/arm64/assembler_arm64.h @@ -111,7 +111,7 @@ class Arm64Assembler : public Assembler { // Emit code that will create an activation on the stack. void BuildFrame(size_t frame_size, ManagedRegister method_reg, const std::vector<ManagedRegister>& callee_save_regs, - const std::vector<ManagedRegister>& entry_spills); + const ManagedRegisterEntrySpills& entry_spills); // Emit code that will remove an activation from the stack. void RemoveFrame(size_t frame_size, diff --git a/compiler/utils/assembler.cc b/compiler/utils/assembler.cc index a7cb2784a7..1921b28232 100644 --- a/compiler/utils/assembler.cc +++ b/compiler/utils/assembler.cc @@ -23,6 +23,7 @@ #include "arm64/assembler_arm64.h" #include "mips/assembler_mips.h" #include "x86/assembler_x86.h" +#include "x86_64/assembler_x86_64.h" #include "globals.h" #include "memory_region.h" @@ -111,9 +112,10 @@ Assembler* Assembler::Create(InstructionSet instruction_set) { return new arm64::Arm64Assembler(); case kMips: return new mips::MipsAssembler(); - case kX86: // Fall-through. - case kX86_64: + case kX86: return new x86::X86Assembler(); + case kX86_64: + return new x86_64::X86_64Assembler(); default: LOG(FATAL) << "Unknown InstructionSet: " << instruction_set; return NULL; diff --git a/compiler/utils/assembler.h b/compiler/utils/assembler.h index cd4fc12e33..c23fd440dc 100644 --- a/compiler/utils/assembler.h +++ b/compiler/utils/assembler.h @@ -24,6 +24,7 @@ #include "arm/constants_arm.h" #include "mips/constants_mips.h" #include "x86/constants_x86.h" +#include "x86_64/constants_x86_64.h" #include "instruction_set.h" #include "managed_register.h" #include "memory_region.h" @@ -47,6 +48,26 @@ namespace mips { namespace x86 { class X86Assembler; } +namespace x86_64 { + class X86_64Assembler; +} + +class ExternalLabel { + public: + ExternalLabel(const char* name, uword address) + : name_(name), address_(address) { + DCHECK(name != nullptr); + } + + const char* name() const { return name_; } + uword address() const { + return address_; + } + + private: + const char* name_; + const uword address_; +}; class Label { public: @@ -95,6 +116,7 @@ class Label { friend class arm::ArmAssembler; friend class mips::MipsAssembler; friend class x86::X86Assembler; + friend class x86_64::X86_64Assembler; DISALLOW_COPY_AND_ASSIGN(Label); }; @@ -335,7 +357,7 @@ class Assembler { // Emit code that will create an activation on the stack virtual void BuildFrame(size_t frame_size, ManagedRegister method_reg, const std::vector<ManagedRegister>& callee_save_regs, - const std::vector<ManagedRegister>& entry_spills) = 0; + const ManagedRegisterEntrySpills& entry_spills) = 0; // Emit code that will remove an activation from the stack virtual void RemoveFrame(size_t frame_size, diff --git a/compiler/utils/managed_register.h b/compiler/utils/managed_register.h index 04c972388f..f007d2804a 100644 --- a/compiler/utils/managed_register.h +++ b/compiler/utils/managed_register.h @@ -17,6 +17,8 @@ #ifndef ART_COMPILER_UTILS_MANAGED_REGISTER_H_ #define ART_COMPILER_UTILS_MANAGED_REGISTER_H_ +#include <vector> + namespace art { namespace arm { @@ -28,10 +30,15 @@ class Arm64ManagedRegister; namespace mips { class MipsManagedRegister; } + namespace x86 { class X86ManagedRegister; } +namespace x86_64 { +class X86_64ManagedRegister; +} + class ManagedRegister { public: // ManagedRegister is a value class. There exists no method to change the @@ -48,6 +55,7 @@ class ManagedRegister { arm64::Arm64ManagedRegister AsArm64() const; mips::MipsManagedRegister AsMips() const; x86::X86ManagedRegister AsX86() const; + x86_64::X86_64ManagedRegister AsX86_64() const; // It is valid to invoke Equals on and with a NoRegister. bool Equals(const ManagedRegister& other) const { @@ -71,6 +79,44 @@ class ManagedRegister { int id_; }; +class ManagedRegisterSpill : public ManagedRegister { + public: + // ManagedRegisterSpill contains information about data type size and location in caller frame + // These additional attributes could be defined by calling convention (EntrySpills) + ManagedRegisterSpill(const ManagedRegister& other, uint32_t size, uint32_t spill_offset) + : ManagedRegister(other), size_(size), spill_offset_(spill_offset) { } + + explicit ManagedRegisterSpill(const ManagedRegister& other) + : ManagedRegister(other), size_(-1), spill_offset_(-1) { } + + int32_t getSpillOffset() { + return spill_offset_; + } + + int32_t getSize() { + return size_; + } + + private: + int32_t size_; + int32_t spill_offset_; +}; + +class ManagedRegisterEntrySpills : public std::vector<ManagedRegisterSpill> { + public: + // The ManagedRegister does not have information about size and offset. + // In this case it's size and offset determined by BuildFrame (assembler) + void push_back(ManagedRegister __x) { + ManagedRegisterSpill spill(__x); + std::vector<ManagedRegisterSpill>::push_back(spill); + } + + void push_back(ManagedRegisterSpill __x) { + std::vector<ManagedRegisterSpill>::push_back(__x); + } + private: +}; + } // namespace art #endif // ART_COMPILER_UTILS_MANAGED_REGISTER_H_ diff --git a/compiler/utils/mips/assembler_mips.cc b/compiler/utils/mips/assembler_mips.cc index ce21b84867..dfd3306fe9 100644 --- a/compiler/utils/mips/assembler_mips.cc +++ b/compiler/utils/mips/assembler_mips.cc @@ -538,7 +538,7 @@ void MipsAssembler::StoreDToOffset(DRegister reg, Register base, int32_t offset) void MipsAssembler::BuildFrame(size_t frame_size, ManagedRegister method_reg, const std::vector<ManagedRegister>& callee_save_regs, - const std::vector<ManagedRegister>& entry_spills) { + const ManagedRegisterEntrySpills& entry_spills) { CHECK_ALIGNED(frame_size, kStackAlignment); // Increase frame to required size. diff --git a/compiler/utils/mips/assembler_mips.h b/compiler/utils/mips/assembler_mips.h index 0f5f2fe199..0d1a94cc26 100644 --- a/compiler/utils/mips/assembler_mips.h +++ b/compiler/utils/mips/assembler_mips.h @@ -357,7 +357,7 @@ class MipsAssembler : public Assembler { // Emit code that will create an activation on the stack virtual void BuildFrame(size_t frame_size, ManagedRegister method_reg, const std::vector<ManagedRegister>& callee_save_regs, - const std::vector<ManagedRegister>& entry_spills); + const ManagedRegisterEntrySpills& entry_spills); // Emit code that will remove an activation from the stack virtual void RemoveFrame(size_t frame_size, diff --git a/compiler/utils/scoped_arena_allocator.cc b/compiler/utils/scoped_arena_allocator.cc index a78d28792b..bd78eaef0d 100644 --- a/compiler/utils/scoped_arena_allocator.cc +++ b/compiler/utils/scoped_arena_allocator.cc @@ -99,6 +99,7 @@ void* ArenaStack::AllocValgrind(size_t bytes, ArenaAllocKind kind) { } CurrentStats()->RecordAlloc(bytes, kind); top_ptr_ = ptr + rounded_bytes; + VALGRIND_MAKE_MEM_UNDEFINED(ptr, bytes); VALGRIND_MAKE_MEM_NOACCESS(ptr + bytes, rounded_bytes - bytes); return ptr; } diff --git a/compiler/utils/x86/assembler_x86.cc b/compiler/utils/x86/assembler_x86.cc index db8956d43b..ebbb43a442 100644 --- a/compiler/utils/x86/assembler_x86.cc +++ b/compiler/utils/x86/assembler_x86.cc @@ -54,6 +54,16 @@ void X86Assembler::call(Label* label) { } +void X86Assembler::call(const ExternalLabel& label) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + intptr_t call_start = buffer_.GetPosition(); + EmitUint8(0xE8); + EmitInt32(label.address()); + static const intptr_t kCallExternalLabelSize = 5; + DCHECK_EQ((buffer_.GetPosition() - call_start), kCallExternalLabelSize); +} + + void X86Assembler::pushl(Register reg) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); EmitUint8(0x50 + reg); @@ -1388,7 +1398,7 @@ void X86Assembler::EmitGenericShift(int reg_or_opcode, void X86Assembler::BuildFrame(size_t frame_size, ManagedRegister method_reg, const std::vector<ManagedRegister>& spill_regs, - const std::vector<ManagedRegister>& entry_spills) { + const ManagedRegisterEntrySpills& entry_spills) { CHECK_ALIGNED(frame_size, kStackAlignment); for (int i = spill_regs.size() - 1; i >= 0; --i) { pushl(spill_regs.at(i).AsX86().AsCpuRegister()); diff --git a/compiler/utils/x86/assembler_x86.h b/compiler/utils/x86/assembler_x86.h index e284d8c152..f906a6f7c7 100644 --- a/compiler/utils/x86/assembler_x86.h +++ b/compiler/utils/x86/assembler_x86.h @@ -227,6 +227,7 @@ class X86Assembler FINAL : public Assembler { void call(Register reg); void call(const Address& address); void call(Label* label); + void call(const ExternalLabel& label); void pushl(Register reg); void pushl(const Address& address); @@ -466,7 +467,7 @@ class X86Assembler FINAL : public Assembler { // Emit code that will create an activation on the stack virtual void BuildFrame(size_t frame_size, ManagedRegister method_reg, const std::vector<ManagedRegister>& callee_save_regs, - const std::vector<ManagedRegister>& entry_spills); + const ManagedRegisterEntrySpills& entry_spills); // Emit code that will remove an activation from the stack virtual void RemoveFrame(size_t frame_size, diff --git a/compiler/utils/x86_64/assembler_x86_64.cc b/compiler/utils/x86_64/assembler_x86_64.cc new file mode 100644 index 0000000000..fa302c924b --- /dev/null +++ b/compiler/utils/x86_64/assembler_x86_64.cc @@ -0,0 +1,1951 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "assembler_x86_64.h" + +#include "base/casts.h" +#include "entrypoints/quick/quick_entrypoints.h" +#include "memory_region.h" +#include "thread.h" + +namespace art { +namespace x86_64 { + +std::ostream& operator<<(std::ostream& os, const XmmRegister& reg) { + return os << "XMM" << static_cast<int>(reg); +} + +std::ostream& operator<<(std::ostream& os, const X87Register& reg) { + return os << "ST" << static_cast<int>(reg); +} + +void X86_64Assembler::call(Register reg) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xFF); + EmitRegisterOperand(2, reg); +} + + +void X86_64Assembler::call(const Address& address) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xFF); + EmitOperand(2, address); +} + + +void X86_64Assembler::call(Label* label) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xE8); + static const int kSize = 5; + EmitLabel(label, kSize); +} + + +void X86_64Assembler::pushq(Register reg) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + rex_rm(reg); + EmitUint8(0x50 + reg); +} + + +void X86_64Assembler::pushq(const Address& address) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xFF); + EmitOperand(6, address); +} + + +void X86_64Assembler::pushq(const Immediate& imm) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + if (imm.is_int8()) { + EmitUint8(0x6A); + EmitUint8(imm.value() & 0xFF); + } else { + EmitUint8(0x68); + EmitImmediate(imm); + } +} + + +void X86_64Assembler::popq(Register reg) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + rex_rm(reg); + EmitUint8(0x58 + reg); +} + + +void X86_64Assembler::popq(const Address& address) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x8F); + EmitOperand(0, address); +} + + +void X86_64Assembler::movq(Register dst, const Immediate& imm) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x48); // REX.W + EmitUint8(0xB8 + dst); + EmitImmediate(imm); +} + + +void X86_64Assembler::movl(Register dst, const Immediate& imm) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xB8 + dst); + EmitImmediate(imm); +} + + +void X86_64Assembler::movq(Register dst, Register src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x48); // REX.W + EmitUint8(0x89); + EmitRegisterOperand(src, dst); +} + + +void X86_64Assembler::movl(Register dst, Register src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x89); + EmitRegisterOperand(src, dst); +} + + +void X86_64Assembler::movq(Register dst, const Address& src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + rex_reg(dst, 8); + EmitUint8(0x8B); + EmitOperand(dst, src); +} + + +void X86_64Assembler::movl(Register dst, const Address& src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + rex_reg(dst, 4); + EmitUint8(0x8B); + EmitOperand(dst, src); +} + + +void X86_64Assembler::movq(const Address& dst, Register src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + rex_reg(src, 8); + EmitUint8(0x89); + EmitOperand(src, dst); +} + + +void X86_64Assembler::movl(const Address& dst, Register src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + rex_reg(src, 4); + EmitUint8(0x89); + EmitOperand(src, dst); +} + + +void X86_64Assembler::movl(const Address& dst, const Immediate& imm) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xC7); + EmitOperand(0, dst); + EmitImmediate(imm); +} + +void X86_64Assembler::movl(const Address& dst, Label* lbl) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xC7); + EmitOperand(0, dst); + EmitLabel(lbl, dst.length_ + 5); +} + +void X86_64Assembler::movzxb(Register dst, ByteRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x0F); + EmitUint8(0xB6); + EmitRegisterOperand(dst, src); +} + + +void X86_64Assembler::movzxb(Register dst, const Address& src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x0F); + EmitUint8(0xB6); + EmitOperand(dst, src); +} + + +void X86_64Assembler::movsxb(Register dst, ByteRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x0F); + EmitUint8(0xBE); + EmitRegisterOperand(dst, src); +} + + +void X86_64Assembler::movsxb(Register dst, const Address& src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x0F); + EmitUint8(0xBE); + EmitOperand(dst, src); +} + + +void X86_64Assembler::movb(Register /*dst*/, const Address& /*src*/) { + LOG(FATAL) << "Use movzxb or movsxb instead."; +} + + +void X86_64Assembler::movb(const Address& dst, ByteRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x88); + EmitOperand(src, dst); +} + + +void X86_64Assembler::movb(const Address& dst, const Immediate& imm) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xC6); + EmitOperand(RAX, dst); + CHECK(imm.is_int8()); + EmitUint8(imm.value() & 0xFF); +} + + +void X86_64Assembler::movzxw(Register dst, Register src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x0F); + EmitUint8(0xB7); + EmitRegisterOperand(dst, src); +} + + +void X86_64Assembler::movzxw(Register dst, const Address& src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x0F); + EmitUint8(0xB7); + EmitOperand(dst, src); +} + + +void X86_64Assembler::movsxw(Register dst, Register src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x0F); + EmitUint8(0xBF); + EmitRegisterOperand(dst, src); +} + + +void X86_64Assembler::movsxw(Register dst, const Address& src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x0F); + EmitUint8(0xBF); + EmitOperand(dst, src); +} + + +void X86_64Assembler::movw(Register /*dst*/, const Address& /*src*/) { + LOG(FATAL) << "Use movzxw or movsxw instead."; +} + + +void X86_64Assembler::movw(const Address& dst, Register src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitOperandSizeOverride(); + EmitUint8(0x89); + EmitOperand(src, dst); +} + + +void X86_64Assembler::leaq(Register dst, const Address& src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + rex_reg(dst, 8); + EmitUint8(0x8D); + EmitOperand(dst, src); +} + + +void X86_64Assembler::cmovl(Condition condition, Register dst, Register src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x0F); + EmitUint8(0x40 + condition); + EmitRegisterOperand(dst, src); +} + + +void X86_64Assembler::setb(Condition condition, Register dst) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x0F); + EmitUint8(0x90 + condition); + EmitOperand(0, Operand(dst)); +} + + +void X86_64Assembler::movss(XmmRegister dst, const Address& src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xF3); + EmitUint8(0x0F); + EmitUint8(0x10); + EmitOperand(dst, src); +} + + +void X86_64Assembler::movss(const Address& dst, XmmRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xF3); + EmitUint8(0x0F); + EmitUint8(0x11); + EmitOperand(src, dst); +} + + +void X86_64Assembler::movss(XmmRegister dst, XmmRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xF3); + EmitUint8(0x0F); + EmitUint8(0x11); + EmitXmmRegisterOperand(src, dst); +} + + +void X86_64Assembler::movd(XmmRegister dst, Register src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x66); + EmitUint8(0x0F); + EmitUint8(0x6E); + EmitOperand(dst, Operand(src)); +} + + +void X86_64Assembler::movd(Register dst, XmmRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x66); + EmitUint8(0x0F); + EmitUint8(0x7E); + EmitOperand(src, Operand(dst)); +} + + +void X86_64Assembler::addss(XmmRegister dst, XmmRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xF3); + EmitUint8(0x0F); + EmitUint8(0x58); + EmitXmmRegisterOperand(dst, src); +} + + +void X86_64Assembler::addss(XmmRegister dst, const Address& src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xF3); + EmitUint8(0x0F); + EmitUint8(0x58); + EmitOperand(dst, src); +} + + +void X86_64Assembler::subss(XmmRegister dst, XmmRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xF3); + EmitUint8(0x0F); + EmitUint8(0x5C); + EmitXmmRegisterOperand(dst, src); +} + + +void X86_64Assembler::subss(XmmRegister dst, const Address& src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xF3); + EmitUint8(0x0F); + EmitUint8(0x5C); + EmitOperand(dst, src); +} + + +void X86_64Assembler::mulss(XmmRegister dst, XmmRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xF3); + EmitUint8(0x0F); + EmitUint8(0x59); + EmitXmmRegisterOperand(dst, src); +} + + +void X86_64Assembler::mulss(XmmRegister dst, const Address& src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xF3); + EmitUint8(0x0F); + EmitUint8(0x59); + EmitOperand(dst, src); +} + + +void X86_64Assembler::divss(XmmRegister dst, XmmRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xF3); + EmitUint8(0x0F); + EmitUint8(0x5E); + EmitXmmRegisterOperand(dst, src); +} + + +void X86_64Assembler::divss(XmmRegister dst, const Address& src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xF3); + EmitUint8(0x0F); + EmitUint8(0x5E); + EmitOperand(dst, src); +} + + +void X86_64Assembler::flds(const Address& src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xD9); + EmitOperand(0, src); +} + + +void X86_64Assembler::fstps(const Address& dst) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xD9); + EmitOperand(3, dst); +} + + +void X86_64Assembler::movsd(XmmRegister dst, const Address& src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xF2); + EmitUint8(0x0F); + EmitUint8(0x10); + EmitOperand(dst, src); +} + + +void X86_64Assembler::movsd(const Address& dst, XmmRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xF2); + EmitUint8(0x0F); + EmitUint8(0x11); + EmitOperand(src, dst); +} + + +void X86_64Assembler::movsd(XmmRegister dst, XmmRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xF2); + EmitUint8(0x0F); + EmitUint8(0x11); + EmitXmmRegisterOperand(src, dst); +} + + +void X86_64Assembler::addsd(XmmRegister dst, XmmRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xF2); + EmitUint8(0x0F); + EmitUint8(0x58); + EmitXmmRegisterOperand(dst, src); +} + + +void X86_64Assembler::addsd(XmmRegister dst, const Address& src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xF2); + EmitUint8(0x0F); + EmitUint8(0x58); + EmitOperand(dst, src); +} + + +void X86_64Assembler::subsd(XmmRegister dst, XmmRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xF2); + EmitUint8(0x0F); + EmitUint8(0x5C); + EmitXmmRegisterOperand(dst, src); +} + + +void X86_64Assembler::subsd(XmmRegister dst, const Address& src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xF2); + EmitUint8(0x0F); + EmitUint8(0x5C); + EmitOperand(dst, src); +} + + +void X86_64Assembler::mulsd(XmmRegister dst, XmmRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xF2); + EmitUint8(0x0F); + EmitUint8(0x59); + EmitXmmRegisterOperand(dst, src); +} + + +void X86_64Assembler::mulsd(XmmRegister dst, const Address& src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xF2); + EmitUint8(0x0F); + EmitUint8(0x59); + EmitOperand(dst, src); +} + + +void X86_64Assembler::divsd(XmmRegister dst, XmmRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xF2); + EmitUint8(0x0F); + EmitUint8(0x5E); + EmitXmmRegisterOperand(dst, src); +} + + +void X86_64Assembler::divsd(XmmRegister dst, const Address& src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xF2); + EmitUint8(0x0F); + EmitUint8(0x5E); + EmitOperand(dst, src); +} + + +void X86_64Assembler::cvtsi2ss(XmmRegister dst, Register src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xF3); + EmitUint8(0x0F); + EmitUint8(0x2A); + EmitOperand(dst, Operand(src)); +} + + +void X86_64Assembler::cvtsi2sd(XmmRegister dst, Register src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xF2); + EmitUint8(0x0F); + EmitUint8(0x2A); + EmitOperand(dst, Operand(src)); +} + + +void X86_64Assembler::cvtss2si(Register dst, XmmRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xF3); + EmitUint8(0x0F); + EmitUint8(0x2D); + EmitXmmRegisterOperand(dst, src); +} + + +void X86_64Assembler::cvtss2sd(XmmRegister dst, XmmRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xF3); + EmitUint8(0x0F); + EmitUint8(0x5A); + EmitXmmRegisterOperand(dst, src); +} + + +void X86_64Assembler::cvtsd2si(Register dst, XmmRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xF2); + EmitUint8(0x0F); + EmitUint8(0x2D); + EmitXmmRegisterOperand(dst, src); +} + + +void X86_64Assembler::cvttss2si(Register dst, XmmRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xF3); + EmitUint8(0x0F); + EmitUint8(0x2C); + EmitXmmRegisterOperand(dst, src); +} + + +void X86_64Assembler::cvttsd2si(Register dst, XmmRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xF2); + EmitUint8(0x0F); + EmitUint8(0x2C); + EmitXmmRegisterOperand(dst, src); +} + + +void X86_64Assembler::cvtsd2ss(XmmRegister dst, XmmRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xF2); + EmitUint8(0x0F); + EmitUint8(0x5A); + EmitXmmRegisterOperand(dst, src); +} + + +void X86_64Assembler::cvtdq2pd(XmmRegister dst, XmmRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xF3); + EmitUint8(0x0F); + EmitUint8(0xE6); + EmitXmmRegisterOperand(dst, src); +} + + +void X86_64Assembler::comiss(XmmRegister a, XmmRegister b) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x0F); + EmitUint8(0x2F); + EmitXmmRegisterOperand(a, b); +} + + +void X86_64Assembler::comisd(XmmRegister a, XmmRegister b) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x66); + EmitUint8(0x0F); + EmitUint8(0x2F); + EmitXmmRegisterOperand(a, b); +} + + +void X86_64Assembler::sqrtsd(XmmRegister dst, XmmRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xF2); + EmitUint8(0x0F); + EmitUint8(0x51); + EmitXmmRegisterOperand(dst, src); +} + + +void X86_64Assembler::sqrtss(XmmRegister dst, XmmRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xF3); + EmitUint8(0x0F); + EmitUint8(0x51); + EmitXmmRegisterOperand(dst, src); +} + + +void X86_64Assembler::xorpd(XmmRegister dst, const Address& src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x66); + EmitUint8(0x0F); + EmitUint8(0x57); + EmitOperand(dst, src); +} + + +void X86_64Assembler::xorpd(XmmRegister dst, XmmRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x66); + EmitUint8(0x0F); + EmitUint8(0x57); + EmitXmmRegisterOperand(dst, src); +} + + +void X86_64Assembler::xorps(XmmRegister dst, const Address& src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x0F); + EmitUint8(0x57); + EmitOperand(dst, src); +} + + +void X86_64Assembler::xorps(XmmRegister dst, XmmRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x0F); + EmitUint8(0x57); + EmitXmmRegisterOperand(dst, src); +} + + +void X86_64Assembler::andpd(XmmRegister dst, const Address& src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x66); + EmitUint8(0x0F); + EmitUint8(0x54); + EmitOperand(dst, src); +} + + +void X86_64Assembler::fldl(const Address& src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xDD); + EmitOperand(0, src); +} + + +void X86_64Assembler::fstpl(const Address& dst) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xDD); + EmitOperand(3, dst); +} + + +void X86_64Assembler::fnstcw(const Address& dst) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xD9); + EmitOperand(7, dst); +} + + +void X86_64Assembler::fldcw(const Address& src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xD9); + EmitOperand(5, src); +} + + +void X86_64Assembler::fistpl(const Address& dst) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xDF); + EmitOperand(7, dst); +} + + +void X86_64Assembler::fistps(const Address& dst) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xDB); + EmitOperand(3, dst); +} + + +void X86_64Assembler::fildl(const Address& src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xDF); + EmitOperand(5, src); +} + + +void X86_64Assembler::fincstp() { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xD9); + EmitUint8(0xF7); +} + + +void X86_64Assembler::ffree(const Immediate& index) { + CHECK_LT(index.value(), 7); + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xDD); + EmitUint8(0xC0 + index.value()); +} + + +void X86_64Assembler::fsin() { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xD9); + EmitUint8(0xFE); +} + + +void X86_64Assembler::fcos() { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xD9); + EmitUint8(0xFF); +} + + +void X86_64Assembler::fptan() { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xD9); + EmitUint8(0xF2); +} + + +void X86_64Assembler::xchgl(Register dst, Register src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x87); + EmitRegisterOperand(dst, src); +} + +void X86_64Assembler::xchgl(Register reg, const Address& address) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x87); + EmitOperand(reg, address); +} + + +void X86_64Assembler::cmpl(Register reg, const Immediate& imm) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitComplex(7, Operand(reg), imm); +} + + +void X86_64Assembler::cmpl(Register reg0, Register reg1) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x3B); + EmitOperand(reg0, Operand(reg1)); +} + + +void X86_64Assembler::cmpl(Register reg, const Address& address) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x3B); + EmitOperand(reg, address); +} + + +void X86_64Assembler::addl(Register dst, Register src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x03); + EmitRegisterOperand(dst, src); +} + + +void X86_64Assembler::addl(Register reg, const Address& address) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x03); + EmitOperand(reg, address); +} + + +void X86_64Assembler::cmpl(const Address& address, Register reg) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x39); + EmitOperand(reg, address); +} + + +void X86_64Assembler::cmpl(const Address& address, const Immediate& imm) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitComplex(7, address, imm); +} + + +void X86_64Assembler::testl(Register reg1, Register reg2) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + rex(reg1, reg2, 4); + EmitUint8(0x85); + EmitRegisterOperand(reg1, reg2); +} + + +void X86_64Assembler::testl(Register reg, const Immediate& immediate) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + // For registers that have a byte variant (RAX, RBX, RCX, and RDX) + // we only test the byte register to keep the encoding short. + if (immediate.is_uint8() && reg < 4) { + // Use zero-extended 8-bit immediate. + if (reg == RAX) { + EmitUint8(0xA8); + } else { + EmitUint8(0xF6); + EmitUint8(0xC0 + reg); + } + EmitUint8(immediate.value() & 0xFF); + } else if (reg == RAX) { + // Use short form if the destination is RAX. + EmitUint8(0xA9); + EmitImmediate(immediate); + } else { + EmitUint8(0xF7); + EmitOperand(0, Operand(reg)); + EmitImmediate(immediate); + } +} + + +void X86_64Assembler::andl(Register dst, Register src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x23); + EmitOperand(dst, Operand(src)); +} + + +void X86_64Assembler::andl(Register dst, const Immediate& imm) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitComplex(4, Operand(dst), imm); +} + + +void X86_64Assembler::orl(Register dst, Register src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x0B); + EmitOperand(dst, Operand(src)); +} + + +void X86_64Assembler::orl(Register dst, const Immediate& imm) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitComplex(1, Operand(dst), imm); +} + + +void X86_64Assembler::xorl(Register dst, Register src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + rex(dst, src, 4); + EmitUint8(0x33); + EmitOperand(dst, Operand(src)); +} + +void X86_64Assembler::rex_reg(Register &dst, size_t size) { + Register src = kNoRegister; + rex(dst, src, size); +} + +void X86_64Assembler::rex_rm(Register &src, size_t size) { + Register dst = kNoRegister; + rex(dst, src, size); +} + +void X86_64Assembler::rex(Register &dst, Register &src, size_t size) { + uint8_t rex = 0; + // REX.WRXB + // W - 64-bit operand + // R - MODRM.reg + // X - SIB.index + // B - MODRM.rm/SIB.base + if (size == 8) { + rex |= 0x48; // REX.W000 + } + if (dst >= Register::R8 && dst < Register::kNumberOfCpuRegisters) { + rex |= 0x44; // REX.0R00 + dst = static_cast<Register>(dst - 8); + } + if (src >= Register::R8 && src < Register::kNumberOfCpuRegisters) { + rex |= 0x41; // REX.000B + src = static_cast<Register>(src - 8); + } + if (rex != 0) { + EmitUint8(rex); + } +} + +void X86_64Assembler::addl(Register reg, const Immediate& imm) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitComplex(0, Operand(reg), imm); +} + + +void X86_64Assembler::addq(Register reg, const Immediate& imm) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x48); // REX.W + EmitComplex(0, Operand(reg), imm); +} + + +void X86_64Assembler::addl(const Address& address, Register reg) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x01); + EmitOperand(reg, address); +} + + +void X86_64Assembler::addl(const Address& address, const Immediate& imm) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitComplex(0, address, imm); +} + + +void X86_64Assembler::adcl(Register reg, const Immediate& imm) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitComplex(2, Operand(reg), imm); +} + + +void X86_64Assembler::adcl(Register dst, Register src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x13); + EmitOperand(dst, Operand(src)); +} + + +void X86_64Assembler::adcl(Register dst, const Address& address) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x13); + EmitOperand(dst, address); +} + + +void X86_64Assembler::subl(Register dst, Register src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x2B); + EmitOperand(dst, Operand(src)); +} + + +void X86_64Assembler::subl(Register reg, const Immediate& imm) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x48); // REX.W + EmitComplex(5, Operand(reg), imm); +} + + +void X86_64Assembler::subl(Register reg, const Address& address) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x2B); + EmitOperand(reg, address); +} + + +void X86_64Assembler::cdq() { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x99); +} + + +void X86_64Assembler::idivl(Register reg) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xF7); + EmitUint8(0xF8 | reg); +} + + +void X86_64Assembler::imull(Register dst, Register src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x0F); + EmitUint8(0xAF); + EmitOperand(dst, Operand(src)); +} + + +void X86_64Assembler::imull(Register reg, const Immediate& imm) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x69); + EmitOperand(reg, Operand(reg)); + EmitImmediate(imm); +} + + +void X86_64Assembler::imull(Register reg, const Address& address) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x0F); + EmitUint8(0xAF); + EmitOperand(reg, address); +} + + +void X86_64Assembler::imull(Register reg) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xF7); + EmitOperand(5, Operand(reg)); +} + + +void X86_64Assembler::imull(const Address& address) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xF7); + EmitOperand(5, address); +} + + +void X86_64Assembler::mull(Register reg) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xF7); + EmitOperand(4, Operand(reg)); +} + + +void X86_64Assembler::mull(const Address& address) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xF7); + EmitOperand(4, address); +} + + +void X86_64Assembler::sbbl(Register dst, Register src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x1B); + EmitOperand(dst, Operand(src)); +} + + +void X86_64Assembler::sbbl(Register reg, const Immediate& imm) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitComplex(3, Operand(reg), imm); +} + + +void X86_64Assembler::sbbl(Register dst, const Address& address) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x1B); + EmitOperand(dst, address); +} + + +void X86_64Assembler::incl(Register reg) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x40 + reg); +} + + +void X86_64Assembler::incl(const Address& address) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xFF); + EmitOperand(0, address); +} + + +void X86_64Assembler::decl(Register reg) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x48 + reg); +} + + +void X86_64Assembler::decl(const Address& address) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xFF); + EmitOperand(1, address); +} + + +void X86_64Assembler::shll(Register reg, const Immediate& imm) { + EmitGenericShift(4, reg, imm); +} + + +void X86_64Assembler::shll(Register operand, Register shifter) { + EmitGenericShift(4, operand, shifter); +} + + +void X86_64Assembler::shrl(Register reg, const Immediate& imm) { + EmitGenericShift(5, reg, imm); +} + + +void X86_64Assembler::shrl(Register operand, Register shifter) { + EmitGenericShift(5, operand, shifter); +} + + +void X86_64Assembler::sarl(Register reg, const Immediate& imm) { + EmitGenericShift(7, reg, imm); +} + + +void X86_64Assembler::sarl(Register operand, Register shifter) { + EmitGenericShift(7, operand, shifter); +} + + +void X86_64Assembler::shld(Register dst, Register src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x0F); + EmitUint8(0xA5); + EmitRegisterOperand(src, dst); +} + + +void X86_64Assembler::negl(Register reg) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xF7); + EmitOperand(3, Operand(reg)); +} + + +void X86_64Assembler::notl(Register reg) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xF7); + EmitUint8(0xD0 | reg); +} + + +void X86_64Assembler::enter(const Immediate& imm) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xC8); + CHECK(imm.is_uint16()); + EmitUint8(imm.value() & 0xFF); + EmitUint8((imm.value() >> 8) & 0xFF); + EmitUint8(0x00); +} + + +void X86_64Assembler::leave() { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xC9); +} + + +void X86_64Assembler::ret() { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xC3); +} + + +void X86_64Assembler::ret(const Immediate& imm) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xC2); + CHECK(imm.is_uint16()); + EmitUint8(imm.value() & 0xFF); + EmitUint8((imm.value() >> 8) & 0xFF); +} + + + +void X86_64Assembler::nop() { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x90); +} + + +void X86_64Assembler::int3() { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xCC); +} + + +void X86_64Assembler::hlt() { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xF4); +} + + +void X86_64Assembler::j(Condition condition, Label* label) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + if (label->IsBound()) { + static const int kShortSize = 2; + static const int kLongSize = 6; + int offset = label->Position() - buffer_.Size(); + CHECK_LE(offset, 0); + if (IsInt(8, offset - kShortSize)) { + EmitUint8(0x70 + condition); + EmitUint8((offset - kShortSize) & 0xFF); + } else { + EmitUint8(0x0F); + EmitUint8(0x80 + condition); + EmitInt32(offset - kLongSize); + } + } else { + EmitUint8(0x0F); + EmitUint8(0x80 + condition); + EmitLabelLink(label); + } +} + + +void X86_64Assembler::jmp(Register reg) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xFF); + EmitRegisterOperand(4, reg); +} + +void X86_64Assembler::jmp(const Address& address) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xFF); + EmitOperand(4, address); +} + +void X86_64Assembler::jmp(Label* label) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + if (label->IsBound()) { + static const int kShortSize = 2; + static const int kLongSize = 5; + int offset = label->Position() - buffer_.Size(); + CHECK_LE(offset, 0); + if (IsInt(8, offset - kShortSize)) { + EmitUint8(0xEB); + EmitUint8((offset - kShortSize) & 0xFF); + } else { + EmitUint8(0xE9); + EmitInt32(offset - kLongSize); + } + } else { + EmitUint8(0xE9); + EmitLabelLink(label); + } +} + + +X86_64Assembler* X86_64Assembler::lock() { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xF0); + return this; +} + + +void X86_64Assembler::cmpxchgl(const Address& address, Register reg) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x0F); + EmitUint8(0xB1); + EmitOperand(reg, address); +} + +void X86_64Assembler::mfence() { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x0F); + EmitUint8(0xAE); + EmitUint8(0xF0); +} + +X86_64Assembler* X86_64Assembler::gs() { + // TODO: fs is a prefix and not an instruction + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x65); + return this; +} + +void X86_64Assembler::AddImmediate(Register reg, const Immediate& imm) { + int value = imm.value(); + if (value > 0) { + if (value == 1) { + incl(reg); + } else if (value != 0) { + addl(reg, imm); + } + } else if (value < 0) { + value = -value; + if (value == 1) { + decl(reg); + } else if (value != 0) { + subl(reg, Immediate(value)); + } + } +} + + +void X86_64Assembler::LoadDoubleConstant(XmmRegister dst, double value) { + // TODO: Need to have a code constants table. + int64_t constant = bit_cast<int64_t, double>(value); + pushq(Immediate(High32Bits(constant))); + pushq(Immediate(Low32Bits(constant))); + movsd(dst, Address(RSP, 0)); + addq(RSP, Immediate(2 * kWordSize)); +} + + +void X86_64Assembler::FloatNegate(XmmRegister f) { + static const struct { + uint32_t a; + uint32_t b; + uint32_t c; + uint32_t d; + } float_negate_constant __attribute__((aligned(16))) = + { 0x80000000, 0x00000000, 0x80000000, 0x00000000 }; + xorps(f, Address::Absolute(reinterpret_cast<uword>(&float_negate_constant))); +} + + +void X86_64Assembler::DoubleNegate(XmmRegister d) { + static const struct { + uint64_t a; + uint64_t b; + } double_negate_constant __attribute__((aligned(16))) = + {0x8000000000000000LL, 0x8000000000000000LL}; + xorpd(d, Address::Absolute(reinterpret_cast<uword>(&double_negate_constant))); +} + + +void X86_64Assembler::DoubleAbs(XmmRegister reg) { + static const struct { + uint64_t a; + uint64_t b; + } double_abs_constant __attribute__((aligned(16))) = + {0x7FFFFFFFFFFFFFFFLL, 0x7FFFFFFFFFFFFFFFLL}; + andpd(reg, Address::Absolute(reinterpret_cast<uword>(&double_abs_constant))); +} + + +void X86_64Assembler::Align(int alignment, int offset) { + CHECK(IsPowerOfTwo(alignment)); + // Emit nop instruction until the real position is aligned. + while (((offset + buffer_.GetPosition()) & (alignment-1)) != 0) { + nop(); + } +} + + +void X86_64Assembler::Bind(Label* label) { + int bound = buffer_.Size(); + CHECK(!label->IsBound()); // Labels can only be bound once. + while (label->IsLinked()) { + int position = label->LinkPosition(); + int next = buffer_.Load<int32_t>(position); + buffer_.Store<int32_t>(position, bound - (position + 4)); + label->position_ = next; + } + label->BindTo(bound); +} + + +void X86_64Assembler::EmitOperand(int reg_or_opcode, const Operand& operand) { + CHECK_GE(reg_or_opcode, 0); + CHECK_LT(reg_or_opcode, 8); + const int length = operand.length_; + CHECK_GT(length, 0); + // Emit the ModRM byte updated with the given reg value. + CHECK_EQ(operand.encoding_[0] & 0x38, 0); + EmitUint8(operand.encoding_[0] + (reg_or_opcode << 3)); + // Emit the rest of the encoded operand. + for (int i = 1; i < length; i++) { + EmitUint8(operand.encoding_[i]); + } +} + + +void X86_64Assembler::EmitImmediate(const Immediate& imm) { + EmitInt32(imm.value()); +} + + +void X86_64Assembler::EmitComplex(int reg_or_opcode, + const Operand& operand, + const Immediate& immediate) { + CHECK_GE(reg_or_opcode, 0); + CHECK_LT(reg_or_opcode, 8); + if (immediate.is_int8()) { + // Use sign-extended 8-bit immediate. + EmitUint8(0x83); + EmitOperand(reg_or_opcode, operand); + EmitUint8(immediate.value() & 0xFF); + } else if (operand.IsRegister(RAX)) { + // Use short form if the destination is eax. + EmitUint8(0x05 + (reg_or_opcode << 3)); + EmitImmediate(immediate); + } else { + EmitUint8(0x81); + EmitOperand(reg_or_opcode, operand); + EmitImmediate(immediate); + } +} + + +void X86_64Assembler::EmitLabel(Label* label, int instruction_size) { + if (label->IsBound()) { + int offset = label->Position() - buffer_.Size(); + CHECK_LE(offset, 0); + EmitInt32(offset - instruction_size); + } else { + EmitLabelLink(label); + } +} + + +void X86_64Assembler::EmitLabelLink(Label* label) { + CHECK(!label->IsBound()); + int position = buffer_.Size(); + EmitInt32(label->position_); + label->LinkTo(position); +} + + +void X86_64Assembler::EmitGenericShift(int reg_or_opcode, + Register reg, + const Immediate& imm) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + CHECK(imm.is_int8()); + if (imm.value() == 1) { + EmitUint8(0xD1); + EmitOperand(reg_or_opcode, Operand(reg)); + } else { + EmitUint8(0xC1); + EmitOperand(reg_or_opcode, Operand(reg)); + EmitUint8(imm.value() & 0xFF); + } +} + + +void X86_64Assembler::EmitGenericShift(int reg_or_opcode, + Register operand, + Register shifter) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + CHECK_EQ(shifter, RCX); + EmitUint8(0xD3); + EmitOperand(reg_or_opcode, Operand(operand)); +} + +void X86_64Assembler::BuildFrame(size_t frame_size, ManagedRegister method_reg, + const std::vector<ManagedRegister>& spill_regs, + const ManagedRegisterEntrySpills& entry_spills) { + CHECK_ALIGNED(frame_size, kStackAlignment); + for (int i = spill_regs.size() - 1; i >= 0; --i) { + pushq(spill_regs.at(i).AsX86_64().AsCpuRegister()); + } + // return address then method on stack + addq(RSP, Immediate(-frame_size + (spill_regs.size() * kPointerSize) + + kPointerSize /*method*/ + kPointerSize /*return address*/)); + pushq(method_reg.AsX86_64().AsCpuRegister()); + + for (size_t i = 0; i < entry_spills.size(); ++i) { + ManagedRegisterSpill spill = entry_spills.at(i); + if (spill.AsX86_64().IsCpuRegister()) { + if (spill.getSize() == 8) { + movq(Address(RSP, frame_size + spill.getSpillOffset()), spill.AsX86_64().AsCpuRegister()); + } else { + CHECK_EQ(spill.getSize(), 4); + movl(Address(RSP, frame_size + spill.getSpillOffset()), spill.AsX86_64().AsCpuRegister()); + } + } else { + if (spill.getSize() == 8) { + movsd(Address(RSP, frame_size + spill.getSpillOffset()), spill.AsX86_64().AsXmmRegister()); + } else { + CHECK_EQ(spill.getSize(), 4); + movss(Address(RSP, frame_size + spill.getSpillOffset()), spill.AsX86_64().AsXmmRegister()); + } + } + } +} + +void X86_64Assembler::RemoveFrame(size_t frame_size, + const std::vector<ManagedRegister>& spill_regs) { + CHECK_ALIGNED(frame_size, kStackAlignment); + addq(RSP, Immediate(frame_size - (spill_regs.size() * kPointerSize) - kPointerSize)); + for (size_t i = 0; i < spill_regs.size(); ++i) { + popq(spill_regs.at(i).AsX86_64().AsCpuRegister()); + } + ret(); +} + +void X86_64Assembler::IncreaseFrameSize(size_t adjust) { + CHECK_ALIGNED(adjust, kStackAlignment); + addq(RSP, Immediate(-adjust)); +} + +void X86_64Assembler::DecreaseFrameSize(size_t adjust) { + CHECK_ALIGNED(adjust, kStackAlignment); + addq(RSP, Immediate(adjust)); +} + +void X86_64Assembler::Store(FrameOffset offs, ManagedRegister msrc, size_t size) { + X86_64ManagedRegister src = msrc.AsX86_64(); + if (src.IsNoRegister()) { + CHECK_EQ(0u, size); + } else if (src.IsCpuRegister()) { + if (size == 4) { + CHECK_EQ(4u, size); + movl(Address(RSP, offs), src.AsCpuRegister()); + } else { + CHECK_EQ(8u, size); + movq(Address(RSP, offs), src.AsCpuRegister()); + } + } else if (src.IsRegisterPair()) { + CHECK_EQ(0u, size); + movq(Address(RSP, offs), src.AsRegisterPairLow()); + movq(Address(RSP, FrameOffset(offs.Int32Value()+4)), + src.AsRegisterPairHigh()); + } else if (src.IsX87Register()) { + if (size == 4) { + fstps(Address(RSP, offs)); + } else { + fstpl(Address(RSP, offs)); + } + } else { + CHECK(src.IsXmmRegister()); + if (size == 4) { + movss(Address(RSP, offs), src.AsXmmRegister()); + } else { + movsd(Address(RSP, offs), src.AsXmmRegister()); + } + } +} + +void X86_64Assembler::StoreRef(FrameOffset dest, ManagedRegister msrc) { + X86_64ManagedRegister src = msrc.AsX86_64(); + CHECK(src.IsCpuRegister()); + movq(Address(RSP, dest), src.AsCpuRegister()); +} + +void X86_64Assembler::StoreRawPtr(FrameOffset dest, ManagedRegister msrc) { + X86_64ManagedRegister src = msrc.AsX86_64(); + CHECK(src.IsCpuRegister()); + movq(Address(RSP, dest), src.AsCpuRegister()); +} + +void X86_64Assembler::StoreImmediateToFrame(FrameOffset dest, uint32_t imm, + ManagedRegister) { + movl(Address(RSP, dest), Immediate(imm)); // TODO(64) movq? +} + +void X86_64Assembler::StoreImmediateToThread(ThreadOffset dest, uint32_t imm, + ManagedRegister) { + gs()->movl(Address::Absolute(dest, true), Immediate(imm)); // TODO(64) movq? +} + +void X86_64Assembler::StoreStackOffsetToThread(ThreadOffset thr_offs, + FrameOffset fr_offs, + ManagedRegister mscratch) { + X86_64ManagedRegister scratch = mscratch.AsX86_64(); + CHECK(scratch.IsCpuRegister()); + leaq(scratch.AsCpuRegister(), Address(RSP, fr_offs)); + gs()->movq(Address::Absolute(thr_offs, true), scratch.AsCpuRegister()); +} + +void X86_64Assembler::StoreStackPointerToThread(ThreadOffset thr_offs) { + gs()->movq(Address::Absolute(thr_offs, true), RSP); +} + +void X86_64Assembler::StoreLabelToThread(ThreadOffset thr_offs, Label* lbl) { + gs()->movl(Address::Absolute(thr_offs, true), lbl); // TODO(64) movq? +} + +void X86_64Assembler::StoreSpanning(FrameOffset /*dst*/, ManagedRegister /*src*/, + FrameOffset /*in_off*/, ManagedRegister /*scratch*/) { + UNIMPLEMENTED(FATAL); // this case only currently exists for ARM +} + +void X86_64Assembler::Load(ManagedRegister mdest, FrameOffset src, size_t size) { + X86_64ManagedRegister dest = mdest.AsX86_64(); + if (dest.IsNoRegister()) { + CHECK_EQ(0u, size); + } else if (dest.IsCpuRegister()) { + if (size == 4) { + CHECK_EQ(4u, size); + movl(dest.AsCpuRegister(), Address(RSP, src)); + } else { + CHECK_EQ(8u, size); + movq(dest.AsCpuRegister(), Address(RSP, src)); + } + } else if (dest.IsRegisterPair()) { + CHECK_EQ(0u, size); + movq(dest.AsRegisterPairLow(), Address(RSP, src)); + movq(dest.AsRegisterPairHigh(), Address(RSP, FrameOffset(src.Int32Value()+4))); + } else if (dest.IsX87Register()) { + if (size == 4) { + flds(Address(RSP, src)); + } else { + fldl(Address(RSP, src)); + } + } else { + CHECK(dest.IsXmmRegister()); + if (size == 4) { + movss(dest.AsXmmRegister(), Address(RSP, src)); + } else { + movsd(dest.AsXmmRegister(), Address(RSP, src)); + } + } +} + +void X86_64Assembler::Load(ManagedRegister mdest, ThreadOffset src, size_t size) { + X86_64ManagedRegister dest = mdest.AsX86_64(); + if (dest.IsNoRegister()) { + CHECK_EQ(0u, size); + } else if (dest.IsCpuRegister()) { + CHECK_EQ(4u, size); + gs()->movq(dest.AsCpuRegister(), Address::Absolute(src, true)); + } else if (dest.IsRegisterPair()) { + CHECK_EQ(8u, size); + gs()->movq(dest.AsRegisterPairLow(), Address::Absolute(src, true)); + gs()->movq(dest.AsRegisterPairHigh(), Address::Absolute(ThreadOffset(src.Int32Value()+4), true)); + } else if (dest.IsX87Register()) { + if (size == 4) { + gs()->flds(Address::Absolute(src, true)); + } else { + gs()->fldl(Address::Absolute(src, true)); + } + } else { + CHECK(dest.IsXmmRegister()); + if (size == 4) { + gs()->movss(dest.AsXmmRegister(), Address::Absolute(src, true)); + } else { + gs()->movsd(dest.AsXmmRegister(), Address::Absolute(src, true)); + } + } +} + +void X86_64Assembler::LoadRef(ManagedRegister mdest, FrameOffset src) { + X86_64ManagedRegister dest = mdest.AsX86_64(); + CHECK(dest.IsCpuRegister()); + movq(dest.AsCpuRegister(), Address(RSP, src)); +} + +void X86_64Assembler::LoadRef(ManagedRegister mdest, ManagedRegister base, + MemberOffset offs) { + X86_64ManagedRegister dest = mdest.AsX86_64(); + CHECK(dest.IsCpuRegister() && dest.IsCpuRegister()); + movq(dest.AsCpuRegister(), Address(base.AsX86_64().AsCpuRegister(), offs)); +} + +void X86_64Assembler::LoadRawPtr(ManagedRegister mdest, ManagedRegister base, + Offset offs) { + X86_64ManagedRegister dest = mdest.AsX86_64(); + CHECK(dest.IsCpuRegister() && dest.IsCpuRegister()); + movq(dest.AsCpuRegister(), Address(base.AsX86_64().AsCpuRegister(), offs)); +} + +void X86_64Assembler::LoadRawPtrFromThread(ManagedRegister mdest, + ThreadOffset offs) { + X86_64ManagedRegister dest = mdest.AsX86_64(); + CHECK(dest.IsCpuRegister()); + gs()->movq(dest.AsCpuRegister(), Address::Absolute(offs, true)); +} + +void X86_64Assembler::SignExtend(ManagedRegister mreg, size_t size) { + X86_64ManagedRegister reg = mreg.AsX86_64(); + CHECK(size == 1 || size == 2) << size; + CHECK(reg.IsCpuRegister()) << reg; + if (size == 1) { + movsxb(reg.AsCpuRegister(), reg.AsByteRegister()); + } else { + movsxw(reg.AsCpuRegister(), reg.AsCpuRegister()); + } +} + +void X86_64Assembler::ZeroExtend(ManagedRegister mreg, size_t size) { + X86_64ManagedRegister reg = mreg.AsX86_64(); + CHECK(size == 1 || size == 2) << size; + CHECK(reg.IsCpuRegister()) << reg; + if (size == 1) { + movzxb(reg.AsCpuRegister(), reg.AsByteRegister()); + } else { + movzxw(reg.AsCpuRegister(), reg.AsCpuRegister()); + } +} + +void X86_64Assembler::Move(ManagedRegister mdest, ManagedRegister msrc, size_t size) { + X86_64ManagedRegister dest = mdest.AsX86_64(); + X86_64ManagedRegister src = msrc.AsX86_64(); + if (!dest.Equals(src)) { + if (dest.IsCpuRegister() && src.IsCpuRegister()) { + movq(dest.AsCpuRegister(), src.AsCpuRegister()); + } else if (src.IsX87Register() && dest.IsXmmRegister()) { + // Pass via stack and pop X87 register + subl(RSP, Immediate(16)); + if (size == 4) { + CHECK_EQ(src.AsX87Register(), ST0); + fstps(Address(RSP, 0)); + movss(dest.AsXmmRegister(), Address(RSP, 0)); + } else { + CHECK_EQ(src.AsX87Register(), ST0); + fstpl(Address(RSP, 0)); + movsd(dest.AsXmmRegister(), Address(RSP, 0)); + } + addq(RSP, Immediate(16)); + } else { + // TODO: x87, SSE + UNIMPLEMENTED(FATAL) << ": Move " << dest << ", " << src; + } + } +} + +void X86_64Assembler::CopyRef(FrameOffset dest, FrameOffset src, + ManagedRegister mscratch) { + X86_64ManagedRegister scratch = mscratch.AsX86_64(); + CHECK(scratch.IsCpuRegister()); + movl(scratch.AsCpuRegister(), Address(RSP, src)); + movl(Address(RSP, dest), scratch.AsCpuRegister()); +} + +void X86_64Assembler::CopyRawPtrFromThread(FrameOffset fr_offs, + ThreadOffset thr_offs, + ManagedRegister mscratch) { + X86_64ManagedRegister scratch = mscratch.AsX86_64(); + CHECK(scratch.IsCpuRegister()); + gs()->movq(scratch.AsCpuRegister(), Address::Absolute(thr_offs, true)); + Store(fr_offs, scratch, 8); +} + +void X86_64Assembler::CopyRawPtrToThread(ThreadOffset thr_offs, + FrameOffset fr_offs, + ManagedRegister mscratch) { + X86_64ManagedRegister scratch = mscratch.AsX86_64(); + CHECK(scratch.IsCpuRegister()); + Load(scratch, fr_offs, 8); + gs()->movq(Address::Absolute(thr_offs, true), scratch.AsCpuRegister()); +} + +void X86_64Assembler::Copy(FrameOffset dest, FrameOffset src, + ManagedRegister mscratch, + size_t size) { + X86_64ManagedRegister scratch = mscratch.AsX86_64(); + if (scratch.IsCpuRegister() && size == 8) { + Load(scratch, src, 4); + Store(dest, scratch, 4); + Load(scratch, FrameOffset(src.Int32Value() + 4), 4); + Store(FrameOffset(dest.Int32Value() + 4), scratch, 4); + } else { + Load(scratch, src, size); + Store(dest, scratch, size); + } +} + +void X86_64Assembler::Copy(FrameOffset /*dst*/, ManagedRegister /*src_base*/, Offset /*src_offset*/, + ManagedRegister /*scratch*/, size_t /*size*/) { + UNIMPLEMENTED(FATAL); +} + +void X86_64Assembler::Copy(ManagedRegister dest_base, Offset dest_offset, FrameOffset src, + ManagedRegister scratch, size_t size) { + CHECK(scratch.IsNoRegister()); + CHECK_EQ(size, 4u); + pushq(Address(RSP, src)); + popq(Address(dest_base.AsX86_64().AsCpuRegister(), dest_offset)); +} + +void X86_64Assembler::Copy(FrameOffset dest, FrameOffset src_base, Offset src_offset, + ManagedRegister mscratch, size_t size) { + Register scratch = mscratch.AsX86_64().AsCpuRegister(); + CHECK_EQ(size, 4u); + movq(scratch, Address(RSP, src_base)); + movq(scratch, Address(scratch, src_offset)); + movq(Address(RSP, dest), scratch); +} + +void X86_64Assembler::Copy(ManagedRegister dest, Offset dest_offset, + ManagedRegister src, Offset src_offset, + ManagedRegister scratch, size_t size) { + CHECK_EQ(size, 4u); + CHECK(scratch.IsNoRegister()); + pushq(Address(src.AsX86_64().AsCpuRegister(), src_offset)); + popq(Address(dest.AsX86_64().AsCpuRegister(), dest_offset)); +} + +void X86_64Assembler::Copy(FrameOffset dest, Offset dest_offset, FrameOffset src, Offset src_offset, + ManagedRegister mscratch, size_t size) { + Register scratch = mscratch.AsX86_64().AsCpuRegister(); + CHECK_EQ(size, 4u); + CHECK_EQ(dest.Int32Value(), src.Int32Value()); + movq(scratch, Address(RSP, src)); + pushq(Address(scratch, src_offset)); + popq(Address(scratch, dest_offset)); +} + +void X86_64Assembler::MemoryBarrier(ManagedRegister) { +#if ANDROID_SMP != 0 + mfence(); +#endif +} + +void X86_64Assembler::CreateSirtEntry(ManagedRegister mout_reg, + FrameOffset sirt_offset, + ManagedRegister min_reg, bool null_allowed) { + X86_64ManagedRegister out_reg = mout_reg.AsX86_64(); + X86_64ManagedRegister in_reg = min_reg.AsX86_64(); + if (in_reg.IsNoRegister()) { // TODO(64): && null_allowed + // Use out_reg as indicator of NULL + in_reg = out_reg; + // TODO: movzwl + movl(in_reg.AsCpuRegister(), Address(RSP, sirt_offset)); + } + CHECK(in_reg.IsCpuRegister()); + CHECK(out_reg.IsCpuRegister()); + VerifyObject(in_reg, null_allowed); + if (null_allowed) { + Label null_arg; + if (!out_reg.Equals(in_reg)) { + xorl(out_reg.AsCpuRegister(), out_reg.AsCpuRegister()); + } + testl(in_reg.AsCpuRegister(), in_reg.AsCpuRegister()); + j(kZero, &null_arg); + leaq(out_reg.AsCpuRegister(), Address(RSP, sirt_offset)); + Bind(&null_arg); + } else { + leaq(out_reg.AsCpuRegister(), Address(RSP, sirt_offset)); + } +} + +void X86_64Assembler::CreateSirtEntry(FrameOffset out_off, + FrameOffset sirt_offset, + ManagedRegister mscratch, + bool null_allowed) { + X86_64ManagedRegister scratch = mscratch.AsX86_64(); + CHECK(scratch.IsCpuRegister()); + if (null_allowed) { + Label null_arg; + movl(scratch.AsCpuRegister(), Address(RSP, sirt_offset)); + testl(scratch.AsCpuRegister(), scratch.AsCpuRegister()); + j(kZero, &null_arg); + leaq(scratch.AsCpuRegister(), Address(RSP, sirt_offset)); + Bind(&null_arg); + } else { + leaq(scratch.AsCpuRegister(), Address(RSP, sirt_offset)); + } + Store(out_off, scratch, 8); +} + +// Given a SIRT entry, load the associated reference. +void X86_64Assembler::LoadReferenceFromSirt(ManagedRegister mout_reg, + ManagedRegister min_reg) { + X86_64ManagedRegister out_reg = mout_reg.AsX86_64(); + X86_64ManagedRegister in_reg = min_reg.AsX86_64(); + CHECK(out_reg.IsCpuRegister()); + CHECK(in_reg.IsCpuRegister()); + Label null_arg; + if (!out_reg.Equals(in_reg)) { + xorl(out_reg.AsCpuRegister(), out_reg.AsCpuRegister()); + } + testl(in_reg.AsCpuRegister(), in_reg.AsCpuRegister()); + j(kZero, &null_arg); + movq(out_reg.AsCpuRegister(), Address(in_reg.AsCpuRegister(), 0)); + Bind(&null_arg); +} + +void X86_64Assembler::VerifyObject(ManagedRegister /*src*/, bool /*could_be_null*/) { + // TODO: not validating references +} + +void X86_64Assembler::VerifyObject(FrameOffset /*src*/, bool /*could_be_null*/) { + // TODO: not validating references +} + +void X86_64Assembler::Call(ManagedRegister mbase, Offset offset, ManagedRegister) { + X86_64ManagedRegister base = mbase.AsX86_64(); + CHECK(base.IsCpuRegister()); + call(Address(base.AsCpuRegister(), offset.Int32Value())); + // TODO: place reference map on call +} + +void X86_64Assembler::Call(FrameOffset base, Offset offset, ManagedRegister mscratch) { + Register scratch = mscratch.AsX86_64().AsCpuRegister(); + movq(scratch, Address(RSP, base)); + call(Address(scratch, offset)); +} + +void X86_64Assembler::Call(ThreadOffset offset, ManagedRegister /*mscratch*/) { + gs()->call(Address::Absolute(offset, true)); +} + +void X86_64Assembler::GetCurrentThread(ManagedRegister tr) { + gs()->movq(tr.AsX86_64().AsCpuRegister(), + Address::Absolute(Thread::SelfOffset(), true)); +} + +void X86_64Assembler::GetCurrentThread(FrameOffset offset, + ManagedRegister mscratch) { + X86_64ManagedRegister scratch = mscratch.AsX86_64(); + gs()->movq(scratch.AsCpuRegister(), Address::Absolute(Thread::SelfOffset(), true)); + movq(Address(RSP, offset), scratch.AsCpuRegister()); +} + +void X86_64Assembler::ExceptionPoll(ManagedRegister /*scratch*/, size_t stack_adjust) { + X86ExceptionSlowPath* slow = new X86ExceptionSlowPath(stack_adjust); + buffer_.EnqueueSlowPath(slow); + gs()->cmpl(Address::Absolute(Thread::ExceptionOffset(), true), Immediate(0)); + j(kNotEqual, slow->Entry()); +} + +void X86ExceptionSlowPath::Emit(Assembler *sasm) { + X86_64Assembler* sp_asm = down_cast<X86_64Assembler*>(sasm); +#define __ sp_asm-> + __ Bind(&entry_); + // Note: the return value is dead + if (stack_adjust_ != 0) { // Fix up the frame. + __ DecreaseFrameSize(stack_adjust_); + } + // Pass exception as argument in RAX + __ gs()->movq(RAX, Address::Absolute(Thread::ExceptionOffset(), true)); // TODO(64): Pass argument via RDI + __ gs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(pDeliverException), true)); + // this call should never return + __ int3(); +#undef __ +} + +static const char* kRegisterNames[] = { + "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi", + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", +}; + +std::ostream& operator<<(std::ostream& os, const Register& rhs) { + if (rhs >= RAX && rhs <= R15) { + os << kRegisterNames[rhs]; + } else { + os << "Register[" << static_cast<int>(rhs) << "]"; + } + return os; +} +} // namespace x86_64 +} // namespace art + diff --git a/compiler/utils/x86_64/assembler_x86_64.h b/compiler/utils/x86_64/assembler_x86_64.h new file mode 100644 index 0000000000..d48ba720ca --- /dev/null +++ b/compiler/utils/x86_64/assembler_x86_64.h @@ -0,0 +1,657 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ART_COMPILER_UTILS_X86_64_ASSEMBLER_X86_64_H_ +#define ART_COMPILER_UTILS_X86_64_ASSEMBLER_X86_64_H_ + +#include <vector> +#include "base/macros.h" +#include "constants_x86_64.h" +#include "globals.h" +#include "managed_register_x86_64.h" +#include "offsets.h" +#include "utils/assembler.h" +#include "utils.h" + +namespace art { +namespace x86_64 { + +class Immediate { + public: + explicit Immediate(int32_t value) : value_(value) {} + + int32_t value() const { return value_; } + + bool is_int8() const { return IsInt(8, value_); } + bool is_uint8() const { return IsUint(8, value_); } + bool is_uint16() const { return IsUint(16, value_); } + + private: + const int32_t value_; + + DISALLOW_COPY_AND_ASSIGN(Immediate); +}; + + +class Operand { + public: + uint8_t mod() const { + return (encoding_at(0) >> 6) & 3; + } + + Register rm() const { + return static_cast<Register>(encoding_at(0) & 7); + } + + ScaleFactor scale() const { + return static_cast<ScaleFactor>((encoding_at(1) >> 6) & 3); + } + + Register index() const { + return static_cast<Register>((encoding_at(1) >> 3) & 7); + } + + Register base() const { + return static_cast<Register>(encoding_at(1) & 7); + } + + int8_t disp8() const { + CHECK_GE(length_, 2); + return static_cast<int8_t>(encoding_[length_ - 1]); + } + + int32_t disp32() const { + CHECK_GE(length_, 5); + int32_t value; + memcpy(&value, &encoding_[length_ - 4], sizeof(value)); + return value; + } + + bool IsRegister(Register reg) const { + return ((encoding_[0] & 0xF8) == 0xC0) // Addressing mode is register only. + && ((encoding_[0] & 0x07) == reg); // Register codes match. + } + + protected: + // Operand can be sub classed (e.g: Address). + Operand() : length_(0) { } + + void SetModRM(int mod, Register rm) { + CHECK_EQ(mod & ~3, 0); + encoding_[0] = (mod << 6) | rm; + length_ = 1; + } + + void SetSIB(ScaleFactor scale, Register index, Register base) { + CHECK_EQ(length_, 1); + CHECK_EQ(scale & ~3, 0); + encoding_[1] = (scale << 6) | (index << 3) | base; + length_ = 2; + } + + void SetDisp8(int8_t disp) { + CHECK(length_ == 1 || length_ == 2); + encoding_[length_++] = static_cast<uint8_t>(disp); + } + + void SetDisp32(int32_t disp) { + CHECK(length_ == 1 || length_ == 2); + int disp_size = sizeof(disp); + memmove(&encoding_[length_], &disp, disp_size); + length_ += disp_size; + } + + private: + byte length_; + byte encoding_[6]; + byte padding_; + + explicit Operand(Register reg) { SetModRM(3, reg); } + + // Get the operand encoding byte at the given index. + uint8_t encoding_at(int index) const { + CHECK_GE(index, 0); + CHECK_LT(index, length_); + return encoding_[index]; + } + + friend class X86_64Assembler; + + DISALLOW_COPY_AND_ASSIGN(Operand); +}; + + +class Address : public Operand { + public: + Address(Register base, int32_t disp) { + Init(base, disp); + } + + Address(Register base, Offset disp) { + Init(base, disp.Int32Value()); + } + + Address(Register base, FrameOffset disp) { + CHECK_EQ(base, RSP); + Init(RSP, disp.Int32Value()); + } + + Address(Register base, MemberOffset disp) { + Init(base, disp.Int32Value()); + } + + void Init(Register base, int32_t disp) { + if (disp == 0 && base != RBP) { + SetModRM(0, base); + if (base == RSP) SetSIB(TIMES_1, RSP, base); + } else if (disp >= -128 && disp <= 127) { + SetModRM(1, base); + if (base == RSP) SetSIB(TIMES_1, RSP, base); + SetDisp8(disp); + } else { + SetModRM(2, base); + if (base == RSP) SetSIB(TIMES_1, RSP, base); + SetDisp32(disp); + } + } + + + Address(Register index, ScaleFactor scale, int32_t disp) { + CHECK_NE(index, RSP); // Illegal addressing mode. + SetModRM(0, RSP); + SetSIB(scale, index, RBP); + SetDisp32(disp); + } + + Address(Register base, Register index, ScaleFactor scale, int32_t disp) { + CHECK_NE(index, RSP); // Illegal addressing mode. + if (disp == 0 && base != RBP) { + SetModRM(0, RSP); + SetSIB(scale, index, base); + } else if (disp >= -128 && disp <= 127) { + SetModRM(1, RSP); + SetSIB(scale, index, base); + SetDisp8(disp); + } else { + SetModRM(2, RSP); + SetSIB(scale, index, base); + SetDisp32(disp); + } + } + + static Address Absolute(uword addr, bool has_rip = false) { + Address result; + if (has_rip) { + result.SetModRM(0, RSP); + result.SetSIB(TIMES_1, RSP, RBP); + result.SetDisp32(addr); + } else { + result.SetModRM(0, RBP); + result.SetDisp32(addr); + } + return result; + } + + static Address Absolute(ThreadOffset addr, bool has_rip = false) { + return Absolute(addr.Int32Value(), has_rip); + } + + private: + Address() {} + + DISALLOW_COPY_AND_ASSIGN(Address); +}; + + +class X86_64Assembler : public Assembler { + public: + X86_64Assembler() {} + virtual ~X86_64Assembler() {} + + /* + * Emit Machine Instructions. + */ + void call(Register reg); + void call(const Address& address); + void call(Label* label); + + void pushq(Register reg); + void pushq(const Address& address); + void pushq(const Immediate& imm); + + void popq(Register reg); + void popq(const Address& address); + + void movq(Register dst, const Immediate& src); + void movl(Register dst, const Immediate& src); + void movq(Register dst, Register src); + void movl(Register dst, Register src); + + void movq(Register dst, const Address& src); + void movl(Register dst, const Address& src); + void movq(const Address& dst, Register src); + void movl(const Address& dst, Register src); + void movl(const Address& dst, const Immediate& imm); + void movl(const Address& dst, Label* lbl); + + void movzxb(Register dst, ByteRegister src); + void movzxb(Register dst, const Address& src); + void movsxb(Register dst, ByteRegister src); + void movsxb(Register dst, const Address& src); + void movb(Register dst, const Address& src); + void movb(const Address& dst, ByteRegister src); + void movb(const Address& dst, const Immediate& imm); + + void movzxw(Register dst, Register src); + void movzxw(Register dst, const Address& src); + void movsxw(Register dst, Register src); + void movsxw(Register dst, const Address& src); + void movw(Register dst, const Address& src); + void movw(const Address& dst, Register src); + + void leaq(Register dst, const Address& src); + + void cmovl(Condition condition, Register dst, Register src); + + void setb(Condition condition, Register dst); + + void movss(XmmRegister dst, const Address& src); + void movss(const Address& dst, XmmRegister src); + void movss(XmmRegister dst, XmmRegister src); + + void movd(XmmRegister dst, Register src); + void movd(Register dst, XmmRegister src); + + void addss(XmmRegister dst, XmmRegister src); + void addss(XmmRegister dst, const Address& src); + void subss(XmmRegister dst, XmmRegister src); + void subss(XmmRegister dst, const Address& src); + void mulss(XmmRegister dst, XmmRegister src); + void mulss(XmmRegister dst, const Address& src); + void divss(XmmRegister dst, XmmRegister src); + void divss(XmmRegister dst, const Address& src); + + void movsd(XmmRegister dst, const Address& src); + void movsd(const Address& dst, XmmRegister src); + void movsd(XmmRegister dst, XmmRegister src); + + void addsd(XmmRegister dst, XmmRegister src); + void addsd(XmmRegister dst, const Address& src); + void subsd(XmmRegister dst, XmmRegister src); + void subsd(XmmRegister dst, const Address& src); + void mulsd(XmmRegister dst, XmmRegister src); + void mulsd(XmmRegister dst, const Address& src); + void divsd(XmmRegister dst, XmmRegister src); + void divsd(XmmRegister dst, const Address& src); + + void cvtsi2ss(XmmRegister dst, Register src); + void cvtsi2sd(XmmRegister dst, Register src); + + void cvtss2si(Register dst, XmmRegister src); + void cvtss2sd(XmmRegister dst, XmmRegister src); + + void cvtsd2si(Register dst, XmmRegister src); + void cvtsd2ss(XmmRegister dst, XmmRegister src); + + void cvttss2si(Register dst, XmmRegister src); + void cvttsd2si(Register dst, XmmRegister src); + + void cvtdq2pd(XmmRegister dst, XmmRegister src); + + void comiss(XmmRegister a, XmmRegister b); + void comisd(XmmRegister a, XmmRegister b); + + void sqrtsd(XmmRegister dst, XmmRegister src); + void sqrtss(XmmRegister dst, XmmRegister src); + + void xorpd(XmmRegister dst, const Address& src); + void xorpd(XmmRegister dst, XmmRegister src); + void xorps(XmmRegister dst, const Address& src); + void xorps(XmmRegister dst, XmmRegister src); + + void andpd(XmmRegister dst, const Address& src); + + void flds(const Address& src); + void fstps(const Address& dst); + + void fldl(const Address& src); + void fstpl(const Address& dst); + + void fnstcw(const Address& dst); + void fldcw(const Address& src); + + void fistpl(const Address& dst); + void fistps(const Address& dst); + void fildl(const Address& src); + + void fincstp(); + void ffree(const Immediate& index); + + void fsin(); + void fcos(); + void fptan(); + + void xchgl(Register dst, Register src); + void xchgl(Register reg, const Address& address); + + void cmpl(Register reg, const Immediate& imm); + void cmpl(Register reg0, Register reg1); + void cmpl(Register reg, const Address& address); + + void cmpl(const Address& address, Register reg); + void cmpl(const Address& address, const Immediate& imm); + + void testl(Register reg1, Register reg2); + void testl(Register reg, const Immediate& imm); + + void andl(Register dst, const Immediate& imm); + void andl(Register dst, Register src); + + void orl(Register dst, const Immediate& imm); + void orl(Register dst, Register src); + + void xorl(Register dst, Register src); + + void addl(Register dst, Register src); + void addq(Register reg, const Immediate& imm); + void addl(Register reg, const Immediate& imm); + void addl(Register reg, const Address& address); + + void addl(const Address& address, Register reg); + void addl(const Address& address, const Immediate& imm); + + void adcl(Register dst, Register src); + void adcl(Register reg, const Immediate& imm); + void adcl(Register dst, const Address& address); + + void subl(Register dst, Register src); + void subl(Register reg, const Immediate& imm); + void subl(Register reg, const Address& address); + + void cdq(); + + void idivl(Register reg); + + void imull(Register dst, Register src); + void imull(Register reg, const Immediate& imm); + void imull(Register reg, const Address& address); + + void imull(Register reg); + void imull(const Address& address); + + void mull(Register reg); + void mull(const Address& address); + + void sbbl(Register dst, Register src); + void sbbl(Register reg, const Immediate& imm); + void sbbl(Register reg, const Address& address); + + void incl(Register reg); + void incl(const Address& address); + + void decl(Register reg); + void decl(const Address& address); + + void shll(Register reg, const Immediate& imm); + void shll(Register operand, Register shifter); + void shrl(Register reg, const Immediate& imm); + void shrl(Register operand, Register shifter); + void sarl(Register reg, const Immediate& imm); + void sarl(Register operand, Register shifter); + void shld(Register dst, Register src); + + void negl(Register reg); + void notl(Register reg); + + void enter(const Immediate& imm); + void leave(); + + void ret(); + void ret(const Immediate& imm); + + void nop(); + void int3(); + void hlt(); + + void j(Condition condition, Label* label); + + void jmp(Register reg); + void jmp(const Address& address); + void jmp(Label* label); + + X86_64Assembler* lock(); + void cmpxchgl(const Address& address, Register reg); + + void mfence(); + + X86_64Assembler* gs(); + + // + // Macros for High-level operations. + // + + void AddImmediate(Register reg, const Immediate& imm); + + void LoadDoubleConstant(XmmRegister dst, double value); + + void DoubleNegate(XmmRegister d); + void FloatNegate(XmmRegister f); + + void DoubleAbs(XmmRegister reg); + + void LockCmpxchgl(const Address& address, Register reg) { + lock()->cmpxchgl(address, reg); + } + + // + // Misc. functionality + // + int PreferredLoopAlignment() { return 16; } + void Align(int alignment, int offset); + void Bind(Label* label); + + // + // Overridden common assembler high-level functionality + // + + // Emit code that will create an activation on the stack + virtual void BuildFrame(size_t frame_size, ManagedRegister method_reg, + const std::vector<ManagedRegister>& callee_save_regs, + const ManagedRegisterEntrySpills& entry_spills); + + // Emit code that will remove an activation from the stack + virtual void RemoveFrame(size_t frame_size, + const std::vector<ManagedRegister>& callee_save_regs); + + virtual void IncreaseFrameSize(size_t adjust); + virtual void DecreaseFrameSize(size_t adjust); + + // Store routines + virtual void Store(FrameOffset offs, ManagedRegister src, size_t size); + virtual void StoreRef(FrameOffset dest, ManagedRegister src); + virtual void StoreRawPtr(FrameOffset dest, ManagedRegister src); + + virtual void StoreImmediateToFrame(FrameOffset dest, uint32_t imm, + ManagedRegister scratch); + + virtual void StoreImmediateToThread(ThreadOffset dest, uint32_t imm, + ManagedRegister scratch); + + virtual void StoreStackOffsetToThread(ThreadOffset thr_offs, + FrameOffset fr_offs, + ManagedRegister scratch); + + virtual void StoreStackPointerToThread(ThreadOffset thr_offs); + + void StoreLabelToThread(ThreadOffset thr_offs, Label* lbl); + + virtual void StoreSpanning(FrameOffset dest, ManagedRegister src, + FrameOffset in_off, ManagedRegister scratch); + + // Load routines + virtual void Load(ManagedRegister dest, FrameOffset src, size_t size); + + virtual void Load(ManagedRegister dest, ThreadOffset src, size_t size); + + virtual void LoadRef(ManagedRegister dest, FrameOffset src); + + virtual void LoadRef(ManagedRegister dest, ManagedRegister base, + MemberOffset offs); + + virtual void LoadRawPtr(ManagedRegister dest, ManagedRegister base, + Offset offs); + + virtual void LoadRawPtrFromThread(ManagedRegister dest, + ThreadOffset offs); + + // Copying routines + virtual void Move(ManagedRegister dest, ManagedRegister src, size_t size); + + virtual void CopyRawPtrFromThread(FrameOffset fr_offs, ThreadOffset thr_offs, + ManagedRegister scratch); + + virtual void CopyRawPtrToThread(ThreadOffset thr_offs, FrameOffset fr_offs, + ManagedRegister scratch); + + virtual void CopyRef(FrameOffset dest, FrameOffset src, + ManagedRegister scratch); + + virtual void Copy(FrameOffset dest, FrameOffset src, ManagedRegister scratch, size_t size); + + virtual void Copy(FrameOffset dest, ManagedRegister src_base, Offset src_offset, + ManagedRegister scratch, size_t size); + + virtual void Copy(ManagedRegister dest_base, Offset dest_offset, FrameOffset src, + ManagedRegister scratch, size_t size); + + virtual void Copy(FrameOffset dest, FrameOffset src_base, Offset src_offset, + ManagedRegister scratch, size_t size); + + virtual void Copy(ManagedRegister dest, Offset dest_offset, + ManagedRegister src, Offset src_offset, + ManagedRegister scratch, size_t size); + + virtual void Copy(FrameOffset dest, Offset dest_offset, FrameOffset src, Offset src_offset, + ManagedRegister scratch, size_t size); + + virtual void MemoryBarrier(ManagedRegister); + + // Sign extension + virtual void SignExtend(ManagedRegister mreg, size_t size); + + // Zero extension + virtual void ZeroExtend(ManagedRegister mreg, size_t size); + + // Exploit fast access in managed code to Thread::Current() + virtual void GetCurrentThread(ManagedRegister tr); + virtual void GetCurrentThread(FrameOffset dest_offset, + ManagedRegister scratch); + + // Set up out_reg to hold a Object** into the SIRT, or to be NULL if the + // value is null and null_allowed. in_reg holds a possibly stale reference + // that can be used to avoid loading the SIRT entry to see if the value is + // NULL. + virtual void CreateSirtEntry(ManagedRegister out_reg, FrameOffset sirt_offset, + ManagedRegister in_reg, bool null_allowed); + + // Set up out_off to hold a Object** into the SIRT, or to be NULL if the + // value is null and null_allowed. + virtual void CreateSirtEntry(FrameOffset out_off, FrameOffset sirt_offset, + ManagedRegister scratch, bool null_allowed); + + // src holds a SIRT entry (Object**) load this into dst + virtual void LoadReferenceFromSirt(ManagedRegister dst, + ManagedRegister src); + + // Heap::VerifyObject on src. In some cases (such as a reference to this) we + // know that src may not be null. + virtual void VerifyObject(ManagedRegister src, bool could_be_null); + virtual void VerifyObject(FrameOffset src, bool could_be_null); + + // Call to address held at [base+offset] + virtual void Call(ManagedRegister base, Offset offset, + ManagedRegister scratch); + virtual void Call(FrameOffset base, Offset offset, + ManagedRegister scratch); + virtual void Call(ThreadOffset offset, ManagedRegister scratch); + + // Generate code to check if Thread::Current()->exception_ is non-null + // and branch to a ExceptionSlowPath if it is. + virtual void ExceptionPoll(ManagedRegister scratch, size_t stack_adjust); + + private: + inline void EmitUint8(uint8_t value); + inline void EmitInt32(int32_t value); + inline void EmitRegisterOperand(int rm, int reg); + inline void EmitXmmRegisterOperand(int rm, XmmRegister reg); + inline void EmitFixup(AssemblerFixup* fixup); + inline void EmitOperandSizeOverride(); + + void EmitOperand(int rm, const Operand& operand); + void EmitImmediate(const Immediate& imm); + void EmitComplex(int rm, const Operand& operand, const Immediate& immediate); + void EmitLabel(Label* label, int instruction_size); + void EmitLabelLink(Label* label); + void EmitNearLabelLink(Label* label); + + void EmitGenericShift(int rm, Register reg, const Immediate& imm); + void EmitGenericShift(int rm, Register operand, Register shifter); + void rex(Register &dst, Register &src, size_t size = 4); + void rex_reg(Register &dst, size_t size = 4); + void rex_rm(Register &src, size_t size = 4); + + DISALLOW_COPY_AND_ASSIGN(X86_64Assembler); +}; + +inline void X86_64Assembler::EmitUint8(uint8_t value) { + buffer_.Emit<uint8_t>(value); +} + +inline void X86_64Assembler::EmitInt32(int32_t value) { + buffer_.Emit<int32_t>(value); +} + +inline void X86_64Assembler::EmitRegisterOperand(int rm, int reg) { + CHECK_GE(rm, 0); + CHECK_LT(rm, 8); + buffer_.Emit<uint8_t>(0xC0 + (rm << 3) + reg); +} + +inline void X86_64Assembler::EmitXmmRegisterOperand(int rm, XmmRegister reg) { + EmitRegisterOperand(rm, static_cast<Register>(reg)); +} + +inline void X86_64Assembler::EmitFixup(AssemblerFixup* fixup) { + buffer_.EmitFixup(fixup); +} + +inline void X86_64Assembler::EmitOperandSizeOverride() { + EmitUint8(0x66); +} + +// Slowpath entered when Thread::Current()->_exception is non-null +class X86ExceptionSlowPath : public SlowPath { + public: + explicit X86ExceptionSlowPath(size_t stack_adjust) : stack_adjust_(stack_adjust) {} + virtual void Emit(Assembler *sp_asm); + private: + const size_t stack_adjust_; +}; + +} // namespace x86_64 +} // namespace art + +#endif // ART_COMPILER_UTILS_X86_64_ASSEMBLER_X86_64_H_ diff --git a/compiler/utils/x86_64/assembler_x86_64_test.cc b/compiler/utils/x86_64/assembler_x86_64_test.cc new file mode 100644 index 0000000000..df0d14e9c8 --- /dev/null +++ b/compiler/utils/x86_64/assembler_x86_64_test.cc @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "assembler_x86_64.h" + +#include "gtest/gtest.h" + +namespace art { + +TEST(AssemblerX86_64, CreateBuffer) { + AssemblerBuffer buffer; + AssemblerBuffer::EnsureCapacity ensured(&buffer); + buffer.Emit<uint8_t>(0x42); + ASSERT_EQ(static_cast<size_t>(1), buffer.Size()); + buffer.Emit<int32_t>(42); + ASSERT_EQ(static_cast<size_t>(5), buffer.Size()); +} + +} // namespace art diff --git a/compiler/utils/x86_64/constants_x86_64.h b/compiler/utils/x86_64/constants_x86_64.h new file mode 100644 index 0000000000..33408027d4 --- /dev/null +++ b/compiler/utils/x86_64/constants_x86_64.h @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ART_COMPILER_UTILS_X86_64_CONSTANTS_X86_64_H_ +#define ART_COMPILER_UTILS_X86_64_CONSTANTS_X86_64_H_ + +#include <iosfwd> + +#include "arch/x86_64/registers_x86_64.h" +#include "base/logging.h" +#include "base/macros.h" +#include "globals.h" + +namespace art { +namespace x86_64 { + +enum ByteRegister { + AL = 0, + CL = 1, + DL = 2, + BL = 3, + AH = 4, + CH = 5, + DH = 6, + BH = 7, + kNoByteRegister = -1 // Signals an illegal register. +}; + + +enum XmmRegister { + _XMM0 = 0, + _XMM1 = 1, + _XMM2 = 2, + _XMM3 = 3, + _XMM4 = 4, + _XMM5 = 5, + _XMM6 = 6, + _XMM7 = 7, + kNumberOfXmmRegisters = 8, + kNoXmmRegister = -1 // Signals an illegal register. +}; +std::ostream& operator<<(std::ostream& os, const XmmRegister& reg); + +enum X87Register { + ST0 = 0, + ST1 = 1, + ST2 = 2, + ST3 = 3, + ST4 = 4, + ST5 = 5, + ST6 = 6, + ST7 = 7, + kNumberOfX87Registers = 8, + kNoX87Register = -1 // Signals an illegal register. +}; +std::ostream& operator<<(std::ostream& os, const X87Register& reg); + +enum ScaleFactor { + TIMES_1 = 0, + TIMES_2 = 1, + TIMES_4 = 2, + TIMES_8 = 3 +}; + +enum Condition { + kOverflow = 0, + kNoOverflow = 1, + kBelow = 2, + kAboveEqual = 3, + kEqual = 4, + kNotEqual = 5, + kBelowEqual = 6, + kAbove = 7, + kSign = 8, + kNotSign = 9, + kParityEven = 10, + kParityOdd = 11, + kLess = 12, + kGreaterEqual = 13, + kLessEqual = 14, + kGreater = 15, + + kZero = kEqual, + kNotZero = kNotEqual, + kNegative = kSign, + kPositive = kNotSign +}; + + +class Instr { + public: + static const uint8_t kHltInstruction = 0xF4; + // We prefer not to use the int3 instruction since it conflicts with gdb. + static const uint8_t kBreakPointInstruction = kHltInstruction; + + bool IsBreakPoint() { + return (*reinterpret_cast<const uint8_t*>(this)) == kBreakPointInstruction; + } + + // Instructions are read out of a code stream. The only way to get a + // reference to an instruction is to convert a pointer. There is no way + // to allocate or create instances of class Instr. + // Use the At(pc) function to create references to Instr. + static Instr* At(uintptr_t pc) { return reinterpret_cast<Instr*>(pc); } + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(Instr); +}; + +} // namespace x86_64 +} // namespace art + +#endif // ART_COMPILER_UTILS_X86_64_CONSTANTS_X86_64_H_ diff --git a/compiler/utils/x86_64/managed_register_x86_64.cc b/compiler/utils/x86_64/managed_register_x86_64.cc new file mode 100644 index 0000000000..057a894d27 --- /dev/null +++ b/compiler/utils/x86_64/managed_register_x86_64.cc @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "managed_register_x86_64.h" + +#include "globals.h" + +namespace art { +namespace x86_64 { + +// Define register pairs. +// This list must be kept in sync with the RegisterPair enum. +#define REGISTER_PAIR_LIST(P) \ + P(RAX, RDX) \ + P(RAX, RCX) \ + P(RAX, RBX) \ + P(RAX, RDI) \ + P(RDX, RCX) \ + P(RDX, RBX) \ + P(RDX, RDI) \ + P(RCX, RBX) \ + P(RCX, RDI) \ + P(RBX, RDI) + + +struct RegisterPairDescriptor { + RegisterPair reg; // Used to verify that the enum is in sync. + Register low; + Register high; +}; + + +static const RegisterPairDescriptor kRegisterPairs[] = { +#define REGISTER_PAIR_ENUMERATION(low, high) { low##_##high, low, high }, + REGISTER_PAIR_LIST(REGISTER_PAIR_ENUMERATION) +#undef REGISTER_PAIR_ENUMERATION +}; + +std::ostream& operator<<(std::ostream& os, const RegisterPair& reg) { + os << X86_64ManagedRegister::FromRegisterPair(reg); + return os; +} + +bool X86_64ManagedRegister::Overlaps(const X86_64ManagedRegister& other) const { + if (IsNoRegister() || other.IsNoRegister()) return false; + CHECK(IsValidManagedRegister()); + CHECK(other.IsValidManagedRegister()); + if (Equals(other)) return true; + if (IsRegisterPair()) { + Register low = AsRegisterPairLow(); + Register high = AsRegisterPairHigh(); + return X86_64ManagedRegister::FromCpuRegister(low).Overlaps(other) || + X86_64ManagedRegister::FromCpuRegister(high).Overlaps(other); + } + if (other.IsRegisterPair()) { + return other.Overlaps(*this); + } + return false; +} + + +int X86_64ManagedRegister::AllocIdLow() const { + CHECK(IsRegisterPair()); + const int r = RegId() - (kNumberOfCpuRegIds + kNumberOfXmmRegIds + + kNumberOfX87RegIds); + CHECK_EQ(r, kRegisterPairs[r].reg); + return kRegisterPairs[r].low; +} + + +int X86_64ManagedRegister::AllocIdHigh() const { + CHECK(IsRegisterPair()); + const int r = RegId() - (kNumberOfCpuRegIds + kNumberOfXmmRegIds + + kNumberOfX87RegIds); + CHECK_EQ(r, kRegisterPairs[r].reg); + return kRegisterPairs[r].high; +} + + +void X86_64ManagedRegister::Print(std::ostream& os) const { + if (!IsValidManagedRegister()) { + os << "No Register"; + } else if (IsXmmRegister()) { + os << "XMM: " << static_cast<int>(AsXmmRegister()); + } else if (IsX87Register()) { + os << "X87: " << static_cast<int>(AsX87Register()); + } else if (IsCpuRegister()) { + os << "CPU: " << static_cast<int>(AsCpuRegister()); + } else if (IsRegisterPair()) { + os << "Pair: " << AsRegisterPairLow() << ", " << AsRegisterPairHigh(); + } else { + os << "??: " << RegId(); + } +} + +std::ostream& operator<<(std::ostream& os, const X86_64ManagedRegister& reg) { + reg.Print(os); + return os; +} + +} // namespace x86_64 +} // namespace art diff --git a/compiler/utils/x86_64/managed_register_x86_64.h b/compiler/utils/x86_64/managed_register_x86_64.h new file mode 100644 index 0000000000..d68c59d2eb --- /dev/null +++ b/compiler/utils/x86_64/managed_register_x86_64.h @@ -0,0 +1,218 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ART_COMPILER_UTILS_X86_64_MANAGED_REGISTER_X86_64_H_ +#define ART_COMPILER_UTILS_X86_64_MANAGED_REGISTER_X86_64_H_ + +#include "constants_x86_64.h" +#include "utils/managed_register.h" + +namespace art { +namespace x86_64 { + +// Values for register pairs. +// The registers in kReservedCpuRegistersArray in x86.cc are not used in pairs. +// The table kRegisterPairs in x86.cc must be kept in sync with this enum. +enum RegisterPair { + RAX_RDX = 0, + RAX_RCX = 1, + RAX_RBX = 2, + RAX_RDI = 3, + RDX_RCX = 4, + RDX_RBX = 5, + RDX_RDI = 6, + RCX_RBX = 7, + RCX_RDI = 8, + RBX_RDI = 9, + kNumberOfRegisterPairs = 10, + kNoRegisterPair = -1, +}; + +std::ostream& operator<<(std::ostream& os, const RegisterPair& reg); + +const int kNumberOfCpuRegIds = kNumberOfCpuRegisters; +const int kNumberOfCpuAllocIds = kNumberOfCpuRegisters; + +const int kNumberOfXmmRegIds = kNumberOfXmmRegisters; +const int kNumberOfXmmAllocIds = kNumberOfXmmRegisters; + +const int kNumberOfX87RegIds = kNumberOfX87Registers; +const int kNumberOfX87AllocIds = kNumberOfX87Registers; + +const int kNumberOfPairRegIds = kNumberOfRegisterPairs; + +const int kNumberOfRegIds = kNumberOfCpuRegIds + kNumberOfXmmRegIds + + kNumberOfX87RegIds + kNumberOfPairRegIds; +const int kNumberOfAllocIds = kNumberOfCpuAllocIds + kNumberOfXmmAllocIds + + kNumberOfX87RegIds; + +// Register ids map: +// [0..R[ cpu registers (enum Register) +// [R..X[ xmm registers (enum XmmRegister) +// [X..S[ x87 registers (enum X87Register) +// [S..P[ register pairs (enum RegisterPair) +// where +// R = kNumberOfCpuRegIds +// X = R + kNumberOfXmmRegIds +// S = X + kNumberOfX87RegIds +// P = X + kNumberOfRegisterPairs + +// Allocation ids map: +// [0..R[ cpu registers (enum Register) +// [R..X[ xmm registers (enum XmmRegister) +// [X..S[ x87 registers (enum X87Register) +// where +// R = kNumberOfCpuRegIds +// X = R + kNumberOfXmmRegIds +// S = X + kNumberOfX87RegIds + + +// An instance of class 'ManagedRegister' represents a single cpu register (enum +// Register), an xmm register (enum XmmRegister), or a pair of cpu registers +// (enum RegisterPair). +// 'ManagedRegister::NoRegister()' provides an invalid register. +// There is a one-to-one mapping between ManagedRegister and register id. +class X86_64ManagedRegister : public ManagedRegister { + public: + ByteRegister AsByteRegister() const { + CHECK(IsCpuRegister()); + CHECK_LT(AsCpuRegister(), RSP); // RSP, RBP, ESI and RDI cannot be encoded as byte registers. + return static_cast<ByteRegister>(id_); + } + + Register AsCpuRegister() const { + CHECK(IsCpuRegister()); + return static_cast<Register>(id_); + } + + XmmRegister AsXmmRegister() const { + CHECK(IsXmmRegister()); + return static_cast<XmmRegister>(id_ - kNumberOfCpuRegIds); + } + + X87Register AsX87Register() const { + CHECK(IsX87Register()); + return static_cast<X87Register>(id_ - + (kNumberOfCpuRegIds + kNumberOfXmmRegIds)); + } + + Register AsRegisterPairLow() const { + CHECK(IsRegisterPair()); + // Appropriate mapping of register ids allows to use AllocIdLow(). + return FromRegId(AllocIdLow()).AsCpuRegister(); + } + + Register AsRegisterPairHigh() const { + CHECK(IsRegisterPair()); + // Appropriate mapping of register ids allows to use AllocIdHigh(). + return FromRegId(AllocIdHigh()).AsCpuRegister(); + } + + bool IsCpuRegister() const { + CHECK(IsValidManagedRegister()); + return (0 <= id_) && (id_ < kNumberOfCpuRegIds); + } + + bool IsXmmRegister() const { + CHECK(IsValidManagedRegister()); + const int test = id_ - kNumberOfCpuRegIds; + return (0 <= test) && (test < kNumberOfXmmRegIds); + } + + bool IsX87Register() const { + CHECK(IsValidManagedRegister()); + const int test = id_ - (kNumberOfCpuRegIds + kNumberOfXmmRegIds); + return (0 <= test) && (test < kNumberOfX87RegIds); + } + + bool IsRegisterPair() const { + CHECK(IsValidManagedRegister()); + const int test = id_ - + (kNumberOfCpuRegIds + kNumberOfXmmRegIds + kNumberOfX87RegIds); + return (0 <= test) && (test < kNumberOfPairRegIds); + } + + void Print(std::ostream& os) const; + + // Returns true if the two managed-registers ('this' and 'other') overlap. + // Either managed-register may be the NoRegister. If both are the NoRegister + // then false is returned. + bool Overlaps(const X86_64ManagedRegister& other) const; + + static X86_64ManagedRegister FromCpuRegister(Register r) { + CHECK_NE(r, kNoRegister); + return FromRegId(r); + } + + static X86_64ManagedRegister FromXmmRegister(XmmRegister r) { + CHECK_NE(r, kNoXmmRegister); + return FromRegId(r + kNumberOfCpuRegIds); + } + + static X86_64ManagedRegister FromX87Register(X87Register r) { + CHECK_NE(r, kNoX87Register); + return FromRegId(r + kNumberOfCpuRegIds + kNumberOfXmmRegIds); + } + + static X86_64ManagedRegister FromRegisterPair(RegisterPair r) { + CHECK_NE(r, kNoRegisterPair); + return FromRegId(r + (kNumberOfCpuRegIds + kNumberOfXmmRegIds + + kNumberOfX87RegIds)); + } + + private: + bool IsValidManagedRegister() const { + return (0 <= id_) && (id_ < kNumberOfRegIds); + } + + int RegId() const { + CHECK(!IsNoRegister()); + return id_; + } + + int AllocId() const { + CHECK(IsValidManagedRegister() && !IsRegisterPair()); + CHECK_LT(id_, kNumberOfAllocIds); + return id_; + } + + int AllocIdLow() const; + int AllocIdHigh() const; + + friend class ManagedRegister; + + explicit X86_64ManagedRegister(int reg_id) : ManagedRegister(reg_id) {} + + static X86_64ManagedRegister FromRegId(int reg_id) { + X86_64ManagedRegister reg(reg_id); + CHECK(reg.IsValidManagedRegister()); + return reg; + } +}; + +std::ostream& operator<<(std::ostream& os, const X86_64ManagedRegister& reg); + +} // namespace x86_64 + +inline x86_64::X86_64ManagedRegister ManagedRegister::AsX86_64() const { + x86_64::X86_64ManagedRegister reg(id_); + CHECK(reg.IsNoRegister() || reg.IsValidManagedRegister()); + return reg; +} + +} // namespace art + +#endif // ART_COMPILER_UTILS_X86_64_MANAGED_REGISTER_X86_64_H_ diff --git a/compiler/utils/x86_64/managed_register_x86_64_test.cc b/compiler/utils/x86_64/managed_register_x86_64_test.cc new file mode 100644 index 0000000000..2dc7581472 --- /dev/null +++ b/compiler/utils/x86_64/managed_register_x86_64_test.cc @@ -0,0 +1,359 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "globals.h" +#include "managed_register_x86_64.h" +#include "gtest/gtest.h" + +namespace art { +namespace x86_64 { + +TEST(X86_64ManagedRegister, NoRegister) { + X86_64ManagedRegister reg = ManagedRegister::NoRegister().AsX86(); + EXPECT_TRUE(reg.IsNoRegister()); + EXPECT_TRUE(!reg.Overlaps(reg)); +} + +TEST(X86_64ManagedRegister, CpuRegister) { + X86_64ManagedRegister reg = X86_64ManagedRegister::FromCpuRegister(RAX); + EXPECT_TRUE(!reg.IsNoRegister()); + EXPECT_TRUE(reg.IsCpuRegister()); + EXPECT_TRUE(!reg.IsXmmRegister()); + EXPECT_TRUE(!reg.IsX87Register()); + EXPECT_TRUE(!reg.IsRegisterPair()); + EXPECT_EQ(RAX, reg.AsCpuRegister()); + + reg = X86_64ManagedRegister::FromCpuRegister(RBX); + EXPECT_TRUE(!reg.IsNoRegister()); + EXPECT_TRUE(reg.IsCpuRegister()); + EXPECT_TRUE(!reg.IsXmmRegister()); + EXPECT_TRUE(!reg.IsX87Register()); + EXPECT_TRUE(!reg.IsRegisterPair()); + EXPECT_EQ(RBX, reg.AsCpuRegister()); + + reg = X86_64ManagedRegister::FromCpuRegister(RCX); + EXPECT_TRUE(!reg.IsNoRegister()); + EXPECT_TRUE(reg.IsCpuRegister()); + EXPECT_TRUE(!reg.IsXmmRegister()); + EXPECT_TRUE(!reg.IsX87Register()); + EXPECT_TRUE(!reg.IsRegisterPair()); + EXPECT_EQ(RCX, reg.AsCpuRegister()); + + reg = X86_64ManagedRegister::FromCpuRegister(RDI); + EXPECT_TRUE(!reg.IsNoRegister()); + EXPECT_TRUE(reg.IsCpuRegister()); + EXPECT_TRUE(!reg.IsXmmRegister()); + EXPECT_TRUE(!reg.IsX87Register()); + EXPECT_TRUE(!reg.IsRegisterPair()); + EXPECT_EQ(RDI, reg.AsCpuRegister()); +} + +TEST(X86_64ManagedRegister, XmmRegister) { + X86_64ManagedRegister reg = X86_64ManagedRegister::FromXmmRegister(XMM0); + EXPECT_TRUE(!reg.IsNoRegister()); + EXPECT_TRUE(!reg.IsCpuRegister()); + EXPECT_TRUE(reg.IsXmmRegister()); + EXPECT_TRUE(!reg.IsX87Register()); + EXPECT_TRUE(!reg.IsRegisterPair()); + EXPECT_EQ(XMM0, reg.AsXmmRegister()); + + reg = X86_64ManagedRegister::FromXmmRegister(XMM1); + EXPECT_TRUE(!reg.IsNoRegister()); + EXPECT_TRUE(!reg.IsCpuRegister()); + EXPECT_TRUE(reg.IsXmmRegister()); + EXPECT_TRUE(!reg.IsX87Register()); + EXPECT_TRUE(!reg.IsRegisterPair()); + EXPECT_EQ(XMM1, reg.AsXmmRegister()); + + reg = X86_64ManagedRegister::FromXmmRegister(XMM7); + EXPECT_TRUE(!reg.IsNoRegister()); + EXPECT_TRUE(!reg.IsCpuRegister()); + EXPECT_TRUE(reg.IsXmmRegister()); + EXPECT_TRUE(!reg.IsX87Register()); + EXPECT_TRUE(!reg.IsRegisterPair()); + EXPECT_EQ(XMM7, reg.AsXmmRegister()); +} + +TEST(X86_64ManagedRegister, X87Register) { + X86_64ManagedRegister reg = X86_64ManagedRegister::FromX87Register(ST0); + EXPECT_TRUE(!reg.IsNoRegister()); + EXPECT_TRUE(!reg.IsCpuRegister()); + EXPECT_TRUE(!reg.IsXmmRegister()); + EXPECT_TRUE(reg.IsX87Register()); + EXPECT_TRUE(!reg.IsRegisterPair()); + EXPECT_EQ(ST0, reg.AsX87Register()); + + reg = X86_64ManagedRegister::FromX87Register(ST1); + EXPECT_TRUE(!reg.IsNoRegister()); + EXPECT_TRUE(!reg.IsCpuRegister()); + EXPECT_TRUE(!reg.IsXmmRegister()); + EXPECT_TRUE(reg.IsX87Register()); + EXPECT_TRUE(!reg.IsRegisterPair()); + EXPECT_EQ(ST1, reg.AsX87Register()); + + reg = X86_64ManagedRegister::FromX87Register(ST7); + EXPECT_TRUE(!reg.IsNoRegister()); + EXPECT_TRUE(!reg.IsCpuRegister()); + EXPECT_TRUE(!reg.IsXmmRegister()); + EXPECT_TRUE(reg.IsX87Register()); + EXPECT_TRUE(!reg.IsRegisterPair()); + EXPECT_EQ(ST7, reg.AsX87Register()); +} + +TEST(X86_64ManagedRegister, RegisterPair) { + X86_64ManagedRegister reg = X86_64ManagedRegister::FromRegisterPair(EAX_EDX); + EXPECT_TRUE(!reg.IsNoRegister()); + EXPECT_TRUE(!reg.IsCpuRegister()); + EXPECT_TRUE(!reg.IsXmmRegister()); + EXPECT_TRUE(!reg.IsX87Register()); + EXPECT_TRUE(reg.IsRegisterPair()); + EXPECT_EQ(RAX, reg.AsRegisterPairLow()); + EXPECT_EQ(RDX, reg.AsRegisterPairHigh()); + + reg = X86_64ManagedRegister::FromRegisterPair(EAX_ECX); + EXPECT_TRUE(!reg.IsNoRegister()); + EXPECT_TRUE(!reg.IsCpuRegister()); + EXPECT_TRUE(!reg.IsXmmRegister()); + EXPECT_TRUE(!reg.IsX87Register()); + EXPECT_TRUE(reg.IsRegisterPair()); + EXPECT_EQ(RAX, reg.AsRegisterPairLow()); + EXPECT_EQ(RCX, reg.AsRegisterPairHigh()); + + reg = X86_64ManagedRegister::FromRegisterPair(EAX_EBX); + EXPECT_TRUE(!reg.IsNoRegister()); + EXPECT_TRUE(!reg.IsCpuRegister()); + EXPECT_TRUE(!reg.IsXmmRegister()); + EXPECT_TRUE(!reg.IsX87Register()); + EXPECT_TRUE(reg.IsRegisterPair()); + EXPECT_EQ(RAX, reg.AsRegisterPairLow()); + EXPECT_EQ(RBX, reg.AsRegisterPairHigh()); + + reg = X86_64ManagedRegister::FromRegisterPair(EAX_EDI); + EXPECT_TRUE(!reg.IsNoRegister()); + EXPECT_TRUE(!reg.IsCpuRegister()); + EXPECT_TRUE(!reg.IsXmmRegister()); + EXPECT_TRUE(!reg.IsX87Register()); + EXPECT_TRUE(reg.IsRegisterPair()); + EXPECT_EQ(RAX, reg.AsRegisterPairLow()); + EXPECT_EQ(RDI, reg.AsRegisterPairHigh()); + + reg = X86_64ManagedRegister::FromRegisterPair(EDX_ECX); + EXPECT_TRUE(!reg.IsNoRegister()); + EXPECT_TRUE(!reg.IsCpuRegister()); + EXPECT_TRUE(!reg.IsXmmRegister()); + EXPECT_TRUE(!reg.IsX87Register()); + EXPECT_TRUE(reg.IsRegisterPair()); + EXPECT_EQ(RDX, reg.AsRegisterPairLow()); + EXPECT_EQ(RCX, reg.AsRegisterPairHigh()); + + reg = X86_64ManagedRegister::FromRegisterPair(EDX_EBX); + EXPECT_TRUE(!reg.IsNoRegister()); + EXPECT_TRUE(!reg.IsCpuRegister()); + EXPECT_TRUE(!reg.IsXmmRegister()); + EXPECT_TRUE(!reg.IsX87Register()); + EXPECT_TRUE(reg.IsRegisterPair()); + EXPECT_EQ(RDX, reg.AsRegisterPairLow()); + EXPECT_EQ(RBX, reg.AsRegisterPairHigh()); + + reg = X86_64ManagedRegister::FromRegisterPair(EDX_EDI); + EXPECT_TRUE(!reg.IsNoRegister()); + EXPECT_TRUE(!reg.IsCpuRegister()); + EXPECT_TRUE(!reg.IsXmmRegister()); + EXPECT_TRUE(!reg.IsX87Register()); + EXPECT_TRUE(reg.IsRegisterPair()); + EXPECT_EQ(RDX, reg.AsRegisterPairLow()); + EXPECT_EQ(RDI, reg.AsRegisterPairHigh()); + + reg = X86_64ManagedRegister::FromRegisterPair(ECX_EBX); + EXPECT_TRUE(!reg.IsNoRegister()); + EXPECT_TRUE(!reg.IsCpuRegister()); + EXPECT_TRUE(!reg.IsXmmRegister()); + EXPECT_TRUE(!reg.IsX87Register()); + EXPECT_TRUE(reg.IsRegisterPair()); + EXPECT_EQ(RCX, reg.AsRegisterPairLow()); + EXPECT_EQ(RBX, reg.AsRegisterPairHigh()); + + reg = X86_64ManagedRegister::FromRegisterPair(ECX_EDI); + EXPECT_TRUE(!reg.IsNoRegister()); + EXPECT_TRUE(!reg.IsCpuRegister()); + EXPECT_TRUE(!reg.IsXmmRegister()); + EXPECT_TRUE(!reg.IsX87Register()); + EXPECT_TRUE(reg.IsRegisterPair()); + EXPECT_EQ(RCX, reg.AsRegisterPairLow()); + EXPECT_EQ(RDI, reg.AsRegisterPairHigh()); + + reg = X86_64ManagedRegister::FromRegisterPair(EBX_EDI); + EXPECT_TRUE(!reg.IsNoRegister()); + EXPECT_TRUE(!reg.IsCpuRegister()); + EXPECT_TRUE(!reg.IsXmmRegister()); + EXPECT_TRUE(!reg.IsX87Register()); + EXPECT_TRUE(reg.IsRegisterPair()); + EXPECT_EQ(RBX, reg.AsRegisterPairLow()); + EXPECT_EQ(RDI, reg.AsRegisterPairHigh()); +} + +TEST(X86_64ManagedRegister, Equals) { + X86_64ManagedRegister reg_eax = X86_64ManagedRegister::FromCpuRegister(RAX); + EXPECT_TRUE(reg_eax.Equals(X86_64ManagedRegister::FromCpuRegister(RAX))); + EXPECT_TRUE(!reg_eax.Equals(X86_64ManagedRegister::FromCpuRegister(RBX))); + EXPECT_TRUE(!reg_eax.Equals(X86_64ManagedRegister::FromCpuRegister(RDI))); + EXPECT_TRUE(!reg_eax.Equals(X86_64ManagedRegister::FromXmmRegister(XMM0))); + EXPECT_TRUE(!reg_eax.Equals(X86_64ManagedRegister::FromXmmRegister(XMM7))); + EXPECT_TRUE(!reg_eax.Equals(X86_64ManagedRegister::FromX87Register(ST0))); + EXPECT_TRUE(!reg_eax.Equals(X86_64ManagedRegister::FromX87Register(ST7))); + EXPECT_TRUE(!reg_eax.Equals(X86_64ManagedRegister::FromRegisterPair(EAX_EDX))); + EXPECT_TRUE(!reg_eax.Equals(X86_64ManagedRegister::FromRegisterPair(EBX_EDI))); + + X86_64ManagedRegister reg_xmm0 = X86_64ManagedRegister::FromXmmRegister(XMM0); + EXPECT_TRUE(!reg_xmm0.Equals(X86_64ManagedRegister::FromCpuRegister(RAX))); + EXPECT_TRUE(!reg_xmm0.Equals(X86_64ManagedRegister::FromCpuRegister(RBX))); + EXPECT_TRUE(!reg_xmm0.Equals(X86_64ManagedRegister::FromCpuRegister(RDI))); + EXPECT_TRUE(reg_xmm0.Equals(X86_64ManagedRegister::FromXmmRegister(XMM0))); + EXPECT_TRUE(!reg_xmm0.Equals(X86_64ManagedRegister::FromXmmRegister(XMM7))); + EXPECT_TRUE(!reg_xmm0.Equals(X86_64ManagedRegister::FromX87Register(ST0))); + EXPECT_TRUE(!reg_xmm0.Equals(X86_64ManagedRegister::FromX87Register(ST7))); + EXPECT_TRUE(!reg_xmm0.Equals(X86_64ManagedRegister::FromRegisterPair(EAX_EDX))); + EXPECT_TRUE(!reg_xmm0.Equals(X86_64ManagedRegister::FromRegisterPair(EBX_EDI))); + + X86_64ManagedRegister reg_st0 = X86_64ManagedRegister::FromX87Register(ST0); + EXPECT_TRUE(!reg_st0.Equals(X86_64ManagedRegister::FromCpuRegister(RAX))); + EXPECT_TRUE(!reg_st0.Equals(X86_64ManagedRegister::FromCpuRegister(RBX))); + EXPECT_TRUE(!reg_st0.Equals(X86_64ManagedRegister::FromCpuRegister(RDI))); + EXPECT_TRUE(!reg_st0.Equals(X86_64ManagedRegister::FromXmmRegister(XMM0))); + EXPECT_TRUE(!reg_st0.Equals(X86_64ManagedRegister::FromXmmRegister(XMM7))); + EXPECT_TRUE(reg_st0.Equals(X86_64ManagedRegister::FromX87Register(ST0))); + EXPECT_TRUE(!reg_st0.Equals(X86_64ManagedRegister::FromX87Register(ST7))); + EXPECT_TRUE(!reg_st0.Equals(X86_64ManagedRegister::FromRegisterPair(EAX_EDX))); + EXPECT_TRUE(!reg_st0.Equals(X86_64ManagedRegister::FromRegisterPair(EBX_EDI))); + + X86_64ManagedRegister reg_pair = X86_64ManagedRegister::FromRegisterPair(EAX_EDX); + EXPECT_TRUE(!reg_pair.Equals(X86_64ManagedRegister::FromCpuRegister(RAX))); + EXPECT_TRUE(!reg_pair.Equals(X86_64ManagedRegister::FromCpuRegister(RBX))); + EXPECT_TRUE(!reg_pair.Equals(X86_64ManagedRegister::FromCpuRegister(RDI))); + EXPECT_TRUE(!reg_pair.Equals(X86_64ManagedRegister::FromXmmRegister(XMM0))); + EXPECT_TRUE(!reg_pair.Equals(X86_64ManagedRegister::FromXmmRegister(XMM7))); + EXPECT_TRUE(!reg_pair.Equals(X86_64ManagedRegister::FromX87Register(ST0))); + EXPECT_TRUE(!reg_pair.Equals(X86_64ManagedRegister::FromX87Register(ST7))); + EXPECT_TRUE(reg_pair.Equals(X86_64ManagedRegister::FromRegisterPair(EAX_EDX))); + EXPECT_TRUE(!reg_pair.Equals(X86_64ManagedRegister::FromRegisterPair(EBX_EDI))); +} + +TEST(X86_64ManagedRegister, Overlaps) { + X86_64ManagedRegister reg = X86_64ManagedRegister::FromCpuRegister(RAX); + EXPECT_TRUE(reg.Overlaps(X86_64ManagedRegister::FromCpuRegister(RAX))); + EXPECT_TRUE(!reg.Overlaps(X86_64ManagedRegister::FromCpuRegister(RBX))); + EXPECT_TRUE(!reg.Overlaps(X86_64ManagedRegister::FromCpuRegister(RDI))); + EXPECT_TRUE(!reg.Overlaps(X86_64ManagedRegister::FromXmmRegister(XMM0))); + EXPECT_TRUE(!reg.Overlaps(X86_64ManagedRegister::FromXmmRegister(XMM7))); + EXPECT_TRUE(!reg.Overlaps(X86_64ManagedRegister::FromX87Register(ST0))); + EXPECT_TRUE(!reg.Overlaps(X86_64ManagedRegister::FromX87Register(ST7))); + EXPECT_TRUE(reg.Overlaps(X86_64ManagedRegister::FromRegisterPair(EAX_EDX))); + EXPECT_TRUE(!reg.Overlaps(X86_64ManagedRegister::FromRegisterPair(EBX_EDI))); + + reg = X86_64ManagedRegister::FromCpuRegister(RDX); + EXPECT_TRUE(!reg.Overlaps(X86_64ManagedRegister::FromCpuRegister(RAX))); + EXPECT_TRUE(!reg.Overlaps(X86_64ManagedRegister::FromCpuRegister(RBX))); + EXPECT_TRUE(!reg.Overlaps(X86_64ManagedRegister::FromCpuRegister(RDI))); + EXPECT_TRUE(!reg.Overlaps(X86_64ManagedRegister::FromXmmRegister(XMM0))); + EXPECT_TRUE(!reg.Overlaps(X86_64ManagedRegister::FromXmmRegister(XMM7))); + EXPECT_TRUE(!reg.Overlaps(X86_64ManagedRegister::FromX87Register(ST0))); + EXPECT_TRUE(!reg.Overlaps(X86_64ManagedRegister::FromX87Register(ST7))); + EXPECT_TRUE(reg.Overlaps(X86_64ManagedRegister::FromRegisterPair(EAX_EDX))); + EXPECT_TRUE(!reg.Overlaps(X86_64ManagedRegister::FromRegisterPair(EBX_EDI))); + + reg = X86_64ManagedRegister::FromCpuRegister(RDI); + EXPECT_TRUE(!reg.Overlaps(X86_64ManagedRegister::FromCpuRegister(RAX))); + EXPECT_TRUE(!reg.Overlaps(X86_64ManagedRegister::FromCpuRegister(RBX))); + EXPECT_TRUE(reg.Overlaps(X86_64ManagedRegister::FromCpuRegister(RDI))); + EXPECT_TRUE(!reg.Overlaps(X86_64ManagedRegister::FromXmmRegister(XMM0))); + EXPECT_TRUE(!reg.Overlaps(X86_64ManagedRegister::FromXmmRegister(XMM7))); + EXPECT_TRUE(!reg.Overlaps(X86_64ManagedRegister::FromX87Register(ST0))); + EXPECT_TRUE(!reg.Overlaps(X86_64ManagedRegister::FromX87Register(ST7))); + EXPECT_TRUE(!reg.Overlaps(X86_64ManagedRegister::FromRegisterPair(EAX_EDX))); + EXPECT_TRUE(reg.Overlaps(X86_64ManagedRegister::FromRegisterPair(EBX_EDI))); + + reg = X86_64ManagedRegister::FromCpuRegister(RBX); + EXPECT_TRUE(!reg.Overlaps(X86_64ManagedRegister::FromCpuRegister(RAX))); + EXPECT_TRUE(reg.Overlaps(X86_64ManagedRegister::FromCpuRegister(RBX))); + EXPECT_TRUE(!reg.Overlaps(X86_64ManagedRegister::FromCpuRegister(RDI))); + EXPECT_TRUE(!reg.Overlaps(X86_64ManagedRegister::FromXmmRegister(XMM0))); + EXPECT_TRUE(!reg.Overlaps(X86_64ManagedRegister::FromXmmRegister(XMM7))); + EXPECT_TRUE(!reg.Overlaps(X86_64ManagedRegister::FromX87Register(ST0))); + EXPECT_TRUE(!reg.Overlaps(X86_64ManagedRegister::FromX87Register(ST7))); + EXPECT_TRUE(!reg.Overlaps(X86_64ManagedRegister::FromRegisterPair(EAX_EDX))); + EXPECT_TRUE(reg.Overlaps(X86_64ManagedRegister::FromRegisterPair(EBX_EDI))); + + reg = X86_64ManagedRegister::FromXmmRegister(XMM0); + EXPECT_TRUE(!reg.Overlaps(X86_64ManagedRegister::FromCpuRegister(RAX))); + EXPECT_TRUE(!reg.Overlaps(X86_64ManagedRegister::FromCpuRegister(RBX))); + EXPECT_TRUE(!reg.Overlaps(X86_64ManagedRegister::FromCpuRegister(RDI))); + EXPECT_TRUE(reg.Overlaps(X86_64ManagedRegister::FromXmmRegister(XMM0))); + EXPECT_TRUE(!reg.Overlaps(X86_64ManagedRegister::FromXmmRegister(XMM7))); + EXPECT_TRUE(!reg.Overlaps(X86_64ManagedRegister::FromX87Register(ST0))); + EXPECT_TRUE(!reg.Overlaps(X86_64ManagedRegister::FromX87Register(ST7))); + EXPECT_TRUE(!reg.Overlaps(X86_64ManagedRegister::FromRegisterPair(EAX_EDX))); + EXPECT_TRUE(!reg.Overlaps(X86_64ManagedRegister::FromRegisterPair(EBX_EDI))); + + reg = X86_64ManagedRegister::FromX87Register(ST0); + EXPECT_TRUE(!reg.Overlaps(X86_64ManagedRegister::FromCpuRegister(RAX))); + EXPECT_TRUE(!reg.Overlaps(X86_64ManagedRegister::FromCpuRegister(RBX))); + EXPECT_TRUE(!reg.Overlaps(X86_64ManagedRegister::FromCpuRegister(RDI))); + EXPECT_TRUE(!reg.Overlaps(X86_64ManagedRegister::FromXmmRegister(XMM0))); + EXPECT_TRUE(!reg.Overlaps(X86_64ManagedRegister::FromXmmRegister(XMM7))); + EXPECT_TRUE(reg.Overlaps(X86_64ManagedRegister::FromX87Register(ST0))); + EXPECT_TRUE(!reg.Overlaps(X86_64ManagedRegister::FromX87Register(ST7))); + EXPECT_TRUE(!reg.Overlaps(X86_64ManagedRegister::FromRegisterPair(EAX_EDX))); + EXPECT_TRUE(!reg.Overlaps(X86_64ManagedRegister::FromRegisterPair(EBX_EDI))); + + reg = X86_64ManagedRegister::FromRegisterPair(EAX_EDX); + EXPECT_TRUE(reg.Overlaps(X86_64ManagedRegister::FromCpuRegister(RAX))); + EXPECT_TRUE(!reg.Overlaps(X86_64ManagedRegister::FromCpuRegister(RBX))); + EXPECT_TRUE(!reg.Overlaps(X86_64ManagedRegister::FromCpuRegister(RDI))); + EXPECT_TRUE(!reg.Overlaps(X86_64ManagedRegister::FromXmmRegister(XMM0))); + EXPECT_TRUE(!reg.Overlaps(X86_64ManagedRegister::FromXmmRegister(XMM7))); + EXPECT_TRUE(!reg.Overlaps(X86_64ManagedRegister::FromX87Register(ST0))); + EXPECT_TRUE(!reg.Overlaps(X86_64ManagedRegister::FromX87Register(ST7))); + EXPECT_TRUE(reg.Overlaps(X86_64ManagedRegister::FromRegisterPair(EAX_EDX))); + EXPECT_TRUE(reg.Overlaps(X86_64ManagedRegister::FromRegisterPair(EDX_ECX))); + EXPECT_TRUE(!reg.Overlaps(X86_64ManagedRegister::FromRegisterPair(EBX_EDI))); + + reg = X86_64ManagedRegister::FromRegisterPair(EBX_EDI); + EXPECT_TRUE(!reg.Overlaps(X86_64ManagedRegister::FromCpuRegister(RAX))); + EXPECT_TRUE(reg.Overlaps(X86_64ManagedRegister::FromCpuRegister(RBX))); + EXPECT_TRUE(reg.Overlaps(X86_64ManagedRegister::FromCpuRegister(RDI))); + EXPECT_TRUE(!reg.Overlaps(X86_64ManagedRegister::FromXmmRegister(XMM0))); + EXPECT_TRUE(!reg.Overlaps(X86_64ManagedRegister::FromXmmRegister(XMM7))); + EXPECT_TRUE(!reg.Overlaps(X86_64ManagedRegister::FromX87Register(ST0))); + EXPECT_TRUE(!reg.Overlaps(X86_64ManagedRegister::FromX87Register(ST7))); + EXPECT_TRUE(!reg.Overlaps(X86_64ManagedRegister::FromRegisterPair(EAX_EDX))); + EXPECT_TRUE(reg.Overlaps(X86_64ManagedRegister::FromRegisterPair(EBX_EDI))); + EXPECT_TRUE(reg.Overlaps(X86_64ManagedRegister::FromRegisterPair(EDX_EBX))); + + reg = X86_64ManagedRegister::FromRegisterPair(EDX_ECX); + EXPECT_TRUE(!reg.Overlaps(X86_64ManagedRegister::FromCpuRegister(RAX))); + EXPECT_TRUE(!reg.Overlaps(X86_64ManagedRegister::FromCpuRegister(RBX))); + EXPECT_TRUE(!reg.Overlaps(X86_64ManagedRegister::FromCpuRegister(RDI))); + EXPECT_TRUE(!reg.Overlaps(X86_64ManagedRegister::FromXmmRegister(XMM0))); + EXPECT_TRUE(!reg.Overlaps(X86_64ManagedRegister::FromXmmRegister(XMM7))); + EXPECT_TRUE(!reg.Overlaps(X86_64ManagedRegister::FromX87Register(ST0))); + EXPECT_TRUE(!reg.Overlaps(X86_64ManagedRegister::FromX87Register(ST7))); + EXPECT_TRUE(reg.Overlaps(X86_64ManagedRegister::FromRegisterPair(EAX_EDX))); + EXPECT_TRUE(!reg.Overlaps(X86_64ManagedRegister::FromRegisterPair(EBX_EDI))); + EXPECT_TRUE(reg.Overlaps(X86_64ManagedRegister::FromRegisterPair(EDX_EBX))); +} + +} // namespace x86_64 +} // namespace art |