Gus Smith via llvm-dev
2018-Mar-18 22:22 UTC
[llvm-dev] Generating a custom opcode from an LLVM intrinsic
Hello all. LLVM newbie here. If anything seems glaringly wrong with my use of LLVM, that's probably why. Here's what I'm trying to do. I have modified the gem5 simulator to accept a "new" x86 instruction. I've done this by just reserving the opcode in gem5's ISA specification, just as all other instructions are specified. I'm trying to get an LLVM backend to generate this opcode during code generation. My current plan is: 1. During an LLVM pass, I'll detect a series of instructions which can be replaced with this new instruction. (The new instruction is a "cache compute" instruction -- in my passes, I replace a series of loads, operations, and stores with this single instruction.) This step is complete. 2. I replace the series of instructions with an intrinsic. I have added an intrinsic using the instructions here <https://llvm.org/docs/ExtendingLLVM.html#adding-a-new-intrinsic-function>. This step is complete. 3. During code generation, the intrinsic should be converted to this reserved opcode. This is where I'm stuck. I'm stuck on step 3. I have two main questions that should unblock me: Question 1: where is the code that maps from intrinsics to instructions? The link above states: "Add support to the .td file for the target(s) of your choice in lib/Target/*/*.td. This is usually a matter of adding a pattern to the .td file that matches the intrinsic, though it may obviously require adding the instructions you want to generate as well. There are lots of examples in the PowerPC and X86 backend to follow." However, looking through these examples isn't illuminating anything for me. Any more documentation or high-level explanation on this subject would be really helpful. I have read something about "lowering" of intrinsics; not sure if that's relevant. Question 2: will I be able to generate this opcode directly from the intrinsic, or will I have to add the opcode as an LLVM IR instruction and specify how it gets compiled? I can imagine two options: option 1: I can define a "translation" from intrinsic straight to an x86 opcode. option 2: I can define a "translation" (perhaps in a .td file? I think that's what they're used for) which translates my intrinsic into a new instruction, and then I can define another translation which will map the new instruction to my opcode during code gen. If this is the case, I'm not sure there's any point to having an intrinsic; I should just add a new instruction instead. Hoping someone can help! As you can tell, I'm a little lost...the documentation for LLVM is great, but it's a little above my level right now :) Gus Smith, PSU -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20180318/d3ae36ce/attachment.html>
Craig Topper via llvm-dev
2018-Mar-18 23:43 UTC
[llvm-dev] Generating a custom opcode from an LLVM intrinsic
Here's a couple examples for mapping an intrinsic to an X86 instruction from X86InstrInfo.td. If you look for int_x86_* in any X86Instr*.td you can find others. let Predicates = [HasCLFLUSHOPT], SchedRW = [WriteLoad] in def CLFLUSHOPT : I<0xAE, MRM7m, (outs), (ins i8mem:$src), "clflushopt\t$src", [(int_x86_clflushopt addr:$src)], IIC_SSE_PREFETCH>, PD; let Predicates = [HasCLWB], SchedRW = [WriteLoad] in def CLWB : I<0xAE, MRM6m, (outs), (ins i8mem:$src), "clwb\t$src", [(int_x86_clwb addr:$src)], IIC_SSE_PREFETCH>, PD; The encoding information for the binary output is buried in these definitions too. If you tell me what opcode you've chosen I can tell you what the right things are to get the binary output. ~Craig On Sun, Mar 18, 2018 at 3:22 PM, Gus Smith via llvm-dev < llvm-dev at lists.llvm.org> wrote:> Hello all. LLVM newbie here. If anything seems glaringly wrong with my use > of LLVM, that's probably why. > > Here's what I'm trying to do. I have modified the gem5 simulator to accept > a "new" x86 instruction. I've done this by just reserving the opcode in > gem5's ISA specification, just as all other instructions are specified. > > I'm trying to get an LLVM backend to generate this opcode during code > generation. My current plan is: > > 1. During an LLVM pass, I'll detect a series of instructions which can > be replaced with this new instruction. (The new instruction is a "cache > compute" instruction -- in my passes, I replace a series of loads, > operations, and stores with this single instruction.) This step is complete. > 2. I replace the series of instructions with an intrinsic. I have > added an intrinsic using the instructions here > <https://llvm.org/docs/ExtendingLLVM.html#adding-a-new-intrinsic-function>. > This step is complete. > 3. During code generation, the intrinsic should be converted to this > reserved opcode. This is where I'm stuck. > > I'm stuck on step 3. I have two main questions that should unblock me: > > Question 1: where is the code that maps from intrinsics to instructions? > The link above states: > > "Add support to the .td file for the target(s) of your choice in > lib/Target/*/*.td. This is usually a matter of adding a pattern to the > .td file that matches the intrinsic, though it may obviously require adding > the instructions you want to generate as well. There are lots of examples > in the PowerPC and X86 backend to follow." > > However, looking through these examples isn't illuminating anything for > me. Any more documentation or high-level explanation on this subject would > be really helpful. I have read something about "lowering" of intrinsics; > not sure if that's relevant. > > Question 2: will I be able to generate this opcode directly from the > intrinsic, or will I have to add the opcode as an LLVM IR instruction and > specify how it gets compiled? I can imagine two options: > option 1: I can define a "translation" from intrinsic straight to an x86 > opcode. > option 2: I can define a "translation" (perhaps in a .td file? I think > that's what they're used for) which translates my intrinsic into a new > instruction, and then I can define another translation which will map the > new instruction to my opcode during code gen. If this is the case, I'm not > sure there's any point to having an intrinsic; I should just add a new > instruction instead. > > Hoping someone can help! As you can tell, I'm a little lost...the > documentation for LLVM is great, but it's a little above my level right now > :) > > Gus Smith, PSU > > > _______________________________________________ > LLVM Developers mailing list > llvm-dev at lists.llvm.org > http://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/20180318/3b2f462e/attachment.html>
Gus Smith via llvm-dev
2018-Mar-19 02:39 UTC
[llvm-dev] Generating a custom opcode from an LLVM intrinsic
Craig, thanks for the quick response. That helps a lot. I had no clue they were buried in there, though I guess I should have looked harder -- the hex should have given me a clue, perhaps! For the sake of my own edification (and not taking up too much of your time) I will try to generate it myself. I've found the definition of the "I" class at line 358 of llvm/lib/Target/X86/X86InstrFormats.td, which helps a lot. Let's assume I want to produce opcode 0x16 (which I'm using because it doesn't seem to be implemented in gem5 otherwise, and would simply produce a warning). Then my guess is that I should use something like: def CACHEADD : I<0x16, FORMAT, (outs), (ins), ASM, [(int_cache_add)]>, PD; where FORMAT comes from http://legup.eecg.utoronto.ca/doxygen/namespacellvm_1_1X86II.html and ASM = ??? and i deleted IIC_SSE_PREFETCH (because I'm not sure what this flag indicates, but I assume it's not needed). I'm not sure what that PD is or if it should stay. Looking for input on this! Clearly it's not correct as-is, but I feel like I'm at least understanding parts of it. Thanks! For posterity, this page helped a lot, and probably should have been read first: https://llvm.org/docs/TableGen/index.html In smaller part, this one helped too, but read the above page first: https://llvm.org/docs/TableGen/LangRef.html On Sun, Mar 18, 2018 at 7:43 PM, Craig Topper <craig.topper at gmail.com> wrote:> Here's a couple examples for mapping an intrinsic to an X86 instruction > from X86InstrInfo.td. If you look for int_x86_* in any X86Instr*.td you can > find others. > > let Predicates = [HasCLFLUSHOPT], SchedRW = [WriteLoad] in > def CLFLUSHOPT : I<0xAE, MRM7m, (outs), (ins i8mem:$src), > "clflushopt\t$src", [(int_x86_clflushopt addr:$src)], > IIC_SSE_PREFETCH>, PD; > > let Predicates = [HasCLWB], SchedRW = [WriteLoad] in > def CLWB : I<0xAE, MRM6m, (outs), (ins i8mem:$src), "clwb\t$src", > [(int_x86_clwb addr:$src)], IIC_SSE_PREFETCH>, PD; > > The encoding information for the binary output is buried in these > definitions too. If you tell me what opcode you've chosen I can tell you > what the right things are to get the binary output. > > > ~Craig > > On Sun, Mar 18, 2018 at 3:22 PM, Gus Smith via llvm-dev < > llvm-dev at lists.llvm.org> wrote: > >> Hello all. LLVM newbie here. If anything seems glaringly wrong with my >> use of LLVM, that's probably why. >> >> Here's what I'm trying to do. I have modified the gem5 simulator to >> accept a "new" x86 instruction. I've done this by just reserving the opcode >> in gem5's ISA specification, just as all other instructions are specified. >> >> I'm trying to get an LLVM backend to generate this opcode during code >> generation. My current plan is: >> >> 1. During an LLVM pass, I'll detect a series of instructions which >> can be replaced with this new instruction. (The new instruction is a "cache >> compute" instruction -- in my passes, I replace a series of loads, >> operations, and stores with this single instruction.) This step is complete. >> 2. I replace the series of instructions with an intrinsic. I have >> added an intrinsic using the instructions here >> <https://llvm.org/docs/ExtendingLLVM.html#adding-a-new-intrinsic-function>. >> This step is complete. >> 3. During code generation, the intrinsic should be converted to this >> reserved opcode. This is where I'm stuck. >> >> I'm stuck on step 3. I have two main questions that should unblock me: >> >> Question 1: where is the code that maps from intrinsics to instructions? >> The link above states: >> >> "Add support to the .td file for the target(s) of your choice in >> lib/Target/*/*.td. This is usually a matter of adding a pattern to the >> .td file that matches the intrinsic, though it may obviously require adding >> the instructions you want to generate as well. There are lots of examples >> in the PowerPC and X86 backend to follow." >> >> However, looking through these examples isn't illuminating anything for >> me. Any more documentation or high-level explanation on this subject would >> be really helpful. I have read something about "lowering" of intrinsics; >> not sure if that's relevant. >> >> Question 2: will I be able to generate this opcode directly from the >> intrinsic, or will I have to add the opcode as an LLVM IR instruction and >> specify how it gets compiled? I can imagine two options: >> option 1: I can define a "translation" from intrinsic straight to an x86 >> opcode. >> option 2: I can define a "translation" (perhaps in a .td file? I think >> that's what they're used for) which translates my intrinsic into a new >> instruction, and then I can define another translation which will map the >> new instruction to my opcode during code gen. If this is the case, I'm not >> sure there's any point to having an intrinsic; I should just add a new >> instruction instead. >> >> Hoping someone can help! As you can tell, I'm a little lost...the >> documentation for LLVM is great, but it's a little above my level right now >> :) >> >> Gus Smith, PSU >> >> >> _______________________________________________ >> LLVM Developers mailing list >> llvm-dev at lists.llvm.org >> http://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/20180318/3f58b518/attachment.html>