1 //! Defines `Module` and related types. 2 3 // TODO: Should `ir::Function` really have a `name`? 4 5 // TODO: Factor out `ir::Function`'s `ext_funcs` and `global_values` into a struct 6 // shared with `DataContext`? 7 8 use super::HashMap; 9 use crate::data_context::DataContext; 10 use cranelift_codegen::binemit; 11 use cranelift_codegen::entity::{entity_impl, PrimaryMap}; 12 use cranelift_codegen::{ir, isa, CodegenError, Context}; 13 use std::borrow::ToOwned; 14 use std::string::String; 15 16 /// A function identifier for use in the `Module` interface. 17 #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] 18 pub struct FuncId(u32); 19 entity_impl!(FuncId, "funcid"); 20 21 /// Function identifiers are namespace 0 in `ir::ExternalName` 22 impl From<FuncId> for ir::ExternalName { 23 fn from(id: FuncId) -> Self { 24 Self::User { 25 namespace: 0, 26 index: id.0, 27 } 28 } 29 } 30 31 impl FuncId { 32 /// Get the `FuncId` for the function named by `name`. 33 pub fn from_name(name: &ir::ExternalName) -> FuncId { 34 if let ir::ExternalName::User { namespace, index } = *name { 35 debug_assert_eq!(namespace, 0); 36 FuncId::from_u32(index) 37 } else { 38 panic!("unexpected ExternalName kind {}", name) 39 } 40 } 41 } 42 43 /// A data object identifier for use in the `Module` interface. 44 #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] 45 pub struct DataId(u32); 46 entity_impl!(DataId, "dataid"); 47 48 /// Data identifiers are namespace 1 in `ir::ExternalName` 49 impl From<DataId> for ir::ExternalName { 50 fn from(id: DataId) -> Self { 51 Self::User { 52 namespace: 1, 53 index: id.0, 54 } 55 } 56 } 57 58 impl DataId { 59 /// Get the `DataId` for the data object named by `name`. 60 pub fn from_name(name: &ir::ExternalName) -> DataId { 61 if let ir::ExternalName::User { namespace, index } = *name { 62 debug_assert_eq!(namespace, 1); 63 DataId::from_u32(index) 64 } else { 65 panic!("unexpected ExternalName kind {}", name) 66 } 67 } 68 } 69 70 /// Linkage refers to where an entity is defined and who can see it. 71 #[derive(Copy, Clone, Debug, PartialEq, Eq)] 72 pub enum Linkage { 73 /// Defined outside of a module. 74 Import, 75 /// Defined inside the module, but not visible outside it. 76 Local, 77 /// Defined inside the module, visible outside it, and may be preempted. 78 Preemptible, 79 /// Defined inside the module, visible inside the current static linkage unit, but not outside. 80 /// 81 /// A static linkage unit is the combination of all object files passed to a linker to create 82 /// an executable or dynamic library. 83 Hidden, 84 /// Defined inside the module, and visible outside it. 85 Export, 86 } 87 88 impl Linkage { 89 fn merge(a: Self, b: Self) -> Self { 90 match a { 91 Self::Export => Self::Export, 92 Self::Hidden => match b { 93 Self::Export => Self::Export, 94 Self::Preemptible => Self::Preemptible, 95 _ => Self::Hidden, 96 }, 97 Self::Preemptible => match b { 98 Self::Export => Self::Export, 99 _ => Self::Preemptible, 100 }, 101 Self::Local => match b { 102 Self::Export => Self::Export, 103 Self::Hidden => Self::Hidden, 104 Self::Preemptible => Self::Preemptible, 105 Self::Local | Self::Import => Self::Local, 106 }, 107 Self::Import => b, 108 } 109 } 110 111 /// Test whether this linkage can have a definition. 112 pub fn is_definable(self) -> bool { 113 match self { 114 Self::Import => false, 115 Self::Local | Self::Preemptible | Self::Hidden | Self::Export => true, 116 } 117 } 118 119 /// Test whether this linkage will have a definition that cannot be preempted. 120 pub fn is_final(self) -> bool { 121 match self { 122 Self::Import | Self::Preemptible => false, 123 Self::Local | Self::Hidden | Self::Export => true, 124 } 125 } 126 } 127 128 /// A declared name may refer to either a function or data declaration 129 #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)] 130 pub enum FuncOrDataId { 131 /// When it's a FuncId 132 Func(FuncId), 133 /// When it's a DataId 134 Data(DataId), 135 } 136 137 /// Mapping to `ir::ExternalName` is trivial based on the `FuncId` and `DataId` mapping. 138 impl From<FuncOrDataId> for ir::ExternalName { 139 fn from(id: FuncOrDataId) -> Self { 140 match id { 141 FuncOrDataId::Func(funcid) => Self::from(funcid), 142 FuncOrDataId::Data(dataid) => Self::from(dataid), 143 } 144 } 145 } 146 147 /// Information about a function which can be called. 148 #[derive(Debug)] 149 pub struct FunctionDeclaration { 150 pub name: String, 151 pub linkage: Linkage, 152 pub signature: ir::Signature, 153 } 154 155 impl FunctionDeclaration { 156 fn merge(&mut self, linkage: Linkage, sig: &ir::Signature) -> Result<(), ModuleError> { 157 self.linkage = Linkage::merge(self.linkage, linkage); 158 if &self.signature != sig { 159 return Err(ModuleError::IncompatibleSignature( 160 self.name.clone(), 161 self.signature.clone(), 162 sig.clone(), 163 )); 164 } 165 Ok(()) 166 } 167 } 168 169 /// Error messages for all `Module` methods 170 #[derive(Debug)] 171 pub enum ModuleError { 172 /// Indicates an identifier was used before it was declared 173 Undeclared(String), 174 175 /// Indicates an identifier was used as data/function first, but then used as the other 176 IncompatibleDeclaration(String), 177 178 /// Indicates a function identifier was declared with a 179 /// different signature than declared previously 180 IncompatibleSignature(String, ir::Signature, ir::Signature), 181 182 /// Indicates an identifier was defined more than once 183 DuplicateDefinition(String), 184 185 /// Indicates an identifier was defined, but was declared as an import 186 InvalidImportDefinition(String), 187 188 /// Wraps a `cranelift-codegen` error 189 Compilation(CodegenError), 190 191 /// Wraps a generic error from a backend 192 Backend(anyhow::Error), 193 } 194 195 // This is manually implementing Error and Display instead of using thiserror to reduce the amount 196 // of dependencies used by Cranelift. 197 impl std::error::Error for ModuleError { 198 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { 199 match self { 200 Self::Undeclared { .. } 201 | Self::IncompatibleDeclaration { .. } 202 | Self::IncompatibleSignature { .. } 203 | Self::DuplicateDefinition { .. } 204 | Self::InvalidImportDefinition { .. } => None, 205 Self::Compilation(source) => Some(source), 206 Self::Backend(source) => Some(&**source), 207 } 208 } 209 } 210 211 impl std::fmt::Display for ModuleError { 212 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 213 match self { 214 Self::Undeclared(name) => { 215 write!(f, "Undeclared identifier: {}", name) 216 } 217 Self::IncompatibleDeclaration(name) => { 218 write!(f, "Incompatible declaration of identifier: {}", name,) 219 } 220 Self::IncompatibleSignature(name, prev_sig, new_sig) => { 221 write!( 222 f, 223 "Function {} signature {:?} is incompatible with previous declaration {:?}", 224 name, new_sig, prev_sig, 225 ) 226 } 227 Self::DuplicateDefinition(name) => { 228 write!(f, "Duplicate definition of identifier: {}", name) 229 } 230 Self::InvalidImportDefinition(name) => { 231 write!( 232 f, 233 "Invalid to define identifier declared as an import: {}", 234 name, 235 ) 236 } 237 Self::Compilation(err) => { 238 write!(f, "Compilation error: {}", err) 239 } 240 Self::Backend(err) => write!(f, "Backend error: {}", err), 241 } 242 } 243 } 244 245 impl std::convert::From<CodegenError> for ModuleError { 246 fn from(source: CodegenError) -> Self { 247 Self::Compilation { 0: source } 248 } 249 } 250 251 /// A convenient alias for a `Result` that uses `ModuleError` as the error type. 252 pub type ModuleResult<T> = Result<T, ModuleError>; 253 254 /// Information about a data object which can be accessed. 255 #[derive(Debug)] 256 pub struct DataDeclaration { 257 pub name: String, 258 pub linkage: Linkage, 259 pub writable: bool, 260 pub tls: bool, 261 } 262 263 impl DataDeclaration { 264 fn merge(&mut self, linkage: Linkage, writable: bool, tls: bool) { 265 self.linkage = Linkage::merge(self.linkage, linkage); 266 self.writable = self.writable || writable; 267 assert_eq!( 268 self.tls, tls, 269 "Can't change TLS data object to normal or in the opposite way", 270 ); 271 } 272 } 273 274 /// This provides a view to the state of a module which allows `ir::ExternalName`s to be translated 275 /// into `FunctionDeclaration`s and `DataDeclaration`s. 276 #[derive(Debug, Default)] 277 pub struct ModuleDeclarations { 278 names: HashMap<String, FuncOrDataId>, 279 functions: PrimaryMap<FuncId, FunctionDeclaration>, 280 data_objects: PrimaryMap<DataId, DataDeclaration>, 281 } 282 283 impl ModuleDeclarations { 284 /// Get the module identifier for a given name, if that name 285 /// has been declared. 286 pub fn get_name(&self, name: &str) -> Option<FuncOrDataId> { 287 self.names.get(name).copied() 288 } 289 290 /// Get an iterator of all function declarations 291 pub fn get_functions(&self) -> impl Iterator<Item = (FuncId, &FunctionDeclaration)> { 292 self.functions.iter() 293 } 294 295 /// Return whether `name` names a function, rather than a data object. 296 pub fn is_function(name: &ir::ExternalName) -> bool { 297 if let ir::ExternalName::User { namespace, .. } = *name { 298 namespace == 0 299 } else { 300 panic!("unexpected ExternalName kind {}", name) 301 } 302 } 303 304 /// Get the `FunctionDeclaration` for the function named by `name`. 305 pub fn get_function_decl(&self, func_id: FuncId) -> &FunctionDeclaration { 306 &self.functions[func_id] 307 } 308 309 /// Get an iterator of all data declarations 310 pub fn get_data_objects(&self) -> impl Iterator<Item = (DataId, &DataDeclaration)> { 311 self.data_objects.iter() 312 } 313 314 /// Get the `DataDeclaration` for the data object named by `name`. 315 pub fn get_data_decl(&self, data_id: DataId) -> &DataDeclaration { 316 &self.data_objects[data_id] 317 } 318 319 /// Declare a function in this module. 320 pub fn declare_function( 321 &mut self, 322 name: &str, 323 linkage: Linkage, 324 signature: &ir::Signature, 325 ) -> ModuleResult<(FuncId, Linkage)> { 326 // TODO: Can we avoid allocating names so often? 327 use super::hash_map::Entry::*; 328 match self.names.entry(name.to_owned()) { 329 Occupied(entry) => match *entry.get() { 330 FuncOrDataId::Func(id) => { 331 let existing = &mut self.functions[id]; 332 existing.merge(linkage, signature)?; 333 Ok((id, existing.linkage)) 334 } 335 FuncOrDataId::Data(..) => { 336 Err(ModuleError::IncompatibleDeclaration(name.to_owned())) 337 } 338 }, 339 Vacant(entry) => { 340 let id = self.functions.push(FunctionDeclaration { 341 name: name.to_owned(), 342 linkage, 343 signature: signature.clone(), 344 }); 345 entry.insert(FuncOrDataId::Func(id)); 346 Ok((id, self.functions[id].linkage)) 347 } 348 } 349 } 350 351 /// Declare an anonymous function in this module. 352 pub fn declare_anonymous_function( 353 &mut self, 354 signature: &ir::Signature, 355 ) -> ModuleResult<FuncId> { 356 let id = self.functions.push(FunctionDeclaration { 357 name: String::new(), 358 linkage: Linkage::Local, 359 signature: signature.clone(), 360 }); 361 self.functions[id].name = format!(".L{:?}", id); 362 Ok(id) 363 } 364 365 /// Declare a data object in this module. 366 pub fn declare_data( 367 &mut self, 368 name: &str, 369 linkage: Linkage, 370 writable: bool, 371 tls: bool, 372 ) -> ModuleResult<(DataId, Linkage)> { 373 // TODO: Can we avoid allocating names so often? 374 use super::hash_map::Entry::*; 375 match self.names.entry(name.to_owned()) { 376 Occupied(entry) => match *entry.get() { 377 FuncOrDataId::Data(id) => { 378 let existing = &mut self.data_objects[id]; 379 existing.merge(linkage, writable, tls); 380 Ok((id, existing.linkage)) 381 } 382 383 FuncOrDataId::Func(..) => { 384 Err(ModuleError::IncompatibleDeclaration(name.to_owned())) 385 } 386 }, 387 Vacant(entry) => { 388 let id = self.data_objects.push(DataDeclaration { 389 name: name.to_owned(), 390 linkage, 391 writable, 392 tls, 393 }); 394 entry.insert(FuncOrDataId::Data(id)); 395 Ok((id, self.data_objects[id].linkage)) 396 } 397 } 398 } 399 400 /// Declare an anonymous data object in this module. 401 pub fn declare_anonymous_data(&mut self, writable: bool, tls: bool) -> ModuleResult<DataId> { 402 let id = self.data_objects.push(DataDeclaration { 403 name: String::new(), 404 linkage: Linkage::Local, 405 writable, 406 tls, 407 }); 408 self.data_objects[id].name = format!(".L{:?}", id); 409 Ok(id) 410 } 411 } 412 413 /// Information about the compiled function. 414 pub struct ModuleCompiledFunction { 415 /// The size of the compiled function. 416 pub size: binemit::CodeOffset, 417 } 418 419 /// A record of a relocation to perform. 420 #[derive(Clone)] 421 pub struct RelocRecord { 422 /// Where in the generated code this relocation is to be applied. 423 pub offset: binemit::CodeOffset, 424 /// The kind of relocation this represents. 425 pub reloc: binemit::Reloc, 426 /// What symbol we're relocating against. 427 pub name: ir::ExternalName, 428 /// The offset to add to the relocation. 429 pub addend: binemit::Addend, 430 } 431 432 /// A `Module` is a utility for collecting functions and data objects, and linking them together. 433 pub trait Module { 434 /// Return the `TargetIsa` to compile for. 435 fn isa(&self) -> &dyn isa::TargetIsa; 436 437 /// Get all declarations in this module. 438 fn declarations(&self) -> &ModuleDeclarations; 439 440 /// Get the module identifier for a given name, if that name 441 /// has been declared. 442 fn get_name(&self, name: &str) -> Option<FuncOrDataId> { 443 self.declarations().get_name(name) 444 } 445 446 /// Return the target information needed by frontends to produce Cranelift IR 447 /// for the current target. 448 fn target_config(&self) -> isa::TargetFrontendConfig { 449 self.isa().frontend_config() 450 } 451 452 /// Create a new `Context` initialized for use with this `Module`. 453 /// 454 /// This ensures that the `Context` is initialized with the default calling 455 /// convention for the `TargetIsa`. 456 fn make_context(&self) -> Context { 457 let mut ctx = Context::new(); 458 ctx.func.signature.call_conv = self.isa().default_call_conv(); 459 ctx 460 } 461 462 /// Clear the given `Context` and reset it for use with a new function. 463 /// 464 /// This ensures that the `Context` is initialized with the default calling 465 /// convention for the `TargetIsa`. 466 fn clear_context(&self, ctx: &mut Context) { 467 ctx.clear(); 468 ctx.func.signature.call_conv = self.isa().default_call_conv(); 469 } 470 471 /// Create a new empty `Signature` with the default calling convention for 472 /// the `TargetIsa`, to which parameter and return types can be added for 473 /// declaring a function to be called by this `Module`. 474 fn make_signature(&self) -> ir::Signature { 475 ir::Signature::new(self.isa().default_call_conv()) 476 } 477 478 /// Clear the given `Signature` and reset for use with a new function. 479 /// 480 /// This ensures that the `Signature` is initialized with the default 481 /// calling convention for the `TargetIsa`. 482 fn clear_signature(&self, sig: &mut ir::Signature) { 483 sig.clear(self.isa().default_call_conv()); 484 } 485 486 /// Declare a function in this module. 487 fn declare_function( 488 &mut self, 489 name: &str, 490 linkage: Linkage, 491 signature: &ir::Signature, 492 ) -> ModuleResult<FuncId>; 493 494 /// Declare an anonymous function in this module. 495 fn declare_anonymous_function(&mut self, signature: &ir::Signature) -> ModuleResult<FuncId>; 496 497 /// Declare a data object in this module. 498 fn declare_data( 499 &mut self, 500 name: &str, 501 linkage: Linkage, 502 writable: bool, 503 tls: bool, 504 ) -> ModuleResult<DataId>; 505 506 /// Declare an anonymous data object in this module. 507 fn declare_anonymous_data(&mut self, writable: bool, tls: bool) -> ModuleResult<DataId>; 508 509 /// Use this when you're building the IR of a function to reference a function. 510 /// 511 /// TODO: Coalesce redundant decls and signatures. 512 /// TODO: Look into ways to reduce the risk of using a FuncRef in the wrong function. 513 fn declare_func_in_func(&self, func: FuncId, in_func: &mut ir::Function) -> ir::FuncRef { 514 let decl = &self.declarations().functions[func]; 515 let signature = in_func.import_signature(decl.signature.clone()); 516 let colocated = decl.linkage.is_final(); 517 in_func.import_function(ir::ExtFuncData { 518 name: ir::ExternalName::user(0, func.as_u32()), 519 signature, 520 colocated, 521 }) 522 } 523 524 /// Use this when you're building the IR of a function to reference a data object. 525 /// 526 /// TODO: Same as above. 527 fn declare_data_in_func(&self, data: DataId, func: &mut ir::Function) -> ir::GlobalValue { 528 let decl = &self.declarations().data_objects[data]; 529 let colocated = decl.linkage.is_final(); 530 func.create_global_value(ir::GlobalValueData::Symbol { 531 name: ir::ExternalName::user(1, data.as_u32()), 532 offset: ir::immediates::Imm64::new(0), 533 colocated, 534 tls: decl.tls, 535 }) 536 } 537 538 /// TODO: Same as above. 539 fn declare_func_in_data(&self, func: FuncId, ctx: &mut DataContext) -> ir::FuncRef { 540 ctx.import_function(ir::ExternalName::user(0, func.as_u32())) 541 } 542 543 /// TODO: Same as above. 544 fn declare_data_in_data(&self, data: DataId, ctx: &mut DataContext) -> ir::GlobalValue { 545 ctx.import_global_value(ir::ExternalName::user(1, data.as_u32())) 546 } 547 548 /// Define a function, producing the function body from the given `Context`. 549 /// 550 /// Returns the size of the function's code and constant data. 551 /// 552 /// Note: After calling this function the given `Context` will contain the compiled function. 553 fn define_function( 554 &mut self, 555 func: FuncId, 556 ctx: &mut Context, 557 trap_sink: &mut dyn binemit::TrapSink, 558 stack_map_sink: &mut dyn binemit::StackMapSink, 559 ) -> ModuleResult<ModuleCompiledFunction>; 560 561 /// Define a function, taking the function body from the given `bytes`. 562 /// 563 /// This function is generally only useful if you need to precisely specify 564 /// the emitted instructions for some reason; otherwise, you should use 565 /// `define_function`. 566 /// 567 /// Returns the size of the function's code. 568 fn define_function_bytes( 569 &mut self, 570 func: FuncId, 571 bytes: &[u8], 572 relocs: &[RelocRecord], 573 ) -> ModuleResult<ModuleCompiledFunction>; 574 575 /// Define a data object, producing the data contents from the given `DataContext`. 576 fn define_data(&mut self, data: DataId, data_ctx: &DataContext) -> ModuleResult<()>; 577 } 578 579 impl<M: Module> Module for &mut M { 580 fn isa(&self) -> &dyn isa::TargetIsa { 581 (**self).isa() 582 } 583 584 fn declarations(&self) -> &ModuleDeclarations { 585 (**self).declarations() 586 } 587 588 fn get_name(&self, name: &str) -> Option<FuncOrDataId> { 589 (**self).get_name(name) 590 } 591 592 fn target_config(&self) -> isa::TargetFrontendConfig { 593 (**self).target_config() 594 } 595 596 fn make_context(&self) -> Context { 597 (**self).make_context() 598 } 599 600 fn clear_context(&self, ctx: &mut Context) { 601 (**self).clear_context(ctx) 602 } 603 604 fn make_signature(&self) -> ir::Signature { 605 (**self).make_signature() 606 } 607 608 fn clear_signature(&self, sig: &mut ir::Signature) { 609 (**self).clear_signature(sig) 610 } 611 612 fn declare_function( 613 &mut self, 614 name: &str, 615 linkage: Linkage, 616 signature: &ir::Signature, 617 ) -> ModuleResult<FuncId> { 618 (**self).declare_function(name, linkage, signature) 619 } 620 621 fn declare_anonymous_function(&mut self, signature: &ir::Signature) -> ModuleResult<FuncId> { 622 (**self).declare_anonymous_function(signature) 623 } 624 625 fn declare_data( 626 &mut self, 627 name: &str, 628 linkage: Linkage, 629 writable: bool, 630 tls: bool, 631 ) -> ModuleResult<DataId> { 632 (**self).declare_data(name, linkage, writable, tls) 633 } 634 635 fn declare_anonymous_data(&mut self, writable: bool, tls: bool) -> ModuleResult<DataId> { 636 (**self).declare_anonymous_data(writable, tls) 637 } 638 639 fn declare_func_in_func(&self, func: FuncId, in_func: &mut ir::Function) -> ir::FuncRef { 640 (**self).declare_func_in_func(func, in_func) 641 } 642 643 fn declare_data_in_func(&self, data: DataId, func: &mut ir::Function) -> ir::GlobalValue { 644 (**self).declare_data_in_func(data, func) 645 } 646 647 fn declare_func_in_data(&self, func: FuncId, ctx: &mut DataContext) -> ir::FuncRef { 648 (**self).declare_func_in_data(func, ctx) 649 } 650 651 fn declare_data_in_data(&self, data: DataId, ctx: &mut DataContext) -> ir::GlobalValue { 652 (**self).declare_data_in_data(data, ctx) 653 } 654 655 fn define_function( 656 &mut self, 657 func: FuncId, 658 ctx: &mut Context, 659 trap_sink: &mut dyn binemit::TrapSink, 660 stack_map_sink: &mut dyn binemit::StackMapSink, 661 ) -> ModuleResult<ModuleCompiledFunction> { 662 (**self).define_function(func, ctx, trap_sink, stack_map_sink) 663 } 664 665 fn define_function_bytes( 666 &mut self, 667 func: FuncId, 668 bytes: &[u8], 669 relocs: &[RelocRecord], 670 ) -> ModuleResult<ModuleCompiledFunction> { 671 (**self).define_function_bytes(func, bytes, relocs) 672 } 673 674 fn define_data(&mut self, data: DataId, data_ctx: &DataContext) -> ModuleResult<()> { 675 (**self).define_data(data, data_ctx) 676 } 677 } 678