summaryrefslogtreecommitdiff
path: root/compiler/utils
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/utils')
-rw-r--r--compiler/utils/mips/assembler_mips.cc309
-rw-r--r--compiler/utils/mips/assembler_mips.h115
-rw-r--r--compiler/utils/mips/assembler_mips32r6_test.cc644
-rw-r--r--compiler/utils/mips/assembler_mips_test.cc653
-rw-r--r--compiler/utils/mips64/assembler_mips64.cc370
-rw-r--r--compiler/utils/mips64/assembler_mips64.h108
-rw-r--r--compiler/utils/mips64/assembler_mips64_test.cc914
7 files changed, 2038 insertions, 1075 deletions
diff --git a/compiler/utils/mips/assembler_mips.cc b/compiler/utils/mips/assembler_mips.cc
index 2cbabcfb32..18099d8e13 100644
--- a/compiler/utils/mips/assembler_mips.cc
+++ b/compiler/utils/mips/assembler_mips.cc
@@ -935,11 +935,11 @@ void MipsAssembler::Bne(Register rs, Register rt, uint16_t imm16) {
}
void MipsAssembler::Beqz(Register rt, uint16_t imm16) {
- Beq(ZERO, rt, imm16);
+ Beq(rt, ZERO, imm16);
}
void MipsAssembler::Bnez(Register rt, uint16_t imm16) {
- Bne(ZERO, rt, imm16);
+ Bne(rt, ZERO, imm16);
}
void MipsAssembler::Bltz(Register rt, uint16_t imm16) {
@@ -3118,7 +3118,7 @@ void MipsAssembler::Branch::InitShortOrLong(MipsAssembler::Branch::OffsetBits of
}
void MipsAssembler::Branch::InitializeType(Type initial_type, bool is_r6) {
- OffsetBits offset_size = GetOffsetSizeNeeded(location_, target_);
+ OffsetBits offset_size_needed = GetOffsetSizeNeeded(location_, target_);
if (is_r6) {
// R6
switch (initial_type) {
@@ -3131,23 +3131,31 @@ void MipsAssembler::Branch::InitializeType(Type initial_type, bool is_r6) {
type_ = kR6Literal;
break;
case kCall:
- InitShortOrLong(offset_size, kR6Call, kR6LongCall);
+ InitShortOrLong(offset_size_needed, kR6Call, kR6LongCall);
break;
case kCondBranch:
switch (condition_) {
case kUncond:
- InitShortOrLong(offset_size, kR6UncondBranch, kR6LongUncondBranch);
+ InitShortOrLong(offset_size_needed, kR6UncondBranch, kR6LongUncondBranch);
break;
case kCondEQZ:
case kCondNEZ:
// Special case for beqzc/bnezc with longer offset than in other b<cond>c instructions.
- type_ = (offset_size <= kOffset23) ? kR6CondBranch : kR6LongCondBranch;
+ type_ = (offset_size_needed <= kOffset23) ? kR6CondBranch : kR6LongCondBranch;
break;
default:
- InitShortOrLong(offset_size, kR6CondBranch, kR6LongCondBranch);
+ InitShortOrLong(offset_size_needed, kR6CondBranch, kR6LongCondBranch);
break;
}
break;
+ case kBareCall:
+ type_ = kR6BareCall;
+ CHECK_LE(offset_size_needed, GetOffsetSize());
+ break;
+ case kBareCondBranch:
+ type_ = (condition_ == kUncond) ? kR6BareUncondBranch : kR6BareCondBranch;
+ CHECK_LE(offset_size_needed, GetOffsetSize());
+ break;
default:
LOG(FATAL) << "Unexpected branch type " << initial_type;
UNREACHABLE();
@@ -3164,18 +3172,26 @@ void MipsAssembler::Branch::InitializeType(Type initial_type, bool is_r6) {
type_ = kLiteral;
break;
case kCall:
- InitShortOrLong(offset_size, kCall, kLongCall);
+ InitShortOrLong(offset_size_needed, kCall, kLongCall);
break;
case kCondBranch:
switch (condition_) {
case kUncond:
- InitShortOrLong(offset_size, kUncondBranch, kLongUncondBranch);
+ InitShortOrLong(offset_size_needed, kUncondBranch, kLongUncondBranch);
break;
default:
- InitShortOrLong(offset_size, kCondBranch, kLongCondBranch);
+ InitShortOrLong(offset_size_needed, kCondBranch, kLongCondBranch);
break;
}
break;
+ case kBareCall:
+ type_ = kBareCall;
+ CHECK_LE(offset_size_needed, GetOffsetSize());
+ break;
+ case kBareCondBranch:
+ type_ = (condition_ == kUncond) ? kBareUncondBranch : kBareCondBranch;
+ CHECK_LE(offset_size_needed, GetOffsetSize());
+ break;
default:
LOG(FATAL) << "Unexpected branch type " << initial_type;
UNREACHABLE();
@@ -3210,7 +3226,11 @@ bool MipsAssembler::Branch::IsUncond(BranchCondition condition, Register lhs, Re
}
}
-MipsAssembler::Branch::Branch(bool is_r6, uint32_t location, uint32_t target, bool is_call)
+MipsAssembler::Branch::Branch(bool is_r6,
+ uint32_t location,
+ uint32_t target,
+ bool is_call,
+ bool is_bare)
: old_location_(location),
location_(location),
target_(target),
@@ -3218,7 +3238,9 @@ MipsAssembler::Branch::Branch(bool is_r6, uint32_t location, uint32_t target, bo
rhs_reg_(0),
condition_(kUncond),
delayed_instruction_(kUnfilledDelaySlot) {
- InitializeType((is_call ? kCall : kCondBranch), is_r6);
+ InitializeType(
+ (is_call ? (is_bare ? kBareCall : kCall) : (is_bare ? kBareCondBranch : kCondBranch)),
+ is_r6);
}
MipsAssembler::Branch::Branch(bool is_r6,
@@ -3226,7 +3248,8 @@ MipsAssembler::Branch::Branch(bool is_r6,
uint32_t target,
MipsAssembler::BranchCondition condition,
Register lhs_reg,
- Register rhs_reg)
+ Register rhs_reg,
+ bool is_bare)
: old_location_(location),
location_(location),
target_(target),
@@ -3276,7 +3299,7 @@ MipsAssembler::Branch::Branch(bool is_r6,
// Branch condition is always true, make the branch unconditional.
condition_ = kUncond;
}
- InitializeType(kCondBranch, is_r6);
+ InitializeType((is_bare ? kBareCondBranch : kCondBranch), is_r6);
}
MipsAssembler::Branch::Branch(bool is_r6,
@@ -3419,20 +3442,44 @@ uint32_t MipsAssembler::Branch::GetOldEndLocation() const {
return GetOldLocation() + GetOldSize();
}
+bool MipsAssembler::Branch::IsBare() const {
+ switch (type_) {
+ // R2 short branches (can't be promoted to long), delay slots filled manually.
+ case kBareUncondBranch:
+ case kBareCondBranch:
+ case kBareCall:
+ // R6 short branches (can't be promoted to long), forbidden/delay slots filled manually.
+ case kR6BareUncondBranch:
+ case kR6BareCondBranch:
+ case kR6BareCall:
+ return true;
+ default:
+ return false;
+ }
+}
+
bool MipsAssembler::Branch::IsLong() const {
switch (type_) {
- // R2 short branches.
+ // R2 short branches (can be promoted to long).
case kUncondBranch:
case kCondBranch:
case kCall:
+ // R2 short branches (can't be promoted to long), delay slots filled manually.
+ case kBareUncondBranch:
+ case kBareCondBranch:
+ case kBareCall:
// R2 near label.
case kLabel:
// R2 near literal.
case kLiteral:
- // R6 short branches.
+ // R6 short branches (can be promoted to long).
case kR6UncondBranch:
case kR6CondBranch:
case kR6Call:
+ // R6 short branches (can't be promoted to long), forbidden/delay slots filled manually.
+ case kR6BareUncondBranch:
+ case kR6BareCondBranch:
+ case kR6BareCall:
// R6 near label.
case kR6Label:
// R6 near literal.
@@ -3464,8 +3511,9 @@ bool MipsAssembler::Branch::IsResolved() const {
}
MipsAssembler::Branch::OffsetBits MipsAssembler::Branch::GetOffsetSize() const {
+ bool r6_cond_branch = (type_ == kR6CondBranch || type_ == kR6BareCondBranch);
OffsetBits offset_size =
- (type_ == kR6CondBranch && (condition_ == kCondEQZ || condition_ == kCondNEZ))
+ (r6_cond_branch && (condition_ == kCondEQZ || condition_ == kCondNEZ))
? kOffset23
: branch_info_[type_].offset_size;
return offset_size;
@@ -3511,8 +3559,9 @@ void MipsAssembler::Branch::Relocate(uint32_t expand_location, uint32_t delta) {
}
void MipsAssembler::Branch::PromoteToLong() {
+ CHECK(!IsBare()); // Bare branches do not promote.
switch (type_) {
- // R2 short branches.
+ // R2 short branches (can be promoted to long).
case kUncondBranch:
type_ = kLongUncondBranch;
break;
@@ -3530,7 +3579,7 @@ void MipsAssembler::Branch::PromoteToLong() {
case kLiteral:
type_ = kFarLiteral;
break;
- // R6 short branches.
+ // R6 short branches (can be promoted to long).
case kR6UncondBranch:
type_ = kR6LongUncondBranch;
break;
@@ -3585,7 +3634,7 @@ uint32_t MipsAssembler::Branch::PromoteIfNeeded(uint32_t location, uint32_t max_
}
// The following logic is for debugging/testing purposes.
// Promote some short branches to long when it's not really required.
- if (UNLIKELY(max_short_distance != std::numeric_limits<uint32_t>::max())) {
+ if (UNLIKELY(max_short_distance != std::numeric_limits<uint32_t>::max() && !IsBare())) {
int64_t distance = static_cast<int64_t>(target_) - location;
distance = (distance >= 0) ? distance : -distance;
if (distance >= max_short_distance) {
@@ -3851,6 +3900,10 @@ void MipsAssembler::Branch::DecrementLocations() {
}
void MipsAssembler::MoveInstructionToDelaySlot(Branch& branch) {
+ if (branch.IsBare()) {
+ // Delay slots are filled manually in bare branches.
+ return;
+ }
if (branch.CanHaveDelayedInstruction(delay_slot_)) {
// The last instruction cannot be used in a different delay slot,
// do not commit the label before it (if any).
@@ -3870,27 +3923,32 @@ void MipsAssembler::MoveInstructionToDelaySlot(Branch& branch) {
}
}
-void MipsAssembler::Buncond(MipsLabel* label) {
+void MipsAssembler::Buncond(MipsLabel* label, bool is_r6, bool is_bare) {
uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved;
- branches_.emplace_back(IsR6(), buffer_.Size(), target, /* is_call */ false);
+ branches_.emplace_back(is_r6, buffer_.Size(), target, /* is_call */ false, is_bare);
MoveInstructionToDelaySlot(branches_.back());
FinalizeLabeledBranch(label);
}
-void MipsAssembler::Bcond(MipsLabel* label, BranchCondition condition, Register lhs, Register rhs) {
+void MipsAssembler::Bcond(MipsLabel* label,
+ bool is_r6,
+ bool is_bare,
+ BranchCondition condition,
+ Register lhs,
+ Register rhs) {
// If lhs = rhs, this can be a NOP.
if (Branch::IsNop(condition, lhs, rhs)) {
return;
}
uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved;
- branches_.emplace_back(IsR6(), buffer_.Size(), target, condition, lhs, rhs);
+ branches_.emplace_back(is_r6, buffer_.Size(), target, condition, lhs, rhs, is_bare);
MoveInstructionToDelaySlot(branches_.back());
FinalizeLabeledBranch(label);
}
-void MipsAssembler::Call(MipsLabel* label) {
+void MipsAssembler::Call(MipsLabel* label, bool is_r6, bool is_bare) {
uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved;
- branches_.emplace_back(IsR6(), buffer_.Size(), target, /* is_call */ true);
+ branches_.emplace_back(is_r6, buffer_.Size(), target, /* is_call */ true, is_bare);
MoveInstructionToDelaySlot(branches_.back());
FinalizeLabeledBranch(label);
}
@@ -4038,10 +4096,14 @@ void MipsAssembler::PromoteBranches() {
// Note: make sure branch_info_[] and EmitBranch() are kept synchronized.
const MipsAssembler::Branch::BranchInfo MipsAssembler::Branch::branch_info_[] = {
- // R2 short branches.
+ // R2 short branches (can be promoted to long).
{ 2, 0, 1, MipsAssembler::Branch::kOffset18, 2 }, // kUncondBranch
{ 2, 0, 1, MipsAssembler::Branch::kOffset18, 2 }, // kCondBranch
{ 2, 0, 1, MipsAssembler::Branch::kOffset18, 2 }, // kCall
+ // R2 short branches (can't be promoted to long), delay slots filled manually.
+ { 1, 0, 1, MipsAssembler::Branch::kOffset18, 2 }, // kBareUncondBranch
+ { 1, 0, 1, MipsAssembler::Branch::kOffset18, 2 }, // kBareCondBranch
+ { 1, 0, 1, MipsAssembler::Branch::kOffset18, 2 }, // kBareCall
// R2 near label.
{ 1, 0, 0, MipsAssembler::Branch::kOffset16, 0 }, // kLabel
// R2 near literal.
@@ -4054,11 +4116,16 @@ const MipsAssembler::Branch::BranchInfo MipsAssembler::Branch::branch_info_[] =
{ 3, 0, 0, MipsAssembler::Branch::kOffset32, 0 }, // kFarLabel
// R2 far literal.
{ 3, 0, 0, MipsAssembler::Branch::kOffset32, 0 }, // kFarLiteral
- // R6 short branches.
+ // R6 short branches (can be promoted to long).
{ 1, 0, 1, MipsAssembler::Branch::kOffset28, 2 }, // kR6UncondBranch
{ 2, 0, 1, MipsAssembler::Branch::kOffset18, 2 }, // kR6CondBranch
// Exception: kOffset23 for beqzc/bnezc.
{ 1, 0, 1, MipsAssembler::Branch::kOffset28, 2 }, // kR6Call
+ // R6 short branches (can't be promoted to long), forbidden/delay slots filled manually.
+ { 1, 0, 1, MipsAssembler::Branch::kOffset28, 2 }, // kR6BareUncondBranch
+ { 1, 0, 1, MipsAssembler::Branch::kOffset18, 2 }, // kR6BareCondBranch
+ // Exception: kOffset23 for beqzc/bnezc.
+ { 1, 0, 1, MipsAssembler::Branch::kOffset28, 2 }, // kR6BareCall
// R6 near label.
{ 1, 0, 0, MipsAssembler::Branch::kOffset21, 2 }, // kR6Label
// R6 near literal.
@@ -4124,6 +4191,21 @@ void MipsAssembler::EmitBranch(MipsAssembler::Branch* branch) {
Bal(offset);
Emit(delayed_instruction);
break;
+ case Branch::kBareUncondBranch:
+ DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot);
+ CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
+ B(offset);
+ break;
+ case Branch::kBareCondBranch:
+ DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot);
+ CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
+ EmitBcondR2(condition, lhs, rhs, offset);
+ break;
+ case Branch::kBareCall:
+ DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot);
+ CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
+ Bal(offset);
+ break;
// R2 near label.
case Branch::kLabel:
@@ -4249,6 +4331,21 @@ void MipsAssembler::EmitBranch(MipsAssembler::Branch* branch) {
CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
Balc(offset);
break;
+ case Branch::kR6BareUncondBranch:
+ DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot);
+ CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
+ Bc(offset);
+ break;
+ case Branch::kR6BareCondBranch:
+ DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot);
+ CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
+ EmitBcondR6(condition, lhs, rhs, offset);
+ break;
+ case Branch::kR6BareCall:
+ DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot);
+ CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
+ Balc(offset);
+ break;
// R6 near label.
case Branch::kR6Label:
@@ -4311,44 +4408,44 @@ void MipsAssembler::EmitBranch(MipsAssembler::Branch* branch) {
CHECK_LT(branch->GetSize(), static_cast<uint32_t>(Branch::kMaxBranchSize));
}
-void MipsAssembler::B(MipsLabel* label) {
- Buncond(label);
+void MipsAssembler::B(MipsLabel* label, bool is_bare) {
+ Buncond(label, /* is_r6 */ (IsR6() && !is_bare), is_bare);
}
-void MipsAssembler::Bal(MipsLabel* label) {
- Call(label);
+void MipsAssembler::Bal(MipsLabel* label, bool is_bare) {
+ Call(label, /* is_r6 */ (IsR6() && !is_bare), is_bare);
}
-void MipsAssembler::Beq(Register rs, Register rt, MipsLabel* label) {
- Bcond(label, kCondEQ, rs, rt);
+void MipsAssembler::Beq(Register rs, Register rt, MipsLabel* label, bool is_bare) {
+ Bcond(label, /* is_r6 */ (IsR6() && !is_bare), is_bare, kCondEQ, rs, rt);
}
-void MipsAssembler::Bne(Register rs, Register rt, MipsLabel* label) {
- Bcond(label, kCondNE, rs, rt);
+void MipsAssembler::Bne(Register rs, Register rt, MipsLabel* label, bool is_bare) {
+ Bcond(label, /* is_r6 */ (IsR6() && !is_bare), is_bare, kCondNE, rs, rt);
}
-void MipsAssembler::Beqz(Register rt, MipsLabel* label) {
- Bcond(label, kCondEQZ, rt);
+void MipsAssembler::Beqz(Register rt, MipsLabel* label, bool is_bare) {
+ Bcond(label, /* is_r6 */ (IsR6() && !is_bare), is_bare, kCondEQZ, rt);
}
-void MipsAssembler::Bnez(Register rt, MipsLabel* label) {
- Bcond(label, kCondNEZ, rt);
+void MipsAssembler::Bnez(Register rt, MipsLabel* label, bool is_bare) {
+ Bcond(label, /* is_r6 */ (IsR6() && !is_bare), is_bare, kCondNEZ, rt);
}
-void MipsAssembler::Bltz(Register rt, MipsLabel* label) {
- Bcond(label, kCondLTZ, rt);
+void MipsAssembler::Bltz(Register rt, MipsLabel* label, bool is_bare) {
+ Bcond(label, /* is_r6 */ (IsR6() && !is_bare), is_bare, kCondLTZ, rt);
}
-void MipsAssembler::Bgez(Register rt, MipsLabel* label) {
- Bcond(label, kCondGEZ, rt);
+void MipsAssembler::Bgez(Register rt, MipsLabel* label, bool is_bare) {
+ Bcond(label, /* is_r6 */ (IsR6() && !is_bare), is_bare, kCondGEZ, rt);
}
-void MipsAssembler::Blez(Register rt, MipsLabel* label) {
- Bcond(label, kCondLEZ, rt);
+void MipsAssembler::Blez(Register rt, MipsLabel* label, bool is_bare) {
+ Bcond(label, /* is_r6 */ (IsR6() && !is_bare), is_bare, kCondLEZ, rt);
}
-void MipsAssembler::Bgtz(Register rt, MipsLabel* label) {
- Bcond(label, kCondGTZ, rt);
+void MipsAssembler::Bgtz(Register rt, MipsLabel* label, bool is_bare) {
+ Bcond(label, /* is_r6 */ (IsR6() && !is_bare), is_bare, kCondGTZ, rt);
}
bool MipsAssembler::CanExchangeWithSlt(Register rs, Register rt) const {
@@ -4399,74 +4496,130 @@ void MipsAssembler::GenerateSltForCondBranch(bool unsigned_slt, Register rs, Reg
}
}
-void MipsAssembler::Blt(Register rs, Register rt, MipsLabel* label) {
- if (IsR6()) {
- Bcond(label, kCondLT, rs, rt);
+void MipsAssembler::Blt(Register rs, Register rt, MipsLabel* label, bool is_bare) {
+ if (IsR6() && !is_bare) {
+ Bcond(label, IsR6(), is_bare, kCondLT, rs, rt);
} else if (!Branch::IsNop(kCondLT, rs, rt)) {
// Synthesize the instruction (not available on R2).
GenerateSltForCondBranch(/* unsigned_slt */ false, rs, rt);
- Bnez(AT, label);
+ Bnez(AT, label, is_bare);
}
}
-void MipsAssembler::Bge(Register rs, Register rt, MipsLabel* label) {
- if (IsR6()) {
- Bcond(label, kCondGE, rs, rt);
+void MipsAssembler::Bge(Register rs, Register rt, MipsLabel* label, bool is_bare) {
+ if (IsR6() && !is_bare) {
+ Bcond(label, IsR6(), is_bare, kCondGE, rs, rt);
} else if (Branch::IsUncond(kCondGE, rs, rt)) {
- B(label);
+ B(label, is_bare);
} else {
// Synthesize the instruction (not available on R2).
GenerateSltForCondBranch(/* unsigned_slt */ false, rs, rt);
- Beqz(AT, label);
+ Beqz(AT, label, is_bare);
}
}
-void MipsAssembler::Bltu(Register rs, Register rt, MipsLabel* label) {
- if (IsR6()) {
- Bcond(label, kCondLTU, rs, rt);
+void MipsAssembler::Bltu(Register rs, Register rt, MipsLabel* label, bool is_bare) {
+ if (IsR6() && !is_bare) {
+ Bcond(label, IsR6(), is_bare, kCondLTU, rs, rt);
} else if (!Branch::IsNop(kCondLTU, rs, rt)) {
// Synthesize the instruction (not available on R2).
GenerateSltForCondBranch(/* unsigned_slt */ true, rs, rt);
- Bnez(AT, label);
+ Bnez(AT, label, is_bare);
}
}
-void MipsAssembler::Bgeu(Register rs, Register rt, MipsLabel* label) {
- if (IsR6()) {
- Bcond(label, kCondGEU, rs, rt);
+void MipsAssembler::Bgeu(Register rs, Register rt, MipsLabel* label, bool is_bare) {
+ if (IsR6() && !is_bare) {
+ Bcond(label, IsR6(), is_bare, kCondGEU, rs, rt);
} else if (Branch::IsUncond(kCondGEU, rs, rt)) {
- B(label);
+ B(label, is_bare);
} else {
// Synthesize the instruction (not available on R2).
GenerateSltForCondBranch(/* unsigned_slt */ true, rs, rt);
- Beqz(AT, label);
+ Beqz(AT, label, is_bare);
}
}
-void MipsAssembler::Bc1f(MipsLabel* label) {
- Bc1f(0, label);
+void MipsAssembler::Bc1f(MipsLabel* label, bool is_bare) {
+ Bc1f(0, label, is_bare);
}
-void MipsAssembler::Bc1f(int cc, MipsLabel* label) {
+void MipsAssembler::Bc1f(int cc, MipsLabel* label, bool is_bare) {
CHECK(IsUint<3>(cc)) << cc;
- Bcond(label, kCondF, static_cast<Register>(cc), ZERO);
+ Bcond(label, /* is_r6 */ false, is_bare, kCondF, static_cast<Register>(cc), ZERO);
}
-void MipsAssembler::Bc1t(MipsLabel* label) {
- Bc1t(0, label);
+void MipsAssembler::Bc1t(MipsLabel* label, bool is_bare) {
+ Bc1t(0, label, is_bare);
}
-void MipsAssembler::Bc1t(int cc, MipsLabel* label) {
+void MipsAssembler::Bc1t(int cc, MipsLabel* label, bool is_bare) {
CHECK(IsUint<3>(cc)) << cc;
- Bcond(label, kCondT, static_cast<Register>(cc), ZERO);
+ Bcond(label, /* is_r6 */ false, is_bare, kCondT, static_cast<Register>(cc), ZERO);
+}
+
+void MipsAssembler::Bc(MipsLabel* label, bool is_bare) {
+ Buncond(label, /* is_r6 */ true, is_bare);
+}
+
+void MipsAssembler::Balc(MipsLabel* label, bool is_bare) {
+ Call(label, /* is_r6 */ true, is_bare);
+}
+
+void MipsAssembler::Beqc(Register rs, Register rt, MipsLabel* label, bool is_bare) {
+ Bcond(label, /* is_r6 */ true, is_bare, kCondEQ, rs, rt);
+}
+
+void MipsAssembler::Bnec(Register rs, Register rt, MipsLabel* label, bool is_bare) {
+ Bcond(label, /* is_r6 */ true, is_bare, kCondNE, rs, rt);
+}
+
+void MipsAssembler::Beqzc(Register rt, MipsLabel* label, bool is_bare) {
+ Bcond(label, /* is_r6 */ true, is_bare, kCondEQZ, rt);
+}
+
+void MipsAssembler::Bnezc(Register rt, MipsLabel* label, bool is_bare) {
+ Bcond(label, /* is_r6 */ true, is_bare, kCondNEZ, rt);
+}
+
+void MipsAssembler::Bltzc(Register rt, MipsLabel* label, bool is_bare) {
+ Bcond(label, /* is_r6 */ true, is_bare, kCondLTZ, rt);
+}
+
+void MipsAssembler::Bgezc(Register rt, MipsLabel* label, bool is_bare) {
+ Bcond(label, /* is_r6 */ true, is_bare, kCondGEZ, rt);
+}
+
+void MipsAssembler::Blezc(Register rt, MipsLabel* label, bool is_bare) {
+ Bcond(label, /* is_r6 */ true, is_bare, kCondLEZ, rt);
+}
+
+void MipsAssembler::Bgtzc(Register rt, MipsLabel* label, bool is_bare) {
+ Bcond(label, /* is_r6 */ true, is_bare, kCondGTZ, rt);
+}
+
+void MipsAssembler::Bltc(Register rs, Register rt, MipsLabel* label, bool is_bare) {
+ Bcond(label, /* is_r6 */ true, is_bare, kCondLT, rs, rt);
+}
+
+void MipsAssembler::Bgec(Register rs, Register rt, MipsLabel* label, bool is_bare) {
+ Bcond(label, /* is_r6 */ true, is_bare, kCondGE, rs, rt);
+}
+
+void MipsAssembler::Bltuc(Register rs, Register rt, MipsLabel* label, bool is_bare) {
+ Bcond(label, /* is_r6 */ true, is_bare, kCondLTU, rs, rt);
+}
+
+void MipsAssembler::Bgeuc(Register rs, Register rt, MipsLabel* label, bool is_bare) {
+ Bcond(label, /* is_r6 */ true, is_bare, kCondGEU, rs, rt);
}
-void MipsAssembler::Bc1eqz(FRegister ft, MipsLabel* label) {
- Bcond(label, kCondF, static_cast<Register>(ft), ZERO);
+void MipsAssembler::Bc1eqz(FRegister ft, MipsLabel* label, bool is_bare) {
+ Bcond(label, /* is_r6 */ true, is_bare, kCondF, static_cast<Register>(ft), ZERO);
}
-void MipsAssembler::Bc1nez(FRegister ft, MipsLabel* label) {
- Bcond(label, kCondT, static_cast<Register>(ft), ZERO);
+void MipsAssembler::Bc1nez(FRegister ft, MipsLabel* label, bool is_bare) {
+ Bcond(label, /* is_r6 */ true, is_bare, kCondT, static_cast<Register>(ft), ZERO);
}
void MipsAssembler::AdjustBaseAndOffset(Register& base,
diff --git a/compiler/utils/mips/assembler_mips.h b/compiler/utils/mips/assembler_mips.h
index a7ff931e7e..7f9d5763f1 100644
--- a/compiler/utils/mips/assembler_mips.h
+++ b/compiler/utils/mips/assembler_mips.h
@@ -636,29 +636,69 @@ class MipsAssembler FINAL : public Assembler, public JNIMacroAssembler<PointerSi
void LoadSConst32(FRegister r, int32_t value, Register temp);
void Addiu32(Register rt, Register rs, int32_t value, Register rtmp = AT);
- // These will generate R2 branches or R6 branches as appropriate and take care of
- // the delay/forbidden slots.
void Bind(MipsLabel* label);
- void B(MipsLabel* label);
- void Bal(MipsLabel* label);
- void Beq(Register rs, Register rt, MipsLabel* label);
- void Bne(Register rs, Register rt, MipsLabel* label);
- void Beqz(Register rt, MipsLabel* label);
- void Bnez(Register rt, MipsLabel* label);
- void Bltz(Register rt, MipsLabel* label);
- void Bgez(Register rt, MipsLabel* label);
- void Blez(Register rt, MipsLabel* label);
- void Bgtz(Register rt, MipsLabel* label);
- void Blt(Register rs, Register rt, MipsLabel* label);
- void Bge(Register rs, Register rt, MipsLabel* label);
- void Bltu(Register rs, Register rt, MipsLabel* label);
- void Bgeu(Register rs, Register rt, MipsLabel* label);
- void Bc1f(MipsLabel* label); // R2
- void Bc1f(int cc, MipsLabel* label); // R2
- void Bc1t(MipsLabel* label); // R2
- void Bc1t(int cc, MipsLabel* label); // R2
- void Bc1eqz(FRegister ft, MipsLabel* label); // R6
- void Bc1nez(FRegister ft, MipsLabel* label); // R6
+ // When `is_bare` is false, the branches will promote to long (if the range
+ // of the individual branch instruction is insufficient) and the delay/
+ // forbidden slots will be taken care of.
+ // Use `is_bare = false` when the branch target may be out of reach of the
+ // individual branch instruction. IOW, this is for general purpose use.
+ //
+ // When `is_bare` is true, just the branch instructions will be generated
+ // leaving delay/forbidden slot filling up to the caller and the branches
+ // won't promote to long if the range is insufficient (you'll get a
+ // compilation error when the range is exceeded).
+ // Use `is_bare = true` when the branch target is known to be within reach
+ // of the individual branch instruction. This is intended for small local
+ // optimizations around delay/forbidden slots.
+ // Also prefer using `is_bare = true` if the code near the branch is to be
+ // patched or analyzed at run time (e.g. introspection) to
+ // - show the intent and
+ // - fail during compilation rather than during patching/execution if the
+ // bare branch range is insufficent but the code size and layout are
+ // expected to remain unchanged
+ //
+ // R2 branches with delay slots that are also available on R6.
+ // On R6 when `is_bare` is false these convert to equivalent R6 compact
+ // branches (to reduce code size). On R2 or when `is_bare` is true they
+ // remain R2 branches with delay slots.
+ void B(MipsLabel* label, bool is_bare = false);
+ void Bal(MipsLabel* label, bool is_bare = false);
+ void Beq(Register rs, Register rt, MipsLabel* label, bool is_bare = false);
+ void Bne(Register rs, Register rt, MipsLabel* label, bool is_bare = false);
+ void Beqz(Register rt, MipsLabel* label, bool is_bare = false);
+ void Bnez(Register rt, MipsLabel* label, bool is_bare = false);
+ void Bltz(Register rt, MipsLabel* label, bool is_bare = false);
+ void Bgez(Register rt, MipsLabel* label, bool is_bare = false);
+ void Blez(Register rt, MipsLabel* label, bool is_bare = false);
+ void Bgtz(Register rt, MipsLabel* label, bool is_bare = false);
+ void Blt(Register rs, Register rt, MipsLabel* label, bool is_bare = false);
+ void Bge(Register rs, Register rt, MipsLabel* label, bool is_bare = false);
+ void Bltu(Register rs, Register rt, MipsLabel* label, bool is_bare = false);
+ void Bgeu(Register rs, Register rt, MipsLabel* label, bool is_bare = false);
+ // R2-only branches with delay slots.
+ void Bc1f(MipsLabel* label, bool is_bare = false); // R2
+ void Bc1f(int cc, MipsLabel* label, bool is_bare = false); // R2
+ void Bc1t(MipsLabel* label, bool is_bare = false); // R2
+ void Bc1t(int cc, MipsLabel* label, bool is_bare = false); // R2
+ // R6-only compact branches without delay/forbidden slots.
+ void Bc(MipsLabel* label, bool is_bare = false); // R6
+ void Balc(MipsLabel* label, bool is_bare = false); // R6
+ // R6-only compact branches with forbidden slots.
+ void Beqc(Register rs, Register rt, MipsLabel* label, bool is_bare = false); // R6
+ void Bnec(Register rs, Register rt, MipsLabel* label, bool is_bare = false); // R6
+ void Beqzc(Register rt, MipsLabel* label, bool is_bare = false); // R6
+ void Bnezc(Register rt, MipsLabel* label, bool is_bare = false); // R6
+ void Bltzc(Register rt, MipsLabel* label, bool is_bare = false); // R6
+ void Bgezc(Register rt, MipsLabel* label, bool is_bare = false); // R6
+ void Blezc(Register rt, MipsLabel* label, bool is_bare = false); // R6
+ void Bgtzc(Register rt, MipsLabel* label, bool is_bare = false); // R6
+ void Bltc(Register rs, Register rt, MipsLabel* label, bool is_bare = false); // R6
+ void Bgec(Register rs, Register rt, MipsLabel* label, bool is_bare = false); // R6
+ void Bltuc(Register rs, Register rt, MipsLabel* label, bool is_bare = false); // R6
+ void Bgeuc(Register rs, Register rt, MipsLabel* label, bool is_bare = false); // R6
+ // R6-only branches with delay slots.
+ void Bc1eqz(FRegister ft, MipsLabel* label, bool is_bare = false); // R6
+ void Bc1nez(FRegister ft, MipsLabel* label, bool is_bare = false); // R6
void EmitLoad(ManagedRegister m_dst, Register src_register, int32_t src_offset, size_t size);
void AdjustBaseAndOffset(Register& base,
@@ -1268,10 +1308,14 @@ class MipsAssembler FINAL : public Assembler, public JNIMacroAssembler<PointerSi
class Branch {
public:
enum Type {
- // R2 short branches.
+ // R2 short branches (can be promoted to long).
kUncondBranch,
kCondBranch,
kCall,
+ // R2 short branches (can't be promoted to long), delay slots filled manually.
+ kBareUncondBranch,
+ kBareCondBranch,
+ kBareCall,
// R2 near label.
kLabel,
// R2 near literal.
@@ -1284,10 +1328,14 @@ class MipsAssembler FINAL : public Assembler, public JNIMacroAssembler<PointerSi
kFarLabel,
// R2 far literal.
kFarLiteral,
- // R6 short branches.
+ // R6 short branches (can be promoted to long).
kR6UncondBranch,
kR6CondBranch,
kR6Call,
+ // R6 short branches (can't be promoted to long), forbidden/delay slots filled manually.
+ kR6BareUncondBranch,
+ kR6BareCondBranch,
+ kR6BareCall,
// R6 near label.
kR6Label,
// R6 near literal.
@@ -1337,7 +1385,7 @@ class MipsAssembler FINAL : public Assembler, public JNIMacroAssembler<PointerSi
// instructions) from the instruction containing the offset.
uint32_t pc_org;
// How large (in bits) a PC-relative offset can be for a given type of branch (kR6CondBranch
- // is an exception: use kOffset23 for beqzc/bnezc).
+ // and kR6BareCondBranch are an exception: use kOffset23 for beqzc/bnezc).
OffsetBits offset_size;
// Some MIPS instructions with PC-relative offsets shift the offset by 2. Encode the shift
// count.
@@ -1346,14 +1394,15 @@ class MipsAssembler FINAL : public Assembler, public JNIMacroAssembler<PointerSi
static const BranchInfo branch_info_[/* Type */];
// Unconditional branch or call.
- Branch(bool is_r6, uint32_t location, uint32_t target, bool is_call);
+ Branch(bool is_r6, uint32_t location, uint32_t target, bool is_call, bool is_bare);
// Conditional branch.
Branch(bool is_r6,
uint32_t location,
uint32_t target,
BranchCondition condition,
Register lhs_reg,
- Register rhs_reg);
+ Register rhs_reg,
+ bool is_bare);
// Label address (in literal area) or literal.
Branch(bool is_r6,
uint32_t location,
@@ -1385,6 +1434,7 @@ class MipsAssembler FINAL : public Assembler, public JNIMacroAssembler<PointerSi
uint32_t GetOldSize() const;
uint32_t GetEndLocation() const;
uint32_t GetOldEndLocation() const;
+ bool IsBare() const;
bool IsLong() const;
bool IsResolved() const;
@@ -1513,9 +1563,14 @@ class MipsAssembler FINAL : public Assembler, public JNIMacroAssembler<PointerSi
VectorRegister wd,
int minor_opcode);
- void Buncond(MipsLabel* label);
- void Bcond(MipsLabel* label, BranchCondition condition, Register lhs, Register rhs = ZERO);
- void Call(MipsLabel* label);
+ void Buncond(MipsLabel* label, bool is_r6, bool is_bare);
+ void Bcond(MipsLabel* label,
+ bool is_r6,
+ bool is_bare,
+ BranchCondition condition,
+ Register lhs,
+ Register rhs = ZERO);
+ void Call(MipsLabel* label, bool is_r6, bool is_bare);
void FinalizeLabeledBranch(MipsLabel* label);
// Various helpers for branch delay slot management.
diff --git a/compiler/utils/mips/assembler_mips32r6_test.cc b/compiler/utils/mips/assembler_mips32r6_test.cc
index b72a14e906..6e52b17000 100644
--- a/compiler/utils/mips/assembler_mips32r6_test.cc
+++ b/compiler/utils/mips/assembler_mips32r6_test.cc
@@ -259,12 +259,119 @@ class AssemblerMIPS32r6Test : public AssemblerTest<mips::MipsAssembler,
return result;
}
+ void BranchHelper(void (mips::MipsAssembler::*f)(mips::MipsLabel*,
+ bool),
+ const std::string& instr_name,
+ bool has_slot,
+ bool is_bare = false) {
+ __ SetReorder(false);
+ mips::MipsLabel label1, label2;
+ (Base::GetAssembler()->*f)(&label1, is_bare);
+ constexpr size_t kAdduCount1 = 63;
+ for (size_t i = 0; i != kAdduCount1; ++i) {
+ __ Addu(mips::ZERO, mips::ZERO, mips::ZERO);
+ }
+ __ Bind(&label1);
+ (Base::GetAssembler()->*f)(&label2, is_bare);
+ constexpr size_t kAdduCount2 = 64;
+ for (size_t i = 0; i != kAdduCount2; ++i) {
+ __ Addu(mips::ZERO, mips::ZERO, mips::ZERO);
+ }
+ __ Bind(&label2);
+ (Base::GetAssembler()->*f)(&label1, is_bare);
+ __ Addu(mips::ZERO, mips::ZERO, mips::ZERO);
+
+ std::string expected =
+ ".set noreorder\n" +
+ instr_name + " 1f\n" +
+ ((is_bare || !has_slot) ? "" : "nop\n") +
+ RepeatInsn(kAdduCount1, "addu $zero, $zero, $zero\n") +
+ "1:\n" +
+ instr_name + " 2f\n" +
+ ((is_bare || !has_slot) ? "" : "nop\n") +
+ RepeatInsn(kAdduCount2, "addu $zero, $zero, $zero\n") +
+ "2:\n" +
+ instr_name + " 1b\n" +
+ ((is_bare || !has_slot) ? "" : "nop\n") +
+ "addu $zero, $zero, $zero\n";
+ DriverStr(expected, instr_name);
+ }
+
+ void BranchCondOneRegHelper(void (mips::MipsAssembler::*f)(mips::Register,
+ mips::MipsLabel*,
+ bool),
+ const std::string& instr_name,
+ bool is_bare = false) {
+ __ SetReorder(false);
+ mips::MipsLabel label;
+ (Base::GetAssembler()->*f)(mips::A0, &label, is_bare);
+ constexpr size_t kAdduCount1 = 63;
+ for (size_t i = 0; i != kAdduCount1; ++i) {
+ __ Addu(mips::ZERO, mips::ZERO, mips::ZERO);
+ }
+ __ Bind(&label);
+ constexpr size_t kAdduCount2 = 64;
+ for (size_t i = 0; i != kAdduCount2; ++i) {
+ __ Addu(mips::ZERO, mips::ZERO, mips::ZERO);
+ }
+ (Base::GetAssembler()->*f)(mips::A1, &label, is_bare);
+ __ Addu(mips::ZERO, mips::ZERO, mips::ZERO);
+
+ std::string expected =
+ ".set noreorder\n" +
+ instr_name + " $a0, 1f\n" +
+ (is_bare ? "" : "nop\n") +
+ RepeatInsn(kAdduCount1, "addu $zero, $zero, $zero\n") +
+ "1:\n" +
+ RepeatInsn(kAdduCount2, "addu $zero, $zero, $zero\n") +
+ instr_name + " $a1, 1b\n" +
+ (is_bare ? "" : "nop\n") +
+ "addu $zero, $zero, $zero\n";
+ DriverStr(expected, instr_name);
+ }
+
void BranchCondTwoRegsHelper(void (mips::MipsAssembler::*f)(mips::Register,
mips::Register,
- mips::MipsLabel*),
- const std::string& instr_name) {
+ mips::MipsLabel*,
+ bool),
+ const std::string& instr_name,
+ bool is_bare = false) {
+ __ SetReorder(false);
+ mips::MipsLabel label;
+ (Base::GetAssembler()->*f)(mips::A0, mips::A1, &label, is_bare);
+ constexpr size_t kAdduCount1 = 63;
+ for (size_t i = 0; i != kAdduCount1; ++i) {
+ __ Addu(mips::ZERO, mips::ZERO, mips::ZERO);
+ }
+ __ Bind(&label);
+ constexpr size_t kAdduCount2 = 64;
+ for (size_t i = 0; i != kAdduCount2; ++i) {
+ __ Addu(mips::ZERO, mips::ZERO, mips::ZERO);
+ }
+ (Base::GetAssembler()->*f)(mips::A2, mips::A3, &label, is_bare);
+ __ Addu(mips::ZERO, mips::ZERO, mips::ZERO);
+
+ std::string expected =
+ ".set noreorder\n" +
+ instr_name + " $a0, $a1, 1f\n" +
+ (is_bare ? "" : "nop\n") +
+ RepeatInsn(kAdduCount1, "addu $zero, $zero, $zero\n") +
+ "1:\n" +
+ RepeatInsn(kAdduCount2, "addu $zero, $zero, $zero\n") +
+ instr_name + " $a2, $a3, 1b\n" +
+ (is_bare ? "" : "nop\n") +
+ "addu $zero, $zero, $zero\n";
+ DriverStr(expected, instr_name);
+ }
+
+ void BranchFpuCondHelper(void (mips::MipsAssembler::*f)(mips::FRegister,
+ mips::MipsLabel*,
+ bool),
+ const std::string& instr_name,
+ bool is_bare = false) {
+ __ SetReorder(false);
mips::MipsLabel label;
- (Base::GetAssembler()->*f)(mips::A0, mips::A1, &label);
+ (Base::GetAssembler()->*f)(mips::F0, &label, is_bare);
constexpr size_t kAdduCount1 = 63;
for (size_t i = 0; i != kAdduCount1; ++i) {
__ Addu(mips::ZERO, mips::ZERO, mips::ZERO);
@@ -274,17 +381,19 @@ class AssemblerMIPS32r6Test : public AssemblerTest<mips::MipsAssembler,
for (size_t i = 0; i != kAdduCount2; ++i) {
__ Addu(mips::ZERO, mips::ZERO, mips::ZERO);
}
- (Base::GetAssembler()->*f)(mips::A2, mips::A3, &label);
+ (Base::GetAssembler()->*f)(mips::F30, &label, is_bare);
+ __ Addu(mips::ZERO, mips::ZERO, mips::ZERO);
std::string expected =
".set noreorder\n" +
- instr_name + " $a0, $a1, 1f\n"
- "nop\n" +
+ instr_name + " $f0, 1f\n" +
+ (is_bare ? "" : "nop\n") +
RepeatInsn(kAdduCount1, "addu $zero, $zero, $zero\n") +
"1:\n" +
RepeatInsn(kAdduCount2, "addu $zero, $zero, $zero\n") +
- instr_name + " $a2, $a3, 1b\n"
- "nop\n";
+ instr_name + " $f30, 1b\n" +
+ (is_bare ? "" : "nop\n") +
+ "addu $zero, $zero, $zero\n";
DriverStr(expected, instr_name);
}
@@ -947,78 +1056,386 @@ TEST_F(AssemblerMIPS32r6Test, StoreQToOffset) {
DriverStr(expected, "StoreQToOffset");
}
-TEST_F(AssemblerMIPS32r6Test, LoadFarthestNearLabelAddress) {
+//////////////
+// BRANCHES //
+//////////////
+
+TEST_F(AssemblerMIPS32r6Test, Bc) {
+ BranchHelper(&mips::MipsAssembler::Bc, "Bc", /* has_slot */ false);
+}
+
+TEST_F(AssemblerMIPS32r6Test, Balc) {
+ BranchHelper(&mips::MipsAssembler::Balc, "Balc", /* has_slot */ false);
+}
+
+TEST_F(AssemblerMIPS32r6Test, Beqc) {
+ BranchCondTwoRegsHelper(&mips::MipsAssembler::Beqc, "Beqc");
+}
+
+TEST_F(AssemblerMIPS32r6Test, Bnec) {
+ BranchCondTwoRegsHelper(&mips::MipsAssembler::Bnec, "Bnec");
+}
+
+TEST_F(AssemblerMIPS32r6Test, Beqzc) {
+ BranchCondOneRegHelper(&mips::MipsAssembler::Beqzc, "Beqzc");
+}
+
+TEST_F(AssemblerMIPS32r6Test, Bnezc) {
+ BranchCondOneRegHelper(&mips::MipsAssembler::Bnezc, "Bnezc");
+}
+
+TEST_F(AssemblerMIPS32r6Test, Bltzc) {
+ BranchCondOneRegHelper(&mips::MipsAssembler::Bltzc, "Bltzc");
+}
+
+TEST_F(AssemblerMIPS32r6Test, Bgezc) {
+ BranchCondOneRegHelper(&mips::MipsAssembler::Bgezc, "Bgezc");
+}
+
+TEST_F(AssemblerMIPS32r6Test, Blezc) {
+ BranchCondOneRegHelper(&mips::MipsAssembler::Blezc, "Blezc");
+}
+
+TEST_F(AssemblerMIPS32r6Test, Bgtzc) {
+ BranchCondOneRegHelper(&mips::MipsAssembler::Bgtzc, "Bgtzc");
+}
+
+TEST_F(AssemblerMIPS32r6Test, Bltc) {
+ BranchCondTwoRegsHelper(&mips::MipsAssembler::Bltc, "Bltc");
+}
+
+TEST_F(AssemblerMIPS32r6Test, Bgec) {
+ BranchCondTwoRegsHelper(&mips::MipsAssembler::Bgec, "Bgec");
+}
+
+TEST_F(AssemblerMIPS32r6Test, Bltuc) {
+ BranchCondTwoRegsHelper(&mips::MipsAssembler::Bltuc, "Bltuc");
+}
+
+TEST_F(AssemblerMIPS32r6Test, Bgeuc) {
+ BranchCondTwoRegsHelper(&mips::MipsAssembler::Bgeuc, "Bgeuc");
+}
+
+TEST_F(AssemblerMIPS32r6Test, Bc1eqz) {
+ BranchFpuCondHelper(&mips::MipsAssembler::Bc1eqz, "Bc1eqz");
+}
+
+TEST_F(AssemblerMIPS32r6Test, Bc1nez) {
+ BranchFpuCondHelper(&mips::MipsAssembler::Bc1nez, "Bc1nez");
+}
+
+TEST_F(AssemblerMIPS32r6Test, B) {
+ BranchHelper(&mips::MipsAssembler::B, "Bc", /* has_slot */ false);
+}
+
+TEST_F(AssemblerMIPS32r6Test, Bal) {
+ BranchHelper(&mips::MipsAssembler::Bal, "Balc", /* has_slot */ false);
+}
+
+TEST_F(AssemblerMIPS32r6Test, Beq) {
+ BranchCondTwoRegsHelper(&mips::MipsAssembler::Beq, "Beqc");
+}
+
+TEST_F(AssemblerMIPS32r6Test, Bne) {
+ BranchCondTwoRegsHelper(&mips::MipsAssembler::Bne, "Bnec");
+}
+
+TEST_F(AssemblerMIPS32r6Test, Beqz) {
+ BranchCondOneRegHelper(&mips::MipsAssembler::Beqz, "Beqzc");
+}
+
+TEST_F(AssemblerMIPS32r6Test, Bnez) {
+ BranchCondOneRegHelper(&mips::MipsAssembler::Bnez, "Bnezc");
+}
+
+TEST_F(AssemblerMIPS32r6Test, Bltz) {
+ BranchCondOneRegHelper(&mips::MipsAssembler::Bltz, "Bltzc");
+}
+
+TEST_F(AssemblerMIPS32r6Test, Bgez) {
+ BranchCondOneRegHelper(&mips::MipsAssembler::Bgez, "Bgezc");
+}
+
+TEST_F(AssemblerMIPS32r6Test, Blez) {
+ BranchCondOneRegHelper(&mips::MipsAssembler::Blez, "Blezc");
+}
+
+TEST_F(AssemblerMIPS32r6Test, Bgtz) {
+ BranchCondOneRegHelper(&mips::MipsAssembler::Bgtz, "Bgtzc");
+}
+
+TEST_F(AssemblerMIPS32r6Test, Blt) {
+ BranchCondTwoRegsHelper(&mips::MipsAssembler::Blt, "Bltc");
+}
+
+TEST_F(AssemblerMIPS32r6Test, Bge) {
+ BranchCondTwoRegsHelper(&mips::MipsAssembler::Bge, "Bgec");
+}
+
+TEST_F(AssemblerMIPS32r6Test, Bltu) {
+ BranchCondTwoRegsHelper(&mips::MipsAssembler::Bltu, "Bltuc");
+}
+
+TEST_F(AssemblerMIPS32r6Test, Bgeu) {
+ BranchCondTwoRegsHelper(&mips::MipsAssembler::Bgeu, "Bgeuc");
+}
+
+TEST_F(AssemblerMIPS32r6Test, BareBc) {
+ BranchHelper(&mips::MipsAssembler::Bc, "Bc", /* has_slot */ false, /* is_bare */ true);
+}
+
+TEST_F(AssemblerMIPS32r6Test, BareBalc) {
+ BranchHelper(&mips::MipsAssembler::Balc, "Balc", /* has_slot */ false, /* is_bare */ true);
+}
+
+TEST_F(AssemblerMIPS32r6Test, BareBeqc) {
+ BranchCondTwoRegsHelper(&mips::MipsAssembler::Beqc, "Beqc", /* is_bare */ true);
+}
+
+TEST_F(AssemblerMIPS32r6Test, BareBnec) {
+ BranchCondTwoRegsHelper(&mips::MipsAssembler::Bnec, "Bnec", /* is_bare */ true);
+}
+
+TEST_F(AssemblerMIPS32r6Test, BareBeqzc) {
+ BranchCondOneRegHelper(&mips::MipsAssembler::Beqzc, "Beqzc", /* is_bare */ true);
+}
+
+TEST_F(AssemblerMIPS32r6Test, BareBnezc) {
+ BranchCondOneRegHelper(&mips::MipsAssembler::Bnezc, "Bnezc", /* is_bare */ true);
+}
+
+TEST_F(AssemblerMIPS32r6Test, BareBltzc) {
+ BranchCondOneRegHelper(&mips::MipsAssembler::Bltzc, "Bltzc", /* is_bare */ true);
+}
+
+TEST_F(AssemblerMIPS32r6Test, BareBgezc) {
+ BranchCondOneRegHelper(&mips::MipsAssembler::Bgezc, "Bgezc", /* is_bare */ true);
+}
+
+TEST_F(AssemblerMIPS32r6Test, BareBlezc) {
+ BranchCondOneRegHelper(&mips::MipsAssembler::Blezc, "Blezc", /* is_bare */ true);
+}
+
+TEST_F(AssemblerMIPS32r6Test, BareBgtzc) {
+ BranchCondOneRegHelper(&mips::MipsAssembler::Bgtzc, "Bgtzc", /* is_bare */ true);
+}
+
+TEST_F(AssemblerMIPS32r6Test, BareBltc) {
+ BranchCondTwoRegsHelper(&mips::MipsAssembler::Bltc, "Bltc", /* is_bare */ true);
+}
+
+TEST_F(AssemblerMIPS32r6Test, BareBgec) {
+ BranchCondTwoRegsHelper(&mips::MipsAssembler::Bgec, "Bgec", /* is_bare */ true);
+}
+
+TEST_F(AssemblerMIPS32r6Test, BareBltuc) {
+ BranchCondTwoRegsHelper(&mips::MipsAssembler::Bltuc, "Bltuc", /* is_bare */ true);
+}
+
+TEST_F(AssemblerMIPS32r6Test, BareBgeuc) {
+ BranchCondTwoRegsHelper(&mips::MipsAssembler::Bgeuc, "Bgeuc", /* is_bare */ true);
+}
+
+TEST_F(AssemblerMIPS32r6Test, BareBc1eqz) {
+ BranchFpuCondHelper(&mips::MipsAssembler::Bc1eqz, "Bc1eqz", /* is_bare */ true);
+}
+
+TEST_F(AssemblerMIPS32r6Test, BareBc1nez) {
+ BranchFpuCondHelper(&mips::MipsAssembler::Bc1nez, "Bc1nez", /* is_bare */ true);
+}
+
+TEST_F(AssemblerMIPS32r6Test, BareB) {
+ BranchHelper(&mips::MipsAssembler::B, "B", /* has_slot */ true, /* is_bare */ true);
+}
+
+TEST_F(AssemblerMIPS32r6Test, BareBal) {
+ BranchHelper(&mips::MipsAssembler::Bal, "Bal", /* has_slot */ true, /* is_bare */ true);
+}
+
+TEST_F(AssemblerMIPS32r6Test, BareBeq) {
+ BranchCondTwoRegsHelper(&mips::MipsAssembler::Beq, "Beq", /* is_bare */ true);
+}
+
+TEST_F(AssemblerMIPS32r6Test, BareBne) {
+ BranchCondTwoRegsHelper(&mips::MipsAssembler::Bne, "Bne", /* is_bare */ true);
+}
+
+TEST_F(AssemblerMIPS32r6Test, BareBeqz) {
+ BranchCondOneRegHelper(&mips::MipsAssembler::Beqz, "Beqz", /* is_bare */ true);
+}
+
+TEST_F(AssemblerMIPS32r6Test, BareBnez) {
+ BranchCondOneRegHelper(&mips::MipsAssembler::Bnez, "Bnez", /* is_bare */ true);
+}
+
+TEST_F(AssemblerMIPS32r6Test, BareBltz) {
+ BranchCondOneRegHelper(&mips::MipsAssembler::Bltz, "Bltz", /* is_bare */ true);
+}
+
+TEST_F(AssemblerMIPS32r6Test, BareBgez) {
+ BranchCondOneRegHelper(&mips::MipsAssembler::Bgez, "Bgez", /* is_bare */ true);
+}
+
+TEST_F(AssemblerMIPS32r6Test, BareBlez) {
+ BranchCondOneRegHelper(&mips::MipsAssembler::Blez, "Blez", /* is_bare */ true);
+}
+
+TEST_F(AssemblerMIPS32r6Test, BareBgtz) {
+ BranchCondOneRegHelper(&mips::MipsAssembler::Bgtz, "Bgtz", /* is_bare */ true);
+}
+
+TEST_F(AssemblerMIPS32r6Test, BareBlt) {
+ BranchCondTwoRegsHelper(&mips::MipsAssembler::Blt, "Blt", /* is_bare */ true);
+}
+
+TEST_F(AssemblerMIPS32r6Test, BareBge) {
+ BranchCondTwoRegsHelper(&mips::MipsAssembler::Bge, "Bge", /* is_bare */ true);
+}
+
+TEST_F(AssemblerMIPS32r6Test, BareBltu) {
+ BranchCondTwoRegsHelper(&mips::MipsAssembler::Bltu, "Bltu", /* is_bare */ true);
+}
+
+TEST_F(AssemblerMIPS32r6Test, BareBgeu) {
+ BranchCondTwoRegsHelper(&mips::MipsAssembler::Bgeu, "Bgeu", /* is_bare */ true);
+}
+
+TEST_F(AssemblerMIPS32r6Test, LongBeqc) {
mips::MipsLabel label;
- __ LoadLabelAddress(mips::V0, mips::ZERO, &label);
- constexpr size_t kAdduCount = 0x3FFDE;
- for (size_t i = 0; i != kAdduCount; ++i) {
+ __ Beqc(mips::A0, mips::A1, &label);
+ constexpr uint32_t kAdduCount1 = (1u << 15) + 1;
+ for (uint32_t i = 0; i != kAdduCount1; ++i) {
__ Addu(mips::ZERO, mips::ZERO, mips::ZERO);
}
__ Bind(&label);
+ constexpr uint32_t kAdduCount2 = (1u << 15) + 1;
+ for (uint32_t i = 0; i != kAdduCount2; ++i) {
+ __ Addu(mips::ZERO, mips::ZERO, mips::ZERO);
+ }
+ __ Beqc(mips::A2, mips::A3, &label);
- std::string expected =
- "lapc $v0, 1f\n" +
- RepeatInsn(kAdduCount, "addu $zero, $zero, $zero\n") +
- "1:\n";
- DriverStr(expected, "LoadFarthestNearLabelAddress");
+ uint32_t offset_forward = 2 + kAdduCount1; // 2: account for auipc and jic.
+ offset_forward <<= 2;
+ offset_forward += (offset_forward & 0x8000) << 1; // Account for sign extension in jic.
+
+ uint32_t offset_back = -(kAdduCount2 + 1); // 1: account for bnec.
+ offset_back <<= 2;
+ offset_back += (offset_back & 0x8000) << 1; // Account for sign extension in jic.
+
+ std::ostringstream oss;
+ oss <<
+ ".set noreorder\n"
+ "bnec $a0, $a1, 1f\n"
+ "auipc $at, 0x" << std::hex << High16Bits(offset_forward) << "\n"
+ "jic $at, 0x" << std::hex << Low16Bits(offset_forward) << "\n"
+ "1:\n" <<
+ RepeatInsn(kAdduCount1, "addu $zero, $zero, $zero\n") <<
+ "2:\n" <<
+ RepeatInsn(kAdduCount2, "addu $zero, $zero, $zero\n") <<
+ "bnec $a2, $a3, 3f\n"
+ "auipc $at, 0x" << std::hex << High16Bits(offset_back) << "\n"
+ "jic $at, 0x" << std::hex << Low16Bits(offset_back) << "\n"
+ "3:\n";
+ std::string expected = oss.str();
+ DriverStr(expected, "LongBeqc");
}
-TEST_F(AssemblerMIPS32r6Test, LoadNearestFarLabelAddress) {
+TEST_F(AssemblerMIPS32r6Test, LongBeqzc) {
+ constexpr uint32_t kNopCount1 = (1u << 20) + 1;
+ constexpr uint32_t kNopCount2 = (1u << 20) + 1;
+ constexpr uint32_t kRequiredCapacity = (kNopCount1 + kNopCount2 + 6u) * 4u;
+ ASSERT_LT(__ GetBuffer()->Capacity(), kRequiredCapacity);
+ __ GetBuffer()->ExtendCapacity(kRequiredCapacity);
mips::MipsLabel label;
- __ LoadLabelAddress(mips::V0, mips::ZERO, &label);
- constexpr size_t kAdduCount = 0x3FFDF;
- for (size_t i = 0; i != kAdduCount; ++i) {
- __ Addu(mips::ZERO, mips::ZERO, mips::ZERO);
+ __ Beqzc(mips::A0, &label);
+ for (uint32_t i = 0; i != kNopCount1; ++i) {
+ __ Nop();
}
__ Bind(&label);
+ for (uint32_t i = 0; i != kNopCount2; ++i) {
+ __ Nop();
+ }
+ __ Beqzc(mips::A2, &label);
- std::string expected =
- "1:\n"
- "auipc $at, %hi(2f - 1b)\n"
- "addiu $v0, $at, %lo(2f - 1b)\n" +
- RepeatInsn(kAdduCount, "addu $zero, $zero, $zero\n") +
- "2:\n";
- DriverStr(expected, "LoadNearestFarLabelAddress");
-}
+ uint32_t offset_forward = 2 + kNopCount1; // 2: account for auipc and jic.
+ offset_forward <<= 2;
+ offset_forward += (offset_forward & 0x8000) << 1; // Account for sign extension in jic.
-TEST_F(AssemblerMIPS32r6Test, LoadFarthestNearLiteral) {
- mips::Literal* literal = __ NewLiteral<uint32_t>(0x12345678);
- __ LoadLiteral(mips::V0, mips::ZERO, literal);
- constexpr size_t kAdduCount = 0x3FFDE;
- for (size_t i = 0; i != kAdduCount; ++i) {
- __ Addu(mips::ZERO, mips::ZERO, mips::ZERO);
+ uint32_t offset_back = -(kNopCount2 + 1); // 1: account for bnezc.
+ offset_back <<= 2;
+ offset_back += (offset_back & 0x8000) << 1; // Account for sign extension in jic.
+
+ // Note, we're using the ".fill" directive to tell the assembler to generate many NOPs
+ // instead of generating them ourselves in the source code. This saves test time.
+ std::ostringstream oss;
+ oss <<
+ ".set noreorder\n"
+ "bnezc $a0, 1f\n"
+ "auipc $at, 0x" << std::hex << High16Bits(offset_forward) << "\n"
+ "jic $at, 0x" << std::hex << Low16Bits(offset_forward) << "\n"
+ "1:\n" <<
+ ".fill 0x" << std::hex << kNopCount1 << " , 4, 0\n"
+ "2:\n" <<
+ ".fill 0x" << std::hex << kNopCount2 << " , 4, 0\n"
+ "bnezc $a2, 3f\n"
+ "auipc $at, 0x" << std::hex << High16Bits(offset_back) << "\n"
+ "jic $at, 0x" << std::hex << Low16Bits(offset_back) << "\n"
+ "3:\n";
+ std::string expected = oss.str();
+ DriverStr(expected, "LongBeqzc");
+}
+
+TEST_F(AssemblerMIPS32r6Test, LongBc) {
+ constexpr uint32_t kNopCount1 = (1u << 25) + 1;
+ constexpr uint32_t kNopCount2 = (1u << 25) + 1;
+ constexpr uint32_t kRequiredCapacity = (kNopCount1 + kNopCount2 + 6u) * 4u;
+ ASSERT_LT(__ GetBuffer()->Capacity(), kRequiredCapacity);
+ __ GetBuffer()->ExtendCapacity(kRequiredCapacity);
+ mips::MipsLabel label1, label2;
+ __ Bc(&label1);
+ for (uint32_t i = 0; i != kNopCount1; ++i) {
+ __ Nop();
+ }
+ __ Bind(&label1);
+ __ Bc(&label2);
+ for (uint32_t i = 0; i != kNopCount2; ++i) {
+ __ Nop();
}
+ __ Bind(&label2);
+ __ Bc(&label1);
- std::string expected =
- "lwpc $v0, 1f\n" +
- RepeatInsn(kAdduCount, "addu $zero, $zero, $zero\n") +
- "1:\n"
- ".word 0x12345678\n";
- DriverStr(expected, "LoadFarthestNearLiteral");
-}
+ uint32_t offset_forward1 = 2 + kNopCount1; // 2: account for auipc and jic.
+ offset_forward1 <<= 2;
+ offset_forward1 += (offset_forward1 & 0x8000) << 1; // Account for sign extension in jic.
-TEST_F(AssemblerMIPS32r6Test, LoadNearestFarLiteral) {
- mips::Literal* literal = __ NewLiteral<uint32_t>(0x12345678);
- __ LoadLiteral(mips::V0, mips::ZERO, literal);
- constexpr size_t kAdduCount = 0x3FFDF;
- for (size_t i = 0; i != kAdduCount; ++i) {
- __ Addu(mips::ZERO, mips::ZERO, mips::ZERO);
- }
+ uint32_t offset_forward2 = 2 + kNopCount2; // 2: account for auipc and jic.
+ offset_forward2 <<= 2;
+ offset_forward2 += (offset_forward2 & 0x8000) << 1; // Account for sign extension in jic.
- std::string expected =
+ uint32_t offset_back = -(2 + kNopCount2); // 2: account for auipc and jic.
+ offset_back <<= 2;
+ offset_back += (offset_back & 0x8000) << 1; // Account for sign extension in jic.
+
+ // Note, we're using the ".fill" directive to tell the assembler to generate many NOPs
+ // instead of generating them ourselves in the source code. This saves a few minutes
+ // of test time.
+ std::ostringstream oss;
+ oss <<
+ ".set noreorder\n"
+ "auipc $at, 0x" << std::hex << High16Bits(offset_forward1) << "\n"
+ "jic $at, 0x" << std::hex << Low16Bits(offset_forward1) << "\n"
+ ".fill 0x" << std::hex << kNopCount1 << " , 4, 0\n"
"1:\n"
- "auipc $at, %hi(2f - 1b)\n"
- "lw $v0, %lo(2f - 1b)($at)\n" +
- RepeatInsn(kAdduCount, "addu $zero, $zero, $zero\n") +
+ "auipc $at, 0x" << std::hex << High16Bits(offset_forward2) << "\n"
+ "jic $at, 0x" << std::hex << Low16Bits(offset_forward2) << "\n"
+ ".fill 0x" << std::hex << kNopCount2 << " , 4, 0\n"
"2:\n"
- ".word 0x12345678\n";
- DriverStr(expected, "LoadNearestFarLiteral");
+ "auipc $at, 0x" << std::hex << High16Bits(offset_back) << "\n"
+ "jic $at, 0x" << std::hex << Low16Bits(offset_back) << "\n";
+ std::string expected = oss.str();
+ DriverStr(expected, "LongBc");
}
-//////////////
-// BRANCHES //
-//////////////
-
TEST_F(AssemblerMIPS32r6Test, ImpossibleReordering) {
mips::MipsLabel label;
__ SetReorder(true);
@@ -1154,43 +1571,80 @@ TEST_F(AssemblerMIPS32r6Test, LongBranchReorder) {
"jic $at, 0x" << std::hex << Low16Bits(offset_back) << "\n"
"3:\n";
std::string expected = oss.str();
- DriverStr(expected, "LongBeqc");
+ DriverStr(expected, "LongBranchReorder");
}
-// TODO: MipsAssembler::Bc
-// MipsAssembler::Jic
-// MipsAssembler::Jialc
-// MipsAssembler::Bltc
-// MipsAssembler::Bltzc
-// MipsAssembler::Bgtzc
-// MipsAssembler::Bgec
-// MipsAssembler::Bgezc
-// MipsAssembler::Blezc
-// MipsAssembler::Bltuc
-// MipsAssembler::Bgeuc
-// MipsAssembler::Beqc
-// MipsAssembler::Bnec
-// MipsAssembler::Beqzc
-// MipsAssembler::Bnezc
-// MipsAssembler::Bc1eqz
-// MipsAssembler::Bc1nez
-// MipsAssembler::Buncond
-// MipsAssembler::Bcond
-// MipsAssembler::Call
-
-// TODO: AssemblerMIPS32r6Test.B
-// AssemblerMIPS32r6Test.Beq
-// AssemblerMIPS32r6Test.Bne
-// AssemblerMIPS32r6Test.Beqz
-// AssemblerMIPS32r6Test.Bnez
-// AssemblerMIPS32r6Test.Bltz
-// AssemblerMIPS32r6Test.Bgez
-// AssemblerMIPS32r6Test.Blez
-// AssemblerMIPS32r6Test.Bgtz
-// AssemblerMIPS32r6Test.Blt
-// AssemblerMIPS32r6Test.Bge
-// AssemblerMIPS32r6Test.Bltu
-// AssemblerMIPS32r6Test.Bgeu
+///////////////////////
+// Loading Constants //
+///////////////////////
+
+TEST_F(AssemblerMIPS32r6Test, LoadFarthestNearLabelAddress) {
+ mips::MipsLabel label;
+ __ LoadLabelAddress(mips::V0, mips::ZERO, &label);
+ constexpr size_t kAdduCount = 0x3FFDE;
+ for (size_t i = 0; i != kAdduCount; ++i) {
+ __ Addu(mips::ZERO, mips::ZERO, mips::ZERO);
+ }
+ __ Bind(&label);
+
+ std::string expected =
+ "lapc $v0, 1f\n" +
+ RepeatInsn(kAdduCount, "addu $zero, $zero, $zero\n") +
+ "1:\n";
+ DriverStr(expected, "LoadFarthestNearLabelAddress");
+}
+
+TEST_F(AssemblerMIPS32r6Test, LoadNearestFarLabelAddress) {
+ mips::MipsLabel label;
+ __ LoadLabelAddress(mips::V0, mips::ZERO, &label);
+ constexpr size_t kAdduCount = 0x3FFDF;
+ for (size_t i = 0; i != kAdduCount; ++i) {
+ __ Addu(mips::ZERO, mips::ZERO, mips::ZERO);
+ }
+ __ Bind(&label);
+
+ std::string expected =
+ "1:\n"
+ "auipc $at, %hi(2f - 1b)\n"
+ "addiu $v0, $at, %lo(2f - 1b)\n" +
+ RepeatInsn(kAdduCount, "addu $zero, $zero, $zero\n") +
+ "2:\n";
+ DriverStr(expected, "LoadNearestFarLabelAddress");
+}
+
+TEST_F(AssemblerMIPS32r6Test, LoadFarthestNearLiteral) {
+ mips::Literal* literal = __ NewLiteral<uint32_t>(0x12345678);
+ __ LoadLiteral(mips::V0, mips::ZERO, literal);
+ constexpr size_t kAdduCount = 0x3FFDE;
+ for (size_t i = 0; i != kAdduCount; ++i) {
+ __ Addu(mips::ZERO, mips::ZERO, mips::ZERO);
+ }
+
+ std::string expected =
+ "lwpc $v0, 1f\n" +
+ RepeatInsn(kAdduCount, "addu $zero, $zero, $zero\n") +
+ "1:\n"
+ ".word 0x12345678\n";
+ DriverStr(expected, "LoadFarthestNearLiteral");
+}
+
+TEST_F(AssemblerMIPS32r6Test, LoadNearestFarLiteral) {
+ mips::Literal* literal = __ NewLiteral<uint32_t>(0x12345678);
+ __ LoadLiteral(mips::V0, mips::ZERO, literal);
+ constexpr size_t kAdduCount = 0x3FFDF;
+ for (size_t i = 0; i != kAdduCount; ++i) {
+ __ Addu(mips::ZERO, mips::ZERO, mips::ZERO);
+ }
+
+ std::string expected =
+ "1:\n"
+ "auipc $at, %hi(2f - 1b)\n"
+ "lw $v0, %lo(2f - 1b)($at)\n" +
+ RepeatInsn(kAdduCount, "addu $zero, $zero, $zero\n") +
+ "2:\n"
+ ".word 0x12345678\n";
+ DriverStr(expected, "LoadNearestFarLiteral");
+}
// MSA instructions.
diff --git a/compiler/utils/mips/assembler_mips_test.cc b/compiler/utils/mips/assembler_mips_test.cc
index 09175309f9..d9bf0b82f4 100644
--- a/compiler/utils/mips/assembler_mips_test.cc
+++ b/compiler/utils/mips/assembler_mips_test.cc
@@ -186,11 +186,51 @@ class AssemblerMIPSTest : public AssemblerTest<mips::MipsAssembler,
return result;
}
+ void BranchHelper(void (mips::MipsAssembler::*f)(mips::MipsLabel*,
+ bool),
+ const std::string& instr_name,
+ bool is_bare = false) {
+ __ SetReorder(false);
+ mips::MipsLabel label1, label2;
+ (Base::GetAssembler()->*f)(&label1, is_bare);
+ constexpr size_t kAdduCount1 = 63;
+ for (size_t i = 0; i != kAdduCount1; ++i) {
+ __ Addu(mips::ZERO, mips::ZERO, mips::ZERO);
+ }
+ __ Bind(&label1);
+ (Base::GetAssembler()->*f)(&label2, is_bare);
+ constexpr size_t kAdduCount2 = 64;
+ for (size_t i = 0; i != kAdduCount2; ++i) {
+ __ Addu(mips::ZERO, mips::ZERO, mips::ZERO);
+ }
+ __ Bind(&label2);
+ (Base::GetAssembler()->*f)(&label1, is_bare);
+ __ Addu(mips::ZERO, mips::ZERO, mips::ZERO);
+
+ std::string expected =
+ ".set noreorder\n" +
+ instr_name + " 1f\n" +
+ (is_bare ? "" : "nop\n") +
+ RepeatInsn(kAdduCount1, "addu $zero, $zero, $zero\n") +
+ "1:\n" +
+ instr_name + " 2f\n" +
+ (is_bare ? "" : "nop\n") +
+ RepeatInsn(kAdduCount2, "addu $zero, $zero, $zero\n") +
+ "2:\n" +
+ instr_name + " 1b\n" +
+ (is_bare ? "" : "nop\n") +
+ "addu $zero, $zero, $zero\n";
+ DriverStr(expected, instr_name);
+ }
+
void BranchCondOneRegHelper(void (mips::MipsAssembler::*f)(mips::Register,
- mips::MipsLabel*),
- const std::string& instr_name) {
+ mips::MipsLabel*,
+ bool),
+ const std::string& instr_name,
+ bool is_bare = false) {
+ __ SetReorder(false);
mips::MipsLabel label;
- (Base::GetAssembler()->*f)(mips::A0, &label);
+ (Base::GetAssembler()->*f)(mips::A0, &label, is_bare);
constexpr size_t kAdduCount1 = 63;
for (size_t i = 0; i != kAdduCount1; ++i) {
__ Addu(mips::ZERO, mips::ZERO, mips::ZERO);
@@ -200,26 +240,64 @@ class AssemblerMIPSTest : public AssemblerTest<mips::MipsAssembler,
for (size_t i = 0; i != kAdduCount2; ++i) {
__ Addu(mips::ZERO, mips::ZERO, mips::ZERO);
}
- (Base::GetAssembler()->*f)(mips::A1, &label);
+ (Base::GetAssembler()->*f)(mips::A1, &label, is_bare);
+ __ Addu(mips::ZERO, mips::ZERO, mips::ZERO);
std::string expected =
".set noreorder\n" +
- instr_name + " $a0, 1f\n"
- "nop\n" +
+ instr_name + " $a0, 1f\n" +
+ (is_bare ? "" : "nop\n") +
RepeatInsn(kAdduCount1, "addu $zero, $zero, $zero\n") +
"1:\n" +
RepeatInsn(kAdduCount2, "addu $zero, $zero, $zero\n") +
- instr_name + " $a1, 1b\n"
- "nop\n";
+ instr_name + " $a1, 1b\n" +
+ (is_bare ? "" : "nop\n") +
+ "addu $zero, $zero, $zero\n";
DriverStr(expected, instr_name);
}
void BranchCondTwoRegsHelper(void (mips::MipsAssembler::*f)(mips::Register,
mips::Register,
- mips::MipsLabel*),
- const std::string& instr_name) {
+ mips::MipsLabel*,
+ bool),
+ const std::string& instr_name,
+ bool is_bare = false) {
+ __ SetReorder(false);
+ mips::MipsLabel label;
+ (Base::GetAssembler()->*f)(mips::A0, mips::A1, &label, is_bare);
+ constexpr size_t kAdduCount1 = 63;
+ for (size_t i = 0; i != kAdduCount1; ++i) {
+ __ Addu(mips::ZERO, mips::ZERO, mips::ZERO);
+ }
+ __ Bind(&label);
+ constexpr size_t kAdduCount2 = 64;
+ for (size_t i = 0; i != kAdduCount2; ++i) {
+ __ Addu(mips::ZERO, mips::ZERO, mips::ZERO);
+ }
+ (Base::GetAssembler()->*f)(mips::A2, mips::A3, &label, is_bare);
+ __ Addu(mips::ZERO, mips::ZERO, mips::ZERO);
+
+ std::string expected =
+ ".set noreorder\n" +
+ instr_name + " $a0, $a1, 1f\n" +
+ (is_bare ? "" : "nop\n") +
+ RepeatInsn(kAdduCount1, "addu $zero, $zero, $zero\n") +
+ "1:\n" +
+ RepeatInsn(kAdduCount2, "addu $zero, $zero, $zero\n") +
+ instr_name + " $a2, $a3, 1b\n" +
+ (is_bare ? "" : "nop\n") +
+ "addu $zero, $zero, $zero\n";
+ DriverStr(expected, instr_name);
+ }
+
+ void BranchFpuCondCodeHelper(void (mips::MipsAssembler::*f)(int,
+ mips::MipsLabel*,
+ bool),
+ const std::string& instr_name,
+ bool is_bare = false) {
+ __ SetReorder(false);
mips::MipsLabel label;
- (Base::GetAssembler()->*f)(mips::A0, mips::A1, &label);
+ (Base::GetAssembler()->*f)(0, &label, is_bare);
constexpr size_t kAdduCount1 = 63;
for (size_t i = 0; i != kAdduCount1; ++i) {
__ Addu(mips::ZERO, mips::ZERO, mips::ZERO);
@@ -229,17 +307,19 @@ class AssemblerMIPSTest : public AssemblerTest<mips::MipsAssembler,
for (size_t i = 0; i != kAdduCount2; ++i) {
__ Addu(mips::ZERO, mips::ZERO, mips::ZERO);
}
- (Base::GetAssembler()->*f)(mips::A2, mips::A3, &label);
+ (Base::GetAssembler()->*f)(7, &label, is_bare);
+ __ Addu(mips::ZERO, mips::ZERO, mips::ZERO);
std::string expected =
".set noreorder\n" +
- instr_name + " $a0, $a1, 1f\n"
- "nop\n" +
+ instr_name + " $fcc0, 1f\n" +
+ (is_bare ? "" : "nop\n") +
RepeatInsn(kAdduCount1, "addu $zero, $zero, $zero\n") +
"1:\n" +
RepeatInsn(kAdduCount2, "addu $zero, $zero, $zero\n") +
- instr_name + " $a2, $a3, 1b\n"
- "nop\n";
+ instr_name + " $fcc7, 1b\n" +
+ (is_bare ? "" : "nop\n") +
+ "addu $zero, $zero, $zero\n";
DriverStr(expected, instr_name);
}
@@ -2072,410 +2152,136 @@ TEST_F(AssemblerMIPSTest, StoreConstToOffset) {
DriverStr(expected, "StoreConstToOffset");
}
+//////////////
+// BRANCHES //
+//////////////
+
TEST_F(AssemblerMIPSTest, B) {
- mips::MipsLabel label1, label2;
- __ B(&label1);
- constexpr size_t kAdduCount1 = 63;
- for (size_t i = 0; i != kAdduCount1; ++i) {
- __ Addu(mips::ZERO, mips::ZERO, mips::ZERO);
- }
- __ Bind(&label1);
- __ B(&label2);
- constexpr size_t kAdduCount2 = 64;
- for (size_t i = 0; i != kAdduCount2; ++i) {
- __ Addu(mips::ZERO, mips::ZERO, mips::ZERO);
- }
- __ Bind(&label2);
- __ B(&label1);
+ BranchHelper(&mips::MipsAssembler::B, "B");
+}
- std::string expected =
- ".set noreorder\n"
- "b 1f\n"
- "nop\n" +
- RepeatInsn(kAdduCount1, "addu $zero, $zero, $zero\n") +
- "1:\n"
- "b 2f\n"
- "nop\n" +
- RepeatInsn(kAdduCount2, "addu $zero, $zero, $zero\n") +
- "2:\n"
- "b 1b\n"
- "nop\n";
- DriverStr(expected, "B");
+TEST_F(AssemblerMIPSTest, Bal) {
+ BranchHelper(&mips::MipsAssembler::Bal, "Bal");
}
TEST_F(AssemblerMIPSTest, Beq) {
- __ SetReorder(false);
BranchCondTwoRegsHelper(&mips::MipsAssembler::Beq, "Beq");
}
TEST_F(AssemblerMIPSTest, Bne) {
- __ SetReorder(false);
BranchCondTwoRegsHelper(&mips::MipsAssembler::Bne, "Bne");
}
TEST_F(AssemblerMIPSTest, Beqz) {
- __ SetReorder(false);
- mips::MipsLabel label;
- __ Beqz(mips::A0, &label);
- constexpr size_t kAdduCount1 = 63;
- for (size_t i = 0; i != kAdduCount1; ++i) {
- __ Addu(mips::ZERO, mips::ZERO, mips::ZERO);
- }
- __ Bind(&label);
- constexpr size_t kAdduCount2 = 64;
- for (size_t i = 0; i != kAdduCount2; ++i) {
- __ Addu(mips::ZERO, mips::ZERO, mips::ZERO);
- }
- __ Beqz(mips::A1, &label);
-
- std::string expected =
- ".set noreorder\n"
- "beq $zero, $a0, 1f\n"
- "nop\n" +
- RepeatInsn(kAdduCount1, "addu $zero, $zero, $zero\n") +
- "1:\n" +
- RepeatInsn(kAdduCount2, "addu $zero, $zero, $zero\n") +
- "beq $zero, $a1, 1b\n"
- "nop\n";
- DriverStr(expected, "Beqz");
+ BranchCondOneRegHelper(&mips::MipsAssembler::Beqz, "Beqz");
}
TEST_F(AssemblerMIPSTest, Bnez) {
- __ SetReorder(false);
- mips::MipsLabel label;
- __ Bnez(mips::A0, &label);
- constexpr size_t kAdduCount1 = 63;
- for (size_t i = 0; i != kAdduCount1; ++i) {
- __ Addu(mips::ZERO, mips::ZERO, mips::ZERO);
- }
- __ Bind(&label);
- constexpr size_t kAdduCount2 = 64;
- for (size_t i = 0; i != kAdduCount2; ++i) {
- __ Addu(mips::ZERO, mips::ZERO, mips::ZERO);
- }
- __ Bnez(mips::A1, &label);
-
- std::string expected =
- ".set noreorder\n"
- "bne $zero, $a0, 1f\n"
- "nop\n" +
- RepeatInsn(kAdduCount1, "addu $zero, $zero, $zero\n") +
- "1:\n" +
- RepeatInsn(kAdduCount2, "addu $zero, $zero, $zero\n") +
- "bne $zero, $a1, 1b\n"
- "nop\n";
- DriverStr(expected, "Bnez");
+ BranchCondOneRegHelper(&mips::MipsAssembler::Bnez, "Bnez");
}
TEST_F(AssemblerMIPSTest, Bltz) {
- __ SetReorder(false);
BranchCondOneRegHelper(&mips::MipsAssembler::Bltz, "Bltz");
}
TEST_F(AssemblerMIPSTest, Bgez) {
- __ SetReorder(false);
BranchCondOneRegHelper(&mips::MipsAssembler::Bgez, "Bgez");
}
TEST_F(AssemblerMIPSTest, Blez) {
- __ SetReorder(false);
BranchCondOneRegHelper(&mips::MipsAssembler::Blez, "Blez");
}
TEST_F(AssemblerMIPSTest, Bgtz) {
- __ SetReorder(false);
BranchCondOneRegHelper(&mips::MipsAssembler::Bgtz, "Bgtz");
}
TEST_F(AssemblerMIPSTest, Blt) {
- __ SetReorder(false);
- mips::MipsLabel label;
- __ Blt(mips::A0, mips::A1, &label);
- constexpr size_t kAdduCount1 = 63;
- for (size_t i = 0; i != kAdduCount1; ++i) {
- __ Addu(mips::ZERO, mips::ZERO, mips::ZERO);
- }
- __ Bind(&label);
- constexpr size_t kAdduCount2 = 64;
- for (size_t i = 0; i != kAdduCount2; ++i) {
- __ Addu(mips::ZERO, mips::ZERO, mips::ZERO);
- }
- __ Blt(mips::A2, mips::A3, &label);
-
- std::string expected =
- ".set noreorder\n"
- "slt $at, $a0, $a1\n"
- "bne $zero, $at, 1f\n"
- "nop\n" +
- RepeatInsn(kAdduCount1, "addu $zero, $zero, $zero\n") +
- "1:\n" +
- RepeatInsn(kAdduCount2, "addu $zero, $zero, $zero\n") +
- "slt $at, $a2, $a3\n"
- "bne $zero, $at, 1b\n"
- "nop\n";
- DriverStr(expected, "Blt");
+ BranchCondTwoRegsHelper(&mips::MipsAssembler::Blt, "Blt");
}
TEST_F(AssemblerMIPSTest, Bge) {
- __ SetReorder(false);
- mips::MipsLabel label;
- __ Bge(mips::A0, mips::A1, &label);
- constexpr size_t kAdduCount1 = 63;
- for (size_t i = 0; i != kAdduCount1; ++i) {
- __ Addu(mips::ZERO, mips::ZERO, mips::ZERO);
- }
- __ Bind(&label);
- constexpr size_t kAdduCount2 = 64;
- for (size_t i = 0; i != kAdduCount2; ++i) {
- __ Addu(mips::ZERO, mips::ZERO, mips::ZERO);
- }
- __ Bge(mips::A2, mips::A3, &label);
-
- std::string expected =
- ".set noreorder\n"
- "slt $at, $a0, $a1\n"
- "beq $zero, $at, 1f\n"
- "nop\n" +
- RepeatInsn(kAdduCount1, "addu $zero, $zero, $zero\n") +
- "1:\n" +
- RepeatInsn(kAdduCount2, "addu $zero, $zero, $zero\n") +
- "slt $at, $a2, $a3\n"
- "beq $zero, $at, 1b\n"
- "nop\n";
- DriverStr(expected, "Bge");
+ BranchCondTwoRegsHelper(&mips::MipsAssembler::Bge, "Bge");
}
TEST_F(AssemblerMIPSTest, Bltu) {
- __ SetReorder(false);
- mips::MipsLabel label;
- __ Bltu(mips::A0, mips::A1, &label);
- constexpr size_t kAdduCount1 = 63;
- for (size_t i = 0; i != kAdduCount1; ++i) {
- __ Addu(mips::ZERO, mips::ZERO, mips::ZERO);
- }
- __ Bind(&label);
- constexpr size_t kAdduCount2 = 64;
- for (size_t i = 0; i != kAdduCount2; ++i) {
- __ Addu(mips::ZERO, mips::ZERO, mips::ZERO);
- }
- __ Bltu(mips::A2, mips::A3, &label);
-
- std::string expected =
- ".set noreorder\n"
- "sltu $at, $a0, $a1\n"
- "bne $zero, $at, 1f\n"
- "nop\n" +
- RepeatInsn(kAdduCount1, "addu $zero, $zero, $zero\n") +
- "1:\n" +
- RepeatInsn(kAdduCount2, "addu $zero, $zero, $zero\n") +
- "sltu $at, $a2, $a3\n"
- "bne $zero, $at, 1b\n"
- "nop\n";
- DriverStr(expected, "Bltu");
+ BranchCondTwoRegsHelper(&mips::MipsAssembler::Bltu, "Bltu");
}
TEST_F(AssemblerMIPSTest, Bgeu) {
- __ SetReorder(false);
- mips::MipsLabel label;
- __ Bgeu(mips::A0, mips::A1, &label);
- constexpr size_t kAdduCount1 = 63;
- for (size_t i = 0; i != kAdduCount1; ++i) {
- __ Addu(mips::ZERO, mips::ZERO, mips::ZERO);
- }
- __ Bind(&label);
- constexpr size_t kAdduCount2 = 64;
- for (size_t i = 0; i != kAdduCount2; ++i) {
- __ Addu(mips::ZERO, mips::ZERO, mips::ZERO);
- }
- __ Bgeu(mips::A2, mips::A3, &label);
-
- std::string expected =
- ".set noreorder\n"
- "sltu $at, $a0, $a1\n"
- "beq $zero, $at, 1f\n"
- "nop\n" +
- RepeatInsn(kAdduCount1, "addu $zero, $zero, $zero\n") +
- "1:\n" +
- RepeatInsn(kAdduCount2, "addu $zero, $zero, $zero\n") +
- "sltu $at, $a2, $a3\n"
- "beq $zero, $at, 1b\n"
- "nop\n";
- DriverStr(expected, "Bgeu");
+ BranchCondTwoRegsHelper(&mips::MipsAssembler::Bgeu, "Bgeu");
}
TEST_F(AssemblerMIPSTest, Bc1f) {
- __ SetReorder(false);
- mips::MipsLabel label;
- __ Bc1f(0, &label);
- constexpr size_t kAdduCount1 = 63;
- for (size_t i = 0; i != kAdduCount1; ++i) {
- __ Addu(mips::ZERO, mips::ZERO, mips::ZERO);
- }
- __ Bind(&label);
- constexpr size_t kAdduCount2 = 64;
- for (size_t i = 0; i != kAdduCount2; ++i) {
- __ Addu(mips::ZERO, mips::ZERO, mips::ZERO);
- }
- __ Bc1f(7, &label);
-
- std::string expected =
- ".set noreorder\n"
- "bc1f $fcc0, 1f\n"
- "nop\n" +
- RepeatInsn(kAdduCount1, "addu $zero, $zero, $zero\n") +
- "1:\n" +
- RepeatInsn(kAdduCount2, "addu $zero, $zero, $zero\n") +
- "bc1f $fcc7, 1b\n"
- "nop\n";
- DriverStr(expected, "Bc1f");
+ BranchFpuCondCodeHelper(&mips::MipsAssembler::Bc1f, "Bc1f");
}
TEST_F(AssemblerMIPSTest, Bc1t) {
- __ SetReorder(false);
- mips::MipsLabel label;
- __ Bc1t(0, &label);
- constexpr size_t kAdduCount1 = 63;
- for (size_t i = 0; i != kAdduCount1; ++i) {
- __ Addu(mips::ZERO, mips::ZERO, mips::ZERO);
- }
- __ Bind(&label);
- constexpr size_t kAdduCount2 = 64;
- for (size_t i = 0; i != kAdduCount2; ++i) {
- __ Addu(mips::ZERO, mips::ZERO, mips::ZERO);
- }
- __ Bc1t(7, &label);
+ BranchFpuCondCodeHelper(&mips::MipsAssembler::Bc1t, "Bc1t");
+}
- std::string expected =
- ".set noreorder\n"
- "bc1t $fcc0, 1f\n"
- "nop\n" +
- RepeatInsn(kAdduCount1, "addu $zero, $zero, $zero\n") +
- "1:\n" +
- RepeatInsn(kAdduCount2, "addu $zero, $zero, $zero\n") +
- "bc1t $fcc7, 1b\n"
- "nop\n";
- DriverStr(expected, "Bc1t");
+TEST_F(AssemblerMIPSTest, BareB) {
+ BranchHelper(&mips::MipsAssembler::B, "B", /* is_bare */ true);
}
-///////////////////////
-// Loading Constants //
-///////////////////////
+TEST_F(AssemblerMIPSTest, BareBal) {
+ BranchHelper(&mips::MipsAssembler::Bal, "Bal", /* is_bare */ true);
+}
-TEST_F(AssemblerMIPSTest, LoadConst32) {
- // IsUint<16>(value)
- __ LoadConst32(mips::V0, 0);
- __ LoadConst32(mips::V0, 65535);
- // IsInt<16>(value)
- __ LoadConst32(mips::V0, -1);
- __ LoadConst32(mips::V0, -32768);
- // Everything else
- __ LoadConst32(mips::V0, 65536);
- __ LoadConst32(mips::V0, 65537);
- __ LoadConst32(mips::V0, 2147483647);
- __ LoadConst32(mips::V0, -32769);
- __ LoadConst32(mips::V0, -65536);
- __ LoadConst32(mips::V0, -65537);
- __ LoadConst32(mips::V0, -2147483647);
- __ LoadConst32(mips::V0, -2147483648);
+TEST_F(AssemblerMIPSTest, BareBeq) {
+ BranchCondTwoRegsHelper(&mips::MipsAssembler::Beq, "Beq", /* is_bare */ true);
+}
- const char* expected =
- // IsUint<16>(value)
- "ori $v0, $zero, 0\n" // __ LoadConst32(mips::V0, 0);
- "ori $v0, $zero, 65535\n" // __ LoadConst32(mips::V0, 65535);
- // IsInt<16>(value)
- "addiu $v0, $zero, -1\n" // __ LoadConst32(mips::V0, -1);
- "addiu $v0, $zero, -32768\n" // __ LoadConst32(mips::V0, -32768);
- // Everything else
- "lui $v0, 1\n" // __ LoadConst32(mips::V0, 65536);
- "lui $v0, 1\n" // __ LoadConst32(mips::V0, 65537);
- "ori $v0, 1\n" // "
- "lui $v0, 32767\n" // __ LoadConst32(mips::V0, 2147483647);
- "ori $v0, 65535\n" // "
- "lui $v0, 65535\n" // __ LoadConst32(mips::V0, -32769);
- "ori $v0, 32767\n" // "
- "lui $v0, 65535\n" // __ LoadConst32(mips::V0, -65536);
- "lui $v0, 65534\n" // __ LoadConst32(mips::V0, -65537);
- "ori $v0, 65535\n" // "
- "lui $v0, 32768\n" // __ LoadConst32(mips::V0, -2147483647);
- "ori $v0, 1\n" // "
- "lui $v0, 32768\n"; // __ LoadConst32(mips::V0, -2147483648);
- DriverStr(expected, "LoadConst32");
+TEST_F(AssemblerMIPSTest, BareBne) {
+ BranchCondTwoRegsHelper(&mips::MipsAssembler::Bne, "Bne", /* is_bare */ true);
}
-TEST_F(AssemblerMIPSTest, LoadFarthestNearLabelAddress) {
- mips::MipsLabel label;
- __ BindPcRelBaseLabel();
- __ LoadLabelAddress(mips::V0, mips::V1, &label);
- constexpr size_t kAddiuCount = 0x1FDE;
- for (size_t i = 0; i != kAddiuCount; ++i) {
- __ Addiu(mips::A0, mips::A1, 0);
- }
- __ Bind(&label);
+TEST_F(AssemblerMIPSTest, BareBeqz) {
+ BranchCondOneRegHelper(&mips::MipsAssembler::Beqz, "Beqz", /* is_bare */ true);
+}
- std::string expected =
- "1:\n"
- "addiu $v0, $v1, %lo(2f - 1b)\n" +
- RepeatInsn(kAddiuCount, "addiu $a0, $a1, %hi(2f - 1b)\n") +
- "2:\n";
- DriverStr(expected, "LoadFarthestNearLabelAddress");
+TEST_F(AssemblerMIPSTest, BareBnez) {
+ BranchCondOneRegHelper(&mips::MipsAssembler::Bnez, "Bnez", /* is_bare */ true);
}
-TEST_F(AssemblerMIPSTest, LoadNearestFarLabelAddress) {
- mips::MipsLabel label;
- __ BindPcRelBaseLabel();
- __ LoadLabelAddress(mips::V0, mips::V1, &label);
- constexpr size_t kAdduCount = 0x1FDF;
- for (size_t i = 0; i != kAdduCount; ++i) {
- __ Addu(mips::ZERO, mips::ZERO, mips::ZERO);
- }
- __ Bind(&label);
+TEST_F(AssemblerMIPSTest, BareBltz) {
+ BranchCondOneRegHelper(&mips::MipsAssembler::Bltz, "Bltz", /* is_bare */ true);
+}
- std::string expected =
- "1:\n"
- "lui $at, %hi(2f - 1b)\n"
- "ori $at, $at, %lo(2f - 1b)\n"
- "addu $v0, $at, $v1\n" +
- RepeatInsn(kAdduCount, "addu $zero, $zero, $zero\n") +
- "2:\n";
- DriverStr(expected, "LoadNearestFarLabelAddress");
+TEST_F(AssemblerMIPSTest, BareBgez) {
+ BranchCondOneRegHelper(&mips::MipsAssembler::Bgez, "Bgez", /* is_bare */ true);
}
-TEST_F(AssemblerMIPSTest, LoadFarthestNearLiteral) {
- mips::Literal* literal = __ NewLiteral<uint32_t>(0x12345678);
- __ BindPcRelBaseLabel();
- __ LoadLiteral(mips::V0, mips::V1, literal);
- constexpr size_t kAddiuCount = 0x1FDE;
- for (size_t i = 0; i != kAddiuCount; ++i) {
- __ Addiu(mips::A0, mips::A1, 0);
- }
+TEST_F(AssemblerMIPSTest, BareBlez) {
+ BranchCondOneRegHelper(&mips::MipsAssembler::Blez, "Blez", /* is_bare */ true);
+}
- std::string expected =
- "1:\n"
- "lw $v0, %lo(2f - 1b)($v1)\n" +
- RepeatInsn(kAddiuCount, "addiu $a0, $a1, %hi(2f - 1b)\n") +
- "2:\n"
- ".word 0x12345678\n";
- DriverStr(expected, "LoadFarthestNearLiteral");
+TEST_F(AssemblerMIPSTest, BareBgtz) {
+ BranchCondOneRegHelper(&mips::MipsAssembler::Bgtz, "Bgtz", /* is_bare */ true);
}
-TEST_F(AssemblerMIPSTest, LoadNearestFarLiteral) {
- mips::Literal* literal = __ NewLiteral<uint32_t>(0x12345678);
- __ BindPcRelBaseLabel();
- __ LoadLiteral(mips::V0, mips::V1, literal);
- constexpr size_t kAdduCount = 0x1FDF;
- for (size_t i = 0; i != kAdduCount; ++i) {
- __ Addu(mips::ZERO, mips::ZERO, mips::ZERO);
- }
+TEST_F(AssemblerMIPSTest, BareBlt) {
+ BranchCondTwoRegsHelper(&mips::MipsAssembler::Blt, "Blt", /* is_bare */ true);
+}
- std::string expected =
- "1:\n"
- "lui $at, %hi(2f - 1b)\n"
- "addu $at, $at, $v1\n"
- "lw $v0, %lo(2f - 1b)($at)\n" +
- RepeatInsn(kAdduCount, "addu $zero, $zero, $zero\n") +
- "2:\n"
- ".word 0x12345678\n";
- DriverStr(expected, "LoadNearestFarLiteral");
+TEST_F(AssemblerMIPSTest, BareBge) {
+ BranchCondTwoRegsHelper(&mips::MipsAssembler::Bge, "Bge", /* is_bare */ true);
+}
+
+TEST_F(AssemblerMIPSTest, BareBltu) {
+ BranchCondTwoRegsHelper(&mips::MipsAssembler::Bltu, "Bltu", /* is_bare */ true);
+}
+
+TEST_F(AssemblerMIPSTest, BareBgeu) {
+ BranchCondTwoRegsHelper(&mips::MipsAssembler::Bgeu, "Bgeu", /* is_bare */ true);
+}
+
+TEST_F(AssemblerMIPSTest, BareBc1f) {
+ BranchFpuCondCodeHelper(&mips::MipsAssembler::Bc1f, "Bc1f", /* is_bare */ true);
+}
+
+TEST_F(AssemblerMIPSTest, BareBc1t) {
+ BranchFpuCondCodeHelper(&mips::MipsAssembler::Bc1t, "Bc1t", /* is_bare */ true);
}
TEST_F(AssemblerMIPSTest, ImpossibleReordering) {
@@ -2554,7 +2360,7 @@ TEST_F(AssemblerMIPSTest, ImpossibleReordering) {
"nop\n"
"addu $t0, $t1, $t2\n"
- "beq $zero, $t0, 1b\n"
+ "beqz $t0, 1b\n"
"nop\n"
"or $t1, $t2, $t3\n"
@@ -2563,17 +2369,17 @@ TEST_F(AssemblerMIPSTest, ImpossibleReordering) {
"and $t0, $t1, $t2\n"
"slt $at, $t1, $t0\n"
- "bne $zero, $at, 1b\n"
+ "bnez $at, 1b\n"
"nop\n"
"xor $at, $t0, $t1\n"
"slt $at, $t1, $t0\n"
- "beq $zero, $at, 1b\n"
+ "beqz $at, 1b\n"
"nop\n"
"subu $t0, $t1, $at\n"
"sltu $at, $t1, $t0\n"
- "bne $zero, $at, 1b\n"
+ "bnez $at, 1b\n"
"nop\n"
"c.olt.s $fcc1, $f2, $f4\n"
@@ -2606,11 +2412,11 @@ TEST_F(AssemblerMIPSTest, ImpossibleReordering) {
"2:\n"
- "bne $zero, $t0, 2b\n"
+ "bnez $t0, 2b\n"
"nop\n"
"sltu $at, $t1, $t0\n"
- "beq $zero, $at, 2b\n"
+ "beqz $at, 2b\n"
"nop\n"
"bc1f $fcc2, 2b\n"
@@ -2666,22 +2472,22 @@ TEST_F(AssemblerMIPSTest, Reordering) {
".set noreorder\n"
"1:\n"
- "beq $zero, $t1, 1b\n"
+ "beqz $t1, 1b\n"
"addu $t0, $t1, $t2\n"
"bne $t2, $t3, 1b\n"
"or $t1, $t2, $t3\n"
"slt $at, $t1, $t2\n"
- "bne $zero, $at, 1b\n"
+ "bnez $at, 1b\n"
"and $t0, $t1, $t2\n"
"slt $at, $t1, $t0\n"
- "beq $zero, $at, 1b\n"
+ "beqz $at, 1b\n"
"xor $t2, $t0, $t1\n"
"sltu $at, $t1, $t0\n"
- "bne $zero, $at, 1b\n"
+ "bnez $at, 1b\n"
"subu $t2, $t1, $t0\n"
"bc1t $fcc1, 1b\n"
@@ -2882,6 +2688,127 @@ TEST_F(AssemblerMIPSTest, LongBranchReorder) {
DriverStr(expected, "LongBranchReorder");
}
+///////////////////////
+// Loading Constants //
+///////////////////////
+
+TEST_F(AssemblerMIPSTest, LoadConst32) {
+ // IsUint<16>(value)
+ __ LoadConst32(mips::V0, 0);
+ __ LoadConst32(mips::V0, 65535);
+ // IsInt<16>(value)
+ __ LoadConst32(mips::V0, -1);
+ __ LoadConst32(mips::V0, -32768);
+ // Everything else
+ __ LoadConst32(mips::V0, 65536);
+ __ LoadConst32(mips::V0, 65537);
+ __ LoadConst32(mips::V0, 2147483647);
+ __ LoadConst32(mips::V0, -32769);
+ __ LoadConst32(mips::V0, -65536);
+ __ LoadConst32(mips::V0, -65537);
+ __ LoadConst32(mips::V0, -2147483647);
+ __ LoadConst32(mips::V0, -2147483648);
+
+ const char* expected =
+ // IsUint<16>(value)
+ "ori $v0, $zero, 0\n" // __ LoadConst32(mips::V0, 0);
+ "ori $v0, $zero, 65535\n" // __ LoadConst32(mips::V0, 65535);
+ // IsInt<16>(value)
+ "addiu $v0, $zero, -1\n" // __ LoadConst32(mips::V0, -1);
+ "addiu $v0, $zero, -32768\n" // __ LoadConst32(mips::V0, -32768);
+ // Everything else
+ "lui $v0, 1\n" // __ LoadConst32(mips::V0, 65536);
+ "lui $v0, 1\n" // __ LoadConst32(mips::V0, 65537);
+ "ori $v0, 1\n" // "
+ "lui $v0, 32767\n" // __ LoadConst32(mips::V0, 2147483647);
+ "ori $v0, 65535\n" // "
+ "lui $v0, 65535\n" // __ LoadConst32(mips::V0, -32769);
+ "ori $v0, 32767\n" // "
+ "lui $v0, 65535\n" // __ LoadConst32(mips::V0, -65536);
+ "lui $v0, 65534\n" // __ LoadConst32(mips::V0, -65537);
+ "ori $v0, 65535\n" // "
+ "lui $v0, 32768\n" // __ LoadConst32(mips::V0, -2147483647);
+ "ori $v0, 1\n" // "
+ "lui $v0, 32768\n"; // __ LoadConst32(mips::V0, -2147483648);
+ DriverStr(expected, "LoadConst32");
+}
+
+TEST_F(AssemblerMIPSTest, LoadFarthestNearLabelAddress) {
+ mips::MipsLabel label;
+ __ BindPcRelBaseLabel();
+ __ LoadLabelAddress(mips::V0, mips::V1, &label);
+ constexpr size_t kAddiuCount = 0x1FDE;
+ for (size_t i = 0; i != kAddiuCount; ++i) {
+ __ Addiu(mips::A0, mips::A1, 0);
+ }
+ __ Bind(&label);
+
+ std::string expected =
+ "1:\n"
+ "addiu $v0, $v1, %lo(2f - 1b)\n" +
+ RepeatInsn(kAddiuCount, "addiu $a0, $a1, %hi(2f - 1b)\n") +
+ "2:\n";
+ DriverStr(expected, "LoadFarthestNearLabelAddress");
+}
+
+TEST_F(AssemblerMIPSTest, LoadNearestFarLabelAddress) {
+ mips::MipsLabel label;
+ __ BindPcRelBaseLabel();
+ __ LoadLabelAddress(mips::V0, mips::V1, &label);
+ constexpr size_t kAdduCount = 0x1FDF;
+ for (size_t i = 0; i != kAdduCount; ++i) {
+ __ Addu(mips::ZERO, mips::ZERO, mips::ZERO);
+ }
+ __ Bind(&label);
+
+ std::string expected =
+ "1:\n"
+ "lui $at, %hi(2f - 1b)\n"
+ "ori $at, $at, %lo(2f - 1b)\n"
+ "addu $v0, $at, $v1\n" +
+ RepeatInsn(kAdduCount, "addu $zero, $zero, $zero\n") +
+ "2:\n";
+ DriverStr(expected, "LoadNearestFarLabelAddress");
+}
+
+TEST_F(AssemblerMIPSTest, LoadFarthestNearLiteral) {
+ mips::Literal* literal = __ NewLiteral<uint32_t>(0x12345678);
+ __ BindPcRelBaseLabel();
+ __ LoadLiteral(mips::V0, mips::V1, literal);
+ constexpr size_t kAddiuCount = 0x1FDE;
+ for (size_t i = 0; i != kAddiuCount; ++i) {
+ __ Addiu(mips::A0, mips::A1, 0);
+ }
+
+ std::string expected =
+ "1:\n"
+ "lw $v0, %lo(2f - 1b)($v1)\n" +
+ RepeatInsn(kAddiuCount, "addiu $a0, $a1, %hi(2f - 1b)\n") +
+ "2:\n"
+ ".word 0x12345678\n";
+ DriverStr(expected, "LoadFarthestNearLiteral");
+}
+
+TEST_F(AssemblerMIPSTest, LoadNearestFarLiteral) {
+ mips::Literal* literal = __ NewLiteral<uint32_t>(0x12345678);
+ __ BindPcRelBaseLabel();
+ __ LoadLiteral(mips::V0, mips::V1, literal);
+ constexpr size_t kAdduCount = 0x1FDF;
+ for (size_t i = 0; i != kAdduCount; ++i) {
+ __ Addu(mips::ZERO, mips::ZERO, mips::ZERO);
+ }
+
+ std::string expected =
+ "1:\n"
+ "lui $at, %hi(2f - 1b)\n"
+ "addu $at, $at, $v1\n"
+ "lw $v0, %lo(2f - 1b)($at)\n" +
+ RepeatInsn(kAdduCount, "addu $zero, $zero, $zero\n") +
+ "2:\n"
+ ".word 0x12345678\n";
+ DriverStr(expected, "LoadNearestFarLiteral");
+}
+
#undef __
} // namespace art
diff --git a/compiler/utils/mips64/assembler_mips64.cc b/compiler/utils/mips64/assembler_mips64.cc
index 7a1beb656b..3aa09fbdb6 100644
--- a/compiler/utils/mips64/assembler_mips64.cc
+++ b/compiler/utils/mips64/assembler_mips64.cc
@@ -795,14 +795,42 @@ void Mips64Assembler::Bc1nez(FpuRegister ft, uint16_t imm16) {
EmitFI(0x11, 0xD, ft, imm16);
}
+void Mips64Assembler::Beq(GpuRegister rs, GpuRegister rt, uint16_t imm16) {
+ EmitI(0x4, rs, rt, imm16);
+}
+
+void Mips64Assembler::Bne(GpuRegister rs, GpuRegister rt, uint16_t imm16) {
+ EmitI(0x5, rs, rt, imm16);
+}
+
void Mips64Assembler::Beqz(GpuRegister rt, uint16_t imm16) {
- EmitI(0x4, ZERO, rt, imm16);
+ Beq(rt, ZERO, imm16);
+}
+
+void Mips64Assembler::Bnez(GpuRegister rt, uint16_t imm16) {
+ Bne(rt, ZERO, imm16);
+}
+
+void Mips64Assembler::Bltz(GpuRegister rt, uint16_t imm16) {
+ EmitI(0x1, rt, static_cast<GpuRegister>(0), imm16);
+}
+
+void Mips64Assembler::Bgez(GpuRegister rt, uint16_t imm16) {
+ EmitI(0x1, rt, static_cast<GpuRegister>(0x1), imm16);
+}
+
+void Mips64Assembler::Blez(GpuRegister rt, uint16_t imm16) {
+ EmitI(0x6, rt, static_cast<GpuRegister>(0), imm16);
+}
+
+void Mips64Assembler::Bgtz(GpuRegister rt, uint16_t imm16) {
+ EmitI(0x7, rt, static_cast<GpuRegister>(0), imm16);
}
-void Mips64Assembler::EmitBcondc(BranchCondition cond,
- GpuRegister rs,
- GpuRegister rt,
- uint32_t imm16_21) {
+void Mips64Assembler::EmitBcondR6(BranchCondition cond,
+ GpuRegister rs,
+ GpuRegister rt,
+ uint32_t imm16_21) {
switch (cond) {
case kCondLT:
Bltc(rs, rt, imm16_21);
@@ -866,6 +894,55 @@ void Mips64Assembler::EmitBcondc(BranchCondition cond,
}
}
+void Mips64Assembler::EmitBcondR2(BranchCondition cond,
+ GpuRegister rs,
+ GpuRegister rt,
+ uint16_t imm16) {
+ switch (cond) {
+ case kCondLTZ:
+ CHECK_EQ(rt, ZERO);
+ Bltz(rs, imm16);
+ break;
+ case kCondGEZ:
+ CHECK_EQ(rt, ZERO);
+ Bgez(rs, imm16);
+ break;
+ case kCondLEZ:
+ CHECK_EQ(rt, ZERO);
+ Blez(rs, imm16);
+ break;
+ case kCondGTZ:
+ CHECK_EQ(rt, ZERO);
+ Bgtz(rs, imm16);
+ break;
+ case kCondEQ:
+ Beq(rs, rt, imm16);
+ break;
+ case kCondNE:
+ Bne(rs, rt, imm16);
+ break;
+ case kCondEQZ:
+ CHECK_EQ(rt, ZERO);
+ Beqz(rs, imm16);
+ break;
+ case kCondNEZ:
+ CHECK_EQ(rt, ZERO);
+ Bnez(rs, imm16);
+ break;
+ case kCondF:
+ case kCondT:
+ case kCondLT:
+ case kCondGE:
+ case kCondLE:
+ case kCondGT:
+ case kCondLTU:
+ case kCondGEU:
+ case kUncond:
+ LOG(FATAL) << "Unexpected branch condition " << cond;
+ UNREACHABLE();
+ }
+}
+
void Mips64Assembler::AddS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
EmitFR(0x11, 0x10, ft, fs, fd, 0x0);
}
@@ -2013,37 +2090,67 @@ void Mips64Assembler::Branch::InitShortOrLong(Mips64Assembler::Branch::OffsetBit
type_ = (offset_size <= branch_info_[short_type].offset_size) ? short_type : long_type;
}
-void Mips64Assembler::Branch::InitializeType(Type initial_type) {
- OffsetBits offset_size = GetOffsetSizeNeeded(location_, target_);
- switch (initial_type) {
- case kLabel:
- case kLiteral:
- case kLiteralUnsigned:
- case kLiteralLong:
- CHECK(!IsResolved());
- type_ = initial_type;
- break;
- case kCall:
- InitShortOrLong(offset_size, kCall, kLongCall);
- break;
- case kCondBranch:
- switch (condition_) {
- case kUncond:
- InitShortOrLong(offset_size, kUncondBranch, kLongUncondBranch);
- break;
- case kCondEQZ:
- case kCondNEZ:
- // Special case for beqzc/bnezc with longer offset than in other b<cond>c instructions.
- type_ = (offset_size <= kOffset23) ? kCondBranch : kLongCondBranch;
- break;
- default:
- InitShortOrLong(offset_size, kCondBranch, kLongCondBranch);
- break;
- }
- break;
- default:
- LOG(FATAL) << "Unexpected branch type " << initial_type;
- UNREACHABLE();
+void Mips64Assembler::Branch::InitializeType(Type initial_type, bool is_r6) {
+ OffsetBits offset_size_needed = GetOffsetSizeNeeded(location_, target_);
+ if (is_r6) {
+ // R6
+ switch (initial_type) {
+ case kLabel:
+ case kLiteral:
+ case kLiteralUnsigned:
+ case kLiteralLong:
+ CHECK(!IsResolved());
+ type_ = initial_type;
+ break;
+ case kCall:
+ InitShortOrLong(offset_size_needed, kCall, kLongCall);
+ break;
+ case kCondBranch:
+ switch (condition_) {
+ case kUncond:
+ InitShortOrLong(offset_size_needed, kUncondBranch, kLongUncondBranch);
+ break;
+ case kCondEQZ:
+ case kCondNEZ:
+ // Special case for beqzc/bnezc with longer offset than in other b<cond>c instructions.
+ type_ = (offset_size_needed <= kOffset23) ? kCondBranch : kLongCondBranch;
+ break;
+ default:
+ InitShortOrLong(offset_size_needed, kCondBranch, kLongCondBranch);
+ break;
+ }
+ break;
+ case kBareCall:
+ type_ = kBareCall;
+ CHECK_LE(offset_size_needed, GetOffsetSize());
+ break;
+ case kBareCondBranch:
+ type_ = (condition_ == kUncond) ? kBareUncondBranch : kBareCondBranch;
+ CHECK_LE(offset_size_needed, GetOffsetSize());
+ break;
+ default:
+ LOG(FATAL) << "Unexpected branch type " << initial_type;
+ UNREACHABLE();
+ }
+ } else {
+ // R2
+ CHECK_EQ(initial_type, kBareCondBranch);
+ switch (condition_) {
+ case kCondLTZ:
+ case kCondGEZ:
+ case kCondLEZ:
+ case kCondGTZ:
+ case kCondEQ:
+ case kCondNE:
+ case kCondEQZ:
+ case kCondNEZ:
+ break;
+ default:
+ LOG(FATAL) << "Unexpected R2 branch condition " << condition_;
+ UNREACHABLE();
+ }
+ type_ = kR2BareCondBranch;
+ CHECK_LE(offset_size_needed, GetOffsetSize());
}
old_type_ = type_;
}
@@ -2076,21 +2183,25 @@ bool Mips64Assembler::Branch::IsUncond(BranchCondition condition,
}
}
-Mips64Assembler::Branch::Branch(uint32_t location, uint32_t target, bool is_call)
+Mips64Assembler::Branch::Branch(uint32_t location, uint32_t target, bool is_call, bool is_bare)
: old_location_(location),
location_(location),
target_(target),
lhs_reg_(ZERO),
rhs_reg_(ZERO),
condition_(kUncond) {
- InitializeType(is_call ? kCall : kCondBranch);
+ InitializeType(
+ (is_call ? (is_bare ? kBareCall : kCall) : (is_bare ? kBareCondBranch : kCondBranch)),
+ /* is_r6 */ true);
}
-Mips64Assembler::Branch::Branch(uint32_t location,
+Mips64Assembler::Branch::Branch(bool is_r6,
+ uint32_t location,
uint32_t target,
Mips64Assembler::BranchCondition condition,
GpuRegister lhs_reg,
- GpuRegister rhs_reg)
+ GpuRegister rhs_reg,
+ bool is_bare)
: old_location_(location),
location_(location),
target_(target),
@@ -2131,7 +2242,7 @@ Mips64Assembler::Branch::Branch(uint32_t location,
// Branch condition is always true, make the branch unconditional.
condition_ = kUncond;
}
- InitializeType(kCondBranch);
+ InitializeType((is_bare ? kBareCondBranch : kCondBranch), is_r6);
}
Mips64Assembler::Branch::Branch(uint32_t location, GpuRegister dest_reg, Type label_or_literal_type)
@@ -2142,7 +2253,7 @@ Mips64Assembler::Branch::Branch(uint32_t location, GpuRegister dest_reg, Type la
rhs_reg_(ZERO),
condition_(kUncond) {
CHECK_NE(dest_reg, ZERO);
- InitializeType(label_or_literal_type);
+ InitializeType(label_or_literal_type, /* is_r6 */ true);
}
Mips64Assembler::BranchCondition Mips64Assembler::Branch::OppositeCondition(
@@ -2238,12 +2349,32 @@ uint32_t Mips64Assembler::Branch::GetOldEndLocation() const {
return GetOldLocation() + GetOldSize();
}
+bool Mips64Assembler::Branch::IsBare() const {
+ switch (type_) {
+ // R6 short branches (can't be promoted to long), forbidden/delay slots filled manually.
+ case kBareUncondBranch:
+ case kBareCondBranch:
+ case kBareCall:
+ // R2 short branches (can't be promoted to long), delay slots filled manually.
+ case kR2BareCondBranch:
+ return true;
+ default:
+ return false;
+ }
+}
+
bool Mips64Assembler::Branch::IsLong() const {
switch (type_) {
- // Short branches.
+ // R6 short branches (can be promoted to long).
case kUncondBranch:
case kCondBranch:
case kCall:
+ // R6 short branches (can't be promoted to long), forbidden/delay slots filled manually.
+ case kBareUncondBranch:
+ case kBareCondBranch:
+ case kBareCall:
+ // R2 short branches (can't be promoted to long), delay slots filled manually.
+ case kR2BareCondBranch:
// Near label.
case kLabel:
// Near literals.
@@ -2271,8 +2402,9 @@ bool Mips64Assembler::Branch::IsResolved() const {
}
Mips64Assembler::Branch::OffsetBits Mips64Assembler::Branch::GetOffsetSize() const {
+ bool r6_cond_branch = (type_ == kCondBranch || type_ == kBareCondBranch);
OffsetBits offset_size =
- (type_ == kCondBranch && (condition_ == kCondEQZ || condition_ == kCondNEZ))
+ (r6_cond_branch && (condition_ == kCondEQZ || condition_ == kCondNEZ))
? kOffset23
: branch_info_[type_].offset_size;
return offset_size;
@@ -2318,8 +2450,9 @@ void Mips64Assembler::Branch::Relocate(uint32_t expand_location, uint32_t delta)
}
void Mips64Assembler::Branch::PromoteToLong() {
+ CHECK(!IsBare()); // Bare branches do not promote.
switch (type_) {
- // Short branches.
+ // R6 short branches (can be promoted to long).
case kUncondBranch:
type_ = kLongUncondBranch;
break;
@@ -2366,7 +2499,7 @@ uint32_t Mips64Assembler::Branch::PromoteIfNeeded(uint32_t max_short_distance) {
}
// The following logic is for debugging/testing purposes.
// Promote some short branches to long when it's not really required.
- if (UNLIKELY(max_short_distance != std::numeric_limits<uint32_t>::max())) {
+ if (UNLIKELY(max_short_distance != std::numeric_limits<uint32_t>::max() && !IsBare())) {
int64_t distance = static_cast<int64_t>(target_) - location_;
distance = (distance >= 0) ? distance : -distance;
if (distance >= max_short_distance) {
@@ -2498,13 +2631,15 @@ void Mips64Assembler::FinalizeLabeledBranch(Mips64Label* label) {
}
}
-void Mips64Assembler::Buncond(Mips64Label* label) {
+void Mips64Assembler::Buncond(Mips64Label* label, bool is_bare) {
uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved;
- branches_.emplace_back(buffer_.Size(), target, /* is_call */ false);
+ branches_.emplace_back(buffer_.Size(), target, /* is_call */ false, is_bare);
FinalizeLabeledBranch(label);
}
void Mips64Assembler::Bcond(Mips64Label* label,
+ bool is_r6,
+ bool is_bare,
BranchCondition condition,
GpuRegister lhs,
GpuRegister rhs) {
@@ -2513,13 +2648,13 @@ void Mips64Assembler::Bcond(Mips64Label* label,
return;
}
uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved;
- branches_.emplace_back(buffer_.Size(), target, condition, lhs, rhs);
+ branches_.emplace_back(is_r6, buffer_.Size(), target, condition, lhs, rhs, is_bare);
FinalizeLabeledBranch(label);
}
-void Mips64Assembler::Call(Mips64Label* label) {
+void Mips64Assembler::Call(Mips64Label* label, bool is_bare) {
uint32_t target = label->IsBound() ? GetLabelLocation(label) : Branch::kUnresolved;
- branches_.emplace_back(buffer_.Size(), target, /* is_call */ true);
+ branches_.emplace_back(buffer_.Size(), target, /* is_call */ true, is_bare);
FinalizeLabeledBranch(label);
}
@@ -2730,11 +2865,18 @@ void Mips64Assembler::PromoteBranches() {
// Note: make sure branch_info_[] and EmitBranch() are kept synchronized.
const Mips64Assembler::Branch::BranchInfo Mips64Assembler::Branch::branch_info_[] = {
- // Short branches.
+ // R6 short branches (can be promoted to long).
{ 1, 0, 1, Mips64Assembler::Branch::kOffset28, 2 }, // kUncondBranch
{ 2, 0, 1, Mips64Assembler::Branch::kOffset18, 2 }, // kCondBranch
// Exception: kOffset23 for beqzc/bnezc
{ 1, 0, 1, Mips64Assembler::Branch::kOffset28, 2 }, // kCall
+ // R6 short branches (can't be promoted to long), forbidden/delay slots filled manually.
+ { 1, 0, 1, Mips64Assembler::Branch::kOffset28, 2 }, // kBareUncondBranch
+ { 1, 0, 1, Mips64Assembler::Branch::kOffset18, 2 }, // kBareCondBranch
+ // Exception: kOffset23 for beqzc/bnezc
+ { 1, 0, 1, Mips64Assembler::Branch::kOffset28, 2 }, // kBareCall
+ // R2 short branches (can't be promoted to long), delay slots filled manually.
+ { 1, 0, 1, Mips64Assembler::Branch::kOffset18, 2 }, // kR2BareCondBranch
// Near label.
{ 1, 0, 0, Mips64Assembler::Branch::kOffset21, 2 }, // kLabel
// Near literals.
@@ -2769,13 +2911,29 @@ void Mips64Assembler::EmitBranch(Mips64Assembler::Branch* branch) {
break;
case Branch::kCondBranch:
CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
- EmitBcondc(condition, lhs, rhs, offset);
+ EmitBcondR6(condition, lhs, rhs, offset);
Nop(); // TODO: improve by filling the forbidden/delay slot.
break;
case Branch::kCall:
CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
Balc(offset);
break;
+ case Branch::kBareUncondBranch:
+ CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
+ Bc(offset);
+ break;
+ case Branch::kBareCondBranch:
+ CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
+ EmitBcondR6(condition, lhs, rhs, offset);
+ break;
+ case Branch::kBareCall:
+ CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
+ Balc(offset);
+ break;
+ case Branch::kR2BareCondBranch:
+ CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
+ EmitBcondR2(condition, lhs, rhs, offset);
+ break;
// Near label.
case Branch::kLabel:
@@ -2804,7 +2962,7 @@ void Mips64Assembler::EmitBranch(Mips64Assembler::Branch* branch) {
Jic(AT, Low16Bits(offset));
break;
case Branch::kLongCondBranch:
- EmitBcondc(Branch::OppositeCondition(condition), lhs, rhs, 2);
+ EmitBcondR6(Branch::OppositeCondition(condition), lhs, rhs, 2);
offset += (offset & 0x8000) << 1; // Account for sign extension in jic.
CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
Auipc(AT, High16Bits(offset));
@@ -2848,68 +3006,108 @@ void Mips64Assembler::EmitBranch(Mips64Assembler::Branch* branch) {
CHECK_LT(branch->GetSize(), static_cast<uint32_t>(Branch::kMaxBranchSize));
}
-void Mips64Assembler::Bc(Mips64Label* label) {
- Buncond(label);
+void Mips64Assembler::Bc(Mips64Label* label, bool is_bare) {
+ Buncond(label, is_bare);
+}
+
+void Mips64Assembler::Balc(Mips64Label* label, bool is_bare) {
+ Call(label, is_bare);
+}
+
+void Mips64Assembler::Bltc(GpuRegister rs, GpuRegister rt, Mips64Label* label, bool is_bare) {
+ Bcond(label, /* is_r6 */ true, is_bare, kCondLT, rs, rt);
+}
+
+void Mips64Assembler::Bltzc(GpuRegister rt, Mips64Label* label, bool is_bare) {
+ Bcond(label, /* is_r6 */ true, is_bare, kCondLTZ, rt);
+}
+
+void Mips64Assembler::Bgtzc(GpuRegister rt, Mips64Label* label, bool is_bare) {
+ Bcond(label, /* is_r6 */ true, is_bare, kCondGTZ, rt);
+}
+
+void Mips64Assembler::Bgec(GpuRegister rs, GpuRegister rt, Mips64Label* label, bool is_bare) {
+ Bcond(label, /* is_r6 */ true, is_bare, kCondGE, rs, rt);
+}
+
+void Mips64Assembler::Bgezc(GpuRegister rt, Mips64Label* label, bool is_bare) {
+ Bcond(label, /* is_r6 */ true, is_bare, kCondGEZ, rt);
+}
+
+void Mips64Assembler::Blezc(GpuRegister rt, Mips64Label* label, bool is_bare) {
+ Bcond(label, /* is_r6 */ true, is_bare, kCondLEZ, rt);
+}
+
+void Mips64Assembler::Bltuc(GpuRegister rs, GpuRegister rt, Mips64Label* label, bool is_bare) {
+ Bcond(label, /* is_r6 */ true, is_bare, kCondLTU, rs, rt);
}
-void Mips64Assembler::Balc(Mips64Label* label) {
- Call(label);
+void Mips64Assembler::Bgeuc(GpuRegister rs, GpuRegister rt, Mips64Label* label, bool is_bare) {
+ Bcond(label, /* is_r6 */ true, is_bare, kCondGEU, rs, rt);
}
-void Mips64Assembler::Bltc(GpuRegister rs, GpuRegister rt, Mips64Label* label) {
- Bcond(label, kCondLT, rs, rt);
+void Mips64Assembler::Beqc(GpuRegister rs, GpuRegister rt, Mips64Label* label, bool is_bare) {
+ Bcond(label, /* is_r6 */ true, is_bare, kCondEQ, rs, rt);
}
-void Mips64Assembler::Bltzc(GpuRegister rt, Mips64Label* label) {
- Bcond(label, kCondLTZ, rt);
+void Mips64Assembler::Bnec(GpuRegister rs, GpuRegister rt, Mips64Label* label, bool is_bare) {
+ Bcond(label, /* is_r6 */ true, is_bare, kCondNE, rs, rt);
}
-void Mips64Assembler::Bgtzc(GpuRegister rt, Mips64Label* label) {
- Bcond(label, kCondGTZ, rt);
+void Mips64Assembler::Beqzc(GpuRegister rs, Mips64Label* label, bool is_bare) {
+ Bcond(label, /* is_r6 */ true, is_bare, kCondEQZ, rs);
}
-void Mips64Assembler::Bgec(GpuRegister rs, GpuRegister rt, Mips64Label* label) {
- Bcond(label, kCondGE, rs, rt);
+void Mips64Assembler::Bnezc(GpuRegister rs, Mips64Label* label, bool is_bare) {
+ Bcond(label, /* is_r6 */ true, is_bare, kCondNEZ, rs);
}
-void Mips64Assembler::Bgezc(GpuRegister rt, Mips64Label* label) {
- Bcond(label, kCondGEZ, rt);
+void Mips64Assembler::Bc1eqz(FpuRegister ft, Mips64Label* label, bool is_bare) {
+ Bcond(label, /* is_r6 */ true, is_bare, kCondF, static_cast<GpuRegister>(ft), ZERO);
}
-void Mips64Assembler::Blezc(GpuRegister rt, Mips64Label* label) {
- Bcond(label, kCondLEZ, rt);
+void Mips64Assembler::Bc1nez(FpuRegister ft, Mips64Label* label, bool is_bare) {
+ Bcond(label, /* is_r6 */ true, is_bare, kCondT, static_cast<GpuRegister>(ft), ZERO);
}
-void Mips64Assembler::Bltuc(GpuRegister rs, GpuRegister rt, Mips64Label* label) {
- Bcond(label, kCondLTU, rs, rt);
+void Mips64Assembler::Bltz(GpuRegister rt, Mips64Label* label, bool is_bare) {
+ CHECK(is_bare);
+ Bcond(label, /* is_r6 */ false, is_bare, kCondLTZ, rt);
}
-void Mips64Assembler::Bgeuc(GpuRegister rs, GpuRegister rt, Mips64Label* label) {
- Bcond(label, kCondGEU, rs, rt);
+void Mips64Assembler::Bgtz(GpuRegister rt, Mips64Label* label, bool is_bare) {
+ CHECK(is_bare);
+ Bcond(label, /* is_r6 */ false, is_bare, kCondGTZ, rt);
}
-void Mips64Assembler::Beqc(GpuRegister rs, GpuRegister rt, Mips64Label* label) {
- Bcond(label, kCondEQ, rs, rt);
+void Mips64Assembler::Bgez(GpuRegister rt, Mips64Label* label, bool is_bare) {
+ CHECK(is_bare);
+ Bcond(label, /* is_r6 */ false, is_bare, kCondGEZ, rt);
}
-void Mips64Assembler::Bnec(GpuRegister rs, GpuRegister rt, Mips64Label* label) {
- Bcond(label, kCondNE, rs, rt);
+void Mips64Assembler::Blez(GpuRegister rt, Mips64Label* label, bool is_bare) {
+ CHECK(is_bare);
+ Bcond(label, /* is_r6 */ false, is_bare, kCondLEZ, rt);
}
-void Mips64Assembler::Beqzc(GpuRegister rs, Mips64Label* label) {
- Bcond(label, kCondEQZ, rs);
+void Mips64Assembler::Beq(GpuRegister rs, GpuRegister rt, Mips64Label* label, bool is_bare) {
+ CHECK(is_bare);
+ Bcond(label, /* is_r6 */ false, is_bare, kCondEQ, rs, rt);
}
-void Mips64Assembler::Bnezc(GpuRegister rs, Mips64Label* label) {
- Bcond(label, kCondNEZ, rs);
+void Mips64Assembler::Bne(GpuRegister rs, GpuRegister rt, Mips64Label* label, bool is_bare) {
+ CHECK(is_bare);
+ Bcond(label, /* is_r6 */ false, is_bare, kCondNE, rs, rt);
}
-void Mips64Assembler::Bc1eqz(FpuRegister ft, Mips64Label* label) {
- Bcond(label, kCondF, static_cast<GpuRegister>(ft), ZERO);
+void Mips64Assembler::Beqz(GpuRegister rs, Mips64Label* label, bool is_bare) {
+ CHECK(is_bare);
+ Bcond(label, /* is_r6 */ false, is_bare, kCondEQZ, rs);
}
-void Mips64Assembler::Bc1nez(FpuRegister ft, Mips64Label* label) {
- Bcond(label, kCondT, static_cast<GpuRegister>(ft), ZERO);
+void Mips64Assembler::Bnez(GpuRegister rs, Mips64Label* label, bool is_bare) {
+ CHECK(is_bare);
+ Bcond(label, /* is_r6 */ false, is_bare, kCondNEZ, rs);
}
void Mips64Assembler::AdjustBaseAndOffset(GpuRegister& base,
diff --git a/compiler/utils/mips64/assembler_mips64.h b/compiler/utils/mips64/assembler_mips64.h
index c39d120bce..023bcd681d 100644
--- a/compiler/utils/mips64/assembler_mips64.h
+++ b/compiler/utils/mips64/assembler_mips64.h
@@ -563,7 +563,14 @@ class Mips64Assembler FINAL : public Assembler, public JNIMacroAssembler<Pointer
void Bnezc(GpuRegister rs, uint32_t imm21);
void Bc1eqz(FpuRegister ft, uint16_t imm16);
void Bc1nez(FpuRegister ft, uint16_t imm16);
- void Beqz(GpuRegister rt, uint16_t imm16);
+ void Beq(GpuRegister rs, GpuRegister rt, uint16_t imm16); // R2
+ void Bne(GpuRegister rs, GpuRegister rt, uint16_t imm16); // R2
+ void Beqz(GpuRegister rt, uint16_t imm16); // R2
+ void Bnez(GpuRegister rt, uint16_t imm16); // R2
+ void Bltz(GpuRegister rt, uint16_t imm16); // R2
+ void Bgez(GpuRegister rt, uint16_t imm16); // R2
+ void Blez(GpuRegister rt, uint16_t imm16); // R2
+ void Bgtz(GpuRegister rt, uint16_t imm16); // R2
void AddS(FpuRegister fd, FpuRegister fs, FpuRegister ft);
void SubS(FpuRegister fd, FpuRegister fs, FpuRegister ft);
@@ -922,22 +929,57 @@ class Mips64Assembler FINAL : public Assembler, public JNIMacroAssembler<Pointer
// the table data) and should be loaded using LoadLabelAddress().
JumpTable* CreateJumpTable(std::vector<Mips64Label*>&& labels);
- void Bc(Mips64Label* label);
- void Balc(Mips64Label* label);
- void Bltc(GpuRegister rs, GpuRegister rt, Mips64Label* label);
- void Bltzc(GpuRegister rt, Mips64Label* label);
- void Bgtzc(GpuRegister rt, Mips64Label* label);
- void Bgec(GpuRegister rs, GpuRegister rt, Mips64Label* label);
- void Bgezc(GpuRegister rt, Mips64Label* label);
- void Blezc(GpuRegister rt, Mips64Label* label);
- void Bltuc(GpuRegister rs, GpuRegister rt, Mips64Label* label);
- void Bgeuc(GpuRegister rs, GpuRegister rt, Mips64Label* label);
- void Beqc(GpuRegister rs, GpuRegister rt, Mips64Label* label);
- void Bnec(GpuRegister rs, GpuRegister rt, Mips64Label* label);
- void Beqzc(GpuRegister rs, Mips64Label* label);
- void Bnezc(GpuRegister rs, Mips64Label* label);
- void Bc1eqz(FpuRegister ft, Mips64Label* label);
- void Bc1nez(FpuRegister ft, Mips64Label* label);
+ // When `is_bare` is false, the branches will promote to long (if the range
+ // of the individual branch instruction is insufficient) and the delay/
+ // forbidden slots will be taken care of.
+ // Use `is_bare = false` when the branch target may be out of reach of the
+ // individual branch instruction. IOW, this is for general purpose use.
+ //
+ // When `is_bare` is true, just the branch instructions will be generated
+ // leaving delay/forbidden slot filling up to the caller and the branches
+ // won't promote to long if the range is insufficient (you'll get a
+ // compilation error when the range is exceeded).
+ // Use `is_bare = true` when the branch target is known to be within reach
+ // of the individual branch instruction. This is intended for small local
+ // optimizations around delay/forbidden slots.
+ // Also prefer using `is_bare = true` if the code near the branch is to be
+ // patched or analyzed at run time (e.g. introspection) to
+ // - show the intent and
+ // - fail during compilation rather than during patching/execution if the
+ // bare branch range is insufficent but the code size and layout are
+ // expected to remain unchanged
+ //
+ // R6 compact branches without delay/forbidden slots.
+ void Bc(Mips64Label* label, bool is_bare = false);
+ void Balc(Mips64Label* label, bool is_bare = false);
+ // R6 compact branches with forbidden slots.
+ void Bltc(GpuRegister rs, GpuRegister rt, Mips64Label* label, bool is_bare = false);
+ void Bltzc(GpuRegister rt, Mips64Label* label, bool is_bare = false);
+ void Bgtzc(GpuRegister rt, Mips64Label* label, bool is_bare = false);
+ void Bgec(GpuRegister rs, GpuRegister rt, Mips64Label* label, bool is_bare = false);
+ void Bgezc(GpuRegister rt, Mips64Label* label, bool is_bare = false);
+ void Blezc(GpuRegister rt, Mips64Label* label, bool is_bare = false);
+ void Bltuc(GpuRegister rs, GpuRegister rt, Mips64Label* label, bool is_bare = false);
+ void Bgeuc(GpuRegister rs, GpuRegister rt, Mips64Label* label, bool is_bare = false);
+ void Beqc(GpuRegister rs, GpuRegister rt, Mips64Label* label, bool is_bare = false);
+ void Bnec(GpuRegister rs, GpuRegister rt, Mips64Label* label, bool is_bare = false);
+ void Beqzc(GpuRegister rs, Mips64Label* label, bool is_bare = false);
+ void Bnezc(GpuRegister rs, Mips64Label* label, bool is_bare = false);
+ // R6 branches with delay slots.
+ void Bc1eqz(FpuRegister ft, Mips64Label* label, bool is_bare = false);
+ void Bc1nez(FpuRegister ft, Mips64Label* label, bool is_bare = false);
+ // R2 branches with delay slots that are also available on R6.
+ // The `is_bare` parameter exists and is checked in these branches only to
+ // prevent programming mistakes. These branches never promote to long, not
+ // even if `is_bare` is false.
+ void Bltz(GpuRegister rt, Mips64Label* label, bool is_bare = false); // R2
+ void Bgtz(GpuRegister rt, Mips64Label* label, bool is_bare = false); // R2
+ void Bgez(GpuRegister rt, Mips64Label* label, bool is_bare = false); // R2
+ void Blez(GpuRegister rt, Mips64Label* label, bool is_bare = false); // R2
+ void Beq(GpuRegister rs, GpuRegister rt, Mips64Label* label, bool is_bare = false); // R2
+ void Bne(GpuRegister rs, GpuRegister rt, Mips64Label* label, bool is_bare = false); // R2
+ void Beqz(GpuRegister rs, Mips64Label* label, bool is_bare = false); // R2
+ void Bnez(GpuRegister rs, Mips64Label* label, bool is_bare = false); // R2
void EmitLoad(ManagedRegister m_dst, GpuRegister src_register, int32_t src_offset, size_t size);
void AdjustBaseAndOffset(GpuRegister& base, int32_t& offset, bool is_doubleword);
@@ -1379,10 +1421,16 @@ class Mips64Assembler FINAL : public Assembler, public JNIMacroAssembler<Pointer
class Branch {
public:
enum Type {
- // Short branches.
+ // R6 short branches (can be promoted to long).
kUncondBranch,
kCondBranch,
kCall,
+ // R6 short branches (can't be promoted to long), forbidden/delay slots filled manually.
+ kBareUncondBranch,
+ kBareCondBranch,
+ kBareCall,
+ // R2 short branches (can't be promoted to long), delay slots filled manually.
+ kR2BareCondBranch,
// Near label.
kLabel,
// Near literals.
@@ -1425,8 +1473,8 @@ class Mips64Assembler FINAL : public Assembler, public JNIMacroAssembler<Pointer
// different origins, e.g. to PC or PC+4. Encode the origin distance (as a number of 4-byte
// instructions) from the instruction containing the offset.
uint32_t pc_org;
- // How large (in bits) a PC-relative offset can be for a given type of branch (kCondBranch is
- // an exception: use kOffset23 for beqzc/bnezc).
+ // How large (in bits) a PC-relative offset can be for a given type of branch (kCondBranch
+ // and kBareCondBranch are an exception: use kOffset23 for beqzc/bnezc).
OffsetBits offset_size;
// Some MIPS instructions with PC-relative offsets shift the offset by 2. Encode the shift
// count.
@@ -1435,13 +1483,15 @@ class Mips64Assembler FINAL : public Assembler, public JNIMacroAssembler<Pointer
static const BranchInfo branch_info_[/* Type */];
// Unconditional branch or call.
- Branch(uint32_t location, uint32_t target, bool is_call);
+ Branch(uint32_t location, uint32_t target, bool is_call, bool is_bare);
// Conditional branch.
- Branch(uint32_t location,
+ Branch(bool is_r6,
+ uint32_t location,
uint32_t target,
BranchCondition condition,
GpuRegister lhs_reg,
- GpuRegister rhs_reg);
+ GpuRegister rhs_reg,
+ bool is_bare);
// Label address (in literal area) or literal.
Branch(uint32_t location, GpuRegister dest_reg, Type label_or_literal_type);
@@ -1467,6 +1517,7 @@ class Mips64Assembler FINAL : public Assembler, public JNIMacroAssembler<Pointer
uint32_t GetOldSize() const;
uint32_t GetEndLocation() const;
uint32_t GetOldEndLocation() const;
+ bool IsBare() const;
bool IsLong() const;
bool IsResolved() const;
@@ -1527,7 +1578,7 @@ class Mips64Assembler FINAL : public Assembler, public JNIMacroAssembler<Pointer
private:
// Completes branch construction by determining and recording its type.
- void InitializeType(Type initial_type);
+ void InitializeType(Type initial_type, bool is_r6);
// Helper for the above.
void InitShortOrLong(OffsetBits ofs_size, Type short_type, Type long_type);
@@ -1554,7 +1605,8 @@ class Mips64Assembler FINAL : public Assembler, public JNIMacroAssembler<Pointer
void EmitI26(int opcode, uint32_t imm26);
void EmitFR(int opcode, int fmt, FpuRegister ft, FpuRegister fs, FpuRegister fd, int funct);
void EmitFI(int opcode, int fmt, FpuRegister rt, uint16_t imm);
- void EmitBcondc(BranchCondition cond, GpuRegister rs, GpuRegister rt, uint32_t imm16_21);
+ void EmitBcondR6(BranchCondition cond, GpuRegister rs, GpuRegister rt, uint32_t imm16_21);
+ void EmitBcondR2(BranchCondition cond, GpuRegister rs, GpuRegister rt, uint16_t imm16);
void EmitMsa3R(int operation,
int df,
VectorRegister wt,
@@ -1568,12 +1620,14 @@ class Mips64Assembler FINAL : public Assembler, public JNIMacroAssembler<Pointer
void EmitMsa2R(int operation, int df, VectorRegister ws, VectorRegister wd, int minor_opcode);
void EmitMsa2RF(int operation, int df, VectorRegister ws, VectorRegister wd, int minor_opcode);
- void Buncond(Mips64Label* label);
+ void Buncond(Mips64Label* label, bool is_bare);
void Bcond(Mips64Label* label,
+ bool is_r6,
+ bool is_bare,
BranchCondition condition,
GpuRegister lhs,
GpuRegister rhs = ZERO);
- void Call(Mips64Label* label);
+ void Call(Mips64Label* label, bool is_bare);
void FinalizeLabeledBranch(Mips64Label* label);
Branch* GetBranch(uint32_t branch_id);
diff --git a/compiler/utils/mips64/assembler_mips64_test.cc b/compiler/utils/mips64/assembler_mips64_test.cc
index 021e335697..1541780e2f 100644
--- a/compiler/utils/mips64/assembler_mips64_test.cc
+++ b/compiler/utils/mips64/assembler_mips64_test.cc
@@ -257,11 +257,46 @@ class AssemblerMIPS64Test : public AssemblerTest<mips64::Mips64Assembler,
return result;
}
+ void BranchHelper(void (mips64::Mips64Assembler::*f)(mips64::Mips64Label*,
+ bool),
+ const std::string& instr_name,
+ bool is_bare = false) {
+ mips64::Mips64Label label1, label2;
+ (Base::GetAssembler()->*f)(&label1, is_bare);
+ constexpr size_t kAdduCount1 = 63;
+ for (size_t i = 0; i != kAdduCount1; ++i) {
+ __ Addu(mips64::ZERO, mips64::ZERO, mips64::ZERO);
+ }
+ __ Bind(&label1);
+ (Base::GetAssembler()->*f)(&label2, is_bare);
+ constexpr size_t kAdduCount2 = 64;
+ for (size_t i = 0; i != kAdduCount2; ++i) {
+ __ Addu(mips64::ZERO, mips64::ZERO, mips64::ZERO);
+ }
+ __ Bind(&label2);
+ (Base::GetAssembler()->*f)(&label1, is_bare);
+ __ Addu(mips64::ZERO, mips64::ZERO, mips64::ZERO);
+
+ std::string expected =
+ ".set noreorder\n" +
+ instr_name + " 1f\n" +
+ RepeatInsn(kAdduCount1, "addu $zero, $zero, $zero\n") +
+ "1:\n" +
+ instr_name + " 2f\n" +
+ RepeatInsn(kAdduCount2, "addu $zero, $zero, $zero\n") +
+ "2:\n" +
+ instr_name + " 1b\n" +
+ "addu $zero, $zero, $zero\n";
+ DriverStr(expected, instr_name);
+ }
+
void BranchCondOneRegHelper(void (mips64::Mips64Assembler::*f)(mips64::GpuRegister,
- mips64::Mips64Label*),
- const std::string& instr_name) {
+ mips64::Mips64Label*,
+ bool),
+ const std::string& instr_name,
+ bool is_bare = false) {
mips64::Mips64Label label;
- (Base::GetAssembler()->*f)(mips64::A0, &label);
+ (Base::GetAssembler()->*f)(mips64::A0, &label, is_bare);
constexpr size_t kAdduCount1 = 63;
for (size_t i = 0; i != kAdduCount1; ++i) {
__ Addu(mips64::ZERO, mips64::ZERO, mips64::ZERO);
@@ -271,26 +306,30 @@ class AssemblerMIPS64Test : public AssemblerTest<mips64::Mips64Assembler,
for (size_t i = 0; i != kAdduCount2; ++i) {
__ Addu(mips64::ZERO, mips64::ZERO, mips64::ZERO);
}
- (Base::GetAssembler()->*f)(mips64::A1, &label);
+ (Base::GetAssembler()->*f)(mips64::A1, &label, is_bare);
+ __ Addu(mips64::ZERO, mips64::ZERO, mips64::ZERO);
std::string expected =
".set noreorder\n" +
- instr_name + " $a0, 1f\n"
- "nop\n" +
+ instr_name + " $a0, 1f\n" +
+ (is_bare ? "" : "nop\n") +
RepeatInsn(kAdduCount1, "addu $zero, $zero, $zero\n") +
"1:\n" +
RepeatInsn(kAdduCount2, "addu $zero, $zero, $zero\n") +
- instr_name + " $a1, 1b\n"
- "nop\n";
+ instr_name + " $a1, 1b\n" +
+ (is_bare ? "" : "nop\n") +
+ "addu $zero, $zero, $zero\n";
DriverStr(expected, instr_name);
}
void BranchCondTwoRegsHelper(void (mips64::Mips64Assembler::*f)(mips64::GpuRegister,
mips64::GpuRegister,
- mips64::Mips64Label*),
- const std::string& instr_name) {
+ mips64::Mips64Label*,
+ bool),
+ const std::string& instr_name,
+ bool is_bare = false) {
mips64::Mips64Label label;
- (Base::GetAssembler()->*f)(mips64::A0, mips64::A1, &label);
+ (Base::GetAssembler()->*f)(mips64::A0, mips64::A1, &label, is_bare);
constexpr size_t kAdduCount1 = 63;
for (size_t i = 0; i != kAdduCount1; ++i) {
__ Addu(mips64::ZERO, mips64::ZERO, mips64::ZERO);
@@ -300,17 +339,51 @@ class AssemblerMIPS64Test : public AssemblerTest<mips64::Mips64Assembler,
for (size_t i = 0; i != kAdduCount2; ++i) {
__ Addu(mips64::ZERO, mips64::ZERO, mips64::ZERO);
}
- (Base::GetAssembler()->*f)(mips64::A2, mips64::A3, &label);
+ (Base::GetAssembler()->*f)(mips64::A2, mips64::A3, &label, is_bare);
+ __ Addu(mips64::ZERO, mips64::ZERO, mips64::ZERO);
std::string expected =
".set noreorder\n" +
- instr_name + " $a0, $a1, 1f\n"
- "nop\n" +
+ instr_name + " $a0, $a1, 1f\n" +
+ (is_bare ? "" : "nop\n") +
RepeatInsn(kAdduCount1, "addu $zero, $zero, $zero\n") +
"1:\n" +
RepeatInsn(kAdduCount2, "addu $zero, $zero, $zero\n") +
- instr_name + " $a2, $a3, 1b\n"
- "nop\n";
+ instr_name + " $a2, $a3, 1b\n" +
+ (is_bare ? "" : "nop\n") +
+ "addu $zero, $zero, $zero\n";
+ DriverStr(expected, instr_name);
+ }
+
+ void BranchFpuCondHelper(void (mips64::Mips64Assembler::*f)(mips64::FpuRegister,
+ mips64::Mips64Label*,
+ bool),
+ const std::string& instr_name,
+ bool is_bare = false) {
+ mips64::Mips64Label label;
+ (Base::GetAssembler()->*f)(mips64::F0, &label, is_bare);
+ constexpr size_t kAdduCount1 = 63;
+ for (size_t i = 0; i != kAdduCount1; ++i) {
+ __ Addu(mips64::ZERO, mips64::ZERO, mips64::ZERO);
+ }
+ __ Bind(&label);
+ constexpr size_t kAdduCount2 = 64;
+ for (size_t i = 0; i != kAdduCount2; ++i) {
+ __ Addu(mips64::ZERO, mips64::ZERO, mips64::ZERO);
+ }
+ (Base::GetAssembler()->*f)(mips64::F31, &label, is_bare);
+ __ Addu(mips64::ZERO, mips64::ZERO, mips64::ZERO);
+
+ std::string expected =
+ ".set noreorder\n" +
+ instr_name + " $f0, 1f\n" +
+ (is_bare ? "" : "nop\n") +
+ RepeatInsn(kAdduCount1, "addu $zero, $zero, $zero\n") +
+ "1:\n" +
+ RepeatInsn(kAdduCount2, "addu $zero, $zero, $zero\n") +
+ instr_name + " $f31, 1b\n" +
+ (is_bare ? "" : "nop\n") +
+ "addu $zero, $zero, $zero\n";
DriverStr(expected, instr_name);
}
@@ -668,120 +741,21 @@ TEST_F(AssemblerMIPS64Test, Sdc1) {
"sdc1");
}
-////////////////
-// CALL / JMP //
-////////////////
+//////////////
+// BRANCHES //
+//////////////
TEST_F(AssemblerMIPS64Test, Jalr) {
DriverStr(".set noreorder\n" +
RepeatRRNoDupes(&mips64::Mips64Assembler::Jalr, "jalr ${reg1}, ${reg2}"), "jalr");
}
-TEST_F(AssemblerMIPS64Test, Balc) {
- mips64::Mips64Label label1, label2;
- __ Balc(&label1);
- constexpr size_t kAdduCount1 = 63;
- for (size_t i = 0; i != kAdduCount1; ++i) {
- __ Addu(mips64::ZERO, mips64::ZERO, mips64::ZERO);
- }
- __ Bind(&label1);
- __ Balc(&label2);
- constexpr size_t kAdduCount2 = 64;
- for (size_t i = 0; i != kAdduCount2; ++i) {
- __ Addu(mips64::ZERO, mips64::ZERO, mips64::ZERO);
- }
- __ Bind(&label2);
- __ Balc(&label1);
-
- std::string expected =
- ".set noreorder\n"
- "balc 1f\n" +
- RepeatInsn(kAdduCount1, "addu $zero, $zero, $zero\n") +
- "1:\n"
- "balc 2f\n" +
- RepeatInsn(kAdduCount2, "addu $zero, $zero, $zero\n") +
- "2:\n"
- "balc 1b\n";
- DriverStr(expected, "Balc");
-}
-
-TEST_F(AssemblerMIPS64Test, LongBalc) {
- constexpr uint32_t kNopCount1 = (1u << 25) + 1;
- constexpr uint32_t kNopCount2 = (1u << 25) + 1;
- constexpr uint32_t kRequiredCapacity = (kNopCount1 + kNopCount2 + 6u) * 4u;
- ASSERT_LT(__ GetBuffer()->Capacity(), kRequiredCapacity);
- __ GetBuffer()->ExtendCapacity(kRequiredCapacity);
- mips64::Mips64Label label1, label2;
- __ Balc(&label1);
- for (uint32_t i = 0; i != kNopCount1; ++i) {
- __ Nop();
- }
- __ Bind(&label1);
- __ Balc(&label2);
- for (uint32_t i = 0; i != kNopCount2; ++i) {
- __ Nop();
- }
- __ Bind(&label2);
- __ Balc(&label1);
-
- uint32_t offset_forward1 = 2 + kNopCount1; // 2: account for auipc and jialc.
- offset_forward1 <<= 2;
- offset_forward1 += (offset_forward1 & 0x8000) << 1; // Account for sign extension in jialc.
-
- uint32_t offset_forward2 = 2 + kNopCount2; // 2: account for auipc and jialc.
- offset_forward2 <<= 2;
- offset_forward2 += (offset_forward2 & 0x8000) << 1; // Account for sign extension in jialc.
-
- uint32_t offset_back = -(2 + kNopCount2); // 2: account for auipc and jialc.
- offset_back <<= 2;
- offset_back += (offset_back & 0x8000) << 1; // Account for sign extension in jialc.
-
- // Note, we're using the ".fill" directive to tell the assembler to generate many NOPs
- // instead of generating them ourselves in the source code. This saves a few minutes
- // of test time.
- std::ostringstream oss;
- oss <<
- ".set noreorder\n"
- "auipc $at, 0x" << std::hex << High16Bits(offset_forward1) << "\n"
- "jialc $at, 0x" << std::hex << Low16Bits(offset_forward1) << "\n"
- ".fill 0x" << std::hex << kNopCount1 << " , 4, 0\n"
- "1:\n"
- "auipc $at, 0x" << std::hex << High16Bits(offset_forward2) << "\n"
- "jialc $at, 0x" << std::hex << Low16Bits(offset_forward2) << "\n"
- ".fill 0x" << std::hex << kNopCount2 << " , 4, 0\n"
- "2:\n"
- "auipc $at, 0x" << std::hex << High16Bits(offset_back) << "\n"
- "jialc $at, 0x" << std::hex << Low16Bits(offset_back) << "\n";
- std::string expected = oss.str();
- DriverStr(expected, "LongBalc");
-}
-
TEST_F(AssemblerMIPS64Test, Bc) {
- mips64::Mips64Label label1, label2;
- __ Bc(&label1);
- constexpr size_t kAdduCount1 = 63;
- for (size_t i = 0; i != kAdduCount1; ++i) {
- __ Addu(mips64::ZERO, mips64::ZERO, mips64::ZERO);
- }
- __ Bind(&label1);
- __ Bc(&label2);
- constexpr size_t kAdduCount2 = 64;
- for (size_t i = 0; i != kAdduCount2; ++i) {
- __ Addu(mips64::ZERO, mips64::ZERO, mips64::ZERO);
- }
- __ Bind(&label2);
- __ Bc(&label1);
+ BranchHelper(&mips64::Mips64Assembler::Bc, "Bc");
+}
- std::string expected =
- ".set noreorder\n"
- "bc 1f\n" +
- RepeatInsn(kAdduCount1, "addu $zero, $zero, $zero\n") +
- "1:\n"
- "bc 2f\n" +
- RepeatInsn(kAdduCount2, "addu $zero, $zero, $zero\n") +
- "2:\n"
- "bc 1b\n";
- DriverStr(expected, "Bc");
+TEST_F(AssemblerMIPS64Test, Balc) {
+ BranchHelper(&mips64::Mips64Assembler::Balc, "Balc");
}
TEST_F(AssemblerMIPS64Test, Beqzc) {
@@ -833,55 +807,107 @@ TEST_F(AssemblerMIPS64Test, Bgeuc) {
}
TEST_F(AssemblerMIPS64Test, Bc1eqz) {
- mips64::Mips64Label label;
- __ Bc1eqz(mips64::F0, &label);
- constexpr size_t kAdduCount1 = 63;
- for (size_t i = 0; i != kAdduCount1; ++i) {
- __ Addu(mips64::ZERO, mips64::ZERO, mips64::ZERO);
- }
- __ Bind(&label);
- constexpr size_t kAdduCount2 = 64;
- for (size_t i = 0; i != kAdduCount2; ++i) {
- __ Addu(mips64::ZERO, mips64::ZERO, mips64::ZERO);
- }
- __ Bc1eqz(mips64::F31, &label);
-
- std::string expected =
- ".set noreorder\n"
- "bc1eqz $f0, 1f\n"
- "nop\n" +
- RepeatInsn(kAdduCount1, "addu $zero, $zero, $zero\n") +
- "1:\n" +
- RepeatInsn(kAdduCount2, "addu $zero, $zero, $zero\n") +
- "bc1eqz $f31, 1b\n"
- "nop\n";
- DriverStr(expected, "Bc1eqz");
+ BranchFpuCondHelper(&mips64::Mips64Assembler::Bc1eqz, "Bc1eqz");
}
TEST_F(AssemblerMIPS64Test, Bc1nez) {
- mips64::Mips64Label label;
- __ Bc1nez(mips64::F0, &label);
- constexpr size_t kAdduCount1 = 63;
- for (size_t i = 0; i != kAdduCount1; ++i) {
- __ Addu(mips64::ZERO, mips64::ZERO, mips64::ZERO);
- }
- __ Bind(&label);
- constexpr size_t kAdduCount2 = 64;
- for (size_t i = 0; i != kAdduCount2; ++i) {
- __ Addu(mips64::ZERO, mips64::ZERO, mips64::ZERO);
- }
- __ Bc1nez(mips64::F31, &label);
+ BranchFpuCondHelper(&mips64::Mips64Assembler::Bc1nez, "Bc1nez");
+}
- std::string expected =
- ".set noreorder\n"
- "bc1nez $f0, 1f\n"
- "nop\n" +
- RepeatInsn(kAdduCount1, "addu $zero, $zero, $zero\n") +
- "1:\n" +
- RepeatInsn(kAdduCount2, "addu $zero, $zero, $zero\n") +
- "bc1nez $f31, 1b\n"
- "nop\n";
- DriverStr(expected, "Bc1nez");
+TEST_F(AssemblerMIPS64Test, BareBc) {
+ BranchHelper(&mips64::Mips64Assembler::Bc, "Bc", /* is_bare */ true);
+}
+
+TEST_F(AssemblerMIPS64Test, BareBalc) {
+ BranchHelper(&mips64::Mips64Assembler::Balc, "Balc", /* is_bare */ true);
+}
+
+TEST_F(AssemblerMIPS64Test, BareBeqzc) {
+ BranchCondOneRegHelper(&mips64::Mips64Assembler::Beqzc, "Beqzc", /* is_bare */ true);
+}
+
+TEST_F(AssemblerMIPS64Test, BareBnezc) {
+ BranchCondOneRegHelper(&mips64::Mips64Assembler::Bnezc, "Bnezc", /* is_bare */ true);
+}
+
+TEST_F(AssemblerMIPS64Test, BareBltzc) {
+ BranchCondOneRegHelper(&mips64::Mips64Assembler::Bltzc, "Bltzc", /* is_bare */ true);
+}
+
+TEST_F(AssemblerMIPS64Test, BareBgezc) {
+ BranchCondOneRegHelper(&mips64::Mips64Assembler::Bgezc, "Bgezc", /* is_bare */ true);
+}
+
+TEST_F(AssemblerMIPS64Test, BareBlezc) {
+ BranchCondOneRegHelper(&mips64::Mips64Assembler::Blezc, "Blezc", /* is_bare */ true);
+}
+
+TEST_F(AssemblerMIPS64Test, BareBgtzc) {
+ BranchCondOneRegHelper(&mips64::Mips64Assembler::Bgtzc, "Bgtzc", /* is_bare */ true);
+}
+
+TEST_F(AssemblerMIPS64Test, BareBeqc) {
+ BranchCondTwoRegsHelper(&mips64::Mips64Assembler::Beqc, "Beqc", /* is_bare */ true);
+}
+
+TEST_F(AssemblerMIPS64Test, BareBnec) {
+ BranchCondTwoRegsHelper(&mips64::Mips64Assembler::Bnec, "Bnec", /* is_bare */ true);
+}
+
+TEST_F(AssemblerMIPS64Test, BareBltc) {
+ BranchCondTwoRegsHelper(&mips64::Mips64Assembler::Bltc, "Bltc", /* is_bare */ true);
+}
+
+TEST_F(AssemblerMIPS64Test, BareBgec) {
+ BranchCondTwoRegsHelper(&mips64::Mips64Assembler::Bgec, "Bgec", /* is_bare */ true);
+}
+
+TEST_F(AssemblerMIPS64Test, BareBltuc) {
+ BranchCondTwoRegsHelper(&mips64::Mips64Assembler::Bltuc, "Bltuc", /* is_bare */ true);
+}
+
+TEST_F(AssemblerMIPS64Test, BareBgeuc) {
+ BranchCondTwoRegsHelper(&mips64::Mips64Assembler::Bgeuc, "Bgeuc", /* is_bare */ true);
+}
+
+TEST_F(AssemblerMIPS64Test, BareBc1eqz) {
+ BranchFpuCondHelper(&mips64::Mips64Assembler::Bc1eqz, "Bc1eqz", /* is_bare */ true);
+}
+
+TEST_F(AssemblerMIPS64Test, BareBc1nez) {
+ BranchFpuCondHelper(&mips64::Mips64Assembler::Bc1nez, "Bc1nez", /* is_bare */ true);
+}
+
+TEST_F(AssemblerMIPS64Test, BareBeqz) {
+ BranchCondOneRegHelper(&mips64::Mips64Assembler::Beqz, "Beqz", /* is_bare */ true);
+}
+
+TEST_F(AssemblerMIPS64Test, BareBnez) {
+ BranchCondOneRegHelper(&mips64::Mips64Assembler::Bnez, "Bnez", /* is_bare */ true);
+}
+
+TEST_F(AssemblerMIPS64Test, BareBltz) {
+ BranchCondOneRegHelper(&mips64::Mips64Assembler::Bltz, "Bltz", /* is_bare */ true);
+}
+
+TEST_F(AssemblerMIPS64Test, BareBgez) {
+ BranchCondOneRegHelper(&mips64::Mips64Assembler::Bgez, "Bgez", /* is_bare */ true);
+}
+
+TEST_F(AssemblerMIPS64Test, BareBlez) {
+ BranchCondOneRegHelper(&mips64::Mips64Assembler::Blez, "Blez", /* is_bare */ true);
+}
+
+TEST_F(AssemblerMIPS64Test, BareBgtz) {
+ BranchCondOneRegHelper(&mips64::Mips64Assembler::Bgtz, "Bgtz", /* is_bare */ true);
+}
+
+TEST_F(AssemblerMIPS64Test, BareBeq) {
+ BranchCondTwoRegsHelper(&mips64::Mips64Assembler::Beq, "Beq", /* is_bare */ true);
+}
+
+TEST_F(AssemblerMIPS64Test, BareBne) {
+ BranchCondTwoRegsHelper(&mips64::Mips64Assembler::Bne, "Bne", /* is_bare */ true);
}
TEST_F(AssemblerMIPS64Test, LongBeqc) {
@@ -924,6 +950,102 @@ TEST_F(AssemblerMIPS64Test, LongBeqc) {
DriverStr(expected, "LongBeqc");
}
+TEST_F(AssemblerMIPS64Test, LongBeqzc) {
+ constexpr uint32_t kNopCount1 = (1u << 20) + 1;
+ constexpr uint32_t kNopCount2 = (1u << 20) + 1;
+ constexpr uint32_t kRequiredCapacity = (kNopCount1 + kNopCount2 + 6u) * 4u;
+ ASSERT_LT(__ GetBuffer()->Capacity(), kRequiredCapacity);
+ __ GetBuffer()->ExtendCapacity(kRequiredCapacity);
+ mips64::Mips64Label label;
+ __ Beqzc(mips64::A0, &label);
+ for (uint32_t i = 0; i != kNopCount1; ++i) {
+ __ Nop();
+ }
+ __ Bind(&label);
+ for (uint32_t i = 0; i != kNopCount2; ++i) {
+ __ Nop();
+ }
+ __ Beqzc(mips64::A2, &label);
+
+ uint32_t offset_forward = 2 + kNopCount1; // 2: account for auipc and jic.
+ offset_forward <<= 2;
+ offset_forward += (offset_forward & 0x8000) << 1; // Account for sign extension in jic.
+
+ uint32_t offset_back = -(kNopCount2 + 1); // 1: account for bnezc.
+ offset_back <<= 2;
+ offset_back += (offset_back & 0x8000) << 1; // Account for sign extension in jic.
+
+ // Note, we're using the ".fill" directive to tell the assembler to generate many NOPs
+ // instead of generating them ourselves in the source code. This saves test time.
+ std::ostringstream oss;
+ oss <<
+ ".set noreorder\n"
+ "bnezc $a0, 1f\n"
+ "auipc $at, 0x" << std::hex << High16Bits(offset_forward) << "\n"
+ "jic $at, 0x" << std::hex << Low16Bits(offset_forward) << "\n"
+ "1:\n" <<
+ ".fill 0x" << std::hex << kNopCount1 << " , 4, 0\n"
+ "2:\n" <<
+ ".fill 0x" << std::hex << kNopCount2 << " , 4, 0\n"
+ "bnezc $a2, 3f\n"
+ "auipc $at, 0x" << std::hex << High16Bits(offset_back) << "\n"
+ "jic $at, 0x" << std::hex << Low16Bits(offset_back) << "\n"
+ "3:\n";
+ std::string expected = oss.str();
+ DriverStr(expected, "LongBeqzc");
+}
+
+TEST_F(AssemblerMIPS64Test, LongBalc) {
+ constexpr uint32_t kNopCount1 = (1u << 25) + 1;
+ constexpr uint32_t kNopCount2 = (1u << 25) + 1;
+ constexpr uint32_t kRequiredCapacity = (kNopCount1 + kNopCount2 + 6u) * 4u;
+ ASSERT_LT(__ GetBuffer()->Capacity(), kRequiredCapacity);
+ __ GetBuffer()->ExtendCapacity(kRequiredCapacity);
+ mips64::Mips64Label label1, label2;
+ __ Balc(&label1);
+ for (uint32_t i = 0; i != kNopCount1; ++i) {
+ __ Nop();
+ }
+ __ Bind(&label1);
+ __ Balc(&label2);
+ for (uint32_t i = 0; i != kNopCount2; ++i) {
+ __ Nop();
+ }
+ __ Bind(&label2);
+ __ Balc(&label1);
+
+ uint32_t offset_forward1 = 2 + kNopCount1; // 2: account for auipc and jialc.
+ offset_forward1 <<= 2;
+ offset_forward1 += (offset_forward1 & 0x8000) << 1; // Account for sign extension in jialc.
+
+ uint32_t offset_forward2 = 2 + kNopCount2; // 2: account for auipc and jialc.
+ offset_forward2 <<= 2;
+ offset_forward2 += (offset_forward2 & 0x8000) << 1; // Account for sign extension in jialc.
+
+ uint32_t offset_back = -(2 + kNopCount2); // 2: account for auipc and jialc.
+ offset_back <<= 2;
+ offset_back += (offset_back & 0x8000) << 1; // Account for sign extension in jialc.
+
+ // Note, we're using the ".fill" directive to tell the assembler to generate many NOPs
+ // instead of generating them ourselves in the source code. This saves a few minutes
+ // of test time.
+ std::ostringstream oss;
+ oss <<
+ ".set noreorder\n"
+ "auipc $at, 0x" << std::hex << High16Bits(offset_forward1) << "\n"
+ "jialc $at, 0x" << std::hex << Low16Bits(offset_forward1) << "\n"
+ ".fill 0x" << std::hex << kNopCount1 << " , 4, 0\n"
+ "1:\n"
+ "auipc $at, 0x" << std::hex << High16Bits(offset_forward2) << "\n"
+ "jialc $at, 0x" << std::hex << Low16Bits(offset_forward2) << "\n"
+ ".fill 0x" << std::hex << kNopCount2 << " , 4, 0\n"
+ "2:\n"
+ "auipc $at, 0x" << std::hex << High16Bits(offset_back) << "\n"
+ "jialc $at, 0x" << std::hex << Low16Bits(offset_back) << "\n";
+ std::string expected = oss.str();
+ DriverStr(expected, "LongBalc");
+}
+
//////////
// MISC //
//////////
@@ -961,235 +1083,6 @@ TEST_F(AssemblerMIPS64Test, Addiupc) {
DriverStr(RepeatRIb(&mips64::Mips64Assembler::Addiupc, 19, code), "Addiupc");
}
-TEST_F(AssemblerMIPS64Test, LoadFarthestNearLabelAddress) {
- mips64::Mips64Label label;
- __ LoadLabelAddress(mips64::V0, &label);
- constexpr uint32_t kAdduCount = 0x3FFDE;
- for (uint32_t i = 0; i != kAdduCount; ++i) {
- __ Addu(mips64::ZERO, mips64::ZERO, mips64::ZERO);
- }
- __ Bind(&label);
-
- std::string expected =
- "lapc $v0, 1f\n" +
- RepeatInsn(kAdduCount, "addu $zero, $zero, $zero\n") +
- "1:\n";
- DriverStr(expected, "LoadFarthestNearLabelAddress");
- EXPECT_EQ(__ GetLabelLocation(&label), (1 + kAdduCount) * 4);
-}
-
-TEST_F(AssemblerMIPS64Test, LoadNearestFarLabelAddress) {
- mips64::Mips64Label label;
- __ LoadLabelAddress(mips64::V0, &label);
- constexpr uint32_t kAdduCount = 0x3FFDF;
- for (uint32_t i = 0; i != kAdduCount; ++i) {
- __ Addu(mips64::ZERO, mips64::ZERO, mips64::ZERO);
- }
- __ Bind(&label);
-
- std::string expected =
- "1:\n"
- "auipc $at, %hi(2f - 1b)\n"
- "daddiu $v0, $at, %lo(2f - 1b)\n" +
- RepeatInsn(kAdduCount, "addu $zero, $zero, $zero\n") +
- "2:\n";
- DriverStr(expected, "LoadNearestFarLabelAddress");
- EXPECT_EQ(__ GetLabelLocation(&label), (2 + kAdduCount) * 4);
-}
-
-TEST_F(AssemblerMIPS64Test, LoadFarthestNearLiteral) {
- mips64::Literal* literal = __ NewLiteral<uint32_t>(0x12345678);
- __ LoadLiteral(mips64::V0, mips64::kLoadWord, literal);
- constexpr uint32_t kAdduCount = 0x3FFDE;
- for (uint32_t i = 0; i != kAdduCount; ++i) {
- __ Addu(mips64::ZERO, mips64::ZERO, mips64::ZERO);
- }
-
- std::string expected =
- "lwpc $v0, 1f\n" +
- RepeatInsn(kAdduCount, "addu $zero, $zero, $zero\n") +
- "1:\n"
- ".word 0x12345678\n";
- DriverStr(expected, "LoadFarthestNearLiteral");
- EXPECT_EQ(__ GetLabelLocation(literal->GetLabel()), (1 + kAdduCount) * 4);
-}
-
-TEST_F(AssemblerMIPS64Test, LoadNearestFarLiteral) {
- mips64::Literal* literal = __ NewLiteral<uint32_t>(0x12345678);
- __ LoadLiteral(mips64::V0, mips64::kLoadWord, literal);
- constexpr uint32_t kAdduCount = 0x3FFDF;
- for (uint32_t i = 0; i != kAdduCount; ++i) {
- __ Addu(mips64::ZERO, mips64::ZERO, mips64::ZERO);
- }
-
- std::string expected =
- "1:\n"
- "auipc $at, %hi(2f - 1b)\n"
- "lw $v0, %lo(2f - 1b)($at)\n" +
- RepeatInsn(kAdduCount, "addu $zero, $zero, $zero\n") +
- "2:\n"
- ".word 0x12345678\n";
- DriverStr(expected, "LoadNearestFarLiteral");
- EXPECT_EQ(__ GetLabelLocation(literal->GetLabel()), (2 + kAdduCount) * 4);
-}
-
-TEST_F(AssemblerMIPS64Test, LoadFarthestNearLiteralUnsigned) {
- mips64::Literal* literal = __ NewLiteral<uint32_t>(0x12345678);
- __ LoadLiteral(mips64::V0, mips64::kLoadUnsignedWord, literal);
- constexpr uint32_t kAdduCount = 0x3FFDE;
- for (uint32_t i = 0; i != kAdduCount; ++i) {
- __ Addu(mips64::ZERO, mips64::ZERO, mips64::ZERO);
- }
-
- std::string expected =
- "lwupc $v0, 1f\n" +
- RepeatInsn(kAdduCount, "addu $zero, $zero, $zero\n") +
- "1:\n"
- ".word 0x12345678\n";
- DriverStr(expected, "LoadFarthestNearLiteralUnsigned");
- EXPECT_EQ(__ GetLabelLocation(literal->GetLabel()), (1 + kAdduCount) * 4);
-}
-
-TEST_F(AssemblerMIPS64Test, LoadNearestFarLiteralUnsigned) {
- mips64::Literal* literal = __ NewLiteral<uint32_t>(0x12345678);
- __ LoadLiteral(mips64::V0, mips64::kLoadUnsignedWord, literal);
- constexpr uint32_t kAdduCount = 0x3FFDF;
- for (uint32_t i = 0; i != kAdduCount; ++i) {
- __ Addu(mips64::ZERO, mips64::ZERO, mips64::ZERO);
- }
-
- std::string expected =
- "1:\n"
- "auipc $at, %hi(2f - 1b)\n"
- "lwu $v0, %lo(2f - 1b)($at)\n" +
- RepeatInsn(kAdduCount, "addu $zero, $zero, $zero\n") +
- "2:\n"
- ".word 0x12345678\n";
- DriverStr(expected, "LoadNearestFarLiteralUnsigned");
- EXPECT_EQ(__ GetLabelLocation(literal->GetLabel()), (2 + kAdduCount) * 4);
-}
-
-TEST_F(AssemblerMIPS64Test, LoadFarthestNearLiteralLong) {
- mips64::Literal* literal = __ NewLiteral<uint64_t>(UINT64_C(0x0123456789ABCDEF));
- __ LoadLiteral(mips64::V0, mips64::kLoadDoubleword, literal);
- constexpr uint32_t kAdduCount = 0x3FFDD;
- for (uint32_t i = 0; i != kAdduCount; ++i) {
- __ Addu(mips64::ZERO, mips64::ZERO, mips64::ZERO);
- }
-
- std::string expected =
- "ldpc $v0, 1f\n" +
- RepeatInsn(kAdduCount, "addu $zero, $zero, $zero\n") +
- "1:\n"
- ".dword 0x0123456789ABCDEF\n";
- DriverStr(expected, "LoadFarthestNearLiteralLong");
- EXPECT_EQ(__ GetLabelLocation(literal->GetLabel()), (1 + kAdduCount) * 4);
-}
-
-TEST_F(AssemblerMIPS64Test, LoadNearestFarLiteralLong) {
- mips64::Literal* literal = __ NewLiteral<uint64_t>(UINT64_C(0x0123456789ABCDEF));
- __ LoadLiteral(mips64::V0, mips64::kLoadDoubleword, literal);
- constexpr uint32_t kAdduCount = 0x3FFDE;
- for (uint32_t i = 0; i != kAdduCount; ++i) {
- __ Addu(mips64::ZERO, mips64::ZERO, mips64::ZERO);
- }
-
- std::string expected =
- "1:\n"
- "auipc $at, %hi(2f - 1b)\n"
- "ld $v0, %lo(2f - 1b)($at)\n" +
- RepeatInsn(kAdduCount, "addu $zero, $zero, $zero\n") +
- "2:\n"
- ".dword 0x0123456789ABCDEF\n";
- DriverStr(expected, "LoadNearestFarLiteralLong");
- EXPECT_EQ(__ GetLabelLocation(literal->GetLabel()), (2 + kAdduCount) * 4);
-}
-
-TEST_F(AssemblerMIPS64Test, LongLiteralAlignmentNop) {
- mips64::Literal* literal1 = __ NewLiteral<uint64_t>(UINT64_C(0x0123456789ABCDEF));
- mips64::Literal* literal2 = __ NewLiteral<uint64_t>(UINT64_C(0x5555555555555555));
- mips64::Literal* literal3 = __ NewLiteral<uint64_t>(UINT64_C(0xAAAAAAAAAAAAAAAA));
- __ LoadLiteral(mips64::A1, mips64::kLoadDoubleword, literal1);
- __ LoadLiteral(mips64::A2, mips64::kLoadDoubleword, literal2);
- __ LoadLiteral(mips64::A3, mips64::kLoadDoubleword, literal3);
- __ LoadLabelAddress(mips64::V0, literal1->GetLabel());
- __ LoadLabelAddress(mips64::V1, literal2->GetLabel());
- // A nop will be inserted here before the 64-bit literals.
-
- std::string expected =
- "ldpc $a1, 1f\n"
- // The GNU assembler incorrectly requires the ldpc instruction to be located
- // at an address that's a multiple of 8. TODO: Remove this workaround if/when
- // the assembler is fixed.
- // "ldpc $a2, 2f\n"
- ".word 0xECD80004\n"
- "ldpc $a3, 3f\n"
- "lapc $v0, 1f\n"
- "lapc $v1, 2f\n"
- "nop\n"
- "1:\n"
- ".dword 0x0123456789ABCDEF\n"
- "2:\n"
- ".dword 0x5555555555555555\n"
- "3:\n"
- ".dword 0xAAAAAAAAAAAAAAAA\n";
- DriverStr(expected, "LongLiteralAlignmentNop");
- EXPECT_EQ(__ GetLabelLocation(literal1->GetLabel()), 6 * 4u);
- EXPECT_EQ(__ GetLabelLocation(literal2->GetLabel()), 8 * 4u);
- EXPECT_EQ(__ GetLabelLocation(literal3->GetLabel()), 10 * 4u);
-}
-
-TEST_F(AssemblerMIPS64Test, LongLiteralAlignmentNoNop) {
- mips64::Literal* literal1 = __ NewLiteral<uint64_t>(UINT64_C(0x0123456789ABCDEF));
- mips64::Literal* literal2 = __ NewLiteral<uint64_t>(UINT64_C(0x5555555555555555));
- __ LoadLiteral(mips64::A1, mips64::kLoadDoubleword, literal1);
- __ LoadLiteral(mips64::A2, mips64::kLoadDoubleword, literal2);
- __ LoadLabelAddress(mips64::V0, literal1->GetLabel());
- __ LoadLabelAddress(mips64::V1, literal2->GetLabel());
-
- std::string expected =
- "ldpc $a1, 1f\n"
- // The GNU assembler incorrectly requires the ldpc instruction to be located
- // at an address that's a multiple of 8. TODO: Remove this workaround if/when
- // the assembler is fixed.
- // "ldpc $a2, 2f\n"
- ".word 0xECD80003\n"
- "lapc $v0, 1f\n"
- "lapc $v1, 2f\n"
- "1:\n"
- ".dword 0x0123456789ABCDEF\n"
- "2:\n"
- ".dword 0x5555555555555555\n";
- DriverStr(expected, "LongLiteralAlignmentNoNop");
- EXPECT_EQ(__ GetLabelLocation(literal1->GetLabel()), 4 * 4u);
- EXPECT_EQ(__ GetLabelLocation(literal2->GetLabel()), 6 * 4u);
-}
-
-TEST_F(AssemblerMIPS64Test, FarLongLiteralAlignmentNop) {
- mips64::Literal* literal = __ NewLiteral<uint64_t>(UINT64_C(0x0123456789ABCDEF));
- __ LoadLiteral(mips64::V0, mips64::kLoadDoubleword, literal);
- __ LoadLabelAddress(mips64::V1, literal->GetLabel());
- constexpr uint32_t kAdduCount = 0x3FFDF;
- for (uint32_t i = 0; i != kAdduCount; ++i) {
- __ Addu(mips64::ZERO, mips64::ZERO, mips64::ZERO);
- }
- // A nop will be inserted here before the 64-bit literal.
-
- std::string expected =
- "1:\n"
- "auipc $at, %hi(3f - 1b)\n"
- "ld $v0, %lo(3f - 1b)($at)\n"
- "2:\n"
- "auipc $at, %hi(3f - 2b)\n"
- "daddiu $v1, $at, %lo(3f - 2b)\n" +
- RepeatInsn(kAdduCount, "addu $zero, $zero, $zero\n") +
- "nop\n"
- "3:\n"
- ".dword 0x0123456789ABCDEF\n";
- DriverStr(expected, "FarLongLiteralAlignmentNop");
- EXPECT_EQ(__ GetLabelLocation(literal->GetLabel()), (5 + kAdduCount) * 4);
-}
-
TEST_F(AssemblerMIPS64Test, Addu) {
DriverStr(RepeatRRR(&mips64::Mips64Assembler::Addu, "addu ${reg1}, ${reg2}, ${reg3}"), "addu");
}
@@ -2740,6 +2633,235 @@ TEST_F(AssemblerMIPS64Test, LoadConst64) {
EXPECT_EQ(tester.GetPathsCovered(), art::mips64::kLoadConst64PathAllPaths);
}
+TEST_F(AssemblerMIPS64Test, LoadFarthestNearLabelAddress) {
+ mips64::Mips64Label label;
+ __ LoadLabelAddress(mips64::V0, &label);
+ constexpr uint32_t kAdduCount = 0x3FFDE;
+ for (uint32_t i = 0; i != kAdduCount; ++i) {
+ __ Addu(mips64::ZERO, mips64::ZERO, mips64::ZERO);
+ }
+ __ Bind(&label);
+
+ std::string expected =
+ "lapc $v0, 1f\n" +
+ RepeatInsn(kAdduCount, "addu $zero, $zero, $zero\n") +
+ "1:\n";
+ DriverStr(expected, "LoadFarthestNearLabelAddress");
+ EXPECT_EQ(__ GetLabelLocation(&label), (1 + kAdduCount) * 4);
+}
+
+TEST_F(AssemblerMIPS64Test, LoadNearestFarLabelAddress) {
+ mips64::Mips64Label label;
+ __ LoadLabelAddress(mips64::V0, &label);
+ constexpr uint32_t kAdduCount = 0x3FFDF;
+ for (uint32_t i = 0; i != kAdduCount; ++i) {
+ __ Addu(mips64::ZERO, mips64::ZERO, mips64::ZERO);
+ }
+ __ Bind(&label);
+
+ std::string expected =
+ "1:\n"
+ "auipc $at, %hi(2f - 1b)\n"
+ "daddiu $v0, $at, %lo(2f - 1b)\n" +
+ RepeatInsn(kAdduCount, "addu $zero, $zero, $zero\n") +
+ "2:\n";
+ DriverStr(expected, "LoadNearestFarLabelAddress");
+ EXPECT_EQ(__ GetLabelLocation(&label), (2 + kAdduCount) * 4);
+}
+
+TEST_F(AssemblerMIPS64Test, LoadFarthestNearLiteral) {
+ mips64::Literal* literal = __ NewLiteral<uint32_t>(0x12345678);
+ __ LoadLiteral(mips64::V0, mips64::kLoadWord, literal);
+ constexpr uint32_t kAdduCount = 0x3FFDE;
+ for (uint32_t i = 0; i != kAdduCount; ++i) {
+ __ Addu(mips64::ZERO, mips64::ZERO, mips64::ZERO);
+ }
+
+ std::string expected =
+ "lwpc $v0, 1f\n" +
+ RepeatInsn(kAdduCount, "addu $zero, $zero, $zero\n") +
+ "1:\n"
+ ".word 0x12345678\n";
+ DriverStr(expected, "LoadFarthestNearLiteral");
+ EXPECT_EQ(__ GetLabelLocation(literal->GetLabel()), (1 + kAdduCount) * 4);
+}
+
+TEST_F(AssemblerMIPS64Test, LoadNearestFarLiteral) {
+ mips64::Literal* literal = __ NewLiteral<uint32_t>(0x12345678);
+ __ LoadLiteral(mips64::V0, mips64::kLoadWord, literal);
+ constexpr uint32_t kAdduCount = 0x3FFDF;
+ for (uint32_t i = 0; i != kAdduCount; ++i) {
+ __ Addu(mips64::ZERO, mips64::ZERO, mips64::ZERO);
+ }
+
+ std::string expected =
+ "1:\n"
+ "auipc $at, %hi(2f - 1b)\n"
+ "lw $v0, %lo(2f - 1b)($at)\n" +
+ RepeatInsn(kAdduCount, "addu $zero, $zero, $zero\n") +
+ "2:\n"
+ ".word 0x12345678\n";
+ DriverStr(expected, "LoadNearestFarLiteral");
+ EXPECT_EQ(__ GetLabelLocation(literal->GetLabel()), (2 + kAdduCount) * 4);
+}
+
+TEST_F(AssemblerMIPS64Test, LoadFarthestNearLiteralUnsigned) {
+ mips64::Literal* literal = __ NewLiteral<uint32_t>(0x12345678);
+ __ LoadLiteral(mips64::V0, mips64::kLoadUnsignedWord, literal);
+ constexpr uint32_t kAdduCount = 0x3FFDE;
+ for (uint32_t i = 0; i != kAdduCount; ++i) {
+ __ Addu(mips64::ZERO, mips64::ZERO, mips64::ZERO);
+ }
+
+ std::string expected =
+ "lwupc $v0, 1f\n" +
+ RepeatInsn(kAdduCount, "addu $zero, $zero, $zero\n") +
+ "1:\n"
+ ".word 0x12345678\n";
+ DriverStr(expected, "LoadFarthestNearLiteralUnsigned");
+ EXPECT_EQ(__ GetLabelLocation(literal->GetLabel()), (1 + kAdduCount) * 4);
+}
+
+TEST_F(AssemblerMIPS64Test, LoadNearestFarLiteralUnsigned) {
+ mips64::Literal* literal = __ NewLiteral<uint32_t>(0x12345678);
+ __ LoadLiteral(mips64::V0, mips64::kLoadUnsignedWord, literal);
+ constexpr uint32_t kAdduCount = 0x3FFDF;
+ for (uint32_t i = 0; i != kAdduCount; ++i) {
+ __ Addu(mips64::ZERO, mips64::ZERO, mips64::ZERO);
+ }
+
+ std::string expected =
+ "1:\n"
+ "auipc $at, %hi(2f - 1b)\n"
+ "lwu $v0, %lo(2f - 1b)($at)\n" +
+ RepeatInsn(kAdduCount, "addu $zero, $zero, $zero\n") +
+ "2:\n"
+ ".word 0x12345678\n";
+ DriverStr(expected, "LoadNearestFarLiteralUnsigned");
+ EXPECT_EQ(__ GetLabelLocation(literal->GetLabel()), (2 + kAdduCount) * 4);
+}
+
+TEST_F(AssemblerMIPS64Test, LoadFarthestNearLiteralLong) {
+ mips64::Literal* literal = __ NewLiteral<uint64_t>(UINT64_C(0x0123456789ABCDEF));
+ __ LoadLiteral(mips64::V0, mips64::kLoadDoubleword, literal);
+ constexpr uint32_t kAdduCount = 0x3FFDD;
+ for (uint32_t i = 0; i != kAdduCount; ++i) {
+ __ Addu(mips64::ZERO, mips64::ZERO, mips64::ZERO);
+ }
+
+ std::string expected =
+ "ldpc $v0, 1f\n" +
+ RepeatInsn(kAdduCount, "addu $zero, $zero, $zero\n") +
+ "1:\n"
+ ".dword 0x0123456789ABCDEF\n";
+ DriverStr(expected, "LoadFarthestNearLiteralLong");
+ EXPECT_EQ(__ GetLabelLocation(literal->GetLabel()), (1 + kAdduCount) * 4);
+}
+
+TEST_F(AssemblerMIPS64Test, LoadNearestFarLiteralLong) {
+ mips64::Literal* literal = __ NewLiteral<uint64_t>(UINT64_C(0x0123456789ABCDEF));
+ __ LoadLiteral(mips64::V0, mips64::kLoadDoubleword, literal);
+ constexpr uint32_t kAdduCount = 0x3FFDE;
+ for (uint32_t i = 0; i != kAdduCount; ++i) {
+ __ Addu(mips64::ZERO, mips64::ZERO, mips64::ZERO);
+ }
+
+ std::string expected =
+ "1:\n"
+ "auipc $at, %hi(2f - 1b)\n"
+ "ld $v0, %lo(2f - 1b)($at)\n" +
+ RepeatInsn(kAdduCount, "addu $zero, $zero, $zero\n") +
+ "2:\n"
+ ".dword 0x0123456789ABCDEF\n";
+ DriverStr(expected, "LoadNearestFarLiteralLong");
+ EXPECT_EQ(__ GetLabelLocation(literal->GetLabel()), (2 + kAdduCount) * 4);
+}
+
+TEST_F(AssemblerMIPS64Test, LongLiteralAlignmentNop) {
+ mips64::Literal* literal1 = __ NewLiteral<uint64_t>(UINT64_C(0x0123456789ABCDEF));
+ mips64::Literal* literal2 = __ NewLiteral<uint64_t>(UINT64_C(0x5555555555555555));
+ mips64::Literal* literal3 = __ NewLiteral<uint64_t>(UINT64_C(0xAAAAAAAAAAAAAAAA));
+ __ LoadLiteral(mips64::A1, mips64::kLoadDoubleword, literal1);
+ __ LoadLiteral(mips64::A2, mips64::kLoadDoubleword, literal2);
+ __ LoadLiteral(mips64::A3, mips64::kLoadDoubleword, literal3);
+ __ LoadLabelAddress(mips64::V0, literal1->GetLabel());
+ __ LoadLabelAddress(mips64::V1, literal2->GetLabel());
+ // A nop will be inserted here before the 64-bit literals.
+
+ std::string expected =
+ "ldpc $a1, 1f\n"
+ // The GNU assembler incorrectly requires the ldpc instruction to be located
+ // at an address that's a multiple of 8. TODO: Remove this workaround if/when
+ // the assembler is fixed.
+ // "ldpc $a2, 2f\n"
+ ".word 0xECD80004\n"
+ "ldpc $a3, 3f\n"
+ "lapc $v0, 1f\n"
+ "lapc $v1, 2f\n"
+ "nop\n"
+ "1:\n"
+ ".dword 0x0123456789ABCDEF\n"
+ "2:\n"
+ ".dword 0x5555555555555555\n"
+ "3:\n"
+ ".dword 0xAAAAAAAAAAAAAAAA\n";
+ DriverStr(expected, "LongLiteralAlignmentNop");
+ EXPECT_EQ(__ GetLabelLocation(literal1->GetLabel()), 6 * 4u);
+ EXPECT_EQ(__ GetLabelLocation(literal2->GetLabel()), 8 * 4u);
+ EXPECT_EQ(__ GetLabelLocation(literal3->GetLabel()), 10 * 4u);
+}
+
+TEST_F(AssemblerMIPS64Test, LongLiteralAlignmentNoNop) {
+ mips64::Literal* literal1 = __ NewLiteral<uint64_t>(UINT64_C(0x0123456789ABCDEF));
+ mips64::Literal* literal2 = __ NewLiteral<uint64_t>(UINT64_C(0x5555555555555555));
+ __ LoadLiteral(mips64::A1, mips64::kLoadDoubleword, literal1);
+ __ LoadLiteral(mips64::A2, mips64::kLoadDoubleword, literal2);
+ __ LoadLabelAddress(mips64::V0, literal1->GetLabel());
+ __ LoadLabelAddress(mips64::V1, literal2->GetLabel());
+
+ std::string expected =
+ "ldpc $a1, 1f\n"
+ // The GNU assembler incorrectly requires the ldpc instruction to be located
+ // at an address that's a multiple of 8. TODO: Remove this workaround if/when
+ // the assembler is fixed.
+ // "ldpc $a2, 2f\n"
+ ".word 0xECD80003\n"
+ "lapc $v0, 1f\n"
+ "lapc $v1, 2f\n"
+ "1:\n"
+ ".dword 0x0123456789ABCDEF\n"
+ "2:\n"
+ ".dword 0x5555555555555555\n";
+ DriverStr(expected, "LongLiteralAlignmentNoNop");
+ EXPECT_EQ(__ GetLabelLocation(literal1->GetLabel()), 4 * 4u);
+ EXPECT_EQ(__ GetLabelLocation(literal2->GetLabel()), 6 * 4u);
+}
+
+TEST_F(AssemblerMIPS64Test, FarLongLiteralAlignmentNop) {
+ mips64::Literal* literal = __ NewLiteral<uint64_t>(UINT64_C(0x0123456789ABCDEF));
+ __ LoadLiteral(mips64::V0, mips64::kLoadDoubleword, literal);
+ __ LoadLabelAddress(mips64::V1, literal->GetLabel());
+ constexpr uint32_t kAdduCount = 0x3FFDF;
+ for (uint32_t i = 0; i != kAdduCount; ++i) {
+ __ Addu(mips64::ZERO, mips64::ZERO, mips64::ZERO);
+ }
+ // A nop will be inserted here before the 64-bit literal.
+
+ std::string expected =
+ "1:\n"
+ "auipc $at, %hi(3f - 1b)\n"
+ "ld $v0, %lo(3f - 1b)($at)\n"
+ "2:\n"
+ "auipc $at, %hi(3f - 2b)\n"
+ "daddiu $v1, $at, %lo(3f - 2b)\n" +
+ RepeatInsn(kAdduCount, "addu $zero, $zero, $zero\n") +
+ "nop\n"
+ "3:\n"
+ ".dword 0x0123456789ABCDEF\n";
+ DriverStr(expected, "FarLongLiteralAlignmentNop");
+ EXPECT_EQ(__ GetLabelLocation(literal->GetLabel()), (5 + kAdduCount) * 4);
+}
+
// MSA instructions.
TEST_F(AssemblerMIPS64Test, AndV) {