xref: /freebsd/contrib/llvm-project/llvm/lib/Target/M68k/M68kInstrData.td (revision 7fdf597e96a02165cfe22ff357b857d5fa15ed8a)
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/// --------------------------------------------------
369///  F  E  D  C  B  A  9  8  7  6 | 5  4  3 | 2  1  0
370/// --------------------------------------------------
371///                               | EFFECTIVE ADDRESS
372///  0  1  0  0  0  1  0  0  1  1 |   MODE  |   REG
373/// --------------------------------------------------
374let Defs = [CCR] in
375class MxMoveToCCR<MxOperand MEMOp, MxEncMemOp SRC_ENC>
376    : MxInst<(outs CCRC:$dst), (ins MEMOp:$src), "move.w\t$src, $dst", []> {
377  let Inst = (ascend
378    (descend 0b0100010011, SRC_ENC.EA),
379    SRC_ENC.Supplement
380  );
381}
382
383class MxMoveToCCRPseudo<MxOperand MEMOp>
384    : MxPseudo<(outs CCRC:$dst), (ins MEMOp:$src)>;
385
386let mayLoad = 1 in
387foreach AM = MxMoveSupportedAMs in {
388  def MOV16c # AM : MxMoveToCCR<!cast<MxOpBundle>("MxOp16AddrMode_"#AM).Op,
389                                !cast<MxEncMemOp>("MxMoveSrcOpEnc_"#AM)>;
390  def MOV8c # AM  : MxMoveToCCRPseudo<!cast<MxOpBundle>("MxOp8AddrMode_"#AM).Op>;
391} // foreach AM
392
393// Only data register is allowed.
394def MOV16cd : MxMoveToCCR<MxOp16AddrMode_d.Op, MxMoveSrcOpEnc_d>;
395def MOV8cd  : MxMoveToCCRPseudo<MxOp8AddrMode_d.Op>;
396
397/// Move from CCR
398/// --------------------------------------------------
399///  F  E  D  C  B  A  9  8  7  6 | 5  4  3 | 2  1  0
400/// --------------------------------------------------
401///                               | EFFECTIVE ADDRESS
402///  0  1  0  0  0  0  1  0  1  1 |   MODE  |   REG
403/// --------------------------------------------------
404let Uses = [CCR] in {
405class MxMoveFromCCR_R
406    : MxInst<(outs MxDRD16:$dst), (ins CCRC:$src), "move.w\t$src, $dst", []>,
407      Requires<[ AtLeastM68010 ]> {
408  let Inst = (descend 0b0100001011, MxEncAddrMode_d<"dst">.EA);
409}
410
411class MxMoveFromCCR_M<MxOperand MEMOp, MxEncMemOp DST_ENC>
412    : MxInst<(outs), (ins MEMOp:$dst, CCRC:$src), "move.w\t$src, $dst", []>,
413      Requires<[ AtLeastM68010 ]> {
414  let Inst = (ascend
415    (descend 0b0100001011, DST_ENC.EA),
416    DST_ENC.Supplement
417  );
418}
419
420class MxMoveFromCCRPseudo<MxOperand MEMOp>
421    : MxPseudo<(outs), (ins MEMOp:$dst, CCRC:$src)>;
422} // let Uses = [CCR]
423
424let mayStore = 1 in
425foreach AM = MxMoveSupportedAMs in {
426  def MOV16 # AM # c
427    : MxMoveFromCCR_M<!cast<MxOpBundle>("MxOp16AddrMode_"#AM).Op,
428                      !cast<MxEncMemOp>("MxMoveDstOpEnc_"#AM)>;
429  def MOV8 # AM # c
430    : MxMoveFromCCRPseudo<!cast<MxOpBundle>("MxOp8AddrMode_"#AM).Op>;
431} // foreach AM
432
433// Only data register is allowed.
434def MOV16dc : MxMoveFromCCR_R;
435def MOV8dc  : MxMoveFromCCRPseudo<MxOp8AddrMode_d.Op>;
436
437//===----------------------------------------------------------------------===//
438// LEA
439//===----------------------------------------------------------------------===//
440
441/// ----------------------------------------------------
442///  F  E  D  C | B  A  9 | 8  7  6 | 5  4  3 | 2  1  0
443/// ----------------------------------------------------
444///  0  1  0  0 | DST REG | 1  1  1 |   MODE  |   REG
445/// ----------------------------------------------------
446class MxLEA<MxOpBundle SRC, MxEncMemOp SRC_ENC>
447    : MxInst<(outs MxARD32:$dst), (ins SRC.Op:$src),
448             "lea\t$src, $dst", [(set i32:$dst, SRC.Pat:$src)]> {
449  let Inst = (ascend
450    (descend 0b0100, (operand "$dst", 3), 0b111, SRC_ENC.EA),
451    SRC_ENC.Supplement
452  );
453}
454
455foreach AM = ["p", "f", "b", "q", "k"] in
456def LEA32 # AM : MxLEA<!cast<MxOpBundle>("MxOp32AddrMode_"#AM),
457                       !cast<MxEncMemOp>("MxMoveSrcOpEnc_"#AM)>;
458
459//===----------------------------------------------------------------------===//
460// LINK/UNLK
461//===----------------------------------------------------------------------===//
462
463let Uses = [SP], Defs = [SP] in {
464let mayStore = 1 in {
465
466def LINK16 : MxInst<(outs), (ins MxARD16:$src, Mxi16imm:$disp), "link.w\t$src, $disp", []> {
467  let Inst = (ascend
468    (descend 0b0100111001010, (operand "$src", 3)),
469    (operand "$disp", 16)
470  );
471}
472
473def LINK32 : MxInst<(outs), (ins MxARD16:$src, Mxi32imm:$disp), "link.l\t$src, $disp", []> {
474  let Inst = (ascend
475    (descend 0b0100100000001, (operand "$src", 3)),
476    (slice "$disp", 31, 16),
477    (slice "$disp", 15, 0)
478  );
479}
480
481def UNLK : MxInst<(outs), (ins MxARD32:$src), "unlk\t$src", []> {
482  let Inst = (descend 0b0100111001011, (operand "$src", 3));
483}
484
485} // let mayStore = 1
486} // let Uses = [SP], Defs = [SP]
487
488//===----------------------------------------------------------------------===//
489// Pseudos
490//===----------------------------------------------------------------------===//
491
492/// Pushe/Pop to/from SP for simplicity
493let Uses = [SP], Defs = [SP], hasSideEffects = 0 in {
494
495// SP <- SP - <size>; (SP) <- Dn
496let mayStore = 1 in {
497def PUSH8d  : MxPseudo<(outs), (ins DR8:$reg)>;
498def PUSH16d : MxPseudo<(outs), (ins DR16:$reg)>;
499def PUSH32r : MxPseudo<(outs), (ins XR32:$reg)>;
500} // let mayStore = 1
501
502// Dn <- (SP); SP <- SP + <size>
503let mayLoad = 1 in {
504def POP8d  : MxPseudo<(outs DR8:$reg),  (ins)>;
505def POP16d : MxPseudo<(outs DR16:$reg), (ins)>;
506def POP32r : MxPseudo<(outs XR32:$reg), (ins)>;
507} // let mayLoad = 1
508
509} // let Uses/Defs = [SP], hasSideEffects = 0
510
511
512let Defs = [CCR] in {
513class MxPseudoMove_RR<MxType DST, MxType SRC, list<dag> PAT = []>
514    : MxPseudo<(outs DST.ROp:$dst), (ins SRC.ROp:$src), PAT>;
515
516class MxPseudoMove_RM<MxType DST, MxOperand SRCOpd, list<dag> PAT = []>
517    : MxPseudo<(outs DST.ROp:$dst), (ins SRCOpd:$src), PAT>;
518
519
520// These Pseudos handle loading immediates to registers.
521// They are expanded post-RA into either move or moveq instructions,
522// depending on size, destination register class, and immediate value.
523// This is done with pseudoinstructions in order to not constrain RA to
524// data registers if moveq matches.
525class MxPseudoMove_DI<MxType TYPE>
526    : MxPseudo<(outs TYPE.ROp:$dst), (ins TYPE.IOp:$src),
527               [(set TYPE.ROp:$dst, imm:$src)]>;
528
529// i8 imm -> reg can always be converted to moveq,
530// but we still emit a pseudo for consistency.
531def MOVI8di  : MxPseudoMove_DI<MxType8d>;
532def MOVI16ri : MxPseudoMove_DI<MxType16r>;
533def MOVI32ri : MxPseudoMove_DI<MxType32r>;
534} // let Defs = [CCR]
535
536/// This group of Pseudos is analogues to the real x86 extending moves, but
537/// since M68k does not have those we need to emulate. These instructions
538/// will be expanded right after RA completed because we need to know precisely
539/// what registers are allocated for the operands and if they overlap we just
540/// extend the value if the registers are completely different we need to move
541/// first.
542foreach EXT = ["S", "Z"] in {
543  let hasSideEffects = 0 in {
544
545    def MOV#EXT#Xd16d8  : MxPseudoMove_RR<MxType16d,  MxType8d>;
546    def MOV#EXT#Xd32d8  : MxPseudoMove_RR<MxType32d,  MxType8d>;
547    def MOV#EXT#Xd32d16 : MxPseudoMove_RR<MxType32r, MxType16r>;
548
549    let mayLoad = 1 in {
550
551      def MOV#EXT#Xd16j8   : MxPseudoMove_RM<MxType16d,  MxType8.JOp>;
552      def MOV#EXT#Xd32j8   : MxPseudoMove_RM<MxType32d,  MxType8.JOp>;
553      def MOV#EXT#Xd32j16  : MxPseudoMove_RM<MxType32d, MxType16.JOp>;
554
555      def MOV#EXT#Xd16p8   : MxPseudoMove_RM<MxType16d,  MxType8.POp>;
556      def MOV#EXT#Xd32p8   : MxPseudoMove_RM<MxType32d,  MxType8.POp>;
557      def MOV#EXT#Xd32p16  : MxPseudoMove_RM<MxType32d, MxType16.POp>;
558
559      def MOV#EXT#Xd16f8   : MxPseudoMove_RM<MxType16d,  MxType8.FOp>;
560      def MOV#EXT#Xd32f8   : MxPseudoMove_RM<MxType32d,  MxType8.FOp>;
561      def MOV#EXT#Xd32f16  : MxPseudoMove_RM<MxType32d, MxType16.FOp>;
562
563      def MOV#EXT#Xd16q8   : MxPseudoMove_RM<MxType16d,  MxType8.QOp>;
564      def MOV#EXT#Xd32q8   : MxPseudoMove_RM<MxType32d,  MxType8.QOp>;
565      def MOV#EXT#Xd32q16  : MxPseudoMove_RM<MxType32d,  MxType16.QOp>;
566
567    }
568  }
569}
570
571/// This group of instructions is similar to the group above but DOES NOT do
572/// any value extension, they just load a smaller register into the lower part
573/// of another register if operands' real registers are different or does
574/// nothing if they are the same.
575def MOVXd16d8  : MxPseudoMove_RR<MxType16d,  MxType8d>;
576def MOVXd32d8  : MxPseudoMove_RR<MxType32d,  MxType8d>;
577def MOVXd32d16 : MxPseudoMove_RR<MxType32r, MxType16r>;
578
579//===----------------------------------------------------------------------===//
580// Extend/Truncate Patterns
581//===----------------------------------------------------------------------===//
582
583// i16 <- sext i8
584def: Pat<(i16 (sext i8:$src)),
585          (EXTRACT_SUBREG (MOVSXd32d8 MxDRD8:$src), MxSubRegIndex16Lo)>;
586def: Pat<(MxSExtLoadi16i8 MxCP_ARI:$src),
587          (EXTRACT_SUBREG (MOVSXd32j8 MxARI8:$src), MxSubRegIndex16Lo)>;
588def: Pat<(MxSExtLoadi16i8 MxCP_ARID:$src),
589          (EXTRACT_SUBREG (MOVSXd32p8 MxARID8:$src), MxSubRegIndex16Lo)>;
590def: Pat<(MxSExtLoadi16i8 MxCP_ARII:$src),
591          (EXTRACT_SUBREG (MOVSXd32f8 MxARII8:$src), MxSubRegIndex16Lo)>;
592def: Pat<(MxSExtLoadi16i8 MxCP_PCD:$src), (MOVSXd16q8 MxPCD8:$src)>;
593
594// i32 <- sext i8
595def: Pat<(i32 (sext i8:$src)), (MOVSXd32d8 MxDRD8:$src)>;
596def: Pat<(MxSExtLoadi32i8 MxCP_ARI :$src), (MOVSXd32j8 MxARI8 :$src)>;
597def: Pat<(MxSExtLoadi32i8 MxCP_ARID:$src), (MOVSXd32p8 MxARID8:$src)>;
598def: Pat<(MxSExtLoadi32i8 MxCP_ARII:$src), (MOVSXd32f8 MxARII8:$src)>;
599def: Pat<(MxSExtLoadi32i8 MxCP_PCD:$src),  (MOVSXd32q8 MxPCD8:$src)>;
600
601// i32 <- sext i16
602def: Pat<(i32 (sext i16:$src)), (MOVSXd32d16 MxDRD16:$src)>;
603def: Pat<(MxSExtLoadi32i16 MxCP_ARI :$src), (MOVSXd32j16 MxARI16 :$src)>;
604def: Pat<(MxSExtLoadi32i16 MxCP_ARID:$src), (MOVSXd32p16 MxARID16:$src)>;
605def: Pat<(MxSExtLoadi32i16 MxCP_ARII:$src), (MOVSXd32f16 MxARII16:$src)>;
606def: Pat<(MxSExtLoadi32i16 MxCP_PCD:$src),  (MOVSXd32q16 MxPCD16:$src)>;
607
608// i16 <- zext i8
609def: Pat<(i16 (zext i8:$src)),
610          (EXTRACT_SUBREG (MOVZXd32d8 MxDRD8:$src), MxSubRegIndex16Lo)>;
611def: Pat<(MxZExtLoadi16i8 MxCP_ARI:$src),
612          (EXTRACT_SUBREG (MOVZXd32j8 MxARI8:$src), MxSubRegIndex16Lo)>;
613def: Pat<(MxZExtLoadi16i8 MxCP_ARID:$src),
614          (EXTRACT_SUBREG (MOVZXd32p8 MxARID8:$src), MxSubRegIndex16Lo)>;
615def: Pat<(MxZExtLoadi16i8 MxCP_ARII:$src),
616          (EXTRACT_SUBREG (MOVZXd32f8 MxARII8:$src), MxSubRegIndex16Lo)>;
617def: Pat<(MxZExtLoadi16i8 MxCP_PCD :$src), (MOVZXd16q8 MxPCD8 :$src)>;
618
619// i32 <- zext i8
620def: Pat<(i32 (zext i8:$src)), (MOVZXd32d8 MxDRD8:$src)>;
621def: Pat<(MxZExtLoadi32i8 MxCP_ARI :$src), (MOVZXd32j8 MxARI8 :$src)>;
622def: Pat<(MxZExtLoadi32i8 MxCP_ARID:$src), (MOVZXd32p8 MxARID8:$src)>;
623def: Pat<(MxZExtLoadi32i8 MxCP_ARII:$src), (MOVZXd32f8 MxARII8:$src)>;
624def: Pat<(MxZExtLoadi32i8 MxCP_PCD :$src), (MOVZXd32q8 MxPCD8 :$src)>;
625
626// i32 <- zext i16
627def: Pat<(i32 (zext i16:$src)), (MOVZXd32d16 MxDRD16:$src)>;
628def: Pat<(MxZExtLoadi32i16 MxCP_ARI :$src), (MOVZXd32j16 MxARI16 :$src)>;
629def: Pat<(MxZExtLoadi32i16 MxCP_ARID:$src), (MOVZXd32p16 MxARID16:$src)>;
630def: Pat<(MxZExtLoadi32i16 MxCP_ARII:$src), (MOVZXd32f16 MxARII16:$src)>;
631def: Pat<(MxZExtLoadi32i16 MxCP_PCD :$src), (MOVZXd32q16 MxPCD16 :$src)>;
632
633// i16 <- anyext i8
634def: Pat<(i16 (anyext i8:$src)),
635          (EXTRACT_SUBREG (MOVZXd32d8 MxDRD8:$src), MxSubRegIndex16Lo)>;
636def: Pat<(MxExtLoadi16i8 MxCP_ARI:$src),
637          (EXTRACT_SUBREG (MOVZXd32j8 MxARI8:$src), MxSubRegIndex16Lo)>;
638def: Pat<(MxExtLoadi16i8 MxCP_ARID:$src),
639          (EXTRACT_SUBREG (MOVZXd32p8 MxARID8:$src), MxSubRegIndex16Lo)>;
640def: Pat<(MxExtLoadi16i8 MxCP_ARII:$src),
641          (EXTRACT_SUBREG (MOVZXd32f8 MxARII8:$src), MxSubRegIndex16Lo)>;
642
643// i32 <- anyext i8
644def: Pat<(i32 (anyext i8:$src)), (MOVZXd32d8 MxDRD8:$src)>;
645def: Pat<(MxExtLoadi32i8 MxCP_ARI :$src), (MOVZXd32j8 MxARI8 :$src)>;
646def: Pat<(MxExtLoadi32i8 MxCP_ARID:$src), (MOVZXd32p8 MxARID8:$src)>;
647def: Pat<(MxExtLoadi32i8 MxCP_ARII:$src), (MOVZXd32f8 MxARII8:$src)>;
648
649// i32 <- anyext i16
650def: Pat<(i32 (anyext i16:$src)), (MOVZXd32d16 MxDRD16:$src)>;
651def: Pat<(MxExtLoadi32i16 MxCP_ARI :$src), (MOVZXd32j16 MxARI16 :$src)>;
652def: Pat<(MxExtLoadi32i16 MxCP_ARID:$src), (MOVZXd32p16 MxARID16:$src)>;
653def: Pat<(MxExtLoadi32i16 MxCP_ARII:$src), (MOVZXd32f16 MxARII16:$src)>;
654
655// trunc patterns
656def : Pat<(i16 (trunc i32:$src)),
657          (EXTRACT_SUBREG MxXRD32:$src, MxSubRegIndex16Lo)>;
658def : Pat<(i8  (trunc i32:$src)),
659          (EXTRACT_SUBREG MxXRD32:$src, MxSubRegIndex8Lo)>;
660def : Pat<(i8  (trunc i16:$src)),
661          (EXTRACT_SUBREG MxXRD16:$src, MxSubRegIndex8Lo)>;
662
663//===----------------------------------------------------------------------===//
664// FMOVE
665//===----------------------------------------------------------------------===//
666
667let Defs = [FPS] in
668class MxFMove<string size, dag outs, dag ins, list<dag> pattern,
669              string rounding = "">
670    : MxInst<outs, ins,
671             "f"#rounding#"move."#size#"\t$src, $dst", pattern> {
672  // Only FMOVE uses FPC
673  let Uses = !if(!eq(rounding, ""), [FPC], []);
674
675  // FSMOVE and FDMOVE are only available after M68040
676  let Predicates = [!if(!eq(rounding, ""), AtLeastM68881, AtLeastM68040)];
677}
678
679// FPDR <- FPDR
680class MxFMove_FF<string rounding, int size,
681                 MxOpBundle Opnd = !cast<MxOpBundle>("MxOp"#size#"AddrMode_fpr")>
682    : MxFMove<"x", (outs Opnd.Op:$dst), (ins Opnd.Op:$src),
683              [(null_frag)], rounding> {
684  let Inst = (ascend
685    (descend 0b1111,
686      /*COPROCESSOR ID*/0b001,
687      0b000,
688      /*MODE + REGISTER*/0b000000
689    ),
690    (descend 0b0, /* R/M */0b0, 0b0,
691      /*SOURCE SPECIFIER*/
692      (operand "$src", 3),
693      /*DESTINATION*/
694      (operand "$dst", 3),
695      /*OPMODE*/
696      !cond(!eq(rounding, "s"): 0b1000000,
697            !eq(rounding, "d"): 0b1000100,
698            true: 0b0000000)
699    )
700  );
701}
702
703foreach rounding = ["", "s", "d"] in {
704  def F # !toupper(rounding) # MOV80fp_fp : MxFMove_FF<rounding, 80>;
705
706  // We don't have `fmove.s` or `fmove.d` because values will be converted to
707  // f80 upon storing into the register, but FMOV32/64fp_fp are still needed
708  // to make codegen easier.
709  let isCodeGenOnly = true in
710  foreach size = [32, 64] in
711    def F # !toupper(rounding) # MOV # size # fp_fp : MxFMove_FF<rounding, size>;
712}
713// Direction
714defvar MxFMove_FP_EA = false;
715defvar MxFMove_EA_FP = true;
716
717// Encoding scheme for FPSYS <-> R/M
718class MxEncFSysMove<bit dir, MxEncMemOp EAEnc, string fsys_reg> {
719  dag Value = (ascend
720    (descend 0b1111,
721      /*COPROCESSOR ID*/0b001,
722      0b000,
723      /*MODE + REGISTER*/
724      EAEnc.EA
725    ),
726    (descend 0b10, /*dir*/ dir,
727      /*REGISTER SELECT*/
728      (operand "$"#fsys_reg, 3, (encoder "encodeFPSYSSelect")),
729      0b0000000000
730    )
731  );
732}
733
734// FPSYS <-> R
735class MxFMove_FSYS_R<string src_reg,
736                     MxOpBundle SrcOpnd = !cast<MxOpBundle>("MxOp32AddrMode_"#src_reg),
737                     MxOpBundle DstOpnd = !cond(!eq(src_reg, "d"): MxOp32AddrMode_fpcs,
738                                                !eq(src_reg, "a"): MxOp32AddrMode_fpi),
739                     MxEncMemOp SrcEnc = !cast<MxEncMemOp>("MxMoveSrcOpEnc_"#src_reg)>
740    : MxFMove<"l", (outs DstOpnd.Op:$dst), (ins SrcOpnd.Op:$src),
741              [(null_frag)]> {
742  let Inst = MxEncFSysMove<MxFMove_FP_EA, SrcEnc, "dst">.Value;
743}
744
745class MxFMove_R_FSYS<string dst_reg,
746                     MxOpBundle SrcOpnd = !cond(!eq(dst_reg, "d"): MxOp32AddrMode_fpcs,
747                                                !eq(dst_reg, "a"): MxOp32AddrMode_fpi),
748                     MxOpBundle DstOpnd = !cast<MxOpBundle>("MxOp32AddrMode_"#dst_reg),
749                     MxEncMemOp DstEnc = !cast<MxEncMemOp>("MxMoveDstOpEnc_"#dst_reg)>
750    : MxFMove<"l", (outs DstOpnd.Op:$dst), (ins SrcOpnd.Op:$src),
751              [(null_frag)]> {
752  let Inst = MxEncFSysMove<MxFMove_EA_FP, DstEnc, "src">.Value;
753}
754
755def FMOVE32fpcs_d : MxFMove_FSYS_R<"d">;
756def FMOVE32d_fpcs : MxFMove_R_FSYS<"d">;
757def FMOVE32fpi_a  : MxFMove_FSYS_R<"a">;
758def FMOVE32a_fpi  : MxFMove_R_FSYS<"a">;
759