"Look again at that dot. That's here. That's home. That's us." — Carl Sagan, 1994
Hello, I’m Shivam, online I go by phyBrackets.
I’m a software engineer based in India. At KDAB I work on customer projects built with Modern C++ and Qt, the kind of software where things actually need to work properly and run fast. I’ve also worked on Clazy, a static analyzer that finds Qt-specific bugs at compile time before they become your problem later, and on a physics engine.
In school I stayed away from computers completely. Other things felt way more interesting to me, physics, biology, chemistry, the kind of questions that are almost too big to even ask. Programming came late for me, and what kept me in it wasn’t the code itself, it was realising that it’s basically the same curiosity just showing up differently. I’m in it now, fully.
LLVM and debug information
Outside of work, I contribute to the LLVM compiler infrastructure, and the thing I’m focused on is how compiler optimizations quietly break debug information.
So here’s what happens. When you compile your code with -O2 or -O3, Clang does a lot of work under the hood, inlining functions, moving instructions around, pulling variables out of memory into registers, throwing away computations it knows are pointless. The final machine code often looks nothing like what you wrote, and that’s fine, that’s the whole idea. But there’s a format called DWARF that gets embedded in your binary alongside the machine code, and its job is to act like a map between that transformed code and your original source. So when you fire up GDB or LLDB, it can still show you where you are, what your variables hold, what called what.
The problem is that a lot of the optimization passes in LLVM’s pipeline just don’t bother keeping that map updated when they change things. A pass inlines a function, or reassociates some arithmetic, or promotes a local variable into a constant, and it just drops the little #dbg_value markers that were tracking your variables through those changes. The DWARF that ends up in the binary is then missing things or just wrong. So your debugger shows <optimized out>, or jumps to the wrong line, or shows a value that stopped being true several optimizations ago. Not because debugging optimized code is some unsolvable problem, but because the compiler just quietly lost track somewhere in the middle.
What I find interesting is that it’s not one clean problem you can fix in one place. It’s a lot of small failures spread across many passes, each one a bit different. I’m working on fixing this across several passes, teaching them to hold onto debug information where they can using DWARF expressions, and at least not throw it away silently when they can’t. LLVM has some tooling for finding these issues, debugify and the newer -fverify-debuginfo-preserve flag in Clang, and the goal I’m working towards is a pipeline where every pass actually takes care of the debug information it touches.
RISC-V
I’m also interested in RISC-V, an open and free instruction set architecture, and honestly one of the more exciting things happening in hardware right now. Most ISAs you run into are really old and carrying a lot of history with them. x86 for example has been accumulating instructions and weird special cases since the late 1970s. RISC-V starts from scratch, a small clean base built on RISC principles, with optional extensions you add only when you actually need them. The base integer ISA has 47 instructions and you can read through the whole spec and actually understand it, which is a rare thing.
What makes it really interesting is that it’s open. Anyone can build chips with it, run it, extend it for specific use cases, without paying anyone for the privilege. There are already RISC-V chips running in embedded systems, in research processors, and more are coming. LLVM has solid RISC-V backend support too, so it connects naturally to the compiler stuff I’m already doing. There’s something really satisfying about understanding a system all the way from how instructions are encoded up through the compiler and into the debugger, and RISC-V makes that actually possible.
Consciousness and the big questions
Outside of all that, I think about neuroscience and consciousness a lot, specifically the hard problem of why there’s something it feels like to be a brain doing computations, when most physical processes just don’t feel like anything. I’ve gone deep on quantum mechanics, blockchain, and a bunch of other rabbit holes over the years. Some stuck. Most of them at least changed how I think about the next thing I picked up.
I find it genuinely hard to stay uninterested in something once I understand even a little bit of it. That’s probably the most honest thing I can say about myself.
This is a digital garden, not a blog, not a portfolio. Notes here are in different stages, some rough ideas, some more worked out, most somewhere in between.