104eeddc0SDimitry Andric//===-- M68kInstrData.td - M68k Data Movement Instructions -*- tablegen -*-===// 2fe6060f1SDimitry Andric// 3fe6060f1SDimitry Andric// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4fe6060f1SDimitry Andric// See https://llvm.org/LICENSE.txt for license information. 5fe6060f1SDimitry Andric// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6fe6060f1SDimitry Andric// 7fe6060f1SDimitry Andric//===----------------------------------------------------------------------===// 8fe6060f1SDimitry Andric/// 9fe6060f1SDimitry Andric/// \file 10fe6060f1SDimitry Andric/// This file describes the Motorola 680x0 data movement instructions which are 11fe6060f1SDimitry Andric/// the basic means of transferring and storing addresses and data. Here is the 12fe6060f1SDimitry Andric/// current status of the file: 13fe6060f1SDimitry Andric/// 14fe6060f1SDimitry Andric/// Machine: 15fe6060f1SDimitry Andric/// 16fe6060f1SDimitry Andric/// EXG [ ] FMOVE [ ] FSMOVE [ ] FDMOVE [ ] FMOVEM [ ] 17fe6060f1SDimitry Andric/// LEA [~] PEA [ ] MOVE [~] MOVE16 [ ] MOVEA [ ] 18bdd1243dSDimitry Andric/// MOVEM [ ] MOVEP [ ] MOVEQ [ ] LINK [~] UNLK [~] 19fe6060f1SDimitry Andric/// 20fe6060f1SDimitry Andric/// Pseudo: 21fe6060f1SDimitry Andric/// 22*0fca6ea1SDimitry Andric/// MOVI [x] MOVSX [x] MOVZX [x] MOVX [x] 23fe6060f1SDimitry Andric/// 24fe6060f1SDimitry Andric/// Map: 25fe6060f1SDimitry Andric/// 26fe6060f1SDimitry Andric/// [ ] - was not touched at all 27fe6060f1SDimitry Andric/// [!] - requires extarnal stuff implemented 28fe6060f1SDimitry Andric/// [~] - in progress but usable 29fe6060f1SDimitry Andric/// [x] - done 30fe6060f1SDimitry Andric/// 31fe6060f1SDimitry Andric//===----------------------------------------------------------------------===// 32fe6060f1SDimitry Andric 33fe6060f1SDimitry Andric//===----------------------------------------------------------------------===// 34fe6060f1SDimitry Andric// MOVE 35fe6060f1SDimitry Andric//===----------------------------------------------------------------------===// 36fe6060f1SDimitry Andric 37fe6060f1SDimitry Andric/// ----------------------------------------------------- 38fe6060f1SDimitry Andric/// F E | D C | B A 9 | 8 7 6 | 5 4 3 | 2 1 0 39fe6060f1SDimitry Andric/// ----------------------------------------------------- 40fe6060f1SDimitry Andric/// | | DESTINATION | SOURCE 41fe6060f1SDimitry Andric/// 0 0 | SIZE | REG | MODE | MODE | REG 42fe6060f1SDimitry Andric/// ----------------------------------------------------- 43fe6060f1SDimitry Andric/// 44fe6060f1SDimitry Andric/// NOTE Move requires EA X version for direct register destination(0) 45fe6060f1SDimitry Andric 4681ad6265SDimitry Andric// MOVE has a different size encoding. 4781ad6265SDimitry Andricclass MxMoveSize<bits<2> value> { 4881ad6265SDimitry Andric bits<2> Value = value; 4981ad6265SDimitry Andric} 50fe6060f1SDimitry Andricdef MxMoveSize8 : MxMoveSize<0b01>; 51fe6060f1SDimitry Andricdef MxMoveSize16 : MxMoveSize<0b11>; 52fe6060f1SDimitry Andricdef MxMoveSize32 : MxMoveSize<0b10>; 53fe6060f1SDimitry Andric 5481ad6265SDimitry Andricclass MxMoveEncoding<MxMoveSize size, MxEncMemOp dst_enc, MxEncMemOp src_enc> { 5581ad6265SDimitry Andric dag Value = (ascend 5681ad6265SDimitry Andric (descend 0b00, size.Value, 5781ad6265SDimitry Andric !cond( 5881ad6265SDimitry Andric !eq(!getdagop(dst_enc.EA), descend): !setdagop(dst_enc.EA, ascend), 5981ad6265SDimitry Andric !eq(!getdagop(dst_enc.EA), ascend): !setdagop(dst_enc.EA, descend)), 6081ad6265SDimitry Andric src_enc.EA), 6181ad6265SDimitry Andric // Source extension 6281ad6265SDimitry Andric src_enc.Supplement, 6381ad6265SDimitry Andric // Destination extension 6481ad6265SDimitry Andric dst_enc.Supplement 6581ad6265SDimitry Andric ); 6681ad6265SDimitry Andric} 67fe6060f1SDimitry Andric 6881ad6265SDimitry Andric// Special encoding for Xn 6981ad6265SDimitry Andricclass MxMoveEncAddrMode_r<string reg_opnd> : MxEncMemOp { 7081ad6265SDimitry Andric let EA = (descend (descend 0b00, (slice "$"#reg_opnd, 3, 3)), 7181ad6265SDimitry Andric (operand "$"#reg_opnd, 3)); 7281ad6265SDimitry Andric} 7381ad6265SDimitry Andric 7481ad6265SDimitry Andric// TODO: Generalize and adopt this utility in other .td files as well. 7581ad6265SDimitry Andricmulticlass MxMoveOperandEncodings<string opnd_name> { 7681ad6265SDimitry Andric // Dn 7781ad6265SDimitry Andric def MxMove#NAME#OpEnc_d : MxEncAddrMode_d<opnd_name>; 7881ad6265SDimitry Andric // An 7981ad6265SDimitry Andric def MxMove#NAME#OpEnc_a : MxEncAddrMode_a<opnd_name>; 8081ad6265SDimitry Andric // Xn 8181ad6265SDimitry Andric def MxMove#NAME#OpEnc_r : MxMoveEncAddrMode_r<opnd_name>; 8281ad6265SDimitry Andric // (An)+ 8381ad6265SDimitry Andric def MxMove#NAME#OpEnc_o : MxEncAddrMode_o<opnd_name>; 8481ad6265SDimitry Andric // -(An) 8581ad6265SDimitry Andric def MxMove#NAME#OpEnc_e : MxEncAddrMode_e<opnd_name>; 8681ad6265SDimitry Andric // (i,PC,Xn) 8781ad6265SDimitry Andric def MxMove#NAME#OpEnc_k : MxEncAddrMode_k<opnd_name>; 8881ad6265SDimitry Andric // (i,PC) 8981ad6265SDimitry Andric def MxMove#NAME#OpEnc_q : MxEncAddrMode_q<opnd_name>; 9081ad6265SDimitry Andric // (i,An,Xn) 9181ad6265SDimitry Andric def MxMove#NAME#OpEnc_f : MxEncAddrMode_f<opnd_name>; 9281ad6265SDimitry Andric // (i,An) 9381ad6265SDimitry Andric def MxMove#NAME#OpEnc_p : MxEncAddrMode_p<opnd_name>; 9481ad6265SDimitry Andric // (ABS).L 9581ad6265SDimitry Andric def MxMove#NAME#OpEnc_b : MxEncAddrMode_abs<opnd_name, /*W/L=*/true>; 9681ad6265SDimitry Andric // (An) 9781ad6265SDimitry Andric def MxMove#NAME#OpEnc_j : MxEncAddrMode_j<opnd_name>; 9881ad6265SDimitry Andric} 9981ad6265SDimitry Andric 10081ad6265SDimitry Andricdefm Src : MxMoveOperandEncodings<"src">; 10181ad6265SDimitry Andricdefm Dst : MxMoveOperandEncodings<"dst">; 10281ad6265SDimitry Andric 10381ad6265SDimitry Andricdefvar MxMoveSupportedAMs = ["o", "e", "k", "q", "f", "p", "b", "j"]; 10481ad6265SDimitry Andric 10581ad6265SDimitry Andriclet Defs = [CCR] in 10681ad6265SDimitry Andricclass MxMove<string size, dag outs, dag ins, list<dag> pattern, MxMoveEncoding enc> 10781ad6265SDimitry Andric : MxInst<outs, ins, "move."#size#"\t$src, $dst", pattern> { 10881ad6265SDimitry Andric let Inst = enc.Value; 10981ad6265SDimitry Andric} 11081ad6265SDimitry Andric 11181ad6265SDimitry Andric// R <- R 11281ad6265SDimitry Andricclass MxMove_RR<MxType TYPE, string DST_REG, string SRC_REG, 11381ad6265SDimitry Andric MxMoveEncoding ENC, 11481ad6265SDimitry Andric MxOpBundle DST = !cast<MxOpBundle>("MxOp"#TYPE.Size#"AddrMode_"#DST_REG), 11581ad6265SDimitry Andric MxOpBundle SRC = !cast<MxOpBundle>("MxOp"#TYPE.Size#"AddrMode_"#SRC_REG)> 11681ad6265SDimitry Andric : MxMove<TYPE.Prefix, 11781ad6265SDimitry Andric (outs DST.Op:$dst), (ins SRC.Op:$src), 118fe6060f1SDimitry Andric [(null_frag)], ENC>; 119fe6060f1SDimitry Andric 12081ad6265SDimitry Andricforeach DST_REG = ["r", "a"] in { 12181ad6265SDimitry Andric foreach SRC_REG = ["r", "a"] in 12281ad6265SDimitry Andric foreach TYPE = [MxType16, MxType32] in 12381ad6265SDimitry Andric def MOV # TYPE.Size # DST_REG # SRC_REG # TYPE.Postfix 12481ad6265SDimitry Andric : MxMove_RR<TYPE, DST_REG, SRC_REG, 12581ad6265SDimitry Andric MxMoveEncoding<!cast<MxMoveSize>("MxMoveSize"#TYPE.Size), 12681ad6265SDimitry Andric !cast<MxEncMemOp>("MxMoveDstOpEnc_"#DST_REG), 12781ad6265SDimitry Andric !cast<MxEncMemOp>("MxMoveSrcOpEnc_"#SRC_REG)>>; 12881ad6265SDimitry Andric} // foreach DST_REG 12981ad6265SDimitry Andricforeach TYPE = [MxType8, MxType16, MxType32] in 13081ad6265SDimitry Andricdef MOV # TYPE.Size # dd # TYPE.Postfix 13181ad6265SDimitry Andric : MxMove_RR<TYPE, "d", "d", 13281ad6265SDimitry Andric MxMoveEncoding<!cast<MxMoveSize>("MxMoveSize"#TYPE.Size), 13381ad6265SDimitry Andric MxMoveDstOpEnc_d, MxMoveSrcOpEnc_d>>; 134fe6060f1SDimitry Andric 13581ad6265SDimitry Andric// M <- R 13681ad6265SDimitry Andriclet mayStore = 1 in { 13781ad6265SDimitry Andricclass MxMove_MR<MxType TYPE, MxOpBundle DST, string SRC_REG, MxMoveEncoding ENC, 13881ad6265SDimitry Andric MxOpBundle SRC = !cast<MxOpBundle>("MxOp"#TYPE.Size#"AddrMode_"#SRC_REG)> 13981ad6265SDimitry Andric : MxMove<TYPE.Prefix, (outs), (ins DST.Op:$dst, SRC.Op:$src), 14081ad6265SDimitry Andric [(store TYPE.VT:$src, DST.Pat:$dst)], ENC>; 14181ad6265SDimitry Andric 14281ad6265SDimitry Andricclass MxMove_MI<MxType TYPE, MxOpBundle DST, MxMoveEncoding ENC, 14381ad6265SDimitry Andric MxImmOpBundle SRC = !cast<MxImmOpBundle>("MxOp"#TYPE.Size#"AddrMode_i")> 14481ad6265SDimitry Andric : MxMove<TYPE.Prefix, (outs), (ins DST.Op:$dst, SRC.Op:$src), 14581ad6265SDimitry Andric [(store SRC.ImmPat:$src, DST.Pat:$dst)], ENC>; 146fe6060f1SDimitry Andric} // let mayStore = 1 147fe6060f1SDimitry Andric 14881ad6265SDimitry Andricforeach REG = ["r", "a", "d"] in 14981ad6265SDimitry Andricforeach AM = MxMoveSupportedAMs in { 15081ad6265SDimitry Andric foreach TYPE = !if(!eq(REG, "d"), [MxType8, MxType16, MxType32], [MxType16, MxType32]) in 15181ad6265SDimitry Andric def MOV # TYPE.Size # AM # REG # TYPE.Postfix 15281ad6265SDimitry Andric : MxMove_MR<TYPE, !cast<MxOpBundle>("MxOp"#TYPE.Size#"AddrMode_"#AM), REG, 15381ad6265SDimitry Andric MxMoveEncoding<!cast<MxMoveSize>("MxMoveSize"#TYPE.Size), 15481ad6265SDimitry Andric !cast<MxEncMemOp>("MxMoveDstOpEnc_"#AM), 15581ad6265SDimitry Andric !cast<MxEncMemOp>("MxMoveSrcOpEnc_"#REG)>>; 15681ad6265SDimitry Andric} // foreach AM 157fe6060f1SDimitry Andric 15881ad6265SDimitry Andricforeach AM = MxMoveSupportedAMs in { 15981ad6265SDimitry Andric foreach TYPE = [MxType8, MxType16, MxType32] in 16081ad6265SDimitry Andric def MOV # TYPE.Size # AM # i # TYPE.Postfix 16181ad6265SDimitry Andric : MxMove_MI<TYPE, !cast<MxOpBundle>("MxOp"#TYPE.Size#"AddrMode_"#AM), 16281ad6265SDimitry Andric MxMoveEncoding<!cast<MxMoveSize>("MxMoveSize"#TYPE.Size), 16381ad6265SDimitry Andric !cast<MxEncMemOp>("MxMoveDstOpEnc_"#AM), 16481ad6265SDimitry Andric MxEncAddrMode_i<"src", TYPE.Size>>>; 16581ad6265SDimitry Andric} // foreach AM 166fe6060f1SDimitry Andric 16781ad6265SDimitry Andric// R <- I 168*0fca6ea1SDimitry Andric// No pattern, as all immediate -> register moves are matched to the MOVI pseudo 16981ad6265SDimitry Andricclass MxMove_RI<MxType TYPE, string DST_REG, MxMoveEncoding ENC, 17081ad6265SDimitry Andric MxImmOpBundle SRC = !cast<MxImmOpBundle>("MxOp"#TYPE.Size#"AddrMode_i"), 17181ad6265SDimitry Andric MxOpBundle DST = !cast<MxOpBundle>("MxOp"#TYPE.Size#"AddrMode_"#DST_REG)> 17281ad6265SDimitry Andric : MxMove<TYPE.Prefix, (outs DST.Op:$dst), (ins SRC.Op:$src), 173*0fca6ea1SDimitry Andric [(null_frag)], ENC>; 17481ad6265SDimitry Andric 17581ad6265SDimitry Andricforeach REG = ["r", "a", "d"] in { 17681ad6265SDimitry Andric foreach TYPE = !if(!eq(REG, "d"), [MxType8, MxType16, MxType32], [MxType16, MxType32]) in 17781ad6265SDimitry Andric def MOV # TYPE.Size # REG # i # TYPE.Postfix 17881ad6265SDimitry Andric : MxMove_RI<TYPE, REG, 17981ad6265SDimitry Andric MxMoveEncoding<!cast<MxMoveSize>("MxMoveSize"#TYPE.Size), 18081ad6265SDimitry Andric !cast<MxEncMemOp>("MxMoveDstOpEnc_"#REG), 18181ad6265SDimitry Andric MxEncAddrMode_i<"src", TYPE.Size>>>; 18281ad6265SDimitry Andric} // foreach REG 18381ad6265SDimitry Andric 18481ad6265SDimitry Andric// R <- M 185fe6060f1SDimitry Andriclet mayLoad = 1 in 18681ad6265SDimitry Andricclass MxMove_RM<MxType TYPE, string DST_REG, MxOpBundle SRC, MxEncMemOp SRC_ENC, 18781ad6265SDimitry Andric MxMoveSize SIZE_ENC = !cast<MxMoveSize>("MxMoveSize"#TYPE.Size), 18881ad6265SDimitry Andric MxOpBundle DST = !cast<MxOpBundle>("MxOp"#TYPE.Size#"AddrMode_"#DST_REG), 18981ad6265SDimitry Andric MxEncMemOp DST_ENC = !cast<MxEncMemOp>("MxMoveDstOpEnc_"#DST_REG)> 19081ad6265SDimitry Andric : MxMove<TYPE.Prefix, (outs DST.Op:$dst), (ins SRC.Op:$src), 19181ad6265SDimitry Andric [(set TYPE.VT:$dst, (TYPE.Load SRC.Pat:$src))], 19281ad6265SDimitry Andric MxMoveEncoding<SIZE_ENC, DST_ENC, SRC_ENC>>; 193fe6060f1SDimitry Andric 19481ad6265SDimitry Andricforeach REG = ["r", "a", "d"] in 19581ad6265SDimitry Andricforeach AM = MxMoveSupportedAMs in { 19681ad6265SDimitry Andric foreach TYPE = !if(!eq(REG, "d"), [MxType8, MxType16, MxType32], [MxType16, MxType32]) in 19781ad6265SDimitry Andric def MOV # TYPE.Size # REG # AM # TYPE.Postfix 19881ad6265SDimitry Andric : MxMove_RM<TYPE, REG, !cast<MxOpBundle>("MxOp"#TYPE.Size#"AddrMode_"#AM), 19981ad6265SDimitry Andric !cast<MxEncMemOp>("MxMoveSrcOpEnc_"#AM)>; 20081ad6265SDimitry Andric} // foreach AM 201fe6060f1SDimitry Andric 20281ad6265SDimitry Andric// Tail call version 20381ad6265SDimitry Andriclet Pattern = [(null_frag)] in { 20481ad6265SDimitry Andric foreach REG = ["r", "a"] in 20581ad6265SDimitry Andric foreach AM = MxMoveSupportedAMs in { 20681ad6265SDimitry Andric foreach TYPE = [MxType16, MxType32] in 20781ad6265SDimitry Andric def MOV # TYPE.Size # REG # AM # _TC 20881ad6265SDimitry Andric : MxMove_RM<TYPE, REG, !cast<MxOpBundle>("MxOp"#TYPE.Size#"AddrMode_"#AM), 20981ad6265SDimitry Andric !cast<MxEncMemOp>("MxMoveSrcOpEnc_"#AM)> { 21081ad6265SDimitry Andric let isCodeGenOnly = true; 211fe6060f1SDimitry Andric } 21281ad6265SDimitry Andric } // foreach AM 21381ad6265SDimitry Andric} // let Pattern 214fe6060f1SDimitry Andric 21581ad6265SDimitry Andriclet mayLoad = 1, mayStore = 1 in 21681ad6265SDimitry Andricclass MxMove_MM<MxType TYPE, MxOpBundle DST, MxOpBundle SRC, 21781ad6265SDimitry Andric MxEncMemOp DST_ENC, MxEncMemOp SRC_ENC> 21881ad6265SDimitry Andric : MxMove<TYPE.Prefix, (outs), (ins DST.Op:$dst, SRC.Op:$src), 21981ad6265SDimitry Andric [(store (TYPE.Load SRC.Pat:$src), DST.Pat:$dst)], 22081ad6265SDimitry Andric MxMoveEncoding<!cast<MxMoveSize>("MxMoveSize"#TYPE.Size), 22181ad6265SDimitry Andric DST_ENC, SRC_ENC>>; 222fe6060f1SDimitry Andric 22381ad6265SDimitry Andricforeach DST_AM = MxMoveSupportedAMs in 22481ad6265SDimitry Andricforeach SRC_AM = MxMoveSupportedAMs in { 22581ad6265SDimitry Andric foreach TYPE = [MxType8, MxType16, MxType32] in 22681ad6265SDimitry Andric def MOV # TYPE.Size # DST_AM # SRC_AM # TYPE.Postfix 22781ad6265SDimitry Andric : MxMove_MM<TYPE, !cast<MxOpBundle>("MxOp"#TYPE.Size#"AddrMode_"#DST_AM), 22881ad6265SDimitry Andric !cast<MxOpBundle>("MxOp"#TYPE.Size#"AddrMode_"#SRC_AM), 22981ad6265SDimitry Andric !cast<MxEncMemOp>("MxMoveDstOpEnc_"#DST_AM), 23081ad6265SDimitry Andric !cast<MxEncMemOp>("MxMoveSrcOpEnc_"#SRC_AM)>; 23181ad6265SDimitry Andric} // foreach SRC_AM 232fe6060f1SDimitry Andric 233fe6060f1SDimitry Andric// Store ABS(basically pointer) as Immdiate to Mem 234fe6060f1SDimitry Andricdef : Pat<(store MxType32.BPat :$src, MxType32.PPat :$dst), 235fe6060f1SDimitry Andric (MOV32pi MxType32.POp :$dst, MxType32.IOp :$src)>; 236fe6060f1SDimitry Andric 237fe6060f1SDimitry Andricdef : Pat<(store MxType32.BPat :$src, MxType32.FPat :$dst), 238fe6060f1SDimitry Andric (MOV32fi MxType32.FOp :$dst, MxType32.IOp :$src)>; 239fe6060f1SDimitry Andric 240fe6060f1SDimitry Andricdef : Pat<(store MxType32.BPat :$src, MxType32.BPat :$dst), 241fe6060f1SDimitry Andric (MOV32bi MxType32.BOp :$dst, MxType32.IOp :$src)>; 242fe6060f1SDimitry Andric 243fe6060f1SDimitry Andricdef : Pat<(store MxType32.BPat :$src, MxType32.JPat :$dst), 244fe6060f1SDimitry Andric (MOV32ji MxType32.JOp :$dst, MxType32.IOp :$src)>; 245fe6060f1SDimitry Andric 246fe6060f1SDimitry Andric//===----------------------------------------------------------------------===// 247*0fca6ea1SDimitry Andric// MOVEQ 248*0fca6ea1SDimitry Andric//===----------------------------------------------------------------------===// 249*0fca6ea1SDimitry Andric 250*0fca6ea1SDimitry Andric/// ------------+---------+---+----------------------- 251*0fca6ea1SDimitry Andric/// F E D C | B A 9 | 8 | 7 6 5 4 3 2 1 0 252*0fca6ea1SDimitry Andric/// ------------+---------+---+----------------------- 253*0fca6ea1SDimitry Andric/// 0 1 1 1 | REG | 0 | DATA 254*0fca6ea1SDimitry Andric/// ------------+---------+---+----------------------- 255*0fca6ea1SDimitry Andric 256*0fca6ea1SDimitry Andric// No pattern, as all immediate -> register moves are matched to the MOVI pseudo 257*0fca6ea1SDimitry Andriclet Defs = [CCR] in 258*0fca6ea1SDimitry Andricdef MOVQ : MxInst<(outs MxDRD32:$dst), (ins Mxi8imm:$imm), 259*0fca6ea1SDimitry Andric "moveq\t$imm, $dst", 260*0fca6ea1SDimitry Andric [(null_frag)]> { 261*0fca6ea1SDimitry Andric let Inst = (descend 0b0111, (operand "$dst", 3), 0b0, (operand "$imm", 8)); 262*0fca6ea1SDimitry Andric} 263*0fca6ea1SDimitry Andric 264*0fca6ea1SDimitry Andric//===----------------------------------------------------------------------===// 265fe6060f1SDimitry Andric// MOVEM 266fe6060f1SDimitry Andric// 267fe6060f1SDimitry Andric// The mask is already pre-processed by the save/restore spill hook 268fe6060f1SDimitry Andric//===----------------------------------------------------------------------===// 269fe6060f1SDimitry Andric 270fe6060f1SDimitry Andric// Direction 27181ad6265SDimitry Andricdefvar MxMOVEM_MR = false; 27281ad6265SDimitry Andricdefvar MxMOVEM_RM = true; 273fe6060f1SDimitry Andric 274fe6060f1SDimitry Andric// Size 27581ad6265SDimitry Andricdefvar MxMOVEM_W = false; 27681ad6265SDimitry Andricdefvar MxMOVEM_L = true; 277fe6060f1SDimitry Andric 278fe6060f1SDimitry Andric/// ---------------+-------------+-------------+--------- 279fe6060f1SDimitry Andric/// F E D C B | A | 9 8 7 | 6 | 5 4 3 | 2 1 0 280fe6060f1SDimitry Andric/// ---------------+---+---------+---+---------+--------- 281fe6060f1SDimitry Andric/// 0 1 0 0 1 | D | 0 0 1 | S | MODE | REG 282fe6060f1SDimitry Andric/// ---------------+---+---------+---+---------+--------- 283fe6060f1SDimitry Andric/// REGISTER LIST MASK 284fe6060f1SDimitry Andric/// ----------------------------------------------------- 285fe6060f1SDimitry Andric/// D - direction(RM,MR) 286fe6060f1SDimitry Andric/// S - size(W,L) 28781ad6265SDimitry Andricclass MxMOVEMEncoding<MxEncMemOp opnd_enc, bit size, bit direction, 28881ad6265SDimitry Andric string mask_op_name> { 28981ad6265SDimitry Andric dag Value = (ascend 29081ad6265SDimitry Andric (descend 0b01001, direction, 0b001, size, opnd_enc.EA), 29181ad6265SDimitry Andric // Mask 29281ad6265SDimitry Andric (operand "$"#mask_op_name, 16), 29381ad6265SDimitry Andric opnd_enc.Supplement 29481ad6265SDimitry Andric ); 29581ad6265SDimitry Andric} 296fe6060f1SDimitry Andric 297fe6060f1SDimitry Andriclet mayStore = 1 in 29881ad6265SDimitry Andricclass MxMOVEM_MR<MxType TYPE, bit SIZE_ENC, 29981ad6265SDimitry Andric MxOperand MEMOp, MxEncMemOp MEM_ENC> 300fe6060f1SDimitry Andric : MxInst<(outs), (ins MEMOp:$dst, MxMoveMask:$mask), 30181ad6265SDimitry Andric "movem."#TYPE.Prefix#"\t$mask, $dst", []> { 30281ad6265SDimitry Andric let Inst = MxMOVEMEncoding<MEM_ENC, SIZE_ENC, MxMOVEM_MR, "mask">.Value; 30381ad6265SDimitry Andric} 30481ad6265SDimitry Andric 30581ad6265SDimitry Andricforeach AM = MxMoveSupportedAMs in { 30681ad6265SDimitry Andric foreach TYPE = [MxType16, MxType32] in 30781ad6265SDimitry Andric def MOVM # TYPE.Size # AM # m # TYPE.Postfix 30881ad6265SDimitry Andric : MxMOVEM_MR<TYPE, !if(!eq(TYPE, MxType16), MxMOVEM_W, MxMOVEM_L), 30981ad6265SDimitry Andric !cast<MxOpBundle>("MxOp"#TYPE.Size#"AddrMode_"#AM).Op, 31081ad6265SDimitry Andric !cast<MxEncMemOp>("MxMoveDstOpEnc_"#AM)>; 31181ad6265SDimitry Andric} // foreach AM 312fe6060f1SDimitry Andric 313fe6060f1SDimitry Andriclet mayLoad = 1 in 31481ad6265SDimitry Andricclass MxMOVEM_RM<MxType TYPE, bit SIZE_ENC, 31581ad6265SDimitry Andric MxOperand MEMOp, MxEncMemOp MEM_ENC> 316fe6060f1SDimitry Andric : MxInst<(outs), (ins MxMoveMask:$mask, MEMOp:$src), 31781ad6265SDimitry Andric "movem."#TYPE.Prefix#"\t$src, $mask", []> { 31881ad6265SDimitry Andric let Inst = MxMOVEMEncoding<MEM_ENC, SIZE_ENC, MxMOVEM_RM, "mask">.Value; 31981ad6265SDimitry Andric} 320fe6060f1SDimitry Andric 32181ad6265SDimitry Andricforeach AM = MxMoveSupportedAMs in { 32281ad6265SDimitry Andric foreach TYPE = [MxType16, MxType32] in 32381ad6265SDimitry Andric def MOVM # TYPE.Size # m # AM # TYPE.Postfix 32481ad6265SDimitry Andric : MxMOVEM_RM<TYPE, !if(!eq(TYPE, MxType16), MxMOVEM_W, MxMOVEM_L), 32581ad6265SDimitry Andric !cast<MxOpBundle>("MxOp"#TYPE.Size#"AddrMode_"#AM).Op, 32681ad6265SDimitry Andric !cast<MxEncMemOp>("MxMoveSrcOpEnc_"#AM)>; 32781ad6265SDimitry Andric} // foreach AM 328fe6060f1SDimitry Andric 329fe6060f1SDimitry Andric// Pseudo versions. These a required by virtual register spill/restore since 330fe6060f1SDimitry Andric// the mask requires real register to encode. These instruction will be expanded 331fe6060f1SDimitry Andric// into real MOVEM after RA finishes. 332fe6060f1SDimitry Andriclet mayStore = 1 in 333fe6060f1SDimitry Andricclass MxMOVEM_MR_Pseudo<MxType TYPE, MxOperand MEMOp> 334fe6060f1SDimitry Andric : MxPseudo<(outs), (ins MEMOp:$dst, TYPE.ROp:$reg)>; 335fe6060f1SDimitry Andriclet mayLoad = 1 in 336fe6060f1SDimitry Andricclass MxMOVEM_RM_Pseudo<MxType TYPE, MxOperand MEMOp> 337fe6060f1SDimitry Andric : MxPseudo<(outs TYPE.ROp:$dst), (ins MEMOp:$src)>; 338fe6060f1SDimitry Andric 339fe6060f1SDimitry Andric// Mem <- Reg 340fe6060f1SDimitry Andricdef MOVM8jm_P : MxMOVEM_MR_Pseudo<MxType8d, MxType8.JOp>; 341fe6060f1SDimitry Andricdef MOVM16jm_P : MxMOVEM_MR_Pseudo<MxType16r, MxType16.JOp>; 342fe6060f1SDimitry Andricdef MOVM32jm_P : MxMOVEM_MR_Pseudo<MxType32r, MxType32.JOp>; 343fe6060f1SDimitry Andric 344fe6060f1SDimitry Andricdef MOVM8pm_P : MxMOVEM_MR_Pseudo<MxType8d, MxType8.POp>; 345fe6060f1SDimitry Andricdef MOVM16pm_P : MxMOVEM_MR_Pseudo<MxType16r, MxType16.POp>; 346fe6060f1SDimitry Andricdef MOVM32pm_P : MxMOVEM_MR_Pseudo<MxType32r, MxType32.POp>; 347fe6060f1SDimitry Andric 348fe6060f1SDimitry Andric// Reg <- Mem 349fe6060f1SDimitry Andricdef MOVM8mj_P : MxMOVEM_RM_Pseudo<MxType8d, MxType8.JOp>; 350fe6060f1SDimitry Andricdef MOVM16mj_P : MxMOVEM_RM_Pseudo<MxType16r, MxType16.JOp>; 351fe6060f1SDimitry Andricdef MOVM32mj_P : MxMOVEM_RM_Pseudo<MxType32r, MxType32.JOp>; 352fe6060f1SDimitry Andric 353fe6060f1SDimitry Andricdef MOVM8mp_P : MxMOVEM_RM_Pseudo<MxType8d, MxType8.POp>; 354fe6060f1SDimitry Andricdef MOVM16mp_P : MxMOVEM_RM_Pseudo<MxType16r, MxType16.POp>; 355fe6060f1SDimitry Andricdef MOVM32mp_P : MxMOVEM_RM_Pseudo<MxType32r, MxType32.POp>; 356fe6060f1SDimitry Andric 357fe6060f1SDimitry Andric 358fe6060f1SDimitry Andric//===----------------------------------------------------------------------===// 359fe6060f1SDimitry Andric// MOVE to/from SR/CCR 360fe6060f1SDimitry Andric// 361fe6060f1SDimitry Andric// A special care must be taken working with to/from CCR since it is basically 362fe6060f1SDimitry Andric// word-size SR register truncated for user mode thus it only supports word-size 363fe6060f1SDimitry Andric// instructions. Plus the original M68000 does not support moves from CCR. So in 364fe6060f1SDimitry Andric// order to use CCR effectively one MUST use proper byte-size pseudo instructi- 365fe6060f1SDimitry Andric// ons that will be resolved sometime after RA pass. 366fe6060f1SDimitry Andric//===----------------------------------------------------------------------===// 367fe6060f1SDimitry Andric 368fe6060f1SDimitry Andric/// -------------------------------------------------- 369fe6060f1SDimitry Andric/// F E D C B A 9 8 7 6 | 5 4 3 | 2 1 0 370fe6060f1SDimitry Andric/// -------------------------------------------------- 371fe6060f1SDimitry Andric/// | EFFECTIVE ADDRESS 372fe6060f1SDimitry Andric/// 0 1 0 0 0 1 0 0 1 1 | MODE | REG 373fe6060f1SDimitry Andric/// -------------------------------------------------- 374fe6060f1SDimitry Andriclet Defs = [CCR] in 37581ad6265SDimitry Andricclass MxMoveToCCR<MxOperand MEMOp, MxEncMemOp SRC_ENC> 37681ad6265SDimitry Andric : MxInst<(outs CCRC:$dst), (ins MEMOp:$src), "move.w\t$src, $dst", []> { 37781ad6265SDimitry Andric let Inst = (ascend 37881ad6265SDimitry Andric (descend 0b0100010011, SRC_ENC.EA), 37981ad6265SDimitry Andric SRC_ENC.Supplement 38081ad6265SDimitry Andric ); 38181ad6265SDimitry Andric} 382fe6060f1SDimitry Andric 38381ad6265SDimitry Andricclass MxMoveToCCRPseudo<MxOperand MEMOp> 38481ad6265SDimitry Andric : MxPseudo<(outs CCRC:$dst), (ins MEMOp:$src)>; 385fe6060f1SDimitry Andric 38681ad6265SDimitry Andriclet mayLoad = 1 in 38781ad6265SDimitry Andricforeach AM = MxMoveSupportedAMs in { 38881ad6265SDimitry Andric def MOV16c # AM : MxMoveToCCR<!cast<MxOpBundle>("MxOp16AddrMode_"#AM).Op, 38981ad6265SDimitry Andric !cast<MxEncMemOp>("MxMoveSrcOpEnc_"#AM)>; 39081ad6265SDimitry Andric def MOV8c # AM : MxMoveToCCRPseudo<!cast<MxOpBundle>("MxOp8AddrMode_"#AM).Op>; 39181ad6265SDimitry Andric} // foreach AM 392fe6060f1SDimitry Andric 39381ad6265SDimitry Andric// Only data register is allowed. 39481ad6265SDimitry Andricdef MOV16cd : MxMoveToCCR<MxOp16AddrMode_d.Op, MxMoveSrcOpEnc_d>; 39581ad6265SDimitry Andricdef MOV8cd : MxMoveToCCRPseudo<MxOp8AddrMode_d.Op>; 396fe6060f1SDimitry Andric 397fe6060f1SDimitry Andric/// Move from CCR 398fe6060f1SDimitry Andric/// -------------------------------------------------- 399fe6060f1SDimitry Andric/// F E D C B A 9 8 7 6 | 5 4 3 | 2 1 0 400fe6060f1SDimitry Andric/// -------------------------------------------------- 401fe6060f1SDimitry Andric/// | EFFECTIVE ADDRESS 402fe6060f1SDimitry Andric/// 0 1 0 0 0 0 1 0 1 1 | MODE | REG 403fe6060f1SDimitry Andric/// -------------------------------------------------- 40481ad6265SDimitry Andriclet Uses = [CCR] in { 40581ad6265SDimitry Andricclass MxMoveFromCCR_R 40681ad6265SDimitry Andric : MxInst<(outs MxDRD16:$dst), (ins CCRC:$src), "move.w\t$src, $dst", []>, 407bdd1243dSDimitry Andric Requires<[ AtLeastM68010 ]> { 40881ad6265SDimitry Andric let Inst = (descend 0b0100001011, MxEncAddrMode_d<"dst">.EA); 40981ad6265SDimitry Andric} 410fe6060f1SDimitry Andric 41181ad6265SDimitry Andricclass MxMoveFromCCR_M<MxOperand MEMOp, MxEncMemOp DST_ENC> 41281ad6265SDimitry Andric : MxInst<(outs), (ins MEMOp:$dst, CCRC:$src), "move.w\t$src, $dst", []>, 413bdd1243dSDimitry Andric Requires<[ AtLeastM68010 ]> { 41481ad6265SDimitry Andric let Inst = (ascend 41581ad6265SDimitry Andric (descend 0b0100001011, DST_ENC.EA), 41681ad6265SDimitry Andric DST_ENC.Supplement 41781ad6265SDimitry Andric ); 41881ad6265SDimitry Andric} 419fe6060f1SDimitry Andric 42081ad6265SDimitry Andricclass MxMoveFromCCRPseudo<MxOperand MEMOp> 42181ad6265SDimitry Andric : MxPseudo<(outs), (ins MEMOp:$dst, CCRC:$src)>; 42281ad6265SDimitry Andric} // let Uses = [CCR] 423fe6060f1SDimitry Andric 42481ad6265SDimitry Andriclet mayStore = 1 in 42581ad6265SDimitry Andricforeach AM = MxMoveSupportedAMs in { 42681ad6265SDimitry Andric def MOV16 # AM # c 42781ad6265SDimitry Andric : MxMoveFromCCR_M<!cast<MxOpBundle>("MxOp16AddrMode_"#AM).Op, 42881ad6265SDimitry Andric !cast<MxEncMemOp>("MxMoveDstOpEnc_"#AM)>; 42981ad6265SDimitry Andric def MOV8 # AM # c 43081ad6265SDimitry Andric : MxMoveFromCCRPseudo<!cast<MxOpBundle>("MxOp8AddrMode_"#AM).Op>; 43181ad6265SDimitry Andric} // foreach AM 432fe6060f1SDimitry Andric 43381ad6265SDimitry Andric// Only data register is allowed. 43481ad6265SDimitry Andricdef MOV16dc : MxMoveFromCCR_R; 43581ad6265SDimitry Andricdef MOV8dc : MxMoveFromCCRPseudo<MxOp8AddrMode_d.Op>; 436fe6060f1SDimitry Andric 437fe6060f1SDimitry Andric//===----------------------------------------------------------------------===// 438fe6060f1SDimitry Andric// LEA 439fe6060f1SDimitry Andric//===----------------------------------------------------------------------===// 440fe6060f1SDimitry Andric 441fe6060f1SDimitry Andric/// ---------------------------------------------------- 442fe6060f1SDimitry Andric/// F E D C | B A 9 | 8 7 6 | 5 4 3 | 2 1 0 443fe6060f1SDimitry Andric/// ---------------------------------------------------- 444fe6060f1SDimitry Andric/// 0 1 0 0 | DST REG | 1 1 1 | MODE | REG 445fe6060f1SDimitry Andric/// ---------------------------------------------------- 44681ad6265SDimitry Andricclass MxLEA<MxOpBundle SRC, MxEncMemOp SRC_ENC> 44781ad6265SDimitry Andric : MxInst<(outs MxARD32:$dst), (ins SRC.Op:$src), 44881ad6265SDimitry Andric "lea\t$src, $dst", [(set i32:$dst, SRC.Pat:$src)]> { 44981ad6265SDimitry Andric let Inst = (ascend 45081ad6265SDimitry Andric (descend 0b0100, (operand "$dst", 3), 0b111, SRC_ENC.EA), 45181ad6265SDimitry Andric SRC_ENC.Supplement 45281ad6265SDimitry Andric ); 45381ad6265SDimitry Andric} 454fe6060f1SDimitry Andric 45581ad6265SDimitry Andricforeach AM = ["p", "f", "b", "q", "k"] in 45681ad6265SDimitry Andricdef LEA32 # AM : MxLEA<!cast<MxOpBundle>("MxOp32AddrMode_"#AM), 45781ad6265SDimitry Andric !cast<MxEncMemOp>("MxMoveSrcOpEnc_"#AM)>; 458fe6060f1SDimitry Andric 459fe6060f1SDimitry Andric//===----------------------------------------------------------------------===// 460bdd1243dSDimitry Andric// LINK/UNLK 461bdd1243dSDimitry Andric//===----------------------------------------------------------------------===// 462bdd1243dSDimitry Andric 463bdd1243dSDimitry Andriclet Uses = [SP], Defs = [SP] in { 464bdd1243dSDimitry Andriclet mayStore = 1 in { 465bdd1243dSDimitry Andric 466bdd1243dSDimitry Andricdef LINK16 : MxInst<(outs), (ins MxARD16:$src, Mxi16imm:$disp), "link.w\t$src, $disp", []> { 467bdd1243dSDimitry Andric let Inst = (ascend 468bdd1243dSDimitry Andric (descend 0b0100111001010, (operand "$src", 3)), 469bdd1243dSDimitry Andric (operand "$disp", 16) 470bdd1243dSDimitry Andric ); 471bdd1243dSDimitry Andric} 472bdd1243dSDimitry Andric 473bdd1243dSDimitry Andricdef LINK32 : MxInst<(outs), (ins MxARD16:$src, Mxi32imm:$disp), "link.l\t$src, $disp", []> { 474bdd1243dSDimitry Andric let Inst = (ascend 475bdd1243dSDimitry Andric (descend 0b0100100000001, (operand "$src", 3)), 476bdd1243dSDimitry Andric (slice "$disp", 31, 16), 477bdd1243dSDimitry Andric (slice "$disp", 15, 0) 478bdd1243dSDimitry Andric ); 479bdd1243dSDimitry Andric} 480bdd1243dSDimitry Andric 481bdd1243dSDimitry Andricdef UNLK : MxInst<(outs), (ins MxARD32:$src), "unlk\t$src", []> { 482bdd1243dSDimitry Andric let Inst = (descend 0b0100111001011, (operand "$src", 3)); 483bdd1243dSDimitry Andric} 484bdd1243dSDimitry Andric 485bdd1243dSDimitry Andric} // let mayStore = 1 486bdd1243dSDimitry Andric} // let Uses = [SP], Defs = [SP] 487bdd1243dSDimitry Andric 488bdd1243dSDimitry Andric//===----------------------------------------------------------------------===// 489fe6060f1SDimitry Andric// Pseudos 490fe6060f1SDimitry Andric//===----------------------------------------------------------------------===// 491fe6060f1SDimitry Andric 492fe6060f1SDimitry Andric/// Pushe/Pop to/from SP for simplicity 493fe6060f1SDimitry Andriclet Uses = [SP], Defs = [SP], hasSideEffects = 0 in { 494fe6060f1SDimitry Andric 495fe6060f1SDimitry Andric// SP <- SP - <size>; (SP) <- Dn 496fe6060f1SDimitry Andriclet mayStore = 1 in { 497fe6060f1SDimitry Andricdef PUSH8d : MxPseudo<(outs), (ins DR8:$reg)>; 498fe6060f1SDimitry Andricdef PUSH16d : MxPseudo<(outs), (ins DR16:$reg)>; 499fe6060f1SDimitry Andricdef PUSH32r : MxPseudo<(outs), (ins XR32:$reg)>; 500fe6060f1SDimitry Andric} // let mayStore = 1 501fe6060f1SDimitry Andric 502fe6060f1SDimitry Andric// Dn <- (SP); SP <- SP + <size> 503fe6060f1SDimitry Andriclet mayLoad = 1 in { 504fe6060f1SDimitry Andricdef POP8d : MxPseudo<(outs DR8:$reg), (ins)>; 505fe6060f1SDimitry Andricdef POP16d : MxPseudo<(outs DR16:$reg), (ins)>; 506fe6060f1SDimitry Andricdef POP32r : MxPseudo<(outs XR32:$reg), (ins)>; 507fe6060f1SDimitry Andric} // let mayLoad = 1 508fe6060f1SDimitry Andric 509fe6060f1SDimitry Andric} // let Uses/Defs = [SP], hasSideEffects = 0 510fe6060f1SDimitry Andric 511fe6060f1SDimitry Andric 512fe6060f1SDimitry Andriclet Defs = [CCR] in { 513fe6060f1SDimitry Andricclass MxPseudoMove_RR<MxType DST, MxType SRC, list<dag> PAT = []> 514fe6060f1SDimitry Andric : MxPseudo<(outs DST.ROp:$dst), (ins SRC.ROp:$src), PAT>; 515fe6060f1SDimitry Andric 516fe6060f1SDimitry Andricclass MxPseudoMove_RM<MxType DST, MxOperand SRCOpd, list<dag> PAT = []> 517fe6060f1SDimitry Andric : MxPseudo<(outs DST.ROp:$dst), (ins SRCOpd:$src), PAT>; 518*0fca6ea1SDimitry Andric 519*0fca6ea1SDimitry Andric 520*0fca6ea1SDimitry Andric// These Pseudos handle loading immediates to registers. 521*0fca6ea1SDimitry Andric// They are expanded post-RA into either move or moveq instructions, 522*0fca6ea1SDimitry Andric// depending on size, destination register class, and immediate value. 523*0fca6ea1SDimitry Andric// This is done with pseudoinstructions in order to not constrain RA to 524*0fca6ea1SDimitry Andric// data registers if moveq matches. 525*0fca6ea1SDimitry Andricclass MxPseudoMove_DI<MxType TYPE> 526*0fca6ea1SDimitry Andric : MxPseudo<(outs TYPE.ROp:$dst), (ins TYPE.IOp:$src), 527*0fca6ea1SDimitry Andric [(set TYPE.ROp:$dst, imm:$src)]>; 528*0fca6ea1SDimitry Andric 529*0fca6ea1SDimitry Andric// i8 imm -> reg can always be converted to moveq, 530*0fca6ea1SDimitry Andric// but we still emit a pseudo for consistency. 531*0fca6ea1SDimitry Andricdef MOVI8di : MxPseudoMove_DI<MxType8d>; 532*0fca6ea1SDimitry Andricdef MOVI16ri : MxPseudoMove_DI<MxType16r>; 533*0fca6ea1SDimitry Andricdef MOVI32ri : MxPseudoMove_DI<MxType32r>; 534*0fca6ea1SDimitry Andric} // let Defs = [CCR] 535fe6060f1SDimitry Andric 536fe6060f1SDimitry Andric/// This group of Pseudos is analogues to the real x86 extending moves, but 537fe6060f1SDimitry Andric/// since M68k does not have those we need to emulate. These instructions 538fe6060f1SDimitry Andric/// will be expanded right after RA completed because we need to know precisely 539fe6060f1SDimitry Andric/// what registers are allocated for the operands and if they overlap we just 540fe6060f1SDimitry Andric/// extend the value if the registers are completely different we need to move 541fe6060f1SDimitry Andric/// first. 542fe6060f1SDimitry Andricforeach EXT = ["S", "Z"] in { 543fe6060f1SDimitry Andric let hasSideEffects = 0 in { 544fe6060f1SDimitry Andric 545fe6060f1SDimitry Andric def MOV#EXT#Xd16d8 : MxPseudoMove_RR<MxType16d, MxType8d>; 546fe6060f1SDimitry Andric def MOV#EXT#Xd32d8 : MxPseudoMove_RR<MxType32d, MxType8d>; 547fe6060f1SDimitry Andric def MOV#EXT#Xd32d16 : MxPseudoMove_RR<MxType32r, MxType16r>; 548fe6060f1SDimitry Andric 549fe6060f1SDimitry Andric let mayLoad = 1 in { 550fe6060f1SDimitry Andric 551fe6060f1SDimitry Andric def MOV#EXT#Xd16j8 : MxPseudoMove_RM<MxType16d, MxType8.JOp>; 552fe6060f1SDimitry Andric def MOV#EXT#Xd32j8 : MxPseudoMove_RM<MxType32d, MxType8.JOp>; 553fe6060f1SDimitry Andric def MOV#EXT#Xd32j16 : MxPseudoMove_RM<MxType32d, MxType16.JOp>; 554fe6060f1SDimitry Andric 555fe6060f1SDimitry Andric def MOV#EXT#Xd16p8 : MxPseudoMove_RM<MxType16d, MxType8.POp>; 556fe6060f1SDimitry Andric def MOV#EXT#Xd32p8 : MxPseudoMove_RM<MxType32d, MxType8.POp>; 557fe6060f1SDimitry Andric def MOV#EXT#Xd32p16 : MxPseudoMove_RM<MxType32d, MxType16.POp>; 558fe6060f1SDimitry Andric 559fe6060f1SDimitry Andric def MOV#EXT#Xd16f8 : MxPseudoMove_RM<MxType16d, MxType8.FOp>; 560fe6060f1SDimitry Andric def MOV#EXT#Xd32f8 : MxPseudoMove_RM<MxType32d, MxType8.FOp>; 561fe6060f1SDimitry Andric def MOV#EXT#Xd32f16 : MxPseudoMove_RM<MxType32d, MxType16.FOp>; 562fe6060f1SDimitry Andric 56306c3fb27SDimitry Andric def MOV#EXT#Xd16q8 : MxPseudoMove_RM<MxType16d, MxType8.QOp>; 56406c3fb27SDimitry Andric def MOV#EXT#Xd32q8 : MxPseudoMove_RM<MxType32d, MxType8.QOp>; 56506c3fb27SDimitry Andric def MOV#EXT#Xd32q16 : MxPseudoMove_RM<MxType32d, MxType16.QOp>; 56606c3fb27SDimitry Andric 567fe6060f1SDimitry Andric } 568fe6060f1SDimitry Andric } 569fe6060f1SDimitry Andric} 570fe6060f1SDimitry Andric 571fe6060f1SDimitry Andric/// This group of instructions is similar to the group above but DOES NOT do 572fe6060f1SDimitry Andric/// any value extension, they just load a smaller register into the lower part 573fe6060f1SDimitry Andric/// of another register if operands' real registers are different or does 574fe6060f1SDimitry Andric/// nothing if they are the same. 575fe6060f1SDimitry Andricdef MOVXd16d8 : MxPseudoMove_RR<MxType16d, MxType8d>; 576fe6060f1SDimitry Andricdef MOVXd32d8 : MxPseudoMove_RR<MxType32d, MxType8d>; 577fe6060f1SDimitry Andricdef MOVXd32d16 : MxPseudoMove_RR<MxType32r, MxType16r>; 578fe6060f1SDimitry Andric 579fe6060f1SDimitry Andric//===----------------------------------------------------------------------===// 580fe6060f1SDimitry Andric// Extend/Truncate Patterns 581fe6060f1SDimitry Andric//===----------------------------------------------------------------------===// 582fe6060f1SDimitry Andric 583fe6060f1SDimitry Andric// i16 <- sext i8 584fe6060f1SDimitry Andricdef: Pat<(i16 (sext i8:$src)), 585fe6060f1SDimitry Andric (EXTRACT_SUBREG (MOVSXd32d8 MxDRD8:$src), MxSubRegIndex16Lo)>; 586fe6060f1SDimitry Andricdef: Pat<(MxSExtLoadi16i8 MxCP_ARI:$src), 587fe6060f1SDimitry Andric (EXTRACT_SUBREG (MOVSXd32j8 MxARI8:$src), MxSubRegIndex16Lo)>; 588fe6060f1SDimitry Andricdef: Pat<(MxSExtLoadi16i8 MxCP_ARID:$src), 589fe6060f1SDimitry Andric (EXTRACT_SUBREG (MOVSXd32p8 MxARID8:$src), MxSubRegIndex16Lo)>; 590fe6060f1SDimitry Andricdef: Pat<(MxSExtLoadi16i8 MxCP_ARII:$src), 591fe6060f1SDimitry Andric (EXTRACT_SUBREG (MOVSXd32f8 MxARII8:$src), MxSubRegIndex16Lo)>; 592647cbc5dSDimitry Andricdef: Pat<(MxSExtLoadi16i8 MxCP_PCD:$src), (MOVSXd16q8 MxPCD8:$src)>; 593fe6060f1SDimitry Andric 594fe6060f1SDimitry Andric// i32 <- sext i8 595fe6060f1SDimitry Andricdef: Pat<(i32 (sext i8:$src)), (MOVSXd32d8 MxDRD8:$src)>; 596fe6060f1SDimitry Andricdef: Pat<(MxSExtLoadi32i8 MxCP_ARI :$src), (MOVSXd32j8 MxARI8 :$src)>; 597fe6060f1SDimitry Andricdef: Pat<(MxSExtLoadi32i8 MxCP_ARID:$src), (MOVSXd32p8 MxARID8:$src)>; 598fe6060f1SDimitry Andricdef: Pat<(MxSExtLoadi32i8 MxCP_ARII:$src), (MOVSXd32f8 MxARII8:$src)>; 599647cbc5dSDimitry Andricdef: Pat<(MxSExtLoadi32i8 MxCP_PCD:$src), (MOVSXd32q8 MxPCD8:$src)>; 600fe6060f1SDimitry Andric 601fe6060f1SDimitry Andric// i32 <- sext i16 602fe6060f1SDimitry Andricdef: Pat<(i32 (sext i16:$src)), (MOVSXd32d16 MxDRD16:$src)>; 603fe6060f1SDimitry Andricdef: Pat<(MxSExtLoadi32i16 MxCP_ARI :$src), (MOVSXd32j16 MxARI16 :$src)>; 604fe6060f1SDimitry Andricdef: Pat<(MxSExtLoadi32i16 MxCP_ARID:$src), (MOVSXd32p16 MxARID16:$src)>; 605fe6060f1SDimitry Andricdef: Pat<(MxSExtLoadi32i16 MxCP_ARII:$src), (MOVSXd32f16 MxARII16:$src)>; 606647cbc5dSDimitry Andricdef: Pat<(MxSExtLoadi32i16 MxCP_PCD:$src), (MOVSXd32q16 MxPCD16:$src)>; 607fe6060f1SDimitry Andric 608fe6060f1SDimitry Andric// i16 <- zext i8 609fe6060f1SDimitry Andricdef: Pat<(i16 (zext i8:$src)), 610fe6060f1SDimitry Andric (EXTRACT_SUBREG (MOVZXd32d8 MxDRD8:$src), MxSubRegIndex16Lo)>; 611fe6060f1SDimitry Andricdef: Pat<(MxZExtLoadi16i8 MxCP_ARI:$src), 612fe6060f1SDimitry Andric (EXTRACT_SUBREG (MOVZXd32j8 MxARI8:$src), MxSubRegIndex16Lo)>; 613fe6060f1SDimitry Andricdef: Pat<(MxZExtLoadi16i8 MxCP_ARID:$src), 614fe6060f1SDimitry Andric (EXTRACT_SUBREG (MOVZXd32p8 MxARID8:$src), MxSubRegIndex16Lo)>; 615fe6060f1SDimitry Andricdef: Pat<(MxZExtLoadi16i8 MxCP_ARII:$src), 616fe6060f1SDimitry Andric (EXTRACT_SUBREG (MOVZXd32f8 MxARII8:$src), MxSubRegIndex16Lo)>; 61706c3fb27SDimitry Andricdef: Pat<(MxZExtLoadi16i8 MxCP_PCD :$src), (MOVZXd16q8 MxPCD8 :$src)>; 618fe6060f1SDimitry Andric 619fe6060f1SDimitry Andric// i32 <- zext i8 620fe6060f1SDimitry Andricdef: Pat<(i32 (zext i8:$src)), (MOVZXd32d8 MxDRD8:$src)>; 621fe6060f1SDimitry Andricdef: Pat<(MxZExtLoadi32i8 MxCP_ARI :$src), (MOVZXd32j8 MxARI8 :$src)>; 622fe6060f1SDimitry Andricdef: Pat<(MxZExtLoadi32i8 MxCP_ARID:$src), (MOVZXd32p8 MxARID8:$src)>; 623fe6060f1SDimitry Andricdef: Pat<(MxZExtLoadi32i8 MxCP_ARII:$src), (MOVZXd32f8 MxARII8:$src)>; 62406c3fb27SDimitry Andricdef: Pat<(MxZExtLoadi32i8 MxCP_PCD :$src), (MOVZXd32q8 MxPCD8 :$src)>; 625fe6060f1SDimitry Andric 626fe6060f1SDimitry Andric// i32 <- zext i16 627fe6060f1SDimitry Andricdef: Pat<(i32 (zext i16:$src)), (MOVZXd32d16 MxDRD16:$src)>; 628fe6060f1SDimitry Andricdef: Pat<(MxZExtLoadi32i16 MxCP_ARI :$src), (MOVZXd32j16 MxARI16 :$src)>; 629fe6060f1SDimitry Andricdef: Pat<(MxZExtLoadi32i16 MxCP_ARID:$src), (MOVZXd32p16 MxARID16:$src)>; 630fe6060f1SDimitry Andricdef: Pat<(MxZExtLoadi32i16 MxCP_ARII:$src), (MOVZXd32f16 MxARII16:$src)>; 63106c3fb27SDimitry Andricdef: Pat<(MxZExtLoadi32i16 MxCP_PCD :$src), (MOVZXd32q16 MxPCD16 :$src)>; 632fe6060f1SDimitry Andric 633fe6060f1SDimitry Andric// i16 <- anyext i8 634fe6060f1SDimitry Andricdef: Pat<(i16 (anyext i8:$src)), 635fe6060f1SDimitry Andric (EXTRACT_SUBREG (MOVZXd32d8 MxDRD8:$src), MxSubRegIndex16Lo)>; 636fe6060f1SDimitry Andricdef: Pat<(MxExtLoadi16i8 MxCP_ARI:$src), 637fe6060f1SDimitry Andric (EXTRACT_SUBREG (MOVZXd32j8 MxARI8:$src), MxSubRegIndex16Lo)>; 638fe6060f1SDimitry Andricdef: Pat<(MxExtLoadi16i8 MxCP_ARID:$src), 639fe6060f1SDimitry Andric (EXTRACT_SUBREG (MOVZXd32p8 MxARID8:$src), MxSubRegIndex16Lo)>; 640fe6060f1SDimitry Andricdef: Pat<(MxExtLoadi16i8 MxCP_ARII:$src), 641fe6060f1SDimitry Andric (EXTRACT_SUBREG (MOVZXd32f8 MxARII8:$src), MxSubRegIndex16Lo)>; 642fe6060f1SDimitry Andric 643fe6060f1SDimitry Andric// i32 <- anyext i8 644fe6060f1SDimitry Andricdef: Pat<(i32 (anyext i8:$src)), (MOVZXd32d8 MxDRD8:$src)>; 645fe6060f1SDimitry Andricdef: Pat<(MxExtLoadi32i8 MxCP_ARI :$src), (MOVZXd32j8 MxARI8 :$src)>; 646fe6060f1SDimitry Andricdef: Pat<(MxExtLoadi32i8 MxCP_ARID:$src), (MOVZXd32p8 MxARID8:$src)>; 647fe6060f1SDimitry Andricdef: Pat<(MxExtLoadi32i8 MxCP_ARII:$src), (MOVZXd32f8 MxARII8:$src)>; 648fe6060f1SDimitry Andric 649fe6060f1SDimitry Andric// i32 <- anyext i16 650fe6060f1SDimitry Andricdef: Pat<(i32 (anyext i16:$src)), (MOVZXd32d16 MxDRD16:$src)>; 651fe6060f1SDimitry Andricdef: Pat<(MxExtLoadi32i16 MxCP_ARI :$src), (MOVZXd32j16 MxARI16 :$src)>; 652fe6060f1SDimitry Andricdef: Pat<(MxExtLoadi32i16 MxCP_ARID:$src), (MOVZXd32p16 MxARID16:$src)>; 653fe6060f1SDimitry Andricdef: Pat<(MxExtLoadi32i16 MxCP_ARII:$src), (MOVZXd32f16 MxARII16:$src)>; 654fe6060f1SDimitry Andric 655fe6060f1SDimitry Andric// trunc patterns 656fe6060f1SDimitry Andricdef : Pat<(i16 (trunc i32:$src)), 657fe6060f1SDimitry Andric (EXTRACT_SUBREG MxXRD32:$src, MxSubRegIndex16Lo)>; 658fe6060f1SDimitry Andricdef : Pat<(i8 (trunc i32:$src)), 659fe6060f1SDimitry Andric (EXTRACT_SUBREG MxXRD32:$src, MxSubRegIndex8Lo)>; 660fe6060f1SDimitry Andricdef : Pat<(i8 (trunc i16:$src)), 661fe6060f1SDimitry Andric (EXTRACT_SUBREG MxXRD16:$src, MxSubRegIndex8Lo)>; 66206c3fb27SDimitry Andric 66306c3fb27SDimitry Andric//===----------------------------------------------------------------------===// 66406c3fb27SDimitry Andric// FMOVE 66506c3fb27SDimitry Andric//===----------------------------------------------------------------------===// 66606c3fb27SDimitry Andric 66706c3fb27SDimitry Andriclet Defs = [FPS] in 66806c3fb27SDimitry Andricclass MxFMove<string size, dag outs, dag ins, list<dag> pattern, 66906c3fb27SDimitry Andric string rounding = ""> 67006c3fb27SDimitry Andric : MxInst<outs, ins, 67106c3fb27SDimitry Andric "f"#rounding#"move."#size#"\t$src, $dst", pattern> { 67206c3fb27SDimitry Andric // Only FMOVE uses FPC 67306c3fb27SDimitry Andric let Uses = !if(!eq(rounding, ""), [FPC], []); 67406c3fb27SDimitry Andric 67506c3fb27SDimitry Andric // FSMOVE and FDMOVE are only available after M68040 67606c3fb27SDimitry Andric let Predicates = [!if(!eq(rounding, ""), AtLeastM68881, AtLeastM68040)]; 67706c3fb27SDimitry Andric} 67806c3fb27SDimitry Andric 67906c3fb27SDimitry Andric// FPDR <- FPDR 68006c3fb27SDimitry Andricclass MxFMove_FF<string rounding, int size, 68106c3fb27SDimitry Andric MxOpBundle Opnd = !cast<MxOpBundle>("MxOp"#size#"AddrMode_fpr")> 68206c3fb27SDimitry Andric : MxFMove<"x", (outs Opnd.Op:$dst), (ins Opnd.Op:$src), 68306c3fb27SDimitry Andric [(null_frag)], rounding> { 68406c3fb27SDimitry Andric let Inst = (ascend 68506c3fb27SDimitry Andric (descend 0b1111, 68606c3fb27SDimitry Andric /*COPROCESSOR ID*/0b001, 68706c3fb27SDimitry Andric 0b000, 68806c3fb27SDimitry Andric /*MODE + REGISTER*/0b000000 68906c3fb27SDimitry Andric ), 69006c3fb27SDimitry Andric (descend 0b0, /* R/M */0b0, 0b0, 69106c3fb27SDimitry Andric /*SOURCE SPECIFIER*/ 69206c3fb27SDimitry Andric (operand "$src", 3), 69306c3fb27SDimitry Andric /*DESTINATION*/ 69406c3fb27SDimitry Andric (operand "$dst", 3), 69506c3fb27SDimitry Andric /*OPMODE*/ 69606c3fb27SDimitry Andric !cond(!eq(rounding, "s"): 0b1000000, 69706c3fb27SDimitry Andric !eq(rounding, "d"): 0b1000100, 69806c3fb27SDimitry Andric true: 0b0000000) 69906c3fb27SDimitry Andric ) 70006c3fb27SDimitry Andric ); 70106c3fb27SDimitry Andric} 70206c3fb27SDimitry Andric 70306c3fb27SDimitry Andricforeach rounding = ["", "s", "d"] in { 70406c3fb27SDimitry Andric def F # !toupper(rounding) # MOV80fp_fp : MxFMove_FF<rounding, 80>; 70506c3fb27SDimitry Andric 70606c3fb27SDimitry Andric // We don't have `fmove.s` or `fmove.d` because values will be converted to 70706c3fb27SDimitry Andric // f80 upon storing into the register, but FMOV32/64fp_fp are still needed 70806c3fb27SDimitry Andric // to make codegen easier. 70906c3fb27SDimitry Andric let isCodeGenOnly = true in 71006c3fb27SDimitry Andric foreach size = [32, 64] in 71106c3fb27SDimitry Andric def F # !toupper(rounding) # MOV # size # fp_fp : MxFMove_FF<rounding, size>; 71206c3fb27SDimitry Andric} 7135f757f3fSDimitry Andric// Direction 7145f757f3fSDimitry Andricdefvar MxFMove_FP_EA = false; 7155f757f3fSDimitry Andricdefvar MxFMove_EA_FP = true; 7165f757f3fSDimitry Andric 7175f757f3fSDimitry Andric// Encoding scheme for FPSYS <-> R/M 7185f757f3fSDimitry Andricclass MxEncFSysMove<bit dir, MxEncMemOp EAEnc, string fsys_reg> { 7195f757f3fSDimitry Andric dag Value = (ascend 7205f757f3fSDimitry Andric (descend 0b1111, 7215f757f3fSDimitry Andric /*COPROCESSOR ID*/0b001, 7225f757f3fSDimitry Andric 0b000, 7235f757f3fSDimitry Andric /*MODE + REGISTER*/ 7245f757f3fSDimitry Andric EAEnc.EA 7255f757f3fSDimitry Andric ), 7265f757f3fSDimitry Andric (descend 0b10, /*dir*/ dir, 7275f757f3fSDimitry Andric /*REGISTER SELECT*/ 7285f757f3fSDimitry Andric (operand "$"#fsys_reg, 3, (encoder "encodeFPSYSSelect")), 7295f757f3fSDimitry Andric 0b0000000000 7305f757f3fSDimitry Andric ) 7315f757f3fSDimitry Andric ); 7325f757f3fSDimitry Andric} 7335f757f3fSDimitry Andric 7345f757f3fSDimitry Andric// FPSYS <-> R 7355f757f3fSDimitry Andricclass MxFMove_FSYS_R<string src_reg, 7365f757f3fSDimitry Andric MxOpBundle SrcOpnd = !cast<MxOpBundle>("MxOp32AddrMode_"#src_reg), 7375f757f3fSDimitry Andric MxOpBundle DstOpnd = !cond(!eq(src_reg, "d"): MxOp32AddrMode_fpcs, 7385f757f3fSDimitry Andric !eq(src_reg, "a"): MxOp32AddrMode_fpi), 7395f757f3fSDimitry Andric MxEncMemOp SrcEnc = !cast<MxEncMemOp>("MxMoveSrcOpEnc_"#src_reg)> 7405f757f3fSDimitry Andric : MxFMove<"l", (outs DstOpnd.Op:$dst), (ins SrcOpnd.Op:$src), 7415f757f3fSDimitry Andric [(null_frag)]> { 7425f757f3fSDimitry Andric let Inst = MxEncFSysMove<MxFMove_FP_EA, SrcEnc, "dst">.Value; 7435f757f3fSDimitry Andric} 7445f757f3fSDimitry Andric 7455f757f3fSDimitry Andricclass MxFMove_R_FSYS<string dst_reg, 7465f757f3fSDimitry Andric MxOpBundle SrcOpnd = !cond(!eq(dst_reg, "d"): MxOp32AddrMode_fpcs, 7475f757f3fSDimitry Andric !eq(dst_reg, "a"): MxOp32AddrMode_fpi), 7485f757f3fSDimitry Andric MxOpBundle DstOpnd = !cast<MxOpBundle>("MxOp32AddrMode_"#dst_reg), 7495f757f3fSDimitry Andric MxEncMemOp DstEnc = !cast<MxEncMemOp>("MxMoveDstOpEnc_"#dst_reg)> 7505f757f3fSDimitry Andric : MxFMove<"l", (outs DstOpnd.Op:$dst), (ins SrcOpnd.Op:$src), 7515f757f3fSDimitry Andric [(null_frag)]> { 7525f757f3fSDimitry Andric let Inst = MxEncFSysMove<MxFMove_EA_FP, DstEnc, "src">.Value; 7535f757f3fSDimitry Andric} 7545f757f3fSDimitry Andric 7555f757f3fSDimitry Andricdef FMOVE32fpcs_d : MxFMove_FSYS_R<"d">; 7565f757f3fSDimitry Andricdef FMOVE32d_fpcs : MxFMove_R_FSYS<"d">; 7575f757f3fSDimitry Andricdef FMOVE32fpi_a : MxFMove_FSYS_R<"a">; 7585f757f3fSDimitry Andricdef FMOVE32a_fpi : MxFMove_R_FSYS<"a">; 759