Commit 0dfd7bcd authored by rodolph.perfetta's avatar rodolph.perfetta Committed by Commit bot

Added a ReverseBits operator and used it to implement Ctz.

Let me know if this is not the right approach

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

Cr-Commit-Position: refs/heads/master@{#34028}
parent 00b919cb
......@@ -1947,6 +1947,16 @@ void Assembler::uxtah(Register dst, Register src1, Register src2, int rotate,
}
void Assembler::rbit(Register dst, Register src, Condition cond) {
// Instruction details available in ARM DDI 0406C.b, A8.8.144.
// cond(31-28) | 011011111111(27-16) | Rd(15-12) | 11110011(11-4) | Rm(3-0)
DCHECK(IsEnabled(ARMv7));
DCHECK(!dst.is(pc));
DCHECK(!src.is(pc));
emit(cond | 0x6FF * B16 | dst.code() * B12 | 0xF3 * B4 | src.code());
}
// Status register access instructions.
void Assembler::mrs(Register dst, SRegister s, Condition cond) {
DCHECK(!dst.is(pc));
......
......@@ -950,6 +950,9 @@ class Assembler : public AssemblerBase {
void uxtah(Register dst, Register src1, Register src2, int rotate = 0,
Condition cond = al);
// Reverse the bits in a register.
void rbit(Register dst, Register src, Condition cond = al);
// Status register access instructions
void mrs(Register dst, SRegister s, Condition cond = al);
......
......@@ -1188,7 +1188,13 @@ void Decoder::DecodeType3(Instruction* instr) {
}
}
} else {
UNREACHABLE();
// PU == 0b01, BW == 0b11, Bits(9, 6) != 0b0001
if ((instr->Bits(20, 16) == 0x1f) &&
(instr->Bits(11, 4) == 0xf3)) {
Format(instr, "rbit'cond 'rd, 'rm");
} else {
UNREACHABLE();
}
}
break;
}
......
......@@ -2920,7 +2920,15 @@ void Simulator::DecodeType3(Instruction* instr) {
}
}
} else {
UNIMPLEMENTED();
// PU == 0b01, BW == 0b11, Bits(9, 6) != 0b0001
if ((instr->Bits(20, 16) == 0x1f) &&
(instr->Bits(11, 4) == 0xf3)) {
// Rbit.
uint32_t rm_val = get_register(instr->RmValue());
set_register(rd, base::bits::ReverseBits(rm_val));
} else {
UNIMPLEMENTED();
}
}
break;
}
......
......@@ -1996,10 +1996,10 @@ void Simulator::VisitDataProcessing1Source(Instruction* instr) {
switch (instr->Mask(DataProcessing1SourceMask)) {
case RBIT_w:
set_wreg(dst, ReverseBits(wreg(src)));
set_wreg(dst, base::bits::ReverseBits(wreg(src)));
break;
case RBIT_x:
set_xreg(dst, ReverseBits(xreg(src)));
set_xreg(dst, base::bits::ReverseBits(xreg(src)));
break;
case REV16_w:
set_wreg(dst, ReverseBytes(wreg(src), 1));
......
......@@ -54,19 +54,6 @@ uint64_t LargestPowerOf2Divisor(uint64_t value);
int MaskToBit(uint64_t mask);
template <typename T>
T ReverseBits(T value) {
DCHECK((sizeof(value) == 1) || (sizeof(value) == 2) || (sizeof(value) == 4) ||
(sizeof(value) == 8));
T result = 0;
for (unsigned i = 0; i < (sizeof(value) * 8); i++) {
result = (result << 1) | (value & 1);
value >>= 1;
}
return result;
}
template <typename T>
T ReverseBytes(T value, int block_bytes_log2) {
DCHECK((sizeof(value) == 4) || (sizeof(value) == 8));
......
......@@ -92,6 +92,20 @@ inline unsigned CountLeadingZeros64(uint64_t value) {
}
// ReverseBits(value) returns |value| in reverse bit order.
template <typename T>
T ReverseBits(T value) {
DCHECK((sizeof(value) == 1) || (sizeof(value) == 2) || (sizeof(value) == 4) ||
(sizeof(value) == 8));
T result = 0;
for (unsigned i = 0; i < (sizeof(value) * 8); i++) {
result = (result << 1) | (value & 1);
value >>= 1;
}
return result;
}
// CountTrailingZeros32(value) returns the number of zero bits preceding the
// least significant 1 bit in |value| if |value| is non-zero, otherwise it
// returns 32.
......
......@@ -708,6 +708,12 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
i.InputInt32(2));
DCHECK_EQ(LeaveCC, i.OutputSBit());
break;
case kArmRbit: {
CpuFeatureScope scope(masm(), ARMv7);
__ rbit(i.OutputRegister(), i.InputRegister(0));
DCHECK_EQ(LeaveCC, i.OutputSBit());
break;
}
case kArmClz:
__ clz(i.OutputRegister(), i.InputRegister(0));
DCHECK_EQ(LeaveCC, i.OutputSBit());
......
......@@ -43,6 +43,7 @@ namespace compiler {
V(ArmUxtb) \
V(ArmUxth) \
V(ArmUxtab) \
V(ArmRbit) \
V(ArmUxtah) \
V(ArmVcmpF32) \
V(ArmVaddF32) \
......@@ -104,7 +105,6 @@ namespace compiler {
V(ArmPush) \
V(ArmPoke)
// Addressing modes represent the "shape" of inputs to an instruction.
// Many instructions support multiple addressing modes. Addressing modes
// are encoded into the InstructionCode of the instruction and tell the
......
......@@ -46,6 +46,7 @@ int InstructionScheduler::GetTargetInstructionFlags(
case kArmUxth:
case kArmUxtab:
case kArmUxtah:
case kArmRbit:
case kArmVcmpF32:
case kArmVaddF32:
case kArmVsubF32:
......
......@@ -760,6 +760,12 @@ void InstructionSelector::VisitWord32Clz(Node* node) {
void InstructionSelector::VisitWord32Ctz(Node* node) { UNREACHABLE(); }
void InstructionSelector::VisitWord32ReverseBits(Node* node) {
DCHECK(IsSupported(ARMv7));
VisitRR(this, kArmRbit, node);
}
void InstructionSelector::VisitWord32Popcnt(Node* node) { UNREACHABLE(); }
......@@ -1645,6 +1651,9 @@ InstructionSelector::SupportedMachineOperatorFlags() {
MachineOperatorBuilder::Flags flags =
MachineOperatorBuilder::kInt32DivIsSafe |
MachineOperatorBuilder::kUint32DivIsSafe;
if (CpuFeatures::IsSupported(ARMv7)) {
flags |= MachineOperatorBuilder::kWord32ReverseBits;
}
if (CpuFeatures::IsSupported(ARMv8)) {
flags |= MachineOperatorBuilder::kFloat32RoundDown |
MachineOperatorBuilder::kFloat64RoundDown |
......
......@@ -983,6 +983,12 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
case kArm64Clz32:
__ Clz(i.OutputRegister32(), i.InputRegister32(0));
break;
case kArm64Rbit:
__ Rbit(i.OutputRegister64(), i.InputRegister64(0));
break;
case kArm64Rbit32:
__ Rbit(i.OutputRegister32(), i.InputRegister32(0));
break;
case kArm64Cmp:
__ Cmp(i.InputOrZeroRegister64(0), i.InputOperand(1));
break;
......
......@@ -73,6 +73,8 @@ namespace compiler {
V(Arm64Ubfx32) \
V(Arm64Ubfiz32) \
V(Arm64Bfi) \
V(Arm64Rbit) \
V(Arm64Rbit32) \
V(Arm64TestAndBranch32) \
V(Arm64TestAndBranch) \
V(Arm64CompareAndBranch32) \
......@@ -149,7 +151,6 @@ namespace compiler {
V(Arm64Ldr) \
V(Arm64Str)
// Addressing modes represent the "shape" of inputs to an instruction.
// Many instructions support multiple addressing modes. Addressing modes
// are encoded into the InstructionCode of the instruction and tell the
......
......@@ -75,6 +75,8 @@ int InstructionScheduler::GetTargetInstructionFlags(
case kArm64Ubfx32:
case kArm64Ubfiz32:
case kArm64Bfi:
case kArm64Rbit:
case kArm64Rbit32:
case kArm64Float32Cmp:
case kArm64Float32Add:
case kArm64Float32Sub:
......
......@@ -974,6 +974,16 @@ void InstructionSelector::VisitWord32Ctz(Node* node) { UNREACHABLE(); }
void InstructionSelector::VisitWord64Ctz(Node* node) { UNREACHABLE(); }
void InstructionSelector::VisitWord32ReverseBits(Node* node) {
VisitRR(this, kArm64Rbit32, node);
}
void InstructionSelector::VisitWord64ReverseBits(Node* node) {
VisitRR(this, kArm64Rbit, node);
}
void InstructionSelector::VisitWord32Popcnt(Node* node) { UNREACHABLE(); }
......@@ -2219,7 +2229,9 @@ InstructionSelector::SupportedMachineOperatorFlags() {
MachineOperatorBuilder::kFloat64RoundTiesEven |
MachineOperatorBuilder::kWord32ShiftIsSafe |
MachineOperatorBuilder::kInt32DivIsSafe |
MachineOperatorBuilder::kUint32DivIsSafe;
MachineOperatorBuilder::kUint32DivIsSafe |
MachineOperatorBuilder::kWord32ReverseBits |
MachineOperatorBuilder::kWord64ReverseBits;
}
} // namespace compiler
......
......@@ -592,6 +592,9 @@ void InstructionSelector::VisitWord32Ctz(Node* node) {
}
void InstructionSelector::VisitWord32ReverseBits(Node* node) { UNREACHABLE(); }
void InstructionSelector::VisitWord32Popcnt(Node* node) {
IA32OperandGenerator g(this);
Emit(kIA32Popcnt, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
......
......@@ -863,6 +863,8 @@ void InstructionSelector::VisitNode(Node* node) {
return MarkAsWord32(node), VisitWord32Clz(node);
case IrOpcode::kWord32Ctz:
return MarkAsWord32(node), VisitWord32Ctz(node);
case IrOpcode::kWord32ReverseBits:
return MarkAsWord32(node), VisitWord32ReverseBits(node);
case IrOpcode::kWord32Popcnt:
return MarkAsWord32(node), VisitWord32Popcnt(node);
case IrOpcode::kWord64Popcnt:
......@@ -885,6 +887,8 @@ void InstructionSelector::VisitNode(Node* node) {
return MarkAsWord64(node), VisitWord64Clz(node);
case IrOpcode::kWord64Ctz:
return MarkAsWord64(node), VisitWord64Ctz(node);
case IrOpcode::kWord64ReverseBits:
return MarkAsWord64(node), VisitWord64ReverseBits(node);
case IrOpcode::kWord64Equal:
return VisitWord64Equal(node);
case IrOpcode::kInt32Add:
......@@ -1182,6 +1186,11 @@ void InstructionSelector::VisitWord64Clz(Node* node) { UNIMPLEMENTED(); }
void InstructionSelector::VisitWord64Ctz(Node* node) { UNIMPLEMENTED(); }
void InstructionSelector::VisitWord64ReverseBits(Node* node) {
UNIMPLEMENTED();
}
void InstructionSelector::VisitWord64Popcnt(Node* node) { UNIMPLEMENTED(); }
......
......@@ -200,6 +200,8 @@ MachineRepresentation StackSlotRepresentationOf(Operator const* op) {
#define PURE_OPTIONAL_OP_LIST(V) \
V(Word32Ctz, Operator::kNoProperties, 1, 0, 1) \
V(Word64Ctz, Operator::kNoProperties, 1, 0, 1) \
V(Word32ReverseBits, Operator::kNoProperties, 1, 0, 1) \
V(Word64ReverseBits, Operator::kNoProperties, 1, 0, 1) \
V(Word32Popcnt, Operator::kNoProperties, 1, 0, 1) \
V(Word64Popcnt, Operator::kNoProperties, 1, 0, 1) \
V(Float32Max, Operator::kNoProperties, 2, 0, 1) \
......@@ -216,7 +218,6 @@ MachineRepresentation StackSlotRepresentationOf(Operator const* op) {
V(Float32RoundTiesEven, Operator::kNoProperties, 1, 0, 1) \
V(Float64RoundTiesEven, Operator::kNoProperties, 1, 0, 1)
#define MACHINE_TYPE_LIST(V) \
V(Float32) \
V(Float64) \
......
......@@ -135,12 +135,15 @@ class MachineOperatorBuilder final : public ZoneObject {
kWord64Ctz = 1u << 17,
kWord32Popcnt = 1u << 18,
kWord64Popcnt = 1u << 19,
kWord32ReverseBits = 1u << 20,
kWord64ReverseBits = 1u << 21,
kAllOptionalOps = kFloat32Max | kFloat32Min | kFloat64Max | kFloat64Min |
kFloat32RoundDown | kFloat64RoundDown | kFloat32RoundUp |
kFloat64RoundUp | kFloat32RoundTruncate |
kFloat64RoundTruncate | kFloat64RoundTiesAway |
kFloat32RoundTiesEven | kFloat64RoundTiesEven |
kWord32Ctz | kWord64Ctz | kWord32Popcnt | kWord64Popcnt
kWord32Ctz | kWord64Ctz | kWord32Popcnt | kWord64Popcnt |
kWord32ReverseBits | kWord64ReverseBits
};
typedef base::Flags<Flag, unsigned> Flags;
......@@ -161,6 +164,8 @@ class MachineOperatorBuilder final : public ZoneObject {
const OptionalOperator Word32Ctz();
const OptionalOperator Word32Popcnt();
const OptionalOperator Word64Popcnt();
const OptionalOperator Word32ReverseBits();
const OptionalOperator Word64ReverseBits();
bool Word32ShiftIsSafe() const { return flags_ & kWord32ShiftIsSafe; }
const Operator* Word64And();
......
......@@ -401,6 +401,9 @@ void InstructionSelector::VisitWord32Clz(Node* node) {
}
void InstructionSelector::VisitWord32ReverseBits(Node* node) { UNREACHABLE(); }
void InstructionSelector::VisitWord32Ctz(Node* node) {
MipsOperandGenerator g(this);
Emit(kMipsCtz, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)));
......
......@@ -562,6 +562,12 @@ void InstructionSelector::VisitWord32Clz(Node* node) {
}
void InstructionSelector::VisitWord32ReverseBits(Node* node) { UNREACHABLE(); }
void InstructionSelector::VisitWord64ReverseBits(Node* node) { UNREACHABLE(); }
void InstructionSelector::VisitWord32Ctz(Node* node) {
Mips64OperandGenerator g(this);
Emit(kMips64Ctz, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)));
......
......@@ -237,6 +237,7 @@
V(Word32Ror) \
V(Word32Clz) \
V(Word32Ctz) \
V(Word32ReverseBits) \
V(Word32Popcnt) \
V(Word64Popcnt) \
V(Word64And) \
......@@ -248,6 +249,7 @@
V(Word64Ror) \
V(Word64Clz) \
V(Word64Ctz) \
V(Word64ReverseBits) \
V(Int32Add) \
V(Int32AddWithOverflow) \
V(Int32Sub) \
......
......@@ -838,6 +838,14 @@ void InstructionSelector::VisitWord64Ctz(Node* node) { UNREACHABLE(); }
#endif
void InstructionSelector::VisitWord32ReverseBits(Node* node) { UNREACHABLE(); }
#if V8_TARGET_ARCH_PPC64
void InstructionSelector::VisitWord64ReverseBits(Node* node) { UNREACHABLE(); }
#endif
void InstructionSelector::VisitInt32Add(Node* node) {
VisitBinop<Int32BinopMatcher>(this, node, kPPC_Add, kInt16Imm);
}
......
......@@ -1967,6 +1967,11 @@ Type* Typer::Visitor::TypeWord32Clz(Node* node) { return Type::Integral32(); }
Type* Typer::Visitor::TypeWord32Ctz(Node* node) { return Type::Integral32(); }
Type* Typer::Visitor::TypeWord32ReverseBits(Node* node) {
return Type::Integral32();
}
Type* Typer::Visitor::TypeWord32Popcnt(Node* node) {
return Type::Integral32();
}
......@@ -1999,6 +2004,11 @@ Type* Typer::Visitor::TypeWord64Clz(Node* node) { return Type::Internal(); }
Type* Typer::Visitor::TypeWord64Ctz(Node* node) { return Type::Internal(); }
Type* Typer::Visitor::TypeWord64ReverseBits(Node* node) {
return Type::Internal();
}
Type* Typer::Visitor::TypeWord64Popcnt(Node* node) { return Type::Internal(); }
......
......@@ -841,6 +841,7 @@ void Verifier::Visitor::Check(Node* node) {
case IrOpcode::kWord32Equal:
case IrOpcode::kWord32Clz:
case IrOpcode::kWord32Ctz:
case IrOpcode::kWord32ReverseBits:
case IrOpcode::kWord32Popcnt:
case IrOpcode::kWord64And:
case IrOpcode::kWord64Or:
......@@ -852,6 +853,7 @@ void Verifier::Visitor::Check(Node* node) {
case IrOpcode::kWord64Clz:
case IrOpcode::kWord64Popcnt:
case IrOpcode::kWord64Ctz:
case IrOpcode::kWord64ReverseBits:
case IrOpcode::kWord64Equal:
case IrOpcode::kInt32Add:
case IrOpcode::kInt32AddWithOverflow:
......
......@@ -728,6 +728,10 @@ Node* WasmGraphBuilder::Unop(wasm::WasmOpcode opcode, Node* input) {
if (m->Word32Ctz().IsSupported()) {
op = m->Word32Ctz().op();
break;
} else if (m->Word32ReverseBits().IsSupported()) {
Node* reversed = graph()->NewNode(m->Word32ReverseBits().op(), input);
Node* result = graph()->NewNode(m->Word32Clz(), reversed);
return result;
} else {
return BuildI32Ctz(input);
}
......@@ -855,6 +859,10 @@ Node* WasmGraphBuilder::Unop(wasm::WasmOpcode opcode, Node* input) {
if (m->Word64Ctz().IsSupported()) {
op = m->Word64Ctz().op();
break;
} else if (m->Word64ReverseBits().IsSupported()) {
Node* reversed = graph()->NewNode(m->Word64ReverseBits().op(), input);
Node* result = graph()->NewNode(m->Word64Clz(), reversed);
return result;
} else {
return BuildI64Ctz(input);
}
......
......@@ -622,6 +622,12 @@ void InstructionSelector::VisitWord32Ctz(Node* node) {
}
void InstructionSelector::VisitWord32ReverseBits(Node* node) { UNREACHABLE(); }
void InstructionSelector::VisitWord64ReverseBits(Node* node) { UNREACHABLE(); }
void InstructionSelector::VisitWord32Popcnt(Node* node) {
X64OperandGenerator g(this);
Emit(kX64Popcnt32, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
......
......@@ -550,6 +550,9 @@ void InstructionSelector::VisitWord32Clz(Node* node) {
void InstructionSelector::VisitWord32Ctz(Node* node) { UNREACHABLE(); }
void InstructionSelector::VisitWord32ReverseBits(Node* node) { UNREACHABLE(); }
void InstructionSelector::VisitWord32Popcnt(Node* node) {
X87OperandGenerator g(this);
Emit(kX87Popcnt, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
......
......@@ -29,6 +29,25 @@ TEST(RunInt32Add) {
}
TEST(RunWord32ReverseBits) {
BufferedRawMachineAssemblerTester<uint32_t> m(MachineType::Uint32());
if (!m.machine()->Word32ReverseBits().IsSupported()) {
// We can only test the operator if it exists on the testing platform.
return;
}
m.Return(m.AddNode(m.machine()->Word32ReverseBits().op(), m.Parameter(0)));
CHECK_EQ(uint32_t(0x00000000), m.Call(uint32_t(0x00000000)));
CHECK_EQ(uint32_t(0x12345678), m.Call(uint32_t(0x1e6a2c48)));
CHECK_EQ(uint32_t(0xfedcba09), m.Call(uint32_t(0x905d3b7f)));
CHECK_EQ(uint32_t(0x01010101), m.Call(uint32_t(0x80808080)));
CHECK_EQ(uint32_t(0x01020408), m.Call(uint32_t(0x10204080)));
CHECK_EQ(uint32_t(0xf0703010), m.Call(uint32_t(0x080c0e0f)));
CHECK_EQ(uint32_t(0x1f8d0a3a), m.Call(uint32_t(0x5c50b1f8)));
CHECK_EQ(uint32_t(0xffffffff), m.Call(uint32_t(0xffffffff)));
}
TEST(RunWord32Ctz) {
BufferedRawMachineAssemblerTester<int32_t> m(MachineType::Uint32());
if (!m.machine()->Word32Ctz().IsSupported()) {
......@@ -132,6 +151,25 @@ TEST(RunWord32Popcnt) {
#if V8_TARGET_ARCH_64_BIT
TEST(RunWord64ReverseBits) {
RawMachineAssemblerTester<uint64_t> m(MachineType::Uint64());
if (!m.machine()->Word64ReverseBits().IsSupported()) {
return;
}
m.Return(m.AddNode(m.machine()->Word64ReverseBits().op(), m.Parameter(0)));
CHECK_EQ(uint64_t(0x0000000000000000), m.Call(uint64_t(0x0000000000000000)));
CHECK_EQ(uint64_t(0x1234567890abcdef), m.Call(uint64_t(0xf7b3d5091e6a2c48)));
CHECK_EQ(uint64_t(0xfedcba0987654321), m.Call(uint64_t(0x84c2a6e1905d3b7f)));
CHECK_EQ(uint64_t(0x0101010101010101), m.Call(uint64_t(0x8080808080808080)));
CHECK_EQ(uint64_t(0x0102040803060c01), m.Call(uint64_t(0x803060c010204080)));
CHECK_EQ(uint64_t(0xf0703010e060200f), m.Call(uint64_t(0xf0040607080c0e0f)));
CHECK_EQ(uint64_t(0x2f8a6df01c21fa3b), m.Call(uint64_t(0xdc5f84380fb651f4)));
CHECK_EQ(uint64_t(0xffffffffffffffff), m.Call(uint64_t(0xffffffffffffffff)));
}
TEST(RunWord64Clz) {
BufferedRawMachineAssemblerTester<int32_t> m(MachineType::Uint64());
m.Return(m.Word64Clz(m.Parameter(0)));
......
......@@ -1819,6 +1819,55 @@ TEST(uxtah) {
}
#define TEST_RBIT(expected_, input_) \
t.input = input_; \
t.result = 0; \
dummy = CALL_GENERATED_CODE(isolate, f, &t, 0, 0, 0, 0); \
CHECK_EQ(expected_, t.result);
TEST(rbit) {
CcTest::InitializeVM();
Isolate* const isolate = CcTest::i_isolate();
HandleScope scope(isolate);
Assembler assm(isolate, nullptr, 0);
if (CpuFeatures::IsSupported(ARMv7)) {
CpuFeatureScope scope(&assm, ARMv7);
typedef struct {
uint32_t input;
uint32_t result;
} T;
T t;
__ ldr(r1, MemOperand(r0, offsetof(T, input)));
__ rbit(r1, r1);
__ str(r1, MemOperand(r0, offsetof(T, result)));
__ 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());
Object* dummy = NULL;
TEST_RBIT(0xffffffff, 0xffffffff);
TEST_RBIT(0x00000000, 0x00000000);
TEST_RBIT(0xffff0000, 0x0000ffff);
TEST_RBIT(0xff00ff00, 0x00ff00ff);
TEST_RBIT(0xf0f0f0f0, 0x0f0f0f0f);
TEST_RBIT(0x1e6a2c48, 0x12345678);
USE(dummy);
}
}
TEST(code_relative_offset) {
// Test extracting the offset of a label from the beginning of the code
// in a register.
......
......@@ -362,6 +362,7 @@ TEST(Type3) {
SET_UP();
if (CpuFeatures::IsSupported(ARMv7)) {
CpuFeatureScope scope(&assm, ARMv7);
COMPARE(ubfx(r0, r1, 5, 10),
"e7e902d1 ubfx r0, r1, #5, #10");
COMPARE(ubfx(r1, r0, 5, 10),
......@@ -437,6 +438,9 @@ TEST(Type3) {
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(rbit(r1, r2), "e6ff1f32 rbit r1, r2");
COMPARE(rbit(r10, ip), "e6ffaf3c rbit r10, ip");
}
COMPARE(smmla(r0, r1, r2, r3), "e7503211 smmla r0, r1, r2, r3");
......
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