use inkwell::values::BasicValue;
use inkwell::values::BasicValueEnum;
use revive_common::BYTE_LENGTH_BYTE;
use crate::polkavm::context::address_space::AddressSpace;
use crate::polkavm::context::pointer::heap::{
build_efficient_load_swap, build_efficient_store_swap,
};
use crate::polkavm::context::pointer::Pointer;
use crate::polkavm::context::Context;
pub fn msize<'ctx>(
context: &mut Context<'ctx>,
) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>> {
Ok(context
.builder()
.build_int_z_extend(
context.build_msize()?,
context.word_type(),
"heap_size_extended",
)?
.as_basic_value_enum())
}
pub fn load<'ctx>(
context: &mut Context<'ctx>,
offset: inkwell::values::IntValue<'ctx>,
) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>> {
let pointer = Pointer::new_with_offset(
context,
AddressSpace::Heap,
context.word_type(),
offset,
"memory_load_pointer",
);
context.build_load(pointer, "memory_load_result")
}
pub fn store<'ctx>(
context: &mut Context<'ctx>,
offset: inkwell::values::IntValue<'ctx>,
value: inkwell::values::IntValue<'ctx>,
) -> anyhow::Result<()> {
let pointer = Pointer::new_with_offset(
context,
AddressSpace::Heap,
context.word_type(),
offset,
"memory_store_pointer",
);
context.build_store(pointer, value)?;
Ok(())
}
pub fn store_byte<'ctx>(
context: &mut Context<'ctx>,
offset: inkwell::values::IntValue<'ctx>,
value: inkwell::values::IntValue<'ctx>,
) -> anyhow::Result<()> {
let byte_type = context.byte_type();
let value = context
.builder()
.build_int_truncate(value, byte_type, "mstore8_value")?;
let pointer = Pointer::new_with_offset(
context,
AddressSpace::Heap,
byte_type,
offset,
"mstore8_destination",
);
let pointer = context.build_sbrk(
pointer.to_int(context),
context.xlen_type().const_int(1, false),
)?;
context
.builder()
.build_store(pointer, value)?
.set_alignment(BYTE_LENGTH_BYTE as u32)
.expect("ICE: alignment is valid");
Ok(())
}
pub fn store_bswap_unchecked<'ctx>(
context: &Context<'ctx>,
offset: inkwell::values::IntValue<'ctx>,
value: inkwell::values::IntValue<'ctx>,
) -> anyhow::Result<()> {
let pointer = context.build_heap_gep_unchecked(offset)?;
build_efficient_store_swap(context, pointer.value, value)
}
pub fn load_bswap_unchecked<'ctx>(
context: &Context<'ctx>,
offset: inkwell::values::IntValue<'ctx>,
) -> anyhow::Result<BasicValueEnum<'ctx>> {
let pointer = context.build_heap_gep_unchecked(offset)?;
build_efficient_load_swap(context, pointer.value)
}
pub fn load_native_inline<'ctx>(
context: &mut Context<'ctx>,
offset: inkwell::values::IntValue<'ctx>,
) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>> {
let length = context
.xlen_type()
.const_int(revive_common::BYTE_LENGTH_WORD as u64, false);
let pointer = context.build_heap_gep(offset, length)?;
let value = context
.builder()
.build_load(context.word_type(), pointer.value, "native_load")?;
context
.basic_block()
.get_last_instruction()
.expect("ICE: load instruction always exists")
.set_alignment(BYTE_LENGTH_BYTE as u32)
.expect("ICE: alignment is valid");
Ok(value)
}
pub fn store_native_inline<'ctx>(
context: &mut Context<'ctx>,
offset: inkwell::values::IntValue<'ctx>,
value: inkwell::values::IntValue<'ctx>,
) -> anyhow::Result<()> {
let length = context
.xlen_type()
.const_int(revive_common::BYTE_LENGTH_WORD as u64, false);
let pointer = context.build_heap_gep(offset, length)?;
context
.builder()
.build_store(pointer.value, value)?
.set_alignment(BYTE_LENGTH_BYTE as u32)
.expect("ICE: alignment is valid");
Ok(())
}