diff options
author | 2016-06-13 14:42:27 +0100 | |
---|---|---|
committer | 2016-06-28 13:29:29 +0000 | |
commit | e652c122d8cc9697d368b9ceada9b377d091e4fd (patch) | |
tree | 699f7f7bc88ff28d2b8f8e735ea48693aa653c95 | |
parent | ca7399a1d7b3c92d73322adf54187fde31eee1bd (diff) |
ARM assembler support for VCNT and VPADDL.
Test: Gtest assembler_thumb2_test.
Change-Id: I8a0e47da746e1c67650cb68196a9f661deed7383
-rw-r--r-- | compiler/utils/arm/assembler_arm.h | 3 | ||||
-rw-r--r-- | compiler/utils/arm/assembler_arm32.cc | 25 | ||||
-rw-r--r-- | compiler/utils/arm/assembler_arm32.h | 3 | ||||
-rw-r--r-- | compiler/utils/arm/assembler_arm32_test.cc | 39 | ||||
-rw-r--r-- | compiler/utils/arm/assembler_thumb2.cc | 24 | ||||
-rw-r--r-- | compiler/utils/arm/assembler_thumb2.h | 3 | ||||
-rw-r--r-- | compiler/utils/arm/assembler_thumb2_test.cc | 39 | ||||
-rw-r--r-- | disassembler/disassembler_arm.cc | 19 |
8 files changed, 155 insertions, 0 deletions
diff --git a/compiler/utils/arm/assembler_arm.h b/compiler/utils/arm/assembler_arm.h index 274d0de166..a571d14a71 100644 --- a/compiler/utils/arm/assembler_arm.h +++ b/compiler/utils/arm/assembler_arm.h @@ -671,6 +671,9 @@ class ArmAssembler : public Assembler { virtual void vcmpdz(DRegister dd, Condition cond = AL) = 0; virtual void vmstat(Condition cond = AL) = 0; // VMRS APSR_nzcv, FPSCR + virtual void vcntd(DRegister dd, DRegister dm) = 0; + virtual void vpaddld(DRegister dd, DRegister dm, int32_t size, bool is_unsigned) = 0; + virtual void vpushs(SRegister reg, int nregs, Condition cond = AL) = 0; virtual void vpushd(DRegister reg, int nregs, Condition cond = AL) = 0; virtual void vpops(SRegister reg, int nregs, Condition cond = AL) = 0; diff --git a/compiler/utils/arm/assembler_arm32.cc b/compiler/utils/arm/assembler_arm32.cc index 0a227b21cd..6f7119d578 100644 --- a/compiler/utils/arm/assembler_arm32.cc +++ b/compiler/utils/arm/assembler_arm32.cc @@ -1264,6 +1264,31 @@ void Arm32Assembler::vmstat(Condition cond) { // VMRS APSR_nzcv, FPSCR Emit(encoding); } +void Arm32Assembler::vcntd(DRegister dd, DRegister dm) { + uint32_t encoding = (B31 | B30 | B29 | B28 | B25 | B24 | B23 | B21 | B20) | + ((static_cast<int32_t>(dd) >> 4) * B22) | + ((static_cast<uint32_t>(dd) & 0xf) * B12) | + (B10 | B8) | + ((static_cast<int32_t>(dm) >> 4) * B5) | + (static_cast<uint32_t>(dm) & 0xf); + + Emit(encoding); +} + +void Arm32Assembler::vpaddld(DRegister dd, DRegister dm, int32_t size, bool is_unsigned) { + CHECK(size == 8 || size == 16 || size == 32) << size; + uint32_t encoding = (B31 | B30 | B29 | B28 | B25 | B24 | B23 | B21 | B20) | + ((static_cast<uint32_t>(size >> 4) & 0x3) * B18) | + ((static_cast<int32_t>(dd) >> 4) * B22) | + ((static_cast<uint32_t>(dd) & 0xf) * B12) | + (B9) | + (is_unsigned ? B7 : 0) | + ((static_cast<int32_t>(dm) >> 4) * B5) | + (static_cast<uint32_t>(dm) & 0xf); + + Emit(encoding); +} + void Arm32Assembler::svc(uint32_t imm24) { CHECK(IsUint<24>(imm24)) << imm24; diff --git a/compiler/utils/arm/assembler_arm32.h b/compiler/utils/arm/assembler_arm32.h index bc6020e008..8726ac85fd 100644 --- a/compiler/utils/arm/assembler_arm32.h +++ b/compiler/utils/arm/assembler_arm32.h @@ -205,6 +205,9 @@ class Arm32Assembler FINAL : public ArmAssembler { void vcmpdz(DRegister dd, Condition cond = AL) OVERRIDE; void vmstat(Condition cond = AL) OVERRIDE; // VMRS APSR_nzcv, FPSCR + void vcntd(DRegister dd, DRegister dm) OVERRIDE; + void vpaddld(DRegister dd, DRegister dm, int32_t size, bool is_unsigned) OVERRIDE; + void vpushs(SRegister reg, int nregs, Condition cond = AL) OVERRIDE; void vpushd(DRegister reg, int nregs, Condition cond = AL) OVERRIDE; void vpops(SRegister reg, int nregs, Condition cond = AL) OVERRIDE; diff --git a/compiler/utils/arm/assembler_arm32_test.cc b/compiler/utils/arm/assembler_arm32_test.cc index e570e22fca..b214062e18 100644 --- a/compiler/utils/arm/assembler_arm32_test.cc +++ b/compiler/utils/arm/assembler_arm32_test.cc @@ -899,4 +899,43 @@ TEST_F(AssemblerArm32Test, revsh) { T3Helper(&arm::Arm32Assembler::revsh, true, "revsh{cond} {reg1}, {reg2}", "revsh"); } +TEST_F(AssemblerArm32Test, vcnt) { + // Different D register numbers are used here, to test register encoding. + // Source register number is encoded as M:Vm, destination register number is encoded as D:Vd, + // For source and destination registers which use D0..D15, the M bit and D bit should be 0. + // For source and destination registers which use D16..D32, the M bit and D bit should be 1. + GetAssembler()->vcntd(arm::D0, arm::D1); + GetAssembler()->vcntd(arm::D19, arm::D20); + GetAssembler()->vcntd(arm::D0, arm::D9); + GetAssembler()->vcntd(arm::D16, arm::D20); + + std::string expected = + "vcnt.8 d0, d1\n" + "vcnt.8 d19, d20\n" + "vcnt.8 d0, d9\n" + "vcnt.8 d16, d20\n"; + + DriverStr(expected, "vcnt"); +} + +TEST_F(AssemblerArm32Test, vpaddl) { + // Different D register numbers are used here, to test register encoding. + // Source register number is encoded as M:Vm, destination register number is encoded as D:Vd, + // For source and destination registers which use D0..D15, the M bit and D bit should be 0. + // For source and destination registers which use D16..D32, the M bit and D bit should be 1. + // Different data types (signed and unsigned) are also tested. + GetAssembler()->vpaddld(arm::D0, arm::D0, 8, true); + GetAssembler()->vpaddld(arm::D20, arm::D20, 8, false); + GetAssembler()->vpaddld(arm::D0, arm::D20, 16, false); + GetAssembler()->vpaddld(arm::D20, arm::D0, 32, true); + + std::string expected = + "vpaddl.u8 d0, d0\n" + "vpaddl.s8 d20, d20\n" + "vpaddl.s16 d0, d20\n" + "vpaddl.u32 d20, d0\n"; + + DriverStr(expected, "vpaddl"); +} + } // namespace art diff --git a/compiler/utils/arm/assembler_thumb2.cc b/compiler/utils/arm/assembler_thumb2.cc index 546dd653af..a72ea410ce 100644 --- a/compiler/utils/arm/assembler_thumb2.cc +++ b/compiler/utils/arm/assembler_thumb2.cc @@ -3117,6 +3117,30 @@ void Thumb2Assembler::vmstat(Condition cond) { // VMRS APSR_nzcv, FPSCR. Emit32(encoding); } +void Thumb2Assembler::vcntd(DRegister dd, DRegister dm) { + uint32_t encoding = (B31 | B30 | B29 | B28 | B27 | B26 | B25 | B24 | B23 | B21 | B20) | + ((static_cast<int32_t>(dd) >> 4) * B22) | + ((static_cast<uint32_t>(dd) & 0xf) * B12) | + (B10 | B8) | + ((static_cast<int32_t>(dm) >> 4) * B5) | + (static_cast<uint32_t>(dm) & 0xf); + + Emit32(encoding); +} + +void Thumb2Assembler::vpaddld(DRegister dd, DRegister dm, int32_t size, bool is_unsigned) { + CHECK(size == 8 || size == 16 || size == 32) << size; + uint32_t encoding = (B31 | B30 | B29 | B28 | B27 | B26 | B25 | B24 | B23 | B21 | B20) | + ((static_cast<uint32_t>(size >> 4) & 0x3) * B18) | + ((static_cast<int32_t>(dd) >> 4) * B22) | + ((static_cast<uint32_t>(dd) & 0xf) * B12) | + (B9) | + (is_unsigned ? B7 : 0) | + ((static_cast<int32_t>(dm) >> 4) * B5) | + (static_cast<uint32_t>(dm) & 0xf); + + Emit32(encoding); +} void Thumb2Assembler::svc(uint32_t imm8) { CHECK(IsUint<8>(imm8)) << imm8; diff --git a/compiler/utils/arm/assembler_thumb2.h b/compiler/utils/arm/assembler_thumb2.h index ce310a4da8..2ca74fc863 100644 --- a/compiler/utils/arm/assembler_thumb2.h +++ b/compiler/utils/arm/assembler_thumb2.h @@ -250,6 +250,9 @@ class Thumb2Assembler FINAL : public ArmAssembler { void vcmpdz(DRegister dd, Condition cond = AL) OVERRIDE; void vmstat(Condition cond = AL) OVERRIDE; // VMRS APSR_nzcv, FPSCR + void vcntd(DRegister dd, DRegister dm) OVERRIDE; + void vpaddld(DRegister dd, DRegister dm, int32_t size, bool is_unsigned) OVERRIDE; + void vpushs(SRegister reg, int nregs, Condition cond = AL) OVERRIDE; void vpushd(DRegister reg, int nregs, Condition cond = AL) OVERRIDE; void vpops(SRegister reg, int nregs, Condition cond = AL) OVERRIDE; diff --git a/compiler/utils/arm/assembler_thumb2_test.cc b/compiler/utils/arm/assembler_thumb2_test.cc index b5cafcbf66..7f1dc49734 100644 --- a/compiler/utils/arm/assembler_thumb2_test.cc +++ b/compiler/utils/arm/assembler_thumb2_test.cc @@ -1380,4 +1380,43 @@ TEST_F(AssemblerThumb2Test, revsh) { DriverStr(expected, "revsh"); } +TEST_F(AssemblerThumb2Test, vcnt) { + // Different D register numbers are used here, to test register encoding. + // Source register number is encoded as M:Vm, destination register number is encoded as D:Vd, + // For source and destination registers which use D0..D15, the M bit and D bit should be 0. + // For source and destination registers which use D16..D32, the M bit and D bit should be 1. + __ vcntd(arm::D0, arm::D1); + __ vcntd(arm::D19, arm::D20); + __ vcntd(arm::D0, arm::D9); + __ vcntd(arm::D16, arm::D20); + + std::string expected = + "vcnt.8 d0, d1\n" + "vcnt.8 d19, d20\n" + "vcnt.8 d0, d9\n" + "vcnt.8 d16, d20\n"; + + DriverStr(expected, "vcnt"); +} + +TEST_F(AssemblerThumb2Test, vpaddl) { + // Different D register numbers are used here, to test register encoding. + // Source register number is encoded as M:Vm, destination register number is encoded as D:Vd, + // For source and destination registers which use D0..D15, the M bit and D bit should be 0. + // For source and destination registers which use D16..D32, the M bit and D bit should be 1. + // Different data types (signed and unsigned) are also tested. + __ vpaddld(arm::D0, arm::D0, 8, true); + __ vpaddld(arm::D20, arm::D20, 8, false); + __ vpaddld(arm::D0, arm::D20, 16, false); + __ vpaddld(arm::D20, arm::D0, 32, true); + + std::string expected = + "vpaddl.u8 d0, d0\n" + "vpaddl.s8 d20, d20\n" + "vpaddl.s16 d0, d20\n" + "vpaddl.u32 d20, d0\n"; + + DriverStr(expected, "vpaddl"); +} + } // namespace art diff --git a/disassembler/disassembler_arm.cc b/disassembler/disassembler_arm.cc index 286faf215a..1a3e3f5d24 100644 --- a/disassembler/disassembler_arm.cc +++ b/disassembler/disassembler_arm.cc @@ -1497,6 +1497,25 @@ size_t DisassemblerArm::DumpThumb32(std::ostream& os, const uint8_t* instr_ptr) } break; } + case 0x7B: case 0x7F: { + FpRegister d(instr, 12, 22); + FpRegister m(instr, 0, 5); + uint32_t sz = (instr >> 18) & 0x3; // Decode size bits. + uint32_t size = (sz == 0) ? 8 : sz << 4; + uint32_t opc2 = (instr >> 7) & 0xF; + uint32_t Q = (instr >> 6) & 1; + if (Q == 0 && opc2 == 0xA && size == 8) { // 1010, VCNT + opcode << "vcnt." << size; + args << d << ", " << m; + } else if (Q == 0 && (opc2 == 0x4 || opc2 == 0x5) && size <= 32) { // 010x, VPADDL + bool op = HasBitSet(instr, 7); + opcode << "vpaddl." << (op ? "u" : "s") << size; + args << d << ", " << m; + } else { + opcode << "UNKNOWN " << op2; + } + break; + } default: // more formats if ((op2 >> 4) == 2) { // 010xxxx // data processing (register) |