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, CompileError, 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 impl<'a> From<CompileError<'a>> for ModuleError { 196 fn from(err: CompileError<'a>) -> Self { 197 Self::Compilation(err.inner) 198 } 199 } 200 201 // This is manually implementing Error and Display instead of using thiserror to reduce the amount 202 // of dependencies used by Cranelift. 203 impl std::error::Error for ModuleError { 204 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { 205 match self { 206 Self::Undeclared { .. } 207 | Self::IncompatibleDeclaration { .. } 208 | Self::IncompatibleSignature { .. } 209 | Self::DuplicateDefinition { .. } 210 | Self::InvalidImportDefinition { .. } => None, 211 Self::Compilation(source) => Some(source), 212 Self::Backend(source) => Some(&**source), 213 } 214 } 215 } 216 217 impl std::fmt::Display for ModuleError { 218 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 219 match self { 220 Self::Undeclared(name) => { 221 write!(f, "Undeclared identifier: {}", name) 222 } 223 Self::IncompatibleDeclaration(name) => { 224 write!(f, "Incompatible declaration of identifier: {}", name,) 225 } 226 Self::IncompatibleSignature(name, prev_sig, new_sig) => { 227 write!( 228 f, 229 "Function {} signature {:?} is incompatible with previous declaration {:?}", 230 name, new_sig, prev_sig, 231 ) 232 } 233 Self::DuplicateDefinition(name) => { 234 write!(f, "Duplicate definition of identifier: {}", name) 235 } 236 Self::InvalidImportDefinition(name) => { 237 write!( 238 f, 239 "Invalid to define identifier declared as an import: {}", 240 name, 241 ) 242 } 243 Self::Compilation(err) => { 244 write!(f, "Compilation error: {}", err) 245 } 246 Self::Backend(err) => write!(f, "Backend error: {}", err), 247 } 248 } 249 } 250 251 impl std::convert::From<CodegenError> for ModuleError { 252 fn from(source: CodegenError) -> Self { 253 Self::Compilation { 0: source } 254 } 255 } 256 257 /// A convenient alias for a `Result` that uses `ModuleError` as the error type. 258 pub type ModuleResult<T> = Result<T, ModuleError>; 259 260 /// Information about a data object which can be accessed. 261 #[derive(Debug)] 262 pub struct DataDeclaration { 263 pub name: String, 264 pub linkage: Linkage, 265 pub writable: bool, 266 pub tls: bool, 267 } 268 269 impl DataDeclaration { 270 fn merge(&mut self, linkage: Linkage, writable: bool, tls: bool) { 271 self.linkage = Linkage::merge(self.linkage, linkage); 272 self.writable = self.writable || writable; 273 assert_eq!( 274 self.tls, tls, 275 "Can't change TLS data object to normal or in the opposite way", 276 ); 277 } 278 } 279 280 /// This provides a view to the state of a module which allows `ir::ExternalName`s to be translated 281 /// into `FunctionDeclaration`s and `DataDeclaration`s. 282 #[derive(Debug, Default)] 283 pub struct ModuleDeclarations { 284 names: HashMap<String, FuncOrDataId>, 285 functions: PrimaryMap<FuncId, FunctionDeclaration>, 286 data_objects: PrimaryMap<DataId, DataDeclaration>, 287 } 288 289 impl ModuleDeclarations { 290 /// Get the module identifier for a given name, if that name 291 /// has been declared. 292 pub fn get_name(&self, name: &str) -> Option<FuncOrDataId> { 293 self.names.get(name).copied() 294 } 295 296 /// Get an iterator of all function declarations 297 pub fn get_functions(&self) -> impl Iterator<Item = (FuncId, &FunctionDeclaration)> { 298 self.functions.iter() 299 } 300 301 /// Return whether `name` names a function, rather than a data object. 302 pub fn is_function(name: &ir::ExternalName) -> bool { 303 if let ir::ExternalName::User { namespace, .. } = *name { 304 namespace == 0 305 } else { 306 panic!("unexpected ExternalName kind {}", name) 307 } 308 } 309 310 /// Get the `FunctionDeclaration` for the function named by `name`. 311 pub fn get_function_decl(&self, func_id: FuncId) -> &FunctionDeclaration { 312 &self.functions[func_id] 313 } 314 315 /// Get an iterator of all data declarations 316 pub fn get_data_objects(&self) -> impl Iterator<Item = (DataId, &DataDeclaration)> { 317 self.data_objects.iter() 318 } 319 320 /// Get the `DataDeclaration` for the data object named by `name`. 321 pub fn get_data_decl(&self, data_id: DataId) -> &DataDeclaration { 322 &self.data_objects[data_id] 323 } 324 325 /// Declare a function in this module. 326 pub fn declare_function( 327 &mut self, 328 name: &str, 329 linkage: Linkage, 330 signature: &ir::Signature, 331 ) -> ModuleResult<(FuncId, Linkage)> { 332 // TODO: Can we avoid allocating names so often? 333 use super::hash_map::Entry::*; 334 match self.names.entry(name.to_owned()) { 335 Occupied(entry) => match *entry.get() { 336 FuncOrDataId::Func(id) => { 337 let existing = &mut self.functions[id]; 338 existing.merge(linkage, signature)?; 339 Ok((id, existing.linkage)) 340 } 341 FuncOrDataId::Data(..) => { 342 Err(ModuleError::IncompatibleDeclaration(name.to_owned())) 343 } 344 }, 345 Vacant(entry) => { 346 let id = self.functions.push(FunctionDeclaration { 347 name: name.to_owned(), 348 linkage, 349 signature: signature.clone(), 350 }); 351 entry.insert(FuncOrDataId::Func(id)); 352 Ok((id, self.functions[id].linkage)) 353 } 354 } 355 } 356 357 /// Declare an anonymous function in this module. 358 pub fn declare_anonymous_function( 359 &mut self, 360 signature: &ir::Signature, 361 ) -> ModuleResult<FuncId> { 362 let id = self.functions.push(FunctionDeclaration { 363 name: String::new(), 364 linkage: Linkage::Local, 365 signature: signature.clone(), 366 }); 367 self.functions[id].name = format!(".L{:?}", id); 368 Ok(id) 369 } 370 371 /// Declare a data object in this module. 372 pub fn declare_data( 373 &mut self, 374 name: &str, 375 linkage: Linkage, 376 writable: bool, 377 tls: bool, 378 ) -> ModuleResult<(DataId, Linkage)> { 379 // TODO: Can we avoid allocating names so often? 380 use super::hash_map::Entry::*; 381 match self.names.entry(name.to_owned()) { 382 Occupied(entry) => match *entry.get() { 383 FuncOrDataId::Data(id) => { 384 let existing = &mut self.data_objects[id]; 385 existing.merge(linkage, writable, tls); 386 Ok((id, existing.linkage)) 387 } 388 389 FuncOrDataId::Func(..) => { 390 Err(ModuleError::IncompatibleDeclaration(name.to_owned())) 391 } 392 }, 393 Vacant(entry) => { 394 let id = self.data_objects.push(DataDeclaration { 395 name: name.to_owned(), 396 linkage, 397 writable, 398 tls, 399 }); 400 entry.insert(FuncOrDataId::Data(id)); 401 Ok((id, self.data_objects[id].linkage)) 402 } 403 } 404 } 405 406 /// Declare an anonymous data object in this module. 407 pub fn declare_anonymous_data(&mut self, writable: bool, tls: bool) -> ModuleResult<DataId> { 408 let id = self.data_objects.push(DataDeclaration { 409 name: String::new(), 410 linkage: Linkage::Local, 411 writable, 412 tls, 413 }); 414 self.data_objects[id].name = format!(".L{:?}", id); 415 Ok(id) 416 } 417 } 418 419 /// Information about the compiled function. 420 pub struct ModuleCompiledFunction { 421 /// The size of the compiled function. 422 pub size: binemit::CodeOffset, 423 } 424 425 /// A `Module` is a utility for collecting functions and data objects, and linking them together. 426 pub trait Module { 427 /// Return the `TargetIsa` to compile for. 428 fn isa(&self) -> &dyn isa::TargetIsa; 429 430 /// Get all declarations in this module. 431 fn declarations(&self) -> &ModuleDeclarations; 432 433 /// Get the module identifier for a given name, if that name 434 /// has been declared. 435 fn get_name(&self, name: &str) -> Option<FuncOrDataId> { 436 self.declarations().get_name(name) 437 } 438 439 /// Return the target information needed by frontends to produce Cranelift IR 440 /// for the current target. 441 fn target_config(&self) -> isa::TargetFrontendConfig { 442 self.isa().frontend_config() 443 } 444 445 /// Create a new `Context` initialized for use with this `Module`. 446 /// 447 /// This ensures that the `Context` is initialized with the default calling 448 /// convention for the `TargetIsa`. 449 fn make_context(&self) -> Context { 450 let mut ctx = Context::new(); 451 ctx.func.signature.call_conv = self.isa().default_call_conv(); 452 ctx 453 } 454 455 /// Clear the given `Context` and reset it for use with a new function. 456 /// 457 /// This ensures that the `Context` is initialized with the default calling 458 /// convention for the `TargetIsa`. 459 fn clear_context(&self, ctx: &mut Context) { 460 ctx.clear(); 461 ctx.func.signature.call_conv = self.isa().default_call_conv(); 462 } 463 464 /// Create a new empty `Signature` with the default calling convention for 465 /// the `TargetIsa`, to which parameter and return types can be added for 466 /// declaring a function to be called by this `Module`. 467 fn make_signature(&self) -> ir::Signature { 468 ir::Signature::new(self.isa().default_call_conv()) 469 } 470 471 /// Clear the given `Signature` and reset for use with a new function. 472 /// 473 /// This ensures that the `Signature` is initialized with the default 474 /// calling convention for the `TargetIsa`. 475 fn clear_signature(&self, sig: &mut ir::Signature) { 476 sig.clear(self.isa().default_call_conv()); 477 } 478 479 /// Declare a function in this module. 480 fn declare_function( 481 &mut self, 482 name: &str, 483 linkage: Linkage, 484 signature: &ir::Signature, 485 ) -> ModuleResult<FuncId>; 486 487 /// Declare an anonymous function in this module. 488 fn declare_anonymous_function(&mut self, signature: &ir::Signature) -> ModuleResult<FuncId>; 489 490 /// Declare a data object in this module. 491 fn declare_data( 492 &mut self, 493 name: &str, 494 linkage: Linkage, 495 writable: bool, 496 tls: bool, 497 ) -> ModuleResult<DataId>; 498 499 /// Declare an anonymous data object in this module. 500 fn declare_anonymous_data(&mut self, writable: bool, tls: bool) -> ModuleResult<DataId>; 501 502 /// Use this when you're building the IR of a function to reference a function. 503 /// 504 /// TODO: Coalesce redundant decls and signatures. 505 /// TODO: Look into ways to reduce the risk of using a FuncRef in the wrong function. 506 fn declare_func_in_func(&self, func: FuncId, in_func: &mut ir::Function) -> ir::FuncRef { 507 let decl = &self.declarations().functions[func]; 508 let signature = in_func.import_signature(decl.signature.clone()); 509 let colocated = decl.linkage.is_final(); 510 in_func.import_function(ir::ExtFuncData { 511 name: ir::ExternalName::user(0, func.as_u32()), 512 signature, 513 colocated, 514 }) 515 } 516 517 /// Use this when you're building the IR of a function to reference a data object. 518 /// 519 /// TODO: Same as above. 520 fn declare_data_in_func(&self, data: DataId, func: &mut ir::Function) -> ir::GlobalValue { 521 let decl = &self.declarations().data_objects[data]; 522 let colocated = decl.linkage.is_final(); 523 func.create_global_value(ir::GlobalValueData::Symbol { 524 name: ir::ExternalName::user(1, data.as_u32()), 525 offset: ir::immediates::Imm64::new(0), 526 colocated, 527 tls: decl.tls, 528 }) 529 } 530 531 /// TODO: Same as above. 532 fn declare_func_in_data(&self, func: FuncId, ctx: &mut DataContext) -> ir::FuncRef { 533 ctx.import_function(ir::ExternalName::user(0, func.as_u32())) 534 } 535 536 /// TODO: Same as above. 537 fn declare_data_in_data(&self, data: DataId, ctx: &mut DataContext) -> ir::GlobalValue { 538 ctx.import_global_value(ir::ExternalName::user(1, data.as_u32())) 539 } 540 541 /// Define a function, producing the function body from the given `Context`. 542 /// 543 /// Returns the size of the function's code and constant data. 544 /// 545 /// Note: After calling this function the given `Context` will contain the compiled function. 546 fn define_function( 547 &mut self, 548 func: FuncId, 549 ctx: &mut Context, 550 ) -> ModuleResult<ModuleCompiledFunction>; 551 552 /// Define a function, taking the function body from the given `bytes`. 553 /// 554 /// This function is generally only useful if you need to precisely specify 555 /// the emitted instructions for some reason; otherwise, you should use 556 /// `define_function`. 557 /// 558 /// Returns the size of the function's code. 559 fn define_function_bytes( 560 &mut self, 561 func: FuncId, 562 bytes: &[u8], 563 relocs: &[MachReloc], 564 ) -> ModuleResult<ModuleCompiledFunction>; 565 566 /// Define a data object, producing the data contents from the given `DataContext`. 567 fn define_data(&mut self, data: DataId, data_ctx: &DataContext) -> ModuleResult<()>; 568 } 569 570 impl<M: Module> Module for &mut M { 571 fn isa(&self) -> &dyn isa::TargetIsa { 572 (**self).isa() 573 } 574 575 fn declarations(&self) -> &ModuleDeclarations { 576 (**self).declarations() 577 } 578 579 fn get_name(&self, name: &str) -> Option<FuncOrDataId> { 580 (**self).get_name(name) 581 } 582 583 fn target_config(&self) -> isa::TargetFrontendConfig { 584 (**self).target_config() 585 } 586 587 fn make_context(&self) -> Context { 588 (**self).make_context() 589 } 590 591 fn clear_context(&self, ctx: &mut Context) { 592 (**self).clear_context(ctx) 593 } 594 595 fn make_signature(&self) -> ir::Signature { 596 (**self).make_signature() 597 } 598 599 fn clear_signature(&self, sig: &mut ir::Signature) { 600 (**self).clear_signature(sig) 601 } 602 603 fn declare_function( 604 &mut self, 605 name: &str, 606 linkage: Linkage, 607 signature: &ir::Signature, 608 ) -> ModuleResult<FuncId> { 609 (**self).declare_function(name, linkage, signature) 610 } 611 612 fn declare_anonymous_function(&mut self, signature: &ir::Signature) -> ModuleResult<FuncId> { 613 (**self).declare_anonymous_function(signature) 614 } 615 616 fn declare_data( 617 &mut self, 618 name: &str, 619 linkage: Linkage, 620 writable: bool, 621 tls: bool, 622 ) -> ModuleResult<DataId> { 623 (**self).declare_data(name, linkage, writable, tls) 624 } 625 626 fn declare_anonymous_data(&mut self, writable: bool, tls: bool) -> ModuleResult<DataId> { 627 (**self).declare_anonymous_data(writable, tls) 628 } 629 630 fn declare_func_in_func(&self, func: FuncId, in_func: &mut ir::Function) -> ir::FuncRef { 631 (**self).declare_func_in_func(func, in_func) 632 } 633 634 fn declare_data_in_func(&self, data: DataId, func: &mut ir::Function) -> ir::GlobalValue { 635 (**self).declare_data_in_func(data, func) 636 } 637 638 fn declare_func_in_data(&self, func: FuncId, ctx: &mut DataContext) -> ir::FuncRef { 639 (**self).declare_func_in_data(func, ctx) 640 } 641 642 fn declare_data_in_data(&self, data: DataId, ctx: &mut DataContext) -> ir::GlobalValue { 643 (**self).declare_data_in_data(data, ctx) 644 } 645 646 fn define_function( 647 &mut self, 648 func: FuncId, 649 ctx: &mut Context, 650 ) -> ModuleResult<ModuleCompiledFunction> { 651 (**self).define_function(func, ctx) 652 } 653 654 fn define_function_bytes( 655 &mut self, 656 func: FuncId, 657 bytes: &[u8], 658 relocs: &[MachReloc], 659 ) -> ModuleResult<ModuleCompiledFunction> { 660 (**self).define_function_bytes(func, bytes, relocs) 661 } 662 663 fn define_data(&mut self, data: DataId, data_ctx: &DataContext) -> ModuleResult<()> { 664 (**self).define_data(data, data_ctx) 665 } 666 } 667