Phil Tomson via llvm-dev
2016-Jan-15 01:34 UTC
[llvm-dev] Expanding a PseudoOp and accessing the DAG
On Thu, Jan 14, 2016 at 6:05 AM, Krzysztof Parzyszek < kparzysz at codeaurora.org> wrote:> On 1/13/2016 4:47 PM, Phil Tomson wrote: > >> >> First off, I got this idea from the LLVM Cookbook chapter 8: Writing an >> LLVM Backend: Lowering to multiple instructions. (now I'm having my >> doubts as to whether this is the right approach) >> > > There is a pass "ExpandISelPseudos", which handles instructions with > custom inserters. You can mark instructions as having custom inserters in > the .td files and then override the EmitInstrWithCustomInserter function to > deal with them. > > > > Let me explain at the assembly level what I'm trying to accomplish. >> >> We're trying to make position independent executables, so we intend to >> have a switch like -fPIE. In that case we've designated some registers >> to be pointers to various address spaces (and our processor is rather >> complicated so there are several address spaces). >> >> Right now, given a global variable called 'answer' in C we end up with >> the following in the .s file: >> >> movimm r1, %rel(answer) # r1 <- offset to 'answer' symbol >> load r1, r1, 0 # r1<-mem[r1+0] >> >> This isn't correct because it should be relative to the GRP register if >> the PIE mode is chosen, what I'd like to get is either: >> >> movimm r1, %rel(answer) >> addI r1, GRP # r1 <- r1 + GRP >> load r1, r1, 0 # r1 <- mem[r1+0] >> >> Or even better: >> >> movimm r1, %rel(answer) >> load r1, r1, GRP # r1 <- mem[r1+GRP] >> >> What I'm getting at the moment is just this part: >> >> load r1, r1, GRP >> >> So the movimm is missing. That's because I've added the Pseudo >> instruction RelAddr and GlobalAddress nodes get converted to RelAddr >> nodes in LowerGlobalAddress.... They used to get converted to the MVINI >> node type there prior to adding the RelAddr pseudo inst. >> >> It feels like more of this needs to be done in the LowerGlobalAddress >> function, but I have no idea how to do it there - you seem to only be >> able to get one instruction out of a lowering like that, not multiple >> instructions. It also seems like (as you point out) the expansion phase >> is too late to be doing it. >> > > Here's what I would do (based on what I understand about your target so > far): > > Define two additional ISD opcodes, specific to your target. One to denote > a "normal" address, the other to mean "address using GRP". For example > (you can invent better names for them): XSTGISD::ADDR_NORMAL and > XSGTISD::ADDR_USE_GRP. Each of them will take a global address as an > operand and return an address, and their only function will be to serve as > a "tag" for the instruction selection algorithm to be able to apply > different selection patterns to them. > > In the .td file, define SDNodes corresponding to these opcodes, e.g. > "addr_normal" and "addr_use_grp".I'm guessing these would be Pseudo Instr nodes? Initially I had this: def SDT_XSTGADDR_NORMAL : SDTypeProfile<0, 1, [SDTCisInt<0>]>; def XSTGADDR_NORMAL : SDNode<"XSTGISD::ADDR_NORMAL", SDT_XSTGADDR_NORMAL>; def addr_normal : XSTGPseudo< (outs), (ins i64imm:$addr), "! ADDR_NORMAL $addr", [(XSTGADDR_NORMAL i64:$addr)]>; But then TableGen gave me: utils/TableGen/DAGISelMatcherGen.cpp:893: void {anonymous}::MatcherGen::EmitResultInstructionAsOperand(const llvm::TreePatternNode*, llvm::SmallVectorImpl<unsigned int>&): Assertion `(!ResultVTs.empty() || TreeHasOutGlue || NodeHasChain) && "Node has no result"' failed. This is apparently because (outs) is empty. So looks like I either need SDNPOutGlue or SDNPHasChain based on the assertion message. This seems to work: def SDT_XSTGADDR_NORMAL : SDTypeProfile<0, 1, [SDTCisInt<0>]>; def XSTGADDR_NORMAL : SDNode<"XSTGISD::ADDR_NORMAL", SDT_XSTGADDR_NORMAL,[SDNPOutGlue]>; def addr_normal : XSTGPseudo< (outs), (ins i64imm:$addr), "! ADDR_NORMAL $addr", [(XSTGADDR_NORMAL i64:$addr)]>; ...but I'm not entirely sure if that's the right definition.> Then, you can have these patterns for loads: > > // Match a load from a non-relocatable address to a simple load > // instruction (with offset 0): > def: Pat<(load (addr_normal tglobaladdr:$addr)), > (load tglobaladdr:$addr, 0)>; > // Match load from a relocatable address to a load with GRP: > def: Pat<(load (addr_use_grp tglobaladdr:$addr)), > (load (movimm tglobaladdr:$addr), GRP)>; > > The patterns above should use tglobaladdr, because you will still need > custom LowerGlobalAddress to generate them first, and it may need to attach > special "target flags" to these addresses. > > Finally, in LowerGlobalAddress, you can check the relocation model, > compilation options, etc. to see if you need to have relocatable addresses, > or not: > > SDValue XSTGISelLowering::LowerGlobalAddress(SDValue Addr, SelectionDAG > &DAG) { > ... > if (NeedGRP) { > SpecialTargetFlags = ...; > SDValue TAddr = DAG.getTargetGlobalAddress(..., SpecialTargetFlags); > return DAG.getNode(XSTGISD::ADDR_USE_GRP, ..., TAddr); > } > > // Non-relocatable address: > SDValue NAddr = DAG.getTargetGlobalAddress(...); > return DAG.getNode(XSTGISD::ADDR_NORMAL, ..., NAddr); > > } > > > -Krzysztof > > -- > Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted > by The Linux Foundation >-------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20160114/da5ec919/attachment.html>
Krzysztof Parzyszek via llvm-dev
2016-Jan-15 13:29 UTC
[llvm-dev] Expanding a PseudoOp and accessing the DAG
Resending to include the mailing list. On 1/14/2016 7:33 PM, Phil Tomson wrote: > > I'm guessing these would be Pseudo Instr nodes? No, they won't be instructions at all, just SDNodes. > Initially I had this: > > def SDT_XSTGADDR_NORMAL : SDTypeProfile<0, 1, [SDTCisInt<0>]>; The type should be "address in, address out", i.e. 1 result and 1 argument: def SDT_XSTGADDR_NORMAL : SDTypeProfile<1, 1, [SDTCisInt<0>, SDTCisSameAs<0, 1>]>; > def XSTGADDR_NORMAL : SDNode<"XSTGISD::ADDR_NORMAL", > SDT_XSTGADDR_NORMAL>; This is pretty much it. The XSTGADDR_NORMAL is what "addr_normal" was meant to be. Now you can use XSTGADDR_NORMAL in patterns for loads and stores. -Krzysztof -- Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation