diff --git a/llvm/cmake/config-ix.cmake b/llvm/cmake/config-ix.cmake --- a/llvm/cmake/config-ix.cmake +++ b/llvm/cmake/config-ix.cmake @@ -452,6 +452,8 @@ set(LLVM_NATIVE_ARCH RISCV) elseif (LLVM_NATIVE_ARCH MATCHES "riscv64") set(LLVM_NATIVE_ARCH RISCV) +elseif (LLVM_NATIVE_ARCH STREQUAL "m68k") + set(LLVM_NATIVE_ARCH M68k) else () message(FATAL_ERROR "Unknown architecture ${LLVM_NATIVE_ARCH}") endif () diff --git a/llvm/include/llvm/ADT/Triple.h b/llvm/include/llvm/ADT/Triple.h --- a/llvm/include/llvm/ADT/Triple.h +++ b/llvm/include/llvm/ADT/Triple.h @@ -58,6 +58,7 @@ bpfeb, // eBPF or extended BPF or 64-bit BPF (big endian) csky, // CSKY: csky hexagon, // Hexagon: hexagon + m68k, // M68k: Motorola 680x0 family mips, // MIPS: mips, mipsallegrex, mipsr6 mipsel, // MIPSEL: mipsel, mipsallegrexe, mipsr6el mips64, // MIPS64: mips64, mips64r6, mipsn32, mipsn32r6 diff --git a/llvm/lib/Support/Triple.cpp b/llvm/lib/Support/Triple.cpp --- a/llvm/lib/Support/Triple.cpp +++ b/llvm/lib/Support/Triple.cpp @@ -44,6 +44,7 @@ case lanai: return "lanai"; case le32: return "le32"; case le64: return "le64"; + case m68k: return "m68k"; case mips64: return "mips64"; case mips64el: return "mips64el"; case mips: return "mips"; @@ -105,6 +106,8 @@ case ppc: case ppcle: return "ppc"; + case m68k: return "m68k"; + case mips: case mipsel: case mips64: @@ -281,6 +284,7 @@ .Case("armeb", armeb) .Case("avr", avr) .StartsWith("bpf", BPFArch) + .Case("m68k", m68k) .Case("mips", mips) .Case("mipsel", mipsel) .Case("mips64", mips64) @@ -419,6 +423,7 @@ .Case("thumb", Triple::thumb) .Case("thumbeb", Triple::thumbeb) .Case("avr", Triple::avr) + .Case("m68k", Triple::m68k) .Case("msp430", Triple::msp430) .Cases("mips", "mipseb", "mipsallegrex", "mipsisa32r6", "mipsr6", Triple::mips) @@ -704,6 +709,7 @@ case Triple::lanai: case Triple::le32: case Triple::le64: + case Triple::m68k: case Triple::mips64: case Triple::mips64el: case Triple::mips: @@ -1277,6 +1283,7 @@ case llvm::Triple::kalimba: case llvm::Triple::lanai: case llvm::Triple::le32: + case llvm::Triple::m68k: case llvm::Triple::mips: case llvm::Triple::mipsel: case llvm::Triple::nvptx: @@ -1361,6 +1368,7 @@ case Triple::kalimba: case Triple::lanai: case Triple::le32: + case Triple::m68k: case Triple::mips: case Triple::mipsel: case Triple::nvptx: @@ -1413,6 +1421,7 @@ case Triple::hexagon: case Triple::kalimba: case Triple::lanai: + case Triple::m68k: case Triple::msp430: case Triple::r600: case Triple::shave: @@ -1537,6 +1546,7 @@ case Triple::lanai: case Triple::sparcv9: case Triple::systemz: + case Triple::m68k: // ARM is intentionally unsupported here, changing the architecture would // drop any arch suffixes. diff --git a/llvm/lib/Target/M68k/CMakeLists.txt b/llvm/lib/Target/M68k/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/M68k/CMakeLists.txt @@ -0,0 +1,36 @@ +add_llvm_component_group(M68k) + +set(LLVM_TARGET_DEFINITIONS M68k.td) + +tablegen(LLVM M68kGenRegisterInfo.inc -gen-register-info) +tablegen(LLVM M68kGenInstrInfo.inc -gen-instr-info) +tablegen(LLVM M68kGenSubtargetInfo.inc -gen-subtarget) +tablegen(LLVM M68kGenMCCodeBeads.inc -gen-code-beads) +tablegen(LLVM M68kGenMCPseudoLowering.inc -gen-pseudo-lowering) +tablegen(LLVM M68kGenDAGISel.inc -gen-dag-isel) +tablegen(LLVM M68kGenCallingConv.inc -gen-callingconv) +tablegen(LLVM M68kGenAsmWriter.inc -gen-asm-writer) + +add_public_tablegen_target(M68kCommonTableGen) + +add_llvm_target(M68kCodeGen + M68kTargetMachine.cpp + + LINK_COMPONENTS + Analysis + AsmPrinter + CodeGen + Core + MC + SelectionDAG + Support + Target + M68kDesc + M68kInfo + + ADD_TO_COMPONENT + M68k +) + +add_subdirectory(TargetInfo) +add_subdirectory(MCTargetDesc) diff --git a/llvm/lib/Target/M68k/M68k.td b/llvm/lib/Target/M68k/M68k.td new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/M68k/M68k.td @@ -0,0 +1,93 @@ +//===-- M68k.td - Motorola 680x0 target definitions ------*- tablegen -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This is a target description file for the Motorola 680x0 family, referred +/// to here as the "M68k" architecture. +/// +//===----------------------------------------------------------------------===// + +include "llvm/Target/Target.td" + +//===----------------------------------------------------------------------===// +// M68k Subtarget features +//===----------------------------------------------------------------------===// + +def FeatureISA00 + : SubtargetFeature<"isa-68000", "SubtargetKind", "M00", + "Is M68000 ISA supported">; + +def FeatureISA10 + : SubtargetFeature<"isa-68010", "SubtargetKind", "M10", + "Is M68010 ISA supported", + [ FeatureISA00 ]>; + +def FeatureISA20 + : SubtargetFeature<"isa-68020", "SubtargetKind", "M20", + "Is M68020 ISA supported", + [ FeatureISA10 ]>; + +def FeatureISA30 + : SubtargetFeature<"isa-68030", "SubtargetKind", "M30", + "Is M68030 ISA supported", + [ FeatureISA20 ]>; + +def FeatureISA40 + : SubtargetFeature<"isa-68040", "SubtargetKind", "M40", + "Is M68040 ISA supported", + [ FeatureISA30 ]>; + +def FeatureISA60 + : SubtargetFeature<"isa-68060", "SubtargetKind", "M60", + "Is M68060 ISA supported", + [ FeatureISA40 ]>; + +//===----------------------------------------------------------------------===// +// M68k processors supported. +//===----------------------------------------------------------------------===// + +include "M68kSchedule.td" + +class Proc Features> + : ProcessorModel; + +def : Proc<"generic", [ FeatureISA00 ]>; +def : Proc<"M68000", [ FeatureISA00 ]>; +def : Proc<"M68010", [ FeatureISA10 ]>; +def : Proc<"M68020", [ FeatureISA20 ]>; +def : Proc<"M68030", [ FeatureISA30 ]>; +def : Proc<"M68040", [ FeatureISA40 ]>; +def : Proc<"M68060", [ FeatureISA60 ]>; + +//===----------------------------------------------------------------------===// +// Register File Description +//===----------------------------------------------------------------------===// + +include "M68kRegisterInfo.td" + +//===----------------------------------------------------------------------===// +// Instruction Descriptions +//===----------------------------------------------------------------------===// + +include "M68kInstrInfo.td" + +def M68kInstrInfo : InstrInfo; + +//===----------------------------------------------------------------------===// +// Calling Conventions +//===----------------------------------------------------------------------===// + +include "M68kCallingConv.td" + +//===----------------------------------------------------------------------===// +// Target +//===----------------------------------------------------------------------===// + +def M68k : Target { + let InstructionSet = M68kInstrInfo; +} diff --git a/llvm/lib/Target/M68k/M68kCallingConv.td b/llvm/lib/Target/M68k/M68kCallingConv.td new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/M68k/M68kCallingConv.td @@ -0,0 +1,119 @@ +//===-- M68kCallingConv.td - Calling Conventions for M68k --*- tablegen -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This describes the calling conventions for the M68k architectures. These +/// conventions assume Int to be 4 bytes and 4 byte aligned. +/// +//===----------------------------------------------------------------------===// + +// TODO Verify C convention follows SysV M68K ABI + +class CCIfSubtarget + : CCIf" + "(State.getMachineFunction().getSubtarget()).", F), A>; + +//===----------------------------------------------------------------------===// +// Return Value Calling Conventions +//===----------------------------------------------------------------------===// + +/// Return-value conventions common to all M68k CC's. +def RetCC_M68kCommon : CallingConv<[ +]>; + +/// M68k C return convention. +/// TODO: Return via address register +def RetCC_M68k_C : CallingConv<[ + CCIfType<[i1], CCPromoteToType>, + CCIfType<[i8], CCAssignToReg<[BD0, BD1]>>, + CCIfType<[i16], CCAssignToReg<[WD0, WD1]>>, + CCIfType<[i32], CCAssignToReg<[D0, D1]>>, + CCDelegateTo +]>; + +/// M68k fastcc return convention. +/// This convention allows to return up to 16 bytes in registers which can be +/// split among 16 1-byte values or used for a single 16-byte value. +/// TODO: Verify its functionality and write tests +def RetCC_M68k_Fast : CallingConv<[ + CCIfType<[i1], CCPromoteToType>, + CCIfType<[i8], CCAssignToReg<[BD0, BD1]>>, + CCIfType<[i16], CCAssignToReg<[WD0, WD1, WA0, WA1]>>, + CCIfType<[i32], CCAssignToReg<[D0, D1, A0, A1]>>, + CCDelegateTo +]>; + +/// This is the root return-value convention for the M68k backend. +def RetCC_M68k : CallingConv<[ + CCIfCC<"CallingConv::Fast", CCDelegateTo>, + CCDelegateTo +]>; + +//===----------------------------------------------------------------------===// +// M68k C Calling Convention +//===----------------------------------------------------------------------===// + +/// CC_M68k_Common - In all M68k calling conventions, extra integers and FP +/// values are spilled on the stack. +def CC_M68k_Common : CallingConv<[ + /// Handles byval parameters. + CCIfByVal>, + + /// Integer values get stored in stack slots that are 4 bytes in + /// size and 4-byte aligned. + CCIfType<[i32], CCAssignToStack<4, 4>> +]>; + +def CC_M68k_Fast : CallingConv<[ + /// Promote i1/i8/i16 arguments to i32. + CCIfType<[i1, i8, i16], CCPromoteToType>, + + /// The 'nest' parameter, if any, is passed in A1. + CCIfNest>, // FIXME verify if this is correct + + /// Since M68k uses %An for pointers and we want them be passed in regs + /// too we have to use custom function. + CCIfType<[i32], CCCustom<"CC_M68k_Any_AssignToReg">>, + + /// Otherwise, same as everything else. + CCDelegateTo +]>; + +def CC_M68k_C : CallingConv<[ + /// Promote i1/i8/i16 arguments to i32. + CCIfType<[i1, i8, i16], CCPromoteToType>, + + /// The 'nest' parameter, if any, is passed in A1. + CCIfNest>, // FIXME verify if this is correct + + /// Use registers only if 'inreg' used and the call is not vararg + CCIfNotVarArg>>>, + + // TODO: Support for 'sret' + + /// Otherwise, same as everything else. + CCDelegateTo +]>; + +/// This is the root argument convention for the M68k backend. +def CC_M68k : CallingConv<[ + CCIfCC<"CallingConv::Fast", CCDelegateTo>, + CCDelegateTo +]>; + +//===----------------------------------------------------------------------===// +// Callee-saved Registers. +//===----------------------------------------------------------------------===// + +def CSR_NoRegs : CalleeSavedRegs<(add)>; + +// A5 - BP +// A6 - FP +def CSR_STD : CalleeSavedRegs<(add D2, D3, D4, D5, D6, D7, + A2, A3, A4, A5, A6)>; + diff --git a/llvm/lib/Target/M68k/M68kInstrArithmetic.td b/llvm/lib/Target/M68k/M68kInstrArithmetic.td new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/M68k/M68kInstrArithmetic.td @@ -0,0 +1,886 @@ +//===-- M68kInstrArithmetic.td - Integer Arith Instrs ------*- tablegen -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file describes the integer arithmetic instructions in the M68k +/// architecture. Here is the current status of the file: +/// +/// Machine: +/// +/// ADD [~] ADDA [~] ADDI [~] ADDQ [ ] ADDX [~] +/// CLR [ ] CMP [~] CMPA [~] CMPI [~] CMPM [ ] +/// CMP2 [ ] DIVS/DIVU [~] DIVSL/DIVUL [ ] EXT [~] EXTB [ ] +/// MULS/MULU [~] NEG [~] NEGX [~] SUB [~] SUBA [~] +/// SUBI [~] SUBQ [ ] SUBX [~] +/// +/// Map: +/// +/// [ ] - was not touched at all +/// [!] - requires extarnal stuff implemented +/// [~] - functional implementation +/// [X] - complete implementation +/// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Encoding +//===----------------------------------------------------------------------===// + +/// Encoding for Normal forms +/// ---------------------------------------------------- +/// F E D C | B A 9 | 8 7 6 | 5 4 3 | 2 1 0 +/// ---------------------------------------------------- +/// | | | EFFECTIVE ADDRESS +/// x x x x | REG | OP MODE | MODE | REG +/// ---------------------------------------------------- +class MxArithEncoding + : MxEncoding; + +/// Encoding for Extended forms +/// ------------------------------------------------------ +/// F E D C | B A 9 | 8 | 7 6 | 5 4 | 3 | 2 1 0 +/// ------------------------------------------------------ +/// x x x x | REG Rx | 1 | SIZE | 0 0 | M | REG Ry +/// ------------------------------------------------------ +/// Rx - destination +/// Ry - source +/// M - address mode switch +class MxArithXEncoding + : MxEncoding, SIZE, MxBead1Bit<0b1>, DST, CMD>; + +/// Encoding for Immediate forms +/// --------------------------------------------------- +/// F E D C B A 9 8 | 7 6 | 5 4 3 | 2 1 0 +/// --------------------------------------------------- +/// | | EFFECTIVE ADDRESS +/// x x x x x x x x | SIZE | MODE | REG +/// --------------------------------------------------- +/// 16-BIT WORD DATA | 8-BIT BYTE DATA +/// --------------------------------------------------- +/// 32-BIT LONG DATA +/// --------------------------------------------------- +/// NOTE It is used to store an immediate to memory, imm-to-reg are handled with +/// normal version +class MxArithImmEncoding + : MxEncoding, + // Source + SRC_EXT.Imm, SRC_EXT.B8, SRC_EXT.Scale, + SRC_EXT.WL, SRC_EXT.DAReg, + // Destination + DST_EXT.Imm, DST_EXT.B8, DST_EXT.Scale, + DST_EXT.WL, DST_EXT.DAReg>; + + +//===----------------------------------------------------------------------===// +// Add/Sub +//===----------------------------------------------------------------------===// + +let Defs = [CCR] in { +let Constraints = "$src = $dst" in { + +// $reg, $ccr <- $reg op $reg +class MxBiArOp_RFRR_xEA CMD> + : MxInst<(outs TYPE.ROp:$dst), (ins TYPE.ROp:$src, TYPE.ROp:$opd), + MN#"."#TYPE.Prefix#"\t$opd, $dst", + [(set TYPE.VT:$dst, CCR, (NODE TYPE.VT:$src, TYPE.VT:$opd))], + MxArithEncoding, + !cast("MxOpMode"#TYPE.Size#TYPE.RLet#"EA"), + MxBeadReg<0>, + !cast("MxEncEA"#TYPE.RLet#"_2"), + MxExtEmpty>>; + +/// This Op is similar to the one above except it uses reversed opmode, some +/// commands(e.g. eor) do not support dEA or rEA modes and require EAd for +/// register only operations. +/// NOTE when using dd commands it is irrelevant which opmode to use(as it seems) +/// but some opcodes support address register and some do not which creates this +/// mess. +class MxBiArOp_RFRR_EAd CMD> + : MxInst<(outs TYPE.ROp:$dst), (ins TYPE.ROp:$src, TYPE.ROp:$opd), + MN#"."#TYPE.Prefix#"\t$opd, $dst", + [(set TYPE.VT:$dst, CCR, (NODE TYPE.VT:$src, TYPE.VT:$opd))], + MxArithEncoding, + !cast("MxOpMode"#TYPE.Size#"EAd"), + MxBeadReg<2>, MxEncEAd_0, MxExtEmpty>>; + +// $reg <- $reg op $imm +class MxBiArOp_RFRI_xEA CMD> + : MxInst<(outs TYPE.ROp:$dst), (ins TYPE.ROp:$src, TYPE.IOp:$opd), + MN#"."#TYPE.Prefix#"\t$opd, $dst", + [(set TYPE.VT:$dst, CCR, (NODE TYPE.VT:$src, TYPE.IPat:$opd))], + MxArithEncoding, + !cast("MxOpMode"#TYPE.Size#TYPE.RLet#"EA"), + MxBeadReg<0>, MxEncEAi, + !cast("MxExtI"#TYPE.Size#"_2")>>; + +// Again, there are two ways to write an immediate to Dn register either dEA +// opmode or using *I encoding, and again some instrucitons also support address +// registers some do not. +class MxBiArOp_RFRI CMD> + : MxInst<(outs TYPE.ROp:$dst), (ins TYPE.ROp:$src, TYPE.IOp:$opd), + MN#"i."#TYPE.Prefix#"\t$opd, $dst", + [(set TYPE.VT:$dst, CCR, (NODE TYPE.VT:$src, TYPE.IPat:$opd))], + MxArithImmEncoding, !cast("MxEncSize"#TYPE.Size), + !cast("MxEncEA"#TYPE.RLet#"_0"), MxExtEmpty, + !cast("MxExtI"#TYPE.Size#"_2")>>; + +let mayLoad = 1 in +class MxBiArOp_RFRM CMD, MxEncEA EA, MxEncExt EXT> + : MxInst<(outs TYPE.ROp:$dst), (ins TYPE.ROp:$src, OPD:$opd), + MN#"."#TYPE.Prefix#"\t$opd, $dst", + [(set TYPE.VT:$dst, CCR, (NODE TYPE.VT:$src, (TYPE.Load PAT:$opd)))], + MxArithEncoding, + !cast("MxOpMode"#TYPE.Size#TYPE.RLet#"EA"), + MxBeadReg<0>, EA, EXT>>; + +} // Constraints + +let mayLoad = 1, mayStore = 1 in { + +// FIXME MxBiArOp_FMR/FMI cannot consume CCR from MxAdd/MxSub which leads for +// MxAdd to survive the match and subsequent mismatch. +class MxBiArOp_FMR CMD, MxEncEA EA, MxEncExt EXT> + : MxInst<(outs), (ins MEMOpd:$dst, TYPE.ROp:$opd), + MN#"."#TYPE.Prefix#"\t$opd, $dst", + [], + MxArithEncoding, + !cast("MxOpMode"#TYPE.Size#"EA"#TYPE.RLet), + MxBeadReg<1>, EA, EXT>>; + +class MxBiArOp_FMI CMD, MxEncEA MEMEA, MxEncExt MEMExt> + : MxInst<(outs), (ins MEMOpd:$dst, TYPE.IOp:$opd), + MN#"."#TYPE.Prefix#"\t$opd, $dst", + [], + MxArithImmEncoding, + !cast("MxEncSize"#TYPE.Size), + MEMEA, MEMExt, + !cast("MxExtI"#TYPE.Size#"_1")>>; +} // mayLoad, mayStore +} // Defs = [CCR] + +multiclass MxBiArOp_DF CMD, bits<4> CMDI> { + + // op $mem, $reg + def NAME#"8dk" : MxBiArOp_RFRM; + def NAME#"16dk" : MxBiArOp_RFRM; + def NAME#"32dk" : MxBiArOp_RFRM; + + def NAME#"8dq" : MxBiArOp_RFRM; + def NAME#"16dq" : MxBiArOp_RFRM; + def NAME#"32dq" : MxBiArOp_RFRM; + + def NAME#"8dp" : MxBiArOp_RFRM; + def NAME#"16dp" : MxBiArOp_RFRM; + def NAME#"32dp" : MxBiArOp_RFRM; + + def NAME#"8df" : MxBiArOp_RFRM; + def NAME#"16df" : MxBiArOp_RFRM; + def NAME#"32df" : MxBiArOp_RFRM; + + def NAME#"8dj" : MxBiArOp_RFRM; + def NAME#"16dj" : MxBiArOp_RFRM; + def NAME#"32dj" : MxBiArOp_RFRM; + + // op $imm, $reg + def NAME#"8di" : MxBiArOp_RFRI_xEA; + def NAME#"16di" : MxBiArOp_RFRI_xEA; + def NAME#"32di" : MxBiArOp_RFRI_xEA; + + // op $reg, $mem + def NAME#"8pd" : MxBiArOp_FMR; + def NAME#"16pd" : MxBiArOp_FMR; + def NAME#"32pd" : MxBiArOp_FMR; + + def NAME#"8fd" : MxBiArOp_FMR; + def NAME#"16fd" : MxBiArOp_FMR; + def NAME#"32fd" : MxBiArOp_FMR; + + def NAME#"8jd" : MxBiArOp_FMR; + def NAME#"16jd" : MxBiArOp_FMR; + def NAME#"32jd" : MxBiArOp_FMR; + + // op $imm, $mem + def NAME#"8pi" : MxBiArOp_FMI; + def NAME#"16pi" : MxBiArOp_FMI; + def NAME#"32pi" : MxBiArOp_FMI; + + def NAME#"8fi" : MxBiArOp_FMI; + def NAME#"16fi" : MxBiArOp_FMI; + def NAME#"32fi" : MxBiArOp_FMI; + + def NAME#"8ji" : MxBiArOp_FMI; + def NAME#"16ji" : MxBiArOp_FMI; + def NAME#"32ji" : MxBiArOp_FMI; + + let isCommutable = isComm in { + + def NAME#"8dd" : MxBiArOp_RFRR_xEA; + def NAME#"16dd" : MxBiArOp_RFRR_xEA; + def NAME#"32dd" : MxBiArOp_RFRR_xEA; + + } // isComm + +} // MxBiArOp_DF + + +// These special snowflakes allowed to match address registers but since *A +// operations do not produce CCR we should not match them against Mx nodes that +// produce it. +let Pattern = [(null_frag)] in +multiclass MxBiArOp_AF CMD, bits<4> CMDI> { + + def NAME#"32rk" : MxBiArOp_RFRM; + def NAME#"32rq" : MxBiArOp_RFRM; + def NAME#"32rf" : MxBiArOp_RFRM; + def NAME#"32rp" : MxBiArOp_RFRM; + def NAME#"32rj" : MxBiArOp_RFRM; + def NAME#"32ri" : MxBiArOp_RFRI_xEA; + + let isCommutable = isComm in + def NAME#"32rr" : MxBiArOp_RFRR_xEA; + +} // MxBiArOp_AF + +// NOTE These naturally produce CCR + +defm ADD : MxBiArOp_DF<"add", MxAdd, 1, 0xD, 0x6>; +defm ADD : MxBiArOp_AF<"add", MxAdd, 1, 0xD, 0x6>; +defm SUB : MxBiArOp_DF<"sub", MxSub, 0, 0x9, 0x4>; +defm SUB : MxBiArOp_AF<"sub", MxSub, 0, 0x9, 0x4>; + + +let Uses = [CCR], Defs = [CCR] in { +let Constraints = "$src = $dst" in { + +// $reg, ccr <- $reg op $reg op ccr +class MxBiArOp_RFRRF CMD> + : MxInst<(outs TYPE.ROp:$dst), (ins TYPE.ROp:$src, TYPE.ROp:$opd), + MN#"."#TYPE.Prefix#"\t$opd, $dst", + [(set TYPE.VT:$dst, CCR, (NODE TYPE.VT:$src, TYPE.VT:$opd, CCR))], + MxArithXEncoding, + !cast("MxEncSize"#TYPE.Size), + MxBead1Bit<0>, MxBeadReg<2>, MxBeadReg<0>>>; + +} // Constraints +} // Uses, Defs + +multiclass MxBiArOp_RFF CMD> { + +let isCommutable = isComm in { + + def NAME#"8dd" : MxBiArOp_RFRRF; + def NAME#"16dd" : MxBiArOp_RFRRF; + def NAME#"32dd" : MxBiArOp_RFRRF; + +} // isComm + +} // MxBiArOp_RFF + +// NOTE These consume and produce CCR +defm ADDX : MxBiArOp_RFF<"addx", MxAddX, 1, 0xD>; +defm SUBX : MxBiArOp_RFF<"subx", MxSubX, 0, 0x9>; + + +//===----------------------------------------------------------------------===// +// And/Xor/Or +//===----------------------------------------------------------------------===// + +defm AND : MxBiArOp_DF<"and", MxAnd, 1, 0xC, 0x2>; +defm OR : MxBiArOp_DF<"or", MxOr, 1, 0x8, 0x0>; + +multiclass MxBiArOp_DF_EAd CMD, bits<4> CMDI> { + + let isCommutable = 1 in { + + def NAME#"8dd" : MxBiArOp_RFRR_EAd; + def NAME#"16dd" : MxBiArOp_RFRR_EAd; + def NAME#"32dd" : MxBiArOp_RFRR_EAd; + + } // isCommutable = 1 + + def NAME#"8di" : MxBiArOp_RFRI; + def NAME#"16di" : MxBiArOp_RFRI; + def NAME#"32di" : MxBiArOp_RFRI; + +} // MxBiArOp_DF_EAd + +defm XOR : MxBiArOp_DF_EAd<"eor", MxXor, 0xB, 0xA>; + + +//===----------------------------------------------------------------------===// +// CMP +//===----------------------------------------------------------------------===// + +let Defs = [CCR] in { +class MxCmp_RR + : MxInst<(outs), (ins TYPE.ROp:$lhs, TYPE.ROp:$rhs), + "cmp."#TYPE.Prefix#"\t$lhs, $rhs", + [(set CCR, (MxCmp TYPE.VT:$lhs, TYPE.VT:$rhs))], + MxArithEncoding, + !cast("MxOpMode"#TYPE.Size#"dEA"), + MxBeadReg<1>, MxEncEAd_0, MxExtEmpty>>; + +class MxCmp_RI + : MxInst<(outs), (ins TYPE.IOp:$imm, TYPE.ROp:$reg), + "cmpi."#TYPE.Prefix#"\t$imm, $reg", + [(set CCR, (MxCmp TYPE.IPat:$imm, TYPE.VT:$reg))], + MxArithImmEncoding, + !cast("MxEncSize"#TYPE.Size), + MxEncEAd_1, MxExtEmpty, + !cast("MxExtI"#TYPE.Size#"_0")>>; + +let mayLoad = 1 in { + +class MxCmp_MI + : MxInst<(outs), (ins TYPE.IOp:$imm, MEMOpd:$mem), + "cmpi."#TYPE.Prefix#"\t$imm, $mem", + [(set CCR, (MxCmp TYPE.IPat:$imm, (load MEMPat:$mem)))], + MxArithImmEncoding, + !cast("MxEncSize"#TYPE.Size), + EA, EXT, + !cast("MxExtI"#TYPE.Size#"_0")>>; + +class MxCmp_BI + : MxInst<(outs), (ins TYPE.IOp:$imm, MxAL32:$abs), + "cmpi."#TYPE.Prefix#"\t$imm, $abs", + [(set CCR, (MxCmp TYPE.IPat:$imm, + (load (i32 (MxWrapper tglobaladdr:$abs)))))], + MxArithImmEncoding, + !cast("MxEncSize"#TYPE.Size), + MxEncEAb, MxExtI32_1, + !cast("MxExtI"#TYPE.Size#"_0")>>; + +class MxCmp_RM + : MxInst<(outs), (ins TYPE.ROp:$reg, MEMOpd:$mem), + "cmp."#TYPE.Prefix#"\t$mem, $reg", + [(set CCR, (MxCmp (load MEMPat:$mem), TYPE.ROp:$reg))], + MxArithEncoding, + !cast("MxOpMode"#TYPE.Size#"dEA"), + MxBeadReg<0>, EA, EXT>>; +} // let mayLoad = 1 + +} // let Defs = [CCR] + +multiclass MMxCmp_RM { + def NAME#TYPE.KOp.Letter : MxCmp_RM; + def NAME#TYPE.QOp.Letter : MxCmp_RM; + def NAME#TYPE.POp.Letter : MxCmp_RM; + def NAME#TYPE.FOp.Letter : MxCmp_RM; + def NAME#TYPE.JOp.Letter : MxCmp_RM; +} + +multiclass MMxCmp_MI { + def NAME#TYPE.KOp.Letter#"i" : MxCmp_MI; + def NAME#TYPE.QOp.Letter#"i" : MxCmp_MI; + def NAME#TYPE.POp.Letter#"i" : MxCmp_MI; + def NAME#TYPE.FOp.Letter#"i" : MxCmp_MI; + def NAME#TYPE.JOp.Letter#"i" : MxCmp_MI; +} + +foreach S = [8, 16, 32] in { + def CMP#S#dd : MxCmp_RR("MxType"#S#"d")>; + def CMP#S#di : MxCmp_RI("MxType"#S#"d")>; + def CMP#S#bi : MxCmp_BI("MxType"#S#"d")>; +} // foreach + +// cmp mem, Dn +defm CMP8d : MMxCmp_RM; +defm CMP16d : MMxCmp_RM; +defm CMP32d : MMxCmp_RM; + +// cmp #imm, mem +defm CMP8 : MMxCmp_MI; +defm CMP16 : MMxCmp_MI; +defm CMP32 : MMxCmp_MI; + + +//===----------------------------------------------------------------------===// +// EXT +//===----------------------------------------------------------------------===// + +def MxExtOpmode_wb : MxBead3Bits<0b010>; +def MxExtOpmode_lw : MxBead3Bits<0b011>; +def MxExtOpmode_lb : MxBead3Bits<0b111>; + +/// --------------------------------------------------- +/// F E D C B A 9 | 8 7 6 | 5 4 3 | 2 1 0 +/// --------------------------------------------------- +/// 0 1 0 0 1 0 0 | OPMODE | 0 0 0 | REG +/// --------------------------------------------------- +class MxExtEncoding + : MxEncoding, MxBead3Bits<0b000>, OPMODE, + MxBead3Bits<0b100>, MxBead4Bits<0b0100>>; + +let Defs = [CCR] in +let Constraints = "$src = $dst" in +class MxExt + : MxInst<(outs TO.ROp:$dst), (ins TO.ROp:$src), + "ext."#TO.Prefix#"\t$src", [], + MxExtEncoding("MxExtOpmode_"#TO.Prefix#FROM.Prefix)>>; + +def EXT16 : MxExt; +def EXT32 : MxExt; + +def : Pat<(sext_inreg i16:$src, i8), (EXT16 $src)>; +def : Pat<(sext_inreg i32:$src, i16), (EXT32 $src)>; +def : Pat<(sext_inreg i32:$src, i8), + (EXT32 (MOVXd32d16 (EXT16 (EXTRACT_SUBREG $src, MxSubRegIndex16Lo))))>; + + +//===----------------------------------------------------------------------===// +// DIV/MUL +//===----------------------------------------------------------------------===// + +def MxSDiMuOpmode : MxBead3Bits<0b111>; +def MxUDiMuOpmode : MxBead3Bits<0b011>; + +/// Word operation: +/// ---------------------------------------------------- +/// F E D C | B A 9 | 8 7 6 | 5 4 3 | 2 1 0 +/// ---------------------------------------------------- +/// | | | EFFECTIVE ADDRESS +/// x x x x | REG | OP MODE | MODE | REG +/// ---------------------------------------------------- +class MxDiMuEncoding + : MxEncoding, CMD, + EXT.Imm, EXT.B8, EXT.Scale, EXT.WL, EXT.DAReg>; + +let Defs = [CCR] in { +let Constraints = "$src = $dst" in { +// $reg <- $reg op $reg +class MxDiMuOp_DD CMD, MxBead3Bits OPMODE, + MxOperand DST, MxOperand OPD> + : MxInst<(outs DST:$dst), (ins DST:$src, OPD:$opd), MN#"\t$opd, $dst", [], + MxDiMuEncoding, OPMODE, MxEncEAd_2, MxExtEmpty>>; + +// $reg <- $reg op $imm +class MxDiMuOp_DI CMD, MxBead3Bits OPMODE, + MxOperand DST, MxOperand OPD> + : MxInst<(outs DST:$dst), (ins DST:$src, unknown:$opd), MN#"\t$opd, $dst", [], + MxDiMuEncoding, OPMODE, MxEncEAi, MxExtI16_2>>; +} // let Constraints +} // Defs = [CCR] + +multiclass MxDiMuOp CMD, bit isComm = 0> { + + let isCommutable = isComm in { + def "S"#NAME#"d32d16" : MxDiMuOp_DD; + def "U"#NAME#"d32d16" : MxDiMuOp_DD; + } + + def "S"#NAME#"d32i16" : MxDiMuOp_DI; + def "U"#NAME#"d32i16" : MxDiMuOp_DI; + +} + +defm DIV : MxDiMuOp<"div", 0x8>; + +// RR i8 +def : Pat<(sdiv i8:$dst, i8:$opd), + (EXTRACT_SUBREG + (SDIVd32d16 (MOVSXd32d8 $dst), (MOVSXd16d8 $opd)), + MxSubRegIndex8Lo)>; + +def : Pat<(udiv i8:$dst, i8:$opd), + (EXTRACT_SUBREG + (UDIVd32d16 (MOVZXd32d8 $dst), (MOVZXd16d8 $opd)), + MxSubRegIndex8Lo)>; + +def : Pat<(srem i8:$dst, i8:$opd), + (EXTRACT_SUBREG + (ASR32di (ASR32di (SDIVd32d16 (MOVSXd32d8 $dst), (MOVSXd16d8 $opd)), 8), 8), + MxSubRegIndex8Lo)>; + +def : Pat<(urem i8:$dst, i8:$opd), + (EXTRACT_SUBREG + (LSR32di (LSR32di (UDIVd32d16 (MOVZXd32d8 $dst), (MOVZXd16d8 $opd)), 8), 8), + MxSubRegIndex8Lo)>; + +// RR i16 +def : Pat<(sdiv i16:$dst, i16:$opd), + (EXTRACT_SUBREG + (SDIVd32d16 (MOVSXd32d16 $dst), $opd), + MxSubRegIndex16Lo)>; + +def : Pat<(udiv i16:$dst, i16:$opd), + (EXTRACT_SUBREG + (UDIVd32d16 (MOVZXd32d16 $dst), $opd), + MxSubRegIndex16Lo)>; + +def : Pat<(srem i16:$dst, i16:$opd), + (EXTRACT_SUBREG + (ASR32di (ASR32di (SDIVd32d16 (MOVSXd32d16 $dst), $opd), 8), 8), + MxSubRegIndex16Lo)>; + +def : Pat<(urem i16:$dst, i16:$opd), + (EXTRACT_SUBREG + (LSR32di (LSR32di (UDIVd32d16 (MOVZXd32d16 $dst), $opd), 8), 8), + MxSubRegIndex16Lo)>; + + +// RI i8 +def : Pat<(sdiv i8:$dst, MximmSExt8:$opd), + (EXTRACT_SUBREG + (SDIVd32i16 (MOVSXd32d8 $dst), imm:$opd), + MxSubRegIndex8Lo)>; + +def : Pat<(udiv i8:$dst, MximmSExt8:$opd), + (EXTRACT_SUBREG + (UDIVd32i16 (MOVZXd32d8 $dst), imm:$opd), + MxSubRegIndex8Lo)>; + +def : Pat<(srem i8:$dst, MximmSExt8:$opd), + (EXTRACT_SUBREG + (ASR32di (ASR32di (SDIVd32i16 (MOVSXd32d8 $dst), imm:$opd), 8), 8), + MxSubRegIndex8Lo)>; + +def : Pat<(urem i8:$dst, MximmSExt8:$opd), + (EXTRACT_SUBREG + (LSR32di (LSR32di (UDIVd32i16 (MOVZXd32d8 $dst), imm:$opd), 8), 8), + MxSubRegIndex8Lo)>; + +// RI i16 +def : Pat<(sdiv i16:$dst, MximmSExt16:$opd), + (EXTRACT_SUBREG + (SDIVd32i16 (MOVSXd32d16 $dst), imm:$opd), + MxSubRegIndex16Lo)>; + +def : Pat<(udiv i16:$dst, MximmSExt16:$opd), + (EXTRACT_SUBREG + (UDIVd32i16 (MOVZXd32d16 $dst), imm:$opd), + MxSubRegIndex16Lo)>; + +def : Pat<(srem i16:$dst, MximmSExt16:$opd), + (EXTRACT_SUBREG + (ASR32di (ASR32di (SDIVd32i16 (MOVSXd32d16 $dst), imm:$opd), 8), 8), + MxSubRegIndex16Lo)>; + +def : Pat<(urem i16:$dst, MximmSExt16:$opd), + (EXTRACT_SUBREG + (LSR32di (LSR32di (UDIVd32i16 (MOVZXd32d16 $dst), imm:$opd), 8), 8), + MxSubRegIndex16Lo)>; + + +defm MUL : MxDiMuOp<"mul", 0xC, 1>; + +// RR +def : Pat<(mul i16:$dst, i16:$opd), + (EXTRACT_SUBREG + (SMULd32d16 (MOVXd32d16 $dst), $opd), + MxSubRegIndex16Lo)>; + +def : Pat<(mulhs i16:$dst, i16:$opd), + (EXTRACT_SUBREG + (ASR32di (ASR32di (SMULd32d16 (MOVXd32d16 $dst), $opd), 8), 8), + MxSubRegIndex16Lo)>; + +def : Pat<(mulhu i16:$dst, i16:$opd), + (EXTRACT_SUBREG + (LSR32di (LSR32di (UMULd32d16 (MOVXd32d16 $dst), $opd), 8), 8), + MxSubRegIndex16Lo)>; + + +// RI +def : Pat<(mul i16:$dst, MximmSExt16:$opd), + (EXTRACT_SUBREG + (SMULd32i16 (MOVXd32d16 $dst), imm:$opd), + MxSubRegIndex16Lo)>; + +def : Pat<(mulhs i16:$dst, MximmSExt16:$opd), + (EXTRACT_SUBREG + (ASR32di (ASR32di (SMULd32i16 (MOVXd32d16 $dst), imm:$opd), 8), 8), + MxSubRegIndex16Lo)>; + +def : Pat<(mulhu i16:$dst, MximmSExt16:$opd), + (EXTRACT_SUBREG + (LSR32di (LSR32di (UMULd32i16 (MOVXd32d16 $dst), imm:$opd), 8), 8), + MxSubRegIndex16Lo)>; + + +//===----------------------------------------------------------------------===// +// NEG/NEGX +//===----------------------------------------------------------------------===// + +/// ------------+------------+------+---------+--------- +/// F E D C | B A 9 8 | 7 6 | 5 4 3 | 2 1 0 +/// ------------+------------+------+------------------- +/// | | | EFFECTIVE ADDRESS +/// 0 1 0 0 | x x x x | SIZE | MODE | REG +/// ------------+------------+------+---------+--------- +class MxNEGEncoding + : MxEncoding, + EXT.Imm, EXT.B8, EXT.Scale, EXT.WL, EXT.DAReg>; + +let Defs = [CCR] in { +let Constraints = "$src = $dst" in { + +class MxNeg_D + : MxInst<(outs TYPE.ROp:$dst), (ins TYPE.ROp:$src), + "neg."#TYPE.Prefix#"\t$dst", + [(set TYPE.VT:$dst, (ineg TYPE.VT:$src))], + MxNEGEncoding, + !cast("MxEncSize"#TYPE.Size), + MxEncEAd_0, MxExtEmpty>>; + +let Uses = [CCR] in { +class MxNegX_D + : MxInst<(outs TYPE.ROp:$dst), (ins TYPE.ROp:$src), + "negx."#TYPE.Prefix#"\t$dst", + [(set TYPE.VT:$dst, (MxSubX 0, TYPE.VT:$src, CCR))], + MxNEGEncoding, + !cast("MxEncSize"#TYPE.Size), + MxEncEAd_0, MxExtEmpty>>; +} + +} // let Constraints +} // let Defs = [CCR] + +foreach S = [8, 16, 32] in { + def NEG#S#d : MxNeg_D("MxType"#S#"d")>; + def NEGX#S#d : MxNegX_D("MxType"#S#"d")>; +} + +def : Pat<(MxSub 0, i8 :$src), (NEG8d MxDRD8 :$src)>; +def : Pat<(MxSub 0, i16:$src), (NEG16d MxDRD16:$src)>; +def : Pat<(MxSub 0, i32:$src), (NEG32d MxDRD32:$src)>; + +//===----------------------------------------------------------------------===// +// no-CCR Patterns +//===----------------------------------------------------------------------===// + +/// Basically the reason for this stuff is that add and addc share the same +/// operand types constraints for whatever reasons and I had to define a common +/// MxAdd and MxSub instructions that produce CCR and then pattern-map add and addc +/// to it. +/// NOTE On the other hand I see no reason why I cannot just drop explicit CCR +/// result. Anyway works for now, hopefully I will better understand how this stuff +/// is designed later +foreach N = ["add", "addc"] in { + + // add reg, reg + def : Pat<(!cast(N) i8 :$src, i8 :$opd), + (ADD8dd MxDRD8 :$src, MxDRD8 :$opd)>; + def : Pat<(!cast(N) i16:$src, i16:$opd), + (ADD16dd MxDRD16:$src, MxDRD16:$opd)>; + def : Pat<(!cast(N) i32:$src, i32:$opd), + (ADD32rr MxXRD32:$src, MxXRD32:$opd)>; + + // add (An), reg + def : Pat<(!cast(N) MxType8.VT:$src, (Mxloadi8 MxType8.JPat:$opd)), + (ADD8dj MxDRD8:$src, MxType8.JOp:$opd)>; + def : Pat<(!cast(N) MxType16.VT:$src, (Mxloadi16 MxType16.JPat:$opd)), + (ADD16dj MxDRD16:$src, MxType16.JOp:$opd)>; + def : Pat<(!cast(N) MxType32.VT:$src, (Mxloadi32 MxType32.JPat:$opd)), + (ADD32rj MxXRD32:$src, MxType32.JOp:$opd)>; + + // add (i,An), reg + def : Pat<(!cast(N) MxType8.VT:$src, (Mxloadi8 MxType8.PPat:$opd)), + (ADD8dp MxDRD8:$src, MxType8.POp:$opd)>; + def : Pat<(!cast(N) MxType16.VT:$src, (Mxloadi16 MxType16.PPat:$opd)), + (ADD16dp MxDRD16:$src, MxType16.POp:$opd)>; + def : Pat<(!cast(N) MxType32.VT:$src, (Mxloadi32 MxType32.PPat:$opd)), + (ADD32rp MxXRD32:$src, MxType32.POp:$opd)>; + + // add (i,An,Xn), reg + def : Pat<(!cast(N) MxType8.VT:$src, (Mxloadi8 MxType8.FPat:$opd)), + (ADD8df MxDRD8:$src, MxType8.FOp:$opd)>; + def : Pat<(!cast(N) MxType16.VT:$src, (Mxloadi16 MxType16.FPat:$opd)), + (ADD16df MxDRD16:$src, MxType16.FOp:$opd)>; + def : Pat<(!cast(N) MxType32.VT:$src, (Mxloadi32 MxType32.FPat:$opd)), + (ADD32rf MxXRD32:$src, MxType32.FOp:$opd)>; + + // add reg, imm + def : Pat<(!cast(N) i8: $src, MximmSExt8:$opd), + (ADD8di MxDRD8 :$src, imm:$opd)>; + def : Pat<(!cast(N) i16:$src, MximmSExt16:$opd), + (ADD16di MxDRD16:$src, imm:$opd)>; + + // LEAp is more complex and thus will be selected over normal ADD32ri but it cannot + // be used with data registers, here by adding complexity to a simple ADD32ri insts + // we make sure it will be selected over LEAp + let AddedComplexity = 15 in { + def : Pat<(!cast(N) i32:$src, MximmSExt32:$opd), + (ADD32ri MxXRD32:$src, imm:$opd)>; + } // AddedComplexity = 15 + + // add imm, (An) + def : Pat<(store (!cast(N) (load MxType8.JPat:$dst), MxType8.IPat:$opd), + MxType8.JPat:$dst), + (ADD8ji MxType8.JOp:$dst, imm:$opd)>; + def : Pat<(store (!cast(N) (load MxType16.JPat:$dst), MxType16.IPat:$opd), + MxType16.JPat:$dst), + (ADD16ji MxType16.JOp:$dst, imm:$opd)>; + def : Pat<(store (!cast(N) (load MxType32.JPat:$dst), MxType32.IPat:$opd), + MxType32.JPat:$dst), + (ADD32ji MxType32.JOp:$dst, imm:$opd)>; + +} // foreach add, addc + +def : Pat<(adde i8 :$src, i8 :$opd), (ADDX8dd MxDRD8 :$src, MxDRD8 :$opd)>; +def : Pat<(adde i16:$src, i16:$opd), (ADDX16dd MxDRD16:$src, MxDRD16:$opd)>; +def : Pat<(adde i32:$src, i32:$opd), (ADDX32dd MxDRD32:$src, MxDRD32:$opd)>; + + + +foreach N = ["sub", "subc"] in { + + // sub reg, reg + def : Pat<(!cast(N) i8 :$src, i8 :$opd), + (SUB8dd MxDRD8 :$src, MxDRD8 :$opd)>; + def : Pat<(!cast(N) i16:$src, i16:$opd), + (SUB16dd MxDRD16:$src, MxDRD16:$opd)>; + def : Pat<(!cast(N) i32:$src, i32:$opd), + (SUB32rr MxXRD32:$src, MxXRD32:$opd)>; + + + // sub (An), reg + def : Pat<(!cast(N) MxType8.VT:$src, (Mxloadi8 MxType8.JPat:$opd)), + (SUB8dj MxDRD8:$src, MxType8.JOp:$opd)>; + def : Pat<(!cast(N) MxType16.VT:$src, (Mxloadi16 MxType16.JPat:$opd)), + (SUB16dj MxDRD16:$src, MxType16.JOp:$opd)>; + def : Pat<(!cast(N) MxType32.VT:$src, (Mxloadi32 MxType32.JPat:$opd)), + (SUB32rj MxXRD32:$src, MxType32.JOp:$opd)>; + + // sub (i,An), reg + def : Pat<(!cast(N) MxType8.VT:$src, (Mxloadi8 MxType8.PPat:$opd)), + (SUB8dp MxDRD8:$src, MxType8.POp:$opd)>; + def : Pat<(!cast(N) MxType16.VT:$src, (Mxloadi16 MxType16.PPat:$opd)), + (SUB16dp MxDRD16:$src, MxType16.POp:$opd)>; + def : Pat<(!cast(N) MxType32.VT:$src, (Mxloadi32 MxType32.PPat:$opd)), + (SUB32rp MxXRD32:$src, MxType32.POp:$opd)>; + + // sub (i,An,Xn), reg + def : Pat<(!cast(N) MxType8.VT:$src, (Mxloadi8 MxType8.FPat:$opd)), + (SUB8df MxDRD8:$src, MxType8.FOp:$opd)>; + def : Pat<(!cast(N) MxType16.VT:$src, (Mxloadi16 MxType16.FPat:$opd)), + (SUB16df MxDRD16:$src, MxType16.FOp:$opd)>; + def : Pat<(!cast(N) MxType32.VT:$src, (Mxloadi32 MxType32.FPat:$opd)), + (SUB32rf MxXRD32:$src, MxType32.FOp:$opd)>; + + // sub reg, imm + def : Pat<(!cast(N) i8 :$src, MximmSExt8 :$opd), + (SUB8di MxDRD8 :$src, imm:$opd)>; + def : Pat<(!cast(N) i16:$src, MximmSExt16:$opd), + (SUB16di MxDRD16:$src, imm:$opd)>; + def : Pat<(!cast(N) i32:$src, MximmSExt32:$opd), + (SUB32ri MxXRD32:$src, imm:$opd)>; + + // sub imm, (An) + def : Pat<(store (!cast(N) (load MxType8.JPat:$dst), MxType8.IPat:$opd), + MxType8.JPat:$dst), + (SUB8ji MxType8.JOp:$dst, imm:$opd)>; + def : Pat<(store (!cast(N) (load MxType16.JPat:$dst), MxType16.IPat:$opd), + MxType16.JPat:$dst), + (SUB16ji MxType16.JOp:$dst, imm:$opd)>; + def : Pat<(store (!cast(N) (load MxType32.JPat:$dst), MxType32.IPat:$opd), + MxType32.JPat:$dst), + (SUB32ji MxType32.JOp:$dst, imm:$opd)>; + +} // foreach sub, subx + +def : Pat<(sube i8 :$src, i8 :$opd), (SUBX8dd MxDRD8 :$src, MxDRD8 :$opd)>; +def : Pat<(sube i16:$src, i16:$opd), (SUBX16dd MxDRD16:$src, MxDRD16:$opd)>; +def : Pat<(sube i32:$src, i32:$opd), (SUBX32dd MxDRD32:$src, MxDRD32:$opd)>; + + +// and reg, reg +def : Pat<(and i8 :$src, i8 :$opd), (AND8dd MxDRD8 :$src, MxDRD8 :$opd)>; +def : Pat<(and i16:$src, i16:$opd), (AND16dd MxDRD16:$src, MxDRD16:$opd)>; +def : Pat<(and i32:$src, i32:$opd), (AND32dd MxDRD32:$src, MxDRD32:$opd)>; + +// and reg, imm +def : Pat<(and i8: $src, MximmSExt8 :$opd), (AND8di MxDRD8 :$src, imm:$opd)>; +def : Pat<(and i16:$src, MximmSExt16:$opd), (AND16di MxDRD16:$src, imm:$opd)>; +def : Pat<(and i32:$src, MximmSExt32:$opd), (AND32di MxDRD32:$src, imm:$opd)>; + + +// xor reg,reg +def : Pat<(xor i8 :$src, i8 :$opd), (XOR8dd MxDRD8 :$src, MxDRD8 :$opd)>; +def : Pat<(xor i16:$src, i16:$opd), (XOR16dd MxDRD16:$src, MxDRD16:$opd)>; +def : Pat<(xor i32:$src, i32:$opd), (XOR32dd MxDRD32:$src, MxDRD32:$opd)>; + +// xor reg, imm +def : Pat<(xor i8: $src, MximmSExt8 :$opd), (XOR8di MxDRD8 :$src, imm:$opd)>; +def : Pat<(xor i16:$src, MximmSExt16:$opd), (XOR16di MxDRD16:$src, imm:$opd)>; +def : Pat<(xor i32:$src, MximmSExt32:$opd), (XOR32di MxDRD32:$src, imm:$opd)>; + + +// or reg, reg +def : Pat<(or i8 :$src, i8 :$opd), (OR8dd MxDRD8 :$src, MxDRD8 :$opd)>; +def : Pat<(or i16:$src, i16:$opd), (OR16dd MxDRD16:$src, MxDRD16:$opd)>; +def : Pat<(or i32:$src, i32:$opd), (OR32dd MxDRD32:$src, MxDRD32:$opd)>; + +// or reg, imm +def : Pat<(or i8: $src, MximmSExt8 :$opd), (OR8di MxDRD8 :$src, imm:$opd)>; +def : Pat<(or i16:$src, MximmSExt16:$opd), (OR16di MxDRD16:$src, imm:$opd)>; +def : Pat<(or i32:$src, MximmSExt32:$opd), (OR32di MxDRD32:$src, imm:$opd)>; diff --git a/llvm/lib/Target/M68k/M68kInstrBits.td b/llvm/lib/Target/M68k/M68kInstrBits.td new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/M68k/M68kInstrBits.td @@ -0,0 +1,100 @@ +//===------- M68kInstrBits.td - Bit Manipulation Instrs --*- tablegen -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file describes the bit manipulation instructions in the M68k +/// architecture. Here is the current status of the file: +/// +/// Machine: +/// +/// BCNG [ ] BCLR [ ] BSET [ ] BTST [~] +/// +/// Map: +/// +/// [ ] - was not touched at all +/// [!] - requires extarnal stuff implemented +/// [~] - in progress but usable +/// [x] - done +/// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// BTST +//===----------------------------------------------------------------------===// + +/// ------------+---------+---------+---------+--------- +/// F E D C | B A 9 | 8 7 6 | 5 4 3 | 2 1 0 +/// ------------+---------+---------+---------+--------- +/// 0 0 0 0 | REG | 1 0 0 | MODE | REG +/// ------------+---------+---------+---------+--------- +class MxBTSTEnc_R + : MxEncoding, REG, MxBead4Bits<0b0000>, + EXT.Imm, EXT.B8, EXT.Scale, EXT.WL, EXT.DAReg>; + +/// -------------------------------+---------+--------- +/// F E D C B A 9 8 . 7 6 | 5 4 3 | 2 1 0 +/// -------------------------------+---------+--------- +/// 0 0 0 0 1 0 0 0 . 0 0 | MODE | REG +/// ------------------------+------+---------+--------- +/// 0 0 0 0 0 0 0 0 | BIT NUMBER +/// ------------------------+-------------------------- +class MxBTSTEnc_I + : MxEncoding, + MxBead4Bits<0b1000>, MxBead4Bits<0b0000>, IMM, + EXT.Imm, EXT.B8, EXT.Scale, EXT.WL, EXT.DAReg>; + +let Defs = [CCR] in { +class MxBTST_RR + : MxInst<(outs), (ins TYPE.ROp:$dst, TYPE.ROp:$bitno), "btst\t$bitno, $dst", + [(set CCR, (MxBt TYPE.VT:$dst, TYPE.VT:$bitno))], + MxBTSTEnc_R, MxEncEAd_0, MxExtEmpty>>; + +class MxBTST_RI + : MxInst<(outs), (ins TYPE.ROp:$dst, TYPE.IOp:$bitno), "btst\t$bitno, $dst", + [(set CCR, (MxBt TYPE.VT:$dst, TYPE.IPat:$bitno))], + MxBTSTEnc_I, MxEncEAd_0, MxExtEmpty>>; + +class MxBTST_MR + : MxInst<(outs), (ins MEMOpd:$dst, TYPE.ROp:$bitno), "btst\t$bitno, $dst", + [(set CCR, (MxBt (TYPE.Load MEMPat:$dst), TYPE.VT:$bitno))], + MxBTSTEnc_R, EA, EXT>>; + +class MxBTST_MI + : MxInst<(outs), (ins MEMOpd:$dst, TYPE.IOp:$bitno), "btst\t$bitno, $dst", + [(set CCR, (MxBt (TYPE.Load MEMPat:$dst), TYPE.IPat:$bitno))], + MxBTSTEnc_I, EA, EXT>>; +} // Defs = [CCR] + +// Register BTST limited to 32 bits only +def BTST32dd : MxBTST_RR; +def BTST32di : MxBTST_RI; + +// Memory BTST limited to 8 bits only +def BTST8jd : MxBTST_MR; +def BTST8pd : MxBTST_MR; +def BTST8fd : MxBTST_MR; +def BTST8qd : MxBTST_MR; +def BTST8kd : MxBTST_MR; + +def BTST8ji : MxBTST_MI; +def BTST8pi : MxBTST_MI; +def BTST8fi : MxBTST_MI; +def BTST8qi : MxBTST_MI; +def BTST8ki : MxBTST_MI; diff --git a/llvm/lib/Target/M68k/M68kInstrCompiler.td b/llvm/lib/Target/M68k/M68kInstrCompiler.td new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/M68k/M68kInstrCompiler.td @@ -0,0 +1,128 @@ +//===-- M68kInstrCompiler.td - Pseudos and Patterns ------*- tablegen -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file describes the various pseudo instructions used by the compiler, +/// as well as Pat patterns used during instruction selection. +/// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// ConstantPool, GlobalAddress, ExternalSymbol, and JumpTable +//===----------------------------------------------------------------------===// + +def : Pat<(i32 (MxWrapper tconstpool :$src)), (MOV32ri tconstpool :$src)>; +def : Pat<(i32 (MxWrapper tglobaladdr :$src)), (MOV32ri tglobaladdr :$src)>; +def : Pat<(i32 (MxWrapper texternalsym :$src)), (MOV32ri texternalsym :$src)>; +def : Pat<(i32 (MxWrapper tjumptable :$src)), (MOV32ri tjumptable :$src)>; +def : Pat<(i32 (MxWrapper tblockaddress :$src)), (MOV32ri tblockaddress :$src)>; + +def : Pat<(add MxDRD32:$src, (MxWrapper tconstpool:$opd)), + (ADD32ri MxDRD32:$src, tconstpool:$opd)>; +def : Pat<(add MxARD32:$src, (MxWrapper tjumptable:$opd)), + (ADD32ri MxARD32:$src, tjumptable:$opd)>; +def : Pat<(add MxARD32:$src, (MxWrapper tglobaladdr :$opd)), + (ADD32ri MxARD32:$src, tglobaladdr:$opd)>; +def : Pat<(add MxARD32:$src, (MxWrapper texternalsym:$opd)), + (ADD32ri MxARD32:$src, texternalsym:$opd)>; +def : Pat<(add MxARD32:$src, (MxWrapper tblockaddress:$opd)), + (ADD32ri MxARD32:$src, tblockaddress:$opd)>; + +def : Pat<(store (i32 (MxWrapper tglobaladdr:$src)), iPTR:$dst), + (MOV32ji MxARI32:$dst, tglobaladdr:$src)>; +def : Pat<(store (i32 (MxWrapper texternalsym:$src)), iPTR:$dst), + (MOV32ji MxARI32:$dst, texternalsym:$src)>; +def : Pat<(store (i32 (MxWrapper tblockaddress:$src)), iPTR:$dst), + (MOV32ji MxARI32:$dst, tblockaddress:$src)>; + +def : Pat<(i32 (MxWrapperPC tconstpool :$src)), (LEA32q tconstpool :$src)>; +def : Pat<(i32 (MxWrapperPC tglobaladdr :$src)), (LEA32q tglobaladdr :$src)>; +def : Pat<(i32 (MxWrapperPC texternalsym :$src)), (LEA32q texternalsym :$src)>; +def : Pat<(i32 (MxWrapperPC tjumptable :$src)), (LEA32q tjumptable :$src)>; +def : Pat<(i32 (MxWrapperPC tblockaddress :$src)), (LEA32q tblockaddress :$src)>; + + +//===----------------------------------------------------------------------===// +// Conditional Move Pseudo Instructions +// +// CMOV* - Used to implement the SELECT DAG operation. Expanded after +// instruction selection into a branch sequence. +//===----------------------------------------------------------------------===// + +let usesCustomInserter = 1, Uses = [CCR] in +class MxCMove + : MxPseudo<(outs TYPE.ROp:$dst), (ins TYPE.ROp:$t, TYPE.ROp:$f, i8imm:$cond), + "", + [(set TYPE.VT:$dst, + (TYPE.VT (MxCmov TYPE.VT:$t, TYPE.VT:$f, imm:$cond, CCR)))]>; + +def CMOV8d : MxCMove; +def CMOV16d : MxCMove; +def CMOV32r : MxCMove; + + +//===----------------------------------------------------------------------===// +// Calls +//===----------------------------------------------------------------------===// + +// ADJCALLSTACKDOWN/UP implicitly use/def %SP because they may be expanded into +// a stack adjustment and the codegen must know that they may modify the stack +// pointer before prolog-epilog rewriting occurs. +// Pessimistically assume ADJCALLSTACKDOWN / ADJCALLSTACKUP will become +// sub / add which can clobber CCR. +let Defs = [SP, CCR], Uses = [SP] in { + + def ADJCALLSTACKDOWN + : MxPseudo<(outs), (ins i32imm:$amt1, i32imm:$amt2), "#ADJCALLSTACKDOWN", + [(MxCallSeqStart timm:$amt1, timm:$amt2)]>; + + def ADJCALLSTACKUP + : MxPseudo<(outs), (ins i32imm:$amt1, i32imm:$amt2), "#ADJCALLSTACKUP", + [(MxCallSeqEnd timm:$amt1, timm:$amt2)]>; + +} // Defs + +//===----------------------------------------------------------------------===// +// Tail Call +//===----------------------------------------------------------------------===// + +// Tailcall stuff. The TCRETURN instructions execute after the epilog, so they +// can never use callee-saved registers. That is the purpose of the XR32_TC +// register classes. + +// FIXME TC is disabled for PIC mode because the global base +// register which is part of the address mode may be assigned a +// callee-saved register. +def : Pat<(MxTCRet (load MxCP_ARII:$dst), imm:$adj), + (TCRETURNj (MOV32af_TC MxARII32:$dst), imm:$adj)>, + Requires<[IsNotPIC]>; + +def : Pat<(MxTCRet AR32_TC:$dst, imm:$adj), + (TCRETURNj MxARI32_TC:$dst, imm:$adj)>; + +def : Pat<(MxTCRet (i32 tglobaladdr:$dst), imm:$adj), + (TCRETURNq MxPCD32:$dst, imm:$adj)>; + +def : Pat<(MxTCRet (i32 texternalsym:$dst), imm:$adj), + (TCRETURNq MxPCD32:$dst, imm:$adj)>; + + +//===----------------------------------------------------------------------===// +// Segmented Stack +// +// When using segmented stacks these are lowered into instructions which first +// check if the current stacklet has enough free memory. If it does, memory is +// allocated by bumping the stack pointer. Otherwise memory is allocated from +// the heap. +//===----------------------------------------------------------------------===// + +let Defs = [SP, CCR], Uses = [SP] in +let usesCustomInserter = 1 in +def SALLOCA : MxPseudo<(outs MxARD32:$dst), (ins MxARD32:$size), + "# variable sized alloca for segmented stacks", + [(set iPTR:$dst, (MxSegAlloca iPTR:$size))]>; diff --git a/llvm/lib/Target/M68k/M68kInstrControl.td b/llvm/lib/Target/M68k/M68kInstrControl.td new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/M68k/M68kInstrControl.td @@ -0,0 +1,317 @@ +//===-- M68kInstrControl.td - Control Flow Instructions --*- tablegen -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file describes the M68k jump, return, call, and related instructions. +/// Here is the current status of the file: +/// +/// Machine: +/// +/// BRA [x] BSR [ ] Bcc [ ] DBcc [ ] FBcc [ ] +/// FDBcc [ ] FNOP [ ] FPn [ ] FScc [ ] FTST [ ] +/// JMP [~] JSR [x] NOP [x] RTD [!] RTR [ ] +/// RTS [x] Scc [x] TST [ ] +/// +/// Pseudo: +/// +/// RET [x] +/// TCRETURNj [x] TCRETURNq [x] +/// TAILJMPj [x] TAILJMPq [x] +/// +/// Map: +/// +/// [ ] - was not touched at all +/// [!] - requires extarnal stuff implemented +/// [~] - in progress but usable +/// [x] - done +/// +/// +/// NOTE +/// Though branch and jump instructions are using memory operands they +/// DO NOT read the jump address from memory, they just calculate EA +/// and jump there. +/// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// NOP +//===----------------------------------------------------------------------===// + +let hasSideEffects = 0 in { + def NOP : MxInst<(outs), (ins), "nop", [], MxEncFixed<0x4E71>>; +} + + +//===----------------------------------------------------------------------===// +// Conditions +//===----------------------------------------------------------------------===// + +/// CC—Carry clear GE—Greater than or equal +/// LS—Lower or same PL—Plus +/// CS—Carry set GT—Greater than +/// LT—Less than T—Always true* +/// EQ—Equal HI—Higher +/// MI—Minus VC—Overflow clear +/// F—Never true* LE—Less than or equal +/// NE—Not equal VS—Overflow set +/// +/// *Not applicable to the Bcc instructions. +def MxCCt : MxBead4Bits<0b0000>; +def MxCCf : MxBead4Bits<0b0001>; +def MxCChi : MxBead4Bits<0b0010>; +def MxCCls : MxBead4Bits<0b0011>; +def MxCCcc : MxBead4Bits<0b0100>; +def MxCCcs : MxBead4Bits<0b0101>; +def MxCCne : MxBead4Bits<0b0110>; +def MxCCeq : MxBead4Bits<0b0111>; +def MxCCvc : MxBead4Bits<0b1000>; +def MxCCvs : MxBead4Bits<0b1001>; +def MxCCpl : MxBead4Bits<0b1010>; +def MxCCmi : MxBead4Bits<0b1011>; +def MxCCge : MxBead4Bits<0b1100>; +def MxCClt : MxBead4Bits<0b1101>; +def MxCCgt : MxBead4Bits<0b1110>; +def MxCCle : MxBead4Bits<0b1111>; + +/// --------------------------------+---------+--------- +/// F E D C | B A 9 8 | 7 6 | 5 4 3 | 2 1 0 +/// --------------------------------+---------+--------- +/// 0 1 0 1 | CONDITION | 1 1 | MODE | REG +/// ---------------------------------------------------- +class MxSccEncoding + : MxEncoding, CC, MxBead4Bits<0b0101>, + EXT.Imm, EXT.B8, EXT.Scale, EXT.WL, EXT.DAReg>; + +let Uses = [CCR] in { +class MxSccR + : MxInst<(outs MxDRD8:$dst), (ins), "s"#CC#"\t$dst", + [(set i8:$dst, (MxSetCC !cast("MxCOND"#CC), CCR))], + MxSccEncoding("MxCC"#CC)>>; + +class MxSccM + : MxInst<(outs), (ins MEMOpd:$dst), "s"#CC#"\t$dst", + [(store (MxSetCC !cast("MxCOND"#CC), CCR), MEMPat:$dst)], + MxSccEncoding("MxCC"#CC)>>; +} + +foreach cc = [ "cc", "ls", "lt", "eq", "mi", "f", "ne", "ge", + "cs", "pl", "gt", "t", "hi", "vc", "le", "vs"] in { +def SET#"d8"#cc : MxSccR; +def SET#"j8"#cc : MxSccM; +def SET#"p8"#cc : MxSccM; +} + +//===----------------------------------------------------------------------===// +// Jumps +//===----------------------------------------------------------------------===// + +///------------------------------+---------+--------- +/// F E D C B A 9 8 7 6 | 5 4 3 | 2 1 0 +///------------------------------+---------+--------- +/// 0 1 0 0 1 1 1 0 1 1 | MODE | REG +///------------------------------+---------+--------- +let isBranch = 1, isTerminator = 1, isBarrier = 1, isIndirectBranch = 1 in +class MxJMP + : MxInst<(outs), (ins LOCOp:$dst), "jmp\t$dst", [(brind iPTR:$dst)], + MxEncoding, + MxBead4Bits<0b1110>, MxBead4Bits<0b0100>, + EXT.Imm, EXT.B8, EXT.Scale, EXT.WL, EXT.DAReg>>; + +def JMP32j : MxJMP; + + +// FIXME Support 16 bit indirect jump. +// Currently M68k does not allow 16 bit indirect jumps use sext operands +// def JMP16r : MxInst<(outs), (ins M68k_ARI16:$dst), +// "jmp\t$dst", +// [(brind AR16:$dst)]>; + +//===----------------------------------------------------------------------===// +// Branches +//===----------------------------------------------------------------------===// + +/// -------------------------------------------------- +/// F E D C | B A 9 8 | 7 6 5 4 3 2 1 0 +/// -------------------------------------------------- +/// 0 1 1 0 | CONDITION | 8-BIT DISPLACEMENT +/// -------------------------------------------------- +/// 16-BIT DISPLACEMENT IF 8-BIT DISPLACEMENT = $00 +/// -------------------------------------------------- +/// 32-BIT DISPLACEMENT IF 8-BIT DISPLACEMENT = $FF +/// -------------------------------------------------- +let isBranch = 1, isTerminator = 1, Uses = [CCR] in +class MxBcc + : MxInst<(outs), (ins TARGET:$dst), "b"#cc#"\t$dst", [], ENC>; + +foreach cc = [ "cc", "ls", "lt", "eq", "mi", "ne", "ge", + "cs", "pl", "gt", "hi", "vc", "le", "vs"] in { + def B#cc#"8" + : MxBcc, + !cast("MxCC"#cc), MxBead4Bits<0x6>>>; + def B#cc#"16" + : MxBcc, + MxBead4Bits<0x0>, !cast("MxCC"#cc), + MxBead4Bits<0x6>, MxBead16Imm<0>>>; +} + +foreach cc = [ "cc", "ls", "lt", "eq", "mi", "ne", "ge", + "cs", "pl", "gt", "hi", "vc", "le", "vs"] in { +def : Pat<(MxBrCond bb:$target, !cast("MxCOND"#cc), CCR), + (!cast("B"#cc#"8") MxBrTarget8:$target)>; +} + +/// ------------------------------------------------- +/// F E D C B A 9 8 | 7 6 5 4 3 2 1 0 +/// ------------------------------------------------- +/// 0 1 1 0 0 0 0 0 | 8-BIT DISPLACEMENT +/// ------------------------------------------------- +/// 16-BIT DISPLACEMENT IF 8-BIT DISPLACEMENT = $00 +/// ------------------------------------------------- +/// 32-BIT DISPLACEMENT IF 8-BIT DISPLACEMENT = $FF +/// ------------------------------------------------- +let isBranch = 1, isTerminator = 1, isBarrier=1 in +class MxBra + : MxInst<(outs), (ins TARGET:$dst), "bra\t$dst", [], ENC>; + +def BRA8 : MxBra, MxBead4Bits<0x0>, + MxBead4Bits<0x6>>>; +def BRA16 : MxBra, MxBead4Bits<0x0>, + MxBead4Bits<0x0>, MxBead4Bits<0x6>, + MxBead16Imm<0>>>; + +def : Pat<(br bb:$target), (BRA8 MxBrTarget8:$target)>; + + +//===----------------------------------------------------------------------===// +// Call +//===----------------------------------------------------------------------===// + +// All calls clobber the non-callee saved registers. %SP is marked as +// a use to prevent stack-pointer assignments that appear immediately +// before calls from potentially appearing dead. Uses for argument +// registers are added manually. +let Uses = [SP] in +let isCall = 1 in +///------------------------------+---------+--------- +/// F E D C B A 9 8 7 6 | 5 4 3 | 2 1 0 +///------------------------------+---------+--------- +/// 0 1 0 0 1 1 1 0 1 0 | MODE | REG +///------------------------------+---------+--------- +class MxCall + : MxInst<(outs), (ins LOCOp:$dst), "jsr\t$dst", [], + MxEncoding, + MxBead4Bits<0b1110>, MxBead4Bits<0b0100>, + EXT.Imm, EXT.B8, EXT.Scale, EXT.WL, EXT.DAReg>>; + +def CALLk : MxCall; +def CALLq : MxCall; +def CALLb : MxCall; +def CALLj : MxCall; + +multiclass CallPat { + let Predicates = [pred] in { + def : Pat<(MxCall (i32 tglobaladdr:$dst)), (callOp tglobaladdr:$dst)>; + def : Pat<(MxCall (i32 texternalsym:$dst)), (callOp texternalsym:$dst)>; + def : Pat<(MxCall (i32 imm:$dst)), (callOp imm:$dst)>; + } +} + +defm : CallPat; +defm : CallPat; + +def : Pat<(MxCall iPTR:$dst), (CALLj MxARI32:$dst)>; + +//===----------------------------------------------------------------------===// +// Tail Call +//===----------------------------------------------------------------------===// + +let isCodeGenOnly = 1 in { +let Uses = [SP] in { +let isCall = 1, isTerminator = 1, isBarrier = 1 in { + +let isReturn = 1 in +def TCRETURNq : MxPseudo<(outs), (ins MxPCD32:$dst, i32imm:$adj)>; +def TAILJMPq : MxPseudo<(outs), (ins MxPCD32:$dst)>; + +// NOTE j does not mean load and jump M68k jmp just calculates EA and jumps +// and it is using Mem form like (An) thus j letter. +let isReturn = 1 in +def TCRETURNj : MxPseudo<(outs), (ins MxARI32_TC:$dst, i32imm:$adj)>; +def TAILJMPj : MxPseudo<(outs), (ins MxARI32_TC:$dst)>; +} // isCall = 1, isTerminator = 1, isBarrier = 1 +} // Uses = [SP] +} // isCodeGenOnly = 1 + +//===----------------------------------------------------------------------===// +// Return +//===----------------------------------------------------------------------===// + +// TODO Implement LINK/UNLK + +let isTerminator = 1, isReturn = 1, isBarrier = 1, hasCtrlDep = 1 in { + +def RTS : MxInst<(outs), (ins), "rts", [], MxEncFixed<0x4E75>>; + +let isCodeGenOnly = 1 in +def RET : MxPseudo<(outs), (ins i32imm:$adj, variable_ops), "", + [(MxRet timm:$adj)]>; +} // isTerminator = 1, isReturn = 1, isBarrier = 1, hasCtrlDep = 1 + +//===----------------------------------------------------------------------===// +// SETCC_C Patterns +//===----------------------------------------------------------------------===// + +// Use subx to materialize carry bit. +let Uses = [CCR], Defs = [CCR], isPseudo = 1 in { +// FIXME These are pseudo ops that should be replaced with Pat<> patterns. +// However, Pat<> can't replicate the destination reg into the inputs of the +// result. +def SETCS_C8d : MxPseudo<(outs MxDRD8:$dst), (ins), "", + [(set MxDRD8:$dst, (MxSetCC_C MxCONDcs, CCR))]>; +def SETCS_C16d : MxPseudo<(outs MxDRD16:$dst), (ins), "", + [(set MxDRD16:$dst, (MxSetCC_C MxCONDcs, CCR))]>; +def SETCS_C32d : MxPseudo<(outs MxXRD32:$dst), (ins), "", + [(set MxXRD32:$dst, (MxSetCC_C MxCONDcs, CCR))]>; +} // Uses = [CCR], Defs = [CCR], isPseudo = 1 + + +def : Pat<(i16 (anyext (i8 (MxSetCC_C MxCONDcs, CCR)))), (SETCS_C16d)>; +def : Pat<(i32 (anyext (i8 (MxSetCC_C MxCONDcs, CCR)))), (SETCS_C32d)>; + +def : Pat<(i16 (sext (i8 (MxSetCC_C MxCONDcs, CCR)))), (SETCS_C16d)>; +def : Pat<(i32 (sext (i8 (MxSetCC_C MxCONDcs, CCR)))), (SETCS_C32d)>; + +// We canonicalize 'scs' to "(and (subx reg,reg), 1)" on the hope that the and +// will be eliminated and that the subx can be extended up to a wider type. When +// this happens, it is great. However, if we are left with an 8-bit subx and an +// and, we might as well just match it as a setb. +def : Pat<(and (i8 (MxSetCC_C MxCONDcs, CCR)), 1), (SETd8cs)>; + +// (add OP, SETB) -> (addx OP, (move 0)) +def : Pat<(add (and (i8 (MxSetCC_C MxCONDcs, CCR)), 1), MxDRD8:$op), + (ADDX8dd MxDRD8:$op, (MOV8di 0))>; +def : Pat<(add (and (i32 (MxSetCC_C MxCONDcs, CCR)), 1), MxXRD32:$op), + (ADDX32dd MxDRD32:$op, (MOV32ri 0))>; + +// (sub OP, SETB) -> (subx OP, (move 0)) +def : Pat<(sub MxDRD8:$op, (and (i8 (MxSetCC_C MxCONDcs, CCR)), 1)), + (SUBX8dd MxDRD8:$op, (MOV8di 0))>; +def : Pat<(sub MxXRD32:$op, (and (i32 (MxSetCC_C MxCONDcs, CCR)), 1)), + (SUBX32dd MxDRD32:$op, (MOV32ri 0))>; + +// (sub OP, SETCC_CARRY) -> (addx OP, (move 0)) +def : Pat<(sub MxDRD8:$op, (i8 (MxSetCC_C MxCONDcs, CCR))), + (ADDX8dd MxDRD8:$op, (MOV8di 0))>; +def : Pat<(sub MxXRD32:$op, (i32 (MxSetCC_C MxCONDcs, CCR))), + (ADDX32dd MxDRD32:$op, (MOV32ri 0))>; diff --git a/llvm/lib/Target/M68k/M68kInstrData.td b/llvm/lib/Target/M68k/M68kInstrData.td new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/M68k/M68kInstrData.td @@ -0,0 +1,712 @@ +//== M68kInstrData.td - M68k Data Movement Instructions -*- tablegen --===// +// +// 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 +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file describes the Motorola 680x0 data movement instructions which are +/// the basic means of transferring and storing addresses and data. Here is the +/// current status of the file: +/// +/// Machine: +/// +/// EXG [ ] FMOVE [ ] FSMOVE [ ] FDMOVE [ ] FMOVEM [ ] +/// LEA [~] PEA [ ] MOVE [~] MOVE16 [ ] MOVEA [ ] +/// MOVEM [ ] MOVEP [ ] MOVEQ [ ] LINK [ ] UNLK [ ] +/// +/// Pseudo: +/// +/// MOVSX [x] MOVZX [x] MOVX [x] +/// +/// Map: +/// +/// [ ] - was not touched at all +/// [!] - requires extarnal stuff implemented +/// [~] - in progress but usable +/// [x] - done +/// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// MOVE +//===----------------------------------------------------------------------===// + +/// ----------------------------------------------------- +/// F E | D C | B A 9 | 8 7 6 | 5 4 3 | 2 1 0 +/// ----------------------------------------------------- +/// | | DESTINATION | SOURCE +/// 0 0 | SIZE | REG | MODE | MODE | REG +/// ----------------------------------------------------- +/// +/// NOTE Move requires EA X version for direct register destination(0) +class MxMoveEncoding + : MxEncoding, + srcExt.Imm, srcExt.B8, srcExt.Scale, srcExt.WL, srcExt.DAReg, + dstExt.Imm, dstExt.B8, dstExt.Scale, dstExt.WL, dstExt.DAReg>; + +/// MOVE has alternate size encoding +class MxMoveSize value> : MxBead2Bits; +def MxMoveSize8 : MxMoveSize<0b01>; +def MxMoveSize16 : MxMoveSize<0b11>; +def MxMoveSize32 : MxMoveSize<0b10>; + +let Defs = [CCR] in +class MxMove pattern, MxEncoding enc> + : MxInst; + +class MxMove_RR + : MxMove; + +let mayStore = 1 in { +class MxMove_MR + : MxMove; + +class MxMove_MI + : MxMove; +} // let mayStore = 1 + +class MxMove_RI + : MxMove; + + +let mayLoad = 1 in +class MxMove_RM + : MxMove>; + +multiclass MMxMove_RM { + + // REG <- (An)+ + def NAME#REG.OOp.Letter#REG.Postfix : MxMove_RM; + + // REG <- -(An) + def NAME#REG.EOp.Letter#REG.Postfix : MxMove_RM; + + // REG <- (i,PC,Xn) + def NAME#REG.KOp.Letter#REG.Postfix : MxMove_RM; + + // REG <- (i,PC) + def NAME#REG.QOp.Letter#REG.Postfix : MxMove_RM; + + // REG <- (i,An,Xn) + def NAME#REG.FOp.Letter#REG.Postfix : MxMove_RM; + + // REG <- (i,An) + def NAME#REG.POp.Letter#REG.Postfix : MxMove_RM; + + // REG <- (ABS) + def NAME#REG.BOp.Letter#REG.Postfix : MxMove_RM; + + // REG <- (An) + def NAME#REG.JOp.Letter#REG.Postfix : MxMove_RM; +} + +let mayLoad = 1, mayStore = 1 in { +class MxMove_MM + : MxMove>; +} // let mayLoad = 1, mayStore = 1 + +multiclass MMxMove_MM { + + // MEM <- (An)+ + def NAME#TYPE.OOp.Letter#TYPE.Postfix + : MxMove_MM; + + // MEM <- -(An) + def NAME#TYPE.EOp.Letter#TYPE.Postfix + : MxMove_MM; + + // MEM <- (i,An) + def NAME#TYPE.POp.Letter#TYPE.Postfix + : MxMove_MM; + + // MEM <- (i,An,Xn) + def NAME#TYPE.FOp.Letter#TYPE.Postfix + : MxMove_MM; + + // MEM <- (i,PC,Xn) + def NAME#TYPE.KOp.Letter#TYPE.Postfix + : MxMove_MM; + + // MEM <- (i,PC) + def NAME#TYPE.QOp.Letter#TYPE.Postfix + : MxMove_MM; + + // MEM <- (ABS) + def NAME#TYPE.BOp.Letter#TYPE.Postfix + : MxMove_MM; + + // MEM <- (An) + def NAME#TYPE.JOp.Letter#TYPE.Postfix + : MxMove_MM; +} + +def MOV8dd + : MxMove_RR>; + +// M <- R +def MOV8fd : MxMove_MR>; + +def MOV8pd : MxMove_MR>; + +def MOV8ed : MxMove_MR>; + +def MOV8od : MxMove_MR>; + +def MOV8bd : MxMove_MR>; + +def MOV8jd : MxMove_MR>; + + +// R <- I +def MOV8di : MxMove_RI>; + +foreach S = [16, 32] in { + foreach D = [ "r", "a" ] in { + + foreach O = [ "r", "a" ] in { + def MOV#S#D#O : MxMove_RR< + !cast("MxType"#S#D), + !cast("MxType"#S#O), + MxMoveEncoding("MxMoveSize"#S), + !cast("MxEncEA"#D#"_1"), MxExtEmpty, + !cast("MxEncEA"#D#"_0_reflected"), MxExtEmpty>>; + } + + // M <- R + def MOV#S#"f"#D : MxMove_MR< + !cast("MxType"#S).FOp, + !cast("MxType"#S).FPat, + !cast("MxType"#S#D), + MxMoveEncoding("MxMoveSize"#S), + !cast("MxEncEA"#D#"_1"), MxExtEmpty, + MxEncEAf_0, MxExtBrief_0>>; + + def MOV#S#"p"#D : MxMove_MR< + !cast("MxType"#S).POp, + !cast("MxType"#S).PPat, + !cast("MxType"#S#D), + MxMoveEncoding("MxMoveSize"#S), + !cast("MxEncEA"#D#"_1"), MxExtEmpty, + MxEncEAp_0, MxExtI16_0>>; + + def MOV#S#"e"#D : MxMove_MR< + !cast("MxType"#S).EOp, + !cast("MxType"#S).EPat, + !cast("MxType"#S#D), + MxMoveEncoding("MxMoveSize"#S), + !cast("MxEncEA"#D#"_1"), MxExtEmpty, + MxEncEAe_0, MxExtEmpty>>; + + def MOV#S#"o"#D : MxMove_MR< + !cast("MxType"#S).OOp, + !cast("MxType"#S).OPat, + !cast("MxType"#S#D), + MxMoveEncoding("MxMoveSize"#S), + !cast("MxEncEA"#D#"_1"), MxExtEmpty, + MxEncEAo_0, MxExtEmpty>>; + + def MOV#S#"b"#D : MxMove_MR< + !cast("MxType"#S).BOp, + !cast("MxType"#S).BPat, + !cast("MxType"#S#D), + MxMoveEncoding("MxMoveSize"#S), + !cast("MxEncEA"#D#"_1"), MxExtEmpty, + MxEncEAb, MxExtI32_0>>; + + def MOV#S#"j"#D : MxMove_MR< + !cast("MxType"#S).JOp, + !cast("MxType"#S).JPat, + !cast("MxType"#S#D), + MxMoveEncoding("MxMoveSize"#S), + !cast("MxEncEA"#D#"_1"), MxExtEmpty, + MxEncEAj_0, MxExtEmpty>>; + + + // R <- I + def MOV#S#D#"i" : MxMove_RI< + !cast("MxType"#S#D), + MxMoveEncoding("MxMoveSize"#S), + MxEncEAi, !cast("MxExtI"#S#"_1"), + !cast("MxEncEA"#D#"_0_reflected"), MxExtEmpty>>; + } +} + +// M <- I +foreach S = [8, 16, 32] in { + def MOV#S#"f"#"i" : MxMove_MI< + !cast("MxType"#S).FOp, + !cast("MxType"#S).FPat, + !cast("MxType"#S), + MxMoveEncoding("MxMoveSize"#S), + MxEncEAi, !cast("MxExtI"#S#"_1"), + MxEncEAf_0, MxExtBrief_0>>; + + def MOV#S#"p"#"i" : MxMove_MI< + !cast("MxType"#S).POp, + !cast("MxType"#S).PPat, + !cast("MxType"#S), + MxMoveEncoding("MxMoveSize"#S), + MxEncEAi, !cast("MxExtI"#S#"_1"), + MxEncEAp_0, MxExtI16_0>>; + + def MOV#S#"b"#"i" : MxMove_MI< + !cast("MxType"#S).BOp, + !cast("MxType"#S).BPat, + !cast("MxType"#S), + MxMoveEncoding("MxMoveSize"#S), + MxEncEAi, !cast("MxExtI"#S#"_1"), + MxEncEAb, MxExtI32_0>>; + + def MOV#S#"j"#"i" : MxMove_MI< + !cast("MxType"#S).JOp, + !cast("MxType"#S).JPat, + !cast("MxType"#S), + MxMoveEncoding("MxMoveSize"#S), + MxEncEAi, !cast("MxExtI"#S#"_1"), + MxEncEAj_0, MxExtEmpty>>; +} + +// Store ABS(basically pointer) as Immdiate to Mem +def : Pat<(store MxType32.BPat :$src, MxType32.PPat :$dst), + (MOV32pi MxType32.POp :$dst, MxType32.IOp :$src)>; + +def : Pat<(store MxType32.BPat :$src, MxType32.FPat :$dst), + (MOV32fi MxType32.FOp :$dst, MxType32.IOp :$src)>; + +def : Pat<(store MxType32.BPat :$src, MxType32.BPat :$dst), + (MOV32bi MxType32.BOp :$dst, MxType32.IOp :$src)>; + +def : Pat<(store MxType32.BPat :$src, MxType32.JPat :$dst), + (MOV32ji MxType32.JOp :$dst, MxType32.IOp :$src)>; + +// R <- M +defm MOV8d : MMxMove_RM; + +defm MOV16r : MMxMove_RM; +defm MOV16a : MMxMove_RM; + +defm MOV32r : MMxMove_RM; +defm MOV32a : MMxMove_RM; + +let Pattern = [(null_frag)] in { +defm MOV16r : MMxMove_RM; +defm MOV16a : MMxMove_RM; + +defm MOV32r : MMxMove_RM; +defm MOV32a : MMxMove_RM; +} // Pattern + +// M <- M +defm MOV8p : MMxMove_MM; +defm MOV16p : MMxMove_MM; +defm MOV32p : MMxMove_MM; + +defm MOV8f : MMxMove_MM; +defm MOV16f : MMxMove_MM; +defm MOV32f : MMxMove_MM; + +defm MOV8b : MMxMove_MM; +defm MOV16b : MMxMove_MM; +defm MOV32b : MMxMove_MM; + +defm MOV8e : MMxMove_MM; +defm MOV16e : MMxMove_MM; +defm MOV32e : MMxMove_MM; + +defm MOV8o : MMxMove_MM; +defm MOV16o : MMxMove_MM; +defm MOV32o : MMxMove_MM; + +defm MOV8j : MMxMove_MM; +defm MOV16j : MMxMove_MM; +defm MOV32j : MMxMove_MM; + +//===----------------------------------------------------------------------===// +// MOVEM +// +// The mask is already pre-processed by the save/restore spill hook +//===----------------------------------------------------------------------===// + +// Direction +def MxMOVEM_MR : MxBead1Bit<0>; +def MxMOVEM_RM : MxBead1Bit<1>; + +// Size +def MxMOVEM_W : MxBead1Bit<0>; +def MxMOVEM_L : MxBead1Bit<1>; + +/// ---------------+-------------+-------------+--------- +/// F E D C B | A | 9 8 7 | 6 | 5 4 3 | 2 1 0 +/// ---------------+---+---------+---+---------+--------- +/// 0 1 0 0 1 | D | 0 0 1 | S | MODE | REG +/// ---------------+---+---------+---+---------+--------- +/// REGISTER LIST MASK +/// ----------------------------------------------------- +/// D - direction(RM,MR) +/// S - size(W,L) +class MxMOVEMEncoding + : MxEncoding, DIR, + MxBead1Bit<1>, MxBead4Bits<0b0100>, IMM, + EXT.Imm, EXT.B8, EXT.Scale, EXT.WL, EXT.DAReg>; + +let mayStore = 1 in +class MxMOVEM_MR + : MxInst<(outs), (ins MEMOp:$dst, MxMoveMask:$mask), + "movem."#TYPE.Prefix#"\t$mask, $dst", [], + MxMOVEMEncoding>>; + +let mayLoad = 1 in +class MxMOVEM_RM + : MxInst<(outs), (ins MxMoveMask:$mask, MEMOp:$src), + "movem."#TYPE.Prefix#"\t$src, $mask", [], + MxMOVEMEncoding>>; + +def MOVM32jm : MxMOVEM_MR; +def MOVM32pm : MxMOVEM_MR; + +def MOVM32mj : MxMOVEM_RM; +def MOVM32mp : MxMOVEM_RM; + +// Pseudo versions. These a required by virtual register spill/restore since +// the mask requires real register to encode. These instruction will be expanded +// into real MOVEM after RA finishes. +let mayStore = 1 in +class MxMOVEM_MR_Pseudo + : MxPseudo<(outs), (ins MEMOp:$dst, TYPE.ROp:$reg)>; +let mayLoad = 1 in +class MxMOVEM_RM_Pseudo + : MxPseudo<(outs TYPE.ROp:$dst), (ins MEMOp:$src)>; + +// Mem <- Reg +def MOVM8jm_P : MxMOVEM_MR_Pseudo; +def MOVM16jm_P : MxMOVEM_MR_Pseudo; +def MOVM32jm_P : MxMOVEM_MR_Pseudo; + +def MOVM8pm_P : MxMOVEM_MR_Pseudo; +def MOVM16pm_P : MxMOVEM_MR_Pseudo; +def MOVM32pm_P : MxMOVEM_MR_Pseudo; + +// Reg <- Mem +def MOVM8mj_P : MxMOVEM_RM_Pseudo; +def MOVM16mj_P : MxMOVEM_RM_Pseudo; +def MOVM32mj_P : MxMOVEM_RM_Pseudo; + +def MOVM8mp_P : MxMOVEM_RM_Pseudo; +def MOVM16mp_P : MxMOVEM_RM_Pseudo; +def MOVM32mp_P : MxMOVEM_RM_Pseudo; + + +//===----------------------------------------------------------------------===// +// MOVE to/from SR/CCR +// +// A special care must be taken working with to/from CCR since it is basically +// word-size SR register truncated for user mode thus it only supports word-size +// instructions. Plus the original M68000 does not support moves from CCR. So in +// order to use CCR effectively one MUST use proper byte-size pseudo instructi- +// ons that will be resolved sometime after RA pass. +//===----------------------------------------------------------------------===// + +/// -------------------------------------------------- +/// F E D C B A 9 8 7 6 | 5 4 3 | 2 1 0 +/// -------------------------------------------------- +/// | EFFECTIVE ADDRESS +/// 0 1 0 0 0 1 0 0 1 1 | MODE | REG +/// -------------------------------------------------- +let Defs = [CCR] in +class MxMoveToCCR + : MxInst<(outs CCRC:$dst), INS, "move.w\t$src, $dst", [], + MxEncoding, MxBead4Bits<0b0001>, MxBead2Bits<0b01>, + EXT.Imm, EXT.B8, EXT.Scale, EXT.WL, EXT.DAReg>>; + +class MxMoveToCCRPseudo : MxPseudo<(outs CCRC:$dst), INS>; + +let mayLoad = 1 in { +def MOV16cp : MxMoveToCCR<(ins MxType16d.POp:$src), MxEncEAp_1, MxExtI16_1>; +def MOV8cp : MxMoveToCCRPseudo<(ins MxType8d.POp:$src)>; +} // let mayLoad = 1 + +def MOV16cd : MxMoveToCCR<(ins MxType16d.ROp:$src), MxEncEAd_1, MxExtEmpty>; +def MOV8cd : MxMoveToCCRPseudo<(ins MxType8d.ROp:$src)>; + +/// Move from CCR +/// -------------------------------------------------- +/// F E D C B A 9 8 7 6 | 5 4 3 | 2 1 0 +/// -------------------------------------------------- +/// | EFFECTIVE ADDRESS +/// 0 1 0 0 0 0 1 0 1 1 | MODE | REG +/// -------------------------------------------------- +let Uses = [CCR] in +class MxMoveFromCCR + : MxInst, MxBead4Bits<0b0000>, MxBead2Bits<0b01>, + EXT.Imm, EXT.B8, EXT.Scale, EXT.WL, EXT.DAReg>>, + Requires<[ IsM68010 ]>; + +class MxMoveFromCCRPseudo : MxPseudo<(outs), INS>; + +let mayStore = 1 in { +def MOV16pc + : MxMoveFromCCR<(outs), (ins MxType16d.POp:$dst, CCRC:$src), MxEncEAp_0, MxExtI16_0>; +def MOV8pc : MxMoveFromCCRPseudo<(ins MxType8d.POp:$dst, CCRC:$src)>; +} // let mayStore = 1 + +def MOV16dc + : MxMoveFromCCR<(outs MxType16d.ROp:$dst), (ins CCRC:$src), MxEncEAd_0, MxExtEmpty>; + +def MOV8dc : MxMoveFromCCRPseudo<(ins MxType8d.ROp:$dst, CCRC:$src)>; + + +//===----------------------------------------------------------------------===// +// LEA +//===----------------------------------------------------------------------===// + +/// ---------------------------------------------------- +/// F E D C | B A 9 | 8 7 6 | 5 4 3 | 2 1 0 +/// ---------------------------------------------------- +/// 0 1 0 0 | DST REG | 1 1 1 | MODE | REG +/// ---------------------------------------------------- +class MxLEA + : MxInst<(outs MxARD32:$dst), (ins SRCOpd:$src), + "lea\t$src, $dst", [(set i32:$dst, SRCPat:$src)], + MxEncoding, MxBeadReg<0>, MxBead4Bits<0x4>, + EXT.Imm, EXT.B8, EXT.Scale, EXT.WL, EXT.DAReg>>; + +def LEA32p : MxLEA; +def LEA32f : MxLEA; +def LEA32q : MxLEA; +def LEA32b : MxLEA; + + +//===----------------------------------------------------------------------===// +// Pseudos +//===----------------------------------------------------------------------===// + +/// Pushe/Pop to/from SP for simplicity +let Uses = [SP], Defs = [SP], hasSideEffects = 0 in { + +// SP <- SP - ; (SP) <- Dn +let mayStore = 1 in { +def PUSH8d : MxPseudo<(outs), (ins DR8:$reg)>; +def PUSH16d : MxPseudo<(outs), (ins DR16:$reg)>; +def PUSH32r : MxPseudo<(outs), (ins XR32:$reg)>; +} // let mayStore = 1 + +// Dn <- (SP); SP <- SP + +let mayLoad = 1 in { +def POP8d : MxPseudo<(outs DR8:$reg), (ins)>; +def POP16d : MxPseudo<(outs DR16:$reg), (ins)>; +def POP32r : MxPseudo<(outs XR32:$reg), (ins)>; +} // let mayLoad = 1 + +} // let Uses/Defs = [SP], hasSideEffects = 0 + + +let Defs = [CCR] in { +class MxPseudoMove_RR PAT = []> + : MxPseudo<(outs DST.ROp:$dst), (ins SRC.ROp:$src), "", PAT>; + +class MxPseudoMove_RM PAT = []> + : MxPseudo<(outs DST.ROp:$dst), (ins SRCOpd:$src), "", PAT>; +} + +/// This group of Pseudos is analogues to the real x86 extending moves, but +/// since M68k does not have those we need to emulate. These instructions +/// will be expanded right after RA completed because we need to know precisely +/// what registers are allocated for the operands and if they overlap we just +/// extend the value if the registers are completely different we need to move +/// first. +foreach EXT = ["S", "Z"] in { + let hasSideEffects = 0 in { + + def MOV#EXT#Xd16d8 : MxPseudoMove_RR; + def MOV#EXT#Xd32d8 : MxPseudoMove_RR; + def MOV#EXT#Xd32d16 : MxPseudoMove_RR; + + let mayLoad = 1 in { + + def MOV#EXT#Xd16j8 : MxPseudoMove_RM; + def MOV#EXT#Xd32j8 : MxPseudoMove_RM; + def MOV#EXT#Xd32j16 : MxPseudoMove_RM; + + def MOV#EXT#Xd16p8 : MxPseudoMove_RM; + def MOV#EXT#Xd32p8 : MxPseudoMove_RM; + def MOV#EXT#Xd32p16 : MxPseudoMove_RM; + + def MOV#EXT#Xd16f8 : MxPseudoMove_RM; + def MOV#EXT#Xd32f8 : MxPseudoMove_RM; + def MOV#EXT#Xd32f16 : MxPseudoMove_RM; + + } + } +} + +/// This group of instructions is similar to the group above but DOES NOT do +/// any value extension, they just load a smaller register into the lower part +/// of another register if operands' real registers are different or does +/// nothing if they are the same. +def MOVXd16d8 : MxPseudoMove_RR; +def MOVXd32d8 : MxPseudoMove_RR; +def MOVXd32d16 : MxPseudoMove_RR; + +//===----------------------------------------------------------------------===// +// Extend/Truncate Patterns +//===----------------------------------------------------------------------===// + +// i16 <- sext i8 +def: Pat<(i16 (sext i8:$src)), + (EXTRACT_SUBREG (MOVSXd32d8 MxDRD8:$src), MxSubRegIndex16Lo)>; +def: Pat<(MxSExtLoadi16i8 MxCP_ARI:$src), + (EXTRACT_SUBREG (MOVSXd32j8 MxARI8:$src), MxSubRegIndex16Lo)>; +def: Pat<(MxSExtLoadi16i8 MxCP_ARID:$src), + (EXTRACT_SUBREG (MOVSXd32p8 MxARID8:$src), MxSubRegIndex16Lo)>; +def: Pat<(MxSExtLoadi16i8 MxCP_ARII:$src), + (EXTRACT_SUBREG (MOVSXd32f8 MxARII8:$src), MxSubRegIndex16Lo)>; + +// i32 <- sext i8 +def: Pat<(i32 (sext i8:$src)), (MOVSXd32d8 MxDRD8:$src)>; +def: Pat<(MxSExtLoadi32i8 MxCP_ARI :$src), (MOVSXd32j8 MxARI8 :$src)>; +def: Pat<(MxSExtLoadi32i8 MxCP_ARID:$src), (MOVSXd32p8 MxARID8:$src)>; +def: Pat<(MxSExtLoadi32i8 MxCP_ARII:$src), (MOVSXd32f8 MxARII8:$src)>; + +// i32 <- sext i16 +def: Pat<(i32 (sext i16:$src)), (MOVSXd32d16 MxDRD16:$src)>; +def: Pat<(MxSExtLoadi32i16 MxCP_ARI :$src), (MOVSXd32j16 MxARI16 :$src)>; +def: Pat<(MxSExtLoadi32i16 MxCP_ARID:$src), (MOVSXd32p16 MxARID16:$src)>; +def: Pat<(MxSExtLoadi32i16 MxCP_ARII:$src), (MOVSXd32f16 MxARII16:$src)>; + +// i16 <- zext i8 +def: Pat<(i16 (zext i8:$src)), + (EXTRACT_SUBREG (MOVZXd32d8 MxDRD8:$src), MxSubRegIndex16Lo)>; +def: Pat<(MxZExtLoadi16i8 MxCP_ARI:$src), + (EXTRACT_SUBREG (MOVZXd32j8 MxARI8:$src), MxSubRegIndex16Lo)>; +def: Pat<(MxZExtLoadi16i8 MxCP_ARID:$src), + (EXTRACT_SUBREG (MOVZXd32p8 MxARID8:$src), MxSubRegIndex16Lo)>; +def: Pat<(MxZExtLoadi16i8 MxCP_ARII:$src), + (EXTRACT_SUBREG (MOVZXd32f8 MxARII8:$src), MxSubRegIndex16Lo)>; + +// i32 <- zext i8 +def: Pat<(i32 (zext i8:$src)), (MOVZXd32d8 MxDRD8:$src)>; +def: Pat<(MxZExtLoadi32i8 MxCP_ARI :$src), (MOVZXd32j8 MxARI8 :$src)>; +def: Pat<(MxZExtLoadi32i8 MxCP_ARID:$src), (MOVZXd32p8 MxARID8:$src)>; +def: Pat<(MxZExtLoadi32i8 MxCP_ARII:$src), (MOVZXd32f8 MxARII8:$src)>; + +// i32 <- zext i16 +def: Pat<(i32 (zext i16:$src)), (MOVZXd32d16 MxDRD16:$src)>; +def: Pat<(MxZExtLoadi32i16 MxCP_ARI :$src), (MOVZXd32j16 MxARI16 :$src)>; +def: Pat<(MxZExtLoadi32i16 MxCP_ARID:$src), (MOVZXd32p16 MxARID16:$src)>; +def: Pat<(MxZExtLoadi32i16 MxCP_ARII:$src), (MOVZXd32f16 MxARII16:$src)>; + +// i16 <- anyext i8 +def: Pat<(i16 (anyext i8:$src)), + (EXTRACT_SUBREG (MOVZXd32d8 MxDRD8:$src), MxSubRegIndex16Lo)>; +def: Pat<(MxExtLoadi16i8 MxCP_ARI:$src), + (EXTRACT_SUBREG (MOVZXd32j8 MxARI8:$src), MxSubRegIndex16Lo)>; +def: Pat<(MxExtLoadi16i8 MxCP_ARID:$src), + (EXTRACT_SUBREG (MOVZXd32p8 MxARID8:$src), MxSubRegIndex16Lo)>; +def: Pat<(MxExtLoadi16i8 MxCP_ARII:$src), + (EXTRACT_SUBREG (MOVZXd32f8 MxARII8:$src), MxSubRegIndex16Lo)>; + +// i32 <- anyext i8 +def: Pat<(i32 (anyext i8:$src)), (MOVZXd32d8 MxDRD8:$src)>; +def: Pat<(MxExtLoadi32i8 MxCP_ARI :$src), (MOVZXd32j8 MxARI8 :$src)>; +def: Pat<(MxExtLoadi32i8 MxCP_ARID:$src), (MOVZXd32p8 MxARID8:$src)>; +def: Pat<(MxExtLoadi32i8 MxCP_ARII:$src), (MOVZXd32f8 MxARII8:$src)>; + +// i32 <- anyext i16 +def: Pat<(i32 (anyext i16:$src)), (MOVZXd32d16 MxDRD16:$src)>; +def: Pat<(MxExtLoadi32i16 MxCP_ARI :$src), (MOVZXd32j16 MxARI16 :$src)>; +def: Pat<(MxExtLoadi32i16 MxCP_ARID:$src), (MOVZXd32p16 MxARID16:$src)>; +def: Pat<(MxExtLoadi32i16 MxCP_ARII:$src), (MOVZXd32f16 MxARII16:$src)>; + +// trunc patterns +def : Pat<(i16 (trunc i32:$src)), + (EXTRACT_SUBREG MxXRD32:$src, MxSubRegIndex16Lo)>; +def : Pat<(i8 (trunc i32:$src)), + (EXTRACT_SUBREG MxXRD32:$src, MxSubRegIndex8Lo)>; +def : Pat<(i8 (trunc i16:$src)), + (EXTRACT_SUBREG MxXRD16:$src, MxSubRegIndex8Lo)>; diff --git a/llvm/lib/Target/M68k/M68kInstrFormats.td b/llvm/lib/Target/M68k/M68kInstrFormats.td new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/M68k/M68kInstrFormats.td @@ -0,0 +1,370 @@ +//=== M68kInstrFormats.td - M68k Instruction Formats ---*- tablegen -*-===// +// The LLVM Compiler Infrastructure +// 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 +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file contains M68k instruction formats. +/// +/// Since M68k has quite a lot memory addressing modes there are more +/// instruction prefixes than just i, r and m: +/// TSF Since Form Letter Description +/// 00 M68000 Dn or An r any register +/// 01 M68000 Dn d data register direct +/// 02 M68000 An a address register direct +/// 03 M68000 (An) j address register indirect +/// 04 M68000 (An)+ o address register indirect with postincrement +/// 05 M68000 -(An) e address register indirect with predecrement +/// 06 M68000 (i,An) p address register indirect with displacement +/// 10 M68000 (i,An,Xn.L) f address register indirect with index and scale = 1 +/// 07 M68000 (i,An,Xn.W) F address register indirect with index and scale = 1 +/// 12 M68020 (i,An,Xn.L,SCALE) g address register indirect with index +/// 11 M68020 (i,An,Xn.W,SCALE) G address register indirect with index +/// 14 M68020 ([bd,An],Xn.L,SCALE,od) u memory indirect postindexed mode +/// 13 M68020 ([bd,An],Xn.W,SCALE,od) U memory indirect postindexed mode +/// 16 M68020 ([bd,An,Xn.L,SCALE],od) v memory indirect preindexed mode +/// 15 M68020 ([bd,An,Xn.W,SCALE],od) V memory indirect preindexed mode +/// 20 M68000 abs.L b absolute long address +/// 17 M68000 abs.W B absolute short address +/// 21 M68000 (i,PC) q program counter with displacement +/// 23 M68000 (i,PC,Xn.L) k program counter with index and scale = 1 +/// 22 M68000 (i,PC,Xn.W) K program counter with index and scale = 1 +/// 25 M68020 (i,PC,Xn.L,SCALE) l program counter with index +/// 24 M68020 (i,PC,Xn.W,SCALE) L program counter with index +/// 27 M68020 ([bd,PC],Xn.L,SCALE,od) x program counter memory indirect postindexed mode +/// 26 M68020 ([bd,PC],Xn.W,SCALE,od) X program counter memory indirect postindexed mode +/// 31 M68020 ([bd,PC,Xn.L,SCALE],od) y program counter memory indirect preindexed mode +/// 30 M68020 ([bd,PC,Xn.W,SCALE],od) Y program counter memory indirect preindexed mode +/// 32 M68000 #immediate i immediate data +/// +/// NOTE that long form is always lowercase, word variants are capitalized +/// +/// Operand can be qualified with size where appropriate to force a particular +/// instruction encoding, e.g.: +/// (i8,An,Xn.W) f8 1 extension word +/// (i16,An,Xn.W) f16 2 extension words +/// (i32,An,Xn.W) f32 3 extension words +/// +/// Form without size qualifier will adapt to operand size automatically, e.g.: +/// (i,An,Xn.W) f 1, 2 or 3 extension words +/// +/// Some forms already imply a particular size of their operands, e.g.: +/// (i,An) p 1 extension word and i is 16bit +/// +/// Operand order follows x86 Intel order(destination before source), e.g.: +/// MOV8df MOVE (4,A0,D0), D1 +/// +/// Number after instruction mnemonics determines the size of the data +/// +//===----------------------------------------------------------------------===// + +/// ??? Is it possible to use this stuff for disassembling? +/// NOTE 1: In case of conditional beads(DA, DAReg), cond part is able to +/// consume any bit, though a more general instructions must be chosen, e.g. +/// d -> r, a -> r + +//===----------------------------------------------------------------------===// +// Encoding primitives +//===----------------------------------------------------------------------===// + +class MxBead type, bit b4 = 0, bit b5 = 0, bit b6 = 0, bit b7 = 0> { + bits<8> Value = 0b00000000; + let Value{3-0} = type; + let Value{4} = b4; + let Value{5} = b5; + let Value{6} = b6; + let Value{7} = b7; +} + +/// System beads, allow to control beading flow +def MxBeadTerm : MxBead<0x0, 0, 0, 0, 0>; +def MxBeadIgnore : MxBead<0x0, 1, 0, 0, 0>; + +/// Add plain bit to the instruction +class MxBead1Bit b> : MxBead<0x1, b>; +class MxBead2Bits b> : MxBead<0x2, b{0}, b{1}>; +class MxBead3Bits b> : MxBead<0x3, b{0}, b{1}, b{2}>; +class MxBead4Bits b> : MxBead<0x4, b{0}, b{1}, b{2}, b{3}>; + +/// bits<3> o - operand number +/// bit a - use alternative, used to select index register or +/// outer displacement/immediate +/// suffix NP means non-padded +class MxBeadDAReg o, bit a = 0> : MxBead<0x5, o{0}, o{1}, o{2}, a>; +class MxBeadDA o, bit a = 0> : MxBead<0x6, o{0}, o{1}, o{2}, a>; +class MxBeadReg o, bit a = 0> : MxBead<0x7, o{0}, o{1}, o{2}, a>; +class MxBead8Disp o, bit a = 0> : MxBead<0x8, o{0}, o{1}, o{2}, a>; + +/// Add Immediate to the instruction. 8-bit version is padded with zeros to fit +/// the word. +class MxBead8Imm o, bit a = 0> : MxBead<0x9, o{0}, o{1}, o{2}, a>; +class MxBead16Imm o, bit a = 0> : MxBead<0xA, o{0}, o{1}, o{2}, a>; +class MxBead32Imm o, bit a = 0> : MxBead<0xB, o{0}, o{1}, o{2}, a>; + +/// Encodes an immediate 0-7(alt. 1-8) into 3 bit field +class MxBead3Imm o, bit a = 0> : MxBead<0xC, o{0}, o{1}, o{2}, a>; + + +class MxEncoding { + bits <192> Value; + let Value{7-0} = n0.Value; + let Value{15-8} = n1.Value; + let Value{23-16} = n2.Value; + let Value{31-24} = n3.Value; + let Value{39-32} = n4.Value; + let Value{47-40} = n5.Value; + let Value{55-48} = n6.Value; + let Value{63-56} = n7.Value; + let Value{71-64} = n8.Value; + let Value{79-72} = n9.Value; + let Value{87-80} = n10.Value; + let Value{95-88} = n11.Value; + let Value{103-96} = n12.Value; + let Value{111-104} = n13.Value; + let Value{119-112} = n14.Value; + let Value{127-120} = n15.Value; + let Value{135-128} = n16.Value; + let Value{143-136} = n17.Value; + let Value{151-144} = n18.Value; + let Value{159-152} = n19.Value; + let Value{167-160} = n20.Value; + let Value{175-168} = n21.Value; + let Value{183-176} = n22.Value; + let Value{191-184} = n23.Value; +} + +class MxEncFixed value> : MxEncoding { + let Value{7-0} = MxBead4Bits.Value; + let Value{15-8} = MxBead4Bits.Value; + let Value{23-16} = MxBead4Bits.Value; + let Value{31-24} = MxBead4Bits.Value; +} + +//===----------------------------------------------------------------------===// +// Encoding composites +// +// These must be lowered to MxEncoding by instr specific wrappers +// +// HERE BE DRAGONS... +//===----------------------------------------------------------------------===// + +class MxEncByte value> : MxEncoding { + MxBead4Bits LO = MxBead4Bits; + MxBead4Bits HI = MxBead4Bits; +} + +def MxEncEmpty : MxEncoding; + + +/// M68k Standard Effective Address layout: +/// +/// :-------------------: +/// | 5 4 3 | 2 1 0 | +/// | mode | reg | +/// :-------------------: +/// +/// If the EA is a direct register mode, bits 4 and 5 are 0, and the register +/// number will be encoded in bit 0 - 3. Since the first address register's +/// (A0) register number is 8, we can easily tell data registers from +/// address registers by only inspecting bit 3 (i.e. if bit 3 is set, it's an +/// address register). +/// +/// +/// But MOVE instruction uses reversed layout for destination EA: +/// +/// :-------------------: +/// | 5 4 3 | 2 1 0 | +/// | reg | mode | +/// :-------------------: +/// +/// And this complicates things a bit because the DA bit is now separated from +/// the register and we have to encode those separately using MxBeadDA +/// +class MxEncEA { + MxBead Reg = reg; + MxBead Mode = mode; + MxBead DA = da; +} + +// FIXME: Is there a way to factorize the addressing mode suffix (i.e. +// 'r', 'd', 'a' etc.) and use something like multiclass to replace? +def MxEncEAr_0: MxEncEA, MxBead2Bits<0b00>>; +def MxEncEAd_0: MxEncEA, MxBead2Bits<0b00>, MxBead1Bit<0>>; +def MxEncEAa_0: MxEncEA, MxBead2Bits<0b00>, MxBead1Bit<1>>; +def MxEncEAj_0: MxEncEA, MxBead2Bits<0b01>, MxBead1Bit<0>>; +def MxEncEAo_0: MxEncEA, MxBead2Bits<0b01>, MxBead1Bit<1>>; +def MxEncEAe_0: MxEncEA, MxBead2Bits<0b10>, MxBead1Bit<0>>; +def MxEncEAp_0: MxEncEA, MxBead2Bits<0b10>, MxBead1Bit<1>>; +def MxEncEAf_0: MxEncEA, MxBead2Bits<0b11>, MxBead1Bit<0>>; + +def MxEncEAa_0_reflected : MxEncEA, MxBead3Bits<0b001>>; +def MxEncEAr_0_reflected : MxEncEA, MxBead2Bits<0b00>, MxBeadDA<0>>; + +def MxEncEAr_1: MxEncEA, MxBead2Bits<0b00>>; +def MxEncEAd_1: MxEncEA, MxBead2Bits<0b00>, MxBead1Bit<0>>; +def MxEncEAa_1: MxEncEA, MxBead2Bits<0b00>, MxBead1Bit<1>>; +def MxEncEAj_1: MxEncEA, MxBead2Bits<0b01>, MxBead1Bit<0>>; +def MxEncEAo_1: MxEncEA, MxBead2Bits<0b01>, MxBead1Bit<1>>; +def MxEncEAe_1: MxEncEA, MxBead2Bits<0b10>, MxBead1Bit<0>>; +def MxEncEAp_1: MxEncEA, MxBead2Bits<0b10>, MxBead1Bit<1>>; +def MxEncEAf_1: MxEncEA, MxBead2Bits<0b11>, MxBead1Bit<0>>; + +def MxEncEAr_2: MxEncEA, MxBead2Bits<0b00>>; +def MxEncEAd_2: MxEncEA, MxBead2Bits<0b00>, MxBead1Bit<0>>; +def MxEncEAa_2: MxEncEA, MxBead2Bits<0b00>, MxBead1Bit<1>>; +def MxEncEAj_2: MxEncEA, MxBead2Bits<0b01>, MxBead1Bit<0>>; +def MxEncEAo_2: MxEncEA, MxBead2Bits<0b01>, MxBead1Bit<1>>; +def MxEncEAe_2: MxEncEA, MxBead2Bits<0b10>, MxBead1Bit<0>>; +def MxEncEAp_2: MxEncEA, MxBead2Bits<0b10>, MxBead1Bit<1>>; +def MxEncEAf_2: MxEncEA, MxBead2Bits<0b11>, MxBead1Bit<0>>; + +def MxEncEAb : MxEncEA, MxBead2Bits<0b11>, MxBead1Bit<1>>; +def MxEncEAq : MxEncEA, MxBead2Bits<0b11>, MxBead1Bit<1>>; +def MxEncEAk : MxEncEA, MxBead2Bits<0b11>, MxBead1Bit<1>>; +def MxEncEAi : MxEncEA, MxBead2Bits<0b11>, MxBead1Bit<1>>; + +// Allows you to specify each bit of opcode +class MxEncOpMode { + MxBead B0 = b0; + MxBead B1 = b1; + MxBead B2 = b2; +} + +// op EA, Dn +def MxOpMode8dEA : MxEncOpMode>; +def MxOpMode16dEA : MxEncOpMode>; +def MxOpMode32dEA : MxEncOpMode>; + +// op EA, An +def MxOpMode16aEA : MxEncOpMode>; +def MxOpMode32aEA : MxEncOpMode>; + +// op EA, Rn +// As you might noticed this guy is special... Since M68k differentiates +// between Data and Address registers we required to use different OPMODE codes +// for Address registers DST operands. One way of dealing with it is to use +// separate tablegen instructions, but in this case it would force Register +// Allocator to use specific Register Classes and eventually will lead to +// superfluous moves. Another approach is to use reg-variadic encoding which will +// change OPMODE base on Register Class used. Luckily, all the bits that differ go +// from 0 to 1 and can be encoded with MxBeadDA. +// Basically, if the register used is of Data type these encodings will be +// the same as MxOpMode{16,32}dEA above and used with regular instructions(e.g. ADD, +// SUB), but if the register is of Address type the appropriate bits will flip and +// the instructions become of *A type(e.g ADDA, SUBA). +def MxOpMode16rEA : MxEncOpMode, MxBeadDA<0>, MxBead1Bit<0>>; +def MxOpMode32rEA : MxEncOpMode, MxBead1Bit<1>, MxBeadDA<0>>; + +// op Dn, EA +def MxOpMode8EAd : MxEncOpMode>; +def MxOpMode16EAd : MxEncOpMode>; +def MxOpMode32EAd : MxEncOpMode>; + + +// Represents two types of extension word: +// - Imm extension word +// - Brief extension word +class MxEncExt { + MxBead Imm = imm; + MxBead B8 = b8; + MxBead Scale = scale; + MxBead WL = wl; + MxBead DAReg = daReg; +} + +def MxExtEmpty : MxEncExt; + +// These handle encoding of displacement fields, absolute addresses and +// immediate values, since encoding for these categories is mainly the same, +// with exception of some weird immediates. +def MxExtI8_0 : MxEncExt>; +def MxExtI16_0 : MxEncExt>; +def MxExtI32_0 : MxEncExt>; + +def MxExtI8_1 : MxEncExt>; +def MxExtI16_1 : MxEncExt>; +def MxExtI32_1 : MxEncExt>; + +def MxExtI8_2 : MxEncExt>; +def MxExtI16_2 : MxEncExt>; +def MxExtI32_2 : MxEncExt>; + +// NOTE They are all using Long Xn +def MxExtBrief_0 : MxEncExt, MxBead1Bit<0b0>, + MxBead2Bits<0b00>, MxBead1Bit<1>, + MxBeadDAReg<0, 1>>; + +def MxExtBrief_1 : MxEncExt, MxBead1Bit<0b0>, + MxBead2Bits<0b00>, MxBead1Bit<1>, + MxBeadDAReg<1, 1>>; + +def MxExtBrief_2 : MxEncExt, MxBead1Bit<0b0>, + MxBead2Bits<0b00>, MxBead1Bit<1>, + MxBeadDAReg<2, 1>>; + +def MxExtBrief_3 : MxEncExt, MxBead1Bit<0b0>, + MxBead2Bits<0b00>, MxBead1Bit<1>, + MxBeadDAReg<3, 1>>; + +def MxExtBrief_4 : MxEncExt, MxBead1Bit<0b0>, + MxBead2Bits<0b00>, MxBead1Bit<1>, + MxBeadDAReg<4, 1>>; + +class MxEncSize value> : MxBead2Bits; +def MxEncSize8 : MxEncSize<0b00>; +def MxEncSize16 : MxEncSize<0b01>; +def MxEncSize32 : MxEncSize<0b10>; +def MxEncSize64 : MxEncSize<0b11>; + +// M68k INSTRUCTION. Most instructions specify the location of an operand by +// using the effective address field in the operation word. The effective address +// is composed of two 3-bit fields: the mode field and the register field. The +// value in the mode field selects the different address modes. The register +// field contains the number of a register. The effective address field may +// require additional information to fully specify the operand. This additional +// information, called the effective address extension, is contained in the +// following word or words and is considered part of the instruction. The +// effective address modes are grouped into three categories: register direct, +// memory addressing, and special. +class MxInst pattern = [], + MxEncoding beads = MxEncEmpty, + InstrItinClass itin = NoItinerary> + : Instruction { + let Namespace = "M68k"; + let OutOperandList = outs; + let InOperandList = ins; + let AsmString = asmStr; + let Pattern = pattern; + let Itinerary = itin; + + // Byte stream + field bits<192> Beads = beads.Value; + + // Number of bytes + let Size = 0; + + let UseLogicalOperandMappings = 1; +} + +// M68k PSEUDO INSTRUCTION +class MxPseudo pattern = []> + : MxInst { + let isPseudo = 1; +} diff --git a/llvm/lib/Target/M68k/M68kInstrInfo.td b/llvm/lib/Target/M68k/M68kInstrInfo.td new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/M68k/M68kInstrInfo.td @@ -0,0 +1,665 @@ +//== M68kInstrInfo.td - Main M68k Instruction Definition -*- tablegen -*-=// +// +// 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 +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file describes the M68k instruction set, defining the instructions +/// and properties of the instructions which are needed for code generation, +/// machine code emission, and analysis. +/// +//===----------------------------------------------------------------------===// + +include "M68kInstrFormats.td" + +//===----------------------------------------------------------------------===// +// Profiles +//===----------------------------------------------------------------------===// + +def MxSDT_CallSeqStart : SDCallSeqStart<[SDTCisVT<0, i32>, SDTCisVT<1, i32>]>; +def MxSDT_CallSeqEnd : SDCallSeqEnd<[SDTCisVT<0, i32>, SDTCisVT<1, i32>]>; + +def MxSDT_Call : SDTypeProfile<0, -1, [SDTCisVT<0, iPTR>]>; + +def MxSDT_Ret : SDTypeProfile<0, -1, [ + /* ADJ */ SDTCisVT<0, i32> +]>; + +def MxSDT_TCRet : SDTypeProfile<0, 2, [SDTCisPtrTy<0>, SDTCisVT<1, i32>]>; + +def MxSDT_Wrapper : SDTypeProfile<1, 1, [SDTCisSameAs<0, 1>, SDTCisPtrTy<0>]>; + +def MxSDT_UnArithCCROut : SDTypeProfile<2, 1, [ + /* RES */ SDTCisInt<0>, + /* CCR */ SDTCisVT<1, i8>, + /* OPD */ SDTCisSameAs<0, 2> +]>; + +// RES, CCR <- op LHS, RHS +def MxSDT_BiArithCCROut : SDTypeProfile<2, 2, [ + /* RES */ SDTCisInt<0>, + /* CCR */ SDTCisVT<1, i8>, + /* LHS */ SDTCisSameAs<0, 2>, + /* RHS */ SDTCisSameAs<0, 3> +]>; + +// RES, CCR <- op LHS, RHS, CCR +def MxSDT_BiArithCCRInOut : SDTypeProfile<2, 3, [ + /* RES 1 */ SDTCisInt<0>, + /* CCR */ SDTCisVT<1, i8>, + /* LHS */ SDTCisSameAs<0, 2>, + /* RHS */ SDTCisSameAs<0, 3>, + /* CCR */ SDTCisSameAs<1, 4> +]>; + +// RES1, RES2, CCR <- op LHS, RHS +def MxSDT_2BiArithCCROut : SDTypeProfile<3, 2, [ + /* RES 1 */ SDTCisInt<0>, + /* RES 2 */ SDTCisSameAs<0, 1>, + /* CCR */ SDTCisVT<1, i8>, + /* LHS */ SDTCisSameAs<0, 2>, + /* RHS */ SDTCisSameAs<0, 3> +]>; + +def MxSDT_CmpTest : SDTypeProfile<1, 2, [ + /* CCR */ SDTCisVT<0, i8>, + /* Ops */ SDTCisSameAs<1, 2> +]>; + +def MxSDT_Cmov : SDTypeProfile<1, 4, [ + /* ARG */ SDTCisSameAs<0, 1>, + /* ARG */ SDTCisSameAs<1, 2>, + /* Cond */ SDTCisVT<3, i8>, + /* CCR */ SDTCisVT<4, i8> +]>; + +def MxSDT_BrCond : SDTypeProfile<0, 3, [ + /* Dest */ SDTCisVT<0, OtherVT>, + /* Cond */ SDTCisVT<1, i8>, + /* CCR */ SDTCisVT<2, i8> +]>; + +def MxSDT_SetCC : SDTypeProfile<1, 2, [ + /* BOOL */ SDTCisVT<0, i8>, + /* Cond */ SDTCisVT<1, i8>, + /* CCR */ SDTCisVT<2, i8> +]>; + +def MxSDT_SetCC_C : SDTypeProfile<1, 2, [ + /* BOOL */ SDTCisInt<0>, + /* Cond */ SDTCisVT<1, i8>, + /* CCR */ SDTCisVT<2, i8> +]>; + + +def MxSDT_SEG_ALLOCA : SDTypeProfile<1, 1,[ + /* MEM */ SDTCisVT<0, iPTR>, + /* SIZE */ SDTCisVT<1, iPTR> +]>; + + +//===----------------------------------------------------------------------===// +// Nodes +//===----------------------------------------------------------------------===// + +def MxCallSeqStart : SDNode<"ISD::CALLSEQ_START", MxSDT_CallSeqStart, + [SDNPHasChain, SDNPOutGlue]>; + +def MxCallSeqEnd : SDNode<"ISD::CALLSEQ_END", MxSDT_CallSeqEnd, + [SDNPHasChain, SDNPOptInGlue, SDNPOutGlue]>; + +def MxCall : SDNode<"M68kISD::CALL", MxSDT_Call, + [SDNPHasChain, SDNPOutGlue, + SDNPOptInGlue, SDNPVariadic]>; + +def MxRet : SDNode<"M68kISD::RET", MxSDT_Ret, + [SDNPHasChain, SDNPOptInGlue, SDNPVariadic]>; + +def MxTCRet : SDNode<"M68kISD::TC_RETURN", MxSDT_TCRet, + [SDNPHasChain, SDNPOptInGlue, SDNPVariadic]>; + +def MxWrapper : SDNode<"M68kISD::Wrapper", MxSDT_Wrapper>; +def MxWrapperPC : SDNode<"M68kISD::WrapperPC", MxSDT_Wrapper>; + +def MxAdd : SDNode<"M68kISD::ADD", MxSDT_BiArithCCROut, [SDNPCommutative]>; +def MxSub : SDNode<"M68kISD::SUB", MxSDT_BiArithCCROut>; +def MxOr : SDNode<"M68kISD::OR", MxSDT_BiArithCCROut, [SDNPCommutative]>; +def MxXor : SDNode<"M68kISD::XOR", MxSDT_BiArithCCROut, [SDNPCommutative]>; +def MxAnd : SDNode<"M68kISD::AND", MxSDT_BiArithCCROut, [SDNPCommutative]>; + +def MxAddX : SDNode<"M68kISD::ADDX", MxSDT_BiArithCCRInOut>; +def MxSubX : SDNode<"M68kISD::SUBX", MxSDT_BiArithCCRInOut>; + +def MxSMul : SDNode<"M68kISD::SMUL", MxSDT_BiArithCCROut, [SDNPCommutative]>; +def MxUMul : SDNode<"M68kISD::UMUL", MxSDT_2BiArithCCROut, [SDNPCommutative]>; + +def MxCmp : SDNode<"M68kISD::CMP", MxSDT_CmpTest>; +def MxBt : SDNode<"M68kISD::BT", MxSDT_CmpTest>; + +def MxCmov : SDNode<"M68kISD::CMOV", MxSDT_Cmov>; +def MxBrCond : SDNode<"M68kISD::BRCOND", MxSDT_BrCond, [SDNPHasChain]>; +def MxSetCC : SDNode<"M68kISD::SETCC", MxSDT_SetCC>; +def MxSetCC_C : SDNode<"M68kISD::SETCC_CARRY", MxSDT_SetCC_C>; + + +def MxSegAlloca : SDNode<"M68kISD::SEG_ALLOCA", MxSDT_SEG_ALLOCA, + [SDNPHasChain]>; + + +//===----------------------------------------------------------------------===// +// Operands +//===----------------------------------------------------------------------===// + +/// Size is the size of the data, either bits of a register or number of bits +/// addressed in memory. Size id is a letter that identifies size. +class MxSize { + int Num = num; + string Id = id; + string Full = full; +} + +def MxSize8 : MxSize<8, "b", "byte">; +def MxSize16 : MxSize<16, "w", "word">; +def MxSize32 : MxSize<32, "l", "long">; + +class MxOperand { + ValueType VT = vt; + string Letter = letter; + MxSize Size = size; + RegisterClass RC = rc; + dag Pat = pat; +} + +class MxRegOp + : RegisterOperand, + MxOperand; + +// REGISTER DIRECT. The operand is in the data register specified by +// the effective address register field. +def MxXRD16 : MxRegOp; +def MxXRD32 : MxRegOp; + +def MxXRD16_TC : MxRegOp; +def MxXRD32_TC : MxRegOp; + +// DATA REGISTER DIRECT. The operand is in the data register specified by +// the effective address register field. +def MxDRD8 : MxRegOp; +def MxDRD16 : MxRegOp; +def MxDRD32 : MxRegOp; + +def MxDRD16_TC : MxRegOp; +def MxDRD32_TC : MxRegOp; + +// ADDRESS REGISTER DIRECT. The operand is in the address register specified by +// the effective address register field. +def MxARD16 : MxRegOp; +def MxARD32 : MxRegOp; + +def MxARD16_TC : MxRegOp; +def MxARD32_TC : MxRegOp; + +// TODO finish parser wiring +def MxMemAsmOperand : AsmOperandClass { + let Name = "MxMemOp"; +} + +class MxMemOp + : Operand, MxOperand { + let PrintMethod = printMethod; + let MIOperandInfo = ops; + let ParserMatchClass = parserMatchClass; + let OperandType = "OPERAND_MEMORY"; +} + +// ADDRESS REGISTER INDIRECT. The address of the operand is in the address +// register specified by the register field. The reference is classified as +// a data reference with the exception of the jump and jump-to-subroutine +// instructions. +def MxARI8 : MxMemOp<(ops AR32), MxSize8, "j", "printARI8Mem">; +def MxARI16 : MxMemOp<(ops AR32), MxSize16, "j", "printARI16Mem">; +def MxARI32 : MxMemOp<(ops AR32), MxSize32, "j", "printARI32Mem">; + +def MxARI8_TC : MxMemOp<(ops AR32_TC), MxSize8, "j", "printARI8Mem">; +def MxARI16_TC : MxMemOp<(ops AR32_TC), MxSize16, "j", "printARI16Mem">; +def MxARI32_TC : MxMemOp<(ops AR32_TC), MxSize32, "j", "printARI32Mem">; + +// ADDRESS REGISTER INDIRECT WITH POSTINCREMENT. The address of the operand is +// in the address register specified by the register field. After the operand +// address is used, it is incremented by one, two, or four depending upon whether +// the size of the operand is byte, word, or long word. If the address register +// is the stack pointer and the operand size is byte, the address is incremented +// by two rather than one to keep the stack pointer on a word boundary. +// The reference is classified as a data reference. +def MxARIPI8 : MxMemOp<(ops AR32), MxSize8, "o", "printARIPI8Mem">; +def MxARIPI16 : MxMemOp<(ops AR32), MxSize16, "o", "printARIPI16Mem">; +def MxARIPI32 : MxMemOp<(ops AR32), MxSize32, "o", "printARIPI32Mem">; + +def MxARIPI8_TC : MxMemOp<(ops AR32_TC), MxSize8, "o", "printARIPI8Mem">; +def MxARIPI16_TC : MxMemOp<(ops AR32_TC), MxSize16, "o", "printARIPI16Mem">; +def MxARIPI32_TC : MxMemOp<(ops AR32_TC), MxSize32, "o", "printARIPI32Mem">; + +// ADDRESS REGISTER INDIRECT WITH PREDECREMENT. The address of the operand is in +// the address register specified by the register field. Before the operand +// address is used, it is decremented by one, two, or four depending upon whether +// the operand size is byte, word, or long word. If the address register is +// the stack pointer and the operand size is byte, the address is decremented by +// two rather than one to keep the stack pointer on a word boundary. +// The reference is classified as a data reference. +def MxARIPD8 : MxMemOp<(ops AR32), MxSize8, "e", "printARIPD8Mem">; +def MxARIPD16 : MxMemOp<(ops AR32), MxSize16, "e", "printARIPD16Mem">; +def MxARIPD32 : MxMemOp<(ops AR32), MxSize32, "e", "printARIPD32Mem">; + +def MxARIPD8_TC : MxMemOp<(ops AR32_TC), MxSize8, "e", "printARIPD8Mem">; +def MxARIPD16_TC : MxMemOp<(ops AR32_TC), MxSize16, "e", "printARIPD16Mem">; +def MxARIPD32_TC : MxMemOp<(ops AR32_TC), MxSize32, "e", "printARIPD32Mem">; + +// ADDRESS REGISTER INDIRECT WITH DISPLACEMENT. This addressing mode requires one +// word of extension. The address of the operand is the sum of the address in +// the address register and the sign-extended 16-bit displacement integer in the +// extension word. The reference is classified as a data reference with the +// exception of the jump and jump-to-subroutine instructions. +def MxARID8 : MxMemOp<(ops i16imm, AR32), MxSize8, "p", "printARID8Mem">; +def MxARID16 : MxMemOp<(ops i16imm, AR32), MxSize16, "p", "printARID16Mem">; +def MxARID32 : MxMemOp<(ops i16imm, AR32), MxSize32, "p", "printARID32Mem">; + +def MxARID8_TC : MxMemOp<(ops i16imm, AR32_TC), MxSize8, "p", "printARID8Mem">; +def MxARID16_TC : MxMemOp<(ops i16imm, AR32_TC), MxSize16, "p", "printARID16Mem">; +def MxARID32_TC : MxMemOp<(ops i16imm, AR32_TC), MxSize32, "p", "printARID32Mem">; + +// ADDRESS REGISTER INDIRECT WITH INDEX. This addressing mode requires one word +// of extension. The address of the operand is the sum of the address in the +// address register, the signextended displacement integer in the low order eight +// bits of the extension word, and the contents of the index register. +// The reference is classified as a data reference with the exception of the +// jump and jump-to-subroutine instructions +def MxARII8 : MxMemOp<(ops i8imm, AR32, XR32), MxSize8, "f", "printARII8Mem">; +def MxARII16 : MxMemOp<(ops i8imm, AR32, XR32), MxSize16, "f", "printARII16Mem">; +def MxARII32 : MxMemOp<(ops i8imm, AR32, XR32), MxSize32, "f", "printARII32Mem">; + +def MxARII8_TC : MxMemOp<(ops i8imm, AR32_TC, XR32_TC), MxSize8, "f", "printARII8Mem">; +def MxARII16_TC : MxMemOp<(ops i8imm, AR32_TC, XR32_TC), MxSize16, "f", "printARII16Mem">; +def MxARII32_TC : MxMemOp<(ops i8imm, AR32_TC, XR32_TC), MxSize32, "f", "printARII32Mem">; + +// ABSOLUTE SHORT ADDRESS. This addressing mode requires one word of extension. +// The address of the operand is the extension word. The 16-bit address is sign +// extended before it is used. The reference is classified as a data reference +// with the exception of the jump and jump-tosubroutine instructions. +def MxAS8 : MxMemOp<(ops OtherVT), MxSize8, "B", "printAS8Mem">; +def MxAS16 : MxMemOp<(ops OtherVT), MxSize16, "B", "printAS16Mem">; +def MxAS32 : MxMemOp<(ops OtherVT), MxSize32, "B", "printAS32Mem">; + +// ABSOLUTE LONG ADDRESS. This addressing mode requires two words of extension. +// The address of the operand is developed by the concatenation of the extension +// words. The high order part of the address is the first extension word; the low +// order part of the address is the second extension word. The reference is +// classified as a data reference with the exception of the jump and jump +// to-subroutine instructions. +def MxAL8 : MxMemOp<(ops OtherVT), MxSize8, "b", "printAL8Mem">; +def MxAL16 : MxMemOp<(ops OtherVT), MxSize16, "b", "printAL16Mem">; +def MxAL32 : MxMemOp<(ops OtherVT), MxSize32, "b", "printAL32Mem">; + +let OperandType = "OPERAND_PCREL" in { +// PROGRAM COUNTER WITH DISPLACEMENT. This addressing mode requires one word of +// extension. The address of the operand is the sum of the address in the program +// counter and the Sign-extended 16-bit displacement integer in the extension +// word. The value in the program counter is the address of the extension word. +// The reference is classified as a program reference. +def MxPCD8 : MxMemOp<(ops i16imm), MxSize8, "q", "printPCD8Mem">; +def MxPCD16 : MxMemOp<(ops i16imm), MxSize16, "q", "printPCD16Mem">; +def MxPCD32 : MxMemOp<(ops i16imm), MxSize32, "q", "printPCD32Mem">; + +// PROGRAM COUNTER WITH INDEX. This addressing mode requires one word of +// extension. The address is the sum of the address in the program counter, the +// sign-extended displacement integer in the lower eight bits of the extension +// word, and the contents of the index register. The value in the program +// counter is the address of the extension word. This reference is classified as +// a program reference. +def MxPCI8 : MxMemOp<(ops i8imm, XR32), MxSize8, "k", "printPCI8Mem">; +def MxPCI16 : MxMemOp<(ops i8imm, XR32), MxSize16, "k", "printPCI16Mem">; +def MxPCI32 : MxMemOp<(ops i8imm, XR32), MxSize32, "k", "printPCI32Mem">; +} // OPERAND_PCREL + +class MxOp + : Operand, + MxOperand; + +let OperandType = "OPERAND_IMMEDIATE", + PrintMethod = "printImmediate" in { +// IMMEDIATE DATA. This addressing mode requires either one or two words of +// extension depending on the size of the operation. +// Byte Operation - operand is low order byte of extension word +// Word Operation - operand is extension word +// Long Word Operation - operand is in the two extension words, +// high order 16 bits are in the first +// extension word, low order 16 bits are +// in the second extension word. +def Mxi8imm : MxOp; +def Mxi16imm : MxOp; +def Mxi32imm : MxOp; +} // OPERAND_IMMEDIATE + +let OperandType = "OPERAND_PCREL", + PrintMethod = "printPCRelImm" in { + +// Branch targets have OtherVT type and print as pc-relative values. +def MxBrTarget8 : Operand; +def MxBrTarget16 : Operand; +def MxBrTarget32 : Operand; + +} // OPERAND_PCREL + +// Used with MOVEM +def MxMoveMask : MxOp { + let OperandType = "OPERAND_IMMEDIATE"; + let PrintMethod = "printMoveMask"; +} + + +//===----------------------------------------------------------------------===// +// Predicates +//===----------------------------------------------------------------------===// + +def SmallCode : Predicate<"TM.getCodeModel() == CodeModel::Small">; +def KernelCode : Predicate<"TM.getCodeModel() == CodeModel::Kernel">; +def FarData : Predicate<"TM.getCodeModel() != CodeModel::Small &&" + "TM.getCodeModel() != CodeModel::Kernel">; +def NearData : Predicate<"TM.getCodeModel() == CodeModel::Small ||" + "TM.getCodeModel() == CodeModel::Kernel">; +def IsPIC : Predicate<"TM.isPositionIndependent()">; +def IsNotPIC : Predicate<"!TM.isPositionIndependent()">; +def IsM68000 : Predicate<"Subtarget.IsM68000()">; +def IsM68010 : Predicate<"Subtarget.IsM68010()">; +def IsM68020 : Predicate<"Subtarget.IsM68020()">; +def IsM68030 : Predicate<"Subtarget.IsM68030()">; +def IsM68040 : Predicate<"Subtarget.IsM68040()">; + + +//===----------------------------------------------------------------------===// +// Condition Codes +// +// These MUST be kept in sync with codes enum in M68kInstrInfo.h +//===----------------------------------------------------------------------===// + +def MxCONDt : PatLeaf<(i8 0)>; // True +def MxCONDf : PatLeaf<(i8 1)>; // False +def MxCONDhi : PatLeaf<(i8 2)>; // High +def MxCONDls : PatLeaf<(i8 3)>; // Less or Same +def MxCONDcc : PatLeaf<(i8 4)>; // Carry Clear +def MxCONDcs : PatLeaf<(i8 5)>; // Carry Set +def MxCONDne : PatLeaf<(i8 6)>; // Not Equal +def MxCONDeq : PatLeaf<(i8 7)>; // Equal +def MxCONDvc : PatLeaf<(i8 8)>; // Overflow Clear +def MxCONDvs : PatLeaf<(i8 9)>; // Overflow Set +def MxCONDpl : PatLeaf<(i8 10)>; // Plus +def MxCONDmi : PatLeaf<(i8 11)>; // Minus +def MxCONDge : PatLeaf<(i8 12)>; // Greater or Equal +def MxCONDlt : PatLeaf<(i8 13)>; // Less Than +def MxCONDgt : PatLeaf<(i8 14)>; // Greater Than +def MxCONDle : PatLeaf<(i8 15)>; // Less or Equal + + +//===----------------------------------------------------------------------===// +// Complex Patterns +//===----------------------------------------------------------------------===// + +// NOTE Though this CP is not strictly necessarily it will simplify instruciton +// definitions +def MxCP_ARI : ComplexPattern; + +def MxCP_ARIPI : ComplexPattern; + +def MxCP_ARIPD : ComplexPattern; + +def MxCP_ARID : ComplexPattern; + +def MxCP_ARII : ComplexPattern; + +def MxCP_AL : ComplexPattern; + +def MxCP_PCD : ComplexPattern; + +def MxCP_PCI : ComplexPattern; + + +//===----------------------------------------------------------------------===// +// Pattern Fragments +//===----------------------------------------------------------------------===// + +def MximmSExt8 : PatLeaf<(i8 imm)>; +def MximmSExt16 : PatLeaf<(i16 imm)>; +def MximmSExt32 : PatLeaf<(i32 imm)>; + +// Used for Shifts and Rotations, since M68k immediates in these instructions +// are 1 <= i <= 8. Generally, if immediate is bigger than 8 it will be moved +// to a register and then an operation is performed. +// +// TODO Need to evaluate whether splitting one big shift(or rotate) +// into a few smaller is faster than doing a move, if so do custom lowering +def Mximm8_1to8 : ImmLeaf= 1 && Imm <= 8; }]>; +def Mximm16_1to8 : ImmLeaf= 1 && Imm <= 8; }]>; +def Mximm32_1to8 : ImmLeaf= 1 && Imm <= 8; }]>; + +// Helper fragments for loads. +// It's always safe to treat a anyext i16 load as a i32 load if the i16 is +// known to be 32-bit aligned or better. Ditto for i8 to i16. +def Mxloadi16 : PatFrag<(ops node:$ptr), (i16 (unindexedload node:$ptr)), [{ + LoadSDNode *LD = cast(N); + ISD::LoadExtType ExtType = LD->getExtensionType(); + if (ExtType == ISD::NON_EXTLOAD) + return true; + if (ExtType == ISD::EXTLOAD) + return LD->getAlignment() >= 2 && !LD->isSimple(); + return false; +}]>; + +def Mxloadi32 : PatFrag<(ops node:$ptr), (i32 (unindexedload node:$ptr)), [{ + LoadSDNode *LD = cast(N); + ISD::LoadExtType ExtType = LD->getExtensionType(); + if (ExtType == ISD::NON_EXTLOAD) + return true; + if (ExtType == ISD::EXTLOAD) + return LD->getAlignment() >= 4 && !LD->isSimple(); + return false; +}]>; + +def Mxloadi8 : PatFrag<(ops node:$ptr), (i8 (load node:$ptr))>; + +def MxSExtLoadi16i8 : PatFrag<(ops node:$ptr), (i16 (sextloadi8 node:$ptr))>; +def MxSExtLoadi32i8 : PatFrag<(ops node:$ptr), (i32 (sextloadi8 node:$ptr))>; +def MxSExtLoadi32i16 : PatFrag<(ops node:$ptr), (i32 (sextloadi16 node:$ptr))>; + +def MxZExtLoadi8i1 : PatFrag<(ops node:$ptr), (i8 (zextloadi1 node:$ptr))>; +def MxZExtLoadi16i1 : PatFrag<(ops node:$ptr), (i16 (zextloadi1 node:$ptr))>; +def MxZExtLoadi32i1 : PatFrag<(ops node:$ptr), (i32 (zextloadi1 node:$ptr))>; +def MxZExtLoadi16i8 : PatFrag<(ops node:$ptr), (i16 (zextloadi8 node:$ptr))>; +def MxZExtLoadi32i8 : PatFrag<(ops node:$ptr), (i32 (zextloadi8 node:$ptr))>; +def MxZExtLoadi32i16 : PatFrag<(ops node:$ptr), (i32 (zextloadi16 node:$ptr))>; + +def MxExtLoadi8i1 : PatFrag<(ops node:$ptr), (i8 (extloadi1 node:$ptr))>; +def MxExtLoadi16i1 : PatFrag<(ops node:$ptr), (i16 (extloadi1 node:$ptr))>; +def MxExtLoadi32i1 : PatFrag<(ops node:$ptr), (i32 (extloadi1 node:$ptr))>; +def MxExtLoadi16i8 : PatFrag<(ops node:$ptr), (i16 (extloadi8 node:$ptr))>; +def MxExtLoadi32i8 : PatFrag<(ops node:$ptr), (i32 (extloadi8 node:$ptr))>; +def MxExtLoadi32i16 : PatFrag<(ops node:$ptr), (i32 (extloadi16 node:$ptr))>; + + +//===----------------------------------------------------------------------===// +// Type Fixtures +// +// Type Fixtures are ValueType related information sets that usually go together +//===----------------------------------------------------------------------===// + +// TODO make it folded like MxType8.F.Op nad MxType8.F.Pat +// TODO move strings into META subclass +// vt: Type of data this fixture refers to +// prefix: Prefix used to identify type +// postfix: Prefix used to qualify type +class MxType { + int Size = vt.Size; + ValueType VT = vt; + string Prefix = prefix; + string Postfix = postfix; + + string RLet = rLet; + MxOperand ROp = rOp; + + MxOperand JOp = jOp; + ComplexPattern JPat = jPat; + + MxOperand OOp = oOp; + ComplexPattern OPat = oPat; + + MxOperand EOp = eOp; + ComplexPattern EPat = ePat; + + MxOperand POp = pOp; + ComplexPattern PPat = pPat; + + MxOperand FOp = fOp; + ComplexPattern FPat = fPat; + + MxOperand BOp = bOp; + ComplexPattern BPat = bPat; + + MxOperand QOp = qOp; + ComplexPattern QPat = qPat; + + MxOperand KOp = kOp; + ComplexPattern KPat = kPat; + + MxOperand IOp = iOp; + PatFrag IPat = iPat; + + PatFrag Load = load; +} + +class MxType8Class + : MxType; + +def MxType8 : MxType8Class; + +class MxType16Class + : MxType; + +def MxType16 : MxType16Class; + +class MxType32Class + : MxType; + +def MxType32 : MxType32Class; + + +def MxType8d : MxType8Class<"d", MxDRD8>; + +def MxType16d : MxType16Class<"d", MxDRD16>; +def MxType16a : MxType16Class<"a", MxARD16>; +def MxType16r : MxType16Class<"r", MxXRD16>; +def MxType32d : MxType32Class<"d", MxDRD32>; +def MxType32a : MxType32Class<"a", MxARD32>; +def MxType32r : MxType32Class<"r", MxXRD32>; + +let Postfix = "_TC" in { +def MxType16d_TC : MxType16Class<"d", MxDRD16_TC>; +def MxType16a_TC : MxType16Class<"a", MxARD16_TC>; +def MxType16r_TC : MxType16Class<"r", MxXRD16_TC>; +def MxType32d_TC : MxType32Class<"d", MxDRD32_TC>; +def MxType32a_TC : MxType32Class<"a", MxARD32_TC>; +def MxType32r_TC : MxType32Class<"r", MxXRD32_TC>; +} + + +//===----------------------------------------------------------------------===// +// Subsystems +//===----------------------------------------------------------------------===// + +include "M68kInstrData.td" +include "M68kInstrShiftRotate.td" +include "M68kInstrBits.td" +include "M68kInstrArithmetic.td" +include "M68kInstrControl.td" + +include "M68kInstrCompiler.td" diff --git a/llvm/lib/Target/M68k/M68kInstrShiftRotate.td b/llvm/lib/Target/M68k/M68kInstrShiftRotate.td new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/M68k/M68kInstrShiftRotate.td @@ -0,0 +1,92 @@ +//===------ M68kInstrShiftRotate.td - Logical Instrs -----*- tablegen -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file describes the logical instructions in the M68k architecture. +/// Here is the current status of the file: +/// +/// Machine: +/// +/// SHL [~] ASR [~] LSR [~] SWAP [ ] +/// ROL [~] ROR [~] ROXL [ ] ROXR [ ] +/// +/// Map: +/// +/// [ ] - was not touched at all +/// [!] - requires extarnal stuff implemented +/// [~] - in progress but usable +/// [x] - done +/// +//===----------------------------------------------------------------------===// + +def MxRODI_R : MxBead1Bit<0>; +def MxRODI_L : MxBead1Bit<1>; + +def MxROOP_AS : MxBead2Bits<0b00>; +def MxROOP_LS : MxBead2Bits<0b01>; +def MxROOP_ROX : MxBead2Bits<0b10>; +def MxROOP_RO : MxBead2Bits<0b11>; + +/// ------------+---------+---+------+---+------+--------- +/// F E D C | B A 9 | 8 | 7 6 | 5 | 4 3 | 2 1 0 +/// ------------+---------+---+------+---+------+--------- +/// 1 1 1 0 | REG/IMM | D | SIZE |R/I| OP | REG +/// ------------+---------+---+------+---+------+--------- +class MxSREncoding_R + : MxEncoding, ROOP, MxBead1Bit<1>, SIZE, DIRECTION, + MxBeadReg<2>, MxBead4Bits<0b1110>>; + +class MxSREncoding_I + : MxEncoding, ROOP, MxBead1Bit<0>, SIZE, DIRECTION, + MxBead3Imm<2, 1>, MxBead4Bits<0b1110>>; + +// $reg <- $reg op $reg +class MxSR_DD + : MxInst<(outs TYPE.ROp:$dst), (ins TYPE.ROp:$src, TYPE.ROp:$opd), + MN#"."#TYPE.Prefix#"\t$opd, $dst", + [(set TYPE.VT:$dst, (NODE TYPE.VT:$src, TYPE.VT:$opd))], + MxSREncoding_R("MxEncSize"#TYPE.Size)>>; + +// $reg <- $reg op $imm +class MxSR_DI + : MxInst<(outs TYPE.ROp:$dst), + (ins TYPE.ROp:$src, !cast("Mxi"#TYPE.Size#"imm"):$opd), + MN#"."#TYPE.Prefix#"\t$opd, $dst", + [(set TYPE.VT:$dst, + (NODE TYPE.VT:$src, + !cast("Mximm"#TYPE.Size#"_1to8"):$opd))], + MxSREncoding_I("MxEncSize"#TYPE.Size)>>; + +multiclass MxSROp { + + let Defs = [CCR] in { + let Constraints = "$src = $dst" in { + + def NAME#"8dd" : MxSR_DD; + def NAME#"16dd" : MxSR_DD; + def NAME#"32dd" : MxSR_DD; + + def NAME#"8di" : MxSR_DI; + def NAME#"16di" : MxSR_DI; + def NAME#"32di" : MxSR_DI; + + } // $src = $dst + } // Defs = [CCR] + +} // MxBiArOp_RF + +defm SHL : MxSROp<"lsl", shl, MxRODI_L, MxROOP_LS>; +defm LSR : MxSROp<"lsr", srl, MxRODI_R, MxROOP_LS>; +defm ASR : MxSROp<"asr", sra, MxRODI_R, MxROOP_AS>; + +defm ROL : MxSROp<"rol", rotl, MxRODI_L, MxROOP_RO>; +defm ROR : MxSROp<"ror", rotr, MxRODI_R, MxROOP_RO>; diff --git a/llvm/lib/Target/M68k/M68kRegisterInfo.td b/llvm/lib/Target/M68k/M68kRegisterInfo.td new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/M68k/M68kRegisterInfo.td @@ -0,0 +1,130 @@ +//== M68kRegisterInfo.td - M68k register definitions ----*- tablegen -*-==// +// +// 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 +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file describes the M68k Register file, defining the registers +/// aliases between the registers, and the register classes built out of the +/// registers. +/// +//===----------------------------------------------------------------------===// + +class MxReg ENC, + list SUBREGS = [], list SUBIDX, + list DWREGS = []> + : Register, DwarfRegNum { + let Namespace = "M68k"; + let HWEncoding = ENC; + let SubRegs = SUBREGS; + let SubRegIndices = SUBIDX; +} + +// Subregister indices. +let Namespace = "M68k" in { + def MxSubRegIndex8Lo : SubRegIndex<8, 0>; + def MxSubRegIndex16Lo : SubRegIndex<16, 0>; +} + +// Generate Data registers and theirs smaller variants +foreach Index = 0-7 in { + def "BD"#Index : MxReg<"d"#Index, Index, [], [], [Index]>; + + def "WD"#Index + : MxReg<"d"#Index, Index, + [!cast("BD"#Index)], [MxSubRegIndex8Lo], + [Index]>; + + def "D"#Index + : MxReg<"d"#Index, Index, + [!cast("WD"#Index)], [MxSubRegIndex16Lo], + [Index]>; + +} // foreach + +// Generate Address registers and theirs smaller variants +foreach Index = 0-7 in { + def "WA"#Index + : MxReg<"a"#Index, Index, [], [], [!add(8,Index)]>; + + def "A"#Index + : MxReg<"a"#Index, Index, + [!cast("WA"#Index)], [MxSubRegIndex16Lo], + [!add(8,Index)]>; +} + +// Alias Registers +class MxAliasReg + : MxReg { + let Aliases = [REG]; +} + +def BP : MxAliasReg<"bp", A5>; +def FP : MxAliasReg<"fp", A6>; +def SP : MxAliasReg<"sp", A7>; + +def USP : MxAliasReg<"usp", A7>; +def SSP : MxAliasReg<"ssp", A7>; +def ISP : MxAliasReg<"isp", A7>; + +// Pseudo Registers +class MxPseudoReg SUBREGS = [], list SUBIDX = []> + : MxReg; + +def CCR : MxPseudoReg<"ccr">; +def SR : MxPseudoReg<"sr">; + +def PC : MxPseudoReg<"pc">; + +//===----------------------------------------------------------------------===// +// Register Classes +//===----------------------------------------------------------------------===// + +class MxRegClass regTypes, int alignment, dag regList> + : RegisterClass<"M68k", regTypes, alignment, regList>; + +// Data Registers +def DR8 : MxRegClass<[i8], 16, (sequence "BD%u", 0, 7)>; +def DR16 : MxRegClass<[i16], 16, (sequence "WD%u", 0, 7)>; +def DR32 : MxRegClass<[i32], 32, (sequence "D%u", 0, 7)>; + +// Address Registers +def AR16 : MxRegClass<[i16], 16, (sequence "WA%u", 0, 6)>; +def AR32 : MxRegClass<[i32], 32, (add (sequence "A%u", 0, 6), SP)>; + +def AR32_NOSP : MxRegClass<[i32], 32, (add (sequence "A%u", 0, 6))>; + +// Index Register Classes +// FIXME try alternative ordering like `D0, D1, A0, A1, ...` +def XR16 : MxRegClass<[i16], 16, (add DR16, AR16)>; +def XR32 : MxRegClass<[i32], 32, (add DR32, AR32)>; + +def SPC : MxRegClass<[i32], 32, (add SP)>; + +let CopyCost = -1 in { + def CCRC : MxRegClass<[i8], 16, (add CCR)>; + def SRC : MxRegClass<[i16], 16, (add SR)>; +} + +let isAllocatable = 0 in { + def PCC : MxRegClass<[i32], 32, (add PC)>; +} + +// Register used with tail call +def DR16_TC : MxRegClass<[i16], 16, (add D0, D1)>; +def DR32_TC : MxRegClass<[i32], 32, (add D0, D1)>; + +def AR16_TC : MxRegClass<[i16], 16, (add A0, A1)>; +def AR32_TC : MxRegClass<[i32], 32, (add A0, A1)>; + +def XR16_TC : MxRegClass<[i16], 16, (add DR16_TC, AR16_TC)>; +def XR32_TC : MxRegClass<[i32], 32, (add DR32_TC, AR32_TC)>; + +// These classes provide spill/restore order if used with MOVEM instruction +def SPILL : MxRegClass<[i32], 32, (add (add (sequence "D%u", 0, 7), + (sequence "A%u", 0, 6)), SP)>; +def SPILL_R : MxRegClass<[i32], 32, (add SP, (add (sequence "A%u", 6, 0), + (sequence "D%u", 7, 0)))>; diff --git a/llvm/lib/Target/M68k/M68kSchedule.td b/llvm/lib/Target/M68k/M68kSchedule.td new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/M68k/M68kSchedule.td @@ -0,0 +1,23 @@ +//===-- M68kSchedule.td - M68k Scheduling Definitions --*- tablegen -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file contains M68k scheduler definitions. +/// +//===----------------------------------------------------------------------===// + +/// This is a very general M68k Scheduling Model and best suited for the very +/// first M68000 CPU, other model must override these characteristics +class M68kSchedModel : SchedMachineModel { + let LoadLatency = 4; // Word (Rn) + let HighLatency = 16; // Long ABS + let PostRAScheduler = 0; + let CompleteModel = 0; +} + +def GenericM68kModel : M68kSchedModel; diff --git a/llvm/lib/Target/M68k/M68kTargetMachine.cpp b/llvm/lib/Target/M68k/M68kTargetMachine.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/M68k/M68kTargetMachine.cpp @@ -0,0 +1,17 @@ +//===-- M68kTargetMachine.cpp - M68k target machine ---------*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file contains implementation for M68k target machine. +/// +//===----------------------------------------------------------------------===// + +/// This is just a placeholder to make current +/// commit buildable. Body of this function will +/// be filled in later commits +extern "C" void LLVMInitializeM68kTarget() {} diff --git a/llvm/lib/Target/M68k/MCTargetDesc/CMakeLists.txt b/llvm/lib/Target/M68k/MCTargetDesc/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/M68k/MCTargetDesc/CMakeLists.txt @@ -0,0 +1,12 @@ +add_llvm_component_library(LLVMM68kDesc + M68kMCTargetDesc.cpp + + LINK_COMPONENTS + MC + MCDisassembler + Support + M68kInfo + + ADD_TO_COMPONENT + M68k +) diff --git a/llvm/lib/Target/M68k/MCTargetDesc/M68kMCTargetDesc.cpp b/llvm/lib/Target/M68k/MCTargetDesc/M68kMCTargetDesc.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/M68k/MCTargetDesc/M68kMCTargetDesc.cpp @@ -0,0 +1,17 @@ +//===-- M68kMCTargetDesc.cpp - M68k Target Descriptions -----*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file provides M68k target specific descriptions. +/// +//===----------------------------------------------------------------------===// + +/// This is just a placeholder to make current +/// commit buildable. Body of this function will +/// be filled in later commits +extern "C" void LLVMInitializeM68kTargetMC() {} diff --git a/llvm/lib/Target/M68k/TargetInfo/CMakeLists.txt b/llvm/lib/Target/M68k/TargetInfo/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/M68k/TargetInfo/CMakeLists.txt @@ -0,0 +1,9 @@ +add_llvm_component_library(LLVMM68kInfo + M68kTargetInfo.cpp + + LINK_COMPONENTS + Support + + ADD_TO_COMPONENT + M68k +) diff --git a/llvm/lib/Target/M68k/TargetInfo/M68kTargetInfo.cpp b/llvm/lib/Target/M68k/TargetInfo/M68kTargetInfo.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/M68k/TargetInfo/M68kTargetInfo.cpp @@ -0,0 +1,17 @@ +//===-- M68kTargetInfo.cpp - M68k Target Implementation -----*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file contains M68k target initializer. +/// +//===----------------------------------------------------------------------===// + +/// This is just a placeholder to make current +/// commit buildable. Body of this function will +/// be filled in later commits +extern "C" void LLVMInitializeM68kTargetInfo() {}