via llvm-dev
2019-Jun-17 06:36 UTC
[llvm-dev] [InstCombine] addrspacecast assumed associative with gep
> What do you mean exactly by "behave differently on the other side of the cast”? Do you have a concrete example?I was hesitant to say only in that it is probably an "abuse of mechanics" and definitely playing with fire, _however_ the target I'm working on has extensive bit operations for a subset of memory, including atomic test-and-set, etc. It's convenient to be able to pass around addresses of these bits, in particular for handling SFRs and interfacing with peripherals that require the use of these instructions. I know this could be handled with intrinsic functions (as with much in LLVM), however this removes the opportunity for globally allocating low cost atomic flags. Modelled as address spaces, p0 and p<bit> would have different CHAR_BITs, of 8 and 1 respectively. This somewhat works as one would expect too, with, ((bit *)&somevalue)[3] producing bit3 of somevalue - at least until the first time you access through a struct or array: gep(addrspacecast(gep p0, 4) to p<bit>, 3) == (p0 + 4) * 8 + 3 As LLVM optimises this expression to: addrspacecast(gep p0, 4 + 3) to p<bit> Producing something entirely different. But that said, I cannot think of a case where this would be a problem _except_ where CHAR_BIT would be different in one addrspace to the other, which LLVM doesn't claim to support AFAIK. Or somewhat generalised, where pX is a subset of pY, but pY has other addressable values between each valid pX in pY. I note LLVM assumes that an address will load the same value regardless of what addrspace it is read from, which I understand as matching GPU behaviour well. I know some processors have different opcodes to retrieve/store high and low instruction words through the same pointer, which means they could not be modelled as separate addrspaces either, but rather requiring implicit functions to dereference - and this is likely to be the better way, to be fair. My personal thoughts are that LLVM should not require these assumptions of GPU-style addrspace layouts, but offer a target hook to make addrspacecast a blackbox for gep and load/store combining. Or at least spell out somewhere exactly what the rules are on addrspacecast, which seems to be what's missing at the moment - is it something that can be used to describe a form of addressable memory, or is it formally required that they share the same byte size and that if an address is castable from one addrspace to another, that those values are strict aliases of one another.
Nicolai Hähnle-Montoro via llvm-dev
2019-Jun-17 12:10 UTC
[llvm-dev] [InstCombine] addrspacecast assumed associative with gep
On Mon, Jun 17, 2019 at 8:37 AM via llvm-dev <llvm-dev at lists.llvm.org> wrote:> > What do you mean exactly by "behave differently on the other side of the cast”? Do you have a concrete example? > > I was hesitant to say only in that it is probably an "abuse of mechanics" and definitely playing with fire, _however_ the target I'm working on has extensive bit operations for a subset of memory, including atomic test-and-set, etc. It's convenient to be able to pass around addresses of these bits, in particular for handling SFRs and interfacing with peripherals that require the use of these instructions. I know this could be handled with intrinsic functions (as with much in LLVM), however this removes the opportunity for globally allocating low cost atomic flags. > > Modelled as address spaces, p0 and p<bit> would have different CHAR_BITs, of 8 and 1 respectively. This somewhat works as one would expect too, with, ((bit *)&somevalue)[3] producing bit3 of somevalue - at least until the first time you access through a struct or array: > > gep(addrspacecast(gep p0, 4) to p<bit>, 3) == (p0 + 4) * 8 + 3 > > As LLVM optimises this expression to: > > addrspacecast(gep p0, 4 + 3) to p<bit> > > Producing something entirely different.I'm trying to figure out what the actual pointer types would be in your, and I keep coming back to the fact that the underlying problem here seems to be that the meaning of i1 in memory is horribly confused... That is, I suspect that the inner gep in your first example should be an i8 gep and the outer gep should be an i1 gep, which means that a pointer bitcast is missing somewhere. I think you're right in that we probably need to say something about which types a gep can actually operate on in a well-defined manner, on a per-address space basis. This may be entirely based on the byte size. Cheers, Nicolai> > But that said, I cannot think of a case where this would be a problem _except_ where CHAR_BIT would be different in one addrspace to the other, which LLVM doesn't claim to support AFAIK. Or somewhat generalised, where pX is a subset of pY, but pY has other addressable values between each valid pX in pY. > > I note LLVM assumes that an address will load the same value regardless of what addrspace it is read from, which I understand as matching GPU behaviour well. I know some processors have different opcodes to retrieve/store high and low instruction words through the same pointer, which means they could not be modelled as separate addrspaces either, but rather requiring implicit functions to dereference - and this is likely to be the better way, to be fair. > > My personal thoughts are that LLVM should not require these assumptions of GPU-style addrspace layouts, but offer a target hook to make addrspacecast a blackbox for gep and load/store combining. Or at least spell out somewhere exactly what the rules are on addrspacecast, which seems to be what's missing at the moment - is it something that can be used to describe a form of addressable memory, or is it formally required that they share the same byte size and that if an address is castable from one addrspace to another, that those values are strict aliases of one another. > > _______________________________________________ > LLVM Developers mailing list > llvm-dev at lists.llvm.org > https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev-- Lerne, wie die Welt wirklich ist, aber vergiss niemals, wie sie sein sollte.
via llvm-dev
2019-Jun-17 12:24 UTC
[llvm-dev] [InstCombine] addrspacecast assumed associative with gep
I quickly gave up on s1, as you say - InstCombine gets stuck in loops and all kinds of terrible things. For interfacing with Clang, treating them as bools works well enough. You are right though, it had completely skipped my mind that the gep there includes the width of those s8 bools, so it's really not as bad as I thought, *head desk* moment. Only really remains the undocumented point of load/store aliasing where the same address can be read/written in different ways (ie microchip's tblrdl/tblrdh program memory operations - high byte is aliased to the low byte, but accessed via different operations), but I agree we're getting minor here and such false-aliasing is probably better blocked via intrinsic functions. Sorry for the noise 😊> -----Original Message----- > From: Nicolai Hähnle-Montoro <nhaehnle at gmail.com> > Sent: Monday, 17 June 2019 8:11 PM > To: alex.davies at iinet.net.au > Cc: Matt Arsenault <arsenm2 at gmail.com>; llvm-dev <llvm- > dev at lists.llvm.org> > Subject: Re: [llvm-dev] [InstCombine] addrspacecast assumed associative > with gep > > On Mon, Jun 17, 2019 at 8:37 AM via llvm-dev <llvm-dev at lists.llvm.org> > wrote: > > > What do you mean exactly by "behave differently on the other side of > the cast”? Do you have a concrete example? > > > > I was hesitant to say only in that it is probably an "abuse of mechanics" and > definitely playing with fire, _however_ the target I'm working on has > extensive bit operations for a subset of memory, including atomic test-and- > set, etc. It's convenient to be able to pass around addresses of these bits, in > particular for handling SFRs and interfacing with peripherals that require the > use of these instructions. I know this could be handled with intrinsic > functions (as with much in LLVM), however this removes the opportunity for > globally allocating low cost atomic flags. > > > > Modelled as address spaces, p0 and p<bit> would have different > CHAR_BITs, of 8 and 1 respectively. This somewhat works as one would > expect too, with, ((bit *)&somevalue)[3] producing bit3 of somevalue - at > least until the first time you access through a struct or array: > > > > gep(addrspacecast(gep p0, 4) to p<bit>, 3) == (p0 + 4) * 8 + 3 > > > > As LLVM optimises this expression to: > > > > addrspacecast(gep p0, 4 + 3) to p<bit> > > > > Producing something entirely different. > > I'm trying to figure out what the actual pointer types would be in your, and I > keep coming back to the fact that the underlying problem here seems to be > that the meaning of i1 in memory is horribly confused... > > That is, I suspect that the inner gep in your first example should be an i8 gep > and the outer gep should be an i1 gep, which means that a pointer bitcast is > missing somewhere. > > I think you're right in that we probably need to say something about which > types a gep can actually operate on in a well-defined manner, on a per- > address space basis. This may be entirely based on the byte size. > > Cheers, > Nicolai > > > > > > But that said, I cannot think of a case where this would be a problem > _except_ where CHAR_BIT would be different in one addrspace to the > other, which LLVM doesn't claim to support AFAIK. Or somewhat > generalised, where pX is a subset of pY, but pY has other addressable values > between each valid pX in pY. > > > > I note LLVM assumes that an address will load the same value regardless of > what addrspace it is read from, which I understand as matching GPU > behaviour well. I know some processors have different opcodes to > retrieve/store high and low instruction words through the same pointer, > which means they could not be modelled as separate addrspaces either, but > rather requiring implicit functions to dereference - and this is likely to be the > better way, to be fair. > > > > My personal thoughts are that LLVM should not require these assumptions > of GPU-style addrspace layouts, but offer a target hook to make > addrspacecast a blackbox for gep and load/store combining. Or at least spell > out somewhere exactly what the rules are on addrspacecast, which seems to > be what's missing at the moment - is it something that can be used to > describe a form of addressable memory, or is it formally required that they > share the same byte size and that if an address is castable from one > addrspace to another, that those values are strict aliases of one another. > > > > _______________________________________________ > > LLVM Developers mailing list > > llvm-dev at lists.llvm.org > > https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev > > > > -- > Lerne, wie die Welt wirklich ist, > aber vergiss niemals, wie sie sein sollte.