Skip to content

Commit 261325f

Browse files
committed
Add -Zcodegen-emit-retag with nop retags.
1 parent 32bd660 commit 261325f

9 files changed

Lines changed: 237 additions & 26 deletions

File tree

compiler/rustc_codegen_ssa/src/mir/block.rs

Lines changed: 58 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ use super::{CachedLlbb, FunctionCx, LocalRef};
2323
use crate::base::{self, is_call_from_compiler_builtins_to_upstream_monomorphization};
2424
use crate::common::{self, IntPredicate};
2525
use crate::errors::CompilerBuiltinsCannotCall;
26+
use crate::mir::retag;
2627
use crate::traits::*;
2728
use crate::{MemFlags, meth};
2829

@@ -263,6 +264,12 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
263264
bx.lifetime_end(tmp, size);
264265
}
265266
fx.store_return(bx, ret_dest, &fn_abi.ret, invokeret);
267+
268+
// If the return value has variants that needed to be retagged,
269+
// then we might be in a different basic block now.
270+
// Update the cached block for `target` to point to this new
271+
// block, where codegen will continue.
272+
fx.cached_llbbs[target] = CachedLlbb::Some(bx.llbb());
266273
}
267274
MergingSucc::False
268275
} else {
@@ -1054,21 +1061,26 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
10541061
let result_layout =
10551062
self.cx.layout_of(self.monomorphized_place_ty(destination.as_ref()));
10561063

1064+
let needs_retag = retag::place_needs_retag(&destination);
1065+
10571066
let return_dest = if result_layout.is_zst() {
10581067
ReturnDest::Nothing
10591068
} else if let Some(index) = destination.as_local() {
10601069
match self.locals[index] {
1061-
LocalRef::Place(dest) => ReturnDest::Store(dest),
1070+
LocalRef::Place(dest) => ReturnDest::Store { dest, needs_retag },
10621071
LocalRef::UnsizedPlace(_) => bug!("return type must be sized"),
10631072
LocalRef::PendingOperand => {
10641073
// Handle temporary places, specifically `Operand` ones, as
10651074
// they don't have `alloca`s.
1066-
ReturnDest::DirectOperand(index)
1075+
ReturnDest::DirectOperand { index, needs_retag }
10671076
}
10681077
LocalRef::Operand(_) => bug!("place local already assigned to"),
10691078
}
10701079
} else {
1071-
ReturnDest::Store(self.codegen_place(bx, destination.as_ref()))
1080+
ReturnDest::Store {
1081+
dest: self.codegen_place(bx, destination.as_ref()),
1082+
needs_retag,
1083+
}
10721084
};
10731085

10741086
let args =
@@ -2097,6 +2109,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
20972109
if fn_ret.is_ignore() {
20982110
return ReturnDest::Nothing;
20992111
}
2112+
2113+
let needs_retag = retag::place_needs_retag(&dest);
2114+
21002115
let dest = if let Some(index) = dest.as_local() {
21012116
match self.locals[index] {
21022117
LocalRef::Place(dest) => dest,
@@ -2110,9 +2125,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
21102125
let tmp = PlaceRef::alloca(bx, fn_ret.layout);
21112126
tmp.storage_live(bx);
21122127
llargs.push(tmp.val.llval);
2113-
ReturnDest::IndirectOperand(tmp, index)
2128+
ReturnDest::IndirectOperand { tmp, index, needs_retag }
21142129
} else {
2115-
ReturnDest::DirectOperand(index)
2130+
ReturnDest::DirectOperand { index, needs_retag }
21162131
};
21172132
}
21182133
LocalRef::Operand(_) => {
@@ -2135,7 +2150,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
21352150
llargs.push(dest.val.llval);
21362151
ReturnDest::Nothing
21372152
} else {
2138-
ReturnDest::Store(dest)
2153+
ReturnDest::Store { dest, needs_retag }
21392154
}
21402155
}
21412156

@@ -2148,19 +2163,27 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
21482163
llval: Bx::Value,
21492164
) {
21502165
use self::ReturnDest::*;
2151-
2166+
let retags_enabled = bx.tcx().sess.opts.unstable_opts.codegen_emit_retag.is_some();
21522167
match dest {
21532168
Nothing => (),
2154-
Store(dst) => bx.store_arg(ret_abi, llval, dst),
2155-
IndirectOperand(tmp, index) => {
2156-
let op = bx.load_operand(tmp);
2169+
Store { dest, needs_retag } => {
2170+
bx.store_arg(ret_abi, llval, dest);
2171+
if retags_enabled && needs_retag {
2172+
self.codegen_retag_place(bx, dest, false);
2173+
}
2174+
}
2175+
IndirectOperand { tmp, index, needs_retag } => {
2176+
let mut op = bx.load_operand(tmp);
2177+
if retags_enabled && needs_retag {
2178+
op = self.codegen_retag_operand(bx, op, false);
2179+
}
21572180
tmp.storage_dead(bx);
21582181
self.overwrite_local(index, LocalRef::Operand(op));
21592182
self.debug_introduce_local(bx, index);
21602183
}
2161-
DirectOperand(index) => {
2184+
DirectOperand { index, needs_retag } => {
21622185
// If there is a cast, we have to store and reload.
2163-
let op = if let PassMode::Cast { .. } = ret_abi.mode {
2186+
let mut op = if let PassMode::Cast { .. } = ret_abi.mode {
21642187
let tmp = PlaceRef::alloca(bx, ret_abi.layout);
21652188
tmp.storage_live(bx);
21662189
bx.store_arg(ret_abi, llval, tmp);
@@ -2170,6 +2193,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
21702193
} else {
21712194
OperandRef::from_immediate_or_packed_pair(bx, llval, ret_abi.layout)
21722195
};
2196+
if retags_enabled && needs_retag {
2197+
op = self.codegen_retag_operand(bx, op, false);
2198+
}
21732199
self.overwrite_local(index, LocalRef::Operand(op));
21742200
self.debug_introduce_local(bx, index);
21752201
}
@@ -2181,11 +2207,28 @@ enum ReturnDest<'tcx, V> {
21812207
/// Do nothing; the return value is indirect or ignored.
21822208
Nothing,
21832209
/// Store the return value to the pointer.
2184-
Store(PlaceRef<'tcx, V>),
2210+
Store {
2211+
/// The destination place
2212+
dest: PlaceRef<'tcx, V>,
2213+
/// If this place needs to be retagged
2214+
needs_retag: bool,
2215+
},
21852216
/// Store an indirect return value to an operand local place.
2186-
IndirectOperand(PlaceRef<'tcx, V>, mir::Local),
2217+
IndirectOperand {
2218+
/// The temp place where the value is loaded from
2219+
tmp: PlaceRef<'tcx, V>,
2220+
/// The local that it is assigned to
2221+
index: mir::Local,
2222+
/// If this local needs to be retagged after the assignment
2223+
needs_retag: bool,
2224+
},
21872225
/// Store a direct return value to an operand local place.
2188-
DirectOperand(mir::Local),
2226+
DirectOperand {
2227+
/// The destination local
2228+
index: mir::Local,
2229+
/// If this local needs to be retagged after the assignment.
2230+
needs_retag: bool,
2231+
},
21892232
}
21902233

21912234
fn load_cast<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(

compiler/rustc_codegen_ssa/src/mir/mod.rs

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ mod locals;
2323
pub mod naked_asm;
2424
pub mod operand;
2525
pub mod place;
26+
mod retag;
2627
mod rvalue;
2728
mod statement;
2829

@@ -401,7 +402,7 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
401402
return vec![];
402403
}
403404

404-
let args = mir
405+
let mut args = mir
405406
.args_iter()
406407
.enumerate()
407408
.map(|(arg_index, local)| {
@@ -535,6 +536,40 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
535536
}
536537
})
537538
.collect::<Vec<_>>();
539+
if bx.tcx().sess.opts.unstable_opts.codegen_emit_retag.is_some() {
540+
if let ty::InstanceKind::DropGlue(_, _) | ty::InstanceKind::AsyncDropGlue(_, _) =
541+
fx.instance.def
542+
{
543+
// We need to special-case drop glue for now. The first argument is
544+
// a raw pointer, but it needs to be treated as if it were `&mut _`.
545+
args[0] = dropee_emit_retag(bx, fx, &args[0]);
546+
} else {
547+
args = args
548+
.iter()
549+
.map(|arg| match arg {
550+
&LocalRef::Place(place_ref) => {
551+
fx.codegen_retag_place(bx, place_ref, true);
552+
LocalRef::Place(place_ref)
553+
}
554+
&LocalRef::UnsizedPlace(place_ref) => {
555+
let operand = bx.load_operand(place_ref);
556+
let retagged = fx.codegen_retag_operand(bx, operand, true);
557+
assert!(matches!(retagged.val, OperandValue::Pair(_, _)));
558+
retagged.val.store(bx, place_ref);
559+
LocalRef::UnsizedPlace(place_ref)
560+
}
561+
&LocalRef::Operand(operand_ref) => {
562+
let retagged = fx.codegen_retag_operand(bx, operand_ref, true);
563+
LocalRef::Operand(retagged)
564+
}
565+
LocalRef::PendingOperand => LocalRef::PendingOperand,
566+
})
567+
.collect::<Vec<_>>();
568+
}
569+
// If we branched during retagging, then we need to update the
570+
// start block to the new location.
571+
fx.cached_llbbs[mir::START_BLOCK] = CachedLlbb::Some(bx.llbb());
572+
}
538573

539574
if fx.instance.def.requires_caller_location(bx.tcx()) {
540575
let mir_args = if let Some(num_untupled) = num_untupled {
@@ -612,3 +647,31 @@ fn find_cold_blocks<'tcx>(
612647

613648
cold_blocks
614649
}
650+
651+
fn dropee_emit_retag<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
652+
bx: &mut Bx,
653+
fx: &mut FunctionCx<'a, 'tcx, Bx>,
654+
local: &LocalRef<'tcx, Bx::Value>,
655+
) -> LocalRef<'tcx, Bx::Value> {
656+
// We have `*mut _` as our first argument
657+
if let &LocalRef::Operand(OperandRef { val, layout, move_annotation }) = local {
658+
if layout.ty.is_raw_ptr()
659+
&& let Some(deref_ty) = layout.ty.builtin_deref(true)
660+
{
661+
// Create `&mut _`
662+
let lifetime = bx.tcx().lifetimes.re_erased;
663+
let subst_ty_kind = ty::Ref(lifetime, deref_ty, ty::Mutability::Mut);
664+
let subst_ty = bx.tcx().mk_ty_from_kind(subst_ty_kind);
665+
let subst_layout = bx.layout_of(subst_ty);
666+
667+
// We want the same operand value, but use the reference type for it.
668+
let operand_ref = OperandRef { val, layout: subst_layout, move_annotation };
669+
670+
let retagged = fx.codegen_retag_operand(bx, operand_ref, true);
671+
672+
// Return the retagged parameter, but use the original layout now.
673+
return LocalRef::Operand(OperandRef { val: retagged.val, layout, move_annotation });
674+
}
675+
}
676+
bug!("dropee isn't a raw pointer")
677+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
//! Experimental support for emitting retags as function calls in generated code.
2+
3+
use rustc_middle::mir::{Place, Rvalue, WithRetag};
4+
5+
use crate::mir::FunctionCx;
6+
use crate::mir::operand::OperandRef;
7+
use crate::mir::place::PlaceRef;
8+
use crate::traits::BuilderMethods;
9+
10+
pub(crate) fn place_needs_retag(place: &Place<'_>) -> bool {
11+
// We're not interested in tracking stores to "outside" locations
12+
!place.is_indirect_first_projection()
13+
}
14+
15+
pub(crate) fn rvalue_needs_retag(rvalue: &Rvalue<'_>) -> bool {
16+
// `Ref` has its own internal retagging
17+
!matches!(rvalue, Rvalue::Ref(..)) && !matches!(rvalue, Rvalue::Use(.., WithRetag::No))
18+
}
19+
20+
impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
21+
/// Retags the pointers within an [`OperandRef`].
22+
pub(crate) fn codegen_retag_operand(
23+
&mut self,
24+
_bx: &mut Bx,
25+
operand: OperandRef<'tcx, Bx::Value>,
26+
_is_fn_entry: bool,
27+
) -> OperandRef<'tcx, Bx::Value> {
28+
operand
29+
}
30+
31+
/// Retags the pointers within a [`PlaceRef`].
32+
pub(crate) fn codegen_retag_place(
33+
&mut self,
34+
_bx: &mut Bx,
35+
_place_ref: PlaceRef<'tcx, Bx::Value>,
36+
_is_fn_entry: bool,
37+
) {
38+
}
39+
}

compiler/rustc_codegen_ssa/src/mir/rvalue.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -515,7 +515,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
515515
let mk_ref = move |tcx: TyCtxt<'tcx>, ty: Ty<'tcx>| {
516516
Ty::new_ref(tcx, tcx.lifetimes.re_erased, ty, bk.to_mutbl_lossy())
517517
};
518-
self.codegen_place_to_pointer(bx, place, mk_ref)
518+
let op = self.codegen_place_to_pointer(bx, place, mk_ref);
519+
if self.cx.tcx().sess.opts.unstable_opts.codegen_emit_retag.is_some() {
520+
self.codegen_retag_operand(bx, op, false)
521+
} else {
522+
op
523+
}
519524
}
520525

521526
mir::Rvalue::RawPtr(kind, place) => {

compiler/rustc_codegen_ssa/src/mir/statement.rs

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use rustc_middle::{bug, span_bug, ty};
33
use tracing::instrument;
44

55
use super::{FunctionCx, LocalRef};
6+
use crate::mir::retag;
67
use crate::traits::*;
78

89
impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
@@ -12,9 +13,18 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
1213
self.set_debug_loc(bx, statement.source_info);
1314
match statement.kind {
1415
mir::StatementKind::Assign(box (ref place, ref rvalue)) => {
16+
let needs_retag = bx.tcx().sess.opts.unstable_opts.codegen_emit_retag.is_some()
17+
&& retag::rvalue_needs_retag(rvalue)
18+
&& retag::place_needs_retag(place);
19+
1520
if let Some(index) = place.as_local() {
1621
match self.locals[index] {
17-
LocalRef::Place(cg_dest) => self.codegen_rvalue(bx, cg_dest, rvalue),
22+
LocalRef::Place(cg_dest) => {
23+
self.codegen_rvalue(bx, cg_dest, rvalue);
24+
if needs_retag {
25+
self.codegen_retag_place(bx, cg_dest, false);
26+
}
27+
}
1828
LocalRef::UnsizedPlace(cg_indirect_dest) => {
1929
let ty = cg_indirect_dest.layout.ty;
2030
span_bug!(
@@ -24,7 +34,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
2434
);
2535
}
2636
LocalRef::PendingOperand => {
27-
let operand = self.codegen_rvalue_operand(bx, rvalue);
37+
let mut operand = self.codegen_rvalue_operand(bx, rvalue);
38+
if needs_retag {
39+
operand = self.codegen_retag_operand(bx, operand, false);
40+
}
2841
self.overwrite_local(index, LocalRef::Operand(operand));
2942
self.debug_introduce_local(bx, index);
3043
}
@@ -39,12 +52,19 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
3952

4053
// If the type is zero-sized, it's already been set here,
4154
// but we still need to make sure we codegen the operand
42-
self.codegen_rvalue_operand(bx, rvalue);
55+
// and emit a retag.
56+
let operand = self.codegen_rvalue_operand(bx, rvalue);
57+
if needs_retag {
58+
self.codegen_retag_operand(bx, operand, false);
59+
}
4360
}
4461
}
4562
} else {
4663
let cg_dest = self.codegen_place(bx, place.as_ref());
4764
self.codegen_rvalue(bx, cg_dest, rvalue);
65+
if needs_retag {
66+
self.codegen_retag_place(bx, cg_dest, false);
67+
}
4868
}
4969
}
5070
mir::StatementKind::SetDiscriminant { box ref place, variant_index } => {

compiler/rustc_interface/src/tests.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -775,6 +775,7 @@ fn test_unstable_options_tracking_hash() {
775775
})
776776
);
777777
tracked!(codegen_backend, Some("abc".to_string()));
778+
tracked!(codegen_emit_retag, Some(CodegenRetagOptions::default()));
778779
tracked!(
779780
coverage_options,
780781
CoverageOptions {

0 commit comments

Comments
 (0)