Path: blob/main/cranelift/codegen/src/ir/extname.rs
1693 views
//! External names.1//!2//! These are identifiers for declaring entities defined outside the current3//! function. The name of an external declaration doesn't have any meaning to4//! Cranelift, which compiles functions independently.56use crate::ir::{KnownSymbol, LibCall};7use alloc::boxed::Box;8use core::fmt::{self, Write};9use core::str::FromStr;1011use cranelift_entity::EntityRef as _;12#[cfg(feature = "enable-serde")]13use serde_derive::{Deserialize, Serialize};1415use super::entities::UserExternalNameRef;16use super::function::FunctionParameters;1718/// An explicit name for a user-defined function, be it defined in code or in CLIF text.19///20/// This is used both for naming a function (for debugging purposes) and for declaring external21/// functions. In the latter case, this becomes an `ExternalName`, which gets embedded in22/// relocations later, etc.23#[derive(Clone, Debug, PartialEq, Eq, Hash)]24#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]25pub enum UserFuncName {26/// A user-defined name, with semantics left to the user.27User(UserExternalName),28/// A name for a test case, mostly intended for Cranelift testing.29Testcase(TestcaseName),30}3132impl UserFuncName {33/// Creates a new external name from a sequence of bytes. Caller is expected34/// to guarantee bytes are only ascii alphanumeric or `_`.35pub fn testcase<T: AsRef<[u8]>>(v: T) -> Self {36Self::Testcase(TestcaseName::new(v))37}3839/// Create a new external name from a user-defined external function reference.40pub fn user(namespace: u32, index: u32) -> Self {41Self::User(UserExternalName::new(namespace, index))42}4344/// Get a `UserExternalName` if this is a user-defined name.45pub fn get_user(&self) -> Option<&UserExternalName> {46match self {47UserFuncName::User(user) => Some(user),48UserFuncName::Testcase(_) => None,49}50}51}5253impl Default for UserFuncName {54fn default() -> Self {55UserFuncName::User(UserExternalName::default())56}57}5859impl fmt::Display for UserFuncName {60fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {61match self {62UserFuncName::User(user) => user.fmt(f),63UserFuncName::Testcase(testcase) => testcase.fmt(f),64}65}66}6768/// An external name in a user-defined symbol table.69///70/// Cranelift does not interpret these numbers in any way, so they can represent arbitrary values.71#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]72#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]73pub struct UserExternalName {74/// Arbitrary.75pub namespace: u32,76/// Arbitrary.77pub index: u32,78}7980impl UserExternalName {81/// Creates a new [UserExternalName].82pub fn new(namespace: u32, index: u32) -> Self {83Self { namespace, index }84}85}8687impl fmt::Display for UserExternalName {88fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {89write!(f, "u{}:{}", self.namespace, self.index)90}91}9293/// A name for a test case.94#[derive(Clone, PartialEq, Eq, Hash)]95#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]96pub struct TestcaseName(Box<[u8]>);9798impl fmt::Display for TestcaseName {99fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {100f.write_char('%')?;101f.write_str(std::str::from_utf8(&self.0).unwrap())102}103}104105impl fmt::Debug for TestcaseName {106fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {107write!(f, "{self}")108}109}110111impl TestcaseName {112pub(crate) fn new<T: AsRef<[u8]>>(v: T) -> Self {113Self(v.as_ref().into())114}115116/// Get the raw test case name as bytes.117pub fn raw(&self) -> &[u8] {118&self.0119}120}121122/// The name of an external is either a reference to a user-defined symbol123/// table, or a short sequence of ascii bytes so that test cases do not have124/// to keep track of a symbol table.125///126/// External names are primarily used as keys by code using Cranelift to map127/// from a `cranelift_codegen::ir::FuncRef` or similar to additional associated128/// data.129///130/// External names can also serve as a primitive testing and debugging tool.131/// In particular, many `.clif` test files use function names to identify132/// functions.133#[derive(Debug, Clone, PartialEq, Eq, Hash)]134#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]135pub enum ExternalName {136/// A reference to a name in a user-defined symbol table.137User(UserExternalNameRef),138/// A test case function name of up to a hardcoded amount of ascii139/// characters. This is not intended to be used outside test cases.140TestCase(TestcaseName),141/// A well-known runtime library function.142LibCall(LibCall),143/// A well-known symbol.144KnownSymbol(KnownSymbol),145}146147impl Default for ExternalName {148fn default() -> Self {149Self::User(UserExternalNameRef::new(0))150}151}152153impl ExternalName {154/// Creates a new external name from a sequence of bytes. Caller is expected155/// to guarantee bytes are only ascii alphanumeric or `_`.156///157/// # Examples158///159/// ```rust160/// # use cranelift_codegen::ir::ExternalName;161/// // Create `ExternalName` from a string.162/// let name = ExternalName::testcase("hello");163/// assert_eq!(name.display(None).to_string(), "%hello");164/// ```165pub fn testcase<T: AsRef<[u8]>>(v: T) -> Self {166Self::TestCase(TestcaseName::new(v))167}168169/// Create a new external name from a user-defined external function reference.170///171/// # Examples172/// ```rust173/// # use cranelift_codegen::ir::{ExternalName, UserExternalNameRef};174/// let user_func_ref: UserExternalNameRef = Default::default(); // usually obtained with `Function::declare_imported_user_function()`175/// let name = ExternalName::user(user_func_ref);176/// assert_eq!(name.display(None).to_string(), "userextname0");177/// ```178pub fn user(func_ref: UserExternalNameRef) -> Self {179Self::User(func_ref)180}181182/// Returns a display for the current `ExternalName`, with extra context to prettify the183/// output.184pub fn display<'a>(185&'a self,186params: Option<&'a FunctionParameters>,187) -> DisplayableExternalName<'a> {188DisplayableExternalName { name: self, params }189}190}191192/// An `ExternalName` that has enough context to be displayed.193pub struct DisplayableExternalName<'a> {194name: &'a ExternalName,195params: Option<&'a FunctionParameters>,196}197198impl<'a> fmt::Display for DisplayableExternalName<'a> {199fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {200match &self.name {201ExternalName::User(func_ref) => {202if let Some(params) = self.params {203let name = ¶ms.user_named_funcs()[*func_ref];204write!(f, "u{}:{}", name.namespace, name.index)205} else {206// Best effort.207write!(f, "{}", *func_ref)208}209}210ExternalName::TestCase(testcase) => testcase.fmt(f),211ExternalName::LibCall(lc) => write!(f, "%{lc}"),212ExternalName::KnownSymbol(ks) => write!(f, "%{ks}"),213}214}215}216217impl FromStr for ExternalName {218type Err = ();219220fn from_str(s: &str) -> Result<Self, Self::Err> {221// Try to parse as a known symbol222if let Ok(ks) = s.parse() {223return Ok(Self::KnownSymbol(ks));224}225226// Try to parse as a libcall name227if let Ok(lc) = s.parse() {228return Ok(Self::LibCall(lc));229}230231// Otherwise its a test case name232Ok(Self::testcase(s.as_bytes()))233}234}235236#[cfg(test)]237mod tests {238use super::ExternalName;239use crate::ir::{240LibCall, UserExternalName, entities::UserExternalNameRef, function::FunctionParameters,241};242use alloc::string::ToString;243use core::u32;244use cranelift_entity::EntityRef as _;245246#[cfg(target_pointer_width = "64")]247#[test]248fn externalname_size() {249assert_eq!(core::mem::size_of::<ExternalName>(), 24);250}251252#[test]253fn display_testcase() {254assert_eq!(ExternalName::testcase("").display(None).to_string(), "%");255assert_eq!(ExternalName::testcase("x").display(None).to_string(), "%x");256assert_eq!(257ExternalName::testcase("x_1").display(None).to_string(),258"%x_1"259);260assert_eq!(261ExternalName::testcase("longname12345678")262.display(None)263.to_string(),264"%longname12345678"265);266assert_eq!(267ExternalName::testcase("longname123456789")268.display(None)269.to_string(),270"%longname123456789"271);272}273274#[test]275fn display_user() {276assert_eq!(277ExternalName::user(UserExternalNameRef::new(0))278.display(None)279.to_string(),280"userextname0"281);282assert_eq!(283ExternalName::user(UserExternalNameRef::new(1))284.display(None)285.to_string(),286"userextname1"287);288assert_eq!(289ExternalName::user(UserExternalNameRef::new((u32::MAX - 1) as _))290.display(None)291.to_string(),292"userextname4294967294"293);294295let mut func_params = FunctionParameters::new();296297// ref 0298func_params.ensure_user_func_name(UserExternalName {299namespace: 13,300index: 37,301});302303// ref 1304func_params.ensure_user_func_name(UserExternalName {305namespace: 2,306index: 4,307});308309assert_eq!(310ExternalName::user(UserExternalNameRef::new(0))311.display(Some(&func_params))312.to_string(),313"u13:37"314);315316assert_eq!(317ExternalName::user(UserExternalNameRef::new(1))318.display(Some(&func_params))319.to_string(),320"u2:4"321);322}323324#[test]325fn parsing() {326assert_eq!(327"FloorF32".parse(),328Ok(ExternalName::LibCall(LibCall::FloorF32))329);330assert_eq!(331ExternalName::LibCall(LibCall::FloorF32)332.display(None)333.to_string(),334"%FloorF32"335);336}337}338339340