diff --git a/llvm/lib/Target/M68k/AsmParser/M68kAsmParser.cpp b/llvm/lib/Target/M68k/AsmParser/M68kAsmParser.cpp --- a/llvm/lib/Target/M68k/AsmParser/M68kAsmParser.cpp +++ b/llvm/lib/Target/M68k/AsmParser/M68kAsmParser.cpp @@ -158,6 +158,7 @@ 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 @@ 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 @@ 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 @@ } 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 @@ 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 @@ /*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 @@ } 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 --- a/llvm/lib/Target/M68k/Disassembler/M68kDisassembler.cpp +++ b/llvm/lib/Target/M68k/Disassembler/M68kDisassembler.cpp @@ -33,14 +33,14 @@ 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 @@ 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 @@ #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 --- a/llvm/lib/Target/M68k/M68kInstrData.td +++ b/llvm/lib/Target/M68k/M68kInstrData.td @@ -614,3 +614,54 @@ (EXTRACT_SUBREG MxXRD32:$src, MxSubRegIndex8Lo)>; def : Pat<(i8 (trunc i16:$src)), (EXTRACT_SUBREG MxXRD16:$src, MxSubRegIndex8Lo)>; + +//===----------------------------------------------------------------------===// +// FMOVE +//===----------------------------------------------------------------------===// + +let Defs = [FPS] in +class MxFMove pattern, + string rounding = ""> + : MxInst { + // 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("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; + + // 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; +} diff --git a/llvm/lib/Target/M68k/M68kInstrInfo.td b/llvm/lib/Target/M68k/M68kInstrInfo.td --- a/llvm/lib/Target/M68k/M68kInstrInfo.td +++ b/llvm/lib/Target/M68k/M68kInstrInfo.td @@ -164,6 +164,9 @@ 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 superClasses = []> : AsmOperandClass { @@ -181,6 +184,8 @@ let RenderMethod = "addRegOperands", SuperClasses = [MxRegClass]in { def MxARegClass : MxOpClass<"AReg">; def MxDRegClass : MxOpClass<"DReg">; + + def MxFPDRegClass : MxOpClass<"FPDReg">; } class MxOperand { @@ -230,6 +235,13 @@ def MxARD32_TC : MxRegOp; } +// FLOATING POINT DATA REGISTER. +let ParserMatchClass = MxFPDRegClass in { + def MxFPR32 : MxRegOp; + def MxFPR64 : MxRegOp; + def MxFPR80 : MxRegOp; +} + class MxMemOp @@ -711,6 +723,10 @@ : MxOpBundle("MxXRD"#size), ?>; } // foreach size = [16, 32] +foreach size = [32, 64, 80] in +def MxOp#size#AddrMode_fpr + : MxOpBundle("MxFPR"#size), ?>; + class MxType8Class : MxType; defm SP : MxAddressRegister<7, "sp", ["usp", "ssp", "isp", "a7"]>; +// Floating Point Registers +class MxFPRegister ALTNAMES = []> + : MxReg; + +foreach i = {0-7} in + def FP#i : MxFPRegister; + +// 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 SUBREGS = [], list SUBIDX = []> @@ -103,9 +116,16 @@ 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 --- /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 --- /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