Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
what is best in optimizer pipeline
value numbering
code motion
peepholing
loop idiom recognition
legalization
thread gassing
op banning
View Results
 
  • Locked thread
Star War Sex Parrot
Oct 2, 2003

compilers was a neat class I guess

maybe I'll take another one

Adbot
ADBOT LOVES YOU

Asymmetric POSTer
Aug 17, 2005

i love being close to the metal

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe

Shinku ABOOKEN posted:

what are phi nodes? why are they bad?

it's the dominant way of handling data flow when control flow merges in ssa

here's a dumb c program

C code:
int x;
if (whatever) {
  x = foo();
} else {
  x = bar();
}
baz(x);
in a more explicit representation that isn't yet in proper ssa form, this looks like:

code:
  if %whatever goto trueBlock else goto falseBlock
trueBlock:
  %fooResult = call @foo()
  store %fooResult to %x
  goto contBlock
falseBlock:
  %barResult = call @bar()
  store %barResult to %x
  goto contBlock
contBlock:
  %mergedValue = load %x
  call @baz(%mergedValue)
the purpose of ssa is to make this data flow explicit, i.e. we don't want to see this opaque load from a variable, we want to see the last value stored there. in a lot of cases, that's easy enough to do, but how do we talk about it after this kind of control-flow merge, where the value is different based on where we came from?

phi nodes are the dominant answer. a phi node is a sort of pseudo-instruction you can put at the start of a block when it has multiple predecessors like this, and it basically says what the value is when coming from all the predecessors:

code:
  if %whatever goto trueBlock else goto falseBlock
trueBlock:
  %fooResult = call @foo()
  goto contBlock
falseBlock:
  %barResult = call @bar()
  goto contBlock
contBlock:
  %mergedValue = phi %fooResult from trueBlock, %barResult from falseBlock
  call @baz(%mergedValue)
they suck because they're a weird orthogonal special case. they look like instructions, but they can only go at the start of a block, and the values they use are not normally valid to reference in the block. if you were writing some optimization involving calls to @foo, and you wanted to insert code everywhere the return value is used, you can't add it here; you have to recognize that the use is a phi node and put the code at the end of trueBlock instead

the way better alternative is to say that basic blocks can have parameters and gotos can have arguments, which ends up looking kindof like a functional program with a lot of explicit tail calls:

code:
  if %whatever goto trueBlock else goto falseBlock
trueBlock:
  %fooResult = call @foo()
  goto contBlock(%fooResult)
falseBlock:
  %barResult = call @bar()
  goto contBlock(%barResult)
contBlock(%mergedValue):
  call @baz(%mergedValue)

rjmccall fucked around with this message at 04:21 on Jun 28, 2017

redleader
Aug 18, 2005

Engage according to operational parameters
good thread op

why can't c/c++ compilers emit warnings when they encounter undefined behaviour? is it just that it's too hard to fit into current compiler architecture? would it be a useless thing to include because every program would be filled with undefined behavior?

Workaday Wizard
Oct 23, 2009

by Pragmatica

good and clear explanation 👍

thanks

Jabor
Jul 16, 2010

#1 Loser at SpaceChem

redleader posted:

good thread op

why can't c/c++ compilers emit warnings when they encounter undefined behaviour? is it just that it's too hard to fit into current compiler architecture? would it be a useless thing to include because every program would be filled with undefined behavior?

They can in many cases. But there are some categories of undefined behavior where the compiler just doesn't know if a particular construction is going to be undefined behavior in practice, and it's not reasonable to emit a warning in cases that may or may not be undefined behavior.

For example, it would not be useful if the compiler threw a "potentially undefined behavior" warning any time you did arithmetic on a signed value.

Malcolm XML
Aug 8, 2009

I always knew it would end like this.

rjmccall posted:

it's the dominant way of handling data flow when control flow merges in ssa

here's a dumb c program

C code:
int x;
if (whatever) {
  x = foo();
} else {
  x = bar();
}
baz(x);
in a more explicit representation that isn't yet in proper ssa form, this looks like:

code:
  if %whatever goto trueBlock else goto falseBlock
trueBlock:
  %fooResult = call @foo()
  store %fooResult to %x
  goto contBlock
falseBlock:
  %barResult = call @bar()
  store %barResult to %x
  goto contBlock
contBlock:
  %mergedValue = load %x
  call @baz(%mergedValue)
the purpose of ssa is to make this data flow explicit, i.e. we don't want to see this opaque load from a variable, we want to see the last value stored there. in a lot of cases, that's easy enough to do, but how do we talk about it after this kind of control-flow merge, where the value is different based on where we came from?

phi nodes are the dominant answer. a phi node is a sort of pseudo-instruction you can put at the start of a block when it has multiple predecessors like this, and it basically says what the value is when coming from all the predecessors:

code:
  if %whatever goto trueBlock else goto falseBlock
trueBlock:
  %fooResult = call @foo()
  goto contBlock
falseBlock:
  %barResult = call @bar()
  goto contBlock
contBlock:
  %mergedValue = phi %fooResult from trueBlock, %barResult from falseBlock
  call @baz(%mergedValue)
they suck because they're a weird orthogonal special case. they look like instructions, but they can only go at the start of a block, and the values they use are not normally valid to reference in the block. if you were writing some optimization involving calls to @foo, and you wanted to insert code everywhere the return value is used, you can't add it here; you have to recognize that the use is a phi node and put the code at the end of trueBlock instead

the way better alternative is to say that basic blocks can have parameters and gotos can have arguments, which ends up looking kindof like a functional program with a lot of explicit tail calls:

code:
  if %whatever goto trueBlock else goto falseBlock
trueBlock:
  %fooResult = call @foo()
  goto contBlock(%fooResult)
falseBlock:
  %barResult = call @bar()
  goto contBlock(%barResult)
contBlock(%mergedValue):
  call @baz(%mergedValue)

CPS >> SSA

redleader
Aug 18, 2005

Engage according to operational parameters

Jabor posted:

For example, it would not be useful if the compiler threw a "potentially undefined behavior" warning any time you did arithmetic on a signed value.

oh yeah, that's right

related (but possibly a little off topic) question: what's up with the c/c++ standards committees that makes them prefer undefined over implementation-defined behavior? i mean surely most compilers would know their target's behavior with (un)signed overflow (for example)

Chris Knight
Jun 5, 2002

me @ ur posts


Fun Shoe

they're coming to take away your child processes

Cocoa Crispies
Jul 20, 2001

Vehicular Manslaughter!

Pillbug

redleader posted:

oh yeah, that's right

related (but possibly a little off topic) question: what's up with the c/c++ standards committees that makes them prefer undefined over implementation-defined behavior? i mean surely most compilers would know their target's behavior with (un)signed overflow (for example)

undefined is implementation-defined

Phobeste
Apr 9, 2006

never, like, count out Touchdown Tom, man
how long before the embedded world gets first class cortex m-4 and subsequent support for building from llvm. also how long until i can stop having to loving compile cross compilers. these questions are probably linked

feedmegin
Jul 30, 2008

Writing compilers is fun I wrote a compiler and it taught me stuff

Captain Foo
May 11, 2004

we vibin'
we slidin'
we breathin'
we dyin'

compilers are black magic to me op

Cocoa Crispies
Jul 20, 2001

Vehicular Manslaughter!

Pillbug

Captain Foo posted:

compilers are black magic to me op

write one to disabuse yourself of that notion

Workaday Wizard
Oct 23, 2009

by Pragmatica

Phobeste posted:

how long before the embedded world gets first class cortex m-4 and subsequent support for building from llvm. also how long until i can stop having to loving compile cross compilers. these questions are probably linked

there is a demo for Rust on Cortex M-4 so I'm going to assume llvm already supports it
https://github.com/antoinealb/rust-demo-cortex-m4

Captain Foo
May 11, 2004

we vibin'
we slidin'
we breathin'
we dyin'

Cocoa Crispies posted:

write one to disabuse yourself of that notion

absolutely not
i don't even program

The Management
Jan 2, 2010

sup, bitch?

Phobeste posted:

how long before the embedded world gets first class cortex m-4 and subsequent support for building from llvm. also how long until i can stop having to loving compile cross compilers. these questions are probably linked

if by first class you mean broken every other day then m4 is fully supported.

what's the alternative to compiling cross compilers? you just want to download a binary that builds for EVERYTHING?

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe
in theory clang is a natural cross compiler and can in fact just generate code for anything. you do have to tell the build system to link in an appropriate backend, though, which is reasonable because backends get pretty big. but it's not like gcc where you need a different binary for every target

Deep Dish Fuckfest
Sep 6, 2006

Advanced
Computer Touching


Toilet Rascal

rjmccall posted:

having a jit enables some really neat dynamic code generation and specialization tricks. i'd love to see more language implementations based on a sane language + execution environment that really take intelligent advantage of both static and dynamic information

instead it feels like jits always spend the bulk of their effort (both in development and at runtime) working around stupidity in the language / runtime model. "i couldn't possibly statically inline this trivial getter, it's in a different class file" :monocle:

how good is modern jitted code compared to what's emitted by a traditional toolchain these days anyway? i've heard about the ability to use info you don't have at compile time to potentially produce better code before, but i have no idea how much of a difference it makes in practice. or any idea what traditional optimizations aren't possible when you're jitting, if any

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe

redleader posted:

related (but possibly a little off topic) question: what's up with the c/c++ standards committees that makes them prefer undefined over implementation-defined behavior? i mean surely most compilers would know their target's behavior with (un)signed overflow (for example)

implementation-defined behavior still has to be semantically well-defined: that is, the implementation has to define exactly what happens. the vast majority of undefined behavior is not this kind of "policy" stuff where that's possible

for example, dereferencing a bad pointer is undefined behavior because there's no reasonable way for the implementation to dynamically determine pointer validity; it would need to track pointers and scopes and allocations and issue a ton of checks and it would all be obscenely expensive and constraining. in theory you could define the results of dereferencing a null pointer to always be a guaranteed trap, but that would force null checks on every access on targets that can't guarantee an unmapped address (which is almost all of them, because many oses do allow you to mmap the zero page)

in the policy places, it usually comes down to optimizability. these rules are designed so that the compiler doesn't have to pessimize behavior just to handle some corner case that, in the committee's judgement, shouldn't be happening in a sensible program. for example, the type aliasing rules are there so that the compiler isn't blocked from doing straightforward memory optimizations out of paranoia that you might have cast the same pointer to different types. the signed-int overflow rules are there so that the compiler can ignore the overflow-related corner cases when looking at an idiomatic for-loop. and so on

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe

you should read the spj paper linked from the tweet in the op

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe

Deep Dish Fuckfest posted:

how good is modern jitted code compared to what's emitted by a traditional toolchain these days anyway? i've heard about the ability to use info you don't have at compile time to potentially produce better code before, but i have no idea how much of a difference it makes in practice. or any idea what traditional optimizations aren't possible when you're jitting, if any

there are a ton of trade-offs around jits, it's really super dependent on the language and the runtime environment

if the language does a lot of dispatch based on the dynamic types of values, like virtual method calls or the overloaded behavior of + in javascript, then jits have the massive natural advantage of being able to dynamically specialize the code for the types that are actually seen. like if the code is "for (i in array) { result += array[i] }" and dynamic sampling suggests that the values in the array are always integers then the jit might generate machine code for this loop where result is actually an integer variable and the loop body does a type check and an overflow check and just bails out to an interpreter if something weird ever happens

even more static languages can end up with a lot of dynamic-seeming behavior because of the build model. like how java class files are meant to each be a kind of miniature dynamic library with its own stable abi w.r.t other classes (other than static final ints), so the jit is actually the first thing that's allowed to do cross-class optimization. or like how the language lets you always link in more code in java / c++, and that code might subclass some class or implement some interface, so you can't statically do an exhaustive class hierarchy analysis (e.g. to devirtualize calls to some method that in practice is never overridden); but a jit can optimistically devirtualize based on the code it sees as long as it has the ability to change its mind later

or you can decide based on the dynamic profile of your program that it's totally worth unrolling / vectorizing this loop but not these other ones

on the other hand none of this dynamic profiling is free and it takes a lot of time + power for it to pay for itself and generally some residue of it sticks around even after specialization. and it's usually the case that profiles don't vary that much from execution to execution, so there's no inherent reason you couldn't generate a good-enough static profile using a representative workload and then do all the same optimizations based on that

the other thing a jit gets you is the ability to optimize for an exact target. like if you statically compile for a wide class of machines, you have to either make pessimal assumptions about the hardware or do a bunch of runtime checks. or if you statically compile for a range of runtime-system releases, you have to perform opaque runtime calls in order to allow details of the runtime system to change. the former is generally not that big of a problem, but the latter can add up to a lot of overhead, especially if you're automatically managing memory. garbage collectors in particular want to change code-generation patterns in like a thousand different places, and the changes they make are very specific to the gc algorithm in use, so if you're generating code for an unknown gc algorithm you basically have to emit every single store of an object pointer as an opaque call into the runtime and it's just murderously slow. even with reference-counting the overhead of having to call the runtime really adds up

Symbolic Butt
Mar 22, 2009

(_!_)
Buglord
I'm doing surgery tomorrow and I'll have to stay home for a while so I'll do this: http://compilers.iecc.com/crenshaw/ :getin:

Malcolm XML
Aug 8, 2009

I always knew it would end like this.

rjmccall posted:

you should read the spj paper linked from the tweet in the op

yeah but equivalent doesn't mean better than

continuations for life

Malcolm XML
Aug 8, 2009

I always knew it would end like this.

rjmccall posted:

you should read the spj paper linked from the tweet in the op

but that paper is cool


https://www.microsoft.com/en-us/research/wp-content/uploads/2016/11/join-points-pldi17.pdf

DONT THREAD ON ME
Oct 1, 2002

by Nyc_Tattoo
Floss Finder
i'm currently writing a toy language interpreter in rust and once im done with that i might try doing a lisp or maybe take a crack at writing a bad c compiler

Malcolm XML
Aug 8, 2009

I always knew it would end like this.
peep my neg hole

Cybernetic Vermin
Apr 18, 2005

MALE SHOEGAZE posted:

i'm currently writing a toy language interpreter in rust and once im done with that i might try doing a lisp or maybe take a crack at writing a bad c compiler

i myself just had a cup of coffee, am pondering perhaps brewing up a fancier pot later, and am considering going on to establish the first hydroponic coffee bean farm on mars

Deep Dish Fuckfest
Sep 6, 2006

Advanced
Computer Touching


Toilet Rascal

thanks for this, i like compilers but i've never had much experience with them beyond using them

the part about optimizing for a specific platform did remind me of the hell of debugging optimized code on some game consoles though. under most circumstances you can just use a debug build, but when you're mostly doing network stuff, everything's asynchronous and bugs depend on timing, so whatever you want to reproduce tends to just disappear on a debug build. symbols don't mean much for optimized code, so you're stuck looking at the disassembled executable. and holy poo poo do console compilers/linkers love to emit the most hosed up spaghetti hell garbage. i mean, i get why they do that, but it makes you long for the simple optimized x64 assembly you get on pc

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe

Malcolm XML posted:

yeah but equivalent doesn't mean better than

continuations for life

i too recommend using intermediate representations that actively make it more difficult to perform important optimizations

my homie dhall
Dec 9, 2010

honey, oh please, it's just a machine
wish I knew what compilers do

Gazpacho
Jun 18, 2004

by Fluffdaddy
Slippery Tilde
They pile com

JewKiller 3000
Nov 28, 2006

by Lowtax
you didn't answer my hard question so here's another easy one: to compile a compiler, do you need a compiler compiler? if so, how do you compile the compiler compiler?

Star War Sex Parrot
Oct 2, 2003

JewKiller 3000 posted:

you didn't answer my hard question so here's another easy one: to compile a compiler, do you need a compiler compiler? if so, how do you compile the compiler compiler?
with a compiler

Asymmetric POSTer
Aug 17, 2005

JewKiller 3000 posted:

you didn't answer my hard question so here's another easy one: to compile a compiler, do you need a compiler compiler? if so, how do you compile the compiler compiler?

lol if you don't handcraft each individual bit in your binaries

RISCy Business
Jun 17, 2015

bork bork bork bork bork bork bork bork bork bork bork bork bork bork bork bork bork bork bork bork bork bork bork bork bork bork bork bork bork bork bork bork bork bork bork bork bork bork bork bork bork bork bork bork bork bork bork bork bork bork bork bork bork bork bork bork bork bork bork bork
Fun Shoe
who delivers the mailman's mail

Gazpacho
Jun 18, 2004

by Fluffdaddy
Slippery Tilde
yosproject: successfully toggle a program that beeps into an x86 using a manually switched JTAG fixture

Perplx
Jun 26, 2004


Best viewed on Orgasma Plasma
Lipstick Apathy

JewKiller 3000 posted:

you didn't answer my hard question so here's another easy one: to compile a compiler, do you need a compiler compiler? if so, how do you compile the compiler compiler?

pen and paper

echinopsis
Apr 13, 2004

by Fluffdaddy

RISCy Business posted:

who delivers the mailman's mail

a different meilman

Adbot
ADBOT LOVES YOU

hifi
Jul 25, 2012

JewKiller 3000 posted:

you didn't answer my hard question so here's another easy one: to compile a compiler, do you need a compiler compiler? if so, how do you compile the compiler compiler?

go just has a requirement of go 1.4 which was the last one you could traditionally compile.

i remember reading an article about what would we do if all the hard drives everywhere were wiped but i can't find it

  • Locked thread