Commit 8977e3d5 authored by bmeurer@chromium.org's avatar bmeurer@chromium.org

[arm] Recognize SXTB, SXTH, UXTB and UXTH.

TEST=cctest,msjunit/asm,unittests
R=jarin@chromium.org

Review URL: https://codereview.chromium.org/709123005

Cr-Commit-Position: refs/heads/master@{#25228}
git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@25228 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 406fa443
...@@ -1798,71 +1798,119 @@ void Assembler::pkhtb(Register dst, ...@@ -1798,71 +1798,119 @@ void Assembler::pkhtb(Register dst,
} }
void Assembler::uxtb(Register dst, void Assembler::sxtb(Register dst, Register src, int rotate, Condition cond) {
const Operand& src, // Instruction details available in ARM DDI 0406C.b, A8.8.233.
Condition cond) { // cond(31-28) | 01101010(27-20) | 1111(19-16) |
// Rd(15-12) | rotate(11-10) | 00(9-8)| 0111(7-4) | Rm(3-0)
DCHECK(!dst.is(pc));
DCHECK(!src.is(pc));
DCHECK(rotate == 0 || rotate == 8 || rotate == 16 || rotate == 24);
emit(cond | 0x6A * B20 | 0xF * B16 | dst.code() * B12 |
((rotate >> 1) & 0xC) * B8 | 7 * B4 | src.code());
}
void Assembler::sxtab(Register dst, Register src1, Register src2, int rotate,
Condition cond) {
// Instruction details available in ARM DDI 0406C.b, A8.8.233.
// cond(31-28) | 01101010(27-20) | Rn(19-16) |
// Rd(15-12) | rotate(11-10) | 00(9-8)| 0111(7-4) | Rm(3-0)
DCHECK(!dst.is(pc));
DCHECK(!src1.is(pc));
DCHECK(!src2.is(pc));
DCHECK(rotate == 0 || rotate == 8 || rotate == 16 || rotate == 24);
emit(cond | 0x6A * B20 | src1.code() * B16 | dst.code() * B12 |
((rotate >> 1) & 0xC) * B8 | 7 * B4 | src2.code());
}
void Assembler::sxth(Register dst, Register src, int rotate, Condition cond) {
// Instruction details available in ARM DDI 0406C.b, A8.8.235.
// cond(31-28) | 01101011(27-20) | 1111(19-16) |
// Rd(15-12) | rotate(11-10) | 00(9-8)| 0111(7-4) | Rm(3-0)
DCHECK(!dst.is(pc));
DCHECK(!src.is(pc));
DCHECK(rotate == 0 || rotate == 8 || rotate == 16 || rotate == 24);
emit(cond | 0x6B * B20 | 0xF * B16 | dst.code() * B12 |
((rotate >> 1) & 0xC) * B8 | 7 * B4 | src.code());
}
void Assembler::sxtah(Register dst, Register src1, Register src2, int rotate,
Condition cond) {
// Instruction details available in ARM DDI 0406C.b, A8.8.235.
// cond(31-28) | 01101011(27-20) | Rn(19-16) |
// Rd(15-12) | rotate(11-10) | 00(9-8)| 0111(7-4) | Rm(3-0)
DCHECK(!dst.is(pc));
DCHECK(!src1.is(pc));
DCHECK(!src2.is(pc));
DCHECK(rotate == 0 || rotate == 8 || rotate == 16 || rotate == 24);
emit(cond | 0x6B * B20 | src1.code() * B16 | dst.code() * B12 |
((rotate >> 1) & 0xC) * B8 | 7 * B4 | src2.code());
}
void Assembler::uxtb(Register dst, Register src, int rotate, Condition cond) {
// Instruction details available in ARM DDI 0406C.b, A8.8.274. // Instruction details available in ARM DDI 0406C.b, A8.8.274.
// cond(31-28) | 01101110(27-20) | 1111(19-16) | // cond(31-28) | 01101110(27-20) | 1111(19-16) |
// Rd(15-12) | rotate(11-10) | 00(9-8)| 0111(7-4) | Rm(3-0) // Rd(15-12) | rotate(11-10) | 00(9-8)| 0111(7-4) | Rm(3-0)
DCHECK(!dst.is(pc)); DCHECK(!dst.is(pc));
DCHECK(!src.rm().is(pc)); DCHECK(!src.is(pc));
DCHECK(!src.rm().is(no_reg)); DCHECK(rotate == 0 || rotate == 8 || rotate == 16 || rotate == 24);
DCHECK(src.rs().is(no_reg)); emit(cond | 0x6E * B20 | 0xF * B16 | dst.code() * B12 |
DCHECK((src.shift_imm_ == 0) || ((rotate >> 1) & 0xC) * B8 | 7 * B4 | src.code());
(src.shift_imm_ == 8) || }
(src.shift_imm_ == 16) ||
(src.shift_imm_ == 24));
// Operand maps ROR #0 to LSL #0. void Assembler::uxtab(Register dst, Register src1, Register src2, int rotate,
DCHECK((src.shift_op() == ROR) ||
((src.shift_op() == LSL) && (src.shift_imm_ == 0)));
emit(cond | 0x6E*B20 | 0xF*B16 | dst.code()*B12 |
((src.shift_imm_ >> 1)&0xC)*B8 | 7*B4 | src.rm().code());
}
void Assembler::uxtab(Register dst,
Register src1,
const Operand& src2,
Condition cond) { Condition cond) {
// Instruction details available in ARM DDI 0406C.b, A8.8.271. // Instruction details available in ARM DDI 0406C.b, A8.8.271.
// cond(31-28) | 01101110(27-20) | Rn(19-16) | // cond(31-28) | 01101110(27-20) | Rn(19-16) |
// Rd(15-12) | rotate(11-10) | 00(9-8)| 0111(7-4) | Rm(3-0) // Rd(15-12) | rotate(11-10) | 00(9-8)| 0111(7-4) | Rm(3-0)
DCHECK(!dst.is(pc)); DCHECK(!dst.is(pc));
DCHECK(!src1.is(pc)); DCHECK(!src1.is(pc));
DCHECK(!src2.rm().is(pc)); DCHECK(!src2.is(pc));
DCHECK(!src2.rm().is(no_reg)); DCHECK(rotate == 0 || rotate == 8 || rotate == 16 || rotate == 24);
DCHECK(src2.rs().is(no_reg)); emit(cond | 0x6E * B20 | src1.code() * B16 | dst.code() * B12 |
DCHECK((src2.shift_imm_ == 0) || ((rotate >> 1) & 0xC) * B8 | 7 * B4 | src2.code());
(src2.shift_imm_ == 8) ||
(src2.shift_imm_ == 16) ||
(src2.shift_imm_ == 24));
// Operand maps ROR #0 to LSL #0.
DCHECK((src2.shift_op() == ROR) ||
((src2.shift_op() == LSL) && (src2.shift_imm_ == 0)));
emit(cond | 0x6E*B20 | src1.code()*B16 | dst.code()*B12 |
((src2.shift_imm_ >> 1) &0xC)*B8 | 7*B4 | src2.rm().code());
} }
void Assembler::uxtb16(Register dst, void Assembler::uxtb16(Register dst, Register src, int rotate, Condition cond) {
const Operand& src,
Condition cond) {
// Instruction details available in ARM DDI 0406C.b, A8.8.275. // Instruction details available in ARM DDI 0406C.b, A8.8.275.
// cond(31-28) | 01101100(27-20) | 1111(19-16) | // cond(31-28) | 01101100(27-20) | 1111(19-16) |
// Rd(15-12) | rotate(11-10) | 00(9-8)| 0111(7-4) | Rm(3-0) // Rd(15-12) | rotate(11-10) | 00(9-8)| 0111(7-4) | Rm(3-0)
DCHECK(!dst.is(pc)); DCHECK(!dst.is(pc));
DCHECK(!src.rm().is(pc)); DCHECK(!src.is(pc));
DCHECK(!src.rm().is(no_reg)); DCHECK(rotate == 0 || rotate == 8 || rotate == 16 || rotate == 24);
DCHECK(src.rs().is(no_reg)); emit(cond | 0x6C * B20 | 0xF * B16 | dst.code() * B12 |
DCHECK((src.shift_imm_ == 0) || ((rotate >> 1) & 0xC) * B8 | 7 * B4 | src.code());
(src.shift_imm_ == 8) || }
(src.shift_imm_ == 16) ||
(src.shift_imm_ == 24));
// Operand maps ROR #0 to LSL #0. void Assembler::uxth(Register dst, Register src, int rotate, Condition cond) {
DCHECK((src.shift_op() == ROR) || // Instruction details available in ARM DDI 0406C.b, A8.8.276.
((src.shift_op() == LSL) && (src.shift_imm_ == 0))); // cond(31-28) | 01101111(27-20) | 1111(19-16) |
emit(cond | 0x6C*B20 | 0xF*B16 | dst.code()*B12 | // Rd(15-12) | rotate(11-10) | 00(9-8)| 0111(7-4) | Rm(3-0)
((src.shift_imm_ >> 1)&0xC)*B8 | 7*B4 | src.rm().code()); DCHECK(!dst.is(pc));
DCHECK(!src.is(pc));
DCHECK(rotate == 0 || rotate == 8 || rotate == 16 || rotate == 24);
emit(cond | 0x6F * B20 | 0xF * B16 | dst.code() * B12 |
((rotate >> 1) & 0xC) * B8 | 7 * B4 | src.code());
}
void Assembler::uxtah(Register dst, Register src1, Register src2, int rotate,
Condition cond) {
// Instruction details available in ARM DDI 0406C.b, A8.8.273.
// cond(31-28) | 01101111(27-20) | Rn(19-16) |
// Rd(15-12) | rotate(11-10) | 00(9-8)| 0111(7-4) | Rm(3-0)
DCHECK(!dst.is(pc));
DCHECK(!src1.is(pc));
DCHECK(!src2.is(pc));
DCHECK(rotate == 0 || rotate == 8 || rotate == 16 || rotate == 24);
emit(cond | 0x6F * B20 | src1.code() * B16 | dst.code() * B12 |
((rotate >> 1) & 0xC) * B8 | 7 * B4 | src2.code());
} }
......
...@@ -1034,12 +1034,20 @@ class Assembler : public AssemblerBase { ...@@ -1034,12 +1034,20 @@ class Assembler : public AssemblerBase {
void pkhtb(Register dst, Register src1, const Operand& src2, void pkhtb(Register dst, Register src1, const Operand& src2,
Condition cond = al); Condition cond = al);
void uxtb(Register dst, const Operand& src, Condition cond = al); void sxtb(Register dst, Register src, int rotate = 0, Condition cond = al);
void sxtab(Register dst, Register src1, Register src2, int rotate = 0,
void uxtab(Register dst, Register src1, const Operand& src2, Condition cond = al);
void sxth(Register dst, Register src, int rotate = 0, Condition cond = al);
void sxtah(Register dst, Register src1, Register src2, int rotate = 0,
Condition cond = al); Condition cond = al);
void uxtb16(Register dst, const Operand& src, Condition cond = al); void uxtb(Register dst, Register src, int rotate = 0, Condition cond = al);
void uxtab(Register dst, Register src1, Register src2, int rotate = 0,
Condition cond = al);
void uxtb16(Register dst, Register src, int rotate = 0, Condition cond = al);
void uxth(Register dst, Register src, int rotate = 0, Condition cond = al);
void uxtah(Register dst, Register src1, Register src2, int rotate = 0,
Condition cond = al);
// Status register access instructions // Status register access instructions
......
...@@ -288,8 +288,8 @@ MemCopyUint16Uint8Function CreateMemCopyUint16Uint8Function( ...@@ -288,8 +288,8 @@ MemCopyUint16Uint8Function CreateMemCopyUint16Uint8Function(
__ bind(&loop); __ bind(&loop);
__ ldr(temp1, MemOperand(src, 4, PostIndex)); __ ldr(temp1, MemOperand(src, 4, PostIndex));
__ uxtb16(temp3, Operand(temp1, ROR, 0)); __ uxtb16(temp3, temp1);
__ uxtb16(temp4, Operand(temp1, ROR, 8)); __ uxtb16(temp4, temp1, 8);
__ pkhbt(temp1, temp3, Operand(temp4, LSL, 16)); __ pkhbt(temp1, temp3, Operand(temp4, LSL, 16));
__ str(temp1, MemOperand(dest)); __ str(temp1, MemOperand(dest));
__ pkhtb(temp1, temp4, Operand(temp3, ASR, 16)); __ pkhtb(temp1, temp4, Operand(temp3, ASR, 16));
...@@ -301,9 +301,9 @@ MemCopyUint16Uint8Function CreateMemCopyUint16Uint8Function( ...@@ -301,9 +301,9 @@ MemCopyUint16Uint8Function CreateMemCopyUint16Uint8Function(
__ mov(chars, Operand(chars, LSL, 31), SetCC); // bit0 => ne, bit1 => cs __ mov(chars, Operand(chars, LSL, 31), SetCC); // bit0 => ne, bit1 => cs
__ b(&not_two, cc); __ b(&not_two, cc);
__ ldrh(temp1, MemOperand(src, 2, PostIndex)); __ ldrh(temp1, MemOperand(src, 2, PostIndex));
__ uxtb(temp3, Operand(temp1, ROR, 8)); __ uxtb(temp3, temp1, 8);
__ mov(temp3, Operand(temp3, LSL, 16)); __ mov(temp3, Operand(temp3, LSL, 16));
__ uxtab(temp3, temp3, Operand(temp1, ROR, 0)); __ uxtab(temp3, temp3, temp1);
__ str(temp3, MemOperand(dest, 4, PostIndex)); __ str(temp3, MemOperand(dest, 4, PostIndex));
__ bind(&not_two); __ bind(&not_two);
__ ldrb(temp1, MemOperand(src), ne); __ ldrb(temp1, MemOperand(src), ne);
......
...@@ -1027,7 +1027,75 @@ void Decoder::DecodeType3(Instruction* instr) { ...@@ -1027,7 +1027,75 @@ void Decoder::DecodeType3(Instruction* instr) {
UNREACHABLE(); UNREACHABLE();
break; break;
case 1: case 1:
UNREACHABLE(); if (instr->Bits(9, 6) == 1) {
if (instr->Bit(20) == 0) {
if (instr->Bits(19, 16) == 0xF) {
switch (instr->Bits(11, 10)) {
case 0:
Format(instr, "sxtb'cond 'rd, 'rm");
break;
case 1:
Format(instr, "sxtb'cond 'rd, 'rm, ror #8");
break;
case 2:
Format(instr, "sxtb'cond 'rd, 'rm, ror #16");
break;
case 3:
Format(instr, "sxtb'cond 'rd, 'rm, ror #24");
break;
}
} else {
switch (instr->Bits(11, 10)) {
case 0:
Format(instr, "sxtab'cond 'rd, 'rn, 'rm");
break;
case 1:
Format(instr, "sxtab'cond 'rd, 'rn, 'rm, ror #8");
break;
case 2:
Format(instr, "sxtab'cond 'rd, 'rn, 'rm, ror #16");
break;
case 3:
Format(instr, "sxtab'cond 'rd, 'rn, 'rm, ror #24");
break;
}
}
} else {
if (instr->Bits(19, 16) == 0xF) {
switch (instr->Bits(11, 10)) {
case 0:
Format(instr, "sxth'cond 'rd, 'rm");
break;
case 1:
Format(instr, "sxth'cond 'rd, 'rm, ror #8");
break;
case 2:
Format(instr, "sxth'cond 'rd, 'rm, ror #16");
break;
case 3:
Format(instr, "sxth'cond 'rd, 'rm, ror #24");
break;
}
} else {
switch (instr->Bits(11, 10)) {
case 0:
Format(instr, "sxtah'cond 'rd, 'rn, 'rm");
break;
case 1:
Format(instr, "sxtah'cond 'rd, 'rn, 'rm, ror #8");
break;
case 2:
Format(instr, "sxtah'cond 'rd, 'rn, 'rm, ror #16");
break;
case 3:
Format(instr, "sxtah'cond 'rd, 'rn, 'rm, ror #24");
break;
}
}
}
} else {
UNREACHABLE();
}
break; break;
case 2: case 2:
if ((instr->Bit(20) == 0) && (instr->Bits(9, 6) == 1)) { if ((instr->Bit(20) == 0) && (instr->Bits(9, 6) == 1)) {
...@@ -1054,36 +1122,70 @@ void Decoder::DecodeType3(Instruction* instr) { ...@@ -1054,36 +1122,70 @@ void Decoder::DecodeType3(Instruction* instr) {
} }
break; break;
case 3: case 3:
if ((instr->Bit(20) == 0) && (instr->Bits(9, 6) == 1)) { if ((instr->Bits(9, 6) == 1)) {
if (instr->Bits(19, 16) == 0xF) { if ((instr->Bit(20) == 0)) {
switch (instr->Bits(11, 10)) { if (instr->Bits(19, 16) == 0xF) {
case 0: switch (instr->Bits(11, 10)) {
Format(instr, "uxtb'cond 'rd, 'rm"); case 0:
break; Format(instr, "uxtb'cond 'rd, 'rm");
case 1: break;
Format(instr, "uxtb'cond 'rd, 'rm, ror #8"); case 1:
break; Format(instr, "uxtb'cond 'rd, 'rm, ror #8");
case 2: break;
Format(instr, "uxtb'cond 'rd, 'rm, ror #16"); case 2:
break; Format(instr, "uxtb'cond 'rd, 'rm, ror #16");
case 3: break;
Format(instr, "uxtb'cond 'rd, 'rm, ror #24"); case 3:
break; Format(instr, "uxtb'cond 'rd, 'rm, ror #24");
break;
}
} else {
switch (instr->Bits(11, 10)) {
case 0:
Format(instr, "uxtab'cond 'rd, 'rn, 'rm");
break;
case 1:
Format(instr, "uxtab'cond 'rd, 'rn, 'rm, ror #8");
break;
case 2:
Format(instr, "uxtab'cond 'rd, 'rn, 'rm, ror #16");
break;
case 3:
Format(instr, "uxtab'cond 'rd, 'rn, 'rm, ror #24");
break;
}
} }
} else { } else {
switch (instr->Bits(11, 10)) { if (instr->Bits(19, 16) == 0xF) {
case 0: switch (instr->Bits(11, 10)) {
Format(instr, "uxtab'cond 'rd, 'rn, 'rm"); case 0:
break; Format(instr, "uxth'cond 'rd, 'rm");
case 1: break;
Format(instr, "uxtab'cond 'rd, 'rn, 'rm, ror #8"); case 1:
break; Format(instr, "uxth'cond 'rd, 'rm, ror #8");
case 2: break;
Format(instr, "uxtab'cond 'rd, 'rn, 'rm, ror #16"); case 2:
break; Format(instr, "uxth'cond 'rd, 'rm, ror #16");
case 3: break;
Format(instr, "uxtab'cond 'rd, 'rn, 'rm, ror #24"); case 3:
break; Format(instr, "uxth'cond 'rd, 'rm, ror #24");
break;
}
} else {
switch (instr->Bits(11, 10)) {
case 0:
Format(instr, "uxtah'cond 'rd, 'rn, 'rm");
break;
case 1:
Format(instr, "uxtah'cond 'rd, 'rn, 'rm, ror #8");
break;
case 2:
Format(instr, "uxtah'cond 'rd, 'rn, 'rm, ror #16");
break;
case 3:
Format(instr, "uxtah'cond 'rd, 'rn, 'rm, ror #24");
break;
}
} }
} }
} else { } else {
......
...@@ -2629,7 +2629,89 @@ void Simulator::DecodeType3(Instruction* instr) { ...@@ -2629,7 +2629,89 @@ void Simulator::DecodeType3(Instruction* instr) {
UNIMPLEMENTED(); UNIMPLEMENTED();
break; break;
case 1: case 1:
UNIMPLEMENTED(); if (instr->Bits(9, 6) == 1) {
if (instr->Bit(20) == 0) {
if (instr->Bits(19, 16) == 0xF) {
// Sxtb.
int32_t rm_val = get_register(instr->RmValue());
int32_t rotate = instr->Bits(11, 10);
switch (rotate) {
case 0:
break;
case 1:
rm_val = (rm_val >> 8) | (rm_val << 24);
break;
case 2:
rm_val = (rm_val >> 16) | (rm_val << 16);
break;
case 3:
rm_val = (rm_val >> 24) | (rm_val << 8);
break;
}
set_register(rd, static_cast<int8_t>(rm_val));
} else {
// Sxtab.
int32_t rn_val = get_register(rn);
int32_t rm_val = get_register(instr->RmValue());
int32_t rotate = instr->Bits(11, 10);
switch (rotate) {
case 0:
break;
case 1:
rm_val = (rm_val >> 8) | (rm_val << 24);
break;
case 2:
rm_val = (rm_val >> 16) | (rm_val << 16);
break;
case 3:
rm_val = (rm_val >> 24) | (rm_val << 8);
break;
}
set_register(rd, rn_val + static_cast<int8_t>(rm_val));
}
} else {
if (instr->Bits(19, 16) == 0xF) {
// Sxth.
int32_t rm_val = get_register(instr->RmValue());
int32_t rotate = instr->Bits(11, 10);
switch (rotate) {
case 0:
break;
case 1:
rm_val = (rm_val >> 8) | (rm_val << 24);
break;
case 2:
rm_val = (rm_val >> 16) | (rm_val << 16);
break;
case 3:
rm_val = (rm_val >> 24) | (rm_val << 8);
break;
}
set_register(rd, static_cast<int16_t>(rm_val));
} else {
// Sxtah.
int32_t rn_val = get_register(rn);
int32_t rm_val = get_register(instr->RmValue());
int32_t rotate = instr->Bits(11, 10);
switch (rotate) {
case 0:
break;
case 1:
rm_val = (rm_val >> 8) | (rm_val << 24);
break;
case 2:
rm_val = (rm_val >> 16) | (rm_val << 16);
break;
case 3:
rm_val = (rm_val >> 24) | (rm_val << 8);
break;
}
set_register(rd, rn_val + static_cast<int16_t>(rm_val));
}
}
} else {
UNREACHABLE();
}
break; break;
case 2: case 2:
if ((instr->Bit(20) == 0) && (instr->Bits(9, 6) == 1)) { if ((instr->Bit(20) == 0) && (instr->Bits(9, 6) == 1)) {
...@@ -2650,8 +2732,7 @@ void Simulator::DecodeType3(Instruction* instr) { ...@@ -2650,8 +2732,7 @@ void Simulator::DecodeType3(Instruction* instr) {
rm_val = (rm_val >> 24) | (rm_val << 8); rm_val = (rm_val >> 24) | (rm_val << 8);
break; break;
} }
set_register(rd, set_register(rd, (rm_val & 0xFF) | (rm_val & 0xFF0000));
(rm_val & 0xFF) | (rm_val & 0xFF0000));
} else { } else {
UNIMPLEMENTED(); UNIMPLEMENTED();
} }
...@@ -2660,44 +2741,85 @@ void Simulator::DecodeType3(Instruction* instr) { ...@@ -2660,44 +2741,85 @@ void Simulator::DecodeType3(Instruction* instr) {
} }
break; break;
case 3: case 3:
if ((instr->Bit(20) == 0) && (instr->Bits(9, 6) == 1)) { if ((instr->Bits(9, 6) == 1)) {
if (instr->Bits(19, 16) == 0xF) { if (instr->Bit(20) == 0) {
// Uxtb. if (instr->Bits(19, 16) == 0xF) {
uint32_t rm_val = get_register(instr->RmValue()); // Uxtb.
int32_t rotate = instr->Bits(11, 10); uint32_t rm_val = get_register(instr->RmValue());
switch (rotate) { int32_t rotate = instr->Bits(11, 10);
case 0: switch (rotate) {
break; case 0:
case 1: break;
rm_val = (rm_val >> 8) | (rm_val << 24); case 1:
break; rm_val = (rm_val >> 8) | (rm_val << 24);
case 2: break;
rm_val = (rm_val >> 16) | (rm_val << 16); case 2:
break; rm_val = (rm_val >> 16) | (rm_val << 16);
case 3: break;
rm_val = (rm_val >> 24) | (rm_val << 8); case 3:
break; rm_val = (rm_val >> 24) | (rm_val << 8);
break;
}
set_register(rd, (rm_val & 0xFF));
} else {
// Uxtab.
uint32_t rn_val = get_register(rn);
uint32_t rm_val = get_register(instr->RmValue());
int32_t rotate = instr->Bits(11, 10);
switch (rotate) {
case 0:
break;
case 1:
rm_val = (rm_val >> 8) | (rm_val << 24);
break;
case 2:
rm_val = (rm_val >> 16) | (rm_val << 16);
break;
case 3:
rm_val = (rm_val >> 24) | (rm_val << 8);
break;
}
set_register(rd, rn_val + (rm_val & 0xFF));
} }
set_register(rd, (rm_val & 0xFF));
} else { } else {
// Uxtab. if (instr->Bits(19, 16) == 0xF) {
uint32_t rn_val = get_register(rn); // Uxth.
uint32_t rm_val = get_register(instr->RmValue()); uint32_t rm_val = get_register(instr->RmValue());
int32_t rotate = instr->Bits(11, 10); int32_t rotate = instr->Bits(11, 10);
switch (rotate) { switch (rotate) {
case 0: case 0:
break; break;
case 1: case 1:
rm_val = (rm_val >> 8) | (rm_val << 24); rm_val = (rm_val >> 8) | (rm_val << 24);
break; break;
case 2: case 2:
rm_val = (rm_val >> 16) | (rm_val << 16); rm_val = (rm_val >> 16) | (rm_val << 16);
break; break;
case 3: case 3:
rm_val = (rm_val >> 24) | (rm_val << 8); rm_val = (rm_val >> 24) | (rm_val << 8);
break; break;
}
set_register(rd, (rm_val & 0xFFFF));
} else {
// Uxtah.
uint32_t rn_val = get_register(rn);
uint32_t rm_val = get_register(instr->RmValue());
int32_t rotate = instr->Bits(11, 10);
switch (rotate) {
case 0:
break;
case 1:
rm_val = (rm_val >> 8) | (rm_val << 24);
break;
case 2:
rm_val = (rm_val >> 16) | (rm_val << 16);
break;
case 3:
rm_val = (rm_val >> 24) | (rm_val << 8);
break;
}
set_register(rd, rn_val + (rm_val & 0xFFFF));
} }
set_register(rd, rn_val + (rm_val & 0xFF));
} }
} else { } else {
UNIMPLEMENTED(); UNIMPLEMENTED();
......
...@@ -299,6 +299,42 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) { ...@@ -299,6 +299,42 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
DCHECK_EQ(LeaveCC, i.OutputSBit()); DCHECK_EQ(LeaveCC, i.OutputSBit());
break; break;
} }
case kArmSxtb:
__ sxtb(i.OutputRegister(), i.InputRegister(0), i.InputInt32(1));
DCHECK_EQ(LeaveCC, i.OutputSBit());
break;
case kArmSxth:
__ sxth(i.OutputRegister(), i.InputRegister(0), i.InputInt32(1));
DCHECK_EQ(LeaveCC, i.OutputSBit());
break;
case kArmSxtab:
__ sxtab(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
i.InputInt32(2));
DCHECK_EQ(LeaveCC, i.OutputSBit());
break;
case kArmSxtah:
__ sxtah(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
i.InputInt32(2));
DCHECK_EQ(LeaveCC, i.OutputSBit());
break;
case kArmUxtb:
__ uxtb(i.OutputRegister(), i.InputRegister(0), i.InputInt32(1));
DCHECK_EQ(LeaveCC, i.OutputSBit());
break;
case kArmUxth:
__ uxth(i.OutputRegister(), i.InputRegister(0), i.InputInt32(1));
DCHECK_EQ(LeaveCC, i.OutputSBit());
break;
case kArmUxtab:
__ uxtab(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
i.InputInt32(2));
DCHECK_EQ(LeaveCC, i.OutputSBit());
break;
case kArmUxtah:
__ uxtah(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
i.InputInt32(2));
DCHECK_EQ(LeaveCC, i.OutputSBit());
break;
case kArmCmp: case kArmCmp:
__ cmp(i.InputRegister(0), i.InputOperand2(1)); __ cmp(i.InputRegister(0), i.InputOperand2(1));
DCHECK_EQ(SetCC, i.OutputSBit()); DCHECK_EQ(SetCC, i.OutputSBit());
......
...@@ -35,6 +35,14 @@ namespace compiler { ...@@ -35,6 +35,14 @@ namespace compiler {
V(ArmMvn) \ V(ArmMvn) \
V(ArmBfc) \ V(ArmBfc) \
V(ArmUbfx) \ V(ArmUbfx) \
V(ArmSxtb) \
V(ArmSxth) \
V(ArmSxtab) \
V(ArmSxtah) \
V(ArmUxtb) \
V(ArmUxth) \
V(ArmUxtab) \
V(ArmUxtah) \
V(ArmVcmpF64) \ V(ArmVcmpF64) \
V(ArmVaddF64) \ V(ArmVaddF64) \
V(ArmVsubF64) \ V(ArmVsubF64) \
......
...@@ -91,6 +91,14 @@ class ArmOperandGenerator : public OperandGenerator { ...@@ -91,6 +91,14 @@ class ArmOperandGenerator : public OperandGenerator {
case kArmUdiv: case kArmUdiv:
case kArmBfc: case kArmBfc:
case kArmUbfx: case kArmUbfx:
case kArmSxtb:
case kArmSxth:
case kArmSxtab:
case kArmSxtah:
case kArmUxtb:
case kArmUxth:
case kArmUxtab:
case kArmUxtah:
case kArmVcmpF64: case kArmVcmpF64:
case kArmVaddF64: case kArmVaddF64:
case kArmVsubF64: case kArmVsubF64:
...@@ -255,8 +263,20 @@ static void VisitBinop(InstructionSelector* selector, Node* node, ...@@ -255,8 +263,20 @@ static void VisitBinop(InstructionSelector* selector, Node* node,
InstructionOperand* outputs[2]; InstructionOperand* outputs[2];
size_t output_count = 0; size_t output_count = 0;
if (TryMatchImmediateOrShift(selector, &opcode, m.right().node(), if (m.left().node() == m.right().node()) {
&input_count, &inputs[1])) { // If both inputs refer to the same operand, enforce allocating a register
// for both of them to ensure that we don't end up generating code like
// this:
//
// mov r0, r1, asr #16
// adds r0, r0, r1, asr #16
// bvs label
InstructionOperand* const input = g.UseRegister(m.left().node());
opcode |= AddressingModeField::encode(kMode_Operand2_R);
inputs[input_count++] = input;
inputs[input_count++] = input;
} else if (TryMatchImmediateOrShift(selector, &opcode, m.right().node(),
&input_count, &inputs[1])) {
inputs[0] = g.UseRegister(m.left().node()); inputs[0] = g.UseRegister(m.left().node());
input_count++; input_count++;
} else if (TryMatchImmediateOrShift(selector, &reverse_opcode, } else if (TryMatchImmediateOrShift(selector, &reverse_opcode,
...@@ -430,12 +450,12 @@ void InstructionSelector::VisitWord32And(Node* node) { ...@@ -430,12 +450,12 @@ void InstructionSelector::VisitWord32And(Node* node) {
return; return;
} }
} }
if (IsSupported(ARMv7) && m.right().HasValue()) { if (m.right().HasValue()) {
// Try to interpret this AND as UBFX.
uint32_t const value = m.right().Value(); uint32_t const value = m.right().Value();
uint32_t width = base::bits::CountPopulation32(value); uint32_t width = base::bits::CountPopulation32(value);
uint32_t msb = base::bits::CountLeadingZeros32(value); uint32_t msb = base::bits::CountLeadingZeros32(value);
if (width != 0 && msb + width == 32) { // Try to interpret this AND as UBFX.
if (IsSupported(ARMv7) && width != 0 && msb + width == 32) {
DCHECK_EQ(0, base::bits::CountTrailingZeros32(value)); DCHECK_EQ(0, base::bits::CountTrailingZeros32(value));
if (m.left().IsWord32Shr()) { if (m.left().IsWord32Shr()) {
Int32BinopMatcher mleft(m.left().node()); Int32BinopMatcher mleft(m.left().node());
...@@ -450,7 +470,6 @@ void InstructionSelector::VisitWord32And(Node* node) { ...@@ -450,7 +470,6 @@ void InstructionSelector::VisitWord32And(Node* node) {
g.TempImmediate(0), g.TempImmediate(width)); g.TempImmediate(0), g.TempImmediate(width));
return; return;
} }
// Try to interpret this AND as BIC. // Try to interpret this AND as BIC.
if (g.CanBeImmediate(~value)) { if (g.CanBeImmediate(~value)) {
Emit(kArmBic | AddressingModeField::encode(kMode_Operand2_I), Emit(kArmBic | AddressingModeField::encode(kMode_Operand2_I),
...@@ -458,16 +477,23 @@ void InstructionSelector::VisitWord32And(Node* node) { ...@@ -458,16 +477,23 @@ void InstructionSelector::VisitWord32And(Node* node) {
g.TempImmediate(~value)); g.TempImmediate(~value));
return; return;
} }
// Try to interpret this AND as UXTH.
// Try to interpret this AND as BFC. if (value == 0xffff) {
width = 32 - width; Emit(kArmUxth, g.DefineAsRegister(m.node()),
msb = base::bits::CountLeadingZeros32(~value); g.UseRegister(m.left().node()), g.TempImmediate(0));
uint32_t lsb = base::bits::CountTrailingZeros32(~value);
if (msb + width + lsb == 32) {
Emit(kArmBfc, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()),
g.TempImmediate(lsb), g.TempImmediate(width));
return; return;
} }
// Try to interpret this AND as BFC.
if (IsSupported(ARMv7)) {
width = 32 - width;
msb = base::bits::CountLeadingZeros32(~value);
uint32_t lsb = base::bits::CountTrailingZeros32(~value);
if (msb + width + lsb == 32) {
Emit(kArmBfc, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()),
g.TempImmediate(lsb), g.TempImmediate(width));
return;
}
}
} }
VisitBinop(this, node, kArmAnd, kArmAnd); VisitBinop(this, node, kArmAnd, kArmAnd);
} }
...@@ -571,6 +597,20 @@ void InstructionSelector::VisitWord32Shr(Node* node) { ...@@ -571,6 +597,20 @@ void InstructionSelector::VisitWord32Shr(Node* node) {
void InstructionSelector::VisitWord32Sar(Node* node) { void InstructionSelector::VisitWord32Sar(Node* node) {
ArmOperandGenerator g(this);
Int32BinopMatcher m(node);
if (CanCover(m.node(), m.left().node()) && m.left().IsWord32Shl()) {
Int32BinopMatcher mleft(m.left().node());
if (mleft.right().Is(16) && m.right().Is(16)) {
Emit(kArmSxth, g.DefineAsRegister(node),
g.UseRegister(mleft.left().node()), g.TempImmediate(0));
return;
} else if (mleft.right().Is(24) && m.right().Is(24)) {
Emit(kArmSxtb, g.DefineAsRegister(node),
g.UseRegister(mleft.left().node()), g.TempImmediate(0));
return;
}
}
VisitShift(this, node, TryMatchASR); VisitShift(this, node, TryMatchASR);
} }
...@@ -583,31 +623,113 @@ void InstructionSelector::VisitWord32Ror(Node* node) { ...@@ -583,31 +623,113 @@ void InstructionSelector::VisitWord32Ror(Node* node) {
void InstructionSelector::VisitInt32Add(Node* node) { void InstructionSelector::VisitInt32Add(Node* node) {
ArmOperandGenerator g(this); ArmOperandGenerator g(this);
Int32BinopMatcher m(node); Int32BinopMatcher m(node);
if (m.left().IsInt32Mul() && CanCover(node, m.left().node())) { if (CanCover(node, m.left().node())) {
Int32BinopMatcher mleft(m.left().node()); switch (m.left().opcode()) {
Emit(kArmMla, g.DefineAsRegister(node), g.UseRegister(mleft.left().node()), case IrOpcode::kInt32Mul: {
g.UseRegister(mleft.right().node()), g.UseRegister(m.right().node())); Int32BinopMatcher mleft(m.left().node());
return; Emit(kArmMla, g.DefineAsRegister(node),
} g.UseRegister(mleft.left().node()),
if (m.right().IsInt32Mul() && CanCover(node, m.right().node())) { g.UseRegister(mleft.right().node()),
Int32BinopMatcher mright(m.right().node()); g.UseRegister(m.right().node()));
Emit(kArmMla, g.DefineAsRegister(node), g.UseRegister(mright.left().node()), return;
g.UseRegister(mright.right().node()), g.UseRegister(m.left().node())); }
return; case IrOpcode::kInt32MulHigh: {
} Int32BinopMatcher mleft(m.left().node());
if (m.left().IsInt32MulHigh() && CanCover(node, m.left().node())) { Emit(kArmSmmla, g.DefineAsRegister(node),
Int32BinopMatcher mleft(m.left().node()); g.UseRegister(mleft.left().node()),
Emit(kArmSmmla, g.DefineAsRegister(node), g.UseRegister(mleft.right().node()),
g.UseRegister(mleft.left().node()), g.UseRegister(m.right().node()));
g.UseRegister(mleft.right().node()), g.UseRegister(m.right().node())); return;
return; }
case IrOpcode::kWord32And: {
Int32BinopMatcher mleft(m.left().node());
if (mleft.right().Is(0xff)) {
Emit(kArmUxtab, g.DefineAsRegister(node),
g.UseRegister(m.right().node()),
g.UseRegister(mleft.left().node()), g.TempImmediate(0));
return;
} else if (mleft.right().Is(0xffff)) {
Emit(kArmUxtah, g.DefineAsRegister(node),
g.UseRegister(m.right().node()),
g.UseRegister(mleft.left().node()), g.TempImmediate(0));
return;
}
}
case IrOpcode::kWord32Sar: {
Int32BinopMatcher mleft(m.left().node());
if (CanCover(mleft.node(), mleft.left().node()) &&
mleft.left().IsWord32Shl()) {
Int32BinopMatcher mleftleft(mleft.left().node());
if (mleft.right().Is(24) && mleftleft.right().Is(24)) {
Emit(kArmSxtab, g.DefineAsRegister(node),
g.UseRegister(m.right().node()),
g.UseRegister(mleftleft.left().node()), g.TempImmediate(0));
return;
} else if (mleft.right().Is(16) && mleftleft.right().Is(16)) {
Emit(kArmSxtah, g.DefineAsRegister(node),
g.UseRegister(m.right().node()),
g.UseRegister(mleftleft.left().node()), g.TempImmediate(0));
return;
}
}
}
default:
break;
}
} }
if (m.right().IsInt32MulHigh() && CanCover(node, m.right().node())) { if (CanCover(node, m.right().node())) {
Int32BinopMatcher mright(m.right().node()); switch (m.right().opcode()) {
Emit(kArmSmmla, g.DefineAsRegister(node), case IrOpcode::kInt32Mul: {
g.UseRegister(mright.left().node()), Int32BinopMatcher mright(m.right().node());
g.UseRegister(mright.right().node()), g.UseRegister(m.left().node())); Emit(kArmMla, g.DefineAsRegister(node),
return; g.UseRegister(mright.left().node()),
g.UseRegister(mright.right().node()),
g.UseRegister(m.left().node()));
return;
}
case IrOpcode::kInt32MulHigh: {
Int32BinopMatcher mright(m.right().node());
Emit(kArmSmmla, g.DefineAsRegister(node),
g.UseRegister(mright.left().node()),
g.UseRegister(mright.right().node()),
g.UseRegister(m.left().node()));
return;
}
case IrOpcode::kWord32And: {
Int32BinopMatcher mright(m.right().node());
if (mright.right().Is(0xff)) {
Emit(kArmUxtab, g.DefineAsRegister(node),
g.UseRegister(m.left().node()),
g.UseRegister(mright.left().node()), g.TempImmediate(0));
return;
} else if (mright.right().Is(0xffff)) {
Emit(kArmUxtah, g.DefineAsRegister(node),
g.UseRegister(m.left().node()),
g.UseRegister(mright.left().node()), g.TempImmediate(0));
return;
}
}
case IrOpcode::kWord32Sar: {
Int32BinopMatcher mright(m.right().node());
if (CanCover(mright.node(), mright.left().node()) &&
mright.left().IsWord32Shl()) {
Int32BinopMatcher mrightleft(mright.left().node());
if (mright.right().Is(24) && mrightleft.right().Is(24)) {
Emit(kArmSxtab, g.DefineAsRegister(node),
g.UseRegister(m.left().node()),
g.UseRegister(mrightleft.left().node()), g.TempImmediate(0));
return;
} else if (mright.right().Is(16) && mrightleft.right().Is(16)) {
Emit(kArmSxtah, g.DefineAsRegister(node),
g.UseRegister(m.left().node()),
g.UseRegister(mrightleft.left().node()), g.TempImmediate(0));
return;
}
}
}
default:
break;
}
} }
VisitBinop(this, node, kArmAdd, kArmAdd); VisitBinop(this, node, kArmAdd, kArmAdd);
} }
......
...@@ -1375,14 +1375,14 @@ TEST(16) { ...@@ -1375,14 +1375,14 @@ TEST(16) {
__ pkhtb(r2, r0, Operand(r1, ASR, 8)); __ pkhtb(r2, r0, Operand(r1, ASR, 8));
__ str(r2, MemOperand(r4, OFFSET_OF(T, dst1))); __ str(r2, MemOperand(r4, OFFSET_OF(T, dst1)));
__ uxtb16(r2, Operand(r0, ROR, 8)); __ uxtb16(r2, r0, 8);
__ str(r2, MemOperand(r4, OFFSET_OF(T, dst2))); __ str(r2, MemOperand(r4, OFFSET_OF(T, dst2)));
__ uxtb(r2, Operand(r0, ROR, 8)); __ uxtb(r2, r0, 8);
__ str(r2, MemOperand(r4, OFFSET_OF(T, dst3))); __ str(r2, MemOperand(r4, OFFSET_OF(T, dst3)));
__ ldr(r0, MemOperand(r4, OFFSET_OF(T, src2))); __ ldr(r0, MemOperand(r4, OFFSET_OF(T, src2)));
__ uxtab(r2, r0, Operand(r1, ROR, 8)); __ uxtab(r2, r0, r1, 8);
__ str(r2, MemOperand(r4, OFFSET_OF(T, dst4))); __ str(r2, MemOperand(r4, OFFSET_OF(T, dst4)));
__ ldm(ia_w, sp, r4.bit() | pc.bit()); __ ldm(ia_w, sp, r4.bit() | pc.bit());
...@@ -1606,6 +1606,214 @@ TEST(smmul) { ...@@ -1606,6 +1606,214 @@ TEST(smmul) {
} }
TEST(sxtb) {
CcTest::InitializeVM();
Isolate* const isolate = CcTest::i_isolate();
HandleScope scope(isolate);
RandomNumberGenerator* const rng = isolate->random_number_generator();
Assembler assm(isolate, nullptr, 0);
__ sxtb(r1, r1);
__ str(r1, MemOperand(r0));
__ bx(lr);
CodeDesc desc;
assm.GetCode(&desc);
Handle<Code> code = isolate->factory()->NewCode(
desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
#ifdef OBJECT_PRINT
code->Print(std::cout);
#endif
F3 f = FUNCTION_CAST<F3>(code->entry());
for (size_t i = 0; i < 128; ++i) {
int32_t r, x = rng->NextInt();
Object* dummy = CALL_GENERATED_CODE(f, &r, x, 0, 0, 0);
CHECK_EQ(static_cast<int32_t>(static_cast<int8_t>(x)), r);
USE(dummy);
}
}
TEST(sxtab) {
CcTest::InitializeVM();
Isolate* const isolate = CcTest::i_isolate();
HandleScope scope(isolate);
RandomNumberGenerator* const rng = isolate->random_number_generator();
Assembler assm(isolate, nullptr, 0);
__ sxtab(r1, r2, r1);
__ str(r1, MemOperand(r0));
__ bx(lr);
CodeDesc desc;
assm.GetCode(&desc);
Handle<Code> code = isolate->factory()->NewCode(
desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
#ifdef OBJECT_PRINT
code->Print(std::cout);
#endif
F3 f = FUNCTION_CAST<F3>(code->entry());
for (size_t i = 0; i < 128; ++i) {
int32_t r, x = rng->NextInt(), y = rng->NextInt();
Object* dummy = CALL_GENERATED_CODE(f, &r, x, y, 0, 0);
CHECK_EQ(static_cast<int32_t>(static_cast<int8_t>(x)) + y, r);
USE(dummy);
}
}
TEST(sxth) {
CcTest::InitializeVM();
Isolate* const isolate = CcTest::i_isolate();
HandleScope scope(isolate);
RandomNumberGenerator* const rng = isolate->random_number_generator();
Assembler assm(isolate, nullptr, 0);
__ sxth(r1, r1);
__ str(r1, MemOperand(r0));
__ bx(lr);
CodeDesc desc;
assm.GetCode(&desc);
Handle<Code> code = isolate->factory()->NewCode(
desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
#ifdef OBJECT_PRINT
code->Print(std::cout);
#endif
F3 f = FUNCTION_CAST<F3>(code->entry());
for (size_t i = 0; i < 128; ++i) {
int32_t r, x = rng->NextInt();
Object* dummy = CALL_GENERATED_CODE(f, &r, x, 0, 0, 0);
CHECK_EQ(static_cast<int32_t>(static_cast<int16_t>(x)), r);
USE(dummy);
}
}
TEST(sxtah) {
CcTest::InitializeVM();
Isolate* const isolate = CcTest::i_isolate();
HandleScope scope(isolate);
RandomNumberGenerator* const rng = isolate->random_number_generator();
Assembler assm(isolate, nullptr, 0);
__ sxtah(r1, r2, r1);
__ str(r1, MemOperand(r0));
__ bx(lr);
CodeDesc desc;
assm.GetCode(&desc);
Handle<Code> code = isolate->factory()->NewCode(
desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
#ifdef OBJECT_PRINT
code->Print(std::cout);
#endif
F3 f = FUNCTION_CAST<F3>(code->entry());
for (size_t i = 0; i < 128; ++i) {
int32_t r, x = rng->NextInt(), y = rng->NextInt();
Object* dummy = CALL_GENERATED_CODE(f, &r, x, y, 0, 0);
CHECK_EQ(static_cast<int32_t>(static_cast<int16_t>(x)) + y, r);
USE(dummy);
}
}
TEST(uxtb) {
CcTest::InitializeVM();
Isolate* const isolate = CcTest::i_isolate();
HandleScope scope(isolate);
RandomNumberGenerator* const rng = isolate->random_number_generator();
Assembler assm(isolate, nullptr, 0);
__ uxtb(r1, r1);
__ str(r1, MemOperand(r0));
__ bx(lr);
CodeDesc desc;
assm.GetCode(&desc);
Handle<Code> code = isolate->factory()->NewCode(
desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
#ifdef OBJECT_PRINT
code->Print(std::cout);
#endif
F3 f = FUNCTION_CAST<F3>(code->entry());
for (size_t i = 0; i < 128; ++i) {
int32_t r, x = rng->NextInt();
Object* dummy = CALL_GENERATED_CODE(f, &r, x, 0, 0, 0);
CHECK_EQ(static_cast<int32_t>(static_cast<uint8_t>(x)), r);
USE(dummy);
}
}
TEST(uxtab) {
CcTest::InitializeVM();
Isolate* const isolate = CcTest::i_isolate();
HandleScope scope(isolate);
RandomNumberGenerator* const rng = isolate->random_number_generator();
Assembler assm(isolate, nullptr, 0);
__ uxtab(r1, r2, r1);
__ str(r1, MemOperand(r0));
__ bx(lr);
CodeDesc desc;
assm.GetCode(&desc);
Handle<Code> code = isolate->factory()->NewCode(
desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
#ifdef OBJECT_PRINT
code->Print(std::cout);
#endif
F3 f = FUNCTION_CAST<F3>(code->entry());
for (size_t i = 0; i < 128; ++i) {
int32_t r, x = rng->NextInt(), y = rng->NextInt();
Object* dummy = CALL_GENERATED_CODE(f, &r, x, y, 0, 0);
CHECK_EQ(static_cast<int32_t>(static_cast<uint8_t>(x)) + y, r);
USE(dummy);
}
}
TEST(uxth) {
CcTest::InitializeVM();
Isolate* const isolate = CcTest::i_isolate();
HandleScope scope(isolate);
RandomNumberGenerator* const rng = isolate->random_number_generator();
Assembler assm(isolate, nullptr, 0);
__ uxth(r1, r1);
__ str(r1, MemOperand(r0));
__ bx(lr);
CodeDesc desc;
assm.GetCode(&desc);
Handle<Code> code = isolate->factory()->NewCode(
desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
#ifdef OBJECT_PRINT
code->Print(std::cout);
#endif
F3 f = FUNCTION_CAST<F3>(code->entry());
for (size_t i = 0; i < 128; ++i) {
int32_t r, x = rng->NextInt();
Object* dummy = CALL_GENERATED_CODE(f, &r, x, 0, 0, 0);
CHECK_EQ(static_cast<int32_t>(static_cast<uint16_t>(x)), r);
USE(dummy);
}
}
TEST(uxtah) {
CcTest::InitializeVM();
Isolate* const isolate = CcTest::i_isolate();
HandleScope scope(isolate);
RandomNumberGenerator* const rng = isolate->random_number_generator();
Assembler assm(isolate, nullptr, 0);
__ uxtah(r1, r2, r1);
__ str(r1, MemOperand(r0));
__ bx(lr);
CodeDesc desc;
assm.GetCode(&desc);
Handle<Code> code = isolate->factory()->NewCode(
desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
#ifdef OBJECT_PRINT
code->Print(std::cout);
#endif
F3 f = FUNCTION_CAST<F3>(code->entry());
for (size_t i = 0; i < 128; ++i) {
int32_t r, x = rng->NextInt(), y = rng->NextInt();
Object* dummy = CALL_GENERATED_CODE(f, &r, x, y, 0, 0);
CHECK_EQ(static_cast<int32_t>(static_cast<uint16_t>(x)) + y, r);
USE(dummy);
}
}
TEST(code_relative_offset) { TEST(code_relative_offset) {
// Test extracting the offset of a label from the beginning of the code // Test extracting the offset of a label from the beginning of the code
// in a register. // in a register.
......
...@@ -410,14 +410,32 @@ TEST(Type3) { ...@@ -410,14 +410,32 @@ TEST(Type3) {
"e6843895 pkhbt r3, r4, r5, lsl #17"); "e6843895 pkhbt r3, r4, r5, lsl #17");
COMPARE(pkhtb(r3, r4, Operand(r5, ASR, 17)), COMPARE(pkhtb(r3, r4, Operand(r5, ASR, 17)),
"e68438d5 pkhtb r3, r4, r5, asr #17"); "e68438d5 pkhtb r3, r4, r5, asr #17");
COMPARE(uxtb(r9, Operand(r10, ROR, 0)),
"e6ef907a uxtb r9, r10"); COMPARE(sxtb(r1, r7, 0, eq), "06af1077 sxtbeq r1, r7");
COMPARE(uxtb(r3, Operand(r4, ROR, 8)), COMPARE(sxtb(r0, r0, 8, ne), "16af0470 sxtbne r0, r0, ror #8");
"e6ef3474 uxtb r3, r4, ror #8"); COMPARE(sxtb(r9, r10, 16), "e6af987a sxtb r9, r10, ror #16");
COMPARE(uxtab(r3, r4, Operand(r5, ROR, 8)), COMPARE(sxtb(r4, r3, 24), "e6af4c73 sxtb r4, r3, ror #24");
"e6e43475 uxtab r3, r4, r5, ror #8");
COMPARE(uxtb16(r3, Operand(r4, ROR, 8)), COMPARE(sxtab(r3, r4, r5), "e6a43075 sxtab r3, r4, r5");
"e6cf3474 uxtb16 r3, r4, ror #8");
COMPARE(sxth(r5, r0), "e6bf5070 sxth r5, r0");
COMPARE(sxth(r5, r9, 8), "e6bf5479 sxth r5, r9, ror #8");
COMPARE(sxth(r5, r9, 16, hi), "86bf5879 sxthhi r5, r9, ror #16");
COMPARE(sxth(r8, r9, 24, cc), "36bf8c79 sxthcc r8, r9, ror #24");
COMPARE(sxtah(r3, r4, r5, 16), "e6b43875 sxtah r3, r4, r5, ror #16");
COMPARE(uxtb(r9, r10), "e6ef907a uxtb r9, r10");
COMPARE(uxtb(r3, r4, 8), "e6ef3474 uxtb r3, r4, ror #8");
COMPARE(uxtab(r3, r4, r5, 8), "e6e43475 uxtab r3, r4, r5, ror #8");
COMPARE(uxtb16(r3, r4, 8), "e6cf3474 uxtb16 r3, r4, ror #8");
COMPARE(uxth(r9, r10), "e6ff907a uxth r9, r10");
COMPARE(uxth(r3, r4, 8), "e6ff3474 uxth r3, r4, ror #8");
COMPARE(uxtah(r3, r4, r5, 24), "e6f43c75 uxtah r3, r4, r5, ror #24");
} }
COMPARE(smmla(r0, r1, r2, r3), "e7503211 smmla r0, r1, r2, r3"); COMPARE(smmla(r0, r1, r2, r3), "e7503211 smmla r0, r1, r2, r3");
......
// Copyright 2014 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
var stdlib = this;
var buffer = new ArrayBuffer(64 * 1024);
var foreign = {}
var sext8 = (function Module(stdlib, foreign, heap) {
"use asm";
function sext8(i) {
i = i|0;
i = i << 24 >> 24;
return i|0;
}
return { sext8: sext8 };
})(stdlib, foreign, buffer).sext8;
assertEquals(-128, sext8(128));
assertEquals(-1, sext8(-1));
assertEquals(-1, sext8(255));
assertEquals(0, sext8(0));
assertEquals(0, sext8(256));
assertEquals(42, sext8(42));
assertEquals(127, sext8(127));
var sext16 = (function Module(stdlib, foreign, heap) {
"use asm";
function sext16(i) {
i = i|0;
i = i << 16 >> 16;
return i|0;
}
return { sext16: sext16 };
})(stdlib, foreign, buffer).sext16;
assertEquals(-32768, sext16(32768));
assertEquals(-1, sext16(-1));
assertEquals(-1, sext16(65535));
assertEquals(0, sext16(0));
assertEquals(0, sext16(65536));
assertEquals(128, sext16(128));
assertEquals(32767, sext16(32767));
// Copyright 2014 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
var stdlib = this;
var buffer = new ArrayBuffer(64 * 1024);
var foreign = {}
var zext8 = (function Module(stdlib, foreign, heap) {
"use asm";
function zext8(i) {
i = i|0;
return i & 0xff;
}
return { zext8: zext8 };
})(stdlib, foreign, buffer).zext8;
assertEquals(0, zext8(0));
assertEquals(0, zext8(0x100));
assertEquals(0xff, zext8(-1));
assertEquals(0xff, zext8(0xff));
var zext16 = (function Module(stdlib, foreign, heap) {
"use asm";
function zext16(i) {
i = i|0;
return i & 0xffff;
}
return { zext16: zext16 };
})(stdlib, foreign, buffer).zext16;
assertEquals(0, zext16(0));
assertEquals(0, zext16(0x10000));
assertEquals(0xffff, zext16(-1));
assertEquals(0xffff, zext16(0xffff));
...@@ -1558,6 +1558,150 @@ TEST_F(InstructionSelectorTest, Int32AddWithInt32MulHigh) { ...@@ -1558,6 +1558,150 @@ TEST_F(InstructionSelectorTest, Int32AddWithInt32MulHigh) {
} }
TEST_F(InstructionSelectorTest, Int32AddWithWord32And) {
{
StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
Node* const p0 = m.Parameter(0);
Node* const p1 = m.Parameter(1);
Node* const r = m.Int32Add(m.Word32And(p0, m.Int32Constant(0xff)), p1);
m.Return(r);
Stream s = m.Build();
ASSERT_EQ(1U, s.size());
EXPECT_EQ(kArmUxtab, s[0]->arch_opcode());
ASSERT_EQ(3U, s[0]->InputCount());
EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(0)));
EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(1)));
EXPECT_EQ(0, s.ToInt32(s[0]->InputAt(2)));
ASSERT_EQ(1U, s[0]->OutputCount());
EXPECT_EQ(s.ToVreg(r), s.ToVreg(s[0]->Output()));
}
{
StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
Node* const p0 = m.Parameter(0);
Node* const p1 = m.Parameter(1);
Node* const r = m.Int32Add(p1, m.Word32And(p0, m.Int32Constant(0xff)));
m.Return(r);
Stream s = m.Build();
ASSERT_EQ(1U, s.size());
EXPECT_EQ(kArmUxtab, s[0]->arch_opcode());
ASSERT_EQ(3U, s[0]->InputCount());
EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(0)));
EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(1)));
EXPECT_EQ(0, s.ToInt32(s[0]->InputAt(2)));
ASSERT_EQ(1U, s[0]->OutputCount());
EXPECT_EQ(s.ToVreg(r), s.ToVreg(s[0]->Output()));
}
{
StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
Node* const p0 = m.Parameter(0);
Node* const p1 = m.Parameter(1);
Node* const r = m.Int32Add(m.Word32And(p0, m.Int32Constant(0xffff)), p1);
m.Return(r);
Stream s = m.Build();
ASSERT_EQ(1U, s.size());
EXPECT_EQ(kArmUxtah, s[0]->arch_opcode());
ASSERT_EQ(3U, s[0]->InputCount());
EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(0)));
EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(1)));
EXPECT_EQ(0, s.ToInt32(s[0]->InputAt(2)));
ASSERT_EQ(1U, s[0]->OutputCount());
EXPECT_EQ(s.ToVreg(r), s.ToVreg(s[0]->Output()));
}
{
StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
Node* const p0 = m.Parameter(0);
Node* const p1 = m.Parameter(1);
Node* const r = m.Int32Add(p1, m.Word32And(p0, m.Int32Constant(0xffff)));
m.Return(r);
Stream s = m.Build();
ASSERT_EQ(1U, s.size());
EXPECT_EQ(kArmUxtah, s[0]->arch_opcode());
ASSERT_EQ(3U, s[0]->InputCount());
EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(0)));
EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(1)));
EXPECT_EQ(0, s.ToInt32(s[0]->InputAt(2)));
ASSERT_EQ(1U, s[0]->OutputCount());
EXPECT_EQ(s.ToVreg(r), s.ToVreg(s[0]->Output()));
}
}
TEST_F(InstructionSelectorTest, Int32AddWithWord32SarWithWord32Shl) {
{
StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
Node* const p0 = m.Parameter(0);
Node* const p1 = m.Parameter(1);
Node* const r = m.Int32Add(
m.Word32Sar(m.Word32Shl(p0, m.Int32Constant(24)), m.Int32Constant(24)),
p1);
m.Return(r);
Stream s = m.Build();
ASSERT_EQ(1U, s.size());
EXPECT_EQ(kArmSxtab, s[0]->arch_opcode());
ASSERT_EQ(3U, s[0]->InputCount());
EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(0)));
EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(1)));
EXPECT_EQ(0, s.ToInt32(s[0]->InputAt(2)));
ASSERT_EQ(1U, s[0]->OutputCount());
EXPECT_EQ(s.ToVreg(r), s.ToVreg(s[0]->Output()));
}
{
StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
Node* const p0 = m.Parameter(0);
Node* const p1 = m.Parameter(1);
Node* const r = m.Int32Add(
p1,
m.Word32Sar(m.Word32Shl(p0, m.Int32Constant(24)), m.Int32Constant(24)));
m.Return(r);
Stream s = m.Build();
ASSERT_EQ(1U, s.size());
EXPECT_EQ(kArmSxtab, s[0]->arch_opcode());
ASSERT_EQ(3U, s[0]->InputCount());
EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(0)));
EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(1)));
EXPECT_EQ(0, s.ToInt32(s[0]->InputAt(2)));
ASSERT_EQ(1U, s[0]->OutputCount());
EXPECT_EQ(s.ToVreg(r), s.ToVreg(s[0]->Output()));
}
{
StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
Node* const p0 = m.Parameter(0);
Node* const p1 = m.Parameter(1);
Node* const r = m.Int32Add(
m.Word32Sar(m.Word32Shl(p0, m.Int32Constant(16)), m.Int32Constant(16)),
p1);
m.Return(r);
Stream s = m.Build();
ASSERT_EQ(1U, s.size());
EXPECT_EQ(kArmSxtah, s[0]->arch_opcode());
ASSERT_EQ(3U, s[0]->InputCount());
EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(0)));
EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(1)));
EXPECT_EQ(0, s.ToInt32(s[0]->InputAt(2)));
ASSERT_EQ(1U, s[0]->OutputCount());
EXPECT_EQ(s.ToVreg(r), s.ToVreg(s[0]->Output()));
}
{
StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
Node* const p0 = m.Parameter(0);
Node* const p1 = m.Parameter(1);
Node* const r = m.Int32Add(
p1,
m.Word32Sar(m.Word32Shl(p0, m.Int32Constant(16)), m.Int32Constant(16)));
m.Return(r);
Stream s = m.Build();
ASSERT_EQ(1U, s.size());
EXPECT_EQ(kArmSxtah, s[0]->arch_opcode());
ASSERT_EQ(3U, s[0]->InputCount());
EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(0)));
EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(1)));
EXPECT_EQ(0, s.ToInt32(s[0]->InputAt(2)));
ASSERT_EQ(1U, s[0]->OutputCount());
EXPECT_EQ(s.ToVreg(r), s.ToVreg(s[0]->Output()));
}
}
TEST_F(InstructionSelectorTest, Int32SubWithInt32Mul) { TEST_F(InstructionSelectorTest, Int32SubWithInt32Mul) {
StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32, kMachInt32); StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32, kMachInt32);
m.Return( m.Return(
...@@ -1943,6 +2087,72 @@ TEST_F(InstructionSelectorTest, Word32AndWithBfcImmediateForARMv7) { ...@@ -1943,6 +2087,72 @@ TEST_F(InstructionSelectorTest, Word32AndWithBfcImmediateForARMv7) {
} }
TEST_F(InstructionSelectorTest, Word32AndWith0xffff) {
{
StreamBuilder m(this, kMachInt32, kMachInt32);
Node* const p0 = m.Parameter(0);
Node* const r = m.Word32And(p0, m.Int32Constant(0xffff));
m.Return(r);
Stream s = m.Build();
ASSERT_EQ(1U, s.size());
EXPECT_EQ(kArmUxth, s[0]->arch_opcode());
ASSERT_EQ(2U, s[0]->InputCount());
EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
EXPECT_EQ(0, s.ToInt32(s[0]->InputAt(1)));
ASSERT_EQ(1U, s[0]->OutputCount());
EXPECT_EQ(s.ToVreg(r), s.ToVreg(s[0]->Output()));
}
{
StreamBuilder m(this, kMachInt32, kMachInt32);
Node* const p0 = m.Parameter(0);
Node* const r = m.Word32And(m.Int32Constant(0xffff), p0);
m.Return(r);
Stream s = m.Build();
ASSERT_EQ(1U, s.size());
EXPECT_EQ(kArmUxth, s[0]->arch_opcode());
ASSERT_EQ(2U, s[0]->InputCount());
EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
EXPECT_EQ(0, s.ToInt32(s[0]->InputAt(1)));
ASSERT_EQ(1U, s[0]->OutputCount());
EXPECT_EQ(s.ToVreg(r), s.ToVreg(s[0]->Output()));
}
}
TEST_F(InstructionSelectorTest, Word32SarWithWord32Shl) {
{
StreamBuilder m(this, kMachInt32, kMachInt32);
Node* const p0 = m.Parameter(0);
Node* const r =
m.Word32Sar(m.Word32Shl(p0, m.Int32Constant(24)), m.Int32Constant(24));
m.Return(r);
Stream s = m.Build();
ASSERT_EQ(1U, s.size());
EXPECT_EQ(kArmSxtb, s[0]->arch_opcode());
ASSERT_EQ(2U, s[0]->InputCount());
EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
EXPECT_EQ(0, s.ToInt32(s[0]->InputAt(1)));
ASSERT_EQ(1U, s[0]->OutputCount());
EXPECT_EQ(s.ToVreg(r), s.ToVreg(s[0]->Output()));
}
{
StreamBuilder m(this, kMachInt32, kMachInt32);
Node* const p0 = m.Parameter(0);
Node* const r =
m.Word32Sar(m.Word32Shl(p0, m.Int32Constant(16)), m.Int32Constant(16));
m.Return(r);
Stream s = m.Build();
ASSERT_EQ(1U, s.size());
EXPECT_EQ(kArmSxth, s[0]->arch_opcode());
ASSERT_EQ(2U, s[0]->InputCount());
EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
EXPECT_EQ(0, s.ToInt32(s[0]->InputAt(1)));
ASSERT_EQ(1U, s[0]->OutputCount());
EXPECT_EQ(s.ToVreg(r), s.ToVreg(s[0]->Output()));
}
}
TEST_F(InstructionSelectorTest, Word32ShrWithWord32AndWithImmediateForARMv7) { TEST_F(InstructionSelectorTest, Word32ShrWithWord32AndWithImmediateForARMv7) {
TRACED_FORRANGE(int32_t, lsb, 0, 31) { TRACED_FORRANGE(int32_t, lsb, 0, 31) {
TRACED_FORRANGE(int32_t, width, 1, 32 - lsb) { TRACED_FORRANGE(int32_t, width, 1, 32 - lsb) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment