diff options
| author | Galen Williamson <galen@vector35.com> | 2025-08-08 19:08:54 -0400 |
|---|---|---|
| committer | Galen Williamson <galen@vector35.com> | 2025-08-14 14:06:49 -0400 |
| commit | 0becd045c5e3e0997c30cb64f19fe21b2b3c421f (patch) | |
| tree | d3bf904ea9919a076f9793d5e9ca50e4f42b0f75 /arch | |
| parent | 2aa2a28a341a2290fe0328a46dbe8e3d7bb3ba4d (diff) | |
[thumb2] improved disassembly and lifting of VCVT instruction for scalar floating-point/integer cases
Diffstat (limited to 'arch')
| -rw-r--r-- | arch/armv7/thumb2_disasm/disassembler.h | 2 | ||||
| -rw-r--r-- | arch/armv7/thumb2_disasm/il_thumb2.cpp | 97 | ||||
| -rw-r--r-- | arch/armv7/thumb2_disasm/spec.cpp | 36 | ||||
| -rw-r--r-- | arch/armv7/thumb2_disasm/spec.txt | 10 |
4 files changed, 76 insertions, 69 deletions
diff --git a/arch/armv7/thumb2_disasm/disassembler.h b/arch/armv7/thumb2_disasm/disassembler.h index 2348ea93..b99836b3 100644 --- a/arch/armv7/thumb2_disasm/disassembler.h +++ b/arch/armv7/thumb2_disasm/disassembler.h @@ -106,6 +106,8 @@ enum COND { COND_EQ=0, COND_NE, COND_CS, COND_CC, COND_MI, COND_PL, COND_VS, #define VFP_DATA_SIZE_F32U32 1 #define VFP_DATA_SIZE_S32F32 2 #define VFP_DATA_SIZE_U32F32 3 +#define VFP_DATA_SIZE_S32F64 4 +#define VFP_DATA_SIZE_U32F64 5 #define VFP_DATA_SIZE_32 8 diff --git a/arch/armv7/thumb2_disasm/il_thumb2.cpp b/arch/armv7/thumb2_disasm/il_thumb2.cpp index a9205b39..cc3856c9 100644 --- a/arch/armv7/thumb2_disasm/il_thumb2.cpp +++ b/arch/armv7/thumb2_disasm/il_thumb2.cpp @@ -1821,7 +1821,6 @@ bool GetLowLevelILForNEONInstruction(Architecture* arch, LowLevelILFunction& il, il.AddInstruction(WriteILOperand(il, instr, 0, ReadILOperand(il, instr, 1), GetRegisterSize(instr, 1))); break; case armv7::ARMV7_VCVT: - // if (instr->format->operandCount == 3) if (IS_FIELD_PRESENT(instr, FIELD_to_fixed)) { if (IS_FIELD_PRESENT(instr, FIELD_imm)) @@ -1864,78 +1863,79 @@ bool GetLowLevelILForNEONInstruction(Architecture* arch, LowLevelILFunction& il, if (IS_FIELD_PRESENT(instr, FIELD_td)) { // VCVT (between floating-point and integer, Advanced SIMD) - /* VCVT<c>.<dt> <Dd>,<Dm> */ // instr->fields[FIELD_regs] = 1 - /* VCVT<c>.<dt> <Qd>,<Qm> */ // instr->fields[FIELD_regs] = 2 + /* VCVT<c>.<dt> <Dd>,<Dm> */ // instr->fields[FIELD_regs] = 1 + /* VCVT<c>.<dt> <Qd>,<Qm> */ // instr->fields[FIELD_regs] = 2 switch (instr->fields[FIELD_dt]) { case VFP_DATA_SIZE_S32F32: case VFP_DATA_SIZE_U32F32: // TODO: iterate over vector components - // il.AddInstruction(WriteILOperand( - // il, instr, 0, il.IntToFloat(GetRegisterSize(instr, 1), ReadILOperand(il, instr, 1)))); // break; case VFP_DATA_SIZE_F32S32: case VFP_DATA_SIZE_F32U32: // TODO: iterate over vector components - // il.AddInstruction(WriteILOperand( - // il, instr, 0, il.FloatToInt(GetRegisterSize(instr, 1), - // il.RoundToInt(GetRegisterSize(instr, 1), - // ReadILOperand(il, instr, 1))))); // break; default: - // TODO: vector unsupported. + // Invalid il.AddInstruction(il.Unimplemented()); } } - else if (instr->format->operationFlags & (INSTR_FORMAT_FLAG_F32 | INSTR_FORMAT_FLAG_F64)) + else if (instr->fields[FIELD_to_integer]) { + // VCVT, VCVTR (between floating-point and integer, Floating-point) + // TODO: handle distinction of VCVTR: + // If R is specified, the operation uses the rounding mode specified by the FPSCR. + // If R is omitted. the operation uses the Round towards Zero rounding mode. + // (Note: Binary Ninja does not currently support specifying any particular rounding mode, so it doesn't matter.) switch (instr->fields[FIELD_dt]) { - case VFP_DATA_SIZE_S32: + case VFP_DATA_SIZE_S32F32: + case VFP_DATA_SIZE_S32F64: + /* VCVT<c>.S32.F32 <Sd>,<Sm> */ + /* VCVT<c>.S32.F64 <Sd>,<Dm> */ + /* VCVTR<c>.S32.F32 <Sd>,<Sm> */ + /* VCVTR<c>.S32.F64 <Sd>,<Dm> */ il.AddInstruction(WriteILOperand( - il, instr, 0, il.IntToFloat(GetRegisterSize(instr, 0), - il.SignExtend(GetRegisterSize(instr, 0), - ReadILOperand(il, instr, 1))))); + il, instr, 0, il.SignExtend(GetRegisterSize(instr, 0), + il.FloatToInt(GetRegisterSize(instr, 0), + il.RoundToInt(GetRegisterSize(instr, 0), + ReadILOperand(il, instr, 1)))))); break; - case VFP_DATA_SIZE_U32: + case VFP_DATA_SIZE_U32F32: + case VFP_DATA_SIZE_U32F64: + /* VCVT<c>.U32.F32 <Sd>,<Sm> */ + /* VCVT<c>.U32.F64 <Sd>,<Dm> */ + /* VCVTR<c>.U32.F32 <Sd>,<Sm> */ + /* VCVTR<c>.U32.F64 <Sd>,<Dm> */ il.AddInstruction(WriteILOperand( - il, instr, 0, il.IntToFloat(GetRegisterSize(instr, 0), - il.ZeroExtend(GetRegisterSize(instr, 0), - ReadILOperand(il, instr, 1))))); + il, instr, 0, il.ZeroExtend(GetRegisterSize(instr, 0), + il.FloatToInt(GetRegisterSize(instr, 0), + il.RoundToInt(GetRegisterSize(instr, 0), + ReadILOperand(il, instr, 1)))))); break; + default: + // Invalid + il.AddInstruction(il.Unimplemented()); } - // il.AddInstruction(WriteILOperand( - // il, instr, 0, il.IntToFloat(GetRegisterSize(instr, 0), ReadILOperand(il, instr, 1)))); } else { // VCVT, VCVTR (between floating-point and integer, Floating-point) switch (instr->fields[FIELD_dt]) { - case VFP_DATA_SIZE_S32F32: + case VFP_DATA_SIZE_S32: + /* VCVT<c>.F32.<dt> <Sd>,<Sm> */ il.AddInstruction(WriteILOperand( - il, instr, 0, il.SignExtend(GetRegisterSize(instr, 0), - il.FloatToInt(GetRegisterSize(instr, 0), - il.RoundToInt(GetRegisterSize(instr, 0), - ReadILOperand(il, instr, 1)))))); - break; - case VFP_DATA_SIZE_U32F32: - // case VFP_DATA_SIZE_S32F64: - // case VFP_DATA_SIZE_U32F64: - il.AddInstruction(WriteILOperand( - il, instr, 0, il.ZeroExtend(GetRegisterSize(instr, 0), - il.FloatToInt(GetRegisterSize(instr, 0), - il.RoundToInt(GetRegisterSize(instr, 0), - ReadILOperand(il, instr, 1)))))); - // il.AddInstruction(WriteILOperand( - // il, instr, 0, il.FloatToInt(GetRegisterSize(instr, 1), - // il.RoundToInt(GetRegisterSize(instr, 1), - // ReadILOperand(il, instr, 1))))); + il, instr, 0, il.IntToFloat(GetRegisterSize(instr, 0), + il.SignExtend(GetRegisterSize(instr, 0), + ReadILOperand(il, instr, 1))))); break; - case VFP_DATA_SIZE_F32S32: - case VFP_DATA_SIZE_F32U32: + case VFP_DATA_SIZE_U32: + /* VCVT<c>.F64.<dt> <Dd>,<Sm> */ il.AddInstruction(WriteILOperand( - il, instr, 0, il.IntToFloat(GetRegisterSize(instr, 0), ReadILOperand(il, instr, 1)))); + il, instr, 0, il.IntToFloat(GetRegisterSize(instr, 0), + il.ZeroExtend(GetRegisterSize(instr, 0), + ReadILOperand(il, instr, 1))))); break; default: // Invalid @@ -1943,19 +1943,6 @@ bool GetLowLevelILForNEONInstruction(Architecture* arch, LowLevelILFunction& il, } } } - // else if (IS_FIELD_PRESENT(instr, FIELD_dt)) - // { - // switch (instr->fields[FIELD_dt]) - // { - // case VFP_DATA_SIZE_F32: - // case VFP_DATA_SIZE_S32: - // il.AddInstruction(WriteILOperand( - // il, instr, 0, il.FloatConvert(GetRegisterSize(instr, 1), ReadILOperand(il, instr, 1)))); - // break; - // default: - // il.AddInstruction(il.Unimplemented()); - // } - // } else il.AddInstruction(il.Unimplemented()); break; diff --git a/arch/armv7/thumb2_disasm/spec.cpp b/arch/armv7/thumb2_disasm/spec.cpp index 38e14d02..b4a9a59d 100644 --- a/arch/armv7/thumb2_disasm/spec.cpp +++ b/arch/armv7/thumb2_disasm/spec.cpp @@ -34286,7 +34286,7 @@ int vcvt_float_fixed(struct decomp_request *req, struct decomp_result *res) return undefined(req, res); } -// gen_crc: EBC7DA24 +// gen_crc: 54397ABD int vcvt_float_int(struct decomp_request *req, struct decomp_result *res) { int rc = -1; @@ -34461,18 +34461,23 @@ int vcvt_float_int(struct decomp_request *req, struct decomp_result *res) res->fields[FIELD_d] = ((res->fields[FIELD_Vd]<<D_width)|(res->fields[FIELD_D])); res->fields_mask[FIELD_d >> 6] |= 1LL << (FIELD_d & 63); } - /* pcode: if (to_integer) then unsigned = (opc1 == '0') */ - if((res->fields[FIELD_to_integer])) { + /* pcode: if to_integer then unsigned = (opc1 == '0') */ + if(res->fields[FIELD_to_integer]) { res->fields[FIELD_unsigned] = ((res->fields[FIELD_opc1]) == (0x0)); res->fields_mask[FIELD_unsigned >> 6] |= 1LL << (FIELD_unsigned & 63); } - /* pcode: if (to_integer) then d = UInt(Vd:D) */ - if((res->fields[FIELD_to_integer])) { + /* pcode: if to_integer then round_zero = (op == '1') */ + if(res->fields[FIELD_to_integer]) { + res->fields[FIELD_round_zero] = ((res->fields[FIELD_op]) == (0x1)); + res->fields_mask[FIELD_round_zero >> 6] |= 1LL << (FIELD_round_zero & 63); + } + /* pcode: if to_integer then d = UInt(Vd:D) */ + if(res->fields[FIELD_to_integer]) { res->fields[FIELD_d] = ((res->fields[FIELD_Vd]<<D_width)|(res->fields[FIELD_D])); res->fields_mask[FIELD_d >> 6] |= 1LL << (FIELD_d & 63); } - /* pcode: if (to_integer) then m = if dp_operation then UInt(M:Vm) else UInt(Vm:M) */ - if((res->fields[FIELD_to_integer])) { + /* pcode: if to_integer then m = if dp_operation then UInt(M:Vm) else UInt(Vm:M) */ + if(res->fields[FIELD_to_integer]) { if(res->fields[FIELD_dp_operation]) { res->fields[FIELD_m] = ((res->fields[FIELD_M]<<Vm_width)|(res->fields[FIELD_Vm])); res->fields_mask[FIELD_m >> 6] |= 1LL << (FIELD_m & 63); @@ -34482,6 +34487,11 @@ int vcvt_float_int(struct decomp_request *req, struct decomp_result *res) res->fields_mask[FIELD_m >> 6] |= 1LL << (FIELD_m & 63); }; } + /* pcode: if !to_integer then round_nearest = FALSE */ + if(!(res->fields[FIELD_to_integer])) { + res->fields[FIELD_round_nearest] = 0; + res->fields_mask[FIELD_round_nearest >> 6] |= 1LL << (FIELD_round_nearest & 63); + } /* pcode: fmt_idx = ((op == '0') * 4) + (opc3 * 2) + sz + 2 */ res->fields[FIELD_fmt_idx] = (((((((res->fields[FIELD_op]) == (0x0))) * (4))) + (((res->fields[FIELD_opc3]) * (2)))) + (res->fields[FIELD_sz])) + (2); res->fields_mask[FIELD_fmt_idx >> 6] |= 1LL << (FIELD_fmt_idx & 63); @@ -34490,9 +34500,15 @@ int vcvt_float_int(struct decomp_request *req, struct decomp_result *res) res->fields[FIELD_fmt_idx] = res->fields[FIELD_sz]; res->fields_mask[FIELD_fmt_idx >> 6] |= 1LL << (FIELD_fmt_idx & 63); } - /* pcode: dt = ((op == '0') * 4) + 2 */ - res->fields[FIELD_dt] = (((((res->fields[FIELD_op]) == (0x0))) * (4))) + (2); - res->fields_mask[FIELD_dt >> 6] |= 1LL << (FIELD_dt & 63); + /* pcode: if to_integer then dt = 2 + (sz * 2) + (1 - opc3) else dt = ((op == '0') * 4) + 2 */ + if(res->fields[FIELD_to_integer]) { + res->fields[FIELD_dt] = ((2) + (((res->fields[FIELD_sz]) * (2)))) + (((1) - (res->fields[FIELD_opc3]))); + res->fields_mask[FIELD_dt >> 6] |= 1LL << (FIELD_dt & 63); + } + else { + res->fields[FIELD_dt] = (((((res->fields[FIELD_op]) == (0x0))) * (4))) + (2); + res->fields_mask[FIELD_dt >> 6] |= 1LL << (FIELD_dt & 63); + } return success(); } /* ENDS if(<encoding_match_test>) ... */ diff --git a/arch/armv7/thumb2_disasm/spec.txt b/arch/armv7/thumb2_disasm/spec.txt index eaffbfce..34b04e65 100644 --- a/arch/armv7/thumb2_disasm/spec.txt +++ b/arch/armv7/thumb2_disasm/spec.txt @@ -5529,12 +5529,14 @@ to_integer = (opc1 == '1'); dp_operation = (sz == 1); unsigned = (opc3 == '0'); m = UInt(Vm:M); d = if dp_operation then UInt(D:Vd) else UInt(Vd:D); -if (to_integer) then unsigned = (opc1 == '0'); -if (to_integer) then d = UInt(Vd:D); -if (to_integer) then m = if dp_operation then UInt(M:Vm) else UInt(Vm:M); +if to_integer then unsigned = (opc1 == '0'); +if to_integer then round_zero = (op == '1'); +if to_integer then d = UInt(Vd:D); +if to_integer then m = if dp_operation then UInt(M:Vm) else UInt(Vm:M); +if !to_integer then round_nearest = FALSE; fmt_idx = ((op == '0') * 4) + (opc3 * 2) + sz + 2; if (opc1 == '0') then fmt_idx = sz; -dt = ((op == '0') * 4) + 2; +if to_integer then dt = 2 + (sz * 2) + (1 - opc3) else dt = ((op == '0') * 4) + 2; pcode_end Encoding T1 ADVSIMD fmt VCVT<c>.<dt> <Dd>,<Dm> |
