1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
//! `__builtin_expect` and `__builtin_expect_with_probability`, which are their first argument.
//!
//! Design: `spec/13-gnu-compat.md` section 13.5.
//!
//! These two say which way a branch is expected to go. The value of `__builtin_expect(x, c)` is
//! `x`, and everything after the first argument is a hint about how often that value will turn out
//! to be `c`. So the answer is the first argument, and the hint is dropped here because there is
//! nothing yet that could read it: branch weights arrive with the optimizer, and until then a node
//! carrying one would be a node every pass has to step over for no gain. `Opcode::Expect` is in the
//! IR waiting for that day.
//!
//! # Why this is not a link error, which is what it was
//!
//! A builtin nothing lowers reaches the assembler as a call to a name no object file defines, and
//! this is the one where that matters most. glibc's `<stdio.h>` writes `getc_unlocked` and its
//! neighbours as extern inline functions in terms of `__builtin_expect` as soon as `__OPTIMIZE__`
//! is set, so before this every program that included that header, called one of those functions
//! and asked for `-O1` failed to link on a name it never wrote. The wider defect, which is that any
//! unimplemented builtin does this rather than saying so, is tamnd/rucc#303.
//!
//! # Why the answer is taken after the call is checked and not before
//!
//! The families next door are recognised before the callee is looked up, because their type comes
//! out of the call and there is no prototype to check them against. These two have one:
//! `long(long, long)` in `features.toml`, which is what gcc gives them, and it is worth keeping.
//! It is where the argument count message comes from, it is what converts the first argument to
//! `long` so that `sizeof(__builtin_expect((char)1, 1))` is eight the way gcc has it, and it is
//! what reports a structure handed to the first parameter in the ordinary words. All of that would
//! have to be written again here to gain nothing.
//!
//! So the call is checked the whole ordinary way and the node is replaced at the end of it. What
//! that costs is that the arguments after the first are checked and then dropped, so a side effect
//! in one does not happen. That is what gcc does with them as well: `__builtin_expect(5, side())`
//! never calls `side`, measured on gcc 16.2.0.
use Symbol;
use Span;
use crateChecker;
use crateExprId;
/// The names whose value is their first argument.
///
/// Both are rows of `features.toml` with a signature, which is what makes them ordinary calls up
/// to the point this replaces them, and the test at the bottom of this file is what keeps the two
/// lists from drifting apart.
const FAMILY: & = &;