Cranelift: Add heap_load and heap_store instructions (#5300)

* Cranelift: Define `heap_load` and `heap_store` instructions

* Cranelift: Implement interpreter support for `heap_load` and `heap_store`

* Cranelift: Add a suite runtests for `heap_{load,store}`

There are so many knobs we can twist for heaps and I wanted to exhaustively test
all of them, so I wrote a script to generate the tests. I've checked in the
script in case we want to make any changes in the future, but I don't think it
is worth adding this to CI to check that scripts are up to date or anything like
that.

* Review feedback
This commit is contained in:
Nick Fitzgerald
2022-11-21 15:00:39 -08:00
committed by GitHub
parent b305f251fb
commit d0d3245a35
24 changed files with 693 additions and 13 deletions

View File

@@ -11,7 +11,9 @@ use crate::testfile::{Comment, Details, Feature, TestFile};
use cranelift_codegen::data_value::DataValue;
use cranelift_codegen::entity::{EntityRef, PrimaryMap};
use cranelift_codegen::ir::entities::{AnyEntity, DynamicType};
use cranelift_codegen::ir::immediates::{Ieee32, Ieee64, Imm64, Offset32, Uimm32, Uimm64};
use cranelift_codegen::ir::immediates::{
HeapImmData, Ieee32, Ieee64, Imm64, Offset32, Uimm32, Uimm64,
};
use cranelift_codegen::ir::instructions::{InstructionData, InstructionFormat, VariableArgs};
use cranelift_codegen::ir::types::INVALID;
use cranelift_codegen::ir::types::*;
@@ -876,6 +878,19 @@ impl<'a> Parser<'a> {
}
}
// Match and consume an optional uimm32 offset immediate.
//
// Note that this will match an empty string as an empty offset, and that if an offset is
// present, it must contain a plus sign.
fn optional_uimm32_offset(&mut self) -> ParseResult<Uimm32> {
match self.token() {
Some(Token::Integer(x)) if x.starts_with('+') => {
self.match_uimm32("expected a uimm32 offset immediate")
}
_ => Ok(Uimm32::from(0)),
}
}
// Match and consume a u8 immediate.
// This is used for lane numbers in SIMD vectors.
fn match_uimm8(&mut self, err_msg: &str) -> ParseResult<u8> {
@@ -2976,6 +2991,42 @@ impl<'a> Parser<'a> {
size,
}
}
InstructionFormat::HeapLoad => {
let heap = self.match_heap("expected heap identifier")?;
ctx.check_heap(heap, self.loc)?;
let flags = self.optional_memflags();
let arg = self.match_value("expected SSA value heap index")?;
let offset = self.optional_uimm32_offset()?;
let heap_imm = ctx.function.dfg.heap_imms.push(HeapImmData {
flags,
heap,
offset,
});
InstructionData::HeapLoad {
opcode,
heap_imm,
arg,
}
}
InstructionFormat::HeapStore => {
let heap = self.match_heap("expected heap identifier")?;
ctx.check_heap(heap, self.loc)?;
let flags = self.optional_memflags();
let index = self.match_value("expected SSA value heap index")?;
let offset = self.optional_uimm32_offset()?;
self.match_token(Token::Comma, "expected ',' between operands")?;
let value = self.match_value("expected SSA value to store")?;
let heap_imm = ctx.function.dfg.heap_imms.push(HeapImmData {
flags,
heap,
offset,
});
InstructionData::HeapStore {
opcode,
heap_imm,
args: [index, value],
}
}
InstructionFormat::TableAddr => {
let table = self.match_table("expected table identifier")?;
ctx.check_table(table, self.loc)?;