1use inkwell::{
6 FloatPredicate, IntPredicate,
7 builder::Builder,
8 context::Context,
9 types::{FloatType, IntType},
10 values::{FloatValue, FunctionValue, IntValue, PointerValue},
11};
12use wowlab_types::numeric::EPSILON;
13
14use super::{
15 backend::RotationBackend,
16 result::{KIND_CAST, KIND_NONE, KIND_POOL, KIND_USE_ITEM, KIND_WAIT},
17};
18
19pub(crate) struct Intrinsics<'ctx> {
20 pub floor: FunctionValue<'ctx>,
21 pub ceil: FunctionValue<'ctx>,
22 pub fabs: FunctionValue<'ctx>,
23 pub minnum: FunctionValue<'ctx>,
24 pub maxnum: FunctionValue<'ctx>,
25}
26
27impl<'ctx> Intrinsics<'ctx> {
28 pub(crate) fn declare(ctx: &'ctx Context, module: &inkwell::module::Module<'ctx>) -> Self {
29 let f64_type = ctx.f64_type();
30 let unary = f64_type.fn_type(&[f64_type.into()], false);
31 let binary = f64_type.fn_type(&[f64_type.into(), f64_type.into()], false);
32
33 Self {
34 floor: module.add_function("llvm.floor.f64", unary, None),
35 ceil: module.add_function("llvm.ceil.f64", unary, None),
36 fabs: module.add_function("llvm.fabs.f64", unary, None),
37 minnum: module.add_function("llvm.minnum.f64", binary, None),
38 maxnum: module.add_function("llvm.maxnum.f64", binary, None),
39 }
40 }
41}
42
43pub(crate) struct JitBackend<'ctx, 'b> {
44 pub(crate) ctx: &'ctx Context,
45 pub(crate) builder: &'b Builder<'ctx>,
46 pub(crate) function: FunctionValue<'ctx>,
47 pub(crate) buf_param: PointerValue<'ctx>,
48 pub(crate) now_param: FloatValue<'ctx>,
49 pub(crate) i8_type: IntType<'ctx>,
50 pub(crate) i32_type: IntType<'ctx>,
51 pub(crate) i64_type: IntType<'ctx>,
52 pub(crate) f64_type: FloatType<'ctx>,
53 pub(crate) bool_type: IntType<'ctx>,
54 pub(crate) intrinsics: Intrinsics<'ctx>,
55}
56
57pub(crate) struct JitEnvironment<'ctx, 'b> {
58 pub(crate) context: &'ctx Context,
59 pub(crate) builder: &'b Builder<'ctx>,
60}
61
62pub(crate) struct JitEntry<'ctx> {
63 pub(crate) function: FunctionValue<'ctx>,
64 pub(crate) buffer: PointerValue<'ctx>,
65 pub(crate) now: FloatValue<'ctx>,
66}
67
68impl<'ctx, 'b> JitBackend<'ctx, 'b> {
69 pub(crate) fn new(
70 environment: &JitEnvironment<'ctx, 'b>,
71 entry: &JitEntry<'ctx>,
72 intrinsics: Intrinsics<'ctx>,
73 ) -> Self {
74 let JitEnvironment {
75 context: ctx,
76 builder,
77 } = environment;
78 let JitEntry {
79 function,
80 buffer: buf_param,
81 now: now_param,
82 } = entry;
83
84 Self {
85 ctx,
86 builder,
87 function: *function,
88 buf_param: *buf_param,
89 now_param: *now_param,
90 i8_type: ctx.i8_type(),
91 i32_type: ctx.i32_type(),
92 i64_type: ctx.i64_type(),
93 f64_type: ctx.f64_type(),
94 bool_type: ctx.bool_type(),
95 intrinsics,
96 }
97 }
98
99 pub(crate) fn pack_result(&self, kind: u8, action_id: u32, payload: u32) -> IntValue<'ctx> {
100 let packed = wowlab_buffer_contract::pack_eval_result(kind, action_id, payload);
101
102 self.i64_type.const_int(packed, false)
103 }
104
105 #[inline]
106 fn gep(&self, offset: usize) -> PointerValue<'ctx> {
107 let offset_val = self.i64_type.const_int(offset as u64, false);
108 unsafe {
111 self.builder
112 .build_in_bounds_gep(self.i8_type, self.buf_param, &[offset_val], "ptr")
113 .unwrap()
114 }
115 }
116
117 fn cond_return(&mut self, cond: IntValue<'ctx>, ret: IntValue<'ctx>, label: &str) {
118 let return_block = self
119 .ctx
120 .append_basic_block(self.function, &format!("ret_{label}"));
121 let cont_block = self
122 .ctx
123 .append_basic_block(self.function, &format!("after_{label}"));
124
125 self.builder
126 .build_conditional_branch(cond, return_block, cont_block)
127 .unwrap();
128 self.builder.position_at_end(return_block);
129 self.builder.build_return(Some(&ret)).unwrap();
130 self.builder.position_at_end(cont_block);
131 }
132}
133
134impl<'ctx> RotationBackend for JitBackend<'ctx, '_> {
135 type Bool = IntValue<'ctx>;
136 type Int = IntValue<'ctx>;
137 type Float = FloatValue<'ctx>;
138
139 fn const_bool(&mut self, v: bool) -> Self::Bool {
140 self.bool_type.const_int(u64::from(v), false)
141 }
142 fn const_i32(&mut self, v: i32) -> Self::Int {
143 self.i64_type
144 .const_int(u64::from_ne_bytes(i64::from(v).to_ne_bytes()), true)
145 }
146 fn const_i64(&mut self, v: i64) -> Self::Int {
147 self.i64_type
148 .const_int(u64::from_ne_bytes(v.to_ne_bytes()), true)
149 }
150 fn const_f64(&mut self, v: f64) -> Self::Float {
151 self.f64_type.const_float(v)
152 }
153
154 fn load_bool(&mut self, offset: usize) -> Self::Bool {
155 let raw = self
156 .builder
157 .build_load(self.i32_type, self.gep(offset), "bool_raw")
158 .unwrap()
159 .into_int_value();
160 let zero = self.i32_type.const_int(0, false);
161
162 self.builder
163 .build_int_compare(IntPredicate::NE, raw, zero, "bool")
164 .unwrap()
165 }
166 fn load_i32(&mut self, offset: usize) -> Self::Int {
167 let raw = self
168 .builder
169 .build_load(self.i32_type, self.gep(offset), "i32_raw")
170 .unwrap()
171 .into_int_value();
172
173 self.builder
174 .build_int_s_extend(raw, self.i64_type, "i32_to_i64")
175 .unwrap()
176 }
177 fn load_i64(&mut self, offset: usize) -> Self::Int {
178 self.builder
179 .build_load(self.i64_type, self.gep(offset), "i64")
180 .unwrap()
181 .into_int_value()
182 }
183 fn load_f64(&mut self, offset: usize) -> Self::Float {
184 self.builder
185 .build_load(self.f64_type, self.gep(offset), "f64")
186 .unwrap()
187 .into_float_value()
188 }
189
190 fn store_bool(&mut self, offset: usize, v: Self::Bool) {
191 let widened = self
192 .builder
193 .build_int_z_extend(v, self.i32_type, "bool_to_i32")
194 .unwrap();
195
196 self.builder.build_store(self.gep(offset), widened).unwrap();
197 }
198 fn store_i32(&mut self, offset: usize, v: Self::Int) {
199 let truncated = self
200 .builder
201 .build_int_truncate(v, self.i32_type, "i64_to_i32")
202 .unwrap();
203
204 self.builder
205 .build_store(self.gep(offset), truncated)
206 .unwrap();
207 }
208 fn store_f64(&mut self, offset: usize, v: Self::Float) {
209 self.builder.build_store(self.gep(offset), v).unwrap();
210 }
211
212 fn now(&mut self) -> Self::Float {
213 self.now_param
214 }
215
216 fn add_f(&mut self, a: Self::Float, b: Self::Float) -> Self::Float {
217 self.builder.build_float_add(a, b, "fadd").unwrap()
218 }
219 fn sub_f(&mut self, a: Self::Float, b: Self::Float) -> Self::Float {
220 self.builder.build_float_sub(a, b, "fsub").unwrap()
221 }
222 fn mul_f(&mut self, a: Self::Float, b: Self::Float) -> Self::Float {
223 self.builder.build_float_mul(a, b, "fmul").unwrap()
224 }
225 fn safe_div_f(&mut self, a: Self::Float, b: Self::Float) -> Self::Float {
226 let zero = self.f64_type.const_float(0.0);
227 let is_zero = self
228 .builder
229 .build_float_compare(FloatPredicate::OEQ, b, zero, "div_zero")
230 .unwrap();
231 let div = self.builder.build_float_div(a, b, "fdiv").unwrap();
232
233 self.builder
234 .build_select(is_zero, zero, div, "safe_div")
235 .unwrap()
236 .into_float_value()
237 }
238 fn true_mod_f(&mut self, a: Self::Float, b: Self::Float) -> Self::Float {
239 let zero = self.f64_type.const_float(0.0);
240 let is_zero = self
241 .builder
242 .build_float_compare(FloatPredicate::OEQ, b, zero, "mod_zero")
243 .unwrap();
244 let div = self.builder.build_float_div(a, b, "mod_div").unwrap();
245 let floored = self.floor_f(div);
246 let prod = self
247 .builder
248 .build_float_mul(b, floored, "mod_prod")
249 .unwrap();
250 let std_mod = self.builder.build_float_sub(a, prod, "mod_std").unwrap();
251 let with_b = self
252 .builder
253 .build_float_add(std_mod, b, "mod_with_b")
254 .unwrap();
255 let div2 = self.builder.build_float_div(with_b, b, "mod_div2").unwrap();
256 let floored2 = self.floor_f(div2);
257 let prod2 = self
258 .builder
259 .build_float_mul(b, floored2, "mod_prod2")
260 .unwrap();
261 let result = self.builder.build_float_sub(with_b, prod2, "mod").unwrap();
262
263 self.builder
264 .build_select(is_zero, zero, result, "true_mod")
265 .unwrap()
266 .into_float_value()
267 }
268 fn min_f(&mut self, a: Self::Float, b: Self::Float) -> Self::Float {
269 self.builder
270 .build_call(self.intrinsics.minnum, &[a.into(), b.into()], "fmin")
271 .unwrap()
272 .try_as_basic_value()
273 .left()
274 .unwrap()
275 .into_float_value()
276 }
277 fn max_f(&mut self, a: Self::Float, b: Self::Float) -> Self::Float {
278 self.builder
279 .build_call(self.intrinsics.maxnum, &[a.into(), b.into()], "fmax")
280 .unwrap()
281 .try_as_basic_value()
282 .left()
283 .unwrap()
284 .into_float_value()
285 }
286 fn floor_f(&mut self, v: Self::Float) -> Self::Float {
287 self.builder
288 .build_call(self.intrinsics.floor, &[v.into()], "floor")
289 .unwrap()
290 .try_as_basic_value()
291 .left()
292 .unwrap()
293 .into_float_value()
294 }
295 fn ceil_f(&mut self, v: Self::Float) -> Self::Float {
296 self.builder
297 .build_call(self.intrinsics.ceil, &[v.into()], "ceil")
298 .unwrap()
299 .try_as_basic_value()
300 .left()
301 .unwrap()
302 .into_float_value()
303 }
304 fn abs_f(&mut self, v: Self::Float) -> Self::Float {
305 self.builder
306 .build_call(self.intrinsics.fabs, &[v.into()], "fabs")
307 .unwrap()
308 .try_as_basic_value()
309 .left()
310 .unwrap()
311 .into_float_value()
312 }
313
314 fn cmp_gt_f(&mut self, a: Self::Float, b: Self::Float) -> Self::Bool {
315 self.builder
316 .build_float_compare(FloatPredicate::OGT, a, b, "fgt")
317 .unwrap()
318 }
319 fn cmp_gte_f(&mut self, a: Self::Float, b: Self::Float) -> Self::Bool {
320 self.builder
321 .build_float_compare(FloatPredicate::OGE, a, b, "fge")
322 .unwrap()
323 }
324 fn cmp_lt_f(&mut self, a: Self::Float, b: Self::Float) -> Self::Bool {
325 self.builder
326 .build_float_compare(FloatPredicate::OLT, a, b, "flt")
327 .unwrap()
328 }
329 fn cmp_lte_f(&mut self, a: Self::Float, b: Self::Float) -> Self::Bool {
330 self.builder
331 .build_float_compare(FloatPredicate::OLE, a, b, "fle")
332 .unwrap()
333 }
334 fn cmp_eq_f(&mut self, a: Self::Float, b: Self::Float) -> Self::Bool {
335 let diff = self.builder.build_float_sub(a, b, "eps_diff").unwrap();
336 let abs = self.abs_f(diff);
337 let eps = self.f64_type.const_float(EPSILON);
338
339 self.builder
340 .build_float_compare(FloatPredicate::OLT, abs, eps, "feq")
341 .unwrap()
342 }
343 fn cmp_ne_f(&mut self, a: Self::Float, b: Self::Float) -> Self::Bool {
344 let diff = self.builder.build_float_sub(a, b, "eps_diff").unwrap();
345 let abs = self.abs_f(diff);
346 let eps = self.f64_type.const_float(EPSILON);
347
348 self.builder
349 .build_float_compare(FloatPredicate::OGE, abs, eps, "fne")
350 .unwrap()
351 }
352 fn cmp_eq_i(&mut self, a: Self::Int, b: Self::Int) -> Self::Bool {
353 self.builder
354 .build_int_compare(IntPredicate::EQ, a, b, "ieq")
355 .unwrap()
356 }
357 fn cmp_ne_i(&mut self, a: Self::Int, b: Self::Int) -> Self::Bool {
358 self.builder
359 .build_int_compare(IntPredicate::NE, a, b, "ine")
360 .unwrap()
361 }
362 fn cmp_gt_i(&mut self, a: Self::Int, b: Self::Int) -> Self::Bool {
363 self.builder
364 .build_int_compare(IntPredicate::SGT, a, b, "igt")
365 .unwrap()
366 }
367 fn cmp_gte_i(&mut self, a: Self::Int, b: Self::Int) -> Self::Bool {
368 self.builder
369 .build_int_compare(IntPredicate::SGE, a, b, "ige")
370 .unwrap()
371 }
372 fn cmp_lt_i(&mut self, a: Self::Int, b: Self::Int) -> Self::Bool {
373 self.builder
374 .build_int_compare(IntPredicate::SLT, a, b, "ilt")
375 .unwrap()
376 }
377 fn cmp_lte_i(&mut self, a: Self::Int, b: Self::Int) -> Self::Bool {
378 self.builder
379 .build_int_compare(IntPredicate::SLE, a, b, "ile")
380 .unwrap()
381 }
382
383 fn and_b(&mut self, a: Self::Bool, b: Self::Bool) -> Self::Bool {
384 self.builder.build_and(a, b, "and").unwrap()
385 }
386 fn or_b(&mut self, a: Self::Bool, b: Self::Bool) -> Self::Bool {
387 self.builder.build_or(a, b, "or").unwrap()
388 }
389 fn not_b(&mut self, a: Self::Bool) -> Self::Bool {
390 let one = self.bool_type.const_int(1, false);
391
392 self.builder.build_xor(a, one, "not").unwrap()
393 }
394
395 fn bool_to_float(&mut self, v: Self::Bool) -> Self::Float {
396 let one = self.f64_type.const_float(1.0);
397 let zero = self.f64_type.const_float(0.0);
398
399 self.builder
400 .build_select(v, one, zero, "b2f")
401 .unwrap()
402 .into_float_value()
403 }
404 fn bool_to_int(&mut self, v: Self::Bool) -> Self::Int {
405 self.builder
406 .build_int_z_extend(v, self.i64_type, "b2i")
407 .unwrap()
408 }
409 fn int_to_float(&mut self, v: Self::Int) -> Self::Float {
410 self.builder
411 .build_signed_int_to_float(v, self.f64_type, "i2f")
412 .unwrap()
413 }
414 fn int_to_bool(&mut self, v: Self::Int) -> Self::Bool {
415 let zero = self.i64_type.const_int(0, false);
416
417 self.builder
418 .build_int_compare(IntPredicate::NE, v, zero, "i2b")
419 .unwrap()
420 }
421 fn float_to_bool(&mut self, v: Self::Float) -> Self::Bool {
422 let zero = self.f64_type.const_float(0.0);
423 self.builder
426 .build_float_compare(FloatPredicate::ONE, v, zero, "f2b")
427 .unwrap()
428 }
429 fn float_to_int(&mut self, v: Self::Float) -> Self::Int {
430 self.builder
431 .build_float_to_signed_int(v, self.i64_type, "f2i")
432 .unwrap()
433 }
434
435 fn select_f(&mut self, cond: Self::Bool, t: Self::Float, f: Self::Float) -> Self::Float {
436 self.builder
437 .build_select(cond, t, f, "sel_f")
438 .unwrap()
439 .into_float_value()
440 }
441 fn select_i(&mut self, cond: Self::Bool, t: Self::Int, f: Self::Int) -> Self::Int {
442 self.builder
443 .build_select(cond, t, f, "sel_i")
444 .unwrap()
445 .into_int_value()
446 }
447 fn select_b(&mut self, cond: Self::Bool, t: Self::Bool, f: Self::Bool) -> Self::Bool {
448 self.builder
449 .build_select(cond, t, f, "sel_b")
450 .unwrap()
451 .into_int_value()
452 }
453
454 fn return_none_if(&mut self, cond: Self::Bool) {
455 let ret = self.pack_result(KIND_NONE, 0, 0);
456
457 self.cond_return(cond, ret, "none");
458 }
459 fn return_cast_if(&mut self, cond: Self::Bool, spell_id: u32, empower_rank: u8) {
460 let ret = self.pack_result(KIND_CAST, spell_id, u32::from(empower_rank));
461
462 self.cond_return(cond, ret, "cast");
463 }
464 fn return_wait_if(&mut self, cond: Self::Bool, seconds: f32) {
465 let ret = self.pack_result(KIND_WAIT, 0, seconds.to_bits());
466
467 self.cond_return(cond, ret, "wait");
468 }
469 fn return_pool_if(&mut self, cond: Self::Bool, target: f32) {
470 let ret = self.pack_result(KIND_POOL, 0, target.to_bits());
471
472 self.cond_return(cond, ret, "pool");
473 }
474 fn return_use_item_if(&mut self, cond: Self::Bool, gear_slot: u8, empower_rank: u8) {
475 let ret = self.pack_result(KIND_USE_ITEM, u32::from(gear_slot), u32::from(empower_rank));
476
477 self.cond_return(cond, ret, "use_item");
478 }
479 fn return_none(&mut self) {
480 let ret = self.pack_result(KIND_NONE, 0, 0);
481
482 self.builder.build_return(Some(&ret)).unwrap();
483 }
484}