Issue 137 lift bin ls (#145)

* Minor reformatting, re-enabling test of CCMP.

* Modified post-decoder of CCMP_n_CONDCMP_IMM, added more tests for it. Also added post-decoders, but NO tests for the register-register variant

* Fixes #144.

* Tests for LDP and STP. Decoder and semantics, but no tests for LDR and STR on the B, H, S, D, and Q vector sub-regs.

* Minor fix

* Minor fix, I think, to pre-index memops

* Minor simplifying code to pre- and post-index address operand handling
This commit is contained in:
Peter Goodman
2017-09-26 12:52:47 -04:00
committed by GitHub
parent d38e16867c
commit c743aa4f85
18 changed files with 34154 additions and 531 deletions
+1 -1
View File
@@ -14,7 +14,7 @@ We use the following nomenclature:
#### Choosing an instruction
Start by finding your instruction within the [XED tables document](/blob/xed/xed.txt).
Start by finding your instruction within the [XED tables document](XED/xed.txt).
We will use `AND` as a running example.
To start off, here are two entries from the tables document:
+1 -1
View File
@@ -31,7 +31,7 @@ designed to maintain the following properties.
- They should actively prevent certain compiler optimizations that obscure the
semantics of the translated machine code. For example, special
[tear fields](https://github.com/trailofbits/remill/blob/master/remill/Arch/X86/Runtime/State.h#L211)
[tear fields](https://github.com/trailofbits/remill/blob/master/remill/Arch/X86/Runtime/State.h#L327)
are introduced so as to prevent load and store coalescing, and preserve the
semantics that writes to logical units of data remain as such.
- They should have a uniform size across all architecture revisions and
+51 -23
View File
@@ -16,22 +16,22 @@ Below is a string representation of the data structures representing our example
```lisp
;; mov eax, 1
(X86_INSTR 8048098 5 MOV_GPRv_IMMv_32
(WRITE_OP (REG_32 EAX))
(READ_OP (IMM_32 1)))
(X86 8048098 5 (BYTES b8 01 00 00 00) MOV_GPRv_IMMv_32
(WRITE_OP (REG_32 EAX))
(READ_OP (IMM_32 1)))
;; push ebx
(X86_INSTR 804809d 1 PUSH_GPRv_50_32
(READ_OP (REG_32 EBX)))
(X86 804809d 1 (BYTES 53) PUSH_GPRv_50_32
(READ_OP (REG_32 EBX)))
;; mov ebx, dword ptr [esp + 8]
(X86_INSTR 804809e 4 MOV_GPRv_MEMv_32
(WRITE_OP (REG_32 EBX))
(READ_OP (ADDR_32 DWORD (SEGMENT SS_BASE) ESP + 0x8))))
(X86 804809e 4 (BYTES 8b 5c 24 08) MOV_GPRv_MEMv_32
(WRITE_OP (REG_32 EBX))
(READ_OP (ADDR_32 DWORD (SEGMENT SS_BASE) ESP + 0x8))))
;; int 0x80
(X86_INSTR 80480a2 2 INT_IMMb
(READ_OP (IMM_8 80)))
(X86 80480a2 2 (BYTES cd 80) INT_IMMb
(READ_OP (IMM_8 80)))
```
## From architecture-specific to architecture-neutral
@@ -42,7 +42,7 @@ The following is an example of the `__remill_basic_block` function for X86.
```C++
// Instructions will be lifted into clones of this function.
Memory *__remill_basic_block(addr_t curr_pc, State &state, Memory *memory) {
Memory *__remill_basic_block(State &state, addr_t curr_pc, Memory *memory) {
...
@@ -82,7 +82,7 @@ The decoder initialized the `name` field with `"EBX"`, and the lifter can look u
In spirit, the lifted code for the instructions in our running example looks like the following C++ code.
```C++
void __remill_sub_804b7a3(addr_t pc, State *state, Memory *memory) {
void __remill_sub_804b7a3(State *state, addr_t pc, Memory *memory) {
auto &EIP = state.gpr.rip.dword;
auto &EAX = state.gpr.rax.dword;
auto &EBX = state.gpr.rbx.dword;
@@ -105,8 +105,8 @@ void __remill_sub_804b7a3(addr_t pc, State *state, Memory *memory) {
// int 0x80
EIP += 2;
memory = INT_IMMb<I8>(memory, state, 0x80);
return __remill_interrupt_call(EIP, state, memory)
return __remill_async_hyper_call(state, EIP, memory)
}
```
@@ -116,9 +116,9 @@ The data structure of `mov ebx, dword [esp+0x8]` was:
```lisp
;; mov ebx, dword ptr [esp + 8]
(X86_INSTR 804809e 4 MOV_GPRv_MEMv_32
(WRITE_OP (REG_32 EBX))
(READ_OP (ADDR_32 DWORD (SEGMENT SS_BASE) ESP + 0x8))))
(X86 804809e 4 (BYTES 8b 5c 24 08) MOV_GPRv_MEMv_32
(WRITE_OP (REG_32 EBX))
(READ_OP (ADDR_32 DWORD (SEGMENT SS_BASE) ESP + 0x8))))
```
The semantics function implementing the `mov` instruction is:
@@ -144,9 +144,8 @@ You can head on over to the [how to add an instruction](ADD_AN_INSTRUCTION.md) d
The spiritual lifted code makes one function call per lifted instruction, where the actual implementation of each function can be arbitrarily complex. If we optimize the bitcode that Remill produces for our few example instructions, then what we get, if translated back to C++, looks like the following.
```C++
void __remill_sub_804b7a3(addr_t pc, State *state, Memory *memory) {
void __remill_sub_804b7a3(State &state, addr_t pc, Memory *memory) {
auto &EIP = state.gpr.rip.dword;
auto &EAX = state.gpr.rax.dword;
auto &EBX = state.gpr.rbx.dword;
@@ -168,7 +167,36 @@ void __remill_sub_804b7a3(addr_t pc, State *state, Memory *memory) {
EIP = pc + 12;
return __remill_async_hyper_call(EIP, state, memory)
return __remill_async_hyper_call(state, EIP, memory)
}
```
As LLVM bitcode, this looks like:
```llvm
; Function Attrs: noinline nounwind
define %struct.Memory* @__remill_sub_804b7a3(%struct.State* dereferenceable(2688) %state2, i32 %pc, %struct.Memory* %memory1) #0 {
%1 = getelementptr inbounds %struct.State, %struct.State* %state2, i64 0, i32 6, i32 33, i32 0, i32 0
%2 = getelementptr inbounds %struct.State, %struct.State* %state2, i64 0, i32 6, i32 1, i32 0, i32 0
%3 = getelementptr inbounds %struct.State, %struct.State* %state2, i64 0, i32 6, i32 3, i32 0, i32 0
%4 = getelementptr inbounds %struct.State, %struct.State* %state2, i64 0, i32 6, i32 13, i32 0, i32 0
store i32 1, i32* %2, align 4
%5 = load i32, i32* %3, align 4
%6 = load i32, i32* %4, align 8
%7 = add i32 %6, -4
%8 = tail call %struct.Memory* @__remill_write_memory_32(%struct.Memory* %memory1, i32 %7, i32 %5) #3
store i32 %7, i32* %4, align 4
%9 = add i32 %6, 4
%10 = tail call i32 @__remill_read_memory_32(%struct.Memory* %8, i32 %9) #3
store i32 %10, i32* %3, align 4
%11 = add i32 %pc, 12
store i32 %11, i32* %1, align 4
%12 = getelementptr inbounds %struct.State, %struct.State* %state2, i64 0, i32 0, i32 2
store i32 128, i32* %12, align 8
%13 = getelementptr inbounds %struct.State, %struct.State* %state2, i64 0, i32 0, i32 0
store i32 4, i32* %13, align 16
%14 = tail call %struct.Memory* @__remill_async_hyper_call(%struct.State* nonnull %state2, i32 %11, %struct.Memory* %8)
ret %struct.Memory* %14
}
```
@@ -188,11 +216,11 @@ The `__remill_async_hyper_call` instruction instructs the "runtime" that an expl
All Remill control-flow intrinsics and Remill lifted basic block functions share the same argument structure:
1. The program counter on entry to the lifted basic block.
2. A pointer to the `State` structure.
1. A pointer to the `State` structure.
2. The program counter on entry to the lifted basic block.
3. A pointer to the opaque `Memory` structure.
In the case of the `__remill_async_hyper_call`, the third argument, the program counter address, is computed to be the address following the `int 0x80` instruction.
In the case of the `__remill_async_hyper_call`, the second argument, the program counter address, is computed to be the address following the `int 0x80` instruction.
## Concluding remarks
+3 -4
View File
@@ -2,10 +2,9 @@
This document provides an index for topics relating to the design, implementation, and workings of Remill. Remill is an open-source, permissively licensed program. Persons interested in helping with the development of Remill should consult the "[How to contribute](CONTRIBUTING.md)" document.
Remill is a [static binary translator](https://en.wikipedia.org/wiki/Binary_translation#Static_binary_translation). It consumes [machine code instructions](https://en.wikipedia.org/wiki/Machine_code#Machine_code_instructions), and produces [LLVM bitcode](http://llvm.org/docs/LangRef.html) modules that accurately represents the semantics and operations performed by those instructions. These modules can be compiled back to machine code or analysed statically.
Remill is a [machine code](https://en.wikipedia.org/wiki/Machine_code#Machine_code_instructions) to [LLVM bitcode](http://llvm.org/docs/LangRef.html) [binary translation](https://en.wikipedia.org/wiki/Binary_translation) library. It provides APIs that enable other tools (e.g. [McSema](https://github.com/trailofbits/mcsema)) to lift the instructions of binary programs into equivalent LLVM bitcode. Remill can and has been used by both static and dynamic binary translators.
Remill's approach to instruction lifting is showcased in the "[How instructions are lifted](docs/LIFE_OF_AN_INSTRUCTION.md)" document. It shows how machine code bytes are decoded and mapped to C++ functions that implement the operational semantics of instructions. The "[How to add and test an instruction](ADD_AN_INSTRUCTION.md)"" document describes the formatting and structure of these C++ functions.
The operations, or semantics, of instructions are implemented using C++ functions. The "[How to add and test an instruction](ADD_AN_INSTRUCTION.md)"" document describes the formatting and structure of these C++ functions.
Remill does not consume binary programs directly. It depends on third-party tools like [Binary Ninja](http://binary.ninja) or [IDA Pro](https://www.hex-rays.com/products/ida) to disassemble binaries and produce "control-flow graph" (CFG) messages that tell Remill about [basic blocks](https://en.wikipedia.org/wiki/Basic_block) of machine code. The "[How to represent and format machine code](CFG_FORMAT.md)" document describes the structure and contents of the CFG file format.
Remill is designed with a narrow purpose: it only lifts machine code to LLVM bitcode.
+33455
View File
File diff suppressed because it is too large Load Diff
+71 -114
View File
@@ -592,10 +592,8 @@ static void AddPreIndexMemOp(Instruction &inst, Action action,
reg_op.size = reg_op.reg.size;
inst.operands.push_back(reg_op);
addr_op.action = Operand::kActionRead;
addr_op.addr.kind = Operand::Address::kAddressCalculation;
addr_op.addr.address_size = 64;
addr_op.addr.base_reg = Reg(kActionRead, kRegX, kUseAsAddress, base_reg);
addr_op.addr.displacement *= 2;
inst.operands.push_back(addr_op);
}
@@ -625,9 +623,8 @@ static void AddPostIndexMemOp(Instruction &inst, Action action,
reg_op.size = reg_op.reg.size;
inst.operands.push_back(reg_op);
addr_op.action = Operand::kActionRead;
addr_op.addr.kind = Operand::Address::kAddressCalculation;
addr_op.addr.address_size = 64;
addr_op.addr.base_reg = Reg(kActionRead, kRegX, kUseAsAddress, base_reg);
addr_op.addr.displacement = disp;
inst.operands.push_back(addr_op);
}
@@ -1460,7 +1457,15 @@ static const char *CondName(uint8_t cond) {
}
}
void SetConditionalFunctionName(uint8_t cond, Instruction &inst) {
void SetConditionalFunctionName(const InstData &data, Instruction &inst,
bool invert_condition=false) {
uint8_t cond = 0;
if (invert_condition) {
cond = data.cond ^ 1;
} else {
cond = data.cond;
}
std::stringstream ss;
ss << inst.function << "_" << CondName(cond);
inst.function = ss.str();
@@ -1470,7 +1475,7 @@ void SetConditionalFunctionName(uint8_t cond, Instruction &inst) {
bool TryDecodeB_ONLY_CONDBRANCH(const InstData &data, Instruction &inst) {
// Add in the condition to the isel name.
SetConditionalFunctionName(data.cond, inst);
SetConditionalFunctionName(data, inst);
DecodeConditionalBranch(inst, data.imm19.simm19 << 2);
return true;
}
@@ -1485,12 +1490,35 @@ bool TryDecodeSTRB_32_LDST_POS(const InstData &data, Instruction &inst) {
// LDRB <Wt>, [<Xn|SP>{, #<pimm>}]
bool TryDecodeLDRB_32_LDST_POS(const InstData &data, Instruction &inst) {
AddRegOperand(inst, kActionRead, kRegW, kUseAsValue, data.Rt);
AddRegOperand(inst, kActionWrite, kRegW, kUseAsValue, data.Rt);
AddBasePlusOffsetMemOp(inst, kActionRead, 8, data.Rn,
data.imm12.uimm);
return true;
}
// LDRB <Wt>, [<Xn|SP>, (<Wm>|<Xm>), <extend> {<amount>}]
bool TryDecodeLDRB_32B_LDST_REGOFF(const InstData &data, Instruction &inst) {
if (!(data.option & 0x2)) { // Sub-word index.
return false; // `if option<1> == '0' then UnallocatedEncoding();`
}
AddRegOperand(inst, kActionWrite, kRegW, kUseAsValue, data.Rt);
AddRegOperand(inst, kActionRead, kRegX, kUseAsAddress, data.Rn);
auto extend_type = static_cast<Extend>(data.option);
AddExtendRegOperand(inst, kRegX, kUseAsValue, data.Rm, extend_type, 64, 0);
return false;
}
// LDRB <Wt>, [<Xn|SP>, <Xm>{, LSL <amount>}]
bool TryDecodeLDRB_32BL_LDST_REGOFF(const InstData &data, Instruction &inst) {
if (!(data.option & 0x2)) { // Sub-word index.
return false; // `if option<1> == '0' then UnallocatedEncoding();`
}
AddRegOperand(inst, kActionWrite, kRegW, kUseAsValue, data.Rt);
AddRegOperand(inst, kActionRead, kRegX, kUseAsAddress, data.Rn);
AddShiftRegOperand(inst, kRegX, kUseAsValue, data.Rm, kShiftLSL, 0);
return false;
}
// STRH <Wt>, [<Xn|SP>{, #<pimm>}]
bool TryDecodeSTRH_32_LDST_POS(const InstData &data, Instruction &inst) {
AddRegOperand(inst, kActionRead, kRegW, kUseAsValue, data.Rt);
@@ -2113,37 +2141,21 @@ bool TryDecodeCLZ_64_DP_1SRC(const InstData &data, Instruction &inst) {
return true;
}
bool DecodeConditionalRegSelect(
const InstData &data,
Instruction &inst,
RegClass r_class,
int8_t n_regs, // signed because otherwise we underflow
bool invert_cond = false
) {
if (!(1 <= n_regs && n_regs <= 3)) {
LOG(ERROR) << "Number of registers in conditional select must be 1 <= x <= 3";
return false;
}
bool DecodeConditionalRegSelect(const InstData &data, Instruction &inst,
RegClass r_class, int n_regs,
bool invert_cond=false) {
CHECK(1 <= n_regs && n_regs <= 3);
AddRegOperand(inst, kActionWrite, r_class, kUseAsValue, data.Rd);
if (--n_regs > 0) {
AddRegOperand(inst, kActionRead, r_class, kUseAsValue, data.Rn);
if (--n_regs > 0) {
AddRegOperand(inst, kActionRead, r_class, kUseAsValue, data.Rn);
}
if (--n_regs > 0) {
AddRegOperand(inst, kActionRead, r_class, kUseAsValue, data.Rm);
if (--n_regs > 0) {
AddRegOperand(inst, kActionRead, r_class, kUseAsValue, data.Rm);
}
uint8_t cond;
if (invert_cond) {
cond = data.cond ^ 1;
} else {
cond = data.cond;
}
// Condition will be part of the isel, not an operand
SetConditionalFunctionName(cond, inst);
// Condition will be part of the isel, not an operand.
SetConditionalFunctionName(data, inst, invert_cond);
return true;
}
@@ -2167,28 +2179,6 @@ bool TryDecodeCSINC_64_CONDSEL(const InstData &data, Instruction &inst) {
return DecodeConditionalRegSelect(data, inst, kRegX, 3);
}
//////////////////////// DEPRICATED ALIAS
// CINC <Wd>, <Wn>, <cond>
bool TryDecodeCINC_CSINC_32_CONDSEL(const InstData &data, Instruction &inst) {
return false;
}
// CINC <Xd>, <Xn>, <cond>
bool TryDecodeCINC_CSINC_64_CONDSEL(const InstData &data, Instruction &inst) {
return false;
}
// CSET <Wd>, <cond>
bool TryDecodeCSET_CSINC_32_CONDSEL(const InstData &data, Instruction &inst) {
return false;
}
// CSET <Xd>, <cond>
bool TryDecodeCSET_CSINC_64_CONDSEL(const InstData &data, Instruction &inst) {
return false;
}
//////////////////////////////////////////
// CSINV <Wd>, <Wn>, <Wm>, <cond>
bool TryDecodeCSINV_32_CONDSEL(const InstData &data, Instruction &inst) {
return DecodeConditionalRegSelect(data, inst, kRegW, 3);
@@ -2199,28 +2189,6 @@ bool TryDecodeCSINV_64_CONDSEL(const InstData &data, Instruction &inst) {
return DecodeConditionalRegSelect(data, inst, kRegX, 3);
}
///////////////// DEPRICATED ALIAS
// CINV <Wd>, <Wn>, <cond>
bool TryDecodeCINV_CSINV_32_CONDSEL(const InstData &data, Instruction &inst) {
return false;
}
// CINV <Xd>, <Xn>, <cond>
bool TryDecodeCINV_CSINV_64_CONDSEL(const InstData &data, Instruction &inst) {
return false;
}
// CSETM <Wd>, <cond>
bool TryDecodeCSETM_CSINV_32_CONDSEL(const InstData &data, Instruction &inst) {
return false;
}
// CSETM <Xd>, <cond>
bool TryDecodeCSETM_CSINV_64_CONDSEL(const InstData &data, Instruction &inst) {
return false;
}
///////////////////////////////////
// CSNEG <Wd>, <Wn>, <Wm>, <cond>
bool TryDecodeCSNEG_32_CONDSEL(const InstData &data, Instruction &inst) {
return DecodeConditionalRegSelect(data, inst, kRegW, 3);
@@ -2233,50 +2201,39 @@ bool TryDecodeCSNEG_64_CONDSEL(const InstData &data, Instruction &inst) {
// CCMP <Wn>, #<imm>, #<nzcv>, <cond>
bool TryDecodeCCMP_32_CONDCMP_IMM(const InstData &data, Instruction &inst) {
DecodeConditionalRegSelect(data, inst, kRegW, 1);
SetConditionalFunctionName(data, inst);
AddRegOperand(inst, kActionRead, kRegW, kUseAsValue, data.Rn);
AddImmOperand(inst, data.imm5.uimm);
AddImmOperand(inst, data.nzcv);
return true;
}
// CCMP CCMP_64_condcmp_imm:
// 0 x nzcv 0
// 1 x nzcv 1
// 2 x nzcv 2
// 3 x nzcv 3
// 4 0 o3 0
// 5 x Rn 0
// 6 x Rn 1
// 7 x Rn 2
// 8 x Rn 3
// 9 x Rn 4
// 10 0 o2 0
// 11 1
// 12 x cond 0
// 13 x cond 1
// 14 x cond 2
// 15 x cond 3
// 16 x imm5 0
// 17 x imm5 1
// 18 x imm5 2
// 19 x imm5 3
// 20 x imm5 4
// 21 0
// 22 1
// 23 0
// 24 0
// 25 1
// 26 0
// 27 1
// 28 1
// 29 1 S 0
// 30 1 op 0
// 31 1 sf 0
// CCMP <Xn>, #<imm>, #<nzcv>, <cond>
bool TryDecodeCCMP_64_CONDCMP_IMM(const InstData &, Instruction &) {
return false;
bool TryDecodeCCMP_64_CONDCMP_IMM(const InstData &data, Instruction &inst) {
SetConditionalFunctionName(data, inst);
AddRegOperand(inst, kActionRead, kRegX, kUseAsValue, data.Rn);
AddImmOperand(inst, data.imm5.uimm);
AddImmOperand(inst, data.nzcv);
return true;
}
// CCMP <Wn>, <Wm>, #<nzcv>, <cond>
bool TryDecodeCCMP_32_CONDCMP_REG(const InstData &data, Instruction &inst) {
SetConditionalFunctionName(data, inst);
AddRegOperand(inst, kActionRead, kRegW, kUseAsValue, data.Rn);
AddRegOperand(inst, kActionRead, kRegW, kUseAsValue, data.Rm);
AddImmOperand(inst, data.nzcv);
return true;
}
// CCMP <Xn>, <Xm>, #<nzcv>, <cond>
bool TryDecodeCCMP_64_CONDCMP_REG(const InstData &data, Instruction &inst) {
SetConditionalFunctionName(data, inst);
AddRegOperand(inst, kActionRead, kRegX, kUseAsValue, data.Rn);
AddRegOperand(inst, kActionRead, kRegX, kUseAsValue, data.Rm);
AddImmOperand(inst, data.nzcv);
return true;
}
} // namespace aarch64
+39 -152
View File
@@ -19,6 +19,45 @@
namespace remill {
namespace aarch64 {
// CINC <Wd>, <Wn>, <cond>
bool TryDecodeCINC_CSINC_32_CONDSEL(const InstData &data, Instruction &inst) {
return false;
}
// CINC <Xd>, <Xn>, <cond>
bool TryDecodeCINC_CSINC_64_CONDSEL(const InstData &data, Instruction &inst) {
return false;
}
// CSET <Wd>, <cond>
bool TryDecodeCSET_CSINC_32_CONDSEL(const InstData &data, Instruction &inst) {
return false;
}
// CSET <Xd>, <cond>
bool TryDecodeCSET_CSINC_64_CONDSEL(const InstData &data, Instruction &inst) {
return false;
}
// CINV <Wd>, <Wn>, <cond>
bool TryDecodeCINV_CSINV_32_CONDSEL(const InstData &data, Instruction &inst) {
return false;
}
// CINV <Xd>, <Xn>, <cond>
bool TryDecodeCINV_CSINV_64_CONDSEL(const InstData &data, Instruction &inst) {
return false;
}
// CSETM <Wd>, <cond>
bool TryDecodeCSETM_CSINV_32_CONDSEL(const InstData &data, Instruction &inst) {
return false;
}
// CSETM <Xd>, <cond>
bool TryDecodeCSETM_CSINV_64_CONDSEL(const InstData &data, Instruction &inst) {
return false;
}
// UMULL <Xd>, <Wn>, <Wm>
bool TryDecodeUMULL_UMADDL_64WA_DP_3SRC(const InstData &, Instruction &) {
@@ -12119,82 +12158,6 @@ bool TryDecodeLDAXR_LR64_LDSTEXCL(const InstData &, Instruction &) {
return false;
}
// LDRB LDRB_32B_ldst_regoff:
// 0 x Rt 0
// 1 x Rt 1
// 2 x Rt 2
// 3 x Rt 3
// 4 x Rt 4
// 5 x Rn 0
// 6 x Rn 1
// 7 x Rn 2
// 8 x Rn 3
// 9 x Rn 4
// 10 0
// 11 1
// 12 x S 0
// 13 x option 0
// 14 x option 1
// 15 x option 2
// 16 x Rm 0
// 17 x Rm 1
// 18 x Rm 2
// 19 x Rm 3
// 20 x Rm 4
// 21 1
// 22 1 opc 0
// 23 0 opc 1
// 24 0
// 25 0
// 26 0 V 0
// 27 1
// 28 1
// 29 1
// 30 0 size 0
// 31 0 size 1
// LDRB <Wt>, [<Xn|SP>, (<Wm>|<Xm>), <extend> {<amount>}]
bool TryDecodeLDRB_32B_LDST_REGOFF(const InstData &, Instruction &) {
return false;
}
// LDRB LDRB_32BL_ldst_regoff:
// 0 x Rt 0
// 1 x Rt 1
// 2 x Rt 2
// 3 x Rt 3
// 4 x Rt 4
// 5 x Rn 0
// 6 x Rn 1
// 7 x Rn 2
// 8 x Rn 3
// 9 x Rn 4
// 10 0
// 11 1
// 12 x S 0
// 13 1 option 0
// 14 1 option 1
// 15 0 option 2
// 16 x Rm 0
// 17 x Rm 1
// 18 x Rm 2
// 19 x Rm 3
// 20 x Rm 4
// 21 1
// 22 1 opc 0
// 23 0 opc 1
// 24 0
// 25 0
// 26 0 V 0
// 27 1
// 28 1
// 29 1
// 30 0 size 0
// 31 0 size 1
// LDRB <Wt>, [<Xn|SP>, <Xm>{, LSL <amount>}]
bool TryDecodeLDRB_32BL_LDST_REGOFF(const InstData &, Instruction &) {
return false;
}
// UADALP UADALP_asimdmisc_P:
// 0 x Rd 0
// 1 x Rd 1
@@ -23482,82 +23445,6 @@ bool TryDecodeFMADD_D_FLOATDP3(const InstData &, Instruction &) {
return false;
}
// CCMP CCMP_32_condcmp_reg:
// 0 x nzcv 0
// 1 x nzcv 1
// 2 x nzcv 2
// 3 x nzcv 3
// 4 0 o3 0
// 5 x Rn 0
// 6 x Rn 1
// 7 x Rn 2
// 8 x Rn 3
// 9 x Rn 4
// 10 0 o2 0
// 11 0
// 12 x cond 0
// 13 x cond 1
// 14 x cond 2
// 15 x cond 3
// 16 x Rm 0
// 17 x Rm 1
// 18 x Rm 2
// 19 x Rm 3
// 20 x Rm 4
// 21 0
// 22 1
// 23 0
// 24 0
// 25 1
// 26 0
// 27 1
// 28 1
// 29 1 S 0
// 30 1 op 0
// 31 0 sf 0
// CCMP <Wn>, <Wm>, #<nzcv>, <cond>
bool TryDecodeCCMP_32_CONDCMP_REG(const InstData &, Instruction &) {
return false;
}
// CCMP CCMP_64_condcmp_reg:
// 0 x nzcv 0
// 1 x nzcv 1
// 2 x nzcv 2
// 3 x nzcv 3
// 4 0 o3 0
// 5 x Rn 0
// 6 x Rn 1
// 7 x Rn 2
// 8 x Rn 3
// 9 x Rn 4
// 10 0 o2 0
// 11 0
// 12 x cond 0
// 13 x cond 1
// 14 x cond 2
// 15 x cond 3
// 16 x Rm 0
// 17 x Rm 1
// 18 x Rm 2
// 19 x Rm 3
// 20 x Rm 4
// 21 0
// 22 1
// 23 0
// 24 0
// 25 1
// 26 0
// 27 1
// 28 1
// 29 1 S 0
// 30 1 op 0
// 31 1 sf 0
// CCMP <Xn>, <Xm>, #<nzcv>, <cond>
bool TryDecodeCCMP_64_CONDCMP_REG(const InstData &, Instruction &) {
return false;
}
// SRSHL SRSHL_asisdsame_only:
// 0 x Rd 0
// 1 x Rd 1
+24 -24
View File
@@ -2180,30 +2180,30 @@ const char * const kIFormName[] = {
};
static bool BFXPreferred(const InstData &data) {
if (data.imms.uimm < data.immr.uimm) {
return false;
}
if (data.imms.uimm == ((data.sf << 5) | 0x1FULL)) {
return false; // `if imms == sf:'11111' then return FALSE;`
}
if (!data.immr.uimm) {
// Must not match 32-bit UXT[BH] or SXT[BH].
if (!data.sf && (data.imms.uimm == 0x7ULL || data.imms.uimm == 0xFULL)) {
return false;
}
// Must not match 64-bit SXT[BHW].
auto uns = (data.opc >> 1) & 1;
if (data.sf && uns) {
if (data.imms.uimm == 0x7ULL || data.imms.uimm == 0xFULL ||
data.imms.uimm == 0x1FULL) {
return false;
}
}
}
return true;
}
//static bool BFXPreferred(const InstData &data) {
// if (data.imms.uimm < data.immr.uimm) {
// return false;
// }
// if (data.imms.uimm == ((data.sf << 5) | 0x1FULL)) {
// return false; // `if imms == sf:'11111' then return FALSE;`
// }
// if (!data.immr.uimm) {
// // Must not match 32-bit UXT[BH] or SXT[BH].
// if (!data.sf && (data.imms.uimm == 0x7ULL || data.imms.uimm == 0xFULL)) {
// return false;
// }
//
// // Must not match 64-bit SXT[BHW].
// auto uns = (data.opc >> 1) & 1;
// if (data.sf && uns) {
// if (data.imms.uimm == 0x7ULL || data.imms.uimm == 0xFULL ||
// data.imms.uimm == 0x1FULL) {
// return false;
// }
// }
// }
// return true;
//}
static bool TryExtractFRECPX_ASISDMISCFP16_R(InstData &inst, uint32_t bits);
+64 -157
View File
@@ -17,181 +17,84 @@
namespace {
template <bool (*check_cond)(const State &), typename D, typename S1, typename S2>
template <bool (*check_cond)(const State &), typename D,
typename S1, typename S2>
DEF_SEM(CSEL, D dst, S1 src1, S2 src2) {
auto val = check_cond(state) ? Read(src1) : Read(src2);
WriteZExt(dst, val);
return memory;
}
} // namespace
DEF_ISEL(CSEL_32_CONDSEL_GE) = CSEL<CondGE, R32W, R32, R32>;
DEF_ISEL(CSEL_32_CONDSEL_GT) = CSEL<CondGT, R32W, R32, R32>;
DEF_ISEL(CSEL_32_CONDSEL_LE) = CSEL<CondLE, R32W, R32, R32>;
DEF_ISEL(CSEL_32_CONDSEL_LT) = CSEL<CondLT, R32W, R32, R32>;
DEF_ISEL(CSEL_32_CONDSEL_EQ) = CSEL<CondEQ, R32W, R32, R32>;
DEF_ISEL(CSEL_32_CONDSEL_NE) = CSEL<CondNE, R32W, R32, R32>;
DEF_ISEL(CSEL_32_CONDSEL_CS) = CSEL<CondCS, R32W, R32, R32>;
DEF_ISEL(CSEL_32_CONDSEL_CC) = CSEL<CondCC, R32W, R32, R32>;
DEF_ISEL(CSEL_32_CONDSEL_MI) = CSEL<CondMI, R32W, R32, R32>;
DEF_ISEL(CSEL_32_CONDSEL_PL) = CSEL<CondPL, R32W, R32, R32>;
DEF_ISEL(CSEL_32_CONDSEL_VS) = CSEL<CondVS, R32W, R32, R32>;
DEF_ISEL(CSEL_32_CONDSEL_VC) = CSEL<CondVC, R32W, R32, R32>;
DEF_ISEL(CSEL_32_CONDSEL_HI) = CSEL<CondHI, R32W, R32, R32>;
DEF_ISEL(CSEL_32_CONDSEL_LS) = CSEL<CondLS, R32W, R32, R32>;
DEF_ISEL(CSEL_32_CONDSEL_AL) = CSEL<CondAL, R32W, R32, R32>;
DEF_ISEL(CSEL_64_CONDSEL_GE) = CSEL<CondGE, R64W, R64, R64>;
DEF_ISEL(CSEL_64_CONDSEL_GT) = CSEL<CondGT, R64W, R64, R64>;
DEF_ISEL(CSEL_64_CONDSEL_LE) = CSEL<CondLE, R64W, R64, R64>;
DEF_ISEL(CSEL_64_CONDSEL_LT) = CSEL<CondLT, R64W, R64, R64>;
DEF_ISEL(CSEL_64_CONDSEL_EQ) = CSEL<CondEQ, R64W, R64, R64>;
DEF_ISEL(CSEL_64_CONDSEL_NE) = CSEL<CondNE, R64W, R64, R64>;
DEF_ISEL(CSEL_64_CONDSEL_CS) = CSEL<CondCS, R64W, R64, R64>;
DEF_ISEL(CSEL_64_CONDSEL_CC) = CSEL<CondCC, R64W, R64, R64>;
DEF_ISEL(CSEL_64_CONDSEL_MI) = CSEL<CondMI, R64W, R64, R64>;
DEF_ISEL(CSEL_64_CONDSEL_PL) = CSEL<CondPL, R64W, R64, R64>;
DEF_ISEL(CSEL_64_CONDSEL_VS) = CSEL<CondVS, R64W, R64, R64>;
DEF_ISEL(CSEL_64_CONDSEL_VC) = CSEL<CondVC, R64W, R64, R64>;
DEF_ISEL(CSEL_64_CONDSEL_HI) = CSEL<CondHI, R64W, R64, R64>;
DEF_ISEL(CSEL_64_CONDSEL_LS) = CSEL<CondLS, R64W, R64, R64>;
DEF_ISEL(CSEL_64_CONDSEL_AL) = CSEL<CondAL, R64W, R64, R64>;
namespace {
template <bool (*check_cond)(const State &), typename D, typename S1, typename S2>
DEF_SEM(CSNEG, D dst, S1 src1, S2 src2) {
auto val = check_cond(state) ? Read(src1) : UAdd(UNot(Read(src2)), ZExtTo<S2>(1));
WriteZExt(dst, val);
return memory;
}
} // namespace
DEF_ISEL(CSNEG_32_CONDSEL_GE) = CSNEG<CondGE, R32W, R32, R32>;
DEF_ISEL(CSNEG_32_CONDSEL_GT) = CSNEG<CondGT, R32W, R32, R32>;
DEF_ISEL(CSNEG_32_CONDSEL_LE) = CSNEG<CondLE, R32W, R32, R32>;
DEF_ISEL(CSNEG_32_CONDSEL_LT) = CSNEG<CondLT, R32W, R32, R32>;
DEF_ISEL(CSNEG_32_CONDSEL_EQ) = CSNEG<CondEQ, R32W, R32, R32>;
DEF_ISEL(CSNEG_32_CONDSEL_NE) = CSNEG<CondNE, R32W, R32, R32>;
DEF_ISEL(CSNEG_32_CONDSEL_CS) = CSNEG<CondCS, R32W, R32, R32>;
DEF_ISEL(CSNEG_32_CONDSEL_CC) = CSNEG<CondCC, R32W, R32, R32>;
DEF_ISEL(CSNEG_32_CONDSEL_MI) = CSNEG<CondMI, R32W, R32, R32>;
DEF_ISEL(CSNEG_32_CONDSEL_PL) = CSNEG<CondPL, R32W, R32, R32>;
DEF_ISEL(CSNEG_32_CONDSEL_VS) = CSNEG<CondVS, R32W, R32, R32>;
DEF_ISEL(CSNEG_32_CONDSEL_VC) = CSNEG<CondVC, R32W, R32, R32>;
DEF_ISEL(CSNEG_32_CONDSEL_HI) = CSNEG<CondHI, R32W, R32, R32>;
DEF_ISEL(CSNEG_32_CONDSEL_LS) = CSNEG<CondLS, R32W, R32, R32>;
DEF_ISEL(CSNEG_32_CONDSEL_AL) = CSNEG<CondAL, R32W, R32, R32>;
DEF_ISEL(CSNEG_64_CONDSEL_GE) = CSNEG<CondGE, R64W, R64, R64>;
DEF_ISEL(CSNEG_64_CONDSEL_GT) = CSNEG<CondGT, R64W, R64, R64>;
DEF_ISEL(CSNEG_64_CONDSEL_LE) = CSNEG<CondLE, R64W, R64, R64>;
DEF_ISEL(CSNEG_64_CONDSEL_LT) = CSNEG<CondLT, R64W, R64, R64>;
DEF_ISEL(CSNEG_64_CONDSEL_EQ) = CSNEG<CondEQ, R64W, R64, R64>;
DEF_ISEL(CSNEG_64_CONDSEL_NE) = CSNEG<CondNE, R64W, R64, R64>;
DEF_ISEL(CSNEG_64_CONDSEL_CS) = CSNEG<CondCS, R64W, R64, R64>;
DEF_ISEL(CSNEG_64_CONDSEL_CC) = CSNEG<CondCC, R64W, R64, R64>;
DEF_ISEL(CSNEG_64_CONDSEL_MI) = CSNEG<CondMI, R64W, R64, R64>;
DEF_ISEL(CSNEG_64_CONDSEL_PL) = CSNEG<CondPL, R64W, R64, R64>;
DEF_ISEL(CSNEG_64_CONDSEL_VS) = CSNEG<CondVS, R64W, R64, R64>;
DEF_ISEL(CSNEG_64_CONDSEL_VC) = CSNEG<CondVC, R64W, R64, R64>;
DEF_ISEL(CSNEG_64_CONDSEL_HI) = CSNEG<CondHI, R64W, R64, R64>;
DEF_ISEL(CSNEG_64_CONDSEL_LS) = CSNEG<CondLS, R64W, R64, R64>;
DEF_ISEL(CSNEG_64_CONDSEL_AL) = CSNEG<CondAL, R64W, R64, R64>;
namespace {
template <bool (*check_cond)(const State &), typename D, typename S1, typename S2>
DEF_SEM(CSINC, D dst, S1 src1, S2 src2) {
auto val = check_cond(state)? Read(src1) : UAdd(Read(src2), 1);
auto val = check_cond(state) ? Read(src1) : Read(src2);
WriteZExt(dst, val);
return memory;
}
} // namespace
DEF_ISEL(CSINC_32_CONDSEL_GE) = CSINC<CondGE, R32W, R32, R32>;
DEF_ISEL(CSINC_32_CONDSEL_GT) = CSINC<CondGT, R32W, R32, R32>;
DEF_ISEL(CSINC_32_CONDSEL_LE) = CSINC<CondLE, R32W, R32, R32>;
DEF_ISEL(CSINC_32_CONDSEL_LT) = CSINC<CondLT, R32W, R32, R32>;
DEF_ISEL(CSINC_32_CONDSEL_EQ) = CSINC<CondEQ, R32W, R32, R32>;
DEF_ISEL(CSINC_32_CONDSEL_NE) = CSINC<CondNE, R32W, R32, R32>;
DEF_ISEL(CSINC_32_CONDSEL_CS) = CSINC<CondCS, R32W, R32, R32>;
DEF_ISEL(CSINC_32_CONDSEL_CC) = CSINC<CondCC, R32W, R32, R32>;
DEF_ISEL(CSINC_32_CONDSEL_MI) = CSINC<CondMI, R32W, R32, R32>;
DEF_ISEL(CSINC_32_CONDSEL_PL) = CSINC<CondPL, R32W, R32, R32>;
DEF_ISEL(CSINC_32_CONDSEL_VS) = CSINC<CondVS, R32W, R32, R32>;
DEF_ISEL(CSINC_32_CONDSEL_VC) = CSINC<CondVC, R32W, R32, R32>;
DEF_ISEL(CSINC_32_CONDSEL_HI) = CSINC<CondHI, R32W, R32, R32>;
DEF_ISEL(CSINC_32_CONDSEL_LS) = CSINC<CondLS, R32W, R32, R32>;
DEF_ISEL(CSINC_32_CONDSEL_AL) = CSINC<CondAL, R32W, R32, R32>;
DEF_ISEL(CSINC_64_CONDSEL_GE) = CSINC<CondGE, R64W, R64, R64>;
DEF_ISEL(CSINC_64_CONDSEL_GT) = CSINC<CondGT, R64W, R64, R64>;
DEF_ISEL(CSINC_64_CONDSEL_LE) = CSINC<CondLE, R64W, R64, R64>;
DEF_ISEL(CSINC_64_CONDSEL_LT) = CSINC<CondLT, R64W, R64, R64>;
DEF_ISEL(CSINC_64_CONDSEL_EQ) = CSINC<CondEQ, R64W, R64, R64>;
DEF_ISEL(CSINC_64_CONDSEL_NE) = CSINC<CondNE, R64W, R64, R64>;
DEF_ISEL(CSINC_64_CONDSEL_CS) = CSINC<CondCS, R64W, R64, R64>;
DEF_ISEL(CSINC_64_CONDSEL_CC) = CSINC<CondCC, R64W, R64, R64>;
DEF_ISEL(CSINC_64_CONDSEL_MI) = CSINC<CondMI, R64W, R64, R64>;
DEF_ISEL(CSINC_64_CONDSEL_PL) = CSINC<CondPL, R64W, R64, R64>;
DEF_ISEL(CSINC_64_CONDSEL_VS) = CSINC<CondVS, R64W, R64, R64>;
DEF_ISEL(CSINC_64_CONDSEL_VC) = CSINC<CondVC, R64W, R64, R64>;
DEF_ISEL(CSINC_64_CONDSEL_HI) = CSINC<CondHI, R64W, R64, R64>;
DEF_ISEL(CSINC_64_CONDSEL_LS) = CSINC<CondLS, R64W, R64, R64>;
DEF_ISEL(CSINC_64_CONDSEL_AL) = CSINC<CondAL, R64W, R64, R64>;
#define DEF_COND_ISEL(isel, sem, ...) \
DEF_ISEL(isel ## _GE) = sem<CondGE, __VA_ARGS__>; \
DEF_ISEL(isel ## _GT) = sem<CondGT, __VA_ARGS__>; \
DEF_ISEL(isel ## _LE) = sem<CondLE, __VA_ARGS__>; \
DEF_ISEL(isel ## _LT) = sem<CondLT, __VA_ARGS__>; \
DEF_ISEL(isel ## _EQ) = sem<CondEQ, __VA_ARGS__>; \
DEF_ISEL(isel ## _NE) = sem<CondNE, __VA_ARGS__>; \
DEF_ISEL(isel ## _CS) = sem<CondCS, __VA_ARGS__>; \
DEF_ISEL(isel ## _CC) = sem<CondCC, __VA_ARGS__>; \
DEF_ISEL(isel ## _MI) = sem<CondMI, __VA_ARGS__>; \
DEF_ISEL(isel ## _PL) = sem<CondPL, __VA_ARGS__>; \
DEF_ISEL(isel ## _VS) = sem<CondVS, __VA_ARGS__>; \
DEF_ISEL(isel ## _VC) = sem<CondVC, __VA_ARGS__>; \
DEF_ISEL(isel ## _HI) = sem<CondHI, __VA_ARGS__>; \
DEF_ISEL(isel ## _LS) = sem<CondLS, __VA_ARGS__>; \
DEF_ISEL(isel ## _AL) = sem<CondAL, __VA_ARGS__>;
DEF_COND_ISEL(CSEL_32_CONDSEL, CSEL, R32W, R32, R32)
DEF_COND_ISEL(CSEL_64_CONDSEL, CSEL, R64W, R64, R64)
namespace {
template <bool (*check_cond)(const State &), typename D, typename S1, typename S2>
DEF_SEM(CSINV, D dst, S1 src1, S2 src2) {
auto val = check_cond(state)? Read(src1) : UNot(Read(src2));
WriteZExt(dst, val);
template <bool (*check_cond)(const State &), typename D,
typename S1, typename S2>
DEF_SEM(CSNEG, D dst, S1 src1, S2 src2) {
WriteZExt(dst, Select(check_cond(state),
Read(src1),
UAdd(UNot(Read(src2)), ZExtTo<S2>(1))));
return memory;
}
} // namespace
DEF_ISEL(CSINV_32_CONDSEL_GE) = CSINV<CondGE, R32W, R32, R32>;
DEF_ISEL(CSINV_32_CONDSEL_GT) = CSINV<CondGT, R32W, R32, R32>;
DEF_ISEL(CSINV_32_CONDSEL_LE) = CSINV<CondLE, R32W, R32, R32>;
DEF_ISEL(CSINV_32_CONDSEL_LT) = CSINV<CondLT, R32W, R32, R32>;
DEF_ISEL(CSINV_32_CONDSEL_EQ) = CSINV<CondEQ, R32W, R32, R32>;
DEF_ISEL(CSINV_32_CONDSEL_NE) = CSINV<CondNE, R32W, R32, R32>;
DEF_ISEL(CSINV_32_CONDSEL_CS) = CSINV<CondCS, R32W, R32, R32>;
DEF_ISEL(CSINV_32_CONDSEL_CC) = CSINV<CondCC, R32W, R32, R32>;
DEF_ISEL(CSINV_32_CONDSEL_MI) = CSINV<CondMI, R32W, R32, R32>;
DEF_ISEL(CSINV_32_CONDSEL_PL) = CSINV<CondPL, R32W, R32, R32>;
DEF_ISEL(CSINV_32_CONDSEL_VS) = CSINV<CondVS, R32W, R32, R32>;
DEF_ISEL(CSINV_32_CONDSEL_VC) = CSINV<CondVC, R32W, R32, R32>;
DEF_ISEL(CSINV_32_CONDSEL_HI) = CSINV<CondHI, R32W, R32, R32>;
DEF_ISEL(CSINV_32_CONDSEL_LS) = CSINV<CondLS, R32W, R32, R32>;
DEF_ISEL(CSINV_32_CONDSEL_AL) = CSINV<CondAL, R32W, R32, R32>;
} // namespace
DEF_ISEL(CSINV_64_CONDSEL_GE) = CSINV<CondGE, R64W, R64, R64>;
DEF_ISEL(CSINV_64_CONDSEL_GT) = CSINV<CondGT, R64W, R64, R64>;
DEF_ISEL(CSINV_64_CONDSEL_LE) = CSINV<CondLE, R64W, R64, R64>;
DEF_ISEL(CSINV_64_CONDSEL_LT) = CSINV<CondLT, R64W, R64, R64>;
DEF_ISEL(CSINV_64_CONDSEL_EQ) = CSINV<CondEQ, R64W, R64, R64>;
DEF_ISEL(CSINV_64_CONDSEL_NE) = CSINV<CondNE, R64W, R64, R64>;
DEF_ISEL(CSINV_64_CONDSEL_CS) = CSINV<CondCS, R64W, R64, R64>;
DEF_ISEL(CSINV_64_CONDSEL_CC) = CSINV<CondCC, R64W, R64, R64>;
DEF_ISEL(CSINV_64_CONDSEL_MI) = CSINV<CondMI, R64W, R64, R64>;
DEF_ISEL(CSINV_64_CONDSEL_PL) = CSINV<CondPL, R64W, R64, R64>;
DEF_ISEL(CSINV_64_CONDSEL_VS) = CSINV<CondVS, R64W, R64, R64>;
DEF_ISEL(CSINV_64_CONDSEL_VC) = CSINV<CondVC, R64W, R64, R64>;
DEF_ISEL(CSINV_64_CONDSEL_HI) = CSINV<CondHI, R64W, R64, R64>;
DEF_ISEL(CSINV_64_CONDSEL_LS) = CSINV<CondLS, R64W, R64, R64>;
DEF_ISEL(CSINV_64_CONDSEL_AL) = CSINV<CondAL, R64W, R64, R64>;
DEF_COND_ISEL(CSNEG_32_CONDSEL, CSNEG, R32W, R32, R32)
DEF_COND_ISEL(CSNEG_64_CONDSEL, CSNEG, R64W, R64, R64)
namespace {
template <bool (*check_cond)(const State &), typename D,
typename S1, typename S2>
DEF_SEM(CSINC, D dst, S1 src1, S2 src2) {
WriteZExt(dst, Select(check_cond(state), Read(src1), UAdd(Read(src2), 1)));
return memory;
}
} // namespace
DEF_COND_ISEL(CSINC_32_CONDSEL, CSINC, R32W, R32, R32)
DEF_COND_ISEL(CSINC_64_CONDSEL, CSINC, R64W, R64, R64)
namespace {
template <bool (*check_cond)(const State &), typename D,
typename S1, typename S2>
DEF_SEM(CSINV, D dst, S1 src1, S2 src2) {
WriteZExt(dst, Select(check_cond(state), Read(src1), UNot(Read(src2))));
return memory;
}
} // namespace
DEF_COND_ISEL(CSINV_32_CONDSEL, CSINV, R32W, R32, R32)
DEF_COND_ISEL(CSINV_64_CONDSEL, CSINV, R64W, R64, R64)
namespace {
template <bool (*check_cond)(const State &), typename S1, typename S2>
DEF_SEM(CCMP, S1 src1, S2 src2, S2 nzcv) {
using T = typename BaseType<S1>::BT;
if (check_cond(state)) {
//
// (void) AddWithCarryNZCV(state, Read(src1), UNot(Read(src2)), T(1));
return memory;
(void) AddWithCarryNZCV(state, Read(src1), UNot(Read(src2)), T(1));
} else {
auto nzcv_val = Read(nzcv);
FLAG_V = UCmpNeq(UAnd(nzcv_val, T(1)), T(0));
@@ -201,6 +104,10 @@ DEF_SEM(CCMP, S1 src1, S2 src2, S2 nzcv) {
}
return memory;
}
} // namespace
} // namespace
DEF_ISEL(CCMP_32_CONDCMP_IMM_EQ) = CCMP<CondEQ, R32, I32>;
DEF_COND_ISEL(CCMP_32_CONDCMP_IMM, CCMP, R32, I32)
DEF_COND_ISEL(CCMP_64_CONDCMP_IMM, CCMP, R64, I64)
DEF_COND_ISEL(CCMP_32_CONDCMP_REG, CCMP, R32, R32)
DEF_COND_ISEL(CCMP_64_CONDCMP_REG, CCMP, R64, R64)
+18 -19
View File
@@ -36,6 +36,18 @@ DEF_SEM(StorePairUpdateIndex64, R64 src1, R64 src2, MV128W dst_mem,
return memory;
}
DEF_SEM(StorePair32, R32 src1, R32 src2, MV64W dst) {
uint32v2_t vec = {};
UWriteV32(dst, UInsertV32(UInsertV32(vec, 0, Read(src1)), 1, Read(src2)));
return memory;
}
DEF_SEM(StorePair64, R64 src1, R64 src2, MV128W dst) {
uint64v2_t vec = {};
UWriteV64(dst, UInsertV64(UInsertV64(vec, 0, Read(src1)), 1, Read(src2)));
return memory;
}
} // namespace
DEF_ISEL(STP_32_LDSTPAIR_PRE) = StorePairUpdateIndex32;
@@ -44,6 +56,9 @@ DEF_ISEL(STP_32_LDSTPAIR_POST) = StorePairUpdateIndex32;
DEF_ISEL(STP_64_LDSTPAIR_PRE) = StorePairUpdateIndex64;
DEF_ISEL(STP_64_LDSTPAIR_POST) = StorePairUpdateIndex64;
DEF_ISEL(STP_32_LDSTPAIR_OFF) = StorePair32;
DEF_ISEL(STP_64_LDSTPAIR_OFF) = StorePair64;
namespace {
template <typename S, typename D>
@@ -84,25 +99,6 @@ DEF_ISEL(STR_64_LDST_REGOFF) = STR_BASE_OFFSET<R64, M64W>;
namespace {
DEF_SEM(StorePair32, R32 src1, R32 src2, MV64W dst) {
uint32v2_t vec = {};
UWriteV32(dst, UInsertV32(UInsertV32(vec, 0, Read(src1)), 1, Read(src2)));
return memory;
}
DEF_SEM(StorePair64, R64 src1, R64 src2, MV128W dst) {
uint64v2_t vec = {};
UWriteV64(dst, UInsertV64(UInsertV64(vec, 0, Read(src1)), 1, Read(src2)));
return memory;
}
} // namespace
DEF_ISEL(STP_32_LDSTPAIR_OFF) = StorePair32;
DEF_ISEL(STP_64_LDSTPAIR_OFF) = StorePair64;
namespace {
DEF_SEM(LoadPairUpdateIndex32, R32W dst1, R32W dst2, MV64 src_mem,
R64W dst_reg, ADDR next_addr) {
auto vec = UReadV32(src_mem);
@@ -170,6 +166,9 @@ DEF_ISEL(LDR_32_LDST_POS) = Load<R32W, M32>;
DEF_ISEL(LDR_64_LDST_POS) = Load<R64W, M64>;
DEF_ISEL(LDRB_32_LDST_POS) = Load<R8W, M8>;
DEF_ISEL(LDRB_32B_LDST_REGOFF) = LDR_BASE_OFFSET<R8W, M8>;
DEF_ISEL(LDRB_32BL_LDST_REGOFF) = LDR_BASE_OFFSET<R8W, M8>;
DEF_ISEL(LDR_32_LOADLIT) = Load<R32W, M32>;
DEF_ISEL(LDR_64_LOADLIT) = Load<R64W, M64>;
+180 -34
View File
@@ -14,42 +14,188 @@
* limitations under the License.
*/
TEST_BEGIN(CCMP_32_CONDCMP_IMM_EQ, ccmp_w0_eq_1, 1)
TEST_BEGIN(CCMP_32_CONDCMP_IMM_GE, ccmp_w0_ge_11, 1)
TEST_INPUTS(
0x11
)
ccmp w0, #0x11, #0x0, eq
0,
1,
0x10,
0x11,
0x12,
0x0fffffff,
0x7fffffff,
0xffffffff)
ccmp ARG1_32, #0x11, #0x0, ge
TEST_END
// TEST_BEGIN(CCMP_32_CONDCMP_IMM_EQ, ccmp_32_cmpne_eq_11_c, 1)
// TEST_INPUTS(
// 0x11,
// 0x0,
// 0x1,
// 0xf,
// 0x7,
// 0xffffff
// )
// mov w9, #0xdead
// ccmp w0, #0x11, #0xc, eq
// b.eq 99f
// mov w9, #0xface
// 99:
// TEST_END
TEST_BEGIN(CCMP_32_CONDCMP_IMM_GT, ccmp_w0_gt_11, 1)
TEST_INPUTS(
0,
1,
0x10,
0x11,
0x12,
0x0fffffff,
0x7fffffff,
0xffffffff)
ccmp ARG1_32, #0x11, #0x0, gt
TEST_END
// TEST_BEGIN(CCMP_32_CONDCMP_IMM_HI, ccmp_32_cmpeq_hi_11_c, 1)
// TEST_INPUTS(
// 0x11,
// 0x0,
// 0x1,
// 0xf,
// 0x7,
// 0xffffff
// )
// mov w9, #0xdead
// ccmp w0, #0x11, #0xc, hi
// b.eq 99f
// mov w9, #0xface
// 99:
// TEST_END
TEST_BEGIN(CCMP_32_CONDCMP_IMM_LE, ccmp_w0_le_11, 1)
TEST_INPUTS(
0,
1,
0x10,
0x11,
0x12,
0x0fffffff,
0x7fffffff,
0xffffffff)
ccmp ARG1_32, #0x11, #0x0, le
TEST_END
TEST_BEGIN(CCMP_32_CONDCMP_IMM_LT, ccmp_w0_lt_11, 1)
TEST_INPUTS(
0,
1,
0x10,
0x11,
0x12,
0x0fffffff,
0x7fffffff,
0xffffffff)
ccmp ARG1_32, #0x11, #0x0, lt
TEST_END
TEST_BEGIN(CCMP_32_CONDCMP_IMM_EQ, ccmp_w0_eq_11, 1)
TEST_INPUTS(
0,
1,
0x10,
0x11,
0x12,
0x0fffffff,
0x7fffffff,
0xffffffff)
ccmp ARG1_32, #0x11, #0x0, eq
TEST_END
TEST_BEGIN(CCMP_32_CONDCMP_IMM_NE, ccmp_w0_ne_11, 1)
TEST_INPUTS(
0,
1,
0x10,
0x11,
0x12,
0x0fffffff,
0x7fffffff,
0xffffffff)
ccmp ARG1_32, #0x11, #0x0, ne
TEST_END
TEST_BEGIN(CCMP_32_CONDCMP_IMM_CS, ccmp_w0_cs_11, 1)
TEST_INPUTS(
0,
1,
0x10,
0x11,
0x12,
0x0fffffff,
0x7fffffff,
0xffffffff)
ccmp ARG1_32, #0x11, #0x0, cs
TEST_END
/* TODO(pag): Are more necessary? */
TEST_BEGIN(CCMP_64_CONDCMP_IMM_GE, ccmp_x0_ge_11, 1)
TEST_INPUTS(
0,
1,
0x10,
0x11,
0x12,
0x0fffffff,
0x7fffffff,
0xffffffff)
ccmp ARG1_64, #0x11, #0x0, ge
TEST_END
TEST_BEGIN(CCMP_64_CONDCMP_IMM_GT, ccmp_x0_gt_11, 1)
TEST_INPUTS(
0,
1,
0x10,
0x11,
0x12,
0x0fffffff,
0x7fffffff,
0xffffffff)
ccmp ARG1_64, #0x11, #0x0, gt
TEST_END
TEST_BEGIN(CCMP_64_CONDCMP_IMM_LE, ccmp_x0_le_11, 1)
TEST_INPUTS(
0,
1,
0x10,
0x11,
0x12,
0x0fffffff,
0x7fffffff,
0xffffffff)
ccmp ARG1_64, #0x11, #0x0, le
TEST_END
TEST_BEGIN(CCMP_64_CONDCMP_IMM_LT, ccmp_x0_lt_11, 1)
TEST_INPUTS(
0,
1,
0x10,
0x11,
0x12,
0x0fffffff,
0x7fffffff,
0xffffffff)
ccmp ARG1_64, #0x11, #0x0, lt
TEST_END
TEST_BEGIN(CCMP_64_CONDCMP_IMM_EQ, ccmp_x0_eq_11, 1)
TEST_INPUTS(
0,
1,
0x10,
0x11,
0x12,
0x0fffffff,
0x7fffffff,
0xffffffff)
ccmp ARG1_64, #0x11, #0x0, eq
TEST_END
TEST_BEGIN(CCMP_64_CONDCMP_IMM_NE, ccmp_x0_ne_11, 1)
TEST_INPUTS(
0,
1,
0x10,
0x11,
0x12,
0x0fffffff,
0x7fffffff,
0xffffffff)
ccmp ARG1_64, #0x11, #0x0, ne
TEST_END
TEST_BEGIN(CCMP_64_CONDCMP_IMM_CS, ccmp_x0_cs_11, 1)
TEST_INPUTS(
0,
1,
0x10,
0x11,
0x12,
0x0fffffff,
0x7fffffff,
0xffffffff)
ccmp ARG1_64, #0x11, #0x0, cs
TEST_END
@@ -0,0 +1,35 @@
/*
* Copyright (c) 2017 Trail of Bits, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* LDP <Wt1>, <Wt2>, [<Xn|SP>{, #<imm>}] */
TEST_BEGIN(LDP_32_LDSTPAIR_OFF, ldp_w0_w1_m64_off, 1)
TEST_INPUTS(0)
add x3, sp, #-256
ldp w4, w5, [x3, #0]
ldp w6, w7, [x3, #32]
ldp w8, w9, [x3, #64]
TEST_END
/* LDP <Xt1>, <Xt2>, [<Xn|SP>{, #<imm>}] */
TEST_BEGIN(LDP_64_LDSTPAIR_OFF, ldp_x0_x1_m128_off, 1)
TEST_INPUTS(0)
add x3, sp, #-256
ldp x4, x5, [x3, #0]
ldp x6, x7, [x3, #32]
ldp x8, x9, [x3, #64]
TEST_END
@@ -0,0 +1,35 @@
/*
* Copyright (c) 2017 Trail of Bits, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* LDP <Wt1>, <Wt2>, [<Xn|SP>], #<imm> */
TEST_BEGIN(LDP_32_LDSTPAIR_POST, ldp_w0_w1_m64_post, 1)
TEST_INPUTS(0)
add x3, sp, #-256
ldp w4, w5, [x3], #0
ldp w6, w7, [x3], #32
ldp w8, w9, [x3], #64
TEST_END
/* LDP <Xt1>, <Xt2>, [<Xn|SP>], #<imm> */
TEST_BEGIN(LDP_64_LDSTPAIR_POST, ldp_x0_x1_m128_post, 1)
TEST_INPUTS(0)
add x3, sp, #-256
ldp x4, x5, [x3], #0
ldp x6, x7, [x3], #32
ldp x8, x9, [x3], #64
TEST_END
@@ -0,0 +1,35 @@
/*
* Copyright (c) 2017 Trail of Bits, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* LDP <Wt1>, <Wt2>, [<Xn|SP>, #<imm>]! */
TEST_BEGIN(LDP_32_LDSTPAIR_PRE, ldp_w0_w1_m64_pre, 1)
TEST_INPUTS(0)
add x3, sp, #-256
ldp w4, w5, [x3, #0]!
ldp w6, w7, [x3, #32]!
ldp w8, w9, [x3, #64]!
TEST_END
/* LDP <Xt1>, <Xt2>, [<Xn|SP>, #<imm>]! */
TEST_BEGIN(LDP_64_LDSTPAIR_PRE, ldp_x0_x1_m128_pre, 1)
TEST_INPUTS(0)
add x3, sp, #-256
ldp x4, x5, [x3, #0]!
ldp x6, x7, [x3, #32]!
ldp x8, x9, [x3, #64]!
TEST_END
@@ -0,0 +1,45 @@
/*
* Copyright (c) 2017 Trail of Bits, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* STP <Wt1>, <Wt2>, [<Xn|SP>{, #<imm>}] */
TEST_BEGIN(STP_32_LDSTPAIR_OFF, stp_w0_w1_m64_off, 2)
TEST_INPUTS(
0, 0,
0, 1,
1, 0,
1, 1,
0x41414141, 0xabababab)
add x3, sp, #-256
stp ARG1_32, ARG1_32, [x3, #0]
stp ARG2_32, ARG2_32, [x3, #32]
stp ARG1_32, ARG2_32, [x3, #64]
TEST_END
/* STP <Xt1>, <Xt2>, [<Xn|SP>{, #<imm>}] */
TEST_BEGIN(STP_64_LDSTPAIR_OFF, stp_x0_x1_m128_off, 2)
TEST_INPUTS(
0, 0,
0, 1,
1, 0,
1, 1,
0x4141414156565656, 0xababababefefefef)
add x3, sp, #-256
stp ARG1_64, ARG1_64, [x3, #0]
stp ARG2_64, ARG2_64, [x3, #32]
stp ARG1_64, ARG2_64, [x3, #64]
TEST_END
@@ -0,0 +1,45 @@
/*
* Copyright (c) 2017 Trail of Bits, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* STP <Wt1>, <Wt2>, [<Xn|SP>], #<imm> */
TEST_BEGIN(STP_32_LDSTPAIR_POST, stp_w0_w1_m64_post, 2)
TEST_INPUTS(
0, 0,
0, 1,
1, 0,
1, 1,
0x41414141, 0xabababab)
add x3, sp, #-256
stp ARG1_32, ARG1_32, [x3], #0
stp ARG2_32, ARG2_32, [x3], #32
stp ARG1_32, ARG2_32, [x3], #64
TEST_END
/* STP <Xt1>, <Xt2>, [<Xn|SP>], #<imm> */
TEST_BEGIN(STP_64_LDSTPAIR_POST, stp_x0_x1_m128_post, 2)
TEST_INPUTS(
0, 0,
0, 1,
1, 0,
1, 1,
0x4141414156565656, 0xababababefefefef)
add x3, sp, #-256
stp ARG1_64, ARG1_64, [x3], #0
stp ARG2_64, ARG2_64, [x3], #32
stp ARG1_64, ARG2_64, [x3], #64
TEST_END
@@ -0,0 +1,45 @@
/*
* Copyright (c) 2017 Trail of Bits, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* STP <Wt1>, <Wt2>, [<Xn|SP>, #<imm>]! */
TEST_BEGIN(STP_32_LDSTPAIR_PRE, stp_w0_w1_m64_pre, 2)
TEST_INPUTS(
0, 0,
0, 1,
1, 0,
1, 1,
0x41414141, 0xabababab)
add x3, sp, #-256
stp ARG1_32, ARG1_32, [x3, #0]!
stp ARG2_32, ARG2_32, [x3, #32]!
stp ARG1_32, ARG2_32, [x3, #64]!
TEST_END
/* STP <Xt1>, <Xt2>, [<Xn|SP>, #<imm>]! */
TEST_BEGIN(STP_64_LDSTPAIR_PRE, stp_x0_x1_m128_pre, 2)
TEST_INPUTS(
0, 0,
0, 1,
1, 0,
1, 1,
0x4141414156565656, 0xababababefefefef)
add x3, sp, #-256
stp ARG1_64, ARG1_64, [x3, #0]!
stp ARG2_64, ARG2_64, [x3, #32]!
stp ARG1_64, ARG2_64, [x3, #64]!
TEST_END
+7 -2
View File
@@ -264,7 +264,13 @@ SYMBOL(__aarch64_test_table_begin):
#include "tests/AArch64/CONVERT/UCVTF_Dn_FLOAT2INT.S"
#include "tests/AArch64/CONVERT/UCVTF_Sn_FLOAT2INT.S"
#include "tests/AArch64/DATAXFER/LDP_n_LDSTPAIR_OFF.S"
#include "tests/AArch64/DATAXFER/LDP_n_LDSTPAIR_POST.S"
#include "tests/AArch64/DATAXFER/LDP_n_LDSTPAIR_PRE.S"
#include "tests/AArch64/DATAXFER/LDR_n_LDST_POS.S"
#include "tests/AArch64/DATAXFER/STP_n_LDSTPAIR_OFF.S"
#include "tests/AArch64/DATAXFER/STP_n_LDSTPAIR_POST.S"
#include "tests/AArch64/DATAXFER/STP_n_LDSTPAIR_PRE.S"
#include "tests/AArch64/DATAXFER/STR_n_LDST_POS.S"
#include "tests/AArch64/LOGICAL/AND_n_LOG_IMM.S"
@@ -280,13 +286,12 @@ SYMBOL(__aarch64_test_table_begin):
#include "tests/AArch64/COND/CSEL_n_CONDSEL.S"
#include "tests/AArch64/COND/x_CSNEG_n_CONDSEL.S"
// #include "tests/AArch64/COND/CCMP_n_CONDCMP_IMM.S"
#include "tests/AArch64/COND/CCMP_n_CONDCMP_IMM.S"
#include "tests/AArch64/COND/x_CSINC_n_CONDSEL.S"
#include "tests/AArch64/COND/x_CSINV_n_CONDSEL.S"
#endif
/* Create a symbol that represents the end of the test information table. */
.section "__aarch64_test_table", "a"
.globl SYMBOL(__aarch64_test_table_end)