Do we know that? I've written "dead" code. It's point was to communicate structure or intent, but it was also still dead. This pattern, in one form or another, crops up a lot IME (in multiple languages, even, with varying abilities to optimize it):
if condition that is "always" false:
abort with message detailing the circumstances
That `if` is "dead", in the sense that the condition is always false. But "dead" sometimes is just a proof — or if I'm not rigourous enough, an assumption — in my head. If the compiler can prove the same proof I have in my head, then the dead code is eliminated. If can't, well, presumably it is left in the binary, either to never be executed, or to be executed in the case that the proof in my head is wrong.
What about assertions that are meant to detect bad hardware? I'd think that's not too uncommon, particularly in shops building their own hardware. Noise on the bus, improper termination, ESD, dirty clock signal, etc. -- there are a million reasons why a bit might flip. I wouldn't want the compiler to optimize "obviously wrong" code out anymore then empty loops.
I think if you're in a language that's doing constant-propagation optimizations, you work around that in one of two ways:
1. you drop down to assembly.
2. you use functions that are purpose built to be sequence points the optimizer won't optimize through. E.g., in Rust, for the case you mention, `read_volatile`.
In either case, this gives the human the same benefit the code is giving the optimizer: an explicit indication that this code that might appear to be doing nothing isn't.
Some conditions depend strictly on inputs and the compiler can't reason much about them, and the developers can't be sure about what their users will do. So that pattern is common. It's a sibling of assertions.
There are even languages with mandatory else branch.
Why is that a problem? Inlining and optimization aren't minor aspects of compiling to native code, they are responsible for order-of-magnitude speedups.
My point is that it is easy to say "don't remove my code" while looking at a simple single-function example, but in actual compilation huge portions of a function are "dead" after inlining, constant propagation and other optimizations: not talking anything about C-specific UB or other shenanigans. You don't want to throw that out.
Apologies for the flippant one liner, You made a good point and deserve more than that.
On the one hand, having the optimizer save you from your own bad code is a huge draw, this is my desperate hope with SQL, I can write garbage queries and the optimizer will save me from myself.
But... Someone put that code there, spent time and effort to get that machinery into place with the expectation that it is doing something. and when the optimizer takes that away with no hint. That does not feel right either. Especially when the program now behaves differently when "optimized" vs unoptimized.
What I mean is that we look at a function in isolation and see that it doesn't have any "dead code", e.g.,:
int factorial(int x) {
if (x < 0) throw invalid_input();
// compute factorial ...
}
This doesn't have any dead code in a static examination: at compilation-time, however, this function may be compiled multiple times, e.g., as factorial(5) or factorial(x) where x is known to be non-negative by range analysis. In this case, the `if (x < 0)` is simply pruned away as "dead code", and you definitely want this! It's not a minor thing, it's a core component of an optimizing compiler.
This same pruning is also responsible for the objectionable pruning away of dead code in the examples of compilers working at cross-purposes to programmers, but it's not easy to have the former behavior without the latter, and that's also why something like -Wdead-code is hard to implement in a way which wouldn't give constant false-positives.
Removing unused inlined functions or false constexpr's is trivial to see. We already have -Winline. We care about removed branches, exprs and stmts due to some optimizer logic.
I'm talking about the optimizer, not the linker, which thanksfully does a lot of pruning.
> Compiler controlled memory: There is a mechanism in the processor where frequently accessed memory locations can be as fast as registers. In Figure 2, if the address of u is the same as x, then the last load μ-op is a nop. The internal value in register r25 is forwarded to register r28, by a process called write-buffer feedforwarding. That is to say, provided the store is pending or the value to be stored is in the write-buffer, then loading form a memory location is as fast as accessing external registers.
I think it over-sells the benefit. Store forwarding is a thing, but it does not erase the cost of the load or store, at least certainly on the last ~20 years of chips and I don't think on the PII (the target of the paper) either.
The load and store still effectively occur in terms of port usage, so the usual throughput, etc, limits apply. There is a benefit in latency of a few cycles. Perhaps also the L1 cache access itself is omitted, which could help for bank conflicts, though on later uarches there were few to none of these so you're left with perhaps a small power benefit.
More registers leads to less spilling not more, unless the compiler is making some really bad choices.
Any easy way to see that is that the system with more registers can always use the same register allocation as the one with fewer, ignoring the extra registers, if that's profitable (i.e. it's not forced into using extra caller-saved registers if it doesn't want to).
Yes, the argument for increasing the number of GPRs is precisely to eliminate the register spilling that in necessary in x86-64 programs whenever a program has already used all available architectural registers, a register spilling that does not happen whenever the same program is compiled for Aarch64 or IBM POWER.
While Walmart has historically denied using "individualized" pricing (charging two people different prices for the exact same item based on their income), they do use behavioral targeting [1]
Members of Walmart+ often see different "final" prices due to exclusive discounts, rewards (Walmart Rewards), or waived shipping/delivery fees that aren't available to guest users. Walmart uses AI to offer personalized promotions. You might see a "Rollback" or a "Just for You" offer on an item you’ve viewed multiple times or purchased previously, effectively changing the price for you specifically via a targeted discount. Like many e-commerce giants, Walmart may also offer "first-time app user" discounts or "win-back" coupons to specific customer segments.
The pre-commit tool (which prek is based on) has a large ecosystem of off the shelf checks for various language linters and other checks and a convenient way of writing them (including working out which files have changed and which checks to run based off of that)
The benefit to many of having them as a hook is that you discover it's broken before you pushed your changes, and not when you finally get around to checking the CI on your branch and realising it failed after 30s.
There is of course no reason why you have to have it installed as a precommit hook - many people prefer to run it manually, and the pre-commit tool/prek allows for that.
If you had a shell script hook, yes you would also run that in CI.
Are you asking what advantage pre-commit has over a shell script?
Mostly just functionality: running multiple hooks, running them in parallel, deciding which hooks to run based on the commit files, "decoding" the commit to a list of files, offering a bunch canned hooks, offering the ability to write and install non-shell hooks in a standard way.
The point is enforcement. If there's a newcomer to developing your repo, you can ask them to install the hooks and from thereon everything they commit will be compatible with the processes in your CI. You don't need to manually run the scripts they'll run automatically as part of the commit or push or whatever process
Critical section was IIRC built on top of windows manual/auto reset events which are a different primitive useful for more than just mutex but without the userspace coordination aspect (32 bit value) of futexes.
What is the point of the intent entry at all? It seems like operations are only durable after the completion record is written so the intent record seems to serve no purpose (unless it is say much larger).
reply