Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 8d257b9

Browse files
committed
Auto merge of rust-lang#117473 - saethlin:codegen-alignment-checks, r=<try>
Move alignment checks to codegen Implementing UB checks entirely in a MIR transform is quite limiting, we don't know for sure what all our types are so we need to make a lot of sacrifices. For example in here we used to emit MIR to compute the alignment mask at runtime, because the pointee type could be generic. Implementing the checks in codegen frees us from that requirement, because we get to deal with monomorphized types. But I don't think we can move these checks entirely into codegen, because inserting the check needs to insert a new terminator into a basic block, which splits the previous basic block into two. We can't add control flow like this in codegen, but we can in MIR. So now the MIR transform just inserts a `TerminatorKind::UbCheck` which is effectively a `Goto` that also reads an `Operand` (because it either goes to the target block or terminates), and codegen expands that new terminator into the actual check. --- Also I'm writing this with the expectation that I implement the niche checks in the same manner, because they have the same problem with polymorphic MIR, possibly worse. r? `@ghost`
2 parents 2c1b65e + 165048a commit 8d257b9

File tree

41 files changed

+252
-255
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+252
-255
lines changed

compiler/rustc_borrowck/src/invalidation.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,8 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> {
205205
| TerminatorKind::UnwindTerminate(_)
206206
| TerminatorKind::Unreachable
207207
| TerminatorKind::FalseEdge { real_target: _, imaginary_target: _ }
208-
| TerminatorKind::FalseUnwind { real_target: _, unwind: _ } => {
208+
| TerminatorKind::FalseUnwind { real_target: _, unwind: _ }
209+
| TerminatorKind::UbCheck { .. } => {
209210
// no data used, thus irrelevant to borrowck
210211
}
211212
}

compiler/rustc_borrowck/src/lib.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -785,7 +785,8 @@ impl<'cx, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx, R> for MirBorro
785785
| TerminatorKind::Return
786786
| TerminatorKind::CoroutineDrop
787787
| TerminatorKind::FalseEdge { real_target: _, imaginary_target: _ }
788-
| TerminatorKind::FalseUnwind { real_target: _, unwind: _ } => {
788+
| TerminatorKind::FalseUnwind { real_target: _, unwind: _ }
789+
| TerminatorKind::UbCheck { .. } => {
789790
// no data used, thus irrelevant to borrowck
790791
}
791792
}
@@ -835,7 +836,8 @@ impl<'cx, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx, R> for MirBorro
835836
| TerminatorKind::Goto { .. }
836837
| TerminatorKind::SwitchInt { .. }
837838
| TerminatorKind::Unreachable
838-
| TerminatorKind::InlineAsm { .. } => {}
839+
| TerminatorKind::InlineAsm { .. }
840+
| TerminatorKind::UbCheck { .. } => {}
839841
}
840842
}
841843
}

compiler/rustc_borrowck/src/type_check/mod.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1358,7 +1358,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
13581358
| TerminatorKind::Drop { .. }
13591359
| TerminatorKind::FalseEdge { .. }
13601360
| TerminatorKind::FalseUnwind { .. }
1361-
| TerminatorKind::InlineAsm { .. } => {
1361+
| TerminatorKind::InlineAsm { .. }
1362+
| TerminatorKind::UbCheck { .. } => {
13621363
// no checks needed for these
13631364
}
13641365

@@ -1690,6 +1691,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
16901691
}
16911692
self.assert_iscleanup_unwind(body, block_data, unwind, is_cleanup);
16921693
}
1694+
TerminatorKind::UbCheck { target, .. } => {
1695+
self.assert_iscleanup(body, block_data, target, is_cleanup)
1696+
}
16931697
}
16941698
}
16951699

compiler/rustc_codegen_cranelift/src/base.rs

Lines changed: 34 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -356,18 +356,6 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) {
356356
source_info.span,
357357
);
358358
}
359-
AssertKind::MisalignedPointerDereference { ref required, ref found } => {
360-
let required = codegen_operand(fx, required).load_scalar(fx);
361-
let found = codegen_operand(fx, found).load_scalar(fx);
362-
let location = fx.get_caller_location(source_info).load_scalar(fx);
363-
364-
codegen_panic_inner(
365-
fx,
366-
rustc_hir::LangItem::PanicMisalignedPointerDereference,
367-
&[required, found, location],
368-
source_info.span,
369-
);
370-
}
371359
_ => {
372360
let msg_str = msg.description();
373361
codegen_panic(fx, msg_str, source_info);
@@ -488,6 +476,40 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) {
488476
let target_block = fx.get_block(*target);
489477
fx.bcx.ins().jump(target_block, &[]);
490478
}
479+
TerminatorKind::UbCheck { target, kind: UbCheckKind::PointerAlignment { pointer } } => {
480+
let location = fx.get_caller_location(source_info).load_scalar(fx);
481+
let pointer = codegen_operand(fx, pointer);
482+
let pointee_ty = pointer.layout().ty.builtin_deref(true).unwrap();
483+
let pointee_layout = fx.layout_of(pointee_ty.ty);
484+
let pointer = pointer.load_scalar(fx);
485+
486+
// Compute the alignment mask
487+
let align = pointee_layout.align.abi.bytes() as i64;
488+
let mask = fx.bcx.ins().iconst(fx.pointer_type, align - 1);
489+
let required = fx.bcx.ins().iconst(fx.pointer_type, align);
490+
491+
// And the pointer with the mask
492+
let masked = fx.bcx.ins().band(pointer, mask);
493+
494+
// Branch on whether the masked value is zero
495+
let is_zero = fx.bcx.ins().icmp_imm(IntCC::Equal, masked, 0);
496+
497+
// Create a new block that we will jump to if !is_zero
498+
let failure = fx.bcx.create_block();
499+
fx.bcx.set_cold_block(failure);
500+
501+
let target = fx.get_block(*target);
502+
fx.bcx.ins().brif(is_zero, target, &[], failure, &[]);
503+
504+
// Codegen the actual panic
505+
fx.bcx.switch_to_block(failure);
506+
codegen_panic_inner(
507+
fx,
508+
rustc_hir::LangItem::PanicMisalignedPointerDereference,
509+
&[required, pointer, location],
510+
source_info.span,
511+
);
512+
}
491513
};
492514
}
493515
}

compiler/rustc_codegen_cranelift/src/constant.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -508,7 +508,8 @@ pub(crate) fn mir_operand_get_const_val<'tcx>(
508508
| TerminatorKind::Return
509509
| TerminatorKind::Unreachable
510510
| TerminatorKind::Drop { .. }
511-
| TerminatorKind::Assert { .. } => {}
511+
| TerminatorKind::Assert { .. }
512+
| TerminatorKind::UbCheck { .. } => {}
512513
TerminatorKind::Yield { .. }
513514
| TerminatorKind::CoroutineDrop
514515
| TerminatorKind::FalseEdge { .. }

compiler/rustc_codegen_ssa/src/mir/analyze.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -277,7 +277,8 @@ pub fn cleanup_kinds(mir: &mir::Body<'_>) -> IndexVec<mir::BasicBlock, CleanupKi
277277
| TerminatorKind::SwitchInt { .. }
278278
| TerminatorKind::Yield { .. }
279279
| TerminatorKind::FalseEdge { .. }
280-
| TerminatorKind::FalseUnwind { .. } => { /* nothing to do */ }
280+
| TerminatorKind::FalseUnwind { .. }
281+
| TerminatorKind::UbCheck { .. } => { /* nothing to do */ }
281282
TerminatorKind::Call { unwind, .. }
282283
| TerminatorKind::InlineAsm { unwind, .. }
283284
| TerminatorKind::Assert { unwind, .. }

compiler/rustc_codegen_ssa/src/mir/block.rs

Lines changed: 79 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use crate::MemFlags;
1212
use rustc_ast as ast;
1313
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
1414
use rustc_hir::lang_items::LangItem;
15-
use rustc_middle::mir::{self, AssertKind, SwitchTargets, UnwindTerminateReason};
15+
use rustc_middle::mir::{self, AssertKind, SwitchTargets, UbCheckKind, UnwindTerminateReason};
1616
use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, ValidityRequirement};
1717
use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths};
1818
use rustc_middle::ty::{self, Instance, Ty};
@@ -616,13 +616,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
616616
// and `#[track_caller]` adds an implicit third argument.
617617
(LangItem::PanicBoundsCheck, vec![index, len, location])
618618
}
619-
AssertKind::MisalignedPointerDereference { ref required, ref found } => {
620-
let required = self.codegen_operand(bx, required).immediate();
621-
let found = self.codegen_operand(bx, found).immediate();
622-
// It's `fn panic_misaligned_pointer_dereference(required: usize, found: usize)`,
623-
// and `#[track_caller]` adds an implicit third argument.
624-
(LangItem::PanicMisalignedPointerDereference, vec![required, found, location])
625-
}
626619
_ => {
627620
let msg = bx.const_str(msg.description());
628621
// It's `pub fn panic(expr: &str)`, with the wide reference being passed
@@ -736,6 +729,79 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
736729
}
737730
}
738731

732+
fn codegen_alignment_check(
733+
&mut self,
734+
helper: &TerminatorCodegenHelper<'tcx>,
735+
bx: &mut Bx,
736+
pointer: &mir::Operand<'tcx>,
737+
source_info: mir::SourceInfo,
738+
target: mir::BasicBlock,
739+
) -> MergingSucc {
740+
let span = source_info.span;
741+
let pointer = self.codegen_operand(bx, pointer);
742+
let pointee_ty = pointer.layout.ty.builtin_deref(true).unwrap();
743+
let pointee_layout = bx.layout_of(pointee_ty.ty);
744+
745+
let mk_usize = |v: u64| {
746+
let layout = bx.layout_of(bx.tcx().types.usize);
747+
let rustc_target::abi::Abi::Scalar(abi) = layout.abi else { unreachable!() };
748+
let v = rustc_middle::mir::interpret::Scalar::from_target_usize(v, &bx.tcx());
749+
bx.scalar_to_backend(v, abi, bx.cx().type_isize())
750+
};
751+
752+
let align = pointee_layout.align.abi.bytes();
753+
let mask = mk_usize(align - 1);
754+
let zero = mk_usize(0);
755+
let required = mk_usize(align);
756+
757+
let ptr_imm = match pointer.val {
758+
crate::mir::OperandValue::Immediate(imm) => imm,
759+
crate::mir::OperandValue::Pair(ptr, _) => ptr,
760+
_ => {
761+
unreachable!("{pointer:?}");
762+
}
763+
};
764+
let int_imm = bx.ptrtoint(ptr_imm, bx.cx().type_isize());
765+
766+
let masked = bx.and(int_imm, mask);
767+
768+
let is_zero = bx.icmp(
769+
crate::base::bin_op_to_icmp_predicate(mir::BinOp::Eq.to_hir_binop(), false),
770+
masked,
771+
zero,
772+
);
773+
774+
let lltarget = helper.llbb_with_cleanup(self, target);
775+
let panic_block = bx.append_sibling_block("panic");
776+
777+
bx.cond_br(is_zero, lltarget, panic_block);
778+
779+
bx.switch_to_block(panic_block);
780+
self.set_debug_loc(bx, source_info);
781+
782+
let location = self.get_caller_location(bx, source_info).immediate();
783+
784+
let found = int_imm;
785+
786+
let (lang_item, args) =
787+
(LangItem::PanicMisalignedPointerDereference, vec![required, found, location]);
788+
789+
let (fn_abi, llfn) = common::build_langcall(bx, Some(span), lang_item);
790+
let merging_succ = helper.do_call(
791+
self,
792+
bx,
793+
fn_abi,
794+
llfn,
795+
&args,
796+
None,
797+
mir::UnwindAction::Unreachable,
798+
&[],
799+
false,
800+
);
801+
assert_eq!(merging_succ, MergingSucc::False);
802+
MergingSucc::False
803+
}
804+
739805
fn codegen_call_terminator(
740806
&mut self,
741807
helper: TerminatorCodegenHelper<'tcx>,
@@ -1291,6 +1357,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
12911357
self.instance,
12921358
mergeable_succ(),
12931359
),
1360+
1361+
mir::TerminatorKind::UbCheck {
1362+
target,
1363+
kind: UbCheckKind::PointerAlignment { ref pointer },
1364+
} => self.codegen_alignment_check(&helper, bx, pointer, terminator.source_info, target),
12941365
}
12951366
}
12961367

compiler/rustc_const_eval/src/const_eval/machine.rs

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -555,12 +555,6 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
555555
RemainderByZero(op) => RemainderByZero(eval_to_int(op)?),
556556
ResumedAfterReturn(coroutine_kind) => ResumedAfterReturn(*coroutine_kind),
557557
ResumedAfterPanic(coroutine_kind) => ResumedAfterPanic(*coroutine_kind),
558-
MisalignedPointerDereference { ref required, ref found } => {
559-
MisalignedPointerDereference {
560-
required: eval_to_int(required)?,
561-
found: eval_to_int(found)?,
562-
}
563-
}
564558
};
565559
Err(ConstEvalErrKind::AssertFailure(err).into())
566560
}

compiler/rustc_const_eval/src/interpret/terminator.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
8585
self.pop_stack_frame(/* unwinding */ false)?
8686
}
8787

88-
Goto { target } => self.go_to_block(target),
88+
Goto { target } | UbCheck { target, .. } => self.go_to_block(target),
8989

9090
SwitchInt { ref discr, ref targets } => {
9191
let discr = self.read_immediate(&self.eval_operand(discr, None)?)?;

compiler/rustc_const_eval/src/transform/check_consts/check.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1058,7 +1058,8 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
10581058
| TerminatorKind::UnwindResume
10591059
| TerminatorKind::Return
10601060
| TerminatorKind::SwitchInt { .. }
1061-
| TerminatorKind::Unreachable => {}
1061+
| TerminatorKind::Unreachable
1062+
| TerminatorKind::UbCheck { .. } => {}
10621063
}
10631064
}
10641065
}

0 commit comments

Comments
 (0)