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.
5 #if defined(_TARGET_ARM_)
7 // This typedef defines the type that we use to hold encoded instructions.
9 typedef unsigned int code_t;
11 /************************************************************************/
12 /* Routines that compute the size of / encode instructions */
13 /************************************************************************/
21 insSize emitInsSize(insFormat insFmt);
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);
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);
36 BYTE* emitOutputLJ(insGroup* ig, BYTE* dst, instrDesc* id);
37 BYTE* emitOutputShortBranch(BYTE* dst, instruction ins, insFormat fmt, ssize_t distVal, instrDescJmp* id);
39 static unsigned emitOutput_Thumb1Instr(BYTE* dst, code_t code);
40 static unsigned emitOutput_Thumb2Instr(BYTE* dst, code_t code);
42 /************************************************************************/
43 /* Debug-only routines to display instructions */
44 /************************************************************************/
48 const char* emitFPregName(unsigned reg, bool varName = true);
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);
66 void emitDispInsHelp(instrDesc* id,
74 void emitDispIns(instrDesc* id,
85 /************************************************************************/
86 /* Private members that deal with target-dependent instr. descriptors */
87 /************************************************************************/
90 instrDesc* emitNewInstrAmd(emitAttr attr, int dsp);
91 instrDesc* emitNewInstrAmdCns(emitAttr attr, int dsp, int cns);
93 instrDesc* emitNewInstrCallDir(
94 int argCnt, VARSET_VALARG_TP GCvars, regMaskTP gcrefRegs, regMaskTP byrefRegs, emitAttr retSize);
96 instrDesc* emitNewInstrCallInd(
97 int argCnt, ssize_t disp, VARSET_VALARG_TP GCvars, regMaskTP gcrefRegs, regMaskTP byrefRegs, emitAttr retSize);
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);
104 /************************************************************************/
105 /* Private helpers for instruction output */
106 /************************************************************************/
109 bool emitInsIsCompare(instruction ins);
110 bool emitInsIsLoad(instruction ins);
111 bool emitInsIsStore(instruction ins);
112 bool emitInsIsLoadOrStore(instruction ins);
114 emitter::insFormat emitInsFormat(instruction ins);
115 emitter::code_t emitInsCode(instruction ins, insFormat fmt);
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);
122 /*****************************************************************************
124 * Convert between an index scale in bytes to a smaller encoding used for
125 * storage in instruction descriptors.
128 inline emitter::opSize emitEncodeScale(size_t scale)
130 assert(scale == 1 || scale == 2 || scale == 4 || scale == 8);
132 return emitSizeEncode[scale - 1];
135 inline emitAttr emitDecodeScale(unsigned ensz)
139 return emitter::emitSizeDecode[ensz];
142 static bool isModImmConst(int imm);
144 static int encodeModImmConst(int imm);
146 static int insUnscaleImm(int imm, emitAttr size);
148 /************************************************************************/
149 /* Public inline informational methods */
150 /************************************************************************/
153 inline static bool isLowRegister(regNumber reg)
155 return (reg <= REG_R7);
158 inline static bool isGeneralRegister(regNumber reg)
160 return (reg <= REG_R15);
163 inline static bool isFloatReg(regNumber reg)
165 return (reg >= REG_F0 && reg <= REG_F31);
168 inline static bool isDoubleReg(regNumber reg)
170 return isFloatReg(reg) && ((reg % 2) == 0);
173 inline static bool insSetsFlags(insFlags flags)
175 return (flags != INS_FLAGS_NOT_SET);
178 inline static bool insDoesNotSetFlags(insFlags flags)
180 return (flags != INS_FLAGS_SET);
183 inline static insFlags insMustSetFlags(insFlags flags)
185 return (flags == INS_FLAGS_SET) ? INS_FLAGS_SET : INS_FLAGS_NOT_SET;
188 inline static insFlags insMustNotSetFlags(insFlags flags)
190 return (flags == INS_FLAGS_NOT_SET) ? INS_FLAGS_NOT_SET : INS_FLAGS_SET;
193 inline static bool insOptsNone(insOpts opt)
195 return (opt == INS_OPTS_NONE);
198 inline static bool insOptAnyInc(insOpts opt)
200 return (opt == INS_OPTS_LDST_PRE_DEC) || (opt == INS_OPTS_LDST_POST_INC);
203 inline static bool insOptsPreDec(insOpts opt)
205 return (opt == INS_OPTS_LDST_PRE_DEC);
208 inline static bool insOptsPostInc(insOpts opt)
210 return (opt == INS_OPTS_LDST_POST_INC);
213 inline static bool insOptAnyShift(insOpts opt)
215 return ((opt >= INS_OPTS_RRX) && (opt <= INS_OPTS_ROR));
218 inline static bool insOptsRRX(insOpts opt)
220 return (opt == INS_OPTS_RRX);
223 inline static bool insOptsLSL(insOpts opt)
225 return (opt == INS_OPTS_LSL);
228 inline static bool insOptsLSR(insOpts opt)
230 return (opt == INS_OPTS_LSR);
233 inline static bool insOptsASR(insOpts opt)
235 return (opt == INS_OPTS_ASR);
238 inline static bool insOptsROR(insOpts opt)
240 return (opt == INS_OPTS_ROR);
243 // Returns the number of bits used by the given 'size'.
244 inline static unsigned getBitWidth(emitAttr size)
246 assert(size <= EA_8BYTE);
247 return (unsigned)size * BITS_PER_BYTE;
250 /************************************************************************/
251 /* The public entry points to output instructions */
252 /************************************************************************/
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);
264 void emitIns(instruction ins);
266 void emitIns_I(instruction ins, emitAttr attr, ssize_t imm);
268 void emitIns_R(instruction ins, emitAttr attr, regNumber reg);
270 void emitIns_R_I(instruction ins, emitAttr attr, regNumber reg, ssize_t imm, insFlags flags = INS_FLAGS_DONT_CARE);
272 void emitIns_R_R(instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, insFlags flags = INS_FLAGS_DONT_CARE);
275 instruction ins, emitAttr attr, regNumber reg1, int imm1, int imm2, insFlags flags = INS_FLAGS_DONT_CARE);
277 void emitIns_R_R_I(instruction ins,
282 insFlags flags = INS_FLAGS_DONT_CARE,
283 insOpts opt = INS_OPTS_NONE);
285 void emitIns_R_R_R(instruction ins,
290 insFlags flags = INS_FLAGS_DONT_CARE);
292 void emitIns_R_R_I_I(instruction ins,
298 insFlags flags = INS_FLAGS_DONT_CARE);
300 void emitIns_R_R_R_I(instruction ins,
306 insFlags flags = INS_FLAGS_DONT_CARE,
307 insOpts opt = INS_OPTS_NONE);
309 void emitIns_R_R_R_R(instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, regNumber reg3, regNumber reg4);
311 void emitIns_C(instruction ins, emitAttr attr, CORINFO_FIELD_HANDLE fdlHnd, int offs);
313 void emitIns_S(instruction ins, emitAttr attr, int varx, int offs);
315 void emitIns_genStackOffset(regNumber r, int varx, int offs);
317 void emitIns_S_R(instruction ins, emitAttr attr, regNumber ireg, int varx, int offs);
319 void emitIns_R_S(instruction ins, emitAttr attr, regNumber ireg, int varx, int offs);
321 void emitIns_S_I(instruction ins, emitAttr attr, int varx, int offs, int val);
323 void emitIns_R_C(instruction ins, emitAttr attr, regNumber reg, CORINFO_FIELD_HANDLE fldHnd, int offs);
325 void emitIns_C_R(instruction ins, emitAttr attr, CORINFO_FIELD_HANDLE fldHnd, regNumber reg, int offs);
327 void emitIns_C_I(instruction ins, emitAttr attr, CORINFO_FIELD_HANDLE fdlHnd, ssize_t offs, ssize_t val);
329 void emitIns_R_L(instruction ins, emitAttr attr, BasicBlock* dst, regNumber reg);
331 void emitIns_R_D(instruction ins, emitAttr attr, unsigned offs, regNumber reg);
333 void emitIns_J_R(instruction ins, emitAttr attr, BasicBlock* dst, regNumber reg);
335 void emitIns_I_AR(instruction ins, emitAttr attr, int val, regNumber reg, int offs);
337 void emitIns_R_AR(instruction ins, emitAttr attr, regNumber ireg, regNumber reg, int offs);
339 void emitIns_R_AI(instruction ins, emitAttr attr, regNumber ireg, ssize_t disp);
341 void emitIns_AR_R(instruction ins, emitAttr attr, regNumber ireg, regNumber reg, int offs);
343 void emitIns_R_ARR(instruction ins, emitAttr attr, regNumber ireg, regNumber reg, regNumber rg2, int disp);
345 void emitIns_ARR_R(instruction ins, emitAttr attr, regNumber ireg, regNumber reg, regNumber rg2, int disp);
348 instruction ins, emitAttr attr, regNumber ireg, regNumber reg, regNumber rg2, unsigned mul, int disp);
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.
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
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
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
379 VARSET_VALARG_TP ptrVars,
382 IL_OFFSETX ilOffset = BAD_IL_OFFSET,
383 regNumber ireg = REG_NA,
384 regNumber xreg = REG_NA,
389 bool isProfLeaveCB = false);
391 /*****************************************************************************
393 * Given an instrDesc, return true if it's a conditional jump.
396 inline bool emitIsCondJump(instrDesc* jmp)
398 return (jmp->idInsFmt() == IF_T2_J1) || (jmp->idInsFmt() == IF_T1_K) || (jmp->idInsFmt() == IF_LARGEJMP);
401 /*****************************************************************************
403 * Given an instrDesc, return true if it's a comapre and jump.
406 inline bool emitIsCmpJump(instrDesc* jmp)
408 return (jmp->idInsFmt() == IF_T1_I);
411 /*****************************************************************************
413 * Given a instrDesc, return true if it's an unconditional jump.
416 inline bool emitIsUncondJump(instrDesc* jmp)
418 return (jmp->idInsFmt() == IF_T2_J2) || (jmp->idInsFmt() == IF_T1_M);
421 /*****************************************************************************
423 * Given a instrDesc, return true if it's a load label instruction.
426 inline bool emitIsLoadLabel(instrDesc* jmp)
428 return (jmp->idInsFmt() == IF_T2_M1) || (jmp->idInsFmt() == IF_T1_J3) || (jmp->idInsFmt() == IF_T2_N1);
431 #endif // _TARGET_ARM_