Folks, So, I think we kind of agree that some named registers could be implemented, and that it should be an intrinsic that passes the name of the register down. This C code: register unsigned long current_stack_pointer asm("sp"); unsigned long get_stack_pointer_addr() { return current_stack_pointer; } void set_stack_pointer_addr(unsigned long addr) { current_stack_pointer = addr; } Would become something like: define i32 @get_stack_pointer_addr() nounwind { entry: %0 = call i32 @llvm.read_register("sp") ret i32 %0 } define void @set_stack_pointer_addr(i32 %addr) nounwind { entry: call void @llvm.write_register("sp", %addr) ret void } Note particularly: - There are no globals defined. Since you can't take the address of that variable, you can only read and write directly to it, it should be safe to translate all reads and writes to intrinsics without any reference to a global variable. - I'm letting the name to be an argument (as opposed to metadata) for simplicity. It might be better to use metadata or some other way. Is that a reasonable expectation of the implementation? Now, onto specifics... 1. RegisterByName I couldn't find a way to get a register by name. I could teach the TableGen backend to print an additional table with a StringSwitch on <Target>GenRegisterInfo.inc and add a method getRegisterByName(char *), but that would expose a huge number of unwanted register classes which could open a huge can of worms. My idea was to be very specific and let the implementation local as <Target>RegisterInfo::getNamedRegister(char *) which will be *just* for named registers and will only map a few cases, erring/warning/asserting otherwise. With this, we can control what kind of register we do accept, and only expand the list when we actually implement support for them. Currently, the only registers we will support are the non-allocatable ones, mainly stack and program counters. Since this is target specific, we could make the default behaviour to be emitting "Register not available for named register globals" error. Is there a better way of doing this? 2. Name in SDNode If I leave the name as a string literal ("sp"), would that become an i8* SDNode? I'm a big rusty on SDNodes, but if I get a Node->getValue() on an i8*, I'll get the address of it. How do I get the value as a string? If I would use metadata, how do I pass it to the intrinsic? @llvm.read_register(!0) !0 = metadata !{metadata !"sp"} Is this valid IR? cheers, --renato
On Fri, Mar 28, 2014 at 03:00:41PM +0000, Renato Golin wrote:> Folks, > > So, I think we kind of agree that some named registers could be > implemented, and that it should be an intrinsic that passes the name > of the register down. > > This C code: > > register unsigned long current_stack_pointer asm("sp"); > unsigned long get_stack_pointer_addr() { > return current_stack_pointer; > } > void set_stack_pointer_addr(unsigned long addr) { > current_stack_pointer = addr; > } > > Would become something like: > > define i32 @get_stack_pointer_addr() nounwind { > entry: > %0 = call i32 @llvm.read_register("sp") > ret i32 %0 > } > > define void @set_stack_pointer_addr(i32 %addr) nounwind { > entry: > call void @llvm.write_register("sp", %addr) > ret void > } > > Note particularly: > - There are no globals defined. Since you can't take the address of > that variable, you can only read and write directly to it, it should > be safe to translate all reads and writes to intrinsics without any > reference to a global variable. > - I'm letting the name to be an argument (as opposed to metadata) for > simplicity. It might be better to use metadata or some other way. > > Is that a reasonable expectation of the implementation? > > Now, onto specifics... > > 1. RegisterByName > > I couldn't find a way to get a register by name. I could teach the > TableGen backend to print an additional table with a StringSwitch on > <Target>GenRegisterInfo.inc and add a method getRegisterByName(char > *), but that would expose a huge number of unwanted register classes > which could open a huge can of worms. > > My idea was to be very specific and let the implementation local as > <Target>RegisterInfo::getNamedRegister(char *) which will be *just* > for named registers and will only map a few cases, > erring/warning/asserting otherwise. > > With this, we can control what kind of register we do accept, and only > expand the list when we actually implement support for them. > Currently, the only registers we will support are the non-allocatable > ones, mainly stack and program counters. > > Since this is target specific, we could make the default behaviour to > be emitting "Register not available for named register globals" error. > > Is there a better way of doing this? > > > 2. Name in SDNode > > If I leave the name as a string literal ("sp"), would that become an > i8* SDNode? I'm a big rusty on SDNodes, but if I get a > Node->getValue() on an i8*, I'll get the address of it. How do I get > the value as a string? >Couldn't you avoid using a string literal in the SDNode, by having the SelectionDAGBuilder look up the register id with the function you proposed above and then add that id as the operand to the intrinsic's SDNode? -Tom> If I would use metadata, how do I pass it to the intrinsic? > > @llvm.read_register(!0) > !0 = metadata !{metadata !"sp"} > > Is this valid IR? > > cheers, > --renato > _______________________________________________ > LLVM Developers mailing list > LLVMdev at cs.uiuc.edu http://llvm.cs.uiuc.edu > http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev
On 3/28/2014 10:00 AM, Renato Golin wrote:> > define i32 @get_stack_pointer_addr() nounwind { > entry: > %0 = call i32 @llvm.read_register("sp") > ret i32 %0 > } > > define void @set_stack_pointer_addr(i32 %addr) nounwind { > entry: > call void @llvm.write_register("sp", %addr) > ret void > }How are you going to represent the side-effects of such builtins? -K -- Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
On 28 March 2014 15:25, Tom Stellard <tom at stellard.net> wrote:> Couldn't you avoid using a string literal in the SDNode, by having the > SelectionDAGBuilder look up the register id with the function you > proposed above and then add that id as the operand to the intrinsic's > SDNode?That's a good idea, change the argument to an id on SelectionDAGBuilder::visitIntrinsicCall() and use the TargetLowering to retrieve the ids. Thanks! --renato
On 28 March 2014 15:56, Krzysztof Parzyszek <kparzysz at codeaurora.org> wrote:> How are you going to represent the side-effects of such builtins?Do you mean the possible adverse effects they can have on the program if you write to the wrong register at the wrong time? I don't think we should represent it at all. That brings me to a related question: is there an attribute that makes sure those intrinsic calls don't get moved around, or hoisted out of loops, etc? A function or parameter attribute that means the same as "load volatile"? cheers, --renato
On Sat, Mar 29, 2014 at 1:30 AM, Renato Golin <renato.golin at linaro.org>wrote:> Folks, > > So, I think we kind of agree that some named registers could be > implemented, and that it should be an intrinsic that passes the name > of the register down. > > This C code: > > register unsigned long current_stack_pointer asm("sp"); > unsigned long get_stack_pointer_addr() { > return current_stack_pointer; > } > void set_stack_pointer_addr(unsigned long addr) { > current_stack_pointer = addr; > } > > Would become something like: > > define i32 @get_stack_pointer_addr() nounwind { > entry: > %0 = call i32 @llvm.read_register("sp") > ret i32 %0 > } > > define void @set_stack_pointer_addr(i32 %addr) nounwind { > entry: > call void @llvm.write_register("sp", %addr) > ret void > } > >Should that be something like; declare void @llvm.write_register.sp(i32 val) declare i32 @llvm.read_register.sp() define i32 @get_stack_pointer_addr() nounwind { entry: %0 = call i32 @llvm.read_register.sp() ret i32 %0 } define void @set_stack_pointer_addr(i32 %addr) nounwind { entry: call void @llvm.write_register.sp(%addr) ret void } Then you don't need to clutter the IR with metadata or a constant i8* to identify the register. There's precedent for overloading intrinsics. -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20140329/8af554ea/attachment.html>
On Fri, Mar 28, 2014 at 03:00:41PM +0000, Renato Golin wrote:> So, I think we kind of agree that some named registers could be > implemented, and that it should be an intrinsic that passes the name > of the register down.I'd like to separate this into two different functionalities: (1) Reserve registers, so that normal allocation won't use them. This can be done on a global or function level. (2) Provide intrinsincs to read/write a given register. The former is also required to implement -ffixed-XXX, the second would be used to used to implement named registers in combination with (1). Joerg
On 29 March 2014 01:16, Jeremy Lakeman <Jeremy.Lakeman at gmail.com> wrote:> Should that be something like; > > declare void @llvm.write_register.sp(i32 val) > declare i32 @llvm.read_register.sp()There are two problems with that: 1. Front-ends have to know all registers that are supported by all LLVM back-ends for that functionality. If the overloading is target-independent but language-dependent, it makes sense. But especially in this case, where we'll implement the feature in multiple steps, it'll be very complicated to coordinate all parts. 2. I'd have to create one multiclass for the intrinsic TableGen pattern for each supported architecture. Given that Intrinsics.td is largely (if not completely) target independent, I'd hate to start a pattern that should be done in the first place. Your argument against adding a global string variable or a metadata node is valid, this is why my first proposal is to use the string directly from the asm() construct. However, if your argument is to use register.sp as "the stack pointer", that would make front-ends understand which register is the stack pointer on each backend, which is something I don't think they should do. cheers, --renato
On 29 March 2014 10:37, Joerg Sonnenberger <joerg at britannica.bec.de> wrote:> I'd like to separate this into two different functionalities:We will. But in reverse order.> (1) Reserve registers, so that normal allocation won't use them. > This can be done on a global or function level.This is the most controversial part of the proposal and is the least important to make all known cases work. I believe that having access to registers in that way can only be explained by the inefficiency of the compiler (for noticing that a register variable should not spill) and could be easily changed to be a hard rule by a given flag, so that register pressure still wouldn't spill the variable. This is similar to named register, but with the additional benefit that the compiler is free to choose the register, while in the second case, the user does. It also would work with all standard C code already available using the `register` keyword. But that's for another discussion...> (2) Provide intrinsincs to read/write a given register.That's the idea right now. Just that. No guarantees. Aperture Labs kind of science (not Black Mesa). cheers, --renato
On Sat, Mar 29, 2014 at 11:46:13AM +1030, Jeremy Lakeman wrote:> declare void @llvm.write_register.sp(i32 val) > declare i32 @llvm.read_register.sp()I'd prefer to use declare void @llvm.write_register(i32 regno, i32 val) declare i32 @llvm.read_register(i32 regno) where regno is the DWARF name or a special reservation e.g. for IP or SP. Joerg