1use cranelift_codegen::ir::condcodes::IntCC;
2use cranelift_codegen::ir::immediates::Offset32;
3use cranelift_codegen::ir::types;
4use cranelift_codegen::ir::{self as clif_ir, InstBuilder, MemFlags};
5use cranelift_frontend::FunctionBuilder;
6use std::collections::HashMap;
7
8use crate::{
9 block::Terminator,
10 instructions::{CallTarget, ContextVariable, Instruction, Size, StorageKey},
11 types::Type,
12 values::{Constant, Value, VarId},
13 IrError, Result,
14};
15use cranelift_frontend::Variable;
16
17pub fn lower_instruction(
18 inst: &Instruction,
19 _variables: &HashMap<VarId, Variable>,
20 ssa_values: &mut HashMap<Value, clif_ir::Value>,
21 builder: &mut FunctionBuilder,
22) -> Result<()> {
23 match inst {
24 Instruction::Add {
25 result,
26 left,
27 right,
28 ..
29 } => {
30 let left = ssa_values.get(left).unwrap();
31 let right = ssa_values.get(right).unwrap();
32 let res = builder.ins().iadd(*left, *right);
33 ssa_values.insert(result.clone(), res);
34 }
35 Instruction::Sub {
36 result,
37 left,
38 right,
39 ..
40 } => {
41 let left = ssa_values.get(left).unwrap();
42 let right = ssa_values.get(right).unwrap();
43 let res = builder.ins().isub(*left, *right);
44 ssa_values.insert(result.clone(), res);
45 }
46 Instruction::Mul {
47 result,
48 left,
49 right,
50 ..
51 } => {
52 let left = ssa_values.get(left).unwrap();
53 let right = ssa_values.get(right).unwrap();
54 let res = builder.ins().imul(*left, *right);
55 ssa_values.insert(result.clone(), res);
56 }
57 Instruction::Div {
58 result,
59 left,
60 right,
61 ..
62 } => {
63 let left = ssa_values.get(left).unwrap();
64 let right = ssa_values.get(right).unwrap();
65 let res = builder.ins().udiv(*left, *right);
66 ssa_values.insert(result.clone(), res);
67 }
68 Instruction::Mod {
69 result,
70 left,
71 right,
72 ..
73 } => {
74 let left = ssa_values.get(left).unwrap();
75 let right = ssa_values.get(right).unwrap();
76 let res = builder.ins().urem(*left, *right);
77 ssa_values.insert(result.clone(), res);
78 }
79 Instruction::Eq {
80 result,
81 left,
82 right,
83 } => {
84 let left = ssa_values.get(left).unwrap();
85 let right = ssa_values.get(right).unwrap();
86 let res = builder.ins().icmp(IntCC::Equal, *left, *right);
87 ssa_values.insert(result.clone(), res);
88 }
89 Instruction::Ne {
90 result,
91 left,
92 right,
93 } => {
94 let left = ssa_values.get(left).unwrap();
95 let right = ssa_values.get(right).unwrap();
96 let res = builder.ins().icmp(IntCC::NotEqual, *left, *right);
97 ssa_values.insert(result.clone(), res);
98 }
99 Instruction::Lt {
100 result,
101 left,
102 right,
103 } => {
104 let left = ssa_values.get(left).unwrap();
105 let right = ssa_values.get(right).unwrap();
106 let res = builder.ins().icmp(IntCC::SignedLessThan, *left, *right);
107 ssa_values.insert(result.clone(), res);
108 }
109 Instruction::Gt {
110 result,
111 left,
112 right,
113 } => {
114 let left = ssa_values.get(left).unwrap();
115 let right = ssa_values.get(right).unwrap();
116 let res = builder.ins().icmp(IntCC::SignedGreaterThan, *left, *right);
117 ssa_values.insert(result.clone(), res);
118 }
119 Instruction::Le {
120 result,
121 left,
122 right,
123 } => {
124 let left = ssa_values.get(left).unwrap();
125 let right = ssa_values.get(right).unwrap();
126 let res = builder
127 .ins()
128 .icmp(IntCC::SignedLessThanOrEqual, *left, *right);
129 ssa_values.insert(result.clone(), res);
130 }
131 Instruction::Ge {
132 result,
133 left,
134 right,
135 } => {
136 let left = ssa_values.get(left).unwrap();
137 let right = ssa_values.get(right).unwrap();
138 let res = builder
139 .ins()
140 .icmp(IntCC::SignedGreaterThanOrEqual, *left, *right);
141 ssa_values.insert(result.clone(), res);
142 }
143 Instruction::Select {
144 result,
145 condition,
146 then_val,
147 else_val,
148 } => {
149 let cond = ssa_values.get(condition).unwrap();
150 let then_v = ssa_values.get(then_val).unwrap();
151 let else_v = ssa_values.get(else_val).unwrap();
152 let res = builder.ins().select(*cond, *then_v, *else_v);
153 ssa_values.insert(result.clone(), res);
154 }
155
156 Instruction::And {
157 result,
158 left,
159 right,
160 } => {
161 let left = ssa_values.get(left).unwrap();
162 let right = ssa_values.get(right).unwrap();
163 let res = builder.ins().band(*left, *right);
164 ssa_values.insert(result.clone(), res);
165 }
166 Instruction::Or {
167 result,
168 left,
169 right,
170 } => {
171 let left = ssa_values.get(left).unwrap();
172 let right = ssa_values.get(right).unwrap();
173 let res = builder.ins().bor(*left, *right);
174 ssa_values.insert(result.clone(), res);
175 }
176 Instruction::Xor {
177 result,
178 left,
179 right,
180 } => {
181 let left = ssa_values.get(left).unwrap();
182 let right = ssa_values.get(right).unwrap();
183 let res = builder.ins().bxor(*left, *right);
184 ssa_values.insert(result.clone(), res);
185 }
186 Instruction::Not { result, operand } => {
187 let operand = ssa_values.get(operand).unwrap();
188 let res = builder.ins().bnot(*operand);
189 ssa_values.insert(result.clone(), res);
190 }
191 Instruction::Shl {
192 result,
193 value,
194 shift,
195 } => {
196 let value = ssa_values.get(value).unwrap();
197 let shift = ssa_values.get(shift).unwrap();
198 let res = builder.ins().ishl(*value, *shift);
199 ssa_values.insert(result.clone(), res);
200 }
201 Instruction::Shr {
202 result,
203 value,
204 shift,
205 } => {
206 let value = ssa_values.get(value).unwrap();
207 let shift = ssa_values.get(shift).unwrap();
208 let res = builder.ins().ushr(*value, *shift);
209 ssa_values.insert(result.clone(), res);
210 }
211 Instruction::Sar {
212 result,
213 value,
214 shift,
215 } => {
216 let value = ssa_values.get(value).unwrap();
217 let shift = ssa_values.get(shift).unwrap();
218 let res = builder.ins().sshr(*value, *shift);
219 ssa_values.insert(result.clone(), res);
220 }
221
222 Instruction::Pow { result, base, exp } => {
223 let base = ssa_values.get(base).unwrap();
224 let exp = ssa_values.get(exp).unwrap();
225 let res = emit_runtime_call(builder, 0, 0, &[*base, *exp])?;
226 ssa_values.insert(result.clone(), res);
227 }
228
229 Instruction::CheckedAdd {
230 result,
231 left,
232 right,
233 ..
234 } => {
235 let left = ssa_values.get(left).unwrap();
236 let right = ssa_values.get(right).unwrap();
237 let (res, overflow) = builder.ins().sadd_overflow(*left, *right);
238
239 let overflow_block = builder.create_block();
240 let continue_block = builder.create_block();
241
242 builder
243 .ins()
244 .brif(overflow, overflow_block, &[], continue_block, &[]);
245
246 builder.switch_to_block(overflow_block);
247 builder.ins().trap(clif_ir::TrapCode::INTEGER_OVERFLOW);
248
249 builder.switch_to_block(continue_block);
250 ssa_values.insert(result.clone(), res);
251 }
252 Instruction::CheckedSub {
253 result,
254 left,
255 right,
256 ..
257 } => {
258 let left = ssa_values.get(left).unwrap();
259 let right = ssa_values.get(right).unwrap();
260 let (res, overflow) = builder.ins().ssub_overflow(*left, *right);
261
262 let overflow_block = builder.create_block();
263 let continue_block = builder.create_block();
264
265 builder
266 .ins()
267 .brif(overflow, overflow_block, &[], continue_block, &[]);
268
269 builder.switch_to_block(overflow_block);
270 builder.ins().trap(clif_ir::TrapCode::INTEGER_OVERFLOW);
271
272 builder.switch_to_block(continue_block);
273 ssa_values.insert(result.clone(), res);
274 }
275 Instruction::CheckedMul {
276 result,
277 left,
278 right,
279 ..
280 } => {
281 let left = ssa_values.get(left).unwrap();
282 let right = ssa_values.get(right).unwrap();
283 let (res, overflow) = builder.ins().smul_overflow(*left, *right);
284
285 let overflow_block = builder.create_block();
286 let continue_block = builder.create_block();
287
288 builder
289 .ins()
290 .brif(overflow, overflow_block, &[], continue_block, &[]);
291
292 builder.switch_to_block(overflow_block);
293 builder.ins().trap(clif_ir::TrapCode::INTEGER_OVERFLOW);
294
295 builder.switch_to_block(continue_block);
296 ssa_values.insert(result.clone(), res);
297 }
298
299 Instruction::Load { result, location } => {
300 let addr = get_location_address(location, ssa_values, builder)?;
301 let res = builder
302 .ins()
303 .load(types::I128, MemFlags::trusted(), addr, Offset32::new(0));
304 ssa_values.insert(result.clone(), res);
305 }
306 Instruction::Store { location, value } => {
307 let addr = get_location_address(location, ssa_values, builder)?;
308 let value = ssa_values.get(value).unwrap();
309 builder
310 .ins()
311 .store(MemFlags::trusted(), *value, addr, Offset32::new(0));
312 }
313 Instruction::Allocate {
314 result,
315 ty: _,
316 size,
317 } => {
318 let size_val = match size {
319 Size::Static(s) => builder.ins().iconst(types::I64, *s as i64),
320 Size::Dynamic(v) => *ssa_values.get(v).unwrap(),
321 };
322 let res = emit_runtime_call(builder, 0, 1, &[size_val])?;
323 ssa_values.insert(result.clone(), res);
324 }
325 Instruction::Copy { dest, src, size } => {
326 let dest_addr = get_location_address(dest, ssa_values, builder)?;
327 let src_addr = get_location_address(src, ssa_values, builder)?;
328 let size = ssa_values.get(size).unwrap();
329 emit_runtime_call_void(builder, 0, 2, &[dest_addr, src_addr, *size])?;
330 }
331
332 Instruction::StorageLoad { result, key } => {
333 let key_val = get_storage_key_value(key, ssa_values, builder)?;
334 let res = emit_runtime_call(builder, 1, 0, &[key_val])?;
335 ssa_values.insert(result.clone(), res);
336 }
337 Instruction::StorageStore { key, value } => {
338 let key_val = get_storage_key_value(key, ssa_values, builder)?;
339 let value = ssa_values.get(value).unwrap();
340 emit_runtime_call_void(builder, 1, 1, &[key_val, *value])?;
341 }
342 Instruction::StorageDelete { key } => {
343 let key_val = get_storage_key_value(key, ssa_values, builder)?;
344 emit_runtime_call_void(builder, 1, 2, &[key_val])?;
345 }
346
347 Instruction::MappingLoad {
348 result,
349 mapping,
350 key,
351 } => {
352 let mapping = ssa_values.get(mapping).unwrap();
353 let key = ssa_values.get(key).unwrap();
354 let res = emit_runtime_call(builder, 2, 0, &[*mapping, *key])?;
355 ssa_values.insert(result.clone(), res);
356 }
357 Instruction::MappingStore {
358 mapping,
359 key,
360 value,
361 } => {
362 let mapping = ssa_values.get(mapping).unwrap();
363 let key = ssa_values.get(key).unwrap();
364 let value = ssa_values.get(value).unwrap();
365 emit_runtime_call_void(builder, 2, 1, &[*mapping, *key, *value])?;
366 }
367
368 Instruction::ArrayLoad {
369 result,
370 array,
371 index,
372 } => {
373 let array = ssa_values.get(array).unwrap();
374 let index = ssa_values.get(index).unwrap();
375 let element_size = builder.ins().iconst(types::I64, 32);
376 let offset = builder.ins().imul(*index, element_size);
377 let addr = builder.ins().iadd(*array, offset);
378 let res = builder
379 .ins()
380 .load(types::I128, MemFlags::trusted(), addr, Offset32::new(0));
381 ssa_values.insert(result.clone(), res);
382 }
383 Instruction::ArrayStore {
384 array,
385 index,
386 value,
387 } => {
388 let array = ssa_values.get(array).unwrap();
389 let index = ssa_values.get(index).unwrap();
390 let value = ssa_values.get(value).unwrap();
391 let element_size = builder.ins().iconst(types::I64, 32);
392 let offset = builder.ins().imul(*index, element_size);
393 let addr = builder.ins().iadd(*array, offset);
394 builder
395 .ins()
396 .store(MemFlags::trusted(), *value, addr, Offset32::new(0));
397 }
398 Instruction::ArrayLength { result, array } => {
399 let array = ssa_values.get(array).unwrap();
400 let offset = builder.ins().iconst(types::I64, -32);
401 let len_addr = builder.ins().iadd(*array, offset);
402 let res =
403 builder
404 .ins()
405 .load(types::I64, MemFlags::trusted(), len_addr, Offset32::new(0));
406 ssa_values.insert(result.clone(), res);
407 }
408 Instruction::ArrayPush { array, value } => {
409 let array = ssa_values.get(array).unwrap();
410 let value = ssa_values.get(value).unwrap();
411 emit_runtime_call_void(builder, 3, 0, &[*array, *value])?;
412 }
413 Instruction::ArrayPop { result, array } => {
414 let array = ssa_values.get(array).unwrap();
415 let res = emit_runtime_call(builder, 3, 1, &[*array])?;
416 ssa_values.insert(result.clone(), res);
417 }
418
419 Instruction::Call {
420 result,
421 target,
422 args,
423 value,
424 } => {
425 let args_vals: Vec<_> = args
426 .iter()
427 .map(|arg| *ssa_values.get(arg).unwrap())
428 .collect();
429 let value_val = value.as_ref().map(|v| *ssa_values.get(v).unwrap());
430 let res = emit_call(builder, target, &args_vals, value_val)?;
431 ssa_values.insert(result.clone(), res);
432 }
433 Instruction::DelegateCall {
434 result,
435 target,
436 selector: _,
437 args,
438 } => {
439 let target = ssa_values.get(target).unwrap();
440 let args_vals: Vec<_> = args
441 .iter()
442 .map(|arg| *ssa_values.get(arg).unwrap())
443 .collect();
444 let mut all_args = vec![*target];
445 all_args.extend(args_vals);
446 let res = emit_runtime_call(builder, 6, 1, &all_args)?;
447 ssa_values.insert(result.clone(), res);
448 }
449 Instruction::StaticCall {
450 result,
451 target,
452 selector: _,
453 args,
454 } => {
455 let target = ssa_values.get(target).unwrap();
456 let args_vals: Vec<_> = args
457 .iter()
458 .map(|arg| *ssa_values.get(arg).unwrap())
459 .collect();
460 let mut all_args = vec![*target];
461 all_args.extend(args_vals);
462 let res = emit_runtime_call(builder, 6, 2, &all_args)?;
463 ssa_values.insert(result.clone(), res);
464 }
465
466 Instruction::Create {
467 result,
468 code,
469 value,
470 } => {
471 let code = ssa_values.get(code).unwrap();
472 let value = ssa_values.get(value).unwrap();
473 let res = emit_runtime_call(builder, 8, 0, &[*code, *value])?;
474 ssa_values.insert(result.clone(), res);
475 }
476 Instruction::Create2 {
477 result,
478 code,
479 salt,
480 value,
481 } => {
482 let code = ssa_values.get(code).unwrap();
483 let salt = ssa_values.get(salt).unwrap();
484 let value = ssa_values.get(value).unwrap();
485 let res = emit_runtime_call(builder, 8, 1, &[*code, *salt, *value])?;
486 ssa_values.insert(result.clone(), res);
487 }
488
489 Instruction::Selfdestruct { beneficiary } => {
490 let beneficiary = ssa_values.get(beneficiary).unwrap();
491 emit_runtime_call_void(builder, 9, 0, &[*beneficiary])?;
492 }
493
494 Instruction::GetContext { result, var } => {
495 let res = emit_get_context(builder, *var)?;
496 ssa_values.insert(result.clone(), res);
497 }
498 Instruction::GetBalance { result, address } => {
499 let address = ssa_values.get(address).unwrap();
500 let res = emit_runtime_call(builder, 10, 0, &[*address])?;
501 ssa_values.insert(result.clone(), res);
502 }
503 Instruction::GetCode { result, address } => {
504 let address = ssa_values.get(address).unwrap();
505 let res = emit_runtime_call(builder, 10, 1, &[*address])?;
506 ssa_values.insert(result.clone(), res);
507 }
508 Instruction::GetCodeSize { result, address } => {
509 let address = ssa_values.get(address).unwrap();
510 let res = emit_runtime_call(builder, 10, 2, &[*address])?;
511 ssa_values.insert(result.clone(), res);
512 }
513 Instruction::GetCodeHash { result, address } => {
514 let address = ssa_values.get(address).unwrap();
515 let res = emit_runtime_call(builder, 10, 3, &[*address])?;
516 ssa_values.insert(result.clone(), res);
517 }
518
519 Instruction::Keccak256 { result, data, len } => {
520 let data = ssa_values.get(data).unwrap();
521 let len = ssa_values.get(len).unwrap();
522 let res = emit_runtime_call(builder, 11, 0, &[*data, *len])?;
523 ssa_values.insert(result.clone(), res);
524 }
525 Instruction::Sha256 { result, data, len } => {
526 let data = ssa_values.get(data).unwrap();
527 let len = ssa_values.get(len).unwrap();
528 let res = emit_runtime_call(builder, 11, 1, &[*data, *len])?;
529 ssa_values.insert(result.clone(), res);
530 }
531 Instruction::Ripemd160 { result, data, len } => {
532 let data = ssa_values.get(data).unwrap();
533 let len = ssa_values.get(len).unwrap();
534 let res = emit_runtime_call(builder, 11, 2, &[*data, *len])?;
535 ssa_values.insert(result.clone(), res);
536 }
537 Instruction::EcRecover {
538 result,
539 hash,
540 v,
541 r,
542 s,
543 } => {
544 let hash = ssa_values.get(hash).unwrap();
545 let v = ssa_values.get(v).unwrap();
546 let r = ssa_values.get(r).unwrap();
547 let s = ssa_values.get(s).unwrap();
548 let res = emit_runtime_call(builder, 11, 3, &[*hash, *v, *r, *s])?;
549 ssa_values.insert(result.clone(), res);
550 }
551
552 Instruction::EmitEvent {
553 event,
554 topics,
555 data,
556 } => {
557 let topics_vals: Vec<_> = topics.iter().map(|t| *ssa_values.get(t).unwrap()).collect();
558 let data_vals: Vec<_> = data.iter().map(|d| *ssa_values.get(d).unwrap()).collect();
559 emit_event(builder, *event, &topics_vals, &data_vals)?;
560 }
561
562 Instruction::Cast { result, value, to } => {
563 let value = ssa_values.get(value).unwrap();
564 let clif_type = convert_type(to)?;
565 let res = builder.ins().bitcast(clif_type, MemFlags::new(), *value);
566 ssa_values.insert(result.clone(), res);
567 }
568 Instruction::ZeroExtend { result, value, to } => {
569 let value = ssa_values.get(value).unwrap();
570 let clif_type = convert_type(to)?;
571 let res = builder.ins().uextend(clif_type, *value);
572 ssa_values.insert(result.clone(), res);
573 }
574 Instruction::SignExtend { result, value, to } => {
575 let value = ssa_values.get(value).unwrap();
576 let clif_type = convert_type(to)?;
577 let res = builder.ins().sextend(clif_type, *value);
578 ssa_values.insert(result.clone(), res);
579 }
580 Instruction::Truncate { result, value, to } => {
581 let value = ssa_values.get(value).unwrap();
582 let clif_type = convert_type(to)?;
583 let res = builder.ins().ireduce(clif_type, *value);
584 ssa_values.insert(result.clone(), res);
585 }
586
587 Instruction::Assert {
588 condition,
589 message: _,
590 } => {
591 let cond = ssa_values.get(condition).unwrap();
592 let trap_block = builder.create_block();
593 let continue_block = builder.create_block();
594
595 builder
596 .ins()
597 .brif(*cond, continue_block, &[], trap_block, &[]);
598
599 builder.switch_to_block(trap_block);
600 builder.ins().trap(clif_ir::TrapCode::unwrap_user(1));
601
602 builder.switch_to_block(continue_block);
603 }
604 Instruction::Require {
605 condition,
606 message: _,
607 } => {
608 let cond = ssa_values.get(condition).unwrap();
609 let trap_block = builder.create_block();
610 let continue_block = builder.create_block();
611
612 builder
613 .ins()
614 .brif(*cond, continue_block, &[], trap_block, &[]);
615
616 builder.switch_to_block(trap_block);
617 builder.ins().trap(clif_ir::TrapCode::unwrap_user(2));
618
619 builder.switch_to_block(continue_block);
620 }
621
622 Instruction::CheckedDiv {
623 result,
624 left,
625 right,
626 ty,
627 } => {
628 let left = ssa_values.get(left).unwrap();
629 let right = ssa_values.get(right).unwrap();
630
631 let zero = builder.ins().iconst(convert_type(ty)?, 0);
632 let is_zero = builder.ins().icmp(IntCC::Equal, *right, zero);
633 builder
634 .ins()
635 .trapnz(is_zero, clif_ir::TrapCode::unwrap_user(10));
636
637 let res = builder.ins().udiv(*left, *right);
638 ssa_values.insert(result.clone(), res);
639 }
640
641 Instruction::Jump { target: _, args: _ } => {}
642 Instruction::Branch {
643 condition: _,
644 then_block: _,
645 else_block: _,
646 then_args: _,
647 else_args: _,
648 } => {}
649 Instruction::Return { value: _ } => {}
650 Instruction::Revert { message: _ } => {
651 builder.ins().trap(clif_ir::TrapCode::unwrap_user(0));
652 }
653
654 Instruction::MemoryAlloc { result, size } => {
655 let size = ssa_values.get(size).unwrap();
656 let res = emit_runtime_call(builder, 20, 1, &[*size])?;
657 ssa_values.insert(result.clone(), res);
658 }
659 Instruction::MemoryCopy { dest, src, size } => {
660 let dest = ssa_values.get(dest).unwrap();
661 let src = ssa_values.get(src).unwrap();
662 let size = ssa_values.get(size).unwrap();
663 emit_runtime_call(builder, 21, 3, &[*dest, *src, *size])?;
664 }
665 Instruction::MemorySize { result } => {
666 let res = emit_runtime_call(builder, 22, 0, &[])?;
667 ssa_values.insert(result.clone(), res);
668 }
669
670 Instruction::Assign { result, value } => {
671 let value = ssa_values.get(value).unwrap();
672 ssa_values.insert(result.clone(), *value);
673 }
674 Instruction::Phi { result, values } => {
675 if let Some((_, first_val)) = values.first() {
676 let val = ssa_values.get(first_val).unwrap();
677 ssa_values.insert(result.clone(), *val);
678 }
679 }
680 }
681 Ok(())
682}
683
684pub fn lower_terminator(
685 term: &Terminator,
686 ssa_values: &HashMap<Value, clif_ir::Value>,
687 builder: &mut FunctionBuilder,
688 block_map: &std::collections::HashMap<crate::block::BlockId, clif_ir::Block>,
689) -> Result<()> {
690 match term {
691 Terminator::Jump(block_id, ..) => {
692 let block = block_map.get(block_id).unwrap();
693 builder.ins().jump(*block, &[]);
694 }
695 Terminator::Branch {
696 condition,
697 then_block,
698 else_block,
699 ..
700 } => {
701 let cond = ssa_values.get(condition).unwrap();
702 let then_dest = block_map.get(then_block).unwrap();
703 let else_dest = block_map.get(else_block).unwrap();
704 builder.ins().brif(*cond, *then_dest, &[], *else_dest, &[]);
705 }
706 Terminator::Return(value) => {
707 let return_value = value.as_ref().and_then(|v| ssa_values.get(v));
708 if let Some(val) = return_value {
709 builder.ins().return_(&[*val]);
710 } else {
711 builder.ins().return_(&[]);
712 }
713 }
714 Terminator::Switch {
715 value,
716 cases,
717 default,
718 } => {
719 let value = ssa_values.get(value).unwrap();
720 let default_block = block_map.get(default).unwrap();
721
722 let mut next_block = None;
723 for (case_val, case_block_id) in cases.iter().rev() {
724 let case_block = block_map.get(case_block_id).unwrap();
725
726 let case_value = match case_val.as_constant() {
727 Some(Constant::Uint(val, _)) => {
728 let bytes = val.to_bytes_le();
729 let mut result = 0u128;
730 for (i, &byte) in bytes.iter().enumerate().take(16) {
731 result |= (byte as u128) << (i * 8);
732 }
733 result as i64
734 }
735 Some(Constant::Int(val, _)) => {
736 use num_traits::cast::ToPrimitive;
737 val.to_i64().unwrap_or(0)
738 }
739 _ => 0,
740 };
741
742 let case_const = if case_value as i64 == case_value {
743 builder.ins().iconst(types::I64, case_value)
744 } else {
745 builder.ins().iconst(types::I64, case_value)
746 };
747 let case_const = builder.ins().sextend(types::I128, case_const);
748 let cmp = builder.ins().icmp(IntCC::Equal, *value, case_const);
749
750 if let Some(nb) = next_block {
751 builder.ins().brif(cmp, *case_block, &[], nb, &[]);
752 } else {
753 builder
754 .ins()
755 .brif(cmp, *case_block, &[], *default_block, &[]);
756 }
757 next_block = Some(*case_block);
758 }
759
760 if next_block.is_none() {
761 builder.ins().jump(*default_block, &[]);
762 }
763 }
764 Terminator::Revert(_msg) => {
765 builder.ins().trap(clif_ir::TrapCode::unwrap_user(3));
766 }
767 Terminator::Panic(_msg) => {
768 builder.ins().trap(clif_ir::TrapCode::unwrap_user(4));
769 }
770 Terminator::Invalid => {
771 builder.ins().trap(clif_ir::TrapCode::unwrap_user(5));
772 }
773 }
774 Ok(())
775}
776
777fn convert_type(ty: &Type) -> Result<types::Type> {
778 match ty {
779 Type::Bool => Ok(types::I8),
780 Type::Uint(8) => Ok(types::I8),
781 Type::Uint(16) => Ok(types::I16),
782 Type::Uint(32) => Ok(types::I32),
783 Type::Uint(64) => Ok(types::I64),
784 Type::Uint(128) => Ok(types::I128),
785 Type::Uint(256) => Ok(types::I128),
786 Type::Int(8) => Ok(types::I8),
787 Type::Int(16) => Ok(types::I16),
788 Type::Int(32) => Ok(types::I32),
789 Type::Int(64) => Ok(types::I64),
790 Type::Int(128) => Ok(types::I128),
791 Type::Int(256) => Ok(types::I128),
792 Type::Address => Ok(types::I128),
793 Type::Bytes4 => Ok(types::I32),
794 Type::Bytes20 => Ok(types::I128),
795 Type::Bytes32 => Ok(types::I128),
796 Type::Bytes(n) if *n <= 32 => Ok(types::I128),
797 _ => Err(IrError::TypeError(format!(
798 "Cannot convert type {:?} to Cranelift",
799 ty
800 ))),
801 }
802}
803
804fn get_location_address(
805 location: &crate::values::Location,
806 ssa_values: &HashMap<Value, clif_ir::Value>,
807 builder: &mut FunctionBuilder,
808) -> Result<clif_ir::Value> {
809 use crate::values::Location;
810 match location {
811 Location::Memory { base, offset } => {
812 let base_val = ssa_values
813 .get(base)
814 .ok_or_else(|| IrError::InvalidInstruction("Base value not found".into()))?;
815 let offset_val = ssa_values
816 .get(offset)
817 .ok_or_else(|| IrError::InvalidInstruction("Offset value not found".into()))?;
818 Ok(builder.ins().iadd(*base_val, *offset_val))
819 }
820 Location::Storage { .. }
821 | Location::Stack { .. }
822 | Location::Calldata { .. }
823 | Location::ReturnData { .. } => Err(IrError::InvalidInstruction(
824 "Unsupported location type in memory operation".into(),
825 )),
826 }
827}
828
829fn get_storage_key_value(
830 key: &StorageKey,
831 ssa_values: &HashMap<Value, clif_ir::Value>,
832 builder: &mut FunctionBuilder,
833) -> Result<clif_ir::Value> {
834 match key {
835 StorageKey::Slot(slot) => {
836 let bytes = slot.to_bytes_le();
837 let mut result = 0u128;
838 for (i, &byte) in bytes.iter().enumerate().take(16) {
839 result |= (byte as u128) << (i * 8);
840 }
841 let slot_val = result as i64;
842 let val = builder.ins().iconst(types::I64, slot_val);
843 Ok(builder.ins().uextend(types::I128, val))
844 }
845 StorageKey::Dynamic(val) => ssa_values
846 .get(val)
847 .copied()
848 .ok_or_else(|| IrError::InvalidInstruction("Dynamic key value not found".into())),
849 StorageKey::Computed(val) => ssa_values
850 .get(val)
851 .copied()
852 .ok_or_else(|| IrError::InvalidInstruction("Computed key value not found".into())),
853 StorageKey::MappingKey { base, key } => {
854 let bytes = base.to_bytes_le();
855 let mut result = 0u128;
856 for (i, &byte) in bytes.iter().enumerate().take(16) {
857 result |= (byte as u128) << (i * 8);
858 }
859 let base_val = result as i64;
860 let base_const_64 = builder.ins().iconst(types::I64, base_val);
861 let base_const = builder.ins().uextend(types::I128, base_const_64);
862 let key_val = ssa_values
863 .get(key)
864 .ok_or_else(|| IrError::InvalidInstruction("Mapping key not found".into()))?;
865
866 emit_runtime_call(builder, 11, 0, &[*key_val, base_const])
867 }
868 StorageKey::ArrayElement { base, index } => {
869 let bytes = base.to_bytes_le();
870 let mut result = 0u128;
871 for (i, &byte) in bytes.iter().enumerate().take(16) {
872 result |= (byte as u128) << (i * 8);
873 }
874 let base_val = result as i64;
875 let base_const_64 = builder.ins().iconst(types::I64, base_val);
876 let base_const = builder.ins().uextend(types::I128, base_const_64);
877 let index_val = ssa_values
878 .get(index)
879 .ok_or_else(|| IrError::InvalidInstruction("Array index not found".into()))?;
880 Ok(builder.ins().iadd(base_const, *index_val))
881 }
882 }
883}
884
885fn emit_runtime_call(
886 builder: &mut FunctionBuilder,
887 namespace: u32,
888 index: u32,
889 args: &[clif_ir::Value],
890) -> Result<clif_ir::Value> {
891 let sig = builder
892 .func
893 .import_signature(cranelift_codegen::ir::Signature {
894 params: args
895 .iter()
896 .map(|_| cranelift_codegen::ir::AbiParam::new(types::I128))
897 .collect(),
898 returns: vec![cranelift_codegen::ir::AbiParam::new(types::I128)],
899 call_conv: cranelift_codegen::isa::CallConv::SystemV,
900 });
901
902 let user_ref = builder
903 .func
904 .declare_imported_user_function(clif_ir::UserExternalName { namespace, index });
905
906 let func_ref = builder
907 .func
908 .import_function(cranelift_codegen::ir::ExtFuncData {
909 name: cranelift_codegen::ir::ExternalName::user(user_ref),
910 signature: sig,
911 colocated: false,
912 });
913
914 let call = builder.ins().call(func_ref, args);
915 Ok(builder.inst_results(call)[0])
916}
917
918fn emit_runtime_call_void(
919 builder: &mut FunctionBuilder,
920 namespace: u32,
921 index: u32,
922 args: &[clif_ir::Value],
923) -> Result<()> {
924 let sig = builder
925 .func
926 .import_signature(cranelift_codegen::ir::Signature {
927 params: args
928 .iter()
929 .map(|_| cranelift_codegen::ir::AbiParam::new(types::I128))
930 .collect(),
931 returns: vec![],
932 call_conv: cranelift_codegen::isa::CallConv::SystemV,
933 });
934
935 let user_ref = builder
936 .func
937 .declare_imported_user_function(clif_ir::UserExternalName { namespace, index });
938
939 let func_ref = builder
940 .func
941 .import_function(cranelift_codegen::ir::ExtFuncData {
942 name: cranelift_codegen::ir::ExternalName::user(user_ref),
943 signature: sig,
944 colocated: false,
945 });
946
947 builder.ins().call(func_ref, args);
948 Ok(())
949}
950
951fn emit_call(
952 builder: &mut FunctionBuilder,
953 target: &CallTarget,
954 args: &[clif_ir::Value],
955 value: Option<clif_ir::Value>,
956) -> Result<clif_ir::Value> {
957 match target {
958 CallTarget::Internal(name) => {
959 let sig = builder
960 .func
961 .import_signature(cranelift_codegen::ir::Signature {
962 params: args
963 .iter()
964 .map(|_| cranelift_codegen::ir::AbiParam::new(types::I128))
965 .collect(),
966 returns: vec![cranelift_codegen::ir::AbiParam::new(types::I128)],
967 call_conv: cranelift_codegen::isa::CallConv::SystemV,
968 });
969
970 let user_ref = builder
971 .func
972 .declare_imported_user_function(clif_ir::UserExternalName {
973 namespace: 4,
974 index: name.len() as u32,
975 });
976
977 let func_ref = builder
978 .func
979 .import_function(cranelift_codegen::ir::ExtFuncData {
980 name: cranelift_codegen::ir::ExternalName::user(user_ref),
981 signature: sig,
982 colocated: true,
983 });
984
985 let call = builder.ins().call(func_ref, args);
986 Ok(builder.inst_results(call)[0])
987 }
988 CallTarget::External(addr) => {
989 let addr_val = match addr {
990 Value::Constant(c) => match c {
991 Constant::Address(bytes) => {
992 let mut val = 0u128;
993 for (i, &byte) in bytes.iter().enumerate().take(16) {
994 val |= (byte as u128) << (i * 8);
995 }
996 let addr_64 = builder.ins().iconst(types::I64, val as i64);
997 builder.ins().uextend(types::I128, addr_64)
998 }
999 _ => {
1000 let zero = builder.ins().iconst(types::I64, 0);
1001 builder.ins().uextend(types::I128, zero)
1002 }
1003 },
1004 _ => {
1005 let zero = builder.ins().iconst(types::I64, 0);
1006 builder.ins().uextend(types::I128, zero)
1007 }
1008 };
1009 let mut all_args = vec![addr_val];
1010 if let Some(val) = value {
1011 all_args.push(val);
1012 }
1013 all_args.extend_from_slice(args);
1014 emit_runtime_call(builder, 6, 0, &all_args)
1015 }
1016 CallTarget::Library(name) => emit_runtime_call(builder, 5, name.len() as u32, args),
1017 CallTarget::Builtin(_) => emit_runtime_call(builder, 7, 0, args),
1018 }
1019}
1020
1021fn emit_get_context(builder: &mut FunctionBuilder, var: ContextVariable) -> Result<clif_ir::Value> {
1022 let ctx_offset = match var {
1023 ContextVariable::MsgSender => 0,
1024 ContextVariable::MsgValue => 20,
1025 ContextVariable::MsgData => 52,
1026 ContextVariable::MsgSig => 84,
1027 ContextVariable::BlockNumber => 116,
1028 ContextVariable::BlockTimestamp => 148,
1029 ContextVariable::BlockDifficulty => 180,
1030 ContextVariable::BlockGasLimit => 212,
1031 ContextVariable::BlockCoinbase => 244,
1032 ContextVariable::ChainId => 264,
1033 ContextVariable::BlockBaseFee => 296,
1034 ContextVariable::TxOrigin => 328,
1035 ContextVariable::TxGasPrice => 348,
1036 ContextVariable::GasLeft => 380,
1037 ContextVariable::ThisAddress => 412,
1038 ContextVariable::ThisBalance => 432,
1039 };
1040
1041 let ctx_ptr = builder.block_params(builder.current_block().unwrap())[0];
1042 Ok(builder.ins().load(
1043 types::I128,
1044 MemFlags::trusted(),
1045 ctx_ptr,
1046 Offset32::new(ctx_offset),
1047 ))
1048}
1049
1050fn emit_event(
1051 builder: &mut FunctionBuilder,
1052 event_id: crate::contract::EventId,
1053 topics: &[clif_ir::Value],
1054 data: &[clif_ir::Value],
1055) -> Result<()> {
1056 let event_val = builder.ins().iconst(types::I32, event_id.0 as i64);
1057 let topic_count = builder.ins().iconst(types::I32, topics.len() as i64);
1058
1059 let data_ptr = builder.ins().iconst(types::I64, 0);
1061 let data_len = builder.ins().iconst(types::I64, data.len() as i64);
1062
1063 let mut args = vec![event_val, topic_count];
1064 args.extend_from_slice(&topics[..topics.len().min(4)]);
1065 while args.len() < 6 {
1066 let zero = builder.ins().iconst(types::I64, 0);
1067 args.push(builder.ins().uextend(types::I128, zero));
1068 }
1069 args.push(data_ptr);
1070 args.push(data_len);
1071
1072 let args_i128: Vec<_> = args
1073 .iter()
1074 .map(|&v| {
1075 if builder.func.dfg.value_type(v) != types::I128 {
1076 builder.ins().uextend(types::I128, v)
1077 } else {
1078 v
1079 }
1080 })
1081 .collect();
1082
1083 emit_runtime_call_void(builder, 12, 0, &args_i128)?;
1084 Ok(())
1085}