Fork of daniellemaywood.uk/gleam — Wasm codegen work
2

Configure Feed

Select the types of activity you want to include in your feed.

gleam / compiler-core / src / cranelift.rs
22 kB 635 lines
1use std::collections::HashMap; 2 3use cranelift::{ 4 codegen::{ 5 Context, 6 ir::{BlockArg, immediates::Offset32}, 7 }, 8 prelude::*, 9}; 10use cranelift_module::{Linkage, Module, default_libcall_names}; 11use cranelift_object::{ObjectBuilder, ObjectModule}; 12use ecow::{EcoString, eco_format}; 13use itertools::Itertools as _; 14 15use crate::cranelift::mir::ast; 16 17pub mod mir; 18 19struct CodeGen<M: Module> { 20 module: M, 21 context: Context, 22 function_context: FunctionBuilderContext, 23} 24 25pub fn compile(module: ast::Module<ast::CompleteType>) -> Vec<u8> { 26 let mut flag_builder = settings::builder(); 27 28 flag_builder 29 .set("is_pic", "true") 30 .expect("unable to set `is_pic` to false"); 31 32 let isa = cranelift_native::builder() 33 .unwrap_or_else(|reason| panic!("host machine not support: {reason}")) 34 .finish(settings::Flags::new(flag_builder)) 35 .expect("unable to build isa target"); 36 37 let mut cranelift = { 38 let module = ObjectModule::new( 39 ObjectBuilder::new(isa, module.name.to_string(), default_libcall_names()) 40 .expect("unable to build object builder"), 41 ); 42 43 CodeGen { 44 function_context: FunctionBuilderContext::new(), 45 context: module.make_context(), 46 module, 47 } 48 }; 49 50 for function in module.functions { 51 FunctionTranslator::new(&mut cranelift).translate(module.name.clone(), function); 52 } 53 54 let product = cranelift.module.finish(); 55 56 product.emit().expect("unable to emit finished product") 57} 58 59struct FunctionTranslator<'m, M: Module> { 60 cg: &'m mut CodeGen<M>, 61} 62 63fn mangle_type_name(type_: &ast::CompleteType) -> EcoString { 64 match type_ { 65 ast::CompleteType::Int => "I".into(), 66 ast::CompleteType::Float => "F".into(), 67 ast::CompleteType::Bool => "B".into(), 68 ast::CompleteType::String => "S".into(), 69 ast::CompleteType::Func { arguments, returns } => { 70 let arguments = arguments 71 .iter() 72 .map(mangle_type_name) 73 .map(|s| eco_format!("{}{}", s.len(), s)) 74 .join(""); 75 76 let returns = mangle_type_name(returns); 77 78 eco_format!("F{}f{}R{}", arguments.len(), arguments, returns) 79 } 80 ast::CompleteType::Tuple { elements } => { 81 let elements = elements 82 .iter() 83 .map(mangle_type_name) 84 .map(|s| eco_format!("{}{}", s.len(), s)) 85 .join(""); 86 87 eco_format!("T{}t{}", elements.len(), elements) 88 } 89 ast::CompleteType::Struct { elements } => { 90 let elements = elements 91 .iter() 92 .map(mangle_type_name) 93 .map(|s| eco_format!("{}{}", s.len(), s)) 94 .join(""); 95 96 eco_format!("C{}c{}", elements.len(), elements) 97 } 98 ast::CompleteType::List(element_type) => { 99 let element = mangle_type_name(element_type); 100 101 eco_format!("L{}{}", element.len(), element) 102 } 103 } 104} 105 106fn mangled_function_name( 107 module: EcoString, 108 name: EcoString, 109 arguments: &[ast::CompleteType], 110 returns: &ast::CompleteType, 111) -> EcoString { 112 let arguments = arguments 113 .iter() 114 .map(mangle_type_name) 115 .map(|s| eco_format!("{}{}", s.len(), s)) 116 .join(""); 117 let returns = mangle_type_name(returns); 118 119 eco_format!( 120 "M{}{}_{}{}_A{}a{}_R{}", 121 module.len(), 122 module.replace("/", "_"), 123 name.len(), 124 name, 125 arguments.len(), 126 arguments, 127 returns, 128 ) 129} 130 131impl<'m, M: Module> FunctionTranslator<'m, M> { 132 fn new(cg: &'m mut CodeGen<M>) -> Self { 133 Self { cg } 134 } 135 136 fn translate(self, module: EcoString, function: ast::Function<ast::CompleteType>) { 137 let arguments: Vec<_> = function 138 .parameters 139 .iter() 140 .map(|parameter| parameter.type_.clone()) 141 .collect(); 142 143 let name = mangled_function_name( 144 module, 145 function.name.clone(), 146 &arguments, 147 &function.return_type, 148 ); 149 150 self.cg.context.func.signature = self.signature_from_function(&function); 151 152 let mut builder = 153 FunctionBuilder::new(&mut self.cg.context.func, &mut self.cg.function_context); 154 155 let entry = builder.create_block(); 156 builder.append_block_params_for_function_params(entry); 157 builder.switch_to_block(entry); 158 builder.seal_block(entry); 159 160 let value = { 161 let mut translator = ExpressionTranslator::new(&mut self.cg.module, &mut builder); 162 163 for (index, parameter) in function.parameters.iter().enumerate() { 164 if let Some(name) = &parameter.name { 165 let var_type = translate_type(&parameter.type_); 166 let var = translator.builder.declare_var(var_type); 167 _ = translator.vars.insert(name.clone(), var); 168 169 let val = translator.builder.block_params(entry)[index]; 170 translator.builder.def_var(var, val); 171 } 172 } 173 174 translator.translate(function.body) 175 }; 176 177 _ = builder.ins().return_(&[value]); 178 179 builder.finalize(); 180 181 let id = self 182 .cg 183 .module 184 .declare_function(&name, Linkage::Export, &self.cg.context.func.signature) 185 .expect("unable to declare function"); 186 187 self.cg 188 .module 189 .define_function(id, &mut self.cg.context) 190 .expect("unable to define function"); 191 192 self.cg.module.clear_context(&mut self.cg.context); 193 } 194 195 fn signature_from_function(&self, function: &ast::Function<ast::CompleteType>) -> Signature { 196 let mut sig = self.cg.module.make_signature(); 197 198 for parameter in &function.parameters { 199 sig.params 200 .push(AbiParam::new(translate_type(&parameter.type_))); 201 } 202 203 sig.returns 204 .push(AbiParam::new(translate_type(&function.return_type))); 205 206 return sig; 207 } 208} 209 210fn translate_type(type_: &ast::CompleteType) -> Type { 211 match type_ { 212 ast::CompleteType::Int => types::I64, 213 ast::CompleteType::Float => types::F64, 214 ast::CompleteType::Bool => types::I64, // wasteful but whatever 215 ast::CompleteType::String => types::I64, 216 ast::CompleteType::Func { 217 arguments: _, 218 returns: _, 219 } => types::I64, 220 ast::CompleteType::Tuple { elements: _ } => types::I64, 221 ast::CompleteType::Struct { elements: _ } => types::I64, 222 ast::CompleteType::List(_complete_type) => types::I64, 223 } 224} 225 226struct ExpressionTranslator<'m, 'b, M: Module> { 227 module: &'m mut M, 228 builder: &'m mut FunctionBuilder<'b>, 229 vars: HashMap<EcoString, Variable>, 230} 231 232impl<'m, 'b, M: Module> ExpressionTranslator<'m, 'b, M> { 233 fn new(module: &'m mut M, builder: &'m mut FunctionBuilder<'b>) -> Self { 234 Self { 235 module, 236 builder, 237 vars: Default::default(), 238 } 239 } 240 241 fn translate(&mut self, expression: ast::Expression<ast::CompleteType>) -> Value { 242 _ = self.module; 243 244 match expression { 245 ast::Expression::Block(expressions) => expressions 246 .into_iter() 247 .map(|expression| self.translate(expression)) 248 .last() 249 .expect("block should be non-empty"), 250 ast::Expression::FunctionRef { 251 module, 252 name, 253 arity: _, 254 type_, 255 } => { 256 let ast::CompleteType::Func { arguments, returns } = type_ else { 257 unreachable!("function ref should have func type") 258 }; 259 260 let name = mangled_function_name(module, name, &arguments, &returns); 261 let sig = { 262 let mut sig = self.module.make_signature(); 263 for argument in arguments { 264 sig.params.push(AbiParam::new(translate_type(&argument))); 265 } 266 sig.returns.push(AbiParam::new(translate_type(&returns))); 267 sig 268 }; 269 270 let id = self 271 .module 272 .declare_function(&name, Linkage::Import, &sig) 273 .expect("unable to declare function for import"); 274 275 let func = self.module.declare_func_in_func(id, self.builder.func); 276 277 self.builder.ins().func_addr(types::I64, func) 278 } 279 ast::Expression::Var(var) => { 280 let var = self 281 .vars 282 .get(&var.name) 283 .cloned() 284 .expect("variable to be defined"); 285 286 self.builder.use_var(var) 287 } 288 ast::Expression::Int { value } => { 289 let value = i64::try_from(value).expect("integer value too large"); 290 291 self.builder.ins().iconst(types::I64, value) 292 } 293 ast::Expression::Float { value } => { 294 let value: f64 = value.parse().expect("invalid float value"); 295 296 self.builder.ins().f64const(value) 297 } 298 ast::Expression::Bool { value } => match value { 299 true => self.builder.ins().iconst(types::I64, 1), 300 false => self.builder.ins().iconst(types::I64, 0), 301 }, 302 ast::Expression::String { value: _ } => todo!(), 303 ast::Expression::Equals { lhs, rhs } => match lhs.type_() { 304 ast::CompleteType::Int => { 305 let lhs = self.translate(*lhs); 306 let rhs = self.translate(*rhs); 307 308 self.builder.ins().icmp(IntCC::Equal, lhs, rhs) 309 } 310 ast::CompleteType::Float => todo!(), 311 ast::CompleteType::Bool => todo!(), 312 ast::CompleteType::String => todo!(), 313 ast::CompleteType::Func { 314 arguments: _, 315 returns: _, 316 } => todo!(), 317 ast::CompleteType::Tuple { elements: _ } => todo!(), 318 ast::CompleteType::Struct { elements: _ } => todo!(), 319 ast::CompleteType::List(_complete_type) => todo!(), 320 }, 321 ast::Expression::NotEquals { lhs: _, rhs: _ } => todo!(), 322 ast::Expression::IntGt { lhs, rhs } => { 323 let lhs = self.translate(*lhs); 324 let rhs = self.translate(*rhs); 325 326 self.builder.ins().icmp(IntCC::SignedGreaterThan, lhs, rhs) 327 } 328 ast::Expression::IntGtEq { lhs, rhs } => { 329 let lhs = self.translate(*lhs); 330 let rhs = self.translate(*rhs); 331 332 self.builder 333 .ins() 334 .icmp(IntCC::SignedGreaterThanOrEqual, lhs, rhs) 335 } 336 ast::Expression::IntLt { lhs, rhs } => { 337 let lhs = self.translate(*lhs); 338 let rhs = self.translate(*rhs); 339 340 self.builder.ins().icmp(IntCC::SignedLessThan, lhs, rhs) 341 } 342 ast::Expression::IntLtEq { lhs, rhs } => { 343 let lhs = self.translate(*lhs); 344 let rhs = self.translate(*rhs); 345 346 self.builder 347 .ins() 348 .icmp(IntCC::SignedLessThanOrEqual, lhs, rhs) 349 } 350 ast::Expression::IntAdd { lhs, rhs } => { 351 let lhs = self.translate(*lhs); 352 let rhs = self.translate(*rhs); 353 354 self.builder.ins().iadd(lhs, rhs) 355 } 356 ast::Expression::IntSub { lhs, rhs } => { 357 let lhs = self.translate(*lhs); 358 let rhs = self.translate(*rhs); 359 360 self.builder.ins().isub(lhs, rhs) 361 } 362 ast::Expression::IntMul { lhs, rhs } => { 363 let lhs = self.translate(*lhs); 364 let rhs = self.translate(*rhs); 365 366 self.builder.ins().imul(lhs, rhs) 367 } 368 ast::Expression::IntDiv { lhs, rhs } => { 369 let lhs = self.translate(*lhs); 370 let rhs = self.translate(*rhs); 371 372 self.builder.ins().sdiv(lhs, rhs) 373 } 374 ast::Expression::IntRem { lhs, rhs } => { 375 let lhs = self.translate(*lhs); 376 let rhs = self.translate(*rhs); 377 378 self.builder.ins().srem(lhs, rhs) 379 } 380 ast::Expression::FloatGt { lhs, rhs } => { 381 let lhs = self.translate(*lhs); 382 let rhs = self.translate(*rhs); 383 384 self.builder.ins().fcmp(FloatCC::GreaterThan, lhs, rhs) 385 } 386 ast::Expression::FloatGtEq { lhs, rhs } => { 387 let lhs = self.translate(*lhs); 388 let rhs = self.translate(*rhs); 389 390 self.builder 391 .ins() 392 .fcmp(FloatCC::GreaterThanOrEqual, lhs, rhs) 393 } 394 ast::Expression::FloatLt { lhs, rhs } => { 395 let lhs = self.translate(*lhs); 396 let rhs = self.translate(*rhs); 397 398 self.builder.ins().fcmp(FloatCC::LessThan, lhs, rhs) 399 } 400 ast::Expression::FloatLtEq { lhs, rhs } => { 401 let lhs = self.translate(*lhs); 402 let rhs = self.translate(*rhs); 403 404 self.builder.ins().fcmp(FloatCC::LessThanOrEqual, lhs, rhs) 405 } 406 ast::Expression::FloatAdd { lhs, rhs } => { 407 let lhs = self.translate(*lhs); 408 let rhs = self.translate(*rhs); 409 410 self.builder.ins().fadd(lhs, rhs) 411 } 412 ast::Expression::FloatSub { lhs, rhs } => { 413 let lhs = self.translate(*lhs); 414 let rhs = self.translate(*rhs); 415 416 self.builder.ins().fsub(lhs, rhs) 417 } 418 ast::Expression::FloatMul { lhs, rhs } => { 419 let lhs = self.translate(*lhs); 420 let rhs = self.translate(*rhs); 421 422 self.builder.ins().fmul(lhs, rhs) 423 } 424 ast::Expression::FloatDiv { lhs, rhs } => { 425 let lhs = self.translate(*lhs); 426 let rhs = self.translate(*rhs); 427 428 self.builder.ins().fdiv(lhs, rhs) 429 } 430 ast::Expression::StringConcat { lhs: _, rhs: _ } => todo!(), 431 ast::Expression::List { 432 items: _, 433 tail: _, 434 type_: _, 435 } => todo!(), 436 ast::Expression::Tuple { items, type_: _ } => { 437 let mut sig = self.module.make_signature(); 438 sig.params.push(AbiParam::new(types::I64)); 439 sig.returns.push(AbiParam::new(types::I64)); 440 441 let id = self 442 .module 443 .declare_function("malloc", Linkage::Import, &sig) 444 .expect("failed to declare malloc"); 445 446 let malloc = self.module.declare_func_in_func(id, &mut self.builder.func); 447 448 let size_arg = self 449 .builder 450 .ins() 451 .iconst(types::I64, (items.len() as i64) * 8); 452 453 let call = self.builder.ins().call(malloc, &[size_arg]); 454 let ptr = self.builder.inst_results(call)[0]; 455 456 for (index, item) in items.into_iter().enumerate() { 457 let index = index as i32; 458 459 let value = self.translate(item); 460 461 _ = self.builder.ins().store( 462 MemFlags::new(), 463 value, 464 ptr, 465 Offset32::new(index * 8), 466 ); 467 } 468 469 ptr 470 } 471 ast::Expression::TupleAccess { 472 value, 473 index, 474 type_, 475 } => { 476 let ptr = self.translate(*value); 477 478 self.builder.ins().load( 479 translate_type(&type_), 480 MemFlags::new(), 481 ptr, 482 Offset32::new(index as i32 * 8), 483 ) 484 } 485 ast::Expression::Struct { 486 tag, 487 items, 488 type_: _, 489 } => { 490 let mut sig = self.module.make_signature(); 491 sig.params.push(AbiParam::new(types::I64)); 492 sig.returns.push(AbiParam::new(types::I64)); 493 494 let id = self 495 .module 496 .declare_function("malloc", Linkage::Import, &sig) 497 .expect("failed to declare malloc"); 498 499 let malloc = self.module.declare_func_in_func(id, &mut self.builder.func); 500 501 let size_arg = self 502 .builder 503 .ins() 504 .iconst(types::I64, (items.len() as i64) * 8 + 8); 505 506 let call = self.builder.ins().call(malloc, &[size_arg]); 507 let ptr = self.builder.inst_results(call)[0]; 508 509 let tag = self.builder.ins().iconst(types::I64, i64::from(tag)); 510 _ = self 511 .builder 512 .ins() 513 .store(MemFlags::new(), tag, ptr, Offset32::new(0)); 514 515 for (index, item) in items.into_iter().enumerate() { 516 let index = index as i32 + 1; 517 518 let value = self.translate(item); 519 520 _ = self.builder.ins().store( 521 MemFlags::new(), 522 value, 523 ptr, 524 Offset32::new(index * 8), 525 ); 526 } 527 528 ptr 529 } 530 ast::Expression::StructTag { value } => { 531 let ptr = self.translate(*value); 532 533 self.builder 534 .ins() 535 .load(types::I64, MemFlags::new(), ptr, Offset32::new(0)) 536 } 537 ast::Expression::StructAccess { 538 value, 539 index, 540 type_, 541 } => { 542 let ptr = self.translate(*value); 543 544 self.builder.ins().load( 545 translate_type(&type_), 546 MemFlags::new(), 547 ptr, 548 Offset32::new(index as i32 * 8 + 8), 549 ) 550 } 551 ast::Expression::Set { name, value } => { 552 let var = self.builder.declare_var(translate_type(&value.type_())); 553 _ = self.vars.insert(name.name, var); 554 555 let val = self.translate(*value); 556 self.builder.def_var(var, val); 557 self.builder.use_var(var) 558 } 559 ast::Expression::If { cond, then, else_ } => { 560 let cond = self.translate(*cond); 561 562 let then_block = self.builder.create_block(); 563 let else_block = self.builder.create_block(); 564 let merge_block = self.builder.create_block(); 565 566 _ = self 567 .builder 568 .append_block_param(merge_block, translate_type(&then.type_())); 569 570 _ = self 571 .builder 572 .ins() 573 .brif(cond, then_block, &[], else_block, &[]); 574 575 self.builder.switch_to_block(then_block); 576 self.builder.seal_block(then_block); 577 578 let then_return = self.translate(*then); 579 _ = self 580 .builder 581 .ins() 582 .jump(merge_block, &[BlockArg::Value(then_return)]); 583 584 self.builder.switch_to_block(else_block); 585 self.builder.seal_block(else_block); 586 587 let else_return = self.translate(*else_); 588 _ = self 589 .builder 590 .ins() 591 .jump(merge_block, &[BlockArg::Value(else_return)]); 592 593 self.builder.switch_to_block(merge_block); 594 self.builder.seal_block(merge_block); 595 596 self.builder.block_params(merge_block)[0] 597 } 598 ast::Expression::Call { 599 target, 600 args, 601 type_, 602 } => { 603 let mut signature = self.module.make_signature(); 604 605 for arg in &args { 606 signature 607 .params 608 .push(AbiParam::new(translate_type(&arg.type_()))); 609 } 610 signature 611 .returns 612 .push(AbiParam::new(translate_type(&type_))); 613 614 let target = self.translate(*target); 615 let args: Vec<_> = args.into_iter().map(|arg| self.translate(arg)).collect(); 616 617 let sig = self.builder.import_signature(signature); 618 let call = self.builder.ins().call_indirect(sig, target, &args); 619 620 self.builder.inst_results(call)[0] 621 } 622 ast::Expression::Panic { type_, .. } => match type_ { 623 ast::CompleteType::Func { .. } 624 | ast::CompleteType::Tuple { .. } 625 | ast::CompleteType::Struct { .. } 626 | ast::CompleteType::List(_) 627 | ast::CompleteType::String 628 | ast::CompleteType::Bool 629 | ast::CompleteType::Int => self.builder.ins().iconst(types::I64, 0), 630 631 ast::CompleteType::Float => self.builder.ins().f64const(0.0), 632 }, 633 } 634 } 635}