Index: include/llvm/Bitcode/LLVMBitCodes.h =================================================================== --- include/llvm/Bitcode/LLVMBitCodes.h +++ include/llvm/Bitcode/LLVMBitCodes.h @@ -397,7 +397,8 @@ ATTR_KIND_IN_ALLOCA = 38, ATTR_KIND_NON_NULL = 39, ATTR_KIND_JUMP_TABLE = 40, - ATTR_KIND_DEREFERENCEABLE = 41 + ATTR_KIND_DEREFERENCEABLE = 41, + ATTR_KIND_HWREG = 42 }; enum ComdatSelectionKindCodes { Index: include/llvm/IR/Argument.h =================================================================== --- include/llvm/IR/Argument.h +++ include/llvm/IR/Argument.h @@ -65,6 +65,10 @@ /// dereferenceable. Otherwise, zero is returned. uint64_t getDereferenceableBytes() const; + /// \brief If this argument has the hwreg attribute on it in its containing + /// function, return the physical register id. Otherwise, zero is returned. + uint64_t getHWReg() const; + /// \brief Return true if this argument has the byval attribute on it in its /// containing function. bool hasByValAttr() const; Index: include/llvm/IR/Attributes.h =================================================================== --- include/llvm/IR/Attributes.h +++ include/llvm/IR/Attributes.h @@ -89,6 +89,7 @@ ///< often, so lazy binding isn't worthwhile NonNull, ///< Pointer is known to be not null Dereferenceable, ///< Pointer is known to be dereferenceable + HWReg, ///< Parameter is in a physical register NoRedZone, ///< Disable redzone NoReturn, ///< Mark the function as not returning NoUnwind, ///< Function doesn't unwind stack @@ -136,6 +137,7 @@ static Attribute getWithStackAlignment(LLVMContext &Context, uint64_t Align); static Attribute getWithDereferenceableBytes(LLVMContext &Context, uint64_t Bytes); + static Attribute getWithHWReg(LLVMContext &Context, uint64_t Reg); //===--------------------------------------------------------------------===// // Attribute Accessors @@ -185,6 +187,9 @@ /// dereferenceable attribute (or zero if unknown). uint64_t getDereferenceableBytes() const; + /// \brief Extract the register id of hwreg parameter (or zero if unknown). + uint64_t getHWReg() const; + /// \brief The Attribute is converted to a string of equivalent mnemonic. This /// is, presumably, for writing out the mnemonics for the assembly writer. std::string getAsString(bool InAttrGrp = false) const; @@ -331,6 +336,9 @@ /// \brief Get the number of dereferenceable bytes (or zero if unknown). uint64_t getDereferenceableBytes(unsigned Index) const; + /// \brief Extract the register id of hwreg parameter. (or zero if unknown). + uint64_t getHWReg(unsigned Index) const; + /// \brief Return the attributes at the index as a string. std::string getAsString(unsigned Index, bool InAttrGrp = false) const; @@ -411,14 +419,15 @@ uint64_t Alignment; uint64_t StackAlignment; uint64_t DerefBytes; + uint64_t HWReg; public: AttrBuilder() : Attrs(0), Alignment(0), StackAlignment(0), DerefBytes(0) {} explicit AttrBuilder(uint64_t Val) - : Attrs(0), Alignment(0), StackAlignment(0), DerefBytes(0) { + : Attrs(0), Alignment(0), StackAlignment(0), DerefBytes(0), HWReg(0) { addRawValue(Val); } AttrBuilder(const Attribute &A) - : Attrs(0), Alignment(0), StackAlignment(0), DerefBytes(0) { + : Attrs(0), Alignment(0), StackAlignment(0), DerefBytes(0), HWReg(0) { addAttribute(A); } AttrBuilder(AttributeSet AS, unsigned Idx); @@ -476,6 +485,9 @@ /// attribute exists (zero is returned otherwise). uint64_t getDereferenceableBytes() const { return DerefBytes; } + /// \brief Extract the register id of hwreg parameter (0=unknown). + uint64_t getHWReg() const { return HWReg; } + /// \brief This turns an int alignment (which must be a power of 2) into the /// form used internally in Attribute. AttrBuilder &addAlignmentAttr(unsigned Align); @@ -488,6 +500,10 @@ /// internally in Attribute. AttrBuilder &addDereferenceableAttr(uint64_t Bytes); + /// \brief This turns the register id into the form used internally in + /// Attribute. + AttrBuilder &addHWRegAttr(uint64_t Reg); + /// \brief Return true if the builder contains no target-independent /// attributes. bool empty() const { return Attrs.none(); } Index: include/llvm/IR/CallSite.h =================================================================== --- include/llvm/IR/CallSite.h +++ include/llvm/IR/CallSite.h @@ -223,6 +223,11 @@ CALLSITE_DELEGATE_GETTER(getDereferenceableBytes(i)); } + /// @brief Extract the hwreg register for a parameter (0=unknown). + uint64_t getHWReg(uint16_t i) const { + CALLSITE_DELEGATE_GETTER(getHWReg(i)); + } + /// \brief Return true if the call should not be treated as a call to a /// builtin. bool isNoBuiltin() const { Index: include/llvm/IR/Function.h =================================================================== --- include/llvm/IR/Function.h +++ include/llvm/IR/Function.h @@ -234,6 +234,11 @@ return AttributeSets.getDereferenceableBytes(i); } + /// @brief Extract the register id of hwreg parameter (0=unknown). + uint64_t getHWReg(unsigned i) const { + return AttributeSets.getHWReg(i); + } + /// @brief Determine if the function does not access memory. bool doesNotAccessMemory() const { return AttributeSets.hasAttribute(AttributeSet::FunctionIndex, Index: include/llvm/IR/Instructions.h =================================================================== --- include/llvm/IR/Instructions.h +++ include/llvm/IR/Instructions.h @@ -1433,6 +1433,11 @@ return AttributeList.getDereferenceableBytes(i); } + /// \brief Extract the register id of a hwreg attribute (0=unknown). + uint64_t getHWReg(unsigned i) const { + return AttributeList.getHWReg(i); + } + /// \brief Return true if the call should not be treated as a call to a /// builtin. bool isNoBuiltin() const { @@ -3125,6 +3130,11 @@ return AttributeList.getDereferenceableBytes(i); } + /// \brief Extract the register id for a hwreg parameter (0=unknown). + uint64_t getHWReg(unsigned i) const { + return AttributeList.getHWReg(i); + } + /// \brief Return true if the call should not be treated as a call to a /// builtin. bool isNoBuiltin() const { Index: include/llvm/Target/TargetCallingConv.h =================================================================== --- include/llvm/Target/TargetCallingConv.h +++ include/llvm/Target/TargetCallingConv.h @@ -54,11 +54,15 @@ static const uint64_t InConsecutiveRegs = 0x1ULL<<63; ///< Struct size static const uint64_t InConsecutiveRegsOffs = 63; + static const uint64_t ExtHWReg = 0xFFFFULL<<0; + static const uint64_t ExtHWRegOffs = 0; + static const uint64_t One = 1ULL; ///< 1 of this type, for shifts uint64_t Flags; + uint64_t Extension; public: - ArgFlagsTy() : Flags(0) { } + ArgFlagsTy() : Flags(0), Extension(0) { } bool isZExt() const { return Flags & ZExt; } void setZExt() { Flags |= One << ZExtOffs; } @@ -120,6 +124,14 @@ /// getRawBits - Represent the flags as a bunch of bits. uint64_t getRawBits() const { return Flags; } + + bool isHWReg() const { return Extension & ExtHWReg; } + void setHWReg(unsigned Reg) { + Extension = (Extension & ~ExtHWReg) | (uint64_t)Reg<> ExtHWRegOffs); + } }; /// InputArg - This struct carries flags and type information about a Index: lib/AsmParser/LLLexer.cpp =================================================================== --- lib/AsmParser/LLLexer.cpp +++ lib/AsmParser/LLLexer.cpp @@ -599,6 +599,7 @@ KEYWORD(inalloca); KEYWORD(cold); KEYWORD(dereferenceable); + KEYWORD(hwreg); KEYWORD(inlinehint); KEYWORD(inreg); KEYWORD(jumptable); Index: lib/AsmParser/LLParser.h =================================================================== --- lib/AsmParser/LLParser.h +++ lib/AsmParser/LLParser.h @@ -224,6 +224,7 @@ bool ParseOptionalCallingConv(unsigned &CC); bool ParseOptionalAlignment(unsigned &Alignment); bool ParseOptionalDereferenceableBytes(uint64_t &Bytes); + bool ParseOptionalHWReg(uint64_t &Reg); bool ParseScopeAndOrdering(bool isAtomic, SynchronizationScope &Scope, AtomicOrdering &Ordering); bool ParseOrdering(AtomicOrdering &Ordering); Index: lib/AsmParser/LLParser.cpp =================================================================== --- lib/AsmParser/LLParser.cpp +++ lib/AsmParser/LLParser.cpp @@ -976,6 +976,7 @@ break; case lltok::kw_byval: case lltok::kw_dereferenceable: + case lltok::kw_hwreg: case lltok::kw_inalloca: case lltok::kw_nest: case lltok::kw_noalias: @@ -1225,6 +1226,13 @@ B.addDereferenceableAttr(Bytes); continue; } + case lltok::kw_hwreg: { + uint64_t Reg; + if (ParseOptionalHWReg(Reg)) + return true; + B.addHWRegAttr(Reg); + continue; + } case lltok::kw_inalloca: B.addAttribute(Attribute::InAlloca); break; case lltok::kw_inreg: B.addAttribute(Attribute::InReg); break; case lltok::kw_nest: B.addAttribute(Attribute::Nest); break; @@ -1303,6 +1311,7 @@ case lltok::kw_nocapture: case lltok::kw_returned: case lltok::kw_sret: + case lltok::kw_hwreg: HaveError |= Error(Lex.getLoc(), "invalid use of parameter-only attribute"); break; @@ -1538,6 +1547,23 @@ return false; } +/// ParseOptionalHWReg +/// ::= 'hwreg' '(' 4 ')' +bool LLParser::ParseOptionalHWReg(uint64_t &Reg) { + Reg = 0; + if (!EatIfPresent(lltok::kw_hwreg)) + return false; + LocTy ParenLoc = Lex.getLoc(); + if (!EatIfPresent(lltok::lparen)) + return Error(ParenLoc, "expected '('"); + LocTy DerefLoc = Lex.getLoc(); + if (ParseUInt64(Reg)) return true; + ParenLoc = Lex.getLoc(); + if (!EatIfPresent(lltok::rparen)) + return Error(DerefLoc, "expected ')'"); + return false; +} + /// ParseOptionalCommaAlign /// ::= /// ::= ',' align 4 Index: lib/AsmParser/LLToken.h =================================================================== --- lib/AsmParser/LLToken.h +++ lib/AsmParser/LLToken.h @@ -106,6 +106,7 @@ kw_inalloca, kw_cold, kw_dereferenceable, + kw_hwreg, kw_inlinehint, kw_inreg, kw_jumptable, Index: lib/Bitcode/Reader/BitcodeReader.cpp =================================================================== --- lib/Bitcode/Reader/BitcodeReader.cpp +++ lib/Bitcode/Reader/BitcodeReader.cpp @@ -1098,6 +1098,8 @@ return Attribute::NonNull; case bitc::ATTR_KIND_DEREFERENCEABLE: return Attribute::Dereferenceable; + case bitc::ATTR_KIND_HWREG: + return Attribute::HWReg; case bitc::ATTR_KIND_NO_RED_ZONE: return Attribute::NoRedZone; case bitc::ATTR_KIND_NO_RETURN: @@ -1214,6 +1216,8 @@ B.addStackAlignmentAttr(Record[++i]); else if (Kind == Attribute::Dereferenceable) B.addDereferenceableAttr(Record[++i]); + else if (Kind == Attribute::HWReg) + B.addHWRegAttr(Record[++i]); } else { // String attribute assert((Record[i] == 3 || Record[i] == 4) && "Invalid attribute group entry"); Index: lib/Bitcode/Writer/BitcodeWriter.cpp =================================================================== --- lib/Bitcode/Writer/BitcodeWriter.cpp +++ lib/Bitcode/Writer/BitcodeWriter.cpp @@ -200,6 +200,8 @@ return bitc::ATTR_KIND_NON_NULL; case Attribute::Dereferenceable: return bitc::ATTR_KIND_DEREFERENCEABLE; + case Attribute::HWReg: + return bitc::ATTR_KIND_HWREG; case Attribute::NoRedZone: return bitc::ATTR_KIND_NO_RED_ZONE; case Attribute::NoReturn: Index: lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp =================================================================== --- lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -7507,6 +7507,8 @@ Flags.setSRet(); if (F.getAttributes().hasAttribute(Idx, Attribute::ByVal)) Flags.setByVal(); + if (F.getAttributes().hasAttribute(Idx, Attribute::HWReg)) + Flags.setHWReg(F.getAttributes().getHWReg(Idx)); if (F.getAttributes().hasAttribute(Idx, Attribute::InAlloca)) { Flags.setInAlloca(); // Set the byval flag for CCAssignFn callbacks that don't know about Index: lib/IR/AttributeImpl.h =================================================================== --- lib/IR/AttributeImpl.h +++ lib/IR/AttributeImpl.h @@ -117,7 +117,7 @@ : EnumAttributeImpl(IntAttrEntry, Kind), Val(Val) { assert( (Kind == Attribute::Alignment || Kind == Attribute::StackAlignment || - Kind == Attribute::Dereferenceable) && + Kind == Attribute::Dereferenceable || Kind == Attribute::HWReg) && "Wrong kind for int attribute!"); } @@ -166,6 +166,7 @@ unsigned getAlignment() const; unsigned getStackAlignment() const; uint64_t getDereferenceableBytes() const; + uint64_t getHWReg() const; std::string getAsString(bool InAttrGrp) const; typedef const Attribute *iterator; Index: lib/IR/Attributes.cpp =================================================================== --- lib/IR/Attributes.cpp +++ lib/IR/Attributes.cpp @@ -94,6 +94,12 @@ return get(Context, Dereferenceable, Bytes); } +Attribute Attribute::getWithHWReg(LLVMContext &Context, + uint64_t Reg) { + assert(Reg && "Reg must be non-zero."); + return get(Context, HWReg, Reg); +} + //===----------------------------------------------------------------------===// // Attribute Accessor Methods //===----------------------------------------------------------------------===// @@ -170,6 +176,13 @@ return pImpl->getValueAsInt(); } +/// This returns the hwreg attribute or zero of not used. +uint64_t Attribute::getHWReg() const { + assert(hasAttribute(Attribute::HWReg) && + "Trying to get hwreg register from non-hwreg attribute!"); + return pImpl->getValueAsInt(); +} + std::string Attribute::getAsString(bool InAttrGrp) const { if (!pImpl) return ""; @@ -291,6 +304,20 @@ return Result; } + if (hasAttribute(Attribute::HWReg)) { + std::string Result; + Result += "hwreg"; + if (InAttrGrp) { + Result += "="; + Result += utostr(getValueAsInt()); + } else { + Result += "("; + Result += utostr(getValueAsInt()); + Result += ")"; + } + return Result; + } + // Convert target-dependent attributes to strings of the form: // // "kind" @@ -426,6 +453,7 @@ case Attribute::InAlloca: return 1ULL << 43; case Attribute::NonNull: return 1ULL << 44; case Attribute::JumpTable: return 1ULL << 45; + case Attribute::HWReg: case Attribute::Dereferenceable: llvm_unreachable("dereferenceable attribute not supported in raw format"); } @@ -519,6 +547,13 @@ return 0; } +uint64_t AttributeSetNode::getHWReg() const { + for (iterator I = begin(), E = end(); I != E; ++I) + if (I->hasAttribute(Attribute::HWReg)) + return I->getHWReg(); + return 0; +} + std::string AttributeSetNode::getAsString(bool InAttrGrp) const { std::string Str; for (iterator I = begin(), E = end(); I != E; ++I) { @@ -554,6 +589,8 @@ Mask |= (Log2_32(ASN->getStackAlignment()) + 1) << 26; else if (Kind == Attribute::Dereferenceable) llvm_unreachable("dereferenceable not supported in bit mask"); + else if (Kind == Attribute::HWReg) + llvm_unreachable("hwreg not supported in bit mask"); else Mask |= AttributeImpl::getAttrMask(Kind); } @@ -663,6 +700,9 @@ Attrs.push_back(std::make_pair(Index, Attribute::getWithDereferenceableBytes(C, B.getDereferenceableBytes()))); + else if (Kind == Attribute::HWReg) + Attrs.push_back(std::make_pair(Index, + Attribute::getWithHWReg(C, B.getHWReg()))); else Attrs.push_back(std::make_pair(Index, Attribute::get(C, Kind))); } @@ -932,6 +972,11 @@ return ASN ? ASN->getDereferenceableBytes() : 0; } +uint64_t AttributeSet::getHWReg(unsigned Index) const { + AttributeSetNode *ASN = getAttributes(Index); + return ASN ? ASN->getHWReg() : 0; +} + std::string AttributeSet::getAsString(unsigned Index, bool InAttrGrp) const { AttributeSetNode *ASN = getAttributes(Index); @@ -1034,8 +1079,8 @@ AttrBuilder &AttrBuilder::addAttribute(Attribute::AttrKind Val) { assert((unsigned)Val < Attribute::EndAttrKinds && "Attribute out of range!"); assert(Val != Attribute::Alignment && Val != Attribute::StackAlignment && - Val != Attribute::Dereferenceable && - "Adding integer attribute without adding a value!"); + Val != Attribute::Dereferenceable && Val != Attribute::HWReg + && "Adding integer attribute without adding a value!"); Attrs[Val] = true; return *this; } @@ -1055,6 +1100,8 @@ StackAlignment = Attr.getStackAlignment(); else if (Kind == Attribute::Dereferenceable) DerefBytes = Attr.getDereferenceableBytes(); + else if (Kind == Attribute::HWReg) + HWReg = Attr.getHWReg(); return *this; } @@ -1099,6 +1146,8 @@ StackAlignment = 0; else if (Kind == Attribute::Dereferenceable) DerefBytes = 0; + else if (Kind == Attribute::HWReg) + HWReg = 0; } else { assert(Attr.isStringAttribute() && "Invalid attribute type!"); std::map::iterator @@ -1149,6 +1198,14 @@ return *this; } +AttrBuilder &AttrBuilder::addHWRegAttr(uint64_t Reg) { + if (Reg == 0) return *this; + + Attrs[Attribute::HWReg] = true; + HWReg = Reg; + return *this; +} + AttrBuilder &AttrBuilder::merge(const AttrBuilder &B) { // FIXME: What if both have alignments, but they don't match?! if (!Alignment) @@ -1227,6 +1284,8 @@ I = Attribute::AttrKind(I + 1)) { if (I == Attribute::Dereferenceable) continue; + if (I == Attribute::HWReg) + continue; if (uint64_t A = (Val & AttributeImpl::getAttrMask(I))) { Attrs[I] = true; Index: lib/IR/Function.cpp =================================================================== --- lib/IR/Function.cpp +++ lib/IR/Function.cpp @@ -117,6 +117,10 @@ return getParent()->getDereferenceableBytes(getArgNo()+1); } +uint64_t Argument::getHWReg() const { + return getParent()->getHWReg(getArgNo()+1); +} + /// hasNestAttr - Return true if this argument has the nest attribute on /// it in its containing function. bool Argument::hasNestAttr() const {