702588a8c174cd254061145313df2566fa48ff25
[platform/upstream/coreclr.git] / src / jit / emitarm.h
1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4
5 #if defined(_TARGET_ARM_)
6
7 // This typedef defines the type that we use to hold encoded instructions.
8 //
9 typedef unsigned int code_t;
10
11 /************************************************************************/
12 /*         Routines that compute the size of / encode instructions      */
13 /************************************************************************/
14
15 struct CnsVal
16 {
17     int  cnsVal;
18     bool cnsReloc;
19 };
20
21 insSize emitInsSize(insFormat insFmt);
22
23 #ifdef FEATURE_ITINSTRUCTION
24 BYTE* emitOutputIT(BYTE* dst, instruction ins, insFormat fmt, code_t condcode);
25 #endif // FEATURE_ITINSTRUCTION
26
27 BYTE* emitOutputLJ(insGroup* ig, BYTE* dst, instrDesc* id);
28 BYTE* emitOutputShortBranch(BYTE* dst, instruction ins, insFormat fmt, ssize_t distVal, instrDescJmp* id);
29
30 static unsigned emitOutput_Thumb1Instr(BYTE* dst, code_t code);
31 static unsigned emitOutput_Thumb2Instr(BYTE* dst, code_t code);
32
33 /************************************************************************/
34 /*             Debug-only routines to display instructions              */
35 /************************************************************************/
36
37 #ifdef DEBUG
38
39 void emitDispInst(instruction ins, insFlags flags);
40 void emitDispImm(int imm, bool addComma, bool alwaysHex = false);
41 void emitDispCond(int cond);
42 void emitDispShiftOpts(insOpts opt);
43 void emitDispRegmask(int imm, bool encodedPC_LR);
44 void emitDispRegRange(regNumber reg, int len, emitAttr attr);
45 void emitDispReg(regNumber reg, emitAttr attr, bool addComma);
46 void emitDispAddrR(regNumber reg, emitAttr attr);
47 void emitDispAddrRI(regNumber reg, int imm, emitAttr attr);
48 void emitDispAddrRR(regNumber reg1, regNumber reg2, emitAttr attr);
49 void emitDispAddrRRI(regNumber reg1, regNumber reg2, int imm, emitAttr attr);
50 void emitDispAddrPUW(regNumber reg, int imm, insOpts opt, emitAttr attr);
51 void emitDispGC(emitAttr attr);
52
53 void emitDispInsHelp(instrDesc* id,
54                      bool       isNew,
55                      bool       doffs,
56                      bool       asmfm,
57                      unsigned   offs = 0,
58                      BYTE*      code = 0,
59                      size_t     sz   = 0,
60                      insGroup*  ig   = NULL);
61 void emitDispIns(instrDesc* id,
62                  bool       isNew,
63                  bool       doffs,
64                  bool       asmfm,
65                  unsigned   offs = 0,
66                  BYTE*      code = 0,
67                  size_t     sz   = 0,
68                  insGroup*  ig   = NULL);
69
70 #endif // DEBUG
71
72 /************************************************************************/
73 /*  Private members that deal with target-dependent instr. descriptors  */
74 /************************************************************************/
75
76 private:
77 instrDesc* emitNewInstrCallDir(
78     int argCnt, VARSET_VALARG_TP GCvars, regMaskTP gcrefRegs, regMaskTP byrefRegs, emitAttr retSize);
79
80 instrDesc* emitNewInstrCallInd(
81     int argCnt, ssize_t disp, VARSET_VALARG_TP GCvars, regMaskTP gcrefRegs, regMaskTP byrefRegs, emitAttr retSize);
82
83 /************************************************************************/
84 /*               Private helpers for instruction output                 */
85 /************************************************************************/
86
87 private:
88 bool emitInsIsCompare(instruction ins);
89 bool emitInsIsLoad(instruction ins);
90 bool emitInsIsStore(instruction ins);
91 bool emitInsIsLoadOrStore(instruction ins);
92
93 emitter::insFormat emitInsFormat(instruction ins);
94 emitter::code_t emitInsCode(instruction ins, insFormat fmt);
95
96 // Generate code for a load or store operation and handle the case
97 // of contained GT_LEA op1 with [base + index<<scale + offset]
98 void emitInsLoadStoreOp(instruction ins, emitAttr attr, regNumber dataReg, GenTreeIndir* indir);
99 void emitInsLoadStoreOp(instruction ins, emitAttr attr, regNumber dataReg, GenTreeIndir* indir, int offset);
100
101 static bool isModImmConst(int imm);
102 static int encodeModImmConst(int imm);
103
104 static int insUnscaleImm(int imm, emitAttr size);
105
106 /************************************************************************/
107 /*           Public inline informational methods                        */
108 /************************************************************************/
109
110 public:
111 inline static bool isLowRegister(regNumber reg)
112 {
113     return (reg <= REG_R7);
114 }
115
116 inline static bool isGeneralRegister(regNumber reg)
117 {
118     return (reg <= REG_R15);
119 }
120
121 inline static bool isFloatReg(regNumber reg)
122 {
123     return (reg >= REG_F0 && reg <= REG_F31);
124 }
125
126 inline static bool isDoubleReg(regNumber reg)
127 {
128     return isFloatReg(reg) && ((reg % 2) == 0);
129 }
130
131 inline static bool insSetsFlags(insFlags flags)
132 {
133     return (flags != INS_FLAGS_NOT_SET);
134 }
135
136 inline static bool insDoesNotSetFlags(insFlags flags)
137 {
138     return (flags != INS_FLAGS_SET);
139 }
140
141 inline static insFlags insMustSetFlags(insFlags flags)
142 {
143     return (flags == INS_FLAGS_SET) ? INS_FLAGS_SET : INS_FLAGS_NOT_SET;
144 }
145
146 inline static insFlags insMustNotSetFlags(insFlags flags)
147 {
148     return (flags == INS_FLAGS_NOT_SET) ? INS_FLAGS_NOT_SET : INS_FLAGS_SET;
149 }
150
151 inline static bool insOptsNone(insOpts opt)
152 {
153     return (opt == INS_OPTS_NONE);
154 }
155
156 inline static bool insOptAnyInc(insOpts opt)
157 {
158     return (opt == INS_OPTS_LDST_PRE_DEC) || (opt == INS_OPTS_LDST_POST_INC);
159 }
160
161 inline static bool insOptsPreDec(insOpts opt)
162 {
163     return (opt == INS_OPTS_LDST_PRE_DEC);
164 }
165
166 inline static bool insOptsPostInc(insOpts opt)
167 {
168     return (opt == INS_OPTS_LDST_POST_INC);
169 }
170
171 inline static bool insOptAnyShift(insOpts opt)
172 {
173     return ((opt >= INS_OPTS_RRX) && (opt <= INS_OPTS_ROR));
174 }
175
176 inline static bool insOptsRRX(insOpts opt)
177 {
178     return (opt == INS_OPTS_RRX);
179 }
180
181 inline static bool insOptsLSL(insOpts opt)
182 {
183     return (opt == INS_OPTS_LSL);
184 }
185
186 inline static bool insOptsLSR(insOpts opt)
187 {
188     return (opt == INS_OPTS_LSR);
189 }
190
191 inline static bool insOptsASR(insOpts opt)
192 {
193     return (opt == INS_OPTS_ASR);
194 }
195
196 inline static bool insOptsROR(insOpts opt)
197 {
198     return (opt == INS_OPTS_ROR);
199 }
200
201 // Returns the number of bits used by the given 'size'.
202 inline static unsigned getBitWidth(emitAttr size)
203 {
204     assert(size <= EA_8BYTE);
205     return (unsigned)size * BITS_PER_BYTE;
206 }
207
208 /************************************************************************/
209 /*           The public entry points to output instructions             */
210 /************************************************************************/
211
212 public:
213 static bool emitIns_valid_imm_for_alu(int imm);
214 static bool emitIns_valid_imm_for_mov(int imm);
215 static bool emitIns_valid_imm_for_small_mov(regNumber reg, int imm, insFlags flags);
216 static bool emitIns_valid_imm_for_add(int imm, insFlags flags = INS_FLAGS_DONT_CARE);
217 static bool emitIns_valid_imm_for_cmp(int imm, insFlags flags);
218 static bool emitIns_valid_imm_for_add_sp(int imm);
219 static bool emitIns_valid_imm_for_ldst_offset(int imm, emitAttr size);
220 static bool emitIns_valid_imm_for_vldst_offset(int imm);
221
222 void emitIns(instruction ins);
223
224 void emitIns_I(instruction ins, emitAttr attr, ssize_t imm);
225
226 void emitIns_R(instruction ins, emitAttr attr, regNumber reg);
227
228 void emitIns_R_I(instruction ins, emitAttr attr, regNumber reg, ssize_t imm, insFlags flags = INS_FLAGS_DONT_CARE);
229
230 void emitIns_R_R(instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, insFlags flags = INS_FLAGS_DONT_CARE);
231
232 void emitIns_R_I_I(
233     instruction ins, emitAttr attr, regNumber reg1, int imm1, int imm2, insFlags flags = INS_FLAGS_DONT_CARE);
234
235 void emitIns_R_R_I(instruction ins,
236                    emitAttr    attr,
237                    regNumber   reg1,
238                    regNumber   reg2,
239                    int         imm,
240                    insFlags    flags = INS_FLAGS_DONT_CARE,
241                    insOpts     opt   = INS_OPTS_NONE);
242
243 void emitIns_R_R_R(instruction ins,
244                    emitAttr    attr,
245                    regNumber   reg1,
246                    regNumber   reg2,
247                    regNumber   reg3,
248                    insFlags    flags = INS_FLAGS_DONT_CARE);
249
250 void emitIns_R_R_I_I(instruction ins,
251                      emitAttr    attr,
252                      regNumber   reg1,
253                      regNumber   reg2,
254                      int         imm1,
255                      int         imm2,
256                      insFlags    flags = INS_FLAGS_DONT_CARE);
257
258 void emitIns_R_R_R_I(instruction ins,
259                      emitAttr    attr,
260                      regNumber   reg1,
261                      regNumber   reg2,
262                      regNumber   reg3,
263                      int         imm,
264                      insFlags    flags = INS_FLAGS_DONT_CARE,
265                      insOpts     opt   = INS_OPTS_NONE);
266
267 void emitIns_R_R_R_R(instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, regNumber reg3, regNumber reg4);
268
269 void emitIns_C(instruction ins, emitAttr attr, CORINFO_FIELD_HANDLE fdlHnd, int offs);
270
271 void emitIns_S(instruction ins, emitAttr attr, int varx, int offs);
272
273 void emitIns_genStackOffset(regNumber r, int varx, int offs);
274
275 void emitIns_S_R(instruction ins, emitAttr attr, regNumber ireg, int varx, int offs);
276
277 void emitIns_R_S(instruction ins, emitAttr attr, regNumber ireg, int varx, int offs);
278
279 void emitIns_S_I(instruction ins, emitAttr attr, int varx, int offs, int val);
280
281 void emitIns_R_C(instruction ins, emitAttr attr, regNumber reg, CORINFO_FIELD_HANDLE fldHnd, int offs);
282
283 void emitIns_C_R(instruction ins, emitAttr attr, CORINFO_FIELD_HANDLE fldHnd, regNumber reg, int offs);
284
285 void emitIns_C_I(instruction ins, emitAttr attr, CORINFO_FIELD_HANDLE fdlHnd, int offs, ssize_t val);
286
287 void emitIns_R_L(instruction ins, emitAttr attr, BasicBlock* dst, regNumber reg);
288
289 void emitIns_R_D(instruction ins, emitAttr attr, unsigned offs, regNumber reg);
290
291 void emitIns_J_R(instruction ins, emitAttr attr, BasicBlock* dst, regNumber reg);
292
293 void emitIns_I_AR(instruction ins, emitAttr attr, int val, regNumber reg, int offs);
294
295 void emitIns_R_AR(instruction ins, emitAttr attr, regNumber ireg, regNumber reg, int offs);
296
297 void emitIns_R_AI(instruction ins, emitAttr attr, regNumber ireg, ssize_t disp);
298
299 void emitIns_AR_R(instruction ins, emitAttr attr, regNumber ireg, regNumber reg, int offs);
300
301 void emitIns_R_ARR(instruction ins, emitAttr attr, regNumber ireg, regNumber reg, regNumber rg2, int disp);
302
303 void emitIns_ARR_R(instruction ins, emitAttr attr, regNumber ireg, regNumber reg, regNumber rg2, int disp);
304
305 void emitIns_R_ARX(
306     instruction ins, emitAttr attr, regNumber ireg, regNumber reg, regNumber rg2, unsigned mul, int disp);
307
308 enum EmitCallType
309 {
310
311     // I have included here, but commented out, all the values used by the x86 emitter.
312     // However, ARM has a much reduced instruction set, and so the ARM emitter only
313     // supports a subset of the x86 variants.  By leaving them commented out, it becomes
314     // a compile time error if code tries to use them (and hopefully see this comment
315     // and know why they are unavailible on ARM), while making it easier to stay
316     // in-sync with x86 and possibly add them back in if needed.
317
318     EC_FUNC_TOKEN, //   Direct call to a helper/static/nonvirtual/global method
319                    //  EC_FUNC_TOKEN_INDIR,    // Indirect call to a helper/static/nonvirtual/global method
320     EC_FUNC_ADDR,  // Direct call to an absolute address
321
322     //  EC_FUNC_VIRTUAL,        // Call to a virtual method (using the vtable)
323     EC_INDIR_R, // Indirect call via register
324                 //  EC_INDIR_SR,            // Indirect call via stack-reference (local var)
325                 //  EC_INDIR_C,             // Indirect call via static class var
326                 //  EC_INDIR_ARD,           // Indirect call via an addressing mode
327
328     EC_COUNT
329 };
330
331 void emitIns_Call(EmitCallType          callType,
332                   CORINFO_METHOD_HANDLE methHnd,                   // used for pretty printing
333                   INDEBUG_LDISASM_COMMA(CORINFO_SIG_INFO* sigInfo) // used to report call sites to the EE
334                   void*            addr,
335                   ssize_t          argSize,
336                   emitAttr         retSize,
337                   VARSET_VALARG_TP ptrVars,
338                   regMaskTP        gcrefRegs,
339                   regMaskTP        byrefRegs,
340                   IL_OFFSETX       ilOffset      = BAD_IL_OFFSET,
341                   regNumber        ireg          = REG_NA,
342                   regNumber        xreg          = REG_NA,
343                   unsigned         xmul          = 0,
344                   int              disp          = 0,
345                   bool             isJump        = false,
346                   bool             isNoGC        = false,
347                   bool             isProfLeaveCB = false);
348
349 /*****************************************************************************
350  *
351  *  Given an instrDesc, return true if it's a conditional jump.
352  */
353
354 inline bool emitIsCondJump(instrDesc* jmp)
355 {
356     return (jmp->idInsFmt() == IF_T2_J1) || (jmp->idInsFmt() == IF_T1_K) || (jmp->idInsFmt() == IF_LARGEJMP);
357 }
358
359 /*****************************************************************************
360  *
361  *  Given an instrDesc, return true if it's a comapre and jump.
362  */
363
364 inline bool emitIsCmpJump(instrDesc* jmp)
365 {
366     return (jmp->idInsFmt() == IF_T1_I);
367 }
368
369 /*****************************************************************************
370  *
371  *  Given a instrDesc, return true if it's an unconditional jump.
372  */
373
374 inline bool emitIsUncondJump(instrDesc* jmp)
375 {
376     return (jmp->idInsFmt() == IF_T2_J2) || (jmp->idInsFmt() == IF_T1_M);
377 }
378
379 /*****************************************************************************
380  *
381  *  Given a instrDesc, return true if it's a load label instruction.
382  */
383
384 inline bool emitIsLoadLabel(instrDesc* jmp)
385 {
386     return (jmp->idInsFmt() == IF_T2_M1) || (jmp->idInsFmt() == IF_T1_J3) || (jmp->idInsFmt() == IF_T2_N1);
387 }
388
389 #endif // _TARGET_ARM_