aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2022-01-27 22:06:42 +0000
committerDimitry Andric <dim@FreeBSD.org>2022-01-27 22:06:42 +0000
commit6f8fc217eaa12bf657be1c6468ed9938d10168b3 (patch)
treea1fd89b864d9b93e2ad68fe1dcf7afee2e3c8d76 /llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp
parent77fc4c146f0870ffb09c1afb823ccbe742c5e6ff (diff)
Diffstat (limited to 'llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp')
-rw-r--r--llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp55
1 files changed, 55 insertions, 0 deletions
diff --git a/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp b/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp
index 96d410e42be2..9ce00f76d9c7 100644
--- a/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp
+++ b/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp
@@ -238,6 +238,12 @@ static DecodeStatus DecodeSVEIncDecImm(MCInst &Inst, unsigned Imm,
uint64_t Addr, const void *Decoder);
static DecodeStatus DecodeSVCROp(MCInst &Inst, unsigned Imm, uint64_t Address,
const void *Decoder);
+static DecodeStatus DecodeCPYMemOpInstruction(MCInst &Inst, uint32_t insn,
+ uint64_t Addr,
+ const void *Decoder);
+static DecodeStatus DecodeSETMemOpInstruction(MCInst &Inst, uint32_t insn,
+ uint64_t Addr,
+ const void *Decoder);
static bool Check(DecodeStatus &Out, DecodeStatus In) {
switch (In) {
@@ -1842,3 +1848,52 @@ static DecodeStatus DecodeSVCROp(MCInst &Inst, unsigned Imm, uint64_t Address,
}
return Fail;
}
+
+static DecodeStatus DecodeCPYMemOpInstruction(MCInst &Inst, uint32_t insn,
+ uint64_t Addr,
+ const void *Decoder) {
+ unsigned Rd = fieldFromInstruction(insn, 0, 5);
+ unsigned Rs = fieldFromInstruction(insn, 16, 5);
+ unsigned Rn = fieldFromInstruction(insn, 5, 5);
+
+ // None of the registers may alias: if they do, then the instruction is not
+ // merely unpredictable but actually entirely unallocated.
+ if (Rd == Rs || Rs == Rn || Rd == Rn)
+ return MCDisassembler::Fail;
+
+ // All three register operands are written back, so they all appear
+ // twice in the operand list, once as outputs and once as inputs.
+ if (!DecodeGPR64commonRegisterClass(Inst, Rd, Addr, Decoder) ||
+ !DecodeGPR64commonRegisterClass(Inst, Rs, Addr, Decoder) ||
+ !DecodeGPR64RegisterClass(Inst, Rn, Addr, Decoder) ||
+ !DecodeGPR64commonRegisterClass(Inst, Rd, Addr, Decoder) ||
+ !DecodeGPR64commonRegisterClass(Inst, Rs, Addr, Decoder) ||
+ !DecodeGPR64RegisterClass(Inst, Rn, Addr, Decoder))
+ return MCDisassembler::Fail;
+
+ return MCDisassembler::Success;
+}
+
+static DecodeStatus DecodeSETMemOpInstruction(MCInst &Inst, uint32_t insn,
+ uint64_t Addr,
+ const void *Decoder) {
+ unsigned Rd = fieldFromInstruction(insn, 0, 5);
+ unsigned Rm = fieldFromInstruction(insn, 16, 5);
+ unsigned Rn = fieldFromInstruction(insn, 5, 5);
+
+ // None of the registers may alias: if they do, then the instruction is not
+ // merely unpredictable but actually entirely unallocated.
+ if (Rd == Rm || Rm == Rn || Rd == Rn)
+ return MCDisassembler::Fail;
+
+ // Rd and Rn (not Rm) register operands are written back, so they appear
+ // twice in the operand list, once as outputs and once as inputs.
+ if (!DecodeGPR64commonRegisterClass(Inst, Rd, Addr, Decoder) ||
+ !DecodeGPR64RegisterClass(Inst, Rn, Addr, Decoder) ||
+ !DecodeGPR64commonRegisterClass(Inst, Rd, Addr, Decoder) ||
+ !DecodeGPR64RegisterClass(Inst, Rn, Addr, Decoder) ||
+ !DecodeGPR64RegisterClass(Inst, Rm, Addr, Decoder))
+ return MCDisassembler::Fail;
+
+ return MCDisassembler::Success;
+}