Revision: 25228
Author: [email protected]
Date: Mon Nov 10 05:48:38 2014 UTC
Log: [arm] Recognize SXTB, SXTH, UXTB and UXTH.
TEST=cctest,msjunit/asm,unittests
[email protected]
Review URL: https://codereview.chromium.org/709123005
https://code.google.com/p/v8/source/detail?r=25228
Added:
/branches/bleeding_edge/test/mjsunit/asm/sign-extend.js
/branches/bleeding_edge/test/mjsunit/asm/zero-extend.js
Modified:
/branches/bleeding_edge/src/arm/assembler-arm.cc
/branches/bleeding_edge/src/arm/assembler-arm.h
/branches/bleeding_edge/src/arm/codegen-arm.cc
/branches/bleeding_edge/src/arm/disasm-arm.cc
/branches/bleeding_edge/src/arm/simulator-arm.cc
/branches/bleeding_edge/src/compiler/arm/code-generator-arm.cc
/branches/bleeding_edge/src/compiler/arm/instruction-codes-arm.h
/branches/bleeding_edge/src/compiler/arm/instruction-selector-arm.cc
/branches/bleeding_edge/test/cctest/test-assembler-arm.cc
/branches/bleeding_edge/test/cctest/test-disasm-arm.cc
/branches/bleeding_edge/test/unittests/compiler/arm/instruction-selector-arm-unittest.cc
=======================================
--- /dev/null
+++ /branches/bleeding_edge/test/mjsunit/asm/sign-extend.js Mon Nov 10
05:48:38 2014 UTC
@@ -0,0 +1,45 @@
+// 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));
=======================================
--- /dev/null
+++ /branches/bleeding_edge/test/mjsunit/asm/zero-extend.js Mon Nov 10
05:48:38 2014 UTC
@@ -0,0 +1,37 @@
+// 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));
=======================================
--- /branches/bleeding_edge/src/arm/assembler-arm.cc Wed Nov 5 11:50:49
2014 UTC
+++ /branches/bleeding_edge/src/arm/assembler-arm.cc Mon Nov 10 05:48:38
2014 UTC
@@ -1798,71 +1798,119 @@
}
-void Assembler::uxtb(Register dst,
- const Operand& src,
- Condition cond) {
+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());
+ 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,
- const Operand& src2,
+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());
}
=======================================
--- /branches/bleeding_edge/src/arm/assembler-arm.h Thu Oct 30 11:00:47
2014 UTC
+++ /branches/bleeding_edge/src/arm/assembler-arm.h Mon Nov 10 05:48:38
2014 UTC
@@ -1034,12 +1034,20 @@
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
=======================================
--- /branches/bleeding_edge/src/arm/codegen-arm.cc Thu Oct 9 14:12:05 2014
UTC
+++ /branches/bleeding_edge/src/arm/codegen-arm.cc Mon Nov 10 05:48:38 2014
UTC
@@ -288,8 +288,8 @@
__ 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 @@
__ mov(chars, Operand(chars, LSL, 31), SetCC); // bit0 => ne, bit1 =>
cs
__ b(¬_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(¬_two);
__ ldrb(temp1, MemOperand(src), ne);
=======================================
--- /branches/bleeding_edge/src/arm/disasm-arm.cc Thu Oct 30 11:00:47 2014
UTC
+++ /branches/bleeding_edge/src/arm/disasm-arm.cc Mon Nov 10 05:48:38 2014
UTC
@@ -1027,7 +1027,75 @@
UNREACHABLE();
break;
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;
case 2:
if ((instr->Bit(20) == 0) && (instr->Bits(9, 6) == 1)) {
@@ -1054,36 +1122,70 @@
}
break;
case 3:
- if ((instr->Bit(20) == 0) && (instr->Bits(9, 6) == 1)) {
- if (instr->Bits(19, 16) == 0xF) {
- switch (instr->Bits(11, 10)) {
- case 0:
- Format(instr, "uxtb'cond 'rd, 'rm");
- break;
- case 1:
- Format(instr, "uxtb'cond 'rd, 'rm, ror #8");
- break;
- case 2:
- Format(instr, "uxtb'cond 'rd, 'rm, ror #16");
- break;
- case 3:
- Format(instr, "uxtb'cond 'rd, 'rm, ror #24");
- break;
+ 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, "uxtb'cond 'rd, 'rm");
+ break;
+ case 1:
+ Format(instr, "uxtb'cond 'rd, 'rm, ror #8");
+ break;
+ case 2:
+ Format(instr, "uxtb'cond 'rd, 'rm, ror #16");
+ break;
+ case 3:
+ 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 {
- 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;
+ 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 {
=======================================
--- /branches/bleeding_edge/src/arm/simulator-arm.cc Wed Nov 5 10:41:43
2014 UTC
+++ /branches/bleeding_edge/src/arm/simulator-arm.cc Mon Nov 10 05:48:38
2014 UTC
@@ -2629,7 +2629,89 @@
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 @@
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,44 +2741,85 @@
}
break;
case 3:
- if ((instr->Bit(20) == 0) && (instr->Bits(9, 6) == 1)) {
- if (instr->Bits(19, 16) == 0xF) {
- // Uxtb.
- 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;
+ 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());
+ 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 & 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 {
- // 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;
+ 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));
}
- set_register(rd, rn_val + (rm_val & 0xFF));
}
} else {
UNIMPLEMENTED();
=======================================
--- /branches/bleeding_edge/src/compiler/arm/code-generator-arm.cc Thu Nov
6 14:59:07 2014 UTC
+++ /branches/bleeding_edge/src/compiler/arm/code-generator-arm.cc Mon Nov
10 05:48:38 2014 UTC
@@ -299,6 +299,42 @@
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());
=======================================
--- /branches/bleeding_edge/src/compiler/arm/instruction-codes-arm.h Mon
Nov 3 10:04:37 2014 UTC
+++ /branches/bleeding_edge/src/compiler/arm/instruction-codes-arm.h Mon
Nov 10 05:48:38 2014 UTC
@@ -35,6 +35,14 @@
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) \
=======================================
--- /branches/bleeding_edge/src/compiler/arm/instruction-selector-arm.cc
Mon Nov 3 10:04:37 2014 UTC
+++ /branches/bleeding_edge/src/compiler/arm/instruction-selector-arm.cc
Mon Nov 10 05:48:38 2014 UTC
@@ -91,6 +91,14 @@
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,8 +263,20 @@
InstructionOperand* outputs[2];
size_t output_count = 0;
- if (TryMatchImmediateOrShift(selector, &opcode, m.right().node(),
- &input_count, &inputs[1])) {
+ 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++;
} else if (TryMatchImmediateOrShift(selector, &reverse_opcode,
@@ -430,12 +450,12 @@
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 @@
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,15 +477,22 @@
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.
- 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;
+ 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);
@@ -571,6 +597,20 @@
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::VisitInt32Add(Node* node) {
ArmOperandGenerator g(this);
Int32BinopMatcher m(node);
- if (m.left().IsInt32Mul() && CanCover(node, m.left().node())) {
- 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()));
- return;
- }
- if (m.left().IsInt32MulHigh() && CanCover(node, m.left().node())) {
- 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()));
- return;
+ 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;
+ }
+ 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()));
+ 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())) {
- 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;
+ 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;
+ }
+ 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);
}
=======================================
--- /branches/bleeding_edge/test/cctest/test-assembler-arm.cc Thu Oct 30
11:00:47 2014 UTC
+++ /branches/bleeding_edge/test/cctest/test-assembler-arm.cc Mon Nov 10
05:48:38 2014 UTC
@@ -1375,14 +1375,14 @@
__ 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());
@@ -1604,6 +1604,214 @@
USE(dummy);
}
}
+
+
+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) {
=======================================
--- /branches/bleeding_edge/test/cctest/test-disasm-arm.cc Thu Oct 30
11:00:47 2014 UTC
+++ /branches/bleeding_edge/test/cctest/test-disasm-arm.cc Mon Nov 10
05:48:38 2014 UTC
@@ -410,14 +410,32 @@
"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");
=======================================
---
/branches/bleeding_edge/test/unittests/compiler/arm/instruction-selector-arm-unittest.cc
Mon Nov 3 10:04:37 2014 UTC
+++
/branches/bleeding_edge/test/unittests/compiler/arm/instruction-selector-arm-unittest.cc
Mon Nov 10 05:48:38 2014 UTC
@@ -1556,6 +1556,150 @@
EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
}
}
+
+
+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) {
@@ -1941,6 +2085,72 @@
}
}
}
+
+
+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) {
--
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
---
You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.