Skip to content

Commit dfc4caf

Browse files
committed
Move decision aboute noalias into codegen_llvm
The frontend shouldn't be deciding whether or not to use mutable noalias attributes, as this is a pure LLVM concern. Only provide the necessary information and do the actual decision in codegen_llvm.
1 parent f826641 commit dfc4caf

File tree

4 files changed

+65
-40
lines changed

4 files changed

+65
-40
lines changed

compiler/rustc_codegen_llvm/src/abi.rs

Lines changed: 49 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -41,12 +41,32 @@ impl ArgAttributeExt for ArgAttribute {
4141
}
4242

4343
pub trait ArgAttributesExt {
44-
fn apply_attrs_to_llfn(&self, idx: AttributePlace, llfn: &Value);
45-
fn apply_attrs_to_callsite(&self, idx: AttributePlace, callsite: &Value);
44+
fn apply_attrs_to_llfn(&self, idx: AttributePlace, cx: &CodegenCx<'_, '_>, llfn: &Value);
45+
fn apply_attrs_to_callsite(
46+
&self,
47+
idx: AttributePlace,
48+
cx: &CodegenCx<'_, '_>,
49+
callsite: &Value,
50+
);
51+
}
52+
53+
fn should_use_mutable_noalias(cx: &CodegenCx<'_, '_>) -> bool {
54+
// Previously we would only emit noalias annotations for LLVM >= 6 or in
55+
// panic=abort mode. That was deemed right, as prior versions had many bugs
56+
// in conjunction with unwinding, but later versions didn’t seem to have
57+
// said issues. See issue #31681.
58+
//
59+
// Alas, later on we encountered a case where noalias would generate wrong
60+
// code altogether even with recent versions of LLVM in *safe* code with no
61+
// unwinding involved. See #54462.
62+
//
63+
// For now, do not enable mutable_noalias by default at all, while the
64+
// issue is being figured out.
65+
cx.tcx.sess.opts.debugging_opts.mutable_noalias
4666
}
4767

4868
impl ArgAttributesExt for ArgAttributes {
49-
fn apply_attrs_to_llfn(&self, idx: AttributePlace, llfn: &Value) {
69+
fn apply_attrs_to_llfn(&self, idx: AttributePlace, cx: &CodegenCx<'_, '_>, llfn: &Value) {
5070
let mut regular = self.regular;
5171
unsafe {
5272
let deref = self.pointee_size.bytes();
@@ -62,6 +82,9 @@ impl ArgAttributesExt for ArgAttributes {
6282
llvm::LLVMRustAddAlignmentAttr(llfn, idx.as_uint(), align.bytes() as u32);
6383
}
6484
regular.for_each_kind(|attr| attr.apply_llfn(idx, llfn));
85+
if regular.contains(ArgAttribute::NoAliasMutRef) && should_use_mutable_noalias(cx) {
86+
llvm::Attribute::NoAlias.apply_llfn(idx, llfn);
87+
}
6588
match self.arg_ext {
6689
ArgExtension::None => {}
6790
ArgExtension::Zext => {
@@ -74,7 +97,12 @@ impl ArgAttributesExt for ArgAttributes {
7497
}
7598
}
7699

77-
fn apply_attrs_to_callsite(&self, idx: AttributePlace, callsite: &Value) {
100+
fn apply_attrs_to_callsite(
101+
&self,
102+
idx: AttributePlace,
103+
cx: &CodegenCx<'_, '_>,
104+
callsite: &Value,
105+
) {
78106
let mut regular = self.regular;
79107
unsafe {
80108
let deref = self.pointee_size.bytes();
@@ -98,6 +126,9 @@ impl ArgAttributesExt for ArgAttributes {
98126
);
99127
}
100128
regular.for_each_kind(|attr| attr.apply_callsite(idx, callsite));
129+
if regular.contains(ArgAttribute::NoAliasMutRef) && should_use_mutable_noalias(cx) {
130+
llvm::Attribute::NoAlias.apply_callsite(idx, callsite);
131+
}
101132
match self.arg_ext {
102133
ArgExtension::None => {}
103134
ArgExtension::Zext => {
@@ -419,13 +450,13 @@ impl<'tcx> FnAbiLlvmExt<'tcx> for FnAbi<'tcx, Ty<'tcx>> {
419450

420451
let mut i = 0;
421452
let mut apply = |attrs: &ArgAttributes| {
422-
attrs.apply_attrs_to_llfn(llvm::AttributePlace::Argument(i), llfn);
453+
attrs.apply_attrs_to_llfn(llvm::AttributePlace::Argument(i), cx, llfn);
423454
i += 1;
424455
i - 1
425456
};
426457
match self.ret.mode {
427458
PassMode::Direct(ref attrs) => {
428-
attrs.apply_attrs_to_llfn(llvm::AttributePlace::ReturnValue, llfn);
459+
attrs.apply_attrs_to_llfn(llvm::AttributePlace::ReturnValue, cx, llfn);
429460
}
430461
PassMode::Indirect { ref attrs, extra_attrs: _, on_stack } => {
431462
assert!(!on_stack);
@@ -480,18 +511,18 @@ impl<'tcx> FnAbiLlvmExt<'tcx> for FnAbi<'tcx, Ty<'tcx>> {
480511
// FIXME(wesleywiser, eddyb): We should apply `nounwind` and `noreturn` as appropriate to this callsite.
481512

482513
let mut i = 0;
483-
let mut apply = |attrs: &ArgAttributes| {
484-
attrs.apply_attrs_to_callsite(llvm::AttributePlace::Argument(i), callsite);
514+
let mut apply = |cx: &CodegenCx<'_, '_>, attrs: &ArgAttributes| {
515+
attrs.apply_attrs_to_callsite(llvm::AttributePlace::Argument(i), cx, callsite);
485516
i += 1;
486517
i - 1
487518
};
488519
match self.ret.mode {
489520
PassMode::Direct(ref attrs) => {
490-
attrs.apply_attrs_to_callsite(llvm::AttributePlace::ReturnValue, callsite);
521+
attrs.apply_attrs_to_callsite(llvm::AttributePlace::ReturnValue, &bx.cx, callsite);
491522
}
492523
PassMode::Indirect { ref attrs, extra_attrs: _, on_stack } => {
493524
assert!(!on_stack);
494-
let i = apply(attrs);
525+
let i = apply(bx.cx, attrs);
495526
unsafe {
496527
llvm::LLVMRustAddStructRetCallSiteAttr(
497528
callsite,
@@ -517,12 +548,12 @@ impl<'tcx> FnAbiLlvmExt<'tcx> for FnAbi<'tcx, Ty<'tcx>> {
517548
}
518549
for arg in &self.args {
519550
if arg.pad.is_some() {
520-
apply(&ArgAttributes::new());
551+
apply(bx.cx, &ArgAttributes::new());
521552
}
522553
match arg.mode {
523554
PassMode::Ignore => {}
524555
PassMode::Indirect { ref attrs, extra_attrs: None, on_stack: true } => {
525-
let i = apply(attrs);
556+
let i = apply(bx.cx, attrs);
526557
unsafe {
527558
llvm::LLVMRustAddByValCallSiteAttr(
528559
callsite,
@@ -533,22 +564,22 @@ impl<'tcx> FnAbiLlvmExt<'tcx> for FnAbi<'tcx, Ty<'tcx>> {
533564
}
534565
PassMode::Direct(ref attrs)
535566
| PassMode::Indirect { ref attrs, extra_attrs: None, on_stack: false } => {
536-
apply(attrs);
567+
apply(bx.cx, attrs);
537568
}
538569
PassMode::Indirect {
539570
ref attrs,
540571
extra_attrs: Some(ref extra_attrs),
541572
on_stack: _,
542573
} => {
543-
apply(attrs);
544-
apply(extra_attrs);
574+
apply(bx.cx, attrs);
575+
apply(bx.cx, extra_attrs);
545576
}
546577
PassMode::Pair(ref a, ref b) => {
547-
apply(a);
548-
apply(b);
578+
apply(bx.cx, a);
579+
apply(bx.cx, b);
549580
}
550581
PassMode::Cast(_) => {
551-
apply(&ArgAttributes::new());
582+
apply(bx.cx, &ArgAttributes::new());
552583
}
553584
}
554585
}

compiler/rustc_middle/src/ty/layout.rs

Lines changed: 11 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2327,24 +2327,7 @@ where
23272327
PointerKind::Shared
23282328
}
23292329
}
2330-
hir::Mutability::Mut => {
2331-
// Previously we would only emit noalias annotations for LLVM >= 6 or in
2332-
// panic=abort mode. That was deemed right, as prior versions had many bugs
2333-
// in conjunction with unwinding, but later versions didn’t seem to have
2334-
// said issues. See issue #31681.
2335-
//
2336-
// Alas, later on we encountered a case where noalias would generate wrong
2337-
// code altogether even with recent versions of LLVM in *safe* code with no
2338-
// unwinding involved. See #54462.
2339-
//
2340-
// For now, do not enable mutable_noalias by default at all, while the
2341-
// issue is being figured out.
2342-
if tcx.sess.opts.debugging_opts.mutable_noalias {
2343-
PointerKind::UniqueBorrowed
2344-
} else {
2345-
PointerKind::Shared
2346-
}
2347-
}
2330+
hir::Mutability::Mut => PointerKind::UniqueBorrowed,
23482331
};
23492332

23502333
cx.layout_of(ty).to_result().ok().map(|layout| PointeeInfo {
@@ -2775,10 +2758,14 @@ where
27752758
// and can be marked as both `readonly` and `noalias`, as
27762759
// LLVM's definition of `noalias` is based solely on memory
27772760
// dependencies rather than pointer equality
2761+
//
2762+
// Due to miscompiles in LLVM < 12, we apply a separate NoAliasMutRef attribute
2763+
// for UniqueBorrowed arguments, so that the codegen backend can decide
2764+
// whether or not to actually emit the attribute.
27782765
let no_alias = match kind {
2779-
PointerKind::Shared => false,
2766+
PointerKind::Shared | PointerKind::UniqueBorrowed => false,
27802767
PointerKind::UniqueOwned => true,
2781-
PointerKind::Frozen | PointerKind::UniqueBorrowed => !is_return,
2768+
PointerKind::Frozen => !is_return,
27822769
};
27832770
if no_alias {
27842771
attrs.set(ArgAttribute::NoAlias);
@@ -2787,6 +2774,10 @@ where
27872774
if kind == PointerKind::Frozen && !is_return {
27882775
attrs.set(ArgAttribute::ReadOnly);
27892776
}
2777+
2778+
if kind == PointerKind::UniqueBorrowed && !is_return {
2779+
attrs.set(ArgAttribute::NoAliasMutRef);
2780+
}
27902781
}
27912782
}
27922783
};

compiler/rustc_target/src/abi/call/mod.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,10 @@ mod attr_impl {
6565
const NoCapture = 1 << 2;
6666
const NonNull = 1 << 3;
6767
const ReadOnly = 1 << 4;
68-
const InReg = 1 << 8;
68+
const InReg = 1 << 5;
69+
// NoAlias on &mut arguments can only be used with LLVM >= 12 due to miscompiles
70+
// in earlier versions. FIXME: Remove this distinction once possible.
71+
const NoAliasMutRef = 1 << 6;
6972
}
7073
}
7174
}

compiler/rustc_target/src/abi/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1112,7 +1112,7 @@ pub enum PointerKind {
11121112
/// `&T` where `T` contains no `UnsafeCell`, is `noalias` and `readonly`.
11131113
Frozen,
11141114

1115-
/// `&mut T`, when we know `noalias` is safe for LLVM.
1115+
/// `&mut T` which is `noalias` but not `readonly`.
11161116
UniqueBorrowed,
11171117

11181118
/// `Box<T>`, unlike `UniqueBorrowed`, it also has `noalias` on returns.

0 commit comments

Comments
 (0)