On 28 March 2014 10:17, Chandler Carruth <chandlerc at google.com> wrote:> This has been the long standing historical objection to the feature. It is a > *really* invasive change to the register allocator to plumb this kind of > register reservation through it.Do you mean only the reserved part or the general named register idea? About reserving registers, we already have the ability to reserve certain registers (R9 on ARM, for instance), so it should not be too hard to reserve arbitrary registers. As far as I could find looking backwards, there were many more impediments back then. The inability to represent this in IR correctly, the idea that it should be part of the language (not an intrinsic) thus breaking optimisation rules, the lack of inline asm knowledge in the back-end (fixed by MC and IAS), and the lack of register reservation mechanisms (which we have today). So, while I appreciate there is vast historical reasons to not support it, otherwise Mark and Behan would not have gone that far convincing us of the __builtin_stack_pointer in the first place, I believe that, not only the harder technical problems have being fixed by now, but the arguments towards builtins are less technically valid than the ones supporting named registers.> Worse, the semantics for it being > inherently translation-unit based become deeply confusing in LLVM due to the > potential for (partial) LTO.I don't know LTO well enough to answer that, maybe Rafael can chime in. But ultimately, this particular feature is draconian in itself, and the GCC docs describe lots of cases where it's not safe to use it. This, and the clear_cache builtins, are particularly dangerous but necessary extensions to implementing low level bare-metal code while keeping the code in a manageable level (C-land). We can only guarantee behaviour that is described in the standards we implement. Anything else may have value but still be unsafe in certain conditions, and in that category we have undefined behaviour, implementation defined behaviour and extensions. It's not because a few things might break that we don't use it, and undefined behaviour is a particularly dangerous field that we all thread happily on a day to day basis. Extensions shouldn't be different. cheers, --renato
On Fri, Mar 28, 2014 at 3:39 AM, Renato Golin <renato.golin at linaro.org>wrote:> On 28 March 2014 10:17, Chandler Carruth <chandlerc at google.com> wrote: > > This has been the long standing historical objection to the feature. It > is a > > *really* invasive change to the register allocator to plumb this kind of > > register reservation through it. > > Do you mean only the reserved part or the general named register idea? >Just the reserved part.> > About reserving registers, we already have the ability to reserve > certain registers (R9 on ARM, for instance), so it should not be too > hard to reserve arbitrary registers. >I don't understand how taking registers out of the allocation set within the innards of the target definition itself is really comparable to making some functions register allocate with one set of registers and other functions register allocate with a different set of registers. I don't think this example really means anything.> As far as I could find looking backwards, there were many more > impediments back then. The inability to represent this in IR > correctly, the idea that it should be part of the language (not an > intrinsic) thus breaking optimisation rules, the lack of inline asm > knowledge in the back-end (fixed by MC and IAS), and the lack of > register reservation mechanisms (which we have today). >I don't understand this paragraph. It seems wrong. - We have never (and still don't have) a representation for this in the IR. But that's OK, the whole point has always been that such a representation would be invented. - I don't recall anyone caring about "language" versus intrinsics. - We have always had knowledge of the important part of inline asm: the constraints and clobbers. Neither MC nor IAS is relevant here. - We don't have a generic register reservation mechanism today. If you don't believe the last part, look at how many bugs and how much time it has taken for developers to try to support the frame pointer register usage on x86. That is actually the closest I know of to register reservation, and it has been an endless source of complexity and bugs despite not even needing to interact with the actual input code outside of inline assembly constraints and clobbers.> Worse, the semantics for it being > > inherently translation-unit based become deeply confusing in LLVM due to > the > > potential for (partial) LTO. > > I don't know LTO well enough to answer that, maybe Rafael can chime in. > > But ultimately, this particular feature is draconian in itself, and > the GCC docs describe lots of cases where it's not safe to use it. >And these seem like excellent reasons to not implement the dangerous feature and instead to provide a significantly safer feature and direct users either to not do the dangerous things, or if they are trying to do the safe thing, use the feature which was designed for it. Also, to reiterate, this email is about reserving allocatable registers, not necessarily about every other way you might design global named registers, such as restricting them to unallocatable registers. I still think that is a silly way of representing things, but I don't have some deep concern over its complexity. I *do* have deep concerns over the complexity of making the register set essentially parameterized by user code. I think that is madness.> This, and the clear_cache builtins, are particularly dangerous but > necessary extensions to implementing low level bare-metal code while > keeping the code in a manageable level (C-land). >Global named register variables which reserve allocatable registers are not necessary for anything. Case in point, multiple operating systems today can be built entirely using a compiler which doesn't support them, down to and including their kernels. But I think your going overboard trying to sell the importance of the general area when the objections are regarding specific aspects of the implementation. No one is arguing that we shouldn't support the concrete known use cases. -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20140328/f236a262/attachment.html>
On 28 March 2014 11:16, Chandler Carruth <chandlerc at google.com> wrote:> Just the reserved part.Ok, in that case, I share you concerns. We could easily only implement the reserved ones (stack pointer being the case in hand). If there is any mad reason why allocatable ones should be used (I heard glibc uses R8 for some special things, haven't confirmed myself), we can discuss this topic later.> I don't understand how taking registers out of the allocation set within the > innards of the target definition itself is really comparable to making some > functions register allocate with one set of registers and other functions > register allocate with a different set of registers. I don't think this > example really means anything.The way the ARM back-end does is to treat R9 as a special register from birth, like the frame pointer, and use it to calculate register pressure and to allow it to be allocated or not. I agree this is not the same as doing it with *any* register, but it shouldn't be particularly hard to add isReserved(Reg), add it to the Reserved list, and avoid it during allocation on a per-module (not function) granularity. We'd have to do that on all targets, yes, it won't be easy, but it should be doable and the register allocator already respects a restricted list of reserved registers dynamically. That's not to say that I'm willing to do it now. I agree we should start with the half-sane implementation of already reserved registers.> I don't understand this paragraph. It seems wrong.It probably is... ;)> - We have never (and still don't have) a representation for this in the IR. > But that's OK, the whole point has always been that such a representation > would be invented. > - I don't recall anyone caring about "language" versus intrinsics.So, from my defective memory, I remember people proposing to add a `register` keyword for global variables with some metadata to identify which register, and the loads and stores would have to behave differently (similar to volatile, but with a specific register attached). I don't remember when, or who, or where, it could have been on an LLVM dev meeting. That was not a good idea. Using intrinsics, we don't need to create the global variables at all, and all reads and writes can be mapped to intrinsics, making this change a lot simpler with zero changes to the IR except the creation of two new intrinsics.> - We have always had knowledge of the important part of inline asm: the > constraints and clobbers. Neither MC nor IAS is relevant here.What I meant here is that the MC layer allowed us to interpret inline assembly more thoroughly and add checks (that we do now for textual output as well, as you know). One of the uses of named registers is to pinpoint inline asm variables to specific registers (for instance to mark the stack pointer as clobbered during an MRC call), and in the past, we couldn't guarantee it because we didn't know what the inline asm had inside, as it was just opaque text. Now we can warn users if they're using it wrong, or if there's any danger of clobbering the wrong registers, because we have that knowledge in the MC layer. Makes sense?> - We don't have a generic register reservation mechanism today.Well, TargetRegisterInfo::getAllocatableSet() enquires the targets for getReservedRegs() which could be set to take into account named register globals. Since they're module globals, this could be done once per compilation job, making it a lot simpler.> If you don't believe the last part...I didn't say it would be simple... ;) And I agree with you that we should not do it "just because". There's where the technical reasons for not implementing it trump the reasons for having it as a feature.> And these seem like excellent reasons to not implement the dangerous feature > and instead to provide a significantly safer feature and direct users either > to not do the dangerous things, or if they are trying to do the safe thing, > use the feature which was designed for it.The point here is that __builting_stack_pointer doesn't provide enough additional value to be worth deviating from the norm. True, you can only use the stack pointers and not allocatable registers, and you don't have to name the register, so it's slightly more target-independent, but those were the only reasons. Named registers exist (and will exist) for ages, and people that use it know of the constraints and they're reportedly not an issue. We could add a warning if the user defines any allocatable register, saying that the register will not be reserved... cheers, --renato