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