[clang] [llvm] [MSP430X] Extended shift instructions (PR #231910)
via cfe-commits
cfe-commits at lists.llvm.org
Sun Oct 25 12:44:35 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-backend-msp430
Author: Robin Mueller (robamu)
<details>
<summary>Changes</summary>
- Add RRCM, RRAM, RRUM, RLAM, RRCX, RRAX, RRUX and RLAX for -mcpu=msp430x
- Encode extended instructions with the extension word in the low bits,
matching their order in memory
- Disassemble MSP430X address instructions and extension words
- Report an error for instructions that need a disabled CPU feature.
They were silently dropped before
Based on https://reviews.llvm.org/D110723, reworked for current
TableGen.
Co-authored-by: Jozef Lawrynowicz <jozefl.opensrc@<!-- -->gmail.com>
Assisted-by: Claude Opus 5.5 <noreply@<!-- -->anthropic.com>
---
Patch is 34.61 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/231910.diff
21 Files Affected:
- (modified) clang/lib/Basic/Targets/MSP430.cpp (+2)
- (modified) clang/lib/Basic/Targets/MSP430.h (+17-1)
- (modified) clang/lib/Driver/ToolChains/CommonArgs.cpp (+3)
- (modified) clang/lib/Driver/ToolChains/Gnu.cpp (+11-12)
- (modified) clang/lib/Driver/ToolChains/MSP430.cpp (+18)
- (modified) clang/lib/Driver/ToolChains/MSP430.h (+2)
- (added) clang/test/Driver/msp430-cpu.c (+25)
- (modified) clang/test/Driver/msp430-toolchain.c (+28)
- (added) clang/test/Preprocessor/msp430-defs.c (+9)
- (modified) llvm/lib/Target/MSP430/AsmParser/MSP430AsmParser.cpp (+17-4)
- (modified) llvm/lib/Target/MSP430/Disassembler/MSP430Disassembler.cpp (+54-2)
- (modified) llvm/lib/Target/MSP430/MCTargetDesc/MSP430MCCodeEmitter.cpp (+18)
- (modified) llvm/lib/Target/MSP430/MSP430InstrFormats.td (+95)
- (modified) llvm/lib/Target/MSP430/MSP430InstrInfo.td (+9)
- (added) llvm/lib/Target/MSP430/MSP430InstrInfoExtended.td (+84)
- (modified) llvm/lib/Target/MSP430/MSP430Subtarget.h (+2)
- (added) llvm/test/MC/Disassembler/MSP430/msp430x-invalid.txt (+13)
- (added) llvm/test/MC/Disassembler/MSP430/msp430x.txt (+18)
- (added) llvm/test/MC/MSP430/msp430x-feature.s (+9)
- (added) llvm/test/MC/MSP430/shifts-430x-invalid.s (+23)
- (added) llvm/test/MC/MSP430/shifts-430x.s (+101)
``````````diff
diff --git a/clang/lib/Basic/Targets/MSP430.cpp b/clang/lib/Basic/Targets/MSP430.cpp
index 844f5d3af70379..989927a8c5ab69 100644
--- a/clang/lib/Basic/Targets/MSP430.cpp
+++ b/clang/lib/Basic/Targets/MSP430.cpp
@@ -29,5 +29,7 @@ void MSP430TargetInfo::getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const {
Builder.defineMacro("MSP430");
Builder.defineMacro("__MSP430__");
+ if (CPU == "msp430x")
+ Builder.defineMacro("__MSP430X__");
// FIXME: defines for different 'flavours' of MCU
}
diff --git a/clang/lib/Basic/Targets/MSP430.h b/clang/lib/Basic/Targets/MSP430.h
index 96a243ef70fae5..fceb7c6e68e201 100644
--- a/clang/lib/Basic/Targets/MSP430.h
+++ b/clang/lib/Basic/Targets/MSP430.h
@@ -23,6 +23,7 @@ namespace targets {
class LLVM_LIBRARY_VISIBILITY MSP430TargetInfo : public TargetInfo {
static const char *const GCCRegNames[];
+ std::string CPU;
public:
MSP430TargetInfo(const llvm::Triple &Triple, const TargetOptions &)
@@ -55,10 +56,25 @@ class LLVM_LIBRARY_VISIBILITY MSP430TargetInfo : public TargetInfo {
return {};
}
+ bool isValidCPUName(StringRef Name) const override {
+ return Name == "msp430" || Name == "msp430x";
+ }
+
+ void fillValidCPUList(SmallVectorImpl<StringRef> &Values) const override {
+ Values.append({"msp430", "msp430x"});
+ }
+
+ bool setCPU(StringRef Name) override {
+ if (!isValidCPUName(Name))
+ return false;
+ CPU = Name;
+ return true;
+ }
+
bool allowsLargerPreferedTypeAlignment() const override { return false; }
bool hasFeature(StringRef Feature) const override {
- return Feature == "msp430";
+ return Feature == "msp430" || (Feature == "msp430x" && CPU == "msp430x");
}
ArrayRef<const char *> getGCCRegNames() const override;
diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp
index 39dcec2f823bdd..08ae8329433452 100644
--- a/clang/lib/Driver/ToolChains/CommonArgs.cpp
+++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp
@@ -810,6 +810,9 @@ std::string tools::getCPUName(const Driver &D, const ArgList &Args,
return std::string(CPUName);
}
+ case llvm::Triple::msp430:
+ return msp430::getMSP430TargetCPU(Args);
+
case llvm::Triple::nvptx:
case llvm::Triple::nvptx64:
if (const Arg *A = Args.getLastArg(options::OPT_march_EQ))
diff --git a/clang/lib/Driver/ToolChains/Gnu.cpp b/clang/lib/Driver/ToolChains/Gnu.cpp
index 90fc71c147364d..0a58b251d0e693 100644
--- a/clang/lib/Driver/ToolChains/Gnu.cpp
+++ b/clang/lib/Driver/ToolChains/Gnu.cpp
@@ -1529,20 +1529,19 @@ static bool findMSP430Multilibs(const Driver &D,
StringRef Path, const ArgList &Args,
DetectedMultilibs &Result) {
FilterNonExistent NonExistent(Path, "/crtbegin.o", D.getVFS());
- MultilibBuilder WithoutExceptions =
- MultilibBuilder("/430").flag("-exceptions", /*Disallow=*/true);
- MultilibBuilder WithExceptions =
- MultilibBuilder("/430/exceptions").flag("-exceptions");
-
- // FIXME: when clang starts to support msp430x ISA additional logic
- // to select between multilib must be implemented
- // MultilibBuilder MSP430xMultilib = MultilibBuilder("/large");
-
- Result.Multilibs.push_back(WithoutExceptions.makeMultilib());
- Result.Multilibs.push_back(WithExceptions.makeMultilib());
- Result.Multilibs.FilterOut(NonExistent);
+ // The MSP430X libraries are in the root, the plain MSP430 ones in /430.
+ // FIXME: Add the /large multilibs once LLVM supports the large memory model.
+ Result.Multilibs =
+ MultilibSetBuilder()
+ .Either(MultilibBuilder().flag("-msp430x"),
+ MultilibBuilder("/430").flag("-msp430x", /*Disallow=*/true))
+ .Maybe(MultilibBuilder("/exceptions").flag("-exceptions"))
+ .makeMultilibSet()
+ .FilterOut(NonExistent);
Multilib::flags_list Flags;
+ std::string CPU = tools::getCPUName(D, Args, TargetTriple);
+ addMultilibFlag(CPU == "msp430x", "-msp430x", Flags);
addMultilibFlag(Args.hasFlag(options::OPT_fexceptions,
options::OPT_fno_exceptions, false),
"-exceptions", Flags);
diff --git a/clang/lib/Driver/ToolChains/MSP430.cpp b/clang/lib/Driver/ToolChains/MSP430.cpp
index 4bd12d1e130e53..5259e0721bdb26 100644
--- a/clang/lib/Driver/ToolChains/MSP430.cpp
+++ b/clang/lib/Driver/ToolChains/MSP430.cpp
@@ -13,6 +13,7 @@
#include "clang/Driver/InputInfo.h"
#include "clang/Driver/Multilib.h"
#include "clang/Options/Options.h"
+#include "llvm/ADT/StringSwitch.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Support/Path.h"
@@ -52,6 +53,23 @@ static StringRef getHWMultLib(const ArgList &Args) {
.Default("-lmul_none");
}
+static bool isMSP430X(StringRef CPU) {
+ return CPU == "msp430x" || CPU == "msp430xv2";
+}
+
+std::string msp430::getMSP430TargetCPU(const ArgList &Args) {
+ if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ))
+ return isMSP430X(A->getValue()) ? "msp430x" : A->getValue();
+ if (const Arg *A = Args.getLastArg(options::OPT_mmcu_EQ)) {
+ StringRef CPU = llvm::StringSwitch<StringRef>(A->getValue())
+#define MSP430_MCU(NAME, CPU, HWMULT) .Case(NAME, CPU)
+#include "clang/Basic/MSP430Target.def"
+ .Default("");
+ return isMSP430X(CPU) ? "msp430x" : CPU.str();
+ }
+ return "";
+}
+
void msp430::getMSP430TargetFeatures(const Driver &D, const ArgList &Args,
std::vector<StringRef> &Features) {
const Arg *MCU = Args.getLastArg(options::OPT_mmcu_EQ);
diff --git a/clang/lib/Driver/ToolChains/MSP430.h b/clang/lib/Driver/ToolChains/MSP430.h
index 865bcfb7cd3da6..3539c62430f675 100644
--- a/clang/lib/Driver/ToolChains/MSP430.h
+++ b/clang/lib/Driver/ToolChains/MSP430.h
@@ -80,6 +80,8 @@ class LLVM_LIBRARY_VISIBILITY Linker final : public Tool {
void getMSP430TargetFeatures(const Driver &D, const llvm::opt::ArgList &Args,
std::vector<llvm::StringRef> &Features);
+std::string getMSP430TargetCPU(const llvm::opt::ArgList &Args);
+
} // end namespace msp430
} // end namespace tools
} // end namespace driver
diff --git a/clang/test/Driver/msp430-cpu.c b/clang/test/Driver/msp430-cpu.c
new file mode 100644
index 00000000000000..d09272436f5700
--- /dev/null
+++ b/clang/test/Driver/msp430-cpu.c
@@ -0,0 +1,25 @@
+// RUN: %clang -### -c %s --target=msp430 2>&1 \
+// RUN: | FileCheck -check-prefix=NO-CPU %s
+// NO-CPU-NOT: "-target-cpu"
+
+// RUN: %clang -### -c %s --target=msp430 -mcpu=msp430 2>&1 \
+// RUN: | FileCheck -check-prefix=MSP430 %s
+// RUN: %clang -### -c %s --target=msp430 -mmcu=msp430c111 2>&1 \
+// RUN: | FileCheck -check-prefix=MSP430 %s
+// MSP430: "-cc1"{{.*}} "-target-cpu" "msp430"
+
+// msp430xv2 is accepted for GCC compatibility and treated as msp430x.
+// RUN: %clang -### -c %s --target=msp430 -mcpu=msp430x 2>&1 \
+// RUN: | FileCheck -check-prefix=MSP430X %s
+// RUN: %clang -### -c %s --target=msp430 -mcpu=msp430xv2 2>&1 \
+// RUN: | FileCheck -check-prefix=MSP430X %s
+// RUN: %clang -### -c %s --target=msp430 -mmcu=msp430f2617 2>&1 \
+// RUN: | FileCheck -check-prefix=MSP430X %s
+// RUN: %clang -### -c %s --target=msp430 -mmcu=msp430f5529 2>&1 \
+// RUN: | FileCheck -check-prefix=MSP430X %s
+// MSP430X: "-cc1"{{.*}} "-target-cpu" "msp430x"
+
+// RUN: not %clang -c %s --target=msp430 -mcpu=not-a-cpu -o /dev/null 2>&1 \
+// RUN: | FileCheck -check-prefix=INVALID %s
+// INVALID: error: unknown target CPU 'not-a-cpu'
+// INVALID-NEXT: note: valid target CPU values are: msp430, msp430x
diff --git a/clang/test/Driver/msp430-toolchain.c b/clang/test/Driver/msp430-toolchain.c
index 45010deb40a54d..45de069b0aafe9 100644
--- a/clang/test/Driver/msp430-toolchain.c
+++ b/clang/test/Driver/msp430-toolchain.c
@@ -126,6 +126,34 @@
// LIBS-EXC-NEG-NOT: "{{.*}}/430"
// LIBS-EXC-NEG-NOT: "{{.*}}430/crt{{.*}}"
+// The MSP430X multilibs are in the root, not in /430.
+// RUN: %clang -### %s --target=msp430 -mcpu=msp430x -rtlib=libgcc \
+// RUN: --sysroot="%S/Inputs/basic_msp430_tree" > %t 2>&1
+// RUN: FileCheck -check-prefix=LIBS-430X-POS %s < %t
+// RUN: FileCheck -check-prefix=LIBS-430X-NEG %s < %t
+// RUN: %clang -### %s --target=msp430 -mmcu=msp430f5529 -rtlib=libgcc \
+// RUN: --sysroot="%S/Inputs/basic_msp430_tree" > %t 2>&1
+// RUN: FileCheck -check-prefix=LIBS-430X-POS %s < %t
+// RUN: FileCheck -check-prefix=LIBS-430X-NEG %s < %t
+// LIBS-430X-POS: "{{.*}}/Inputs/basic_msp430_tree{{/|\\\\}}msp430-elf{{/|\\\\}}lib{{/|\\\\}}crt0.o"
+// LIBS-430X-POS: "{{.*}}/Inputs/basic_msp430_tree/lib/gcc/msp430-elf/8.3.1{{/|\\\\}}crtbegin_no_eh.o"
+// LIBS-430X-POS: "-L{{.*}}/Inputs/basic_msp430_tree/lib/gcc/msp430-elf/8.3.1{{/|\\\\}}"
+// LIBS-430X-POS: "-L{{.*}}/Inputs/basic_msp430_tree{{/|\\\\}}msp430-elf{{/|\\\\}}lib{{/|\\\\}}"
+// LIBS-430X-POS: "{{.*}}/Inputs/basic_msp430_tree/lib/gcc/msp430-elf/8.3.1{{/|\\\\}}crtend_no_eh.o"
+// LIBS-430X-NEG-NOT: /430
+// LIBS-430X-NEG-NOT: /exceptions
+
+// RUN: %clang -### %s --target=msp430 -mcpu=msp430x -rtlib=libgcc -fexceptions \
+// RUN: --sysroot="%S/Inputs/basic_msp430_tree" > %t 2>&1
+// RUN: FileCheck -check-prefix=LIBS-430X-EXC-POS %s < %t
+// RUN: FileCheck -check-prefix=LIBS-430X-EXC-NEG %s < %t
+// LIBS-430X-EXC-POS: "{{.*}}/Inputs/basic_msp430_tree{{/|\\\\}}msp430-elf{{/|\\\\}}lib/exceptions{{/|\\\\}}crt0.o"
+// LIBS-430X-EXC-POS: "{{.*}}/Inputs/basic_msp430_tree/lib/gcc/msp430-elf/8.3.1/exceptions{{/|\\\\}}crtbegin.o"
+// LIBS-430X-EXC-POS: "-L{{.*}}/Inputs/basic_msp430_tree/lib/gcc/msp430-elf/8.3.1/exceptions"
+// LIBS-430X-EXC-POS: "-L{{.*}}/Inputs/basic_msp430_tree{{/|\\\\}}msp430-elf{{/|\\\\}}lib/exceptions"
+// LIBS-430X-EXC-POS: "{{.*}}/Inputs/basic_msp430_tree/lib/gcc/msp430-elf/8.3.1/exceptions{{/|\\\\}}crtend.o"
+// LIBS-430X-EXC-NEG-NOT: /430
+
// RUN: %clang -### %s --target=msp430 -rtlib=libgcc \
// RUN: -fstack-protector --sysroot="%S/Inputs/basic_msp430_tree" 2>&1 \
// RUN: | FileCheck -check-prefix=LIBS-SSP %s
diff --git a/clang/test/Preprocessor/msp430-defs.c b/clang/test/Preprocessor/msp430-defs.c
new file mode 100644
index 00000000000000..6eea5c6e7521cc
--- /dev/null
+++ b/clang/test/Preprocessor/msp430-defs.c
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -triple msp430 -E -dM %s -o - \
+// RUN: | FileCheck -check-prefix=MSP430 %s
+// RUN: %clang_cc1 -triple msp430 -target-cpu msp430 -E -dM %s -o - \
+// RUN: | FileCheck -check-prefix=MSP430 %s
+// MSP430-NOT: #define __MSP430X__
+
+// RUN: %clang_cc1 -triple msp430 -target-cpu msp430x -E -dM %s -o - \
+// RUN: | FileCheck -check-prefix=MSP430X %s
+// MSP430X: #define __MSP430X__ 1
diff --git a/llvm/lib/Target/MSP430/AsmParser/MSP430AsmParser.cpp b/llvm/lib/Target/MSP430/AsmParser/MSP430AsmParser.cpp
index 847ca9b6297042..d21e1cb024d907 100644
--- a/llvm/lib/Target/MSP430/AsmParser/MSP430AsmParser.cpp
+++ b/llvm/lib/Target/MSP430/AsmParser/MSP430AsmParser.cpp
@@ -162,11 +162,8 @@ class MSP430Operand : public MCParsedAsmOperand {
bool isPostIndReg() const { return Kind == k_PostIndReg; }
bool isCGImm() const {
- if (Kind != k_Imm)
- return false;
-
int64_t Val;
- if (!Imm->evaluateAsAbsolute(Val))
+ if (!isImm() || !Imm->evaluateAsAbsolute(Val))
return false;
if (Val == 0 || Val == 1 || Val == 2 || Val == 4 || Val == 8 || Val == -1)
@@ -175,6 +172,19 @@ class MSP430Operand : public MCParsedAsmOperand {
return false;
}
+ /// Shift count of the MSP430X multi-bit shifts (RRAM, RRUM, RLAM). It is
+ /// encoded as count - 1 in a 2-bit field, so only 1 to 4 is valid.
+ bool isRpt2Imm() const {
+ int64_t Val;
+ if (!isImm() || !Imm->evaluateAsAbsolute(Val))
+ return false;
+
+ if (Val >= 1 && Val <= 4)
+ return true;
+
+ return false;
+ }
+
StringRef getToken() const {
assert(Kind == k_Tok && "Invalid access!");
return Tok;
@@ -265,6 +275,9 @@ bool MSP430AsmParser::matchAndEmitInstruction(SMLoc Loc, unsigned &Opcode,
return false;
case Match_MnemonicFail:
return Error(Loc, "invalid instruction mnemonic");
+ case Match_MissingFeature:
+ return Error(Loc,
+ "instruction requires a CPU feature not currently enabled");
case Match_InvalidOperand: {
SMLoc ErrorLoc = Loc;
if (ErrorInfo != ~0U) {
diff --git a/llvm/lib/Target/MSP430/Disassembler/MSP430Disassembler.cpp b/llvm/lib/Target/MSP430/Disassembler/MSP430Disassembler.cpp
index e6666e8cafdf9d..3f473bc1504801 100644
--- a/llvm/lib/Target/MSP430/Disassembler/MSP430Disassembler.cpp
+++ b/llvm/lib/Target/MSP430/Disassembler/MSP430Disassembler.cpp
@@ -44,6 +44,10 @@ class MSP430Disassembler : public MCDisassembler {
ArrayRef<uint8_t> Bytes, uint64_t Address,
raw_ostream &CStream) const;
+ DecodeStatus getInstructionX(MCInst &MI, uint64_t &Size,
+ ArrayRef<uint8_t> Bytes, uint64_t Address,
+ raw_ostream &CStream) const;
+
public:
MSP430Disassembler(const MCSubtargetInfo &STI, MCContext &Ctx)
: MCDisassembler(STI, Ctx) {}
@@ -119,6 +123,15 @@ static DecodeStatus DecodeCGImm(MCInst &MI, uint64_t Bits, uint64_t Address,
return MCDisassembler::Success;
}
+/// Decode the 2-bit shift count of RRCM, RRAM, RRUM and RLAM. It is stored as
+/// count - 1.
+static DecodeStatus decodeRpt2Imm(MCInst &MI, uint64_t Bits, uint64_t Address,
+ const MCDisassembler *Decoder) {
+ int64_t Imm = Bits + 1;
+ MI.addOperand(MCOperand::createImm(Imm));
+ return MCDisassembler::Success;
+}
+
static DecodeStatus DecodeMemOperand(MCInst &MI, uint64_t Bits,
uint64_t Address,
const MCDisassembler *Decoder) {
@@ -353,6 +366,37 @@ DecodeStatus MSP430Disassembler::getInstructionCJ(MCInst &MI, uint64_t &Size,
return DecodeStatus::Success;
}
+static bool isExtensionWord(uint64_t Word) { return (Word & 0xf800) == 0x1800; }
+
+DecodeStatus MSP430Disassembler::getInstructionX(MCInst &MI, uint64_t &Size,
+ ArrayRef<uint8_t> Bytes,
+ uint64_t Address,
+ raw_ostream &CStream) const {
+ uint64_t Insn = support::endian::read16le(Bytes.data());
+ unsigned Words = 1;
+ if (isExtensionWord(Insn)) {
+ if (Bytes.size() < 4) {
+ Size = 2;
+ return DecodeStatus::Fail;
+ }
+ Insn |= (uint64_t)support::endian::read16le(Bytes.data() + 2) << 16;
+ Words = 2;
+ }
+
+ // MSP430X32 decodes the extension word together with the following Format I
+ // or II word. Each combination is its own instruction, like RRCX_16 or
+ // ADDX16rr, so the plain Format I and II tables are not used here.
+ const uint8_t *DecoderTable =
+ Words == 2 ? DecoderTableMSP430X32 : DecoderTableMSP430X16;
+ DecodeStatus Result =
+ decodeInstruction(DecoderTable, MI, Insn, Address, this, STI);
+ // The word after an extension word is a valid Format I or II instruction on
+ // its own. Skip it on failure too, so it is not shown without the extension
+ // word.
+ Size = Words * 2;
+ return Result;
+}
+
DecodeStatus MSP430Disassembler::getInstruction(MCInst &MI, uint64_t &Size,
ArrayRef<uint8_t> Bytes,
uint64_t Address,
@@ -362,10 +406,18 @@ DecodeStatus MSP430Disassembler::getInstruction(MCInst &MI, uint64_t &Size,
return MCDisassembler::Fail;
}
+ // The first word selects the instruction format:
+ // 0x0000-0x0fff MSP430X address instructions
+ // 0x1000-0x17ff Format II
+ // 0x1800-0x1fff MSP430X extension word, followed by a Format I or II word
+ // 0x2000-0x3fff Jumps
+ // 0x4000-0xffff Format I
uint64_t Insn = support::endian::read16le(Bytes.data());
- unsigned Opc = fieldFromInstruction(Insn, 13, 3);
- switch (Opc) {
+ unsigned FormatBits = fieldFromInstruction(Insn, 13, 3);
+ switch (FormatBits) {
case 0:
+ if (!(Insn & 0x1000) || isExtensionWord(Insn))
+ return getInstructionX(MI, Size, Bytes, Address, CStream);
return getInstructionII(MI, Size, Bytes, Address, CStream);
case 1:
return getInstructionCJ(MI, Size, Bytes, Address, CStream);
diff --git a/llvm/lib/Target/MSP430/MCTargetDesc/MSP430MCCodeEmitter.cpp b/llvm/lib/Target/MSP430/MCTargetDesc/MSP430MCCodeEmitter.cpp
index f018bdbeb0bfbc..0436434658049e 100644
--- a/llvm/lib/Target/MSP430/MCTargetDesc/MSP430MCCodeEmitter.cpp
+++ b/llvm/lib/Target/MSP430/MCTargetDesc/MSP430MCCodeEmitter.cpp
@@ -64,6 +64,12 @@ class MSP430MCCodeEmitter : public MCCodeEmitter {
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const;
+ /// Encode the repetition count for a 430X extended format exception
+ /// instruction.
+ unsigned getRpt2ImmOpValue(const MCInst &MI, unsigned Op,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const;
+
unsigned getCCOpValue(const MCInst &MI, unsigned Op,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const;
@@ -192,6 +198,18 @@ unsigned MSP430MCCodeEmitter::getCGImmOpValue(const MCInst &MI, unsigned Op,
}
}
+unsigned
+MSP430MCCodeEmitter::getRpt2ImmOpValue(const MCInst &MI, unsigned Op,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const {
+ const MCOperand &MO = MI.getOperand(Op);
+ assert(MO.isImm() && "expr operand expected");
+
+ int64_t Imm = MO.getImm();
+ assert((Imm >= 1 && Imm <= 4) && "invalid repetition count");
+ return Imm - 1;
+}
+
unsigned MSP430MCCodeEmitter::getCCOpValue(const MCInst &MI, unsigned Op,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const {
diff --git a/llvm/lib/Target/MSP430/MSP430InstrFormats.td b/llvm/lib/Target/MSP430/MSP430InstrFormats.td
index 0e784aa4ff9144..f850100cd2eddc 100644
--- a/llvm/lib/Target/MSP430/MSP430InstrFormats.td
+++ b/llvm/lib/Target/MSP430/MSP430InstrFormats.td
@@ -28,6 +28,13 @@ class DestMode<bit val> {
def DstReg : DestMode<0>; // r
def DstMem : DestMode<1>; // m
+class ALKind<bit val> {
+ bit Value = val;
+}
+
+def ALAddr : ALKind<0>;
+def ALWord : ALKind<1>;
+
// Generic MSP430 Format
class MSP430Inst<dag outs, dag ins, int size, string asmstr> : Instruction {
field bits<48> Inst;
@@ -432,6 +439,94 @@ class CJForm<dag outs, dag ins, string asmstr, list<dag> pattern>
let Inst{9-0} = dst;
}
+// RRCM, RRAM, RRUM and RLAM. Single-word MSP430X instructions with their own
+// layout in the Format II opcode space, without an extension word. TI calls
+// them Format II exceptions.
+class IIExtExcRotForm<bits<2> opcode, ALKind al,
+ dag outs, dag ins, string asmstr, list<dag> pattern>
+ : MSP430Inst<outs, ins, 2, asmstr> {
+ let Pattern = pattern;
+ let DecoderNamespace = "MSP430X";
+
+ bits<4> rd;
+ bits<2> cnt;
+
+ let Inst{15-12} = 0b0000;
+ let Inst{11-10} = cnt;
+ let Inst{9-8} = opcode;
+ let Inst{7-5} = 0b010;
+ let Inst{4} = al.Value;
+ let Inst{3-0} = rd;
+}
+
+class IIExtExcRotForm16<bits<2> opcode,
+ dag outs, dag ins, string asmstr, list<dag> pattern>
+ : IIExtExcRotForm<opcode, ALWord, outs, ins, asmstr, pattern>;
+
+// MSP430X extended instructions in register mode.
+//
+// The extension word precedes the instruction word in memory, so it occupies
+// Inst{15-0} and the instruction word is in Inst{31-16}.
+//
+// FIXME: Add the non-register mode, which is needed for 20-bit memory
+// operands.
+class ExtRegForm<bit zc, bit rpt, ALKind al,
+ dag outs, dag ins, string asmstr, list<dag> pattern>
+ : MSP430Inst<outs, ins, 4, asmstr> {
+ let Pattern = pattern;
+ let DecoderNamespace = "MSP430X";
+
+ bits<4> cnt = 0;
+
+ let Inst{15-9} = 0b0001100;
+ let Inst{8} = zc;
+ let Inst{7} = rpt;
+ let Inst{6} = al.Value;
+ let Inst{5-4} = 0b00;
...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/231910
More information about the cfe-commits
mailing list