diff --git a/llvm/lib/Target/MSP430/AsmParser/MSP430AsmParser.cpp b/llvm/lib/Target/MSP430/AsmParser/MSP430AsmParser.cpp --- a/llvm/lib/Target/MSP430/AsmParser/MSP430AsmParser.cpp +++ b/llvm/lib/Target/MSP430/AsmParser/MSP430AsmParser.cpp @@ -163,11 +163,8 @@ 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) @@ -176,6 +173,19 @@ return false; } + /// Return true if the immediate value can be used for a 2-bit reptition + /// count after it is encoded. + 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; diff --git a/llvm/lib/Target/MSP430/Disassembler/MSP430Disassembler.cpp b/llvm/lib/Target/MSP430/Disassembler/MSP430Disassembler.cpp --- a/llvm/lib/Target/MSP430/Disassembler/MSP430Disassembler.cpp +++ b/llvm/lib/Target/MSP430/Disassembler/MSP430Disassembler.cpp @@ -102,6 +102,11 @@ static DecodeStatus DecodeCGImm(MCInst &MI, uint64_t Bits, uint64_t Address, const void *Decoder); +/// Decode the repetition count from the extension word in a 430X extended +/// instruction. +static DecodeStatus decodeRptImm(MCInst &MI, uint64_t Bits, uint64_t Address, + const void *Decoder); + static DecodeStatus DecodeMemOperand(MCInst &MI, uint64_t Bits, uint64_t Address, const void *Decoder); @@ -125,6 +130,15 @@ return MCDisassembler::Success; } +static DecodeStatus decodeRptImm(MCInst &MI, uint64_t Bits, uint64_t Address, + const void *Decoder) { + if (Bits >= 16) + return MCDisassembler::Fail; + 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 void *Decoder) { diff --git a/llvm/lib/Target/MSP430/MCTargetDesc/MSP430MCCodeEmitter.cpp b/llvm/lib/Target/MSP430/MCTargetDesc/MSP430MCCodeEmitter.cpp --- a/llvm/lib/Target/MSP430/MCTargetDesc/MSP430MCCodeEmitter.cpp +++ b/llvm/lib/Target/MSP430/MCTargetDesc/MSP430MCCodeEmitter.cpp @@ -10,9 +10,10 @@ // //===----------------------------------------------------------------------===// -#include "MSP430.h" -#include "MCTargetDesc/MSP430MCTargetDesc.h" #include "MCTargetDesc/MSP430FixupKinds.h" +#include "MCTargetDesc/MSP430MCTargetDesc.h" +#include "MSP430.h" +#include "MSP430InstrInfo.h" #include "llvm/ADT/APFloat.h" #include "llvm/ADT/SmallVector.h" @@ -66,6 +67,12 @@ SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const; + /// Encode the repetition count for a 430X extended format exception + /// instruction. + unsigned getRpt2ImmOpValue(const MCInst &MI, unsigned Op, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const; + unsigned getCCOpValue(const MCInst &MI, unsigned Op, SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const; @@ -79,6 +86,15 @@ const MCSubtargetInfo &STI) const override; }; +/// Move the extension word from the last word of the 64-bit encoded value, to +/// the first word of the encoded value. +static uint64_t fixExtensionWord(uint64_t EncodedValue) { + uint64_t ExtensionWord = EncodedValue >> 48; + EncodedValue <<= 16; + EncodedValue |= ExtensionWord; + return EncodedValue; +} + void MSP430MCCodeEmitter::encodeInstruction(const MCInst &MI, raw_ostream &OS, SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const { @@ -87,9 +103,12 @@ unsigned Size = Desc.getSize(); // Initialize fixup offset - Offset = 2; + Offset = ((Desc.TSFlags & MSP430TSFlags::ExtensionWord) ? 4 : 2); uint64_t BinaryOpCode = getBinaryCodeForInstr(MI, Fixups, STI); + if (Desc.TSFlags & MSP430TSFlags::ExtensionWord) + BinaryOpCode = fixExtensionWord(BinaryOpCode); + size_t WordCount = Size / 2; while (WordCount--) { @@ -181,6 +200,18 @@ } } +unsigned +MSP430MCCodeEmitter::getRpt2ImmOpValue(const MCInst &MI, unsigned Op, + SmallVectorImpl &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 &Fixups, const MCSubtargetInfo &STI) const { diff --git a/llvm/lib/Target/MSP430/MSP430ISelDAGToDAG.cpp b/llvm/lib/Target/MSP430/MSP430ISelDAGToDAG.cpp --- a/llvm/lib/Target/MSP430/MSP430ISelDAGToDAG.cpp +++ b/llvm/lib/Target/MSP430/MSP430ISelDAGToDAG.cpp @@ -92,13 +92,17 @@ class MSP430DAGToDAGISel : public SelectionDAGISel { public: MSP430DAGToDAGISel(MSP430TargetMachine &TM, CodeGenOpt::Level OptLevel) - : SelectionDAGISel(TM, OptLevel) {} + : SelectionDAGISel(TM, OptLevel), Subtarget(nullptr) {} private: + const MSP430Subtarget *Subtarget; + StringRef getPassName() const override { return "MSP430 DAG->DAG Pattern Instruction Selection"; } + bool runOnMachineFunction(MachineFunction &MF) override; + bool MatchAddress(SDValue N, MSP430ISelAddressMode &AM); bool MatchWrapper(SDValue N, MSP430ISelAddressMode &AM); bool MatchAddressBase(SDValue N, MSP430ISelAddressMode &AM); @@ -120,6 +124,11 @@ }; } // end anonymous namespace +bool MSP430DAGToDAGISel::runOnMachineFunction(MachineFunction &MF) { + Subtarget = &MF.getSubtarget(); + return SelectionDAGISel::runOnMachineFunction(MF); +} + /// createMSP430ISelDag - This pass converts a legalized DAG into a /// MSP430-specific DAG, ready for instruction scheduling. /// diff --git a/llvm/lib/Target/MSP430/MSP430ISelLowering.h b/llvm/lib/Target/MSP430/MSP430ISelLowering.h --- a/llvm/lib/Target/MSP430/MSP430ISelLowering.h +++ b/llvm/lib/Target/MSP430/MSP430ISelLowering.h @@ -71,6 +71,8 @@ class MSP430Subtarget; class MSP430TargetLowering : public TargetLowering { + const MSP430Subtarget *Subtarget; + public: explicit MSP430TargetLowering(const TargetMachine &TM, const MSP430Subtarget &STI); diff --git a/llvm/lib/Target/MSP430/MSP430ISelLowering.cpp b/llvm/lib/Target/MSP430/MSP430ISelLowering.cpp --- a/llvm/lib/Target/MSP430/MSP430ISelLowering.cpp +++ b/llvm/lib/Target/MSP430/MSP430ISelLowering.cpp @@ -43,7 +43,7 @@ MSP430TargetLowering::MSP430TargetLowering(const TargetMachine &TM, const MSP430Subtarget &STI) - : TargetLowering(TM) { + : TargetLowering(TM), Subtarget(&STI) { // Set up the register classes. addRegisterClass(MVT::i8, &MSP430::GR8RegClass); diff --git a/llvm/lib/Target/MSP430/MSP430InstrFormats.td b/llvm/lib/Target/MSP430/MSP430InstrFormats.td --- a/llvm/lib/Target/MSP430/MSP430InstrFormats.td +++ b/llvm/lib/Target/MSP430/MSP430InstrFormats.td @@ -28,10 +28,17 @@ def DstReg : DestMode<0>; // r def DstMem : DestMode<1>; // m +class ALKind { + bit Value = val; +} + +def ALAddr : ALKind<0>; +def ALWord : ALKind<1>; + // Generic MSP430 Format class MSP430Inst : Instruction { - field bits<48> Inst; - field bits<48> SoftFail = 0; + field bits<64> Inst; + field bits<64> SoftFail = 0; let Namespace = "MSP430"; @@ -40,6 +47,9 @@ let AsmString = asmstr; let Size = size; + + bit ExtensionWordFlag = 0; + let TSFlags{0} = ExtensionWordFlag; } // MSP430 Double Operand (Format I) Instructions @@ -433,6 +443,84 @@ let Inst{9-0} = dst; } +// MSP430 Extended Format II Instruction Format Exception - Rotation. +class IIExtExcRotForm opcode, ALKind al, + dag outs, dag ins, string asmstr, list pattern> + : MSP430Inst { + let Pattern = pattern; + + 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 opcode, dag outs, dag ins, string asmstr, list pattern> + : IIExtExcRotForm; + +// The 430X extension word for register addressing modes. +// +// MSP430MCCodeEmitter expects the ExtensionWord field to be positioned at bits +// [63:48] of the Inst field in the MSP430Inst that the instruction corresponds +// to. encodeInstruction will rearrange the bits of the instruction to ensure +// the ExtensionWord is positioned correctly in the final binary encoding. +// +// Until the MSP430 large memory model is supported, there's no benefit to using +// non-register mode extended instructions, so they are not currently +// implemented. +class ExtensionWordRegForm { + bits<16> ExtensionWord; + bits<4> cnt = 0; + + let ExtensionWord{15-9} = 0b0001100; + let ExtensionWord{8} = zc; + let ExtensionWord{7} = rpt; + let ExtensionWord{6} = al.Value; + let ExtensionWord{5-4} = 0b00; + let ExtensionWord{3-0} = cnt; +} + +class II16rExtended opcode, bit zc, bit rpt, + dag outs, dag ins, string asmstr, list pattern> + : IIForm16, + ExtensionWordRegForm { + let Pattern = pattern; + let ExtensionWordFlag = 1; + let Inst{63-48} = ExtensionWord; +} + +class I16rExtended opcode, bit zc, bit rpt, + dag outs, dag ins, string asmstr, list pattern> + : IForm16, + ExtensionWordRegForm { + let Pattern = pattern; + let ExtensionWordFlag = 1; + let Inst{63-48} = ExtensionWord; +} + +class II8rExtended opcode, bit zc, bit rpt, + dag outs, dag ins, string asmstr, list pattern> + : IIForm8, + ExtensionWordRegForm { + let Pattern = pattern; + let ExtensionWordFlag = 1; + let Inst{63-48} = ExtensionWord; +} + +class I8rExtended opcode, bit zc, bit rpt, + dag outs, dag ins, string asmstr, list pattern> + : IForm8, + ExtensionWordRegForm { + let Pattern = pattern; + let ExtensionWordFlag = 1; + let Inst{63-48} = ExtensionWord; +} + // Pseudo instructions class Pseudo pattern> : MSP430Inst { diff --git a/llvm/lib/Target/MSP430/MSP430InstrInfo.h b/llvm/lib/Target/MSP430/MSP430InstrInfo.h --- a/llvm/lib/Target/MSP430/MSP430InstrInfo.h +++ b/llvm/lib/Target/MSP430/MSP430InstrInfo.h @@ -20,6 +20,17 @@ #include "MSP430GenInstrInfo.inc" namespace llvm { +/// Namespace to describe the target-specific flags of an MSP430Inst. +/// +/// The flag bit positions need to match the TSFlag bits set in the MSP430Inst +/// TableGen class defined in MSP430InstrFormats.td. +namespace MSP430TSFlags { +enum { + /// This bit is set if the instruction is an MSP430X extended instruction with + /// an extension word. + ExtensionWord = 0x1, +}; +} // namespace MSP430TSFlags class MSP430Subtarget; diff --git a/llvm/lib/Target/MSP430/MSP430InstrInfo.td b/llvm/lib/Target/MSP430/MSP430InstrInfo.td --- a/llvm/lib/Target/MSP430/MSP430InstrInfo.td +++ b/llvm/lib/Target/MSP430/MSP430InstrInfo.td @@ -12,6 +12,13 @@ include "MSP430InstrFormats.td" +//===----------------------------------------------------------------------===// +// Feature predicates. +//===----------------------------------------------------------------------===// + +// True when MSP430X extended instructions are available. +def HasMSP430X : Predicate<"Subtarget->hasMSP430X()">; + //===----------------------------------------------------------------------===// // Type Constraints. //===----------------------------------------------------------------------===// @@ -1039,3 +1046,5 @@ 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 --- /dev/null +++ b/llvm/lib/Target/MSP430/MSP430InstrInfoExtended.td @@ -0,0 +1,73 @@ +//===-- 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, + ImmLeaf= 1 && Imm <= 4;}]> { + let ParserMatchClass = Rpt2ImmAsmOperand; + let EncoderMethod = "getRpt2ImmOpValue"; + let DecoderMethod = "decodeRptImm"; +} + +//===----------------------------------------------------------------------===// +// Shift Instructions +// +let Predicates = [HasMSP430X] in { +let Constraints = "$rs = $rd", Defs = [SR] in { + multiclass IIExtExcRot OpCode> { + def _16 : IIExtExcRotForm16; + } + + defm RRAM : IIExtExcRot<"rram", 0b01>; + defm RRUM : IIExtExcRot<"rrum", 0b11>; + defm RLAM : IIExtExcRot<"rlam", 0b10>; + + multiclass IIExtRot OpCode, bit ZC> { + def _8 : II8rExtended; + def _16 : II16rExtended; + } + defm RRAX : IIExtRot<"rrax", 0b010, 0>; + // RRUX is encoded as RRCX with the ZC flag set. + defm RRUX : IIExtRot<"rrux", 0b000, 1>; + + multiclass IExtRot OpCode> { + def _8 : I8rExtended; + def _16 : I16rExtended; + } + + // RLAX is encoded as ADDX. + defm RLAX : IExtRot<"rlax", 0b0101>; + +} // Defs = [SR], Constraints = "$rs = $rd" +} // Predicates = [HasMSP430X] diff --git a/llvm/test/MC/MSP430/shifts-430x-invalid.s b/llvm/test/MC/MSP430/shifts-430x-invalid.s new file mode 100644 --- /dev/null +++ b/llvm/test/MC/MSP430/shifts-430x-invalid.s @@ -0,0 +1,19 @@ +// 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 reptition count is too large. + rrum #5, r12 + rram #5, r12 + rlam #5, r12 +// 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. + 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 diff --git a/llvm/test/MC/MSP430/shifts-430x.s b/llvm/test/MC/MSP430/shifts-430x.s new file mode 100644 --- /dev/null +++ b/llvm/test/MC/MSP430/shifts-430x.s @@ -0,0 +1,70 @@ +// 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] + +// 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] + +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: + rlax r12 + +// CHECK-LABEL: rlax: +// CHECK: rlax r12 ; encoding: [0x40,0x18,0x0c,0x5c] + +rlax_b: + rlax.b r12 + +// CHECK-LABEL: rlax_b: +// CHECK-NEXT: rlax.b r12 ; encoding: [0x40,0x18,0x4c,0x5c]