Skip to content

Commit 96e9e1d

Browse files
authored
Rollup merge of #158170 - usamoi:loop-unroll-stmt, r=JonathanBrouwer,saethlin
parse attrs if a loop's parent hir node is a stmt fix this case: ```rust // unroll doesn't work #[unsafe(no_mangle)] fn f(n: usize) -> usize { let mut sum = 0; let mut i = 0; #[unroll(4)] loop { if i < n { sum += i; i += 1; } else { break; } } sum } // unroll works #[unsafe(no_mangle)] fn g(n: usize) { let mut i = 0; #[unroll(4)] loop { if i < n { i += 1; } else { break; } } } ``` cc #156874 r? saethlin
2 parents ab5beac + d8cf805 commit 96e9e1d

2 files changed

Lines changed: 78 additions & 13 deletions

File tree

compiler/rustc_mir_build/src/thir/cx/expr.rs

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use rustc_middle::ty::{
2222
UpvarArgs,
2323
};
2424
use rustc_middle::{bug, span_bug};
25-
use rustc_span::Span;
25+
use rustc_span::{DesugaringKind, Span};
2626
use tracing::{debug, info, instrument, trace};
2727

2828
use crate::diagnostics::*;
@@ -72,18 +72,24 @@ impl<'tcx> ThirBuildCx<'tcx> {
7272

7373
let mut attrs = ThinVec::new();
7474

75-
if let ExprKind::Loop { .. } = expr.kind {
76-
// For loops defined with loop and while, the expr already has the attrs
77-
if let hir::Node::Block(_) = self.tcx.parent_hir_node(hir_expr.hir_id) {
78-
attrs = parsed_attrs(hir_expr.hir_id, self.tcx);
79-
}
80-
81-
// For loop desugaring puts us pretty deep down the HIR tree
82-
if let hir::Node::Arm(arm) = self.tcx.parent_hir_node(hir_expr.hir_id)
83-
&& let hir::Node::Expr(expr) = self.tcx.parent_hir_node(arm.hir_id)
84-
&& let hir::Node::Expr(expr) = self.tcx.parent_hir_node(expr.hir_id)
85-
{
86-
attrs = parsed_attrs(expr.hir_id, self.tcx);
75+
if let hir::ExprKind::Loop(_, _, _, span) = hir_expr.kind {
76+
match span.desugaring_kind() {
77+
// `for` loop desugaring puts us pretty deep down the HIR tree
78+
Some(DesugaringKind::ForLoop) => {
79+
let arm = self.tcx.parent_hir_node(hir_expr.hir_id).expect_arm();
80+
let expr = self.tcx.parent_hir_node(arm.hir_id).expect_expr();
81+
std::assert_matches!(expr.kind, hir::ExprKind::Match(..));
82+
// ignore async for loops
83+
if let hir::Node::Expr(expr) = self.tcx.parent_hir_node(expr.hir_id) {
84+
std::assert_matches!(expr.kind, hir::ExprKind::DropTemps(..));
85+
attrs = parsed_attrs(expr.hir_id, self.tcx)
86+
}
87+
}
88+
// For loops defined with `loop` and `while`, the expr already has the attrs
89+
Some(DesugaringKind::WhileLoop) | None => {
90+
attrs = parsed_attrs(hir_expr.hir_id, self.tcx);
91+
}
92+
_ => (),
8793
}
8894
}
8995

tests/codegen-llvm/loop-attrs/unroll-loop-metadata.rs

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
#![crate_type = "lib"]
44
#![feature(loop_hints)]
5+
#![feature(stmt_expr_attributes)]
56

67
// This test ensures that we emit the expected LLVM metadata for loop hint attributes.
78
// It does not test that loops are optimized as expected, because successful unrolling removes the
@@ -26,5 +27,63 @@ pub fn unroll_hint() {
2627
}
2728
}
2829

30+
// HIR for a `loop` statement is a bit different, make sure we still apply the metadata in that
31+
// case.
32+
33+
#[no_mangle]
34+
pub fn unroll_full() {
35+
// CHECK-LABEL: @unroll_full
36+
// CHECK: !llvm.loop ![[FULL:[0-9]+]]
37+
let mut i = 0;
38+
let _return = (#[unroll(full)]
39+
loop {
40+
unsafe { maybe_has_side_effect() }
41+
i += 1;
42+
if i >= 10 {
43+
break 1;
44+
}
45+
});
46+
}
47+
48+
#[no_mangle]
49+
pub fn unroll_never() {
50+
// CHECK-LABEL: @unroll_never
51+
// CHECK: !llvm.loop ![[DISABLE:[0-9]+]]
52+
let mut i = 0;
53+
let _return = (1 + #[unroll(never)]
54+
loop {
55+
unsafe { maybe_has_side_effect() }
56+
i += 1;
57+
if i >= 10 {
58+
break 1;
59+
}
60+
});
61+
}
62+
63+
#[no_mangle]
64+
pub fn unroll_count() {
65+
// CHECK-LABEL: @unroll_count
66+
// CHECK: !llvm.loop ![[COUNT:[0-9]+]]
67+
let mut i = 0;
68+
#[unroll(5)]
69+
loop {
70+
unsafe { maybe_has_side_effect() }
71+
i += 1;
72+
if i >= 10 {
73+
break;
74+
}
75+
}
76+
unsafe { maybe_has_side_effect() }
77+
}
78+
2979
// CHECK: ![[HINT]] = distinct !{![[HINT]], ![[INNER_HINT:[0-9]+]]}
3080
// CHECK: ![[INNER_HINT]] = !{!"llvm.loop.unroll.enable"}
81+
82+
// CHECK: ![[FULL]] = distinct !{![[FULL]], ![[INNER_FULL:[0-9]+]]}
83+
// CHECK: ![[INNER_FULL]] = !{!"llvm.loop.unroll.full"}
84+
85+
// CHECK: ![[DISABLE]] = distinct !{![[DISABLE]], ![[INNER_DISABLE:[0-9]+]]}
86+
// CHECK: ![[INNER_DISABLE]] = !{!"llvm.loop.unroll.disable"}
87+
88+
// CHECK: ![[COUNT]] = distinct !{![[COUNT]], ![[INNER_COUNT:[0-9]+]]}
89+
// CHECK: ![[INNER_COUNT]] = !{!"llvm.loop.unroll.count", i32 5}

0 commit comments

Comments
 (0)