robert muth
2009-Jun-08 21:42 UTC
[LLVMdev] patch for llc/ARM: added mechanism to move switch tables from .text -> .data; also cleanup and documentation
On Sun, Jun 7, 2009 at 11:53 PM, Evan Cheng <evan.cheng at apple.com> wrote:> > On Jun 7, 2009, at 6:59 AM, robert muth wrote: > >> On Sat, Jun 6, 2009 at 4:51 PM, Evan Cheng<evan.cheng at apple.com> >> wrote: >>> +cl::opt<std::string> FlagJumpTableSection("jumptable-section", >>> + cl::init(".data.jtab")); >>> + >> >> I thought it would be nice to group all the jumptables together. >> But as long as it stays configurable, I am fine to change the default >> to ".data". > > There is already a TargetAsmInfo::JumpTableDataSection. Why not just > use that?Nice find. I will use that and possible change the current setting, ".const", if it does not work,>> >>> Is this necessary? Why not just put it in the normal data section? >>> Also "outline" jumptable seems like a strange term. Can you think of >>> something else? >> >> >> Yes, that is a tough one. How about "NonInline" instead. > > Or "OutOfLine"?That works for me.> Please add a test case as well. Thanks,I am not sure how to go about testing. I have a script that compiles a bunch of test programs (gnu c torture test, etc.) and then runs the executables on qemu. I run this script with and without my flags and make sure that I do not introduce any new problems -- there are currently plenty of vararg issues. I was thinking of sending this script to the list or maybe checking it into the llvm tree. The key is that whatever tests there are they should just be run with and without the new flag. How do you run backend tests? Robert> Evan > >> >> Robert >> >>> Thanks, >>> Evan >>> >>> Sent from my iPhone >>> On Jun 2, 2009, at 6:26 PM, robert muth <robert at muth.org> wrote: >>> >>> Hi: >>> >>> This is my first patch submission. Hopefully, this is the proper the >>> protocol. >>> Attached is a patch for the llc ARM backend: >>> >>> Added mechanism to generate switch table in a data section >>> rather than having it interleaved with the code. >>> This is controlled by command line flags and off by default. >>> Also, tried to document and improve the code where I modified it. >>> >>> Robert >>> >>> <llc.patch.txt> >>> >>> _______________________________________________ >>> LLVM Developers mailing list >>> LLVMdev at cs.uiuc.edu http://llvm.cs.uiuc.edu >>> http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev >>> >>> _______________________________________________ >>> LLVM Developers mailing list >>> LLVMdev at cs.uiuc.edu http://llvm.cs.uiuc.edu >>> http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev >>> >>> >> >> _______________________________________________ >> LLVM Developers mailing list >> LLVMdev at cs.uiuc.edu http://llvm.cs.uiuc.edu >> http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev > > _______________________________________________ > LLVM Developers mailing list > LLVMdev at cs.uiuc.edu http://llvm.cs.uiuc.edu > http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev >
Evan Cheng
2009-Jun-11 18:27 UTC
[LLVMdev] patch for llc/ARM: added mechanism to move switch tables from .text -> .data; also cleanup and documentation
On Jun 8, 2009, at 2:42 PM, robert muth wrote:> On Sun, Jun 7, 2009 at 11:53 PM, Evan Cheng <evan.cheng at apple.com> > wrote: >> >> On Jun 7, 2009, at 6:59 AM, robert muth wrote: >> >>> On Sat, Jun 6, 2009 at 4:51 PM, Evan Cheng<evan.cheng at apple.com> >>> wrote: >>>> +cl::opt<std::string> FlagJumpTableSection("jumptable-section", >>>> + >>>> cl::init(".data.jtab")); >>>> + >>> >>> I thought it would be nice to group all the jumptables together. >>> But as long as it stays configurable, I am fine to change the >>> default >>> to ".data". >> >> There is already a TargetAsmInfo::JumpTableDataSection. Why not just >> use that? > > Nice find. I will use that and possible change the current setting, > ".const", if it does not work, > >>> >>>> Is this necessary? Why not just put it in the normal data section? >>>> Also "outline" jumptable seems like a strange term. Can you think >>>> of >>>> something else? >>> >>> >>> Yes, that is a tough one. How about "NonInline" instead. >> >> Or "OutOfLine"? > > That works for me. > >> Please add a test case as well. Thanks, > > I am not sure how to go about testing.For this please just add a test case to the llvm dejagnu tests. thanks, Evan> > I have a script that compiles a bunch of test > programs (gnu c torture test, etc.) and then runs the executables > on qemu. I run this script with and without my flags and > make sure that I do not introduce any new problems > -- there are currently plenty of vararg issues. > > I was thinking of sending this script to the list > or maybe checking it into the llvm tree. > > The key is that whatever tests there are they should just > be run with and without the new flag. > How do you run backend tests? > > Robert > > > > >> Evan >> >>> >>> Robert >>> >>>> Thanks, >>>> Evan >>>> >>>> Sent from my iPhone >>>> On Jun 2, 2009, at 6:26 PM, robert muth <robert at muth.org> wrote: >>>> >>>> Hi: >>>> >>>> This is my first patch submission. Hopefully, this is the proper >>>> the >>>> protocol. >>>> Attached is a patch for the llc ARM backend: >>>> >>>> Added mechanism to generate switch table in a data section >>>> rather than having it interleaved with the code. >>>> This is controlled by command line flags and off by default. >>>> Also, tried to document and improve the code where I modified it. >>>> >>>> Robert >>>> >>>> <llc.patch.txt> >>>> >>>> _______________________________________________ >>>> LLVM Developers mailing list >>>> LLVMdev at cs.uiuc.edu http://llvm.cs.uiuc.edu >>>> http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev >>>> >>>> _______________________________________________ >>>> LLVM Developers mailing list >>>> LLVMdev at cs.uiuc.edu http://llvm.cs.uiuc.edu >>>> http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev >>>> >>>> >>> >>> _______________________________________________ >>> LLVM Developers mailing list >>> LLVMdev at cs.uiuc.edu http://llvm.cs.uiuc.edu >>> http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev >> >> _______________________________________________ >> LLVM Developers mailing list >> LLVMdev at cs.uiuc.edu http://llvm.cs.uiuc.edu >> http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev >> > > _______________________________________________ > LLVM Developers mailing list > LLVMdev at cs.uiuc.edu http://llvm.cs.uiuc.edu > http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev
robert muth
2009-Jun-24 21:20 UTC
[LLVMdev] patch for llc/ARM: added mechanism to move switch tables from .text -> .data; also cleanup and documentation
Evan: Sorry for the late follow up, I was out of town last week. Enclosed please find the updated patch including all your suggestions and a dejagnus test. Robert On Thu, Jun 11, 2009 at 2:27 PM, Evan Cheng <evan.cheng at apple.com> wrote:> > On Jun 8, 2009, at 2:42 PM, robert muth wrote: > > > On Sun, Jun 7, 2009 at 11:53 PM, Evan Cheng <evan.cheng at apple.com> > > wrote: > >> > >> On Jun 7, 2009, at 6:59 AM, robert muth wrote: > >> > >>> On Sat, Jun 6, 2009 at 4:51 PM, Evan Cheng<evan.cheng at apple.com> > >>> wrote: > >>>> +cl::opt<std::string> FlagJumpTableSection("jumptable-section", > >>>> + > >>>> cl::init(".data.jtab")); > >>>> + > >>> > >>> I thought it would be nice to group all the jumptables together. > >>> But as long as it stays configurable, I am fine to change the > >>> default > >>> to ".data". > >> > >> There is already a TargetAsmInfo::JumpTableDataSection. Why not just > >> use that? > > > > Nice find. I will use that and possible change the current setting, > > ".const", if it does not work, > > > >>> > >>>> Is this necessary? Why not just put it in the normal data section? > >>>> Also "outline" jumptable seems like a strange term. Can you think > >>>> of > >>>> something else? > >>> > >>> > >>> Yes, that is a tough one. How about "NonInline" instead. > >> > >> Or "OutOfLine"? > > > > That works for me. > > > >> Please add a test case as well. Thanks, > > > > I am not sure how to go about testing. > > For this please just add a test case to the llvm dejagnu tests. > > thanks, > > Evan > > > > > I have a script that compiles a bunch of test > > programs (gnu c torture test, etc.) and then runs the executables > > on qemu. I run this script with and without my flags and > > make sure that I do not introduce any new problems > > -- there are currently plenty of vararg issues. > > > > I was thinking of sending this script to the list > > or maybe checking it into the llvm tree. > > > > The key is that whatever tests there are they should just > > be run with and without the new flag. > > How do you run backend tests? > > > > Robert > > > > > > > > > >> Evan > >> > >>> > >>> Robert > >>> > >>>> Thanks, > >>>> Evan > >>>> > >>>> Sent from my iPhone > >>>> On Jun 2, 2009, at 6:26 PM, robert muth <robert at muth.org> wrote: > >>>> > >>>> Hi: > >>>> > >>>> This is my first patch submission. Hopefully, this is the proper > >>>> the > >>>> protocol. > >>>> Attached is a patch for the llc ARM backend: > >>>> > >>>> Added mechanism to generate switch table in a data section > >>>> rather than having it interleaved with the code. > >>>> This is controlled by command line flags and off by default. > >>>> Also, tried to document and improve the code where I modified it. > >>>> > >>>> Robert > >>>> > >>>> <llc.patch.txt> > >>>> > >>>> _______________________________________________ > >>>> LLVM Developers mailing list > >>>> LLVMdev at cs.uiuc.edu http://llvm.cs.uiuc.edu > >>>> http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev > >>>> > >>>> _______________________________________________ > >>>> LLVM Developers mailing list > >>>> LLVMdev at cs.uiuc.edu http://llvm.cs.uiuc.edu > >>>> http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev > >>>> > >>>> > >>> > >>> _______________________________________________ > >>> LLVM Developers mailing list > >>> LLVMdev at cs.uiuc.edu http://llvm.cs.uiuc.edu > >>> http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev > >> > >> _______________________________________________ > >> LLVM Developers mailing list > >> LLVMdev at cs.uiuc.edu http://llvm.cs.uiuc.edu > >> http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev > >> > > > > _______________________________________________ > > LLVM Developers mailing list > > LLVMdev at cs.uiuc.edu http://llvm.cs.uiuc.edu > > http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev > > _______________________________________________ > LLVM Developers mailing list > LLVMdev at cs.uiuc.edu http://llvm.cs.uiuc.edu > http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev >-------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20090624/01802d9c/attachment.html> -------------- next part -------------- Index: test/CodeGen/ARM/switch.ll ==================================================================--- test/CodeGen/ARM/switch.ll (revision 0) +++ test/CodeGen/ARM/switch.ll (revision 0) @@ -0,0 +1,82 @@ +; Note: jump table has 7 entries +; RUN: llvm-as < %s | llc -march=arm | \ +; RUN: grep .long | count 7 +; Note: no section change +; RUN: llvm-as < %s | llc -march=arm | \ +; RUN: grep .text | count 1 +; Note: no data section +; RUN: llvm-as < %s | llc -march=arm | \ +; RUN: not grep .data +; +; Note: jump table has 7 entries + 1 entry for the table start +; RUN: llvm-as < %s | llc -march=arm -outline-jumptables | \ +; RUN: grep .long | count 8 +; Note one section change +; RUN: llvm-as < %s | llc -march=arm -outline-jumptables | \ +; RUN: grep .text | count 2 +; Note: has data section +; RUN: llvm-as < %s | llc -march=arm -outline-jumptables | \ +; RUN: grep .data | count 1 + + +define i32 @f(i32 %i) nounwind { +entry: + %i_addr = alloca i32 ; <i32*> [#uses=2] + %retval = alloca i32 ; <i32*> [#uses=2] + %0 = alloca i32 ; <i32*> [#uses=8] + %"alloca point" = bitcast i32 0 to i32 ; <i32> [#uses=0] + store i32 %i, i32* %i_addr + %1 = load i32* %i_addr, align 4 ; <i32> [#uses=1] + switch i32 %1, label %bb7 [ + i32 -2, label %bb + i32 -1, label %bb1 + i32 0, label %bb2 + i32 1, label %bb3 + i32 2, label %bb4 + i32 3, label %bb5 + i32 4, label %bb6 + ] + +bb: ; preds = %entry + store i32 33, i32* %0, align 4 + br label %bb8 + +bb1: ; preds = %entry + store i32 0, i32* %0, align 4 + br label %bb8 + +bb2: ; preds = %entry + store i32 7, i32* %0, align 4 + br label %bb8 + +bb3: ; preds = %entry + store i32 4, i32* %0, align 4 + br label %bb8 + +bb4: ; preds = %entry + store i32 3, i32* %0, align 4 + br label %bb8 + +bb5: ; preds = %entry + store i32 15, i32* %0, align 4 + br label %bb8 + +bb6: ; preds = %entry + store i32 9, i32* %0, align 4 + br label %bb8 + +bb7: ; preds = %entry + store i32 999, i32* %0, align 4 + br label %bb8 + +bb8: ; preds = %bb6, %bb5, %bb4, %bb3, %bb2, %bb1, %bb + %2 = load i32* %0, align 4 ; <i32> [#uses=1] + store i32 %2, i32* %retval, align 4 + br label %return + +return: ; preds = %bb8 + %retval9 = load i32* %retval ; <i32> [#uses=1] + ret i32 %retval9 +} + + Index: lib/Target/ARM/ARMISelLowering.h ==================================================================--- lib/Target/ARM/ARMISelLowering.h (revision 74072) +++ lib/Target/ARM/ARMISelLowering.h (working copy) @@ -202,9 +202,10 @@ /// make the right decision when generating code for different targets. const ARMSubtarget *Subtarget; - /// ARMPCLabelIndex - Keep track the number of ARM PC labels created. - /// + /// ARMPCLabelIndex - Keep track of the number of ARM PC labels created. unsigned ARMPCLabelIndex; + /// ARMJumpTableIndex - Keep track of the number ofJump Tables + unsigned ARMJumpTableIndex; void addTypeForNEON(MVT VT, MVT PromotedLdStVT, MVT PromotedBitwiseVT); void addDRTypeForNEON(MVT VT); Index: lib/Target/ARM/ARMConstantPoolValue.h ==================================================================--- lib/Target/ARM/ARMConstantPoolValue.h (revision 74072) +++ lib/Target/ARM/ARMConstantPoolValue.h (working copy) @@ -25,6 +25,7 @@ enum ARMCPKind { CPValue, CPNonLazyPtr, + CPDataSegmentJumpTable, CPStub }; } @@ -54,7 +55,6 @@ ARMConstantPoolValue(GlobalValue *GV, ARMCP::ARMCPKind Kind, const char *Modifier); - GlobalValue *getGV() const { return GV; } const char *getSymbol() const { return S; } const char *getModifier() const { return Modifier; } @@ -63,6 +63,9 @@ unsigned getLabelId() const { return LabelId; } bool isNonLazyPointer() const { return Kind == ARMCP::CPNonLazyPtr; } bool isStub() const { return Kind == ARMCP::CPStub; } + bool isValue() const { return Kind == ARMCP::CPValue; } + bool isDataSegmentJumpTable() const { + return Kind == ARMCP::CPDataSegmentJumpTable; } unsigned char getPCAdjustment() const { return PCAdjust; } virtual int getExistingMachineCPValue(MachineConstantPool *CP, Index: lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp ==================================================================--- lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp (revision 74072) +++ lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp (working copy) @@ -33,13 +33,17 @@ #include "llvm/ADT/Statistic.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringSet.h" +#include "llvm/Support/CommandLine.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/Mangler.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/raw_ostream.h" #include <cctype> +#include <sstream> using namespace llvm; +extern cl::opt<bool> FlagOutlineJumpTables; + STATISTIC(EmittedInsts, "Number of machine instrs printed"); namespace { @@ -141,6 +145,7 @@ /// EmitMachineConstantPoolValue - Print a machine constantpool value to /// the .s file. virtual void EmitMachineConstantPoolValue(MachineConstantPoolValue *MCPV) { + // NOTE: A lot of this code is replicated in ARMConstantPoolValue::print printDataDirective(MCPV->getType()); ARMConstantPoolValue *ACPV = static_cast<ARMConstantPoolValue*>(MCPV); @@ -157,8 +162,13 @@ } else if (ACPV->isStub()) { FnStubs.insert(Name); printSuffixedName(Name, "$stub"); - } else + } else if (ACPV->isDataSegmentJumpTable()) { + // requires synchronization with code (grep for "$jumptable$") + O << Name << "$jumptable$" << ACPV->getLabelId(); + } else { + assert(ACPV->isValue() && "unknown CP kind"); O << Name; + } if (ACPV->hasModifier()) O << "(" << ACPV->getModifier() << ")"; if (ACPV->getPCAdjustment() != 0) { O << "-(" << TAI->getPrivateGlobalPrefix() << "PC" @@ -757,12 +767,31 @@ } } + void ARMAsmPrinter::printJTBlockOperand(const MachineInstr *MI, int OpNo) { - const MachineOperand &MO1 = MI->getOperand(OpNo); - const MachineOperand &MO2 = MI->getOperand(OpNo+1); // Unique Id - unsigned JTI = MO1.getIndex(); - O << TAI->getPrivateGlobalPrefix() << "JTI" << getFunctionNumber() - << '_' << JTI << '_' << MO2.getImm() << ":\n"; + std::stringstream prefix; + + const unsigned JTI = MI->getOperand(OpNo).getIndex(); + const unsigned uid = MI->getOperand(OpNo+1).getImm(); + + if (FlagOutlineJumpTables) { + // needs to be synchronized with ARMConstantPoolValue.cpp + prefix << ".T$jumptable$" << uid; + } else { + // needs to be synchronized with other places in this file + prefix << TAI->getPrivateGlobalPrefix() << "JTI" << getFunctionNumber() + << '_' << JTI << '_' << uid; + } + + if (FlagOutlineJumpTables) { + // switch out of text section + O << TAI->getJumpTableDataSection(); + O << ".align 4\n"; + O << "\n\n"; + } + + // the table label + O << prefix.str() << ":\n"; const char *JTEntryDirective = TAI->getJumpTableDirective(); if (!JTEntryDirective) @@ -777,24 +806,28 @@ for (unsigned i = 0, e = JTBBs.size(); i != e; ++i) { MachineBasicBlock *MBB = JTBBs[i]; if (UseSet && JTSets.insert(MBB).second) - printPICJumpTableSetLabel(JTI, MO2.getImm(), MBB); + printPICJumpTableSetLabel(JTI, uid, MBB); O << JTEntryDirective << ' '; if (UseSet) - O << TAI->getPrivateGlobalPrefix() << getFunctionNumber() - << '_' << JTI << '_' << MO2.getImm() - << "_set_" << MBB->getNumber(); + O << prefix.str() << "_set_" << MBB->getNumber(); else if (TM.getRelocationModel() == Reloc::PIC_) { printBasicBlockLabel(MBB, false, false, false); // If the arch uses custom Jump Table directives, don't calc relative to JT if (!TAI->getJumpTableDirective()) - O << '-' << TAI->getPrivateGlobalPrefix() << "JTI" - << getFunctionNumber() << '_' << JTI << '_' << MO2.getImm(); + O << '-' << prefix.str(); } else printBasicBlockLabel(MBB, false, false, false); if (i != e-1) O << '\n'; } + + if (FlagOutlineJumpTables) { + // switch back into the text section + O << "\n\n"; + O << ".text\n"; + O << "\n\n"; + } } Index: lib/Target/ARM/ARMTargetAsmInfo.cpp ==================================================================--- lib/Target/ARM/ARMTargetAsmInfo.cpp (revision 74072) +++ lib/Target/ARM/ARMTargetAsmInfo.cpp (working copy) @@ -52,6 +52,7 @@ SetDirective = "\t.set\t"; ProtectedDirective = NULL; HasDotTypeDotSizeDirective = false; + JumpTableDataSection = "\t.section .data,\"aMS\",%progbits,1\n"; SupportsDebugInformation = true; } @@ -86,6 +87,7 @@ StaticCtorsSection = "\t.section .ctors,\"aw\",%progbits"; StaticDtorsSection = "\t.section .dtors,\"aw\",%progbits"; } + JumpTableDataSection = "\t.section .data,\"aMS\",%progbits,1\n"; SupportsDebugInformation = true; } Index: lib/Target/ARM/ARMISelLowering.cpp ==================================================================--- lib/Target/ARM/ARMISelLowering.cpp (revision 74072) +++ lib/Target/ARM/ARMISelLowering.cpp (working copy) @@ -36,9 +36,16 @@ #include "llvm/CodeGen/SelectionDAG.h" #include "llvm/Target/TargetOptions.h" #include "llvm/ADT/VectorExtras.h" +#include "llvm/Support/CommandLine.h" #include "llvm/Support/MathExtras.h" + using namespace llvm; + + +cl::opt<bool> FlagOutlineJumpTables("outline-jumptables", + cl::desc("move jumptables from text to data")); + static bool CC_ARM_APCS_Custom_f64(unsigned &ValNo, MVT &ValVT, MVT &LocVT, CCValAssign::LocInfo &LocInfo, ISD::ArgFlagsTy &ArgFlags, @@ -1686,27 +1693,119 @@ return Res; } -SDValue ARMTargetLowering::LowerBR_JT(SDValue Op, SelectionDAG &DAG) { + + +// Similar to LowerBR_JT_Inline except that the jumptable +// is moved to the data segment. +// This causes a extra load to access the table but keeps the +// text segment small and avoids some issues with generating PIC +// Needs to be activated with a commandline flag. +static SDValue LowerBR_JT_OutOfLine(SDValue Op, + SelectionDAG &DAG, + unsigned Num, + MVT PTy) { + SDValue Chain = Op.getOperand(0); - SDValue Table = Op.getOperand(1); - SDValue Index = Op.getOperand(2); - DebugLoc dl = Op.getDebugLoc(); - MVT PTy = getPointerTy(); - JumpTableSDNode *JT = cast<JumpTableSDNode>(Table); + const JumpTableSDNode *JT = cast<JumpTableSDNode>(Op.getOperand(1)); + const SDValue Index = Op.getOperand(2); + + + const DebugLoc dl = Op.getDebugLoc(); + + const SDValue UId = DAG.getConstant(Num, PTy); + const SDValue JTI = DAG.getTargetJumpTable(JT->getIndex(), PTy); + + // create a new global symbol for the jumptable + ARMConstantPoolValue *CPV = new ARMConstantPoolValue(".T", Num, + ARMCP::CPDataSegmentJumpTable); + const SDValue CPAddr = DAG.getTargetConstantPool(CPV, PTy, 4); + + // An ARM idiosyncrasy: wrap each constant pool entry before accessing it + const SDValue Wrapper = DAG.getNode(ARMISD::Wrapper, dl, MVT::i32, CPAddr); + + // Load Table start from constan pool + const SDValue Table = DAG.getLoad(PTy, dl, DAG.getEntryNode(), Wrapper, NULL, 0); + + // table entries are 4 bytes, so multiple index by 4 + const SDValue ScaledIndex = DAG.getNode(ISD::MUL, dl, PTy, Index, DAG.getConstant(4, PTy)); + + // add scaled index to table beginning + const SDValue TabEntryAddr = DAG.getNode(ISD::ADD, dl, PTy, ScaledIndex, Table); + const SDValue JumpTarget = DAG.getLoad(PTy, dl, Chain, TabEntryAddr, NULL, 0); + + return DAG.getNode(ARMISD::BR_JT, dl, MVT::Other, Chain, JumpTarget, JTI, UId); +} + + +static SDValue LowerBR_JT_Inline(SDValue Op, + SelectionDAG &DAG, + bool isPIC, + MVT PTy) { + // The Jumptable idiom we are aiming for looks somthing like this: + // + // .set PCRELV0, (.LJTI9_0_0-(.LPCRELL0+8)) + // .LPCRELL0: + // add r3, pc, #PCRELV0 + // ldr pc, [r3, +r0, lsl #2] + // .LJTI9_0_0: + // .long .LBB9_2 + // .long .LBB9_5 + // .long .LBB9_7 + // .long .LBB9_4 + // .long .LBB9_8 + // + // In pic mode the table entries are relative to table beginning + // requiring and extra addition + // + // The code generation logic for ARMISD::BR_JT will also + // emit the table (c.f. ARMAsmPrinter::printJTBlockOperand()) + // Also check "def BR_JTm" in ARMInstrInfo.td + + // allocate constant pool entry ARMFunctionInfo *AFI = DAG.getMachineFunction().getInfo<ARMFunctionInfo>(); - SDValue UId = DAG.getConstant(AFI->createJumpTableUId(), PTy); - SDValue JTI = DAG.getTargetJumpTable(JT->getIndex(), PTy); - Table = DAG.getNode(ARMISD::WrapperJT, dl, MVT::i32, JTI, UId); - Index = DAG.getNode(ISD::MUL, dl, PTy, Index, DAG.getConstant(4, PTy)); - SDValue Addr = DAG.getNode(ISD::ADD, dl, PTy, Index, Table); - bool isPIC = getTargetMachine().getRelocationModel() == Reloc::PIC_; - Addr = DAG.getLoad(isPIC ? (MVT)MVT::i32 : PTy, dl, - Chain, Addr, NULL, 0); - Chain = Addr.getValue(1); - if (isPIC) - Addr = DAG.getNode(ISD::ADD, dl, PTy, Addr, Table); - return DAG.getNode(ARMISD::BR_JT, dl, MVT::Other, Chain, Addr, JTI, UId); + + SDValue Chain = Op.getOperand(0); + + const JumpTableSDNode *JT = cast<JumpTableSDNode>(Op.getOperand(1)); + const SDValue Index = Op.getOperand(2); + const DebugLoc dl = Op.getDebugLoc(); + + + const SDValue UId = DAG.getConstant(AFI->createJumpTableUId(), PTy); + + const SDValue JTI = DAG.getTargetJumpTable(JT->getIndex(), PTy); + + // this uses pcrel magic to materialize the table start address + const SDValue Table = DAG.getNode(ARMISD::WrapperJT, dl, MVT::i32, JTI, UId); + + // table entries are 4 bytes, so multiple index by 4 + const SDValue ScaledIndex = DAG.getNode(ISD::MUL, dl, PTy, Index, DAG.getConstant(4, PTy)); + + // add scaled index to table beginning + const SDValue TabEntryAddr = DAG.getNode(ISD::ADD, dl, PTy, ScaledIndex, Table); + SDValue JumpTarget; + if (isPIC) { + JumpTarget = DAG.getLoad((MVT)MVT::i32, dl, Chain, TabEntryAddr, NULL, 0); + Chain = JumpTarget.getValue(1); + // the table entry is not the actual target but relative to other stuff + // TODO: explain the exact magic here + JumpTarget = DAG.getNode(ISD::ADD, dl, PTy, JumpTarget, Table); + } else { + JumpTarget = DAG.getLoad(PTy, dl, Chain, TabEntryAddr, NULL, 0); + Chain = JumpTarget.getValue(1); + } + + return DAG.getNode(ARMISD::BR_JT, dl, MVT::Other, Chain, JumpTarget, JTI, UId); +} + +SDValue ARMTargetLowering::LowerBR_JT(SDValue Op, SelectionDAG &DAG) { + if (FlagOutlineJumpTables) { + return LowerBR_JT_OutOfLine(Op, DAG, ++ARMJumpTableIndex, getPointerTy()); + } else { + const bool isPIC = getTargetMachine().getRelocationModel() == Reloc::PIC_; + return LowerBR_JT_Inline(Op, DAG, isPIC, getPointerTy()); + } } static SDValue LowerFP_TO_INT(SDValue Op, SelectionDAG &DAG) { Index: lib/Target/ARM/ARMConstantPoolValue.cpp ==================================================================--- lib/Target/ARM/ARMConstantPoolValue.cpp (revision 74072) +++ lib/Target/ARM/ARMConstantPoolValue.cpp (working copy) @@ -84,12 +84,26 @@ } void ARMConstantPoolValue::print(raw_ostream &O) const { + // NOTE: this is not used for codegeneration, moreover + // some of the logic is replicated in + // EmitMachineConstantPoolValue() + if (GV) O << GV->getName(); else O << S; - if (isNonLazyPointer()) O << "$non_lazy_ptr"; - else if (isStub()) O << "$stub"; + + if (isNonLazyPointer()) { + O << "$non_lazy_ptr"; + } else if (isStub()) { + O << "$stub"; + } else if (isDataSegmentJumpTable()) { + // requires synchronization with ARMAsmPrinter.cpp + O << "$jumptable$" << LabelId; + } else { + assert(isValue() && "unknown CP kind"); + } + if (Modifier) O << "(" << Modifier << ")"; if (PCAdjust != 0) { O << "-(LPC" << LabelId << "+" << (unsigned)PCAdjust;
Reasonably Related Threads
- [LLVMdev] patch for llc/ARM: added mechanism to move switch tables from .text -> .data; also cleanup and documentation
- [LLVMdev] patch for llc/ARM: added mechanism to move switch tables from .text -> .data; also cleanup and documentation
- [LLVMdev] patch for llc/ARM: added mechanism to move switch tables from .text -> .data; also cleanup and documentation
- [LLVMdev] ARM backend playing with alternative jump table implementations
- [LLVMdev] patch for llc/ARM: added mechanism to move switch tables from .text -> .data; also cleanup and documentation