Skip to content

Commit 88f9260

Browse files
committed
[thumb2] improved disassembly and lifting of VCVT instruction for scalar floating-point/integer cases
1 parent 9e27655 commit 88f9260

File tree

4 files changed

+76
-69
lines changed

4 files changed

+76
-69
lines changed

arch/armv7/thumb2_disasm/disassembler.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,8 @@ enum COND { COND_EQ=0, COND_NE, COND_CS, COND_CC, COND_MI, COND_PL, COND_VS,
106106
#define VFP_DATA_SIZE_F32U32 1
107107
#define VFP_DATA_SIZE_S32F32 2
108108
#define VFP_DATA_SIZE_U32F32 3
109+
#define VFP_DATA_SIZE_S32F64 4
110+
#define VFP_DATA_SIZE_U32F64 5
109111

110112
#define VFP_DATA_SIZE_32 8
111113

arch/armv7/thumb2_disasm/il_thumb2.cpp

Lines changed: 42 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1821,7 +1821,6 @@ bool GetLowLevelILForNEONInstruction(Architecture* arch, LowLevelILFunction& il,
18211821
il.AddInstruction(WriteILOperand(il, instr, 0, ReadILOperand(il, instr, 1), GetRegisterSize(instr, 1)));
18221822
break;
18231823
case armv7::ARMV7_VCVT:
1824-
// if (instr->format->operandCount == 3)
18251824
if (IS_FIELD_PRESENT(instr, FIELD_to_fixed))
18261825
{
18271826
if (IS_FIELD_PRESENT(instr, FIELD_imm))
@@ -1864,98 +1863,86 @@ bool GetLowLevelILForNEONInstruction(Architecture* arch, LowLevelILFunction& il,
18641863
if (IS_FIELD_PRESENT(instr, FIELD_td))
18651864
{
18661865
// VCVT (between floating-point and integer, Advanced SIMD)
1867-
/* VCVT<c>.<dt> <Dd>,<Dm> */ // instr->fields[FIELD_regs] = 1
1868-
/* VCVT<c>.<dt> <Qd>,<Qm> */ // instr->fields[FIELD_regs] = 2
1866+
/* VCVT<c>.<dt> <Dd>,<Dm> */ // instr->fields[FIELD_regs] = 1
1867+
/* VCVT<c>.<dt> <Qd>,<Qm> */ // instr->fields[FIELD_regs] = 2
18691868
switch (instr->fields[FIELD_dt])
18701869
{
18711870
case VFP_DATA_SIZE_S32F32:
18721871
case VFP_DATA_SIZE_U32F32:
18731872
// TODO: iterate over vector components
1874-
// il.AddInstruction(WriteILOperand(
1875-
// il, instr, 0, il.IntToFloat(GetRegisterSize(instr, 1), ReadILOperand(il, instr, 1))));
18761873
// break;
18771874
case VFP_DATA_SIZE_F32S32:
18781875
case VFP_DATA_SIZE_F32U32:
18791876
// TODO: iterate over vector components
1880-
// il.AddInstruction(WriteILOperand(
1881-
// il, instr, 0, il.FloatToInt(GetRegisterSize(instr, 1),
1882-
// il.RoundToInt(GetRegisterSize(instr, 1),
1883-
// ReadILOperand(il, instr, 1)))));
18841877
// break;
18851878
default:
1886-
// TODO: vector unsupported.
1879+
// Invalid
18871880
il.AddInstruction(il.Unimplemented());
18881881
}
18891882
}
1890-
else if (instr->format->operationFlags & (INSTR_FORMAT_FLAG_F32 | INSTR_FORMAT_FLAG_F64))
1883+
else if (instr->fields[FIELD_to_integer])
18911884
{
1885+
// VCVT, VCVTR (between floating-point and integer, Floating-point)
1886+
// TODO: handle distinction of VCVTR:
1887+
// If R is specified, the operation uses the rounding mode specified by the FPSCR.
1888+
// If R is omitted. the operation uses the Round towards Zero rounding mode.
1889+
// (Note: Binary Ninja does not currently support specifying any particular rounding mode, so it doesn't matter.)
18921890
switch (instr->fields[FIELD_dt])
18931891
{
1894-
case VFP_DATA_SIZE_S32:
1892+
case VFP_DATA_SIZE_S32F32:
1893+
case VFP_DATA_SIZE_S32F64:
1894+
/* VCVT<c>.S32.F32 <Sd>,<Sm> */
1895+
/* VCVT<c>.S32.F64 <Sd>,<Dm> */
1896+
/* VCVTR<c>.S32.F32 <Sd>,<Sm> */
1897+
/* VCVTR<c>.S32.F64 <Sd>,<Dm> */
18951898
il.AddInstruction(WriteILOperand(
1896-
il, instr, 0, il.IntToFloat(GetRegisterSize(instr, 0),
1897-
il.SignExtend(GetRegisterSize(instr, 0),
1898-
ReadILOperand(il, instr, 1)))));
1899+
il, instr, 0, il.SignExtend(GetRegisterSize(instr, 0),
1900+
il.FloatToInt(GetRegisterSize(instr, 0),
1901+
il.RoundToInt(GetRegisterSize(instr, 0),
1902+
ReadILOperand(il, instr, 1))))));
18991903
break;
1900-
case VFP_DATA_SIZE_U32:
1904+
case VFP_DATA_SIZE_U32F32:
1905+
case VFP_DATA_SIZE_U32F64:
1906+
/* VCVT<c>.U32.F32 <Sd>,<Sm> */
1907+
/* VCVT<c>.U32.F64 <Sd>,<Dm> */
1908+
/* VCVTR<c>.U32.F32 <Sd>,<Sm> */
1909+
/* VCVTR<c>.U32.F64 <Sd>,<Dm> */
19011910
il.AddInstruction(WriteILOperand(
1902-
il, instr, 0, il.IntToFloat(GetRegisterSize(instr, 0),
1903-
il.ZeroExtend(GetRegisterSize(instr, 0),
1904-
ReadILOperand(il, instr, 1)))));
1911+
il, instr, 0, il.ZeroExtend(GetRegisterSize(instr, 0),
1912+
il.FloatToInt(GetRegisterSize(instr, 0),
1913+
il.RoundToInt(GetRegisterSize(instr, 0),
1914+
ReadILOperand(il, instr, 1))))));
19051915
break;
1916+
default:
1917+
// Invalid
1918+
il.AddInstruction(il.Unimplemented());
19061919
}
1907-
// il.AddInstruction(WriteILOperand(
1908-
// il, instr, 0, il.IntToFloat(GetRegisterSize(instr, 0), ReadILOperand(il, instr, 1))));
19091920
}
19101921
else
19111922
{
19121923
// VCVT, VCVTR (between floating-point and integer, Floating-point)
19131924
switch (instr->fields[FIELD_dt])
19141925
{
1915-
case VFP_DATA_SIZE_S32F32:
1926+
case VFP_DATA_SIZE_S32:
1927+
/* VCVT<c>.F32.<dt> <Sd>,<Sm> */
19161928
il.AddInstruction(WriteILOperand(
1917-
il, instr, 0, il.SignExtend(GetRegisterSize(instr, 0),
1918-
il.FloatToInt(GetRegisterSize(instr, 0),
1919-
il.RoundToInt(GetRegisterSize(instr, 0),
1920-
ReadILOperand(il, instr, 1))))));
1921-
break;
1922-
case VFP_DATA_SIZE_U32F32:
1923-
// case VFP_DATA_SIZE_S32F64:
1924-
// case VFP_DATA_SIZE_U32F64:
1925-
il.AddInstruction(WriteILOperand(
1926-
il, instr, 0, il.ZeroExtend(GetRegisterSize(instr, 0),
1927-
il.FloatToInt(GetRegisterSize(instr, 0),
1928-
il.RoundToInt(GetRegisterSize(instr, 0),
1929-
ReadILOperand(il, instr, 1))))));
1930-
// il.AddInstruction(WriteILOperand(
1931-
// il, instr, 0, il.FloatToInt(GetRegisterSize(instr, 1),
1932-
// il.RoundToInt(GetRegisterSize(instr, 1),
1933-
// ReadILOperand(il, instr, 1)))));
1929+
il, instr, 0, il.IntToFloat(GetRegisterSize(instr, 0),
1930+
il.SignExtend(GetRegisterSize(instr, 0),
1931+
ReadILOperand(il, instr, 1)))));
19341932
break;
1935-
case VFP_DATA_SIZE_F32S32:
1936-
case VFP_DATA_SIZE_F32U32:
1933+
case VFP_DATA_SIZE_U32:
1934+
/* VCVT<c>.F64.<dt> <Dd>,<Sm> */
19371935
il.AddInstruction(WriteILOperand(
1938-
il, instr, 0, il.IntToFloat(GetRegisterSize(instr, 0), ReadILOperand(il, instr, 1))));
1936+
il, instr, 0, il.IntToFloat(GetRegisterSize(instr, 0),
1937+
il.ZeroExtend(GetRegisterSize(instr, 0),
1938+
ReadILOperand(il, instr, 1)))));
19391939
break;
19401940
default:
19411941
// Invalid
19421942
il.AddInstruction(il.Unimplemented());
19431943
}
19441944
}
19451945
}
1946-
// else if (IS_FIELD_PRESENT(instr, FIELD_dt))
1947-
// {
1948-
// switch (instr->fields[FIELD_dt])
1949-
// {
1950-
// case VFP_DATA_SIZE_F32:
1951-
// case VFP_DATA_SIZE_S32:
1952-
// il.AddInstruction(WriteILOperand(
1953-
// il, instr, 0, il.FloatConvert(GetRegisterSize(instr, 1), ReadILOperand(il, instr, 1))));
1954-
// break;
1955-
// default:
1956-
// il.AddInstruction(il.Unimplemented());
1957-
// }
1958-
// }
19591946
else
19601947
il.AddInstruction(il.Unimplemented());
19611948
break;

arch/armv7/thumb2_disasm/spec.cpp

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -34286,7 +34286,7 @@ int vcvt_float_fixed(struct decomp_request *req, struct decomp_result *res)
3428634286
return undefined(req, res);
3428734287
}
3428834288

34289-
// gen_crc: EBC7DA24
34289+
// gen_crc: 54397ABD
3429034290
int vcvt_float_int(struct decomp_request *req, struct decomp_result *res)
3429134291
{
3429234292
int rc = -1;
@@ -34461,18 +34461,23 @@ int vcvt_float_int(struct decomp_request *req, struct decomp_result *res)
3446134461
res->fields[FIELD_d] = ((res->fields[FIELD_Vd]<<D_width)|(res->fields[FIELD_D]));
3446234462
res->fields_mask[FIELD_d >> 6] |= 1LL << (FIELD_d & 63);
3446334463
}
34464-
/* pcode: if (to_integer) then unsigned = (opc1 == '0') */
34465-
if((res->fields[FIELD_to_integer])) {
34464+
/* pcode: if to_integer then unsigned = (opc1 == '0') */
34465+
if(res->fields[FIELD_to_integer]) {
3446634466
res->fields[FIELD_unsigned] = ((res->fields[FIELD_opc1]) == (0x0));
3446734467
res->fields_mask[FIELD_unsigned >> 6] |= 1LL << (FIELD_unsigned & 63);
3446834468
}
34469-
/* pcode: if (to_integer) then d = UInt(Vd:D) */
34470-
if((res->fields[FIELD_to_integer])) {
34469+
/* pcode: if to_integer then round_zero = (op == '1') */
34470+
if(res->fields[FIELD_to_integer]) {
34471+
res->fields[FIELD_round_zero] = ((res->fields[FIELD_op]) == (0x1));
34472+
res->fields_mask[FIELD_round_zero >> 6] |= 1LL << (FIELD_round_zero & 63);
34473+
}
34474+
/* pcode: if to_integer then d = UInt(Vd:D) */
34475+
if(res->fields[FIELD_to_integer]) {
3447134476
res->fields[FIELD_d] = ((res->fields[FIELD_Vd]<<D_width)|(res->fields[FIELD_D]));
3447234477
res->fields_mask[FIELD_d >> 6] |= 1LL << (FIELD_d & 63);
3447334478
}
34474-
/* pcode: if (to_integer) then m = if dp_operation then UInt(M:Vm) else UInt(Vm:M) */
34475-
if((res->fields[FIELD_to_integer])) {
34479+
/* pcode: if to_integer then m = if dp_operation then UInt(M:Vm) else UInt(Vm:M) */
34480+
if(res->fields[FIELD_to_integer]) {
3447634481
if(res->fields[FIELD_dp_operation]) {
3447734482
res->fields[FIELD_m] = ((res->fields[FIELD_M]<<Vm_width)|(res->fields[FIELD_Vm]));
3447834483
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)
3448234487
res->fields_mask[FIELD_m >> 6] |= 1LL << (FIELD_m & 63);
3448334488
};
3448434489
}
34490+
/* pcode: if !to_integer then round_nearest = FALSE */
34491+
if(!(res->fields[FIELD_to_integer])) {
34492+
res->fields[FIELD_round_nearest] = 0;
34493+
res->fields_mask[FIELD_round_nearest >> 6] |= 1LL << (FIELD_round_nearest & 63);
34494+
}
3448534495
/* pcode: fmt_idx = ((op == '0') * 4) + (opc3 * 2) + sz + 2 */
3448634496
res->fields[FIELD_fmt_idx] = (((((((res->fields[FIELD_op]) == (0x0))) * (4))) + (((res->fields[FIELD_opc3]) * (2)))) + (res->fields[FIELD_sz])) + (2);
3448734497
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)
3449034500
res->fields[FIELD_fmt_idx] = res->fields[FIELD_sz];
3449134501
res->fields_mask[FIELD_fmt_idx >> 6] |= 1LL << (FIELD_fmt_idx & 63);
3449234502
}
34493-
/* pcode: dt = ((op == '0') * 4) + 2 */
34494-
res->fields[FIELD_dt] = (((((res->fields[FIELD_op]) == (0x0))) * (4))) + (2);
34495-
res->fields_mask[FIELD_dt >> 6] |= 1LL << (FIELD_dt & 63);
34503+
/* pcode: if to_integer then dt = 2 + (sz * 2) + (1 - opc3) else dt = ((op == '0') * 4) + 2 */
34504+
if(res->fields[FIELD_to_integer]) {
34505+
res->fields[FIELD_dt] = ((2) + (((res->fields[FIELD_sz]) * (2)))) + (((1) - (res->fields[FIELD_opc3])));
34506+
res->fields_mask[FIELD_dt >> 6] |= 1LL << (FIELD_dt & 63);
34507+
}
34508+
else {
34509+
res->fields[FIELD_dt] = (((((res->fields[FIELD_op]) == (0x0))) * (4))) + (2);
34510+
res->fields_mask[FIELD_dt >> 6] |= 1LL << (FIELD_dt & 63);
34511+
}
3449634512

3449734513
return success();
3449834514
} /* ENDS if(<encoding_match_test>) ... */

arch/armv7/thumb2_disasm/spec.txt

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5529,12 +5529,14 @@ to_integer = (opc1 == '1'); dp_operation = (sz == 1);
55295529
unsigned = (opc3 == '0');
55305530
m = UInt(Vm:M);
55315531
d = if dp_operation then UInt(D:Vd) else UInt(Vd:D);
5532-
if (to_integer) then unsigned = (opc1 == '0');
5533-
if (to_integer) then d = UInt(Vd:D);
5534-
if (to_integer) then m = if dp_operation then UInt(M:Vm) else UInt(Vm:M);
5532+
if to_integer then unsigned = (opc1 == '0');
5533+
if to_integer then round_zero = (op == '1');
5534+
if to_integer then d = UInt(Vd:D);
5535+
if to_integer then m = if dp_operation then UInt(M:Vm) else UInt(Vm:M);
5536+
if !to_integer then round_nearest = FALSE;
55355537
fmt_idx = ((op == '0') * 4) + (opc3 * 2) + sz + 2;
55365538
if (opc1 == '0') then fmt_idx = sz;
5537-
dt = ((op == '0') * 4) + 2;
5539+
if to_integer then dt = 2 + (sz * 2) + (1 - opc3) else dt = ((op == '0') * 4) + 2;
55385540
pcode_end
55395541
Encoding T1 ADVSIMD
55405542
fmt VCVT<c>.<dt> <Dd>,<Dm>

0 commit comments

Comments
 (0)