Index: llvm/lib/Target/M680x0/M680x0.h =================================================================== --- /dev/null +++ llvm/lib/Target/M680x0/M680x0.h @@ -0,0 +1,53 @@ +//===- M680x0.h - Top-level interface for M680x0 representation -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file contains the entry points for global functions defined in the +/// M680x0 target library, as used by the LLVM JIT. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_M680x0_M680x0_H +#define LLVM_LIB_TARGET_M680x0_M680x0_H + +#include "llvm/Support/CodeGen.h" + +namespace llvm { + +class FunctionPass; +class M680x0TargetMachine; + +/// This pass converts a legalized DAG into a M680x0-specific DAG, ready for +/// instruction scheduling. +FunctionPass *createM680x0ISelDag(M680x0TargetMachine &TM); + +/// Return a Machine IR pass that expands M680x0-specific pseudo +/// instructions into a sequence of actual instructions. This pass +/// must run after prologue/epilogue insertion and before lowering +/// the MachineInstr to MC. +FunctionPass *createM680x0ExpandPseudoPass(); + +/// This pass initializes a global base register for PIC on M680x0. +FunctionPass *createM680x0GlobalBaseRegPass(); + +/// Finds sequential MOVEM instruction and collapse them into a single one. This +/// pass has to be run after all pseudo expansions and prologue/epilogue +/// emission so that all possible MOVEM are already in place. +FunctionPass *createM680x0CollapseMOVEMPass(); + +/// Finds MOVE instructions before any conditioanl branch instruction and +/// replaces them with MOVEM instruction. Motorola's MOVEs do trash(V,C) flags +/// register which prevents branch from taking the correct route. This pass +/// has to be run after all pseudo expansions and prologue/epilogue emission +/// so that all possible MOVEs are present. +FunctionPass *createM680x0ConvertMOVToMOVMPass(); + +} // namespace llvm + +#endif Index: llvm/lib/Target/M680x0/M680x0.td =================================================================== --- /dev/null +++ llvm/lib/Target/M680x0/M680x0.td @@ -0,0 +1,85 @@ +//===-- M680x0.td - Motorola 680x0 target definitions ------*- tablegen -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This is a target description file for the Motorola 680x0 family, referred +/// to here as the "M680x0" architecture. +/// +//===----------------------------------------------------------------------===// + +include "llvm/Target/Target.td" + +//===----------------------------------------------------------------------===// +// X86 Subtarget features +//===----------------------------------------------------------------------===// + +def FeatureISAx00 + : SubtargetFeature<"x00", "IsM68000", "true", "Is M68000 ISA supported">; + +def FeatureISAx10 + : SubtargetFeature<"x10", "IsM68010", "true", "Is M68010 ISA supported", + [ FeatureISAx00 ]>; + +def FeatureISAx20 + : SubtargetFeature<"x20", "IsM68020", "true", "Is M68020 ISA supported", + [ FeatureISAx10 ]>; + +def FeatureISAx30 + : SubtargetFeature<"x30", "IsM68030", "true", "Is M68030 ISA supported", + [ FeatureISAx20 ]>; + +def FeatureISAx40 + : SubtargetFeature<"x40", "IsM68040", "true", "Is M68040 ISA supported", + [ FeatureISAx30 ]>; + +//===----------------------------------------------------------------------===// +// M680x0 processors supported. +//===----------------------------------------------------------------------===// + +include "M680x0Schedule.td" + +class Proc Features> + : ProcessorModel; + +def : Proc<"generic", [ FeatureISAx00 ]>; +def : Proc<"M68000", [ FeatureISAx00 ]>; +def : Proc<"M68010", [ FeatureISAx10 ]>; +def : Proc<"M68020", [ FeatureISAx20 ]>; +def : Proc<"M68030", [ FeatureISAx30 ]>; +def : Proc<"M68040", [ FeatureISAx40 ]>; + +//===----------------------------------------------------------------------===// +// Register File Description +//===----------------------------------------------------------------------===// + +include "M680x0RegisterInfo.td" + +//===----------------------------------------------------------------------===// +// Instruction Descriptions +//===----------------------------------------------------------------------===// + +include "M680x0InstrInfo.td" + +def M680x0InstrInfo : InstrInfo; + +//===----------------------------------------------------------------------===// +// Calling Conventions +//===----------------------------------------------------------------------===// + +include "M680x0CallingConv.td" + +//===----------------------------------------------------------------------===// +// Target +//===----------------------------------------------------------------------===// + +def M680x0 : Target { + let InstructionSet = M680x0InstrInfo; + // let AssemblyParserVariants = [ATTAsmParserVariant, IntelAsmParserVariant]; + // let AssemblyWriters = [ATTAsmWriter, IntelAsmWriter]; +} Index: llvm/lib/Target/M680x0/M680x0InstrArithmetic.td =================================================================== --- /dev/null +++ llvm/lib/Target/M680x0/M680x0InstrArithmetic.td @@ -0,0 +1,845 @@ +//===-- M680x0InstrArithmetic.td - Integer Arith Instrs ----*- tablegen -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file describes the integer arithmetic instructions in the M680x0 +/// 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, + SRC_EXT.Imm, SRC_EXT.B8, SRC_EXT.Scale, SRC_EXT.WL, SRC_EXT.DAReg, + 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 { + +class MxBiArOp_FMR CMD, MxEncEA EA, MxEncExt EXT> + : MxInst<(outs), (ins MEMOpd:$dst, TYPE.ROp:$opd), + MN#"."#TYPE.Prefix#"\t$opd, $dst", + // FIXME #20 These cannot consume CCR from MxAdd/MxSub which leads for + // MxAdd to survive the match and subsequent malmatch. + /* [(store (NODE (TYPE.Load MEMPat:$dst), TYPE.VT:$opd), MEMPat:$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", + // FIXME #20 Same as above + /* [(store (NODE (TYPE.Load MEMPat:$dst), TYPE.IPat:$opd), MEMPat:$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; + +} // isCommutable = ? + +} // 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; + +} // isCommutable = ? + +} // 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 node = ["add", "addc"] in { + +// add reg, reg +def : Pat<(!cast(node) i8 :$src, i8 :$opd), (ADD8dd MxDRD8 :$src, MxDRD8 :$opd)>; +def : Pat<(!cast(node) i16:$src, i16:$opd), (ADD16dd MxDRD16:$src, MxDRD16:$opd)>; +def : Pat<(!cast(node) i32:$src, i32:$opd), (ADD32rr MxXRD32:$src, MxXRD32:$opd)>; + +// add (An), reg +def : Pat<(!cast(node) MxType8.VT:$src, (Mxloadi8 MxType8.JPat:$opd)), + (ADD8dj MxDRD8:$src, MxType8.JOp:$opd)>; +def : Pat<(!cast(node) MxType16.VT:$src, (Mxloadi16 MxType16.JPat:$opd)), + (ADD16dj MxDRD16:$src, MxType16.JOp:$opd)>; +def : Pat<(!cast(node) MxType32.VT:$src, (Mxloadi32 MxType32.JPat:$opd)), + (ADD32rj MxXRD32:$src, MxType32.JOp:$opd)>; + +// add (i,An), reg +def : Pat<(!cast(node) MxType8.VT:$src, (Mxloadi8 MxType8.PPat:$opd)), + (ADD8dp MxDRD8:$src, MxType8.POp:$opd)>; +def : Pat<(!cast(node) MxType16.VT:$src, (Mxloadi16 MxType16.PPat:$opd)), + (ADD16dp MxDRD16:$src, MxType16.POp:$opd)>; +def : Pat<(!cast(node) MxType32.VT:$src, (Mxloadi32 MxType32.PPat:$opd)), + (ADD32rp MxXRD32:$src, MxType32.POp:$opd)>; + +// add (i,An,Xn), reg +def : Pat<(!cast(node) MxType8.VT:$src, (Mxloadi8 MxType8.FPat:$opd)), + (ADD8df MxDRD8:$src, MxType8.FOp:$opd)>; +def : Pat<(!cast(node) MxType16.VT:$src, (Mxloadi16 MxType16.FPat:$opd)), + (ADD16df MxDRD16:$src, MxType16.FOp:$opd)>; +def : Pat<(!cast(node) MxType32.VT:$src, (Mxloadi32 MxType32.FPat:$opd)), + (ADD32rf MxXRD32:$src, MxType32.FOp:$opd)>; + +// add reg, imm +def : Pat<(!cast(node) i8: $src, MximmSExt8:$opd), (ADD8di MxDRD8 :$src, imm:$opd)>; +def : Pat<(!cast(node) 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(node) i32:$src, MximmSExt32:$opd), (ADD32ri MxXRD32:$src, imm:$opd)>; +} // AddedComplexity = 15 + +// add imm, (An) +def : Pat<(store (!cast(node) (load MxType8.JPat:$dst), MxType8.IPat:$opd), MxType8.JPat:$dst), + (ADD8ji MxType8.JOp:$dst, imm:$opd)>; +def : Pat<(store (!cast(node) (load MxType16.JPat:$dst), MxType16.IPat:$opd), MxType16.JPat:$dst), + (ADD16ji MxType16.JOp:$dst, imm:$opd)>; +def : Pat<(store (!cast(node) (load MxType32.JPat:$dst), MxType32.IPat:$opd), MxType32.JPat:$dst), + (ADD32ji MxType32.JOp:$dst, imm:$opd)>; + +// These patterns treat AL value as immediate +/* def : Pat<(!cast(node) MxType32r.ROp:$src, MxType32r.BPat:$opd), */ +/* (ADD32ri MxXRD32:$src, MxType32r.IOp:$opd)>; */ +/* */ +/* def : Pat<(store (!cast(node) (load MxType32.FPat:$dst), MxType32.BPat:$opd), MxType32.FPat:$dst), */ +/* (ADD32ji MxType8.FOp:$dst, MxType32.IOp:$opd)>; */ +/* */ +/* def : Pat<(store (!cast(node) (load MxType32.PPat:$dst), MxType32.BPat:$opd), MxType32.PPat:$dst), */ +/* (ADD32ji MxType8.POp:$dst, MxType32.IOp:$opd)>; */ +/* */ +/* def : Pat<(store (!cast(node) (load MxType32.JPat:$dst), MxType32.BPat:$opd), MxType32.JPat:$dst), */ +/* (ADD32ji MxType8.JOp:$dst, MxType32.IOp:$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 node = ["sub", "subc"] in { + +// sub reg, reg +def : Pat<(!cast(node) i8 :$src, i8 :$opd), (SUB8dd MxDRD8 :$src, MxDRD8 :$opd)>; +def : Pat<(!cast(node) i16:$src, i16:$opd), (SUB16dd MxDRD16:$src, MxDRD16:$opd)>; +def : Pat<(!cast(node) i32:$src, i32:$opd), (SUB32rr MxXRD32:$src, MxXRD32:$opd)>; + + +// sub (An), reg +def : Pat<(!cast(node) MxType8.VT:$src, (Mxloadi8 MxType8.JPat:$opd)), + (SUB8dj MxDRD8:$src, MxType8.JOp:$opd)>; +def : Pat<(!cast(node) MxType16.VT:$src, (Mxloadi16 MxType16.JPat:$opd)), + (SUB16dj MxDRD16:$src, MxType16.JOp:$opd)>; +def : Pat<(!cast(node) MxType32.VT:$src, (Mxloadi32 MxType32.JPat:$opd)), + (SUB32rj MxXRD32:$src, MxType32.JOp:$opd)>; + +// sub (i,An), reg +def : Pat<(!cast(node) MxType8.VT:$src, (Mxloadi8 MxType8.PPat:$opd)), + (SUB8dp MxDRD8:$src, MxType8.POp:$opd)>; +def : Pat<(!cast(node) MxType16.VT:$src, (Mxloadi16 MxType16.PPat:$opd)), + (SUB16dp MxDRD16:$src, MxType16.POp:$opd)>; +def : Pat<(!cast(node) MxType32.VT:$src, (Mxloadi32 MxType32.PPat:$opd)), + (SUB32rp MxXRD32:$src, MxType32.POp:$opd)>; + +// sub (i,An,Xn), reg +def : Pat<(!cast(node) MxType8.VT:$src, (Mxloadi8 MxType8.FPat:$opd)), + (SUB8df MxDRD8:$src, MxType8.FOp:$opd)>; +def : Pat<(!cast(node) MxType16.VT:$src, (Mxloadi16 MxType16.FPat:$opd)), + (SUB16df MxDRD16:$src, MxType16.FOp:$opd)>; +def : Pat<(!cast(node) MxType32.VT:$src, (Mxloadi32 MxType32.FPat:$opd)), + (SUB32rf MxXRD32:$src, MxType32.FOp:$opd)>; + +// sub reg, imm +def : Pat<(!cast(node) i8 :$src, MximmSExt8 :$opd), (SUB8di MxDRD8 :$src, imm:$opd)>; +def : Pat<(!cast(node) i16:$src, MximmSExt16:$opd), (SUB16di MxDRD16:$src, imm:$opd)>; +def : Pat<(!cast(node) i32:$src, MximmSExt32:$opd), (SUB32ri MxXRD32:$src, imm:$opd)>; + +// sub imm, (An) +def : Pat<(store (!cast(node) (load MxType8.JPat:$dst), MxType8.IPat:$opd), MxType8.JPat:$dst), + (SUB8ji MxType8.JOp:$dst, imm:$opd)>; +def : Pat<(store (!cast(node) (load MxType16.JPat:$dst), MxType16.IPat:$opd), MxType16.JPat:$dst), + (SUB16ji MxType16.JOp:$dst, imm:$opd)>; +def : Pat<(store (!cast(node) (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, mem +/* def : Pat<(and MxDRD8:$src, (Mxloadi8 addr:$opd)), */ +/* (AND8rm MxDRD8:$src, addr:$opd)>; */ +/* def : Pat<(and MxXRD16:$src, (Mxloadi16 addr:$opd)), */ +/* (AND16rm MxXRD16:$src, addr:$opd)>; */ +/* def : Pat<(and MxXRD32:$src, (Mxloadi32 addr:$opd)), */ +/* (AND32rm MxXRD32:$src, addr:$opd)>; */ +/* def : Pat<(and GR64:$src, (loadi64 addr:$opd)), */ +/* (AND64rm GR64:$src, addr:$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, mem +/* def : Pat<(xor MxDRD8:$src, (Mxloadi8 addr:$opd)), */ +/* (XOR8rm MxDRD8:$src, addr:$opd)>; */ +/* def : Pat<(xor MxXRD16:$src, (Mxloadi16 addr:$opd)), */ +/* (XOR16rm MxXRD16:$src, addr:$opd)>; */ +/* def : Pat<(xor MxXRD32:$src, (Mxloadi32 addr:$opd)), */ +/* (XOR32rm MxXRD32:$src, addr:$opd)>; */ +/* def : Pat<(xor GR64:$src, (loadi64 addr:$opd)), */ +/* (XOR64rm GR64:$src, addr:$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/mem +/* def : Pat<(or MxDRD8:$src, (Mxloadi8 addr:$opd)), */ +/* (OR8rm MxDRD8:$src, addr:$opd)>; */ +/* def : Pat<(or MxXRD16:$src, (Mxloadi16 addr:$opd)), */ +/* (OR16rm MxXRD16:$src, addr:$opd)>; */ +/* def : Pat<(or MxXRD32:$src, (Mxloadi32 addr:$opd)), */ +/* (OR32rm MxXRD32:$src, addr:$opd)>; */ +/* def : Pat<(or GR64:$src, (loadi64 addr:$opd)), */ +/* (OR64rm GR64:$src, addr:$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)>; Index: llvm/lib/Target/M680x0/M680x0InstrBits.td =================================================================== --- /dev/null +++ llvm/lib/Target/M680x0/M680x0InstrBits.td @@ -0,0 +1,91 @@ +//===------- M680x0InstrBits.td - Bit Manipulation Instrs --*- tablegen -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file describes the bit manipulation instructions in the M680x0 +/// 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; Index: llvm/lib/Target/M680x0/M680x0InstrBuilder.h =================================================================== --- /dev/null +++ llvm/lib/Target/M680x0/M680x0InstrBuilder.h @@ -0,0 +1,96 @@ +//===-- M680x0InstrBuilder.h - Functions to build M680x0 insts --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file exposes functions that may be used with BuildMI from the +/// MachineInstrBuilder.h file to handle M680x0'isms in a clean way. +/// +/// TODO #42 edit the following mem stuff +/// The BuildMem function may be used with the BuildMI function to add entire +/// memory references in a single, typed, function call. M680x0 memory +/// references can be very complex expressions (described in the README), so +/// wrapping them up behind an easier to use interface makes sense. +/// Descriptions of the functions are included below. +/// +/// For reference, the order of operands for memory references is: +/// (Operand), Base, Scale, Index, Displacement. +/// +//===----------------------------------------------------------------------===// +// +#ifndef LLVM_LIB_TARGET_M6800_M6800INSTRBUILDER_H +#define LLVM_LIB_TARGET_M6800_M6800INSTRBUILDER_H + +#include "llvm/ADT/SmallVector.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineInstr.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineMemOperand.h" +#include "llvm/CodeGen/MachineOperand.h" +#include "llvm/MC/MCInstrDesc.h" + +#include + +namespace llvm { + +static inline const MachineInstrBuilder & +addOffset(const MachineInstrBuilder &MIB, int Offset) { + return MIB.addImm(Offset); +} + +/// addRegIndirectWithDisp - This function is used to add a memory reference +/// of the form (Offset, Base), i.e., one with no scale or index, but with a +/// displacement. An example is: (4,D0). +static inline const MachineInstrBuilder & +addRegIndirectWithDisp(const MachineInstrBuilder &MIB, unsigned Reg, + bool isKill, int Offset) { + return MIB.addImm(Offset).addReg(Reg, getKillRegState(isKill)); +} + +/// addFrameReference - This function is used to add a reference to the base of +/// an abstract object on the stack frame of the current function. This +/// reference has base register as the FrameIndex offset until it is resolved. +/// This allows a constant offset to be specified as well... +static inline const MachineInstrBuilder & +addFrameReference(const MachineInstrBuilder &MIB, int FI, int Offset = 0) { + MachineInstr *MI = MIB; + MachineFunction &MF = *MI->getParent()->getParent(); + MachineFrameInfo &MFI = MF.getFrameInfo(); + const MCInstrDesc &MCID = MI->getDesc(); + auto Flags = MachineMemOperand::MONone; + if (MCID.mayLoad()) + Flags |= MachineMemOperand::MOLoad; + if (MCID.mayStore()) + Flags |= MachineMemOperand::MOStore; + MachineMemOperand *MMO = MF.getMachineMemOperand( + MachinePointerInfo::getFixedStack(MF, FI, Offset), Flags, + MFI.getObjectSize(FI), MFI.getObjectAlign(FI)); + return MIB.addImm(Offset).addFrameIndex(FI).addMemOperand(MMO); +} + +static inline const MachineInstrBuilder & +addMemOperand(const MachineInstrBuilder &MIB, int FI, int Offset = 0) { + MachineInstr *MI = MIB; + MachineFunction &MF = *MI->getParent()->getParent(); + MachineFrameInfo &MFI = MF.getFrameInfo(); + const MCInstrDesc &MCID = MI->getDesc(); + auto Flags = MachineMemOperand::MONone; + if (MCID.mayLoad()) + Flags |= MachineMemOperand::MOLoad; + if (MCID.mayStore()) + Flags |= MachineMemOperand::MOStore; + MachineMemOperand *MMO = MF.getMachineMemOperand( + MachinePointerInfo::getFixedStack(MF, FI, Offset), Flags, + MFI.getObjectSize(FI), MFI.getObjectAlign(FI)); + return MIB.addMemOperand(MMO); +} + +} // end namespace llvm + +#endif // LLVM_LIB_TARGET_M6800_M6800INSTRBUILDER_H Index: llvm/lib/Target/M680x0/M680x0InstrCompiler.td =================================================================== --- /dev/null +++ llvm/lib/Target/M680x0/M680x0InstrCompiler.td @@ -0,0 +1,129 @@ +//===-- M680x0InstrCompiler.td - Pseudos and Patterns ------*- tablegen -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \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 +//===----------------------------------------------------------------------===// + +// FIXME #7 need to read more about TC in llvm + +// 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 #7 This 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))]>; Index: llvm/lib/Target/M680x0/M680x0InstrControl.td =================================================================== --- /dev/null +++ llvm/lib/Target/M680x0/M680x0InstrControl.td @@ -0,0 +1,312 @@ +//===-- M680x0InstrControl.td - Control Flow Instructions --*- tablegen -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file describes the M680x0 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 #21 M680x0 does not allow 16 bit indirect jumps use sext operands +/* def JMP16r : MxInst<(outs), (ins M680x0_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; + +def : Pat<(MxCall (i32 tglobaladdr:$dst)), (CALLq tglobaladdr:$dst)>, Requires<[IsPIC]>; +def : Pat<(MxCall (i32 texternalsym:$dst)), (CALLq texternalsym:$dst)>, Requires<[IsPIC]>; +def : Pat<(MxCall (i32 imm:$dst)), (CALLq imm:$dst)>, Requires<[IsPIC]>; + +def : Pat<(MxCall (i32 tglobaladdr:$dst)), (CALLb tglobaladdr:$dst)>, Requires<[IsNotPIC]>; +def : Pat<(MxCall (i32 texternalsym:$dst)), (CALLb texternalsym:$dst)>, Requires<[IsNotPIC]>; +def : Pat<(MxCall (i32 imm:$dst)), (CALLb imm:$dst)>, Requires<[IsNotPIC]>; + +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 M680x0 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)>; +} +} // let Uses = [SP] +} // let isCodeGenOnly = 1 + +//===----------------------------------------------------------------------===// +// Return +//===----------------------------------------------------------------------===// + +// TODO #43 don't forget about 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)]>; +} // let isCodeGenOnly = 1 + +} + + +//===----------------------------------------------------------------------===// +// SETCC_C Patterns +//===----------------------------------------------------------------------===// + +// Use subx to materialize carry bit. +let Uses = [CCR], Defs = [CCR], isPseudo = 1 in { +// FIXME #22 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))]>; +} // isCodeGenOnly + + +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))>; Index: llvm/lib/Target/M680x0/M680x0InstrData.td =================================================================== --- /dev/null +++ llvm/lib/Target/M680x0/M680x0InstrData.td @@ -0,0 +1,718 @@ +//== M680x0InstrData.td - M680x0 Data Movement Instructions -*- tablegen --===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \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< + srcEA.Reg, srcEA.DA, srcEA.Mode, dstEA.DA, dstEA.Mode, dstEA.Reg, size, MxBead2Bits<0b00>, + 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 { + +// NOTE tablegen defines implicitly created defs inside multiclass which +// breaks some code like letting Pattern afterwards in _TC + +// 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)>; + +// FIXME #23 Tablegen needs to parse complex defm names inside the loop FFS + +// 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 mayLoad = 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 M680x0 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)>; Index: llvm/lib/Target/M680x0/M680x0InstrFormats.td =================================================================== --- /dev/null +++ llvm/lib/Target/M680x0/M680x0InstrFormats.td @@ -0,0 +1,373 @@ +//=== M680x0InstrFormats.td - M680x0 Instruction Formats ---*- tablegen -*-===// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file contains M680x0 instruction formats. +/// +/// Since M680x0 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 quilified 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 alreay 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 instruciton +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 dispacement/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; + + +/// M680x0 Standard Effective Address layout: +/// +/// :-------------------: +/// | 5 4 3 | 2 1 0 | +/// | mode | reg | +/// :-------------------: +/// +/// If the EA is a direct register use the 3 bit is known to distinguish +/// between Data and Address register types and bits 5 and 4 are 0. This allows +/// us to encode EA as MxBead2Bits<0b00> and MxBeadDAReg. +/// +/// +/// 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; +} + +// NOTE: freaking tablegen... +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 M680x0 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>; + +/* class MxExtBrief opN, bits<1> wl = 0b1> */ +/* : MxEncExt, MxBead1Bit<0b0>, */ +/* MxBead2Bits<0b00>, MxBead1Bit, */ +/* MxBeadDAReg>; */ + +// 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>; + +// M680x0 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 = "M680x0"; + 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; +} + +// M680x0 PSEUDO INSTRUCTION +class MxPseudo pattern = []> + : MxInst { + let isPseudo = 1; +} Index: llvm/lib/Target/M680x0/M680x0InstrInfo.h =================================================================== --- /dev/null +++ llvm/lib/Target/M680x0/M680x0InstrInfo.h @@ -0,0 +1,339 @@ +//===-- M680x0InstrInfo.h - M680x0 Instruction Information ------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file contains the M680x0 implementation of the TargetInstrInfo class. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_M680X0_M680X0INSTRINFO_H +#define LLVM_LIB_TARGET_M680X0_M680X0INSTRINFO_H + +#include "M680x0.h" +#include "M680x0RegisterInfo.h" + +#include "MCTargetDesc/M680x0BaseInfo.h" + +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/TargetInstrInfo.h" + +#define GET_INSTRINFO_HEADER +#include "M680x0GenInstrInfo.inc" + +namespace llvm { + +class M680x0Subtarget; + +namespace M680x0 { + +// These MUST be kept in sync with codes definitions in M680x0InstrInfo.td +enum CondCode { + COND_T = 0, // True + COND_F = 1, // False + COND_HI = 2, // High + COND_LS = 3, // Less or Same + COND_CC = 4, // Carry Clear + COND_CS = 5, // Carry Set + COND_NE = 6, // Not Equal + COND_EQ = 7, // Equal + COND_VC = 8, // Overflow Clear + COND_VS = 9, // Overflow Set + COND_PL = 10, // Plus + COND_MI = 11, // Minus + COND_GE = 12, // Greater or Equal + COND_LT = 13, // Less Than + COND_GT = 14, // Greater Than + COND_LE = 15, // Less or Equal + LAST_VALID_COND = COND_LE, + COND_INVALID +}; + +// FIXME #25 would be nice tablegen to generate these predicates and converters +// mb tag based + +static inline M680x0::CondCode GetOppositeBranchCondition(M680x0::CondCode CC) { + switch (CC) { + default: + llvm_unreachable("Illegal condition code!"); + case M680x0::COND_T: + return M680x0::COND_F; + case M680x0::COND_F: + return M680x0::COND_T; + case M680x0::COND_HI: + return M680x0::COND_LS; + case M680x0::COND_LS: + return M680x0::COND_HI; + case M680x0::COND_CC: + return M680x0::COND_CS; + case M680x0::COND_CS: + return M680x0::COND_CC; + case M680x0::COND_NE: + return M680x0::COND_EQ; + case M680x0::COND_EQ: + return M680x0::COND_NE; + case M680x0::COND_VC: + return M680x0::COND_VS; + case M680x0::COND_VS: + return M680x0::COND_VC; + case M680x0::COND_PL: + return M680x0::COND_MI; + case M680x0::COND_MI: + return M680x0::COND_PL; + case M680x0::COND_GE: + return M680x0::COND_LT; + case M680x0::COND_LT: + return M680x0::COND_GE; + case M680x0::COND_GT: + return M680x0::COND_LE; + case M680x0::COND_LE: + return M680x0::COND_GT; + } +} + +static inline unsigned GetCondBranchFromCond(M680x0::CondCode CC) { + switch (CC) { + default: + llvm_unreachable("Illegal condition code!"); + case M680x0::COND_EQ: + return M680x0::Beq8; + case M680x0::COND_NE: + return M680x0::Bne8; + case M680x0::COND_LT: + return M680x0::Blt8; + case M680x0::COND_LE: + return M680x0::Ble8; + case M680x0::COND_GT: + return M680x0::Bgt8; + case M680x0::COND_GE: + return M680x0::Bge8; + case M680x0::COND_CS: + return M680x0::Bcs8; + case M680x0::COND_LS: + return M680x0::Bls8; + case M680x0::COND_HI: + return M680x0::Bhi8; + case M680x0::COND_CC: + return M680x0::Bcc8; + case M680x0::COND_MI: + return M680x0::Bmi8; + case M680x0::COND_PL: + return M680x0::Bpl8; + case M680x0::COND_VS: + return M680x0::Bvs8; + case M680x0::COND_VC: + return M680x0::Bvc8; + } +} + +static inline M680x0::CondCode GetCondFromBranchOpc(unsigned Opcode) { + switch (Opcode) { + default: + return M680x0::COND_INVALID; + case M680x0::Beq8: + return M680x0::COND_EQ; + case M680x0::Bne8: + return M680x0::COND_NE; + case M680x0::Blt8: + return M680x0::COND_LT; + case M680x0::Ble8: + return M680x0::COND_LE; + case M680x0::Bgt8: + return M680x0::COND_GT; + case M680x0::Bge8: + return M680x0::COND_GE; + case M680x0::Bcs8: + return M680x0::COND_CS; + case M680x0::Bls8: + return M680x0::COND_LS; + case M680x0::Bhi8: + return M680x0::COND_HI; + case M680x0::Bcc8: + return M680x0::COND_CC; + case M680x0::Bmi8: + return M680x0::COND_MI; + case M680x0::Bpl8: + return M680x0::COND_PL; + case M680x0::Bvs8: + return M680x0::COND_VS; + case M680x0::Bvc8: + return M680x0::COND_VC; + } +} + +static inline unsigned IsCMP(unsigned Op) { + switch (Op) { + default: + return false; + case M680x0::CMP8dd: + case M680x0::CMP8df: + case M680x0::CMP8di: + case M680x0::CMP8dj: + case M680x0::CMP8dp: + case M680x0::CMP16dd: + case M680x0::CMP16df: + case M680x0::CMP16di: + case M680x0::CMP16dj: + case M680x0::CMP16dp: + return true; + } +} + +static inline bool IsSETCC(unsigned SETCC) { + switch (SETCC) { + default: + return false; + case M680x0::SETd8eq: + case M680x0::SETd8ne: + case M680x0::SETd8lt: + case M680x0::SETd8ge: + case M680x0::SETd8le: + case M680x0::SETd8gt: + case M680x0::SETd8cs: + case M680x0::SETd8cc: + case M680x0::SETd8ls: + case M680x0::SETd8hi: + case M680x0::SETd8pl: + case M680x0::SETd8mi: + case M680x0::SETd8vc: + case M680x0::SETd8vs: + case M680x0::SETj8eq: + case M680x0::SETj8ne: + case M680x0::SETj8lt: + case M680x0::SETj8ge: + case M680x0::SETj8le: + case M680x0::SETj8gt: + case M680x0::SETj8cs: + case M680x0::SETj8cc: + case M680x0::SETj8ls: + case M680x0::SETj8hi: + case M680x0::SETj8pl: + case M680x0::SETj8mi: + case M680x0::SETj8vc: + case M680x0::SETj8vs: + case M680x0::SETp8eq: + case M680x0::SETp8ne: + case M680x0::SETp8lt: + case M680x0::SETp8ge: + case M680x0::SETp8le: + case M680x0::SETp8gt: + case M680x0::SETp8cs: + case M680x0::SETp8cc: + case M680x0::SETp8ls: + case M680x0::SETp8hi: + case M680x0::SETp8pl: + case M680x0::SETp8mi: + case M680x0::SETp8vc: + case M680x0::SETp8vs: + return true; + } +} + +} // namespace M680x0 + +class M680x0InstrInfo : public M680x0GenInstrInfo { + virtual void anchor(); + +protected: + const M680x0Subtarget &Subtarget; + const M680x0RegisterInfo RI; + +public: + explicit M680x0InstrInfo(const M680x0Subtarget &STI); + + static const M680x0InstrInfo *create(M680x0Subtarget &STI); + + /// TargetInstrInfo is a superset of MRegister info. As such, whenever a + /// client has an instance of instruction info, it should always be able to + /// get register info as well (through this method). + const M680x0RegisterInfo &getRegisterInfo() const { return RI; }; + + bool analyzeBranch(MachineBasicBlock &MBB, MachineBasicBlock *&TBB, + MachineBasicBlock *&FBB, + SmallVectorImpl &Cond, + bool AllowModify) const override; + + bool AnalyzeBranchImpl(MachineBasicBlock &MBB, MachineBasicBlock *&TBB, + MachineBasicBlock *&FBB, + SmallVectorImpl &Cond, + bool AllowModify) const; + + unsigned removeBranch(MachineBasicBlock &MBB, + int *BytesRemoved = nullptr) const override; + + unsigned insertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB, + MachineBasicBlock *FBB, ArrayRef Cond, + const DebugLoc &DL, + int *BytesAdded = nullptr) const override; + + void copyPhysReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI, + const DebugLoc &DL, MCRegister DestReg, MCRegister SrcReg, + bool KillSrc) const override; + + bool getStackSlotRange(const TargetRegisterClass *RC, unsigned SubIdx, + unsigned &Size, unsigned &Offset, + const MachineFunction &MF) const override; + + void storeRegToStackSlot(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, Register SrcReg, + bool isKill, int FrameIndex, + const TargetRegisterClass *RC, + const TargetRegisterInfo *TRI) const override; + + void loadRegFromStackSlot(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, Register DestReg, + int FrameIndex, const TargetRegisterClass *RC, + const TargetRegisterInfo *TRI) const override; + + bool expandPostRAPseudo(MachineInstr &MI) const override; + + /// Add appropriate SExt nodes + void AddSExt(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, + DebugLoc DL, unsigned Reg, MVT From, MVT To) const; + + /// Add appropriate ZExt nodes + void AddZExt(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, + DebugLoc DL, unsigned Reg, MVT From, MVT To) const; + + /// Move across register classes without extension + bool ExpandMOVX_RR(MachineInstrBuilder &MIB, MVT MVTDst, MVT MVTSrc) const; + + /// Move from register and extend + bool ExpandMOVSZX_RR(MachineInstrBuilder &MIB, bool isSigned, MVT MVTDst, + MVT MVTSrc) const; + + /// Move from memory and extend + bool ExpandMOVSZX_RM(MachineInstrBuilder &MIB, bool isSigned, + const MCInstrDesc &Desc, MVT MVTDst, MVT MVTSrc) const; + + /// Push/Pop to/from stack + bool ExpandPUSH_POP(MachineInstrBuilder &MIB, const MCInstrDesc &Desc, + bool isPush) const; + + /// Moves to/from CCR + bool ExpandCCR(MachineInstrBuilder &MIB, bool isToCCR) const; + + /// Expand all MOVEM pseudos into real MOVEMs + bool ExpandMOVEM(MachineInstrBuilder &MIB, const MCInstrDesc &Desc, + bool isRM) const; + + /// Return a virtual register initialized with the the global base register + /// value. Output instructions required to initialize the register in the + /// function entry block, if necessary. + unsigned getGlobalBaseReg(MachineFunction *MF) const; + + std::pair + decomposeMachineOperandsTargetFlags(unsigned TF) const override; + + ArrayRef> + getSerializableDirectMachineOperandTargetFlags() const override; +}; + +} // namespace llvm + +#endif Index: llvm/lib/Target/M680x0/M680x0InstrInfo.cpp =================================================================== --- /dev/null +++ llvm/lib/Target/M680x0/M680x0InstrInfo.cpp @@ -0,0 +1,853 @@ +//===-- M680x0InstrInfo.cpp - M680x0 Instruction Information ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file contains the M680x0 declaration of the TargetInstrInfo class. +/// +//===----------------------------------------------------------------------===// + +#include "M680x0InstrInfo.h" + +#include "M680x0InstrBuilder.h" +#include "M680x0MachineFunction.h" +#include "M680x0TargetMachine.h" + +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/ScopeExit.h" +#include "llvm/CodeGen/LivePhysRegs.h" +#include "llvm/CodeGen/LiveVariables.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/TargetRegistry.h" + +#include + +using namespace llvm; + +#define DEBUG_TYPE "M680x0-instr-info" + +#define GET_INSTRINFO_CTOR_DTOR +#include "M680x0GenInstrInfo.inc" + +// Pin the vtable to this file. +void M680x0InstrInfo::anchor() {} + +M680x0InstrInfo::M680x0InstrInfo(const M680x0Subtarget &STI) + : M680x0GenInstrInfo(M680x0::ADJCALLSTACKDOWN, M680x0::ADJCALLSTACKUP, 0, + M680x0::RET), + Subtarget(STI), RI(STI) {} + +static M680x0::CondCode getCondFromBranchOpc(unsigned BrOpc) { + switch (BrOpc) { + default: + return M680x0::COND_INVALID; + case M680x0::Beq8: + return M680x0::COND_EQ; + case M680x0::Bne8: + return M680x0::COND_NE; + case M680x0::Blt8: + return M680x0::COND_LT; + case M680x0::Ble8: + return M680x0::COND_LE; + case M680x0::Bgt8: + return M680x0::COND_GT; + case M680x0::Bge8: + return M680x0::COND_GE; + case M680x0::Bcs8: + return M680x0::COND_CS; + case M680x0::Bls8: + return M680x0::COND_LS; + case M680x0::Bhi8: + return M680x0::COND_HI; + case M680x0::Bcc8: + return M680x0::COND_CC; + case M680x0::Bmi8: + return M680x0::COND_MI; + case M680x0::Bpl8: + return M680x0::COND_PL; + case M680x0::Bvs8: + return M680x0::COND_VS; + case M680x0::Bvc8: + return M680x0::COND_VC; + } +} + +bool M680x0InstrInfo::AnalyzeBranchImpl(MachineBasicBlock &MBB, + MachineBasicBlock *&TBB, + MachineBasicBlock *&FBB, + SmallVectorImpl &Cond, + bool AllowModify) const { + + auto UncondBranch = + std::pair{ + MBB.rend(), nullptr}; + + // Erase any instructions if allowed at the end of the scope. + std::vector> EraseList; + auto FinalizeOnReturn = llvm::make_scope_exit([&EraseList] { + std::for_each(EraseList.begin(), EraseList.end(), + [](decltype(EraseList)::value_type &ref) { + ref.get().eraseFromParent(); + }); + }); + + // Start from the bottom of the block and work up, examining the + // terminator instructions. + for (auto iter = MBB.rbegin(); iter != MBB.rend(); iter = std::next(iter)) { + + auto Opcode = iter->getOpcode(); + + if (iter->isDebugInstr()) { + continue; + } + + // Working from the bottom, when we see a non-terminator instruction, we're + // done. + if (!isUnpredicatedTerminator(*iter)) { + break; + } + + // A terminator that isn't a branch can't easily be handled by this + // analysis. + if (!iter->isBranch()) { + return true; + } + + // Handle unconditional branches. + if (Opcode == M680x0::BRA8 || Opcode == M680x0::BRA16) { + UncondBranch = {iter, iter->getOperand(0).getMBB()}; + + // TBB is used to indicate the unconditional destination. + TBB = UncondBranch.second; + + if (!AllowModify) { + continue; + } + + // If the block has any instructions after a JMP, erase them. + EraseList.insert(EraseList.begin(), MBB.rbegin(), iter); + + Cond.clear(); + FBB = nullptr; + + // Erase the JMP if it's equivalent to a fall-through. + if (MBB.isLayoutSuccessor(UncondBranch.second)) { + TBB = nullptr; + EraseList.push_back(*iter); + UncondBranch = {MBB.rend(), nullptr}; + } + + continue; + } + + // Handle conditional branches. + auto BranchCode = M680x0::GetCondFromBranchOpc(Opcode); + + // Can't handle indirect branch. + if (BranchCode == M680x0::COND_INVALID) { + return true; + } + + // In practice we should never have an undef CCR operand, if we do + // abort here as we are not prepared to preserve the flag. + // ??? Is this required? + // if (iter->getOperand(1).isUndef()) + // return true; + + // Working from the bottom, handle the first conditional branch. + if (Cond.empty()) { + MachineBasicBlock *CondBranchTarget = iter->getOperand(0).getMBB(); + + // If we see something like this: + // + // bcc l1 + // bra l2 + // ... + // l1: + // ... + // l2: + if (UncondBranch.first != MBB.rend()) { + + assert(std::next(UncondBranch.first) == iter && "Wrong block layout."); + + // And we are allowed to modify the block and the target block of the + // conditional branch is the direct successor of this block: + // + // bcc l1 + // bra l2 + // l1: + // ... + // l2: + // + // we change it to this if allowed: + // + // bncc l2 + // l1: + // ... + // l2: + // + // Which is a bit more efficient. + if (AllowModify && MBB.isLayoutSuccessor(CondBranchTarget)) { + + BranchCode = GetOppositeBranchCondition(BranchCode); + unsigned BNCC = GetCondBranchFromCond(BranchCode); + + BuildMI(MBB, *UncondBranch.first, MBB.rfindDebugLoc(iter), get(BNCC)) + .addMBB(UncondBranch.second); + + EraseList.push_back(*iter); + EraseList.push_back(*UncondBranch.first); + + TBB = UncondBranch.second; + FBB = nullptr; + Cond.push_back(MachineOperand::CreateImm(BranchCode)); + + // Otherwise preserve TBB, FBB and Cond as requested + } else { + TBB = CondBranchTarget; + FBB = UncondBranch.second; + Cond.push_back(MachineOperand::CreateImm(BranchCode)); + } + + UncondBranch = {MBB.rend(), nullptr}; + continue; + } + + TBB = CondBranchTarget; + FBB = nullptr; + Cond.push_back(MachineOperand::CreateImm(BranchCode)); + + continue; + } + + // Handle subsequent conditional branches. Only handle the case where all + // conditional branches branch to the same destination and their condition + // opcodes fit one of the special multi-branch idioms. + assert(Cond.size() == 1); + assert(TBB); + + // If the conditions are the same, we can leave them alone. + auto OldBranchCode = static_cast(Cond[0].getImm()); + auto NewTBB = iter->getOperand(0).getMBB(); + if (OldBranchCode == BranchCode && TBB == NewTBB) { + continue; + } + + // If they differ we cannot do much here. + return true; + } + + return false; +} + +bool M680x0InstrInfo::analyzeBranch(MachineBasicBlock &MBB, + MachineBasicBlock *&TBB, + MachineBasicBlock *&FBB, + SmallVectorImpl &Cond, + bool AllowModify) const { + // FIXME: This implementation is super buggy, disable for now + //return AnalyzeBranchImpl(MBB, TBB, FBB, Cond, AllowModify); + return true; +} + +unsigned M680x0InstrInfo::removeBranch(MachineBasicBlock &MBB, + int *BytesRemoved) const { + assert(!BytesRemoved && "code size not handled"); + + MachineBasicBlock::iterator I = MBB.end(); + unsigned Count = 0; + + while (I != MBB.begin()) { + --I; + if (I->isDebugValue()) + continue; + if (I->getOpcode() != M680x0::BRA8 && + getCondFromBranchOpc(I->getOpcode()) == M680x0::COND_INVALID) + break; + // Remove the branch. + I->eraseFromParent(); + I = MBB.end(); + ++Count; + } + + return Count; +} + +unsigned M680x0InstrInfo::insertBranch( + MachineBasicBlock &MBB, MachineBasicBlock *TBB, MachineBasicBlock *FBB, + ArrayRef Cond, const DebugLoc &DL, int *BytesAdded) const { + // Shouldn't be a fall through. + assert(TBB && "InsertBranch must not be told to insert a fallthrough"); + assert((Cond.size() == 1 || Cond.size() == 0) && + "M680x0 branch conditions have one component!"); + assert(!BytesAdded && "code size not handled"); + + if (Cond.empty()) { + // Unconditional branch? + assert(!FBB && "Unconditional branch with multiple successors!"); + BuildMI(&MBB, DL, get(M680x0::BRA8)).addMBB(TBB); + return 1; + } + + // If FBB is null, it is implied to be a fall-through block. + bool FallThru = FBB == nullptr; + + // Conditional branch. + unsigned Count = 0; + M680x0::CondCode CC = (M680x0::CondCode)Cond[0].getImm(); + unsigned Opc = GetCondBranchFromCond(CC); + BuildMI(&MBB, DL, get(Opc)).addMBB(TBB); + ++Count; + if (!FallThru) { + // Two-way Conditional branch. Insert the second branch. + BuildMI(&MBB, DL, get(M680x0::BRA8)).addMBB(FBB); + ++Count; + } + return Count; +} + +void M680x0InstrInfo::AddSExt(MachineBasicBlock &MBB, + MachineBasicBlock::iterator I, DebugLoc DL, + unsigned Reg, MVT From, MVT To) const { + if (From == MVT::i8) { + unsigned R = Reg; + // EXT16 requires i16 register + if (To == MVT::i32) { + R = RI.getSubReg(Reg, M680x0::MxSubRegIndex16Lo); + assert(R && "No viable SUB register available"); + } + BuildMI(MBB, I, DL, get(M680x0::EXT16), R).addReg(R); + } + + if (To == MVT::i32) { + BuildMI(MBB, I, DL, get(M680x0::EXT32), Reg).addReg(Reg); + } +} + +void M680x0InstrInfo::AddZExt(MachineBasicBlock &MBB, + MachineBasicBlock::iterator I, DebugLoc DL, + unsigned Reg, MVT From, MVT To) const { + + unsigned Mask, And; + if (From == MVT::i8) { + Mask = 0xFF; + } else { + Mask = 0xFFFF; + } + + if (To == MVT::i16) { + And = M680x0::AND16di; + } else { // i32 + And = M680x0::AND32di; + } + + // TODO #46 use xor r,r to decrease size + BuildMI(MBB, I, DL, get(And), Reg).addReg(Reg).addImm(Mask); +} + +bool M680x0InstrInfo::ExpandMOVX_RR(MachineInstrBuilder &MIB, MVT MVTDst, + MVT MVTSrc) const { + unsigned SubIdx; + + unsigned Move = MVTDst == MVT::i16 ? M680x0::MOV16rr : M680x0::MOV32rr; + + if (MVTSrc == MVT::i8) { + SubIdx = M680x0::MxSubRegIndex8Lo; + } else { // i16 + SubIdx = M680x0::MxSubRegIndex16Lo; + } + + unsigned Dst = MIB->getOperand(0).getReg(); + unsigned Src = MIB->getOperand(1).getReg(); + + assert(Dst != Src && "You cannot use the same Regs with MOVX_RR"); + + auto TRI = getRegisterInfo(); + + auto RCDst = TRI.getMaximalPhysRegClass(Dst, MVTDst); + auto RCSrc = TRI.getMaximalPhysRegClass(Src, MVTSrc); + + assert(RCDst && RCSrc && "Wrong use of MOVX_RR"); + assert(RCDst != RCSrc && "You cannot use the same Reg Classes with MOVX_RR"); + + // We need to find the super source register that matches the size of Dst + unsigned SSrc = RI.getMatchingMegaReg(Src, RCDst); + assert(SSrc && "No viable MEGA register available"); + + DebugLoc DL = MIB->getDebugLoc(); + + // If it happens to that super source register is the destination register + // we do nothing + if (Dst == SSrc) { + LLVM_DEBUG(dbgs() << "Remove " << *MIB.getInstr() << '\n'); + MIB->eraseFromParent(); + } else { // otherwise we need to MOV + LLVM_DEBUG(dbgs() << "Expand " << *MIB.getInstr() << " to MOV\n"); + MIB->setDesc(get(Move)); + MIB->getOperand(1).setReg(SSrc); + } + + return true; +} + +/// Expand SExt MOVE pseudos into a MOV and a EXT if the operands are two +/// different registers or just EXT if it is the same register +bool M680x0InstrInfo::ExpandMOVSZX_RR(MachineInstrBuilder &MIB, bool isSigned, + MVT MVTDst, MVT MVTSrc) const { + LLVM_DEBUG(dbgs() << "Expand " << *MIB.getInstr() << " to "); + + unsigned Move; + + if (MVTDst == MVT::i16) { + Move = M680x0::MOV16rr; + } else { // i32 + Move = M680x0::MOV32rr; + } + + unsigned Dst = MIB->getOperand(0).getReg(); + unsigned Src = MIB->getOperand(1).getReg(); + + assert(Dst != Src && "You cannot use the same Regs with MOVSX_RR"); + + auto TRI = getRegisterInfo(); + + auto RCDst = TRI.getMaximalPhysRegClass(Dst, MVTDst); + auto RCSrc = TRI.getMaximalPhysRegClass(Src, MVTSrc); + + assert(RCDst && RCSrc && "Wrong use of MOVSX_RR"); + assert(RCDst != RCSrc && "You cannot use the same Reg Classes with MOVSX_RR"); + + // We need to find the super source register that matches the size of Dst + unsigned SSrc = RI.getMatchingMegaReg(Src, RCDst); + assert(SSrc && "No viable MEGA register available"); + + MachineBasicBlock &MBB = *MIB->getParent(); + DebugLoc DL = MIB->getDebugLoc(); + + if (Dst != SSrc) { + LLVM_DEBUG(dbgs() << "Move and " << '\n'); + BuildMI(MBB, MIB.getInstr(), DL, get(Move), Dst).addReg(SSrc); + } + + if (isSigned) { + LLVM_DEBUG(dbgs() << "Sign Extend" << '\n'); + AddSExt(MBB, MIB.getInstr(), DL, Dst, MVTSrc, MVTDst); + } else { + LLVM_DEBUG(dbgs() << "Zero Extend" << '\n'); + AddZExt(MBB, MIB.getInstr(), DL, Dst, MVTSrc, MVTDst); + } + + MIB->eraseFromParent(); + + return true; +} + +bool M680x0InstrInfo::ExpandMOVSZX_RM(MachineInstrBuilder &MIB, bool isSigned, + const MCInstrDesc &Desc, MVT MVTDst, + MVT MVTSrc) const { + LLVM_DEBUG(dbgs() << "Expand " << *MIB.getInstr() << " to LOAD and "); + + unsigned Dst = MIB->getOperand(0).getReg(); + + // We need the subreg of Dst to make instruction verifier happy because the + // real machine instruction consumes and produces values of the same size and + // the registers the will be used here fall into different classes and this + // makes IV cry. We could of course use bigger operation but this will put + // some pressure on cache and memory so no. + unsigned SubDst = + RI.getSubReg(Dst, MVTSrc == MVT::i8 ? M680x0::MxSubRegIndex8Lo + : M680x0::MxSubRegIndex16Lo); + assert(SubDst && "No viable SUB register available"); + + // Make this a plain move + MIB->setDesc(Desc); + MIB->getOperand(0).setReg(SubDst); + + MachineBasicBlock::iterator I = MIB.getInstr(); + I++; + MachineBasicBlock &MBB = *MIB->getParent(); + DebugLoc DL = MIB->getDebugLoc(); + + if (isSigned) { + LLVM_DEBUG(dbgs() << "Sign Extend" << '\n'); + AddSExt(MBB, I, DL, Dst, MVTSrc, MVTDst); + } else { + LLVM_DEBUG(dbgs() << "Zero Extend" << '\n'); + AddZExt(MBB, I, DL, Dst, MVTSrc, MVTDst); + } + + return true; +} + +bool M680x0InstrInfo::ExpandPUSH_POP(MachineInstrBuilder &MIB, + const MCInstrDesc &Desc, + bool isPush) const { + MachineBasicBlock::iterator I = MIB.getInstr(); + I++; + MachineBasicBlock &MBB = *MIB->getParent(); + MachineOperand MO = MIB->getOperand(0); + DebugLoc DL = MIB->getDebugLoc(); + if (isPush) { + BuildMI(MBB, I, DL, Desc).addReg(RI.getStackRegister()).add(MO); + } else { + BuildMI(MBB, I, DL, Desc, MO.getReg()).addReg(RI.getStackRegister()); + } + MIB->eraseFromParent(); + return true; +} + +bool M680x0InstrInfo::ExpandCCR(MachineInstrBuilder &MIB, bool isToCCR) const { + + // Replace the pseudo instruction with the real one + if (isToCCR) { + MIB->setDesc(get(M680x0::MOV16cd)); + } else { + // FIXME #24 M68010 or better is required + MIB->setDesc(get(M680x0::MOV16dc)); + } + + // Promote used register to the next class + auto &Opd = MIB->getOperand(1); + Opd.setReg(getRegisterInfo().getMatchingSuperReg( + Opd.getReg(), M680x0::MxSubRegIndex8Lo, &M680x0::DR16RegClass)); + + return true; +} + +bool M680x0InstrInfo::ExpandMOVEM(MachineInstrBuilder &MIB, + const MCInstrDesc &Desc, bool isRM) const { + int Reg = 0, Offset = 0, Base = 0; + auto XR32 = RI.getRegClass(M680x0::XR32RegClassID); + auto DL = MIB->getDebugLoc(); + auto MI = MIB.getInstr(); + auto &MBB = *MIB->getParent(); + + if (isRM) { + Reg = MIB->getOperand(0).getReg(); + Offset = MIB->getOperand(1).getImm(); + Base = MIB->getOperand(2).getReg(); + } else { + Offset = MIB->getOperand(0).getImm(); + Base = MIB->getOperand(1).getReg(); + Reg = MIB->getOperand(2).getReg(); + } + + // If the register is not in XR32 then it is smaller than 32 bit, we + // implicitly promote it to 32 + if (!XR32->contains(Reg)) { + Reg = RI.getMatchingMegaReg(Reg, XR32); + assert(Reg && "Has not meaningful MEGA register"); + } + + unsigned Mask = 1 << RI.getSpillRegisterOrder(Reg); + if (isRM) { + BuildMI(MBB, MI, DL, Desc) + .addImm(Mask) + .addImm(Offset) + .addReg(Base) + .addReg(Reg, RegState::ImplicitDefine) + .copyImplicitOps(*MIB); + } else { + BuildMI(MBB, MI, DL, Desc) + .addImm(Offset) + .addReg(Base) + .addImm(Mask) + .addReg(Reg, RegState::Implicit) + .copyImplicitOps(*MIB); + } + + MIB->eraseFromParent(); + + return true; +} + +/// Expand a single-def pseudo instruction to a two-addr +/// instruction with two undef reads of the register being defined. +/// This is used for mapping: +/// %d0 = SETCS_C32d +/// to: +/// %d0 = SUBX32dd %d0, %d0 +/// +static bool Expand2AddrUndef(MachineInstrBuilder &MIB, + const MCInstrDesc &Desc) { + assert(Desc.getNumOperands() == 3 && "Expected two-addr instruction."); + unsigned Reg = MIB->getOperand(0).getReg(); + MIB->setDesc(Desc); + + // MachineInstr::addOperand() will insert explicit operands before any + // implicit operands. + MIB.addReg(Reg, RegState::Undef).addReg(Reg, RegState::Undef); + // But we don't trust that. + assert(MIB->getOperand(1).getReg() == Reg && + MIB->getOperand(2).getReg() == Reg && "Misplaced operand"); + return true; +} + +bool M680x0InstrInfo::expandPostRAPseudo(MachineInstr &MI) const { + MachineInstrBuilder MIB(*MI.getParent()->getParent(), MI); + switch (MI.getOpcode()) { + case M680x0::PUSH8d: + return ExpandPUSH_POP(MIB, get(M680x0::MOV8ed), true); + case M680x0::PUSH16d: + return ExpandPUSH_POP(MIB, get(M680x0::MOV16er), true); + case M680x0::PUSH32r: + return ExpandPUSH_POP(MIB, get(M680x0::MOV32er), true); + + case M680x0::POP8d: + return ExpandPUSH_POP(MIB, get(M680x0::MOV8do), false); + case M680x0::POP16d: + return ExpandPUSH_POP(MIB, get(M680x0::MOV16ro), false); + case M680x0::POP32r: + return ExpandPUSH_POP(MIB, get(M680x0::MOV32ro), false); + + case M680x0::SETCS_C8d: + return Expand2AddrUndef(MIB, get(M680x0::SUBX8dd)); + case M680x0::SETCS_C16d: + return Expand2AddrUndef(MIB, get(M680x0::SUBX16dd)); + case M680x0::SETCS_C32d: + return Expand2AddrUndef(MIB, get(M680x0::SUBX32dd)); + } + return false; +} + +void M680x0InstrInfo::copyPhysReg(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, + const DebugLoc &DL, MCRegister DstReg, + MCRegister SrcReg, bool KillSrc) const { + unsigned Opc = 0; + + // First deal with the normal symmetric copies. + if (M680x0::XR32RegClass.contains(DstReg, SrcReg)) + Opc = M680x0::MOV32rr; + else if (M680x0::XR16RegClass.contains(DstReg, SrcReg)) + Opc = M680x0::MOV16rr; + else if (M680x0::DR8RegClass.contains(DstReg, SrcReg)) { + Opc = M680x0::MOV8dd; + } + + if (Opc) { + BuildMI(MBB, MI, DL, get(Opc), DstReg) + .addReg(SrcReg, getKillRegState(KillSrc)); + return; + } + + // Now deal with asymmetrically sized copies. The cases that follow are upcast + // moves. + // + // NOTE + // These moves are not aware of type nature of these values and thus + // won't do any SExt or ZExt and upper bits will basically contain garbage. + MachineInstrBuilder MIB(*MBB.getParent(), MI); + if (M680x0::DR8RegClass.contains(SrcReg)) { + if (M680x0::XR16RegClass.contains(DstReg)) { + Opc = M680x0::MOVXd16d8; + } else if (M680x0::XR32RegClass.contains(DstReg)) { + Opc = M680x0::MOVXd32d8; + } + } else if (M680x0::XR16RegClass.contains(SrcReg)) { + if (M680x0::XR32RegClass.contains(DstReg)) { + Opc = M680x0::MOVXd32d16; + } + } + + if (Opc) { + BuildMI(MBB, MI, DL, get(Opc), DstReg) + .addReg(SrcReg, getKillRegState(KillSrc)); + return; + } + + bool FromCCR = SrcReg == M680x0::CCR; + bool FromSR = SrcReg == M680x0::SR; + bool ToCCR = DstReg == M680x0::CCR; + bool ToSR = DstReg == M680x0::SR; + + if (FromCCR) { + assert(M680x0::DR8RegClass.contains(DstReg) && + "Need DR8 register to copy CCR"); + Opc = M680x0::MOV8dc; + } else if (ToCCR) { + assert(M680x0::DR8RegClass.contains(SrcReg) && + "Need DR8 register to copy CCR"); + Opc = M680x0::MOV8cd; + } else if (FromSR || ToSR) { + llvm_unreachable("Cannot emit SR copy instruction"); + } + + if (Opc) { + BuildMI(MBB, MI, DL, get(Opc), DstReg) + .addReg(SrcReg, getKillRegState(KillSrc)); + return; + } + + LLVM_DEBUG(dbgs() << "Cannot copy " << RI.getName(SrcReg) << " to " + << RI.getName(DstReg) << '\n'); + llvm_unreachable("Cannot emit physreg copy instruction"); +} + +namespace { +unsigned getLoadStoreRegOpcode(unsigned Reg, const TargetRegisterClass *RC, + const TargetRegisterInfo *TRI, + const M680x0Subtarget &STI, bool load) { + switch (TRI->getRegSizeInBits(*RC)) { + default: + llvm_unreachable("Unknown spill size"); + case 8: + if (M680x0::DR8RegClass.hasSubClassEq(RC)) { + return load ? M680x0::MOVM8mp_P : M680x0::MOVM8pm_P; + } else if (M680x0::CCRCRegClass.hasSubClassEq(RC)) { + return load ? M680x0::MOV16cp : M680x0::MOV16pc; + } + llvm_unreachable("Unknown 1-byte regclass"); + case 16: + assert(M680x0::XR16RegClass.hasSubClassEq(RC) && "Unknown 2-byte regclass"); + return load ? M680x0::MOVM16mp_P : M680x0::MOVM16pm_P; + case 32: + assert(M680x0::XR32RegClass.hasSubClassEq(RC) && "Unknown 4-byte regclass"); + return load ? M680x0::MOVM32mp_P : M680x0::MOVM32pm_P; + } +} + +unsigned getStoreRegOpcode(unsigned SrcReg, const TargetRegisterClass *RC, + const TargetRegisterInfo *TRI, + const M680x0Subtarget &STI) { + return getLoadStoreRegOpcode(SrcReg, RC, TRI, STI, false); +} + +unsigned getLoadRegOpcode(unsigned DstReg, const TargetRegisterClass *RC, + const TargetRegisterInfo *TRI, + const M680x0Subtarget &STI) { + return getLoadStoreRegOpcode(DstReg, RC, TRI, STI, true); +} +} // end anonymous namespace + +bool M680x0InstrInfo::getStackSlotRange(const TargetRegisterClass *RC, + unsigned SubIdx, unsigned &Size, + unsigned &Offset, + const MachineFunction &MF) const { + // The slot size must be the maximum size so we can easily use MOVEM.L + Size = 4; + Offset = 0; + return true; +} + +void M680x0InstrInfo::storeRegToStackSlot(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, + Register SrcReg, bool isKill, + int FrameIndex, + const TargetRegisterClass *RC, + const TargetRegisterInfo *TRI) const { + const MachineFunction &MF = *MBB.getParent(); + assert(MF.getFrameInfo().getObjectSize(FrameIndex) == 4 && + "Stack slot too small for store"); + unsigned Opc = getStoreRegOpcode(SrcReg, RC, TRI, Subtarget); + DebugLoc DL = MBB.findDebugLoc(MI); + // (0,FrameIndex) <- $reg + addFrameReference(BuildMI(MBB, MI, DL, get(Opc)), FrameIndex) + .addReg(SrcReg, getKillRegState(isKill)); +} + +void M680x0InstrInfo::loadRegFromStackSlot( + MachineBasicBlock &MBB, MachineBasicBlock::iterator MI, Register DstReg, + int FrameIndex, const TargetRegisterClass *RC, + const TargetRegisterInfo *TRI) const { + const MachineFunction &MF = *MBB.getParent(); + assert(MF.getFrameInfo().getObjectSize(FrameIndex) == 4 && + "Stack slot too small for store"); + unsigned Opc = getLoadRegOpcode(DstReg, RC, TRI, Subtarget); + DebugLoc DL = MBB.findDebugLoc(MI); + addFrameReference(BuildMI(MBB, MI, DL, get(Opc), DstReg), FrameIndex); +} + +/// Return a virtual register initialized with the the global base register +/// value. Output instructions required to initialize the register in the +/// function entry block, if necessary. +/// +/// TODOss #47 Eliminate this and move the code to M680x0MachineFunctionInfo. +unsigned M680x0InstrInfo::getGlobalBaseReg(MachineFunction *MF) const { + M680x0MachineFunctionInfo *MxFI = MF->getInfo(); + unsigned GlobalBaseReg = MxFI->getGlobalBaseReg(); + if (GlobalBaseReg != 0) + return GlobalBaseReg; + + // Create the register. The code to initialize it is inserted later, + // by the CGBR pass (below). + // + // NOTE + // Normally M680x0 uses A5 register as global base pointer but this will + // create unnecessary spill if we use less then 4 registers in code; since A5 + // is callee-save anyway we could try to allocate caller-save first and if + // lucky get one, otherwise it does not really matter which callee-save to + // use. + MachineRegisterInfo &RegInfo = MF->getRegInfo(); + GlobalBaseReg = RegInfo.createVirtualRegister(&M680x0::AR32_NOSPRegClass); + MxFI->setGlobalBaseReg(GlobalBaseReg); + return GlobalBaseReg; +} + +std::pair +M680x0InstrInfo::decomposeMachineOperandsTargetFlags(unsigned TF) const { + return std::make_pair(TF, 0u); +} + +ArrayRef> +M680x0InstrInfo::getSerializableDirectMachineOperandTargetFlags() const { + using namespace M680x0II; + static const std::pair TargetFlags[] = { + {MO_ABSOLUTE_ADDRESS, "M680x0-absolute"}, + {MO_PC_RELATIVE_ADDRESS, "M680x0-pcrel"}, + {MO_GOT, "M680x0-got"}, + {MO_GOTOFF, "M680x0-gotoff"}, + {MO_GOTPCREL, "M680x0-gotpcrel"}, + {MO_PLT, "M680x0-plt"}}; + return makeArrayRef(TargetFlags); +} + +namespace { +/// Create Global Base Reg pass. This initializes the PIC global base register +struct CGBR : public MachineFunctionPass { + static char ID; + CGBR() : MachineFunctionPass(ID) {} + + bool runOnMachineFunction(MachineFunction &MF) override { + const M680x0Subtarget &STI = MF.getSubtarget(); + M680x0MachineFunctionInfo *MxFI = MF.getInfo(); + + unsigned GlobalBaseReg = MxFI->getGlobalBaseReg(); + + // If we didn't need a GlobalBaseReg, don't insert code. + if (GlobalBaseReg == 0) + return false; + + // Insert the set of GlobalBaseReg into the first MBB of the function + MachineBasicBlock &FirstMBB = MF.front(); + MachineBasicBlock::iterator MBBI = FirstMBB.begin(); + DebugLoc DL = FirstMBB.findDebugLoc(MBBI); + const M680x0InstrInfo *TII = STI.getInstrInfo(); + + // Generate lea (__GLOBAL_OFFSET_TABLE_,%PC), %A5 + BuildMI(FirstMBB, MBBI, DL, TII->get(M680x0::LEA32q), GlobalBaseReg) + .addExternalSymbol("_GLOBAL_OFFSET_TABLE_", M680x0II::MO_GOTPCREL); + + return true; + } + + StringRef getPassName() const override { + return "M680x0 PIC Global Base Reg Initialization"; + } + + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.setPreservesCFG(); + MachineFunctionPass::getAnalysisUsage(AU); + } +}; +} // namespace + +char CGBR::ID = 0; +FunctionPass *llvm::createM680x0GlobalBaseRegPass() { return new CGBR(); } Index: llvm/lib/Target/M680x0/M680x0InstrInfo.td =================================================================== --- /dev/null +++ llvm/lib/Target/M680x0/M680x0InstrInfo.td @@ -0,0 +1,636 @@ +//== M680x0InstrInfo.td - Main M680x0 Instruction Definition -*- tablegen -*-=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file describes the M680x0 instruction set, defining the instructions +/// and properties of the instructions which are needed for code generation, +/// machine code emission, and analysis. +/// +//===----------------------------------------------------------------------===// + +include "M680x0InstrFormats.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<"M680x0ISD::CALL", MxSDT_Call, + [SDNPHasChain, SDNPOutGlue, + SDNPOptInGlue, SDNPVariadic]>; + +def MxRet : SDNode<"M680x0ISD::RET", MxSDT_Ret, + [SDNPHasChain, SDNPOptInGlue, SDNPVariadic]>; + +def MxTCRet : SDNode<"M680x0ISD::TC_RETURN", MxSDT_TCRet, + [SDNPHasChain, SDNPOptInGlue, SDNPVariadic]>; + +def MxWrapper : SDNode<"M680x0ISD::Wrapper", MxSDT_Wrapper>; +def MxWrapperPC : SDNode<"M680x0ISD::WrapperPC", MxSDT_Wrapper>; + +def MxAdd : SDNode<"M680x0ISD::ADD", MxSDT_BiArithCCROut, [SDNPCommutative]>; +def MxSub : SDNode<"M680x0ISD::SUB", MxSDT_BiArithCCROut>; +def MxOr : SDNode<"M680x0ISD::OR", MxSDT_BiArithCCROut, [SDNPCommutative]>; +def MxXor : SDNode<"M680x0ISD::XOR", MxSDT_BiArithCCROut, [SDNPCommutative]>; +def MxAnd : SDNode<"M680x0ISD::AND", MxSDT_BiArithCCROut, [SDNPCommutative]>; + +def MxAddX : SDNode<"M680x0ISD::ADDX", MxSDT_BiArithCCRInOut>; +def MxSubX : SDNode<"M680x0ISD::SUBX", MxSDT_BiArithCCRInOut>; + +def MxSMul : SDNode<"M680x0ISD::SMUL", MxSDT_BiArithCCROut, [SDNPCommutative]>; +def MxUMul : SDNode<"M680x0ISD::UMUL", MxSDT_2BiArithCCROut, [SDNPCommutative]>; + +def MxCmp : SDNode<"M680x0ISD::CMP", MxSDT_CmpTest>; +def MxBt : SDNode<"M680x0ISD::BT", MxSDT_CmpTest>; + +def MxCmov : SDNode<"M680x0ISD::CMOV", MxSDT_Cmov>; +def MxBrCond : SDNode<"M680x0ISD::BRCOND", MxSDT_BrCond, [SDNPHasChain]>; +def MxSetCC : SDNode<"M680x0ISD::SETCC", MxSDT_SetCC>; +def MxSetCC_C : SDNode<"M680x0ISD::SETCC_CARRY", MxSDT_SetCC_C>; + + +def MxSegAlloca : SDNode<"M680x0ISD::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", + /* ParserMatchClass = M680x0AbsMemAsmOperand, */ + 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 M680x0InstrInfo.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 stricly 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 M680x0 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 #48 you 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->isVolatile(); + 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->isVolatile(); + 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 #49 make it folded like MxType8.F.Op nad MxType8.F.Pat +// TODO #49 move strings into META subclass +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 "M680x0InstrData.td" +include "M680x0InstrShiftRotate.td" +include "M680x0InstrBits.td" +include "M680x0InstrArithmetic.td" +include "M680x0InstrControl.td" + +include "M680x0InstrCompiler.td" Index: llvm/lib/Target/M680x0/M680x0InstrShiftRotate.td =================================================================== --- /dev/null +++ llvm/lib/Target/M680x0/M680x0InstrShiftRotate.td @@ -0,0 +1,86 @@ +//===------ M680x0InstrShiftRotate.td - Logical Instrs -----*- tablegen -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file describes the logical instructions in the M680x0 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>; Index: llvm/lib/Target/M680x0/M680x0MachineFunction.h =================================================================== --- /dev/null +++ llvm/lib/Target/M680x0/M680x0MachineFunction.h @@ -0,0 +1,116 @@ +//===-- M680x0MachineFunctionInfo.h - M680x0 private data ---------*- C++ -*-=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file declares the M680x0 specific subclass of MachineFunctionInfo. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_M680X0_M680X0MACHINEFUNCTION_H +#define LLVM_LIB_TARGET_M680X0_M680X0MACHINEFUNCTION_H + +#include "llvm/CodeGen/CallingConvLower.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/Support/MachineValueType.h" + +namespace llvm { + +class M680x0MachineFunctionInfo : public MachineFunctionInfo { + MachineFunction &MF; + + /// Non-zero if the function has base pointer and makes call to + /// llvm.eh.sjlj.setjmp. When non-zero, the value is a displacement from the + /// frame pointer to a slot where the base pointer is stashed. + signed char RestoreBasePointerOffset = 0; + + /// Size of the callee-saved register portion of the stack frame in bytes. + unsigned CalleeSavedFrameSize = 0; + + /// Number of bytes function pops on return (in addition to the space used by + /// the return address). Used on windows platform for stdcall & fastcall + /// name decoration + unsigned BytesToPopOnReturn = 0; + + /// FrameIndex for return slot. + int ReturnAddrIndex = 0; + + /// The number of bytes by which return address stack slot is moved as the + /// result of tail call optimization. + int TailCallReturnAddrDelta = 0; + + /// keeps track of the virtual register initialized for use as the global + /// base register. This is used for PIC in some PIC relocation models. + unsigned GlobalBaseReg = 0; + + /// FrameIndex for start of varargs area. + int VarArgsFrameIndex = 0; + + /// Keeps track of whether this function uses sequences of pushes to pass + /// function parameters. + bool HasPushSequences = false; + + /// Some subtargets require that sret lowering includes + /// returning the value of the returned struct in a register. This field + /// holds the virtual register into which the sret argument is passed. + unsigned SRetReturnReg = 0; + + /// A list of virtual and physical registers that must be forwarded to every + /// musttail call. + SmallVector ForwardedMustTailRegParms; + + /// The number of bytes on stack consumed by the arguments being passed on + /// the stack. + unsigned ArgumentStackSize = 0; + +public: + M680x0MachineFunctionInfo() = default; + explicit M680x0MachineFunctionInfo(MachineFunction &MF) : MF(MF) {} + + bool getRestoreBasePointer() const { return RestoreBasePointerOffset != 0; } + void setRestoreBasePointer(const MachineFunction *MF); + int getRestoreBasePointerOffset() const { return RestoreBasePointerOffset; } + + unsigned getCalleeSavedFrameSize() const { return CalleeSavedFrameSize; } + void setCalleeSavedFrameSize(unsigned bytes) { CalleeSavedFrameSize = bytes; } + + unsigned getBytesToPopOnReturn() const { return BytesToPopOnReturn; } + void setBytesToPopOnReturn(unsigned bytes) { BytesToPopOnReturn = bytes; } + + int getRAIndex() const { return ReturnAddrIndex; } + void setRAIndex(int Index) { ReturnAddrIndex = Index; } + + int getTCReturnAddrDelta() const { return TailCallReturnAddrDelta; } + void setTCReturnAddrDelta(int delta) { TailCallReturnAddrDelta = delta; } + + unsigned getGlobalBaseReg() const { return GlobalBaseReg; } + void setGlobalBaseReg(unsigned Reg) { GlobalBaseReg = Reg; } + + int getVarArgsFrameIndex() const { return VarArgsFrameIndex; } + void setVarArgsFrameIndex(int Index) { VarArgsFrameIndex = Index; } + + bool getHasPushSequences() const { return HasPushSequences; } + void setHasPushSequences(bool HasPush) { HasPushSequences = HasPush; } + + unsigned getSRetReturnReg() const { return SRetReturnReg; } + void setSRetReturnReg(unsigned Reg) { SRetReturnReg = Reg; } + + unsigned getArgumentStackSize() const { return ArgumentStackSize; } + void setArgumentStackSize(unsigned size) { ArgumentStackSize = size; } + + SmallVectorImpl &getForwardedMustTailRegParms() { + return ForwardedMustTailRegParms; + } + +private: + virtual void anchor(); +}; + +} // end of namespace llvm + +#endif // M680X0_MACHINE_FUNCTION_INFO_H Index: llvm/lib/Target/M680x0/M680x0MachineFunction.cpp =================================================================== --- /dev/null +++ llvm/lib/Target/M680x0/M680x0MachineFunction.cpp @@ -0,0 +1,21 @@ +//===-- M680x0MachineFunctionInfo.cpp - M680x0 private data ----*- C++ -*--===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "M680x0MachineFunction.h" + +#include "M680x0InstrInfo.h" +#include "M680x0Subtarget.h" + +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/IR/Function.h" + +using namespace llvm; + +void M680x0MachineFunctionInfo::anchor() {} Index: llvm/lib/Target/M680x0/M680x0RegisterInfo.h =================================================================== --- /dev/null +++ llvm/lib/Target/M680x0/M680x0RegisterInfo.h @@ -0,0 +1,115 @@ +//===-- M680x0RegisterInfo.h - M680x0 Register Information Impl --*- C++ --===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file contains the M680x0 implementation of the TargetRegisterInfo +/// class. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_M680X0_M680X0REGISTERINFO_H +#define LLVM_LIB_TARGET_M680X0_M680X0REGISTERINFO_H + +#include "M680x0.h" + +#include "llvm/CodeGen/TargetRegisterInfo.h" + +#define GET_REGINFO_HEADER +#include "M680x0GenRegisterInfo.inc" + +namespace llvm { +class M680x0Subtarget; +class TargetInstrInfo; +class Type; + +class M680x0RegisterInfo : public M680x0GenRegisterInfo { + virtual void anchor(); + + /// Physical register used as stack ptr. + unsigned StackPtr; + + /// Physical register used as frame ptr. + unsigned FramePtr; + + /// Physical register used as a base ptr in complex stack frames. I.e., when + /// we need a 3rd base, not just SP and FP, due to variable size stack + /// objects. + unsigned BasePtr; + + /// Physical register used to store GOT address if needed. + unsigned GlobalBasePtr; + +protected: + const M680x0Subtarget &Subtarget; + +public: + M680x0RegisterInfo(const M680x0Subtarget &Subtarget); + + const MCPhysReg *getCalleeSavedRegs(const MachineFunction *MF) const override; + + const uint32_t *getCallPreservedMask(const MachineFunction &MF, + CallingConv::ID) const override; + + /// Returns a register class with registers that can be used in forming tail + /// calls. + const TargetRegisterClass * + getRegsForTailCall(const MachineFunction &MF) const; + + /// Return a mega-register of the specified register Reg so its sub-register + /// of index SubIdx is Reg, its super(or mega) Reg. In other words it will + /// return a register that is not direct super register but still shares + /// physical register with Reg. + /// NOTE not sure about the term though. + unsigned getMatchingMegaReg(unsigned Reg, + const TargetRegisterClass *RC) const; + + /// Returns the Register Class of a physical register of the given type, + /// picking the biggest register class of the right type that contains this + /// physreg. + const TargetRegisterClass *getMaximalPhysRegClass(unsigned reg, MVT VT) const; + + /// Return index of a register within a register class, otherwise return -1 + int getRegisterOrder(unsigned Reg, const TargetRegisterClass &TRC) const; + + /// Return spill order index of a register, if there is none then trap + int getSpillRegisterOrder(unsigned Reg) const; + + BitVector getReservedRegs(const MachineFunction &MF) const override; + + bool requiresRegisterScavenging(const MachineFunction &MF) const override; + + bool trackLivenessAfterRegAlloc(const MachineFunction &MF) const override; + + /// FrameIndex represent objects inside a abstract stack. We must replace + /// FrameIndex with an stack/frame pointer direct reference. + void eliminateFrameIndex(MachineBasicBlock::iterator II, int SPAdj, + unsigned FIOperandNum, + RegScavenger *RS = nullptr) const override; + + bool hasBasePointer(const MachineFunction &MF) const; + + /// True if the stack can be realigned for the target. + bool canRealignStack(const MachineFunction &MF) const override; + + Register getFrameRegister(const MachineFunction &MF) const override; + unsigned getStackRegister() const { return StackPtr; } + unsigned getBaseRegister() const { return BasePtr; } + unsigned getGlobalBaseRegister() const { return GlobalBasePtr; } + + const TargetRegisterClass *intRegClass(unsigned Size) const; + + // FIXME #52 Actually implement any size spill and remove this override + unsigned getSpillSize(const TargetRegisterClass &RC) const override { + return 4; + } +}; + +} // end namespace llvm + +#endif Index: llvm/lib/Target/M680x0/M680x0RegisterInfo.cpp =================================================================== --- /dev/null +++ llvm/lib/Target/M680x0/M680x0RegisterInfo.cpp @@ -0,0 +1,286 @@ +//===-- M680x0RegisterInfo.cpp - CPU0 Register Information -----*- C++ -*--===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file contains the CPU0 implementation of the TargetRegisterInfo class. +/// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "m680x0-reg-info" + +#include "M680x0RegisterInfo.h" + +#include "M680x0.h" +#include "M680x0MachineFunction.h" +#include "M680x0Subtarget.h" + +#include "MCTargetDesc/M680x0MCTargetDesc.h" + +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/Type.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" + +#define GET_REGINFO_TARGET_DESC +#include "M680x0GenRegisterInfo.inc" + +using namespace llvm; + +static cl::opt EnableBasePointer( + "m680x0-use-base-pointer", cl::Hidden, cl::init(true), + cl::desc("Enable use of a base pointer for complex stack frames")); + +// Pin the vtable to this file. +void M680x0RegisterInfo::anchor() {} + +M680x0RegisterInfo::M680x0RegisterInfo(const M680x0Subtarget &ST) + // FIXME x26 not sure it this the correct value, it expects RA, but M680x0 + // passes IP anyway, how this works? + : M680x0GenRegisterInfo(M680x0::A0, + 0, 0, M680x0::PC), + Subtarget(ST) { + StackPtr = M680x0::SP; + FramePtr = M680x0::A6; + GlobalBasePtr = M680x0::A5; + BasePtr = M680x0::A4; +} + +//===----------------------------------------------------------------------===// +// Callee Saved Registers methods +//===----------------------------------------------------------------------===// + +const MCPhysReg * +M680x0RegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const { + return CSR_STD_SaveList; +} + +const uint32_t * +M680x0RegisterInfo::getCallPreservedMask(const MachineFunction &MF, + CallingConv::ID) const { + return CSR_STD_RegMask; +} + +const TargetRegisterClass * +M680x0RegisterInfo::getRegsForTailCall(const MachineFunction &MF) const { + return &M680x0::XR32_TCRegClass; +} + +unsigned +M680x0RegisterInfo::getMatchingMegaReg(unsigned Reg, + const TargetRegisterClass *RC) const { + for (MCSuperRegIterator Super(Reg, this); Super.isValid(); ++Super) + if (RC->contains(*Super)) + return *Super; + return 0; +} + +const TargetRegisterClass * +M680x0RegisterInfo::getMaximalPhysRegClass(unsigned reg, MVT VT) const { + assert(Register::isPhysicalRegister(reg) && "reg must be a physical register"); + + // Pick the most sub register class of the right type that contains + // this physreg. + const TargetRegisterClass *BestRC = nullptr; + for (regclass_iterator I = regclass_begin(), E = regclass_end(); I != E; + ++I) { + const TargetRegisterClass *RC = *I; + if ((VT == MVT::Other || isTypeLegalForClass(*RC, VT)) && + RC->contains(reg) && + (!BestRC || + (BestRC->hasSubClass(RC) && RC->getNumRegs() > BestRC->getNumRegs()))) + BestRC = RC; + } + + assert(BestRC && "Couldn't find the register class"); + return BestRC; +} + +int M680x0RegisterInfo::getRegisterOrder(unsigned Reg, + const TargetRegisterClass &TRC) const { + for (unsigned i = 0; i < TRC.getNumRegs(); ++i) { + if (regsOverlap(Reg, TRC.getRegister(i))) { + return i; + } + } + return -1; +} + +int M680x0RegisterInfo::getSpillRegisterOrder(unsigned Reg) const { + int Result = getRegisterOrder(Reg, *getRegClass(M680x0::SPILLRegClassID)); + if (Result < 0) { + llvm_unreachable("Cannot determine spill order"); + } + return Result; +} + +BitVector M680x0RegisterInfo::getReservedRegs(const MachineFunction &MF) const { + const M680x0FrameLowering *TFI = getFrameLowering(MF); + + BitVector Reserved(getNumRegs()); + + // Set a register's and its sub-registers and aliases as reserved. + auto setBitVector = [&Reserved, this](unsigned Reg) { + for (MCRegAliasIterator I(Reg, this, /* self */ true); I.isValid(); ++I) { + Reserved.set(*I); + } + for (MCSubRegIterator I(Reg, this, /* self */ true); I.isValid(); ++I) { + Reserved.set(*I); + } + }; + + setBitVector(M680x0::PC); + setBitVector(M680x0::SP); + + if (TFI->hasFP(MF)) { + setBitVector(FramePtr); + } + + // Set the base-pointer register and its aliases as reserved if needed. + if (hasBasePointer(MF)) { + CallingConv::ID CC = MF.getFunction().getCallingConv(); + const uint32_t *RegMask = getCallPreservedMask(MF, CC); + if (MachineOperand::clobbersPhysReg(RegMask, getBaseRegister())) + report_fatal_error("Stack realignment in presence of dynamic allocas is " + "not supported with" + "this calling convention."); + + setBitVector(getBaseRegister()); + } + + // // Set the global-base-pointer register and its aliases as reserved if + // needed. if (getGlobalBaseRegister()) { + // for (MCSubRegIterator I(getGlobalBaseRegister(), this, + // #<{(|Self=|)}>#true); I.isValid(); ++I) + // Reserved.set(*I); + // } + + return Reserved; +} + +void M680x0RegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, + int SPAdj, unsigned FIOperandNum, + RegScavenger *RS) const { + MachineInstr &MI = *II; + MachineFunction &MF = *MI.getParent()->getParent(); + const M680x0FrameLowering *TFI = getFrameLowering(MF); + + // We have either (i,An,Rn) or (i,An) EA form + // NOTE Base contains the FI and we need to backtrace a bit to get Disp + MachineOperand &Disp = MI.getOperand(FIOperandNum - 1); + MachineOperand &Base = MI.getOperand(FIOperandNum); + + int Imm = (int)(Disp.getImm()); + int FIndex = (int)(Base.getIndex()); + + // unsigned Opc = MI.getOpcode(); + // FIXME #7 there is no jmp from mem yet + // bool AfterFPPop = Opc == M680x0::TAILJMPm || Opc == M680x0::TCRETURNmi; + bool AfterFPPop = false; + + unsigned BasePtr; + if (hasBasePointer(MF)) + BasePtr = (FIndex < 0 ? FramePtr : getBaseRegister()); + else if (needsStackRealignment(MF)) + BasePtr = (FIndex < 0 ? FramePtr : StackPtr); + else if (AfterFPPop) + BasePtr = StackPtr; + else + BasePtr = (TFI->hasFP(MF) ? FramePtr : StackPtr); + + Base.ChangeToRegister(BasePtr, false); + + // Now add the frame object offset to the offset from FP. + int FIOffset; + Register IgnoredFrameReg; + if (AfterFPPop) { + // Tail call jmp happens after FP is popped. + const MachineFrameInfo &MFI = MF.getFrameInfo(); + FIOffset = MFI.getObjectOffset(FIndex) - TFI->getOffsetOfLocalArea(); + } else { + FIOffset = TFI->getFrameIndexReference(MF, FIndex, IgnoredFrameReg); + } + + if (BasePtr == StackPtr) + FIOffset += SPAdj; + + long long Offset = FIOffset + Imm; + // if (Size == 16) { + // assert(isInt<16>(Offset) && "Cannot use disp greater 16 bit"); + // } else if (Size == 8) { + // assert(isInt<8>(Offset) && "Cannot use disp greater 8 bit"); + // } else { + // } + Disp.ChangeToImmediate(Offset); +} + +bool M680x0RegisterInfo::requiresRegisterScavenging( + const MachineFunction &MF) const { + return true; +} + +bool M680x0RegisterInfo::trackLivenessAfterRegAlloc( + const MachineFunction &MF) const { + return true; +} + +static bool CantUseSP(const MachineFrameInfo &MFI) { + return MFI.hasVarSizedObjects() || MFI.hasOpaqueSPAdjustment(); +} + +bool M680x0RegisterInfo::hasBasePointer(const MachineFunction &MF) const { + const MachineFrameInfo &MFI = MF.getFrameInfo(); + + if (!EnableBasePointer) + return false; + + // When we need stack realignment, we can't address the stack from the frame + // pointer. When we have dynamic allocas or stack-adjusting inline asm, we + // can't address variables from the stack pointer. MS inline asm can + // reference locals while also adjusting the stack pointer. When we can't + // use both the SP and the FP, we need a separate base pointer register. + bool CantUseFP = needsStackRealignment(MF); + return CantUseFP && CantUseSP(MFI); +} + +bool M680x0RegisterInfo::canRealignStack(const MachineFunction &MF) const { + if (!TargetRegisterInfo::canRealignStack(MF)) + return false; + + const MachineFrameInfo &MFI = MF.getFrameInfo(); + const MachineRegisterInfo *MRI = &MF.getRegInfo(); + + // Stack realignment requires a frame pointer. If we already started + // register allocation with frame pointer elimination, it is too late now. + if (!MRI->canReserveReg(FramePtr)) + return false; + + // If a base pointer is necessary. Check that it isn't too late to reserve it. + if (CantUseSP(MFI)) + return MRI->canReserveReg(BasePtr); + + return true; +} + +Register M680x0RegisterInfo::getFrameRegister(const MachineFunction &MF) const { + const TargetFrameLowering *TFI = MF.getSubtarget().getFrameLowering(); + return TFI->hasFP(MF) ? FramePtr : StackPtr; +} + +const TargetRegisterClass * +M680x0RegisterInfo::intRegClass(unsigned size) const { + // if (isInt<8>(size)) { + // return &M680x0::DR8RegClass; + // } else if (isInt<16>(size)) { + // return &M680x0::DR16RegClass; + // } + return &M680x0::DR32RegClass; +} Index: llvm/lib/Target/M680x0/M680x0RegisterInfo.td =================================================================== --- /dev/null +++ llvm/lib/Target/M680x0/M680x0RegisterInfo.td @@ -0,0 +1,133 @@ +//== M680x0RegisterInfo.td - M680x0 register definitions ----*- tablegen -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file describes the M680x0 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 = "M680x0"; + let HWEncoding = ENC; + let SubRegs = SUBREGS; + let SubRegIndices = SUBIDX; +} + +// Subregister indices. +let Namespace = "M680x0" 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>; + +// TODO #50 get rid of "pseudo" registers and use just MxReg variants and use +// HWEncoding's other 13 bits to encode type(and potentially other info) of +// register. + +// 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<"M680x0", 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 #27 try order 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)))>; Index: llvm/lib/Target/M680x0/M680x0Subtarget.h =================================================================== --- /dev/null +++ llvm/lib/Target/M680x0/M680x0Subtarget.h @@ -0,0 +1,160 @@ +//===-- M680x0Subtarget.h - Define Subtarget for the M680x0 -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file declares the M680x0 specific subclass of TargetSubtargetInfo. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_CPU0_M680X0SUBTARGET_H +#define LLVM_LIB_TARGET_CPU0_M680X0SUBTARGET_H + +#include "M680x0FrameLowering.h" +#include "M680x0ISelLowering.h" +#include "M680x0InstrInfo.h" + +#include "llvm/CodeGen/SelectionDAGTargetInfo.h" +#include "llvm/CodeGen/TargetSubtargetInfo.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/MC/MCInstrItineraries.h" +#include "llvm/Support/Alignment.h" + +#include + +#define GET_SUBTARGETINFO_HEADER +#include "M680x0GenSubtargetInfo.inc" + +extern bool M680x0ReserveGP; +extern bool M680x0NoCpload; + +namespace llvm { +class StringRef; + +class M680x0TargetMachine; + +class M680x0Subtarget : public M680x0GenSubtargetInfo { + virtual void anchor(); + +protected: + // These define which ISA is supported. Since each Motorola M680x0 ISA is + // built on top of the previous one whenever an ISA is selected the previous + // selected as well. + bool IsM68000 = false; + bool IsM68010 = false; + bool IsM68020 = false; + bool IsM68030 = false; + bool IsM68040 = false; + + InstrItineraryData InstrItins; + + /// Small section is used. + bool UseSmallSection = true; + + const M680x0TargetMachine &TM; + + SelectionDAGTargetInfo TSInfo; + M680x0InstrInfo InstrInfo; + M680x0FrameLowering FrameLowering; + M680x0TargetLowering TLInfo; + + /// The minimum alignment known to hold of the stack frame on + /// entry to the function and which must be maintained by every function. + unsigned stackAlignment = 8; + + Triple TargetTriple; + +public: + /// This constructor initializes the data members to match that + /// of the specified triple. + M680x0Subtarget(const Triple &TT, StringRef CPU, + StringRef FS, const M680x0TargetMachine &_TM); + + /// Parses features string setting specified subtarget options. Definition + /// of function is auto generated by tblgen. + void ParseSubtargetFeatures(StringRef CPU, StringRef TuneCPU, StringRef FS); + + bool isM68000() const { return IsM68000; } + bool isM68010() const { return IsM68010; } + bool isM68020() const { return IsM68020; } + bool isM68030() const { return IsM68030; } + bool isM68040() const { return IsM68040; } + + bool useSmallSection() const { return UseSmallSection; } + + bool abiUsesSoftFloat() const; + + const Triple &getTargetTriple() const { return TargetTriple; } + + bool isTargetELF() const { return TargetTriple.isOSBinFormatELF(); } + + /// Return true if the subtarget allows calls to immediate address. + bool isLegalToCallImmediateAddr() const; + + bool isPositionIndependent() const; + + /// Classify a global variable reference for the current subtarget according + /// to how we should reference it in a non-pcrel context. + unsigned char classifyLocalReference(const GlobalValue *GV) const; + + /// Classify a global variable reference for the current subtarget according + /// to how we should reference it in a non-pcrel context. + unsigned char classifyGlobalReference(const GlobalValue *GV, + const Module &M) const; + unsigned char classifyGlobalReference(const GlobalValue *GV) const; + + /// Classify a external variable reference for the current subtarget according + /// to how we should reference it in a non-pcrel context. + unsigned char classifyExternalReference(const Module &M) const; + + /// Classify a global function reference for the current subtarget. + unsigned char classifyGlobalFunctionReference(const GlobalValue *GV, + const Module &M) const; + unsigned char classifyGlobalFunctionReference(const GlobalValue *GV) const; + + /// Classify a blockaddress reference for the current subtarget according to + /// how we should reference it in a non-pcrel context. + unsigned char classifyBlockAddressReference() const; + + unsigned getJumpTableEncoding() const; + + /// TODO this must be controlled by options like -malign-int and -mshort + Align getStackAlignment() const { return Align(stackAlignment); } + + /// getSlotSize - Stack slot size in bytes. + unsigned getSlotSize() const { return 4; } + + M680x0Subtarget & + initializeSubtargetDependencies(StringRef CPU, Triple TT, StringRef FS, + const M680x0TargetMachine &TM); + + const SelectionDAGTargetInfo *getSelectionDAGInfo() const override { + return &TSInfo; + } + + const M680x0InstrInfo *getInstrInfo() const override { return &InstrInfo; } + + const M680x0FrameLowering *getFrameLowering() const override { + return &FrameLowering; + } + + const M680x0RegisterInfo *getRegisterInfo() const override { + return &InstrInfo.getRegisterInfo(); + } + + const M680x0TargetLowering *getTargetLowering() const override { + return &TLInfo; + } + + const InstrItineraryData *getInstrItineraryData() const override { + return &InstrItins; + } +}; +} // namespace llvm + +#endif Index: llvm/lib/Target/M680x0/M680x0Subtarget.cpp =================================================================== --- /dev/null +++ llvm/lib/Target/M680x0/M680x0Subtarget.cpp @@ -0,0 +1,250 @@ +//===-- M680x0Subtarget.cpp - M680x0 Subtarget Information ------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file implements the M680x0 specific subclass of TargetSubtargetInfo. +/// +//===----------------------------------------------------------------------===// + +#include "M680x0Subtarget.h" + +#include "M680x0MachineFunction.h" +#include "M680x0.h" +#include "M680x0RegisterInfo.h" +#include "M680x0TargetMachine.h" + +#include "llvm/IR/Attributes.h" +#include "llvm/IR/Function.h" +#include "llvm/CodeGen/MachineJumpTableInfo.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/TargetRegistry.h" + +using namespace llvm; + +#define DEBUG_TYPE "m680x0-subtarget" + +#define GET_SUBTARGETINFO_TARGET_DESC +#define GET_SUBTARGETINFO_CTOR +#include "M680x0GenSubtargetInfo.inc" + +extern bool FixGlobalBaseReg; + +/// Select the M680x0 CPU for the given triple and cpu name. +static StringRef selectM680x0CPU(Triple TT, StringRef CPU) { + if (CPU.empty() || CPU == "generic") { + CPU = "M68000"; + } + return CPU; +} + +void M680x0Subtarget::anchor() { } + +M680x0Subtarget:: +M680x0Subtarget(const Triple &TT, StringRef CPU, + StringRef FS, + const M680x0TargetMachine &TM) : + M680x0GenSubtargetInfo(TT, CPU, /*TuneCPU*/ CPU, FS), TM(TM), TSInfo(), + InstrInfo(initializeSubtargetDependencies(CPU, TT, FS, TM)), + FrameLowering(*this, this->getStackAlignment()), + TLInfo(TM, *this), TargetTriple(TT) { +} + +bool M680x0Subtarget:: +isPositionIndependent() const { return TM.isPositionIndependent(); } + +bool M680x0Subtarget:: +isLegalToCallImmediateAddr() const { return true; } + +bool M680x0Subtarget:: +abiUsesSoftFloat() const { +// return TM->Options.UseSoftFloat; + return true; +} + +M680x0Subtarget & M680x0Subtarget:: +initializeSubtargetDependencies(StringRef CPU, Triple TT, StringRef FS, + const M680x0TargetMachine &TM) { + std::string CPUName = selectM680x0CPU(TT, CPU).str(); + + // Parse features string. + // ParseSubtargetFeatures(CPUName, FS); + // The only CPU supported thus far + IsM68000 = true; + + // Initialize scheduling itinerary for the specified CPU. + InstrItins = getInstrItineraryForCPU(CPUName); + + // Default stack alignment is 8 bytes, ??? Do I need this override? + // if (StackAlignOverride) + // stackAlignment = StackAlignOverride; + // else + stackAlignment = 8; + + return *this; +} + +//===----------------------------------------------------------------------===// +// Code Model +// +// Key assumptions: +// - Whenever possible we use pc-rel encoding since it is smaller(16 bit) than +// absolute(32 bit). +// - GOT is reachable within 16 bit offset for both Small and Medium models. +// - Code section is reachable within 16 bit offset for both models. +// +// ---------------------+-------------------------+-------------------------- +// | Small | Medium +// +-------------------------+------------+------------- +// | Static | PIC | Static | PIC +// ---------------------+------------+------------+------------+------------- +// branch | pc-rel | pc-rel | pc-rel | pc-rel +// ---------------------+------------+------------+------------+------------- +// call global | @PLT | @PLT | @PLT | @PLT +// ---------------------+------------+------------+------------+------------- +// call internal | pc-rel | pc-rel | pc-rel | pc-rel +// ---------------------+------------+------------+------------+------------- +// data local | pc-rel | pc-rel | ~pc-rel | ^pc-rel +// ---------------------+------------+------------+------------+------------- +// data local big* | pc-rel | pc-rel | absolute | @GOTOFF +// ---------------------+------------+------------+------------+------------- +// data global | pc-rel | @GOTPCREL | ~pc-rel | @GOTPCREL +// ---------------------+------------+------------+------------+------------- +// data global big* | pc-rel | @GOTPCREL | absolute | @GOTPCREL +// ---------------------+------------+------------+------------+------------- +// +// * Big data potentially cannot be reached within 16 bit offset and requires +// special handling for old(x00 and x10) CPUs. Normally these symbols go into +// separate .ldata section which mapped after normal .data and .text, but I +// don't really know how this must be done for M680x0 atm... will try to dig +// this info out from GCC. For now CPUs prior to M68020 will use static ref +// for Static Model and @GOT based references for PIC. +// +// ~ These are absolute for older CPUs for now. +// ^ These are @GOTOFF for older CPUs for now. +//===----------------------------------------------------------------------===// + +/// Classify a blockaddress reference for the current subtarget according to how +/// we should reference it in a non-pcrel context. +unsigned char M680x0Subtarget::classifyBlockAddressReference() const { + // Unless we start to support Large Code Model branching is always pc-rel + return M680x0II::MO_PC_RELATIVE_ADDRESS; +} + +unsigned char M680x0Subtarget:: +classifyLocalReference(const GlobalValue *GV) const { + switch (TM.getCodeModel()) { + default: llvm_unreachable("Unsupported code model"); + case CodeModel::Small: + case CodeModel::Kernel: { + return M680x0II::MO_PC_RELATIVE_ADDRESS; + } + case CodeModel::Medium: { + if (isPositionIndependent()) { + // On M68020 and better we can fit big any data offset into dips field. + if (IsM68020) { + return M680x0II::MO_PC_RELATIVE_ADDRESS; + } + // Otherwise we could check the data size and make sure it will fit into + // 16 bit offset. For now we will be conservative and go with @GOTOFF + return M680x0II::MO_GOTOFF; + } else { + if (IsM68020) { + return M680x0II::MO_PC_RELATIVE_ADDRESS; + } + return M680x0II::MO_ABSOLUTE_ADDRESS; + } + } + } +} + +unsigned char M680x0Subtarget:: +classifyExternalReference(const Module &M) const { + if (TM.shouldAssumeDSOLocal(M, nullptr)) + return classifyLocalReference(nullptr); + + if (isPositionIndependent()) { + return M680x0II::MO_GOTPCREL; + } else { + return M680x0II::MO_GOT; + } +} + +unsigned char M680x0Subtarget:: +classifyGlobalReference(const GlobalValue *GV) const { + return classifyGlobalReference(GV, *GV->getParent()); +} + +unsigned char M680x0Subtarget:: +classifyGlobalReference(const GlobalValue *GV, const Module &M) const { + if (TM.shouldAssumeDSOLocal(M, GV)) + return classifyLocalReference(GV); + + switch (TM.getCodeModel()) { + default: llvm_unreachable("Unsupported code model"); + case CodeModel::Small: + case CodeModel::Kernel: { + if (isPositionIndependent()) { + return M680x0II::MO_GOTPCREL; + } else { + return M680x0II::MO_PC_RELATIVE_ADDRESS; + } + } + case CodeModel::Medium: { + if (isPositionIndependent()) { + return M680x0II::MO_GOTPCREL; + } else { + if (IsM68020) { + return M680x0II::MO_PC_RELATIVE_ADDRESS; + } + return M680x0II::MO_ABSOLUTE_ADDRESS; + } + } + } +} + +unsigned M680x0Subtarget:: +getJumpTableEncoding() const { + if (isPositionIndependent()) { + // The only time we want to use GOTOFF(used when with EK_Custom32) is when + // the potential delta between the jump target and table base can be larger + // than displacement field, which is True for older CPUs(16 bit disp) + // in Medium model(can have large data way beyond 16 bit). + if (TM.getCodeModel() == CodeModel::Medium && !isM68020()) + return MachineJumpTableInfo::EK_Custom32; + + return MachineJumpTableInfo::EK_LabelDifference32; + } + + // In non-pic modes, just use the address of a block. + return MachineJumpTableInfo::EK_BlockAddress; +} + +unsigned char M680x0Subtarget:: +classifyGlobalFunctionReference(const GlobalValue *GV) const { + return classifyGlobalFunctionReference(GV, *GV->getParent()); +} + +unsigned char M680x0Subtarget:: +classifyGlobalFunctionReference(const GlobalValue *GV, const Module &M) const { + // local always use pc-rel referencing + if (TM.shouldAssumeDSOLocal(M, GV)) + return M680x0II::MO_NO_FLAG; + + // If the function is marked as non-lazy, generate an indirect call + // which loads from the GOT directly. This avoids runtime overhead + // at the cost of eager binding. + auto *F = dyn_cast_or_null(GV); + if (F && F->hasFnAttribute(Attribute::NonLazyBind)) { + return M680x0II::MO_GOTPCREL; + } + + // otherwise linker will figure this out + return M680x0II::MO_PLT; +} Index: llvm/lib/Target/M680x0/M680x0TargetMachine.h =================================================================== --- /dev/null +++ llvm/lib/Target/M680x0/M680x0TargetMachine.h @@ -0,0 +1,57 @@ +//===-- M680x0TargetMachine.h - Define TargetMachine for M680x0 ----- C++ -===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file declares the M680x0 specific subclass of TargetMachine. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_M680X0_M680X0TARGETMACHINE_H +#define LLVM_LIB_TARGET_M680X0_M680X0TARGETMACHINE_H + +#include "M680x0Subtarget.h" +#include "MCTargetDesc/M680x0MCTargetDesc.h" + +#include "llvm/CodeGen/Passes.h" +#include "llvm/CodeGen/SelectionDAGISel.h" +#include "llvm/CodeGen/TargetFrameLowering.h" +#include "llvm/Target/TargetMachine.h" + +namespace llvm { +class formatted_raw_ostream; +class M680x0RegisterInfo; + +class M680x0TargetMachine : public LLVMTargetMachine { + std::unique_ptr TLOF; + M680x0Subtarget Subtarget; + + mutable StringMap> SubtargetMap; + +public: + M680x0TargetMachine(const Target &T, const Triple &TT, StringRef CPU, + StringRef FS, const TargetOptions &Options, + Optional RM, Optional CM, + CodeGenOpt::Level OL, bool JIT); + + ~M680x0TargetMachine() override; + + const M680x0Subtarget *getSubtargetImpl() const { return &Subtarget; } + + const M680x0Subtarget *getSubtargetImpl(const Function &F) const override; + + // Pass Pipeline Configuration + TargetPassConfig *createPassConfig(PassManagerBase &PM) override; + + TargetLoweringObjectFile *getObjFileLowering() const override { + return TLOF.get(); + } +}; +} // namespace llvm + +#endif Index: llvm/lib/Target/M680x0/M680x0TargetMachine.cpp =================================================================== --- /dev/null +++ llvm/lib/Target/M680x0/M680x0TargetMachine.cpp @@ -0,0 +1,170 @@ +//===-- M680x0TargetMachine.cpp - M680x0 target machine ---------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file contains implementation for M680x0 target machine. +/// +//===----------------------------------------------------------------------===// + +#include "M680x0.h" +#include "M680x0TargetMachine.h" + +#include "M680x0Subtarget.h" +#include "M680x0TargetObjectFile.h" + +#include "llvm/CodeGen/Passes.h" +#include "llvm/CodeGen/TargetPassConfig.h" +#include "llvm/IR/LegacyPassManager.h" +#include "llvm/Support/TargetRegistry.h" +#include + +using namespace llvm; + +#define DEBUG_TYPE "m680x0" + +extern "C" void LLVMInitializeM680x0Target() { + RegisterTargetMachine X(TheM680x0Target); +} + +namespace { + +// FIXME #28 this layout is true for M68000 original cpu, other variants will +// affect DL computation +std::string computeDataLayout(const Triple &TT, StringRef CPU, + const TargetOptions &Options) { + std::string Ret = ""; + // M680x0 is Big Endian + Ret += "E"; + + // FIXME #28 how to wire it with the used object format? + Ret += "-m:e"; + + // M680x0 pointers are always 32 bit wide even for 16 bit cpus + Ret += "-p:32:32"; + + // M680x0 requires i8 to align on 2 byte boundry + Ret += "-i8:8:8-i16:16:16-i32:32:32"; + + // FIXME #29 no floats at the moment + + // The registers can hold 8, 16, 32 bits + Ret += "-n8:16:32"; + + // Aggregates are 32 bit aligned and stack is 16 bit aligned + Ret += "-a:0:32-S16"; + + return Ret; +} + +Reloc::Model getEffectiveRelocModel(const Triple &TT, + Optional RM) { + // If not defined we default to static + if (!RM.hasValue()) { + return Reloc::Static; + } + + return *RM; +} + +CodeModel::Model getEffectiveCodeModel(Optional CM, + bool JIT) { + if (!CM) { + return CodeModel::Small; + } else if (CM == CodeModel::Large) { + llvm_unreachable("Large code model is not supported"); + } else if (CM == CodeModel::Kernel) { + // FIXME #31 Kernel afaik is small cm plus some weird binding + llvm_unreachable("Kernel code model is not supported"); + } + return CM.getValue(); +} +} // end anonymous namespace + +M680x0TargetMachine::M680x0TargetMachine(const Target &T, const Triple &TT, + StringRef CPU, StringRef FS, + const TargetOptions &Options, + Optional RM, + Optional CM, + CodeGenOpt::Level OL, bool JIT) + : LLVMTargetMachine(T, computeDataLayout(TT, CPU, Options), TT, CPU, FS, + Options, getEffectiveRelocModel(TT, RM), + ::getEffectiveCodeModel(CM, JIT), OL), + TLOF(std::make_unique()), + Subtarget(TT, CPU, FS, *this) { + initAsmInfo(); +} + +M680x0TargetMachine::~M680x0TargetMachine() {} + +const M680x0Subtarget * +M680x0TargetMachine::getSubtargetImpl(const Function &F) const { + Attribute CPUAttr = F.getFnAttribute("target-cpu"); + Attribute FSAttr = F.getFnAttribute("target-features"); + + std::string CPU = !CPUAttr.hasAttribute(Attribute::None) + ? CPUAttr.getValueAsString().str() + : TargetCPU; + std::string FS = !FSAttr.hasAttribute(Attribute::None) + ? FSAttr.getValueAsString().str() + : TargetFS; + + auto &I = SubtargetMap[CPU + FS]; + if (!I) { + // This needs to be done before we create a new subtarget since any + // creation will depend on the TM and the code generation flags on the + // function that reside in TargetOptions. + resetTargetOptions(F); + I = std::make_unique(TargetTriple, CPU, FS, *this); + } + return I.get(); +} + +//===----------------------------------------------------------------------===// +// Pass Pipeline Configuration +//===----------------------------------------------------------------------===// + +namespace { +class M680x0PassConfig : public TargetPassConfig { +public: + M680x0PassConfig(M680x0TargetMachine &TM, PassManagerBase &PM) + : TargetPassConfig(TM, PM) {} + + M680x0TargetMachine &getM680x0TargetMachine() const { + return getTM(); + } + + const M680x0Subtarget &getM680x0Subtarget() const { + return *getM680x0TargetMachine().getSubtargetImpl(); + } + + bool addInstSelector() override; + void addPreSched2() override; + void addPreEmitPass() override; +}; +} // namespace + +TargetPassConfig *M680x0TargetMachine::createPassConfig(PassManagerBase &PM) { + return new M680x0PassConfig(*this, PM); +} + +bool M680x0PassConfig::addInstSelector() { + // Install an instruction selector. + addPass(createM680x0ISelDag(getM680x0TargetMachine())); + addPass(createM680x0GlobalBaseRegPass()); + return false; +} + +void M680x0PassConfig::addPreSched2() { + addPass(createM680x0ExpandPseudoPass()); +} + +void M680x0PassConfig::addPreEmitPass() { + addPass(createM680x0CollapseMOVEMPass()); + // addPass(createM680x0ConvertMOVToMOVMPass()); +} Index: llvm/lib/Target/M680x0/TargetInfo/CMakeLists.txt =================================================================== --- /dev/null +++ llvm/lib/Target/M680x0/TargetInfo/CMakeLists.txt @@ -0,0 +1,3 @@ +add_llvm_component_library(LLVMM680x0Info + M680x0TargetInfo.cpp +) Index: llvm/lib/Target/M680x0/TargetInfo/LLVMBuild.txt =================================================================== --- /dev/null +++ llvm/lib/Target/M680x0/TargetInfo/LLVMBuild.txt @@ -0,0 +1,23 @@ +;===- ./lib/Target/M680x0/TargetInfo/LLVMBuild.txt ---------------*- Conf -*--===; +; +; The LLVM Compiler Infrastructure +; +; This file is distributed under the University of Illinois Open Source +; License. See LICENSE.TXT for details. +; +;===------------------------------------------------------------------------===; +; +; This is an LLVMBuild description file for the components in this subdirectory. +; +; For more information on the LLVMBuild system, please see: +; +; http://llvm.org/docs/LLVMBuild.html +; +;===------------------------------------------------------------------------===; + +[component_0] +type = Library +name = M680x0Info +parent = M680x0 +required_libraries = Support +add_to_library_groups = M680x0 Index: llvm/lib/Target/M680x0/TargetInfo/M680x0TargetInfo.cpp =================================================================== --- /dev/null +++ llvm/lib/Target/M680x0/TargetInfo/M680x0TargetInfo.cpp @@ -0,0 +1,28 @@ +//===-- M680x0TargetInfo.cpp - M680x0 Target Implementation -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file contains M680x0 target initializer. +/// +//===----------------------------------------------------------------------===// + +#include "M680x0.h" + +#include "MCTargetDesc/M680x0MCTargetDesc.h" + +#include "llvm/Support/TargetRegistry.h" + +using namespace llvm; + +Target llvm::TheM680x0Target; + +extern "C" void LLVMInitializeM680x0TargetInfo() { + RegisterTarget X( + TheM680x0Target, "m680x0", "Motorola 68000 family", "M680x0"); +}