xref: /freebsd/contrib/llvm-project/llvm/lib/Target/M68k/M68kInstrData.td (revision 1db9f3b21e39176dd5b67cf8ac378633b172463e)
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///     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
168class MxMove_RI<MxType TYPE, string DST_REG, MxMoveEncoding ENC,
169                MxImmOpBundle SRC = !cast<MxImmOpBundle>("MxOp"#TYPE.Size#"AddrMode_i"),
170                MxOpBundle DST = !cast<MxOpBundle>("MxOp"#TYPE.Size#"AddrMode_"#DST_REG)>
171    : MxMove<TYPE.Prefix, (outs DST.Op:$dst), (ins SRC.Op:$src),
172              [(set TYPE.VT:$dst, SRC.ImmPat:$src)], ENC>;
173
174foreach REG = ["r", "a", "d"] in {
175  foreach TYPE = !if(!eq(REG, "d"), [MxType8, MxType16, MxType32], [MxType16, MxType32]) in
176  def MOV # TYPE.Size # REG # i # TYPE.Postfix
177      : MxMove_RI<TYPE, REG,
178                  MxMoveEncoding<!cast<MxMoveSize>("MxMoveSize"#TYPE.Size),
179                                 !cast<MxEncMemOp>("MxMoveDstOpEnc_"#REG),
180                                 MxEncAddrMode_i<"src", TYPE.Size>>>;
181} // foreach REG
182
183// R <- M
184let mayLoad = 1 in
185class MxMove_RM<MxType TYPE, string DST_REG, MxOpBundle SRC, MxEncMemOp SRC_ENC,
186                MxMoveSize SIZE_ENC = !cast<MxMoveSize>("MxMoveSize"#TYPE.Size),
187                MxOpBundle DST = !cast<MxOpBundle>("MxOp"#TYPE.Size#"AddrMode_"#DST_REG),
188                MxEncMemOp DST_ENC = !cast<MxEncMemOp>("MxMoveDstOpEnc_"#DST_REG)>
189    : MxMove<TYPE.Prefix, (outs DST.Op:$dst), (ins SRC.Op:$src),
190             [(set TYPE.VT:$dst, (TYPE.Load SRC.Pat:$src))],
191             MxMoveEncoding<SIZE_ENC, DST_ENC, SRC_ENC>>;
192
193foreach REG = ["r", "a", "d"] in
194foreach AM = MxMoveSupportedAMs in {
195  foreach TYPE = !if(!eq(REG, "d"), [MxType8, MxType16, MxType32], [MxType16, MxType32]) in
196  def MOV # TYPE.Size # REG # AM # TYPE.Postfix
197      : MxMove_RM<TYPE, REG, !cast<MxOpBundle>("MxOp"#TYPE.Size#"AddrMode_"#AM),
198                  !cast<MxEncMemOp>("MxMoveSrcOpEnc_"#AM)>;
199} // foreach AM
200
201// Tail call version
202let Pattern = [(null_frag)] in {
203  foreach REG = ["r", "a"] in
204  foreach AM = MxMoveSupportedAMs in {
205    foreach TYPE = [MxType16, MxType32] in
206    def MOV # TYPE.Size # REG # AM # _TC
207        : MxMove_RM<TYPE, REG, !cast<MxOpBundle>("MxOp"#TYPE.Size#"AddrMode_"#AM),
208                    !cast<MxEncMemOp>("MxMoveSrcOpEnc_"#AM)> {
209      let isCodeGenOnly = true;
210    }
211  } // foreach AM
212} // let Pattern
213
214let mayLoad = 1, mayStore = 1 in
215class MxMove_MM<MxType TYPE, MxOpBundle DST, MxOpBundle SRC,
216                MxEncMemOp DST_ENC, MxEncMemOp SRC_ENC>
217    : MxMove<TYPE.Prefix, (outs), (ins DST.Op:$dst, SRC.Op:$src),
218             [(store (TYPE.Load SRC.Pat:$src), DST.Pat:$dst)],
219             MxMoveEncoding<!cast<MxMoveSize>("MxMoveSize"#TYPE.Size),
220                            DST_ENC, SRC_ENC>>;
221
222foreach DST_AM = MxMoveSupportedAMs in
223foreach SRC_AM = MxMoveSupportedAMs in {
224  foreach TYPE = [MxType8, MxType16, MxType32] in
225  def MOV # TYPE.Size # DST_AM # SRC_AM # TYPE.Postfix
226      : MxMove_MM<TYPE, !cast<MxOpBundle>("MxOp"#TYPE.Size#"AddrMode_"#DST_AM),
227                  !cast<MxOpBundle>("MxOp"#TYPE.Size#"AddrMode_"#SRC_AM),
228                  !cast<MxEncMemOp>("MxMoveDstOpEnc_"#DST_AM),
229                  !cast<MxEncMemOp>("MxMoveSrcOpEnc_"#SRC_AM)>;
230} // foreach SRC_AM
231
232// Store ABS(basically pointer) as Immdiate to Mem
233def : Pat<(store   MxType32.BPat :$src, MxType32.PPat :$dst),
234          (MOV32pi MxType32.POp  :$dst, MxType32.IOp  :$src)>;
235
236def : Pat<(store   MxType32.BPat :$src, MxType32.FPat :$dst),
237          (MOV32fi MxType32.FOp  :$dst, MxType32.IOp  :$src)>;
238
239def : Pat<(store   MxType32.BPat :$src, MxType32.BPat :$dst),
240          (MOV32bi MxType32.BOp  :$dst, MxType32.IOp  :$src)>;
241
242def : Pat<(store   MxType32.BPat :$src, MxType32.JPat :$dst),
243          (MOV32ji MxType32.JOp  :$dst, MxType32.IOp  :$src)>;
244
245//===----------------------------------------------------------------------===//
246// MOVEM
247//
248// The mask is already pre-processed by the save/restore spill hook
249//===----------------------------------------------------------------------===//
250
251// Direction
252defvar MxMOVEM_MR = false;
253defvar MxMOVEM_RM = true;
254
255// Size
256defvar MxMOVEM_W = false;
257defvar MxMOVEM_L = true;
258
259/// ---------------+-------------+-------------+---------
260///  F  E  D  C  B | A | 9  8  7 | 6 | 5  4  3 | 2  1  0
261/// ---------------+---+---------+---+---------+---------
262///  0  1  0  0  1 | D | 0  0  1 | S |   MODE  |   REG
263/// ---------------+---+---------+---+---------+---------
264///                  REGISTER LIST MASK
265/// -----------------------------------------------------
266/// D - direction(RM,MR)
267/// S - size(W,L)
268class MxMOVEMEncoding<MxEncMemOp opnd_enc, bit size, bit direction,
269                      string mask_op_name> {
270  dag Value = (ascend
271    (descend 0b01001, direction, 0b001, size, opnd_enc.EA),
272    // Mask
273    (operand "$"#mask_op_name, 16),
274    opnd_enc.Supplement
275  );
276}
277
278let mayStore = 1 in
279class MxMOVEM_MR<MxType TYPE, bit SIZE_ENC,
280                 MxOperand MEMOp, MxEncMemOp MEM_ENC>
281    : MxInst<(outs), (ins MEMOp:$dst, MxMoveMask:$mask),
282             "movem."#TYPE.Prefix#"\t$mask, $dst", []> {
283  let Inst = MxMOVEMEncoding<MEM_ENC, SIZE_ENC, MxMOVEM_MR, "mask">.Value;
284}
285
286foreach AM = MxMoveSupportedAMs in {
287  foreach TYPE = [MxType16, MxType32] in
288  def MOVM # TYPE.Size # AM # m # TYPE.Postfix
289      : MxMOVEM_MR<TYPE, !if(!eq(TYPE, MxType16), MxMOVEM_W, MxMOVEM_L),
290                   !cast<MxOpBundle>("MxOp"#TYPE.Size#"AddrMode_"#AM).Op,
291                   !cast<MxEncMemOp>("MxMoveDstOpEnc_"#AM)>;
292} // foreach AM
293
294let mayLoad = 1 in
295class MxMOVEM_RM<MxType TYPE, bit SIZE_ENC,
296                 MxOperand MEMOp, MxEncMemOp MEM_ENC>
297    : MxInst<(outs), (ins MxMoveMask:$mask, MEMOp:$src),
298             "movem."#TYPE.Prefix#"\t$src, $mask", []> {
299  let Inst = MxMOVEMEncoding<MEM_ENC, SIZE_ENC, MxMOVEM_RM, "mask">.Value;
300}
301
302foreach AM = MxMoveSupportedAMs in {
303  foreach TYPE = [MxType16, MxType32] in
304  def MOVM # TYPE.Size # m # AM # TYPE.Postfix
305      : MxMOVEM_RM<TYPE, !if(!eq(TYPE, MxType16), MxMOVEM_W, MxMOVEM_L),
306                   !cast<MxOpBundle>("MxOp"#TYPE.Size#"AddrMode_"#AM).Op,
307                   !cast<MxEncMemOp>("MxMoveSrcOpEnc_"#AM)>;
308} // foreach AM
309
310// Pseudo versions. These a required by virtual register spill/restore since
311// the mask requires real register to encode. These instruction will be expanded
312// into real MOVEM after RA finishes.
313let mayStore = 1 in
314class MxMOVEM_MR_Pseudo<MxType TYPE, MxOperand MEMOp>
315    : MxPseudo<(outs), (ins MEMOp:$dst, TYPE.ROp:$reg)>;
316let mayLoad = 1 in
317class MxMOVEM_RM_Pseudo<MxType TYPE, MxOperand MEMOp>
318    : MxPseudo<(outs TYPE.ROp:$dst), (ins MEMOp:$src)>;
319
320// Mem <- Reg
321def MOVM8jm_P  : MxMOVEM_MR_Pseudo<MxType8d,  MxType8.JOp>;
322def MOVM16jm_P : MxMOVEM_MR_Pseudo<MxType16r, MxType16.JOp>;
323def MOVM32jm_P : MxMOVEM_MR_Pseudo<MxType32r, MxType32.JOp>;
324
325def MOVM8pm_P  : MxMOVEM_MR_Pseudo<MxType8d,  MxType8.POp>;
326def MOVM16pm_P : MxMOVEM_MR_Pseudo<MxType16r, MxType16.POp>;
327def MOVM32pm_P : MxMOVEM_MR_Pseudo<MxType32r, MxType32.POp>;
328
329// Reg <- Mem
330def MOVM8mj_P  : MxMOVEM_RM_Pseudo<MxType8d,  MxType8.JOp>;
331def MOVM16mj_P : MxMOVEM_RM_Pseudo<MxType16r, MxType16.JOp>;
332def MOVM32mj_P : MxMOVEM_RM_Pseudo<MxType32r, MxType32.JOp>;
333
334def MOVM8mp_P  : MxMOVEM_RM_Pseudo<MxType8d,  MxType8.POp>;
335def MOVM16mp_P : MxMOVEM_RM_Pseudo<MxType16r, MxType16.POp>;
336def MOVM32mp_P : MxMOVEM_RM_Pseudo<MxType32r, MxType32.POp>;
337
338
339//===----------------------------------------------------------------------===//
340// MOVE to/from SR/CCR
341//
342// A special care must be taken working with to/from CCR since it is basically
343// word-size SR register truncated for user mode thus it only supports word-size
344// instructions. Plus the original M68000 does not support moves from CCR. So in
345// order to use CCR effectively one MUST use proper byte-size pseudo instructi-
346// ons that will be resolved sometime after RA pass.
347//===----------------------------------------------------------------------===//
348
349/// --------------------------------------------------
350///  F  E  D  C  B  A  9  8  7  6 | 5  4  3 | 2  1  0
351/// --------------------------------------------------
352///                               | EFFECTIVE ADDRESS
353///  0  1  0  0  0  1  0  0  1  1 |   MODE  |   REG
354/// --------------------------------------------------
355let Defs = [CCR] in
356class MxMoveToCCR<MxOperand MEMOp, MxEncMemOp SRC_ENC>
357    : MxInst<(outs CCRC:$dst), (ins MEMOp:$src), "move.w\t$src, $dst", []> {
358  let Inst = (ascend
359    (descend 0b0100010011, SRC_ENC.EA),
360    SRC_ENC.Supplement
361  );
362}
363
364class MxMoveToCCRPseudo<MxOperand MEMOp>
365    : MxPseudo<(outs CCRC:$dst), (ins MEMOp:$src)>;
366
367let mayLoad = 1 in
368foreach AM = MxMoveSupportedAMs in {
369  def MOV16c # AM : MxMoveToCCR<!cast<MxOpBundle>("MxOp16AddrMode_"#AM).Op,
370                                !cast<MxEncMemOp>("MxMoveSrcOpEnc_"#AM)>;
371  def MOV8c # AM  : MxMoveToCCRPseudo<!cast<MxOpBundle>("MxOp8AddrMode_"#AM).Op>;
372} // foreach AM
373
374// Only data register is allowed.
375def MOV16cd : MxMoveToCCR<MxOp16AddrMode_d.Op, MxMoveSrcOpEnc_d>;
376def MOV8cd  : MxMoveToCCRPseudo<MxOp8AddrMode_d.Op>;
377
378/// Move from CCR
379/// --------------------------------------------------
380///  F  E  D  C  B  A  9  8  7  6 | 5  4  3 | 2  1  0
381/// --------------------------------------------------
382///                               | EFFECTIVE ADDRESS
383///  0  1  0  0  0  0  1  0  1  1 |   MODE  |   REG
384/// --------------------------------------------------
385let Uses = [CCR] in {
386class MxMoveFromCCR_R
387    : MxInst<(outs MxDRD16:$dst), (ins CCRC:$src), "move.w\t$src, $dst", []>,
388      Requires<[ AtLeastM68010 ]> {
389  let Inst = (descend 0b0100001011, MxEncAddrMode_d<"dst">.EA);
390}
391
392class MxMoveFromCCR_M<MxOperand MEMOp, MxEncMemOp DST_ENC>
393    : MxInst<(outs), (ins MEMOp:$dst, CCRC:$src), "move.w\t$src, $dst", []>,
394      Requires<[ AtLeastM68010 ]> {
395  let Inst = (ascend
396    (descend 0b0100001011, DST_ENC.EA),
397    DST_ENC.Supplement
398  );
399}
400
401class MxMoveFromCCRPseudo<MxOperand MEMOp>
402    : MxPseudo<(outs), (ins MEMOp:$dst, CCRC:$src)>;
403} // let Uses = [CCR]
404
405let mayStore = 1 in
406foreach AM = MxMoveSupportedAMs in {
407  def MOV16 # AM # c
408    : MxMoveFromCCR_M<!cast<MxOpBundle>("MxOp16AddrMode_"#AM).Op,
409                      !cast<MxEncMemOp>("MxMoveDstOpEnc_"#AM)>;
410  def MOV8 # AM # c
411    : MxMoveFromCCRPseudo<!cast<MxOpBundle>("MxOp8AddrMode_"#AM).Op>;
412} // foreach AM
413
414// Only data register is allowed.
415def MOV16dc : MxMoveFromCCR_R;
416def MOV8dc  : MxMoveFromCCRPseudo<MxOp8AddrMode_d.Op>;
417
418//===----------------------------------------------------------------------===//
419// LEA
420//===----------------------------------------------------------------------===//
421
422/// ----------------------------------------------------
423///  F  E  D  C | B  A  9 | 8  7  6 | 5  4  3 | 2  1  0
424/// ----------------------------------------------------
425///  0  1  0  0 | DST REG | 1  1  1 |   MODE  |   REG
426/// ----------------------------------------------------
427class MxLEA<MxOpBundle SRC, MxEncMemOp SRC_ENC>
428    : MxInst<(outs MxARD32:$dst), (ins SRC.Op:$src),
429             "lea\t$src, $dst", [(set i32:$dst, SRC.Pat:$src)]> {
430  let Inst = (ascend
431    (descend 0b0100, (operand "$dst", 3), 0b111, SRC_ENC.EA),
432    SRC_ENC.Supplement
433  );
434}
435
436foreach AM = ["p", "f", "b", "q", "k"] in
437def LEA32 # AM : MxLEA<!cast<MxOpBundle>("MxOp32AddrMode_"#AM),
438                       !cast<MxEncMemOp>("MxMoveSrcOpEnc_"#AM)>;
439
440//===----------------------------------------------------------------------===//
441// LINK/UNLK
442//===----------------------------------------------------------------------===//
443
444let Uses = [SP], Defs = [SP] in {
445let mayStore = 1 in {
446
447def LINK16 : MxInst<(outs), (ins MxARD16:$src, Mxi16imm:$disp), "link.w\t$src, $disp", []> {
448  let Inst = (ascend
449    (descend 0b0100111001010, (operand "$src", 3)),
450    (operand "$disp", 16)
451  );
452}
453
454def LINK32 : MxInst<(outs), (ins MxARD16:$src, Mxi32imm:$disp), "link.l\t$src, $disp", []> {
455  let Inst = (ascend
456    (descend 0b0100100000001, (operand "$src", 3)),
457    (slice "$disp", 31, 16),
458    (slice "$disp", 15, 0)
459  );
460}
461
462def UNLK : MxInst<(outs), (ins MxARD32:$src), "unlk\t$src", []> {
463  let Inst = (descend 0b0100111001011, (operand "$src", 3));
464}
465
466} // let mayStore = 1
467} // let Uses = [SP], Defs = [SP]
468
469//===----------------------------------------------------------------------===//
470// Pseudos
471//===----------------------------------------------------------------------===//
472
473/// Pushe/Pop to/from SP for simplicity
474let Uses = [SP], Defs = [SP], hasSideEffects = 0 in {
475
476// SP <- SP - <size>; (SP) <- Dn
477let mayStore = 1 in {
478def PUSH8d  : MxPseudo<(outs), (ins DR8:$reg)>;
479def PUSH16d : MxPseudo<(outs), (ins DR16:$reg)>;
480def PUSH32r : MxPseudo<(outs), (ins XR32:$reg)>;
481} // let mayStore = 1
482
483// Dn <- (SP); SP <- SP + <size>
484let mayLoad = 1 in {
485def POP8d  : MxPseudo<(outs DR8:$reg),  (ins)>;
486def POP16d : MxPseudo<(outs DR16:$reg), (ins)>;
487def POP32r : MxPseudo<(outs XR32:$reg), (ins)>;
488} // let mayLoad = 1
489
490} // let Uses/Defs = [SP], hasSideEffects = 0
491
492
493let Defs = [CCR] in {
494class MxPseudoMove_RR<MxType DST, MxType SRC, list<dag> PAT = []>
495    : MxPseudo<(outs DST.ROp:$dst), (ins SRC.ROp:$src), PAT>;
496
497class MxPseudoMove_RM<MxType DST, MxOperand SRCOpd, list<dag> PAT = []>
498    : MxPseudo<(outs DST.ROp:$dst), (ins SRCOpd:$src), PAT>;
499}
500
501/// This group of Pseudos is analogues to the real x86 extending moves, but
502/// since M68k does not have those we need to emulate. These instructions
503/// will be expanded right after RA completed because we need to know precisely
504/// what registers are allocated for the operands and if they overlap we just
505/// extend the value if the registers are completely different we need to move
506/// first.
507foreach EXT = ["S", "Z"] in {
508  let hasSideEffects = 0 in {
509
510    def MOV#EXT#Xd16d8  : MxPseudoMove_RR<MxType16d,  MxType8d>;
511    def MOV#EXT#Xd32d8  : MxPseudoMove_RR<MxType32d,  MxType8d>;
512    def MOV#EXT#Xd32d16 : MxPseudoMove_RR<MxType32r, MxType16r>;
513
514    let mayLoad = 1 in {
515
516      def MOV#EXT#Xd16j8   : MxPseudoMove_RM<MxType16d,  MxType8.JOp>;
517      def MOV#EXT#Xd32j8   : MxPseudoMove_RM<MxType32d,  MxType8.JOp>;
518      def MOV#EXT#Xd32j16  : MxPseudoMove_RM<MxType32d, MxType16.JOp>;
519
520      def MOV#EXT#Xd16p8   : MxPseudoMove_RM<MxType16d,  MxType8.POp>;
521      def MOV#EXT#Xd32p8   : MxPseudoMove_RM<MxType32d,  MxType8.POp>;
522      def MOV#EXT#Xd32p16  : MxPseudoMove_RM<MxType32d, MxType16.POp>;
523
524      def MOV#EXT#Xd16f8   : MxPseudoMove_RM<MxType16d,  MxType8.FOp>;
525      def MOV#EXT#Xd32f8   : MxPseudoMove_RM<MxType32d,  MxType8.FOp>;
526      def MOV#EXT#Xd32f16  : MxPseudoMove_RM<MxType32d, MxType16.FOp>;
527
528      def MOV#EXT#Xd16q8   : MxPseudoMove_RM<MxType16d,  MxType8.QOp>;
529      def MOV#EXT#Xd32q8   : MxPseudoMove_RM<MxType32d,  MxType8.QOp>;
530      def MOV#EXT#Xd32q16  : MxPseudoMove_RM<MxType32d,  MxType16.QOp>;
531
532    }
533  }
534}
535
536/// This group of instructions is similar to the group above but DOES NOT do
537/// any value extension, they just load a smaller register into the lower part
538/// of another register if operands' real registers are different or does
539/// nothing if they are the same.
540def MOVXd16d8  : MxPseudoMove_RR<MxType16d,  MxType8d>;
541def MOVXd32d8  : MxPseudoMove_RR<MxType32d,  MxType8d>;
542def MOVXd32d16 : MxPseudoMove_RR<MxType32r, MxType16r>;
543
544//===----------------------------------------------------------------------===//
545// Extend/Truncate Patterns
546//===----------------------------------------------------------------------===//
547
548// i16 <- sext i8
549def: Pat<(i16 (sext i8:$src)),
550          (EXTRACT_SUBREG (MOVSXd32d8 MxDRD8:$src), MxSubRegIndex16Lo)>;
551def: Pat<(MxSExtLoadi16i8 MxCP_ARI:$src),
552          (EXTRACT_SUBREG (MOVSXd32j8 MxARI8:$src), MxSubRegIndex16Lo)>;
553def: Pat<(MxSExtLoadi16i8 MxCP_ARID:$src),
554          (EXTRACT_SUBREG (MOVSXd32p8 MxARID8:$src), MxSubRegIndex16Lo)>;
555def: Pat<(MxSExtLoadi16i8 MxCP_ARII:$src),
556          (EXTRACT_SUBREG (MOVSXd32f8 MxARII8:$src), MxSubRegIndex16Lo)>;
557def: Pat<(MxSExtLoadi16i8 MxCP_PCD:$src), (MOVSXd16q8 MxPCD8:$src)>;
558
559// i32 <- sext i8
560def: Pat<(i32 (sext i8:$src)), (MOVSXd32d8 MxDRD8:$src)>;
561def: Pat<(MxSExtLoadi32i8 MxCP_ARI :$src), (MOVSXd32j8 MxARI8 :$src)>;
562def: Pat<(MxSExtLoadi32i8 MxCP_ARID:$src), (MOVSXd32p8 MxARID8:$src)>;
563def: Pat<(MxSExtLoadi32i8 MxCP_ARII:$src), (MOVSXd32f8 MxARII8:$src)>;
564def: Pat<(MxSExtLoadi32i8 MxCP_PCD:$src),  (MOVSXd32q8 MxPCD8:$src)>;
565
566// i32 <- sext i16
567def: Pat<(i32 (sext i16:$src)), (MOVSXd32d16 MxDRD16:$src)>;
568def: Pat<(MxSExtLoadi32i16 MxCP_ARI :$src), (MOVSXd32j16 MxARI16 :$src)>;
569def: Pat<(MxSExtLoadi32i16 MxCP_ARID:$src), (MOVSXd32p16 MxARID16:$src)>;
570def: Pat<(MxSExtLoadi32i16 MxCP_ARII:$src), (MOVSXd32f16 MxARII16:$src)>;
571def: Pat<(MxSExtLoadi32i16 MxCP_PCD:$src),  (MOVSXd32q16 MxPCD16:$src)>;
572
573// i16 <- zext i8
574def: Pat<(i16 (zext i8:$src)),
575          (EXTRACT_SUBREG (MOVZXd32d8 MxDRD8:$src), MxSubRegIndex16Lo)>;
576def: Pat<(MxZExtLoadi16i8 MxCP_ARI:$src),
577          (EXTRACT_SUBREG (MOVZXd32j8 MxARI8:$src), MxSubRegIndex16Lo)>;
578def: Pat<(MxZExtLoadi16i8 MxCP_ARID:$src),
579          (EXTRACT_SUBREG (MOVZXd32p8 MxARID8:$src), MxSubRegIndex16Lo)>;
580def: Pat<(MxZExtLoadi16i8 MxCP_ARII:$src),
581          (EXTRACT_SUBREG (MOVZXd32f8 MxARII8:$src), MxSubRegIndex16Lo)>;
582def: Pat<(MxZExtLoadi16i8 MxCP_PCD :$src), (MOVZXd16q8 MxPCD8 :$src)>;
583
584// i32 <- zext i8
585def: Pat<(i32 (zext i8:$src)), (MOVZXd32d8 MxDRD8:$src)>;
586def: Pat<(MxZExtLoadi32i8 MxCP_ARI :$src), (MOVZXd32j8 MxARI8 :$src)>;
587def: Pat<(MxZExtLoadi32i8 MxCP_ARID:$src), (MOVZXd32p8 MxARID8:$src)>;
588def: Pat<(MxZExtLoadi32i8 MxCP_ARII:$src), (MOVZXd32f8 MxARII8:$src)>;
589def: Pat<(MxZExtLoadi32i8 MxCP_PCD :$src), (MOVZXd32q8 MxPCD8 :$src)>;
590
591// i32 <- zext i16
592def: Pat<(i32 (zext i16:$src)), (MOVZXd32d16 MxDRD16:$src)>;
593def: Pat<(MxZExtLoadi32i16 MxCP_ARI :$src), (MOVZXd32j16 MxARI16 :$src)>;
594def: Pat<(MxZExtLoadi32i16 MxCP_ARID:$src), (MOVZXd32p16 MxARID16:$src)>;
595def: Pat<(MxZExtLoadi32i16 MxCP_ARII:$src), (MOVZXd32f16 MxARII16:$src)>;
596def: Pat<(MxZExtLoadi32i16 MxCP_PCD :$src), (MOVZXd32q16 MxPCD16 :$src)>;
597
598// i16 <- anyext i8
599def: Pat<(i16 (anyext i8:$src)),
600          (EXTRACT_SUBREG (MOVZXd32d8 MxDRD8:$src), MxSubRegIndex16Lo)>;
601def: Pat<(MxExtLoadi16i8 MxCP_ARI:$src),
602          (EXTRACT_SUBREG (MOVZXd32j8 MxARI8:$src), MxSubRegIndex16Lo)>;
603def: Pat<(MxExtLoadi16i8 MxCP_ARID:$src),
604          (EXTRACT_SUBREG (MOVZXd32p8 MxARID8:$src), MxSubRegIndex16Lo)>;
605def: Pat<(MxExtLoadi16i8 MxCP_ARII:$src),
606          (EXTRACT_SUBREG (MOVZXd32f8 MxARII8:$src), MxSubRegIndex16Lo)>;
607
608// i32 <- anyext i8
609def: Pat<(i32 (anyext i8:$src)), (MOVZXd32d8 MxDRD8:$src)>;
610def: Pat<(MxExtLoadi32i8 MxCP_ARI :$src), (MOVZXd32j8 MxARI8 :$src)>;
611def: Pat<(MxExtLoadi32i8 MxCP_ARID:$src), (MOVZXd32p8 MxARID8:$src)>;
612def: Pat<(MxExtLoadi32i8 MxCP_ARII:$src), (MOVZXd32f8 MxARII8:$src)>;
613
614// i32 <- anyext i16
615def: Pat<(i32 (anyext i16:$src)), (MOVZXd32d16 MxDRD16:$src)>;
616def: Pat<(MxExtLoadi32i16 MxCP_ARI :$src), (MOVZXd32j16 MxARI16 :$src)>;
617def: Pat<(MxExtLoadi32i16 MxCP_ARID:$src), (MOVZXd32p16 MxARID16:$src)>;
618def: Pat<(MxExtLoadi32i16 MxCP_ARII:$src), (MOVZXd32f16 MxARII16:$src)>;
619
620// trunc patterns
621def : Pat<(i16 (trunc i32:$src)),
622          (EXTRACT_SUBREG MxXRD32:$src, MxSubRegIndex16Lo)>;
623def : Pat<(i8  (trunc i32:$src)),
624          (EXTRACT_SUBREG MxXRD32:$src, MxSubRegIndex8Lo)>;
625def : Pat<(i8  (trunc i16:$src)),
626          (EXTRACT_SUBREG MxXRD16:$src, MxSubRegIndex8Lo)>;
627
628//===----------------------------------------------------------------------===//
629// FMOVE
630//===----------------------------------------------------------------------===//
631
632let Defs = [FPS] in
633class MxFMove<string size, dag outs, dag ins, list<dag> pattern,
634              string rounding = "">
635    : MxInst<outs, ins,
636             "f"#rounding#"move."#size#"\t$src, $dst", pattern> {
637  // Only FMOVE uses FPC
638  let Uses = !if(!eq(rounding, ""), [FPC], []);
639
640  // FSMOVE and FDMOVE are only available after M68040
641  let Predicates = [!if(!eq(rounding, ""), AtLeastM68881, AtLeastM68040)];
642}
643
644// FPDR <- FPDR
645class MxFMove_FF<string rounding, int size,
646                 MxOpBundle Opnd = !cast<MxOpBundle>("MxOp"#size#"AddrMode_fpr")>
647    : MxFMove<"x", (outs Opnd.Op:$dst), (ins Opnd.Op:$src),
648              [(null_frag)], rounding> {
649  let Inst = (ascend
650    (descend 0b1111,
651      /*COPROCESSOR ID*/0b001,
652      0b000,
653      /*MODE + REGISTER*/0b000000
654    ),
655    (descend 0b0, /* R/M */0b0, 0b0,
656      /*SOURCE SPECIFIER*/
657      (operand "$src", 3),
658      /*DESTINATION*/
659      (operand "$dst", 3),
660      /*OPMODE*/
661      !cond(!eq(rounding, "s"): 0b1000000,
662            !eq(rounding, "d"): 0b1000100,
663            true: 0b0000000)
664    )
665  );
666}
667
668foreach rounding = ["", "s", "d"] in {
669  def F # !toupper(rounding) # MOV80fp_fp : MxFMove_FF<rounding, 80>;
670
671  // We don't have `fmove.s` or `fmove.d` because values will be converted to
672  // f80 upon storing into the register, but FMOV32/64fp_fp are still needed
673  // to make codegen easier.
674  let isCodeGenOnly = true in
675  foreach size = [32, 64] in
676    def F # !toupper(rounding) # MOV # size # fp_fp : MxFMove_FF<rounding, size>;
677}
678// Direction
679defvar MxFMove_FP_EA = false;
680defvar MxFMove_EA_FP = true;
681
682// Encoding scheme for FPSYS <-> R/M
683class MxEncFSysMove<bit dir, MxEncMemOp EAEnc, string fsys_reg> {
684  dag Value = (ascend
685    (descend 0b1111,
686      /*COPROCESSOR ID*/0b001,
687      0b000,
688      /*MODE + REGISTER*/
689      EAEnc.EA
690    ),
691    (descend 0b10, /*dir*/ dir,
692      /*REGISTER SELECT*/
693      (operand "$"#fsys_reg, 3, (encoder "encodeFPSYSSelect")),
694      0b0000000000
695    )
696  );
697}
698
699// FPSYS <-> R
700class MxFMove_FSYS_R<string src_reg,
701                     MxOpBundle SrcOpnd = !cast<MxOpBundle>("MxOp32AddrMode_"#src_reg),
702                     MxOpBundle DstOpnd = !cond(!eq(src_reg, "d"): MxOp32AddrMode_fpcs,
703                                                !eq(src_reg, "a"): MxOp32AddrMode_fpi),
704                     MxEncMemOp SrcEnc = !cast<MxEncMemOp>("MxMoveSrcOpEnc_"#src_reg)>
705    : MxFMove<"l", (outs DstOpnd.Op:$dst), (ins SrcOpnd.Op:$src),
706              [(null_frag)]> {
707  let Inst = MxEncFSysMove<MxFMove_FP_EA, SrcEnc, "dst">.Value;
708}
709
710class MxFMove_R_FSYS<string dst_reg,
711                     MxOpBundle SrcOpnd = !cond(!eq(dst_reg, "d"): MxOp32AddrMode_fpcs,
712                                                !eq(dst_reg, "a"): MxOp32AddrMode_fpi),
713                     MxOpBundle DstOpnd = !cast<MxOpBundle>("MxOp32AddrMode_"#dst_reg),
714                     MxEncMemOp DstEnc = !cast<MxEncMemOp>("MxMoveDstOpEnc_"#dst_reg)>
715    : MxFMove<"l", (outs DstOpnd.Op:$dst), (ins SrcOpnd.Op:$src),
716              [(null_frag)]> {
717  let Inst = MxEncFSysMove<MxFMove_EA_FP, DstEnc, "src">.Value;
718}
719
720def FMOVE32fpcs_d : MxFMove_FSYS_R<"d">;
721def FMOVE32d_fpcs : MxFMove_R_FSYS<"d">;
722def FMOVE32fpi_a  : MxFMove_FSYS_R<"a">;
723def FMOVE32a_fpi  : MxFMove_R_FSYS<"a">;
724