-
Notifications
You must be signed in to change notification settings - Fork 12.7k
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
rustc_codegen_llvm: traitification of LLVM-specific CodegenCx and Builder methods #55627
Conversation
r? @pnkfelix (rust_highfive has picked a reviewer for you, use r? to override) |
This comment has been minimized.
This comment has been minimized.
6538a47
to
cffad3f
Compare
r? @eddyb |
This comment has been minimized.
This comment has been minimized.
Thanks for fixing the bug ! It was a silly mistake from my part... |
rustc_target: pass contexts by reference, not value. `LayoutOf` now takes `&self` instead of `self`, and so does every method generic over a context that implements `LayoutOf` and/or other traits, like `HasDataLayout`, `HasTyCtxt`, etc. Originally using by-value `Copy` types was relevant because `TyCtxt` was one of those types, but now `TyCtxt::layout_of` is separate from `LayoutOf`, and `TyCtxt` is not an often used layout context. Passing these context by reference is a lot nicer for miri, which has `self: &mut EvalContext`, and needed `f(&self)` (that is, creating `&&mut EvalContext` references) for layout purposes. Now, the `&mut EvalContext` can be passed to a function expecting `&C`, directly. This should help with #54012 / #55627 (to not need `where &'a T::Cx: LayoutOf` bounds). r? @nikomatsakis or @oli-obk or @nagisa cc @sunfishcode
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.
First batch of comments (my browser hates me already!)
src/librustc_codegen_llvm/abi.rs
Outdated
fn store_fn_arg( | ||
&mut self, | ||
ty: &ArgType<'tcx, Ty<'tcx>>, | ||
idx: &mut usize, dst: PlaceRef<'tcx, <Self::CodegenCx as Backend<'ll>>::Value> |
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.
dst
should probably be on its own line.
bx: &mut Builder<'a, 'll, 'tcx, &'ll Value>, | ||
idx: &mut usize, | ||
dst: PlaceRef<'tcx, &'ll Value> | ||
) { |
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 is a LLVM-ism, does Cranelift support getting at the function params from a builder? What I'd do instead is also pass a slice of values, alongside the index.
src/librustc_codegen_llvm/abi.rs
Outdated
@@ -104,29 +106,29 @@ impl ArgAttributesExt for ArgAttributes { | |||
} | |||
|
|||
pub trait LlvmType { | |||
fn llvm_type(&self, cx: &CodegenCx<'ll, '_>) -> &'ll Type; | |||
fn llvm_type(&self, cx: &CodegenCx<'ll, '_, &'ll Value>) -> &'ll Type; |
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.
Maybe have a crate-wide type-alias so that we can continue to write CodegenCx<'ll, '_>
instead of CodegenCx<'ll, '_, &'ll Value>
in rustc_codegen_llvm
?
&mut self, | ||
ty: &FnType<'tcx, Ty<'tcx>>, | ||
callsite: <Self::CodegenCx as Backend<'ll>>::Value | ||
) { |
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, I think it might be better if instead of the "apply attrs" LLVM-ism, the call
/invoke
methods of Builder
took an FnType
and internally called the LLVM-only apply_attrs_callsite
.
} | ||
fn fn_type_of_instance(&self, instance: &Instance<'tcx>) -> FnType<'tcx, Ty<'tcx>> { | ||
FnType::of_instance(&self, instance) | ||
} |
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.
Do any of these depend on anything LLVM-specific? IMO these could be moved into rustc_codegen_ssa
or even rustc
itself!
src/librustc_codegen_llvm/builder.rs
Outdated
inputs: &[&'ll Value], output: &'ll Type, | ||
volatile: bool, alignstack: bool, | ||
dia: AsmDialect) -> Option<&'ll Value> { | ||
fn inline_asm_call(&mut self, asm: *const c_char, cons: *const c_char, |
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.
For this to be a safe Rust function, btw, *const c_char
needs to be replaced with &CStr
.
cmp, | ||
src, | ||
AtomicOrdering::from_generic(order), | ||
AtomicOrdering::from_generic(failure_order), |
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 makes me think From
should be implemented instead. Then, the LLVM-specific AtomicOrdering
do not need to be imported, removing rustc_codegen_ssa::common::
noise in the signature and we can just do order.into()
and whatnot.
/// If LLVM lifetime intrinsic support is disabled (i.e. optimizations | ||
/// off) or `ptr` is zero-sized, then no-op (does not call `emit`). | ||
fn call_lifetime_intrinsic(&self, intrinsic: &str, ptr: &'ll Value, size: Size) { | ||
fn call_lifetime_intrinsic(&mut self, intrinsic: &str, ptr: &'ll Value, size: Size) { |
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 probably needs to be generalized to storage_{live,dead}
(which is what the MIR contains).
src/librustc_codegen_llvm/builder.rs
Outdated
&self.cx | ||
} | ||
|
||
fn delete_basic_block(&mut self, bb: &'ll BasicBlock) { |
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 unsafe! The trait method should be marked as such. Maybe we can find a way to avoid doing it at all.
} | ||
|
||
fn do_not_inline(&mut self, llret: &'ll Value) { | ||
llvm::Attribute::NoInline.apply_callsite(llvm::AttributePlace::Function, llret); |
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.
Applying attributes via the return value is a LLVM-ism, we should clean it up.
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.
Second round of comments, got through rustc_codegen_llvm
and rustc_codegen_ssa::back
, things seems pretty good so far!
src/librustc_codegen_llvm/callee.rs
Outdated
@@ -57,9 +53,9 @@ pub fn get_fn( | |||
|
|||
// Create a fn pointer with the substituted signature. | |||
let fn_ptr_ty = tcx.mk_fn_ptr(sig); | |||
let llptrty = cx.layout_of(fn_ptr_ty).llvm_type(cx); | |||
let llptrty = cx.backend_type(&cx.layout_of(fn_ptr_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.
Any reason this can't be a method in an extension trait on TyLayout
still?
That is, I'd prefer to write cx.layout_of(fn_ptr_ty).codegen_type(cx)
.
OTOH, another thing we can do is remove the &
there.
TyLayout
is a "cheap" type, a pair of references IIRC, by design!
src/librustc_codegen_llvm/common.rs
Outdated
Funclet { | ||
cleanuppad, | ||
operand: OperandBundleDef::new("funclet", &[cleanuppad]), | ||
impl<'ll, 'tcx : 'll> ConstMethods<'ll, 'tcx> for CodegenCx<'ll, 'tcx, &'ll Value> { |
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 should probably be moved to the consts.rs
file or something.
match span { | ||
Some(span) => tcx.sess.span_fatal(span, &msg[..]), | ||
None => tcx.sess.fatal(&msg[..]), | ||
fn scalar_to_backend( |
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'd maybe call this codegen_scalar
or, better, const_scalar
.
src/librustc_codegen_llvm/consts.rs
Outdated
unsafe { | ||
let bitcast = llvm::LLVMConstPointerCast(new_g, self.val_ty(old_g)); | ||
llvm::LLVMReplaceAllUsesWith(old_g, bitcast); | ||
llvm::LLVMDeleteGlobal(old_g); |
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 seems like would require this method to be marked as unsafe
(as references to old_g
might still be around, outside of the LLVM module itself).
src/librustc_codegen_llvm/context.rs
Outdated
use syntax::symbol::LocalInternedString; | ||
use abi::Abi; | ||
|
||
/// There is one `CodegenCx` per compilation unit. Each one has its own LLVM | ||
/// `llvm::Context` so that several compilation units may be optimized in parallel. | ||
/// All other LLVM data structures in the `CodegenCx` are tied to that `llvm::Context`. | ||
pub struct CodegenCx<'a, 'tcx: 'a> { | ||
pub tcx: TyCtxt<'a, 'tcx, 'tcx>, | ||
pub struct CodegenCx<'ll, 'tcx: 'll, V> { |
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 local struct. You can do V = &'ll Value
here!
src/librustc_codegen_llvm/type_.rs
Outdated
impl<'a, 'll: 'a, 'tcx: 'll> DerivedTypeMethods<'a, 'll, 'tcx> for CodegenCx<'ll, 'tcx, &'ll Value> | ||
{} | ||
|
||
impl LayoutTypeMethods<'ll, 'tcx> for CodegenCx<'ll, 'tcx, &'ll Value> { |
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.
These should be inverted - that is, implemented on TyLayout
, in rustc_codegen_ssa
. I guess you still need this trait, hmm.
src/librustc_codegen_ssa/README.md
Outdated
{ | ||
fn new_block<'b>( | ||
cx: &'a Self::CodegenCx, | ||
llfn: <Self::CodegenCx as Backend<'ll>>::Value, |
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 you could have Value
in a trait that's only associated types, and is implemented for builders to point to their backend's associated types.
|
||
/// Additional resources used by optimize_and_codegen (not module specific) | ||
#[derive(Clone)] | ||
pub struct CodegenContext<B : WriteBackendMethods> { |
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 reminds me the name Codegen
in the context of the "back" module, is suboptimal.
Including in "optimize_and_codegen". I think we could call this step "emitting machine code/a binary", so maybe optimize_and_emit
? OptimizeAndEmitContext
is not great, but more descriptive.
cc @michaelwoerister @rkruppe @alexcrichton
Also, :
should be :
.
self.obj_is_bitcode = sess.target.target.options.obj_is_bitcode || | ||
sess.opts.debugging_opts.cross_lang_lto.enabled(); | ||
let embed_bitcode = sess.target.target.options.embed_bitcode || | ||
sess.opts.debugging_opts.embed_bitcode; |
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.
Not sure what to do about all of these LLVM-specific options.
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.
Maybe rename bitcode
to ir
, to generalize? or llvm_bc
, to make it clear it's LLVM-specific.
let mut note = prog.stderr.clone(); | ||
note.extend_from_slice(&prog.stdout); | ||
|
||
|
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.
Maybe someone should search for llvm
(case-insensitive) in rustc_codegen_ssa
.
There's a general issue, that |
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.
Third batch, and that's all the comments for now! Let me know if I can help resolve everything.
// option. This file may not be copied, modified, or distributed | ||
// except according to those terms. | ||
|
||
//! Codegen the completed AST to the LLVM IR. |
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.
Outdated comment - could even be removed, base
ended up as a dumping ground (and common
similarly), they should be properly redistributed around IMO.
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.
But only the comment is a concern for now.
src/librustc_codegen_ssa/base.rs
Outdated
|
||
|
||
pub struct StatRecorder<'a, 'll: 'a, 'tcx: 'll, Cx: 'a + CodegenMethods<'a, 'll, 'tcx>> | ||
where &'a Cx : LayoutOf<Ty = Ty<'tcx>, TyLayout = TyLayout<'tcx>> + HasTyCtxt<'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.
So, &'a Cx : LayoutOf + HasTyCtxt
bounds should not longer be needed, since my PR landed.
Also, we either need to 1. avoid putting bounds on structs 2. enable the implied bounds feature to avoid writing the bounds anywhere else. cc @nikomatsakis
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, are any of these "stats" useful anymore? It feels like any new infrastructure should be designed with MIR in mind...
} | ||
} | ||
|
||
pub fn bin_op_to_fcmp_predicate(op: hir::BinOpKind) -> RealPredicate { |
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.
IMO Real
in the type name should be changed to Float
. I have no idea why LLVM chose that (wrong) name in the first place.
src/librustc_codegen_ssa/base.rs
Outdated
|
||
pub fn compare_simd_types<'a, 'll:'a, 'tcx:'ll, Bx : BuilderMethods<'a, 'll, 'tcx>>( | ||
bx: &mut Bx, | ||
lhs: <Bx::CodegenCx as Backend<'ll>>::Value, |
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.
As I mentioned earlier, I think it would be cleaner if builders implemented the same trait holding associated types, so this was just Bx::Value
.
Also, I'm seeing 'll
in this crate - that shouldn't be needed!
After all, we're abstracting over types like &'ll Value
- so the parametrization should only exist in rustc_codegen_llvm
.
backend: B, | ||
tcx: TyCtxt<'ll, 'tcx, 'tcx>, | ||
rx: mpsc::Receiver<Box<dyn Any + Send>> | ||
) -> OngoingCodegen<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.
I'm impressed all of this entrypoint stuff could be reused!
src/librustc_codegen_utils/lib.rs
Outdated
@@ -21,6 +21,7 @@ | |||
#![feature(custom_attribute)] | |||
#![feature(nll)] | |||
#![allow(unused_attributes)] | |||
#![allow(dead_code)] |
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.
Why is this needed? It should, at all, be placed on individual items!
bb: mir::BasicBlock, | ||
terminator: &mir::Terminator<'tcx>) | ||
{ | ||
fn codegen_terminator<Bx: BuilderMethods<'a, 'll, '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.
Could we, instead, make Bx
an associated type on Cx
? That would get rid of some of the explicit parametrization.
@@ -329,25 +347,25 @@ impl FunctionCx<'a, 'll, 'tcx> { | |||
// NOTE: Unlike binops, negation doesn't have its own | |||
// checked operation, just a comparison with the minimum | |||
// value, so we have to check for the assert message. | |||
if !bx.cx.check_overflow { | |||
if !bx.cx().check_overflow() { |
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 should be on an extension trait on TyCtxt
in rustc_codegen_ssa
.
@@ -159,48 +169,67 @@ impl OperandRef<'ll, 'tcx> { | |||
|
|||
/// If this operand is a `Pair`, we return an aggregate with the two values. | |||
/// For other cases, see `immediate`. | |||
pub fn immediate_or_packed_pair(self, bx: &Builder<'a, 'll, 'tcx>) -> &'ll Value { | |||
pub fn immediate_or_packed_pair<Bx: BuilderMethods<'a, 'll, '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.
These packing methods should be relegated to the backend.
AFAIK, Cranelift uses multiple returns instead of packing two values into one.
)); | ||
ll_t_in_const | ||
); | ||
base::call_assume(&mut bx, cmp); |
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 should be a builder method.
cffad3f
to
1764f2c
Compare
The job Click to expand the log.
I'm a bot! I can only do what humans tell me to, so if this was not helpful or you have suggestions for improvements, please ping or otherwise contact |
☔ The latest upstream changes (presumably #55410) made this pull request unmergeable. Please resolve the merge conflicts. |
1764f2c
to
09235bb
Compare
The job Click to expand the log.
I'm a bot! I can only do what humans tell me to, so if this was not helpful or you have suggestions for improvements, please ping or otherwise contact |
☔ The latest upstream changes (presumably #55746) made this pull request unmergeable. Please resolve the merge conflicts. |
@sunfishcode Can you take a look at fixing the merge conflicts and resolving the CI failure here? |
@Mark-Simulacrum I'm rebasing it and getting close to finishing. |
⌛ Testing commit 756f84d with merge c5b7d98c594251886e5f58bf7197a8aa59053ad3... |
💔 Test failed - status-appveyor |
@alexcrichton @retep998 Is this spurious, or a real failure? @bors retry (just in case) |
rustc_codegen_llvm: traitification of LLVM-specific CodegenCx and Builder methods This PR is the continuation of #54012 and earlier PRs, in the grand plan of #45274 to allow for multiple codegen backends. High-level summary: interpose a set of traits between Rust's codegen logic and the LLVM APIs, allowing another backend to implement the traits and share most of the codegen logic. These traits are currently somewhat LLVM-specific, but once this refactoring is in place, they can evolve to be more general. See [this README](https://github.com/rust-lang/rust/blob/756f84d7cef90b7364ae88ca707e59670dde4c92/src/librustc_codegen_ssa/README.md) for a writeup on the current trait organization.
☀️ Test successful - status-appveyor, status-travis |
Add rustc_codegen_ssa to sysroot Outside of rustc you are currently unable to use it. r? @nikomatsakis (because you r+'ed rust-lang#55627)
Enable tests on rustc_codegen_ssa This enables unittests in rustc_codegen_ssa. There are some tests, primarily in [`back/rpath/tests.rs`](https://github.com/rust-lang/rust/blob/HEAD/compiler/rustc_codegen_ssa/src/back/rpath/tests.rs) that haven't ever been running since the unittests are disabled. From what I can tell, this was just a consequence of how things evolved. When testing was initially added in rust-lang#33282, `librustc_trans` had test=false because it didn't have any tests. `rustc_codegen_ssa` eventually split off from that (rust-lang#55627), and the rpath module eventually got merged in too (from `librustc_back` where it used to live). That migration didn't enable the tests. This also includes some fluent diagnostic tests, though I'm not sure what exactly they are testing.
Enable tests on rustc_codegen_ssa This enables unittests in rustc_codegen_ssa. There are some tests, primarily in [`back/rpath/tests.rs`](https://github.com/rust-lang/rust/blob/HEAD/compiler/rustc_codegen_ssa/src/back/rpath/tests.rs) that haven't ever been running since the unittests are disabled. From what I can tell, this was just a consequence of how things evolved. When testing was initially added in rust-lang#33282, `librustc_trans` had test=false because it didn't have any tests. `rustc_codegen_ssa` eventually split off from that (rust-lang#55627), and the rpath module eventually got merged in too (from `librustc_back` where it used to live). That migration didn't enable the tests. This also includes some fluent diagnostic tests, though I'm not sure what exactly they are testing.
This PR is the continuation of #54012 and earlier PRs, in the grand plan of #45274 to allow for multiple codegen backends.
High-level summary: interpose a set of traits between Rust's codegen logic and the LLVM APIs, allowing another backend to implement the traits and share most of the codegen logic. These traits are currently somewhat LLVM-specific, but once this refactoring is in place, they can evolve to be more general.
See this README for a writeup on the current trait organization.