[Hexagon] Failure to disassemble some new-value instructions

Dear list,

I noticed that the Hexagon disassembler has issues with disassembling some firmwares I have. When tracing one of these problems, the handling of some new-value instructions in HexagonDisassembler::getSingleInstruction() turned out to be the cause, specifically this statement:

[lines 384-386 in HexagonDisassembler.cpp in HEAD]
     else if (SubregBit)
       // Subreg bit should not be set for non-doublevector newvalue producers
       return MCDisassembler::Fail;

Where does the requirement come from? Maybe I overlooked it, but I do not see it in the Hexagon V5/V55 Programmer’s Reference Manual.

One instruction packet I have encountered in the wild that triggers this failure is:

10: e0 7e df 78 78df7ee0 { r0 = #-9
14: 01 40 91 91 91914001 r1 = memw(r17 + #0)
18: 10 e1 03 25 2503e110 if (cmp.gtu(r1.new, #1)) jump:t 0x30 }

Removing the requirement seems to work fine (see attached patch).

Cheers,
Ralf

hexagon-new-value.patch (810 Bytes)

This looks similar to https://llvm.org/bugs/show_bug.cgi?id=25956, it looks like the instruction is encoded incorrectly, for instance if you re-assemble that packet that bit is not set.

I added r259380 which points out the location in the manual which says this bit must be 0, 10.11 "Nt[0] is reserved and should always be encoded as zero".

Your patch does work around the issue in the meantime.

Such bits often become non-zero on later versions of the architecture.

As Ralf says the code in question came from firmware, not from LLVM, it’s entirely possible that it’s a valid but undocumented instruction, and attempting to use re-assembled code with that bit forced to zero will not work.