LLVM Coding Standards
spir
denis.spir at gmail.com
Mon Apr 11 12:58:57 PDT 2011
[slightly OT]
Hello,
I'm reading (just for interest) the LLVM Coding Standards at
http://llvm.org/docs/CodingStandards.html. Find them very interesting because
their purposes are clearly explained. Below sample.
Denis
=== sample ===================================
Use Early Exits and continue to Simplify Code
When reading code, keep in mind how much state and how many previous decisions
have to be remembered by the reader to understand a block of code. Aim to
reduce indentation where possible when it doesn't make it more difficult to
understand the code. One great way to do this is by making use of early exits
and the continue keyword in long loops. As an example of using an early exit
from a function, consider this "bad" code:
Value *DoSomething(Instruction *I) {
if (!isa<TerminatorInst>(I) &&
I->hasOneUse() && SomeOtherThing(I)) {
... some long code ....
}
return 0;
}
This code has several problems if the body of the 'if' is large. When you're
looking at the top of the function, it isn't immediately clear that this only
does interesting things with non-terminator instructions, and only applies to
things with the other predicates. Second, it is relatively difficult to
describe (in comments) why these predicates are important because the if
statement makes it difficult to lay out the comments. Third, when you're deep
within the body of the code, it is indented an extra level. Finally, when
reading the top of the function, it isn't clear what the result is if the
predicate isn't true; you have to read to the end of the function to know that
it returns null.
It is much preferred to format the code like this:
Value *DoSomething(Instruction *I) {
// Terminators never need 'something' done to them because ...
if (isa<TerminatorInst>(I))
return 0;
// We conservatively avoid transforming instructions with multiple uses
// because goats like cheese.
if (!I->hasOneUse())
return 0;
// This is really just here for example.
if (!SomeOtherThing(I))
return 0;
... some long code ....
}
This fixes these problems. A similar problem frequently happens in for loops. A
silly example is something like this:
for (BasicBlock::iterator II = BB->begin(), E = BB->end(); II != E; ++II) {
if (BinaryOperator *BO = dyn_cast<BinaryOperator>(II)) {
Value *LHS = BO->getOperand(0);
Value *RHS = BO->getOperand(1);
if (LHS != RHS) {
...
}
}
}
When you have very, very small loops, this sort of structure is fine. But if it
exceeds more than 10-15 lines, it becomes difficult for people to read and
understand at a glance. The problem with this sort of code is that it gets very
nested very quickly. Meaning that the reader of the code has to keep a lot of
context in their brain to remember what is going immediately on in the loop,
because they don't know if/when the if conditions will have elses etc. It is
strongly preferred to structure the loop like this:
for (BasicBlock::iterator II = BB->begin(), E = BB->end(); II != E; ++II) {
BinaryOperator *BO = dyn_cast<BinaryOperator>(II);
if (!BO) continue;
Value *LHS = BO->getOperand(0);
Value *RHS = BO->getOperand(1);
if (LHS == RHS) continue;
...
}
This has all the benefits of using early exits for functions: it reduces
nesting of the loop, it makes it easier to describe why the conditions are
true, and it makes it obvious to the reader that there is no else coming up
that they have to push context into their brain for. If a loop is large, this
can be a big understandability win.
========================================
--
_________________
vita es estrany
spir.wikidot.com
More information about the Digitalmars-d
mailing list