2 ** MIPS instruction emitter.
3 ** Copyright (C) 2005-2012 Mike Pall. See Copyright Notice in luajit.h
6 /* -- Emit basic instructions --------------------------------------------- */
8 static void emit_dst(ASMState
*as
, MIPSIns mi
, Reg rd
, Reg rs
, Reg rt
)
10 *--as
->mcp
= mi
| MIPSF_D(rd
) | MIPSF_S(rs
) | MIPSF_T(rt
);
13 static void emit_dta(ASMState
*as
, MIPSIns mi
, Reg rd
, Reg rt
, uint32_t a
)
15 *--as
->mcp
= mi
| MIPSF_D(rd
) | MIPSF_T(rt
) | MIPSF_A(a
);
18 #define emit_ds(as, mi, rd, rs) emit_dst(as, (mi), (rd), (rs), 0)
19 #define emit_tg(as, mi, rt, rg) emit_dst(as, (mi), (rg)&31, 0, (rt))
21 static void emit_tsi(ASMState
*as
, MIPSIns mi
, Reg rt
, Reg rs
, int32_t i
)
23 *--as
->mcp
= mi
| MIPSF_T(rt
) | MIPSF_S(rs
) | (i
& 0xffff);
26 #define emit_ti(as, mi, rt, i) emit_tsi(as, (mi), (rt), 0, (i))
27 #define emit_hsi(as, mi, rh, rs, i) emit_tsi(as, (mi), (rh) & 31, (rs), (i))
29 static void emit_fgh(ASMState
*as
, MIPSIns mi
, Reg rf
, Reg rg
, Reg rh
)
31 *--as
->mcp
= mi
| MIPSF_F(rf
&31) | MIPSF_G(rg
&31) | MIPSF_H(rh
&31);
34 #define emit_fg(as, mi, rf, rg) emit_fgh(as, (mi), (rf), (rg), 0)
36 static void emit_rotr(ASMState
*as
, Reg dest
, Reg src
, Reg tmp
, uint32_t shift
)
38 if ((as
->flags
& JIT_F_MIPS32R2
)) {
39 emit_dta(as
, MIPSI_ROTR
, dest
, src
, shift
);
41 emit_dst(as
, MIPSI_OR
, dest
, dest
, tmp
);
42 emit_dta(as
, MIPSI_SLL
, dest
, src
, (-shift
)&31);
43 emit_dta(as
, MIPSI_SRL
, tmp
, src
, shift
);
47 /* -- Emit loads/stores --------------------------------------------------- */
49 /* Prefer rematerialization of BASE/L from global_State over spills. */
50 #define emit_canremat(ref) ((ref) <= REF_BASE)
52 /* Try to find a one step delta relative to another constant. */
53 static int emit_kdelta1(ASMState
*as
, Reg t
, int32_t i
)
55 RegSet work
= ~as
->freeset
& RSET_GPR
;
57 Reg r
= rset_picktop(work
);
58 IRRef ref
= regcost_ref(as
->cost
[r
]);
61 int32_t delta
= i
- (ra_iskref(ref
) ? ra_krefk(as
, ref
) : IR(ref
)->i
);
62 if (checki16(delta
)) {
63 emit_tsi(as
, MIPSI_ADDIU
, t
, r
, delta
);
69 return 0; /* Failed. */
72 /* Load a 32 bit constant into a GPR. */
73 static void emit_loadi(ASMState
*as
, Reg r
, int32_t i
)
76 emit_ti(as
, MIPSI_LI
, r
, i
);
79 int32_t jgl
= i32ptr(J2G(as
->J
));
80 if ((uint32_t)(i
-jgl
) < 65536) {
81 emit_tsi(as
, MIPSI_ADDIU
, r
, RID_JGL
, i
-jgl
-32768);
83 } else if (emit_kdelta1(as
, r
, i
)) {
85 } else if ((i
>> 16) == 0) {
86 emit_tsi(as
, MIPSI_ORI
, r
, RID_ZERO
, i
);
89 emit_tsi(as
, MIPSI_ORI
, r
, r
, i
);
91 emit_ti(as
, MIPSI_LUI
, r
, (i
>> 16));
95 #define emit_loada(as, r, addr) emit_loadi(as, (r), i32ptr((addr)))
97 static Reg
ra_allock(ASMState
*as
, int32_t k
, RegSet allow
);
98 static void ra_allockreg(ASMState
*as
, int32_t k
, Reg r
);
100 /* Get/set from constant pointer. */
101 static void emit_lsptr(ASMState
*as
, MIPSIns mi
, Reg r
, void *p
, RegSet allow
)
103 int32_t jgl
= i32ptr(J2G(as
->J
));
104 int32_t i
= i32ptr(p
);
106 if ((uint32_t)(i
-jgl
) < 65536) {
110 base
= ra_allock(as
, i
-(int16_t)i
, allow
);
112 emit_tsi(as
, mi
, r
, base
, i
);
115 #define emit_loadn(as, r, tv) \
116 emit_lsptr(as, MIPSI_LDC1, ((r) & 31), (void *)(tv), RSET_GPR)
118 /* Get/set global_State fields. */
119 static void emit_lsglptr(ASMState
*as
, MIPSIns mi
, Reg r
, int32_t ofs
)
121 emit_tsi(as
, mi
, r
, RID_JGL
, ofs
-32768);
124 #define emit_getgl(as, r, field) \
125 emit_lsglptr(as, MIPSI_LW, (r), (int32_t)offsetof(global_State, field))
126 #define emit_setgl(as, r, field) \
127 emit_lsglptr(as, MIPSI_SW, (r), (int32_t)offsetof(global_State, field))
129 /* Trace number is determined from per-trace exit stubs. */
130 #define emit_setvmstate(as, i) UNUSED(i)
132 /* -- Emit control-flow instructions -------------------------------------- */
134 /* Label for internal jumps. */
135 typedef MCode
*MCLabel
;
137 /* Return label pointing to current PC. */
138 #define emit_label(as) ((as)->mcp)
140 static void emit_branch(ASMState
*as
, MIPSIns mi
, Reg rs
, Reg rt
, MCode
*target
)
143 ptrdiff_t delta
= target
- p
;
144 lua_assert(((delta
+ 0x8000) >> 16) == 0);
145 *--p
= mi
| MIPSF_S(rs
) | MIPSF_T(rt
) | ((uint32_t)delta
& 0xffffu
);
149 static void emit_jmp(ASMState
*as
, MCode
*target
)
151 *--as
->mcp
= MIPSI_NOP
;
152 emit_branch(as
, MIPSI_B
, RID_ZERO
, RID_ZERO
, (target
));
155 static void emit_call(ASMState
*as
, void *target
)
159 if ((((uintptr_t)target
^ (uintptr_t)p
) >> 28) == 0)
160 *--p
= MIPSI_JAL
| (((uintptr_t)target
>>2) & 0x03ffffffu
);
161 else /* Target out of range: need indirect call. */
162 *--p
= MIPSI_JALR
| MIPSF_S(RID_CFUNCADDR
);
164 ra_allockreg(as
, i32ptr(target
), RID_CFUNCADDR
);
167 /* -- Emit generic operations --------------------------------------------- */
169 #define emit_move(as, dst, src) \
170 emit_ds(as, MIPSI_MOVE, (dst), (src))
172 /* Generic move between two regs. */
173 static void emit_movrr(ASMState
*as
, IRIns
*ir
, Reg dst
, Reg src
)
175 if (dst
< RID_MAX_GPR
)
176 emit_move(as
, dst
, src
);
178 emit_fg(as
, irt_isnum(ir
->t
) ? MIPSI_MOV_D
: MIPSI_MOV_S
, dst
, src
);
181 /* Generic load of register from stack slot. */
182 static void emit_spload(ASMState
*as
, IRIns
*ir
, Reg r
, int32_t ofs
)
185 emit_tsi(as
, MIPSI_LW
, r
, RID_SP
, ofs
);
187 emit_tsi(as
, irt_isnum(ir
->t
) ? MIPSI_LDC1
: MIPSI_LWC1
,
188 (r
& 31), RID_SP
, ofs
);
191 /* Generic store of register to stack slot. */
192 static void emit_spstore(ASMState
*as
, IRIns
*ir
, Reg r
, int32_t ofs
)
195 emit_tsi(as
, MIPSI_SW
, r
, RID_SP
, ofs
);
197 emit_tsi(as
, irt_isnum(ir
->t
) ? MIPSI_SDC1
: MIPSI_SWC1
,
198 (r
&31), RID_SP
, ofs
);
201 /* Add offset to pointer. */
202 static void emit_addptr(ASMState
*as
, Reg r
, int32_t ofs
)
205 lua_assert(checki16(ofs
));
206 emit_tsi(as
, MIPSI_ADDIU
, r
, r
, ofs
);
210 #define emit_spsub(as, ofs) emit_addptr(as, RID_SP, -(ofs))