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::entity::{entity_impl, PrimaryMap}; 11 use cranelift_codegen::{binemit, MachReloc}; 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 `Module` is a utility for collecting functions and data objects, and linking them together. 420 pub trait Module { 421 /// Return the `TargetIsa` to compile for. 422 fn isa(&self) -> &dyn isa::TargetIsa; 423 424 /// Get all declarations in this module. 425 fn declarations(&self) -> &ModuleDeclarations; 426 427 /// Get the module identifier for a given name, if that name 428 /// has been declared. 429 fn get_name(&self, name: &str) -> Option<FuncOrDataId> { 430 self.declarations().get_name(name) 431 } 432 433 /// Return the target information needed by frontends to produce Cranelift IR 434 /// for the current target. 435 fn target_config(&self) -> isa::TargetFrontendConfig { 436 self.isa().frontend_config() 437 } 438 439 /// Create a new `Context` initialized for use with this `Module`. 440 /// 441 /// This ensures that the `Context` is initialized with the default calling 442 /// convention for the `TargetIsa`. 443 fn make_context(&self) -> Context { 444 let mut ctx = Context::new(); 445 ctx.func.signature.call_conv = self.isa().default_call_conv(); 446 ctx 447 } 448 449 /// Clear the given `Context` and reset it for use with a new function. 450 /// 451 /// This ensures that the `Context` is initialized with the default calling 452 /// convention for the `TargetIsa`. 453 fn clear_context(&self, ctx: &mut Context) { 454 ctx.clear(); 455 ctx.func.signature.call_conv = self.isa().default_call_conv(); 456 } 457 458 /// Create a new empty `Signature` with the default calling convention for 459 /// the `TargetIsa`, to which parameter and return types can be added for 460 /// declaring a function to be called by this `Module`. 461 fn make_signature(&self) -> ir::Signature { 462 ir::Signature::new(self.isa().default_call_conv()) 463 } 464 465 /// Clear the given `Signature` and reset for use with a new function. 466 /// 467 /// This ensures that the `Signature` is initialized with the default 468 /// calling convention for the `TargetIsa`. 469 fn clear_signature(&self, sig: &mut ir::Signature) { 470 sig.clear(self.isa().default_call_conv()); 471 } 472 473 /// Declare a function in this module. 474 fn declare_function( 475 &mut self, 476 name: &str, 477 linkage: Linkage, 478 signature: &ir::Signature, 479 ) -> ModuleResult<FuncId>; 480 481 /// Declare an anonymous function in this module. 482 fn declare_anonymous_function(&mut self, signature: &ir::Signature) -> ModuleResult<FuncId>; 483 484 /// Declare a data object in this module. 485 fn declare_data( 486 &mut self, 487 name: &str, 488 linkage: Linkage, 489 writable: bool, 490 tls: bool, 491 ) -> ModuleResult<DataId>; 492 493 /// Declare an anonymous data object in this module. 494 fn declare_anonymous_data(&mut self, writable: bool, tls: bool) -> ModuleResult<DataId>; 495 496 /// Use this when you're building the IR of a function to reference a function. 497 /// 498 /// TODO: Coalesce redundant decls and signatures. 499 /// TODO: Look into ways to reduce the risk of using a FuncRef in the wrong function. 500 fn declare_func_in_func(&self, func: FuncId, in_func: &mut ir::Function) -> ir::FuncRef { 501 let decl = &self.declarations().functions[func]; 502 let signature = in_func.import_signature(decl.signature.clone()); 503 let colocated = decl.linkage.is_final(); 504 in_func.import_function(ir::ExtFuncData { 505 name: ir::ExternalName::user(0, func.as_u32()), 506 signature, 507 colocated, 508 }) 509 } 510 511 /// Use this when you're building the IR of a function to reference a data object. 512 /// 513 /// TODO: Same as above. 514 fn declare_data_in_func(&self, data: DataId, func: &mut ir::Function) -> ir::GlobalValue { 515 let decl = &self.declarations().data_objects[data]; 516 let colocated = decl.linkage.is_final(); 517 func.create_global_value(ir::GlobalValueData::Symbol { 518 name: ir::ExternalName::user(1, data.as_u32()), 519 offset: ir::immediates::Imm64::new(0), 520 colocated, 521 tls: decl.tls, 522 }) 523 } 524 525 /// TODO: Same as above. 526 fn declare_func_in_data(&self, func: FuncId, ctx: &mut DataContext) -> ir::FuncRef { 527 ctx.import_function(ir::ExternalName::user(0, func.as_u32())) 528 } 529 530 /// TODO: Same as above. 531 fn declare_data_in_data(&self, data: DataId, ctx: &mut DataContext) -> ir::GlobalValue { 532 ctx.import_global_value(ir::ExternalName::user(1, data.as_u32())) 533 } 534 535 /// Define a function, producing the function body from the given `Context`. 536 /// 537 /// Returns the size of the function's code and constant data. 538 /// 539 /// Note: After calling this function the given `Context` will contain the compiled function. 540 fn define_function( 541 &mut self, 542 func: FuncId, 543 ctx: &mut Context, 544 ) -> ModuleResult<ModuleCompiledFunction>; 545 546 /// Define a function, taking the function body from the given `bytes`. 547 /// 548 /// This function is generally only useful if you need to precisely specify 549 /// the emitted instructions for some reason; otherwise, you should use 550 /// `define_function`. 551 /// 552 /// Returns the size of the function's code. 553 fn define_function_bytes( 554 &mut self, 555 func: FuncId, 556 bytes: &[u8], 557 relocs: &[MachReloc], 558 ) -> ModuleResult<ModuleCompiledFunction>; 559 560 /// Define a data object, producing the data contents from the given `DataContext`. 561 fn define_data(&mut self, data: DataId, data_ctx: &DataContext) -> ModuleResult<()>; 562 } 563 564 impl<M: Module> Module for &mut M { 565 fn isa(&self) -> &dyn isa::TargetIsa { 566 (**self).isa() 567 } 568 569 fn declarations(&self) -> &ModuleDeclarations { 570 (**self).declarations() 571 } 572 573 fn get_name(&self, name: &str) -> Option<FuncOrDataId> { 574 (**self).get_name(name) 575 } 576 577 fn target_config(&self) -> isa::TargetFrontendConfig { 578 (**self).target_config() 579 } 580 581 fn make_context(&self) -> Context { 582 (**self).make_context() 583 } 584 585 fn clear_context(&self, ctx: &mut Context) { 586 (**self).clear_context(ctx) 587 } 588 589 fn make_signature(&self) -> ir::Signature { 590 (**self).make_signature() 591 } 592 593 fn clear_signature(&self, sig: &mut ir::Signature) { 594 (**self).clear_signature(sig) 595 } 596 597 fn declare_function( 598 &mut self, 599 name: &str, 600 linkage: Linkage, 601 signature: &ir::Signature, 602 ) -> ModuleResult<FuncId> { 603 (**self).declare_function(name, linkage, signature) 604 } 605 606 fn declare_anonymous_function(&mut self, signature: &ir::Signature) -> ModuleResult<FuncId> { 607 (**self).declare_anonymous_function(signature) 608 } 609 610 fn declare_data( 611 &mut self, 612 name: &str, 613 linkage: Linkage, 614 writable: bool, 615 tls: bool, 616 ) -> ModuleResult<DataId> { 617 (**self).declare_data(name, linkage, writable, tls) 618 } 619 620 fn declare_anonymous_data(&mut self, writable: bool, tls: bool) -> ModuleResult<DataId> { 621 (**self).declare_anonymous_data(writable, tls) 622 } 623 624 fn declare_func_in_func(&self, func: FuncId, in_func: &mut ir::Function) -> ir::FuncRef { 625 (**self).declare_func_in_func(func, in_func) 626 } 627 628 fn declare_data_in_func(&self, data: DataId, func: &mut ir::Function) -> ir::GlobalValue { 629 (**self).declare_data_in_func(data, func) 630 } 631 632 fn declare_func_in_data(&self, func: FuncId, ctx: &mut DataContext) -> ir::FuncRef { 633 (**self).declare_func_in_data(func, ctx) 634 } 635 636 fn declare_data_in_data(&self, data: DataId, ctx: &mut DataContext) -> ir::GlobalValue { 637 (**self).declare_data_in_data(data, ctx) 638 } 639 640 fn define_function( 641 &mut self, 642 func: FuncId, 643 ctx: &mut Context, 644 ) -> ModuleResult<ModuleCompiledFunction> { 645 (**self).define_function(func, ctx) 646 } 647 648 fn define_function_bytes( 649 &mut self, 650 func: FuncId, 651 bytes: &[u8], 652 relocs: &[MachReloc], 653 ) -> ModuleResult<ModuleCompiledFunction> { 654 (**self).define_function_bytes(func, bytes, relocs) 655 } 656 657 fn define_data(&mut self, data: DataId, data_ctx: &DataContext) -> ModuleResult<()> { 658 (**self).define_data(data, data_ctx) 659 } 660 } 661