-
Notifications
You must be signed in to change notification settings - Fork 13.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Stop generating an intermediate deref when taking references to statics #76982
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2008,7 +2008,9 @@ pub enum Rvalue<'tcx> { | |
/// Accessing a thread local static. This is inherently a runtime operation, even if llvm | ||
/// treats it as an access to a static. This `Rvalue` yields a reference to the thread local | ||
/// static. | ||
ThreadLocalRef(DefId), | ||
/// The `Ty` field is the type at which the access is happening, so e.g. a | ||
/// `&raw SOME_TLS` will yield a raw pointer, while `&SOME_TLS` will yield a reference. | ||
ThreadLocalRef(DefId, Ty<'tcx>), | ||
|
||
/// Create a raw pointer to the given place | ||
/// Can be generated by raw address of expressions (`&raw const x`), | ||
|
@@ -2149,9 +2151,14 @@ impl<'tcx> Debug for Rvalue<'tcx> { | |
UnaryOp(ref op, ref a) => write!(fmt, "{:?}({:?})", op, a), | ||
Discriminant(ref place) => write!(fmt, "discriminant({:?})", place), | ||
NullaryOp(ref op, ref t) => write!(fmt, "{:?}({:?})", op, t), | ||
ThreadLocalRef(did) => ty::tls::with(|tcx| { | ||
let muta = tcx.static_mutability(did).unwrap().prefix_str(); | ||
write!(fmt, "&/*tls*/ {}{}", muta, tcx.def_path_str(did)) | ||
ThreadLocalRef(did, ty) => ty::tls::with(|tcx| { | ||
let muta = ty.builtin_deref(true).unwrap().mutbl.prefix_str(); | ||
let raw = match ty.kind() { | ||
ty::Ref(..) => "", | ||
ty::RawPtr(..) => "raw ", | ||
_ => bug!("Rvalue::ThreadLocalRef types can only be pointer or reference"), | ||
}; | ||
write!(fmt, "&{}/*tls*/ {}{}", raw, muta, tcx.def_path_str(did)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why is TLS between "raw" and "mut"? |
||
}), | ||
Ref(region, borrow_kind, ref place) => { | ||
let kind_str = match borrow_kind { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -229,12 +229,8 @@ fn make_mirror_unadjusted<'a, 'tcx>( | |
} | ||
} | ||
|
||
hir::ExprKind::AddrOf(hir::BorrowKind::Ref, mutbl, ref arg) => { | ||
ExprKind::Borrow { borrow_kind: mutbl.to_borrow_kind(), arg: arg.to_ref() } | ||
} | ||
|
||
hir::ExprKind::AddrOf(hir::BorrowKind::Raw, mutability, ref arg) => { | ||
ExprKind::AddressOf { mutability, arg: arg.to_ref() } | ||
hir::ExprKind::AddrOf(kind, mutability, arg) => { | ||
convert_addr_of_expr(cx, kind, mutability, arg) | ||
} | ||
|
||
hir::ExprKind::Block(ref blk, _) => ExprKind::Block { body: &blk }, | ||
|
@@ -863,15 +859,7 @@ fn convert_path_expr<'a, 'tcx>( | |
Res::Def(DefKind::Static, id) => { | ||
let ty = cx.tcx.static_ptr_ty(id); | ||
let temp_lifetime = cx.region_scope_tree.temporary_scope(expr.hir_id.local_id); | ||
let kind = if cx.tcx.is_thread_local_static(id) { | ||
ExprKind::ThreadLocalRef(id) | ||
} else { | ||
let ptr = cx.tcx.create_static_alloc(id); | ||
ExprKind::StaticRef { | ||
literal: ty::Const::from_scalar(cx.tcx, Scalar::Ptr(ptr.into()), ty), | ||
def_id: id, | ||
} | ||
}; | ||
let kind = convert_static_ref(cx, id, ty); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "kind" is a really confusing variable name here, this is an expression after all. |
||
ExprKind::Deref { arg: Expr { ty, temp_lifetime, span: expr.span, kind }.to_ref() } | ||
} | ||
|
||
|
@@ -881,6 +869,47 @@ fn convert_path_expr<'a, 'tcx>( | |
} | ||
} | ||
|
||
fn convert_static_ref<'tcx>(cx: &mut Cx<'_, 'tcx>, id: DefId, ty: Ty<'tcx>) -> ExprKind<'tcx> { | ||
if cx.tcx.is_thread_local_static(id) { | ||
ExprKind::ThreadLocalRef(id, ty) | ||
} else { | ||
let ptr = cx.tcx.create_static_alloc(id); | ||
ExprKind::StaticRef { | ||
literal: ty::Const::from_scalar(cx.tcx, Scalar::Ptr(ptr.into()), ty), | ||
def_id: id, | ||
} | ||
} | ||
} | ||
|
||
fn convert_addr_of_expr<'tcx>( | ||
cx: &mut Cx<'_, 'tcx>, | ||
kind: hir::BorrowKind, | ||
mutability: hir::Mutability, | ||
arg: &'tcx hir::Expr<'tcx>, | ||
) -> ExprKind<'tcx> { | ||
// Fast path so that taking a reference to a static doesn't end up | ||
// as `&*&STATIC` but just `&STATIC` | ||
if let hir::ExprKind::Path(qpath) = &arg.kind { | ||
let res = cx.typeck_results().qpath_res(qpath, arg.hir_id); | ||
if let Res::Def(DefKind::Static, id) = res { | ||
let mut tm = cx.tcx.static_ptr_ty(id).builtin_deref(true).unwrap(); | ||
tm.mutbl = mutability; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This looks like shoehorning the existing There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yes, it's still used further up. I didn't want to repeat its code, but I could split out the part that obtains the static's type into a separate function There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In particular, that function contains some subtle logic if I recall correctly (for using raw ptrs vs references), and now we overlay our own logic on top of this here... given how critical this code is, I'd prefer that to be cleaner, even if that makes the code longer. Also it would be good to have some comments explaining why all of this here crucially has to be exactly the way it is. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Ah, I just saw that. But that further up should now not be reachable any more for refs-to-static, right, just for when it is used as a value? If so, please add a comment explaining that. Also, doesn't that mean we can always use a shared reference, as we always just read? Well and I guess a raw pointer for unsafe-to-read things to make sure we do not sidestep the unsafety checker. I feel like all the subtle logic that determines the type of the reference we use for reads and for address-of should be in one place. |
||
let ty = match kind { | ||
hir::BorrowKind::Ref => cx.tcx.mk_ref(cx.tcx.lifetimes.re_erased, tm), | ||
hir::BorrowKind::Raw => cx.tcx.mk_ptr(tm), | ||
}; | ||
return convert_static_ref(cx, id, ty); | ||
} | ||
} | ||
match kind { | ||
hir::BorrowKind::Ref => { | ||
ExprKind::Borrow { borrow_kind: mutability.to_borrow_kind(), arg: arg.to_ref() } | ||
} | ||
|
||
hir::BorrowKind::Raw => ExprKind::AddressOf { mutability, arg: arg.to_ref() }, | ||
} | ||
} | ||
|
||
fn convert_var<'tcx>( | ||
cx: &mut Cx<'_, 'tcx>, | ||
expr: &'tcx hir::Expr<'tcx>, | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you are matching anyway, the same match could also extract the mutability... do you think taht would make the code cleaner?