1use crate::emit::EmitContext;
4use crate::ir::Value;
5use crate::parse::IndicesToIds;
6use crate::{FunctionId, GlobalId, Result};
7use crate::{HeapType, RefType};
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 RefI31,
59}
60
61impl ConstExpr {
62 pub(crate) fn eval(init: &wasmparser::ConstExpr, ids: &IndicesToIds) -> Result<ConstExpr> {
63 use wasmparser::Operator::*;
64 let mut reader = init.get_operators_reader();
65 let mut ops = Vec::new();
66
67 loop {
68 let op = reader.read()?;
69 match op {
70 End => break,
71 I32Const { value } => ops.push(ConstOp::I32Const(value)),
72 I64Const { value } => ops.push(ConstOp::I64Const(value)),
73 F32Const { value } => ops.push(ConstOp::F32Const(f32::from_bits(value.bits()))),
74 F64Const { value } => ops.push(ConstOp::F64Const(f64::from_bits(value.bits()))),
75 V128Const { value } => ops.push(ConstOp::V128Const(v128_to_u128(&value))),
76 GlobalGet { global_index } => {
77 ops.push(ConstOp::GlobalGet(ids.get_global(global_index)?))
78 }
79 RefNull { hty } => {
80 let heap_type = HeapType::try_from(hty)?;
81 let ref_type = RefType {
82 nullable: true,
83 heap_type,
84 };
85 ops.push(ConstOp::RefNull(ref_type));
86 }
87 RefFunc { function_index } => {
88 ops.push(ConstOp::RefFunc(ids.get_func(function_index)?))
89 }
90 I32Add => ops.push(ConstOp::I32Add),
91 I32Sub => ops.push(ConstOp::I32Sub),
92 I32Mul => ops.push(ConstOp::I32Mul),
93 I64Add => ops.push(ConstOp::I64Add),
94 I64Sub => ops.push(ConstOp::I64Sub),
95 I64Mul => ops.push(ConstOp::I64Mul),
96 RefI31 => ops.push(ConstOp::RefI31),
97 _ => bail!("unsupported operation in constant expression: {:?}", op),
98 }
99 }
100
101 reader.finish()?;
102
103 if ops.len() == 1 {
105 match &ops[0] {
106 ConstOp::I32Const(v) => return Ok(ConstExpr::Value(Value::I32(*v))),
107 ConstOp::I64Const(v) => return Ok(ConstExpr::Value(Value::I64(*v))),
108 ConstOp::F32Const(v) => return Ok(ConstExpr::Value(Value::F32(*v))),
109 ConstOp::F64Const(v) => return Ok(ConstExpr::Value(Value::F64(*v))),
110 ConstOp::V128Const(v) => return Ok(ConstExpr::Value(Value::V128(*v))),
111 ConstOp::GlobalGet(g) => return Ok(ConstExpr::Global(*g)),
112 ConstOp::RefNull(ty) => return Ok(ConstExpr::RefNull(*ty)),
113 ConstOp::RefFunc(f) => return Ok(ConstExpr::RefFunc(*f)),
114 _ => {}
115 }
116 }
117
118 Ok(ConstExpr::Extended(ops))
119 }
120
121 pub(crate) fn to_wasmencoder_type(&self, cx: &EmitContext) -> wasm_encoder::ConstExpr {
122 use wasm_encoder::{Encode, Instruction};
123 match self {
124 ConstExpr::Value(v) => match v {
125 Value::I32(v) => wasm_encoder::ConstExpr::i32_const(*v),
126 Value::I64(v) => wasm_encoder::ConstExpr::i64_const(*v),
127 Value::F32(v) => wasm_encoder::ConstExpr::f32_const((*v).into()),
128 Value::F64(v) => wasm_encoder::ConstExpr::f64_const((*v).into()),
129 Value::V128(v) => wasm_encoder::ConstExpr::v128_const(*v as i128),
130 },
131 ConstExpr::Global(g) => {
132 wasm_encoder::ConstExpr::global_get(cx.indices.get_global_index(*g))
133 }
134 ConstExpr::RefNull(ty) => {
135 wasm_encoder::ConstExpr::ref_null(ty.heap_type.to_wasmencoder_heap_type())
136 }
137 ConstExpr::RefFunc(f) => {
138 wasm_encoder::ConstExpr::ref_func(cx.indices.get_func_index(*f))
139 }
140 ConstExpr::Extended(ops) => {
141 let mut bytes = Vec::new();
142 for op in ops {
143 match op {
144 ConstOp::I32Const(v) => Instruction::I32Const(*v).encode(&mut bytes),
145 ConstOp::I64Const(v) => Instruction::I64Const(*v).encode(&mut bytes),
146 ConstOp::F32Const(v) => {
147 Instruction::F32Const((*v).into()).encode(&mut bytes)
148 }
149 ConstOp::F64Const(v) => {
150 Instruction::F64Const((*v).into()).encode(&mut bytes)
151 }
152 ConstOp::V128Const(v) => {
153 Instruction::V128Const(*v as i128).encode(&mut bytes)
154 }
155 ConstOp::GlobalGet(g) => {
156 Instruction::GlobalGet(cx.indices.get_global_index(*g))
157 .encode(&mut bytes)
158 }
159 ConstOp::RefNull(ty) => {
160 Instruction::RefNull(ty.heap_type.to_wasmencoder_heap_type())
161 .encode(&mut bytes)
162 }
163 ConstOp::RefFunc(f) => {
164 Instruction::RefFunc(cx.indices.get_func_index(*f)).encode(&mut bytes)
165 }
166 ConstOp::I32Add => Instruction::I32Add.encode(&mut bytes),
167 ConstOp::I32Sub => Instruction::I32Sub.encode(&mut bytes),
168 ConstOp::I32Mul => Instruction::I32Mul.encode(&mut bytes),
169 ConstOp::I64Add => Instruction::I64Add.encode(&mut bytes),
170 ConstOp::I64Sub => Instruction::I64Sub.encode(&mut bytes),
171 ConstOp::I64Mul => Instruction::I64Mul.encode(&mut bytes),
172 ConstOp::RefI31 => Instruction::RefI31.encode(&mut bytes),
173 }
174 }
175 wasm_encoder::ConstExpr::raw(bytes)
177 }
178 }
179 }
180}
181
182pub(crate) fn v128_to_u128(value: &wasmparser::V128) -> u128 {
183 let n = value.bytes();
184 (n[0] as u128)
185 | ((n[1] as u128) << 8)
186 | ((n[2] as u128) << 16)
187 | ((n[3] as u128) << 24)
188 | ((n[4] as u128) << 32)
189 | ((n[5] as u128) << 40)
190 | ((n[6] as u128) << 48)
191 | ((n[7] as u128) << 56)
192 | ((n[8] as u128) << 64)
193 | ((n[9] as u128) << 72)
194 | ((n[10] as u128) << 80)
195 | ((n[11] as u128) << 88)
196 | ((n[12] as u128) << 96)
197 | ((n[13] as u128) << 104)
198 | ((n[14] as u128) << 112)
199 | ((n[15] as u128) << 120)
200}