diff options
Diffstat (limited to 'compiler/rustc_codegen_cranelift/src/pointer.rs')
| -rw-r--r-- | compiler/rustc_codegen_cranelift/src/pointer.rs | 206 |
1 files changed, 206 insertions, 0 deletions
diff --git a/compiler/rustc_codegen_cranelift/src/pointer.rs b/compiler/rustc_codegen_cranelift/src/pointer.rs new file mode 100644 index 00000000000..b2036d7bcd4 --- /dev/null +++ b/compiler/rustc_codegen_cranelift/src/pointer.rs @@ -0,0 +1,206 @@ +//! Defines [`Pointer`] which is used to improve the quality of the generated clif ir for pointer +//! operations. + +use crate::prelude::*; + +use rustc_target::abi::Align; + +use cranelift_codegen::ir::immediates::Offset32; + +/// A pointer pointing either to a certain address, a certain stack slot or nothing. +#[derive(Copy, Clone, Debug)] +pub(crate) struct Pointer { + base: PointerBase, + offset: Offset32, +} + +#[derive(Copy, Clone, Debug)] +pub(crate) enum PointerBase { + Addr(Value), + Stack(StackSlot), + Dangling(Align), +} + +impl Pointer { + pub(crate) fn new(addr: Value) -> Self { + Pointer { + base: PointerBase::Addr(addr), + offset: Offset32::new(0), + } + } + + pub(crate) fn stack_slot(stack_slot: StackSlot) -> Self { + Pointer { + base: PointerBase::Stack(stack_slot), + offset: Offset32::new(0), + } + } + + pub(crate) fn const_addr<'a, 'tcx>( + fx: &mut FunctionCx<'a, 'tcx, impl Module>, + addr: i64, + ) -> Self { + let addr = fx.bcx.ins().iconst(fx.pointer_type, addr); + Pointer { + base: PointerBase::Addr(addr), + offset: Offset32::new(0), + } + } + + pub(crate) fn dangling(align: Align) -> Self { + Pointer { + base: PointerBase::Dangling(align), + offset: Offset32::new(0), + } + } + + #[cfg(debug_assertions)] + pub(crate) fn base_and_offset(self) -> (PointerBase, Offset32) { + (self.base, self.offset) + } + + pub(crate) fn get_addr<'a, 'tcx>(self, fx: &mut FunctionCx<'a, 'tcx, impl Module>) -> Value { + match self.base { + PointerBase::Addr(base_addr) => { + let offset: i64 = self.offset.into(); + if offset == 0 { + base_addr + } else { + fx.bcx.ins().iadd_imm(base_addr, offset) + } + } + PointerBase::Stack(stack_slot) => { + fx.bcx + .ins() + .stack_addr(fx.pointer_type, stack_slot, self.offset) + } + PointerBase::Dangling(align) => fx + .bcx + .ins() + .iconst(fx.pointer_type, i64::try_from(align.bytes()).unwrap()), + } + } + + pub(crate) fn offset<'a, 'tcx>( + self, + fx: &mut FunctionCx<'a, 'tcx, impl Module>, + extra_offset: Offset32, + ) -> Self { + self.offset_i64(fx, extra_offset.into()) + } + + pub(crate) fn offset_i64<'a, 'tcx>( + self, + fx: &mut FunctionCx<'a, 'tcx, impl Module>, + extra_offset: i64, + ) -> Self { + if let Some(new_offset) = self.offset.try_add_i64(extra_offset) { + Pointer { + base: self.base, + offset: new_offset, + } + } else { + let base_offset: i64 = self.offset.into(); + if let Some(new_offset) = base_offset.checked_add(extra_offset) { + let base_addr = match self.base { + PointerBase::Addr(addr) => addr, + PointerBase::Stack(stack_slot) => { + fx.bcx.ins().stack_addr(fx.pointer_type, stack_slot, 0) + } + PointerBase::Dangling(align) => fx + .bcx + .ins() + .iconst(fx.pointer_type, i64::try_from(align.bytes()).unwrap()), + }; + let addr = fx.bcx.ins().iadd_imm(base_addr, new_offset); + Pointer { + base: PointerBase::Addr(addr), + offset: Offset32::new(0), + } + } else { + panic!( + "self.offset ({}) + extra_offset ({}) not representable in i64", + base_offset, extra_offset + ); + } + } + } + + pub(crate) fn offset_value<'a, 'tcx>( + self, + fx: &mut FunctionCx<'a, 'tcx, impl Module>, + extra_offset: Value, + ) -> Self { + match self.base { + PointerBase::Addr(addr) => Pointer { + base: PointerBase::Addr(fx.bcx.ins().iadd(addr, extra_offset)), + offset: self.offset, + }, + PointerBase::Stack(stack_slot) => { + let base_addr = fx + .bcx + .ins() + .stack_addr(fx.pointer_type, stack_slot, self.offset); + Pointer { + base: PointerBase::Addr(fx.bcx.ins().iadd(base_addr, extra_offset)), + offset: Offset32::new(0), + } + } + PointerBase::Dangling(align) => { + let addr = fx + .bcx + .ins() + .iconst(fx.pointer_type, i64::try_from(align.bytes()).unwrap()); + Pointer { + base: PointerBase::Addr(fx.bcx.ins().iadd(addr, extra_offset)), + offset: self.offset, + } + } + } + } + + pub(crate) fn load<'a, 'tcx>( + self, + fx: &mut FunctionCx<'a, 'tcx, impl Module>, + ty: Type, + flags: MemFlags, + ) -> Value { + match self.base { + PointerBase::Addr(base_addr) => fx.bcx.ins().load(ty, flags, base_addr, self.offset), + PointerBase::Stack(stack_slot) => { + if ty == types::I128 || ty.is_vector() { + // WORKAROUND for stack_load.i128 and stack_load.iXxY not being implemented + let base_addr = fx.bcx.ins().stack_addr(fx.pointer_type, stack_slot, 0); + fx.bcx.ins().load(ty, flags, base_addr, self.offset) + } else { + fx.bcx.ins().stack_load(ty, stack_slot, self.offset) + } + } + PointerBase::Dangling(_align) => unreachable!(), + } + } + + pub(crate) fn store<'a, 'tcx>( + self, + fx: &mut FunctionCx<'a, 'tcx, impl Module>, + value: Value, + flags: MemFlags, + ) { + match self.base { + PointerBase::Addr(base_addr) => { + fx.bcx.ins().store(flags, value, base_addr, self.offset); + } + PointerBase::Stack(stack_slot) => { + let val_ty = fx.bcx.func.dfg.value_type(value); + if val_ty == types::I128 || val_ty.is_vector() { + // WORKAROUND for stack_store.i128 and stack_store.iXxY not being implemented + let base_addr = fx.bcx.ins().stack_addr(fx.pointer_type, stack_slot, 0); + fx.bcx.ins().store(flags, value, base_addr, self.offset); + } else { + fx.bcx.ins().stack_store(value, stack_slot, self.offset); + } + } + PointerBase::Dangling(_align) => unreachable!(), + } + } +} |
