Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion compiler/rustc_borrowck/src/handle_placeholders.rs
Original file line number Diff line number Diff line change
Expand Up @@ -348,7 +348,7 @@ pub(crate) fn compute_sccs_applying_placeholder_outlives_constraints<'tcx>(
}
}

fn rewrite_placeholder_outlives<'tcx>(
pub(crate) fn rewrite_placeholder_outlives<'tcx>(
sccs: &Sccs<RegionVid, ConstraintSccIndex>,
annotations: &SccAnnotations<'_, '_, RegionTracker>,
fr_static: RegionVid,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ pub(super) fn apply_member_constraints<'tcx>(
debug!(?member_constraints);
for scc_a in rcx.constraint_sccs.all_sccs() {
debug!(?scc_a);
// Start by adding the region values required by outlives constraints. This
// Start by adding the region values required by outlives constraints. This
// matches how we compute the final region values in `fn compute_regions`.
//
// We need to do this here to get a lower bound when applying member constraints.
Expand All @@ -64,6 +64,7 @@ fn apply_member_constraint<'tcx>(
// If the member region lives in a higher universe, we currently choose
// the most conservative option by leaving it unchanged.
if !rcx.max_placeholder_universe_reached(member).is_root() {
debug!("member region reached non root universe, bailing");
return;
}

Expand Down
7 changes: 7 additions & 0 deletions compiler/rustc_borrowck/src/region_infer/opaque_types/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,10 @@ fn collect_defining_uses<'tcx>(
}
} else {
errors.push(DeferredOpaqueTypeError::InvalidOpaqueTypeArgs(err));
debug!(
"collect_defining_uses: InvalidOpaqueTypeArgs for {:?} := {:?}",
non_nll_opaque_type_key, hidden_type
);
}
continue;
}
Expand All @@ -277,6 +281,7 @@ fn collect_defining_uses<'tcx>(
defining_uses
}

#[instrument(level = "debug", skip(rcx, concrete_opaque_types, defining_uses, errors))]
fn compute_concrete_types_from_defining_uses<'tcx>(
rcx: &RegionCtxt<'_, 'tcx>,
concrete_opaque_types: &mut ConcreteOpaqueTypes<'tcx>,
Expand All @@ -288,13 +293,15 @@ fn compute_concrete_types_from_defining_uses<'tcx>(
let mut decls_modulo_regions: FxIndexMap<OpaqueTypeKey<'tcx>, (OpaqueTypeKey<'tcx>, Span)> =
FxIndexMap::default();
for &DefiningUse { opaque_type_key, ref arg_regions, hidden_type } in defining_uses {
debug!(?opaque_type_key, ?arg_regions, ?hidden_type);
// After applying member constraints, we now map all regions in the hidden type
// to the `arg_regions` of this defining use. In case a region in the hidden type
// ended up not being equal to any such region, we error.
let hidden_type =
match hidden_type.try_fold_with(&mut ToArgRegionsFolder::new(rcx, arg_regions)) {
Ok(hidden_type) => hidden_type,
Err(r) => {
debug!("UnexpectedHiddenRegion: {:?}", r);
errors.push(DeferredOpaqueTypeError::UnexpectedHiddenRegion {
hidden_type,
opaque_type_key,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ use crate::constraints::ConstraintSccIndex;
use crate::handle_placeholders::{SccAnnotations, region_definitions};
use crate::region_infer::reverse_sccs::ReverseSccGraph;
use crate::region_infer::values::RegionValues;
use crate::region_infer::{ConstraintSccs, RegionDefinition, RegionTracker, Representative};
use crate::region_infer::{
ConstraintSccs, OutlivesConstraintSet, RegionDefinition, RegionTracker, Representative,
};
use crate::type_check::MirTypeckRegionConstraints;
use crate::type_check::free_region_relations::UniversalRegionRelations;
use crate::universal_regions::UniversalRegions;
Expand Down Expand Up @@ -39,16 +41,36 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx> {
location_map: Rc<DenseLocationMap>,
constraints: &MirTypeckRegionConstraints<'tcx>,
) -> RegionCtxt<'a, 'tcx> {
let mut outlives_constraints = constraints.outlives_constraints.clone();
let universal_regions = &universal_region_relations.universal_regions;
let (definitions, _has_placeholders) = region_definitions(infcx, universal_regions);

let compute_sccs =
|outlives_constraints: &OutlivesConstraintSet<'tcx>,
annotations: &mut SccAnnotations<'_, 'tcx, RegionTracker>| {
ConstraintSccs::new_with_annotation(
&outlives_constraints
.graph(definitions.len())
.region_graph(outlives_constraints, universal_regions.fr_static),
annotations,
)
};

let mut scc_annotations = SccAnnotations::init(&definitions);
let constraint_sccs = ConstraintSccs::new_with_annotation(
&constraints
.outlives_constraints
.graph(definitions.len())
.region_graph(&constraints.outlives_constraints, universal_regions.fr_static),
&mut scc_annotations,
let mut constraint_sccs = compute_sccs(&outlives_constraints, &mut scc_annotations);

let added_constraints = crate::handle_placeholders::rewrite_placeholder_outlives(
&constraint_sccs,
&scc_annotations,
universal_regions.fr_static,
&mut outlives_constraints,
);

if added_constraints {
scc_annotations = SccAnnotations::init(&definitions);
constraint_sccs = compute_sccs(&outlives_constraints, &mut scc_annotations);
}

let scc_annotations = scc_annotations.scc_to_annotation;

// Unlike the `RegionInferenceContext`, we only care about free regions
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_codegen_ssa/src/mir/rvalue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1048,14 +1048,14 @@ pub(super) fn transmute_scalar<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
imm = match (from_scalar.primitive(), to_scalar.primitive()) {
(Int(..) | Float(_), Int(..) | Float(_)) => bx.bitcast(imm, to_backend_ty),
(Pointer(..), Pointer(..)) => bx.pointercast(imm, to_backend_ty),
(Int(..), Pointer(..)) => bx.ptradd(bx.const_null(bx.type_ptr()), imm),
(Int(..), Pointer(..)) => bx.inttoptr(imm, to_backend_ty),
(Pointer(..), Int(..)) => {
// FIXME: this exposes the provenance, which shouldn't be necessary.
bx.ptrtoint(imm, to_backend_ty)
}
(Float(_), Pointer(..)) => {
let int_imm = bx.bitcast(imm, bx.cx().type_isize());
bx.ptradd(bx.const_null(bx.type_ptr()), int_imm)
bx.inttoptr(int_imm, to_backend_ty)
}
(Pointer(..), Float(_)) => {
// FIXME: this exposes the provenance, which shouldn't be necessary.
Expand Down
29 changes: 29 additions & 0 deletions compiler/rustc_middle/src/mir/loops.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
use rustc_index::bit_set::DenseBitSet;

use super::*;

/// Compute the set of loop headers in the given body. A loop header is usually defined as a block
/// which dominates one of its predecessors. This definition is only correct for reducible CFGs.
/// However, computing dominators is expensive, so we approximate according to the post-order
/// traversal order. A loop header for us is a block which is visited after its predecessor in
/// post-order. This is ok as we mostly need a heuristic.
pub fn maybe_loop_headers(body: &Body<'_>) -> DenseBitSet<BasicBlock> {
let mut maybe_loop_headers = DenseBitSet::new_empty(body.basic_blocks.len());
let mut visited = DenseBitSet::new_empty(body.basic_blocks.len());
for (bb, bbdata) in traversal::postorder(body) {
// Post-order means we visit successors before the block for acyclic CFGs.
// If the successor is not visited yet, consider it a loop header.
for succ in bbdata.terminator().successors() {
if !visited.contains(succ) {
maybe_loop_headers.insert(succ);
}
}

// Only mark `bb` as visited after we checked the successors, in case we have a self-loop.
// bb1: goto -> bb1;
let _new = visited.insert(bb);
debug_assert!(_new);
}

maybe_loop_headers
}
1 change: 1 addition & 0 deletions compiler/rustc_middle/src/mir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ mod statement;
mod syntax;
mod terminator;

pub mod loops;
pub mod traversal;
pub mod visit;

Expand Down
6 changes: 6 additions & 0 deletions compiler/rustc_mir_transform/src/gvn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ impl<'tcx> crate::MirPass<'tcx> for GVN {
let ssa = SsaLocals::new(tcx, body, typing_env);
// Clone dominators because we need them while mutating the body.
let dominators = body.basic_blocks.dominators().clone();
let maybe_loop_headers = loops::maybe_loop_headers(body);

let mut state = VnState::new(tcx, body, typing_env, &ssa, dominators, &body.local_decls);

Expand All @@ -136,6 +137,11 @@ impl<'tcx> crate::MirPass<'tcx> for GVN {

let reverse_postorder = body.basic_blocks.reverse_postorder().to_vec();
for bb in reverse_postorder {
// N.B. With loops, reverse postorder cannot produce a valid topological order.
// A statement or terminator from inside the loop, that is not processed yet, may have performed an indirect write.
if maybe_loop_headers.contains(bb) {
state.invalidate_derefs();
}
let data = &mut body.basic_blocks.as_mut_preserves_cfg()[bb];
state.visit_basic_block_data(bb, data);
}
Expand Down
20 changes: 1 addition & 19 deletions compiler/rustc_mir_transform/src/jump_threading.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ impl<'tcx> crate::MirPass<'tcx> for JumpThreading {
body,
arena,
map: Map::new(tcx, body, Some(MAX_PLACES)),
loop_headers: loop_headers(body),
loop_headers: loops::maybe_loop_headers(body),
opportunities: Vec::new(),
};

Expand Down Expand Up @@ -832,21 +832,3 @@ enum Update {
Incr,
Decr,
}

/// Compute the set of loop headers in the given body. We define a loop header as a block which has
/// at least a predecessor which it dominates. This definition is only correct for reducible CFGs.
/// But if the CFG is already irreducible, there is no point in trying much harder.
/// is already irreducible.
fn loop_headers(body: &Body<'_>) -> DenseBitSet<BasicBlock> {
let mut loop_headers = DenseBitSet::new_empty(body.basic_blocks.len());
let dominators = body.basic_blocks.dominators();
// Only visit reachable blocks.
for (bb, bbdata) in traversal::preorder(body) {
for succ in bbdata.terminator().successors() {
if dominators.dominates(succ, bb) {
loop_headers.insert(succ);
}
}
}
loop_headers
}
2 changes: 1 addition & 1 deletion tests/codegen-llvm/common_prim_int_ptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
#[no_mangle]
pub fn insert_int(x: usize) -> Result<usize, Box<()>> {
// CHECK: start:
// CHECK-NEXT: %[[WO_PROV:.+]] = getelementptr i8, ptr null, [[USIZE:i[0-9]+]] %x
// CHECK-NEXT: %[[WO_PROV:.+]] = inttoptr [[USIZE:i[0-9]+]] %x to ptr
// CHECK-NEXT: %[[R:.+]] = insertvalue { [[USIZE]], ptr } { [[USIZE]] 0, ptr poison }, ptr %[[WO_PROV]], 1
// CHECK-NEXT: ret { [[USIZE]], ptr } %[[R]]
Ok(x)
Expand Down
2 changes: 1 addition & 1 deletion tests/codegen-llvm/enum/enum-aggregate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ fn make_ok_ptr(x: NonNull<u16>) -> Result<NonNull<u16>, usize> {
fn make_ok_int(x: usize) -> Result<usize, NonNull<u16>> {
// CHECK-LABEL: { i64, ptr } @make_ok_int(i64 %x)
// CHECK-NEXT: start:
// CHECK-NEXT: %[[NOPROV:.+]] = getelementptr i8, ptr null, i64 %x
// CHECK-NEXT: %[[NOPROV:.+]] = inttoptr i64 %x to ptr
// CHECK-NEXT: %[[R:.+]] = insertvalue { i64, ptr } { i64 0, ptr poison }, ptr %[[NOPROV]], 1
// CHECK-NEXT: ret { i64, ptr } %[[R]]
Ok(x)
Expand Down
22 changes: 22 additions & 0 deletions tests/codegen-llvm/int-ptr-int-enum-miscompile.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// This is a regression test for https://github.com/rust-lang/rust/issues/147265.

//@ compile-flags: -Copt-level=3

#![crate_type = "lib"]

#[no_mangle]
pub fn mk_result(a: usize) -> Result<u8, *const u8> {
// CHECK-LABEL: @mk_result
// CHECK-NOT: unreachable
// CHECK: load i8,
// CHECK-NOT: unreachable
match g(a) {
Ok(b) => Ok(unsafe { *(b as *const u8) }),
Err(c) => Err(c),
}
}

#[cold]
fn g(a: usize) -> Result<usize, *const u8> {
Ok(a)
}
2 changes: 1 addition & 1 deletion tests/codegen-llvm/intrinsics/transmute-niched.rs
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,7 @@ pub unsafe fn check_four_or_eight_to_nonnull(x: FourOrEight) -> NonNull<u8> {
// OPT: call void @llvm.assume(i1 %1)
// CHECK-NOT: icmp
// CHECK-NOT: assume
// CHECK: %[[RET:.+]] = getelementptr i8, ptr null, i64 %x
// CHECK: %[[RET:.+]] = inttoptr i64 %x to ptr
// CHECK-NEXT: ret ptr %[[RET]]

transmute(x)
Expand Down
4 changes: 2 additions & 2 deletions tests/codegen-llvm/intrinsics/transmute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,7 @@ pub unsafe fn check_pair_with_bool(x: (u8, bool)) -> (bool, i8) {
pub unsafe fn check_float_to_pointer(x: f64) -> *const () {
// CHECK-NOT: alloca
// CHECK: %0 = bitcast double %x to i64
// CHECK: %_0 = getelementptr i8, ptr null, i64 %0
// CHECK: %_0 = inttoptr i64 %0 to ptr
// CHECK: ret ptr %_0
transmute(x)
}
Expand Down Expand Up @@ -378,7 +378,7 @@ pub unsafe fn check_issue_110005(x: (usize, bool)) -> Option<Box<[u8]>> {
// CHECK-LABEL: @check_pair_to_dst_ref(
#[no_mangle]
pub unsafe fn check_pair_to_dst_ref<'a>(x: (usize, usize)) -> &'a [u8] {
// CHECK: %_0.0 = getelementptr i8, ptr null, i64 %x.0
// CHECK: %_0.0 = inttoptr i64 %x.0 to ptr
// CHECK: %0 = icmp ne ptr %_0.0, null
// CHECK: call void @llvm.assume(i1 %0)
// CHECK: %1 = insertvalue { ptr, i64 } poison, ptr %_0.0, 0
Expand Down
2 changes: 1 addition & 1 deletion tests/codegen-llvm/transmute-scalar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ pub fn ptr_to_int(p: *mut u16) -> usize {
}

// CHECK: define{{.*}}ptr @int_to_ptr([[USIZE]] %i)
// CHECK: %_0 = getelementptr i8, ptr null, [[USIZE]] %i
// CHECK: %_0 = inttoptr [[USIZE]] %i to ptr
// CHECK-NEXT: ret ptr %_0
#[no_mangle]
pub fn int_to_ptr(i: usize) -> *mut u16 {
Expand Down
Loading
Loading