xref: /llvm-project/llvm/lib/Target/M68k/M68kInstrData.td (revision a0d77492110cce44d563166ed7ce21fdb3670f64)
1//===-- M68kInstrData.td - M68k Data Movement Instructions -*- tablegen -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8///
9/// \file
10/// This file describes the Motorola 680x0 data movement instructions which are
11/// the basic means of transferring and storing addresses and data. Here is the
12/// current status of the file:
13///
14///  Machine:
15///
16///     EXG   [ ]     FMOVE [ ]     FSMOVE [ ]     FDMOVE [ ]     FMOVEM [ ]
17///     LEA   [~]     PEA   [ ]     MOVE   [~]     MOVE16 [ ]     MOVEA  [ ]
18///     MOVEM [ ]     MOVEP [ ]     MOVEQ  [ ]     LINK   [~]     UNLK   [~]
19///
20///  Pseudo:
21///
22///     MOVI  [x]     MOVSX [x]     MOVZX [x]     MOVX   [x]
23///
24///  Map:
25///
26///   [ ] - was not touched at all
27///   [!] - requires extarnal stuff implemented
28///   [~] - in progress but usable
29///   [x] - done
30///
31//===----------------------------------------------------------------------===//
32
33//===----------------------------------------------------------------------===//
34// MOVE
35//===----------------------------------------------------------------------===//
36
37/// -----------------------------------------------------
38///  F  E | D  C | B  A  9 | 8  7  6 | 5  4  3 | 2  1  0
39/// -----------------------------------------------------
40///       |      |    DESTINATION    |       SOURCE
41///  0  0 | SIZE |   REG   |   MODE  |   MODE  |   REG
42/// -----------------------------------------------------
43///
44/// NOTE Move requires EA X version for direct register destination(0)
45
46// MOVE has a different size encoding.
47class MxMoveSize<bits<2> value> {
48  bits<2> Value = value;
49}
50def MxMoveSize8  : MxMoveSize<0b01>;
51def MxMoveSize16 : MxMoveSize<0b11>;
52def MxMoveSize32 : MxMoveSize<0b10>;
53
54class MxMoveEncoding<MxMoveSize size, MxEncMemOp dst_enc, MxEncMemOp src_enc> {
55  dag Value = (ascend
56    (descend 0b00, size.Value,
57             !cond(
58               !eq(!getdagop(dst_enc.EA), descend): !setdagop(dst_enc.EA, ascend),
59               !eq(!getdagop(dst_enc.EA), ascend): !setdagop(dst_enc.EA, descend)),
60             src_enc.EA),
61    // Source extension
62    src_enc.Supplement,
63    // Destination extension
64    dst_enc.Supplement
65  );
66}
67
68// Special encoding for Xn
69class MxMoveEncAddrMode_r<string reg_opnd> : MxEncMemOp {
70  let EA = (descend (descend 0b00, (slice "$"#reg_opnd, 3, 3)),
71                    (operand "$"#reg_opnd, 3));
72}
73
74// TODO: Generalize and adopt this utility in other .td files as well.
75multiclass MxMoveOperandEncodings<string opnd_name> {
76  // Dn
77  def MxMove#NAME#OpEnc_d : MxEncAddrMode_d<opnd_name>;
78  // An
79  def MxMove#NAME#OpEnc_a : MxEncAddrMode_a<opnd_name>;
80  // Xn
81  def MxMove#NAME#OpEnc_r : MxMoveEncAddrMode_r<opnd_name>;
82  // (An)+
83  def MxMove#NAME#OpEnc_o : MxEncAddrMode_o<opnd_name>;
84  // -(An)
85  def MxMove#NAME#OpEnc_e : MxEncAddrMode_e<opnd_name>;
86  // (i,PC,Xn)
87  def MxMove#NAME#OpEnc_k : MxEncAddrMode_k<opnd_name>;
88  // (i,PC)
89  def MxMove#NAME#OpEnc_q : MxEncAddrMode_q<opnd_name>;
90  // (i,An,Xn)
91  def MxMove#NAME#OpEnc_f : MxEncAddrMode_f<opnd_name>;
92  // (i,An)
93  def MxMove#NAME#OpEnc_p : MxEncAddrMode_p<opnd_name>;
94  // (ABS).L
95  def MxMove#NAME#OpEnc_b : MxEncAddrMode_abs<opnd_name, /*W/L=*/true>;
96  // (An)
97  def MxMove#NAME#OpEnc_j : MxEncAddrMode_j<opnd_name>;
98}
99
100defm Src : MxMoveOperandEncodings<"src">;
101defm Dst : MxMoveOperandEncodings<"dst">;
102
103defvar MxMoveSupportedAMs = ["o", "e", "k", "q", "f", "p", "b", "j"];
104
105let Defs = [CCR] in
106class MxMove<string size, dag outs, dag ins, list<dag> pattern, MxMoveEncoding enc>
107    : MxInst<outs, ins, "move."#size#"\t$src, $dst", pattern> {
108  let Inst = enc.Value;
109}
110
111// R <- R
112class MxMove_RR<MxType TYPE, string DST_REG, string SRC_REG,
113                MxMoveEncoding ENC,
114                MxOpBundle DST = !cast<MxOpBundle>("MxOp"#TYPE.Size#"AddrMode_"#DST_REG),
115                MxOpBundle SRC = !cast<MxOpBundle>("MxOp"#TYPE.Size#"AddrMode_"#SRC_REG)>
116    : MxMove<TYPE.Prefix,
117             (outs DST.Op:$dst), (ins SRC.Op:$src),
118             [(null_frag)], ENC>;
119
120foreach DST_REG = ["r", "a"] in {
121  foreach SRC_REG = ["r", "a"] in
122  foreach TYPE = [MxType16, MxType32] in
123  def MOV # TYPE.Size # DST_REG # SRC_REG # TYPE.Postfix
124      : MxMove_RR<TYPE, DST_REG, SRC_REG,
125                  MxMoveEncoding<!cast<MxMoveSize>("MxMoveSize"#TYPE.Size),
126                                 !cast<MxEncMemOp>("MxMoveDstOpEnc_"#DST_REG),
127                                 !cast<MxEncMemOp>("MxMoveSrcOpEnc_"#SRC_REG)>>;
128} // foreach DST_REG
129foreach TYPE = [MxType8, MxType16, MxType32] in
130def MOV # TYPE.Size # dd # TYPE.Postfix
131    : MxMove_RR<TYPE, "d", "d",
132                MxMoveEncoding<!cast<MxMoveSize>("MxMoveSize"#TYPE.Size),
133                               MxMoveDstOpEnc_d, MxMoveSrcOpEnc_d>>;
134
135// M <- R
136let mayStore = 1 in {
137class MxMove_MR<MxType TYPE, MxOpBundle DST, string SRC_REG, MxMoveEncoding ENC,
138                MxOpBundle SRC = !cast<MxOpBundle>("MxOp"#TYPE.Size#"AddrMode_"#SRC_REG)>
139    : MxMove<TYPE.Prefix, (outs), (ins DST.Op:$dst, SRC.Op:$src),
140             [(store TYPE.VT:$src, DST.Pat:$dst)], ENC>;
141
142class MxMove_MI<MxType TYPE, MxOpBundle DST, MxMoveEncoding ENC,
143                MxImmOpBundle SRC = !cast<MxImmOpBundle>("MxOp"#TYPE.Size#"AddrMode_i")>
144    : MxMove<TYPE.Prefix, (outs), (ins DST.Op:$dst, SRC.Op:$src),
145             [(store SRC.ImmPat:$src, DST.Pat:$dst)], ENC>;
146} // let mayStore = 1
147
148foreach REG = ["r", "a", "d"] in
149foreach AM = MxMoveSupportedAMs in {
150  foreach TYPE = !if(!eq(REG, "d"), [MxType8, MxType16, MxType32], [MxType16, MxType32]) in
151  def MOV # TYPE.Size # AM # REG # TYPE.Postfix
152      : MxMove_MR<TYPE, !cast<MxOpBundle>("MxOp"#TYPE.Size#"AddrMode_"#AM), REG,
153                  MxMoveEncoding<!cast<MxMoveSize>("MxMoveSize"#TYPE.Size),
154                                 !cast<MxEncMemOp>("MxMoveDstOpEnc_"#AM),
155                                 !cast<MxEncMemOp>("MxMoveSrcOpEnc_"#REG)>>;
156} // foreach AM
157
158foreach AM = MxMoveSupportedAMs in {
159  foreach TYPE = [MxType8, MxType16, MxType32] in
160  def MOV # TYPE.Size # AM # i # TYPE.Postfix
161      : MxMove_MI<TYPE, !cast<MxOpBundle>("MxOp"#TYPE.Size#"AddrMode_"#AM),
162                  MxMoveEncoding<!cast<MxMoveSize>("MxMoveSize"#TYPE.Size),
163                                 !cast<MxEncMemOp>("MxMoveDstOpEnc_"#AM),
164                                 MxEncAddrMode_i<"src", TYPE.Size>>>;
165} // foreach AM
166
167// R <- I
168// No pattern, as all immediate -> register moves are matched to the MOVI pseudo
169class MxMove_RI<MxType TYPE, string DST_REG, MxMoveEncoding ENC,
170                MxImmOpBundle SRC = !cast<MxImmOpBundle>("MxOp"#TYPE.Size#"AddrMode_i"),
171                MxOpBundle DST = !cast<MxOpBundle>("MxOp"#TYPE.Size#"AddrMode_"#DST_REG)>
172    : MxMove<TYPE.Prefix, (outs DST.Op:$dst), (ins SRC.Op:$src),
173              [(null_frag)], ENC>;
174
175foreach REG = ["r", "a", "d"] in {
176  foreach TYPE = !if(!eq(REG, "d"), [MxType8, MxType16, MxType32], [MxType16, MxType32]) in
177  def MOV # TYPE.Size # REG # i # TYPE.Postfix
178      : MxMove_RI<TYPE, REG,
179                  MxMoveEncoding<!cast<MxMoveSize>("MxMoveSize"#TYPE.Size),
180                                 !cast<MxEncMemOp>("MxMoveDstOpEnc_"#REG),
181                                 MxEncAddrMode_i<"src", TYPE.Size>>>;
182} // foreach REG
183
184// R <- M
185let mayLoad = 1 in
186class MxMove_RM<MxType TYPE, string DST_REG, MxOpBundle SRC, MxEncMemOp SRC_ENC,
187                MxMoveSize SIZE_ENC = !cast<MxMoveSize>("MxMoveSize"#TYPE.Size),
188                MxOpBundle DST = !cast<MxOpBundle>("MxOp"#TYPE.Size#"AddrMode_"#DST_REG),
189                MxEncMemOp DST_ENC = !cast<MxEncMemOp>("MxMoveDstOpEnc_"#DST_REG)>
190    : MxMove<TYPE.Prefix, (outs DST.Op:$dst), (ins SRC.Op:$src),
191             [(set TYPE.VT:$dst, (TYPE.Load SRC.Pat:$src))],
192             MxMoveEncoding<SIZE_ENC, DST_ENC, SRC_ENC>>;
193
194foreach REG = ["r", "a", "d"] in
195foreach AM = MxMoveSupportedAMs in {
196  foreach TYPE = !if(!eq(REG, "d"), [MxType8, MxType16, MxType32], [MxType16, MxType32]) in
197  def MOV # TYPE.Size # REG # AM # TYPE.Postfix
198      : MxMove_RM<TYPE, REG, !cast<MxOpBundle>("MxOp"#TYPE.Size#"AddrMode_"#AM),
199                  !cast<MxEncMemOp>("MxMoveSrcOpEnc_"#AM)>;
200} // foreach AM
201
202// Tail call version
203let Pattern = [(null_frag)] in {
204  foreach REG = ["r", "a"] in
205  foreach AM = MxMoveSupportedAMs in {
206    foreach TYPE = [MxType16, MxType32] in
207    def MOV # TYPE.Size # REG # AM # _TC
208        : MxMove_RM<TYPE, REG, !cast<MxOpBundle>("MxOp"#TYPE.Size#"AddrMode_"#AM),
209                    !cast<MxEncMemOp>("MxMoveSrcOpEnc_"#AM)> {
210      let isCodeGenOnly = true;
211    }
212  } // foreach AM
213} // let Pattern
214
215let mayLoad = 1, mayStore = 1 in
216class MxMove_MM<MxType TYPE, MxOpBundle DST, MxOpBundle SRC,
217                MxEncMemOp DST_ENC, MxEncMemOp SRC_ENC>
218    : MxMove<TYPE.Prefix, (outs), (ins DST.Op:$dst, SRC.Op:$src),
219             [(store (TYPE.Load SRC.Pat:$src), DST.Pat:$dst)],
220             MxMoveEncoding<!cast<MxMoveSize>("MxMoveSize"#TYPE.Size),
221                            DST_ENC, SRC_ENC>>;
222
223foreach DST_AM = MxMoveSupportedAMs in
224foreach SRC_AM = MxMoveSupportedAMs in {
225  foreach TYPE = [MxType8, MxType16, MxType32] in
226  def MOV # TYPE.Size # DST_AM # SRC_AM # TYPE.Postfix
227      : MxMove_MM<TYPE, !cast<MxOpBundle>("MxOp"#TYPE.Size#"AddrMode_"#DST_AM),
228                  !cast<MxOpBundle>("MxOp"#TYPE.Size#"AddrMode_"#SRC_AM),
229                  !cast<MxEncMemOp>("MxMoveDstOpEnc_"#DST_AM),
230                  !cast<MxEncMemOp>("MxMoveSrcOpEnc_"#SRC_AM)>;
231} // foreach SRC_AM
232
233// Store ABS(basically pointer) as Immdiate to Mem
234def : Pat<(store   MxType32.BPat :$src, MxType32.PPat :$dst),
235          (MOV32pi MxType32.POp  :$dst, MxType32.IOp  :$src)>;
236
237def : Pat<(store   MxType32.BPat :$src, MxType32.FPat :$dst),
238          (MOV32fi MxType32.FOp  :$dst, MxType32.IOp  :$src)>;
239
240def : Pat<(store   MxType32.BPat :$src, MxType32.BPat :$dst),
241          (MOV32bi MxType32.BOp  :$dst, MxType32.IOp  :$src)>;
242
243def : Pat<(store   MxType32.BPat :$src, MxType32.JPat :$dst),
244          (MOV32ji MxType32.JOp  :$dst, MxType32.IOp  :$src)>;
245
246//===----------------------------------------------------------------------===//
247// MOVEQ
248//===----------------------------------------------------------------------===//
249
250/// ------------+---------+---+-----------------------
251///  F  E  D  C | B  A  9 | 8 | 7  6  5  4  3  2  1  0
252/// ------------+---------+---+-----------------------
253///  0  1  1  1 |   REG   | 0 |          DATA
254/// ------------+---------+---+-----------------------
255
256// No pattern, as all immediate -> register moves are matched to the MOVI pseudo
257let Defs = [CCR] in
258def MOVQ : MxInst<(outs MxDRD32:$dst), (ins Mxi8imm:$imm),
259                  "moveq\t$imm, $dst",
260                  [(null_frag)]> {
261  let Inst = (descend 0b0111, (operand "$dst", 3), 0b0, (operand "$imm", 8));
262}
263
264//===----------------------------------------------------------------------===//
265// MOVEM
266//
267// The mask is already pre-processed by the save/restore spill hook
268//===----------------------------------------------------------------------===//
269
270// Direction
271defvar MxMOVEM_MR = false;
272defvar MxMOVEM_RM = true;
273
274// Size
275defvar MxMOVEM_W = false;
276defvar MxMOVEM_L = true;
277
278/// ---------------+-------------+-------------+---------
279///  F  E  D  C  B | A | 9  8  7 | 6 | 5  4  3 | 2  1  0
280/// ---------------+---+---------+---+---------+---------
281///  0  1  0  0  1 | D | 0  0  1 | S |   MODE  |   REG
282/// ---------------+---+---------+---+---------+---------
283///                  REGISTER LIST MASK
284/// -----------------------------------------------------
285/// D - direction(RM,MR)
286/// S - size(W,L)
287class MxMOVEMEncoding<MxEncMemOp opnd_enc, bit size, bit direction,
288                      string mask_op_name> {
289  dag Value = (ascend
290    (descend 0b01001, direction, 0b001, size, opnd_enc.EA),
291    // Mask
292    (operand "$"#mask_op_name, 16),
293    opnd_enc.Supplement
294  );
295}
296
297let mayStore = 1 in
298class MxMOVEM_MR<MxType TYPE, bit SIZE_ENC,
299                 MxOperand MEMOp, MxEncMemOp MEM_ENC>
300    : MxInst<(outs), (ins MEMOp:$dst, MxMoveMask:$mask),
301             "movem."#TYPE.Prefix#"\t$mask, $dst", []> {
302  let Inst = MxMOVEMEncoding<MEM_ENC, SIZE_ENC, MxMOVEM_MR, "mask">.Value;
303}
304
305foreach AM = MxMoveSupportedAMs in {
306  foreach TYPE = [MxType16, MxType32] in
307  def MOVM # TYPE.Size # AM # m # TYPE.Postfix
308      : MxMOVEM_MR<TYPE, !if(!eq(TYPE, MxType16), MxMOVEM_W, MxMOVEM_L),
309                   !cast<MxOpBundle>("MxOp"#TYPE.Size#"AddrMode_"#AM).Op,
310                   !cast<MxEncMemOp>("MxMoveDstOpEnc_"#AM)>;
311} // foreach AM
312
313let mayLoad = 1 in
314class MxMOVEM_RM<MxType TYPE, bit SIZE_ENC,
315                 MxOperand MEMOp, MxEncMemOp MEM_ENC>
316    : MxInst<(outs), (ins MxMoveMask:$mask, MEMOp:$src),
317             "movem."#TYPE.Prefix#"\t$src, $mask", []> {
318  let Inst = MxMOVEMEncoding<MEM_ENC, SIZE_ENC, MxMOVEM_RM, "mask">.Value;
319}
320
321foreach AM = MxMoveSupportedAMs in {
322  foreach TYPE = [MxType16, MxType32] in
323  def MOVM # TYPE.Size # m # AM # TYPE.Postfix
324      : MxMOVEM_RM<TYPE, !if(!eq(TYPE, MxType16), MxMOVEM_W, MxMOVEM_L),
325                   !cast<MxOpBundle>("MxOp"#TYPE.Size#"AddrMode_"#AM).Op,
326                   !cast<MxEncMemOp>("MxMoveSrcOpEnc_"#AM)>;
327} // foreach AM
328
329// Pseudo versions. These a required by virtual register spill/restore since
330// the mask requires real register to encode. These instruction will be expanded
331// into real MOVEM after RA finishes.
332let mayStore = 1 in
333class MxMOVEM_MR_Pseudo<MxType TYPE, MxOperand MEMOp>
334    : MxPseudo<(outs), (ins MEMOp:$dst, TYPE.ROp:$reg)>;
335let mayLoad = 1 in
336class MxMOVEM_RM_Pseudo<MxType TYPE, MxOperand MEMOp>
337    : MxPseudo<(outs TYPE.ROp:$dst), (ins MEMOp:$src)>;
338
339// Mem <- Reg
340def MOVM8jm_P  : MxMOVEM_MR_Pseudo<MxType8d,  MxType8.JOp>;
341def MOVM16jm_P : MxMOVEM_MR_Pseudo<MxType16r, MxType16.JOp>;
342def MOVM32jm_P : MxMOVEM_MR_Pseudo<MxType32r, MxType32.JOp>;
343
344def MOVM8pm_P  : MxMOVEM_MR_Pseudo<MxType8d,  MxType8.POp>;
345def MOVM16pm_P : MxMOVEM_MR_Pseudo<MxType16r, MxType16.POp>;
346def MOVM32pm_P : MxMOVEM_MR_Pseudo<MxType32r, MxType32.POp>;
347
348// Reg <- Mem
349def MOVM8mj_P  : MxMOVEM_RM_Pseudo<MxType8d,  MxType8.JOp>;
350def MOVM16mj_P : MxMOVEM_RM_Pseudo<MxType16r, MxType16.JOp>;
351def MOVM32mj_P : MxMOVEM_RM_Pseudo<MxType32r, MxType32.JOp>;
352
353def MOVM8mp_P  : MxMOVEM_RM_Pseudo<MxType8d,  MxType8.POp>;
354def MOVM16mp_P : MxMOVEM_RM_Pseudo<MxType16r, MxType16.POp>;
355def MOVM32mp_P : MxMOVEM_RM_Pseudo<MxType32r, MxType32.POp>;
356
357
358//===----------------------------------------------------------------------===//
359// MOVE to/from SR/CCR
360//
361// A special care must be taken working with to/from CCR since it is basically
362// word-size SR register truncated for user mode thus it only supports word-size
363// instructions. Plus the original M68000 does not support moves from CCR. So in
364// order to use CCR effectively one MUST use proper byte-size pseudo instructi-
365// ons that will be resolved sometime after RA pass.
366//===----------------------------------------------------------------------===//
367
368/// Move to CCR
369/// --------------------------------------------------
370///  F  E  D  C  B  A  9  8  7  6 | 5  4  3 | 2  1  0
371/// --------------------------------------------------
372///                               | EFFECTIVE ADDRESS
373///  0  1  0  0  0  1  0  0  1  1 |   MODE  |   REG
374/// --------------------------------------------------
375let Defs = [CCR] in {
376class MxMoveToCCR<MxOperand MEMOp, MxEncMemOp SRC_ENC>
377    : MxInst<(outs CCRC:$dst), (ins MEMOp:$src), "move.w\t$src, $dst", []> {
378  let Inst = (ascend
379    (descend 0b0100010011, SRC_ENC.EA),
380    SRC_ENC.Supplement
381  );
382}
383
384class MxMoveToCCRPseudo<MxOperand MEMOp>
385    : MxPseudo<(outs CCRC:$dst), (ins MEMOp:$src)>;
386} // let Defs = [CCR]
387
388let mayLoad = 1 in
389foreach AM = MxMoveSupportedAMs in {
390  def MOV16c # AM : MxMoveToCCR<!cast<MxOpBundle>("MxOp16AddrMode_"#AM).Op,
391                                !cast<MxEncMemOp>("MxMoveSrcOpEnc_"#AM)>;
392  def MOV8c # AM  : MxMoveToCCRPseudo<!cast<MxOpBundle>("MxOp8AddrMode_"#AM).Op>;
393} // foreach AM
394
395// Only data register is allowed.
396def MOV16cd : MxMoveToCCR<MxOp16AddrMode_d.Op, MxMoveSrcOpEnc_d>;
397def MOV8cd  : MxMoveToCCRPseudo<MxOp8AddrMode_d.Op>;
398
399/// Move from CCR
400/// --------------------------------------------------
401///  F  E  D  C  B  A  9  8  7  6 | 5  4  3 | 2  1  0
402/// --------------------------------------------------
403///                               | EFFECTIVE ADDRESS
404///  0  1  0  0  0  0  1  0  1  1 |   MODE  |   REG
405/// --------------------------------------------------
406let Uses = [CCR] in {
407class MxMoveFromCCR_R
408    : MxInst<(outs MxDRD16:$dst), (ins CCRC:$src), "move.w\t$src, $dst", []>,
409      Requires<[ AtLeastM68010 ]> {
410  let Inst = (descend 0b0100001011, MxEncAddrMode_d<"dst">.EA);
411}
412
413class MxMoveFromCCR_M<MxOperand MEMOp, MxEncMemOp DST_ENC>
414    : MxInst<(outs), (ins MEMOp:$dst, CCRC:$src), "move.w\t$src, $dst", []>,
415      Requires<[ AtLeastM68010 ]> {
416  let Inst = (ascend
417    (descend 0b0100001011, DST_ENC.EA),
418    DST_ENC.Supplement
419  );
420}
421
422class MxMoveFromCCRPseudo<MxOperand MEMOp>
423    : MxPseudo<(outs), (ins MEMOp:$dst, CCRC:$src)>;
424class MxMoveFromCCR_RPseudo<MxOperand MEMOp>
425    : MxPseudo<(outs MEMOp:$dst), (ins CCRC:$src)>;
426} // let Uses = [CCR]
427
428let mayStore = 1 in
429foreach AM = MxMoveSupportedAMs in {
430  def MOV16 # AM # c
431    : MxMoveFromCCR_M<!cast<MxOpBundle>("MxOp16AddrMode_"#AM).Op,
432                      !cast<MxEncMemOp>("MxMoveDstOpEnc_"#AM)>;
433  def MOV8 # AM # c
434    : MxMoveFromCCRPseudo<!cast<MxOpBundle>("MxOp8AddrMode_"#AM).Op>;
435} // foreach AM
436
437// Only data register is allowed.
438def MOV16dc : MxMoveFromCCR_R;
439def MOV8dc  : MxMoveFromCCR_RPseudo<MxOp8AddrMode_d.Op>;
440
441/// Move to SR
442/// --------------------------------------------------
443///  F  E  D  C  B  A  9  8  7  6 | 5  4  3 | 2  1  0
444/// --------------------------------------------------
445///                               | EFFECTIVE ADDRESS
446///  0  1  0  0  0  1  1  0  1  1 |   MODE  |   REG
447/// --------------------------------------------------
448let Defs = [SR] in {
449class MxMoveToSR<MxOperand MEMOp, MxEncMemOp SRC_ENC>
450    : MxInst<(outs SRC:$dst), (ins MEMOp:$src), "move.w\t$src, $dst", []> {
451  let Inst = (ascend
452    (descend 0b0100011011, SRC_ENC.EA),
453    SRC_ENC.Supplement
454  );
455}
456} // let Defs = [SR]
457
458let mayLoad = 1 in
459foreach AM = MxMoveSupportedAMs in {
460  def MOV16s # AM : MxMoveToSR<!cast<MxOpBundle>("MxOp16AddrMode_"#AM).Op,
461                                !cast<MxEncMemOp>("MxMoveSrcOpEnc_"#AM)>;
462} // foreach AM
463
464def MOV16sd : MxMoveToSR<MxOp16AddrMode_d.Op, MxMoveSrcOpEnc_d>;
465
466/// Move from SR
467/// --------------------------------------------------
468///  F  E  D  C  B  A  9  8  7  6 | 5  4  3 | 2  1  0
469/// --------------------------------------------------
470///                               | EFFECTIVE ADDRESS
471///  0  1  0  0  0  0  0  0  1  1 |   MODE  |   REG
472/// --------------------------------------------------
473let Uses = [SR] in {
474class MxMoveFromSR_R
475    : MxInst<(outs MxDRD16:$dst), (ins SRC:$src), "move.w\t$src, $dst", []>,
476      Requires<[ AtLeastM68010 ]> {
477  let Inst = (descend 0b0100000011, MxEncAddrMode_d<"dst">.EA);
478}
479
480class MxMoveFromSR_M<MxOperand MEMOp, MxEncMemOp DST_ENC>
481    : MxInst<(outs), (ins MEMOp:$dst, SRC:$src), "move.w\t$src, $dst", []>,
482      Requires<[ AtLeastM68010 ]> {
483  let Inst = (ascend
484    (descend 0b0100000011, DST_ENC.EA),
485    DST_ENC.Supplement
486  );
487}
488} // let Uses = [SR]
489
490let mayStore = 1 in
491foreach AM = MxMoveSupportedAMs in {
492  def MOV16 # AM # s
493    : MxMoveFromSR_M<!cast<MxOpBundle>("MxOp16AddrMode_"#AM).Op,
494                      !cast<MxEncMemOp>("MxMoveDstOpEnc_"#AM)>;
495} // foreach AM
496
497def MOV16ds : MxMoveFromSR_R;
498
499//===----------------------------------------------------------------------===//
500// LEA
501//===----------------------------------------------------------------------===//
502
503/// ----------------------------------------------------
504///  F  E  D  C | B  A  9 | 8  7  6 | 5  4  3 | 2  1  0
505/// ----------------------------------------------------
506///  0  1  0  0 | DST REG | 1  1  1 |   MODE  |   REG
507/// ----------------------------------------------------
508class MxLEA<MxOpBundle SRC, MxEncMemOp SRC_ENC>
509    : MxInst<(outs MxARD32:$dst), (ins SRC.Op:$src),
510             "lea\t$src, $dst", [(set i32:$dst, SRC.Pat:$src)]> {
511  let Inst = (ascend
512    (descend 0b0100, (operand "$dst", 3), 0b111, SRC_ENC.EA),
513    SRC_ENC.Supplement
514  );
515}
516
517foreach AM = ["p", "f", "b", "q", "k"] in
518def LEA32 # AM : MxLEA<!cast<MxOpBundle>("MxOp32AddrMode_"#AM),
519                       !cast<MxEncMemOp>("MxMoveSrcOpEnc_"#AM)>;
520
521//===----------------------------------------------------------------------===//
522// LINK/UNLK
523//===----------------------------------------------------------------------===//
524
525let Uses = [SP], Defs = [SP] in {
526let mayStore = 1 in {
527
528def LINK16 : MxInst<(outs), (ins MxARD16:$src, Mxi16imm:$disp), "link.w\t$src, $disp", []> {
529  let Inst = (ascend
530    (descend 0b0100111001010, (operand "$src", 3)),
531    (operand "$disp", 16)
532  );
533}
534
535def LINK32 : MxInst<(outs), (ins MxARD16:$src, Mxi32imm:$disp), "link.l\t$src, $disp", []> {
536  let Inst = (ascend
537    (descend 0b0100100000001, (operand "$src", 3)),
538    (slice "$disp", 31, 16),
539    (slice "$disp", 15, 0)
540  );
541}
542
543def UNLK : MxInst<(outs), (ins MxARD32:$src), "unlk\t$src", []> {
544  let Inst = (descend 0b0100111001011, (operand "$src", 3));
545}
546
547} // let mayStore = 1
548} // let Uses = [SP], Defs = [SP]
549
550//===----------------------------------------------------------------------===//
551// Pseudos
552//===----------------------------------------------------------------------===//
553
554/// Pushe/Pop to/from SP for simplicity
555let Uses = [SP], Defs = [SP], hasSideEffects = 0 in {
556
557// SP <- SP - <size>; (SP) <- Dn
558let mayStore = 1 in {
559def PUSH8d  : MxPseudo<(outs), (ins DR8:$reg)>;
560def PUSH16d : MxPseudo<(outs), (ins DR16:$reg)>;
561def PUSH32r : MxPseudo<(outs), (ins XR32:$reg)>;
562} // let mayStore = 1
563
564// Dn <- (SP); SP <- SP + <size>
565let mayLoad = 1 in {
566def POP8d  : MxPseudo<(outs DR8:$reg),  (ins)>;
567def POP16d : MxPseudo<(outs DR16:$reg), (ins)>;
568def POP32r : MxPseudo<(outs XR32:$reg), (ins)>;
569} // let mayLoad = 1
570
571} // let Uses/Defs = [SP], hasSideEffects = 0
572
573
574let Defs = [CCR] in {
575class MxPseudoMove_RR<MxType DST, MxType SRC, list<dag> PAT = []>
576    : MxPseudo<(outs DST.ROp:$dst), (ins SRC.ROp:$src), PAT>;
577
578class MxPseudoMove_RM<MxType DST, MxOperand SRCOpd, list<dag> PAT = []>
579    : MxPseudo<(outs DST.ROp:$dst), (ins SRCOpd:$src), PAT>;
580
581
582// These Pseudos handle loading immediates to registers.
583// They are expanded post-RA into either move or moveq instructions,
584// depending on size, destination register class, and immediate value.
585// This is done with pseudoinstructions in order to not constrain RA to
586// data registers if moveq matches.
587class MxPseudoMove_DI<MxType TYPE>
588    : MxPseudo<(outs TYPE.ROp:$dst), (ins TYPE.IOp:$src),
589               [(set TYPE.ROp:$dst, imm:$src)]>;
590
591// i8 imm -> reg can always be converted to moveq,
592// but we still emit a pseudo for consistency.
593def MOVI8di  : MxPseudoMove_DI<MxType8d>;
594def MOVI16ri : MxPseudoMove_DI<MxType16r>;
595def MOVI32ri : MxPseudoMove_DI<MxType32r>;
596} // let Defs = [CCR]
597
598/// This group of Pseudos is analogues to the real x86 extending moves, but
599/// since M68k does not have those we need to emulate. These instructions
600/// will be expanded right after RA completed because we need to know precisely
601/// what registers are allocated for the operands and if they overlap we just
602/// extend the value if the registers are completely different we need to move
603/// first.
604foreach EXT = ["S", "Z"] in {
605  let hasSideEffects = 0 in {
606
607    def MOV#EXT#Xd16d8  : MxPseudoMove_RR<MxType16d,  MxType8d>;
608    def MOV#EXT#Xd32d8  : MxPseudoMove_RR<MxType32d,  MxType8d>;
609    def MOV#EXT#Xd32d16 : MxPseudoMove_RR<MxType32r, MxType16r>;
610
611    let mayLoad = 1 in {
612
613      def MOV#EXT#Xd16j8   : MxPseudoMove_RM<MxType16d,  MxType8.JOp>;
614      def MOV#EXT#Xd32j8   : MxPseudoMove_RM<MxType32d,  MxType8.JOp>;
615      def MOV#EXT#Xd32j16  : MxPseudoMove_RM<MxType32d, MxType16.JOp>;
616
617      def MOV#EXT#Xd16p8   : MxPseudoMove_RM<MxType16d,  MxType8.POp>;
618      def MOV#EXT#Xd32p8   : MxPseudoMove_RM<MxType32d,  MxType8.POp>;
619      def MOV#EXT#Xd32p16  : MxPseudoMove_RM<MxType32d, MxType16.POp>;
620
621      def MOV#EXT#Xd16f8   : MxPseudoMove_RM<MxType16d,  MxType8.FOp>;
622      def MOV#EXT#Xd32f8   : MxPseudoMove_RM<MxType32d,  MxType8.FOp>;
623      def MOV#EXT#Xd32f16  : MxPseudoMove_RM<MxType32d, MxType16.FOp>;
624
625      def MOV#EXT#Xd16q8   : MxPseudoMove_RM<MxType16d,  MxType8.QOp>;
626      def MOV#EXT#Xd32q8   : MxPseudoMove_RM<MxType32d,  MxType8.QOp>;
627      def MOV#EXT#Xd32q16  : MxPseudoMove_RM<MxType32d,  MxType16.QOp>;
628
629    }
630  }
631}
632
633/// This group of instructions is similar to the group above but DOES NOT do
634/// any value extension, they just load a smaller register into the lower part
635/// of another register if operands' real registers are different or does
636/// nothing if they are the same.
637def MOVXd16d8  : MxPseudoMove_RR<MxType16d,  MxType8d>;
638def MOVXd32d8  : MxPseudoMove_RR<MxType32d,  MxType8d>;
639def MOVXd32d16 : MxPseudoMove_RR<MxType32r, MxType16r>;
640
641//===----------------------------------------------------------------------===//
642// Extend/Truncate Patterns
643//===----------------------------------------------------------------------===//
644
645// i16 <- sext i8
646def: Pat<(i16 (sext i8:$src)),
647          (EXTRACT_SUBREG (MOVSXd32d8 MxDRD8:$src), MxSubRegIndex16Lo)>;
648def: Pat<(MxSExtLoadi16i8 MxCP_ARI:$src),
649          (EXTRACT_SUBREG (MOVSXd32j8 MxARI8:$src), MxSubRegIndex16Lo)>;
650def: Pat<(MxSExtLoadi16i8 MxCP_ARID:$src),
651          (EXTRACT_SUBREG (MOVSXd32p8 MxARID8:$src), MxSubRegIndex16Lo)>;
652def: Pat<(MxSExtLoadi16i8 MxCP_ARII:$src),
653          (EXTRACT_SUBREG (MOVSXd32f8 MxARII8:$src), MxSubRegIndex16Lo)>;
654def: Pat<(MxSExtLoadi16i8 MxCP_PCD:$src), (MOVSXd16q8 MxPCD8:$src)>;
655
656// i32 <- sext i8
657def: Pat<(i32 (sext i8:$src)), (MOVSXd32d8 MxDRD8:$src)>;
658def: Pat<(MxSExtLoadi32i8 MxCP_ARI :$src), (MOVSXd32j8 MxARI8 :$src)>;
659def: Pat<(MxSExtLoadi32i8 MxCP_ARID:$src), (MOVSXd32p8 MxARID8:$src)>;
660def: Pat<(MxSExtLoadi32i8 MxCP_ARII:$src), (MOVSXd32f8 MxARII8:$src)>;
661def: Pat<(MxSExtLoadi32i8 MxCP_PCD:$src),  (MOVSXd32q8 MxPCD8:$src)>;
662
663// i32 <- sext i16
664def: Pat<(i32 (sext i16:$src)), (MOVSXd32d16 MxDRD16:$src)>;
665def: Pat<(MxSExtLoadi32i16 MxCP_ARI :$src), (MOVSXd32j16 MxARI16 :$src)>;
666def: Pat<(MxSExtLoadi32i16 MxCP_ARID:$src), (MOVSXd32p16 MxARID16:$src)>;
667def: Pat<(MxSExtLoadi32i16 MxCP_ARII:$src), (MOVSXd32f16 MxARII16:$src)>;
668def: Pat<(MxSExtLoadi32i16 MxCP_PCD:$src),  (MOVSXd32q16 MxPCD16:$src)>;
669
670// i16 <- zext i8
671def: Pat<(i16 (zext i8:$src)),
672          (EXTRACT_SUBREG (MOVZXd32d8 MxDRD8:$src), MxSubRegIndex16Lo)>;
673def: Pat<(MxZExtLoadi16i8 MxCP_ARI:$src),
674          (EXTRACT_SUBREG (MOVZXd32j8 MxARI8:$src), MxSubRegIndex16Lo)>;
675def: Pat<(MxZExtLoadi16i8 MxCP_ARID:$src),
676          (EXTRACT_SUBREG (MOVZXd32p8 MxARID8:$src), MxSubRegIndex16Lo)>;
677def: Pat<(MxZExtLoadi16i8 MxCP_ARII:$src),
678          (EXTRACT_SUBREG (MOVZXd32f8 MxARII8:$src), MxSubRegIndex16Lo)>;
679def: Pat<(MxZExtLoadi16i8 MxCP_PCD :$src), (MOVZXd16q8 MxPCD8 :$src)>;
680
681// i32 <- zext i8
682def: Pat<(i32 (zext i8:$src)), (MOVZXd32d8 MxDRD8:$src)>;
683def: Pat<(MxZExtLoadi32i8 MxCP_ARI :$src), (MOVZXd32j8 MxARI8 :$src)>;
684def: Pat<(MxZExtLoadi32i8 MxCP_ARID:$src), (MOVZXd32p8 MxARID8:$src)>;
685def: Pat<(MxZExtLoadi32i8 MxCP_ARII:$src), (MOVZXd32f8 MxARII8:$src)>;
686def: Pat<(MxZExtLoadi32i8 MxCP_PCD :$src), (MOVZXd32q8 MxPCD8 :$src)>;
687
688// i32 <- zext i16
689def: Pat<(i32 (zext i16:$src)), (MOVZXd32d16 MxDRD16:$src)>;
690def: Pat<(MxZExtLoadi32i16 MxCP_ARI :$src), (MOVZXd32j16 MxARI16 :$src)>;
691def: Pat<(MxZExtLoadi32i16 MxCP_ARID:$src), (MOVZXd32p16 MxARID16:$src)>;
692def: Pat<(MxZExtLoadi32i16 MxCP_ARII:$src), (MOVZXd32f16 MxARII16:$src)>;
693def: Pat<(MxZExtLoadi32i16 MxCP_PCD :$src), (MOVZXd32q16 MxPCD16 :$src)>;
694
695// i16 <- anyext i8
696def: Pat<(i16 (anyext i8:$src)),
697          (EXTRACT_SUBREG (MOVZXd32d8 MxDRD8:$src), MxSubRegIndex16Lo)>;
698def: Pat<(MxExtLoadi16i8 MxCP_ARI:$src),
699          (EXTRACT_SUBREG (MOVZXd32j8 MxARI8:$src), MxSubRegIndex16Lo)>;
700def: Pat<(MxExtLoadi16i8 MxCP_ARID:$src),
701          (EXTRACT_SUBREG (MOVZXd32p8 MxARID8:$src), MxSubRegIndex16Lo)>;
702def: Pat<(MxExtLoadi16i8 MxCP_ARII:$src),
703          (EXTRACT_SUBREG (MOVZXd32f8 MxARII8:$src), MxSubRegIndex16Lo)>;
704
705// i32 <- anyext i8
706def: Pat<(i32 (anyext i8:$src)), (MOVZXd32d8 MxDRD8:$src)>;
707def: Pat<(MxExtLoadi32i8 MxCP_ARI :$src), (MOVZXd32j8 MxARI8 :$src)>;
708def: Pat<(MxExtLoadi32i8 MxCP_ARID:$src), (MOVZXd32p8 MxARID8:$src)>;
709def: Pat<(MxExtLoadi32i8 MxCP_ARII:$src), (MOVZXd32f8 MxARII8:$src)>;
710
711// i32 <- anyext i16
712def: Pat<(i32 (anyext i16:$src)), (MOVZXd32d16 MxDRD16:$src)>;
713def: Pat<(MxExtLoadi32i16 MxCP_ARI :$src), (MOVZXd32j16 MxARI16 :$src)>;
714def: Pat<(MxExtLoadi32i16 MxCP_ARID:$src), (MOVZXd32p16 MxARID16:$src)>;
715def: Pat<(MxExtLoadi32i16 MxCP_ARII:$src), (MOVZXd32f16 MxARII16:$src)>;
716
717// trunc patterns
718def : Pat<(i16 (trunc i32:$src)),
719          (EXTRACT_SUBREG MxXRD32:$src, MxSubRegIndex16Lo)>;
720def : Pat<(i8  (trunc i32:$src)),
721          (EXTRACT_SUBREG MxXRD32:$src, MxSubRegIndex8Lo)>;
722def : Pat<(i8  (trunc i16:$src)),
723          (EXTRACT_SUBREG MxXRD16:$src, MxSubRegIndex8Lo)>;
724
725//===----------------------------------------------------------------------===//
726// FMOVE
727//===----------------------------------------------------------------------===//
728
729let Defs = [FPS] in
730class MxFMove<string size, dag outs, dag ins, list<dag> pattern,
731              string rounding = "">
732    : MxInst<outs, ins,
733             "f"#rounding#"move."#size#"\t$src, $dst", pattern> {
734  // Only FMOVE uses FPC
735  let Uses = !if(!eq(rounding, ""), [FPC], []);
736
737  // FSMOVE and FDMOVE are only available after M68040
738  let Predicates = [!if(!eq(rounding, ""), AtLeastM68881, AtLeastM68040)];
739}
740
741// FPDR <- FPDR
742class MxFMove_FF<string rounding, int size,
743                 MxOpBundle Opnd = !cast<MxOpBundle>("MxOp"#size#"AddrMode_fpr")>
744    : MxFMove<"x", (outs Opnd.Op:$dst), (ins Opnd.Op:$src),
745              [(null_frag)], rounding> {
746  let Inst = (ascend
747    (descend 0b1111,
748      /*COPROCESSOR ID*/0b001,
749      0b000,
750      /*MODE + REGISTER*/0b000000
751    ),
752    (descend 0b0, /* R/M */0b0, 0b0,
753      /*SOURCE SPECIFIER*/
754      (operand "$src", 3),
755      /*DESTINATION*/
756      (operand "$dst", 3),
757      /*OPMODE*/
758      !cond(!eq(rounding, "s"): 0b1000000,
759            !eq(rounding, "d"): 0b1000100,
760            true: 0b0000000)
761    )
762  );
763}
764
765foreach rounding = ["", "s", "d"] in {
766  def F # !toupper(rounding) # MOV80fp_fp : MxFMove_FF<rounding, 80>;
767
768  // We don't have `fmove.s` or `fmove.d` because values will be converted to
769  // f80 upon storing into the register, but FMOV32/64fp_fp are still needed
770  // to make codegen easier.
771  let isCodeGenOnly = true in
772  foreach size = [32, 64] in
773    def F # !toupper(rounding) # MOV # size # fp_fp : MxFMove_FF<rounding, size>;
774}
775// Direction
776defvar MxFMove_FP_EA = false;
777defvar MxFMove_EA_FP = true;
778
779// Encoding scheme for FPSYS <-> R/M
780class MxEncFSysMove<bit dir, MxEncMemOp EAEnc, string fsys_reg> {
781  dag Value = (ascend
782    (descend 0b1111,
783      /*COPROCESSOR ID*/0b001,
784      0b000,
785      /*MODE + REGISTER*/
786      EAEnc.EA
787    ),
788    (descend 0b10, /*dir*/ dir,
789      /*REGISTER SELECT*/
790      (operand "$"#fsys_reg, 3, (encoder "encodeFPSYSSelect")),
791      0b0000000000
792    )
793  );
794}
795
796// FPSYS <-> R
797class MxFMove_FSYS_R<string src_reg,
798                     MxOpBundle SrcOpnd = !cast<MxOpBundle>("MxOp32AddrMode_"#src_reg),
799                     MxOpBundle DstOpnd = !cond(!eq(src_reg, "d"): MxOp32AddrMode_fpcs,
800                                                !eq(src_reg, "a"): MxOp32AddrMode_fpi),
801                     MxEncMemOp SrcEnc = !cast<MxEncMemOp>("MxMoveSrcOpEnc_"#src_reg)>
802    : MxFMove<"l", (outs DstOpnd.Op:$dst), (ins SrcOpnd.Op:$src),
803              [(null_frag)]> {
804  let Inst = MxEncFSysMove<MxFMove_FP_EA, SrcEnc, "dst">.Value;
805}
806
807class MxFMove_R_FSYS<string dst_reg,
808                     MxOpBundle SrcOpnd = !cond(!eq(dst_reg, "d"): MxOp32AddrMode_fpcs,
809                                                !eq(dst_reg, "a"): MxOp32AddrMode_fpi),
810                     MxOpBundle DstOpnd = !cast<MxOpBundle>("MxOp32AddrMode_"#dst_reg),
811                     MxEncMemOp DstEnc = !cast<MxEncMemOp>("MxMoveDstOpEnc_"#dst_reg)>
812    : MxFMove<"l", (outs DstOpnd.Op:$dst), (ins SrcOpnd.Op:$src),
813              [(null_frag)]> {
814  let Inst = MxEncFSysMove<MxFMove_EA_FP, DstEnc, "src">.Value;
815}
816
817def FMOVE32fpcs_d : MxFMove_FSYS_R<"d">;
818def FMOVE32d_fpcs : MxFMove_R_FSYS<"d">;
819def FMOVE32fpi_a  : MxFMove_FSYS_R<"a">;
820def FMOVE32a_fpi  : MxFMove_R_FSYS<"a">;
821