3 ** Copyright (C) 2005-2021 Mike Pall. See Copyright Notice in luajit.h
17 #include "lj_carith.h"
19 /* -- C data arithmetic --------------------------------------------------- */
21 /* Binary operands of an operator converted to ctypes. */
22 typedef struct CDArith
{
27 /* Check arguments for arithmetic metamethods. */
28 static int carith_checkarg(lua_State
*L
, CTState
*cts
, CDArith
*ca
)
34 lj_err_argt(L
, 1, LUA_TCDATA
);
35 for (i
= 0; i
< 2; i
++, o
++) {
37 GCcdata
*cd
= cdataV(o
);
38 CTypeID id
= (CTypeID
)cd
->ctypeid
;
39 CType
*ct
= ctype_raw(cts
, id
);
40 uint8_t *p
= (uint8_t *)cdataptr(cd
);
41 if (ctype_isptr(ct
->info
)) {
42 p
= (uint8_t *)cdata_getptr(p
, ct
->size
);
43 if (ctype_isref(ct
->info
)) ct
= ctype_rawchild(cts
, ct
);
44 } else if (ctype_isfunc(ct
->info
)) {
45 p
= (uint8_t *)*(void **)p
;
47 lj_ctype_intern(cts
, CTINFO(CT_PTR
, CTALIGN_PTR
|id
), CTSIZE_PTR
));
49 if (ctype_isenum(ct
->info
)) ct
= ctype_child(cts
, ct
);
52 } else if (tvisint(o
)) {
53 ca
->ct
[i
] = ctype_get(cts
, CTID_INT32
);
54 ca
->p
[i
] = (uint8_t *)&o
->i
;
55 } else if (tvisnum(o
)) {
56 ca
->ct
[i
] = ctype_get(cts
, CTID_DOUBLE
);
57 ca
->p
[i
] = (uint8_t *)&o
->n
;
58 } else if (tvisnil(o
)) {
59 ca
->ct
[i
] = ctype_get(cts
, CTID_P_VOID
);
60 ca
->p
[i
] = (uint8_t *)0;
61 } else if (tvisstr(o
)) {
62 TValue
*o2
= i
== 0 ? o
+1 : o
-1;
63 CType
*ct
= ctype_raw(cts
, cdataV(o2
)->ctypeid
);
65 ca
->p
[i
] = (uint8_t *)strVdata(o
);
67 if (ctype_isenum(ct
->info
)) {
69 CType
*cct
= lj_ctype_getfield(cts
, ct
, strV(o
), &ofs
);
70 if (cct
&& ctype_isconstval(cct
->info
)) {
71 ca
->ct
[i
] = ctype_child(cts
, cct
);
72 ca
->p
[i
] = (uint8_t *)&cct
->size
; /* Assumes ct does not grow. */
75 ca
->ct
[1-i
] = ct
; /* Use enum to improve error message. */
82 ca
->p
[i
] = (void *)(intptr_t)1; /* To make it unequal. */
89 /* Pointer arithmetic. */
90 static int carith_ptr(lua_State
*L
, CTState
*cts
, CDArith
*ca
, MMS mm
)
92 CType
*ctp
= ca
->ct
[0];
93 uint8_t *pp
= ca
->p
[0];
98 if (ctype_isptr(ctp
->info
) || ctype_isrefarray(ctp
->info
)) {
99 if ((mm
== MM_sub
|| mm
== MM_eq
|| mm
== MM_lt
|| mm
== MM_le
) &&
100 (ctype_isptr(ca
->ct
[1]->info
) || ctype_isrefarray(ca
->ct
[1]->info
))) {
101 uint8_t *pp2
= ca
->p
[1];
102 if (mm
== MM_eq
) { /* Pointer equality. Incompatible pointers are ok. */
103 setboolV(L
->top
-1, (pp
== pp2
));
106 if (!lj_cconv_compatptr(cts
, ctp
, ca
->ct
[1], CCF_IGNQUAL
))
108 if (mm
== MM_sub
) { /* Pointer difference. */
110 sz
= lj_ctype_size(cts
, ctype_cid(ctp
->info
)); /* Element size. */
111 if (sz
== 0 || sz
== CTSIZE_INVALID
)
113 diff
= ((intptr_t)pp
- (intptr_t)pp2
) / (int32_t)sz
;
114 /* All valid pointer differences on x64 are in (-2^47, +2^47),
115 ** which fits into a double without loss of precision.
117 setintptrV(L
->top
-1, (int32_t)diff
);
119 } else if (mm
== MM_lt
) { /* Pointer comparison (unsigned). */
120 setboolV(L
->top
-1, ((uintptr_t)pp
< (uintptr_t)pp2
));
123 lua_assert(mm
== MM_le
);
124 setboolV(L
->top
-1, ((uintptr_t)pp
<= (uintptr_t)pp2
));
128 if (!((mm
== MM_add
|| mm
== MM_sub
) && ctype_isnum(ca
->ct
[1]->info
)))
130 lj_cconv_ct_ct(cts
, ctype_get(cts
, CTID_INT_PSZ
), ca
->ct
[1],
131 (uint8_t *)&idx
, ca
->p
[1], 0);
132 if (mm
== MM_sub
) idx
= -idx
;
133 } else if (mm
== MM_add
&& ctype_isnum(ctp
->info
) &&
134 (ctype_isptr(ca
->ct
[1]->info
) || ctype_isrefarray(ca
->ct
[1]->info
))) {
135 /* Swap pointer and index. */
136 ctp
= ca
->ct
[1]; pp
= ca
->p
[1];
137 lj_cconv_ct_ct(cts
, ctype_get(cts
, CTID_INT_PSZ
), ca
->ct
[0],
138 (uint8_t *)&idx
, ca
->p
[0], 0);
142 sz
= lj_ctype_size(cts
, ctype_cid(ctp
->info
)); /* Element size. */
143 if (sz
== CTSIZE_INVALID
)
145 pp
+= idx
*(int32_t)sz
; /* Compute pointer + index. */
146 id
= lj_ctype_intern(cts
, CTINFO(CT_PTR
, CTALIGN_PTR
|ctype_cid(ctp
->info
)),
148 cd
= lj_cdata_new(cts
, id
, CTSIZE_PTR
);
149 *(uint8_t **)cdataptr(cd
) = pp
;
150 setcdataV(L
, L
->top
-1, cd
);
155 /* 64 bit integer arithmetic. */
156 static int carith_int64(lua_State
*L
, CTState
*cts
, CDArith
*ca
, MMS mm
)
158 if (ctype_isnum(ca
->ct
[0]->info
) && ca
->ct
[0]->size
<= 8 &&
159 ctype_isnum(ca
->ct
[1]->info
) && ca
->ct
[1]->size
<= 8) {
160 CTypeID id
= (((ca
->ct
[0]->info
& CTF_UNSIGNED
) && ca
->ct
[0]->size
== 8) ||
161 ((ca
->ct
[1]->info
& CTF_UNSIGNED
) && ca
->ct
[1]->size
== 8)) ?
162 CTID_UINT64
: CTID_INT64
;
163 CType
*ct
= ctype_get(cts
, id
);
165 uint64_t u0
, u1
, *up
;
166 lj_cconv_ct_ct(cts
, ct
, ca
->ct
[0], (uint8_t *)&u0
, ca
->p
[0], 0);
168 lj_cconv_ct_ct(cts
, ct
, ca
->ct
[1], (uint8_t *)&u1
, ca
->p
[1], 0);
171 setboolV(L
->top
-1, (u0
== u1
));
175 id
== CTID_INT64
? ((int64_t)u0
< (int64_t)u1
) : (u0
< u1
));
179 id
== CTID_INT64
? ((int64_t)u0
<= (int64_t)u1
) : (u0
<= u1
));
183 cd
= lj_cdata_new(cts
, id
, 8);
184 up
= (uint64_t *)cdataptr(cd
);
185 setcdataV(L
, L
->top
-1, cd
);
187 case MM_add
: *up
= u0
+ u1
; break;
188 case MM_sub
: *up
= u0
- u1
; break;
189 case MM_mul
: *up
= u0
* u1
; break;
191 if (id
== CTID_INT64
)
192 *up
= (uint64_t)lj_carith_divi64((int64_t)u0
, (int64_t)u1
);
194 *up
= lj_carith_divu64(u0
, u1
);
197 if (id
== CTID_INT64
)
198 *up
= (uint64_t)lj_carith_modi64((int64_t)u0
, (int64_t)u1
);
200 *up
= lj_carith_modu64(u0
, u1
);
203 if (id
== CTID_INT64
)
204 *up
= (uint64_t)lj_carith_powi64((int64_t)u0
, (int64_t)u1
);
206 *up
= lj_carith_powu64(u0
, u1
);
208 case MM_unm
: *up
= (uint64_t)-(int64_t)u0
; break;
209 default: lua_assert(0); break;
217 /* Handle ctype arithmetic metamethods. */
218 static int lj_carith_meta(lua_State
*L
, CTState
*cts
, CDArith
*ca
, MMS mm
)
221 if (tviscdata(L
->base
)) {
222 CTypeID id
= cdataV(L
->base
)->ctypeid
;
223 CType
*ct
= ctype_raw(cts
, id
);
224 if (ctype_isptr(ct
->info
)) id
= ctype_cid(ct
->info
);
225 tv
= lj_ctype_meta(cts
, id
, mm
);
227 if (!tv
&& L
->base
+1 < L
->top
&& tviscdata(L
->base
+1)) {
228 CTypeID id
= cdataV(L
->base
+1)->ctypeid
;
229 CType
*ct
= ctype_raw(cts
, id
);
230 if (ctype_isptr(ct
->info
)) id
= ctype_cid(ct
->info
);
231 tv
= lj_ctype_meta(cts
, id
, mm
);
235 int i
, isenum
= -1, isstr
= -1;
236 if (mm
== MM_eq
) { /* Equality checks never raise an error. */
237 int eq
= ca
->p
[0] == ca
->p
[1];
238 setboolV(L
->top
-1, eq
);
239 setboolV(&G(L
)->tmptv2
, eq
); /* Remember for trace recorder. */
242 for (i
= 0; i
< 2; i
++) {
243 if (ca
->ct
[i
] && tviscdata(L
->base
+i
)) {
244 if (ctype_isenum(ca
->ct
[i
]->info
)) isenum
= i
;
245 repr
[i
] = strdata(lj_ctype_repr(L
, ctype_typeid(cts
, ca
->ct
[i
]), NULL
));
247 if (tvisstr(&L
->base
[i
])) isstr
= i
;
248 repr
[i
] = lj_typename(&L
->base
[i
]);
251 if ((isenum
^ isstr
) == 1)
252 lj_err_callerv(L
, LJ_ERR_FFI_BADCONV
, repr
[isstr
], repr
[isenum
]);
253 lj_err_callerv(L
, mm
== MM_len
? LJ_ERR_FFI_BADLEN
:
254 mm
== MM_concat
? LJ_ERR_FFI_BADCONCAT
:
255 mm
< MM_add
? LJ_ERR_FFI_BADCOMP
: LJ_ERR_FFI_BADARITH
,
258 return lj_meta_tailcall(L
, tv
);
261 /* Arithmetic operators for cdata. */
262 int lj_carith_op(lua_State
*L
, MMS mm
)
264 CTState
*cts
= ctype_cts(L
);
266 if (carith_checkarg(L
, cts
, &ca
) && mm
!= MM_len
&& mm
!= MM_concat
) {
267 if (carith_int64(L
, cts
, &ca
, mm
) || carith_ptr(L
, cts
, &ca
, mm
)) {
268 copyTV(L
, &G(L
)->tmptv2
, L
->top
-1); /* Remember for trace recorder. */
272 return lj_carith_meta(L
, cts
, &ca
, mm
);
275 /* -- 64 bit integer arithmetic helpers ----------------------------------- */
277 #if LJ_32 && LJ_HASJIT
278 /* Signed/unsigned 64 bit multiplication. */
279 int64_t lj_carith_mul64(int64_t a
, int64_t b
)
285 /* Unsigned 64 bit division. */
286 uint64_t lj_carith_divu64(uint64_t a
, uint64_t b
)
288 if (b
== 0) return U64x(80000000,00000000);
292 /* Signed 64 bit division. */
293 int64_t lj_carith_divi64(int64_t a
, int64_t b
)
295 if (b
== 0 || (a
== (int64_t)U64x(80000000,00000000) && b
== -1))
296 return U64x(80000000,00000000);
300 /* Unsigned 64 bit modulo. */
301 uint64_t lj_carith_modu64(uint64_t a
, uint64_t b
)
303 if (b
== 0) return U64x(80000000,00000000);
307 /* Signed 64 bit modulo. */
308 int64_t lj_carith_modi64(int64_t a
, int64_t b
)
310 if (b
== 0) return U64x(80000000,00000000);
311 if (a
== (int64_t)U64x(80000000,00000000) && b
== -1) return 0;
315 /* Unsigned 64 bit x^k. */
316 uint64_t lj_carith_powu64(uint64_t x
, uint64_t k
)
321 for (; (k
& 1) == 0; k
>>= 1) x
*= x
;
323 if ((k
>>= 1) != 0) {
335 /* Signed 64 bit x^k. */
336 int64_t lj_carith_powi64(int64_t x
, int64_t k
)
342 return U64x(7fffffff
,ffffffff
);
346 return (k
& 1) ? -1 : 1;
350 return (int64_t)lj_carith_powu64((uint64_t)x
, (uint64_t)k
);