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