[llvm] 7486b7b - [M68k] Basic FP register files and FMOVE implementations

Min-Yih Hsu via llvm-commits llvm-commits at lists.llvm.org
Sat Apr 8 10:44:16 PDT 2023


Author: Min-Yih Hsu
Date: 2023-04-08T10:42:47-07:00
New Revision: 7486b7b6bac5c3046090da8356777cff412853fc

URL: https://github.com/llvm/llvm-project/commit/7486b7b6bac5c3046090da8356777cff412853fc
DIFF: https://github.com/llvm/llvm-project/commit/7486b7b6bac5c3046090da8356777cff412853fc.diff

LOG: [M68k] Basic FP register files and FMOVE implementations

  - FP registers and register classes definitions
  - MC support for FP registers
  - MC support for the FPDR -> FPDR variant of FMOVE/FSMOVE/FDSMOVE

Note that we don't implement 32/64-bit FP registers with subregisters since
f32/f64 values will be converted to f80 upon storing into a register,
rather than occupying part of the register.
So we only use register classes with different value types to distinguish
them.

Differential Revision: https://reviews.llvm.org/D147480

Added: 
    llvm/test/MC/Disassembler/M68k/fp-data.txt
    llvm/test/MC/M68k/Data/Classes/MxFMove_FF.s

Modified: 
    llvm/lib/Target/M68k/AsmParser/M68kAsmParser.cpp
    llvm/lib/Target/M68k/Disassembler/M68kDisassembler.cpp
    llvm/lib/Target/M68k/M68kInstrData.td
    llvm/lib/Target/M68k/M68kInstrInfo.td
    llvm/lib/Target/M68k/M68kRegisterInfo.td

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Target/M68k/AsmParser/M68kAsmParser.cpp b/llvm/lib/Target/M68k/AsmParser/M68kAsmParser.cpp
index 59fa782829fde..c606eaa9af13e 100644
--- a/llvm/lib/Target/M68k/AsmParser/M68kAsmParser.cpp
+++ b/llvm/lib/Target/M68k/AsmParser/M68kAsmParser.cpp
@@ -158,6 +158,7 @@ class M68kOperand : public MCParsedAsmOperand {
   bool isReg() const override;
   bool isAReg() const;
   bool isDReg() const;
+  bool isFPDReg() const;
   unsigned getReg() const override;
   void addRegOperands(MCInst &Inst, unsigned N) const;
 
@@ -234,10 +235,10 @@ extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeM68kAsmParser() {
 
 static inline unsigned getRegisterByIndex(unsigned RegisterIndex) {
   static unsigned RegistersByIndex[] = {
-      M68k::D0, M68k::D1, M68k::D2, M68k::D3, M68k::D4, M68k::D5,
-      M68k::D6, M68k::D7, M68k::A0, M68k::A1, M68k::A2, M68k::A3,
-      M68k::A4, M68k::A5, M68k::A6, M68k::SP,
-  };
+      M68k::D0,  M68k::D1,  M68k::D2,  M68k::D3,  M68k::D4,  M68k::D5,
+      M68k::D6,  M68k::D7,  M68k::A0,  M68k::A1,  M68k::A2,  M68k::A3,
+      M68k::A4,  M68k::A5,  M68k::A6,  M68k::SP,  M68k::FP0, M68k::FP1,
+      M68k::FP2, M68k::FP3, M68k::FP4, M68k::FP5, M68k::FP6, M68k::FP7};
   assert(RegisterIndex <=
          sizeof(RegistersByIndex) / sizeof(RegistersByIndex[0]));
   return RegistersByIndex[RegisterIndex];
@@ -248,6 +249,8 @@ static inline unsigned getRegisterIndex(unsigned Register) {
     return Register - M68k::D0;
   if (Register >= M68k::A0 && Register <= M68k::A6)
     return Register - M68k::A0 + 8;
+  if (Register >= M68k::FP0 && Register <= M68k::FP7)
+    return Register - M68k::FP0 + 16;
 
   switch (Register) {
   case M68k::SP:
@@ -488,7 +491,7 @@ void M68kOperand::addPCIOperands(MCInst &Inst, unsigned N) const {
 }
 
 static inline bool checkRegisterClass(unsigned RegNo, bool Data, bool Address,
-                                      bool SP) {
+                                      bool SP, bool FPDR = false) {
   switch (RegNo) {
   case M68k::A0:
   case M68k::A1:
@@ -516,6 +519,16 @@ static inline bool checkRegisterClass(unsigned RegNo, bool Data, bool Address,
   case M68k::CCR:
     return false;
 
+  case M68k::FP0:
+  case M68k::FP1:
+  case M68k::FP2:
+  case M68k::FP3:
+  case M68k::FP4:
+  case M68k::FP5:
+  case M68k::FP6:
+  case M68k::FP7:
+    return FPDR;
+
   default:
     llvm_unreachable("unexpected register type");
     return false;
@@ -534,6 +547,13 @@ bool M68kOperand::isDReg() const {
                                        /*Address=*/false, /*SP=*/false);
 }
 
+bool M68kOperand::isFPDReg() const {
+  return isReg() && checkRegisterClass(getReg(),
+                                       /*Data=*/false,
+                                       /*Address=*/false, /*SP=*/false,
+                                       /*FPDR=*/true);
+}
+
 unsigned M68kAsmParser::validateTargetOperandClass(MCParsedAsmOperand &Op,
                                                    unsigned Kind) {
   M68kOperand &Operand = (M68kOperand &)Op;
@@ -641,6 +661,14 @@ bool M68kAsmParser::parseRegisterName(MCRegister &RegNo, SMLoc Loc,
       }
       break;
     }
+  } else if (StringRef(RegisterNameLower).starts_with("fp") &&
+             RegisterNameLower.size() > 2) {
+    // Floating point data register.
+    auto RegIndex = unsigned(RegisterNameLower[2] - '0');
+    if (RegIndex >= 8 || RegisterNameLower.size() > 3)
+      return false;
+    RegNo = getRegisterByIndex(16 + RegIndex);
+    return true;
   }
 
   return false;

diff  --git a/llvm/lib/Target/M68k/Disassembler/M68kDisassembler.cpp b/llvm/lib/Target/M68k/Disassembler/M68kDisassembler.cpp
index ffe4869e8fe56..2124a35cc65a4 100644
--- a/llvm/lib/Target/M68k/Disassembler/M68kDisassembler.cpp
+++ b/llvm/lib/Target/M68k/Disassembler/M68kDisassembler.cpp
@@ -33,14 +33,14 @@ using namespace llvm;
 typedef MCDisassembler::DecodeStatus DecodeStatus;
 
 static const unsigned RegisterDecode[] = {
-    M68k::D0, M68k::D1, M68k::D2, M68k::D3, M68k::D4, M68k::D5,
-    M68k::D6, M68k::D7, M68k::A0, M68k::A1, M68k::A2, M68k::A3,
-    M68k::A4, M68k::A5, M68k::A6, M68k::SP,
-};
+    M68k::D0,  M68k::D1,  M68k::D2,  M68k::D3,  M68k::D4,  M68k::D5,
+    M68k::D6,  M68k::D7,  M68k::A0,  M68k::A1,  M68k::A2,  M68k::A3,
+    M68k::A4,  M68k::A5,  M68k::A6,  M68k::SP,  M68k::FP0, M68k::FP1,
+    M68k::FP2, M68k::FP3, M68k::FP4, M68k::FP5, M68k::FP6, M68k::FP7};
 
 static DecodeStatus DecodeRegisterClass(MCInst &Inst, uint64_t RegNo,
                                         uint64_t Address, const void *Decoder) {
-  if (RegNo >= 16)
+  if (RegNo >= 24)
     return DecodeStatus::Fail;
   Inst.addOperand(MCOperand::createReg(RegisterDecode[RegNo]));
   return DecodeStatus::Success;
@@ -88,6 +88,15 @@ static DecodeStatus DecodeXR16RegisterClass(MCInst &Inst, uint64_t RegNo,
   return DecodeRegisterClass(Inst, RegNo, Address, Decoder);
 }
 
+static DecodeStatus DecodeFPDRRegisterClass(MCInst &Inst, uint64_t RegNo,
+                                            uint64_t Address,
+                                            const void *Decoder) {
+  return DecodeRegisterClass(Inst, RegNo | 16ULL, Address, Decoder);
+}
+#define DecodeFPDR32RegisterClass DecodeFPDRRegisterClass
+#define DecodeFPDR64RegisterClass DecodeFPDRRegisterClass
+#define DecodeFPDR80RegisterClass DecodeFPDRRegisterClass
+
 static DecodeStatus DecodeCCRCRegisterClass(MCInst &Inst, APInt &Insn,
                                             uint64_t Address,
                                             const void *Decoder) {
@@ -102,6 +111,10 @@ static DecodeStatus DecodeImm32(MCInst &Inst, uint64_t Imm, uint64_t Address,
 
 #include "M68kGenDisassemblerTable.inc"
 
+#undef DecodeFPDR32RegisterClass
+#undef DecodeFPDR64RegisterClass
+#undef DecodeFPDR80RegisterClass
+
 /// A disassembler class for M68k.
 struct M68kDisassembler : public MCDisassembler {
   M68kDisassembler(const MCSubtargetInfo &STI, MCContext &Ctx)

diff  --git a/llvm/lib/Target/M68k/M68kInstrData.td b/llvm/lib/Target/M68k/M68kInstrData.td
index ed37bd1f3daeb..00fcb3db8eb68 100644
--- a/llvm/lib/Target/M68k/M68kInstrData.td
+++ b/llvm/lib/Target/M68k/M68kInstrData.td
@@ -614,3 +614,54 @@ def : Pat<(i8  (trunc i32:$src)),
           (EXTRACT_SUBREG MxXRD32:$src, MxSubRegIndex8Lo)>;
 def : Pat<(i8  (trunc i16:$src)),
           (EXTRACT_SUBREG MxXRD16:$src, MxSubRegIndex8Lo)>;
+
+//===----------------------------------------------------------------------===//
+// FMOVE
+//===----------------------------------------------------------------------===//
+
+let Defs = [FPS] in
+class MxFMove<string size, dag outs, dag ins, list<dag> pattern,
+              string rounding = "">
+    : MxInst<outs, ins,
+             "f"#rounding#"move."#size#"\t$src, $dst", pattern> {
+  // Only FMOVE uses FPC
+  let Uses = !if(!eq(rounding, ""), [FPC], []);
+
+  // FSMOVE and FDMOVE are only available after M68040
+  let Predicates = [!if(!eq(rounding, ""), AtLeastM68881, AtLeastM68040)];
+}
+
+// FPDR <- FPDR
+class MxFMove_FF<string rounding, int size,
+                 MxOpBundle Opnd = !cast<MxOpBundle>("MxOp"#size#"AddrMode_fpr")>
+    : MxFMove<"x", (outs Opnd.Op:$dst), (ins Opnd.Op:$src),
+              [(null_frag)], rounding> {
+  let Inst = (ascend
+    (descend 0b1111,
+      /*COPROCESSOR ID*/0b001,
+      0b000,
+      /*MODE + REGISTER*/0b000000
+    ),
+    (descend 0b0, /* R/M */0b0, 0b0,
+      /*SOURCE SPECIFIER*/
+      (operand "$src", 3),
+      /*DESTINATION*/
+      (operand "$dst", 3),
+      /*OPMODE*/
+      !cond(!eq(rounding, "s"): 0b1000000,
+            !eq(rounding, "d"): 0b1000100,
+            true: 0b0000000)
+    )
+  );
+}
+
+foreach rounding = ["", "s", "d"] in {
+  def F # !toupper(rounding) # MOV80fp_fp : MxFMove_FF<rounding, 80>;
+
+  // We don't have `fmove.s` or `fmove.d` because values will be converted to
+  // f80 upon storing into the register, but FMOV32/64fp_fp are still needed
+  // to make codegen easier.
+  let isCodeGenOnly = true in
+  foreach size = [32, 64] in
+    def F # !toupper(rounding) # MOV # size # fp_fp : MxFMove_FF<rounding, size>;
+}

diff  --git a/llvm/lib/Target/M68k/M68kInstrInfo.td b/llvm/lib/Target/M68k/M68kInstrInfo.td
index 4a7bea5763fed..6d3370d5ee90d 100644
--- a/llvm/lib/Target/M68k/M68kInstrInfo.td
+++ b/llvm/lib/Target/M68k/M68kInstrInfo.td
@@ -164,6 +164,9 @@ class MxSize<int num, string id, string full> {
 def MxSize8  : MxSize<8,  "b", "byte">;
 def MxSize16 : MxSize<16, "w", "word">;
 def MxSize32 : MxSize<32, "l", "long">;
+def MxSizeF32 : MxSize<32, "s", "f32">;
+def MxSizeF64 : MxSize<64, "d", "f64">;
+def MxSizeF80 : MxSize<80, "x", "f80">;
 
 class MxOpClass<string name,
                 list<AsmOperandClass> superClasses = []> : AsmOperandClass {
@@ -181,6 +184,8 @@ def MxRegClass : MxOpClass<"Reg">;
 let RenderMethod = "addRegOperands", SuperClasses = [MxRegClass]in {
   def MxARegClass : MxOpClass<"AReg">;
   def MxDRegClass : MxOpClass<"DReg">;
+
+  def MxFPDRegClass : MxOpClass<"FPDReg">;
 }
 
 class MxOperand<ValueType vt, MxSize size, string letter, RegisterClass rc, dag pat = (null_frag)> {
@@ -230,6 +235,13 @@ let ParserMatchClass = MxARegClass in {
   def MxARD32_TC : MxRegOp<i32, AR32_TC, MxSize32, "a">;
 }
 
+// FLOATING POINT DATA REGISTER.
+let ParserMatchClass = MxFPDRegClass in {
+  def MxFPR32 : MxRegOp<f32, FPDR32, MxSizeF32, "fp">;
+  def MxFPR64 : MxRegOp<f64, FPDR64, MxSizeF64, "fp">;
+  def MxFPR80 : MxRegOp<f80, FPDR80, MxSizeF80, "fp">;
+}
+
 class MxMemOp<dag ops, MxSize size, string letter,
               string printMethod = "printOperand",
               AsmOperandClass parserMatchClass = ImmAsmOperand>
@@ -711,6 +723,10 @@ foreach size = [16, 32] in {
     : MxOpBundle<size, !cast<MxOperand>("MxXRD"#size), ?>;
 } // foreach size = [16, 32]
 
+foreach size = [32, 64, 80] in
+def MxOp#size#AddrMode_fpr
+  : MxOpBundle<size, !cast<MxOperand>("MxFPR"#size), ?>;
+
 class MxType8Class<string rLet, MxOperand reg>
     : MxType<i8, "b", "", rLet, reg,
              MxARI8,   MxCP_ARI,

diff  --git a/llvm/lib/Target/M68k/M68kRegisterInfo.td b/llvm/lib/Target/M68k/M68kRegisterInfo.td
index 49874a2b1099c..1567bcbb73196 100644
--- a/llvm/lib/Target/M68k/M68kRegisterInfo.td
+++ b/llvm/lib/Target/M68k/M68kRegisterInfo.td
@@ -68,6 +68,19 @@ defm A5 : MxAddressRegister<5, "a5", ["bp"]>;
 defm A6 : MxAddressRegister<6, "a6", ["fp"]>;
 defm SP : MxAddressRegister<7, "sp", ["usp", "ssp", "isp", "a7"]>;
 
+// Floating Point Registers
+class MxFPRegister<int INDEX, string REG_NAME, list<string> ALTNAMES = []>
+    : MxReg<REG_NAME, INDEX, /*SUBREGS=*/[], /*SUBIDX=*/[],
+            /*DWREGS=*/[!add(18,INDEX)], ALTNAMES>;
+
+foreach i = {0-7} in
+  def FP#i : MxFPRegister<i, "fp"#i>;
+
+// Unlike their counterparts in integer registers, these
+// control registers can be accessed and modified by instructions.
+def FPC   : MxFPRegister<8,  "fpcr",  ["fpc"]>;
+def FPS   : MxFPRegister<9,  "fpsr",  ["fps"]>;
+def FPIAR : MxFPRegister<10, "fpiar", ["fpi"]>;
 
 // Pseudo Registers
 class MxPseudoReg<string N, list<Register> SUBREGS = [], list<SubRegIndex> SUBIDX = []>
@@ -103,9 +116,16 @@ def XR32 : MxRegClass<[i32], 32, (add DR32, AR32)>;
 
 def SPC  : MxRegClass<[i32], 32, (add SP)>;
 
+// Floating Point Data Registers
+def FPDR32 : MxRegClass<[f32], 32, (sequence "FP%u", 0, 7)>;
+def FPDR64 : MxRegClass<[f64], 32, (add FPDR32)>;
+def FPDR80 : MxRegClass<[f80], 32, (add FPDR32)>;
+
 let CopyCost = -1 in {
   def CCRC : MxRegClass<[i8],  16, (add CCR)>;
   def SRC  : MxRegClass<[i16], 16, (add SR)>;
+
+  def FPCR : MxRegClass<[i32], 32, (add FPC, FPS, FPIAR)>;
 }
 
 let isAllocatable = 0 in {

diff  --git a/llvm/test/MC/Disassembler/M68k/fp-data.txt b/llvm/test/MC/Disassembler/M68k/fp-data.txt
new file mode 100644
index 0000000000000..4e953793c7eae
--- /dev/null
+++ b/llvm/test/MC/Disassembler/M68k/fp-data.txt
@@ -0,0 +1,10 @@
+# RUN: llvm-mc -disassemble -triple m68k -mcpu=M68040 %s | FileCheck %s
+
+# CHECK: fmove.x %fp7, %fp2
+0xf2 0x00 0x1d 0x00
+
+# CHECK: fsmove.x %fp6, %fp1
+0xf2 0x00 0x18 0xc0
+
+# CHECK: fdmove.x %fp3, %fp0
+0xf2 0x00 0x0c 0x44

diff  --git a/llvm/test/MC/M68k/Data/Classes/MxFMove_FF.s b/llvm/test/MC/M68k/Data/Classes/MxFMove_FF.s
new file mode 100644
index 0000000000000..e3fef6079beea
--- /dev/null
+++ b/llvm/test/MC/M68k/Data/Classes/MxFMove_FF.s
@@ -0,0 +1,13 @@
+; RUN: llvm-mc -triple=m68k -mcpu=M68040 -show-encoding < %s | FileCheck %s
+
+; CHECK: fmove.x %fp7, %fp2
+; CHECK-SAME: [0xf2,0x00,0x1d,0x00]
+fmove.x %fp7, %fp2
+
+; CHECK: fsmove.x %fp6, %fp1
+; CHECK-SAME: [0xf2,0x00,0x18,0xc0]
+fsmove.x %fp6, %fp1
+
+; CHECK: fdmove.x %fp3, %fp0
+; CHECK-SAME: [0xf2,0x00,0x0c,0x44]
+fdmove.x %fp3, %fp0


        


More information about the llvm-commits mailing list