summaryrefslogtreecommitdiff
path: root/arch
diff options
context:
space:
mode:
authorGalen Williamson <galen@vector35.com>2025-08-08 19:08:54 -0400
committerGalen Williamson <galen@vector35.com>2025-08-14 14:06:49 -0400
commit0becd045c5e3e0997c30cb64f19fe21b2b3c421f (patch)
treed3bf904ea9919a076f9793d5e9ca50e4f42b0f75 /arch
parent2aa2a28a341a2290fe0328a46dbe8e3d7bb3ba4d (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.h2
-rw-r--r--arch/armv7/thumb2_disasm/il_thumb2.cpp97
-rw-r--r--arch/armv7/thumb2_disasm/spec.cpp36
-rw-r--r--arch/armv7/thumb2_disasm/spec.txt10
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>