7 ms·
> According to the Intel optimization manual, using EBP, RBP, or R13 as the base address will make LEA slower. No, that's not what was written there. The manua
by acqq 7y ago
> According to the Intel optimization manual, using EBP, RBP, or R13 as the base address will make LEA slower.
No, that's not what was written there. The manual is clear:
For LEA instructions with three source operands and some specific situations, instruction latency has
increased to 3 cycles" where one of these spcific situations is: "LEA that uses base and index registers where the base is EBP, RBP, or R13."
Note "with three source operands" and "uses base and index" as in "both at the same time." So it's not enough that LEA just "uses EBP, RBP or R13."
LEA is often used, and often used with EBP/RBP. It wouldn't be in Intel's interest to harm common uses (the existing already compiled code base).
If you care about how long which instruction takes in order to make some implementation decisions, the article just too misleading when it talks about the LEA.
- BeeOnRope 7y agoIt's not clear and you are not correct in this case – at least per the actual behavior, and I assume the intent of the manual (but of course we can argue about whether the item is well-written). The list given in that item is "or", i.e., if any of those conditions apply, you get the slow lea. The prose isn't giving additional conditions, it is just summarizing the list (although I can determine that not by careful parsing of the prose but rather because it's the only way the thing makes sense).
- acqq 7y agoNo, it's clear, especially if you'd know what it is about (BP is used in various calling conventions, so it has to be fast in common cases). That the list there is OR doesn't make every LEA which uses BP slow, as the article claims. Only LEAs which use both BP and the index registers at the same time (or the three operand LEA variants) are "slow". It's documented in the said Intel's manual, even with the examples. One can write a lot of LEAs without three operands or without index register and of course use {E,R}BP in them without any issue. The relevant section from which the article took the material but made wrong conclusion is: "3.5.1.2 Using LEA"
- BeeOnRope 7y agoMaybe I misunderstood your claim. I thought your claim was that the LEA needs to be three operand plus satisfy one of the claims in the list? If you are just saying that the issue is that the author says "ebp as base" rather than "ebp as base in an indexed addressing mode", then I agree.
- acqq 7y ago> If you are just saying that the issue is that the author says "ebp as base" rather than "ebp as base in an indexed addressing mode" Correct. I specifically wrote "One can write a lot of LEAs without three operands or without index register and of course use {E,R}BP in them without any issue." Even if "OR" list notes that some uses of LEA are slower (actually, if I would say, with "higher latency"), LEA with BP is still too useful to reduce the logic to the article's claim: "using EBP, RBP, or R13 as the base address will make LEA slower." No it won't for enough cases where it's important to use it. I didn't even address the topic that higher latency doesn't even have to mean that the throughput is reduced at all, when the rest of the code fits. But even at the low level of precision of the article, it's still a wrong claim, that what's written in that sentence. It's just a detail, but at this level (of caring about which instruction to use where), everything is exactly about the details.
- BeeOnRope 7y agoYes, the author should have made it clear that the slow LEA caveat only applies to the indexed addressing case. I probably misunderstood what you were saying here: > Note "with three source operands" and "uses base and index" as in "both at the same time." When you said "both" I thought you were referring to both clauses you mentioned ("3-arg" and "base and index"), but I see now you may have saying both base and index (it was the mention of 3-arg that threw me off). Slow LEA is slower in a throughput sense too: half the throughput on modern mainstream Intel except Ice Lake. > I didn't even address the topic that higher latency doesn't even have to mean that the throughput is reduced at all, when the rest of the code fits. Agreed, but that's true of almost any fine-granied performance discussion ever. I think it's fine to say that a LEA with half the throughput and triple the latency is slower in a sense, even though "in-situ" there may be plenty of cases where it makes no measurable difference. The same is true of other slow stuff like muls, divs, branch mispredictions, atomic ops: there are cases where all of those don't matter (not just in an approximate sense, as in "the penalty is zero"). You are not wrong but always putting that caveat gets tiring, it would be nice if we could just assume it. Beyond that, almost any use of a "slower" instruction can actually speed things up, e.g. due to an alignment or scheduling effect, but man I don't want to mention that every time either. As a practical matter, few people have the capability to mentally simulate the pipeline to determine whether slow LEA is going to have an impact or not (and this is error prone and in any case not all the details are out there to do it totally accurately. So the problematic r13/rbp cases are mostly easy to avoid, just avoiding them seems like reasonable advice.
- CalChris 7y agoMoreover, the 3 operand case is the slow path for LEA and then there's only 1 execution port for it on Skylake, Port 1, vs 2 ports for fast LEAs. The slow path is 3 cycles vs fast path's 1 cycle: Intel even recommends: Assembly/Compiler Coding Rule 30. (ML impact, L generality) If an LEA instruction using the scaled index is on the critical path, a sequence with ADDs may be better. As to the article, partial register stalls aren't that bad on modern CPUs, not 5-6 cycles. And CFLAG bits get renamed. I think the article gets at that. Basically, anything which sticks out in a real benchmark gets hammered down and optimized by Intel.
- userbinator 7y agoThe source of the confusion is because a lot of assemblers will let you write [EBP+reg] or even just [EBP] (and disassemblers may correspondingly show those forms) but that's not how it's actually encoded; since the days of the 8086 (and BP, 16 bits) it was intended that BP would always be used with an offset to access memory in a stack frame (hence it uses the SS: segment by default), and thus the position in the encoding for BP without an offset was instead used for absolute addressing. This tradition continued in the 32-bit and now 64-bit (where R13 is the "high REX" of RBP), thus if you write [EBP+ECX], it actually gets encoded as [EBP+ECX+0]. There's the third operand --- it's just "hidden". Hence the somewhat misleading wording of that advice.
- acqq 7y ago> thus if you write [EBP+ECX], it actually gets encoded as [EBP+ECX+0]. And that's not as important as you make it appear. If you write [EBP + 24] (where the index register is simply not used), do you think that's a "slow" LEA? The [EBP + 24] form is what my (and I guess most of other's) compiler produced most of the time. Open any program with disassembler and try to count how often index register is ever used with EBP, and how often no index register is used. Former happens practically never, the later (no index) is very common.