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-exception 6// 7//===----------------------------------------------------------------------===// 8/// 9/// \file 10/// This file describes the Motorola 680x0 data movement instructions which are 11/// the basic means of transferring and storing addresses and data. Here is the 12/// 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 all 27/// [!] - requires extarnal stuff implemented 28/// [~] - in progress but usable 29/// [x] - done 30/// 31//===----------------------------------------------------------------------===// 32 33//===----------------------------------------------------------------------===// 34// MOVE 35//===----------------------------------------------------------------------===// 36 37/// ----------------------------------------------------- 38/// F E | D C | B A 9 | 8 7 6 | 5 4 3 | 2 1 0 39/// ----------------------------------------------------- 40/// | | DESTINATION | SOURCE 41/// 0 0 | SIZE | REG | MODE | MODE | REG 42/// ----------------------------------------------------- 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 = (ascend 56 (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 extension 62 src_enc.Supplement, 63 // Destination extension 64 dst_enc.Supplement 65 ); 66} 67 68// Special encoding for Xn 69class 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 // Dn 77 def MxMove#NAME#OpEnc_d : MxEncAddrMode_d<opnd_name>; 78 // An 79 def MxMove#NAME#OpEnc_a : MxEncAddrMode_a<opnd_name>; 80 // Xn 81 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).L 95 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] in 106class 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 <- R 112class 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"] in 122 foreach TYPE = [MxType16, MxType32] in 123 def MOV # TYPE.Size # DST_REG # SRC_REG # TYPE.Postfix 124 : 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_REG 129foreach TYPE = [MxType8, MxType16, MxType32] in 130def MOV # TYPE.Size # dd # TYPE.Postfix 131 : MxMove_RR<TYPE, "d", "d", 132 MxMoveEncoding<!cast<MxMoveSize>("MxMoveSize"#TYPE.Size), 133 MxMoveDstOpEnc_d, MxMoveSrcOpEnc_d>>; 134 135// M <- R 136let 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 = 1 147 148foreach REG = ["r", "a", "d"] in 149foreach AM = MxMoveSupportedAMs in { 150 foreach TYPE = !if(!eq(REG, "d"), [MxType8, MxType16, MxType32], [MxType16, MxType32]) in 151 def MOV # TYPE.Size # AM # REG # TYPE.Postfix 152 : 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 AM 157 158foreach AM = MxMoveSupportedAMs in { 159 foreach TYPE = [MxType8, MxType16, MxType32] in 160 def MOV # TYPE.Size # AM # i # TYPE.Postfix 161 : 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 AM 166 167// R <- I 168// No pattern, as all immediate -> register moves are matched to the MOVI pseudo 169class 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]) in 177 def MOV # TYPE.Size # REG # i # TYPE.Postfix 178 : MxMove_RI<TYPE, REG, 179 MxMoveEncoding<!cast<MxMoveSize>("MxMoveSize"#TYPE.Size), 180 !cast<MxEncMemOp>("MxMoveDstOpEnc_"#REG), 181 MxEncAddrMode_i<"src", TYPE.Size>>>; 182} // foreach REG 183 184// R <- M 185let mayLoad = 1 in 186class 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"] in 195foreach AM = MxMoveSupportedAMs in { 196 foreach TYPE = !if(!eq(REG, "d"), [MxType8, MxType16, MxType32], [MxType16, MxType32]) in 197 def MOV # TYPE.Size # REG # AM # TYPE.Postfix 198 : MxMove_RM<TYPE, REG, !cast<MxOpBundle>("MxOp"#TYPE.Size#"AddrMode_"#AM), 199 !cast<MxEncMemOp>("MxMoveSrcOpEnc_"#AM)>; 200} // foreach AM 201 202// Tail call version 203let Pattern = [(null_frag)] in { 204 foreach REG = ["r", "a"] in 205 foreach AM = MxMoveSupportedAMs in { 206 foreach TYPE = [MxType16, MxType32] in 207 def MOV # TYPE.Size # REG # AM # _TC 208 : MxMove_RM<TYPE, REG, !cast<MxOpBundle>("MxOp"#TYPE.Size#"AddrMode_"#AM), 209 !cast<MxEncMemOp>("MxMoveSrcOpEnc_"#AM)> { 210 let isCodeGenOnly = true; 211 } 212 } // foreach AM 213} // let Pattern 214 215let mayLoad = 1, mayStore = 1 in 216class 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 in 224foreach SRC_AM = MxMoveSupportedAMs in { 225 foreach TYPE = [MxType8, MxType16, MxType32] in 226 def MOV # TYPE.Size # DST_AM # SRC_AM # TYPE.Postfix 227 : 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_AM 232 233// Store ABS(basically pointer) as Immdiate to Mem 234def : 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// MOVEQ 248//===----------------------------------------------------------------------===// 249 250/// ------------+---------+---+----------------------- 251/// F E D C | B A 9 | 8 | 7 6 5 4 3 2 1 0 252/// ------------+---------+---+----------------------- 253/// 0 1 1 1 | REG | 0 | DATA 254/// ------------+---------+---+----------------------- 255 256// No pattern, as all immediate -> register moves are matched to the MOVI pseudo 257let Defs = [CCR] in 258def 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// MOVEM 266// 267// The mask is already pre-processed by the save/restore spill hook 268//===----------------------------------------------------------------------===// 269 270// Direction 271defvar MxMOVEM_MR = false; 272defvar MxMOVEM_RM = true; 273 274// Size 275defvar 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 0 280/// ---------------+---+---------+---+---------+--------- 281/// 0 1 0 0 1 | D | 0 0 1 | S | MODE | REG 282/// ---------------+---+---------+---+---------+--------- 283/// REGISTER LIST MASK 284/// ----------------------------------------------------- 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 = (ascend 290 (descend 0b01001, direction, 0b001, size, opnd_enc.EA), 291 // Mask 292 (operand "$"#mask_op_name, 16), 293 opnd_enc.Supplement 294 ); 295} 296 297let mayStore = 1 in 298class MxMOVEM_MR<MxType TYPE, bit SIZE_ENC, 299 MxOperand MEMOp, MxEncMemOp MEM_ENC> 300 : MxInst<(outs), (ins MEMOp:$dst, MxMoveMask:$mask), 301 "movem."#TYPE.Prefix#"\t$mask, $dst", []> { 302 let Inst = MxMOVEMEncoding<MEM_ENC, SIZE_ENC, MxMOVEM_MR, "mask">.Value; 303} 304 305foreach AM = MxMoveSupportedAMs in { 306 foreach TYPE = [MxType16, MxType32] in 307 def MOVM # TYPE.Size # AM # m # TYPE.Postfix 308 : MxMOVEM_MR<TYPE, !if(!eq(TYPE, MxType16), MxMOVEM_W, MxMOVEM_L), 309 !cast<MxOpBundle>("MxOp"#TYPE.Size#"AddrMode_"#AM).Op, 310 !cast<MxEncMemOp>("MxMoveDstOpEnc_"#AM)>; 311} // foreach AM 312 313let mayLoad = 1 in 314class MxMOVEM_RM<MxType TYPE, bit SIZE_ENC, 315 MxOperand MEMOp, MxEncMemOp MEM_ENC> 316 : MxInst<(outs), (ins MxMoveMask:$mask, MEMOp:$src), 317 "movem."#TYPE.Prefix#"\t$src, $mask", []> { 318 let Inst = MxMOVEMEncoding<MEM_ENC, SIZE_ENC, MxMOVEM_RM, "mask">.Value; 319} 320 321foreach AM = MxMoveSupportedAMs in { 322 foreach TYPE = [MxType16, MxType32] in 323 def MOVM # TYPE.Size # m # AM # TYPE.Postfix 324 : MxMOVEM_RM<TYPE, !if(!eq(TYPE, MxType16), MxMOVEM_W, MxMOVEM_L), 325 !cast<MxOpBundle>("MxOp"#TYPE.Size#"AddrMode_"#AM).Op, 326 !cast<MxEncMemOp>("MxMoveSrcOpEnc_"#AM)>; 327} // foreach AM 328 329// Pseudo versions. These a required by virtual register spill/restore since 330// the mask requires real register to encode. These instruction will be expanded 331// into real MOVEM after RA finishes. 332let mayStore = 1 in 333class MxMOVEM_MR_Pseudo<MxType TYPE, MxOperand MEMOp> 334 : MxPseudo<(outs), (ins MEMOp:$dst, TYPE.ROp:$reg)>; 335let mayLoad = 1 in 336class MxMOVEM_RM_Pseudo<MxType TYPE, MxOperand MEMOp> 337 : MxPseudo<(outs TYPE.ROp:$dst), (ins MEMOp:$src)>; 338 339// Mem <- Reg 340def MOVM8jm_P : MxMOVEM_MR_Pseudo<MxType8d, MxType8.JOp>; 341def MOVM16jm_P : MxMOVEM_MR_Pseudo<MxType16r, MxType16.JOp>; 342def MOVM32jm_P : MxMOVEM_MR_Pseudo<MxType32r, MxType32.JOp>; 343 344def MOVM8pm_P : MxMOVEM_MR_Pseudo<MxType8d, MxType8.POp>; 345def MOVM16pm_P : MxMOVEM_MR_Pseudo<MxType16r, MxType16.POp>; 346def MOVM32pm_P : MxMOVEM_MR_Pseudo<MxType32r, MxType32.POp>; 347 348// Reg <- Mem 349def MOVM8mj_P : MxMOVEM_RM_Pseudo<MxType8d, MxType8.JOp>; 350def MOVM16mj_P : MxMOVEM_RM_Pseudo<MxType16r, MxType16.JOp>; 351def MOVM32mj_P : MxMOVEM_RM_Pseudo<MxType32r, MxType32.JOp>; 352 353def MOVM8mp_P : MxMOVEM_RM_Pseudo<MxType8d, MxType8.POp>; 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/CCR 360// 361// A special care must be taken working with to/from CCR since it is basically 362// word-size SR register truncated for user mode thus it only supports word-size 363// instructions. Plus the original M68000 does not support moves from CCR. So in 364// 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 CCR 369/// -------------------------------------------------- 370/// F E D C B A 9 8 7 6 | 5 4 3 | 2 1 0 371/// -------------------------------------------------- 372/// | EFFECTIVE ADDRESS 373/// 0 1 0 0 0 1 0 0 1 1 | MODE | REG 374/// -------------------------------------------------- 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 = (ascend 379 (descend 0b0100010011, SRC_ENC.EA), 380 SRC_ENC.Supplement 381 ); 382} 383 384class MxMoveToCCRPseudo<MxOperand MEMOp> 385 : MxPseudo<(outs CCRC:$dst), (ins MEMOp:$src)>; 386} // let Defs = [CCR] 387 388let mayLoad = 1 in 389foreach 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 AM 394 395// Only data register is allowed. 396def MOV16cd : MxMoveToCCR<MxOp16AddrMode_d.Op, MxMoveSrcOpEnc_d>; 397def MOV8cd : MxMoveToCCRPseudo<MxOp8AddrMode_d.Op>; 398 399/// Move from CCR 400/// -------------------------------------------------- 401/// F E D C B A 9 8 7 6 | 5 4 3 | 2 1 0 402/// -------------------------------------------------- 403/// | EFFECTIVE ADDRESS 404/// 0 1 0 0 0 0 1 0 1 1 | MODE | REG 405/// -------------------------------------------------- 406let Uses = [CCR] in { 407class MxMoveFromCCR_R 408 : 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 = (ascend 417 (descend 0b0100001011, DST_ENC.EA), 418 DST_ENC.Supplement 419 ); 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 in 429foreach AM = MxMoveSupportedAMs in { 430 def MOV16 # AM # c 431 : MxMoveFromCCR_M<!cast<MxOpBundle>("MxOp16AddrMode_"#AM).Op, 432 !cast<MxEncMemOp>("MxMoveDstOpEnc_"#AM)>; 433 def MOV8 # AM # c 434 : MxMoveFromCCRPseudo<!cast<MxOpBundle>("MxOp8AddrMode_"#AM).Op>; 435} // foreach AM 436 437// Only data register is allowed. 438def MOV16dc : MxMoveFromCCR_R; 439def MOV8dc : MxMoveFromCCR_RPseudo<MxOp8AddrMode_d.Op>; 440 441/// Move to SR 442/// -------------------------------------------------- 443/// F E D C B A 9 8 7 6 | 5 4 3 | 2 1 0 444/// -------------------------------------------------- 445/// | EFFECTIVE ADDRESS 446/// 0 1 0 0 0 1 1 0 1 1 | MODE | REG 447/// -------------------------------------------------- 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 = (ascend 452 (descend 0b0100011011, SRC_ENC.EA), 453 SRC_ENC.Supplement 454 ); 455} 456} // let Defs = [SR] 457 458let mayLoad = 1 in 459foreach AM = MxMoveSupportedAMs in { 460 def MOV16s # AM : MxMoveToSR<!cast<MxOpBundle>("MxOp16AddrMode_"#AM).Op, 461 !cast<MxEncMemOp>("MxMoveSrcOpEnc_"#AM)>; 462} // foreach AM 463 464def MOV16sd : MxMoveToSR<MxOp16AddrMode_d.Op, MxMoveSrcOpEnc_d>; 465 466/// Move from SR 467/// -------------------------------------------------- 468/// F E D C B A 9 8 7 6 | 5 4 3 | 2 1 0 469/// -------------------------------------------------- 470/// | EFFECTIVE ADDRESS 471/// 0 1 0 0 0 0 0 0 1 1 | MODE | REG 472/// -------------------------------------------------- 473let Uses = [SR] in { 474class MxMoveFromSR_R 475 : 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 = (ascend 484 (descend 0b0100000011, DST_ENC.EA), 485 DST_ENC.Supplement 486 ); 487} 488} // let Uses = [SR] 489 490let mayStore = 1 in 491foreach AM = MxMoveSupportedAMs in { 492 def MOV16 # AM # s 493 : MxMoveFromSR_M<!cast<MxOpBundle>("MxOp16AddrMode_"#AM).Op, 494 !cast<MxEncMemOp>("MxMoveDstOpEnc_"#AM)>; 495} // foreach AM 496 497def MOV16ds : MxMoveFromSR_R; 498 499//===----------------------------------------------------------------------===// 500// LEA 501//===----------------------------------------------------------------------===// 502 503/// ---------------------------------------------------- 504/// F E D C | B A 9 | 8 7 6 | 5 4 3 | 2 1 0 505/// ---------------------------------------------------- 506/// 0 1 0 0 | DST REG | 1 1 1 | MODE | REG 507/// ---------------------------------------------------- 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 = (ascend 512 (descend 0b0100, (operand "$dst", 3), 0b111, SRC_ENC.EA), 513 SRC_ENC.Supplement 514 ); 515} 516 517foreach AM = ["p", "f", "b", "q", "k"] in 518def LEA32 # AM : MxLEA<!cast<MxOpBundle>("MxOp32AddrMode_"#AM), 519 !cast<MxEncMemOp>("MxMoveSrcOpEnc_"#AM)>; 520 521//===----------------------------------------------------------------------===// 522// LINK/UNLK 523//===----------------------------------------------------------------------===// 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 = (ascend 530 (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 = (ascend 537 (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 = 1 548} // let Uses = [SP], Defs = [SP] 549 550//===----------------------------------------------------------------------===// 551// Pseudos 552//===----------------------------------------------------------------------===// 553 554/// Pushe/Pop to/from SP for simplicity 555let Uses = [SP], Defs = [SP], hasSideEffects = 0 in { 556 557// SP <- SP - <size>; (SP) <- Dn 558let 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 = 1 563 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 = 1 570 571} // let Uses/Defs = [SP], hasSideEffects = 0 572 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 to 586// 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, but 599/// since M68k does not have those we need to emulate. These instructions 600/// will be expanded right after RA completed because we need to know precisely 601/// what registers are allocated for the operands and if they overlap we just 602/// extend the value if the registers are completely different we need to move 603/// 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 do 634/// any value extension, they just load a smaller register into the lower part 635/// of another register if operands' real registers are different or does 636/// 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 Patterns 643//===----------------------------------------------------------------------===// 644 645// i16 <- sext i8 646def: 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 i8 657def: 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 i16 664def: 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 i8 671def: 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 i8 682def: 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 i16 689def: 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 i8 696def: 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)>; 704 705// i32 <- anyext i8 706def: Pat<(i32 (anyext i8:$src)), (MOVZXd32d8 MxDRD8:$src)>; 707def: Pat<(MxExtLoadi32i8 MxCP_ARI :$src), (MOVZXd32j8 MxARI8 :$src)>; 708def: Pat<(MxExtLoadi32i8 MxCP_ARID:$src), (MOVZXd32p8 MxARID8:$src)>; 709def: Pat<(MxExtLoadi32i8 MxCP_ARII:$src), (MOVZXd32f8 MxARII8:$src)>; 710 711// i32 <- anyext i16 712def: Pat<(i32 (anyext i16:$src)), (MOVZXd32d16 MxDRD16:$src)>; 713def: Pat<(MxExtLoadi32i16 MxCP_ARI :$src), (MOVZXd32j16 MxARI16 :$src)>; 714def: Pat<(MxExtLoadi32i16 MxCP_ARID:$src), (MOVZXd32p16 MxARID16:$src)>; 715def: Pat<(MxExtLoadi32i16 MxCP_ARII:$src), (MOVZXd32f16 MxARII16:$src)>; 716 717// trunc patterns 718def : Pat<(i16 (trunc i32:$src)), 719 (EXTRACT_SUBREG MxXRD32:$src, MxSubRegIndex16Lo)>; 720def : Pat<(i8 (trunc i32:$src)), 721 (EXTRACT_SUBREG MxXRD32:$src, MxSubRegIndex8Lo)>; 722def : Pat<(i8 (trunc i16:$src)), 723 (EXTRACT_SUBREG MxXRD16:$src, MxSubRegIndex8Lo)>; 724 725//===----------------------------------------------------------------------===// 726// FMOVE 727//===----------------------------------------------------------------------===// 728 729let Defs = [FPS] in 730class MxFMove<string size, dag outs, dag ins, list<dag> pattern, 731 string rounding = ""> 732 : MxInst<outs, ins, 733 "f"#rounding#"move."#size#"\t$src, $dst", pattern> { 734 // Only FMOVE uses FPC 735 let Uses = !if(!eq(rounding, ""), [FPC], []); 736 737 // FSMOVE and FDMOVE are only available after M68040 738 let Predicates = [!if(!eq(rounding, ""), AtLeastM68881, AtLeastM68040)]; 739} 740 741// FPDR <- FPDR 742class MxFMove_FF<string rounding, int size, 743 MxOpBundle Opnd = !cast<MxOpBundle>("MxOp"#size#"AddrMode_fpr")> 744 : MxFMove<"x", (outs Opnd.Op:$dst), (ins Opnd.Op:$src), 745 [(null_frag)], rounding> { 746 let Inst = (ascend 747 (descend 0b1111, 748 /*COPROCESSOR ID*/0b001, 749 0b000, 750 /*MODE + REGISTER*/0b000000 751 ), 752 (descend 0b0, /* R/M */0b0, 0b0, 753 /*SOURCE SPECIFIER*/ 754 (operand "$src", 3), 755 /*DESTINATION*/ 756 (operand "$dst", 3), 757 /*OPMODE*/ 758 !cond(!eq(rounding, "s"): 0b1000000, 759 !eq(rounding, "d"): 0b1000100, 760 true: 0b0000000) 761 ) 762 ); 763} 764 765foreach rounding = ["", "s", "d"] in { 766 def F # !toupper(rounding) # MOV80fp_fp : MxFMove_FF<rounding, 80>; 767 768 // We don't have `fmove.s` or `fmove.d` because values will be converted to 769 // f80 upon storing into the register, but FMOV32/64fp_fp are still needed 770 // to make codegen easier. 771 let isCodeGenOnly = true in 772 foreach size = [32, 64] in 773 def F # !toupper(rounding) # MOV # size # fp_fp : MxFMove_FF<rounding, size>; 774} 775// Direction 776defvar MxFMove_FP_EA = false; 777defvar MxFMove_EA_FP = true; 778 779// Encoding scheme for FPSYS <-> R/M 780class MxEncFSysMove<bit dir, MxEncMemOp EAEnc, string fsys_reg> { 781 dag Value = (ascend 782 (descend 0b1111, 783 /*COPROCESSOR ID*/0b001, 784 0b000, 785 /*MODE + REGISTER*/ 786 EAEnc.EA 787 ), 788 (descend 0b10, /*dir*/ dir, 789 /*REGISTER SELECT*/ 790 (operand "$"#fsys_reg, 3, (encoder "encodeFPSYSSelect")), 791 0b0000000000 792 ) 793 ); 794} 795 796// FPSYS <-> R 797class MxFMove_FSYS_R<string src_reg, 798 MxOpBundle SrcOpnd = !cast<MxOpBundle>("MxOp32AddrMode_"#src_reg), 799 MxOpBundle DstOpnd = !cond(!eq(src_reg, "d"): MxOp32AddrMode_fpcs, 800 !eq(src_reg, "a"): MxOp32AddrMode_fpi), 801 MxEncMemOp SrcEnc = !cast<MxEncMemOp>("MxMoveSrcOpEnc_"#src_reg)> 802 : MxFMove<"l", (outs DstOpnd.Op:$dst), (ins SrcOpnd.Op:$src), 803 [(null_frag)]> { 804 let Inst = MxEncFSysMove<MxFMove_FP_EA, SrcEnc, "dst">.Value; 805} 806 807class MxFMove_R_FSYS<string dst_reg, 808 MxOpBundle SrcOpnd = !cond(!eq(dst_reg, "d"): MxOp32AddrMode_fpcs, 809 !eq(dst_reg, "a"): MxOp32AddrMode_fpi), 810 MxOpBundle DstOpnd = !cast<MxOpBundle>("MxOp32AddrMode_"#dst_reg), 811 MxEncMemOp DstEnc = !cast<MxEncMemOp>("MxMoveDstOpEnc_"#dst_reg)> 812 : MxFMove<"l", (outs DstOpnd.Op:$dst), (ins SrcOpnd.Op:$src), 813 [(null_frag)]> { 814 let Inst = MxEncFSysMove<MxFMove_EA_FP, DstEnc, "src">.Value; 815} 816 817def FMOVE32fpcs_d : MxFMove_FSYS_R<"d">; 818def FMOVE32d_fpcs : MxFMove_R_FSYS<"d">; 819def FMOVE32fpi_a : MxFMove_FSYS_R<"a">; 820def FMOVE32a_fpi : MxFMove_R_FSYS<"a">; 821