Live data from Hacker News

Is This a Branch?

bartwronski.com

61–70 of 78 posts

Re: Is This a Branch?

#61
Testing with only one if statement is not convincing at all.

I'm pretty sure that once you have a couple of mixes and steps etc., the branch prediction becomes exponentially harder and you are better off with the one line mixes, step, clamps etc. In general, from experience writing a lot of shaders, I want to avoid if statements, function calls and most importantly loops.

Now maybe if statements are efficient in some conditions, but if you want to add new details to the same shader some months later, you can't be sure the generated instructions and branch prediction will be as efficient.

There is also coding style: Id rather stick to a bunch of mixes, steps and clamps than a salad of mixes, steps and clamps with some multiline if statements in between.

Re: Is This a Branch?

#62

Earlier quoted context omitted.

I don't want to come of as insensitive, it sounds like you've had some really bad experiences with ternaries in the past and it's important to acknowledge your experience. But I just want to say that not all ternaries are like that. In a more serious tone, ternaries in places where they should be used, i.e. as expressions, are in my opinion much clearer to read than replacing them with an if-else statement. In my min…

> In my mind, an if/else block is an imperative entity that describes two different actions that could happen. Even if in reality both branches are trivial, my mind will be unnecessarily occupied with the fact that it needs to reason about code here, not just data That's true in some languages. But in some languages if-else can also be used as in expression. e.g. in Rust I can write: let foo = if condition { "FOO" }…

... which is equivalent to a ternary, hence the thesis.

Re: Is This a Branch?

#63
post #58
post #46

Earlier quoted context omitted.

This is one things I like so much about SBCL, it not only compiles the Lisp code directly to native code, with the disassemble function you can print out the generated code for each function to see how much the compiler was able to optimize a function. This is especially important in the context of dynamic languages to see where generic operators have to be called and where the type inferencer was able to compile it…

Many Lisp compilers do that. What makes SBCL special is a) using type information as compile-time assertions and b) the level of diagnostic output during compilation. The compiler explains in detail when operations can't be optimized further, for example because of lack of type information.

Well, yes. How SBCL uses the type annotations as well as type inferencing to completely eliminate type checking throughout sections of code and generating highly efficient assembly code makes looking at the assembly output of SBCL especially interesting to look at. It gives you good feedback whether your type annotations had the desired optimization outcomes. I didn't want to indicate that other Lisp implementations wouldn't offer native compilation or a disassemble function.

Re: Is This a Branch?

#64
post #33

Earlier quoted context omitted.

I've been messing around with some code that uses: #define TERN(c, a, b) c ? a : b I'm not a fan of ternaries, but that macro makes it kind of more ligible.

I don't advocate the use of this macro, but if you do use it you should really wrap the parameters and the whole expression in parentheses to avoid precedence issues: #define TERN(c, a, b) ((c) ? (a) : (b))

Exactly, this is C macro 101.

Re: Is This a Branch?

#65
post #56

Earlier quoted context omitted.

I've been designing a programming language where nothing is a side-effect – including calling conventions, processor caches, branch predictors, locks, graphics modes, etc.. “Runtime has to be independent of the value of the input” would be how that language expresses "constant time" – and it would take into account every part of the compiler's model of the target architecture (which, by the way, is also described in…

> processor caches, branch predictors You can't "take this into account" because it requires state that isn't visible to you and also requires you to know the design of future hardware!

It requires state that can be inferred and manipulated. For the cache, assuming you know how large the cache is, you can just fill up the cache with useless pages, evicting whatever might be vulnerable to a timing attack, before having it loaded back in. Very slow, but it works. (You might be able to get away with less, depending on the OS's guarantees and what you can assume about how your program will run – and the language requires you to make those assumptions explicit, even if it's a case of "assume this manually-written assembly does the right thing without violating any invariants".)

Yes, these tricks don't have forwards-compatible guarantees in the general case – but if the processor manufacturer makes guarantees about all members of a family, then you can optimise to those, and in any case having something that provably works in all supported processors (and can be ported to later processors if necessary, just by using an extra library (if the library is correct)) is still useful.

Re: Is This a Branch?

#66

Earlier quoted context omitted.

Meh. When sufficiently terse, ternary expressions are frequently more readable than a more verbose if/else equivalent. I would agree that ternaries can get out of hand quickly though.

What (besides the words if and else and the curly braces) makes the if/else equivalent more verbose)?

In C and C++, ternaries are frequently used on the right hand side of an assignment statement. if/else can't be used in such a context.

Here's a concrete example:

    const int min = x 
Note also that this prevents variable min from being made const, unless you are using c++ and wrap the entire if/else in an immediately invoked lambda, which of course would require additional verbosity.

Re: Is This a Branch?

#68
post #47

Earlier quoted context omitted.

This sounds tempting, but it would trigger a wave of unreadable, irrelevant micro optimization by many programmers. If you have a desired assembly result, write it yourself in the first place. The one concession to this I would like is a "constant time" marker for cryptography functions where it is an absolutely critical property that there be no data dependant branches. (This is a little different on GPUs where bran…

I've been designing a programming language where nothing is a side-effect – including calling conventions, processor caches, branch predictors, locks, graphics modes, etc.. “Runtime has to be independent of the value of the input” would be how that language expresses "constant time" – and it would take into account every part of the compiler's model of the target architecture (which, by the way, is also described in…

Unless I’m misunderstanding your point, I don’t think what you want is possible, due to microcode. You give the AMD/Intel/Arm/etc platform some instructions to execute, and then they execute it in ways that are not guaranteed to stay the same, between microcode updates and between hardware revisions. The only guarantee is that the results you get should be the same as if the instructions you requested were executed in the order you requested them.

Re: Is This a Branch?

#69

Earlier quoted context omitted.

Yes, the : and ? are single characters that are easily lost/overlooked among the rest of the code on that line. Even worse when there are nested ternaries.

When I find a place where a complex ternary is probably the best choice, I'm a big fan of the following format, because I find it clear that each line is a new condition myvar = condition_1 ? value_1 : condition_2 ? value_2 : condition_3 ? value_3 : value_fallback;

And, to illustrate my point, hypothetical "if statement is also conditional expression" syntax, to illustate how much more readable "ifs" are than "?:":

  myvar = if(condition_1) {value_1}
      else if(condition_2) {value_2}
      else if(condition_3) {value_3}
      else {value_fallback};

Re: Is This a Branch?

#70
post #31

Earlier quoted context omitted.

We're talking C. As soon as a ternary calls a function, all bets are off what could be happening in addition to the value being computed. And thanks to the preprocessor, any identifier could potentially be calling a function.

Hmm? Which part implies “all bets are off”? There’s the condition (evaluated first), the true case and the false case. Only one of the cases is evaluated. I’m assuming you were alluding to some sort of “ x++ = x++ * *x++” style situation, but the ternary expression isn’t a statement and there are sequence points in between. As a bonus, the first result for “ternary operator evaluation order” gave me someone who linke…

I was not thinking about local state; you're right that the sequence points ensure an orderly evaluation there.

My point was that since ternaries can call functions, and functions can have side effects on global state, the concept of an "if" being a "statement" vs a ternary being an "expression / value" is not nearly as meaningful as it's made out to be. A ternary can trade stocks, fire a 500W laser, unlock a velociraptor enclosure, etc, just as easily as an if can.

Post reply on HN