MIPS: Implement Bovc and Bnvc instruction macros.

Implement Bovc and Bnvc instruction macros in macro assembler.

The change 6f920d7d59 revealed an issue with AddBranchOvf for mips R6.
All branching instructions other than BOVC and BNVC are handled by Branch macro, which assures
correct handling of long and short branches. As a consequence, AddBranchOvf for R6 was working correctly
only before trampoline was emitted, but the case of long branch was not handled at all. Implemented
instruction macros enable proper handling of BOVC and BNVC in cases when long branching is needed.

TEST=test/intl/general/case-mapping.js

BUG=

Review-Url: https://codereview.chromium.org/2225323002
Cr-Commit-Position: refs/heads/master@{#38513}
This commit is contained in:
marija.antic 2016-08-09 23:06:38 -07:00 committed by Commit bot
parent 3909250a6c
commit 93809055aa
6 changed files with 200 additions and 5 deletions

View File

@ -1186,6 +1186,27 @@ void MacroAssembler::Lsa(Register rd, Register rt, Register rs, uint8_t sa,
}
}
void MacroAssembler::Bovc(Register rs, Register rt, Label* L) {
if (is_trampoline_emitted()) {
Label skip;
bnvc(rs, rt, &skip);
BranchLong(L, PROTECT);
bind(&skip);
} else {
bovc(rs, rt, L);
}
}
void MacroAssembler::Bnvc(Register rs, Register rt, Label* L) {
if (is_trampoline_emitted()) {
Label skip;
bovc(rs, rt, &skip);
BranchLong(L, PROTECT);
bind(&skip);
} else {
bnvc(rs, rt, L);
}
}
// ------------Pseudo-instructions-------------
@ -3337,7 +3358,6 @@ bool MacroAssembler::BranchShortCheck(int32_t offset, Label* L, Condition cond,
Register rs, const Operand& rt,
BranchDelaySlot bdslot) {
BRANCH_ARGS_CHECK(cond, rs, rt);
if (!L) {
if (IsMipsArchVariant(kMips32r6) && bdslot == PROTECT) {
DCHECK(is_int26(offset));
@ -5394,9 +5414,9 @@ void MacroAssembler::AddBranchOvf(Register dst, Register left, Register right,
Move(left_reg, left);
Move(right_reg, right);
addu(dst, left, right);
bnvc(left_reg, right_reg, no_overflow_label);
Bnvc(left_reg, right_reg, no_overflow_label);
} else {
bovc(left, right, overflow_label);
Bovc(left, right, overflow_label);
addu(dst, left, right);
if (no_overflow_label) bc(no_overflow_label);
}

View File

@ -831,6 +831,10 @@ class MacroAssembler: public Assembler {
void Ins(Register rt, Register rs, uint16_t pos, uint16_t size);
void Ext(Register rt, Register rs, uint16_t pos, uint16_t size);
// MIPS32 R6 instruction macros.
void Bovc(Register rt, Register rs, Label* L);
void Bnvc(Register rt, Register rs, Label* L);
// Int64Lowering instructions
void AddPair(Register dst_low, Register dst_high, Register left_low,
Register left_high, Register right_low, Register right_high);

View File

@ -1332,6 +1332,27 @@ void MacroAssembler::Dlsa(Register rd, Register rt, Register rs, uint8_t sa,
}
}
void MacroAssembler::Bovc(Register rs, Register rt, Label* L) {
if (is_trampoline_emitted()) {
Label skip;
bnvc(rs, rt, &skip);
BranchLong(L, PROTECT);
bind(&skip);
} else {
bovc(rs, rt, L);
}
}
void MacroAssembler::Bnvc(Register rs, Register rt, Label* L) {
if (is_trampoline_emitted()) {
Label skip;
bovc(rs, rt, &skip);
BranchLong(L, PROTECT);
bind(&skip);
} else {
bnvc(rs, rt, L);
}
}
// ------------Pseudo-instructions-------------
@ -5606,9 +5627,9 @@ void MacroAssembler::AddBranchOvf(Register dst, Register left, Register right,
Move(left_reg, left);
Move(right_reg, right);
addu(dst, left, right);
bnvc(left_reg, right_reg, no_overflow_label);
Bnvc(left_reg, right_reg, no_overflow_label);
} else {
bovc(left, right, overflow_label);
Bovc(left, right, overflow_label);
addu(dst, left, right);
if (no_overflow_label) bc(no_overflow_label);
}

View File

@ -881,6 +881,10 @@ class MacroAssembler: public Assembler {
void Dextm(Register rt, Register rs, uint16_t pos, uint16_t size);
void Dextu(Register rt, Register rs, uint16_t pos, uint16_t size);
// MIPS64 R6 instruction macros.
void Bovc(Register rt, Register rs, Label* L);
void Bnvc(Register rt, Register rs, Label* L);
// ---------------------------------------------------------------------------
// FPU macros. These do not handle special cases like NaN or +- inf.

View File

@ -634,6 +634,79 @@ static bool runOverflow(IN_TYPE valLeft, IN_TYPE valRight,
return r;
}
TEST(BranchOverflowInt32BothLabelsTrampoline) {
if (!IsMipsArchVariant(kMips32r6)) return;
static const int kMaxBranchOffset = (1 << (18 - 1)) - 1;
FOR_INT32_INPUTS(i, overflow_int32_test_values) {
FOR_INT32_INPUTS(j, overflow_int32_test_values) {
FOR_ENUM_INPUTS(br, OverflowBranchType, overflow_branch_type) {
FOR_STRUCT_INPUTS(regComb, OverflowRegisterCombination,
overflow_register_combination) {
int32_t ii = *i;
int32_t jj = *j;
enum OverflowBranchType branchType = *br;
struct OverflowRegisterCombination rc = *regComb;
// If left and right register are same then left and right
// test values must also be same, otherwise we skip the test
if (rc.left.code() == rc.right.code()) {
if (ii != jj) {
continue;
}
}
bool res1 = runOverflow<int32_t>(
ii, jj, [branchType, rc](MacroAssembler* masm, int32_t valLeft,
int32_t valRight) {
Label overflow, no_overflow, end;
__ li(rc.left, valLeft);
__ li(rc.right, valRight);
switch (branchType) {
case kAddBranchOverflow:
__ AddBranchOvf(rc.dst, rc.left, rc.right, &overflow,
&no_overflow, rc.scratch);
break;
case kSubBranchOverflow:
__ SubBranchOvf(rc.dst, rc.left, rc.right, &overflow,
&no_overflow, rc.scratch);
break;
}
Label done;
size_t nr_calls =
kMaxBranchOffset / (2 * Instruction::kInstrSize) + 2;
for (size_t i = 0; i < nr_calls; ++i) {
__ BranchShort(&done, eq, a0, Operand(a1));
}
__ bind(&done);
__ li(v0, 2);
__ Branch(&end);
__ bind(&overflow);
__ li(v0, 1);
__ Branch(&end);
__ bind(&no_overflow);
__ li(v0, 0);
__ bind(&end);
});
switch (branchType) {
case kAddBranchOverflow:
CHECK_EQ(IsAddOverflow<int32_t>(ii, jj), res1);
break;
case kSubBranchOverflow:
CHECK_EQ(IsSubOverflow<int32_t>(ii, jj), res1);
break;
default:
UNREACHABLE();
}
}
}
}
}
}
TEST(BranchOverflowInt32BothLabels) {
FOR_INT32_INPUTS(i, overflow_int32_test_values) {
FOR_INT32_INPUTS(j, overflow_int32_test_values) {

View File

@ -874,6 +874,79 @@ static bool runOverflow(IN_TYPE valLeft, IN_TYPE valRight,
return r;
}
TEST(BranchOverflowInt32BothLabelsTrampoline) {
if (kArchVariant != kMips64r6) return;
static const int kMaxBranchOffset = (1 << (18 - 1)) - 1;
FOR_INT32_INPUTS(i, overflow_int32_test_values) {
FOR_INT32_INPUTS(j, overflow_int32_test_values) {
FOR_ENUM_INPUTS(br, OverflowBranchType, overflow_branch_type) {
FOR_STRUCT_INPUTS(regComb, OverflowRegisterCombination,
overflow_register_combination) {
int32_t ii = *i;
int32_t jj = *j;
enum OverflowBranchType branchType = *br;
struct OverflowRegisterCombination rc = *regComb;
// If left and right register are same then left and right
// test values must also be same, otherwise we skip the test
if (rc.left.code() == rc.right.code()) {
if (ii != jj) {
continue;
}
}
bool res1 = runOverflow<int32_t>(
ii, jj, [branchType, rc](MacroAssembler* masm, int32_t valLeft,
int32_t valRight) {
Label overflow, no_overflow, end;
__ li(rc.left, valLeft);
__ li(rc.right, valRight);
switch (branchType) {
case kAddBranchOverflow:
__ AddBranchOvf(rc.dst, rc.left, rc.right, &overflow,
&no_overflow, rc.scratch);
break;
case kSubBranchOverflow:
__ SubBranchOvf(rc.dst, rc.left, rc.right, &overflow,
&no_overflow, rc.scratch);
break;
}
Label done;
size_t nr_calls =
kMaxBranchOffset / (2 * Instruction::kInstrSize) + 2;
for (size_t i = 0; i < nr_calls; ++i) {
__ BranchShort(&done, eq, a0, Operand(a1));
}
__ bind(&done);
__ li(v0, 2);
__ Branch(&end);
__ bind(&overflow);
__ li(v0, 1);
__ Branch(&end);
__ bind(&no_overflow);
__ li(v0, 0);
__ bind(&end);
});
switch (branchType) {
case kAddBranchOverflow:
CHECK_EQ(IsAddOverflow<int32_t>(ii, jj), res1);
break;
case kSubBranchOverflow:
CHECK_EQ(IsSubOverflow<int32_t>(ii, jj), res1);
break;
default:
UNREACHABLE();
}
}
}
}
}
}
TEST(BranchOverflowInt32BothLabels) {
FOR_INT32_INPUTS(i, overflow_int32_test_values) {
FOR_INT32_INPUTS(j, overflow_int32_test_values) {