Index: docs/BitCodeFormat.rst =================================================================== --- docs/BitCodeFormat.rst +++ docs/BitCodeFormat.rst @@ -741,7 +741,7 @@ MODULE_CODE_FUNCTION Record ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -``[FUNCTION, type, callingconv, isproto, linkage, paramattr, alignment, section, visibility, gc, prefix, dllstorageclass]`` +``[FUNCTION, type, callingconv, isproto, linkage, paramattr, alignment, section, visibility, gc, prefix, prologue, dllstorageclass]`` The ``FUNCTION`` record (code 8) marks the declaration or definition of a function. The operand fields are: @@ -787,6 +787,9 @@ * *prefix*: If non-zero, the value index of the prefix data for this function, plus 1. +* *prologue*: If non-zero, the value index of the prologue data for this function, + plus 1. + * *dllstorageclass*: An encoding of the :ref:`dllstorageclass` of this function Index: docs/LangRef.rst =================================================================== --- docs/LangRef.rst +++ docs/LangRef.rst @@ -633,7 +633,8 @@ attributes `), optional :ref:`function attributes `, an optional section, an optional alignment, an optional :ref:`comdat `, -an optional :ref:`garbage collector name `, an optional :ref:`prefix `, an opening +an optional :ref:`garbage collector name `, an optional :ref:`prefix `, +an optional :ref:`prologue `, an opening curly brace, a list of basic blocks, and a closing curly brace. LLVM function declarations consist of the "``declare``" keyword, an @@ -643,7 +644,8 @@ an optional ``unnamed_addr`` attribute, a return type, an optional :ref:`parameter attribute ` for the return type, a function name, a possibly empty list of arguments, an optional alignment, an optional -:ref:`garbage collector name ` and an optional :ref:`prefix `. +:ref:`garbage collector name `, an optional :ref:`prefix `, +and an optional :ref:`prologue `. A function definition contains a list of basic blocks, forming the CFG (Control Flow Graph) for the function. Each basic block may optionally start with a label @@ -680,7 +682,7 @@ [cconv] [ret attrs] @ ([argument list]) [unnamed_addr] [fn Attrs] [section "name"] [comdat $] - [align N] [gc] [prefix Constant] { ... } + [align N] [gc] [prefix Constant] [prologue Constant] { ... } The argument list is a comma seperated sequence of arguments where each argument is of the following form @@ -1021,47 +1023,79 @@ Prefix Data ----------- -Prefix data is data associated with a function which the code generator -will emit immediately before the function body. The purpose of this feature -is to allow frontends to associate language-specific runtime metadata with -specific functions and make it available through the function pointer while -still allowing the function pointer to be called. To access the data for a -given function, a program may bitcast the function pointer to a pointer to -the constant's type. This implies that the IR symbol points to the start -of the prefix data. +Prefix data is data associated with a function which the code +generator will emit immediately before the function's entrypoint. +The purpose of this feature is to allow frontends to associate +language-specific runtime metadata with specific functions and make it +available through the function pointer while still allowing the +function pointer to be called. -To maintain the semantics of ordinary function calls, the prefix data must +To access the data for a given function, a program may bitcast the +function pointer to a pointer to the constant's type and dereference +index -1. This implies that the IR symbol points just past the end of +the prefix data. For instance, take the example of a function annotated +with a single ``i32``, + +.. code-block:: llvm + + define void @f() prefix i32 123 { ... } + +The prefix data can be referenced as, + +.. code-block:: llvm + + %0 = bitcast *void () @f to *i32 + %a = getelementptr inbounds *i32 %0, i32 -1 + %b = load i32* %a + +Prefix data is laid out as if it were an initializer for a global variable +of the prefix data's type. The function will be placed such that the +beginning of the prefix data is aligned. This means that if the size +of the prefix data is not a multiple of the alignment size, the +function's entrypoint will not be aligned. If alignment of the +function's entrypoint is desired, padding must be added to the prefix +data. + +A function may have prefix data but no body. This has similar semantics +to the ``available_externally`` linkage in that the data may be used by the +optimizers but will not be emitted in the object file. + +.. _prologuedata: + +Prologue Data +------------- + +The ``prologue`` attribute allows arbitrary code (encoded as bytes) to +be inserted prior to the function body. This can be used for enabling +function hot-patching and instrumentation. + +To maintain the semantics of ordinary function calls, the prologue data must have a particular format. Specifically, it must begin with a sequence of bytes which decode to a sequence of machine instructions, valid for the module's target, which transfer control to the point immediately succeeding -the prefix data, without performing any other visible action. This allows +the prologue data, without performing any other visible action. This allows the inliner and other passes to reason about the semantics of the function -definition without needing to reason about the prefix data. Obviously this -makes the format of the prefix data highly target dependent. +definition without needing to reason about the prologue data. Obviously this +makes the format of the prologue data highly target dependent. -Prefix data is laid out as if it were an initializer for a global variable -of the prefix data's type. No padding is automatically placed between the -prefix data and the function body. If padding is required, it must be part -of the prefix data. - -A trivial example of valid prefix data for the x86 architecture is ``i8 144``, +A trivial example of valid prologue data for the x86 architecture is ``i8 144``, which encodes the ``nop`` instruction: .. code-block:: llvm - define void @f() prefix i8 144 { ... } + define void @f() prologue i8 144 { ... } -Generally prefix data can be formed by encoding a relative branch instruction -which skips the metadata, as in this example of valid prefix data for the +Generally prologue data can be formed by encoding a relative branch instruction +which skips the metadata, as in this example of valid prologue data for the x86_64 architecture, where the first two bytes encode ``jmp .+10``: .. code-block:: llvm %0 = type <{ i8, i8, i8* }> - define void @f() prefix %0 <{ i8 235, i8 8, i8* @md}> { ... } + define void @f() prologue %0 <{ i8 235, i8 8, i8* @md}> { ... } -A function may have prefix data but no body. This has similar semantics +A function may have prologue data but no body. This has similar semantics to the ``available_externally`` linkage in that the data may be used by the optimizers but will not be emitted in the object file. Index: docs/ReleaseNotes.rst =================================================================== --- docs/ReleaseNotes.rst +++ docs/ReleaseNotes.rst @@ -58,6 +58,48 @@ Makes programs 10x faster by doing Special New Thing. +Prefix data rework +------------------ + +The semantics of the ``prefix`` attribute have been changed. Users +that want the previous ``prefix`` semantics should instead use +``prologue``. To motivate this change, let's examine the primary +usecases that these attributes aim to serve, + + 1. Function prologue sigils: TODO figure out what Reid meant by this + + 2. Function hot-patching: Enable the user to insert ``nop`` operations + at the beginning of the function which can later be safely replaced + with a call to some instrumentation facility. + + 3. Runtime metadata: Allow a compiler to insert data for use by the + runtime during execution. GHC is one example of a compiler that + needs this functionality for its tables-next-to-code functionality. + +Previously ``prefix`` served cases (1) and (2) quite well by allowing the user +to introduce arbitrary data at the entrypoint but before the function +body. Case (3), however, was poorly handled by this approach as it +required that prefix data was valid executable code. + +In this release the concept of prefix data has been redefined to be +data which occurs immediately before the function entrypoint (i.e. the +symbol address). Since prefix data now occurs before the function +entrypoint, there is no need for the data to be valid code. + +The previous notion of prefix data now goes under the name "prologue +data" to emphasize its duality with the function epilogue. + +The intention here is to handle cases (1) and (2) with prologue data and +case (3) with prefix data. See the language reference for further details +on the semantics of these attributes. + +This refactoring arose out of discussions_ with Reid Kleckner in +response to a proposal to introduce the notion of symbol offsets to +enable handling of case (3). + +.. _discussions: http://lists.cs.uiuc.edu/pipermail/llvmdev/2014-May/073235.html + + Changes to the ARM Backend -------------------------- Index: include/llvm/IR/Function.h =================================================================== --- include/llvm/IR/Function.h +++ include/llvm/IR/Function.h @@ -87,11 +87,14 @@ ValueSymbolTable *SymTab; ///< Symbol table of args/instructions AttributeSet AttributeSets; ///< Parameter attributes - // HasLazyArguments is stored in Value::SubclassData. - /*bool HasLazyArguments;*/ - - // The Calling Convention is stored in Value::SubclassData. - /*CallingConv::ID CallingConvention;*/ + /* + * Value::SubclassData + * + * bit 0 : HasLazyArguments + * bit 1 : HasPrefixData + * bit 2 : HasPrologueData + * bit 3-6: CallingConvention + */ friend class SymbolTableListTraits; @@ -102,7 +105,7 @@ /// needs it. The hasLazyArguments predicate returns true if the arg list /// hasn't been set up yet. bool hasLazyArguments() const { - return getSubclassDataFromValue() & 1; + return getSubclassDataFromValue() & (1<<0); } void CheckLazyArguments() const { if (hasLazyArguments()) @@ -162,11 +165,11 @@ /// calling convention of this function. The enum values for the known /// calling conventions are defined in CallingConv.h. CallingConv::ID getCallingConv() const { - return static_cast(getSubclassDataFromValue() >> 2); + return static_cast(getSubclassDataFromValue() >> 3); } void setCallingConv(CallingConv::ID CC) { - setValueSubclassData((getSubclassDataFromValue() & 3) | - (static_cast(CC) << 2)); + setValueSubclassData((getSubclassDataFromValue() & 7) | + (static_cast(CC) << 3)); } /// @brief Return the attribute list for this Function. @@ -448,12 +451,19 @@ bool arg_empty() const; bool hasPrefixData() const { - return getSubclassDataFromValue() & 2; + return getSubclassDataFromValue() & (1<<1); } Constant *getPrefixData() const; void setPrefixData(Constant *PrefixData); + bool hasPrologueData() const { + return getSubclassDataFromValue() & (1<<2); + } + + Constant *getPrologueData() const; + void setPrologueData(Constant *Offset); + /// viewCFG - This function is meant for use from the debugger. You can just /// say 'call F->viewCFG()' and a ghostview window should pop up from the /// program, displaying the CFG of the current function with the code for each Index: lib/AsmParser/LLLexer.cpp =================================================================== --- lib/AsmParser/LLLexer.cpp +++ lib/AsmParser/LLLexer.cpp @@ -573,6 +573,7 @@ KEYWORD(inteldialect); KEYWORD(gc); KEYWORD(prefix); + KEYWORD(prologue); KEYWORD(ccc); KEYWORD(fastcc); Index: lib/AsmParser/LLParser.h =================================================================== --- lib/AsmParser/LLParser.h +++ lib/AsmParser/LLParser.h @@ -201,6 +201,7 @@ return false; } bool ParseStringConstant(std::string &Result); + bool ParseInt32(signed &Val); bool ParseUInt32(unsigned &Val); bool ParseUInt32(unsigned &Val, LocTy &Loc) { Loc = Lex.getLoc(); Index: lib/AsmParser/LLParser.cpp =================================================================== --- lib/AsmParser/LLParser.cpp +++ lib/AsmParser/LLParser.cpp @@ -1150,6 +1150,19 @@ return false; } +/// ParseInt32 +/// ::= int32 +bool LLParser::ParseInt32(signed &Val) { + if (Lex.getKind() != lltok::APSInt) + return TokError("expected integer"); + int64_t Val64 = Lex.getAPSIntVal().getLimitedValue(0x7FFFFFFFULL+1); + if (Val64 != signed(Val64)) + return TokError("expected 32-bit integer (too large)"); + Val = Val64; + Lex.Lex(); + return false; +} + /// ParseUInt32 /// ::= uint32 bool LLParser::ParseUInt32(unsigned &Val) { @@ -3120,7 +3133,7 @@ /// FunctionHeader /// ::= OptionalLinkage OptionalVisibility OptionalCallingConv OptRetAttrs /// OptUnnamedAddr Type GlobalName '(' ArgList ')' OptFuncAttrs OptSection -/// OptionalAlign OptGC OptionalPrefix +/// OptionalAlign OptGC OptionalPrefix OptionalPrologue bool LLParser::ParseFunctionHeader(Function *&Fn, bool isDefine) { // Parse the linkage. LocTy LinkageLoc = Lex.getLoc(); @@ -3201,6 +3214,7 @@ bool UnnamedAddr; LocTy UnnamedAddrLoc; Constant *Prefix = nullptr; + Constant *Prologue = nullptr; Comdat *C; if (ParseArgumentList(ArgList, isVarArg) || @@ -3215,7 +3229,9 @@ (EatIfPresent(lltok::kw_gc) && ParseStringConstant(GC)) || (EatIfPresent(lltok::kw_prefix) && - ParseGlobalTypeAndValue(Prefix))) + ParseGlobalTypeAndValue(Prefix)) || + (EatIfPresent(lltok::kw_prologue) && + ParseGlobalTypeAndValue(Prologue))) return true; if (FuncAttrs.contains(Attribute::Builtin)) @@ -3316,6 +3332,7 @@ Fn->setComdat(C); if (!GC.empty()) Fn->setGC(GC.c_str()); Fn->setPrefixData(Prefix); + Fn->setPrologueData(Prologue); ForwardRefAttrGroups[Fn] = FwdRefAttrGrps; // Add all of the arguments we parsed to the function. Index: lib/AsmParser/LLToken.h =================================================================== --- lib/AsmParser/LLToken.h +++ lib/AsmParser/LLToken.h @@ -83,6 +83,7 @@ kw_inteldialect, kw_gc, kw_prefix, + kw_prologue, kw_c, kw_cc, kw_ccc, kw_fastcc, kw_coldcc, Index: lib/Bitcode/Reader/BitcodeReader.h =================================================================== --- lib/Bitcode/Reader/BitcodeReader.h +++ lib/Bitcode/Reader/BitcodeReader.h @@ -143,6 +143,7 @@ std::vector > GlobalInits; std::vector > AliasInits; std::vector > FunctionPrefixes; + std::vector > FunctionPrologues; SmallVector InstsWithTBAATag; Index: lib/Bitcode/Reader/BitcodeReader.cpp =================================================================== --- lib/Bitcode/Reader/BitcodeReader.cpp +++ lib/Bitcode/Reader/BitcodeReader.cpp @@ -1152,10 +1152,12 @@ std::vector > GlobalInitWorklist; std::vector > AliasInitWorklist; std::vector > FunctionPrefixWorklist; + std::vector > FunctionPrologueWorklist; GlobalInitWorklist.swap(GlobalInits); AliasInitWorklist.swap(AliasInits); FunctionPrefixWorklist.swap(FunctionPrefixes); + FunctionPrologueWorklist.swap(FunctionPrologues); while (!GlobalInitWorklist.empty()) { unsigned ValID = GlobalInitWorklist.back().second; @@ -1197,6 +1199,19 @@ FunctionPrefixWorklist.pop_back(); } + while (!FunctionPrologueWorklist.empty()) { + unsigned ValID = FunctionPrologueWorklist.back().second; + if (ValID >= ValueList.size()) { + FunctionPrologues.push_back(FunctionPrologueWorklist.back()); + } else { + if (Constant *C = dyn_cast_or_null(ValueList[ValID])) + FunctionPrologueWorklist.back().first->setPrologueData(C); + else + return Error(BitcodeError::ExpectedConstant); + } + FunctionPrologueWorklist.pop_back(); + } + return std::error_code(); } @@ -2011,7 +2026,7 @@ } // FUNCTION: [type, callingconv, isproto, linkage, paramattr, // alignment, section, visibility, gc, unnamed_addr, - // dllstorageclass] + // prefix, prologue, dllstorageclass] case bitc::MODULE_CODE_FUNCTION: { if (Record.size() < 8) return Error(BitcodeError::InvalidRecord); @@ -2054,14 +2069,16 @@ Func->setUnnamedAddr(UnnamedAddr); if (Record.size() > 10 && Record[10] != 0) FunctionPrefixes.push_back(std::make_pair(Func, Record[10]-1)); + if (Record.size() > 11 && Record[11] != 0) + FunctionPrologues.push_back(std::make_pair(Func, Record[11]-1)); - if (Record.size() > 11) - Func->setDLLStorageClass(GetDecodedDLLStorageClass(Record[11])); + if (Record.size() > 12) + Func->setDLLStorageClass(GetDecodedDLLStorageClass(Record[12])); else UpgradeDLLImportExportLinkage(Func, Record[3]); - if (Record.size() > 12) - if (unsigned ComdatID = Record[12]) { + if (Record.size() > 13) + if (unsigned ComdatID = Record[13]) { assert(ComdatID <= ComdatList.size()); Func->setComdat(ComdatList[ComdatID - 1]); } Index: lib/Bitcode/Writer/BitcodeWriter.cpp =================================================================== --- lib/Bitcode/Writer/BitcodeWriter.cpp +++ lib/Bitcode/Writer/BitcodeWriter.cpp @@ -670,7 +670,7 @@ // Emit the function proto information. for (const Function &F : *M) { // FUNCTION: [type, callingconv, isproto, linkage, paramattrs, alignment, - // section, visibility, gc, unnamed_addr, prefix] + // section, visibility, gc, unnamed_addr, prefix, prologue] Vals.push_back(VE.getTypeID(F.getType())); Vals.push_back(F.getCallingConv()); Vals.push_back(F.isDeclaration()); @@ -682,7 +682,9 @@ Vals.push_back(F.hasGC() ? GCMap[F.getGC()] : 0); Vals.push_back(F.hasUnnamedAddr()); Vals.push_back(F.hasPrefixData() ? (VE.getValueID(F.getPrefixData()) + 1) - : 0); + : 0); + Vals.push_back(F.hasPrologueData() ? (VE.getValueID(F.getPrologueData()) + 1) + : 0); Vals.push_back(getEncodedDLLStorageClass(F)); Vals.push_back(F.hasComdat() ? VE.getComdatID(F.getComdat()) : 0); Index: lib/Bitcode/Writer/ValueEnumerator.cpp =================================================================== --- lib/Bitcode/Writer/ValueEnumerator.cpp +++ lib/Bitcode/Writer/ValueEnumerator.cpp @@ -85,10 +85,14 @@ for (const GlobalAlias &A : M.aliases()) if (!isa(A.getAliasee())) orderValue(A.getAliasee(), OM); - for (const Function &F : M) + for (const Function &F : M) { if (F.hasPrefixData()) if (!isa(F.getPrefixData())) orderValue(F.getPrefixData(), OM); + if (F.hasPrologueData()) + if (!isa(F.getPrologueData())) + orderValue(F.getPrologueData(), OM); + } OM.LastGlobalConstantID = OM.size(); // Initializers of GlobalValues are processed in @@ -264,9 +268,12 @@ predictValueUseListOrder(G.getInitializer(), nullptr, OM, Stack); for (const GlobalAlias &A : M.aliases()) predictValueUseListOrder(A.getAliasee(), nullptr, OM, Stack); - for (const Function &F : M) + for (const Function &F : M) { if (F.hasPrefixData()) predictValueUseListOrder(F.getPrefixData(), nullptr, OM, Stack); + if (F.hasPrologueData()) + predictValueUseListOrder(F.getPrologueData(), nullptr, OM, Stack); + } return Stack; } @@ -314,6 +321,11 @@ if (I->hasPrefixData()) EnumerateValue(I->getPrefixData()); + // Enumerate the prologue data constants. + for (Module::const_iterator I = M.begin(), E = M.end(); I != E; ++I) + if (I->hasPrologueData()) + EnumerateValue(I->getPrologueData()); + // Insert constants and metadata that are named at module level into the slot // pool so that the module symbol table can refer to them... EnumerateValueSymbolTable(M.getValueSymbolTable()); Index: lib/CodeGen/AsmPrinter/AsmPrinter.cpp =================================================================== --- lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -64,6 +64,8 @@ char AsmPrinter::ID = 0; +static const MCExpr *lowerConstant(const Constant *CV, AsmPrinter &AP); + typedef DenseMap> gcp_map_type; static gcp_map_type &getGCMap(void *&P) { if (!P) @@ -508,6 +510,10 @@ OutStreamer.GetCommentOS() << '\n'; } + // Emit the prefix data. + if (F->hasPrefixData()) + EmitGlobalConstant(F->getPrefixData()); + // Emit the CurrentFnSym. This is a virtual function to allow targets to // do their wild and crazy things as required. EmitFunctionEntryLabel(); @@ -528,9 +534,9 @@ HI.Handler->beginFunction(MF); } - // Emit the prefix data. - if (F->hasPrefixData()) - EmitGlobalConstant(F->getPrefixData()); + // Emit the prologue data. + if (F->hasPrologueData()) + EmitGlobalConstant(F->getPrologueData()); } /// EmitFunctionEntryLabel - Emit the label that is the entrypoint for the Index: lib/IR/AsmWriter.cpp =================================================================== --- lib/IR/AsmWriter.cpp +++ lib/IR/AsmWriter.cpp @@ -101,6 +101,11 @@ if (F.hasPrefixData()) if (!isa(F.getPrefixData())) orderValue(F.getPrefixData(), OM); + + if (F.hasPrologueData()) + if (!isa(F.getPrologueData())) + orderValue(F.getPrologueData(), OM); + orderValue(&F, OM); if (F.isDeclaration()) @@ -1901,6 +1906,11 @@ Out << " prefix "; writeOperand(F->getPrefixData(), true); } + if (F->hasPrologueData()) { + Out << " prologue "; + writeOperand(F->getPrologueData(), true); + } + if (F->isDeclaration()) { Out << '\n'; } else { Index: lib/IR/Function.cpp =================================================================== --- lib/IR/Function.cpp +++ lib/IR/Function.cpp @@ -298,7 +298,7 @@ // Clear the lazy arguments bit. unsigned SDC = getSubclassDataFromValue(); - const_cast(this)->setValueSubclassData(SDC &= ~1); + const_cast(this)->setValueSubclassData(SDC &= ~(1<<0)); } size_t Function::arg_size() const { @@ -335,8 +335,9 @@ while (!BasicBlocks.empty()) BasicBlocks.begin()->eraseFromParent(); - // Prefix data is stored in a side table. + // Prefix and prologue data are stored in a side table. setPrefixData(nullptr); + setPrologueData(nullptr); } void Function::addAttribute(unsigned i, Attribute::AttrKind attr) { @@ -416,6 +417,10 @@ setPrefixData(SrcF->getPrefixData()); else setPrefixData(nullptr); + if (SrcF->hasPrologueData()) + setPrologueData(SrcF->getPrologueData()); + else + setPrologueData(nullptr); } /// getIntrinsicID - This method returns the ID number of the specified @@ -894,11 +899,40 @@ PDHolder->setOperand(0, PrefixData); else PDHolder = ReturnInst::Create(getContext(), PrefixData); - SCData |= 2; + SCData |= (1<<1); } else { delete PDHolder; PDMap.erase(this); - SCData &= ~2; + SCData &= ~(1<<1); } setValueSubclassData(SCData); } + +Constant *Function::getPrologueData() const { + assert(hasPrologueData()); + const LLVMContextImpl::PrologueDataMapTy &SOMap = + getContext().pImpl->PrologueDataMap; + assert(SOMap.find(this) != SOMap.end()); + return cast(SOMap.find(this)->second->getReturnValue()); +} + +void Function::setPrologueData(Constant *PrologueData) { + if (!PrologueData && !hasPrologueData()) + return; + + unsigned PDData = getSubclassDataFromValue(); + LLVMContextImpl::PrologueDataMapTy &PDMap = getContext().pImpl->PrologueDataMap; + ReturnInst *&PDHolder = PDMap[this]; + if (PrologueData) { + if (PDHolder) + PDHolder->setOperand(0, PrologueData); + else + PDHolder = ReturnInst::Create(getContext(), PrologueData); + PDData |= (1<<2); + } else { + delete PDHolder; + PDMap.erase(this); + PDData &= ~(1<<2); + } + setValueSubclassData(PDData); +} Index: lib/IR/LLVMContextImpl.h =================================================================== --- lib/IR/LLVMContextImpl.h +++ lib/IR/LLVMContextImpl.h @@ -401,6 +401,12 @@ typedef DenseMap PrefixDataMapTy; PrefixDataMapTy PrefixDataMap; + /// \brief Mapping from a function to its prologue data, which is stored as + /// the operand of an unparented ReturnInst so that the prologue data has a + /// Use. + typedef DenseMap PrologueDataMapTy; + PrologueDataMapTy PrologueDataMap; + int getOrAddScopeRecordIdxEntry(MDNode *N, int ExistingIdx); int getOrAddScopeInlinedAtIdxEntry(MDNode *Scope, MDNode *IA,int ExistingIdx); Index: lib/IR/TypeFinder.cpp =================================================================== --- lib/IR/TypeFinder.cpp +++ lib/IR/TypeFinder.cpp @@ -47,6 +47,9 @@ if (FI->hasPrefixData()) incorporateValue(FI->getPrefixData()); + if (FI->hasPrologueData()) + incorporateValue(FI->getPrologueData()); + // First incorporate the arguments. for (Function::const_arg_iterator AI = FI->arg_begin(), AE = FI->arg_end(); AI != AE; ++AI) Index: lib/Linker/LinkModules.cpp =================================================================== --- lib/Linker/LinkModules.cpp +++ lib/Linker/LinkModules.cpp @@ -1480,11 +1480,16 @@ if (DoNotLinkFromSource.count(SF)) continue; Function *DF = cast(ValueMap[SF]); - if (SF->hasPrefixData()) { - // Link in the prefix data. + + // Link in the prefix data. + if (SF->hasPrefixData()) DF->setPrefixData(MapValue( SF->getPrefixData(), ValueMap, RF_None, &TypeMap, &ValMaterializer)); - } + + // Link in the prologue data. + if (SF->hasPrologueData()) + DF->setPrologueData(MapValue( + SF->getPrologueData(), ValueMap, RF_None, &TypeMap, &ValMaterializer)); // Materialize if needed. if (std::error_code EC = SF->materialize()) Index: lib/Target/Mips/AsmParser/MipsAsmParser.cpp =================================================================== --- lib/Target/Mips/AsmParser/MipsAsmParser.cpp +++ lib/Target/Mips/AsmParser/MipsAsmParser.cpp @@ -809,6 +809,29 @@ bool isMemWithGRPMM16Base() const { return isMem() && getMemBase()->isMM16AsmReg(); } + template bool isMemWithUimmOffsetSP() const { + return isMem() && isConstantMemOff() && isUInt(getConstantMemOff()) + && getMemBase()->isRegIdx() && (getMemBase()->getGPR32Reg() == Mips::SP); + } + bool isRegList16() const { + if (!isRegList()) + return false; + + int Size = RegList.List->size(); + if (Size < 2 || Size > 5 || *RegList.List->begin() != Mips::S0 || + RegList.List->back() != Mips::RA) + return false; + + int PrevReg = *RegList.List->begin(); + for (int i = 1; i < Size - 1; i++) { + int Reg = (*(RegList.List))[i]; + if ( Reg != PrevReg + 1) + return false; + PrevReg = Reg; + } + + return true; + } bool isInvNum() const { return Kind == k_Immediate; } bool isLSAImm() const { if (!isConstantImm()) Index: lib/Target/Mips/Disassembler/MipsDisassembler.cpp =================================================================== --- lib/Target/Mips/Disassembler/MipsDisassembler.cpp +++ lib/Target/Mips/Disassembler/MipsDisassembler.cpp @@ -380,6 +380,10 @@ uint64_t Address, const void *Decoder); +static DecodeStatus DecodeRegListOperand16(MCInst &Inst, unsigned Insn, + uint64_t Address, + const void *Decoder); + namespace llvm { extern Target TheMipselTarget, TheMipsTarget, TheMips64Target, TheMips64elTarget; @@ -1609,3 +1613,23 @@ return MCDisassembler::Success; } + +static DecodeStatus DecodeRegListOperand16(MCInst &Inst, unsigned Insn, + uint64_t Address, + const void *Decoder) { + unsigned Regs[] = {Mips::S0, Mips::S1, Mips::S2, Mips::S3}; + unsigned RegNum; + + unsigned RegLst = fieldFromInstruction(Insn, 4, 2); + // Empty register lists are not allowed. + if (RegLst == 0) + return MCDisassembler::Fail; + + RegNum = RegLst & 0x3; + for (unsigned i = 0; i < RegNum - 1; i++) + Inst.addOperand(MCOperand::CreateReg(Regs[i])); + + Inst.addOperand(MCOperand::CreateReg(Mips::RA)); + + return MCDisassembler::Success; +} Index: lib/Target/Mips/InstPrinter/MipsInstPrinter.cpp =================================================================== --- lib/Target/Mips/InstPrinter/MipsInstPrinter.cpp +++ lib/Target/Mips/InstPrinter/MipsInstPrinter.cpp @@ -233,6 +233,8 @@ break; case Mips::SWM32_MM: case Mips::LWM32_MM: + case Mips::SWM16_MM: + case Mips::LWM16_MM: opNum = MI->getNumOperands() - 2; break; } Index: lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.h =================================================================== --- lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.h +++ lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.h @@ -154,6 +154,9 @@ unsigned getMemEncodingMMImm12(const MCInst &MI, unsigned OpNo, SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const; + unsigned getMemEncodingMMImm4sp(const MCInst &MI, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const; unsigned getSizeExtEncoding(const MCInst &MI, unsigned OpNo, SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const; @@ -187,6 +190,10 @@ unsigned getRegisterListOpValue(const MCInst &MI, unsigned OpNo, SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const; + + unsigned getRegisterListOpValue16(const MCInst &MI, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const; }; // class MipsMCCodeEmitter } // namespace llvm. Index: lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp =================================================================== --- lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp +++ lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp @@ -699,6 +699,30 @@ return (OffBits & 0x0FFF) | RegBits; } +unsigned MipsMCCodeEmitter:: +getMemEncodingMMImm4sp(const MCInst &MI, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const { + // opNum can be invalid if instruction had reglist as operand + // MemOperand is always last operand of instruction (base + offset) + switch (MI.getOpcode()) { + default: + break; + case Mips::SWM16_MM: + case Mips::LWM16_MM: + OpNo = MI.getNumOperands() - 2; + break; + } + + // Offset is encoded in bits 4-0. + assert(MI.getOperand(OpNo).isReg()); + // Base register is always SP - thus it is not encoded. + assert(MI.getOperand(OpNo+1).isImm()); + unsigned OffBits = getMachineOpValue(MI, MI.getOperand(OpNo+1), Fixups, STI); + + return ((OffBits >> 2) & 0x0F); +} + unsigned MipsMCCodeEmitter::getSizeExtEncoding(const MCInst &MI, unsigned OpNo, SmallVectorImpl &Fixups, @@ -830,4 +854,11 @@ return res; } +unsigned +MipsMCCodeEmitter::getRegisterListOpValue16(const MCInst &MI, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const { + return (MI.getNumOperands() - 4); +} + #include "MipsGenMCCodeEmitter.inc" Index: lib/Target/Mips/MicroMipsInstrFormats.td =================================================================== --- lib/Target/Mips/MicroMipsInstrFormats.td +++ lib/Target/Mips/MicroMipsInstrFormats.td @@ -838,3 +838,15 @@ let Inst{15-12} = funct; let Inst{11-0} = addr{11-0}; } + +class LWM_FM_MM16 funct> : MMArch { + bits<2> rt; + bits<4> addr; + + bits<16> Inst; + + let Inst{15-10} = 0x11; + let Inst{9-6} = funct; + let Inst{5-4} = rt; + let Inst{3-0} = addr; +} Index: lib/Target/Mips/MicroMipsInstrInfo.td =================================================================== --- lib/Target/Mips/MicroMipsInstrInfo.td +++ lib/Target/Mips/MicroMipsInstrInfo.td @@ -86,6 +86,22 @@ let OperandType = "OPERAND_MEMORY"; } +def MipsMemUimm4AsmOperand : AsmOperandClass { + let Name = "MemOffsetUimm4"; + let SuperClasses = [MipsMemAsmOperand]; + let RenderMethod = "addMemOperands"; + let ParserMethod = "parseMemOperand"; + let PredicateMethod = "isMemWithUimmOffsetSP<6>"; +} + +def mem_mm_4sp : Operand { + let PrintMethod = "printMemOperand"; + let MIOperandInfo = (ops GPR32, uimm8); + let EncoderMethod = "getMemEncodingMMImm4sp"; + let ParserMatchClass = MipsMemUimm4AsmOperand; + let OperandType = "OPERAND_MEMORY"; +} + def jmptarget_mm : Operand { let EncoderMethod = "getJumpTargetOpValueMM"; } @@ -339,6 +355,20 @@ let DecoderMethod = "DecodeRegListOperand"; } +def RegList16AsmOperand : AsmOperandClass { + let Name = "RegList16"; + let ParserMethod = "parseRegisterList"; + let PredicateMethod = "isRegList16"; + let RenderMethod = "addRegListOperands"; +} + +def reglist16 : Operand { + let EncoderMethod = "getRegisterListOpValue16"; + let DecoderMethod = "DecodeRegListOperand16"; + let PrintMethod = "printRegisterList"; + let ParserMatchClass = RegList16AsmOperand; +} + class StoreMultMM : InstSE<(outs), (ins reglist:$rt, mem_mm_12:$addr), @@ -355,6 +385,22 @@ let mayLoad = 1; } +class StoreMultMM16 : + MicroMipsInst16<(outs), (ins reglist16:$rt, mem_mm_4sp:$addr), + !strconcat(opstr, "\t$rt, $addr"), [], Itin, FrmI> { + let mayStore = 1; +} + +class LoadMultMM16 : + MicroMipsInst16<(outs reglist16:$rt), (ins mem_mm_4sp:$addr), + !strconcat(opstr, "\t$rt, $addr"), [], Itin, FrmI> { + let mayLoad = 1; +} + def ADDU16_MM : ArithRMM16<"addu16", GPRMM16Opnd, 1, II_ADDU, add>, ARITH_FM_MM16<0>; def SUBU16_MM : ArithRMM16<"subu16", GPRMM16Opnd, 0, II_SUBU, sub>, @@ -504,6 +550,8 @@ /// Load and Store Instructions - multiple def SWM32_MM : StoreMultMM<"swm32">, LWM_FM_MM<0xd>; def LWM32_MM : LoadMultMM<"lwm32">, LWM_FM_MM<0x5>; + def SWM16_MM : StoreMultMM16<"swm16">, LWM_FM_MM16<0x5>; + def LWM16_MM : LoadMultMM16<"lwm16">, LWM_FM_MM16<0x4>; /// Move Conditional def MOVZ_I_MM : MMRel, CMov_I_I_FT<"movz", GPR32Opnd, GPR32Opnd, Index: lib/Transforms/IPO/GlobalDCE.cpp =================================================================== --- lib/Transforms/IPO/GlobalDCE.cpp +++ lib/Transforms/IPO/GlobalDCE.cpp @@ -219,6 +219,9 @@ if (F->hasPrefixData()) MarkUsedGlobalsAsNeeded(F->getPrefixData()); + if (F->hasPrologueData()) + MarkUsedGlobalsAsNeeded(F->getPrologueData()); + for (Function::iterator BB = F->begin(), E = F->end(); BB != E; ++BB) for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ++I) for (User::op_iterator U = I->op_begin(), E = I->op_end(); U != E; ++U) Index: test/CodeGen/X86/prefixdata.ll =================================================================== --- test/CodeGen/X86/prefixdata.ll +++ test/CodeGen/X86/prefixdata.ll @@ -2,15 +2,13 @@ @i = linkonce_odr global i32 1 -; CHECK: f: -; CHECK-NEXT: .cfi_startproc +; CHECK: .type f,@function ; CHECK-NEXT: .long 1 define void @f() prefix i32 1 { ret void } -; CHECK: g: -; CHECK-NEXT: .cfi_startproc +; CHECK: .type g,@function ; CHECK-NEXT: .quad i define void @g() prefix i32* @i { ret void Index: test/CodeGen/X86/prologuedata.ll =================================================================== --- test/CodeGen/X86/prologuedata.ll +++ test/CodeGen/X86/prologuedata.ll @@ -5,13 +5,13 @@ ; CHECK: f: ; CHECK-NEXT: .cfi_startproc ; CHECK-NEXT: .long 1 -define void @f() prefix i32 1 { +define void @f() prologue i32 1 { ret void } ; CHECK: g: ; CHECK-NEXT: .cfi_startproc ; CHECK-NEXT: .quad i -define void @g() prefix i32* @i { +define void @g() prologue i32* @i { ret void } Index: test/Feature/prologuedata.ll =================================================================== --- /dev/null +++ test/Feature/prologuedata.ll @@ -0,0 +1,18 @@ +; RUN: llvm-as < %s | llvm-dis > %t1.ll +; RUN: FileCheck %s < %t1.ll +; RUN: llvm-as < %t1.ll | llvm-dis > %t2.ll +; RUN: diff %t1.ll %t2.ll +; RUN: opt -O3 -S < %t1.ll | FileCheck %s + +; CHECK: @i +@i = linkonce_odr global i32 1 + +; CHECK: f(){{.*}}prologue i32 1 +define void @f() prologue i32 1 { + ret void +} + +; CHECK: g(){{.*}}prologue i32* @i +define void @g() prologue i32* @i { + ret void +} Index: test/Linker/prologuedata.ll =================================================================== --- test/Linker/prologuedata.ll +++ test/Linker/prologuedata.ll @@ -3,7 +3,7 @@ @i = linkonce_odr global i32 1 -; CHECK: define void @f() prefix i32* @i -define void @f() prefix i32* @i { +; CHECK: define void @f() prologue i32* @i +define void @f() prologue i32* @i { ret void } Index: test/MC/Mips/micromips-invalid.s =================================================================== --- test/MC/Mips/micromips-invalid.s +++ test/MC/Mips/micromips-invalid.s @@ -22,6 +22,15 @@ li16 $4, -2 # CHECK: :[[@LINE]]:{{[0-9]+}}: error: immediate operand value out of range addiur2 $9, $7, -1 # CHECK: :[[@LINE]]:{{[0-9]+}}: error: invalid operand for instruction addiur2 $6, $7, 10 # CHECK: :[[@LINE]]:{{[0-9]+}}: error: immediate operand value out of range + lwm16 $5, $6, $ra, 8($sp) # CHECK: :[[@LINE]]:{{[0-9]+}}: error: $16 or $31 expected + lwm16 $16, $19, $ra, 8($sp) # CHECK: :[[@LINE]]:{{[0-9]+}}: error: consecutive register numbers expected + lwm16 $16-$25, $ra, 8($sp) # CHECK: :[[@LINE]]:{{[0-9]+}}: error: invalid register operand + lwm16 $16, 8($sp) # CHECK: :[[@LINE]]:{{[0-9]+}}: error: invalid operand for instruction + lwm16 $16, $17, 8($sp) # CHECK: :[[@LINE]]:{{[0-9]+}}: error: invalid operand for instruction + lwm16 $16-$20, 8($sp) # CHECK: :[[@LINE]]:{{[0-9]+}}: error: invalid operand for instruction + swm16 $5, $6, $ra, 8($sp) # CHECK: :[[@LINE]]:{{[0-9]+}}: error: $16 or $31 expected + swm16 $16, $19, $ra, 8($sp) # CHECK: :[[@LINE]]:{{[0-9]+}}: error: consecutive register numbers expected + swm16 $16-$25, $ra, 8($sp) # CHECK: :[[@LINE]]:{{[0-9]+}}: error: invalid register operand lwm32 $5, $6, 8($4) # CHECK: :[[@LINE]]:{{[0-9]+}}: error: $16 or $31 expected lwm32 $16, $19, 8($4) # CHECK: :[[@LINE]]:{{[0-9]+}}: error: consecutive register numbers expected lwm32 $16-$25, 8($4) # CHECK: :[[@LINE]]:{{[0-9]+}}: error: invalid register operand Index: test/MC/Mips/micromips-loadstore-instructions.s =================================================================== --- test/MC/Mips/micromips-loadstore-instructions.s +++ test/MC/Mips/micromips-loadstore-instructions.s @@ -29,6 +29,8 @@ # CHECK-EL: lwm32 $16, $17, $18, $19, $20, $21, $22, $23, $fp, $ra, 8($4) # encoding: [0x24,0x23,0x08,0x50] # CHECK-EL: swm32 $16, $17, 8($4) # encoding: [0x44,0x20,0x08,0xd0] # CHECK-EL: swm32 $16, $17, $18, $19, 8($4) # encoding: [0x84,0x20,0x08,0xd0] +# CHECK-EL: lwm16 $16, $17, $ra, 8($sp) # encoding: [0x12,0x45] +# CHECK-EL: swm16 $16, $17, $ra, 8($sp) # encoding: [0x52,0x45] #------------------------------------------------------------------------------ # Big endian #------------------------------------------------------------------------------ @@ -52,6 +54,8 @@ # CHECK-EB: lwm32 $16, $17, $18, $19, $20, $21, $22, $23, $fp, $ra, 8($4) # encoding: [0x23,0x24,0x50,0x08] # CHECK-EB: swm32 $16, $17, 8($4) # encoding: [0x20,0x44,0xd0,0x08] # CHECK-EB: swm32 $16, $17, $18, $19, 8($4) # encoding: [0x20,0x84,0xd0,0x08] +# CHECK-EB: lwm16 $16, $17, $ra, 8($sp) # encoding: [0x45,0x12] +# CHECK-EB: swm16 $16, $17, $ra, 8($sp) # encoding: [0x45,0x52] lb $5, 8($4) lbu $6, 8($4) lh $2, 8($4) @@ -72,3 +76,5 @@ lwm32 $16-$23, $30 - $31, 8($4) swm32 $16, $17, 8($4) swm32 $16 - $19, 8($4) + lwm16 $16, $17, $ra, 8($sp) + swm16 $16, $17, $ra, 8($sp) Index: tools/verify-uselistorder/verify-uselistorder.cpp =================================================================== --- tools/verify-uselistorder/verify-uselistorder.cpp +++ tools/verify-uselistorder/verify-uselistorder.cpp @@ -197,9 +197,12 @@ map(G.getInitializer()); for (const GlobalAlias &A : M.aliases()) map(A.getAliasee()); - for (const Function &F : M) + for (const Function &F : M) { if (F.hasPrefixData()) map(F.getPrefixData()); + if (F.hasPrologueData()) + map(F.getPrologueData()); + } // Function bodies. for (const Function &F : M) { @@ -463,9 +466,12 @@ changeValueUseList(G.getInitializer()); for (GlobalAlias &A : M.aliases()) changeValueUseList(A.getAliasee()); - for (Function &F : M) + for (Function &F : M) { if (F.hasPrefixData()) changeValueUseList(F.getPrefixData()); + if (F.hasPrologueData()) + changeValueUseList(F.getPrologueData()); + } // Function bodies. for (Function &F : M) {