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-08-04 23:01

From what I've read, that's part of the principle behind SSA: to split up the idea of a "variable" into multiple ones, and each is only used once, so they correspond exactly to labelling the flow of data between operations. However that still clings to the notion of a "variable", which should be considered source-code-only. When generating code, it's better to think of how data flows between different operations in order to finally arrive at one or more final results.
The variables can always be closer to the assembly level than the source. For example, divisor and modulus result variables can be introduced for ever divide instruction.

In response to the in place add example
I think the best way to take advantage of this would be to generate code in an abstract assembly where addition always created a new variable to follow SSA style. Then apply the optimal register allocation algorithm, which will collapse many of the variables together. Then expand the add instructions as:


add X, Y -> C becomes:
MOV C, X
ADD C, Y

add X, Y -> Y becomes:
ADD Y, X

add X, Y -> X becomes:
ADD X, Y


Using the fewest registers is also not necessarily the best policy; processors can parallelise better when multiple registers are used, and the instructions are not dependent. For example, although the minimum number of registers for memory-to-memory copies is 1, when there are several of these to be done, you'll see e.g.

mov eax, [esp+8]
mov ecx, [esp+16]
mov edx, [esp+64]
mov ebx, [esp+96]
mov [esi+4], eax
mov [esi+8], ecx
mov [esi+12], edx
mov [esi+16], ebx


>instead of repeatedly using eax. Thus the algorithm should, when the minimum number of registers used is below the amount available, shuffle the order of operations (while maintaining their dependency ordering) to increase it. The optimal solution isn't the minimum number of registers, but the exact amount available.
That's a good point. The compiler will need to take this parallel execution into account as well. If you had an arbitrarily large amount of registers, you would never store two variables in the same register, to avoid locking up the parallelism. Sequential operations that use the same register will cost more than sequential operations that do not depend on each other. This cost can be incorporated by taking into account the previous instructions when calculating the cost of the current instruction. If the current instruction depends on the execution of close previous instructions, it should cost more.

Thus we should examine those "creative methods" and quantify the exact steps and decisions they take, in order to implement an algorithm that can behave like a programmer thinks, with the added advantage of computer speed.
The problem is that people rarely have a proof of optimality for their solution if the problem is very large. People instead invest effort into the solution until it is good enough. Once it is no longer worth continued effort, they stop and use what they have.

Because of the "accepted fact" that graph colouring is the way to do register allocation, and that it's proved to be NP-complete, few academics have challenged those norms and entertained the possibility that RA might not be. It's necessary to "think outside the box" here.
If RA is not NP complete, then either of two things are probably true: the graph to color has a restrictive structure and can be optimally colored by a polynomial time algorithm, or the graph is arbitrary but the assembly code encodes accessible information about the structure of the graph that can be used to get a coloring in polynomial time, and the coloring becomes difficult only if you ignore this information.

By using abstraction to transform RA to graph colouring you have transformed a very specific problem into a very general one, and increased its complexity. Because I am quite convinced that RA is not NP-complete I do not believe in using this abstraction.
Translating RA to graph coloring directly will be lossy. Kind of like taking a cryptographic hash of a string then then trying to recover the original string. But the information in RA that makes it easier than general graph coloring could also appear in other contexts. So it is worth abstracting. It's just that the conventional abstraction is misguided.

Why not forget about it completely and think of the solution to the specific problem from the ground up, using first principles? It seems people are more interested in building abstractions on top of abstractions than solving the actual problem, and I do not think that is a good use of resources. By indoctrinating others in this way, it becomes harder for them to think freely and innovate. The fact that linear-scan and the interest in SSA stuff is so recent clearly illustrates this.
The theoretical developments indirectly pay off to a lot of things. Just think, where did SSA come from?

In summary, it's an issue of perspective. Asm programmers do not think of variables much, but more about results of computation being held in registers/memory, and probably wouldn't care about assigning names to them. It's not "eax is currently holding j", it's "eax is holding the result of ...", and they're free to move that data around without having to think about what it's called. The flow model I talk about is a lot closer to this, and SSA is a step in the right direction. It's a little sad to see all this research being spent on these traditional directions, and not gaining much, when we could've had much better compilers back then, if they had chosen to think about these things "bottom-up".
A lot of things that appear to be very different can turn out to be equivalent. But graph coloring appears to have more research because it is a more general problem, and has a broader range of applications. But even then, I wouldn't consider it that popular. But then register allocation is a step further into the specific. No one really cares about compilers. Just look at databases, networking, and graphics. Then look at compilers.

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