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 #ifdef FEATURE_ITINSTRUCTION
24 BYTE* emitOutputIT(BYTE* dst, instruction ins, insFormat fmt, code_t condcode);
25 #endif // FEATURE_ITINSTRUCTION
27 BYTE* emitOutputLJ(insGroup* ig, BYTE* dst, instrDesc* id);
28 BYTE* emitOutputShortBranch(BYTE* dst, instruction ins, insFormat fmt, ssize_t distVal, instrDescJmp* id);
30 static unsigned emitOutput_Thumb1Instr(BYTE* dst, code_t code);
31 static unsigned emitOutput_Thumb2Instr(BYTE* dst, code_t code);
33 /************************************************************************/
34 /* Debug-only routines to display instructions */
35 /************************************************************************/
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);
53 void emitDispInsHelp(instrDesc* id,
61 void emitDispIns(instrDesc* id,
72 /************************************************************************/
73 /* Private members that deal with target-dependent instr. descriptors */
74 /************************************************************************/
77 instrDesc* emitNewInstrCallDir(
78 int argCnt, VARSET_VALARG_TP GCvars, regMaskTP gcrefRegs, regMaskTP byrefRegs, emitAttr retSize);
80 instrDesc* emitNewInstrCallInd(
81 int argCnt, ssize_t disp, VARSET_VALARG_TP GCvars, regMaskTP gcrefRegs, regMaskTP byrefRegs, emitAttr retSize);
83 /************************************************************************/
84 /* Private helpers for instruction output */
85 /************************************************************************/
88 bool emitInsIsCompare(instruction ins);
89 bool emitInsIsLoad(instruction ins);
90 bool emitInsIsStore(instruction ins);
91 bool emitInsIsLoadOrStore(instruction ins);
93 emitter::insFormat emitInsFormat(instruction ins);
94 emitter::code_t emitInsCode(instruction ins, insFormat fmt);
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);
101 static bool isModImmConst(int imm);
102 static int encodeModImmConst(int imm);
104 static int insUnscaleImm(int imm, emitAttr size);
106 /************************************************************************/
107 /* Public inline informational methods */
108 /************************************************************************/
111 inline static bool isLowRegister(regNumber reg)
113 return (reg <= REG_R7);
116 inline static bool isGeneralRegister(regNumber reg)
118 return (reg <= REG_R15);
121 inline static bool isFloatReg(regNumber reg)
123 return (reg >= REG_F0 && reg <= REG_F31);
126 inline static bool isDoubleReg(regNumber reg)
128 return isFloatReg(reg) && ((reg % 2) == 0);
131 inline static bool insSetsFlags(insFlags flags)
133 return (flags != INS_FLAGS_NOT_SET);
136 inline static bool insDoesNotSetFlags(insFlags flags)
138 return (flags != INS_FLAGS_SET);
141 inline static insFlags insMustSetFlags(insFlags flags)
143 return (flags == INS_FLAGS_SET) ? INS_FLAGS_SET : INS_FLAGS_NOT_SET;
146 inline static insFlags insMustNotSetFlags(insFlags flags)
148 return (flags == INS_FLAGS_NOT_SET) ? INS_FLAGS_NOT_SET : INS_FLAGS_SET;
151 inline static bool insOptsNone(insOpts opt)
153 return (opt == INS_OPTS_NONE);
156 inline static bool insOptAnyInc(insOpts opt)
158 return (opt == INS_OPTS_LDST_PRE_DEC) || (opt == INS_OPTS_LDST_POST_INC);
161 inline static bool insOptsPreDec(insOpts opt)
163 return (opt == INS_OPTS_LDST_PRE_DEC);
166 inline static bool insOptsPostInc(insOpts opt)
168 return (opt == INS_OPTS_LDST_POST_INC);
171 inline static bool insOptAnyShift(insOpts opt)
173 return ((opt >= INS_OPTS_RRX) && (opt <= INS_OPTS_ROR));
176 inline static bool insOptsRRX(insOpts opt)
178 return (opt == INS_OPTS_RRX);
181 inline static bool insOptsLSL(insOpts opt)
183 return (opt == INS_OPTS_LSL);
186 inline static bool insOptsLSR(insOpts opt)
188 return (opt == INS_OPTS_LSR);
191 inline static bool insOptsASR(insOpts opt)
193 return (opt == INS_OPTS_ASR);
196 inline static bool insOptsROR(insOpts opt)
198 return (opt == INS_OPTS_ROR);
201 // Returns the number of bits used by the given 'size'.
202 inline static unsigned getBitWidth(emitAttr size)
204 assert(size <= EA_8BYTE);
205 return (unsigned)size * BITS_PER_BYTE;
208 /************************************************************************/
209 /* The public entry points to output instructions */
210 /************************************************************************/
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);
222 void emitIns(instruction ins);
224 void emitIns_I(instruction ins, emitAttr attr, ssize_t imm);
226 void emitIns_R(instruction ins, emitAttr attr, regNumber reg);
228 void emitIns_R_I(instruction ins, emitAttr attr, regNumber reg, ssize_t imm, insFlags flags = INS_FLAGS_DONT_CARE);
230 void emitIns_R_R(instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, insFlags flags = INS_FLAGS_DONT_CARE);
233 instruction ins, emitAttr attr, regNumber reg1, int imm1, int imm2, insFlags flags = INS_FLAGS_DONT_CARE);
235 void emitIns_R_R_I(instruction ins,
240 insFlags flags = INS_FLAGS_DONT_CARE,
241 insOpts opt = INS_OPTS_NONE);
243 void emitIns_R_R_R(instruction ins,
248 insFlags flags = INS_FLAGS_DONT_CARE);
250 void emitIns_R_R_I_I(instruction ins,
256 insFlags flags = INS_FLAGS_DONT_CARE);
258 void emitIns_R_R_R_I(instruction ins,
264 insFlags flags = INS_FLAGS_DONT_CARE,
265 insOpts opt = INS_OPTS_NONE);
267 void emitIns_R_R_R_R(instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, regNumber reg3, regNumber reg4);
269 void emitIns_C(instruction ins, emitAttr attr, CORINFO_FIELD_HANDLE fdlHnd, int offs);
271 void emitIns_S(instruction ins, emitAttr attr, int varx, int offs);
273 void emitIns_genStackOffset(regNumber r, int varx, int offs);
275 void emitIns_S_R(instruction ins, emitAttr attr, regNumber ireg, int varx, int offs);
277 void emitIns_R_S(instruction ins, emitAttr attr, regNumber ireg, int varx, int offs);
279 void emitIns_S_I(instruction ins, emitAttr attr, int varx, int offs, int val);
281 void emitIns_R_C(instruction ins, emitAttr attr, regNumber reg, CORINFO_FIELD_HANDLE fldHnd, int offs);
283 void emitIns_C_R(instruction ins, emitAttr attr, CORINFO_FIELD_HANDLE fldHnd, regNumber reg, int offs);
285 void emitIns_C_I(instruction ins, emitAttr attr, CORINFO_FIELD_HANDLE fdlHnd, int offs, ssize_t val);
287 void emitIns_R_L(instruction ins, emitAttr attr, BasicBlock* dst, regNumber reg);
289 void emitIns_R_D(instruction ins, emitAttr attr, unsigned offs, regNumber reg);
291 void emitIns_J_R(instruction ins, emitAttr attr, BasicBlock* dst, regNumber reg);
293 void emitIns_I_AR(instruction ins, emitAttr attr, int val, regNumber reg, int offs);
295 void emitIns_R_AR(instruction ins, emitAttr attr, regNumber ireg, regNumber reg, int offs);
297 void emitIns_R_AI(instruction ins, emitAttr attr, regNumber ireg, ssize_t disp);
299 void emitIns_AR_R(instruction ins, emitAttr attr, regNumber ireg, regNumber reg, int offs);
301 void emitIns_R_ARR(instruction ins, emitAttr attr, regNumber ireg, regNumber reg, regNumber rg2, int disp);
303 void emitIns_ARR_R(instruction ins, emitAttr attr, regNumber ireg, regNumber reg, regNumber rg2, int disp);
306 instruction ins, emitAttr attr, regNumber ireg, regNumber reg, regNumber rg2, unsigned mul, int disp);
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.
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
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
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
337 VARSET_VALARG_TP ptrVars,
340 IL_OFFSETX ilOffset = BAD_IL_OFFSET,
341 regNumber ireg = REG_NA,
342 regNumber xreg = REG_NA,
347 bool isProfLeaveCB = false);
349 /*****************************************************************************
351 * Given an instrDesc, return true if it's a conditional jump.
354 inline bool emitIsCondJump(instrDesc* jmp)
356 return (jmp->idInsFmt() == IF_T2_J1) || (jmp->idInsFmt() == IF_T1_K) || (jmp->idInsFmt() == IF_LARGEJMP);
359 /*****************************************************************************
361 * Given an instrDesc, return true if it's a comapre and jump.
364 inline bool emitIsCmpJump(instrDesc* jmp)
366 return (jmp->idInsFmt() == IF_T1_I);
369 /*****************************************************************************
371 * Given a instrDesc, return true if it's an unconditional jump.
374 inline bool emitIsUncondJump(instrDesc* jmp)
376 return (jmp->idInsFmt() == IF_T2_J2) || (jmp->idInsFmt() == IF_T1_M);
379 /*****************************************************************************
381 * Given a instrDesc, return true if it's a load label instruction.
384 inline bool emitIsLoadLabel(instrDesc* jmp)
386 return (jmp->idInsFmt() == IF_T2_M1) || (jmp->idInsFmt() == IF_T1_J3) || (jmp->idInsFmt() == IF_T2_N1);
389 #endif // _TARGET_ARM_