Skip to content

Commit 4cace1f

Browse files
authored
[ARM] Verify that disassembled instruction is correct (#157360)
This change adds basic `MCInst` verification (checks the number of operands) and fixes detected bugs. * `RFE*` instructions have only one operand, but `DecodeRFEInstruction` added two. * `DecodeMVEModImmInstruction` and `DecodeMVEVCMP` added a `vpred` operand, but this is what `AddThumbPredicate` normally does. This resulted in an extra `vpred` operand. * `DecodeMVEVADCInstruction` added an extra immediate operand. * `getARMInstruction` added a `pred` operand to instructions that don't have one (via `DecodePredicateOperand`). * `AddThumb1SBit` appended an extra register operand to instructions that don't modify CPSR (such as `tBL`). * Instructions in `NEONDup` namespace have `pred` operand that the generated code successfully decodes. The operand was added once again by `getARMInstruction`/`getThumbInstruction` via `AddThumbPredicate`. Functional changes extracted from #156540.
1 parent 4c7ebf8 commit 4cace1f

File tree

2 files changed

+28
-42
lines changed

2 files changed

+28
-42
lines changed

llvm/lib/Target/ARM/Disassembler/ARMDisassembler.cpp

Lines changed: 27 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ class ARMDisassembler : public MCDisassembler {
152152
void AddThumb1SBit(MCInst &MI, bool InITBlock) const;
153153
bool isVectorPredicable(const MCInst &MI) const;
154154
DecodeStatus AddThumbPredicate(MCInst&) const;
155-
void UpdateThumbVFPPredicate(DecodeStatus &, MCInst&) const;
155+
void UpdateThumbPredicate(DecodeStatus &S, MCInst &MI) const;
156156

157157
llvm::endianness InstructionEndianness;
158158
};
@@ -1378,24 +1378,6 @@ static DecodeStatus DecodeRFEInstruction(MCInst &Inst, unsigned Insn,
13781378
DecodeStatus S = MCDisassembler::Success;
13791379

13801380
unsigned Rn = fieldFromInstruction(Insn, 16, 4);
1381-
unsigned mode = fieldFromInstruction(Insn, 23, 2);
1382-
1383-
switch (mode) {
1384-
case 0:
1385-
mode = ARM_AM::da;
1386-
break;
1387-
case 1:
1388-
mode = ARM_AM::ia;
1389-
break;
1390-
case 2:
1391-
mode = ARM_AM::db;
1392-
break;
1393-
case 3:
1394-
mode = ARM_AM::ib;
1395-
break;
1396-
}
1397-
1398-
Inst.addOperand(MCOperand::createImm(mode));
13991381
if (!Check(S, DecodeGPRRegisterClass(Inst, Rn, Address, Decoder)))
14001382
return MCDisassembler::Fail;
14011383

@@ -2792,10 +2774,6 @@ static DecodeStatus DecodeMVEModImmInstruction(MCInst &Inst, unsigned Insn,
27922774

27932775
Inst.addOperand(MCOperand::createImm(imm));
27942776

2795-
Inst.addOperand(MCOperand::createImm(ARMVCC::None));
2796-
Inst.addOperand(MCOperand::createReg(0));
2797-
Inst.addOperand(MCOperand::createImm(0));
2798-
27992777
return S;
28002778
}
28012779

@@ -2820,7 +2798,6 @@ static DecodeStatus DecodeMVEVADCInstruction(MCInst &Inst, unsigned Insn,
28202798
return MCDisassembler::Fail;
28212799
if (!fieldFromInstruction(Insn, 12, 1)) // I bit clear => need input FPSCR
28222800
Inst.addOperand(MCOperand::createReg(ARM::FPSCR_NZCV));
2823-
Inst.addOperand(MCOperand::createImm(Qd));
28242801

28252802
return S;
28262803
}
@@ -5926,10 +5903,6 @@ static DecodeStatus DecodeMVEVCMP(MCInst &Inst, unsigned Insn, uint64_t Address,
59265903
if (!Check(S, predicate_decoder(Inst, fc, Address, Decoder)))
59275904
return MCDisassembler::Fail;
59285905

5929-
Inst.addOperand(MCOperand::createImm(ARMVCC::None));
5930-
Inst.addOperand(MCOperand::createReg(0));
5931-
Inst.addOperand(MCOperand::createImm(0));
5932-
59335906
return S;
59345907
}
59355908

@@ -6073,9 +6046,23 @@ DecodeStatus ARMDisassembler::getInstruction(MCInst &MI, uint64_t &Size,
60736046
ArrayRef<uint8_t> Bytes,
60746047
uint64_t Address,
60756048
raw_ostream &CS) const {
6049+
DecodeStatus S;
60766050
if (STI.hasFeature(ARM::ModeThumb))
6077-
return getThumbInstruction(MI, Size, Bytes, Address, CS);
6078-
return getARMInstruction(MI, Size, Bytes, Address, CS);
6051+
S = getThumbInstruction(MI, Size, Bytes, Address, CS);
6052+
else
6053+
S = getARMInstruction(MI, Size, Bytes, Address, CS);
6054+
if (S == DecodeStatus::Fail)
6055+
return S;
6056+
6057+
// Verify that the decoded instruction has the correct number of operands.
6058+
const MCInstrDesc &MCID = MCII->get(MI.getOpcode());
6059+
if (!MCID.isVariadic() && MI.getNumOperands() != MCID.getNumOperands()) {
6060+
reportFatalInternalError(MCII->getName(MI.getOpcode()) + ": expected " +
6061+
Twine(MCID.getNumOperands()) + " operands, got " +
6062+
Twine(MI.getNumOperands()) + "\n");
6063+
}
6064+
6065+
return S;
60796066
}
60806067

60816068
DecodeStatus ARMDisassembler::getARMInstruction(MCInst &MI, uint64_t &Size,
@@ -6114,7 +6101,7 @@ DecodeStatus ARMDisassembler::getARMInstruction(MCInst &MI, uint64_t &Size,
61146101
const DecodeTable Tables[] = {
61156102
{DecoderTableVFP32, false}, {DecoderTableVFPV832, false},
61166103
{DecoderTableNEONData32, true}, {DecoderTableNEONLoadStore32, true},
6117-
{DecoderTableNEONDup32, true}, {DecoderTablev8NEON32, false},
6104+
{DecoderTableNEONDup32, false}, {DecoderTablev8NEON32, false},
61186105
{DecoderTablev8Crypto32, false},
61196106
};
61206107

@@ -6124,8 +6111,10 @@ DecodeStatus ARMDisassembler::getARMInstruction(MCInst &MI, uint64_t &Size,
61246111
Size = 4;
61256112
// Add a fake predicate operand, because we share these instruction
61266113
// definitions with Thumb2 where these instructions are predicable.
6127-
if (Table.DecodePred && !DecodePredicateOperand(MI, 0xE, Address, this))
6128-
return MCDisassembler::Fail;
6114+
if (Table.DecodePred && MCII->get(MI.getOpcode()).isPredicable()) {
6115+
MI.addOperand(MCOperand::createImm(ARMCC::AL));
6116+
MI.addOperand(MCOperand::createReg(ARM::NoRegister));
6117+
}
61296118
return Result;
61306119
}
61316120
}
@@ -6159,8 +6148,6 @@ void ARMDisassembler::AddThumb1SBit(MCInst &MI, bool InITBlock) const {
61596148
return;
61606149
}
61616150
}
6162-
6163-
MI.insert(I, MCOperand::createReg(InITBlock ? ARM::NoRegister : ARM::CPSR));
61646151
}
61656152

61666153
bool ARMDisassembler::isVectorPredicable(const MCInst &MI) const {
@@ -6291,13 +6278,12 @@ ARMDisassembler::AddThumbPredicate(MCInst &MI) const {
62916278
return S;
62926279
}
62936280

6294-
// Thumb VFP instructions are a special case. Because we share their
6295-
// encodings between ARM and Thumb modes, and they are predicable in ARM
6281+
// Thumb VFP and some NEON instructions are a special case. Because we share
6282+
// their encodings between ARM and Thumb modes, and they are predicable in ARM
62966283
// mode, the auto-generated decoder will give them an (incorrect)
62976284
// predicate operand. We need to rewrite these operands based on the IT
62986285
// context as a post-pass.
6299-
void ARMDisassembler::UpdateThumbVFPPredicate(
6300-
DecodeStatus &S, MCInst &MI) const {
6286+
void ARMDisassembler::UpdateThumbPredicate(DecodeStatus &S, MCInst &MI) const {
63016287
unsigned CC;
63026288
CC = ITBlock.getITCC();
63036289
if (CC == 0xF)
@@ -6444,7 +6430,7 @@ DecodeStatus ARMDisassembler::getThumbInstruction(MCInst &MI, uint64_t &Size,
64446430
decodeInstruction(DecoderTableVFP32, MI, Insn32, Address, this, STI);
64456431
if (Result != MCDisassembler::Fail) {
64466432
Size = 4;
6447-
UpdateThumbVFPPredicate(Result, MI);
6433+
UpdateThumbPredicate(Result, MI);
64486434
return Result;
64496435
}
64506436
}
@@ -6461,7 +6447,7 @@ DecodeStatus ARMDisassembler::getThumbInstruction(MCInst &MI, uint64_t &Size,
64616447
STI);
64626448
if (Result != MCDisassembler::Fail) {
64636449
Size = 4;
6464-
Check(Result, AddThumbPredicate(MI));
6450+
UpdateThumbPredicate(Result, MI);
64656451
return Result;
64666452
}
64676453
}

llvm/test/MC/Disassembler/ARM/arm-tests.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -354,7 +354,7 @@
354354
# CHECK: strheq r0, [r0, -r0]
355355
0xb0 0x00 0x00 0x01
356356

357-
# CHECK: rfedb #4!
357+
# CHECK: rfedb r2!
358358
0x14 0x0 0x32 0xf9
359359

360360
# CHECK: stc2l p0, c0, [r2], #-96

0 commit comments

Comments
 (0)