Skip to content

Commit 9f0b7ad

Browse files
committed
Auto merge of #138489 - tmiasko:call-tmps-lifetime, r=<try>
Describe lifetime of call argument temporaries passed indirectly Fixes #132014.
2 parents 7290b04 + 653bbb9 commit 9f0b7ad

File tree

4 files changed

+103
-40
lines changed

4 files changed

+103
-40
lines changed

compiler/rustc_codegen_ssa/src/mir/block.rs

+33-13
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use std::cmp;
22

3-
use rustc_abi::{BackendRepr, ExternAbi, HasDataLayout, Reg, WrappingRange};
3+
use rustc_abi::{BackendRepr, ExternAbi, HasDataLayout, Reg, Size, WrappingRange};
44
use rustc_ast as ast;
55
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
66
use rustc_data_structures::packed::Pu128;
@@ -158,7 +158,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
158158
llargs: &[Bx::Value],
159159
destination: Option<(ReturnDest<'tcx, Bx::Value>, mir::BasicBlock)>,
160160
mut unwind: mir::UnwindAction,
161-
copied_constant_arguments: &[PlaceRef<'tcx, <Bx as BackendTypes>::Value>],
161+
lifetime_ends_after_call: &[(Bx::Value, Size)],
162162
instance: Option<Instance<'tcx>>,
163163
mergeable_succ: bool,
164164
) -> MergingSucc {
@@ -245,8 +245,8 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
245245
if let Some((ret_dest, target)) = destination {
246246
bx.switch_to_block(fx.llbb(target));
247247
fx.set_debug_loc(bx, self.terminator.source_info);
248-
for tmp in copied_constant_arguments {
249-
bx.lifetime_end(tmp.val.llval, tmp.layout.size);
248+
for &(tmp, size) in lifetime_ends_after_call {
249+
bx.lifetime_end(tmp, size);
250250
}
251251
fx.store_return(bx, ret_dest, &fn_abi.ret, invokeret);
252252
}
@@ -259,8 +259,8 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
259259
}
260260

261261
if let Some((ret_dest, target)) = destination {
262-
for tmp in copied_constant_arguments {
263-
bx.lifetime_end(tmp.val.llval, tmp.layout.size);
262+
for &(tmp, size) in lifetime_ends_after_call {
263+
bx.lifetime_end(tmp, size);
264264
}
265265
fx.store_return(bx, ret_dest, &fn_abi.ret, llret);
266266
self.funclet_br(fx, bx, target, mergeable_succ)
@@ -1049,7 +1049,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
10491049
(args, None)
10501050
};
10511051

1052-
let mut copied_constant_arguments = vec![];
1052+
// Keeps track of temporary allocas whose liftime need to be ended after the call.
1053+
let mut lifetime_ends_after_call: Vec<(Bx::Value, Size)> = Vec::new();
10531054
'make_args: for (i, arg) in first_args.iter().enumerate() {
10541055
let mut op = self.codegen_operand(bx, &arg.node);
10551056

@@ -1137,19 +1138,26 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
11371138
bx.lifetime_start(tmp.val.llval, tmp.layout.size);
11381139
op.val.store(bx, tmp);
11391140
op.val = Ref(tmp.val);
1140-
copied_constant_arguments.push(tmp);
1141+
lifetime_ends_after_call.push((tmp.val.llval, tmp.layout.size));
11411142
}
11421143
_ => {}
11431144
}
11441145

1145-
self.codegen_argument(bx, op, &mut llargs, &fn_abi.args[i]);
1146+
self.codegen_argument(
1147+
bx,
1148+
op,
1149+
&mut llargs,
1150+
&fn_abi.args[i],
1151+
&mut lifetime_ends_after_call,
1152+
);
11461153
}
11471154
let num_untupled = untuple.map(|tup| {
11481155
self.codegen_arguments_untupled(
11491156
bx,
11501157
&tup.node,
11511158
&mut llargs,
11521159
&fn_abi.args[first_args.len()..],
1160+
&mut lifetime_ends_after_call,
11531161
)
11541162
});
11551163

@@ -1174,7 +1182,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
11741182
);
11751183

11761184
let last_arg = fn_abi.args.last().unwrap();
1177-
self.codegen_argument(bx, location, &mut llargs, last_arg);
1185+
self.codegen_argument(
1186+
bx,
1187+
location,
1188+
&mut llargs,
1189+
last_arg,
1190+
&mut lifetime_ends_after_call,
1191+
);
11781192
}
11791193

11801194
let fn_ptr = match (instance, llfn) {
@@ -1190,7 +1204,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
11901204
&llargs,
11911205
destination,
11921206
unwind,
1193-
&copied_constant_arguments,
1207+
&lifetime_ends_after_call,
11941208
instance,
11951209
mergeable_succ,
11961210
)
@@ -1475,6 +1489,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
14751489
op: OperandRef<'tcx, Bx::Value>,
14761490
llargs: &mut Vec<Bx::Value>,
14771491
arg: &ArgAbi<'tcx, Ty<'tcx>>,
1492+
lifetime_ends_after_call: &mut Vec<(Bx::Value, Size)>,
14781493
) {
14791494
match arg.mode {
14801495
PassMode::Ignore => return,
@@ -1513,7 +1528,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
15131528
None => arg.layout.align.abi,
15141529
};
15151530
let scratch = PlaceValue::alloca(bx, arg.layout.size, required_align);
1531+
bx.lifetime_start(scratch.llval, arg.layout.size);
15161532
op.val.store(bx, scratch.with_type(arg.layout));
1533+
lifetime_ends_after_call.push((scratch.llval, arg.layout.size));
15171534
(scratch.llval, scratch.align, true)
15181535
}
15191536
PassMode::Cast { .. } => {
@@ -1534,7 +1551,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
15341551
// alignment requirements may be higher than the type's alignment, so copy
15351552
// to a higher-aligned alloca.
15361553
let scratch = PlaceValue::alloca(bx, arg.layout.size, required_align);
1554+
bx.lifetime_start(scratch.llval, arg.layout.size);
15371555
bx.typed_place_copy(scratch, op_place_val, op.layout);
1556+
lifetime_ends_after_call.push((scratch.llval, arg.layout.size));
15381557
(scratch.llval, scratch.align, true)
15391558
} else {
15401559
(op_place_val.llval, op_place_val.align, true)
@@ -1616,6 +1635,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
16161635
operand: &mir::Operand<'tcx>,
16171636
llargs: &mut Vec<Bx::Value>,
16181637
args: &[ArgAbi<'tcx, Ty<'tcx>>],
1638+
lifetime_ends_after_call: &mut Vec<(Bx::Value, Size)>,
16191639
) -> usize {
16201640
let tuple = self.codegen_operand(bx, operand);
16211641

@@ -1628,13 +1648,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
16281648
for i in 0..tuple.layout.fields.count() {
16291649
let field_ptr = tuple_ptr.project_field(bx, i);
16301650
let field = bx.load_operand(field_ptr);
1631-
self.codegen_argument(bx, field, llargs, &args[i]);
1651+
self.codegen_argument(bx, field, llargs, &args[i], lifetime_ends_after_call);
16321652
}
16331653
} else {
16341654
// If the tuple is immediate, the elements are as well.
16351655
for i in 0..tuple.layout.fields.count() {
16361656
let op = tuple.extract_field(self, bx, i);
1637-
self.codegen_argument(bx, op, llargs, &args[i]);
1657+
self.codegen_argument(bx, op, llargs, &args[i], lifetime_ends_after_call);
16381658
}
16391659
}
16401660
tuple.layout.fields.count()

tests/codegen/align-byval-alignment-mismatch.rs

+2
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,10 @@ extern "C" {
5454
pub unsafe fn rust_to_c_increases_alignment(x: Align1) {
5555
// i686-linux: start:
5656
// i686-linux-NEXT: [[ALLOCA:%[0-9a-z]+]] = alloca [48 x i8], align 4
57+
// i686-linux-NEXT: call void @llvm.lifetime.start.p0(i64 48, ptr {{.*}}[[ALLOCA]])
5758
// i686-linux-NEXT: call void @llvm.memcpy.{{.+}}(ptr {{.*}}align 4 {{.*}}[[ALLOCA]], ptr {{.*}}align 1 {{.*}}%x
5859
// i686-linux-NEXT: call void @extern_c_align1({{.+}} [[ALLOCA]])
60+
// i686-linux-NEXT: call void @llvm.lifetime.end.p0(i64 48, ptr {{.*}}[[ALLOCA]])
5961

6062
// x86_64-linux: start:
6163
// x86_64-linux-NEXT: call void @extern_c_align1

tests/codegen/call-tmps-lifetime.rs

+68
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
// Test that temporary allocas used for call arguments have their lifetimes described by
2+
// intrinsics.
3+
//
4+
//@ add-core-stubs
5+
//@ compile-flags: -Copt-level=1 -Cno-prepopulate-passes --crate-type=lib --target i686-unknown-linux-gnu
6+
//@ needs-llvm-components: x86
7+
#![feature(no_core)]
8+
#![no_std]
9+
#![no_core]
10+
extern crate minicore;
11+
use minicore::*;
12+
13+
// Const operand. Regression test for #98156.
14+
//
15+
// CHECK-LABEL: define void @const_indirect(
16+
// CHECK-NEXT: start:
17+
// CHECK-NEXT: [[B:%.*]] = alloca
18+
// CHECK-NEXT: [[A:%.*]] = alloca
19+
// CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 4096, ptr [[A]])
20+
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[A]], ptr align 4 {{.*}}, i32 4096, i1 false)
21+
// CHECK-NEXT: call void %h(ptr {{.*}} [[A]])
22+
// CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 4096, ptr [[A]])
23+
// CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 4096, ptr [[B]])
24+
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[B]], ptr align 4 {{.*}}, i32 4096, i1 false)
25+
// CHECK-NEXT: call void %h(ptr {{.*}} [[B]])
26+
// CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 4096, ptr [[B]])
27+
#[no_mangle]
28+
pub fn const_indirect(h: extern "C" fn([u32; 1024])) {
29+
const C: [u32; 1024] = [0; 1024];
30+
h(C);
31+
h(C);
32+
}
33+
34+
#[repr(C)]
35+
pub struct Str {
36+
pub ptr: *const u8,
37+
pub len: usize,
38+
}
39+
40+
// Pair of immediates. Regression test for #132014.
41+
//
42+
// CHECK-LABEL: define void @immediate_indirect(ptr {{.*}}%s.0, i32 {{.*}}%s.1, ptr {{.*}}%g)
43+
// CHECK-NEXT: start:
44+
// CHECK-NEXT: [[A:%.*]] = alloca
45+
// CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 8, ptr [[A]])
46+
// CHECK-NEXT: store ptr %s.0, ptr [[A]]
47+
// CHECK-NEXT: [[B:%.]] = getelementptr inbounds i8, ptr [[A]], i32 4
48+
// CHECK-NEXT: store i32 %s.1, ptr [[B]]
49+
// CHECK-NEXT: call void %g(ptr {{.*}} [[A]])
50+
// CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 8, ptr [[A]])
51+
#[no_mangle]
52+
pub fn immediate_indirect(s: Str, g: extern "C" fn(Str)) {
53+
g(s);
54+
}
55+
56+
// Indirect argument with a higher alignment requirement than the type's.
57+
//
58+
// CHECK-LABEL: define void @align_indirect(ptr{{.*}} align 1{{.*}} %a, ptr{{.*}} %fun)
59+
// CHECK-NEXT: start:
60+
// CHECK-NEXT: [[A:%.*]] = alloca [1024 x i8], align 4
61+
// CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 1024, ptr [[A]])
62+
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[A]], ptr align 1 %a, i32 1024, i1 false)
63+
// CHECK-NEXT: call void %fun(ptr {{.*}} [[A]])
64+
// CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 1024, ptr [[A]])
65+
#[no_mangle]
66+
pub fn align_indirect(a: [u8; 1024], fun: extern "C" fn([u8; 1024])) {
67+
fun(a);
68+
}

tests/codegen/issues/issue-98156-const-arg-temp-lifetime.rs

-27
This file was deleted.

0 commit comments

Comments
 (0)