825 lines · plain
1//===-- M68kInstrData.td - M68k Data Movement Instructions -*- tablegen -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8///9/// \file10/// This file describes the Motorola 680x0 data movement instructions which are11/// the basic means of transferring and storing addresses and data. Here is the12/// current status of the file:13///14/// Machine:15///16/// EXG [ ] FMOVE [ ] FSMOVE [ ] FDMOVE [ ] FMOVEM [ ]17/// LEA [~] PEA [ ] MOVE [~] MOVE16 [ ] MOVEA [ ]18/// MOVEM [ ] MOVEP [ ] MOVEQ [ ] LINK [~] UNLK [~]19///20/// Pseudo:21///22/// MOVI [x] MOVSX [x] MOVZX [x] MOVX [x]23///24/// Map:25///26/// [ ] - was not touched at all27/// [!] - requires extarnal stuff implemented28/// [~] - in progress but usable29/// [x] - done30///31//===----------------------------------------------------------------------===//32 33//===----------------------------------------------------------------------===//34// MOVE35//===----------------------------------------------------------------------===//36 37/// -----------------------------------------------------38/// F E | D C | B A 9 | 8 7 6 | 5 4 3 | 2 1 039/// -----------------------------------------------------40/// | | DESTINATION | SOURCE41/// 0 0 | SIZE | REG | MODE | MODE | REG42/// -----------------------------------------------------43///44/// NOTE Move requires EA X version for direct register destination(0)45 46// MOVE has a different size encoding.47class MxMoveSize<bits<2> value> {48 bits<2> Value = value;49}50def MxMoveSize8 : MxMoveSize<0b01>;51def MxMoveSize16 : MxMoveSize<0b11>;52def MxMoveSize32 : MxMoveSize<0b10>;53 54class MxMoveEncoding<MxMoveSize size, MxEncMemOp dst_enc, MxEncMemOp src_enc> {55 dag Value = (ascend56 (descend 0b00, size.Value,57 !cond(58 !eq(!getdagop(dst_enc.EA), descend): !setdagop(dst_enc.EA, ascend),59 !eq(!getdagop(dst_enc.EA), ascend): !setdagop(dst_enc.EA, descend)),60 src_enc.EA),61 // Source extension62 src_enc.Supplement,63 // Destination extension64 dst_enc.Supplement65 );66}67 68// Special encoding for Xn69class MxMoveEncAddrMode_r<string reg_opnd> : MxEncMemOp {70 let EA = (descend (descend 0b00, (slice "$"#reg_opnd, 3, 3)),71 (operand "$"#reg_opnd, 3));72}73 74// TODO: Generalize and adopt this utility in other .td files as well.75multiclass MxMoveOperandEncodings<string opnd_name> {76 // Dn77 def MxMove#NAME#OpEnc_d : MxEncAddrMode_d<opnd_name>;78 // An79 def MxMove#NAME#OpEnc_a : MxEncAddrMode_a<opnd_name>;80 // Xn81 def MxMove#NAME#OpEnc_r : MxMoveEncAddrMode_r<opnd_name>;82 // (An)+83 def MxMove#NAME#OpEnc_o : MxEncAddrMode_o<opnd_name>;84 // -(An)85 def MxMove#NAME#OpEnc_e : MxEncAddrMode_e<opnd_name>;86 // (i,PC,Xn)87 def MxMove#NAME#OpEnc_k : MxEncAddrMode_k<opnd_name>;88 // (i,PC)89 def MxMove#NAME#OpEnc_q : MxEncAddrMode_q<opnd_name>;90 // (i,An,Xn)91 def MxMove#NAME#OpEnc_f : MxEncAddrMode_f<opnd_name>;92 // (i,An)93 def MxMove#NAME#OpEnc_p : MxEncAddrMode_p<opnd_name>;94 // (ABS).L95 def MxMove#NAME#OpEnc_b : MxEncAddrMode_abs<opnd_name, /*W/L=*/true>;96 // (An)97 def MxMove#NAME#OpEnc_j : MxEncAddrMode_j<opnd_name>;98}99 100defm Src : MxMoveOperandEncodings<"src">;101defm Dst : MxMoveOperandEncodings<"dst">;102 103defvar MxMoveSupportedAMs = ["o", "e", "k", "q", "f", "p", "b", "j"];104 105let Defs = [CCR] in106class MxMove<string size, dag outs, dag ins, list<dag> pattern, MxMoveEncoding enc>107 : MxInst<outs, ins, "move."#size#"\t$src, $dst", pattern> {108 let Inst = enc.Value;109}110 111// R <- R112class MxMove_RR<MxType TYPE, string DST_REG, string SRC_REG,113 MxMoveEncoding ENC,114 MxOpBundle DST = !cast<MxOpBundle>("MxOp"#TYPE.Size#"AddrMode_"#DST_REG),115 MxOpBundle SRC = !cast<MxOpBundle>("MxOp"#TYPE.Size#"AddrMode_"#SRC_REG)>116 : MxMove<TYPE.Prefix,117 (outs DST.Op:$dst), (ins SRC.Op:$src),118 [(null_frag)], ENC>;119 120foreach DST_REG = ["r", "a"] in {121 foreach SRC_REG = ["r", "a"] in122 foreach TYPE = [MxType16, MxType32] in123 def MOV # TYPE.Size # DST_REG # SRC_REG # TYPE.Postfix124 : MxMove_RR<TYPE, DST_REG, SRC_REG,125 MxMoveEncoding<!cast<MxMoveSize>("MxMoveSize"#TYPE.Size),126 !cast<MxEncMemOp>("MxMoveDstOpEnc_"#DST_REG),127 !cast<MxEncMemOp>("MxMoveSrcOpEnc_"#SRC_REG)>>;128} // foreach DST_REG129foreach TYPE = [MxType8, MxType16, MxType32] in130def MOV # TYPE.Size # dd # TYPE.Postfix131 : MxMove_RR<TYPE, "d", "d",132 MxMoveEncoding<!cast<MxMoveSize>("MxMoveSize"#TYPE.Size),133 MxMoveDstOpEnc_d, MxMoveSrcOpEnc_d>>;134 135// M <- R136let mayStore = 1 in {137class MxMove_MR<MxType TYPE, MxOpBundle DST, string SRC_REG, MxMoveEncoding ENC,138 MxOpBundle SRC = !cast<MxOpBundle>("MxOp"#TYPE.Size#"AddrMode_"#SRC_REG)>139 : MxMove<TYPE.Prefix, (outs), (ins DST.Op:$dst, SRC.Op:$src),140 [(store TYPE.VT:$src, DST.Pat:$dst)], ENC>;141 142class MxMove_MI<MxType TYPE, MxOpBundle DST, MxMoveEncoding ENC,143 MxImmOpBundle SRC = !cast<MxImmOpBundle>("MxOp"#TYPE.Size#"AddrMode_i")>144 : MxMove<TYPE.Prefix, (outs), (ins DST.Op:$dst, SRC.Op:$src),145 [(store SRC.ImmPat:$src, DST.Pat:$dst)], ENC>;146} // let mayStore = 1147 148foreach REG = ["r", "a", "d"] in149foreach AM = MxMoveSupportedAMs in {150 foreach TYPE = !if(!eq(REG, "d"), [MxType8, MxType16, MxType32], [MxType16, MxType32]) in151 def MOV # TYPE.Size # AM # REG # TYPE.Postfix152 : MxMove_MR<TYPE, !cast<MxOpBundle>("MxOp"#TYPE.Size#"AddrMode_"#AM), REG,153 MxMoveEncoding<!cast<MxMoveSize>("MxMoveSize"#TYPE.Size),154 !cast<MxEncMemOp>("MxMoveDstOpEnc_"#AM),155 !cast<MxEncMemOp>("MxMoveSrcOpEnc_"#REG)>>;156} // foreach AM157 158foreach AM = MxMoveSupportedAMs in {159 foreach TYPE = [MxType8, MxType16, MxType32] in160 def MOV # TYPE.Size # AM # i # TYPE.Postfix161 : MxMove_MI<TYPE, !cast<MxOpBundle>("MxOp"#TYPE.Size#"AddrMode_"#AM),162 MxMoveEncoding<!cast<MxMoveSize>("MxMoveSize"#TYPE.Size),163 !cast<MxEncMemOp>("MxMoveDstOpEnc_"#AM),164 MxEncAddrMode_i<"src", TYPE.Size>>>;165} // foreach AM166 167// R <- I168// No pattern, as all immediate -> register moves are matched to the MOVI pseudo169class MxMove_RI<MxType TYPE, string DST_REG, MxMoveEncoding ENC,170 MxImmOpBundle SRC = !cast<MxImmOpBundle>("MxOp"#TYPE.Size#"AddrMode_i"),171 MxOpBundle DST = !cast<MxOpBundle>("MxOp"#TYPE.Size#"AddrMode_"#DST_REG)>172 : MxMove<TYPE.Prefix, (outs DST.Op:$dst), (ins SRC.Op:$src),173 [(null_frag)], ENC>;174 175foreach REG = ["r", "a", "d"] in {176 foreach TYPE = !if(!eq(REG, "d"), [MxType8, MxType16, MxType32], [MxType16, MxType32]) in177 def MOV # TYPE.Size # REG # i # TYPE.Postfix178 : MxMove_RI<TYPE, REG,179 MxMoveEncoding<!cast<MxMoveSize>("MxMoveSize"#TYPE.Size),180 !cast<MxEncMemOp>("MxMoveDstOpEnc_"#REG),181 MxEncAddrMode_i<"src", TYPE.Size>>>;182} // foreach REG183 184// R <- M185let mayLoad = 1 in186class MxMove_RM<MxType TYPE, string DST_REG, MxOpBundle SRC, MxEncMemOp SRC_ENC,187 MxMoveSize SIZE_ENC = !cast<MxMoveSize>("MxMoveSize"#TYPE.Size),188 MxOpBundle DST = !cast<MxOpBundle>("MxOp"#TYPE.Size#"AddrMode_"#DST_REG),189 MxEncMemOp DST_ENC = !cast<MxEncMemOp>("MxMoveDstOpEnc_"#DST_REG)>190 : MxMove<TYPE.Prefix, (outs DST.Op:$dst), (ins SRC.Op:$src),191 [(set TYPE.VT:$dst, (TYPE.Load SRC.Pat:$src))],192 MxMoveEncoding<SIZE_ENC, DST_ENC, SRC_ENC>>;193 194foreach REG = ["r", "a", "d"] in195foreach AM = MxMoveSupportedAMs in {196 foreach TYPE = !if(!eq(REG, "d"), [MxType8, MxType16, MxType32], [MxType16, MxType32]) in197 def MOV # TYPE.Size # REG # AM # TYPE.Postfix198 : MxMove_RM<TYPE, REG, !cast<MxOpBundle>("MxOp"#TYPE.Size#"AddrMode_"#AM),199 !cast<MxEncMemOp>("MxMoveSrcOpEnc_"#AM)>;200} // foreach AM201 202// Tail call version203let Pattern = [(null_frag)] in {204 foreach REG = ["r", "a"] in205 foreach AM = MxMoveSupportedAMs in {206 foreach TYPE = [MxType16, MxType32] in207 def MOV # TYPE.Size # REG # AM # _TC208 : MxMove_RM<TYPE, REG, !cast<MxOpBundle>("MxOp"#TYPE.Size#"AddrMode_"#AM),209 !cast<MxEncMemOp>("MxMoveSrcOpEnc_"#AM)> {210 let isCodeGenOnly = true;211 }212 } // foreach AM213} // let Pattern214 215let mayLoad = 1, mayStore = 1 in216class MxMove_MM<MxType TYPE, MxOpBundle DST, MxOpBundle SRC,217 MxEncMemOp DST_ENC, MxEncMemOp SRC_ENC>218 : MxMove<TYPE.Prefix, (outs), (ins DST.Op:$dst, SRC.Op:$src),219 [(store (TYPE.Load SRC.Pat:$src), DST.Pat:$dst)],220 MxMoveEncoding<!cast<MxMoveSize>("MxMoveSize"#TYPE.Size),221 DST_ENC, SRC_ENC>>;222 223foreach DST_AM = MxMoveSupportedAMs in224foreach SRC_AM = MxMoveSupportedAMs in {225 foreach TYPE = [MxType8, MxType16, MxType32] in226 def MOV # TYPE.Size # DST_AM # SRC_AM # TYPE.Postfix227 : MxMove_MM<TYPE, !cast<MxOpBundle>("MxOp"#TYPE.Size#"AddrMode_"#DST_AM),228 !cast<MxOpBundle>("MxOp"#TYPE.Size#"AddrMode_"#SRC_AM),229 !cast<MxEncMemOp>("MxMoveDstOpEnc_"#DST_AM),230 !cast<MxEncMemOp>("MxMoveSrcOpEnc_"#SRC_AM)>;231} // foreach SRC_AM232 233// Store ABS(basically pointer) as Immdiate to Mem234def : Pat<(store MxType32.BPat :$src, MxType32.PPat :$dst),235 (MOV32pi MxType32.POp :$dst, MxType32.IOp :$src)>;236 237def : Pat<(store MxType32.BPat :$src, MxType32.FPat :$dst),238 (MOV32fi MxType32.FOp :$dst, MxType32.IOp :$src)>;239 240def : Pat<(store MxType32.BPat :$src, MxType32.BPat :$dst),241 (MOV32bi MxType32.BOp :$dst, MxType32.IOp :$src)>;242 243def : Pat<(store MxType32.BPat :$src, MxType32.JPat :$dst),244 (MOV32ji MxType32.JOp :$dst, MxType32.IOp :$src)>;245 246//===----------------------------------------------------------------------===//247// MOVEQ248//===----------------------------------------------------------------------===//249 250/// ------------+---------+---+-----------------------251/// F E D C | B A 9 | 8 | 7 6 5 4 3 2 1 0252/// ------------+---------+---+-----------------------253/// 0 1 1 1 | REG | 0 | DATA254/// ------------+---------+---+-----------------------255 256// No pattern, as all immediate -> register moves are matched to the MOVI pseudo257let Defs = [CCR] in258def MOVQ : MxInst<(outs MxDRD32:$dst), (ins Mxi8imm:$imm),259 "moveq\t$imm, $dst",260 [(null_frag)]> {261 let Inst = (descend 0b0111, (operand "$dst", 3), 0b0, (operand "$imm", 8));262}263 264//===----------------------------------------------------------------------===//265// MOVEM266//267// The mask is already pre-processed by the save/restore spill hook268//===----------------------------------------------------------------------===//269 270// Direction271defvar MxMOVEM_MR = false;272defvar MxMOVEM_RM = true;273 274// Size275defvar MxMOVEM_W = false;276defvar MxMOVEM_L = true;277 278/// ---------------+-------------+-------------+---------279/// F E D C B | A | 9 8 7 | 6 | 5 4 3 | 2 1 0280/// ---------------+---+---------+---+---------+---------281/// 0 1 0 0 1 | D | 0 0 1 | S | MODE | REG282/// ---------------+---+---------+---+---------+---------283/// REGISTER LIST MASK284/// -----------------------------------------------------285/// D - direction(RM,MR)286/// S - size(W,L)287class MxMOVEMEncoding<MxEncMemOp opnd_enc, bit size, bit direction,288 string mask_op_name> {289 dag Value = (ascend290 (descend 0b01001, direction, 0b001, size, opnd_enc.EA),291 // Mask292 (operand "$"#mask_op_name, 16),293 opnd_enc.Supplement294 );295}296 297let mayStore = 1 in298class MxMOVEM_MR<MxType TYPE, bit SIZE_ENC,299 MxOperand MEMOp, MxEncMemOp MEM_ENC,300 MxOp MASKOp>301 : MxInst<(outs), (ins MEMOp:$dst, MASKOp:$mask),302 "movem."#TYPE.Prefix#"\t$mask, $dst", []> {303 let Inst = MxMOVEMEncoding<MEM_ENC, SIZE_ENC, MxMOVEM_MR, "mask">.Value;304}305 306foreach AM = MxMoveSupportedAMs in {307 foreach TYPE = [MxType16, MxType32] in308 def MOVM # TYPE.Size # AM # m # TYPE.Postfix309 : MxMOVEM_MR<TYPE, !if(!eq(TYPE, MxType16), MxMOVEM_W, MxMOVEM_L),310 !cast<MxOpBundle>("MxOp"#TYPE.Size#"AddrMode_"#AM).Op,311 !cast<MxEncMemOp>("MxMoveDstOpEnc_"#AM),312 !if(!eq(AM, "e"), MxInverseMoveMask, MxMoveMask)>;313} // foreach AM314 315let mayLoad = 1 in316class MxMOVEM_RM<MxType TYPE, bit SIZE_ENC,317 MxOperand MEMOp, MxEncMemOp MEM_ENC,318 MxOp MASKOp>319 : MxInst<(outs), (ins MASKOp:$mask, MEMOp:$src),320 "movem."#TYPE.Prefix#"\t$src, $mask", []> {321 let Inst = MxMOVEMEncoding<MEM_ENC, SIZE_ENC, MxMOVEM_RM, "mask">.Value;322}323 324foreach AM = MxMoveSupportedAMs in {325 foreach TYPE = [MxType16, MxType32] in326 def MOVM # TYPE.Size # m # AM # TYPE.Postfix327 : MxMOVEM_RM<TYPE, !if(!eq(TYPE, MxType16), MxMOVEM_W, MxMOVEM_L),328 !cast<MxOpBundle>("MxOp"#TYPE.Size#"AddrMode_"#AM).Op,329 !cast<MxEncMemOp>("MxMoveSrcOpEnc_"#AM),330 !if(!eq(AM, "e"), MxInverseMoveMask, MxMoveMask)>;331} // foreach AM332 333// Pseudo versions. These a required by virtual register spill/restore since334// the mask requires real register to encode. These instruction will be expanded335// into real MOVEM after RA finishes.336let mayStore = 1 in337class MxMOVEM_MR_Pseudo<MxType TYPE, MxOperand MEMOp>338 : MxPseudo<(outs), (ins MEMOp:$dst, TYPE.ROp:$reg)>;339let mayLoad = 1 in340class MxMOVEM_RM_Pseudo<MxType TYPE, MxOperand MEMOp>341 : MxPseudo<(outs TYPE.ROp:$dst), (ins MEMOp:$src)>;342 343// Mem <- Reg344def MOVM16jm_P : MxMOVEM_MR_Pseudo<MxType16r, MxType16.JOp>;345def MOVM32jm_P : MxMOVEM_MR_Pseudo<MxType32r, MxType32.JOp>;346 347def MOVM16pm_P : MxMOVEM_MR_Pseudo<MxType16r, MxType16.POp>;348def MOVM32pm_P : MxMOVEM_MR_Pseudo<MxType32r, MxType32.POp>;349 350// Reg <- Mem351def MOVM16mj_P : MxMOVEM_RM_Pseudo<MxType16r, MxType16.JOp>;352def MOVM32mj_P : MxMOVEM_RM_Pseudo<MxType32r, MxType32.JOp>;353 354def MOVM16mp_P : MxMOVEM_RM_Pseudo<MxType16r, MxType16.POp>;355def MOVM32mp_P : MxMOVEM_RM_Pseudo<MxType32r, MxType32.POp>;356 357 358//===----------------------------------------------------------------------===//359// MOVE to/from SR/CCR360//361// A special care must be taken working with to/from CCR since it is basically362// word-size SR register truncated for user mode thus it only supports word-size363// instructions. Plus the original M68000 does not support moves from CCR. So in364// order to use CCR effectively one MUST use proper byte-size pseudo instructi-365// ons that will be resolved sometime after RA pass.366//===----------------------------------------------------------------------===//367 368/// Move to CCR369/// --------------------------------------------------370/// F E D C B A 9 8 7 6 | 5 4 3 | 2 1 0371/// --------------------------------------------------372/// | EFFECTIVE ADDRESS373/// 0 1 0 0 0 1 0 0 1 1 | MODE | REG374/// --------------------------------------------------375let Defs = [CCR] in {376class MxMoveToCCR<MxOperand MEMOp, MxEncMemOp SRC_ENC>377 : MxInst<(outs CCRC:$dst), (ins MEMOp:$src), "move.w\t$src, $dst", []> {378 let Inst = (ascend379 (descend 0b0100010011, SRC_ENC.EA),380 SRC_ENC.Supplement381 );382}383 384class MxMoveToCCRPseudo<MxOperand MEMOp>385 : MxPseudo<(outs CCRC:$dst), (ins MEMOp:$src)>;386} // let Defs = [CCR]387 388let mayLoad = 1 in389foreach AM = MxMoveSupportedAMs in {390 def MOV16c # AM : MxMoveToCCR<!cast<MxOpBundle>("MxOp16AddrMode_"#AM).Op,391 !cast<MxEncMemOp>("MxMoveSrcOpEnc_"#AM)>;392 def MOV8c # AM : MxMoveToCCRPseudo<!cast<MxOpBundle>("MxOp8AddrMode_"#AM).Op>;393} // foreach AM394 395// Only data register is allowed.396def MOV16cd : MxMoveToCCR<MxOp16AddrMode_d.Op, MxMoveSrcOpEnc_d>;397def MOV8cd : MxMoveToCCRPseudo<MxOp8AddrMode_d.Op>;398 399/// Move from CCR400/// --------------------------------------------------401/// F E D C B A 9 8 7 6 | 5 4 3 | 2 1 0402/// --------------------------------------------------403/// | EFFECTIVE ADDRESS404/// 0 1 0 0 0 0 1 0 1 1 | MODE | REG405/// --------------------------------------------------406let Uses = [CCR] in {407class MxMoveFromCCR_R408 : MxInst<(outs MxDRD16:$dst), (ins CCRC:$src), "move.w\t$src, $dst", []>,409 Requires<[ AtLeastM68010 ]> {410 let Inst = (descend 0b0100001011, MxEncAddrMode_d<"dst">.EA);411}412 413class MxMoveFromCCR_M<MxOperand MEMOp, MxEncMemOp DST_ENC>414 : MxInst<(outs), (ins MEMOp:$dst, CCRC:$src), "move.w\t$src, $dst", []>,415 Requires<[ AtLeastM68010 ]> {416 let Inst = (ascend417 (descend 0b0100001011, DST_ENC.EA),418 DST_ENC.Supplement419 );420}421 422class MxMoveFromCCRPseudo<MxOperand MEMOp>423 : MxPseudo<(outs), (ins MEMOp:$dst, CCRC:$src)>;424class MxMoveFromCCR_RPseudo<MxOperand MEMOp>425 : MxPseudo<(outs MEMOp:$dst), (ins CCRC:$src)>;426} // let Uses = [CCR]427 428let mayStore = 1 in429foreach AM = MxMoveSupportedAMs in {430 def MOV16 # AM # c431 : MxMoveFromCCR_M<!cast<MxOpBundle>("MxOp16AddrMode_"#AM).Op,432 !cast<MxEncMemOp>("MxMoveDstOpEnc_"#AM)>;433 def MOV8 # AM # c434 : MxMoveFromCCRPseudo<!cast<MxOpBundle>("MxOp8AddrMode_"#AM).Op>;435} // foreach AM436 437// Only data register is allowed.438def MOV16dc : MxMoveFromCCR_R;439def MOV8dc : MxMoveFromCCR_RPseudo<MxOp8AddrMode_d.Op>;440 441/// Move to SR442/// --------------------------------------------------443/// F E D C B A 9 8 7 6 | 5 4 3 | 2 1 0444/// --------------------------------------------------445/// | EFFECTIVE ADDRESS446/// 0 1 0 0 0 1 1 0 1 1 | MODE | REG447/// --------------------------------------------------448let Defs = [SR] in {449class MxMoveToSR<MxOperand MEMOp, MxEncMemOp SRC_ENC>450 : MxInst<(outs SRC:$dst), (ins MEMOp:$src), "move.w\t$src, $dst", []> {451 let Inst = (ascend452 (descend 0b0100011011, SRC_ENC.EA),453 SRC_ENC.Supplement454 );455}456} // let Defs = [SR]457 458let mayLoad = 1 in459foreach AM = MxMoveSupportedAMs in {460 def MOV16s # AM : MxMoveToSR<!cast<MxOpBundle>("MxOp16AddrMode_"#AM).Op,461 !cast<MxEncMemOp>("MxMoveSrcOpEnc_"#AM)>;462} // foreach AM463 464def MOV16sd : MxMoveToSR<MxOp16AddrMode_d.Op, MxMoveSrcOpEnc_d>;465 466/// Move from SR467/// --------------------------------------------------468/// F E D C B A 9 8 7 6 | 5 4 3 | 2 1 0469/// --------------------------------------------------470/// | EFFECTIVE ADDRESS471/// 0 1 0 0 0 0 0 0 1 1 | MODE | REG472/// --------------------------------------------------473let Uses = [SR] in {474class MxMoveFromSR_R475 : MxInst<(outs MxDRD16:$dst), (ins SRC:$src), "move.w\t$src, $dst", []>,476 Requires<[ AtLeastM68010 ]> {477 let Inst = (descend 0b0100000011, MxEncAddrMode_d<"dst">.EA);478}479 480class MxMoveFromSR_M<MxOperand MEMOp, MxEncMemOp DST_ENC>481 : MxInst<(outs), (ins MEMOp:$dst, SRC:$src), "move.w\t$src, $dst", []>,482 Requires<[ AtLeastM68010 ]> {483 let Inst = (ascend484 (descend 0b0100000011, DST_ENC.EA),485 DST_ENC.Supplement486 );487}488} // let Uses = [SR]489 490let mayStore = 1 in491foreach AM = MxMoveSupportedAMs in {492 def MOV16 # AM # s493 : MxMoveFromSR_M<!cast<MxOpBundle>("MxOp16AddrMode_"#AM).Op,494 !cast<MxEncMemOp>("MxMoveDstOpEnc_"#AM)>;495} // foreach AM496 497def MOV16ds : MxMoveFromSR_R;498 499//===----------------------------------------------------------------------===//500// LEA501//===----------------------------------------------------------------------===//502 503/// ----------------------------------------------------504/// F E D C | B A 9 | 8 7 6 | 5 4 3 | 2 1 0505/// ----------------------------------------------------506/// 0 1 0 0 | DST REG | 1 1 1 | MODE | REG507/// ----------------------------------------------------508class MxLEA<MxOpBundle SRC, MxEncMemOp SRC_ENC>509 : MxInst<(outs MxARD32:$dst), (ins SRC.Op:$src),510 "lea\t$src, $dst", [(set i32:$dst, SRC.Pat:$src)]> {511 let Inst = (ascend512 (descend 0b0100, (operand "$dst", 3), 0b111, SRC_ENC.EA),513 SRC_ENC.Supplement514 );515}516 517foreach AM = ["p", "f", "b", "q", "k"] in518def LEA32 # AM : MxLEA<!cast<MxOpBundle>("MxOp32AddrMode_"#AM),519 !cast<MxEncMemOp>("MxMoveSrcOpEnc_"#AM)>;520 521//===----------------------------------------------------------------------===//522// LINK/UNLK523//===----------------------------------------------------------------------===//524 525let Uses = [SP], Defs = [SP] in {526let mayStore = 1 in {527 528def LINK16 : MxInst<(outs), (ins MxARD16:$src, Mxi16imm:$disp), "link.w\t$src, $disp", []> {529 let Inst = (ascend530 (descend 0b0100111001010, (operand "$src", 3)),531 (operand "$disp", 16)532 );533}534 535def LINK32 : MxInst<(outs), (ins MxARD16:$src, Mxi32imm:$disp), "link.l\t$src, $disp", []> {536 let Inst = (ascend537 (descend 0b0100100000001, (operand "$src", 3)),538 (slice "$disp", 31, 16),539 (slice "$disp", 15, 0)540 );541}542 543def UNLK : MxInst<(outs), (ins MxARD32:$src), "unlk\t$src", []> {544 let Inst = (descend 0b0100111001011, (operand "$src", 3));545}546 547} // let mayStore = 1548} // let Uses = [SP], Defs = [SP]549 550//===----------------------------------------------------------------------===//551// Pseudos552//===----------------------------------------------------------------------===//553 554/// Pushe/Pop to/from SP for simplicity555let Uses = [SP], Defs = [SP], hasSideEffects = 0 in {556 557// SP <- SP - <size>; (SP) <- Dn558let mayStore = 1 in {559def PUSH8d : MxPseudo<(outs), (ins DR8:$reg)>;560def PUSH16d : MxPseudo<(outs), (ins DR16:$reg)>;561def PUSH32r : MxPseudo<(outs), (ins XR32:$reg)>;562} // let mayStore = 1563 564// Dn <- (SP); SP <- SP + <size>565let mayLoad = 1 in {566def POP8d : MxPseudo<(outs DR8:$reg), (ins)>;567def POP16d : MxPseudo<(outs DR16:$reg), (ins)>;568def POP32r : MxPseudo<(outs XR32:$reg), (ins)>;569} // let mayLoad = 1570 571} // let Uses/Defs = [SP], hasSideEffects = 0572 573 574let Defs = [CCR] in {575class MxPseudoMove_RR<MxType DST, MxType SRC, list<dag> PAT = []>576 : MxPseudo<(outs DST.ROp:$dst), (ins SRC.ROp:$src), PAT>;577 578class MxPseudoMove_RM<MxType DST, MxOperand SRCOpd, list<dag> PAT = []>579 : MxPseudo<(outs DST.ROp:$dst), (ins SRCOpd:$src), PAT>;580 581 582// These Pseudos handle loading immediates to registers.583// They are expanded post-RA into either move or moveq instructions,584// depending on size, destination register class, and immediate value.585// This is done with pseudoinstructions in order to not constrain RA to586// data registers if moveq matches.587class MxPseudoMove_DI<MxType TYPE>588 : MxPseudo<(outs TYPE.ROp:$dst), (ins TYPE.IOp:$src),589 [(set TYPE.ROp:$dst, imm:$src)]>;590 591// i8 imm -> reg can always be converted to moveq,592// but we still emit a pseudo for consistency.593def MOVI8di : MxPseudoMove_DI<MxType8d>;594def MOVI16ri : MxPseudoMove_DI<MxType16r>;595def MOVI32ri : MxPseudoMove_DI<MxType32r>;596} // let Defs = [CCR]597 598/// This group of Pseudos is analogues to the real x86 extending moves, but599/// since M68k does not have those we need to emulate. These instructions600/// will be expanded right after RA completed because we need to know precisely601/// what registers are allocated for the operands and if they overlap we just602/// extend the value if the registers are completely different we need to move603/// first.604foreach EXT = ["S", "Z"] in {605 let hasSideEffects = 0 in {606 607 def MOV#EXT#Xd16d8 : MxPseudoMove_RR<MxType16d, MxType8d>;608 def MOV#EXT#Xd32d8 : MxPseudoMove_RR<MxType32d, MxType8d>;609 def MOV#EXT#Xd32d16 : MxPseudoMove_RR<MxType32r, MxType16r>;610 611 let mayLoad = 1 in {612 613 def MOV#EXT#Xd16j8 : MxPseudoMove_RM<MxType16d, MxType8.JOp>;614 def MOV#EXT#Xd32j8 : MxPseudoMove_RM<MxType32d, MxType8.JOp>;615 def MOV#EXT#Xd32j16 : MxPseudoMove_RM<MxType32d, MxType16.JOp>;616 617 def MOV#EXT#Xd16p8 : MxPseudoMove_RM<MxType16d, MxType8.POp>;618 def MOV#EXT#Xd32p8 : MxPseudoMove_RM<MxType32d, MxType8.POp>;619 def MOV#EXT#Xd32p16 : MxPseudoMove_RM<MxType32d, MxType16.POp>;620 621 def MOV#EXT#Xd16f8 : MxPseudoMove_RM<MxType16d, MxType8.FOp>;622 def MOV#EXT#Xd32f8 : MxPseudoMove_RM<MxType32d, MxType8.FOp>;623 def MOV#EXT#Xd32f16 : MxPseudoMove_RM<MxType32d, MxType16.FOp>;624 625 def MOV#EXT#Xd16q8 : MxPseudoMove_RM<MxType16d, MxType8.QOp>;626 def MOV#EXT#Xd32q8 : MxPseudoMove_RM<MxType32d, MxType8.QOp>;627 def MOV#EXT#Xd32q16 : MxPseudoMove_RM<MxType32d, MxType16.QOp>;628 629 }630 }631}632 633/// This group of instructions is similar to the group above but DOES NOT do634/// any value extension, they just load a smaller register into the lower part635/// of another register if operands' real registers are different or does636/// nothing if they are the same.637def MOVXd16d8 : MxPseudoMove_RR<MxType16d, MxType8d>;638def MOVXd32d8 : MxPseudoMove_RR<MxType32d, MxType8d>;639def MOVXd32d16 : MxPseudoMove_RR<MxType32r, MxType16r>;640 641//===----------------------------------------------------------------------===//642// Extend/Truncate Patterns643//===----------------------------------------------------------------------===//644 645// i16 <- sext i8646def: Pat<(i16 (sext i8:$src)),647 (EXTRACT_SUBREG (MOVSXd32d8 MxDRD8:$src), MxSubRegIndex16Lo)>;648def: Pat<(MxSExtLoadi16i8 MxCP_ARI:$src),649 (EXTRACT_SUBREG (MOVSXd32j8 MxARI8:$src), MxSubRegIndex16Lo)>;650def: Pat<(MxSExtLoadi16i8 MxCP_ARID:$src),651 (EXTRACT_SUBREG (MOVSXd32p8 MxARID8:$src), MxSubRegIndex16Lo)>;652def: Pat<(MxSExtLoadi16i8 MxCP_ARII:$src),653 (EXTRACT_SUBREG (MOVSXd32f8 MxARII8:$src), MxSubRegIndex16Lo)>;654def: Pat<(MxSExtLoadi16i8 MxCP_PCD:$src), (MOVSXd16q8 MxPCD8:$src)>;655 656// i32 <- sext i8657def: Pat<(i32 (sext i8:$src)), (MOVSXd32d8 MxDRD8:$src)>;658def: Pat<(MxSExtLoadi32i8 MxCP_ARI :$src), (MOVSXd32j8 MxARI8 :$src)>;659def: Pat<(MxSExtLoadi32i8 MxCP_ARID:$src), (MOVSXd32p8 MxARID8:$src)>;660def: Pat<(MxSExtLoadi32i8 MxCP_ARII:$src), (MOVSXd32f8 MxARII8:$src)>;661def: Pat<(MxSExtLoadi32i8 MxCP_PCD:$src), (MOVSXd32q8 MxPCD8:$src)>;662 663// i32 <- sext i16664def: Pat<(i32 (sext i16:$src)), (MOVSXd32d16 MxDRD16:$src)>;665def: Pat<(MxSExtLoadi32i16 MxCP_ARI :$src), (MOVSXd32j16 MxARI16 :$src)>;666def: Pat<(MxSExtLoadi32i16 MxCP_ARID:$src), (MOVSXd32p16 MxARID16:$src)>;667def: Pat<(MxSExtLoadi32i16 MxCP_ARII:$src), (MOVSXd32f16 MxARII16:$src)>;668def: Pat<(MxSExtLoadi32i16 MxCP_PCD:$src), (MOVSXd32q16 MxPCD16:$src)>;669 670// i16 <- zext i8671def: Pat<(i16 (zext i8:$src)),672 (EXTRACT_SUBREG (MOVZXd32d8 MxDRD8:$src), MxSubRegIndex16Lo)>;673def: Pat<(MxZExtLoadi16i8 MxCP_ARI:$src),674 (EXTRACT_SUBREG (MOVZXd32j8 MxARI8:$src), MxSubRegIndex16Lo)>;675def: Pat<(MxZExtLoadi16i8 MxCP_ARID:$src),676 (EXTRACT_SUBREG (MOVZXd32p8 MxARID8:$src), MxSubRegIndex16Lo)>;677def: Pat<(MxZExtLoadi16i8 MxCP_ARII:$src),678 (EXTRACT_SUBREG (MOVZXd32f8 MxARII8:$src), MxSubRegIndex16Lo)>;679def: Pat<(MxZExtLoadi16i8 MxCP_PCD :$src), (MOVZXd16q8 MxPCD8 :$src)>;680 681// i32 <- zext i8682def: Pat<(i32 (zext i8:$src)), (MOVZXd32d8 MxDRD8:$src)>;683def: Pat<(MxZExtLoadi32i8 MxCP_ARI :$src), (MOVZXd32j8 MxARI8 :$src)>;684def: Pat<(MxZExtLoadi32i8 MxCP_ARID:$src), (MOVZXd32p8 MxARID8:$src)>;685def: Pat<(MxZExtLoadi32i8 MxCP_ARII:$src), (MOVZXd32f8 MxARII8:$src)>;686def: Pat<(MxZExtLoadi32i8 MxCP_PCD :$src), (MOVZXd32q8 MxPCD8 :$src)>;687 688// i32 <- zext i16689def: Pat<(i32 (zext i16:$src)), (MOVZXd32d16 MxDRD16:$src)>;690def: Pat<(MxZExtLoadi32i16 MxCP_ARI :$src), (MOVZXd32j16 MxARI16 :$src)>;691def: Pat<(MxZExtLoadi32i16 MxCP_ARID:$src), (MOVZXd32p16 MxARID16:$src)>;692def: Pat<(MxZExtLoadi32i16 MxCP_ARII:$src), (MOVZXd32f16 MxARII16:$src)>;693def: Pat<(MxZExtLoadi32i16 MxCP_PCD :$src), (MOVZXd32q16 MxPCD16 :$src)>;694 695// i16 <- anyext i8696def: Pat<(i16 (anyext i8:$src)),697 (EXTRACT_SUBREG (MOVZXd32d8 MxDRD8:$src), MxSubRegIndex16Lo)>;698def: Pat<(MxExtLoadi16i8 MxCP_ARI:$src),699 (EXTRACT_SUBREG (MOVZXd32j8 MxARI8:$src), MxSubRegIndex16Lo)>;700def: Pat<(MxExtLoadi16i8 MxCP_ARID:$src),701 (EXTRACT_SUBREG (MOVZXd32p8 MxARID8:$src), MxSubRegIndex16Lo)>;702def: Pat<(MxExtLoadi16i8 MxCP_ARII:$src),703 (EXTRACT_SUBREG (MOVZXd32f8 MxARII8:$src), MxSubRegIndex16Lo)>;704def: Pat<(MxExtLoadi16i8 MxCP_PCD:$src),705 (EXTRACT_SUBREG (MOVZXd32q8 MxPCD8:$src), MxSubRegIndex16Lo)>;706 707// i32 <- anyext i8708def: Pat<(i32 (anyext i8:$src)), (MOVZXd32d8 MxDRD8:$src)>;709def: Pat<(MxExtLoadi32i8 MxCP_ARI :$src), (MOVZXd32j8 MxARI8 :$src)>;710def: Pat<(MxExtLoadi32i8 MxCP_ARID:$src), (MOVZXd32p8 MxARID8:$src)>;711def: Pat<(MxExtLoadi32i8 MxCP_ARII:$src), (MOVZXd32f8 MxARII8:$src)>;712def: Pat<(MxExtLoadi32i8 MxCP_PCD:$src), (MOVZXd32q8 MxPCD8:$src)>;713 714// i32 <- anyext i16715def: Pat<(i32 (anyext i16:$src)), (MOVZXd32d16 MxDRD16:$src)>;716def: Pat<(MxExtLoadi32i16 MxCP_ARI :$src), (MOVZXd32j16 MxARI16 :$src)>;717def: Pat<(MxExtLoadi32i16 MxCP_ARID:$src), (MOVZXd32p16 MxARID16:$src)>;718def: Pat<(MxExtLoadi32i16 MxCP_ARII:$src), (MOVZXd32f16 MxARII16:$src)>;719def: Pat<(MxExtLoadi32i16 MxCP_PCD:$src), (MOVZXd32q16 MxPCD16:$src)>;720 721// trunc patterns722def : Pat<(i16 (trunc i32:$src)),723 (EXTRACT_SUBREG MxXRD32:$src, MxSubRegIndex16Lo)>;724def : Pat<(i8 (trunc i32:$src)),725 (EXTRACT_SUBREG MxXRD32:$src, MxSubRegIndex8Lo)>;726def : Pat<(i8 (trunc i16:$src)),727 (EXTRACT_SUBREG MxXRD16:$src, MxSubRegIndex8Lo)>;728 729//===----------------------------------------------------------------------===//730// FMOVE731//===----------------------------------------------------------------------===//732 733let Defs = [FPS] in734class MxFMove<string size, dag outs, dag ins, list<dag> pattern,735 string rounding = "">736 : MxInst<outs, ins,737 "f"#rounding#"move."#size#"\t$src, $dst", pattern> {738 // Only FMOVE uses FPC739 let Uses = !if(!eq(rounding, ""), [FPC], []);740 741 // FSMOVE and FDMOVE are only available after M68040742 let Predicates = [!if(!eq(rounding, ""), AtLeastM68881, AtLeastM68040)];743}744 745// FPDR <- FPDR746class MxFMove_FF<string rounding, int size,747 MxOpBundle Opnd = !cast<MxOpBundle>("MxOp"#size#"AddrMode_fpr")>748 : MxFMove<"x", (outs Opnd.Op:$dst), (ins Opnd.Op:$src),749 [(null_frag)], rounding> {750 let Inst = (ascend751 (descend 0b1111,752 /*COPROCESSOR ID*/0b001,753 0b000,754 /*MODE + REGISTER*/0b000000755 ),756 (descend 0b0, /* R/M */0b0, 0b0,757 /*SOURCE SPECIFIER*/758 (operand "$src", 3),759 /*DESTINATION*/760 (operand "$dst", 3),761 /*OPMODE*/762 !cond(!eq(rounding, "s"): 0b1000000,763 !eq(rounding, "d"): 0b1000100,764 true: 0b0000000)765 )766 );767}768 769foreach rounding = ["", "s", "d"] in {770 def F # !toupper(rounding) # MOV80fp_fp : MxFMove_FF<rounding, 80>;771 772 // We don't have `fmove.s` or `fmove.d` because values will be converted to773 // f80 upon storing into the register, but FMOV32/64fp_fp are still needed774 // to make codegen easier.775 let isCodeGenOnly = true in776 foreach size = [32, 64] in777 def F # !toupper(rounding) # MOV # size # fp_fp : MxFMove_FF<rounding, size>;778}779// Direction780defvar MxFMove_FP_EA = false;781defvar MxFMove_EA_FP = true;782 783// Encoding scheme for FPSYS <-> R/M784class MxEncFSysMove<bit dir, MxEncMemOp EAEnc, string fsys_reg> {785 dag Value = (ascend786 (descend 0b1111,787 /*COPROCESSOR ID*/0b001,788 0b000,789 /*MODE + REGISTER*/790 EAEnc.EA791 ),792 (descend 0b10, /*dir*/ dir,793 /*REGISTER SELECT*/794 (operand "$"#fsys_reg, 3, (encoder "encodeFPSYSSelect")),795 0b0000000000796 )797 );798}799 800// FPSYS <-> R801class MxFMove_FSYS_R<string src_reg,802 MxOpBundle SrcOpnd = !cast<MxOpBundle>("MxOp32AddrMode_"#src_reg),803 MxOpBundle DstOpnd = !cond(!eq(src_reg, "d"): MxOp32AddrMode_fpcs,804 !eq(src_reg, "a"): MxOp32AddrMode_fpi),805 MxEncMemOp SrcEnc = !cast<MxEncMemOp>("MxMoveSrcOpEnc_"#src_reg)>806 : MxFMove<"l", (outs DstOpnd.Op:$dst), (ins SrcOpnd.Op:$src),807 [(null_frag)]> {808 let Inst = MxEncFSysMove<MxFMove_FP_EA, SrcEnc, "dst">.Value;809}810 811class MxFMove_R_FSYS<string dst_reg,812 MxOpBundle SrcOpnd = !cond(!eq(dst_reg, "d"): MxOp32AddrMode_fpcs,813 !eq(dst_reg, "a"): MxOp32AddrMode_fpi),814 MxOpBundle DstOpnd = !cast<MxOpBundle>("MxOp32AddrMode_"#dst_reg),815 MxEncMemOp DstEnc = !cast<MxEncMemOp>("MxMoveDstOpEnc_"#dst_reg)>816 : MxFMove<"l", (outs DstOpnd.Op:$dst), (ins SrcOpnd.Op:$src),817 [(null_frag)]> {818 let Inst = MxEncFSysMove<MxFMove_EA_FP, DstEnc, "src">.Value;819}820 821def FMOVE32fpcs_d : MxFMove_FSYS_R<"d">;822def FMOVE32d_fpcs : MxFMove_R_FSYS<"d">;823def FMOVE32fpi_a : MxFMove_FSYS_R<"a">;824def FMOVE32a_fpi : MxFMove_R_FSYS<"a">;825