-
Notifications
You must be signed in to change notification settings - Fork 12.9k
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
Cleanup old trans #38302
Cleanup old trans #38302
Conversation
Nice! You don't have to wait for my shim-MIR PR - I can handle that. |
val: MaybeSizedValue, discr: Disr, ix: usize) -> ValueRef { | ||
trans_field_ptr_builder(&bcx.build(), t, val, discr, ix) | ||
trans_field_ptr_builder(bcx, t, val, discr, ix) |
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.
IIUC this function is redundant now. Is cleaning that up in scope for this PR?
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.
Yeah, I also commented on it, there's a bunch like this.
I will want to look over the PR later. |
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.
Great work! Most of changes I have in mind are further cleanup (fully removing the global builder and its debuginfo machinery, _builder
fn variants, Block
etc.).
@@ -327,6 +327,8 @@ language_item_table! { | |||
PanicBoundsCheckFnLangItem, "panic_bounds_check", panic_bounds_check_fn; | |||
PanicFmtLangItem, "panic_fmt", panic_fmt; | |||
|
|||
// ExchangeMallocFnLangItem cannot unwind, or MIR trans will break. See note | |||
// on `malloc_raw_dyn` in librustc_trans/base.rs. |
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.
What I meant was actually to add this at the implementation site in liballoc
, in case someone changes it.
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.
Good to put this into liballoc. Is this a new requirement, or just a new comment? Since we know the discussion about panic on oom will come back.
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 we ever decide to allow allocation to panic, we’ll have to change trans. Not a hard requirement, but not a comment either.
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.
Hmm, actually it looks like it's possible to make this panic friendly; but I may be wrong. @eddyb what we need for that is ownership of BAB, right? We have that, so if that's what we need, I can "fix" this.
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.
You can simply change how MIR for allocation is generated. No need to fiddle in trans… unless there’s some old cruft in old trans that still generates calls to this itself… in which case you’ll have a hard and bad time fixing this :)
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.
No, this is only called from MIR. In fact, the actual function should be inlined.
val: MaybeSizedValue, discr: Disr, ix: usize) -> ValueRef { | ||
trans_field_ptr_builder(&bcx.build(), t, val, discr, ix) | ||
trans_field_ptr_builder(bcx, t, val, discr, ix) |
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.
You can change trans_field_ptr_builder
to trans_field_ptr
, including its signature. The _builder
split was for the old B(
.
pub fn load_ty<'blk, 'tcx>( | ||
cx: &BlockAndBuilder<'blk, 'tcx>, ptr: ValueRef, t: Ty<'tcx> | ||
) -> ValueRef { | ||
load_ty_builder(cx, ptr, t) |
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.
Same thing here, load_ty_builder
should not exist anymore.
} | ||
|
||
load_fat_ptr_builder(&B(cx), src, ty) | ||
load_fat_ptr_builder(cx, src, ty) |
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.
Same _builder
cleanup needed.
Lifetime::End.call(&bcx.build(), ptr); | ||
} | ||
pub fn call_lifetime_end(bcx: &BlockAndBuilder, ptr: ValueRef) { | ||
Lifetime::End.call(bcx, ptr); |
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.
You can probably inline these 2 at their callsites now.
} | ||
|
||
let llret_ty = type_of::type_of(ccx, ret_ty); | ||
|
||
let simple = get_simple_intrinsic(ccx, name); | ||
let llval = match (simple, name) { | ||
(Some(llfn), _) => { | ||
Call(bcx, llfn, &llargs, call_debug_location) | ||
bcx.call(llfn, &llargs, bcx.lpad().and_then(|b| b.bundle())) |
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.
Oh, everywhere you have a call that's not to drop glue or box_free
you can just put None
instead of bcx.lpad().and_then(|b| b.bundle())
- the latter is for cleanup blocks (unwinding landing pads) which are restricted in MIR, e.g. they can't just have arbitrary function calls like intrinsics.
return; | ||
} | ||
|
||
let ptr = self.trans_operand(&bcx, &args[0]); |
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.
Extraneous space after =
.
} | ||
|
||
pub fn store_operand_direct(&mut self, | ||
bcx: Block<'bcx, 'tcx>, | ||
bcx: &BlockAndBuilder<'bcx, '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.
Rename this function to store_operand
.
llval = Some(val); | ||
bcx | ||
}); | ||
let val = base::malloc_raw_dyn(&bcx, llty_ptr, box_ty, llsize, llalign); |
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.
Is this the only call? Because then you could inline it.
AddIncomingToPhi(current, next, body_bcx.llbb); | ||
Br(body_bcx, header_bcx.llbb, DebugLoc::None); | ||
// FIXME(simulacrum): The code below is identical to the closure (add) above, but using the | ||
// closure doesn't compile due to body_bcx still being borrowed when dropped. |
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.
Is this due to over-zealous inference 😞?
Let me test whether this fixes issue |
Nope, #35566 is still not fixed. |
Update: looks like @est31 was hitting the bug at stage0, which ofc is not fixed. I've suggested a manual way to test that the bug is indeed fixed at stage1 and later. |
Now it fails when compiling stage1 std artifacts:
|
d87189d
to
a81bc72
Compare
About the drop_in_place change, is this an example of a program that changes behaviour? Just to understand. Current stable/beta/nightly doesn't run the "B" drop after the panic of "A". struct PrintDrop(&'static str);
impl Drop for PrintDrop {
fn drop(&mut self) {
println!("Dropping {}", self.0);
if self.0 == "A" {
panic!();
}
}
}
use std::mem::forget;
use std::ptr::drop_in_place;
fn main() {
let mut x = (PrintDrop("A"), PrintDrop("B"));
unsafe {
drop_in_place(&mut x);
forget(x);
}
} |
The example @eddyb gave me for the |
@@ -314,18 +312,109 @@ pub struct FunctionContext<'a, 'tcx: 'a> { | |||
|
|||
// Used and maintained by the debuginfo module. | |||
pub debug_context: debuginfo::FunctionDebugContext, | |||
|
|||
owned_builder: OwnedBuilder<'a, '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.
You should probably name this alloca_builder
.
@@ -303,9 +304,6 @@ pub struct FunctionContext<'a, 'tcx: 'a> { | |||
// error reporting and symbol generation. | |||
pub span: Option<Span>, | |||
|
|||
// The arena that blocks are allocated from. | |||
//pub block_arena: &'a TypedArena<BlockS<'a, 'tcx>>, | |||
|
|||
// The arena that landing pads are allocated from. | |||
pub funclet_arena: TypedArena<Funclet>, |
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.
Still need to kill this.
// This is later removed in FunctionContext::cleanup. | ||
self.alloca_insert_pt.set(Some(unsafe { | ||
entry_bcx.load(C_null(Type::i8p(self.ccx))); | ||
llvm::LLVMGetFirstInstruction(entry_bcx.llbb()) |
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.
I don't think the LLVMGetFirstInstruction
call is needed and you can just the result of the .load(...)
.
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.
The load returns the ValueRef
for the first instruction?
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.
The load is the first instruction.
|
||
self.owned_builder.builder.position_at_start(entry_bcx.llbb()); | ||
|
||
if !self.fn_ty.ret.is_ignore() && !skip_retptr { |
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.
Oh this is weird, I wonder if this should maybe be inlined.
let slot = if self.fn_ty.ret.is_indirect() { | ||
get_param(self.llfn, 0) | ||
} else { | ||
self.alloca(llty, "sret_slot") |
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.
llty
can be computed on this branch alone. Which IMO should not exist anymore.
let b = self.ccx.builder(); | ||
b.position_before(self.alloca_insert_pt.get().unwrap()); | ||
b.alloca(ty, name) | ||
self.owned_builder.builder.alloca(ty, name) |
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.
Should rename the method on Builder
to dynamic_alloca
or something.
pub fn builder<'a>(&'a self) -> Builder<'a, 'tcx> { | ||
Builder::new(self) | ||
} | ||
|
||
pub fn raw_builder<'a>(&'a self) -> BuilderRef { | ||
self.local().builder.b |
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.
Looks like the underlying builder is not exactly gone.
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.
Also OwnedBuilder
should be the only Builder
, i.e. the latter should not be a distinct type.
mir: mir, | ||
llfn: llfndecl, | ||
llretslotptr: Cell::new(None), | ||
param_env: ccx.tcx().empty_parameter_environment(), |
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.
Is this used at all anymore?
landingpad_alloca: Cell::new(None), | ||
fn_ty: fn_ty, | ||
param_substs: param_substs, | ||
span: None, |
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.
... or this?
f02257a
to
bcfe02d
Compare
// have been instructed to skip it for immediate return | ||
// values, or there is nothing to return at all. | ||
// This is later removed in the drop of FunctionContext. | ||
fcx.alloca_insert_pt = Some(val); |
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.
Can you avoid having two variables named val
, i.e. can you move this up a bit more? Maybe rename it to dummy
.
5a2f7d8
to
11fb0a1
Compare
let mir = fcx.mir(); | ||
pub fn create_mir_scopes<'tcx>( | ||
fcx: &FunctionContext, | ||
mir: Ref<'tcx, Mir<'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.
Can this be a regular reference?
pub fn trans_mir<'blk, 'tcx: 'blk>(fcx: &'blk FunctionContext<'blk, 'tcx>) { | ||
pub fn trans_mir<'blk, 'tcx: 'blk>( | ||
fcx: &'blk FunctionContext<'blk, 'tcx>, | ||
mir: Ref<'tcx, Mir<'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.
Can this get away with being a reference?
832e1e4
to
ff3829d
Compare
|
||
/// Access a field, at a point when the value's case is known. | ||
pub fn trans_field_ptr_builder<'blk, 'tcx>(bcx: &BlockAndBuilder<'blk, 'tcx>, | ||
pub fn trans_field_ptr<'blk, 'tcx>(bcx: &BlockAndBuilder<'blk, 'tcx>, | ||
t: Ty<'tcx>, | ||
val: MaybeSizedValue, | ||
discr: Disr, ix: usize) | ||
-> ValueRef { |
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.
Indentation is off here.
DebugLoc::None.apply(self); | ||
self.cleanup(); | ||
pub fn finish(&'blk self, ret_cx: &BlockAndBuilder<'blk, 'tcx>) { | ||
self.build_return_block(ret_cx); |
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.
This is just an alias for build_return_block
and the latter should be inlined.
In some cases there is no return value, in the rest the ABI should match so it's just a matter of passing a return pointer in where applicable and returning the result of the call elsewhere.
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.
Looked again and I think trans_ctor_shim
is the only place that needs an alloca
for the return value, sometimes (and then only a few cases in build_return_block
apply).
} | ||
(_, None) => { | ||
let retval = if llty == Type::i1(self.ccx) { | ||
let val = LoadRangeAssert(ret_cx, retslot, 0, 2, llvm::False); | ||
Trunc(ret_cx, val, llty) | ||
let val = ret_cx.load_range_assert(retslot, 0, 2, llvm::False); |
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.
Yeah, all of this should be unnecessary, it'd be a waste of time to actually write something to an alloca and read it later.
-> Result<'blk, 'tcx> { | ||
trans_call_inner(bcx, debug_loc, self, args, dest) | ||
dest: Option<ValueRef>, | ||
lpad: Option<&'blk llvm::OperandBundleDef>) { |
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.
Something tells me all remaining uses have None
for lpad
. Also, trans_call_inner
can be inlined.
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.
Wait, that's poorly named, it should be cleanup_bundle
.
opt_llretslot: Option<ValueRef>) | ||
-> Result<'blk, 'tcx> { | ||
dest: Option<ValueRef>, | ||
lpad: Option<&'blk llvm::OperandBundleDef>) { | ||
// Introduce a temporary cleanup scope that will contain cleanups | ||
// for the arguments while they are being evaluated. The purpose | ||
// this cleanup is to ensure that, should a panic occur while | ||
// evaluating argument N, the values for arguments 0...N-1 are all | ||
// cleaned up. If no panic occurs, the values are handed off to | ||
// the callee, and hence none of the cleanups in this temporary | ||
// scope will ever execute. |
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.
This comment is outdated heh.
Call(bcx, llfn, &[], call_debug_location); | ||
Unreachable(bcx); | ||
return Result::new(bcx, C_undef(Type::nil(ccx).ptr_to())); | ||
bcx.call(llfn, &[], None); |
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.
I think this can be folded into the get_simple_intrinsic
use below.
ret_bcx.at_start(|ret_bcx| { | ||
debug_loc.apply_to_bcx(ret_bcx); | ||
bcx.set_source_location(scope, debug_span); |
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.
Needs to be ret_bcx.set_source_location(...)
.
let bcx = self.bcx(bb); | ||
pub fn init_cpad(&mut self, bb: mir::BasicBlock, | ||
funclets: &mut IndexVec<mir::BasicBlock, Option<Funclet>>) { | ||
let bcx = self.build_block(bb); |
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.
This function can probably just iterate over cleanup_kinds
to produce funclets
, without the RPO visit order (as CleanupKind::Internal
doesn't need to reference a different functlets
entry).
@@ -290,32 +278,32 @@ pub fn trans_mir<'blk, 'tcx: 'blk>(fcx: &'blk FunctionContext<'blk, 'tcx>) { | |||
|
|||
let mut rpo = traversal::reverse_postorder(&mir); | |||
|
|||
let mut funclets: IndexVec<mir::BasicBlock, Option<Funclet>> = | |||
IndexVec::from_elem(None, mir.basic_blocks()); | |||
|
|||
// Prepare each block for translation. | |||
for (bb, _) in rpo.by_ref() { |
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.
This is what I mean, the order is irrelevant here now.
Br(body_bcx, header_bcx.llbb, DebugLoc::None); | ||
f(&body_bcx, if zst { data_ptr } else { current }); | ||
let next = add(&body_bcx, current, C_uint(bcx.ccx(), 1usize)); | ||
body_bcx.add_incoming_to_phi(current, next, body_bcx.llbb()); |
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.
This is mildly confusing, heh, it'd make more sense as header_bcx.add_incoming_to_phi(...)
.
☔ The latest upstream changes (presumably #37429) made this pull request unmergeable. Please resolve the merge conflicts. |
d4f0717
to
aa9b367
Compare
|
||
if fn_ret.0.is_never() { | ||
bcx.unreachable(); | ||
} |
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.
This can't ever be the case.
InternalDebugLocation::new(scope, loc.line, loc.col.to_usize()) | ||
} else { | ||
UnknownLocation | ||
}; | ||
set_debug_location(fcx.ccx, builder, dbg_loc); | ||
set_debug_location(mir.ccx(), builder, dbg_loc); |
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.
FWIW, here and a few times above, builder
has a ccx
of its own. trans::debuginfo
should maybe take just debug_context
, not the whole mir
context.
mir: &'a mir::Mir<'tcx>, | ||
pub mir: &'a mir::Mir<'tcx>, | ||
|
||
pub debug_context: debuginfo::FunctionDebugContext, |
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.
Yeah I'd rather these not be made public.
This does not make unreachable and other terminators take self by-value because it is deemed too difficult. We would need to create by-value methods on BAB that call into Builder, due to the Deref to builder.
We cannot inline due to it being recursive.
Also improves cache quality.
7d03df9
to
0013d4c
Compare
Rebased. |
@bors r+ |
📌 Commit 0013d4c has been approved by |
Cleanup old trans This is a cleanup of old trans, with the following main points: - Remove the `build.rs` API (prefer using `Builder` directly, which is now passed where needed through `BlockAndBuilder`). - Remove `Block` (inlining it into `BlockAndBuilder`) - Remove `Callee::call`, primarily through inlining and simplification of code. - Thinned `FunctionContext`: - `mir`, `debug_scopes`, `scopes`, and `fn_ty` are moved to `MirContext`. - `param_env` is moved to `SharedCrateContext` and renamed to `empty_param_env`. - `llretslotptr` is removed, replaced with more careful management of the return values in calls. - `landingpad_alloca` is inlined into cleanup. - `param_substs` are moved to `MirContext`. - `span` is removed, it was never set to anything but `None`. - `block_arena` and `lpad_arena` are removed, since neither was necessary (landing pads and block are quite small, and neither needs arena allocation). - Fixed `drop_in_place` not running other destructors in the same function. Fixes #35566 (thanks to @est31 for confirming).
This is a cleanup of old trans, with the following main points:
build.rs
API (prefer usingBuilder
directly, which is now passed where needed throughBlockAndBuilder
).Block
(inlining it intoBlockAndBuilder
)Callee::call
, primarily through inlining and simplification of code.FunctionContext
:mir
,debug_scopes
,scopes
, andfn_ty
are moved toMirContext
.param_env
is moved toSharedCrateContext
and renamed toempty_param_env
.llretslotptr
is removed, replaced with more careful management of the return values in calls.landingpad_alloca
is inlined into cleanup.param_substs
are moved toMirContext
.span
is removed, it was never set to anything butNone
.block_arena
andlpad_arena
are removed, since neither was necessary (landing pads and block are quite small, and neither needs arena allocation).drop_in_place
not running other destructors in the same function.Fixes #35566 (thanks to @est31 for confirming).