1use crate::emit::EmitContext;
4use crate::ir::Value;
5use crate::parse::IndicesToIds;
6use crate::RefType;
7use crate::{FunctionId, GlobalId, Result};
8use anyhow::bail;
9
10#[derive(Debug, Clone)]
13pub enum ConstExpr {
14 Value(Value),
16 Global(GlobalId),
18 RefNull(RefType),
20 RefFunc(FunctionId),
22 Extended(Vec<ConstOp>),
24}
25
26#[derive(Debug, Copy, Clone)]
28pub enum ConstOp {
29 I32Const(i32),
31 I64Const(i64),
33 F32Const(f32),
35 F64Const(f64),
37 V128Const(u128),
39 GlobalGet(GlobalId),
41 RefNull(RefType),
43 RefFunc(FunctionId),
45 I32Add,
47 I32Sub,
49 I32Mul,
51 I64Add,
53 I64Sub,
55 I64Mul,
57}
58
59impl ConstExpr {
60 pub(crate) fn eval(init: &wasmparser::ConstExpr, ids: &IndicesToIds) -> Result<ConstExpr> {
61 use wasmparser::Operator::*;
62 let mut reader = init.get_operators_reader();
63 let mut ops = Vec::new();
64
65 loop {
66 let op = reader.read()?;
67 match op {
68 End => break,
69 I32Const { value } => ops.push(ConstOp::I32Const(value)),
70 I64Const { value } => ops.push(ConstOp::I64Const(value)),
71 F32Const { value } => ops.push(ConstOp::F32Const(f32::from_bits(value.bits()))),
72 F64Const { value } => ops.push(ConstOp::F64Const(f64::from_bits(value.bits()))),
73 V128Const { value } => ops.push(ConstOp::V128Const(v128_to_u128(&value))),
74 GlobalGet { global_index } => {
75 ops.push(ConstOp::GlobalGet(ids.get_global(global_index)?))
76 }
77 RefNull { hty } => {
78 let val_type = match hty {
79 wasmparser::HeapType::Abstract { shared: _, ty } => match ty {
80 wasmparser::AbstractHeapType::Func => RefType::Funcref,
81 wasmparser::AbstractHeapType::Extern => RefType::Externref,
82 other => bail!(
83 "unsupported abstract heap type in constant expression: {other:?}"
84 ),
85 },
86 wasmparser::HeapType::Concrete(_) => {
87 bail!("unsupported concrete heap type in constant expression")
88 }
89 };
90 ops.push(ConstOp::RefNull(val_type));
91 }
92 RefFunc { function_index } => {
93 ops.push(ConstOp::RefFunc(ids.get_func(function_index)?))
94 }
95 I32Add => ops.push(ConstOp::I32Add),
96 I32Sub => ops.push(ConstOp::I32Sub),
97 I32Mul => ops.push(ConstOp::I32Mul),
98 I64Add => ops.push(ConstOp::I64Add),
99 I64Sub => ops.push(ConstOp::I64Sub),
100 I64Mul => ops.push(ConstOp::I64Mul),
101 _ => bail!("unsupported operation in constant expression: {:?}", op),
102 }
103 }
104
105 reader.finish()?;
106
107 if ops.len() == 1 {
109 match &ops[0] {
110 ConstOp::I32Const(v) => return Ok(ConstExpr::Value(Value::I32(*v))),
111 ConstOp::I64Const(v) => return Ok(ConstExpr::Value(Value::I64(*v))),
112 ConstOp::F32Const(v) => return Ok(ConstExpr::Value(Value::F32(*v))),
113 ConstOp::F64Const(v) => return Ok(ConstExpr::Value(Value::F64(*v))),
114 ConstOp::V128Const(v) => return Ok(ConstExpr::Value(Value::V128(*v))),
115 ConstOp::GlobalGet(g) => return Ok(ConstExpr::Global(*g)),
116 ConstOp::RefNull(ty) => return Ok(ConstExpr::RefNull(*ty)),
117 ConstOp::RefFunc(f) => return Ok(ConstExpr::RefFunc(*f)),
118 _ => {}
119 }
120 }
121
122 Ok(ConstExpr::Extended(ops))
123 }
124
125 pub(crate) fn to_wasmencoder_type(&self, cx: &EmitContext) -> wasm_encoder::ConstExpr {
126 use wasm_encoder::{Encode, Instruction};
127 match self {
128 ConstExpr::Value(v) => match v {
129 Value::I32(v) => wasm_encoder::ConstExpr::i32_const(*v),
130 Value::I64(v) => wasm_encoder::ConstExpr::i64_const(*v),
131 Value::F32(v) => wasm_encoder::ConstExpr::f32_const((*v).into()),
132 Value::F64(v) => wasm_encoder::ConstExpr::f64_const((*v).into()),
133 Value::V128(v) => wasm_encoder::ConstExpr::v128_const(*v as i128),
134 },
135 ConstExpr::Global(g) => {
136 wasm_encoder::ConstExpr::global_get(cx.indices.get_global_index(*g))
137 }
138 ConstExpr::RefNull(ty) => wasm_encoder::ConstExpr::ref_null(match ty {
139 RefType::Externref => wasm_encoder::HeapType::Abstract {
140 shared: false,
141 ty: wasm_encoder::AbstractHeapType::Extern,
142 },
143 RefType::Funcref => wasm_encoder::HeapType::Abstract {
144 shared: false,
145 ty: wasm_encoder::AbstractHeapType::Func,
146 },
147 RefType::Exnref => wasm_encoder::HeapType::Abstract {
148 shared: false,
149 ty: wasm_encoder::AbstractHeapType::Exn,
150 },
151 }),
152 ConstExpr::RefFunc(f) => {
153 wasm_encoder::ConstExpr::ref_func(cx.indices.get_func_index(*f))
154 }
155 ConstExpr::Extended(ops) => {
156 let mut bytes = Vec::new();
157 for op in ops {
158 match op {
159 ConstOp::I32Const(v) => Instruction::I32Const(*v).encode(&mut bytes),
160 ConstOp::I64Const(v) => Instruction::I64Const(*v).encode(&mut bytes),
161 ConstOp::F32Const(v) => {
162 Instruction::F32Const((*v).into()).encode(&mut bytes)
163 }
164 ConstOp::F64Const(v) => {
165 Instruction::F64Const((*v).into()).encode(&mut bytes)
166 }
167 ConstOp::V128Const(v) => {
168 Instruction::V128Const(*v as i128).encode(&mut bytes)
169 }
170 ConstOp::GlobalGet(g) => {
171 Instruction::GlobalGet(cx.indices.get_global_index(*g))
172 .encode(&mut bytes)
173 }
174 ConstOp::RefNull(ty) => Instruction::RefNull(match ty {
175 RefType::Externref => wasm_encoder::HeapType::Abstract {
176 shared: false,
177 ty: wasm_encoder::AbstractHeapType::Extern,
178 },
179 RefType::Funcref => wasm_encoder::HeapType::Abstract {
180 shared: false,
181 ty: wasm_encoder::AbstractHeapType::Func,
182 },
183 RefType::Exnref => wasm_encoder::HeapType::Abstract {
184 shared: false,
185 ty: wasm_encoder::AbstractHeapType::Exn,
186 },
187 })
188 .encode(&mut bytes),
189 ConstOp::RefFunc(f) => {
190 Instruction::RefFunc(cx.indices.get_func_index(*f)).encode(&mut bytes)
191 }
192 ConstOp::I32Add => Instruction::I32Add.encode(&mut bytes),
193 ConstOp::I32Sub => Instruction::I32Sub.encode(&mut bytes),
194 ConstOp::I32Mul => Instruction::I32Mul.encode(&mut bytes),
195 ConstOp::I64Add => Instruction::I64Add.encode(&mut bytes),
196 ConstOp::I64Sub => Instruction::I64Sub.encode(&mut bytes),
197 ConstOp::I64Mul => Instruction::I64Mul.encode(&mut bytes),
198 }
199 }
200 wasm_encoder::ConstExpr::raw(bytes)
202 }
203 }
204 }
205}
206
207pub(crate) fn v128_to_u128(value: &wasmparser::V128) -> u128 {
208 let n = value.bytes();
209 (n[0] as u128)
210 | ((n[1] as u128) << 8)
211 | ((n[2] as u128) << 16)
212 | ((n[3] as u128) << 24)
213 | ((n[4] as u128) << 32)
214 | ((n[5] as u128) << 40)
215 | ((n[6] as u128) << 48)
216 | ((n[7] as u128) << 56)
217 | ((n[8] as u128) << 64)
218 | ((n[9] as u128) << 72)
219 | ((n[10] as u128) << 80)
220 | ((n[11] as u128) << 88)
221 | ((n[12] as u128) << 96)
222 | ((n[13] as u128) << 104)
223 | ((n[14] as u128) << 112)
224 | ((n[15] as u128) << 120)
225}