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,
}
void Assembler::uxtb(Register dst,
const Operand& src,
void Assembler::sxtb(Register dst, Register src, int rotate, Condition cond) {
// Instruction details available in ARM DDI 0406C.b, A8.8.233.
// 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.
// cond(31-28) | 01101110(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.rm().is(pc));
DCHECK(!src.rm().is(no_reg));
DCHECK(src.rs().is(no_reg));
DCHECK((src.shift_imm_ == 0) ||
(src.shift_imm_ == 8) ||
(src.shift_imm_ == 16) ||
(src.shift_imm_ == 24));
// Operand maps ROR #0 to LSL #0.
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,
DCHECK(!src.is(pc));
DCHECK(rotate == 0 || rotate == 8 || rotate == 16 || rotate == 24);
emit(cond | 0x6E * B20 | 0xF * B16 | dst.code() * B12 |
((rotate >> 1) & 0xC) * B8 | 7 * B4 | src.code());
}
void Assembler::uxtab(Register dst, Register src1, Register src2, int rotate,
Condition cond) {
// Instruction details available in ARM DDI 0406C.b, A8.8.271.
// cond(31-28) | 01101110(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.rm().is(pc));
DCHECK(!src2.rm().is(no_reg));
DCHECK(src2.rs().is(no_reg));
DCHECK((src2.shift_imm_ == 0) ||
(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());
DCHECK(!src2.is(pc));
DCHECK(rotate == 0 || rotate == 8 || rotate == 16 || rotate == 24);
emit(cond | 0x6E * B20 | src1.code() * B16 | dst.code() * B12 |
((rotate >> 1) & 0xC) * B8 | 7 * B4 | src2.code());
}
void Assembler::uxtb16(Register dst,
const Operand& src,
Condition cond) {
void Assembler::uxtb16(Register dst, Register src, int rotate, Condition cond) {
// Instruction details available in ARM DDI 0406C.b, A8.8.275.
// cond(31-28) | 01101100(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.rm().is(pc));
DCHECK(!src.rm().is(no_reg));
DCHECK(src.rs().is(no_reg));
DCHECK((src.shift_imm_ == 0) ||
(src.shift_imm_ == 8) ||
(src.shift_imm_ == 16) ||
(src.shift_imm_ == 24));
// Operand maps ROR #0 to LSL #0.
DCHECK((src.shift_op() == ROR) ||
((src.shift_op() == LSL) && (src.shift_imm_ == 0)));
emit(cond | 0x6C*B20 | 0xF*B16 | dst.code()*B12 |
((src.shift_imm_ >> 1)&0xC)*B8 | 7*B4 | src.rm().code());
DCHECK(!src.is(pc));
DCHECK(rotate == 0 || rotate == 8 || rotate == 16 || rotate == 24);
emit(cond | 0x6C * B20 | 0xF * B16 | dst.code() * B12 |
((rotate >> 1) & 0xC) * B8 | 7 * B4 | src.code());
}
void Assembler::uxth(Register dst, Register src, int rotate, Condition cond) {
// Instruction details available in ARM DDI 0406C.b, A8.8.276.
// cond(31-28) | 01101111(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 | 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 {
void pkhtb(Register dst, Register src1, const Operand& src2,
Condition cond = al);
void uxtb(Register dst, const Operand& src, Condition cond = al);
void uxtab(Register dst, Register src1, const Operand& src2,
void sxtb(Register dst, Register src, int rotate = 0, Condition cond = al);
void sxtab(Register dst, Register src1, Register src2, int rotate = 0,
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);
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
......
......@@ -288,8 +288,8 @@ MemCopyUint16Uint8Function CreateMemCopyUint16Uint8Function(
__ bind(&loop);
__ ldr(temp1, MemOperand(src, 4, PostIndex));
__ uxtb16(temp3, Operand(temp1, ROR, 0));
__ uxtb16(temp4, Operand(temp1, ROR, 8));
__ uxtb16(temp3, temp1);
__ uxtb16(temp4, temp1, 8);
__ pkhbt(temp1, temp3, Operand(temp4, LSL, 16));
__ str(temp1, MemOperand(dest));
__ pkhtb(temp1, temp4, Operand(temp3, ASR, 16));
......@@ -301,9 +301,9 @@ MemCopyUint16Uint8Function CreateMemCopyUint16Uint8Function(
__ mov(chars, Operand(chars, LSL, 31), SetCC); // bit0 => ne, bit1 => cs
__ b(&not_two, cc);
__ ldrh(temp1, MemOperand(src, 2, PostIndex));
__ uxtb(temp3, Operand(temp1, ROR, 8));
__ uxtb(temp3, temp1, 8);
__ mov(temp3, Operand(temp3, LSL, 16));
__ uxtab(temp3, temp3, Operand(temp1, ROR, 0));
__ uxtab(temp3, temp3, temp1);
__ str(temp3, MemOperand(dest, 4, PostIndex));
__ bind(&not_two);
__ ldrb(temp1, MemOperand(src), ne);
......
......@@ -1027,7 +1027,75 @@ void Decoder::DecodeType3(Instruction* instr) {
UNREACHABLE();
break;
case 1:
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;
case 2:
if ((instr->Bit(20) == 0) && (instr->Bits(9, 6) == 1)) {
......@@ -1054,7 +1122,8 @@ void Decoder::DecodeType3(Instruction* instr) {
}
break;
case 3:
if ((instr->Bit(20) == 0) && (instr->Bits(9, 6) == 1)) {
if ((instr->Bits(9, 6) == 1)) {
if ((instr->Bit(20) == 0)) {
if (instr->Bits(19, 16) == 0xF) {
switch (instr->Bits(11, 10)) {
case 0:
......@@ -1086,6 +1155,39 @@ void Decoder::DecodeType3(Instruction* instr) {
break;
}
}
} else {
if (instr->Bits(19, 16) == 0xF) {
switch (instr->Bits(11, 10)) {
case 0:
Format(instr, "uxth'cond 'rd, 'rm");
break;
case 1:
Format(instr, "uxth'cond 'rd, 'rm, ror #8");
break;
case 2:
Format(instr, "uxth'cond 'rd, 'rm, ror #16");
break;
case 3:
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 {
UNREACHABLE();
}
......
......@@ -2629,7 +2629,89 @@ void Simulator::DecodeType3(Instruction* instr) {
UNIMPLEMENTED();
break;
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;
case 2:
if ((instr->Bit(20) == 0) && (instr->Bits(9, 6) == 1)) {
......@@ -2650,8 +2732,7 @@ void Simulator::DecodeType3(Instruction* instr) {
rm_val = (rm_val >> 24) | (rm_val << 8);
break;
}
set_register(rd,
(rm_val & 0xFF) | (rm_val & 0xFF0000));
set_register(rd, (rm_val & 0xFF) | (rm_val & 0xFF0000));
} else {
UNIMPLEMENTED();
}
......@@ -2660,7 +2741,8 @@ void Simulator::DecodeType3(Instruction* instr) {
}
break;
case 3:
if ((instr->Bit(20) == 0) && (instr->Bits(9, 6) == 1)) {
if ((instr->Bits(9, 6) == 1)) {
if (instr->Bit(20) == 0) {
if (instr->Bits(19, 16) == 0xF) {
// Uxtb.
uint32_t rm_val = get_register(instr->RmValue());
......@@ -2699,6 +2781,46 @@ void Simulator::DecodeType3(Instruction* instr) {
}
set_register(rd, rn_val + (rm_val & 0xFF));
}
} else {
if (instr->Bits(19, 16) == 0xF) {
// Uxth.
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, (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));
}
}
} else {
UNIMPLEMENTED();
}
......
......@@ -299,6 +299,42 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
DCHECK_EQ(LeaveCC, i.OutputSBit());
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:
__ cmp(i.InputRegister(0), i.InputOperand2(1));
DCHECK_EQ(SetCC, i.OutputSBit());
......
......@@ -35,6 +35,14 @@ namespace compiler {
V(ArmMvn) \
V(ArmBfc) \
V(ArmUbfx) \
V(ArmSxtb) \
V(ArmSxth) \
V(ArmSxtab) \
V(ArmSxtah) \
V(ArmUxtb) \
V(ArmUxth) \
V(ArmUxtab) \
V(ArmUxtah) \
V(ArmVcmpF64) \
V(ArmVaddF64) \
V(ArmVsubF64) \
......
......@@ -91,6 +91,14 @@ class ArmOperandGenerator : public OperandGenerator {
case kArmUdiv:
case kArmBfc:
case kArmUbfx:
case kArmSxtb:
case kArmSxth:
case kArmSxtab:
case kArmSxtah:
case kArmUxtb:
case kArmUxth:
case kArmUxtab:
case kArmUxtah:
case kArmVcmpF64:
case kArmVaddF64:
case kArmVsubF64:
......@@ -255,7 +263,19 @@ static void VisitBinop(InstructionSelector* selector, Node* node,
InstructionOperand* outputs[2];
size_t output_count = 0;
if (TryMatchImmediateOrShift(selector, &opcode, m.right().node(),
if (m.left().node() == m.right().node()) {
// 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());
input_count++;
......@@ -430,12 +450,12 @@ void InstructionSelector::VisitWord32And(Node* node) {
return;
}
}
if (IsSupported(ARMv7) && m.right().HasValue()) {
// Try to interpret this AND as UBFX.
if (m.right().HasValue()) {
uint32_t const value = m.right().Value();
uint32_t width = base::bits::CountPopulation32(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));
if (m.left().IsWord32Shr()) {
Int32BinopMatcher mleft(m.left().node());
......@@ -450,7 +470,6 @@ void InstructionSelector::VisitWord32And(Node* node) {
g.TempImmediate(0), g.TempImmediate(width));
return;
}
// Try to interpret this AND as BIC.
if (g.CanBeImmediate(~value)) {
Emit(kArmBic | AddressingModeField::encode(kMode_Operand2_I),
......@@ -458,8 +477,14 @@ void InstructionSelector::VisitWord32And(Node* node) {
g.TempImmediate(~value));
return;
}
// Try to interpret this AND as UXTH.
if (value == 0xffff) {
Emit(kArmUxth, g.DefineAsRegister(m.node()),
g.UseRegister(m.left().node()), g.TempImmediate(0));
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);
......@@ -469,6 +494,7 @@ void InstructionSelector::VisitWord32And(Node* node) {
return;
}
}
}
VisitBinop(this, node, kArmAnd, kArmAnd);
}
......@@ -571,6 +597,20 @@ void InstructionSelector::VisitWord32Shr(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);
}
......@@ -583,31 +623,113 @@ void InstructionSelector::VisitWord32Ror(Node* node) {
void InstructionSelector::VisitInt32Add(Node* node) {
ArmOperandGenerator g(this);
Int32BinopMatcher m(node);
if (m.left().IsInt32Mul() && CanCover(node, m.left().node())) {
if (CanCover(node, m.left().node())) {
switch (m.left().opcode()) {
case IrOpcode::kInt32Mul: {
Int32BinopMatcher mleft(m.left().node());
Emit(kArmMla, g.DefineAsRegister(node), g.UseRegister(mleft.left().node()),
g.UseRegister(mleft.right().node()), g.UseRegister(m.right().node()));
return;
}
if (m.right().IsInt32Mul() && CanCover(node, m.right().node())) {
Int32BinopMatcher mright(m.right().node());
Emit(kArmMla, g.DefineAsRegister(node), g.UseRegister(mright.left().node()),
g.UseRegister(mright.right().node()), g.UseRegister(m.left().node()));
Emit(kArmMla, g.DefineAsRegister(node),
g.UseRegister(mleft.left().node()),
g.UseRegister(mleft.right().node()),
g.UseRegister(m.right().node()));
return;
}
if (m.left().IsInt32MulHigh() && CanCover(node, m.left().node())) {
case IrOpcode::kInt32MulHigh: {
Int32BinopMatcher mleft(m.left().node());
Emit(kArmSmmla, g.DefineAsRegister(node),
g.UseRegister(mleft.left().node()),
g.UseRegister(mleft.right().node()), g.UseRegister(m.right().node()));
g.UseRegister(mleft.right().node()),
g.UseRegister(m.right().node()));
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 (CanCover(node, m.right().node())) {
switch (m.right().opcode()) {
case IrOpcode::kInt32Mul: {
Int32BinopMatcher mright(m.right().node());
Emit(kArmMla, g.DefineAsRegister(node),
g.UseRegister(mright.left().node()),
g.UseRegister(mright.right().node()),
g.UseRegister(m.left().node()));
return;
}
if (m.right().IsInt32MulHigh() && CanCover(node, m.right().node())) {
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()));
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);
}
......
......@@ -1375,14 +1375,14 @@ TEST(16) {
__ pkhtb(r2, r0, Operand(r1, ASR, 8));
__ 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)));
__ uxtb(r2, Operand(r0, ROR, 8));
__ uxtb(r2, r0, 8);
__ str(r2, MemOperand(r4, OFFSET_OF(T, dst3)));
__ 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)));
__ ldm(ia_w, sp, r4.bit() | pc.bit());
......@@ -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 extracting the offset of a label from the beginning of the code
// in a register.
......
......@@ -410,14 +410,32 @@ TEST(Type3) {
"e6843895 pkhbt r3, r4, r5, lsl #17");
COMPARE(pkhtb(r3, r4, Operand(r5, ASR, 17)),
"e68438d5 pkhtb r3, r4, r5, asr #17");
COMPARE(uxtb(r9, Operand(r10, ROR, 0)),
"e6ef907a uxtb r9, r10");
COMPARE(uxtb(r3, Operand(r4, ROR, 8)),
"e6ef3474 uxtb r3, r4, ror #8");
COMPARE(uxtab(r3, r4, Operand(r5, ROR, 8)),
"e6e43475 uxtab r3, r4, r5, ror #8");
COMPARE(uxtb16(r3, Operand(r4, ROR, 8)),
"e6cf3474 uxtb16 r3, r4, ror #8");
COMPARE(sxtb(r1, r7, 0, eq), "06af1077 sxtbeq r1, r7");
COMPARE(sxtb(r0, r0, 8, ne), "16af0470 sxtbne r0, r0, ror #8");
COMPARE(sxtb(r9, r10, 16), "e6af987a sxtb r9, r10, ror #16");
COMPARE(sxtb(r4, r3, 24), "e6af4c73 sxtb r4, r3, ror #24");
COMPARE(sxtab(r3, r4, r5), "e6a43075 sxtab r3, r4, r5");
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");
......
// 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) {
}
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) {
StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32, kMachInt32);
m.Return(
......@@ -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) {
TRACED_FORRANGE(int32_t, lsb, 0, 31) {
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