1 use crate::codegen::ir::{ArgumentExtension, ArgumentPurpose}; 2 use crate::config::Config; 3 use anyhow::Result; 4 use arbitrary::{Arbitrary, Unstructured}; 5 use cranelift::codegen::ir::immediates::Offset32; 6 use cranelift::codegen::ir::instructions::InstructionFormat; 7 use cranelift::codegen::ir::stackslot::StackSize; 8 use cranelift::codegen::ir::{types::*, FuncRef, LibCall, UserExternalName, UserFuncName}; 9 use cranelift::codegen::ir::{ 10 AbiParam, Block, ExternalName, Function, JumpTable, Opcode, Signature, StackSlot, Type, Value, 11 }; 12 use cranelift::codegen::isa::CallConv; 13 use cranelift::frontend::{FunctionBuilder, FunctionBuilderContext, Switch, Variable}; 14 use cranelift::prelude::{ 15 EntityRef, ExtFuncData, FloatCC, InstBuilder, IntCC, JumpTableData, MemFlags, StackSlotData, 16 StackSlotKind, 17 }; 18 use std::collections::HashMap; 19 use std::ops::RangeInclusive; 20 21 type BlockSignature = Vec<Type>; 22 23 fn insert_opcode( 24 fgen: &mut FunctionGenerator, 25 builder: &mut FunctionBuilder, 26 opcode: Opcode, 27 args: &'static [Type], 28 rets: &'static [Type], 29 ) -> Result<()> { 30 let mut vals = Vec::with_capacity(args.len()); 31 for &arg in args.into_iter() { 32 let var = fgen.get_variable_of_type(arg)?; 33 let val = builder.use_var(var); 34 vals.push(val); 35 } 36 37 // For pretty much every instruction the control type is the return type 38 // except for Iconcat and Isplit which are *special* and the control type 39 // is the input type. 40 let ctrl_type = if opcode == Opcode::Iconcat || opcode == Opcode::Isplit { 41 args.first() 42 } else { 43 rets.first() 44 } 45 .copied() 46 .unwrap_or(INVALID); 47 48 // Choose the appropriate instruction format for this opcode 49 let (inst, dfg) = match opcode.format() { 50 InstructionFormat::NullAry => builder.ins().NullAry(opcode, ctrl_type), 51 InstructionFormat::Unary => builder.ins().Unary(opcode, ctrl_type, vals[0]), 52 InstructionFormat::Binary => builder.ins().Binary(opcode, ctrl_type, vals[0], vals[1]), 53 InstructionFormat::Ternary => builder 54 .ins() 55 .Ternary(opcode, ctrl_type, vals[0], vals[1], vals[2]), 56 _ => unimplemented!(), 57 }; 58 let results = dfg.inst_results(inst).to_vec(); 59 60 for (val, &ty) in results.into_iter().zip(rets) { 61 let var = fgen.get_variable_of_type(ty)?; 62 builder.def_var(var, val); 63 } 64 Ok(()) 65 } 66 67 fn insert_call( 68 fgen: &mut FunctionGenerator, 69 builder: &mut FunctionBuilder, 70 opcode: Opcode, 71 _args: &'static [Type], 72 _rets: &'static [Type], 73 ) -> Result<()> { 74 assert_eq!(opcode, Opcode::Call, "only call handled at the moment"); 75 let (sig, func_ref) = fgen.u.choose(&fgen.resources.func_refs)?.clone(); 76 77 let actuals = fgen.generate_values_for_signature( 78 builder, 79 sig.params.iter().map(|abi_param| abi_param.value_type), 80 )?; 81 82 builder.ins().call(func_ref, &actuals); 83 Ok(()) 84 } 85 86 fn insert_stack_load( 87 fgen: &mut FunctionGenerator, 88 builder: &mut FunctionBuilder, 89 _opcode: Opcode, 90 _args: &'static [Type], 91 rets: &'static [Type], 92 ) -> Result<()> { 93 let typevar = rets[0]; 94 let type_size = typevar.bytes(); 95 let (slot, slot_size) = fgen.stack_slot_with_size(type_size)?; 96 let offset = fgen.u.int_in_range(0..=(slot_size - type_size))? as i32; 97 98 let val = builder.ins().stack_load(typevar, slot, offset); 99 let var = fgen.get_variable_of_type(typevar)?; 100 builder.def_var(var, val); 101 102 Ok(()) 103 } 104 105 fn insert_stack_store( 106 fgen: &mut FunctionGenerator, 107 builder: &mut FunctionBuilder, 108 _opcode: Opcode, 109 args: &'static [Type], 110 _rets: &'static [Type], 111 ) -> Result<()> { 112 let typevar = args[0]; 113 let type_size = typevar.bytes(); 114 let (slot, slot_size) = fgen.stack_slot_with_size(type_size)?; 115 let offset = fgen.u.int_in_range(0..=(slot_size - type_size))? as i32; 116 117 let arg0 = fgen.get_variable_of_type(typevar)?; 118 let arg0 = builder.use_var(arg0); 119 120 builder.ins().stack_store(arg0, slot, offset); 121 Ok(()) 122 } 123 124 fn insert_cmp( 125 fgen: &mut FunctionGenerator, 126 builder: &mut FunctionBuilder, 127 opcode: Opcode, 128 args: &'static [Type], 129 rets: &'static [Type], 130 ) -> Result<()> { 131 let lhs = fgen.get_variable_of_type(args[0])?; 132 let lhs = builder.use_var(lhs); 133 134 let rhs = fgen.get_variable_of_type(args[1])?; 135 let rhs = builder.use_var(rhs); 136 137 let res = if opcode == Opcode::Fcmp { 138 let cc = *fgen.u.choose(FloatCC::all())?; 139 builder.ins().fcmp(cc, lhs, rhs) 140 } else { 141 let cc = *fgen.u.choose(IntCC::all())?; 142 builder.ins().icmp(cc, lhs, rhs) 143 }; 144 145 let var = fgen.get_variable_of_type(rets[0])?; 146 builder.def_var(var, res); 147 148 Ok(()) 149 } 150 151 fn insert_const( 152 fgen: &mut FunctionGenerator, 153 builder: &mut FunctionBuilder, 154 _opcode: Opcode, 155 _args: &'static [Type], 156 rets: &'static [Type], 157 ) -> Result<()> { 158 let typevar = rets[0]; 159 let var = fgen.get_variable_of_type(typevar)?; 160 let val = fgen.generate_const(builder, typevar)?; 161 builder.def_var(var, val); 162 Ok(()) 163 } 164 165 fn insert_load_store( 166 fgen: &mut FunctionGenerator, 167 builder: &mut FunctionBuilder, 168 opcode: Opcode, 169 args: &'static [Type], 170 rets: &'static [Type], 171 ) -> Result<()> { 172 let ctrl_type = *rets.first().or(args.first()).unwrap(); 173 let type_size = ctrl_type.bytes(); 174 let (address, offset) = fgen.generate_load_store_address(builder, type_size)?; 175 176 // TODO: More advanced MemFlags 177 let flags = MemFlags::new(); 178 179 // The variable being loaded or stored into 180 let var = fgen.get_variable_of_type(ctrl_type)?; 181 182 if opcode.can_store() { 183 let val = builder.use_var(var); 184 185 builder 186 .ins() 187 .Store(opcode, ctrl_type, flags, offset, val, address); 188 } else { 189 let (inst, dfg) = builder 190 .ins() 191 .Load(opcode, ctrl_type, flags, offset, address); 192 193 let new_val = dfg.first_result(inst); 194 builder.def_var(var, new_val); 195 } 196 197 Ok(()) 198 } 199 200 type OpcodeInserter = fn( 201 fgen: &mut FunctionGenerator, 202 builder: &mut FunctionBuilder, 203 Opcode, 204 &'static [Type], 205 &'static [Type], 206 ) -> Result<()>; 207 208 // TODO: Derive this from the `cranelift-meta` generator. 209 const OPCODE_SIGNATURES: &'static [( 210 Opcode, 211 &'static [Type], // Args 212 &'static [Type], // Rets 213 OpcodeInserter, 214 )] = &[ 215 (Opcode::Nop, &[], &[], insert_opcode), 216 // Iadd 217 (Opcode::Iadd, &[I8, I8], &[I8], insert_opcode), 218 (Opcode::Iadd, &[I16, I16], &[I16], insert_opcode), 219 (Opcode::Iadd, &[I32, I32], &[I32], insert_opcode), 220 (Opcode::Iadd, &[I64, I64], &[I64], insert_opcode), 221 (Opcode::Iadd, &[I128, I128], &[I128], insert_opcode), 222 // Isub 223 (Opcode::Isub, &[I8, I8], &[I8], insert_opcode), 224 (Opcode::Isub, &[I16, I16], &[I16], insert_opcode), 225 (Opcode::Isub, &[I32, I32], &[I32], insert_opcode), 226 (Opcode::Isub, &[I64, I64], &[I64], insert_opcode), 227 (Opcode::Isub, &[I128, I128], &[I128], insert_opcode), 228 // Imul 229 (Opcode::Imul, &[I8, I8], &[I8], insert_opcode), 230 (Opcode::Imul, &[I16, I16], &[I16], insert_opcode), 231 (Opcode::Imul, &[I32, I32], &[I32], insert_opcode), 232 (Opcode::Imul, &[I64, I64], &[I64], insert_opcode), 233 (Opcode::Imul, &[I128, I128], &[I128], insert_opcode), 234 // Udiv 235 // udiv.i128 not implemented on x64: https://github.com/bytecodealliance/wasmtime/issues/4756 236 (Opcode::Udiv, &[I8, I8], &[I8], insert_opcode), 237 (Opcode::Udiv, &[I16, I16], &[I16], insert_opcode), 238 (Opcode::Udiv, &[I32, I32], &[I32], insert_opcode), 239 (Opcode::Udiv, &[I64, I64], &[I64], insert_opcode), 240 // (Opcode::Udiv, &[I128, I128], &[I128], insert_opcode), 241 // Sdiv 242 // sdiv.i128 not implemented on x64: https://github.com/bytecodealliance/wasmtime/issues/4770 243 (Opcode::Sdiv, &[I8, I8], &[I8], insert_opcode), 244 (Opcode::Sdiv, &[I16, I16], &[I16], insert_opcode), 245 (Opcode::Sdiv, &[I32, I32], &[I32], insert_opcode), 246 (Opcode::Sdiv, &[I64, I64], &[I64], insert_opcode), 247 // (Opcode::Sdiv, &[I128, I128], &[I128], insert_opcode), 248 // Rotr 249 (Opcode::Rotr, &[I8, I8], &[I8], insert_opcode), 250 (Opcode::Rotr, &[I8, I16], &[I8], insert_opcode), 251 (Opcode::Rotr, &[I8, I32], &[I8], insert_opcode), 252 (Opcode::Rotr, &[I8, I64], &[I8], insert_opcode), 253 (Opcode::Rotr, &[I8, I128], &[I8], insert_opcode), 254 (Opcode::Rotr, &[I16, I8], &[I16], insert_opcode), 255 (Opcode::Rotr, &[I16, I16], &[I16], insert_opcode), 256 (Opcode::Rotr, &[I16, I32], &[I16], insert_opcode), 257 (Opcode::Rotr, &[I16, I64], &[I16], insert_opcode), 258 (Opcode::Rotr, &[I16, I128], &[I16], insert_opcode), 259 (Opcode::Rotr, &[I32, I8], &[I32], insert_opcode), 260 (Opcode::Rotr, &[I32, I16], &[I32], insert_opcode), 261 (Opcode::Rotr, &[I32, I32], &[I32], insert_opcode), 262 (Opcode::Rotr, &[I32, I64], &[I32], insert_opcode), 263 (Opcode::Rotr, &[I32, I128], &[I32], insert_opcode), 264 (Opcode::Rotr, &[I64, I8], &[I64], insert_opcode), 265 (Opcode::Rotr, &[I64, I16], &[I64], insert_opcode), 266 (Opcode::Rotr, &[I64, I32], &[I64], insert_opcode), 267 (Opcode::Rotr, &[I64, I64], &[I64], insert_opcode), 268 (Opcode::Rotr, &[I64, I128], &[I64], insert_opcode), 269 (Opcode::Rotr, &[I128, I8], &[I128], insert_opcode), 270 (Opcode::Rotr, &[I128, I16], &[I128], insert_opcode), 271 (Opcode::Rotr, &[I128, I32], &[I128], insert_opcode), 272 (Opcode::Rotr, &[I128, I64], &[I128], insert_opcode), 273 (Opcode::Rotr, &[I128, I128], &[I128], insert_opcode), 274 // Rotl 275 (Opcode::Rotl, &[I8, I8], &[I8], insert_opcode), 276 (Opcode::Rotl, &[I8, I16], &[I8], insert_opcode), 277 (Opcode::Rotl, &[I8, I32], &[I8], insert_opcode), 278 (Opcode::Rotl, &[I8, I64], &[I8], insert_opcode), 279 (Opcode::Rotl, &[I8, I128], &[I8], insert_opcode), 280 (Opcode::Rotl, &[I16, I8], &[I16], insert_opcode), 281 (Opcode::Rotl, &[I16, I16], &[I16], insert_opcode), 282 (Opcode::Rotl, &[I16, I32], &[I16], insert_opcode), 283 (Opcode::Rotl, &[I16, I64], &[I16], insert_opcode), 284 (Opcode::Rotl, &[I16, I128], &[I16], insert_opcode), 285 (Opcode::Rotl, &[I32, I8], &[I32], insert_opcode), 286 (Opcode::Rotl, &[I32, I16], &[I32], insert_opcode), 287 (Opcode::Rotl, &[I32, I32], &[I32], insert_opcode), 288 (Opcode::Rotl, &[I32, I64], &[I32], insert_opcode), 289 (Opcode::Rotl, &[I32, I128], &[I32], insert_opcode), 290 (Opcode::Rotl, &[I64, I8], &[I64], insert_opcode), 291 (Opcode::Rotl, &[I64, I16], &[I64], insert_opcode), 292 (Opcode::Rotl, &[I64, I32], &[I64], insert_opcode), 293 (Opcode::Rotl, &[I64, I64], &[I64], insert_opcode), 294 (Opcode::Rotl, &[I64, I128], &[I64], insert_opcode), 295 (Opcode::Rotl, &[I128, I8], &[I128], insert_opcode), 296 (Opcode::Rotl, &[I128, I16], &[I128], insert_opcode), 297 (Opcode::Rotl, &[I128, I32], &[I128], insert_opcode), 298 (Opcode::Rotl, &[I128, I64], &[I128], insert_opcode), 299 (Opcode::Rotl, &[I128, I128], &[I128], insert_opcode), 300 // Ishl 301 // Some test cases disabled due to: https://github.com/bytecodealliance/wasmtime/issues/4699 302 (Opcode::Ishl, &[I8, I8], &[I8], insert_opcode), 303 (Opcode::Ishl, &[I8, I16], &[I8], insert_opcode), 304 (Opcode::Ishl, &[I8, I32], &[I8], insert_opcode), 305 (Opcode::Ishl, &[I8, I64], &[I8], insert_opcode), 306 // (Opcode::Ishl, &[I8, I128], &[I8], insert_opcode), 307 (Opcode::Ishl, &[I16, I8], &[I16], insert_opcode), 308 (Opcode::Ishl, &[I16, I16], &[I16], insert_opcode), 309 (Opcode::Ishl, &[I16, I32], &[I16], insert_opcode), 310 (Opcode::Ishl, &[I16, I64], &[I16], insert_opcode), 311 // (Opcode::Ishl, &[I16, I128], &[I16], insert_opcode), 312 (Opcode::Ishl, &[I32, I8], &[I32], insert_opcode), 313 (Opcode::Ishl, &[I32, I16], &[I32], insert_opcode), 314 (Opcode::Ishl, &[I32, I32], &[I32], insert_opcode), 315 (Opcode::Ishl, &[I32, I64], &[I32], insert_opcode), 316 (Opcode::Ishl, &[I32, I128], &[I32], insert_opcode), 317 (Opcode::Ishl, &[I64, I8], &[I64], insert_opcode), 318 (Opcode::Ishl, &[I64, I16], &[I64], insert_opcode), 319 (Opcode::Ishl, &[I64, I32], &[I64], insert_opcode), 320 (Opcode::Ishl, &[I64, I64], &[I64], insert_opcode), 321 (Opcode::Ishl, &[I64, I128], &[I64], insert_opcode), 322 (Opcode::Ishl, &[I128, I8], &[I128], insert_opcode), 323 (Opcode::Ishl, &[I128, I16], &[I128], insert_opcode), 324 (Opcode::Ishl, &[I128, I32], &[I128], insert_opcode), 325 (Opcode::Ishl, &[I128, I64], &[I128], insert_opcode), 326 (Opcode::Ishl, &[I128, I128], &[I128], insert_opcode), 327 // Sshr 328 (Opcode::Sshr, &[I8, I8], &[I8], insert_opcode), 329 (Opcode::Sshr, &[I8, I16], &[I8], insert_opcode), 330 (Opcode::Sshr, &[I8, I32], &[I8], insert_opcode), 331 (Opcode::Sshr, &[I8, I64], &[I8], insert_opcode), 332 (Opcode::Sshr, &[I8, I128], &[I8], insert_opcode), 333 (Opcode::Sshr, &[I16, I8], &[I16], insert_opcode), 334 (Opcode::Sshr, &[I16, I16], &[I16], insert_opcode), 335 (Opcode::Sshr, &[I16, I32], &[I16], insert_opcode), 336 (Opcode::Sshr, &[I16, I64], &[I16], insert_opcode), 337 (Opcode::Sshr, &[I16, I128], &[I16], insert_opcode), 338 (Opcode::Sshr, &[I32, I8], &[I32], insert_opcode), 339 (Opcode::Sshr, &[I32, I16], &[I32], insert_opcode), 340 (Opcode::Sshr, &[I32, I32], &[I32], insert_opcode), 341 (Opcode::Sshr, &[I32, I64], &[I32], insert_opcode), 342 (Opcode::Sshr, &[I32, I128], &[I32], insert_opcode), 343 (Opcode::Sshr, &[I64, I8], &[I64], insert_opcode), 344 (Opcode::Sshr, &[I64, I16], &[I64], insert_opcode), 345 (Opcode::Sshr, &[I64, I32], &[I64], insert_opcode), 346 (Opcode::Sshr, &[I64, I64], &[I64], insert_opcode), 347 (Opcode::Sshr, &[I64, I128], &[I64], insert_opcode), 348 (Opcode::Sshr, &[I128, I8], &[I128], insert_opcode), 349 (Opcode::Sshr, &[I128, I16], &[I128], insert_opcode), 350 (Opcode::Sshr, &[I128, I32], &[I128], insert_opcode), 351 (Opcode::Sshr, &[I128, I64], &[I128], insert_opcode), 352 (Opcode::Sshr, &[I128, I128], &[I128], insert_opcode), 353 // Ushr 354 (Opcode::Ushr, &[I8, I8], &[I8], insert_opcode), 355 (Opcode::Ushr, &[I8, I16], &[I8], insert_opcode), 356 (Opcode::Ushr, &[I8, I32], &[I8], insert_opcode), 357 (Opcode::Ushr, &[I8, I64], &[I8], insert_opcode), 358 (Opcode::Ushr, &[I8, I128], &[I8], insert_opcode), 359 (Opcode::Ushr, &[I16, I8], &[I16], insert_opcode), 360 (Opcode::Ushr, &[I16, I16], &[I16], insert_opcode), 361 (Opcode::Ushr, &[I16, I32], &[I16], insert_opcode), 362 (Opcode::Ushr, &[I16, I64], &[I16], insert_opcode), 363 (Opcode::Ushr, &[I16, I128], &[I16], insert_opcode), 364 (Opcode::Ushr, &[I32, I8], &[I32], insert_opcode), 365 (Opcode::Ushr, &[I32, I16], &[I32], insert_opcode), 366 (Opcode::Ushr, &[I32, I32], &[I32], insert_opcode), 367 (Opcode::Ushr, &[I32, I64], &[I32], insert_opcode), 368 (Opcode::Ushr, &[I32, I128], &[I32], insert_opcode), 369 (Opcode::Ushr, &[I64, I8], &[I64], insert_opcode), 370 (Opcode::Ushr, &[I64, I16], &[I64], insert_opcode), 371 (Opcode::Ushr, &[I64, I32], &[I64], insert_opcode), 372 (Opcode::Ushr, &[I64, I64], &[I64], insert_opcode), 373 (Opcode::Ushr, &[I64, I128], &[I64], insert_opcode), 374 (Opcode::Ushr, &[I128, I8], &[I128], insert_opcode), 375 (Opcode::Ushr, &[I128, I16], &[I128], insert_opcode), 376 (Opcode::Ushr, &[I128, I32], &[I128], insert_opcode), 377 (Opcode::Ushr, &[I128, I64], &[I128], insert_opcode), 378 (Opcode::Ushr, &[I128, I128], &[I128], insert_opcode), 379 // Uextend 380 (Opcode::Uextend, &[I8], &[I16], insert_opcode), 381 (Opcode::Uextend, &[I8], &[I32], insert_opcode), 382 (Opcode::Uextend, &[I8], &[I64], insert_opcode), 383 (Opcode::Uextend, &[I8], &[I128], insert_opcode), 384 (Opcode::Uextend, &[I16], &[I32], insert_opcode), 385 (Opcode::Uextend, &[I16], &[I64], insert_opcode), 386 (Opcode::Uextend, &[I16], &[I128], insert_opcode), 387 (Opcode::Uextend, &[I32], &[I64], insert_opcode), 388 (Opcode::Uextend, &[I32], &[I128], insert_opcode), 389 (Opcode::Uextend, &[I64], &[I128], insert_opcode), 390 // Sextend 391 (Opcode::Sextend, &[I8], &[I16], insert_opcode), 392 (Opcode::Sextend, &[I8], &[I32], insert_opcode), 393 (Opcode::Sextend, &[I8], &[I64], insert_opcode), 394 (Opcode::Sextend, &[I8], &[I128], insert_opcode), 395 (Opcode::Sextend, &[I16], &[I32], insert_opcode), 396 (Opcode::Sextend, &[I16], &[I64], insert_opcode), 397 (Opcode::Sextend, &[I16], &[I128], insert_opcode), 398 (Opcode::Sextend, &[I32], &[I64], insert_opcode), 399 (Opcode::Sextend, &[I32], &[I128], insert_opcode), 400 (Opcode::Sextend, &[I64], &[I128], insert_opcode), 401 // Ireduce 402 (Opcode::Ireduce, &[I16], &[I8], insert_opcode), 403 (Opcode::Ireduce, &[I32], &[I8], insert_opcode), 404 (Opcode::Ireduce, &[I32], &[I16], insert_opcode), 405 (Opcode::Ireduce, &[I64], &[I8], insert_opcode), 406 (Opcode::Ireduce, &[I64], &[I16], insert_opcode), 407 (Opcode::Ireduce, &[I64], &[I32], insert_opcode), 408 (Opcode::Ireduce, &[I128], &[I8], insert_opcode), 409 (Opcode::Ireduce, &[I128], &[I16], insert_opcode), 410 (Opcode::Ireduce, &[I128], &[I32], insert_opcode), 411 (Opcode::Ireduce, &[I128], &[I64], insert_opcode), 412 // Isplit 413 (Opcode::Isplit, &[I128], &[I64, I64], insert_opcode), 414 // Iconcat 415 (Opcode::Iconcat, &[I64, I64], &[I128], insert_opcode), 416 // Fadd 417 (Opcode::Fadd, &[F32, F32], &[F32], insert_opcode), 418 (Opcode::Fadd, &[F64, F64], &[F64], insert_opcode), 419 // Fmul 420 (Opcode::Fmul, &[F32, F32], &[F32], insert_opcode), 421 (Opcode::Fmul, &[F64, F64], &[F64], insert_opcode), 422 // Fsub 423 (Opcode::Fsub, &[F32, F32], &[F32], insert_opcode), 424 (Opcode::Fsub, &[F64, F64], &[F64], insert_opcode), 425 // Fdiv 426 (Opcode::Fdiv, &[F32, F32], &[F32], insert_opcode), 427 (Opcode::Fdiv, &[F64, F64], &[F64], insert_opcode), 428 // Fmin 429 (Opcode::Fmin, &[F32, F32], &[F32], insert_opcode), 430 (Opcode::Fmin, &[F64, F64], &[F64], insert_opcode), 431 // Fmax 432 (Opcode::Fmax, &[F32, F32], &[F32], insert_opcode), 433 (Opcode::Fmax, &[F64, F64], &[F64], insert_opcode), 434 // FminPseudo 435 (Opcode::FminPseudo, &[F32, F32], &[F32], insert_opcode), 436 (Opcode::FminPseudo, &[F64, F64], &[F64], insert_opcode), 437 // FmaxPseudo 438 (Opcode::FmaxPseudo, &[F32, F32], &[F32], insert_opcode), 439 (Opcode::FmaxPseudo, &[F64, F64], &[F64], insert_opcode), 440 // Fcopysign 441 (Opcode::Fcopysign, &[F32, F32], &[F32], insert_opcode), 442 (Opcode::Fcopysign, &[F64, F64], &[F64], insert_opcode), 443 // Fma 444 (Opcode::Fma, &[F32, F32, F32], &[F32], insert_opcode), 445 (Opcode::Fma, &[F64, F64, F64], &[F64], insert_opcode), 446 // Fabs 447 (Opcode::Fabs, &[F32], &[F32], insert_opcode), 448 (Opcode::Fabs, &[F64], &[F64], insert_opcode), 449 // Fneg 450 (Opcode::Fneg, &[F32], &[F32], insert_opcode), 451 (Opcode::Fneg, &[F64], &[F64], insert_opcode), 452 // Sqrt 453 (Opcode::Sqrt, &[F32], &[F32], insert_opcode), 454 (Opcode::Sqrt, &[F64], &[F64], insert_opcode), 455 // Ceil 456 (Opcode::Ceil, &[F32], &[F32], insert_opcode), 457 (Opcode::Ceil, &[F64], &[F64], insert_opcode), 458 // Floor 459 (Opcode::Floor, &[F32], &[F32], insert_opcode), 460 (Opcode::Floor, &[F64], &[F64], insert_opcode), 461 // Trunc 462 (Opcode::Trunc, &[F32], &[F32], insert_opcode), 463 (Opcode::Trunc, &[F64], &[F64], insert_opcode), 464 // Nearest 465 (Opcode::Nearest, &[F32], &[F32], insert_opcode), 466 (Opcode::Nearest, &[F64], &[F64], insert_opcode), 467 // Fcmp 468 (Opcode::Fcmp, &[F32, F32], &[B1], insert_cmp), 469 (Opcode::Fcmp, &[F64, F64], &[B1], insert_cmp), 470 // Icmp 471 (Opcode::Icmp, &[I8, I8], &[B1], insert_cmp), 472 (Opcode::Icmp, &[I16, I16], &[B1], insert_cmp), 473 (Opcode::Icmp, &[I32, I32], &[B1], insert_cmp), 474 (Opcode::Icmp, &[I64, I64], &[B1], insert_cmp), 475 (Opcode::Icmp, &[I128, I128], &[B1], insert_cmp), 476 // Stack Access 477 (Opcode::StackStore, &[I8], &[], insert_stack_store), 478 (Opcode::StackStore, &[I16], &[], insert_stack_store), 479 (Opcode::StackStore, &[I32], &[], insert_stack_store), 480 (Opcode::StackStore, &[I64], &[], insert_stack_store), 481 (Opcode::StackStore, &[I128], &[], insert_stack_store), 482 (Opcode::StackLoad, &[], &[I8], insert_stack_load), 483 (Opcode::StackLoad, &[], &[I16], insert_stack_load), 484 (Opcode::StackLoad, &[], &[I32], insert_stack_load), 485 (Opcode::StackLoad, &[], &[I64], insert_stack_load), 486 (Opcode::StackLoad, &[], &[I128], insert_stack_load), 487 // Loads 488 (Opcode::Load, &[], &[I8], insert_load_store), 489 (Opcode::Load, &[], &[I16], insert_load_store), 490 (Opcode::Load, &[], &[I32], insert_load_store), 491 (Opcode::Load, &[], &[I64], insert_load_store), 492 (Opcode::Load, &[], &[I128], insert_load_store), 493 (Opcode::Load, &[], &[F32], insert_load_store), 494 (Opcode::Load, &[], &[F64], insert_load_store), 495 // Special Loads 496 (Opcode::Uload8, &[], &[I16], insert_load_store), 497 (Opcode::Uload8, &[], &[I32], insert_load_store), 498 (Opcode::Uload8, &[], &[I64], insert_load_store), 499 (Opcode::Uload16, &[], &[I32], insert_load_store), 500 (Opcode::Uload16, &[], &[I64], insert_load_store), 501 (Opcode::Uload32, &[], &[I64], insert_load_store), 502 (Opcode::Sload8, &[], &[I16], insert_load_store), 503 (Opcode::Sload8, &[], &[I32], insert_load_store), 504 (Opcode::Sload8, &[], &[I64], insert_load_store), 505 (Opcode::Sload16, &[], &[I32], insert_load_store), 506 (Opcode::Sload16, &[], &[I64], insert_load_store), 507 (Opcode::Sload32, &[], &[I64], insert_load_store), 508 // TODO: Unimplemented in the interpreter 509 // Opcode::Uload8x8 510 // Opcode::Sload8x8 511 // Opcode::Uload16x4 512 // Opcode::Sload16x4 513 // Opcode::Uload32x2 514 // Opcode::Sload32x2 515 // Stores 516 (Opcode::Store, &[I8], &[], insert_load_store), 517 (Opcode::Store, &[I16], &[], insert_load_store), 518 (Opcode::Store, &[I32], &[], insert_load_store), 519 (Opcode::Store, &[I64], &[], insert_load_store), 520 (Opcode::Store, &[I128], &[], insert_load_store), 521 (Opcode::Store, &[F32], &[], insert_load_store), 522 (Opcode::Store, &[F64], &[], insert_load_store), 523 // Special Stores 524 (Opcode::Istore8, &[I16], &[], insert_load_store), 525 (Opcode::Istore8, &[I32], &[], insert_load_store), 526 (Opcode::Istore8, &[I64], &[], insert_load_store), 527 (Opcode::Istore16, &[I32], &[], insert_load_store), 528 (Opcode::Istore16, &[I64], &[], insert_load_store), 529 (Opcode::Istore32, &[I64], &[], insert_load_store), 530 // Integer Consts 531 (Opcode::Iconst, &[], &[I8], insert_const), 532 (Opcode::Iconst, &[], &[I16], insert_const), 533 (Opcode::Iconst, &[], &[I32], insert_const), 534 (Opcode::Iconst, &[], &[I64], insert_const), 535 (Opcode::Iconst, &[], &[I128], insert_const), 536 // Float Consts 537 (Opcode::F32const, &[], &[F32], insert_const), 538 (Opcode::F64const, &[], &[F64], insert_const), 539 // Bool Consts 540 (Opcode::Bconst, &[], &[B1], insert_const), 541 // Call 542 (Opcode::Call, &[], &[], insert_call), 543 ]; 544 545 /// These libcalls need a interpreter implementation in `cranelift-fuzzgen.rs` 546 const ALLOWED_LIBCALLS: &'static [LibCall] = &[ 547 LibCall::CeilF32, 548 LibCall::CeilF64, 549 LibCall::FloorF32, 550 LibCall::FloorF64, 551 LibCall::TruncF32, 552 LibCall::TruncF64, 553 ]; 554 555 pub struct FunctionGenerator<'r, 'data> 556 where 557 'data: 'r, 558 { 559 u: &'r mut Unstructured<'data>, 560 config: &'r Config, 561 resources: Resources, 562 } 563 564 #[derive(Default)] 565 struct Resources { 566 vars: HashMap<Type, Vec<Variable>>, 567 blocks: Vec<(Block, BlockSignature)>, 568 blocks_without_params: Vec<Block>, 569 jump_tables: Vec<JumpTable>, 570 func_refs: Vec<(Signature, FuncRef)>, 571 stack_slots: Vec<(StackSlot, StackSize)>, 572 } 573 574 impl<'r, 'data> FunctionGenerator<'r, 'data> 575 where 576 'data: 'r, 577 { 578 pub fn new(u: &'r mut Unstructured<'data>, config: &'r Config) -> Self { 579 Self { 580 u, 581 config, 582 resources: Resources::default(), 583 } 584 } 585 586 /// Generates a random value for config `param` 587 fn param(&mut self, param: &RangeInclusive<usize>) -> Result<usize> { 588 Ok(self.u.int_in_range(param.clone())?) 589 } 590 591 fn generate_callconv(&mut self) -> Result<CallConv> { 592 // TODO: Generate random CallConvs per target 593 Ok(CallConv::SystemV) 594 } 595 596 fn system_callconv(&mut self) -> CallConv { 597 // TODO: This currently only runs on linux, so this is the only choice 598 // We should improve this once we generate flags and targets 599 CallConv::SystemV 600 } 601 602 fn generate_type(&mut self) -> Result<Type> { 603 // TODO: It would be nice if we could get these directly from cranelift 604 let scalars = [ 605 // IFLAGS, FFLAGS, 606 B1, // B8, B16, B32, B64, B128, 607 I8, I16, I32, I64, I128, F32, F64, 608 // R32, R64, 609 ]; 610 // TODO: vector types 611 612 let ty = self.u.choose(&scalars[..])?; 613 Ok(*ty) 614 } 615 616 fn generate_abi_param(&mut self) -> Result<AbiParam> { 617 let value_type = self.generate_type()?; 618 // TODO: There are more argument purposes to be explored... 619 let purpose = ArgumentPurpose::Normal; 620 let extension = match self.u.int_in_range(0..=2)? { 621 2 => ArgumentExtension::Sext, 622 1 => ArgumentExtension::Uext, 623 _ => ArgumentExtension::None, 624 }; 625 626 Ok(AbiParam { 627 value_type, 628 purpose, 629 extension, 630 }) 631 } 632 633 fn generate_signature(&mut self) -> Result<Signature> { 634 let callconv = self.generate_callconv()?; 635 let mut sig = Signature::new(callconv); 636 637 for _ in 0..self.param(&self.config.signature_params)? { 638 sig.params.push(self.generate_abi_param()?); 639 } 640 641 for _ in 0..self.param(&self.config.signature_rets)? { 642 sig.returns.push(self.generate_abi_param()?); 643 } 644 645 Ok(sig) 646 } 647 648 /// Finds a stack slot with size of at least n bytes 649 fn stack_slot_with_size(&mut self, n: u32) -> Result<(StackSlot, StackSize)> { 650 let first = self 651 .resources 652 .stack_slots 653 .partition_point(|&(_slot, size)| size < n); 654 Ok(*self.u.choose(&self.resources.stack_slots[first..])?) 655 } 656 657 /// Generates an address that should allow for a store or a load. 658 /// 659 /// Addresses aren't generated like other values. They are never stored in variables so that 660 /// we don't run the risk of returning them from a function, which would make the fuzzer 661 /// complain since they are different from the interpreter to the backend. 662 /// 663 /// The address is not guaranteed to be valid, but there's a chance that it is. 664 /// 665 /// `min_size`: Controls the amount of space that the address should have.This is not 666 /// guaranteed to be respected 667 fn generate_load_store_address( 668 &mut self, 669 builder: &mut FunctionBuilder, 670 min_size: u32, 671 ) -> Result<(Value, Offset32)> { 672 // TODO: Currently our only source of addresses is stack_addr, but we should 673 // add heap_addr, global_value, symbol_value eventually 674 let (addr, available_size) = { 675 let (ss, slot_size) = self.stack_slot_with_size(min_size)?; 676 let max_offset = slot_size.saturating_sub(min_size); 677 let offset = self.u.int_in_range(0..=max_offset)? as i32; 678 let base_addr = builder.ins().stack_addr(I64, ss, offset); 679 let available_size = (slot_size as i32).saturating_sub(offset); 680 (base_addr, available_size) 681 }; 682 683 // TODO: Insert a bunch of amode opcodes here to modify the address! 684 685 // Now that we have an address and a size, we just choose a random offset to return to the 686 // caller. Try to preserve min_size bytes. 687 let max_offset = available_size.saturating_sub(min_size as i32); 688 let offset = self.u.int_in_range(0..=max_offset)? as i32; 689 690 Ok((addr, offset.into())) 691 } 692 693 /// Get a variable of type `ty` from the current function 694 fn get_variable_of_type(&mut self, ty: Type) -> Result<Variable> { 695 let opts = self.resources.vars.get(&ty).map_or(&[][..], Vec::as_slice); 696 let var = self.u.choose(opts)?; 697 Ok(*var) 698 } 699 700 /// Generates an instruction(`iconst`/`fconst`/etc...) to introduce a constant value 701 fn generate_const(&mut self, builder: &mut FunctionBuilder, ty: Type) -> Result<Value> { 702 Ok(match ty { 703 I128 => { 704 // See: https://github.com/bytecodealliance/wasmtime/issues/2906 705 let hi = builder.ins().iconst(I64, self.u.arbitrary::<i64>()?); 706 let lo = builder.ins().iconst(I64, self.u.arbitrary::<i64>()?); 707 builder.ins().iconcat(lo, hi) 708 } 709 ty if ty.is_int() => { 710 let imm64 = match ty { 711 I8 => self.u.arbitrary::<i8>()? as i64, 712 I16 => self.u.arbitrary::<i16>()? as i64, 713 I32 => self.u.arbitrary::<i32>()? as i64, 714 I64 => self.u.arbitrary::<i64>()?, 715 _ => unreachable!(), 716 }; 717 builder.ins().iconst(ty, imm64) 718 } 719 ty if ty.is_bool() => builder.ins().bconst(ty, bool::arbitrary(self.u)?), 720 // f{32,64}::arbitrary does not generate a bunch of important values 721 // such as Signaling NaN's / NaN's with payload, so generate floats from integers. 722 F32 => builder 723 .ins() 724 .f32const(f32::from_bits(u32::arbitrary(self.u)?)), 725 F64 => builder 726 .ins() 727 .f64const(f64::from_bits(u64::arbitrary(self.u)?)), 728 _ => unimplemented!(), 729 }) 730 } 731 732 /// Chooses a random block which can be targeted by a jump / branch. 733 /// This means any block that is not the first block. 734 /// 735 /// For convenience we also generate values that match the block's signature 736 fn generate_target_block( 737 &mut self, 738 builder: &mut FunctionBuilder, 739 ) -> Result<(Block, Vec<Value>)> { 740 let block_targets = &self.resources.blocks[1..]; 741 let (block, signature) = self.u.choose(block_targets)?.clone(); 742 let args = self.generate_values_for_signature(builder, signature.into_iter())?; 743 Ok((block, args)) 744 } 745 746 fn generate_values_for_signature<I: Iterator<Item = Type>>( 747 &mut self, 748 builder: &mut FunctionBuilder, 749 signature: I, 750 ) -> Result<Vec<Value>> { 751 signature 752 .map(|ty| { 753 let var = self.get_variable_of_type(ty)?; 754 let val = builder.use_var(var); 755 Ok(val) 756 }) 757 .collect() 758 } 759 760 fn generate_return(&mut self, builder: &mut FunctionBuilder) -> Result<()> { 761 let types: Vec<Type> = { 762 let rets = &builder.func.signature.returns; 763 rets.iter().map(|p| p.value_type).collect() 764 }; 765 let vals = self.generate_values_for_signature(builder, types.into_iter())?; 766 767 builder.ins().return_(&vals[..]); 768 Ok(()) 769 } 770 771 fn generate_jump(&mut self, builder: &mut FunctionBuilder) -> Result<()> { 772 let (block, args) = self.generate_target_block(builder)?; 773 builder.ins().jump(block, &args[..]); 774 Ok(()) 775 } 776 777 /// Generates a br_table into a random block 778 fn generate_br_table(&mut self, builder: &mut FunctionBuilder) -> Result<()> { 779 let var = self.get_variable_of_type(I32)?; // br_table only supports I32 780 let val = builder.use_var(var); 781 782 let default_block = *self.u.choose(&self.resources.blocks_without_params)?; 783 784 let jt = *self.u.choose(&self.resources.jump_tables)?; 785 builder.ins().br_table(val, default_block, jt); 786 Ok(()) 787 } 788 789 /// Generates a brz/brnz into a random block 790 fn generate_br(&mut self, builder: &mut FunctionBuilder) -> Result<()> { 791 let (block, args) = self.generate_target_block(builder)?; 792 793 let condbr_types = [I8, I16, I32, I64, I128, B1]; 794 let _type = *self.u.choose(&condbr_types[..])?; 795 let var = self.get_variable_of_type(_type)?; 796 let val = builder.use_var(var); 797 798 if bool::arbitrary(self.u)? { 799 builder.ins().brz(val, block, &args[..]); 800 } else { 801 builder.ins().brnz(val, block, &args[..]); 802 } 803 804 // After brz/brnz we must generate a jump 805 self.generate_jump(builder)?; 806 Ok(()) 807 } 808 809 fn generate_bricmp(&mut self, builder: &mut FunctionBuilder) -> Result<()> { 810 let (block, args) = self.generate_target_block(builder)?; 811 let cond = *self.u.choose(IntCC::all())?; 812 813 let bricmp_types = [ 814 I8, I16, I32, 815 I64, 816 // I128 - TODO: https://github.com/bytecodealliance/wasmtime/issues/4406 817 ]; 818 let _type = *self.u.choose(&bricmp_types[..])?; 819 820 let lhs_var = self.get_variable_of_type(_type)?; 821 let lhs_val = builder.use_var(lhs_var); 822 823 let rhs_var = self.get_variable_of_type(_type)?; 824 let rhs_val = builder.use_var(rhs_var); 825 826 builder 827 .ins() 828 .br_icmp(cond, lhs_val, rhs_val, block, &args[..]); 829 830 // After bricmp's we must generate a jump 831 self.generate_jump(builder)?; 832 Ok(()) 833 } 834 835 fn generate_switch(&mut self, builder: &mut FunctionBuilder) -> Result<()> { 836 let _type = *self.u.choose(&[I8, I16, I32, I64, I128][..])?; 837 let switch_var = self.get_variable_of_type(_type)?; 838 let switch_val = builder.use_var(switch_var); 839 840 let default_block = *self.u.choose(&self.resources.blocks_without_params)?; 841 842 // Build this into a HashMap since we cannot have duplicate entries. 843 let mut entries = HashMap::new(); 844 for _ in 0..self.param(&self.config.switch_cases)? { 845 // The Switch API only allows for entries that are addressable by the index type 846 // so we need to limit the range of values that we generate. 847 let (ty_min, ty_max) = _type.bounds(false); 848 let range_start = self.u.int_in_range(ty_min..=ty_max)?; 849 850 // We can either insert a contiguous range of blocks or a individual block 851 // This is done because the Switch API specializes contiguous ranges. 852 let range_size = if bool::arbitrary(self.u)? { 853 1 854 } else { 855 self.param(&self.config.switch_max_range_size)? 856 } as u128; 857 858 // Build the switch entries 859 for i in 0..range_size { 860 let index = range_start.wrapping_add(i) % ty_max; 861 let block = *self.u.choose(&self.resources.blocks_without_params)?; 862 entries.insert(index, block); 863 } 864 } 865 866 let mut switch = Switch::new(); 867 for (entry, block) in entries.into_iter() { 868 switch.set_entry(entry, block); 869 } 870 switch.emit(builder, switch_val, default_block); 871 872 Ok(()) 873 } 874 875 /// We always need to exit safely out of a block. 876 /// This either means a jump into another block or a return. 877 fn finalize_block(&mut self, builder: &mut FunctionBuilder) -> Result<()> { 878 let gen = self.u.choose( 879 &[ 880 Self::generate_bricmp, 881 Self::generate_br, 882 Self::generate_br_table, 883 Self::generate_jump, 884 Self::generate_return, 885 Self::generate_switch, 886 ][..], 887 )?; 888 889 gen(self, builder) 890 } 891 892 /// Fills the current block with random instructions 893 fn generate_instructions(&mut self, builder: &mut FunctionBuilder) -> Result<()> { 894 for _ in 0..self.param(&self.config.instructions_per_block)? { 895 let (op, args, rets, inserter) = *self.u.choose(OPCODE_SIGNATURES)?; 896 inserter(self, builder, op, args, rets)?; 897 } 898 899 Ok(()) 900 } 901 902 fn generate_jumptables(&mut self, builder: &mut FunctionBuilder) -> Result<()> { 903 for _ in 0..self.param(&self.config.jump_tables_per_function)? { 904 let mut jt_data = JumpTableData::new(); 905 906 for _ in 0..self.param(&self.config.jump_table_entries)? { 907 let block = *self.u.choose(&self.resources.blocks_without_params)?; 908 jt_data.push_entry(block); 909 } 910 911 self.resources 912 .jump_tables 913 .push(builder.create_jump_table(jt_data)); 914 } 915 Ok(()) 916 } 917 918 fn generate_funcrefs(&mut self, builder: &mut FunctionBuilder) -> Result<()> { 919 let count = self.param(&self.config.funcrefs_per_function)?; 920 for func_index in 0..count.try_into().unwrap() { 921 let (ext_name, sig) = if self.u.arbitrary::<bool>()? { 922 let user_func_ref = builder 923 .func 924 .declare_imported_user_function(UserExternalName { 925 namespace: 0, 926 index: func_index, 927 }); 928 let name = ExternalName::User(user_func_ref); 929 let signature = self.generate_signature()?; 930 (name, signature) 931 } else { 932 let libcall = *self.u.choose(ALLOWED_LIBCALLS)?; 933 // TODO: Use [CallConv::for_libcall] once we generate flags. 934 let callconv = self.system_callconv(); 935 let signature = libcall.signature(callconv); 936 (ExternalName::LibCall(libcall), signature) 937 }; 938 939 let sig_ref = builder.import_signature(sig.clone()); 940 let func_ref = builder.import_function(ExtFuncData { 941 name: ext_name, 942 signature: sig_ref, 943 colocated: self.u.arbitrary()?, 944 }); 945 946 self.resources.func_refs.push((sig, func_ref)); 947 } 948 949 Ok(()) 950 } 951 952 fn generate_stack_slots(&mut self, builder: &mut FunctionBuilder) -> Result<()> { 953 for _ in 0..self.param(&self.config.static_stack_slots_per_function)? { 954 let bytes = self.param(&self.config.static_stack_slot_size)? as u32; 955 let ss_data = StackSlotData::new(StackSlotKind::ExplicitSlot, bytes); 956 let slot = builder.create_sized_stack_slot(ss_data); 957 self.resources.stack_slots.push((slot, bytes)); 958 } 959 960 self.resources 961 .stack_slots 962 .sort_unstable_by_key(|&(_slot, bytes)| bytes); 963 964 Ok(()) 965 } 966 967 /// Zero initializes the stack slot by inserting `stack_store`'s. 968 fn initialize_stack_slots(&mut self, builder: &mut FunctionBuilder) -> Result<()> { 969 let i128_zero = builder.ins().iconst(I128, 0); 970 let i64_zero = builder.ins().iconst(I64, 0); 971 let i32_zero = builder.ins().iconst(I32, 0); 972 let i16_zero = builder.ins().iconst(I16, 0); 973 let i8_zero = builder.ins().iconst(I8, 0); 974 975 for &(slot, init_size) in self.resources.stack_slots.iter() { 976 let mut size = init_size; 977 978 // Insert the largest available store for the remaining size. 979 while size != 0 { 980 let offset = (init_size - size) as i32; 981 let (val, filled) = match size { 982 sz if sz / 16 > 0 => (i128_zero, 16), 983 sz if sz / 8 > 0 => (i64_zero, 8), 984 sz if sz / 4 > 0 => (i32_zero, 4), 985 sz if sz / 2 > 0 => (i16_zero, 2), 986 _ => (i8_zero, 1), 987 }; 988 builder.ins().stack_store(val, slot, offset); 989 size -= filled; 990 } 991 } 992 Ok(()) 993 } 994 995 /// Creates a random amount of blocks in this function 996 fn generate_blocks( 997 &mut self, 998 builder: &mut FunctionBuilder, 999 sig: &Signature, 1000 ) -> Result<Vec<(Block, BlockSignature)>> { 1001 let extra_block_count = self.param(&self.config.blocks_per_function)?; 1002 1003 // We must always have at least one block, so we generate the "extra" blocks and add 1 for 1004 // the entry block. 1005 let block_count = 1 + extra_block_count; 1006 1007 (0..block_count) 1008 .map(|i| { 1009 let is_entry = i == 0; 1010 let block = builder.create_block(); 1011 1012 // Optionally mark blocks that are not the entry block as cold 1013 if !is_entry { 1014 if bool::arbitrary(self.u)? { 1015 builder.set_cold_block(block); 1016 } 1017 } 1018 1019 // The first block has to have the function signature, but for the rest of them we generate 1020 // a random signature; 1021 if is_entry { 1022 builder.append_block_params_for_function_params(block); 1023 Ok((block, sig.params.iter().map(|a| a.value_type).collect())) 1024 } else { 1025 let sig = self.generate_block_signature()?; 1026 sig.iter().for_each(|ty| { 1027 builder.append_block_param(block, *ty); 1028 }); 1029 Ok((block, sig)) 1030 } 1031 }) 1032 .collect() 1033 } 1034 1035 fn generate_block_signature(&mut self) -> Result<BlockSignature> { 1036 let param_count = self.param(&self.config.block_signature_params)?; 1037 1038 let mut params = Vec::with_capacity(param_count); 1039 for _ in 0..param_count { 1040 params.push(self.generate_type()?); 1041 } 1042 Ok(params) 1043 } 1044 1045 fn build_variable_pool(&mut self, builder: &mut FunctionBuilder) -> Result<()> { 1046 let block = builder.current_block().unwrap(); 1047 1048 // Define variables for the function signature 1049 let mut vars: Vec<_> = builder 1050 .func 1051 .signature 1052 .params 1053 .iter() 1054 .map(|param| param.value_type) 1055 .zip(builder.block_params(block).iter().copied()) 1056 .collect(); 1057 1058 // Create a pool of vars that are going to be used in this function 1059 for _ in 0..self.param(&self.config.vars_per_function)? { 1060 let ty = self.generate_type()?; 1061 let value = self.generate_const(builder, ty)?; 1062 vars.push((ty, value)); 1063 } 1064 1065 for (id, (ty, value)) in vars.into_iter().enumerate() { 1066 let var = Variable::new(id); 1067 builder.declare_var(var, ty); 1068 builder.def_var(var, value); 1069 self.resources 1070 .vars 1071 .entry(ty) 1072 .or_insert_with(Vec::new) 1073 .push(var); 1074 } 1075 1076 Ok(()) 1077 } 1078 1079 /// We generate a function in multiple stages: 1080 /// 1081 /// * First we generate a random number of empty blocks 1082 /// * Then we generate a random pool of variables to be used throughout the function 1083 /// * We then visit each block and generate random instructions 1084 /// 1085 /// Because we generate all blocks and variables up front we already know everything that 1086 /// we need when generating instructions (i.e. jump targets / variables) 1087 pub fn generate(mut self) -> Result<Function> { 1088 let sig = self.generate_signature()?; 1089 1090 let mut fn_builder_ctx = FunctionBuilderContext::new(); 1091 // function name must be in a different namespace than TESTFILE_NAMESPACE (0) 1092 let mut func = Function::with_name_signature(UserFuncName::user(1, 0), sig.clone()); 1093 1094 let mut builder = FunctionBuilder::new(&mut func, &mut fn_builder_ctx); 1095 1096 self.resources.blocks = self.generate_blocks(&mut builder, &sig)?; 1097 1098 // Valid blocks for jump tables have to have no parameters in the signature, and must also 1099 // not be the first block. 1100 self.resources.blocks_without_params = self.resources.blocks[1..] 1101 .iter() 1102 .filter(|(_, sig)| sig.len() == 0) 1103 .map(|(b, _)| *b) 1104 .collect(); 1105 1106 // Function preamble 1107 self.generate_jumptables(&mut builder)?; 1108 self.generate_funcrefs(&mut builder)?; 1109 self.generate_stack_slots(&mut builder)?; 1110 1111 // Main instruction generation loop 1112 for (i, (block, block_sig)) in self.resources.blocks.clone().iter().enumerate() { 1113 let is_block0 = i == 0; 1114 builder.switch_to_block(*block); 1115 1116 if is_block0 { 1117 // The first block is special because we must create variables both for the 1118 // block signature and for the variable pool. Additionally, we must also define 1119 // initial values for all variables that are not the function signature. 1120 self.build_variable_pool(&mut builder)?; 1121 1122 // Stack slots have random bytes at the beginning of the function 1123 // initialize them to a constant value so that execution stays predictable. 1124 self.initialize_stack_slots(&mut builder)?; 1125 } else { 1126 // Define variables for the block params 1127 for (i, ty) in block_sig.iter().enumerate() { 1128 let var = self.get_variable_of_type(*ty)?; 1129 let block_param = builder.block_params(*block)[i]; 1130 builder.def_var(var, block_param); 1131 } 1132 } 1133 1134 // Generate block instructions 1135 self.generate_instructions(&mut builder)?; 1136 1137 self.finalize_block(&mut builder)?; 1138 } 1139 1140 builder.seal_all_blocks(); 1141 builder.finalize(); 1142 1143 Ok(func) 1144 } 1145 } 1146