Index: include/llvm/CodeGen/ISDOpcodes.h =================================================================== --- include/llvm/CodeGen/ISDOpcodes.h +++ include/llvm/CodeGen/ISDOpcodes.h @@ -65,6 +65,9 @@ /// The address of the GOT GLOBAL_OFFSET_TABLE, + /// The address of the entry point of the function. + FUNCBASE, + /// FRAMEADDR, RETURNADDR - These nodes represent llvm.frameaddress and /// llvm.returnaddress on the DAG. These nodes take one operand, the index /// of the frame or return address to return. An index of zero corresponds Index: include/llvm/CodeGen/MIRYamlMapping.h =================================================================== --- include/llvm/CodeGen/MIRYamlMapping.h +++ include/llvm/CodeGen/MIRYamlMapping.h @@ -126,6 +126,8 @@ MachineJumpTableInfo::EK_GPRel32BlockAddress); IO.enumCase(EntryKind, "label-difference32", MachineJumpTableInfo::EK_LabelDifference32); + IO.enumCase(EntryKind, "funcbase-difference32", + MachineJumpTableInfo::EK_FuncBaseDifference32); IO.enumCase(EntryKind, "inline", MachineJumpTableInfo::EK_Inline); IO.enumCase(EntryKind, "custom32", MachineJumpTableInfo::EK_Custom32); } Index: include/llvm/CodeGen/MachineFunction.h =================================================================== --- include/llvm/CodeGen/MachineFunction.h +++ include/llvm/CodeGen/MachineFunction.h @@ -640,6 +640,10 @@ /// getPICBaseSymbol - Return a function-local symbol to represent the PIC /// base. MCSymbol *getPICBaseSymbol() const; + + /// getFuncBaseSymbol - Return a function-local symbol to represent the entry + /// point. + MCSymbol *getFuncBaseSymbol() const; }; //===--------------------------------------------------------------------===// Index: include/llvm/CodeGen/MachineJumpTableInfo.h =================================================================== --- include/llvm/CodeGen/MachineJumpTableInfo.h +++ include/llvm/CodeGen/MachineJumpTableInfo.h @@ -67,6 +67,13 @@ /// .word L4_5_set_123 EK_LabelDifference32, + /// EK_FuncBaseDifference32 - Each entry is the address of the block minus + /// the start of the function. This is used for position-independent code + /// and in medium and large code models. + EK_FuncBaseDifference32, + EK_FuncBaseDifference16, + EK_FuncBaseDifference8, + /// EK_Inline - Jump table entries are emitted inline at their point of /// use. It is the responsibility of the target to emit the entries. EK_Inline, Index: include/llvm/CodeGen/SelectionDAG.h =================================================================== --- include/llvm/CodeGen/SelectionDAG.h +++ include/llvm/CodeGen/SelectionDAG.h @@ -749,6 +749,11 @@ return getNode(ISD::GLOBAL_OFFSET_TABLE, SDLoc(), VT); } + /// Return a FUNCBASE node. This does not have a useful SDLoc. + SDValue getFUNCBASE(EVT VT) { + return getNode(ISD::FUNCBASE, SDLoc(), VT); + } + /// Gets or creates the specified node. /// SDValue getNode(unsigned Opcode, const SDLoc &DL, EVT VT, Index: lib/CodeGen/AsmPrinter/AsmPrinter.cpp =================================================================== --- lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -565,6 +565,17 @@ // do their wild and crazy things as required. EmitFunctionEntryLabel(); + if (const MachineJumpTableInfo *MJTI = MF->getJumpTableInfo()) { + switch (MJTI->getEntryKind()) { + default: + break; + case MachineJumpTableInfo::EK_FuncBaseDifference32: + case MachineJumpTableInfo::EK_FuncBaseDifference16: + case MachineJumpTableInfo::EK_FuncBaseDifference8: + OutStreamer->EmitLabel(MF->getFuncBaseSymbol()); + } + } + // If the function had address-taken blocks that got deleted, then we have // references to the dangling symbols. Emit them at the start of the function // so that we don't get references to undefined symbols. @@ -1377,7 +1388,10 @@ const Function *F = MF->getFunction(); const TargetLoweringObjectFile &TLOF = getObjFileLowering(); bool JTInDiffSection = !TLOF.shouldPutJumpTableInFunctionSection( - MJTI->getEntryKind() == MachineJumpTableInfo::EK_LabelDifference32, + MJTI->getEntryKind() == MachineJumpTableInfo::EK_LabelDifference32 || + MJTI->getEntryKind() == MachineJumpTableInfo::EK_FuncBaseDifference32 || + MJTI->getEntryKind() == MachineJumpTableInfo::EK_FuncBaseDifference16 || + MJTI->getEntryKind() == MachineJumpTableInfo::EK_FuncBaseDifference8, *F); if (JTInDiffSection) { // Drop it in the readonly section. @@ -1493,6 +1507,19 @@ Value = MCBinaryExpr::createSub(Value, Base, OutContext); break; } + + case MachineJumpTableInfo::EK_FuncBaseDifference32: + case MachineJumpTableInfo::EK_FuncBaseDifference16: + case MachineJumpTableInfo::EK_FuncBaseDifference8: { + // Each entry is the address of the block minus the address of + // the entry point of the function. + Value = MCSymbolRefExpr::create(MBB->getSymbol(), OutContext); + MCSymbol *FB = MF->getFuncBaseSymbol(); + + const MCExpr *Base = MCSymbolRefExpr::create(FB, OutContext); + Value = MCBinaryExpr::createSub(Value, Base, OutContext); + break; + } } assert(Value && "Unknown entry kind!"); Index: lib/CodeGen/MachineFunction.cpp =================================================================== --- lib/CodeGen/MachineFunction.cpp +++ lib/CodeGen/MachineFunction.cpp @@ -568,6 +568,13 @@ Twine(getFunctionNumber()) + "$pb"); } +/// Return a function-local symbol to represent the entry point. +MCSymbol *MachineFunction::getFuncBaseSymbol() const { + const DataLayout &DL = getDataLayout(); + return Ctx.getOrCreateSymbol(Twine(DL.getPrivateGlobalPrefix()) + + Twine(getFunctionNumber()) + "$fb"); +} + //===----------------------------------------------------------------------===// // MachineFrameInfo implementation //===----------------------------------------------------------------------===// @@ -780,8 +787,6 @@ /// Return the size of each entry in the jump table. unsigned MachineJumpTableInfo::getEntrySize(const DataLayout &TD) const { - // The size of a jump table entry is 4 bytes unless the entry is just the - // address of a block, in which case it is the pointer size. switch (getEntryKind()) { case MachineJumpTableInfo::EK_BlockAddress: return TD.getPointerSize(); @@ -789,8 +794,13 @@ return 8; case MachineJumpTableInfo::EK_GPRel32BlockAddress: case MachineJumpTableInfo::EK_LabelDifference32: + case MachineJumpTableInfo::EK_FuncBaseDifference32: case MachineJumpTableInfo::EK_Custom32: return 4; + case MachineJumpTableInfo::EK_FuncBaseDifference16: + return 2; + case MachineJumpTableInfo::EK_FuncBaseDifference8: + return 1; case MachineJumpTableInfo::EK_Inline: return 0; } @@ -809,8 +819,13 @@ return TD.getABIIntegerTypeAlignment(64); case MachineJumpTableInfo::EK_GPRel32BlockAddress: case MachineJumpTableInfo::EK_LabelDifference32: + case MachineJumpTableInfo::EK_FuncBaseDifference32: case MachineJumpTableInfo::EK_Custom32: return TD.getABIIntegerTypeAlignment(32); + case MachineJumpTableInfo::EK_FuncBaseDifference16: + return TD.getABIIntegerTypeAlignment(16); + case MachineJumpTableInfo::EK_FuncBaseDifference8: + return TD.getABIIntegerTypeAlignment(8); case MachineJumpTableInfo::EK_Inline: return 1; } Index: lib/CodeGen/SelectionDAG/LegalizeDAG.cpp =================================================================== --- lib/CodeGen/SelectionDAG/LegalizeDAG.cpp +++ lib/CodeGen/SelectionDAG/LegalizeDAG.cpp @@ -1020,6 +1020,7 @@ case ISD::FRAMEADDR: case ISD::RETURNADDR: case ISD::ADDROFRETURNADDR: + case ISD::FUNCBASE: // These operations lie about being legal: when they claim to be legal, // they should actually be custom-lowered. Action = TLI.getOperationAction(Node->getOpcode(), Node->getValueType(0)); @@ -3566,7 +3567,10 @@ ISD::SEXTLOAD, dl, PTy, Chain, Addr, MachinePointerInfo::getJumpTable(DAG.getMachineFunction()), MemVT); Addr = LD; - if (TM.isPositionIndependent()) { + if (TM.isPositionIndependent() || + TLI.getJumpTableEncoding() == MachineJumpTableInfo::EK_FuncBaseDifference32 || + TLI.getJumpTableEncoding() == MachineJumpTableInfo::EK_FuncBaseDifference16 || + TLI.getJumpTableEncoding() == MachineJumpTableInfo::EK_FuncBaseDifference8) { // For PIC, the sequence is: // BRIND(load(Jumptable + index) + RelocBase) // RelocBase can be JumpTable, GOT or some sort of global base. Index: lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp =================================================================== --- lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp +++ lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp @@ -99,6 +99,7 @@ case ISD::FrameIndex: return "FrameIndex"; case ISD::JumpTable: return "JumpTable"; case ISD::GLOBAL_OFFSET_TABLE: return "GLOBAL_OFFSET_TABLE"; + case ISD::FUNCBASE: return "FUNCBASE"; case ISD::RETURNADDR: return "RETURNADDR"; case ISD::ADDROFRETURNADDR: return "ADDROFRETURNADDR"; case ISD::FRAMEADDR: return "FRAMEADDR"; Index: lib/CodeGen/SelectionDAG/TargetLowering.cpp =================================================================== --- lib/CodeGen/SelectionDAG/TargetLowering.cpp +++ lib/CodeGen/SelectionDAG/TargetLowering.cpp @@ -293,14 +293,19 @@ SDValue TargetLowering::getPICJumpTableRelocBase(SDValue Table, SelectionDAG &DAG) const { - // If our PIC model is GP relative, use the global offset table as the base. - unsigned JTEncoding = getJumpTableEncoding(); - - if ((JTEncoding == MachineJumpTableInfo::EK_GPRel64BlockAddress) || - (JTEncoding == MachineJumpTableInfo::EK_GPRel32BlockAddress)) + switch (getJumpTableEncoding()) { + case MachineJumpTableInfo::EK_GPRel32BlockAddress: + case MachineJumpTableInfo::EK_GPRel64BlockAddress: return DAG.getGLOBAL_OFFSET_TABLE(getPointerTy(DAG.getDataLayout())); - return Table; + case MachineJumpTableInfo::EK_FuncBaseDifference32: + case MachineJumpTableInfo::EK_FuncBaseDifference16: + case MachineJumpTableInfo::EK_FuncBaseDifference8: + return DAG.getFUNCBASE(getPointerTy(DAG.getDataLayout())); + + default: + return Table; + } } /// This returns the relocation base for the given PIC jumptable, the same as @@ -308,8 +313,15 @@ const MCExpr * TargetLowering::getPICJumpTableRelocBaseExpr(const MachineFunction *MF, unsigned JTI,MCContext &Ctx) const{ - // The normal PIC reloc base is the label at the start of the jump table. - return MCSymbolRefExpr::create(MF->getJTISymbol(JTI, Ctx), Ctx); + switch (getJumpTableEncoding()) { + case MachineJumpTableInfo::EK_FuncBaseDifference32: + case MachineJumpTableInfo::EK_FuncBaseDifference16: + case MachineJumpTableInfo::EK_FuncBaseDifference8: + return MCSymbolRefExpr::create(MF->getPICBaseSymbol(), Ctx); + default: + // The normal PIC reloc base is the label at the start of the jump table. + return MCSymbolRefExpr::create(MF->getJTISymbol(JTI, Ctx), Ctx); + } } bool Index: lib/Target/X86/X86ISelLowering.h =================================================================== --- lib/Target/X86/X86ISelLowering.h +++ lib/Target/X86/X86ISelLowering.h @@ -1144,6 +1144,7 @@ SDValue LowerDYNAMIC_STACKALLOC(SDValue Op, SelectionDAG &DAG) const; SDValue LowerVASTART(SDValue Op, SelectionDAG &DAG) const; SDValue LowerVAARG(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerFUNCBASE(SDValue Op, SelectionDAG &DAG) const; SDValue LowerRETURNADDR(SDValue Op, SelectionDAG &DAG) const; SDValue LowerADDROFRETURNADDR(SDValue Op, SelectionDAG &DAG) const; SDValue LowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) const; Index: lib/Target/X86/X86ISelLowering.cpp =================================================================== --- lib/Target/X86/X86ISelLowering.cpp +++ lib/Target/X86/X86ISelLowering.cpp @@ -18933,6 +18933,24 @@ } } +SDValue X86TargetLowering::LowerFUNCBASE(SDValue Op, SelectionDAG &DAG) const { + unsigned char OpFlag = Subtarget.classifyLocalReference(nullptr); + MachineFunction &MF = DAG.getMachineFunction(); + EVT PtrVT = getPointerTy(DAG.getDataLayout()); + SDLoc DL; + + SDValue Result = DAG.getMCSymbol(MF.getFuncBaseSymbol(), PtrVT); + Result = DAG.getNode(getGlobalWrapperKind(), DL, PtrVT, Result); + + // With PIC, the address is actually $g + Offset. + if (OpFlag) + Result = + DAG.getNode(ISD::ADD, DL, PtrVT, + DAG.getNode(X86ISD::GlobalBaseReg, SDLoc(), PtrVT), Result); + + return Result; +} + SDValue X86TargetLowering::LowerRETURNADDR(SDValue Op, SelectionDAG &DAG) const { MachineFrameInfo &MFI = DAG.getMachineFunction().getFrameInfo(); @@ -22087,6 +22105,7 @@ case ISD::INTRINSIC_WO_CHAIN: return LowerINTRINSIC_WO_CHAIN(Op, Subtarget, DAG); case ISD::INTRINSIC_VOID: case ISD::INTRINSIC_W_CHAIN: return LowerINTRINSIC_W_CHAIN(Op, Subtarget, DAG); + case ISD::FUNCBASE: return LowerFUNCBASE(Op, DAG); case ISD::RETURNADDR: return LowerRETURNADDR(Op, DAG); case ISD::ADDROFRETURNADDR: return LowerADDROFRETURNADDR(Op, DAG); case ISD::FRAMEADDR: return LowerFRAMEADDR(Op, DAG);