-
Notifications
You must be signed in to change notification settings - Fork 2
Symbol
A symbol is a unique name for a definition. Definitions always use symbols to refer to other definitions, rather than referencing them directly. This allows definitions to be replaced by new definitions of the same name without modifying the definitions that refer to them.
A definition has two parts: a name, which is a list of strings, and an id, which is a positive 32-bit integer. When a definition is printed or parsed, components of the name are separated by dots. The id is printed after a '#' character, following the name. The id may be omitted if it is zero. Some examples:
a
a.b
a.b#42
The components of the name may contain any character. However, if a component contains a character which is not alphanumeric or '$' or '_', then that component must be quoted with double quotes. Any non-printable character or double quote within a component must be escaped.
a."\"foo\"".b
a."foo bar".b
a."new\nline".b
In Tungsten assembly, all symbols are prefixed with either a '@' or '%' character. '@' symbols are global symbols. When a global symbol is parsed, the '@' is simply discarded. '%' symbols are local symbols. When a local symbol is parsed, the '%' is discarded, and the name of the parent scope is prepended to the symbol name. For example, consider the following snippet:
function unit @f(int64 %x) {
block %entry {
int64 %y = int64 @f.x + int64 12
branch @f.exit(int64 %y)
}
block %exit(int64 %x) {
return int64 %x
}
}
Since the parameter %x is defined within the function f, the parsed name would be f.x. Likewise, the blocks %entry and %exit would be parsed as f.entry and f.exit. The parameter %x in f.exit would be parsed as f.exit.x. So when we return %x in f.exit, we mean f.exit.x. In f.entry, we need to write @f.x, since %x would parse as f.entry.x, and there is no such symbol.
Note that symbols may be omitted in assembly for instructions of unit type, such as return and branch. These symbols have names generated by the parser.
Whether a symbol is local or global has nothing to do with the definition. Local notation is just a shorter way to write the same thing. The following code snippet uses all global symbols and is equivalent (although generated names may be different).
function unit @f(int64 @f.x) {
block @f.entry {
int64 @f.entry.y = int64 @f.x + int64 12
unit anon$#1 = branch @f.exit(int64 @f.entry.y)
}
block @f.exit(int64 @f.exit.x) {
unit anon$#2 = return int64 @f.exit.x
}
}
Tungsten has a few useful utilities for creating symbols.
- The
tungsten.Utilitiesobject provides asymbolFromStringmethod which converts a symbol from a string. This is an implicit method, so any file which importsUtilitieswill be able to use strings in any place that expects a symbol. This function can parse any symbol the assembler can. The local/global prefix is optional. If included, it will be prepended to the first component of the name. - A
SymbolFactoryclass is provided. It is initialized with an id. Each symbol created with the factory will get a unique id greater than the starting id. This is the best way to generate names for new definitions. TheModuleclass provides ahighestSymbolIdmethod, which can be used to initializeSymbolFactory.