Return Styles: Pseud0ch, Terminal, Valhalla, NES, Geocities, Blue Moon. Entire thread

Any decent modern general-purpose languages?

Name: Anonymous 2012-07-25 10:55

Assembly: Unportable. No standardised syntax.
Classical Visual Basic: Some good parts. Shit overall.
C: Shitty standard library. Deficient type system. Can't into Unicode. ``Unportable assembly.''
D and C++: Obfuscated boilerplate languages.
Java and C#: Forced OOP.
Common Lisp: Archaic cons-based library. Writing complex macros is a PitA due to the unlispy quotation syntaxes.
Scheme: CL without namespaces.
Clojure and Erlang: Concurrency is unneeded outside of a few very specific applications. Parallelism is where it's at.
OCaml: Great language, only one, deficient, implementation.
Haskell: Academic sex toy.
Forth: Reinventing the wheel over and over.
Ruby: Implicit declarations. Slow as fuck.
Python: Implicit declarations. FioC.
Perl: Brain damage.
PHP: Pretty much shit.
JavaScript: "" == false

It's impossible to list them all but, please, what decent modern general-purpose languages exist?

Name: Anonymous 2012-07-28 19:04

>>84
>You find a more clever solution than the ASM output
>encouraging people to be clever
get out

Name: Anonymous 2012-07-28 19:27

>>124
>encouraging people to be stupid
get out

Name: Anonymous 2012-07-28 20:22

>>125
>>124-san has a point. “Clever” designs suffer from not-invented-here syndrome more often, i.e. more bugs and less support. Masters don't only know how but when they use each tool.

Name: Anonymous 2012-07-28 21:37

01111111 GET

Name: Anonymous 2012-07-28 21:46

2^7 ``GET''!

Name: Anonymous 2012-07-28 23:39

>>127
299593 GET? wtf

Name: Anonymous 2012-07-28 23:45

>>129
There are only 10 kinds of people in the world....

Name: Anonymous 2012-07-28 23:57

>>129
what does it feel like to have friends

Name: Anonymous 2012-07-29 0:03

>>130
There are only 10 kinds of people in the world, those who fully understand octal, those who understand it but feign ignorance so their peers won't call them faggots, those who confuse it with hexadecimal, those who confuse it with decimal, those who confuse it with binary, those who refuse to understand it, those who are incapable of understanding it, and those who only use it for UNIX permissions.

Name: Anonymous 2012-07-29 1:24

>>132
Too long of a delivery, but you get points for a valiant attempt.

Name: Anonymous 2012-07-29 1:41

>>133

I found it rather humorous, but I find you point assignment to be absolute enraging and I hope you slowly die in a fire in which you seek shelter in a pool of mud, and temporarily find relief, but are inevitably slowly cooked by the surrounding flames.

Name: Anonymous 2012-07-29 4:33

>>134
Too long of a delivery, but you get points for a valiant attempt.

Name: Cudder !MhMRSATORI!fR8duoqGZdD/iE5 2012-07-29 5:04

>>112
Actually, the majority of stuff I work on is x86, Windows or Linux. If I was using some other architecture then I'd write in Asm for that too. (Although MIPS and ARM are a bit... boring.)

>>115,118,120
I was expecting replies like this. You still put blind faith in compilers and think they're god-like and better than anyone else. That's what the academia always says. But consider that if it was true, I wouldn't be writing this today. I've probably read through more compiler output than anyone else here, and quite frankly, most of it sucks. ICC is the best I've seen, MSVC is a close second, and GCC is far behind. Delphi is... about the worst I've ever seen.

>>123
The majority of those are provided in different versions for each platform. Like I said above, if you really want portability, use Java.

>>124,125,126
If they're lazy idiots they can let the compiler hold their hand and do everything for them. If they're intelligent they'll find a way to do things more efficiently. It's about letting the programmer exploit her capabilities to the limit.

Name: Anonymous 2012-07-29 5:22

My little cudder
Compilers are magic

Name: Anonymous 2012-07-29 5:34

>>136
+1 for mentioning gcc is complete shit

- Tremendous Faggot
  163k •31 •320 •628
  96% accept rate

Name: Anonymous 2012-07-29 5:41

>>38
>crying about garbage collection
as if writing 1 line is so hard

>>26
also no pointers? have fun being a useless language

have fun with your unused "future" languages

Name: Anonymous 2012-07-29 6:20

>>138
The other ones are non-free and closed-source, thus introduce security risks.

Name: Anonymous 2012-07-29 6:23

>>136,138
I'm no x86 assembly expert but what's wrong with gcc's output?

Name: Anonymous 2012-07-29 6:28

>>141
It doesn't have NSA backdoors so it threatens national security.

Name: Anonymous 2012-07-29 6:41

>>141
It can't produce code as well as something like ICC in some cases. Then again, ICC probably has a massive budget pumped into it compared, so it kinda makes sense.

Name: Anonymous 2012-07-29 7:09

12 squared dubs get claimed

Name: Anonymous 2012-07-29 7:14

>>136

I was expecting replies like this. You still put blind faith in compilers and think they're god-like and better than anyone else. That's what the academia always says. But consider that if it was true, I wouldn't be writing this today. I've probably read through more compiler output than anyone else here, and quite frankly, most of it sucks. ICC is the best I've seen, MSVC is a close second, and GCC is far behind. Delphi is... about the worst I've ever seen.

Yes, we don't have a qualifying implementation yet. But someday we might. And with the benefits it would bring, I don't understand why more people aren't concerned with improving the tools they use every day. Instead, they just crank out applications using what is currently available and popular. A possible solution to a problem brought up in this thread:

* include a construct in the language that places constraints on data types. This constraint can be formally checked with static code analysis, tested dynamically with asserts in testing, and then used as a hint for optimization when building the release version. The compiler could consider a violation of the constraint as undefined behavior, and assume its truth when generating optimal assembly. This way, you can get your architecture specific optimizations without creating undocumented and undetectable restrictions on the inputs.

Would be nifty:

* Automate profiling of generated machine code. Select constructs that give the best performance based upon empirical data collected from are large set test runs.

If they're lazy idiots they can let the compiler hold their hand and do everything for them. If they're intelligent they'll find a way to do things more efficiently. It's about letting the programmer exploit her capabilities to the limit.

Lazy and idiotic is all relative. Computer are idiots. But they are far from lazy. A VERY determined idiot may be able to write a better program than you if given a disproportionately larger amount of time to do it in.

Name: Anonymous 2012-07-29 7:38

>>145




I think that












what you want













already exists














in the form of
















design by

















contract.













Some systems,


















in fact,



















do statically check
















them, when they
















can.

Name: Anonymous 2012-07-29 7:47

>>145
Automate profiling of generated machine code. Select constructs that give the best performance based upon empirical data collected from are large set test runs.
http://theory.stanford.edu/~aiken/publications/papers/asplos06.pdf

Name: Anonymous 2012-07-29 9:38

Hey faggots, try out this multiboot kernel: ArCtGwMAAQD7T1HkAAAQAAAAEAAAAAAAAAAAACAAEAAxwLkAgAsAZjEBQUEPMcHgCIH5oI8LAHLu6+c=

Name: Anonymous 2012-07-29 10:41

>>5
So, I'm not alone with such thoughts. Unfortunately one have to write his own language with such properties. Atleast I haven't seen one.

Name: Anonymous 2012-07-29 10:47

>>1
Haskell. Anything other is shit.

Name: Anonymous 2012-07-29 12:07

>>136
If they're lazy
Writing clean code isn't lazy, it's polite.

exploit her capabilities to the limit.
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it."

Name: Anonymous 2012-07-29 15:01

>>146,147

Yeah, I didn't doubt that they didn't already exist. Just if they were in wide spread use in industry. Thanks for the link.

Name: Anonymous 2012-07-29 15:15

>>147

The problem of emitting efficient SIMD code has confounded
compiler-authors for many years; gcc at least does not appear to
attempt to use SIMD instructions.

Oh gaawd

Name: Anonymous 2012-07-29 15:26

>>152
For contracts:
The D Programming Language has contracts by the kitchen sink law. No static checking, but they're not checked at runtime when release-building.
C# has http://msdn.microsoft.com/it-it/devlabs/dd491992.aspx
There was some work on static contracts for Haskell here: http://research.microsoft.com/en-us/um/people/simonpj/papers/verify/HaskellContract.ps but it doesn't seem to be implemented anywhere, nor I know if there have been any new developments.

Name: Racketfan 2012-07-29 15:43

Racket-lang.org

Name: Anonymous 2012-07-29 15:53

I am offended that PHP is listed as a programming language. PHP is not a programming language. It's a miscarriage of engineering, a monstrously deformed abortion that by some cruel fluke of nature has managed to cling to life.

Name: Anonymous 2012-07-29 16:12

>>156
I agree. But not just cling to life; it has become central to the average, modern website. Such a shame..

Name: Anonymous 2012-07-29 16:22

>>156
It would be unfair to not list PHP and then list JS, D, C++ and C.

Name: Anonymous 2012-07-29 16:27

>>158
Please don't even begin to compare C to PHP.

Name: Anonymous 2012-07-29 16:46

>>156
PHP is touring complete

Name: Anonymous 2012-07-29 16:50

>>158
i don't see why javascript SHOULDN'T be up there, even if PHP weren't listed

Name: Anonymous 2012-07-29 16:53

>>157
>>158
I realize that it mostly works and is useful, and sometimes use it myself when I need a tiny server backend for something, what jostles my flaps is the horrible choices in its design that result in ephemeral and obscure bugs creeping in to large projects. Of the useful, widespread programming languages it has the worst intrinsic flaws and insanities, that aren't the result of deliberate design decisions so much as incompetence. And so I am buttfurious on the internet about it.

Name: Anonymous 2012-07-29 17:08

>>162
>>157
>>158

buttfurious
Gabe plots cake, ``please''!

Name: Anonymous 2012-07-29 17:31

>>162
You know what else mostly works? A rusty knife.

Name: Anonymous 2012-07-29 17:32

>>164
Exactly.

Name: Anonymous 2012-07-29 17:36

>>165
I hope you'll enjoy tetanus, then?

Name: Anonymous 2012-07-29 19:03

>>166
HAX MY TETANUS

Name: Anonymous 2012-07-29 19:51

>>162
back to /g/, ``please''!

Name: Anonymous 2012-07-29 22:27

>>72
you're experience has maid you clothes minded.
[b][i]what[/i][/b]

Name: Anonymous 2012-07-29 22:38

So /g/ finally raided /prog/. I'm out of here, again.

fuck off, ``faggots"

Name: Anonymous 2012-07-29 23:26

>>170

no, we are just pretending to be from /g/.

Name: Cudder !MhMRSATORI!fR8duoqGZdD/iE5 2012-07-30 5:45

I don't understand why more people aren't concerned with improving the tools they use every day
Because they think compilers are somehow magical and mysterious entities. One of (many) somewhat-sluggish projects has been to write a better C compiler, one that generates code closer to how an assembly language programmer would write it---by necessity, not by pattern.

* Automate profiling of generated machine code. Select constructs that give the best performance based upon empirical data collected from are large set test runs.
MSVC has PGO, which is not bad, but is a bit of a pain to use and thus not used much except in special cases. Optimisation should be more "ubiquitous", not a special-case thing to be applied after you discover that things aren't quite right. I know they still teach that "premature optimisation" bullshit; but going back to change something that's been written already is a waste of resources. Optimisation should be integrated into design, thought of as "what's the best way to do this" throughout so that the final product doesn't need much more done to it.

>>151
That quote may be true for those who don't understand fundamentals like binary and machine instructions, but being clever---and thorough with the design---when writing code can in many cases completely avoid ever having to debug it, as you will have essentially proved it correct before ever running it.

>>156
Whatever you call it, it's become ubiquitous for websites for a reason. The same with all the other languages you complain about. "Purity" or whatever you want to call it has no real practical advantage. Pragmatism does.

Name: Anonymous 2012-07-30 6:30

>>172
Whatever you call it, it's become ubiquitous for websites for a reason.
The Jews at Zend bribed Web hosts.

Name: Anonymous 2012-07-30 7:35

Its only real selling point was that it had a foothold on at least 1% of all the internet's domains by 1998. In 1998 you had a choice of ASP classique, Coldfusion and PHP3 for 1. sticking your spaghetti code all over your HTML which was the fad back then and 2. run in-process in the web server instead of CGI. The next closest competitor had WSGI came about by 2003, mod_python came on a CD for a book in 2000, PHP was at version 3 by 1998. There were others a little later (JSP rushed out in 1999) but by then the Code-In-HTML language market was cornered by PHP on Linux and ASP on Windows.

Its other selling point, hosting companies liked PHP because of the shitty safe_mode when it came to cramming thousands of sites on a server.

Name: Anonymous 2012-07-30 8:02

>>172
While you ``optimize'' your bitfiddling code, I'll implement a better algorithm, Cudder.

Name: Anonymous 2012-07-30 12:04

>>175
LOL
Did you understand what he talked about?

Name: Anonymous 2012-07-30 13:22

>>172
"premature optimisation" bullshit
Optimisation should be integrated into design
Truth: asm is less readable and thus less maintanable.
Ideally, programs should be executable algorithms, expressed in adequate abstractions. Optimization should be done just when necessary, because it's architecture-dependent and almost write-only.
Or are you telling me to follow master FrozenVoid?
IHBT

Name: Anonymous 2012-07-30 16:30

>>137
I wanna have a threesome with you and Cudderspace

Name: Anonymous 2012-07-30 18:27

>>172
Optimisation should be integrated into design, thought of as "what's the best way to do this" throughout so that the final product doesn't need much more done to it.

"The best way to do this" is the most readable way to do it. If the optimized way is the most readable then do that, if the nieve way is the most readable then do that. If it profiles badly, THEN rewrite it in the optimized way and leave a small novel in the comments on why you made every choice you made and what its actually accomplishing.

I'm not saying that your way of coding is wrong or bad or anything, I'm just saying that it makes people not want to work with you.

Name: Anonymous 2012-07-30 18:30

>>177,179
Typical “premature optimisation” bullshiters. It's good to plan ahead.

Name: Anonymous 2012-07-30 18:36

>>177
your post is full of shit

Name: Anonymous 2012-07-30 18:41

>>180
then go to /optimisation/, this is /prog/

Name: Anonymous 2012-07-30 19:24

>>180
Sometimes its needed. Sometimes.
But you're likely to spend much more time optimising ahead and them spend much more to fix bugs. See this: http://tibleiz.net/asm-xml/
3 in 4 releases are bugfixes.

Name: Anonymous 2012-07-30 19:46

>>179
OR I could just write it correctly the first time. Code readability is over-rated. As long as it was not intentionally obfuscated, a programmer worth his salt will be able to figure out what it does (because it's right there in front of his face).

Name: Anonymous 2012-07-30 20:18

>>177
3/10.

>>183
You're now blurring "optimizing ahead" and "writing shitty code" into one thing. You can not optimize your design ahead-of-time and still have bug riddled code.

Of course, this partially does depend on your language. If you're gonna be writing a decently sizeable system in something like C, you will indeed need to do a fair degree of ``premature optimization'', simply because changing large chunks later takes so much time and will end up introducing more bugs in the process.

Name: Anonymous 2012-07-30 21:13

>>185
What's with these X/10 little shits coming to /prog/?

Did /g/ finally invade us?

Name: Anonymous 2012-07-30 21:15

>>186
Nice attempt to avoid my argument.
Have fun with your slow programs!

Name: Anonymous 2012-07-30 22:18

>>185
The whole point of planning ahead is when you haven't code yet, such as the asmxml project at its beginning. From the ground up it was designed to be optimised, but still had bugs and new feature requests. Maybe a new feature can disrupt your clever design, and you'll be walking on eggs to implement it. But now that the design is clever and everything is coded in asm, it's a pita.

Name: 188 2012-07-30 22:29

http://www.adacore.com/adaanswers/gems/gem-93-high-performance-multi-core-programming-part-1/

When it comes to performance, no amount of tweaking can compensate for an inherently slow design.

Name: 188 2012-07-30 22:40

But you check the "design" and see that it doesn't involve rewriting your app in asm because your compiler doesn't output optimal code.

Name: Anonymous 2012-07-30 22:48

>>184
OR I could just write it correctly the first time. Code readability is over-rated. As long as it was not intentionally obfuscated, a programmer worth his salt will be able to figure out what it does (because it's right there in front of his face).
What if you fucked up everything and are too stupid to realize it, and the superior programmer is reading your fucked up code, trying to infer what the fuck you were actually trying to do from your endless chain of tacit false assumptions?

>>186
yes

>>188
It's too late for them. Don't bother.

Name: Anonymous 2012-07-30 22:49

This thread is fail.

>>172
That quote may be true for those who don't understand fundamentals like binary and machine instructions
That quote may be Brian W. Kernighan

Name: Anonymous 2012-07-31 2:12

>>172
I don't understand why more people aren't concerned with improving the tools they use every day
Because they think compilers are somehow magical and mysterious entities.
People are probably just either satisfied with suboptimal machine code generation or they don't know any better.
One of (many) somewhat-sluggish projects has been to write a better C compiler, one that generates code closer to how an assembly language programmer would write it---by necessity, not by pattern.
This would be very nifty. The only implementation strategy for machine code generation I've seen so far is to simply convert syntactical constructs to a stream of equivalent instructions and apply a series of optimizations that maintain equivalence throughout the process. Albeit, there can be other things going on like using a minimum amount of registers. In the whole process, the compiler doesn't really know what you are trying to do. It's just spitting out machine code it knows is equivalent to the higher level source code you gave it, and then simplifying it a bit. An optimizing compiler tries to find a highest performing program within the equivalence class of the program the programmer submitted. So it applies all these operations that it knows preserve equivalence, but will likely improve performance.

It seems like in order for the compiler to truly generate assembly with necessity, it would need to have a complete high level understanding of what you are trying to do. But as soon as I start to think about whether this is possible, or already implemented, it feels like it comes down to a philosophical question. If I turn the steering wheel of my car to the left, does my car realize that I want to go left, and turns its wheels by necessity? Or is it just doing what the mechanical engineer designed it to do, which was to allow rotation of the steering wheel was to directly affect the wheels?

Name: Cudder !MhMRSATORI!fR8duoqGZdD/iE5 2012-07-31 6:27

>>177
Truth: asm is less readable and thus less maintanable.
Readability is subjective (size or speed is NOT), but to someone experienced, it's more readable. Even the format is consistent. The only thing is, it also tends to be more voluminous.

>>183
Look at the bugtrackers of other XML libraries and you'll find much worse.

When I was talking about design, I meant decisions that are not easy to reverse, and that can have huge consequences for efficiency. For example, instead of the obvious (and inefficient) "make objects out of everything and copy data into them" parsing algorithm, do it in-place so there's no unnecessary copying of data. Simplify the design to make it more "direct". I'll use the web browser as an example here since we're all familiar with them: how long is the path (in terms of # of instructions or call depth) between Firefox getting a WM_PAINT and its first API call into the OS to draw the page content into the window? In the browser design I'm planning, it's < 5. I'm not planning to do any memory allocation/deallocation there either.

Maybe "optimisation" is the wrong word for this, but what else do you call making something more efficient? If you plan your design like this and have it carefully thought out before writing a single line of code, the chances are high that you'll be ahead of those who "optimise later", without even needing to go to inline Asm. You could say that, despite the compiler's stupidity, everyone is using the same compiler but your design has already been optimised at a higher level, so its inefficient output is still going to be more efficient than the output from an inefficient design.

>>193
It seems like in order for the compiler to truly generate assembly with necessity, it would need to have a complete high level understanding of what you are trying to do.
That's not necessary, all it needs to understand is the semantics of the source language. What we agree is not statement-by-statement translation and applying optimisation afterwards (there's that anti-premature-optimisation again!), but my idea is to generate code "backwards", working from the desired result. E.g. in


int foo() {
 int i = f();
 int j = k();
 int l = 2 + j;
 ... /* code that does a lot with l, but never has effect on i, j, nor other global variables */
 return i + 2*j;
}


a "dumb" or "traditional" compiler would emit code for all that stuff in the middle, and optimisation might have a chance at removing (some of) it and moving variables into registers. An "intelligent" compiler could work backwards and "think" "This function's result depends on i and j. What do i and j depend on? f() and k(). What do f() and k() depend on? ... " Eventually it might determine that f() and k() are actually constant, and substitute that in, propagate the changes down, and reduce foo() itself to a constant. And of course, all of this might not even be done if foo() can never get called from any entry point. At every reference to a nonlocal variable, this process would need to be performed as their results are "visible" to other functions.

For things like register allocation (done after the above), the compiler could track how many variables are actually needed, and then choose how many extra "slots" are required in memory. It can alter their allocation to registers depending on their usage and loop nesting level. In size/balanced optimisation mode, if it sees certain variables having LIFO-like usage patterns, it can emit push/pop (single byte instructions) instead of explicitly doing a stack allocate and moves. If there's a long-running inner loop with frequently accessed variables, push the less frequently used variables on the stack. This is how an Asm programmer does register allocation by necessity.

Due to the halting problem it's not possible to prove that f() or k() terminate even if they do not depend on nonlocal variables, but the compiler can offer an option to simulate their execution for a limited number of cycles. No deep understanding (other than language semantics) required by the compiler, just a different way of approaching the problem.

Follow this process to its logical conclusion, even into library functions and such, and your printf("%d\n", fib(5)); becomes a fputs("2178309\n", stdio);. In the output binary too, there will be nothing more than what the compiler found was needed. That is the ultimate goal.

Name: Anonymous 2012-07-31 10:49

>>194
side-effects troubles optimizing compilers
don't want functional programming
LOL

Name: Anonymous 2012-07-31 11:25

Use Eiffel.

Name: Anonymous 2012-07-31 12:24

>>194
If you plan your design like this and have it carefully thought out before writing a single line of code, the chances are high that you'll be ahead of those who "optimise later", without even needing to go to inline Asm.
well the issue isn't that you're making things more efficient, efficiency is generally good, the issue is that it's your only priority.

take a contrived fibinacci example. you don't want to use the recursive O(2^n) algorithm...

but you also probably also don't want to use the O(1) algorithm unless you have a REALLY good reason to:


const double inverseSqrt5 = 0.44721359549995793928183473374626
const double phi = 1.6180339887498948482045868343656

static int Fibonacci(int n) {
    return (int)Math.Floor(Math.Pow(phi, n) * inverseSqrt5 + 0.5);
}

Name: >>197 2012-07-31 12:25

>>197
forgot to quote first line.

Name: Anonymous 2012-07-31 12:39

>>197
but you also probably also don't want to use the O(1) algorithm unless you have a REALLY good reason to
Why? The meaning of the function is captured by int Fibonacci(int n). How it is implemented is none of anyone's business.

Name: Anonymous 2012-07-31 12:42

>>197
what is the value of (int)std::numeric_limits<double>::infinity(), anyway?

Name: Anonymous 2012-07-31 13:05

>>199
it is if there's a typo.

Name: Anonymous 2012-07-31 13:09

>>199
How it is implemented is none of anyone's business.
Also you make a lot of statements like this, leading me to believe that you've never actually worked with other people before. Am I correct?

Name: Corporate Critter 2012-07-31 13:32

>>1
Why not put HTML5 on your list?

Name: Anonymous 2012-07-31 13:48

ITT: Excuses for not knowing assembly

Stay mediocre

Name: Anonymous 2012-07-31 14:43

JACKSON 5 + 200 GET

Name: Anonymous 2012-07-31 14:44

JACKSON 5 * 41 GET

Name: Anonymous 2012-07-31 14:52

>>204
Itt: i know assembly, try again.

Name: Anonymous 2012-07-31 15:02

>>206
5*41 is not 206

Name: Anonymous 2012-07-31 22:59

That's not necessary, all it needs to understand is the semantics of the source language. What we agree is not statement-by-statement translation and applying optimisation afterwards (there's that anti-premature-optimisation again!), but my idea is to generate code "backwards", working from the desired result. E.g. in


int foo() {
 int i = f();
 int j = k();
 int l = 2 + j;
 ... /* code that does a lot with l, but never has effect on i, j, nor other global variables */
 return i + 2*j;
}


a "dumb" or "traditional" compiler would emit code for all that stuff in the middle, and optimisation might have a chance at removing (some of) it and moving variables into registers. An "intelligent" compiler could work backwards and "think" "This function's result depends on i and j. What do i and j depend on? f() and k(). What do f() and k() depend on? ... " Eventually it might determine that f() and k() are actually constant, and substitute that in, propagate the changes down, and reduce foo() itself to a constant.

Yeah, this can actually be formulated as a simple graph algorithm. Every intermediate expression is a node. An expression X has a directed edge to an expression Y if and only if the evaluation of X depends on the result of the evaluation of Y. We then look at the node for the expression being returned from the subroutine. Perform a depth first traversal. In the post order phase, emit assembly instructions for evaluating the current node. This will ensure the dependencies for each expression are evaluated in time. Further more, expressions whose values do not contribute to the return value will not be reachable from the return expression node. So the depth first traversal will never reach, and never emit assembly for these unused expressions. And even further more, but the expression dependency graph also provides a scheme for evaluating dependencies in parallel. The disadvantage of trying to take advantage of that is the cost of synchronization. The time it takes to evaluate an expression node may vary very much with different inputs. Effective synchronization would likely need to be dynamic, and the inherent cost of managing this would only make it advantages when the expressions have intensive evaluation procedures.

And of course, all of this might not even be done if foo() can never get called from any entry point. At every reference to a nonlocal variable, this process would need to be performed as their results are "visible" to other functions.

Yeap.

For things like register allocation (done after the above), the compiler could track how many variables are actually needed, and then choose how many extra "slots" are required in memory. It can alter their allocation to registers depending on their usage and loop nesting level.

Yeah, register allocation can be stated as a graph coloring problem.

http://en.wikipedia.org/wiki/Graph_coloring#Register_allocation
The textbook approach to this problem is to model it as a graph coloring problem.[29] The compiler constructs an interference graph, where vertices are symbolic registers and an edge connects two nodes if they are needed at the same time. If the graph can be colored with k colors then the variables can be stored in k registers.

For general graphs, finding an optimal coloring is NP hard, and finding a coloring using less than k colors is NP complete. But you can get your optimal register allocation if you are willing to wait. If the variable interference graph has certain characteristics, it could be possible to color it easier.

In size/balanced optimisation mode, if it sees certain variables having LIFO-like usage patterns, it can emit push/pop (single byte instructions) instead of explicitly doing a stack allocate and moves. If there's a long-running inner loop with frequently accessed variables, push the less frequently used variables on the stack. This is how an Asm programmer does register allocation by necessity.

Cool stuff. This could be stated as an optimization problem.

Due to the halting problem it's not possible to prove that f() or k() terminate even if they do not depend on nonlocal variables, but the compiler can offer an option to simulate their execution for a limited number of cycles. No deep understanding (other than language semantics) required by the compiler, just a different way of approaching the problem.

I saw a language that offered something similar. At function definitions you could specify a maximum time out for the function. This might be useful in some real time applications, but I could see it getting in the way otherwise.

http://en.wikipedia.org/wiki/Hume_(language)

Follow this process to its logical conclusion, even into library functions and such, and your printf("%d\n", fib(5)); becomes a fputs("2178309\n", stdio);. In the output binary too, there will be nothing more than what the compiler found was needed. That is the ultimate goal.

Yeap, that's all possible with function inlining and constant folding. If the printf implementation prepares the "2178309\n" string by writing into a buffer, the compiler would need to understand this and evaluate the resulting state of the buffer at compile time.

Name: Anonymous 2012-07-31 23:24

>>200
0, apparently.

Name: Anonymous 2012-07-31 23:37

>>210
Is that guaranteed by the standard, implementation defined, or undefined?

Also, what's the point of a factorial function that only works for extremely small values?

Name: Anonymous 2012-08-01 4:42

Name: Cudder !MhMRSATORI!fR8duoqGZdD/iE5 2012-08-01 7:24

The disadvantage of trying to take advantage of that is the cost of synchronization.
???
As I mentioned above all recent CPUs automatically parallelise when there are no dependencies between instructions.

For general graphs, finding an optimal coloring is NP hard, and finding a coloring using less than k colors is NP complete.
I've never really understood this obsession with graph colouring for RA. Perhaps it's too general for register allocation, or register-memory/register-immediate/memory-immediate architectures like x86 can avoid this issue. In the flow graph, think of a wire connecting two nodes for each variable's value that needs to be preserved. Then the "thickness" of the "bundle" between each node is how many units (bytes e.g. if each wire represents 8 bits) of data need to be preserved between them. Assign the ones used in the innermost loops/most often to registers first. The rest can go in memory, or swapped with another if there's a change in use (x86 conveniently provides an xchg instruction for this.)

This algorithm is quite different from any I've seen before (except perhaps linear scan, although that one is not particularly efficient) and has some traits of the optimise-first approach: instead of attempting to allocate everything to registers and "spill" afterwards, determine the maximum storage needed first, then allocate to both memory and registers. For example you have 80 bits of "real" local variables (i.e. values that actually get used and need preservation, which may not correspond to the number of declarations in the source code) and 56 bits of registers. A dumb graph-colouring algorithm is NOT going to see the 24 bits until it's too late. Then it goes back, "spills", tries again, etc. The algorithm I described above is going to allocate the 24 bits somehow (pre-allocation via stack, push/pop, etc.), and fit everything in naturally.

At function definitions you could specify a maximum time out for the function.
That's not what I meant. It's a compile-time optimisation constraint to prevent compilation from taking too long, at the expense of possible lost pre-computation. E.g. you write a program that computes 64K digits of pi. This is self-contained and should terminate, so theoretically could be computed by the compiler. With a low precomputation limit, it doesn't finish so at best the compiler can save the partial state and you end up with e.g. a program that contains 4K digits already computed and another 60K to go. Set it high enough and you get a program that only contains the 64K digits you want because the computation terminated in the compiler.

If the printf implementation prepares the "2178309\n" string by writing into a buffer, the compiler would need to understand this and evaluate the resulting state of the buffer at compile time.
It's just the collection of visible state changes induced by the program. You could just collect the library function calls it made, along with their associated data, and emit code to do only that, if the program depended on no input. Programs are deterministic. If they have no input they will always produce the same output (or not halt). If they halt with no input then capture their output and that is the embodiment of the process it performs.

Name: Anonymous 2012-08-02 0:59

As I mentioned above all recent CPUs automatically parallelise when there are no dependencies between instructions.
Yes, so it would be silly to explicitly use threads to evaluate expressions whose evaluations are only a few primitive opcodes long. But if the values are the returned values from procedures that take inputs and take a while, and have time of execution that varies with their inputs, spawning child threads to compute the values and then joining them for the calculation of the common dependency will allow for the dependencies to be calculated in parallel.

I've never really understood this obsession with graph colouring for RA. Perhaps it's too general for register allocation,
To answer this question, one must ask if it is possible to create a chunk of code that will yield a variable interference graph isomorphic to an arbitrary graph.

or register-memory/register-immediate/memory-immediate architectures like x86 can avoid this issue.
Only if the number of registers is two.

In the flow graph, think of a wire connecting two nodes for each variable's value that needs to be preserved. Then the "thickness" of the "bundle" between each node is how many units (bytes e.g. if each wire represents 8 bits) of data need to be preserved between them.
Larger data types can be represented as a series of independent variables, where each variable represents a fixed size portion of the data type. If allocated in memory, and extra restriction that each portion must be in successive memory addresses can be assigned.

Assign the ones used in the innermost loops/most often to registers first.
why? And what's a loop in this context? what code representation are you operating on?

The rest can go in memory, or swapped with another if there's a change in use (x86 conveniently provides an xchg instruction for this.)
Yes, if there is spillage, there will need to be registers reserved for swapping values in between the swapping register and the variables permanent memory address.

This algorithm is quite different from any I've seen before (except perhaps linear scan, although that one is not particularly efficient) and has some traits of the optimise-first approach:
Without a proof of optimality, it's crap.

instead of attempting to allocate everything to registers and "spill" afterwards, determine the maximum storage needed first, then allocate to both memory and registers. For example you have 80 bits of "real" local variables (i.e. values that actually get used and need preservation, which may not correspond to the number of declarations in the source code) and 56 bits of registers.
Multiple variables can still be allocated in a single memory address, much how multiple variables can be allocated in a single register. An optimal graph coloring will give you a smallest number of slots needed to allocate your variables. Some of these slots will be in registers and if there are too many slots, they will be in memory as well. But in any case, a minimal amount of slots and memory will be used.

A dumb graph-colouring algorithm is NOT going to see the 24 bits until it's too late. Then it goes back, "spills", tries again, etc.
The graph coloring algorithm doesn't know about registers or spills. It just gives you colors. How you interpret and use these colors in a separate issue.

The algorithm I described above is going to allocate the 24 bits somehow (pre-allocation via stack, push/pop, etc.), and fit everything in naturally.
naturally. I wish this word was stricken from anything technical. If it ain't optimal it's crap.

That's not what I meant. It's a compile-time optimisation constraint to prevent compilation from taking too long, at the expense of possible lost pre-computation. E.g. you write a program that computes 64K digits of pi. This is self-contained and should terminate, so theoretically could be computed by the compiler. With a low precomputation limit, it doesn't finish so at best the compiler can save the partial state and you end up with e.g. a program that contains 4K digits already computed and another 60K to go. Set it high enough and you get a program that only contains the 64K digits you want because the computation terminated in the compiler.
my bad. That's a good point to be aware of if pushing those computations to compile time.

It's just the collection of visible state changes induced by the program. You could just collect the library function calls it made, along with their associated data, and emit code to do only that, if the program depended on no input. Programs are deterministic. If they have no input they will always produce the same output (or not halt). If they halt with no input then capture their output and that is the embodiment of the process it performs.
Yeah, constant folding on function calls can go a long way. It would be most powerful if it could adapt to almost any user function, as well as library functions.


Anyways, I'm going to try to get optimal register allocation in polynomial time. Wish me luck!

Name: Cudder !MhMRSATORI!fR8duoqGZdD/iE5 2012-08-02 7:22

why? And what's a loop in this context? what code representation are you operating on?
Obviously because they will be read/written the most and thus deserve to be in registers, at least for the duration of that loop. It should also be obvious what a loop is, it's whatever corresponds to a loop in the source language. A loop within a loop is also similarly self-explanatory. The representation doesn't matter.

Yes, if there is spillage, there will need to be registers reserved for swapping values in between the swapping register and the variables permanent memory address.
This is where it seems you're still stuck with "the old way": a variable does not ever need to be at a "permanent memory address". There doesn't even need to be any correlation between how variables are defined and used in the source and the output, as long as they are semantically equivalent. Think of a variable as just a label for a "flow" of data between two or more operations. That flow might not exist if the operations that it connects aren't important to the final result of the function.

Without a proof of optimality, it's crap.
That's what academics think. The real world says otherwise.

Multiple variables can still be allocated in a single memory address, much how multiple variables can be allocated in a single register.
But multiple registers OR memory addresses may be allocated to one "variable" too.

The graph coloring algorithm doesn't know about registers or spills. It just gives you colors. How you interpret and use these colors in a separate issue.
That's exactly the point I'm making: it's too general.

Anyways, I'm going to try to get optimal register allocation in polynomial time. Wish me luck!
According to the RA article on Wikipedia this is possible with SSA, and there's nothing about anything being NP-complete on its page. Unfortunately they're both full of academic verbiage so it's difficult to determine what they're really talking about.

Another two examples of why more "targeted" algorithms can work better: instructions that require operands in particular registers, and those that prefer particular registers. With traditional graph colouring, you can force allocation of a certain register, but there's no way to specify a preference. An Asm programmer can think "there's a divide coming up: let's arrange things so that its input will be in the right registers when the time comes" and override that choice with something more important when necessary. Traditional RA algorithms can't do that.

tl;dr: Register allocation is one area where compilers could improve significantly, but due to a reluctance to challenge existing norms, has not. It's only recently that stuff like linear-scan (closer to what someone with common sense, but not exposure to previous biases, would come up with) and SSA started getting visibility. These basics should've been where we started.

To whoever started the insistence that register allocation is as general a problem as graph colouring and propagated it: FUCK YOU.

Name: Anonymous 2012-08-02 23:36

>>215

Obviously because they will be read/written the most and thus deserve to be in registers, at least for the duration of that loop. It should also be obvious what a loop is, it's whatever corresponds to a loop in the source language. A loop within a loop is also similarly self-explanatory. The representation doesn't matter.
It sounds like you are operating on the source language directly. In the version I was thinking of, it was to take abstract assembly that uses an unbounded amount of variables, and then output the same assembly but using as few variables as possible. When operating at the assembly level, loop constructs can become very complex and general. I'm not sure which approach would be better. It feels like it would be better to do it after the compiler has done its other optimizations, but I could be wrong.

This is where it seems you're still stuck with "the old way": a variable does not ever need to be at a "permanent memory address". There doesn't even need to be any correlation between how variables are defined and used in the source and the output, as long as they are semantically equivalent. Think of a variable as just a label for a "flow" of data between two or more operations. That flow might not exist if the operations that it connects aren't important to the final result of the function.
Well that's interesting. Is there an advantage to allocating a single variable in multiple locations? Each location is essentially a variable. So this could be modeled as variable assignment. I could see this getting very interesting if each storage location had a different cost of access. But assuming each register is equally cheap to read and write to, all you have to worry about is swapping values in and out of memory and the behavior of the special purpose registers, in which case, you might not need to go there.

That's what academics think. The real world says otherwise.
The real world is satisfied with crap.

But multiple registers OR memory addresses may be allocated to one "variable" too.
I'm not sure if there is an advantage in doing that. The algorithm would be creating a new variable that is equivalent to another previously defined one. If the goal is to create an equivalent program using the fewest amount of variables, and hence, needing the fewest amount of storage locations, then creating new variables doesn't seem like a good idea. But if the goal is to increase performance, then maybe it's possible in some circumstances to use more storage locations. At that point you'd need to work with a model closely related to the processor. It wouldn't be enough to just assume that using the minimum amount of storage locations will give you the most speed, although you'd think that would be true if there was no spillage as a result.

That's exactly the point I'm making: it's too general.
Whether or not graph coloring is too general for register allocation depends the class of graphs created in the construction of the variable interference graph. If it can form an arbitrary graph, then optimal register allocation is just as hard as graph coloring. But if the class of graphs is actually more limited, then it can be possible to use a special purpose graph coloring algorithm that takes advantage of properties present in the restricted class of graphs.

According to the RA article on Wikipedia this is possible with SSA, and there's nothing about anything being NP-complete on its page. Unfortunately they're both full of academic verbiage so it's difficult to determine what they're really talking about.
Good news! In the version I am working with, I am getting lines in the assembly where each variable must be holding its current value. If in a single line there are multiple variables that must hold their values, then these variables cannot be allocated in the same place. This yields a set of cliques. Now finding a clique in a graph is NP Complete, and the encoding we get for the variable interference graph is all of its cliques. So if it is possible to optimally color a graph using knowledge of what all its cliques are, then that could be used to optimally color the variable interference graph. I got something working for one example, but once I apply it to general graphs I get lost. Maybe there's a structure to the variable interference graph that I'm unknowingly taking advantage of.

Another two examples of why more "targeted" algorithms can work better: instructions that require operands in particular registers, and those that prefer particular registers. With traditional graph colouring, you can force allocation of a certain register, but there's no way to specify a preference.
The problem becomes much more complex, but you can use utility functions to rank the optimality of a coloring. But this requires a calculation of a utility function.

An Asm programmer can think "there's a divide coming up: let's arrange things so that its input will be in the right registers when the time comes" and override that choice with something more important when necessary. Traditional RA algorithms can't do that.
They can understand that the registers used by the divide instruction must be used to store the variables resulting from the division. This can be represented by allocating variables for the result of the division and forcing their colors to represent the registers they are put in by the instruction.

tl;dr: Register allocation is one area where compilers could improve significantly, but due to a reluctance to challenge existing norms, has not. It's only recently that stuff like linear-scan (closer to what someone with common sense, but not exposure to previous biases, would come up with) and SSA started getting visibility. These basics should've been where we started.
Indeed. But that makes it more exciting doesn't it? The late start makes it more likely that you might discover something new.

To whoever started the insistence that register allocation is as general a problem as graph colouring and propagated it: FUCK YOU.
so sorry! But really graph coloring is just solving the same problem in a more abstract setting. If you want to build more restrictions from the platform into the algorithm, just add more information to your definition of the graph to reflect the extra restrictions. These additions are usually small, and the advantage of using graphs is that all research and developments that have gone into graph algorithms will be easy for you to leverage. But there is the problem of graphs being such general objects. It could be that your domain is much less general than graph coloring. In which case it may be more useful to operate within the domain itself and never create a graph.

Name: Anonymous 2012-08-03 1:06

>>213-217
tl;dr

Name: Anonymous 2012-08-03 4:07

CHECK

Name: Anonymous 2012-08-03 4:07

OUT

Name: Anonymous 2012-08-03 4:07

THESE

Name: Anonymous 2012-08-03 4:08

TRIPS

Name: Anonymous 2012-08-03 4:08

FAGGOTS

Name: Cudder !MhMRSATORI!fR8duoqGZdD/iE5 2012-08-03 4:52

In the version I was thinking of, it was to take abstract assembly that uses an unbounded amount of variables, and then output the same assembly but using as few variables as possible.
That's basically SSA. Determining loop nesting level in Asm isn't difficult either: count the maximum number of complete cycles in the flow control graph enclosing a use of a given "variable".

Is there an advantage to allocating a single variable in multiple locations?
As I said in what you quoted, at this phase of compilation you should forget about what variables were present in the source code, and think of them as only labels for a flow of data between two computational nodes. Registers and memory serve as temporary storage locations for this flow, and thus it may occupy different locations at different points in the code. The advantage is additional freedom in code generation.
But assuming each register is equally cheap to read and write to
They're not. For example, the accumulator is preferred for many instructions. (e)DX must hold the remainder of a division. If a division is coming up but all the registers are already used for values that will be used afterwards, it makes sense to move whatever DX is storing into memory (possibly a push on the stack) and pull it back into a (possibly different) register sometime later when the compiler decides that it'll be used enough that it should get a register.

The real world is satisfied with crap.
Whatever you call it, that's the way things are.

I lost you at the graph colouring stuff, so I can't say much there.

The late start makes it more likely that you might discover something new.
It's only new to those who have buried their heads in the academic "literature" (propaganda?) all along. Try asking any Asm programmers if they colour graphs to allocate registers when they write code. I sure don't.

But really graph coloring is just solving the same problem in a more abstract setting.
Too abstract. If I were forced to choose an NP-complete problem to represent register allocation, it would be bin packing. At least that intuitively feels like the process of allocating items (values) to different bins (registers).

But there is the problem of graphs being such general objects. It could be that your domain is much less general than graph coloring.
I have a very strong feeling that it is: If all programs can be transformed into SSA form and doing so isn't NP-complete, and by doing so you can allocate registers in polynomial time, whereas doing it for the same program not in SSA is supposed to be NP-complete, then isn't that like saying P=NP? Following this to its conclusion, take any NP-complete problem, reduce it to graph colouring, reduce graph colouring to RA, derive a program from it, convert the program to SSA, RA that, and you've solved the NP-complete problem in polynomial time.

The other big drawback of thinking so abstractly is that only those who know much about graph theory (unlike me) can talk about RA like that. It creates a rather closed-minded environment and propagates the "thou shalt use graph colouring" myth. In contrast, the way I describe and think about it, it wouldn't be difficult at all for even a 10-year-old to understand and relate to the underlying problem. Getting rid of all that academic cruft and theory is a great way to get others thinking about these sorts of problems, and as a result drive innovation and progress through greater proliferation of practical, readily applicable ideas.

"Farmers don't want to learn about spherical cows. They just want the milk."

Newer Posts
Don't change these.
Name: Email:
Entire Thread Thread List