xref: /freebsd/contrib/llvm-project/llvm/lib/Target/M68k/M68kInstrData.td (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
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///
22fe6060f1SDimitry Andric///     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
16881ad6265SDimitry Andricclass MxMove_RI<MxType TYPE, string DST_REG, MxMoveEncoding ENC,
16981ad6265SDimitry Andric                MxImmOpBundle SRC = !cast<MxImmOpBundle>("MxOp"#TYPE.Size#"AddrMode_i"),
17081ad6265SDimitry Andric                MxOpBundle DST = !cast<MxOpBundle>("MxOp"#TYPE.Size#"AddrMode_"#DST_REG)>
17181ad6265SDimitry Andric    : MxMove<TYPE.Prefix, (outs DST.Op:$dst), (ins SRC.Op:$src),
17281ad6265SDimitry Andric              [(set TYPE.VT:$dst, SRC.ImmPat:$src)], ENC>;
17381ad6265SDimitry Andric
17481ad6265SDimitry Andricforeach REG = ["r", "a", "d"] in {
17581ad6265SDimitry Andric  foreach TYPE = !if(!eq(REG, "d"), [MxType8, MxType16, MxType32], [MxType16, MxType32]) in
17681ad6265SDimitry Andric  def MOV # TYPE.Size # REG # i # TYPE.Postfix
17781ad6265SDimitry Andric      : MxMove_RI<TYPE, REG,
17881ad6265SDimitry Andric                  MxMoveEncoding<!cast<MxMoveSize>("MxMoveSize"#TYPE.Size),
17981ad6265SDimitry Andric                                 !cast<MxEncMemOp>("MxMoveDstOpEnc_"#REG),
18081ad6265SDimitry Andric                                 MxEncAddrMode_i<"src", TYPE.Size>>>;
18181ad6265SDimitry Andric} // foreach REG
18281ad6265SDimitry Andric
18381ad6265SDimitry Andric// R <- M
184fe6060f1SDimitry Andriclet mayLoad = 1 in
18581ad6265SDimitry Andricclass MxMove_RM<MxType TYPE, string DST_REG, MxOpBundle SRC, MxEncMemOp SRC_ENC,
18681ad6265SDimitry Andric                MxMoveSize SIZE_ENC = !cast<MxMoveSize>("MxMoveSize"#TYPE.Size),
18781ad6265SDimitry Andric                MxOpBundle DST = !cast<MxOpBundle>("MxOp"#TYPE.Size#"AddrMode_"#DST_REG),
18881ad6265SDimitry Andric                MxEncMemOp DST_ENC = !cast<MxEncMemOp>("MxMoveDstOpEnc_"#DST_REG)>
18981ad6265SDimitry Andric    : MxMove<TYPE.Prefix, (outs DST.Op:$dst), (ins SRC.Op:$src),
19081ad6265SDimitry Andric             [(set TYPE.VT:$dst, (TYPE.Load SRC.Pat:$src))],
19181ad6265SDimitry Andric             MxMoveEncoding<SIZE_ENC, DST_ENC, SRC_ENC>>;
192fe6060f1SDimitry Andric
19381ad6265SDimitry Andricforeach REG = ["r", "a", "d"] in
19481ad6265SDimitry Andricforeach AM = MxMoveSupportedAMs in {
19581ad6265SDimitry Andric  foreach TYPE = !if(!eq(REG, "d"), [MxType8, MxType16, MxType32], [MxType16, MxType32]) in
19681ad6265SDimitry Andric  def MOV # TYPE.Size # REG # AM # TYPE.Postfix
19781ad6265SDimitry Andric      : MxMove_RM<TYPE, REG, !cast<MxOpBundle>("MxOp"#TYPE.Size#"AddrMode_"#AM),
19881ad6265SDimitry Andric                  !cast<MxEncMemOp>("MxMoveSrcOpEnc_"#AM)>;
19981ad6265SDimitry Andric} // foreach AM
200fe6060f1SDimitry Andric
20181ad6265SDimitry Andric// Tail call version
20281ad6265SDimitry Andriclet Pattern = [(null_frag)] in {
20381ad6265SDimitry Andric  foreach REG = ["r", "a"] in
20481ad6265SDimitry Andric  foreach AM = MxMoveSupportedAMs in {
20581ad6265SDimitry Andric    foreach TYPE = [MxType16, MxType32] in
20681ad6265SDimitry Andric    def MOV # TYPE.Size # REG # AM # _TC
20781ad6265SDimitry Andric        : MxMove_RM<TYPE, REG, !cast<MxOpBundle>("MxOp"#TYPE.Size#"AddrMode_"#AM),
20881ad6265SDimitry Andric                    !cast<MxEncMemOp>("MxMoveSrcOpEnc_"#AM)> {
20981ad6265SDimitry Andric      let isCodeGenOnly = true;
210fe6060f1SDimitry Andric    }
21181ad6265SDimitry Andric  } // foreach AM
21281ad6265SDimitry Andric} // let Pattern
213fe6060f1SDimitry Andric
21481ad6265SDimitry Andriclet mayLoad = 1, mayStore = 1 in
21581ad6265SDimitry Andricclass MxMove_MM<MxType TYPE, MxOpBundle DST, MxOpBundle SRC,
21681ad6265SDimitry Andric                MxEncMemOp DST_ENC, MxEncMemOp SRC_ENC>
21781ad6265SDimitry Andric    : MxMove<TYPE.Prefix, (outs), (ins DST.Op:$dst, SRC.Op:$src),
21881ad6265SDimitry Andric             [(store (TYPE.Load SRC.Pat:$src), DST.Pat:$dst)],
21981ad6265SDimitry Andric             MxMoveEncoding<!cast<MxMoveSize>("MxMoveSize"#TYPE.Size),
22081ad6265SDimitry Andric                            DST_ENC, SRC_ENC>>;
221fe6060f1SDimitry Andric
22281ad6265SDimitry Andricforeach DST_AM = MxMoveSupportedAMs in
22381ad6265SDimitry Andricforeach SRC_AM = MxMoveSupportedAMs in {
22481ad6265SDimitry Andric  foreach TYPE = [MxType8, MxType16, MxType32] in
22581ad6265SDimitry Andric  def MOV # TYPE.Size # DST_AM # SRC_AM # TYPE.Postfix
22681ad6265SDimitry Andric      : MxMove_MM<TYPE, !cast<MxOpBundle>("MxOp"#TYPE.Size#"AddrMode_"#DST_AM),
22781ad6265SDimitry Andric                  !cast<MxOpBundle>("MxOp"#TYPE.Size#"AddrMode_"#SRC_AM),
22881ad6265SDimitry Andric                  !cast<MxEncMemOp>("MxMoveDstOpEnc_"#DST_AM),
22981ad6265SDimitry Andric                  !cast<MxEncMemOp>("MxMoveSrcOpEnc_"#SRC_AM)>;
23081ad6265SDimitry Andric} // foreach SRC_AM
231fe6060f1SDimitry Andric
232fe6060f1SDimitry Andric// Store ABS(basically pointer) as Immdiate to Mem
233fe6060f1SDimitry Andricdef : Pat<(store   MxType32.BPat :$src, MxType32.PPat :$dst),
234fe6060f1SDimitry Andric          (MOV32pi MxType32.POp  :$dst, MxType32.IOp  :$src)>;
235fe6060f1SDimitry Andric
236fe6060f1SDimitry Andricdef : Pat<(store   MxType32.BPat :$src, MxType32.FPat :$dst),
237fe6060f1SDimitry Andric          (MOV32fi MxType32.FOp  :$dst, MxType32.IOp  :$src)>;
238fe6060f1SDimitry Andric
239fe6060f1SDimitry Andricdef : Pat<(store   MxType32.BPat :$src, MxType32.BPat :$dst),
240fe6060f1SDimitry Andric          (MOV32bi MxType32.BOp  :$dst, MxType32.IOp  :$src)>;
241fe6060f1SDimitry Andric
242fe6060f1SDimitry Andricdef : Pat<(store   MxType32.BPat :$src, MxType32.JPat :$dst),
243fe6060f1SDimitry Andric          (MOV32ji MxType32.JOp  :$dst, MxType32.IOp  :$src)>;
244fe6060f1SDimitry Andric
245fe6060f1SDimitry Andric//===----------------------------------------------------------------------===//
246fe6060f1SDimitry Andric// MOVEM
247fe6060f1SDimitry Andric//
248fe6060f1SDimitry Andric// The mask is already pre-processed by the save/restore spill hook
249fe6060f1SDimitry Andric//===----------------------------------------------------------------------===//
250fe6060f1SDimitry Andric
251fe6060f1SDimitry Andric// Direction
25281ad6265SDimitry Andricdefvar MxMOVEM_MR = false;
25381ad6265SDimitry Andricdefvar MxMOVEM_RM = true;
254fe6060f1SDimitry Andric
255fe6060f1SDimitry Andric// Size
25681ad6265SDimitry Andricdefvar MxMOVEM_W = false;
25781ad6265SDimitry Andricdefvar MxMOVEM_L = true;
258fe6060f1SDimitry Andric
259fe6060f1SDimitry Andric/// ---------------+-------------+-------------+---------
260fe6060f1SDimitry Andric///  F  E  D  C  B | A | 9  8  7 | 6 | 5  4  3 | 2  1  0
261fe6060f1SDimitry Andric/// ---------------+---+---------+---+---------+---------
262fe6060f1SDimitry Andric///  0  1  0  0  1 | D | 0  0  1 | S |   MODE  |   REG
263fe6060f1SDimitry Andric/// ---------------+---+---------+---+---------+---------
264fe6060f1SDimitry Andric///                  REGISTER LIST MASK
265fe6060f1SDimitry Andric/// -----------------------------------------------------
266fe6060f1SDimitry Andric/// D - direction(RM,MR)
267fe6060f1SDimitry Andric/// S - size(W,L)
26881ad6265SDimitry Andricclass MxMOVEMEncoding<MxEncMemOp opnd_enc, bit size, bit direction,
26981ad6265SDimitry Andric                      string mask_op_name> {
27081ad6265SDimitry Andric  dag Value = (ascend
27181ad6265SDimitry Andric    (descend 0b01001, direction, 0b001, size, opnd_enc.EA),
27281ad6265SDimitry Andric    // Mask
27381ad6265SDimitry Andric    (operand "$"#mask_op_name, 16),
27481ad6265SDimitry Andric    opnd_enc.Supplement
27581ad6265SDimitry Andric  );
27681ad6265SDimitry Andric}
277fe6060f1SDimitry Andric
278fe6060f1SDimitry Andriclet mayStore = 1 in
27981ad6265SDimitry Andricclass MxMOVEM_MR<MxType TYPE, bit SIZE_ENC,
28081ad6265SDimitry Andric                 MxOperand MEMOp, MxEncMemOp MEM_ENC>
281fe6060f1SDimitry Andric    : MxInst<(outs), (ins MEMOp:$dst, MxMoveMask:$mask),
28281ad6265SDimitry Andric             "movem."#TYPE.Prefix#"\t$mask, $dst", []> {
28381ad6265SDimitry Andric  let Inst = MxMOVEMEncoding<MEM_ENC, SIZE_ENC, MxMOVEM_MR, "mask">.Value;
28481ad6265SDimitry Andric}
28581ad6265SDimitry Andric
28681ad6265SDimitry Andricforeach AM = MxMoveSupportedAMs in {
28781ad6265SDimitry Andric  foreach TYPE = [MxType16, MxType32] in
28881ad6265SDimitry Andric  def MOVM # TYPE.Size # AM # m # TYPE.Postfix
28981ad6265SDimitry Andric      : MxMOVEM_MR<TYPE, !if(!eq(TYPE, MxType16), MxMOVEM_W, MxMOVEM_L),
29081ad6265SDimitry Andric                   !cast<MxOpBundle>("MxOp"#TYPE.Size#"AddrMode_"#AM).Op,
29181ad6265SDimitry Andric                   !cast<MxEncMemOp>("MxMoveDstOpEnc_"#AM)>;
29281ad6265SDimitry Andric} // foreach AM
293fe6060f1SDimitry Andric
294fe6060f1SDimitry Andriclet mayLoad = 1 in
29581ad6265SDimitry Andricclass MxMOVEM_RM<MxType TYPE, bit SIZE_ENC,
29681ad6265SDimitry Andric                 MxOperand MEMOp, MxEncMemOp MEM_ENC>
297fe6060f1SDimitry Andric    : MxInst<(outs), (ins MxMoveMask:$mask, MEMOp:$src),
29881ad6265SDimitry Andric             "movem."#TYPE.Prefix#"\t$src, $mask", []> {
29981ad6265SDimitry Andric  let Inst = MxMOVEMEncoding<MEM_ENC, SIZE_ENC, MxMOVEM_RM, "mask">.Value;
30081ad6265SDimitry Andric}
301fe6060f1SDimitry Andric
30281ad6265SDimitry Andricforeach AM = MxMoveSupportedAMs in {
30381ad6265SDimitry Andric  foreach TYPE = [MxType16, MxType32] in
30481ad6265SDimitry Andric  def MOVM # TYPE.Size # m # AM # TYPE.Postfix
30581ad6265SDimitry Andric      : MxMOVEM_RM<TYPE, !if(!eq(TYPE, MxType16), MxMOVEM_W, MxMOVEM_L),
30681ad6265SDimitry Andric                   !cast<MxOpBundle>("MxOp"#TYPE.Size#"AddrMode_"#AM).Op,
30781ad6265SDimitry Andric                   !cast<MxEncMemOp>("MxMoveSrcOpEnc_"#AM)>;
30881ad6265SDimitry Andric} // foreach AM
309fe6060f1SDimitry Andric
310fe6060f1SDimitry Andric// Pseudo versions. These a required by virtual register spill/restore since
311fe6060f1SDimitry Andric// the mask requires real register to encode. These instruction will be expanded
312fe6060f1SDimitry Andric// into real MOVEM after RA finishes.
313fe6060f1SDimitry Andriclet mayStore = 1 in
314fe6060f1SDimitry Andricclass MxMOVEM_MR_Pseudo<MxType TYPE, MxOperand MEMOp>
315fe6060f1SDimitry Andric    : MxPseudo<(outs), (ins MEMOp:$dst, TYPE.ROp:$reg)>;
316fe6060f1SDimitry Andriclet mayLoad = 1 in
317fe6060f1SDimitry Andricclass MxMOVEM_RM_Pseudo<MxType TYPE, MxOperand MEMOp>
318fe6060f1SDimitry Andric    : MxPseudo<(outs TYPE.ROp:$dst), (ins MEMOp:$src)>;
319fe6060f1SDimitry Andric
320fe6060f1SDimitry Andric// Mem <- Reg
321fe6060f1SDimitry Andricdef MOVM8jm_P  : MxMOVEM_MR_Pseudo<MxType8d,  MxType8.JOp>;
322fe6060f1SDimitry Andricdef MOVM16jm_P : MxMOVEM_MR_Pseudo<MxType16r, MxType16.JOp>;
323fe6060f1SDimitry Andricdef MOVM32jm_P : MxMOVEM_MR_Pseudo<MxType32r, MxType32.JOp>;
324fe6060f1SDimitry Andric
325fe6060f1SDimitry Andricdef MOVM8pm_P  : MxMOVEM_MR_Pseudo<MxType8d,  MxType8.POp>;
326fe6060f1SDimitry Andricdef MOVM16pm_P : MxMOVEM_MR_Pseudo<MxType16r, MxType16.POp>;
327fe6060f1SDimitry Andricdef MOVM32pm_P : MxMOVEM_MR_Pseudo<MxType32r, MxType32.POp>;
328fe6060f1SDimitry Andric
329fe6060f1SDimitry Andric// Reg <- Mem
330fe6060f1SDimitry Andricdef MOVM8mj_P  : MxMOVEM_RM_Pseudo<MxType8d,  MxType8.JOp>;
331fe6060f1SDimitry Andricdef MOVM16mj_P : MxMOVEM_RM_Pseudo<MxType16r, MxType16.JOp>;
332fe6060f1SDimitry Andricdef MOVM32mj_P : MxMOVEM_RM_Pseudo<MxType32r, MxType32.JOp>;
333fe6060f1SDimitry Andric
334fe6060f1SDimitry Andricdef MOVM8mp_P  : MxMOVEM_RM_Pseudo<MxType8d,  MxType8.POp>;
335fe6060f1SDimitry Andricdef MOVM16mp_P : MxMOVEM_RM_Pseudo<MxType16r, MxType16.POp>;
336fe6060f1SDimitry Andricdef MOVM32mp_P : MxMOVEM_RM_Pseudo<MxType32r, MxType32.POp>;
337fe6060f1SDimitry Andric
338fe6060f1SDimitry Andric
339fe6060f1SDimitry Andric//===----------------------------------------------------------------------===//
340fe6060f1SDimitry Andric// MOVE to/from SR/CCR
341fe6060f1SDimitry Andric//
342fe6060f1SDimitry Andric// A special care must be taken working with to/from CCR since it is basically
343fe6060f1SDimitry Andric// word-size SR register truncated for user mode thus it only supports word-size
344fe6060f1SDimitry Andric// instructions. Plus the original M68000 does not support moves from CCR. So in
345fe6060f1SDimitry Andric// order to use CCR effectively one MUST use proper byte-size pseudo instructi-
346fe6060f1SDimitry Andric// ons that will be resolved sometime after RA pass.
347fe6060f1SDimitry Andric//===----------------------------------------------------------------------===//
348fe6060f1SDimitry Andric
349fe6060f1SDimitry Andric/// --------------------------------------------------
350fe6060f1SDimitry Andric///  F  E  D  C  B  A  9  8  7  6 | 5  4  3 | 2  1  0
351fe6060f1SDimitry Andric/// --------------------------------------------------
352fe6060f1SDimitry Andric///                               | EFFECTIVE ADDRESS
353fe6060f1SDimitry Andric///  0  1  0  0  0  1  0  0  1  1 |   MODE  |   REG
354fe6060f1SDimitry Andric/// --------------------------------------------------
355fe6060f1SDimitry Andriclet Defs = [CCR] in
35681ad6265SDimitry Andricclass MxMoveToCCR<MxOperand MEMOp, MxEncMemOp SRC_ENC>
35781ad6265SDimitry Andric    : MxInst<(outs CCRC:$dst), (ins MEMOp:$src), "move.w\t$src, $dst", []> {
35881ad6265SDimitry Andric  let Inst = (ascend
35981ad6265SDimitry Andric    (descend 0b0100010011, SRC_ENC.EA),
36081ad6265SDimitry Andric    SRC_ENC.Supplement
36181ad6265SDimitry Andric  );
36281ad6265SDimitry Andric}
363fe6060f1SDimitry Andric
36481ad6265SDimitry Andricclass MxMoveToCCRPseudo<MxOperand MEMOp>
36581ad6265SDimitry Andric    : MxPseudo<(outs CCRC:$dst), (ins MEMOp:$src)>;
366fe6060f1SDimitry Andric
36781ad6265SDimitry Andriclet mayLoad = 1 in
36881ad6265SDimitry Andricforeach AM = MxMoveSupportedAMs in {
36981ad6265SDimitry Andric  def MOV16c # AM : MxMoveToCCR<!cast<MxOpBundle>("MxOp16AddrMode_"#AM).Op,
37081ad6265SDimitry Andric                                !cast<MxEncMemOp>("MxMoveSrcOpEnc_"#AM)>;
37181ad6265SDimitry Andric  def MOV8c # AM  : MxMoveToCCRPseudo<!cast<MxOpBundle>("MxOp8AddrMode_"#AM).Op>;
37281ad6265SDimitry Andric} // foreach AM
373fe6060f1SDimitry Andric
37481ad6265SDimitry Andric// Only data register is allowed.
37581ad6265SDimitry Andricdef MOV16cd : MxMoveToCCR<MxOp16AddrMode_d.Op, MxMoveSrcOpEnc_d>;
37681ad6265SDimitry Andricdef MOV8cd  : MxMoveToCCRPseudo<MxOp8AddrMode_d.Op>;
377fe6060f1SDimitry Andric
378fe6060f1SDimitry Andric/// Move from CCR
379fe6060f1SDimitry Andric/// --------------------------------------------------
380fe6060f1SDimitry Andric///  F  E  D  C  B  A  9  8  7  6 | 5  4  3 | 2  1  0
381fe6060f1SDimitry Andric/// --------------------------------------------------
382fe6060f1SDimitry Andric///                               | EFFECTIVE ADDRESS
383fe6060f1SDimitry Andric///  0  1  0  0  0  0  1  0  1  1 |   MODE  |   REG
384fe6060f1SDimitry Andric/// --------------------------------------------------
38581ad6265SDimitry Andriclet Uses = [CCR] in {
38681ad6265SDimitry Andricclass MxMoveFromCCR_R
38781ad6265SDimitry Andric    : MxInst<(outs MxDRD16:$dst), (ins CCRC:$src), "move.w\t$src, $dst", []>,
388bdd1243dSDimitry Andric      Requires<[ AtLeastM68010 ]> {
38981ad6265SDimitry Andric  let Inst = (descend 0b0100001011, MxEncAddrMode_d<"dst">.EA);
39081ad6265SDimitry Andric}
391fe6060f1SDimitry Andric
39281ad6265SDimitry Andricclass MxMoveFromCCR_M<MxOperand MEMOp, MxEncMemOp DST_ENC>
39381ad6265SDimitry Andric    : MxInst<(outs), (ins MEMOp:$dst, CCRC:$src), "move.w\t$src, $dst", []>,
394bdd1243dSDimitry Andric      Requires<[ AtLeastM68010 ]> {
39581ad6265SDimitry Andric  let Inst = (ascend
39681ad6265SDimitry Andric    (descend 0b0100001011, DST_ENC.EA),
39781ad6265SDimitry Andric    DST_ENC.Supplement
39881ad6265SDimitry Andric  );
39981ad6265SDimitry Andric}
400fe6060f1SDimitry Andric
40181ad6265SDimitry Andricclass MxMoveFromCCRPseudo<MxOperand MEMOp>
40281ad6265SDimitry Andric    : MxPseudo<(outs), (ins MEMOp:$dst, CCRC:$src)>;
40381ad6265SDimitry Andric} // let Uses = [CCR]
404fe6060f1SDimitry Andric
40581ad6265SDimitry Andriclet mayStore = 1 in
40681ad6265SDimitry Andricforeach AM = MxMoveSupportedAMs in {
40781ad6265SDimitry Andric  def MOV16 # AM # c
40881ad6265SDimitry Andric    : MxMoveFromCCR_M<!cast<MxOpBundle>("MxOp16AddrMode_"#AM).Op,
40981ad6265SDimitry Andric                      !cast<MxEncMemOp>("MxMoveDstOpEnc_"#AM)>;
41081ad6265SDimitry Andric  def MOV8 # AM # c
41181ad6265SDimitry Andric    : MxMoveFromCCRPseudo<!cast<MxOpBundle>("MxOp8AddrMode_"#AM).Op>;
41281ad6265SDimitry Andric} // foreach AM
413fe6060f1SDimitry Andric
41481ad6265SDimitry Andric// Only data register is allowed.
41581ad6265SDimitry Andricdef MOV16dc : MxMoveFromCCR_R;
41681ad6265SDimitry Andricdef MOV8dc  : MxMoveFromCCRPseudo<MxOp8AddrMode_d.Op>;
417fe6060f1SDimitry Andric
418fe6060f1SDimitry Andric//===----------------------------------------------------------------------===//
419fe6060f1SDimitry Andric// LEA
420fe6060f1SDimitry Andric//===----------------------------------------------------------------------===//
421fe6060f1SDimitry Andric
422fe6060f1SDimitry Andric/// ----------------------------------------------------
423fe6060f1SDimitry Andric///  F  E  D  C | B  A  9 | 8  7  6 | 5  4  3 | 2  1  0
424fe6060f1SDimitry Andric/// ----------------------------------------------------
425fe6060f1SDimitry Andric///  0  1  0  0 | DST REG | 1  1  1 |   MODE  |   REG
426fe6060f1SDimitry Andric/// ----------------------------------------------------
42781ad6265SDimitry Andricclass MxLEA<MxOpBundle SRC, MxEncMemOp SRC_ENC>
42881ad6265SDimitry Andric    : MxInst<(outs MxARD32:$dst), (ins SRC.Op:$src),
42981ad6265SDimitry Andric             "lea\t$src, $dst", [(set i32:$dst, SRC.Pat:$src)]> {
43081ad6265SDimitry Andric  let Inst = (ascend
43181ad6265SDimitry Andric    (descend 0b0100, (operand "$dst", 3), 0b111, SRC_ENC.EA),
43281ad6265SDimitry Andric    SRC_ENC.Supplement
43381ad6265SDimitry Andric  );
43481ad6265SDimitry Andric}
435fe6060f1SDimitry Andric
43681ad6265SDimitry Andricforeach AM = ["p", "f", "b", "q", "k"] in
43781ad6265SDimitry Andricdef LEA32 # AM : MxLEA<!cast<MxOpBundle>("MxOp32AddrMode_"#AM),
43881ad6265SDimitry Andric                       !cast<MxEncMemOp>("MxMoveSrcOpEnc_"#AM)>;
439fe6060f1SDimitry Andric
440fe6060f1SDimitry Andric//===----------------------------------------------------------------------===//
441bdd1243dSDimitry Andric// LINK/UNLK
442bdd1243dSDimitry Andric//===----------------------------------------------------------------------===//
443bdd1243dSDimitry Andric
444bdd1243dSDimitry Andriclet Uses = [SP], Defs = [SP] in {
445bdd1243dSDimitry Andriclet mayStore = 1 in {
446bdd1243dSDimitry Andric
447bdd1243dSDimitry Andricdef LINK16 : MxInst<(outs), (ins MxARD16:$src, Mxi16imm:$disp), "link.w\t$src, $disp", []> {
448bdd1243dSDimitry Andric  let Inst = (ascend
449bdd1243dSDimitry Andric    (descend 0b0100111001010, (operand "$src", 3)),
450bdd1243dSDimitry Andric    (operand "$disp", 16)
451bdd1243dSDimitry Andric  );
452bdd1243dSDimitry Andric}
453bdd1243dSDimitry Andric
454bdd1243dSDimitry Andricdef LINK32 : MxInst<(outs), (ins MxARD16:$src, Mxi32imm:$disp), "link.l\t$src, $disp", []> {
455bdd1243dSDimitry Andric  let Inst = (ascend
456bdd1243dSDimitry Andric    (descend 0b0100100000001, (operand "$src", 3)),
457bdd1243dSDimitry Andric    (slice "$disp", 31, 16),
458bdd1243dSDimitry Andric    (slice "$disp", 15, 0)
459bdd1243dSDimitry Andric  );
460bdd1243dSDimitry Andric}
461bdd1243dSDimitry Andric
462bdd1243dSDimitry Andricdef UNLK : MxInst<(outs), (ins MxARD32:$src), "unlk\t$src", []> {
463bdd1243dSDimitry Andric  let Inst = (descend 0b0100111001011, (operand "$src", 3));
464bdd1243dSDimitry Andric}
465bdd1243dSDimitry Andric
466bdd1243dSDimitry Andric} // let mayStore = 1
467bdd1243dSDimitry Andric} // let Uses = [SP], Defs = [SP]
468bdd1243dSDimitry Andric
469bdd1243dSDimitry Andric//===----------------------------------------------------------------------===//
470fe6060f1SDimitry Andric// Pseudos
471fe6060f1SDimitry Andric//===----------------------------------------------------------------------===//
472fe6060f1SDimitry Andric
473fe6060f1SDimitry Andric/// Pushe/Pop to/from SP for simplicity
474fe6060f1SDimitry Andriclet Uses = [SP], Defs = [SP], hasSideEffects = 0 in {
475fe6060f1SDimitry Andric
476fe6060f1SDimitry Andric// SP <- SP - <size>; (SP) <- Dn
477fe6060f1SDimitry Andriclet mayStore = 1 in {
478fe6060f1SDimitry Andricdef PUSH8d  : MxPseudo<(outs), (ins DR8:$reg)>;
479fe6060f1SDimitry Andricdef PUSH16d : MxPseudo<(outs), (ins DR16:$reg)>;
480fe6060f1SDimitry Andricdef PUSH32r : MxPseudo<(outs), (ins XR32:$reg)>;
481fe6060f1SDimitry Andric} // let mayStore = 1
482fe6060f1SDimitry Andric
483fe6060f1SDimitry Andric// Dn <- (SP); SP <- SP + <size>
484fe6060f1SDimitry Andriclet mayLoad = 1 in {
485fe6060f1SDimitry Andricdef POP8d  : MxPseudo<(outs DR8:$reg),  (ins)>;
486fe6060f1SDimitry Andricdef POP16d : MxPseudo<(outs DR16:$reg), (ins)>;
487fe6060f1SDimitry Andricdef POP32r : MxPseudo<(outs XR32:$reg), (ins)>;
488fe6060f1SDimitry Andric} // let mayLoad = 1
489fe6060f1SDimitry Andric
490fe6060f1SDimitry Andric} // let Uses/Defs = [SP], hasSideEffects = 0
491fe6060f1SDimitry Andric
492fe6060f1SDimitry Andric
493fe6060f1SDimitry Andriclet Defs = [CCR] in {
494fe6060f1SDimitry Andricclass MxPseudoMove_RR<MxType DST, MxType SRC, list<dag> PAT = []>
495fe6060f1SDimitry Andric    : MxPseudo<(outs DST.ROp:$dst), (ins SRC.ROp:$src), PAT>;
496fe6060f1SDimitry Andric
497fe6060f1SDimitry Andricclass MxPseudoMove_RM<MxType DST, MxOperand SRCOpd, list<dag> PAT = []>
498fe6060f1SDimitry Andric    : MxPseudo<(outs DST.ROp:$dst), (ins SRCOpd:$src), PAT>;
499fe6060f1SDimitry Andric}
500fe6060f1SDimitry Andric
501fe6060f1SDimitry Andric/// This group of Pseudos is analogues to the real x86 extending moves, but
502fe6060f1SDimitry Andric/// since M68k does not have those we need to emulate. These instructions
503fe6060f1SDimitry Andric/// will be expanded right after RA completed because we need to know precisely
504fe6060f1SDimitry Andric/// what registers are allocated for the operands and if they overlap we just
505fe6060f1SDimitry Andric/// extend the value if the registers are completely different we need to move
506fe6060f1SDimitry Andric/// first.
507fe6060f1SDimitry Andricforeach EXT = ["S", "Z"] in {
508fe6060f1SDimitry Andric  let hasSideEffects = 0 in {
509fe6060f1SDimitry Andric
510fe6060f1SDimitry Andric    def MOV#EXT#Xd16d8  : MxPseudoMove_RR<MxType16d,  MxType8d>;
511fe6060f1SDimitry Andric    def MOV#EXT#Xd32d8  : MxPseudoMove_RR<MxType32d,  MxType8d>;
512fe6060f1SDimitry Andric    def MOV#EXT#Xd32d16 : MxPseudoMove_RR<MxType32r, MxType16r>;
513fe6060f1SDimitry Andric
514fe6060f1SDimitry Andric    let mayLoad = 1 in {
515fe6060f1SDimitry Andric
516fe6060f1SDimitry Andric      def MOV#EXT#Xd16j8   : MxPseudoMove_RM<MxType16d,  MxType8.JOp>;
517fe6060f1SDimitry Andric      def MOV#EXT#Xd32j8   : MxPseudoMove_RM<MxType32d,  MxType8.JOp>;
518fe6060f1SDimitry Andric      def MOV#EXT#Xd32j16  : MxPseudoMove_RM<MxType32d, MxType16.JOp>;
519fe6060f1SDimitry Andric
520fe6060f1SDimitry Andric      def MOV#EXT#Xd16p8   : MxPseudoMove_RM<MxType16d,  MxType8.POp>;
521fe6060f1SDimitry Andric      def MOV#EXT#Xd32p8   : MxPseudoMove_RM<MxType32d,  MxType8.POp>;
522fe6060f1SDimitry Andric      def MOV#EXT#Xd32p16  : MxPseudoMove_RM<MxType32d, MxType16.POp>;
523fe6060f1SDimitry Andric
524fe6060f1SDimitry Andric      def MOV#EXT#Xd16f8   : MxPseudoMove_RM<MxType16d,  MxType8.FOp>;
525fe6060f1SDimitry Andric      def MOV#EXT#Xd32f8   : MxPseudoMove_RM<MxType32d,  MxType8.FOp>;
526fe6060f1SDimitry Andric      def MOV#EXT#Xd32f16  : MxPseudoMove_RM<MxType32d, MxType16.FOp>;
527fe6060f1SDimitry Andric
52806c3fb27SDimitry Andric      def MOV#EXT#Xd16q8   : MxPseudoMove_RM<MxType16d,  MxType8.QOp>;
52906c3fb27SDimitry Andric      def MOV#EXT#Xd32q8   : MxPseudoMove_RM<MxType32d,  MxType8.QOp>;
53006c3fb27SDimitry Andric      def MOV#EXT#Xd32q16  : MxPseudoMove_RM<MxType32d,  MxType16.QOp>;
53106c3fb27SDimitry Andric
532fe6060f1SDimitry Andric    }
533fe6060f1SDimitry Andric  }
534fe6060f1SDimitry Andric}
535fe6060f1SDimitry Andric
536fe6060f1SDimitry Andric/// This group of instructions is similar to the group above but DOES NOT do
537fe6060f1SDimitry Andric/// any value extension, they just load a smaller register into the lower part
538fe6060f1SDimitry Andric/// of another register if operands' real registers are different or does
539fe6060f1SDimitry Andric/// nothing if they are the same.
540fe6060f1SDimitry Andricdef MOVXd16d8  : MxPseudoMove_RR<MxType16d,  MxType8d>;
541fe6060f1SDimitry Andricdef MOVXd32d8  : MxPseudoMove_RR<MxType32d,  MxType8d>;
542fe6060f1SDimitry Andricdef MOVXd32d16 : MxPseudoMove_RR<MxType32r, MxType16r>;
543fe6060f1SDimitry Andric
544fe6060f1SDimitry Andric//===----------------------------------------------------------------------===//
545fe6060f1SDimitry Andric// Extend/Truncate Patterns
546fe6060f1SDimitry Andric//===----------------------------------------------------------------------===//
547fe6060f1SDimitry Andric
548fe6060f1SDimitry Andric// i16 <- sext i8
549fe6060f1SDimitry Andricdef: Pat<(i16 (sext i8:$src)),
550fe6060f1SDimitry Andric          (EXTRACT_SUBREG (MOVSXd32d8 MxDRD8:$src), MxSubRegIndex16Lo)>;
551fe6060f1SDimitry Andricdef: Pat<(MxSExtLoadi16i8 MxCP_ARI:$src),
552fe6060f1SDimitry Andric          (EXTRACT_SUBREG (MOVSXd32j8 MxARI8:$src), MxSubRegIndex16Lo)>;
553fe6060f1SDimitry Andricdef: Pat<(MxSExtLoadi16i8 MxCP_ARID:$src),
554fe6060f1SDimitry Andric          (EXTRACT_SUBREG (MOVSXd32p8 MxARID8:$src), MxSubRegIndex16Lo)>;
555fe6060f1SDimitry Andricdef: Pat<(MxSExtLoadi16i8 MxCP_ARII:$src),
556fe6060f1SDimitry Andric          (EXTRACT_SUBREG (MOVSXd32f8 MxARII8:$src), MxSubRegIndex16Lo)>;
557fe6060f1SDimitry Andric
558fe6060f1SDimitry Andric// i32 <- sext i8
559fe6060f1SDimitry Andricdef: Pat<(i32 (sext i8:$src)), (MOVSXd32d8 MxDRD8:$src)>;
560fe6060f1SDimitry Andricdef: Pat<(MxSExtLoadi32i8 MxCP_ARI :$src), (MOVSXd32j8 MxARI8 :$src)>;
561fe6060f1SDimitry Andricdef: Pat<(MxSExtLoadi32i8 MxCP_ARID:$src), (MOVSXd32p8 MxARID8:$src)>;
562fe6060f1SDimitry Andricdef: Pat<(MxSExtLoadi32i8 MxCP_ARII:$src), (MOVSXd32f8 MxARII8:$src)>;
563fe6060f1SDimitry Andric
564fe6060f1SDimitry Andric// i32 <- sext i16
565fe6060f1SDimitry Andricdef: Pat<(i32 (sext i16:$src)), (MOVSXd32d16 MxDRD16:$src)>;
566fe6060f1SDimitry Andricdef: Pat<(MxSExtLoadi32i16 MxCP_ARI :$src), (MOVSXd32j16 MxARI16 :$src)>;
567fe6060f1SDimitry Andricdef: Pat<(MxSExtLoadi32i16 MxCP_ARID:$src), (MOVSXd32p16 MxARID16:$src)>;
568fe6060f1SDimitry Andricdef: Pat<(MxSExtLoadi32i16 MxCP_ARII:$src), (MOVSXd32f16 MxARII16:$src)>;
569fe6060f1SDimitry Andric
570fe6060f1SDimitry Andric// i16 <- zext i8
571fe6060f1SDimitry Andricdef: Pat<(i16 (zext i8:$src)),
572fe6060f1SDimitry Andric          (EXTRACT_SUBREG (MOVZXd32d8 MxDRD8:$src), MxSubRegIndex16Lo)>;
573fe6060f1SDimitry Andricdef: Pat<(MxZExtLoadi16i8 MxCP_ARI:$src),
574fe6060f1SDimitry Andric          (EXTRACT_SUBREG (MOVZXd32j8 MxARI8:$src), MxSubRegIndex16Lo)>;
575fe6060f1SDimitry Andricdef: Pat<(MxZExtLoadi16i8 MxCP_ARID:$src),
576fe6060f1SDimitry Andric          (EXTRACT_SUBREG (MOVZXd32p8 MxARID8:$src), MxSubRegIndex16Lo)>;
577fe6060f1SDimitry Andricdef: Pat<(MxZExtLoadi16i8 MxCP_ARII:$src),
578fe6060f1SDimitry Andric          (EXTRACT_SUBREG (MOVZXd32f8 MxARII8:$src), MxSubRegIndex16Lo)>;
57906c3fb27SDimitry Andricdef: Pat<(MxZExtLoadi16i8 MxCP_PCD :$src), (MOVZXd16q8 MxPCD8 :$src)>;
580fe6060f1SDimitry Andric
581fe6060f1SDimitry Andric// i32 <- zext i8
582fe6060f1SDimitry Andricdef: Pat<(i32 (zext i8:$src)), (MOVZXd32d8 MxDRD8:$src)>;
583fe6060f1SDimitry Andricdef: Pat<(MxZExtLoadi32i8 MxCP_ARI :$src), (MOVZXd32j8 MxARI8 :$src)>;
584fe6060f1SDimitry Andricdef: Pat<(MxZExtLoadi32i8 MxCP_ARID:$src), (MOVZXd32p8 MxARID8:$src)>;
585fe6060f1SDimitry Andricdef: Pat<(MxZExtLoadi32i8 MxCP_ARII:$src), (MOVZXd32f8 MxARII8:$src)>;
58606c3fb27SDimitry Andricdef: Pat<(MxZExtLoadi32i8 MxCP_PCD :$src), (MOVZXd32q8 MxPCD8 :$src)>;
587fe6060f1SDimitry Andric
588fe6060f1SDimitry Andric// i32 <- zext i16
589fe6060f1SDimitry Andricdef: Pat<(i32 (zext i16:$src)), (MOVZXd32d16 MxDRD16:$src)>;
590fe6060f1SDimitry Andricdef: Pat<(MxZExtLoadi32i16 MxCP_ARI :$src), (MOVZXd32j16 MxARI16 :$src)>;
591fe6060f1SDimitry Andricdef: Pat<(MxZExtLoadi32i16 MxCP_ARID:$src), (MOVZXd32p16 MxARID16:$src)>;
592fe6060f1SDimitry Andricdef: Pat<(MxZExtLoadi32i16 MxCP_ARII:$src), (MOVZXd32f16 MxARII16:$src)>;
59306c3fb27SDimitry Andricdef: Pat<(MxZExtLoadi32i16 MxCP_PCD :$src), (MOVZXd32q16 MxPCD16 :$src)>;
594fe6060f1SDimitry Andric
595fe6060f1SDimitry Andric// i16 <- anyext i8
596fe6060f1SDimitry Andricdef: Pat<(i16 (anyext i8:$src)),
597fe6060f1SDimitry Andric          (EXTRACT_SUBREG (MOVZXd32d8 MxDRD8:$src), MxSubRegIndex16Lo)>;
598fe6060f1SDimitry Andricdef: Pat<(MxExtLoadi16i8 MxCP_ARI:$src),
599fe6060f1SDimitry Andric          (EXTRACT_SUBREG (MOVZXd32j8 MxARI8:$src), MxSubRegIndex16Lo)>;
600fe6060f1SDimitry Andricdef: Pat<(MxExtLoadi16i8 MxCP_ARID:$src),
601fe6060f1SDimitry Andric          (EXTRACT_SUBREG (MOVZXd32p8 MxARID8:$src), MxSubRegIndex16Lo)>;
602fe6060f1SDimitry Andricdef: Pat<(MxExtLoadi16i8 MxCP_ARII:$src),
603fe6060f1SDimitry Andric          (EXTRACT_SUBREG (MOVZXd32f8 MxARII8:$src), MxSubRegIndex16Lo)>;
604fe6060f1SDimitry Andric
605fe6060f1SDimitry Andric// i32 <- anyext i8
606fe6060f1SDimitry Andricdef: Pat<(i32 (anyext i8:$src)), (MOVZXd32d8 MxDRD8:$src)>;
607fe6060f1SDimitry Andricdef: Pat<(MxExtLoadi32i8 MxCP_ARI :$src), (MOVZXd32j8 MxARI8 :$src)>;
608fe6060f1SDimitry Andricdef: Pat<(MxExtLoadi32i8 MxCP_ARID:$src), (MOVZXd32p8 MxARID8:$src)>;
609fe6060f1SDimitry Andricdef: Pat<(MxExtLoadi32i8 MxCP_ARII:$src), (MOVZXd32f8 MxARII8:$src)>;
610fe6060f1SDimitry Andric
611fe6060f1SDimitry Andric// i32 <- anyext i16
612fe6060f1SDimitry Andricdef: Pat<(i32 (anyext i16:$src)), (MOVZXd32d16 MxDRD16:$src)>;
613fe6060f1SDimitry Andricdef: Pat<(MxExtLoadi32i16 MxCP_ARI :$src), (MOVZXd32j16 MxARI16 :$src)>;
614fe6060f1SDimitry Andricdef: Pat<(MxExtLoadi32i16 MxCP_ARID:$src), (MOVZXd32p16 MxARID16:$src)>;
615fe6060f1SDimitry Andricdef: Pat<(MxExtLoadi32i16 MxCP_ARII:$src), (MOVZXd32f16 MxARII16:$src)>;
616fe6060f1SDimitry Andric
617fe6060f1SDimitry Andric// trunc patterns
618fe6060f1SDimitry Andricdef : Pat<(i16 (trunc i32:$src)),
619fe6060f1SDimitry Andric          (EXTRACT_SUBREG MxXRD32:$src, MxSubRegIndex16Lo)>;
620fe6060f1SDimitry Andricdef : Pat<(i8  (trunc i32:$src)),
621fe6060f1SDimitry Andric          (EXTRACT_SUBREG MxXRD32:$src, MxSubRegIndex8Lo)>;
622fe6060f1SDimitry Andricdef : Pat<(i8  (trunc i16:$src)),
623fe6060f1SDimitry Andric          (EXTRACT_SUBREG MxXRD16:$src, MxSubRegIndex8Lo)>;
62406c3fb27SDimitry Andric
62506c3fb27SDimitry Andric//===----------------------------------------------------------------------===//
62606c3fb27SDimitry Andric// FMOVE
62706c3fb27SDimitry Andric//===----------------------------------------------------------------------===//
62806c3fb27SDimitry Andric
62906c3fb27SDimitry Andriclet Defs = [FPS] in
63006c3fb27SDimitry Andricclass MxFMove<string size, dag outs, dag ins, list<dag> pattern,
63106c3fb27SDimitry Andric              string rounding = "">
63206c3fb27SDimitry Andric    : MxInst<outs, ins,
63306c3fb27SDimitry Andric             "f"#rounding#"move."#size#"\t$src, $dst", pattern> {
63406c3fb27SDimitry Andric  // Only FMOVE uses FPC
63506c3fb27SDimitry Andric  let Uses = !if(!eq(rounding, ""), [FPC], []);
63606c3fb27SDimitry Andric
63706c3fb27SDimitry Andric  // FSMOVE and FDMOVE are only available after M68040
63806c3fb27SDimitry Andric  let Predicates = [!if(!eq(rounding, ""), AtLeastM68881, AtLeastM68040)];
63906c3fb27SDimitry Andric}
64006c3fb27SDimitry Andric
64106c3fb27SDimitry Andric// FPDR <- FPDR
64206c3fb27SDimitry Andricclass MxFMove_FF<string rounding, int size,
64306c3fb27SDimitry Andric                 MxOpBundle Opnd = !cast<MxOpBundle>("MxOp"#size#"AddrMode_fpr")>
64406c3fb27SDimitry Andric    : MxFMove<"x", (outs Opnd.Op:$dst), (ins Opnd.Op:$src),
64506c3fb27SDimitry Andric              [(null_frag)], rounding> {
64606c3fb27SDimitry Andric  let Inst = (ascend
64706c3fb27SDimitry Andric    (descend 0b1111,
64806c3fb27SDimitry Andric      /*COPROCESSOR ID*/0b001,
64906c3fb27SDimitry Andric      0b000,
65006c3fb27SDimitry Andric      /*MODE + REGISTER*/0b000000
65106c3fb27SDimitry Andric    ),
65206c3fb27SDimitry Andric    (descend 0b0, /* R/M */0b0, 0b0,
65306c3fb27SDimitry Andric      /*SOURCE SPECIFIER*/
65406c3fb27SDimitry Andric      (operand "$src", 3),
65506c3fb27SDimitry Andric      /*DESTINATION*/
65606c3fb27SDimitry Andric      (operand "$dst", 3),
65706c3fb27SDimitry Andric      /*OPMODE*/
65806c3fb27SDimitry Andric      !cond(!eq(rounding, "s"): 0b1000000,
65906c3fb27SDimitry Andric            !eq(rounding, "d"): 0b1000100,
66006c3fb27SDimitry Andric            true: 0b0000000)
66106c3fb27SDimitry Andric    )
66206c3fb27SDimitry Andric  );
66306c3fb27SDimitry Andric}
66406c3fb27SDimitry Andric
66506c3fb27SDimitry Andricforeach rounding = ["", "s", "d"] in {
66606c3fb27SDimitry Andric  def F # !toupper(rounding) # MOV80fp_fp : MxFMove_FF<rounding, 80>;
66706c3fb27SDimitry Andric
66806c3fb27SDimitry Andric  // We don't have `fmove.s` or `fmove.d` because values will be converted to
66906c3fb27SDimitry Andric  // f80 upon storing into the register, but FMOV32/64fp_fp are still needed
67006c3fb27SDimitry Andric  // to make codegen easier.
67106c3fb27SDimitry Andric  let isCodeGenOnly = true in
67206c3fb27SDimitry Andric  foreach size = [32, 64] in
67306c3fb27SDimitry Andric    def F # !toupper(rounding) # MOV # size # fp_fp : MxFMove_FF<rounding, size>;
67406c3fb27SDimitry Andric}
675*5f757f3fSDimitry Andric// Direction
676*5f757f3fSDimitry Andricdefvar MxFMove_FP_EA = false;
677*5f757f3fSDimitry Andricdefvar MxFMove_EA_FP = true;
678*5f757f3fSDimitry Andric
679*5f757f3fSDimitry Andric// Encoding scheme for FPSYS <-> R/M
680*5f757f3fSDimitry Andricclass MxEncFSysMove<bit dir, MxEncMemOp EAEnc, string fsys_reg> {
681*5f757f3fSDimitry Andric  dag Value = (ascend
682*5f757f3fSDimitry Andric    (descend 0b1111,
683*5f757f3fSDimitry Andric      /*COPROCESSOR ID*/0b001,
684*5f757f3fSDimitry Andric      0b000,
685*5f757f3fSDimitry Andric      /*MODE + REGISTER*/
686*5f757f3fSDimitry Andric      EAEnc.EA
687*5f757f3fSDimitry Andric    ),
688*5f757f3fSDimitry Andric    (descend 0b10, /*dir*/ dir,
689*5f757f3fSDimitry Andric      /*REGISTER SELECT*/
690*5f757f3fSDimitry Andric      (operand "$"#fsys_reg, 3, (encoder "encodeFPSYSSelect")),
691*5f757f3fSDimitry Andric      0b0000000000
692*5f757f3fSDimitry Andric    )
693*5f757f3fSDimitry Andric  );
694*5f757f3fSDimitry Andric}
695*5f757f3fSDimitry Andric
696*5f757f3fSDimitry Andric// FPSYS <-> R
697*5f757f3fSDimitry Andricclass MxFMove_FSYS_R<string src_reg,
698*5f757f3fSDimitry Andric                     MxOpBundle SrcOpnd = !cast<MxOpBundle>("MxOp32AddrMode_"#src_reg),
699*5f757f3fSDimitry Andric                     MxOpBundle DstOpnd = !cond(!eq(src_reg, "d"): MxOp32AddrMode_fpcs,
700*5f757f3fSDimitry Andric                                                !eq(src_reg, "a"): MxOp32AddrMode_fpi),
701*5f757f3fSDimitry Andric                     MxEncMemOp SrcEnc = !cast<MxEncMemOp>("MxMoveSrcOpEnc_"#src_reg)>
702*5f757f3fSDimitry Andric    : MxFMove<"l", (outs DstOpnd.Op:$dst), (ins SrcOpnd.Op:$src),
703*5f757f3fSDimitry Andric              [(null_frag)]> {
704*5f757f3fSDimitry Andric  let Inst = MxEncFSysMove<MxFMove_FP_EA, SrcEnc, "dst">.Value;
705*5f757f3fSDimitry Andric}
706*5f757f3fSDimitry Andric
707*5f757f3fSDimitry Andricclass MxFMove_R_FSYS<string dst_reg,
708*5f757f3fSDimitry Andric                     MxOpBundle SrcOpnd = !cond(!eq(dst_reg, "d"): MxOp32AddrMode_fpcs,
709*5f757f3fSDimitry Andric                                                !eq(dst_reg, "a"): MxOp32AddrMode_fpi),
710*5f757f3fSDimitry Andric                     MxOpBundle DstOpnd = !cast<MxOpBundle>("MxOp32AddrMode_"#dst_reg),
711*5f757f3fSDimitry Andric                     MxEncMemOp DstEnc = !cast<MxEncMemOp>("MxMoveDstOpEnc_"#dst_reg)>
712*5f757f3fSDimitry Andric    : MxFMove<"l", (outs DstOpnd.Op:$dst), (ins SrcOpnd.Op:$src),
713*5f757f3fSDimitry Andric              [(null_frag)]> {
714*5f757f3fSDimitry Andric  let Inst = MxEncFSysMove<MxFMove_EA_FP, DstEnc, "src">.Value;
715*5f757f3fSDimitry Andric}
716*5f757f3fSDimitry Andric
717*5f757f3fSDimitry Andricdef FMOVE32fpcs_d : MxFMove_FSYS_R<"d">;
718*5f757f3fSDimitry Andricdef FMOVE32d_fpcs : MxFMove_R_FSYS<"d">;
719*5f757f3fSDimitry Andricdef FMOVE32fpi_a  : MxFMove_FSYS_R<"a">;
720*5f757f3fSDimitry Andricdef FMOVE32a_fpi  : MxFMove_R_FSYS<"a">;
721