https://github.com/robamu updated 
https://github.com/llvm/llvm-project/pull/231910

>From 57a5269cfa25e50d1afa7e586dc457fb03ccc710 Mon Sep 17 00:00:00 2001
From: Robin Mueller <[email protected]>
Date: Thu, 1 Oct 2026 13:52:04 +0200
Subject: [PATCH 1/2] [MSP430][Clang] MSP430X Target CPU selection

- Pass -target-cpu to LLVM, taken from `-mcpu` or derived from `-mmcu`.
- Unknown `-mcpu` values for MSP430 are rejected now
- `-mcpu=msp430x` and `-mcpu=msp430xv2` are both mapped to msp430x. The
  newer revision does not change the generated code, only CPU cycle
  counts
- The information can also be derived from `-mmcu` only using the target
  table, which contains the CPU type.
- Added `MSP430X` and `__MSP430X__` defines. The `__MSP430X__` define matches 
GCC
- Updated GCC Multilib finder to use the GCC root libraries (MSP430X) for
  the MSP430X CPU target. Otherwise, it will still use the /430
  subdirectory like before.

Based on https://reviews.llvm.org/D109174.

Co-authored-by: Jozef Lawrynowicz <[email protected]>
Assisted-by: Claude Code (Claude Opus 5.5)
---
 clang/lib/Basic/Targets/MSP430.cpp         |  2 ++
 clang/lib/Basic/Targets/MSP430.h           | 18 +++++++++++++-
 clang/lib/Driver/ToolChains/CommonArgs.cpp |  3 +++
 clang/lib/Driver/ToolChains/Gnu.cpp        | 23 +++++++++---------
 clang/lib/Driver/ToolChains/MSP430.cpp     | 18 ++++++++++++++
 clang/lib/Driver/ToolChains/MSP430.h       |  2 ++
 clang/test/Driver/msp430-cpu.c             | 25 +++++++++++++++++++
 clang/test/Driver/msp430-toolchain.c       | 28 ++++++++++++++++++++++
 clang/test/Preprocessor/msp430-defs.c      |  9 +++++++
 9 files changed, 115 insertions(+), 13 deletions(-)
 create mode 100644 clang/test/Driver/msp430-cpu.c
 create mode 100644 clang/test/Preprocessor/msp430-defs.c

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

>From 9e20f75a0258394cbc8372ef98ab757dcb59551c Mon Sep 17 00:00:00 2001
From: Robin Mueller <[email protected]>
Date: Thu, 1 Oct 2026 15:56:25 +0200
Subject: [PATCH 2/2] [MSP430] Add assembler support for MSP430X shift
 instructions

- 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 <[email protected]>
Assisted-by: Claude Opus 5.5 <[email protected]>
---
 .../MSP430/AsmParser/MSP430AsmParser.cpp      |  21 +++-
 .../Disassembler/MSP430Disassembler.cpp       |  56 +++++++++-
 .../MCTargetDesc/MSP430MCCodeEmitter.cpp      |  18 ++++
 llvm/lib/Target/MSP430/MSP430InstrFormats.td  |  95 ++++++++++++++++
 llvm/lib/Target/MSP430/MSP430InstrInfo.td     |   9 ++
 .../Target/MSP430/MSP430InstrInfoExtended.td  |  84 +++++++++++++++
 llvm/lib/Target/MSP430/MSP430Subtarget.h      |   2 +
 .../Disassembler/MSP430/msp430x-invalid.txt   |  13 +++
 llvm/test/MC/Disassembler/MSP430/msp430x.txt  |  18 ++++
 llvm/test/MC/MSP430/msp430x-feature.s         |   9 ++
 llvm/test/MC/MSP430/shifts-430x-invalid.s     |  23 ++++
 llvm/test/MC/MSP430/shifts-430x.s             | 101 ++++++++++++++++++
 12 files changed, 443 insertions(+), 6 deletions(-)
 create mode 100644 llvm/lib/Target/MSP430/MSP430InstrInfoExtended.td
 create mode 100644 llvm/test/MC/Disassembler/MSP430/msp430x-invalid.txt
 create mode 100644 llvm/test/MC/Disassembler/MSP430/msp430x.txt
 create mode 100644 llvm/test/MC/MSP430/msp430x-feature.s
 create mode 100644 llvm/test/MC/MSP430/shifts-430x-invalid.s
 create mode 100644 llvm/test/MC/MSP430/shifts-430x.s

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;
+  let Inst{3-0}  = cnt;
+}
+
+// Same layout as IIForm, moved behind the extension word.
+class IIExtRegForm<bits<3> opcode, bit bw, bit zc, bit rpt,
+                   dag outs, dag ins, string asmstr, list<dag> pattern>
+  : ExtRegForm<zc, rpt, ALWord, outs, ins, asmstr, pattern> {
+  bits<4> rs;
+
+  let Inst{31-26} = 0b000100;
+  let Inst{25-23} = opcode;
+  let Inst{22}    = bw;
+  let Inst{21-20} = SrcReg.Value;
+  let Inst{19-16} = rs;
+}
+
+// Same layout as IForm, moved behind the extension word.
+class IExtRegForm<bits<4> opcode, bit bw, bit zc, bit rpt,
+                  dag outs, dag ins, string asmstr, list<dag> pattern>
+  : ExtRegForm<zc, rpt, ALWord, outs, ins, asmstr, pattern> {
+  bits<4> rs;
+  bits<4> rd;
+
+  let Inst{31-28} = opcode;
+  let Inst{27-24} = rs;
+  let Inst{23}    = DstReg.Value;
+  let Inst{22}    = bw;
+  let Inst{21-20} = SrcReg.Value;
+  let Inst{19-16} = rd;
+}
+
+class II8rExtended<bits<3> opcode, bit zc, bit rpt,
+                   dag outs, dag ins, string asmstr, list<dag> pattern>
+  : IIExtRegForm<opcode, 1, zc, rpt, outs, ins, asmstr, pattern>;
+class II16rExtended<bits<3> opcode, bit zc, bit rpt,
+                    dag outs, dag ins, string asmstr, list<dag> pattern>
+  : IIExtRegForm<opcode, 0, zc, rpt, outs, ins, asmstr, pattern>;
+class I8rExtended<bits<4> opcode, bit zc, bit rpt,
+                  dag outs, dag ins, string asmstr, list<dag> pattern>
+  : IExtRegForm<opcode, 1, zc, rpt, outs, ins, asmstr, pattern>;
+class I16rExtended<bits<4> opcode, bit zc, bit rpt,
+                   dag outs, dag ins, string asmstr, list<dag> pattern>
+  : IExtRegForm<opcode, 0, zc, rpt, outs, ins, asmstr, pattern>;
+
 // Pseudo instructions
 class Pseudo<dag outs, dag ins, string asmstr, list<dag> pattern>
   : MSP430Inst<outs, ins, 0, asmstr> {
diff --git a/llvm/lib/Target/MSP430/MSP430InstrInfo.td 
b/llvm/lib/Target/MSP430/MSP430InstrInfo.td
index f25c96e3109a9d..3e870be0c0f588 100644
--- a/llvm/lib/Target/MSP430/MSP430InstrInfo.td
+++ b/llvm/lib/Target/MSP430/MSP430InstrInfo.td
@@ -12,6 +12,13 @@
 
 include "MSP430InstrFormats.td"
 
+//===----------------------------------------------------------------------===//
+// Feature predicates.
+//===----------------------------------------------------------------------===//
+
+def HasMSP430X : Predicate<"Subtarget->hasMSP430X()">,
+                 AssemblerPredicate<(all_of FeatureX), "MSP430X">;
+
 
//===----------------------------------------------------------------------===//
 // Type Constraints.
 
//===----------------------------------------------------------------------===//
@@ -990,3 +997,5 @@ def : Pat<(and GR16:$src, 255), (ZEXT16r GR16:$src)>;
 def : Pat<(MSP430cmp (trunc (and_su GR16:$src, GR16:$src2)), 0),
           (BIT8rr (EXTRACT_SUBREG GR16:$src, subreg_8bit),
                   (EXTRACT_SUBREG GR16:$src2, subreg_8bit))>;
+
+include "MSP430InstrInfoExtended.td"
diff --git a/llvm/lib/Target/MSP430/MSP430InstrInfoExtended.td 
b/llvm/lib/Target/MSP430/MSP430InstrInfoExtended.td
new file mode 100644
index 00000000000000..d56b42875955d3
--- /dev/null
+++ b/llvm/lib/Target/MSP430/MSP430InstrInfoExtended.td
@@ -0,0 +1,84 @@
+//===-- MSP430InstrInfoExtended.td - MSP430X Instruction defs 
-------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file describes the MSP430X extended instructions in TableGen format.
+//
+//===----------------------------------------------------------------------===//
+
+// TODO: Most extended instructions have a .A version that enables 20-bit
+// operands. This requires support the large memory model to be implemented.
+//
+// Only the extended instructions that are useful in the small memory model
+// (16-bit pointers) are implemented so far. Instructions like MOVX are not
+// required in the small memory model, and have increased size/cycle count
+// compared to their 430 versions.
+
+def Rpt2ImmAsmOperand : AsmOperandClass {
+  let Name = "Rpt2Imm";
+  let RenderMethod = "addImmOperands";
+}
+
+def rpt2imm : Operand<i8>,
+              ImmLeaf<i8, [{return Imm >= 1 && Imm <= 4;}]> {
+  let ParserMatchClass = Rpt2ImmAsmOperand;
+  let EncoderMethod = "getRpt2ImmOpValue";
+  let DecoderMethod = "decodeRpt2Imm";
+}
+
+//===----------------------------------------------------------------------===//
+//  Shift Instructions
+//
+let Predicates = [HasMSP430X] in {
+let Constraints = "$rs = $rd", Defs = [SR] in {
+  multiclass IIExtExcRot<string Mnemonic, bits<2> OpCode,
+                         list<Register> uses> {
+    let Uses = uses in
+    def _16 : IIExtExcRotForm16<OpCode,
+                                (outs GR16:$rd), (ins GR16:$rs, rpt2imm:$cnt),
+                                !strconcat(Mnemonic, "\t$cnt, $rd"), []>;
+  }
+
+  defm RRCM : IIExtExcRot<"rrcm", 0b00, [SR]>;
+  defm RRAM : IIExtExcRot<"rram", 0b01, []>;
+  defm RRUM : IIExtExcRot<"rrum", 0b11, []>;
+  defm RLAM : IIExtExcRot<"rlam", 0b10, []>;
+
+  multiclass IIExtRot<string Mnemonic, bits<3> OpCode, bit ZC,
+                      list<Register> uses> {
+    let Uses = uses in {
+    def _8  :  II8rExtended<OpCode, ZC, 0,
+                            (outs GR8:$rd), (ins GR8:$rs),
+                            !strconcat(Mnemonic, ".b\t$rd"), []>;
+    def _16 : II16rExtended<OpCode, ZC, 0,
+                            (outs GR16:$rd), (ins GR16:$rs),
+                            !strconcat(Mnemonic, "\t$rd"), []>;
+    }
+  }
+  defm RRCX : IIExtRot<"rrcx", 0b000, 0, [SR]>;
+  defm RRAX : IIExtRot<"rrax", 0b010, 0, []>;
+  // RRUX is encoded as RRCX with the ZC flag set.
+  defm RRUX : IIExtRot<"rrux", 0b000, 1, []>;
+
+} // Defs = [SR], Constraints = "$rs = $rd"
+
+//===----------------------------------------------------------------------===//
+//  Arithmetic Instructions
+//
+let Defs = [SR], Constraints = "$src2 = $rd" in {
+  def ADDX8rr  : I8rExtended<0b0101, 0, 0,
+                             (outs GR8:$rd), (ins GR8:$src2, GR8:$rs),
+                             "addx.b\t$rs, $rd", []>;
+  def ADDX16rr : I16rExtended<0b0101, 0, 0,
+                              (outs GR16:$rd), (ins GR16:$src2, GR16:$rs),
+                              "addx\t$rs, $rd", []>;
+}
+
+// Alias printing is disabled for the same reason as for RLA.
+def RLAX8r  : InstAlias<"rlax.b\t$dst", (ADDX8rr  GR8:$dst,  GR8:$dst),  0>;
+def RLAX16r : InstAlias<"rlax\t$dst",   (ADDX16rr GR16:$dst, GR16:$dst), 0>;
+} // Predicates = [HasMSP430X]
diff --git a/llvm/lib/Target/MSP430/MSP430Subtarget.h 
b/llvm/lib/Target/MSP430/MSP430Subtarget.h
index d88bf11bddb3d7..cbb94ae970b91f 100644
--- a/llvm/lib/Target/MSP430/MSP430Subtarget.h
+++ b/llvm/lib/Target/MSP430/MSP430Subtarget.h
@@ -66,6 +66,8 @@ class MSP430Subtarget : public MSP430GenSubtargetInfo {
   bool hasHWMult32() const { return HWMultMode == MSP430::HWMult::HW32; }
   bool hasHWMultF5() const { return HWMultMode == MSP430::HWMult::F5; }
 
+  bool hasMSP430X() const { return ExtendedInsts; }
+
   const TargetFrameLowering *getFrameLowering() const override {
     return &FrameLowering;
   }
diff --git a/llvm/test/MC/Disassembler/MSP430/msp430x-invalid.txt 
b/llvm/test/MC/Disassembler/MSP430/msp430x-invalid.txt
new file mode 100644
index 00000000000000..0ac8a359e23880
--- /dev/null
+++ b/llvm/test/MC/Disassembler/MSP430/msp430x-invalid.txt
@@ -0,0 +1,13 @@
+# RUN: llvm-mc -disassemble %s -triple=msp430 -mcpu=msp430x 2>&1 >/dev/null \
+# RUN:   | FileCheck %s --check-prefix=WARN
+# RUN: llvm-mc -disassemble %s -triple=msp430 -mcpu=msp430x 2>/dev/null \
+# RUN:   | FileCheck %s
+
+# An unsupported extended instruction (rpt #4 + rrax r12) is skipped as a
+# whole. Its instruction word must not show up as rra r12.
+# CHECK: rram #1, r12
+# CHECK-NEXT: rram #2, r12
+# WARN: :[[@LINE+2]]:1: warning: invalid instruction encoding
+0x5c 0x01
+0x43 0x18 0x0c 0x11
+0x5c 0x05
diff --git a/llvm/test/MC/Disassembler/MSP430/msp430x.txt 
b/llvm/test/MC/Disassembler/MSP430/msp430x.txt
new file mode 100644
index 00000000000000..0ee456ef92dd31
--- /dev/null
+++ b/llvm/test/MC/Disassembler/MSP430/msp430x.txt
@@ -0,0 +1,18 @@
+# RUN: llvm-mc -disassemble %s -triple=msp430 -mcpu=msp430x | FileCheck %s
+
+0x5c 0x01                     # CHECK: rram #1, r12
+0x5c 0x0d                     # CHECK: rram #4, r12
+0x55 0x07                     # CHECK: rrum #2, r5
+0x5f 0x0a                     # CHECK: rlam #3, r15
+0x5c 0x00                     # CHECK: rrcm #1, r12
+0x56 0x0c                     # CHECK: rrcm #4, r6
+0x40 0x18 0x0c 0x11           # CHECK: rrax r12
+0x40 0x18 0x4c 0x11           # CHECK: rrax.b r12
+0x40 0x18 0x0c 0x10           # CHECK: rrcx r12
+0x40 0x18 0x48 0x10           # CHECK: rrcx.b r8
+0x40 0x19 0x0c 0x10           # CHECK: rrux r12
+0x40 0x19 0x47 0x10           # CHECK: rrux.b r7
+0x40 0x18 0x0c 0x5c           # CHECK: addx r12, r12
+0x40 0x18 0x49 0x59           # CHECK: addx.b r9, r9
+0x40 0x18 0x0c 0x55           # CHECK: addx r5, r12
+0x40 0x18 0x47 0x55           # CHECK: addx.b r5, r7
diff --git a/llvm/test/MC/MSP430/msp430x-feature.s 
b/llvm/test/MC/MSP430/msp430x-feature.s
new file mode 100644
index 00000000000000..6d6ece721088e3
--- /dev/null
+++ b/llvm/test/MC/MSP430/msp430x-feature.s
@@ -0,0 +1,9 @@
+// MSP430X instructions require -mcpu=msp430x.
+// RUN: not llvm-mc -triple msp430 %s 2>&1 | FileCheck %s
+
+  rram #1, r12
+// CHECK: :[[@LINE-1]]:3: error: instruction requires a CPU feature not 
currently enabled
+  rrax r12
+// CHECK: :[[@LINE-1]]:3: error: instruction requires a CPU feature not 
currently enabled
+  rlax r12
+// CHECK: :[[@LINE-1]]:3: error: instruction requires a CPU feature not 
currently enabled
diff --git a/llvm/test/MC/MSP430/shifts-430x-invalid.s 
b/llvm/test/MC/MSP430/shifts-430x-invalid.s
new file mode 100644
index 00000000000000..c333b40e2304d4
--- /dev/null
+++ b/llvm/test/MC/MSP430/shifts-430x-invalid.s
@@ -0,0 +1,23 @@
+// Tests to check for incorrect use of MSP430X shift instructions.
+// RUN: not llvm-mc --triple=msp430 -mcpu=msp430x < %s 2>&1 | FileCheck %s
+
+foo:
+// Check for an error when the repetition count is too large.
+  rrum #5, r12
+  rram #5, r12
+  rlam #5, r12
+  rrcm #5, r12
+// CHECK: :8: error: invalid operand for instruction
+// CHECK: :8: error: invalid operand for instruction
+// CHECK: :8: error: invalid operand for instruction
+// CHECK: :8: error: invalid operand for instruction
+
+// Check for an error when RxxX shifts have a shift amount operand.
+  rrcx #3, r12
+  rrux #3, r12
+  rrax #3, r12
+  rlax #3, r12
+// CHECK: :8: error: invalid operand for instruction
+// CHECK: :8: error: invalid operand for instruction
+// CHECK: :8: error: invalid operand for instruction
+// CHECK: :8: error: invalid operand for instruction
diff --git a/llvm/test/MC/MSP430/shifts-430x.s 
b/llvm/test/MC/MSP430/shifts-430x.s
new file mode 100644
index 00000000000000..ccf2d8ec9b6bd6
--- /dev/null
+++ b/llvm/test/MC/MSP430/shifts-430x.s
@@ -0,0 +1,101 @@
+// Test the encoding of shift instructions for the 430X CPU.
+
+// RUN: llvm-mc -triple msp430 -mcpu=msp430x -show-encoding < %s | FileCheck %s
+rxxm:
+       rrum    #1, r12                         ; encoding: [0x5c,0x03]
+       rrum    #2, r12                         ; encoding: [0x5c,0x07]
+       rrum    #3, r12                         ; encoding: [0x5c,0x0b]
+       rrum    #4, r12                         ; encoding: [0x5c,0x0f]
+
+       rram    #1, r12                         ; encoding: [0x5c,0x01]
+       rram    #2, r12                         ; encoding: [0x5c,0x05]
+       rram    #3, r12                         ; encoding: [0x5c,0x09]
+       rram    #4, r12                         ; encoding: [0x5c,0x0d]
+
+       rlam    #1, r12                         ; encoding: [0x5c,0x02]
+       rlam    #2, r12                         ; encoding: [0x5c,0x06]
+       rlam    #3, r12                         ; encoding: [0x5c,0x0a]
+       rlam    #4, r12                         ; encoding: [0x5c,0x0e]
+
+       rrcm    #1, r12                         ; encoding: [0x5c,0x00]
+       rrcm    #2, r12                         ; encoding: [0x5c,0x04]
+       rrcm    #3, r12                         ; encoding: [0x5c,0x08]
+       rrcm    #4, r12                         ; encoding: [0x5c,0x0c]
+
+// CHECK-LABEL: rxxm:
+// CHECK-NEXT: rrum    #1, r12                         ; encoding: [0x5c,0x03]
+// CHECK: rrum #2, r12                         ; encoding: [0x5c,0x07]
+// CHECK: rrum #3, r12                         ; encoding: [0x5c,0x0b]
+// CHECK: rrum #4, r12                         ; encoding: [0x5c,0x0f]
+
+// CHECK: rram #1, r12                         ; encoding: [0x5c,0x01]
+// CHECK: rram #2, r12                         ; encoding: [0x5c,0x05]
+// CHECK: rram #3, r12                         ; encoding: [0x5c,0x09]
+// CHECK: rram #4, r12                         ; encoding: [0x5c,0x0d]
+
+// CHECK: rlam #1, r12                         ; encoding: [0x5c,0x02]
+// CHECK: rlam #2, r12                         ; encoding: [0x5c,0x06]
+// CHECK: rlam #3, r12                         ; encoding: [0x5c,0x0a]
+// CHECK: rlam #4, r12                         ; encoding: [0x5c,0x0e]
+
+// CHECK: rrcm #1, r12                         ; encoding: [0x5c,0x00]
+// CHECK: rrcm #2, r12                         ; encoding: [0x5c,0x04]
+// CHECK: rrcm #3, r12                         ; encoding: [0x5c,0x08]
+// CHECK: rrcm #4, r12                         ; encoding: [0x5c,0x0c]
+
+rrcx:
+  rrcx r12
+
+// CHECK-LABEL: rrcx:
+// CHECK-NEXT: rrcx    r12                             ; encoding: 
[0x40,0x18,0x0c,0x10]
+
+rrcx_b:
+  rrcx.b r12
+
+// CHECK-LABEL: rrcx_b:
+// CHECK-NEXT: rrcx.b  r12                             ; encoding: 
[0x40,0x18,0x4c,0x10]
+
+rrux:
+  rrux r12
+
+// CHECK-LABEL: rrux:
+// CHECK-NEXT: rrux    r12                             ; encoding: 
[0x40,0x19,0x0c,0x10]
+
+rrux_b:
+  rrux.b r12
+
+// CHECK-LABEL: rrux_b:
+// CHECK-NEXT: rrux.b  r12                             ; encoding: 
[0x40,0x19,0x4c,0x10]
+
+rrax:
+  rrax r12
+
+// CHECK-LABEL: rrax:
+// CHECK-NEXT: rrax    r12                             ; encoding: 
[0x40,0x18,0x0c,0x11]
+
+rrax_b:
+  rrax.b r12
+
+// CHECK-LABEL: rrax_b:
+// CHECK-NEXT: rrax.b  r12                             ; encoding: 
[0x40,0x18,0x4c,0x11]
+
+// RLAX is an alias of ADDX with both registers equal. Alias printing is
+// disabled, so it prints as ADDX.
+rlax:
+  rlax r12
+
+// CHECK-LABEL: rlax:
+// CHECK-NEXT: addx    r12, r12                        ; encoding: 
[0x40,0x18,0x0c,0x5c]
+
+rlax_b:
+  rlax.b r12
+
+// CHECK-LABEL: rlax_b:
+// CHECK-NEXT: addx.b  r12, r12                        ; encoding: 
[0x40,0x18,0x4c,0x5c]
+
+// ADDX with different registers must not be treated as RLAX.
+addx:
+  addx r5, r12
+
+// CHECK-LABEL: addx:
+// CHECK-NEXT: addx    r5, r12                         ; encoding: 
[0x40,0x18,0x0c,0x55]

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to