Skip to content

Commit 3238e0d

Browse files
committed
Optimise the last field operations in derive[PartialOrd]
1 parent 44efb05 commit 3238e0d

File tree

1 file changed

+72
-51
lines changed

1 file changed

+72
-51
lines changed

src/libsyntax_ext/deriving/cmp/partial_ord.rs

Lines changed: 72 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -190,58 +190,79 @@ pub fn cs_partial_cmp(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P<
190190

191191
/// Strict inequality.
192192
fn cs_op(less: bool, equal: bool, cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P<Expr> {
193-
let op = if less { BinOpKind::Lt } else { BinOpKind::Gt };
194-
cs_fold(false, // need foldr,
195-
|cx, span, subexpr, self_f, other_fs| {
196-
// build up a series of chain ||'s and &&'s from the inside
197-
// out (hence foldr) to get lexical ordering, i.e. for op ==
198-
// `ast::lt`
199-
//
200-
// ```
201-
// self.f1 < other.f1 || (!(other.f1 < self.f1) &&
202-
// (self.f2 < other.f2 || (!(other.f2 < self.f2) &&
203-
// (false)
204-
// ))
205-
// )
206-
// ```
207-
//
208-
// The optimiser should remove the redundancy. We explicitly
209-
// get use the binops to avoid auto-deref dereferencing too many
210-
// layers of pointers, if the type includes pointers.
211-
//
212-
let other_f = match (other_fs.len(), other_fs.get(0)) {
213-
(1, Some(o_f)) => o_f,
214-
_ => cx.span_bug(span, "not exactly 2 arguments in `derive(PartialOrd)`"),
215-
};
216-
217-
let strict_ineq = cx.expr_binary(span, op, self_f.clone(), other_f.clone());
193+
let strict_op = if less { BinOpKind::Lt } else { BinOpKind::Gt };
194+
cs_fold1(false, // need foldr,
195+
|cx, span, subexpr, self_f, other_fs| {
196+
// build up a series of chain ||'s and &&'s from the inside
197+
// out (hence foldr) to get lexical ordering, i.e. for op ==
198+
// `ast::lt`
199+
//
200+
// ```
201+
// self.f1 < other.f1 || (!(other.f1 < self.f1) &&
202+
// (self.f2 < other.f2 || (!(other.f2 < self.f2) &&
203+
// (false)
204+
// ))
205+
// )
206+
// ```
207+
//
208+
// The optimiser should remove the redundancy. We explicitly
209+
// get use the binops to avoid auto-deref dereferencing too many
210+
// layers of pointers, if the type includes pointers.
211+
//
212+
let other_f = match (other_fs.len(), other_fs.get(0)) {
213+
(1, Some(o_f)) => o_f,
214+
_ => cx.span_bug(span, "not exactly 2 arguments in `derive(PartialOrd)`"),
215+
};
218216

219-
let deleg_cmp = if !equal {
220-
cx.expr_unary(span,
221-
ast::UnOp::Not,
222-
cx.expr_binary(span, op, other_f.clone(), self_f))
223-
} else {
224-
cx.expr_binary(span, BinOpKind::Eq, self_f, other_f.clone())
225-
};
217+
let strict_ineq = cx.expr_binary(span, strict_op, self_f.clone(), other_f.clone());
226218

227-
let and = cx.expr_binary(span, BinOpKind::And, deleg_cmp, subexpr);
228-
cx.expr_binary(span, BinOpKind::Or, strict_ineq, and)
229-
},
230-
cx.expr_bool(span, equal),
231-
Box::new(|cx, span, (self_args, tag_tuple), _non_self_args| {
232-
if self_args.len() != 2 {
233-
cx.span_bug(span, "not exactly 2 arguments in `derive(PartialOrd)`")
234-
} else {
235-
let op = match (less, equal) {
236-
(true, true) => LeOp,
237-
(true, false) => LtOp,
238-
(false, true) => GeOp,
239-
(false, false) => GtOp,
219+
let deleg_cmp = if !equal {
220+
cx.expr_unary(span,
221+
ast::UnOp::Not,
222+
cx.expr_binary(span, strict_op, other_f.clone(), self_f))
223+
} else {
224+
cx.expr_binary(span, BinOpKind::Eq, self_f, other_f.clone())
240225
};
241-
some_ordering_collapsed(cx, span, op, tag_tuple)
242-
}
243-
}),
244-
cx,
245-
span,
246-
substr)
226+
227+
let and = cx.expr_binary(span, BinOpKind::And, deleg_cmp, subexpr);
228+
cx.expr_binary(span, BinOpKind::Or, strict_ineq, and)
229+
},
230+
|cx, args| {
231+
match args {
232+
Some((span, self_f, other_fs)) => {
233+
// Special-case the base case to generate cleaner code with
234+
// fewer operations (e.g. `<=` instead of `<` and `==`).
235+
let other_f = match (other_fs.len(), other_fs.get(0)) {
236+
(1, Some(o_f)) => o_f,
237+
_ => cx.span_bug(span, "not exactly 2 arguments in `derive(PartialOrd)`"),
238+
};
239+
240+
let op = match (less, equal) {
241+
(false, false) => BinOpKind::Gt,
242+
(false, true) => BinOpKind::Ge,
243+
(true, false) => BinOpKind::Lt,
244+
(true, true) => BinOpKind::Le,
245+
};
246+
247+
cx.expr_binary(span, op, self_f, other_f.clone())
248+
}
249+
None => cx.expr_bool(span, equal)
250+
}
251+
},
252+
Box::new(|cx, span, (self_args, tag_tuple), _non_self_args| {
253+
if self_args.len() != 2 {
254+
cx.span_bug(span, "not exactly 2 arguments in `derive(PartialOrd)`")
255+
} else {
256+
let op = match (less, equal) {
257+
(false, false) => GtOp,
258+
(false, true) => GeOp,
259+
(true, false) => LtOp,
260+
(true, true) => LeOp,
261+
};
262+
some_ordering_collapsed(cx, span, op, tag_tuple)
263+
}
264+
}),
265+
cx,
266+
span,
267+
substr)
247268
}

0 commit comments

Comments
 (0)