Skip to content

Commit 99e7c15

Browse files
committed
Auto merge of #141869 - GuillaumeGomez:rollup-vicg807, r=GuillaumeGomez
Rollup of 9 pull requests Successful merges: - #140370 (Improve diagnostics for usage of qualified paths within tuple struct exprs/pats) - #141224 (terminology: allocated object → allocation) - #141622 (implement `va_arg` for `powerpc`) - #141666 (source_span_for_markdown_range: fix utf8 violation) - #141789 (Exclude `CARGO_HOME` from `generate-copyright` in-tree determination) - #141823 (Drive-by refactor: use `OnceCell` for the reverse region SCC graph) - #141834 (Add unimplemented `current_dll_path()` for WASI) - #141846 (Fix TLS model on bootstrap for cygwin) - #141852 (resolve if-let-chain FIXME on bootstrap) r? `@ghost` `@rustbot` modify labels: rollup
2 parents a88fc0e + 90f418f commit 99e7c15

File tree

36 files changed

+771
-273
lines changed

36 files changed

+771
-273
lines changed

compiler/rustc_borrowck/src/region_infer/mod.rs

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use std::cell::OnceCell;
12
use std::collections::VecDeque;
23
use std::rc::Rc;
34

@@ -197,8 +198,8 @@ pub struct RegionInferenceContext<'tcx> {
197198

198199
/// Reverse of the SCC constraint graph -- i.e., an edge `A -> B` exists if
199200
/// `B: A`. This is used to compute the universal regions that are required
200-
/// to outlive a given SCC. Computed lazily.
201-
rev_scc_graph: Option<ReverseSccGraph>,
201+
/// to outlive a given SCC.
202+
rev_scc_graph: OnceCell<ReverseSccGraph>,
202203

203204
/// The "R0 member of [R1..Rn]" constraints, indexed by SCC.
204205
member_constraints: Rc<MemberConstraintSet<'tcx, ConstraintSccIndex>>,
@@ -502,7 +503,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
502503
constraint_graph,
503504
constraint_sccs,
504505
scc_annotations,
505-
rev_scc_graph: None,
506+
rev_scc_graph: OnceCell::new(),
506507
member_constraints,
507508
member_constraints_applied: Vec::new(),
508509
universe_causes,
@@ -809,9 +810,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
809810
member_constraint_index: NllMemberConstraintIndex,
810811
choice_regions: &[ty::RegionVid],
811812
) {
812-
// Lazily compute the reverse graph, we'll need it later.
813-
self.compute_reverse_scc_graph();
814-
815813
// Create a mutable vector of the options. We'll try to winnow
816814
// them down.
817815
let mut choice_regions: Vec<ty::RegionVid> = choice_regions.to_vec();
@@ -849,7 +847,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
849847
// R0`). Therefore, we need only keep an option `O` if `UB: O`
850848
// for all UB.
851849
let universal_region_relations = &self.universal_region_relations;
852-
for ub in self.rev_scc_graph.as_ref().unwrap().upper_bounds(scc) {
850+
for ub in self.reverse_scc_graph().upper_bounds(scc) {
853851
debug!(?ub);
854852
choice_regions.retain(|&o_r| universal_region_relations.outlives(ub, o_r));
855853
}

compiler/rustc_borrowck/src/region_infer/opaque_types.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -215,9 +215,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
215215
// FIXME: We could probably compute the LUB if there is one.
216216
let scc = self.constraint_sccs.scc(vid);
217217
let upper_bounds: Vec<_> = self
218-
.rev_scc_graph
219-
.as_ref()
220-
.unwrap()
218+
.reverse_scc_graph()
221219
.upper_bounds(scc)
222220
.filter_map(|vid| self.definitions[vid].external_name)
223221
.filter(|r| !r.is_static())

compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -59,13 +59,10 @@ impl ReverseSccGraph {
5959
}
6060

6161
impl RegionInferenceContext<'_> {
62-
/// Compute the reverse SCC-based constraint graph (lazily).
63-
pub(super) fn compute_reverse_scc_graph(&mut self) {
64-
if self.rev_scc_graph.is_some() {
65-
return;
66-
}
67-
68-
self.rev_scc_graph =
69-
Some(ReverseSccGraph::compute(&self.constraint_sccs, self.universal_regions()));
62+
/// Return the reverse graph of the region SCCs, initialising it if needed.
63+
pub(super) fn reverse_scc_graph(&self) -> &ReverseSccGraph {
64+
self.rev_scc_graph.get_or_init(|| {
65+
ReverseSccGraph::compute(&self.constraint_sccs, self.universal_regions())
66+
})
7067
}
7168
}

compiler/rustc_codegen_llvm/src/va_arg.rs

Lines changed: 182 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ fn emit_direct_ptr_va_arg<'ll, 'tcx>(
4040
align: Align,
4141
slot_size: Align,
4242
allow_higher_align: bool,
43+
force_right_adjust: bool,
4344
) -> (&'ll Value, Align) {
4445
let va_list_ty = bx.type_ptr();
4546
let va_list_addr = list.immediate();
@@ -57,7 +58,10 @@ fn emit_direct_ptr_va_arg<'ll, 'tcx>(
5758
let next = bx.inbounds_ptradd(addr, full_direct_size);
5859
bx.store(next, va_list_addr, bx.tcx().data_layout.pointer_align.abi);
5960

60-
if size.bytes() < slot_size.bytes() && bx.tcx().sess.target.endian == Endian::Big {
61+
if size.bytes() < slot_size.bytes()
62+
&& bx.tcx().sess.target.endian == Endian::Big
63+
&& force_right_adjust
64+
{
6165
let adjusted_size = bx.cx().const_i32((slot_size.bytes() - size.bytes()) as i32);
6266
let adjusted = bx.inbounds_ptradd(addr, adjusted_size);
6367
(adjusted, addr_align)
@@ -81,16 +85,23 @@ enum AllowHigherAlign {
8185
Yes,
8286
}
8387

88+
enum ForceRightAdjust {
89+
No,
90+
Yes,
91+
}
92+
8493
fn emit_ptr_va_arg<'ll, 'tcx>(
8594
bx: &mut Builder<'_, 'll, 'tcx>,
8695
list: OperandRef<'tcx, &'ll Value>,
8796
target_ty: Ty<'tcx>,
8897
pass_mode: PassMode,
8998
slot_size: SlotSize,
9099
allow_higher_align: AllowHigherAlign,
100+
force_right_adjust: ForceRightAdjust,
91101
) -> &'ll Value {
92102
let indirect = matches!(pass_mode, PassMode::Indirect);
93103
let allow_higher_align = matches!(allow_higher_align, AllowHigherAlign::Yes);
104+
let force_right_adjust = matches!(force_right_adjust, ForceRightAdjust::Yes);
94105
let slot_size = Align::from_bytes(slot_size as u64).unwrap();
95106

96107
let layout = bx.cx.layout_of(target_ty);
@@ -103,8 +114,15 @@ fn emit_ptr_va_arg<'ll, 'tcx>(
103114
} else {
104115
(layout.llvm_type(bx.cx), layout.size, layout.align)
105116
};
106-
let (addr, addr_align) =
107-
emit_direct_ptr_va_arg(bx, list, size, align.abi, slot_size, allow_higher_align);
117+
let (addr, addr_align) = emit_direct_ptr_va_arg(
118+
bx,
119+
list,
120+
size,
121+
align.abi,
122+
slot_size,
123+
allow_higher_align,
124+
force_right_adjust,
125+
);
108126
if indirect {
109127
let tmp_ret = bx.load(llty, addr, addr_align);
110128
bx.load(bx.cx.layout_of(target_ty).llvm_type(bx.cx), tmp_ret, align.abi)
@@ -208,6 +226,7 @@ fn emit_aapcs_va_arg<'ll, 'tcx>(
208226
PassMode::Direct,
209227
SlotSize::Bytes8,
210228
AllowHigherAlign::Yes,
229+
ForceRightAdjust::No,
211230
);
212231
bx.br(end);
213232

@@ -218,6 +237,150 @@ fn emit_aapcs_va_arg<'ll, 'tcx>(
218237
val
219238
}
220239

240+
fn emit_powerpc_va_arg<'ll, 'tcx>(
241+
bx: &mut Builder<'_, 'll, 'tcx>,
242+
list: OperandRef<'tcx, &'ll Value>,
243+
target_ty: Ty<'tcx>,
244+
) -> &'ll Value {
245+
let dl = bx.cx.data_layout();
246+
247+
// struct __va_list_tag {
248+
// unsigned char gpr;
249+
// unsigned char fpr;
250+
// unsigned short reserved;
251+
// void *overflow_arg_area;
252+
// void *reg_save_area;
253+
// };
254+
let va_list_addr = list.immediate();
255+
256+
// Peel off any newtype wrappers.
257+
let layout = {
258+
let mut layout = bx.cx.layout_of(target_ty);
259+
260+
while let Some((_, inner)) = layout.non_1zst_field(bx.cx) {
261+
layout = inner;
262+
}
263+
264+
layout
265+
};
266+
267+
// Rust does not currently support any powerpc softfloat targets.
268+
let target = &bx.cx.tcx.sess.target;
269+
let is_soft_float_abi = target.abi == "softfloat";
270+
assert!(!is_soft_float_abi);
271+
272+
// All instances of VaArgSafe are passed directly.
273+
let is_indirect = false;
274+
275+
let (is_i64, is_int, is_f64) = match layout.layout.backend_repr() {
276+
BackendRepr::Scalar(scalar) => match scalar.primitive() {
277+
rustc_abi::Primitive::Int(integer, _) => (integer.size().bits() == 64, true, false),
278+
rustc_abi::Primitive::Float(float) => (false, false, float.size().bits() == 64),
279+
rustc_abi::Primitive::Pointer(_) => (false, true, false),
280+
},
281+
_ => unreachable!("all instances of VaArgSafe are represented as scalars"),
282+
};
283+
284+
let num_regs_addr = if is_int || is_soft_float_abi {
285+
va_list_addr // gpr
286+
} else {
287+
bx.inbounds_ptradd(va_list_addr, bx.const_usize(1)) // fpr
288+
};
289+
290+
let mut num_regs = bx.load(bx.type_i8(), num_regs_addr, dl.i8_align.abi);
291+
292+
// "Align" the register count when the type is passed as `i64`.
293+
if is_i64 || (is_f64 && is_soft_float_abi) {
294+
num_regs = bx.add(num_regs, bx.const_u8(1));
295+
num_regs = bx.and(num_regs, bx.const_u8(0b1111_1110));
296+
}
297+
298+
let max_regs = 8u8;
299+
let use_regs = bx.icmp(IntPredicate::IntULT, num_regs, bx.const_u8(max_regs));
300+
301+
let in_reg = bx.append_sibling_block("va_arg.in_reg");
302+
let in_mem = bx.append_sibling_block("va_arg.in_mem");
303+
let end = bx.append_sibling_block("va_arg.end");
304+
305+
bx.cond_br(use_regs, in_reg, in_mem);
306+
307+
let reg_addr = {
308+
bx.switch_to_block(in_reg);
309+
310+
let reg_safe_area_ptr = bx.inbounds_ptradd(va_list_addr, bx.cx.const_usize(1 + 1 + 2 + 4));
311+
let mut reg_addr = bx.load(bx.type_ptr(), reg_safe_area_ptr, dl.pointer_align.abi);
312+
313+
// Floating-point registers start after the general-purpose registers.
314+
if !is_int && !is_soft_float_abi {
315+
reg_addr = bx.inbounds_ptradd(reg_addr, bx.cx.const_usize(32))
316+
}
317+
318+
// Get the address of the saved value by scaling the number of
319+
// registers we've used by the number of.
320+
let reg_size = if is_int || is_soft_float_abi { 4 } else { 8 };
321+
let reg_offset = bx.mul(num_regs, bx.cx().const_u8(reg_size));
322+
let reg_addr = bx.inbounds_ptradd(reg_addr, reg_offset);
323+
324+
// Increase the used-register count.
325+
let reg_incr = if is_i64 || (is_f64 && is_soft_float_abi) { 2 } else { 1 };
326+
let new_num_regs = bx.add(num_regs, bx.cx.const_u8(reg_incr));
327+
bx.store(new_num_regs, num_regs_addr, dl.i8_align.abi);
328+
329+
bx.br(end);
330+
331+
reg_addr
332+
};
333+
334+
let mem_addr = {
335+
bx.switch_to_block(in_mem);
336+
337+
bx.store(bx.const_u8(max_regs), num_regs_addr, dl.i8_align.abi);
338+
339+
// Everything in the overflow area is rounded up to a size of at least 4.
340+
let overflow_area_align = Align::from_bytes(4).unwrap();
341+
342+
let size = if !is_indirect {
343+
layout.layout.size.align_to(overflow_area_align)
344+
} else {
345+
dl.pointer_size
346+
};
347+
348+
let overflow_area_ptr = bx.inbounds_ptradd(va_list_addr, bx.cx.const_usize(1 + 1 + 2));
349+
let mut overflow_area = bx.load(bx.type_ptr(), overflow_area_ptr, dl.pointer_align.abi);
350+
351+
// Round up address of argument to alignment
352+
if layout.layout.align.abi > overflow_area_align {
353+
overflow_area = round_pointer_up_to_alignment(
354+
bx,
355+
overflow_area,
356+
layout.layout.align.abi,
357+
bx.type_ptr(),
358+
);
359+
}
360+
361+
let mem_addr = overflow_area;
362+
363+
// Increase the overflow area.
364+
overflow_area = bx.inbounds_ptradd(overflow_area, bx.const_usize(size.bytes()));
365+
bx.store(overflow_area, overflow_area_ptr, dl.pointer_align.abi);
366+
367+
bx.br(end);
368+
369+
mem_addr
370+
};
371+
372+
// Return the appropriate result.
373+
bx.switch_to_block(end);
374+
let val_addr = bx.phi(bx.type_ptr(), &[reg_addr, mem_addr], &[in_reg, in_mem]);
375+
let val_type = layout.llvm_type(bx);
376+
let val_addr = if is_indirect {
377+
bx.load(bx.cx.type_ptr(), val_addr, dl.pointer_align.abi)
378+
} else {
379+
val_addr
380+
};
381+
bx.load(val_type, val_addr, layout.align.abi)
382+
}
383+
221384
fn emit_s390x_va_arg<'ll, 'tcx>(
222385
bx: &mut Builder<'_, 'll, 'tcx>,
223386
list: OperandRef<'tcx, &'ll Value>,
@@ -728,6 +891,7 @@ pub(super) fn emit_va_arg<'ll, 'tcx>(
728891
PassMode::Direct,
729892
SlotSize::Bytes4,
730893
if target.is_like_windows { AllowHigherAlign::No } else { AllowHigherAlign::Yes },
894+
ForceRightAdjust::No,
731895
),
732896
"aarch64" | "arm64ec" if target.is_like_windows || target.is_like_darwin => {
733897
emit_ptr_va_arg(
@@ -737,10 +901,24 @@ pub(super) fn emit_va_arg<'ll, 'tcx>(
737901
PassMode::Direct,
738902
SlotSize::Bytes8,
739903
if target.is_like_windows { AllowHigherAlign::No } else { AllowHigherAlign::Yes },
904+
ForceRightAdjust::No,
740905
)
741906
}
742907
"aarch64" => emit_aapcs_va_arg(bx, addr, target_ty),
743908
"s390x" => emit_s390x_va_arg(bx, addr, target_ty),
909+
"powerpc" => emit_powerpc_va_arg(bx, addr, target_ty),
910+
"powerpc64" | "powerpc64le" => emit_ptr_va_arg(
911+
bx,
912+
addr,
913+
target_ty,
914+
PassMode::Direct,
915+
SlotSize::Bytes8,
916+
AllowHigherAlign::Yes,
917+
match &*target.arch {
918+
"powerpc64" => ForceRightAdjust::Yes,
919+
_ => ForceRightAdjust::No,
920+
},
921+
),
744922
// Windows x86_64
745923
"x86_64" if target.is_like_windows => {
746924
let target_ty_size = bx.cx.size_of(target_ty).bytes();
@@ -755,6 +933,7 @@ pub(super) fn emit_va_arg<'ll, 'tcx>(
755933
},
756934
SlotSize::Bytes8,
757935
AllowHigherAlign::No,
936+
ForceRightAdjust::No,
758937
)
759938
}
760939
// This includes `target.is_like_darwin`, which on x86_64 targets is like sysv64.

0 commit comments

Comments
 (0)