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