Hendrik Greving via llvm-dev
2019-Dec-18 20:39 UTC
[llvm-dev] Spilling to register for a given register class
Ok, thanks. Except the question was meant slightly different. Less w.r.t. organizing the register classes, and more w.r.t. implementation. I've noticed for instance that when trying to model this straight forwardly by writing a vreg from spills and reading this from fills (not further elaborated here), that the spiller can't handle vreg def-use pairs: there are assertions making sure a spill does not have any uses , e.g. see InlineSpiller.cpp, allDefsAreDead() calls. This made me wonder if this is supported natively at all. On Wed, Dec 18, 2019 at 12:02 PM Quentin Colombet <qcolombet at apple.com> wrote:> Hi Hendrik, > > This question is a recurring one. Check for instance > https://lists.llvm.org/pipermail/llvm-dev/2016-February/095436.html > <https://lists.llvm.org/pipermail/llvm-dev/2016-February/095457.html> for > a related conversation. > > What this conservation boils down to is that you can achieve that by > providing a larger register class that contains the union of the registers > that are used with where they can be spilled. > > For instance, let say you have a register class GPR that can be spilled > into SPR. > You would create three register classes: GPR, SPR and GPR_union_SPR. > GPR_union_SPR is never explicitly used in any real instruction (i.e., it > does not appear in any MC description), but will give a way to regalloc to > relax the constraints on available registers when doing live-range > splitting. > > Let say you have the following code: > V1(gpr) = op > … // <— too high gpr pressure > = op V1(gpr) > > What RA will do is first split the live range of V1: > V1(gpr) = op > V2 = copy V1 > … // <— too high gpr pressure > V3(gpr) = copy V2 > = op V3(gpr) > > Now, V2 does not need to be constrained on gpr anymore and will end up > using GPR_union_SPR. So effectively, if there is no GPR available for V2, > an SPR will be used and thus V1 will be “spilled” to a GPR. > > Disclaimer: The live-range splitting may act up and it may not be as > straight forward to apply this solution but the idea remains valid. > > AMDGPU does something a bit different IIRC, it basically runs the > allocator several times: > - First they allocate GPRs and spill them into SPR, since SPR registers > are not taken into account during this iteration there is no issue for > creating new live ranges during spilling for these ones > - Second they allocate SPRs and they get spilled to memory. > > Cheers, > -Quentin > > On Dec 17, 2019, at 1:47 PM, Hendrik Greving via llvm-dev < > llvm-dev at lists.llvm.org> wrote: > > Hello, for an architecture that doesn't have a good way to load/store a > given register class to memory, is it instead easy to spill/fill from > another register class instead? > e.g. > - storeRegToStack/loadRegFromStack use a pseudo instruction and add > virtual register operand is not supported (spill optimization doesn't seem > to like this). > - AMDGPU backend seems to do sth. similar? > > The only way to safely do it seems to use register scavenger to get a temp > register, and spill this in eliminateFrameIndex? Is there an obvious way to > spill to a register instead? Thanks in advance for any hints > _______________________________________________ > LLVM Developers mailing list > llvm-dev at lists.llvm.org > https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev > > >-------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20191218/c30c6bbd/attachment.html>
Quentin Colombet via llvm-dev
2019-Dec-18 21:11 UTC
[llvm-dev] Spilling to register for a given register class
For the register class union solution, what I was saying is if you have the larger union register class, the spilling happens automatically via live-range splitting (i.e., we don’t hit the inline spiller). For the iterative regalloc idea (where you may hit the inline spiller problem), you would need to look at AMDGPU. I don’t remember how it works on top of my head.> On Dec 18, 2019, at 12:39 PM, Hendrik Greving <hendrik.greving.smi at gmail.com> wrote: > > Ok, thanks. Except the question was meant slightly different. Less w.r.t. organizing the register classes, and more w.r.t. implementation. I've noticed for instance that when trying to model this straight forwardly by writing a vreg from spills and reading this from fills (not further elaborated here), that the spiller can't handle vreg def-use pairs: there are assertions making sure a spill does not have any uses , e.g. see InlineSpiller.cpp, allDefsAreDead() calls. This made me wonder if this is supported natively at all. > > On Wed, Dec 18, 2019 at 12:02 PM Quentin Colombet <qcolombet at apple.com <mailto:qcolombet at apple.com>> wrote: > Hi Hendrik, > > This question is a recurring one. Check for instance https://lists.llvm.org/pipermail/llvm-dev/2016-February/095436.html <https://lists.llvm.org/pipermail/llvm-dev/2016-February/095457.html> for a related conversation. > > What this conservation boils down to is that you can achieve that by providing a larger register class that contains the union of the registers that are used with where they can be spilled. > > For instance, let say you have a register class GPR that can be spilled into SPR. > You would create three register classes: GPR, SPR and GPR_union_SPR. GPR_union_SPR is never explicitly used in any real instruction (i.e., it does not appear in any MC description), but will give a way to regalloc to relax the constraints on available registers when doing live-range splitting. > > Let say you have the following code: > V1(gpr) = op > … // <— too high gpr pressure > = op V1(gpr) > > What RA will do is first split the live range of V1: > V1(gpr) = op > V2 = copy V1 > … // <— too high gpr pressure > V3(gpr) = copy V2 > = op V3(gpr) > > Now, V2 does not need to be constrained on gpr anymore and will end up using GPR_union_SPR. So effectively, if there is no GPR available for V2, an SPR will be used and thus V1 will be “spilled” to a GPR. > > Disclaimer: The live-range splitting may act up and it may not be as straight forward to apply this solution but the idea remains valid. > > AMDGPU does something a bit different IIRC, it basically runs the allocator several times: > - First they allocate GPRs and spill them into SPR, since SPR registers are not taken into account during this iteration there is no issue for creating new live ranges during spilling for these ones > - Second they allocate SPRs and they get spilled to memory. > > Cheers, > -Quentin > >> On Dec 17, 2019, at 1:47 PM, Hendrik Greving via llvm-dev <llvm-dev at lists.llvm.org <mailto:llvm-dev at lists.llvm.org>> wrote: >> >> Hello, for an architecture that doesn't have a good way to load/store a given register class to memory, is it instead easy to spill/fill from another register class instead? >> e.g. >> - storeRegToStack/loadRegFromStack use a pseudo instruction and add virtual register operand is not supported (spill optimization doesn't seem to like this). >> - AMDGPU backend seems to do sth. similar? >> >> The only way to safely do it seems to use register scavenger to get a temp register, and spill this in eliminateFrameIndex? Is there an obvious way to spill to a register instead? Thanks in advance for any hints >> _______________________________________________ >> LLVM Developers mailing list >> llvm-dev at lists.llvm.org <mailto:llvm-dev at lists.llvm.org> >> https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev <https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev> >-------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20191218/737484ff/attachment.html>
Hendrik Greving via llvm-dev
2019-Dec-18 22:55 UTC
[llvm-dev] Spilling to register for a given register class
Ack'd, thanks On Wed, Dec 18, 2019 at 1:11 PM Quentin Colombet <qcolombet at apple.com> wrote:> For the register class union solution, what I was saying is if you have > the larger union register class, the spilling happens automatically via > live-range splitting (i.e., we don’t hit the inline spiller). > > For the iterative regalloc idea (where you may hit the inline spiller > problem), you would need to look at AMDGPU. I don’t remember how it works > on top of my head. > > On Dec 18, 2019, at 12:39 PM, Hendrik Greving < > hendrik.greving.smi at gmail.com> wrote: > > Ok, thanks. Except the question was meant slightly different. Less w.r.t. > organizing the register classes, and more w.r.t. implementation. I've > noticed for instance that when trying to model this straight forwardly by > writing a vreg from spills and reading this from fills (not further > elaborated here), that the spiller can't handle vreg def-use pairs: there > are assertions making sure a spill does not have any uses , e.g. see > InlineSpiller.cpp, allDefsAreDead() calls. This made me wonder if this is > supported natively at all. > > On Wed, Dec 18, 2019 at 12:02 PM Quentin Colombet <qcolombet at apple.com> > wrote: > >> Hi Hendrik, >> >> This question is a recurring one. Check for instance >> https://lists.llvm.org/pipermail/llvm-dev/2016-February/095436.html >> <https://lists.llvm.org/pipermail/llvm-dev/2016-February/095457.html> for >> a related conversation. >> >> What this conservation boils down to is that you can achieve that by >> providing a larger register class that contains the union of the registers >> that are used with where they can be spilled. >> >> For instance, let say you have a register class GPR that can be spilled >> into SPR. >> You would create three register classes: GPR, SPR and GPR_union_SPR. >> GPR_union_SPR is never explicitly used in any real instruction (i.e., it >> does not appear in any MC description), but will give a way to regalloc to >> relax the constraints on available registers when doing live-range >> splitting. >> >> Let say you have the following code: >> V1(gpr) = op >> … // <— too high gpr pressure >> = op V1(gpr) >> >> What RA will do is first split the live range of V1: >> V1(gpr) = op >> V2 = copy V1 >> … // <— too high gpr pressure >> V3(gpr) = copy V2 >> = op V3(gpr) >> >> Now, V2 does not need to be constrained on gpr anymore and will end up >> using GPR_union_SPR. So effectively, if there is no GPR available for V2, >> an SPR will be used and thus V1 will be “spilled” to a GPR. >> >> Disclaimer: The live-range splitting may act up and it may not be as >> straight forward to apply this solution but the idea remains valid. >> >> AMDGPU does something a bit different IIRC, it basically runs the >> allocator several times: >> - First they allocate GPRs and spill them into SPR, since SPR registers >> are not taken into account during this iteration there is no issue for >> creating new live ranges during spilling for these ones >> - Second they allocate SPRs and they get spilled to memory. >> >> Cheers, >> -Quentin >> >> On Dec 17, 2019, at 1:47 PM, Hendrik Greving via llvm-dev < >> llvm-dev at lists.llvm.org> wrote: >> >> Hello, for an architecture that doesn't have a good way to load/store a >> given register class to memory, is it instead easy to spill/fill from >> another register class instead? >> e.g. >> - storeRegToStack/loadRegFromStack use a pseudo instruction and add >> virtual register operand is not supported (spill optimization doesn't seem >> to like this). >> - AMDGPU backend seems to do sth. similar? >> >> The only way to safely do it seems to use register scavenger to get a >> temp register, and spill this in eliminateFrameIndex? Is there an obvious >> way to spill to a register instead? Thanks in advance for any hints >> _______________________________________________ >> LLVM Developers mailing list >> llvm-dev at lists.llvm.org >> https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev >> >> >> >-------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20191218/6bce94fb/attachment.html>