solar_codegen/backend/evm/assembler/
inst.rs1use solar_data_structures::{index::Idx, newtype_index};
2
3newtype_index! {
4 pub struct Label;
6
7 pub struct DeferredConst;
13
14 pub(in crate::backend::evm) struct PushValueId;
16}
17
18pub(super) trait AsmIndex: Idx {
19 const NAME: &'static str;
20
21 fn inst_payload(self) -> u32 {
22 let index =
23 u32::try_from(self.index()).unwrap_or_else(|_| panic!("{} overflow", Self::NAME));
24 assert!(index <= AsmInst::PAYLOAD_MASK, "{} overflow", Self::NAME);
25 index
26 }
27
28 fn from_inst_payload(payload: u32) -> Self {
29 Self::from_usize(payload as usize)
30 }
31}
32
33impl AsmIndex for Label {
34 const NAME: &'static str = "assembler label index";
35}
36
37impl AsmIndex for DeferredConst {
38 const NAME: &'static str = "assembler deferred constant index";
39}
40
41impl AsmIndex for PushValueId {
42 const NAME: &'static str = "assembler push value index";
43}
44
45#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
47pub(in crate::backend::evm) struct AsmInst(u32);
48
49impl AsmInst {
50 pub(in crate::backend::evm) const PLACEHOLDER: Self = Self(0);
51 pub(in crate::backend::evm) const PAYLOAD_MASK: u32 = 0x0fff_ffff;
52 const INLINE_PUSH_MAX: u32 = 0x7fff_ffff;
53 const TAG_MASK: u32 = 0xf000_0000;
54 const TAG_OP: u32 = 0x8000_0000;
55 const TAG_PUSH: u32 = 0x9000_0000;
56 const TAG_PUSH_LABEL: u32 = 0xa000_0000;
57 const TAG_PUSH_DEFERRED: u32 = 0xb000_0000;
58 const TAG_PUSH_IMMUTABLE: u32 = 0xc000_0000;
59 const TAG_LABEL: u32 = 0xd000_0000;
60
61 pub(in crate::backend::evm) fn op(opcode: u8) -> Self {
62 Self(Self::TAG_OP | u32::from(opcode))
63 }
64
65 pub(in crate::backend::evm) fn push_inline(value: u32) -> Option<Self> {
66 (value <= Self::INLINE_PUSH_MAX).then_some(Self(value))
67 }
68
69 pub(in crate::backend::evm) fn push(index: PushValueId) -> Self {
70 Self::tagged(Self::TAG_PUSH, index.inst_payload())
71 }
72
73 pub(in crate::backend::evm) fn push_label(label: Label) -> Self {
74 Self::tagged(Self::TAG_PUSH_LABEL, label.inst_payload())
75 }
76
77 pub(in crate::backend::evm) fn push_deferred(id: DeferredConst) -> Self {
78 Self::tagged(Self::TAG_PUSH_DEFERRED, id.inst_payload())
79 }
80
81 pub(in crate::backend::evm) fn push_immutable(id: u32) -> Self {
82 Self::tagged(Self::TAG_PUSH_IMMUTABLE, id)
83 }
84
85 pub(in crate::backend::evm) fn label(label: Label) -> Self {
86 Self::tagged(Self::TAG_LABEL, label.inst_payload())
87 }
88
89 fn tagged(tag: u32, payload: u32) -> Self {
90 assert!(payload <= Self::PAYLOAD_MASK, "assembler instruction payload overflow");
91 Self(tag | payload)
92 }
93
94 pub(in crate::backend::evm) fn kind(self) -> AsmInstKind {
95 if self.0 <= Self::INLINE_PUSH_MAX {
96 return AsmInstKind::PushInline(self.0);
97 }
98
99 let payload = self.0 & Self::PAYLOAD_MASK;
100 match self.0 & Self::TAG_MASK {
101 Self::TAG_OP => AsmInstKind::Op(payload as u8),
102 Self::TAG_PUSH => AsmInstKind::Push(PushValueId::from_inst_payload(payload)),
103 Self::TAG_PUSH_LABEL => AsmInstKind::PushLabel(Label::from_inst_payload(payload)),
104 Self::TAG_PUSH_DEFERRED => {
105 AsmInstKind::PushDeferred(DeferredConst::from_inst_payload(payload))
106 }
107 Self::TAG_PUSH_IMMUTABLE => AsmInstKind::PushImmutable(payload),
108 Self::TAG_LABEL => AsmInstKind::Label(Label::from_inst_payload(payload)),
109 _ => unreachable!("invalid assembler instruction tag"),
110 }
111 }
112}
113
114#[derive(Clone, Copy, Debug, PartialEq, Eq)]
115pub(in crate::backend::evm) enum AsmInstKind {
116 Op(u8),
117 PushInline(u32),
118 Push(PushValueId),
119 PushLabel(Label),
120 PushDeferred(DeferredConst),
121 PushImmutable(u32),
122 Label(Label),
123}