Remove heaps from core Cranelift, push them into cranelift-wasm (#5386)

* cranelift-wasm: translate Wasm loads into lower-level CLIF operations

Rather than using `heap_{load,store,addr}`.

* cranelift: Remove the `heap_{addr,load,store}` instructions

These are now legalized in the `cranelift-wasm` frontend.

* cranelift: Remove the `ir::Heap` entity from CLIF

* Port basic memory operation tests to .wat filetests

* Remove test for verifying CLIF heaps

* Remove `heap_addr` from replace_branching_instructions_and_cfg_predecessors.clif test

* Remove `heap_addr` from readonly.clif test

* Remove `heap_addr` from `table_addr.clif` test

* Remove `heap_addr` from the simd-fvpromote_low.clif test

* Remove `heap_addr` from simd-fvdemote.clif test

* Remove `heap_addr` from the load-op-store.clif test

* Remove the CLIF heap runtest

* Remove `heap_addr` from the global_value.clif test

* Remove `heap_addr` from fpromote.clif runtests

* Remove `heap_addr` from fdemote.clif runtests

* Remove `heap_addr` from memory.clif parser test

* Remove `heap_addr` from reject_load_readonly.clif test

* Remove `heap_addr` from reject_load_notrap.clif test

* Remove `heap_addr` from load_readonly_notrap.clif test

* Remove `static-heap-without-guard-pages.clif` test

Will be subsumed when we port `make-heap-load-store-tests.sh` to generating
`.wat` tests.

* Remove `static-heap-with-guard-pages.clif` test

Will be subsumed when we port `make-heap-load-store-tests.sh` over to `.wat`
tests.

* Remove more heap tests

These will be subsumed by porting `make-heap-load-store-tests.sh` over to `.wat`
tests.

* Remove `heap_addr` from `simple-alias.clif` test

* Remove `heap_addr` from partial-redundancy.clif test

* Remove `heap_addr` from multiple-blocks.clif test

* Remove `heap_addr` from fence.clif test

* Remove `heap_addr` from extends.clif test

* Remove runtests that rely on heaps

Heaps are not a thing in CLIF or the interpreter anymore

* Add generated load/store `.wat` tests

* Enable memory-related wasm features in `.wat` tests

* Remove CLIF heap from fcmp-mem-bug.clif test

* Add a mode for compiling `.wat` all the way to assembly in filetests

* Also generate WAT to assembly tests in `make-load-store-tests.sh`

* cargo fmt

* Reinstate `f{de,pro}mote.clif` tests without the heap bits

* Remove undefined doc link

* Remove outdated SVG and dot file from docs

* Add docs about `None` returns for base address computation helpers

* Factor out `env.heap_access_spectre_mitigation()` to a local

* Expand docs for `FuncEnvironment::heaps` trait method

* Restore f{de,pro}mote+load clif runtests with stack memory
This commit is contained in:
Nick Fitzgerald
2022-12-14 16:26:45 -08:00
committed by GitHub
parent e03d65cca7
commit c0b587ac5f
198 changed files with 2494 additions and 4232 deletions

View File

@@ -4,12 +4,11 @@ use crate::entity::{self, PrimaryMap, SecondaryMap};
use crate::ir;
use crate::ir::builder::ReplaceBuilder;
use crate::ir::dynamic_type::{DynamicTypeData, DynamicTypes};
use crate::ir::immediates::HeapImmData;
use crate::ir::instructions::{BranchInfo, CallInfo, InstructionData};
use crate::ir::{types, ConstantData, ConstantPool, Immediate};
use crate::ir::{
Block, DynamicType, FuncRef, HeapImm, Inst, SigRef, Signature, Type, Value,
ValueLabelAssignments, ValueList, ValueListPool,
Block, DynamicType, FuncRef, Inst, SigRef, Signature, Type, Value, ValueLabelAssignments,
ValueList, ValueListPool,
};
use crate::ir::{ExtFuncData, RelSourceLoc};
use crate::packed_option::ReservedValue;
@@ -84,9 +83,6 @@ pub struct DataFlowGraph {
/// Stores large immediates that otherwise will not fit on InstructionData
pub immediates: PrimaryMap<Immediate, ConstantData>,
/// Out-of-line heap access immediates that don't fit in `InstructionData`.
pub heap_imms: PrimaryMap<HeapImm, HeapImmData>,
}
impl DataFlowGraph {
@@ -105,7 +101,6 @@ impl DataFlowGraph {
values_labels: None,
constants: ConstantPool::new(),
immediates: PrimaryMap::new(),
heap_imms: PrimaryMap::new(),
}
}

View File

@@ -368,60 +368,6 @@ impl SigRef {
}
}
/// An opaque reference to a [heap](https://en.wikipedia.org/wiki/Memory_management#DYNAMIC).
///
/// Heaps are used to access dynamically allocated memory through
/// [`heap_addr`](super::InstBuilder::heap_addr).
///
/// To create a heap, use [`FunctionBuilder::create_heap`](https://docs.rs/cranelift-frontend/*/cranelift_frontend/struct.FunctionBuilder.html#method.create_heap).
///
/// While the order is stable, it is arbitrary.
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
pub struct Heap(u32);
entity_impl!(Heap, "heap");
impl Heap {
/// Create a new heap reference from its number.
///
/// This method is for use by the parser.
pub fn with_number(n: u32) -> Option<Self> {
if n < u32::MAX {
Some(Self(n))
} else {
None
}
}
}
/// An opaque reference to some out-of-line immediates for `heap_{load,store}`
/// instructions.
///
/// These immediates are too large to store in
/// [`InstructionData`](super::instructions::InstructionData) and therefore must
/// be tracked separately in
/// [`DataFlowGraph::heap_imms`](super::dfg::DataFlowGraph). `HeapImm` provides
/// a way to reference values stored there.
///
/// While the order is stable, it is arbitrary.
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
pub struct HeapImm(u32);
entity_impl!(HeapImm, "heap_imm");
impl HeapImm {
/// Create a new `HeapImm` reference from its number.
///
/// This method is for use by the parser.
pub fn with_number(n: u32) -> Option<Self> {
if n < u32::MAX {
Some(Self(n))
} else {
None
}
}
}
/// An opaque reference to a [WebAssembly
/// table](https://developer.mozilla.org/en-US/docs/WebAssembly/Understanding_the_text_format#WebAssembly_tables).
///
@@ -477,8 +423,6 @@ pub enum AnyEntity {
FuncRef(FuncRef),
/// A function call signature.
SigRef(SigRef),
/// A heap.
Heap(Heap),
/// A table.
Table(Table),
/// A function's stack limit
@@ -500,7 +444,6 @@ impl fmt::Display for AnyEntity {
Self::Constant(r) => r.fmt(f),
Self::FuncRef(r) => r.fmt(f),
Self::SigRef(r) => r.fmt(f),
Self::Heap(r) => r.fmt(f),
Self::Table(r) => r.fmt(f),
Self::StackLimit => write!(f, "stack_limit"),
}
@@ -579,12 +522,6 @@ impl From<SigRef> for AnyEntity {
}
}
impl From<Heap> for AnyEntity {
fn from(r: Heap) -> Self {
Self::Heap(r)
}
}
impl From<Table> for AnyEntity {
fn from(r: Table) -> Self {
Self::Table(r)

View File

@@ -8,8 +8,8 @@ use crate::ir;
use crate::ir::JumpTables;
use crate::ir::{
instructions::BranchInfo, Block, DynamicStackSlot, DynamicStackSlotData, DynamicType,
ExtFuncData, FuncRef, GlobalValue, GlobalValueData, Heap, HeapData, Inst, InstructionData,
JumpTable, JumpTableData, Opcode, SigRef, StackSlot, StackSlotData, Table, TableData, Type,
ExtFuncData, FuncRef, GlobalValue, GlobalValueData, Inst, InstructionData, JumpTable,
JumpTableData, Opcode, SigRef, StackSlot, StackSlotData, Table, TableData, Type,
};
use crate::ir::{DataFlowGraph, Layout, Signature};
use crate::ir::{DynamicStackSlots, SourceLocs, StackSlots};
@@ -170,9 +170,6 @@ pub struct FunctionStencil {
/// Global values referenced.
pub global_values: PrimaryMap<ir::GlobalValue, ir::GlobalValueData>,
/// Heaps referenced.
pub heaps: PrimaryMap<ir::Heap, ir::HeapData>,
/// Tables referenced.
pub tables: PrimaryMap<ir::Table, ir::TableData>,
@@ -205,7 +202,6 @@ impl FunctionStencil {
self.sized_stack_slots.clear();
self.dynamic_stack_slots.clear();
self.global_values.clear();
self.heaps.clear();
self.tables.clear();
self.jump_tables.clear();
self.dfg.clear();
@@ -261,11 +257,6 @@ impl FunctionStencil {
.concrete()
}
/// Declares a heap accessible to the function.
pub fn create_heap(&mut self, data: HeapData) -> Heap {
self.heaps.push(data)
}
/// Declares a table accessible to the function.
pub fn create_table(&mut self, data: TableData) -> Table {
self.tables.push(data)
@@ -447,7 +438,6 @@ impl Function {
sized_stack_slots: StackSlots::new(),
dynamic_stack_slots: DynamicStackSlots::new(),
global_values: PrimaryMap::new(),
heaps: PrimaryMap::new(),
tables: PrimaryMap::new(),
jump_tables: PrimaryMap::new(),
dfg: DataFlowGraph::new(),

View File

@@ -1,67 +0,0 @@
//! Heaps.
use crate::ir::immediates::Uimm64;
use crate::ir::{GlobalValue, Type};
use core::fmt;
#[cfg(feature = "enable-serde")]
use serde::{Deserialize, Serialize};
/// Information about a heap declaration.
#[derive(Clone, PartialEq, Hash)]
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
pub struct HeapData {
/// The address of the start of the heap's storage.
pub base: GlobalValue,
/// Guaranteed minimum heap size in bytes. Heap accesses before `min_size` don't need bounds
/// checking.
pub min_size: Uimm64,
/// Size in bytes of the offset-guard pages following the heap.
pub offset_guard_size: Uimm64,
/// Heap style, with additional style-specific info.
pub style: HeapStyle,
/// The index type for the heap.
pub index_type: Type,
}
/// Style of heap including style-specific information.
#[derive(Clone, PartialEq, Hash)]
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
pub enum HeapStyle {
/// A dynamic heap can be relocated to a different base address when it is grown.
Dynamic {
/// Global value providing the current bound of the heap in bytes.
bound_gv: GlobalValue,
},
/// A static heap has a fixed base address and a number of not-yet-allocated pages before the
/// offset-guard pages.
Static {
/// Heap bound in bytes. The offset-guard pages are allocated after the bound.
bound: Uimm64,
},
}
impl fmt::Display for HeapData {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(match self.style {
HeapStyle::Dynamic { .. } => "dynamic",
HeapStyle::Static { .. } => "static",
})?;
write!(f, " {}, min {}", self.base, self.min_size)?;
match self.style {
HeapStyle::Dynamic { bound_gv } => write!(f, ", bound {}", bound_gv)?,
HeapStyle::Static { bound } => write!(f, ", bound {}", bound)?,
}
write!(
f,
", offset_guard {}, index_type {}",
self.offset_guard_size, self.index_type
)
}
}

View File

@@ -4,7 +4,6 @@
//! Each type here should have a corresponding definition in the
//! `cranelift-codegen/meta/src/shared/immediates` crate in the meta language.
use crate::ir;
use alloc::vec::Vec;
use core::cmp::Ordering;
use core::convert::TryFrom;
@@ -1178,18 +1177,6 @@ impl Not for Ieee64 {
}
}
/// Out-of-line heap access immediates.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
pub struct HeapImmData {
/// The memory flags for the heap access.
pub flags: ir::MemFlags,
/// The heap being accessed.
pub heap: ir::Heap,
/// The static offset added to the heap access's index.
pub offset: Uimm32,
}
#[cfg(test)]
mod tests {
use super::*;

View File

@@ -11,7 +11,6 @@ mod extfunc;
mod extname;
pub mod function;
mod globalvalue;
mod heap;
pub mod immediates;
pub mod instructions;
pub mod jumptable;
@@ -37,8 +36,8 @@ pub use crate::ir::constant::{ConstantData, ConstantPool};
pub use crate::ir::dfg::{DataFlowGraph, ValueDef};
pub use crate::ir::dynamic_type::{dynamic_to_fixed, DynamicTypeData, DynamicTypes};
pub use crate::ir::entities::{
Block, Constant, DynamicStackSlot, DynamicType, FuncRef, GlobalValue, Heap, HeapImm, Immediate,
Inst, JumpTable, SigRef, StackSlot, Table, UserExternalNameRef, Value,
Block, Constant, DynamicStackSlot, DynamicType, FuncRef, GlobalValue, Immediate, Inst,
JumpTable, SigRef, StackSlot, Table, UserExternalNameRef, Value,
};
pub use crate::ir::extfunc::{
AbiParam, ArgumentExtension, ArgumentPurpose, ExtFuncData, Signature,
@@ -46,7 +45,6 @@ pub use crate::ir::extfunc::{
pub use crate::ir::extname::{ExternalName, UserExternalName, UserFuncName};
pub use crate::ir::function::{DisplayFunctionAnnotations, Function};
pub use crate::ir::globalvalue::GlobalValueData;
pub use crate::ir::heap::{HeapData, HeapStyle};
pub use crate::ir::instructions::{
InstructionData, Opcode, ValueList, ValueListPool, VariableArgs,
};