Skip to main content

thalir_core/codegen/
lowering.rs

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    // Not yet implemented: event data packing requires ABI encoding helpers
1060    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}