Hi Ludovic, Ludovic Courtès <l...@gnu.org> writes: > As Dave Thompson wrote on IRC yesterday, this can make a significant > difference for applications such as graphics and game engines.
Yes, it's especially important to be able to avoid heap allocation in games, where GC pauses can be painful. However, any application that needs to do a lot of inexact arithmetic should benefit from the fact that it's a lot cheaper to pack these immediate floats than to allocate and later reclaim a heap-allocated cell. > I hadn’t > read the message yet and thought “hey, why not make instructions for > things like trigonometric functions so you get unboxed floats” but > obviously, as Dave pointed out, that wouldn’t scale well. :-) The unboxing done by our compiler is still the best option where it can be done. However, there are many cases where floats must be boxed, and that seems unavoidable in a language like Scheme. > Fixrats can make rationals more practical in applications where one > would have avoided them for performance. Yes, exactly, that's my motivation for fixrats. I probably should have said so explicitly in my original message, so thanks for mentioning it. I've certainly avoided exact rationals in the past for performance reasons, although they would have made the code much clearer. I suspect I'm not alone. My hope is that in a future, we might be able to use exact rationals more frequently. > IIUC, your plan is to have a different tagging on 32-bit platforms, > without fixflos, right? I’m curious to see how much complexity would > entail from that. Yes, although I'm avoiding the term "fixflos" because IEEE doubles are also fixed width, and thus the term "fixflos" wouldn't adequately distinguish them from IEEE doubles. Anyway, I agree that it's inconvenient to have different tags on different targets, and I've been working to minimize the differences. At present, I'm currently implementing an alternative strategy where pairs are tagged in their pointers instead of in their CARs, which enables us to separate the heap tags and immediate tags into two independent spaces. In this new approach, the heap tags are left unchanged, and the only tags that vary with target word size are the fixints, fixrats, iflos, and pair pointers. All other tags will be uniform across targets, including the non-number immediates. Here's the new version: ;; /* with iflos: xxx: iflo (000 < xxx < 110) ;; (64-bit) 0111: fixrat ;; 1111: fixnum ;; 0110: pair ;; 000: tagged heap object (thob) ;; tttt1110: other immediate ;; ;; without iflos: 1: fixnum ;; (32-bit) 010: fixrat ;; 100: pair ;; 000: tagged heap object (thob) ;; tttt1110: other immediate This new approach brings its own complications, mainly two: (1) It breaks the long-standing assumptions in Guile that all non-immediates have a tag in their first word and that pointers are always untagged. In my preliminary patch, I introduce a new concept called a "tagged heap object" or "thob", and most existing checks for SCM_NIMP or !SCM_IMP must be changed to use SCM_THOB_P. (2) Our existing VM instructions almost invariably specify offsets with a granularity of whole words. To support tagged pair pointers with good performance, I think we need a few new instructions that specify byte offsets, to avoid the expensive extra step of removing the tag before accessing the CAR or CDR of a pair. I've already implemented these changes, and am now in another painful round of debugging. I suspect it will be fine, and likely preferable to my earlier approach of changing all tc7 tags to tc11. I'll report back when I have it working. Thanks, Mark