Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/cranelift/codegen/src/ir/entities.rs
3068 views
1
//! Cranelift IR entity references.
2
//!
3
//! Instructions in Cranelift IR need to reference other entities in the function. This can be other
4
//! parts of the function like basic blocks or stack slots, or it can be external entities
5
//! that are declared in the function preamble in the text format.
6
//!
7
//! These entity references in instruction operands are not implemented as Rust references both
8
//! because Rust's ownership and mutability rules make it difficult, and because 64-bit pointers
9
//! take up a lot of space, and we want a compact in-memory representation. Instead, entity
10
//! references are structs wrapping a `u32` index into a table in the `Function` main data
11
//! structure. There is a separate index type for each entity type, so we don't lose type safety.
12
//!
13
//! The `entities` module defines public types for the entity references along with constants
14
//! representing an invalid reference. We prefer to use `Option<EntityRef>` whenever possible, but
15
//! unfortunately that type is twice as large as the 32-bit index type on its own. Thus, compact
16
//! data structures use the `PackedOption<EntityRef>` representation, while function arguments and
17
//! return values prefer the more Rust-like `Option<EntityRef>` variant.
18
//!
19
//! The entity references all implement the `Display` trait in a way that matches the textual IR
20
//! format.
21
22
use crate::entity::entity_impl;
23
use core::fmt;
24
use core::u32;
25
#[cfg(feature = "enable-serde")]
26
use serde_derive::{Deserialize, Serialize};
27
28
/// An opaque reference to a [basic block](https://en.wikipedia.org/wiki/Basic_block) in a
29
/// [`Function`](super::function::Function).
30
///
31
/// You can get a `Block` using
32
/// [`FunctionBuilder::create_block`](https://docs.rs/cranelift-frontend/*/cranelift_frontend/struct.FunctionBuilder.html#method.create_block)
33
///
34
/// While the order is stable, it is arbitrary and does not necessarily resemble the layout order.
35
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
36
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
37
pub struct Block(u32);
38
entity_impl!(Block, "block");
39
40
impl Block {
41
/// Create a new block reference from its number. This corresponds to the `blockNN` representation.
42
///
43
/// This method is for use by the parser.
44
pub fn with_number(n: u32) -> Option<Self> {
45
if n < u32::MAX { Some(Self(n)) } else { None }
46
}
47
}
48
49
/// An opaque reference to an SSA value.
50
///
51
/// You can get a constant `Value` from the following
52
/// [`InstBuilder`](super::InstBuilder) instructions:
53
///
54
/// - [`iconst`](super::InstBuilder::iconst) for integer constants
55
/// - [`f16const`](super::InstBuilder::f16const) for 16-bit float constants
56
/// - [`f32const`](super::InstBuilder::f32const) for 32-bit float constants
57
/// - [`f64const`](super::InstBuilder::f64const) for 64-bit float constants
58
/// - [`f128const`](super::InstBuilder::f128const) for 128-bit float constants
59
/// - [`vconst`](super::InstBuilder::vconst) for vector constants
60
///
61
/// Any `InstBuilder` instruction that has an output will also return a `Value`.
62
///
63
/// While the order is stable, it is arbitrary.
64
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
65
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
66
pub struct Value(u32);
67
entity_impl!(Value, "v");
68
69
impl Value {
70
/// Create a value from its number representation.
71
/// This is the number in the `vNN` notation.
72
///
73
/// This method is for use by the parser.
74
pub fn with_number(n: u32) -> Option<Self> {
75
if n < u32::MAX / 2 {
76
Some(Self(n))
77
} else {
78
None
79
}
80
}
81
}
82
83
/// An opaque reference to an instruction in a [`Function`](super::Function).
84
///
85
/// Most usage of `Inst` is internal. `Inst`ructions are returned by
86
/// [`InstBuilder`](super::InstBuilder) instructions that do not return a
87
/// [`Value`], such as control flow and trap instructions, as well as instructions that return a
88
/// variable (potentially zero!) number of values, like call or call-indirect instructions. To get
89
/// the `Value` of such instructions, use [`inst_results`](super::DataFlowGraph::inst_results) or
90
/// its analogue in `cranelift_frontend::FuncBuilder`.
91
///
92
/// [inst_comment]: https://github.com/bjorn3/rustc_codegen_cranelift/blob/0f8814fd6da3d436a90549d4bb19b94034f2b19c/src/pretty_clif.rs
93
///
94
/// While the order is stable, it is arbitrary and does not necessarily resemble the layout order.
95
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
96
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
97
pub struct Inst(u32);
98
entity_impl!(Inst, "inst");
99
100
/// An opaque reference to a stack slot.
101
///
102
/// Stack slots represent an address on the
103
/// [call stack](https://en.wikipedia.org/wiki/Call_stack).
104
///
105
/// `StackSlot`s can be created with
106
/// [`FunctionBuilder::create_sized_stack_slot`](https://docs.rs/cranelift-frontend/*/cranelift_frontend/struct.FunctionBuilder.html#method.create_sized_stack_slot)
107
/// or
108
/// [`FunctionBuilder::create_dynamic_stack_slot`](https://docs.rs/cranelift-frontend/*/cranelift_frontend/struct.FunctionBuilder.html#method.create_dynamic_stack_slot).
109
///
110
/// `StackSlot`s are most often used with
111
/// [`stack_addr`](super::InstBuilder::stack_addr),
112
/// [`stack_load`](super::InstBuilder::stack_load), and
113
/// [`stack_store`](super::InstBuilder::stack_store).
114
///
115
/// While the order is stable, it is arbitrary and does not necessarily resemble the stack order.
116
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
117
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
118
pub struct StackSlot(u32);
119
entity_impl!(StackSlot, "ss");
120
121
impl StackSlot {
122
/// Create a new stack slot reference from its number.
123
///
124
/// This method is for use by the parser.
125
pub fn with_number(n: u32) -> Option<Self> {
126
if n < u32::MAX { Some(Self(n)) } else { None }
127
}
128
}
129
130
/// An opaque reference to a dynamic stack slot.
131
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
132
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
133
pub struct DynamicStackSlot(u32);
134
entity_impl!(DynamicStackSlot, "dss");
135
136
impl DynamicStackSlot {
137
/// Create a new stack slot reference from its number.
138
///
139
/// This method is for use by the parser.
140
pub fn with_number(n: u32) -> Option<Self> {
141
if n < u32::MAX { Some(Self(n)) } else { None }
142
}
143
}
144
145
/// An opaque reference to a dynamic type.
146
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
147
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
148
pub struct DynamicType(u32);
149
entity_impl!(DynamicType, "dt");
150
151
impl DynamicType {
152
/// Create a new dynamic type reference from its number.
153
///
154
/// This method is for use by the parser.
155
pub fn with_number(n: u32) -> Option<Self> {
156
if n < u32::MAX { Some(Self(n)) } else { None }
157
}
158
}
159
160
/// An opaque reference to a global value.
161
///
162
/// A `GlobalValue` is a [`Value`] that will be live across the entire
163
/// function lifetime. It can be preloaded from other global values.
164
///
165
/// You can create a `GlobalValue` in the following ways:
166
///
167
/// - When compiling to native code, you can use it for objects in static memory with
168
/// [`Module::declare_data_in_func`](https://docs.rs/cranelift-module/*/cranelift_module/trait.Module.html#method.declare_data_in_func).
169
/// - For any compilation target, it can be registered with
170
/// [`FunctionBuilder::create_global_value`](https://docs.rs/cranelift-frontend/*/cranelift_frontend/struct.FunctionBuilder.html#method.create_global_value).
171
///
172
/// `GlobalValue`s can be retrieved with
173
/// [`InstBuilder:global_value`](super::InstBuilder::global_value).
174
///
175
/// While the order is stable, it is arbitrary.
176
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
177
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
178
pub struct GlobalValue(u32);
179
entity_impl!(GlobalValue, "gv");
180
181
impl GlobalValue {
182
/// Create a new global value reference from its number.
183
///
184
/// This method is for use by the parser.
185
pub fn with_number(n: u32) -> Option<Self> {
186
if n < u32::MAX { Some(Self(n)) } else { None }
187
}
188
}
189
190
/// An opaque reference to a memory type.
191
///
192
/// A `MemoryType` is a descriptor of a struct layout in memory, with
193
/// types and proof-carrying-code facts optionally attached to the
194
/// fields.
195
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
196
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
197
pub struct MemoryType(u32);
198
entity_impl!(MemoryType, "mt");
199
200
impl MemoryType {
201
/// Create a new memory type reference from its number.
202
///
203
/// This method is for use by the parser.
204
pub fn with_number(n: u32) -> Option<Self> {
205
if n < u32::MAX { Some(Self(n)) } else { None }
206
}
207
}
208
209
/// An opaque reference to a constant.
210
///
211
/// You can store [`ConstantData`](super::ConstantData) in a
212
/// [`ConstantPool`](super::ConstantPool) for efficient storage and retrieval.
213
/// See [`ConstantPool::insert`](super::ConstantPool::insert).
214
///
215
/// While the order is stable, it is arbitrary and does not necessarily resemble the order in which
216
/// the constants are written in the constant pool.
217
#[derive(Copy, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)]
218
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
219
pub struct Constant(u32);
220
entity_impl!(Constant, "const");
221
222
impl Constant {
223
/// Create a const reference from its number.
224
///
225
/// This method is for use by the parser.
226
pub fn with_number(n: u32) -> Option<Self> {
227
if n < u32::MAX { Some(Self(n)) } else { None }
228
}
229
}
230
231
/// An opaque reference to an immediate.
232
///
233
/// Some immediates (e.g. SIMD shuffle masks) are too large to store in the
234
/// [`InstructionData`](super::instructions::InstructionData) struct and therefore must be
235
/// tracked separately in [`DataFlowGraph::immediates`](super::dfg::DataFlowGraph). `Immediate`
236
/// provides a way to reference values stored there.
237
///
238
/// While the order is stable, it is arbitrary.
239
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
240
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
241
pub struct Immediate(u32);
242
entity_impl!(Immediate, "imm");
243
244
impl Immediate {
245
/// Create an immediate reference from its number.
246
///
247
/// This method is for use by the parser.
248
pub fn with_number(n: u32) -> Option<Self> {
249
if n < u32::MAX { Some(Self(n)) } else { None }
250
}
251
}
252
253
/// An opaque reference to a [jump table](https://en.wikipedia.org/wiki/Branch_table).
254
///
255
/// `JumpTable`s are used for indirect branching and are specialized for dense,
256
/// 0-based jump offsets. If you want a jump table which doesn't start at 0,
257
/// or is not contiguous, consider using a [`Switch`](https://docs.rs/cranelift-frontend/*/cranelift_frontend/struct.Switch.html) instead.
258
///
259
/// `JumpTable` are used with [`br_table`](super::InstBuilder::br_table).
260
///
261
/// `JumpTable`s can be created with
262
/// [`create_jump_table`](https://docs.rs/cranelift-frontend/*/cranelift_frontend/struct.FunctionBuilder.html#method.create_jump_table).
263
///
264
/// While the order is stable, it is arbitrary.
265
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
266
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
267
pub struct JumpTable(u32);
268
entity_impl!(JumpTable, "jt");
269
270
impl JumpTable {
271
/// Create a new jump table reference from its number.
272
///
273
/// This method is for use by the parser.
274
pub fn with_number(n: u32) -> Option<Self> {
275
if n < u32::MAX { Some(Self(n)) } else { None }
276
}
277
}
278
279
/// An opaque reference to another [`Function`](super::Function).
280
///
281
/// `FuncRef`s are used for [direct](super::InstBuilder::call) function calls
282
/// and by [`func_addr`](super::InstBuilder::func_addr) for use in
283
/// [indirect](super::InstBuilder::call_indirect) function calls.
284
///
285
/// `FuncRef`s can be created with
286
///
287
/// - [`FunctionBuilder::import_function`](https://docs.rs/cranelift-frontend/*/cranelift_frontend/struct.FunctionBuilder.html#method.import_function)
288
/// for external functions
289
/// - [`Module::declare_func_in_func`](https://docs.rs/cranelift-module/*/cranelift_module/trait.Module.html#method.declare_func_in_func)
290
/// for functions declared elsewhere in the same native
291
/// [`Module`](https://docs.rs/cranelift-module/*/cranelift_module/trait.Module.html)
292
///
293
/// While the order is stable, it is arbitrary.
294
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
295
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
296
pub struct FuncRef(u32);
297
entity_impl!(FuncRef, "fn");
298
299
impl FuncRef {
300
/// Create a new external function reference from its number.
301
///
302
/// This method is for use by the parser.
303
pub fn with_number(n: u32) -> Option<Self> {
304
if n < u32::MAX { Some(Self(n)) } else { None }
305
}
306
}
307
308
/// A reference to an `UserExternalName`, declared with `Function::declare_imported_user_function`.
309
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Default)]
310
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
311
pub struct UserExternalNameRef(u32);
312
entity_impl!(UserExternalNameRef, "userextname");
313
314
/// An opaque reference to a function [`Signature`](super::Signature).
315
///
316
/// `SigRef`s are used to declare a function with
317
/// [`FunctionBuilder::import_function`](https://docs.rs/cranelift-frontend/*/cranelift_frontend/struct.FunctionBuilder.html#method.import_function)
318
/// as well as to make an [indirect function call](super::InstBuilder::call_indirect).
319
///
320
/// `SigRef`s can be created with
321
/// [`FunctionBuilder::import_signature`](https://docs.rs/cranelift-frontend/*/cranelift_frontend/struct.FunctionBuilder.html#method.import_signature).
322
///
323
/// You can retrieve the [`Signature`](super::Signature) that was used to create a `SigRef` with
324
/// [`FunctionBuilder::signature`](https://docs.rs/cranelift-frontend/*/cranelift_frontend/struct.FunctionBuilder.html#method.signature) or
325
/// [`func.dfg.signatures`](super::dfg::DataFlowGraph::signatures).
326
///
327
/// While the order is stable, it is arbitrary.
328
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
329
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
330
pub struct SigRef(u32);
331
entity_impl!(SigRef, "sig");
332
333
impl SigRef {
334
/// Create a new function signature reference from its number.
335
///
336
/// This method is for use by the parser.
337
pub fn with_number(n: u32) -> Option<Self> {
338
if n < u32::MAX { Some(Self(n)) } else { None }
339
}
340
}
341
342
/// An opaque exception tag.
343
///
344
/// Exception tags are used to denote the identity of an exception for
345
/// matching by catch-handlers in exception tables.
346
///
347
/// The index space is arbitrary and is given meaning only by the
348
/// embedder of Cranelift. Cranelift will carry through these tags
349
/// from exception tables to the handler metadata produced as output
350
/// (for use by the embedder's unwinder).
351
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
352
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
353
pub struct ExceptionTag(u32);
354
entity_impl!(ExceptionTag, "tag");
355
356
impl ExceptionTag {
357
/// Create a new exception tag from its arbitrary index.
358
///
359
/// This method is for use by the parser.
360
pub fn with_number(n: u32) -> Option<Self> {
361
if n < u32::MAX { Some(Self(n)) } else { None }
362
}
363
}
364
365
/// An opaque reference to an exception table.
366
///
367
/// `ExceptionTable`s are used for describing exception catch handlers on
368
/// `try_call` and `try_call_indirect` instructions.
369
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
370
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
371
pub struct ExceptionTable(u32);
372
entity_impl!(ExceptionTable, "extable");
373
374
impl ExceptionTable {
375
/// Create a new exception table reference from its number.
376
///
377
/// This method is for use by the parser.
378
pub fn with_number(n: u32) -> Option<Self> {
379
if n < u32::MAX { Some(Self(n)) } else { None }
380
}
381
}
382
383
/// An opaque reference to any of the entities defined in this module that can appear in CLIF IR.
384
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
385
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
386
pub enum AnyEntity {
387
/// The whole function.
388
Function,
389
/// a basic block.
390
Block(Block),
391
/// An instruction.
392
Inst(Inst),
393
/// An SSA value.
394
Value(Value),
395
/// A stack slot.
396
StackSlot(StackSlot),
397
/// A dynamic stack slot.
398
DynamicStackSlot(DynamicStackSlot),
399
/// A dynamic type
400
DynamicType(DynamicType),
401
/// A Global value.
402
GlobalValue(GlobalValue),
403
/// A memory type.
404
MemoryType(MemoryType),
405
/// A jump table.
406
JumpTable(JumpTable),
407
/// A constant.
408
Constant(Constant),
409
/// An external function.
410
FuncRef(FuncRef),
411
/// A function call signature.
412
SigRef(SigRef),
413
/// An exception table.
414
ExceptionTable(ExceptionTable),
415
/// A function's stack limit
416
StackLimit,
417
}
418
419
impl fmt::Display for AnyEntity {
420
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
421
match *self {
422
Self::Function => write!(f, "function"),
423
Self::Block(r) => r.fmt(f),
424
Self::Inst(r) => r.fmt(f),
425
Self::Value(r) => r.fmt(f),
426
Self::StackSlot(r) => r.fmt(f),
427
Self::DynamicStackSlot(r) => r.fmt(f),
428
Self::DynamicType(r) => r.fmt(f),
429
Self::GlobalValue(r) => r.fmt(f),
430
Self::MemoryType(r) => r.fmt(f),
431
Self::JumpTable(r) => r.fmt(f),
432
Self::Constant(r) => r.fmt(f),
433
Self::FuncRef(r) => r.fmt(f),
434
Self::SigRef(r) => r.fmt(f),
435
Self::ExceptionTable(r) => r.fmt(f),
436
Self::StackLimit => write!(f, "stack_limit"),
437
}
438
}
439
}
440
441
impl fmt::Debug for AnyEntity {
442
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
443
(self as &dyn fmt::Display).fmt(f)
444
}
445
}
446
447
impl From<Block> for AnyEntity {
448
fn from(r: Block) -> Self {
449
Self::Block(r)
450
}
451
}
452
453
impl From<Inst> for AnyEntity {
454
fn from(r: Inst) -> Self {
455
Self::Inst(r)
456
}
457
}
458
459
impl From<Value> for AnyEntity {
460
fn from(r: Value) -> Self {
461
Self::Value(r)
462
}
463
}
464
465
impl From<StackSlot> for AnyEntity {
466
fn from(r: StackSlot) -> Self {
467
Self::StackSlot(r)
468
}
469
}
470
471
impl From<DynamicStackSlot> for AnyEntity {
472
fn from(r: DynamicStackSlot) -> Self {
473
Self::DynamicStackSlot(r)
474
}
475
}
476
477
impl From<DynamicType> for AnyEntity {
478
fn from(r: DynamicType) -> Self {
479
Self::DynamicType(r)
480
}
481
}
482
483
impl From<GlobalValue> for AnyEntity {
484
fn from(r: GlobalValue) -> Self {
485
Self::GlobalValue(r)
486
}
487
}
488
489
impl From<MemoryType> for AnyEntity {
490
fn from(r: MemoryType) -> Self {
491
Self::MemoryType(r)
492
}
493
}
494
495
impl From<JumpTable> for AnyEntity {
496
fn from(r: JumpTable) -> Self {
497
Self::JumpTable(r)
498
}
499
}
500
501
impl From<Constant> for AnyEntity {
502
fn from(r: Constant) -> Self {
503
Self::Constant(r)
504
}
505
}
506
507
impl From<FuncRef> for AnyEntity {
508
fn from(r: FuncRef) -> Self {
509
Self::FuncRef(r)
510
}
511
}
512
513
impl From<SigRef> for AnyEntity {
514
fn from(r: SigRef) -> Self {
515
Self::SigRef(r)
516
}
517
}
518
519
impl From<ExceptionTable> for AnyEntity {
520
fn from(r: ExceptionTable) -> Self {
521
Self::ExceptionTable(r)
522
}
523
}
524
525
#[cfg(test)]
526
mod tests {
527
use super::*;
528
use alloc::string::ToString;
529
530
#[test]
531
fn value_with_number() {
532
assert_eq!(Value::with_number(0).unwrap().to_string(), "v0");
533
assert_eq!(Value::with_number(1).unwrap().to_string(), "v1");
534
535
assert_eq!(Value::with_number(u32::MAX / 2), None);
536
assert!(Value::with_number(u32::MAX / 2 - 1).is_some());
537
}
538
539
#[test]
540
fn memory() {
541
use crate::packed_option::PackedOption;
542
use core::mem;
543
// This is the whole point of `PackedOption`.
544
assert_eq!(
545
mem::size_of::<Value>(),
546
mem::size_of::<PackedOption<Value>>()
547
);
548
}
549
550
#[test]
551
fn memory_option() {
552
use core::mem;
553
// PackedOption is used because Option<EntityRef> is twice as large
554
// as EntityRef. If this ever fails to be the case, this test will fail.
555
assert_eq!(mem::size_of::<Value>() * 2, mem::size_of::<Option<Value>>());
556
}
557
558
#[test]
559
fn constant_with_number() {
560
assert_eq!(Constant::with_number(0).unwrap().to_string(), "const0");
561
assert_eq!(Constant::with_number(1).unwrap().to_string(), "const1");
562
}
563
}
564
565