The main difference is that it primarily targets 8-bit chips, so often has to expand a statement into multiple instructions, while I'm targeting ARM, which can get quite a lot done in a single instruction. But I absolutely will cite it as precedent.
13,747 karma · joined March 7, 2014
The main difference is that it primarily targets 8-bit chips, so often has to expand a statement into multiple instructions, while I'm targeting ARM, which can get quite a lot done in a single instruction. But I absolutely will cite it as precedent.
Time is a circle. Assembler could come back if it's an appealing target for LLMs. Currently it's not, but that's my hypothesis.
* It's possible to embed variable names into the debug info, so your debugger inspects those rather than just numbered registers.
* Optimizing compilers can do transformations which highly obscure the relationship between source and binary code. Here they closely match.
Thanks for your interest!
Dan Luu has done that kind of evaluation[2], and found that LLMs do well in a range of languages, but do underperform in assembler. My hypothesis is that expressing programmer intent clearly, and having the compiler verify things like consistent placement of variables in registers, will fix the problems that hold LLMs back.
This has been a hobby project, but it feels ready to break containment. I'm open to a research opportunity where I'd be able to work on it for real - get in touch.
[0]: https://github.com/raphlinus/symbolasm
It helps that I'm currently targeting ARM (Cortex M33, RP2350 specifically). Old-school x86 would be much less pleasant, as it's got so many arbitrary-seeming rules of what works and what doesn't. One quirk, when optimizing for file size, are the rules for which instructions have 16 bit encodings and which need 32. But again, the plan is to have a tight feedback loop.
In this syntax (though I'm not yet targeting x86_64) it would look something like a = round(fma(a, b, c)) where the variables have the appropriate vector type (and have been placed into registers with @zmm1 syntax when first assigned).
The design of the language is entirely by hand, as was the implementation when I started, but lately I have been using AI to speed implementation.
I set myself the goal of putting a DX7 in the hands of a million people. My little app only got a fraction of that, but now that the engine is in Dexed and now the M-VAVE, it seems like that might well happen.
I wonder if they'd send me one. But for $60 I can just get one :)
Arguably, seq_cst is helpful for informal reasoning, because it's not hard to imagine all permutations and interleavings. But in my opinion, nobody should be doing lock-free programming based on informal reasoning. Algorithms should be considered incorrect unless they've been rigorously validated, ideally with formal methods or at least model checking.
Very few lock-free algorithms require sequential consistency. There are exceptions, such as Chase-Lev queues, but they are rare.
The added confidence that seq_cst gives you if the algorithm hasn't been properly validated is IMHO worthless.
But there's another point in the tradeoff space. One of the explicit design decisions in Fearless SIMD is to support "downcasting," or specialization to a specific microarchitecture. At least for the kind of problems I've worked on, even when you're doing something fancy with arch-specific permutations or what not, the majority of the operations will be pretty vanilla, and can be expressed well in the portable subset.
So you can think of a library like Fearless SIMD as enabling your extreme optimization use case, just more ergonomically.
Of course, this depends on LLVM compiling intrinsics to assembly efficiently. That hasn't always been the case, and is not perfect now (a number of issues have been filed against rustc and LLVM while developing Fearless SIMD), but is pretty good.
As always, though, you do have to measure performance, and I frequently look at the assembler output to double-check that it's doing the right thing. The day of "fire and forget" portable SIMD has not yet arrived.
[1]: https://youtu.be/g9Rgu6YEuqY?si=_l9JwKhjvIdFEDEX&t=3819
That said, Photoshop doesn't feel like the sweet spot of what to run on this hardware. There's only 520kB of fast static RAM, and that's not enough to run a framebuffer with enough bit depth to hold a photo reasonably. I have invented a 4bpp compression scheme which opens up possibilities, but it's asymmetrical and in its current form compression is very slow, so it wouldn't be suitable for interactive work.
As a general matter, emulation makes a ton of sense. You can emulate all kinds of computers up to the late 80s, including video subsystems. Of course Mac and PC don't really do anything interesting like tiles and sprites, they're pretty much just dumb framebuffers.
I think hyperbezier would be a natural fit for boat hulls, but it's not a mathematically precise approximation to elastica either. I'd say to carefully evaluate it, and I'd very much like to hear how that goes.
ETA: "parallel curve of elastica" is an intriguing curve family to consider for this application, as it has the correct number of parameters and ticks a lot of the other boxes. However, the math for this is hard mode.
First, for hair rendering you've got a 3D trajectory, which Béziers can handle just fine, but I'm not sure about these spirals. I do have a chapter in my thesis and there has been a bit of followup from others, but I can't say anything with confidence.
That said, because of the specular reflections, applications like hair really would benefit from higher degrees of continuity. Cem Yuksel has a recent SIGGRAPH paper on how to tweak Béziers to get more continuity. In fact, seeing that was one of the motivations to take this work off the back burner.
I'm not sure about maps. But I do know of applications representing the centerline for autonomous vehicles that use polynomial spiral representations, specifically because of the extremely high degrees of continuity you can attain. For that, you don't have to represent these high-tension curvature regions.
I do think there is a specific application for drawing smooth connecting lines in autogenerated diagrams. These tend to be S-shaped, and with Béziers you tend to get curvature peaks near the endpoints. You're much better off with monotonic curvature and with spirals that's easier to achieve. And I also believe being able to get those squircle/superellipse shapes would help as well.
The other question is whether the control is local. As others have remarked, this has much more to do with the way the curve is embedded into a spline than the curve family itself. In particular, it is deeply affected by the continuity constraints. As payment for the local support, cubic Béziers only give G1 continuity. Euler spiral splines, by contrast, are G2 but changes do cause those ripples.
The pen tool prototype linked in the blog post suggests giving designers more choices. If you specify all control points, you get G1 just like a cubic Bézier. But it also gives the choice of specifying one control point on a smooth endpoint, and solving the other for G2 continuity. In my experience, it feels more like local control than Euler spiral-like splines. When you want smoother curves, you do that, and when you're willing to sacrifice continuity for local control, that's also possible.
Yes, there are regions of the parameter space where moving a control point has vanishing effect on the curve shape. I'm not thrilled about this and have explored alternatives, but this is the best I could come up with. Pretty much all approaches based on solving for optimal curve fit have discontinuous "flipping" behavior. Another approach would be to split
We haven't yet done the work wiring this up into a spline like the older pen tool draft. The "auto point" is not a form of subdivision but is a way of achieving G2 continuity.
Yes, hyperbeziers can be split and subdivided without much trouble at all, and being closed under subdivision is an important mathematical property that was lacking in the earlier draft. This follows directly from their formulation as polynomials. If you look into the code, you'll see that there's subdivision at the near-cusp to make the integral robust.
The P/C naming evokes Hermite but there wasn't a lot of thought into it.
Math is heavier, but this is more nuanced than you might expect. My feeling is that computers are fast, so if we can draw higher quality curves with less human effort, it's worth it. But the seeming simplicity of Béziers is deceptive; you often have to solve inverse arc length problems (for example to compute dashing), and curve fitting is really hard (I have a blog post in the pipeline on that). So I think overall the math is only slightly heavier.
The goal is human-driven interactive design, originally motivated by font design. Splitting into more Béziers obviously gives much finer control, but it's hard to avoid them getting lumpy. In most fonts you have a minimum number of Bézier segments and accept whatever fine details the Bézier math gives you. That's even more so when making variable fonts, where the control points are interpolated.
I haven't yet done a rigorous comparison with NURBS. While they're hugely popular in CAD, they're basically unused in things like font design.
Thanks for these questions, they obviously show a deeper understanding.
There are other Bézier shapes that the hyperbezier can't match, including two cusps on the interior. As you say, I consider these not very useful in actual 2D design, and am happy to give them up for smoother curves and the increased range of superellipse shapes.
Take the irow loop in vga12.inc[1] (of course I'm going to look at the graphics code). Each iteration does push di; rep stosb; pop di; add di, ROW_BYTES (and some other stuff). Why not save the push/pop and add (ROW_BYTES - count), which could be stored in a register (dx is free here)? Just the push+pop is 15+12 cycles.
[1]: https://github.com/jggonz/os8088/blob/1f2fae44180fadaf85368c...
[1]: https://github.com/DusterTheFirst/pico-dvi-rs/blob/main/src/...
This works today with tinyusb and pico-pio-usb, but I'm also playing with a Rust port which I'm hoping will have higher performance.
According to [1], the weight of a modern runnable version is around 39k.
The ratio of how good it sounds compared to how much computing power it uses is ridiculous. The C64 has ballpark 3 orders of magnitude less CPU throughput as an RP2350, and the codebase uses an impressive array of tricks to do actual formant synthesis (barely) and a pretty refined form of Elovitz text to phoneme conversion. One of my favorite tricks is its up and down bouncy pitch, which is not random, but based on the opposite contour as the first formant. It's simplistic but enough to make it not sound like a robotic monotone.
I've been playing around with this some myself and SAM is an inspiration, along with other landmark systems like MITalk (predecessor to DECtalk), SP0256, and other. I believe it's possible to use modern techniques to get pretty good sounding speech in, say, 64k and 10% of the throughput of a RP2350. It's really cool to see projects like OP, especially under permissive license.
There's something else a lot stranger going on, though. It is a proper monospace font, but the typesetting on the shirt is not. There's some kerning going on (I noticed it especially in the 'Iy' pair), and also it appears that narrower characters such as 'i' take less horizontal space. If I had to guess, I would say that it was set with a tool such as "optical kerning" in InDesign.