Allow creating llvm::Function in non-zero address spaces

Most users won't have to worry about this as all of the
'getOrInsertFunction' functions on Module will default to the program
address space.

An overload has been added to Function::Create to abstract away the
details for most callers.

This is based on https://reviews.llvm.org/D37054 but without the changes to
make passing a Module to Function::Create() mandatory. I have also added
some more tests and fixed the LLParser to accept call instructions for
types in the program address space.

Reviewed By: bjope

Differential Revision: https://reviews.llvm.org/D47541

llvm-svn: 340519
This commit is contained in:
Alexander Richardson 2018-08-23 09:25:17 +00:00
parent ba9eee5fad
commit 6bcf2ba2f0
23 changed files with 369 additions and 119 deletions

View File

@ -719,7 +719,7 @@ an optional ``unnamed_addr`` attribute, a return type, an optional
:ref:`parameter attribute <paramattrs>` for the return type, a function
name, a (possibly empty) argument list (each with optional :ref:`parameter
attributes <paramattrs>`), optional :ref:`function attributes <fnattrs>`,
an optional section, an optional alignment,
an optional address space, an optional section, an optional alignment,
an optional :ref:`comdat <langref_comdats>`,
an optional :ref:`garbage collector name <gc>`, an optional :ref:`prefix <prefixdata>`,
an optional :ref:`prologue <prologuedata>`,
@ -731,8 +731,8 @@ LLVM function declarations consist of the "``declare``" keyword, an
optional :ref:`linkage type <linkage>`, an optional :ref:`visibility style
<visibility>`, an optional :ref:`DLL storage class <dllstorageclass>`, an
optional :ref:`calling convention <callingconv>`, an optional ``unnamed_addr``
or ``local_unnamed_addr`` attribute, a return type, an optional :ref:`parameter
attribute <paramattrs>` for the return type, a function name, a possibly
or ``local_unnamed_addr`` attribute, an optional address space, a return type,
an optional :ref:`parameter attribute <paramattrs>` for the return type, a function name, a possibly
empty list of arguments, an optional alignment, an optional :ref:`garbage
collector name <gc>`, an optional :ref:`prefix <prefixdata>`, and an optional
:ref:`prologue <prologuedata>`.
@ -769,13 +769,16 @@ be significant and two identical functions can be merged.
If the ``local_unnamed_addr`` attribute is given, the address is known to
not be significant within the module.
If an explicit address space is not given, it will default to the program
address space from the :ref:`datalayout string<langref_datalayout>`.
Syntax::
define [linkage] [PreemptionSpecifier] [visibility] [DLLStorageClass]
[cconv] [ret attrs]
<ResultType> @<FunctionName> ([argument list])
[(unnamed_addr|local_unnamed_addr)] [fn Attrs] [section "name"]
[comdat [($name)]] [align N] [gc] [prefix Constant]
[(unnamed_addr|local_unnamed_addr)] [AddrSpace] [fn Attrs]
[section "name"] [comdat [($name)]] [align N] [gc] [prefix Constant]
[prologue Constant] [personality Constant] (!name !N)* { ... }
The argument list is a comma separated sequence of arguments where each
@ -6452,7 +6455,7 @@ Syntax:
::
<result> = invoke [cconv] [ret attrs] <ty>|<fnty> <fnptrval>(<function args>) [fn attrs]
<result> = invoke [cconv] [ret attrs] [addrspace(<num>)] [<ty>|<fnty> <fnptrval>(<function args>) [fn attrs]
[operand bundles] to label <normal label> unwind label <exception label>
Overview:
@ -6488,6 +6491,9 @@ This instruction requires several arguments:
#. The optional :ref:`Parameter Attributes <paramattrs>` list for return
values. Only '``zeroext``', '``signext``', and '``inreg``' attributes
are valid here.
#. The optional addrspace attribute can be used to indicate the adress space
of the called function. If it is not specified, the program address space
from the :ref:`datalayout string<langref_datalayout>` will be used.
#. '``ty``': the type of the call instruction itself which is also the
type of the return value. Functions that return no value are marked
``void``.
@ -9503,8 +9509,8 @@ Syntax:
::
<result> = [tail | musttail | notail ] call [fast-math flags] [cconv] [ret attrs] <ty>|<fnty> <fnptrval>(<function args>) [fn attrs]
[ operand bundles ]
<result> = [tail | musttail | notail ] call [fast-math flags] [cconv] [ret attrs] [addrspace(<num>)]
[<ty>|<fnty> <fnptrval>(<function args>) [fn attrs] [ operand bundles ]
Overview:
"""""""""
@ -9575,6 +9581,9 @@ This instruction requires several arguments:
#. The optional :ref:`Parameter Attributes <paramattrs>` list for return
values. Only '``zeroext``', '``signext``', and '``inreg``' attributes
are valid here.
#. The optional addrspace attribute can be used to indicate the adress space
of the called function. If it is not specified, the program address space
from the :ref:`datalayout string<langref_datalayout>` will be used.
#. '``ty``': the type of the call instruction itself which is also the
type of the return value. Functions that return no value are marked
``void``.

View File

@ -120,7 +120,7 @@ private:
/// function is automatically inserted into the end of the function list for
/// the module.
///
Function(FunctionType *Ty, LinkageTypes Linkage,
Function(FunctionType *Ty, LinkageTypes Linkage, unsigned AddrSpace,
const Twine &N = "", Module *M = nullptr);
public:
@ -134,10 +134,24 @@ public:
const Function &getFunction() const { return *this; }
static Function *Create(FunctionType *Ty, LinkageTypes Linkage,
const Twine &N = "", Module *M = nullptr) {
return new Function(Ty, Linkage, N, M);
unsigned AddrSpace, const Twine &N = "",
Module *M = nullptr) {
return new Function(Ty, Linkage, AddrSpace, N, M);
}
// TODO: remove this once all users have been updated to pass an AddrSpace
static Function *Create(FunctionType *Ty, LinkageTypes Linkage,
const Twine &N = "", Module *M = nullptr) {
return new Function(Ty, Linkage, static_cast<unsigned>(-1), N, M);
}
/// Creates a new function and attaches it to a module.
///
/// Places the function in the program address space as specified
/// by the module's data layout.
static Function *Create(FunctionType *Ty, LinkageTypes Linkage,
const Twine &N, Module &M);
// Provide fast operand accessors.
DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value);

View File

@ -189,6 +189,7 @@ public:
GlobalValue(const GlobalValue &) = delete;
unsigned getAlignment() const;
unsigned getAddressSpace() const;
enum class UnnamedAddr {
None,

View File

@ -1317,7 +1317,8 @@ bool LLParser::ParseFnAttributeValuePairs(AttrBuilder &B,
static inline GlobalValue *createGlobalFwdRef(Module *M, PointerType *PTy,
const std::string &Name) {
if (auto *FT = dyn_cast<FunctionType>(PTy->getElementType()))
return Function::Create(FT, GlobalValue::ExternalWeakLinkage, Name, M);
return Function::Create(FT, GlobalValue::ExternalWeakLinkage,
PTy->getAddressSpace(), Name, M);
else
return new GlobalVariable(*M, PTy->getElementType(), false,
GlobalValue::ExternalWeakLinkage, nullptr, Name,
@ -1325,11 +1326,33 @@ static inline GlobalValue *createGlobalFwdRef(Module *M, PointerType *PTy,
PTy->getAddressSpace());
}
Value *LLParser::checkValidVariableType(LocTy Loc, const Twine &Name, Type *Ty,
Value *Val, bool IsCall) {
if (Val->getType() == Ty)
return Val;
// For calls we also accept variables in the program address space.
Type *SuggestedTy = Ty;
if (IsCall && isa<PointerType>(Ty)) {
Type *TyInProgAS = cast<PointerType>(Ty)->getElementType()->getPointerTo(
M->getDataLayout().getProgramAddressSpace());
SuggestedTy = TyInProgAS;
if (Val->getType() == TyInProgAS)
return Val;
}
if (Ty->isLabelTy())
Error(Loc, "'" + Name + "' is not a basic block");
else
Error(Loc, "'" + Name + "' defined with type '" +
getTypeString(Val->getType()) + "' but expected '" +
getTypeString(SuggestedTy) + "'");
return nullptr;
}
/// GetGlobalVal - Get a value with the specified name or ID, creating a
/// forward reference record if needed. This can return null if the value
/// exists but does not have the right type.
GlobalValue *LLParser::GetGlobalVal(const std::string &Name, Type *Ty,
LocTy Loc) {
LocTy Loc, bool IsCall) {
PointerType *PTy = dyn_cast<PointerType>(Ty);
if (!PTy) {
Error(Loc, "global variable reference must have pointer type");
@ -1349,12 +1372,9 @@ GlobalValue *LLParser::GetGlobalVal(const std::string &Name, Type *Ty,
}
// If we have the value in the symbol table or fwd-ref table, return it.
if (Val) {
if (Val->getType() == Ty) return Val;
Error(Loc, "'@" + Name + "' defined with type '" +
getTypeString(Val->getType()) + "'");
return nullptr;
}
if (Val)
return cast_or_null<GlobalValue>(
checkValidVariableType(Loc, "@" + Name, Ty, Val, IsCall));
// Otherwise, create a new forward reference for this value and remember it.
GlobalValue *FwdVal = createGlobalFwdRef(M, PTy, Name);
@ -1362,7 +1382,8 @@ GlobalValue *LLParser::GetGlobalVal(const std::string &Name, Type *Ty,
return FwdVal;
}
GlobalValue *LLParser::GetGlobalVal(unsigned ID, Type *Ty, LocTy Loc) {
GlobalValue *LLParser::GetGlobalVal(unsigned ID, Type *Ty, LocTy Loc,
bool IsCall) {
PointerType *PTy = dyn_cast<PointerType>(Ty);
if (!PTy) {
Error(Loc, "global variable reference must have pointer type");
@ -1380,12 +1401,9 @@ GlobalValue *LLParser::GetGlobalVal(unsigned ID, Type *Ty, LocTy Loc) {
}
// If we have the value in the symbol table or fwd-ref table, return it.
if (Val) {
if (Val->getType() == Ty) return Val;
Error(Loc, "'@" + Twine(ID) + "' defined with type '" +
getTypeString(Val->getType()) + "'");
return nullptr;
}
if (Val)
return cast_or_null<GlobalValue>(
checkValidVariableType(Loc, "@" + Twine(ID), Ty, Val, IsCall));
// Otherwise, create a new forward reference for this value and remember it.
GlobalValue *FwdVal = createGlobalFwdRef(M, PTy, "");
@ -1500,8 +1518,8 @@ bool LLParser::ParseOptionalThreadLocal(GlobalVariable::ThreadLocalMode &TLM) {
/// ParseOptionalAddrSpace
/// := /*empty*/
/// := 'addrspace' '(' uint32 ')'
bool LLParser::ParseOptionalAddrSpace(unsigned &AddrSpace) {
AddrSpace = 0;
bool LLParser::ParseOptionalAddrSpace(unsigned &AddrSpace, unsigned DefaultAS) {
AddrSpace = DefaultAS;
if (!EatIfPresent(lltok::kw_addrspace))
return false;
return ParseToken(lltok::lparen, "expected '(' in address space") ||
@ -2741,19 +2759,6 @@ bool LLParser::PerFunctionState::FinishFunction() {
return false;
}
static bool isValidVariableType(Module *M, Type *Ty, Value *Val, bool IsCall) {
if (Val->getType() == Ty)
return true;
// For calls we also accept variables in the program address space
if (IsCall && isa<PointerType>(Ty)) {
Type *TyInProgAS = cast<PointerType>(Ty)->getElementType()->getPointerTo(
M->getDataLayout().getProgramAddressSpace());
if (Val->getType() == TyInProgAS)
return true;
}
return false;
}
/// GetVal - Get a value with the specified name or ID, creating a
/// forward reference record if needed. This can return null if the value
/// exists but does not have the right type.
@ -2771,16 +2776,8 @@ Value *LLParser::PerFunctionState::GetVal(const std::string &Name, Type *Ty,
}
// If we have the value in the symbol table or fwd-ref table, return it.
if (Val) {
if (isValidVariableType(P.M, Ty, Val, IsCall))
return Val;
if (Ty->isLabelTy())
P.Error(Loc, "'%" + Name + "' is not a basic block");
else
P.Error(Loc, "'%" + Name + "' defined with type '" +
getTypeString(Val->getType()) + "'");
return nullptr;
}
if (Val)
return P.checkValidVariableType(Loc, "%" + Name, Ty, Val, IsCall);
// Don't make placeholders with invalid type.
if (!Ty->isFirstClassType()) {
@ -2814,16 +2811,8 @@ Value *LLParser::PerFunctionState::GetVal(unsigned ID, Type *Ty, LocTy Loc,
}
// If we have the value in the symbol table or fwd-ref table, return it.
if (Val) {
if (isValidVariableType(P.M, Ty, Val, IsCall))
return Val;
if (Ty->isLabelTy())
P.Error(Loc, "'%" + Twine(ID) + "' is not a basic block");
else
P.Error(Loc, "'%" + Twine(ID) + "' defined with type '" +
getTypeString(Val->getType()) + "'");
return nullptr;
}
if (Val)
return P.checkValidVariableType(Loc, "%" + Twine(ID), Ty, Val, IsCall);
if (!Ty->isFirstClassType()) {
P.Error(Loc, "invalid use of a non-first-class type");
@ -4940,10 +4929,10 @@ bool LLParser::ConvertValIDToValue(Type *Ty, ValID &ID, Value *&V,
return false;
}
case ValID::t_GlobalName:
V = GetGlobalVal(ID.StrVal, Ty, ID.Loc);
V = GetGlobalVal(ID.StrVal, Ty, ID.Loc, IsCall);
return V == nullptr;
case ValID::t_GlobalID:
V = GetGlobalVal(ID.UIntVal, Ty, ID.Loc);
V = GetGlobalVal(ID.UIntVal, Ty, ID.Loc, IsCall);
return V == nullptr;
case ValID::t_APSInt:
if (!Ty->isIntegerTy())
@ -5086,8 +5075,8 @@ bool LLParser::ParseTypeAndBasicBlock(BasicBlock *&BB, LocTy &Loc,
/// FunctionHeader
/// ::= OptionalLinkage OptionalPreemptionSpecifier OptionalVisibility
/// OptionalCallingConv OptRetAttrs OptUnnamedAddr Type GlobalName
/// '(' ArgList ')' OptFuncAttrs OptSection OptionalAlign OptGC
/// OptionalPrefix OptionalPrologue OptPersonalityFn
/// '(' ArgList ')' OptAddrSpace OptFuncAttrs OptSection OptionalAlign
/// OptGC OptionalPrefix OptionalPrologue OptPersonalityFn
bool LLParser::ParseFunctionHeader(Function *&Fn, bool isDefine) {
// Parse the linkage.
LocTy LinkageLoc = Lex.getLoc();
@ -5165,6 +5154,7 @@ bool LLParser::ParseFunctionHeader(Function *&Fn, bool isDefine) {
unsigned Alignment;
std::string GC;
GlobalValue::UnnamedAddr UnnamedAddr = GlobalValue::UnnamedAddr::None;
unsigned AddrSpace = 0;
Constant *Prefix = nullptr;
Constant *Prologue = nullptr;
Constant *PersonalityFn = nullptr;
@ -5172,6 +5162,7 @@ bool LLParser::ParseFunctionHeader(Function *&Fn, bool isDefine) {
if (ParseArgumentList(ArgList, isVarArg) ||
ParseOptionalUnnamedAddr(UnnamedAddr) ||
ParseOptionalProgramAddrSpace(AddrSpace) ||
ParseFnAttributeValuePairs(FuncAttrs, FwdRefAttrGrps, false,
BuiltinLoc) ||
(EatIfPresent(lltok::kw_section) &&
@ -5216,7 +5207,7 @@ bool LLParser::ParseFunctionHeader(Function *&Fn, bool isDefine) {
FunctionType *FT =
FunctionType::get(RetType, ParamTypeList, isVarArg);
PointerType *PFT = PointerType::getUnqual(FT);
PointerType *PFT = PointerType::get(FT, AddrSpace);
Fn = nullptr;
if (!FunctionName.empty()) {
@ -5230,8 +5221,9 @@ bool LLParser::ParseFunctionHeader(Function *&Fn, bool isDefine) {
"function as global value!");
if (Fn->getType() != PFT)
return Error(FRVI->second.second, "invalid forward reference to "
"function '" + FunctionName + "' with wrong type!");
"function '" + FunctionName + "' with wrong type: "
"expected '" + getTypeString(PFT) + "' but was '" +
getTypeString(Fn->getType()) + "'");
ForwardRefVals.erase(FRVI);
} else if ((Fn = M->getFunction(FunctionName))) {
// Reject redefinitions.
@ -5249,16 +5241,21 @@ bool LLParser::ParseFunctionHeader(Function *&Fn, bool isDefine) {
Fn = cast<Function>(I->second.first);
if (Fn->getType() != PFT)
return Error(NameLoc, "type of definition and forward reference of '@" +
Twine(NumberedVals.size()) + "' disagree");
Twine(NumberedVals.size()) + "' disagree: "
"expected '" + getTypeString(PFT) + "' but was '" +
getTypeString(Fn->getType()) + "'");
ForwardRefValIDs.erase(I);
}
}
if (!Fn)
Fn = Function::Create(FT, GlobalValue::ExternalLinkage, FunctionName, M);
Fn = Function::Create(FT, GlobalValue::ExternalLinkage, AddrSpace,
FunctionName, M);
else // Move the forward-reference to the correct spot in the module.
M->getFunctionList().splice(M->end(), M->getFunctionList(), Fn);
assert(Fn->getAddressSpace() == AddrSpace && "Created function in wrong AS");
if (FunctionName.empty())
NumberedVals.push_back(Fn);
@ -5777,6 +5774,7 @@ bool LLParser::ParseInvoke(Instruction *&Inst, PerFunctionState &PFS) {
std::vector<unsigned> FwdRefAttrGrps;
LocTy NoBuiltinLoc;
unsigned CC;
unsigned InvokeAddrSpace;
Type *RetType = nullptr;
LocTy RetTypeLoc;
ValID CalleeID;
@ -5785,6 +5783,7 @@ bool LLParser::ParseInvoke(Instruction *&Inst, PerFunctionState &PFS) {
BasicBlock *NormalBB, *UnwindBB;
if (ParseOptionalCallingConv(CC) || ParseOptionalReturnAttrs(RetAttrs) ||
ParseOptionalProgramAddrSpace(InvokeAddrSpace) ||
ParseType(RetType, RetTypeLoc, true /*void allowed*/) ||
ParseValID(CalleeID) || ParseParameterList(ArgList, PFS) ||
ParseFnAttributeValuePairs(FnAttrs, FwdRefAttrGrps, false,
@ -5816,8 +5815,8 @@ bool LLParser::ParseInvoke(Instruction *&Inst, PerFunctionState &PFS) {
// Look up the callee.
Value *Callee;
if (ConvertValIDToValue(PointerType::getUnqual(Ty), CalleeID, Callee, &PFS,
/*IsCall=*/true))
if (ConvertValIDToValue(PointerType::get(Ty, InvokeAddrSpace), CalleeID,
Callee, &PFS, /*IsCall=*/true))
return true;
// Set up the Attribute for the function.
@ -6360,6 +6359,7 @@ bool LLParser::ParseCall(Instruction *&Inst, PerFunctionState &PFS,
AttrBuilder RetAttrs, FnAttrs;
std::vector<unsigned> FwdRefAttrGrps;
LocTy BuiltinLoc;
unsigned CallAddrSpace;
unsigned CC;
Type *RetType = nullptr;
LocTy RetTypeLoc;
@ -6376,6 +6376,7 @@ bool LLParser::ParseCall(Instruction *&Inst, PerFunctionState &PFS,
FastMathFlags FMF = EatFastMathFlagsIfPresent();
if (ParseOptionalCallingConv(CC) || ParseOptionalReturnAttrs(RetAttrs) ||
ParseOptionalProgramAddrSpace(CallAddrSpace) ||
ParseType(RetType, RetTypeLoc, true /*void allowed*/) ||
ParseValID(CalleeID) ||
ParseParameterList(ArgList, PFS, TCK == CallInst::TCK_MustTail,
@ -6408,8 +6409,8 @@ bool LLParser::ParseCall(Instruction *&Inst, PerFunctionState &PFS,
// Look up the callee.
Value *Callee;
if (ConvertValIDToValue(PointerType::getUnqual(Ty), CalleeID, Callee, &PFS,
/*IsCall=*/true))
if (ConvertValIDToValue(PointerType::get(Ty, CallAddrSpace), CalleeID, Callee,
&PFS, /*IsCall=*/true))
return true;
// Set up the Attribute for the function.

View File

@ -202,8 +202,9 @@ namespace llvm {
/// GetGlobalVal - Get a value with the specified name or ID, creating a
/// forward reference record if needed. This can return null if the value
/// exists but does not have the right type.
GlobalValue *GetGlobalVal(const std::string &Name, Type *Ty, LocTy Loc);
GlobalValue *GetGlobalVal(unsigned ID, Type *Ty, LocTy Loc);
GlobalValue *GetGlobalVal(const std::string &N, Type *Ty, LocTy Loc,
bool IsCall);
GlobalValue *GetGlobalVal(unsigned ID, Type *Ty, LocTy Loc, bool IsCall);
/// Get a Comdat with the specified name, creating a forward reference
/// record if needed.
@ -267,7 +268,11 @@ namespace llvm {
bool ParseTLSModel(GlobalVariable::ThreadLocalMode &TLM);
bool ParseOptionalThreadLocal(GlobalVariable::ThreadLocalMode &TLM);
bool ParseOptionalUnnamedAddr(GlobalVariable::UnnamedAddr &UnnamedAddr);
bool ParseOptionalAddrSpace(unsigned &AddrSpace);
bool ParseOptionalAddrSpace(unsigned &AddrSpace, unsigned DefaultAS = 0);
bool ParseOptionalProgramAddrSpace(unsigned &AddrSpace) {
return ParseOptionalAddrSpace(
AddrSpace, M->getDataLayout().getProgramAddressSpace());
};
bool ParseOptionalParamAttrs(AttrBuilder &B);
bool ParseOptionalReturnAttrs(AttrBuilder &B);
bool ParseOptionalLinkage(unsigned &Res, bool &HasLinkage,
@ -448,6 +453,9 @@ namespace llvm {
bool ConvertValIDToValue(Type *Ty, ValID &ID, Value *&V,
PerFunctionState *PFS, bool IsCall);
Value *checkValidVariableType(LocTy Loc, const Twine &Name, Type *Ty,
Value *Val, bool IsCall);
bool parseConstantValue(Type *Ty, Constant *&C);
bool ParseValue(Type *Ty, Value *&V, PerFunctionState *PFS);
bool ParseValue(Type *Ty, Value *&V, PerFunctionState &PFS) {

View File

@ -2938,7 +2938,7 @@ Error BitcodeReader::parseGlobalVarRecord(ArrayRef<uint64_t> Record) {
Error BitcodeReader::parseFunctionRecord(ArrayRef<uint64_t> Record) {
// v1: [type, callingconv, isproto, linkage, paramattr, alignment, section,
// visibility, gc, unnamed_addr, prologuedata, dllstorageclass, comdat,
// prefixdata, personalityfn, preemption specifier] (name in VST)
// prefixdata, personalityfn, preemption specifier, addrspace] (name in VST)
// v2: [strtab_offset, strtab_size, v1]
StringRef Name;
std::tie(Name, Record) = readNameFromStrtab(Record);
@ -2957,8 +2957,12 @@ Error BitcodeReader::parseFunctionRecord(ArrayRef<uint64_t> Record) {
if (CC & ~CallingConv::MaxID)
return error("Invalid calling convention ID");
Function *Func =
Function::Create(FTy, GlobalValue::ExternalLinkage, Name, TheModule);
unsigned AddrSpace = TheModule->getDataLayout().getProgramAddressSpace();
if (Record.size() > 16)
AddrSpace = Record[16];
Function *Func = Function::Create(FTy, GlobalValue::ExternalLinkage,
AddrSpace, Name, TheModule);
Func->setCallingConv(CC);
bool isProto = Record[2];

View File

@ -1264,7 +1264,7 @@ void ModuleBitcodeWriter::writeModuleInfo() {
// FUNCTION: [strtab offset, strtab size, type, callingconv, isproto,
// linkage, paramattrs, alignment, section, visibility, gc,
// unnamed_addr, prologuedata, dllstorageclass, comdat,
// prefixdata, personalityfn, DSO_Local]
// prefixdata, personalityfn, DSO_Local, addrspace]
Vals.push_back(addToStrtab(F.getName()));
Vals.push_back(F.getName().size());
Vals.push_back(VE.getTypeID(F.getFunctionType()));
@ -1287,6 +1287,8 @@ void ModuleBitcodeWriter::writeModuleInfo() {
F.hasPersonalityFn() ? (VE.getValueID(F.getPersonalityFn()) + 1) : 0);
Vals.push_back(F.isDSOLocal());
Vals.push_back(F.getAddressSpace());
unsigned AbbrevToUse = 0;
Stream.EmitRecord(bitc::MODULE_CODE_FUNCTION, Vals, AbbrevToUse);
Vals.clear();

View File

@ -3350,6 +3350,13 @@ void AssemblyWriter::printFunction(const Function *F) {
StringRef UA = getUnnamedAddrEncoding(F->getUnnamedAddr());
if (!UA.empty())
Out << ' ' << UA;
// We print the function address space if it is non-zero or if we are writing
// a module with a non-zero program address space or if there is no valid
// Module* so that the file can be parsed without the datalayout string.
const Module *Mod = F->getParent();
if (F->getAddressSpace() != 0 || !Mod ||
Mod->getDataLayout().getProgramAddressSpace() != 0)
Out << " addrspace(" << F->getAddressSpace() << ")";
if (Attrs.hasAttributes(AttributeList::FunctionIndex))
Out << " #" << Machine.getAttributeGroupSlot(Attrs.getFnAttributes());
if (F->hasSection()) {
@ -3487,6 +3494,23 @@ void AssemblyWriter::printInfoComment(const Value &V) {
AnnotationWriter->printInfoComment(V, Out);
}
static void maybePrintCallAddrSpace(const Value *Operand, const Instruction *I,
raw_ostream &Out) {
// We print the address space of the call if it is non-zero.
unsigned CallAddrSpace = Operand->getType()->getPointerAddressSpace();
bool PrintAddrSpace = CallAddrSpace != 0;
if (!PrintAddrSpace) {
const Module *Mod = getModuleFromVal(I);
// We also print it if it is zero but not equal to the program address space
// or if we can't find a valid Module* to make it possible to parse
// the resulting file even without a datalayout string.
if (!Mod || Mod->getDataLayout().getProgramAddressSpace() != 0)
PrintAddrSpace = true;
}
if (PrintAddrSpace)
Out << " addrspace(" << CallAddrSpace << ")";
}
// This member is called for each Instruction in a function..
void AssemblyWriter::printInstruction(const Instruction &I) {
if (AnnotationWriter) AnnotationWriter->emitInstructionAnnot(&I, Out);
@ -3684,6 +3708,9 @@ void AssemblyWriter::printInstruction(const Instruction &I) {
if (PAL.hasAttributes(AttributeList::ReturnIndex))
Out << ' ' << PAL.getAsString(AttributeList::ReturnIndex);
// Only print addrspace(N) if necessary:
maybePrintCallAddrSpace(Operand, &I, Out);
// If possible, print out the short form of the call instruction. We can
// only do this if the first argument is a pointer to a nonvararg function,
// and if the return type is not a pointer to a function.
@ -3726,6 +3753,9 @@ void AssemblyWriter::printInstruction(const Instruction &I) {
if (PAL.hasAttributes(AttributeList::ReturnIndex))
Out << ' ' << PAL.getAsString(AttributeList::ReturnIndex);
// Only print addrspace(N) if necessary:
maybePrintCallAddrSpace(Operand, &I, Out);
// If possible, print out the short form of the invoke instruction. We can
// only do this if the first argument is a pointer to a nonvararg function,
// and if the return type is not a pointer to a function.

View File

@ -464,7 +464,7 @@ static bool UpgradeIntrinsicFunction1(Function *F, Function *&NewFn) {
// the end of the name. Change name from llvm.arm.neon.vclz.* to
// llvm.ctlz.*
FunctionType* fType = FunctionType::get(F->getReturnType(), args, false);
NewFn = Function::Create(fType, F->getLinkage(),
NewFn = Function::Create(fType, F->getLinkage(), F->getAddressSpace(),
"llvm.ctlz." + Name.substr(14), F->getParent());
return true;
}
@ -480,7 +480,7 @@ static bool UpgradeIntrinsicFunction1(Function *F, Function *&NewFn) {
// Can't use Intrinsic::getDeclaration here as the return types might
// then only be structurally equal.
FunctionType* fType = FunctionType::get(F->getReturnType(), Tys, false);
NewFn = Function::Create(fType, F->getLinkage(),
NewFn = Function::Create(fType, F->getLinkage(), F->getAddressSpace(),
"llvm." + Name + ".p0i8", F->getParent());
return true;
}

View File

@ -203,6 +203,11 @@ unsigned Function::getInstructionCount() {
return NumInstrs;
}
Function *Function::Create(FunctionType *Ty, LinkageTypes Linkage,
const Twine &N, Module &M) {
return Create(Ty, Linkage, M.getDataLayout().getProgramAddressSpace(), N, &M);
}
void Function::removeFromParent() {
getParent()->getFunctionList().remove(getIterator());
}
@ -215,10 +220,19 @@ void Function::eraseFromParent() {
// Function Implementation
//===----------------------------------------------------------------------===//
Function::Function(FunctionType *Ty, LinkageTypes Linkage, const Twine &name,
Module *ParentModule)
static unsigned computeAddrSpace(unsigned AddrSpace, Module *M) {
// If AS == -1 and we are passed a valid module pointer we place the function
// in the program address space. Otherwise we default to AS0.
if (AddrSpace == static_cast<unsigned>(-1))
return M ? M->getDataLayout().getProgramAddressSpace() : 0;
return AddrSpace;
}
Function::Function(FunctionType *Ty, LinkageTypes Linkage, unsigned AddrSpace,
const Twine &name, Module *ParentModule)
: GlobalObject(Ty, Value::FunctionVal,
OperandTraits<Function>::op_begin(this), 0, Linkage, name),
OperandTraits<Function>::op_begin(this), 0, Linkage, name,
computeAddrSpace(AddrSpace, ParentModule)),
NumArgs(Ty->getNumParams()) {
assert(FunctionType::isValidReturnType(getReturnType()) &&
"invalid return type");

View File

@ -108,6 +108,11 @@ unsigned GlobalValue::getAlignment() const {
return cast<GlobalObject>(this)->getAlignment();
}
unsigned GlobalValue::getAddressSpace() const {
PointerType *PtrTy = getType();
return PtrTy->getAddressSpace();
}
void GlobalObject::setAlignment(unsigned Align) {
assert((Align & (Align-1)) == 0 && "Alignment is not a power of 2!");
assert(Align <= MaximumAlignment &&

View File

@ -145,7 +145,8 @@ Constant *Module::getOrInsertFunction(StringRef Name, FunctionType *Ty,
GlobalValue *F = getNamedValue(Name);
if (!F) {
// Nope, add it
Function *New = Function::Create(Ty, GlobalVariable::ExternalLinkage, Name);
Function *New = Function::Create(Ty, GlobalVariable::ExternalLinkage,
DL.getProgramAddressSpace(), Name);
if (!New->isIntrinsic()) // Intrinsics get attrs set on construction
New->setAttributes(AttributeList);
FunctionList.push_back(New);
@ -154,8 +155,9 @@ Constant *Module::getOrInsertFunction(StringRef Name, FunctionType *Ty,
// If the function exists but has the wrong type, return a bitcast to the
// right type.
if (F->getType() != PointerType::getUnqual(Ty))
return ConstantExpr::getBitCast(F, PointerType::getUnqual(Ty));
auto *PTy = PointerType::get(Ty, F->getAddressSpace());
if (F->getType() != PTy)
return ConstantExpr::getBitCast(F, PTy);
// Otherwise, we just found the existing function or a prototype.
return F;

View File

@ -645,8 +645,8 @@ DataFlowSanitizer::buildWrapperFunction(Function *F, StringRef NewFName,
GlobalValue::LinkageTypes NewFLink,
FunctionType *NewFT) {
FunctionType *FT = F->getFunctionType();
Function *NewF = Function::Create(NewFT, NewFLink, NewFName,
F->getParent());
Function *NewF = Function::Create(NewFT, NewFLink, F->getAddressSpace(),
NewFName, F->getParent());
NewF->copyAttributesFrom(F);
NewF->removeAttributes(
AttributeList::ReturnIndex,
@ -819,7 +819,8 @@ bool DataFlowSanitizer::runOnModule(Module &M) {
// easily identify cases of mismatching ABIs.
if (getInstrumentedABI() == IA_Args && !IsZeroArgsVoidRet) {
FunctionType *NewFT = getArgsFunctionType(FT);
Function *NewF = Function::Create(NewFT, F.getLinkage(), "", &M);
Function *NewF = Function::Create(NewFT, F.getLinkage(),
F.getAddressSpace(), "", &M);
NewF->copyAttributesFrom(&F);
NewF->removeAttributes(
AttributeList::ReturnIndex,

View File

@ -235,8 +235,8 @@ Function *llvm::CloneFunction(Function *F, ValueToValueMapTy &VMap,
ArgTypes, F->getFunctionType()->isVarArg());
// Create the new function...
Function *NewF =
Function::Create(FTy, F->getLinkage(), F->getName(), F->getParent());
Function *NewF = Function::Create(FTy, F->getLinkage(), F->getAddressSpace(),
F->getName(), F->getParent());
// Loop over the arguments, copying the names of the mapped arguments over...
Function::arg_iterator DestI = NewF->arg_begin();

View File

@ -74,8 +74,9 @@ std::unique_ptr<Module> llvm::CloneModule(
// Loop over the functions in the module, making external functions as before
for (const Function &I : M) {
Function *NF = Function::Create(cast<FunctionType>(I.getValueType()),
I.getLinkage(), I.getName(), New.get());
Function *NF =
Function::Create(cast<FunctionType>(I.getValueType()), I.getLinkage(),
I.getAddressSpace(), I.getName(), New.get());
NF->copyAttributesFrom(&I);
VMap[&I] = NF;
}
@ -91,8 +92,8 @@ std::unique_ptr<Module> llvm::CloneModule(
GlobalValue *GV;
if (I->getValueType()->isFunctionTy())
GV = Function::Create(cast<FunctionType>(I->getValueType()),
GlobalValue::ExternalLinkage, I->getName(),
New.get());
GlobalValue::ExternalLinkage,
I->getAddressSpace(), I->getName(), New.get());
else
GV = new GlobalVariable(
*New, I->getValueType(), false, GlobalValue::ExternalLinkage,

View File

@ -670,10 +670,9 @@ Function *CodeExtractor::constructFunction(const ValueSet &inputs,
AllowVarArgs && oldFunction->isVarArg());
// Create the new function
Function *newFunction = Function::Create(funcType,
GlobalValue::InternalLinkage,
oldFunction->getName() + "_" +
header->getName(), M);
Function *newFunction = Function::Create(
funcType, GlobalValue::InternalLinkage, oldFunction->getAddressSpace(),
oldFunction->getName() + "_" + header->getName(), M);
// If the old function is no-throw, so is the new one.
if (oldFunction->doesNotThrow())
newFunction->setDoesNotThrow();

View File

@ -1,11 +1,22 @@
; RUN: llvm-as %s -data-layout=P200 -o /dev/null
; RUN: not llvm-as %s -o /dev/null 2>&1 | FileCheck %s
; RUN: llvm-as %s -data-layout=P42 -o - | llvm-dis - -o - | FileCheck %s -check-prefix PROGAS42
; Check that numbered variables in a nonzero program address space 200 can be used in a call instruction
define i8 @test_unnamed(i8(i32)*, i8(i32) addrspace(200)*) {
%first = call i8 %0(i32 0) ; this is fine
%second = call i8 %1(i32 0) ; this is also fine if it's the program AS
; CHECK: call-nonzero-program-addrspace-2.ll:[[@LINE-1]]:21: error: '%1' defined with type 'i8 (i32) addrspace(200)*'
define i8 @test_unnamed(i8(i32)*, i8(i32) addrspace(42)*) {
; Calls with explicit address spaces are fine:
call addrspace(0) i8 %0(i32 0)
call addrspace(42) i8 %1(i32 0)
; this call is fine if the program address space is 42
call i8 %1(i32 0)
; CHECK: call-nonzero-program-addrspace-2.ll:[[@LINE-1]]:11: error: '%1' defined with type 'i8 (i32) addrspace(42)*' but expected 'i8 (i32)*'
ret i8 0
}
; PROGAS42: target datalayout = "P42"
; PROGAS42: define i8 @test_unnamed(i8 (i32)*, i8 (i32) addrspace(42)*) addrspace(42) {
; PROGAS42-NEXT: %3 = call addrspace(0) i8 %0(i32 0)
; PROGAS42-NEXT: %4 = call addrspace(42) i8 %1(i32 0)
; PROGAS42-NEXT: %5 = call addrspace(42) i8 %1(i32 0)
; PROGAS42-NEXT: ret i8 0
; PROGAS42-NEXT: }

View File

@ -1,13 +1,23 @@
; RUN: llvm-as %s -data-layout=P200 -o /dev/null
; RUN: not llvm-as %s -o /dev/null 2>&1 | FileCheck %s
; RUN: llvm-as %s -data-layout=P42 -o - | llvm-dis - -o - | FileCheck %s -check-prefix PROGAS42
; Check that variables in a nonzero program address space 200 can be used in a call instruction
; Check that variables in a nonzero program address space 42 can be used in a call instruction
define i8 @test(i8(i32)* %fnptr0, i8(i32) addrspace(200)* %fnptr200) {
%first = call i8 %fnptr0(i32 0) ; this is fine
%second = call i8 %fnptr200(i32 0) ; this is also fine if it's the program AS
; CHECK: call-nonzero-program-addrspace.ll:[[@LINE-1]]:21: error: '%fnptr200' defined with type 'i8 (i32) addrspace(200)*'
define i8 @test(i8(i32)* %fnptr0, i8(i32) addrspace(42)* %fnptr42) {
%explicit_as_0 = call addrspace(0) i8 %fnptr0(i32 0)
%explicit_as_42 = call addrspace(42) i8 %fnptr42(i32 0)
; Calling %fnptr42 without an explicit addrspace() in the call instruction is only okay if the program AS is 42
%call_no_as = call i8 %fnptr42(i32 0)
; CHECK: call-nonzero-program-addrspace.ll:[[@LINE-1]]:25: error: '%fnptr42' defined with type 'i8 (i32) addrspace(42)*' but expected 'i8 (i32)*'
ret i8 0
}
declare i32 @__gxx_personality_v0(...)
; PROGAS42: target datalayout = "P42"
; PROGAS42: define i8 @test(i8 (i32)* %fnptr0, i8 (i32) addrspace(42)* %fnptr42) addrspace(42) {
; Print addrspace(0) since the program address space is non-zero:
; PROGAS42-NEXT: %explicit_as_0 = call addrspace(0) i8 %fnptr0(i32 0)
; Also print addrspace(42) since we always print non-zero addrspace:
; PROGAS42-NEXT: %explicit_as_42 = call addrspace(42) i8 %fnptr42(i32 0)
; PROGAS42-NEXT: %call_no_as = call addrspace(42) i8 %fnptr42(i32 0)
; PROGAS42-NEXT: ret i8 0
; PROGAS42-NEXT: }

View File

@ -1,12 +1,15 @@
; RUN: llvm-as %s -data-layout=P200 -o /dev/null
; RUN: not llvm-as %s -o /dev/null 2>&1 | FileCheck %s
; RUN: llvm-as %s -data-layout=P200 -o - | llvm-dis - -o - | FileCheck %s -check-prefix PROGAS200
; Check that variables in a nonzero program address space 200 can be used in a invoke instruction
define i8 @test_invoke(i8(i32)* %fnptr0, i8(i32) addrspace(200)* %fnptr200) personality i32 (...)* @__gxx_personality_v0 {
%first = invoke i8 %fnptr0(i32 0) to label %ok unwind label %lpad ; this is fine
%second = invoke i8 %fnptr200(i32 0) to label %ok unwind label %lpad ; this is also fine if it's the program AS
; CHECK: invoke-nonzero-program-addrspace.ll:[[@LINE-1]]:23: error: '%fnptr200' defined with type 'i8 (i32) addrspace(200)*'
define i8 @test_invoke(i8(i32)* %fnptr0, i8(i32) addrspace(200)* %fnptr200) personality i32 (...) addrspace(200)* @__gxx_personality_v0 {
%explicit_as_0 = invoke addrspace(0) i8 %fnptr0(i32 0) to label %ok unwind label %lpad
%explicit_as_42 = invoke addrspace(200) i8 %fnptr200(i32 0) to label %ok unwind label %lpad
; The following is only okay if the program address space is 200:
%no_as = invoke i8 %fnptr200(i32 0) to label %ok unwind label %lpad
; CHECK: invoke-nonzero-program-addrspace.ll:[[@LINE-1]]:22: error: '%fnptr200' defined with type 'i8 (i32) addrspace(200)*' but expected 'i8 (i32)*'
ok:
ret i8 0
lpad:
@ -16,3 +19,12 @@ lpad:
}
declare i32 @__gxx_personality_v0(...)
; PROGAS200: target datalayout = "P200"
; PROGAS200: define i8 @test_invoke(i8 (i32)* %fnptr0, i8 (i32) addrspace(200)* %fnptr200) addrspace(200) personality i32 (...) addrspace(200)* @__gxx_personality_v0 {
; PROGAS200: %explicit_as_0 = invoke addrspace(0) i8 %fnptr0(i32 0)
; PROGAS200: %explicit_as_42 = invoke addrspace(200) i8 %fnptr200(i32 0)
; PROGAS200: %no_as = invoke addrspace(200) i8 %fnptr200(i32 0)
; PROGAS200: ret i8 0
; PROGAS200: }

View File

@ -0,0 +1,39 @@
; Verify that forward declarations from call instructions work even with non-zero AS
; RUN: llvm-as %s -o - | llvm-dis - | FileCheck %s
define void @call_named() {
entry:
%0 = tail call addrspace(40) i32 @named(i16* null)
; CHECK: %0 = tail call addrspace(40) i32 @named(i16* null)
ret void
}
define void @call_numbered() {
entry:
%0 = tail call addrspace(40) i32 @0(i16* null)
; CHECK: %0 = tail call addrspace(40) i32 @0(i16* null)
ret void
}
define i32 @invoked() personality i8* null {
entry:
%0 = invoke addrspace(40) i32 @foo() to label %l1 unwind label %lpad
; CHECK: invoke addrspace(40) i32 @foo()
l1:
br label %return
lpad:
%1 = landingpad { i8*, i32 }
catch i8* null
catch i8* null
ret i32 0
return:
ret i32 0
}
declare i32 @foo() addrspace(40)
; CHECK: declare i32 @foo() addrspace(40)
declare i32 @named(i16* nocapture) addrspace(40)
; CHECK: declare i32 @named(i16* nocapture) addrspace(40)
declare i32 @0(i16*) addrspace(40)
; CHECK: declare i32 @0(i16*) addrspace(40)

View File

@ -0,0 +1,35 @@
; RUN: llvm-as %s -o - | llvm-dis - | FileCheck %s -check-prefixes CHECK,PROG-AS0
; RUN: llvm-as -data-layout "P200" %s -o - | llvm-dis | FileCheck %s -check-prefixes CHECK,PROG-AS200
; RUN: not llvm-as -data-layout "P123456789" %s -o /dev/null 2>&1 | FileCheck %s -check-prefix BAD-DATALAYOUT
; BAD-DATALAYOUT: LLVM ERROR: Invalid address space, must be a 24-bit integer
; PROG-AS0-NOT: target datalayout
; PROG-AS200: target datalayout = "P200"
; Check that a function declaration without an address space (i.e. AS0) does not
; have the addrspace() attribute printed if it is address space zero and it is
; equal to the program address space.
; PROG-AS0: define void @no_as() {
; PROG-AS200: define void @no_as() addrspace(200) {
define void @no_as() {
ret void
}
; A function with an explicit addrspace should only have the addrspace printed
; if it is non-zero or if the module has a nonzero datalayout
; PROG-AS0: define void @explit_as0() {
; PROG-AS200: define void @explit_as0() addrspace(0) {
define void @explit_as0() addrspace(0) {
ret void
}
; CHECK: define void @explit_as200() addrspace(200) {
define void @explit_as200() addrspace(200) {
ret void
}
; CHECK: define void @explicit_as3() addrspace(3) {
define void @explicit_as3() addrspace(3) {
ret void
}

View File

@ -0,0 +1,23 @@
; Verify that we accept calls to variables in the program AS:
; RUN: llvm-as -data-layout "P40" %s -o - | llvm-dis - | FileCheck %s
; CHECK: target datalayout = "P40"
; We should get a sensible error for a non-program address call:
; RUN: not llvm-as -data-layout "P39" %s -o /dev/null 2>&1 | FileCheck %s -check-prefix ERR-AS39
; ERR-AS39: error: '%0' defined with type 'i16 (i16) addrspace(40)*' but expected 'i16 (i16) addrspace(39)*'
; And also if we don't set a custom program address space:
; RUN: not llvm-as %s -o /dev/null 2>&1 | FileCheck %s -check-prefix ERR-AS0
; ERR-AS0: error: '%0' defined with type 'i16 (i16) addrspace(40)*' but expected 'i16 (i16)*'
%fun1 = type i16 (i16)
%funptr1 = type %fun1 addrspace(40)*
@fun_ptr = global %funptr1 @fun
define i16 @fun(i16 %arg) addrspace(40) {
entry:
%0 = load %funptr1, %funptr1* @fun_ptr
%result = call i16 %0(i16 %arg)
ret i16 %result
}

View File

@ -0,0 +1,29 @@
; Verify that we accept calls to variables in the program AS:
; RUN: llvm-as -data-layout "P40" %s -o - | llvm-dis - | FileCheck %s
; CHECK: target datalayout = "P40"
; We should get a sensible error for a non-program address call:
; RUN: not llvm-as -data-layout "P39" %s -o /dev/null 2>&1 | FileCheck %s -check-prefix ERR-AS39
; ERR-AS39: error: '%fnptr' defined with type 'void (i16) addrspace(40)*' but expected 'void (i16) addrspace(39)*'
; And also if we don't set a custom program address space:
; RUN: not llvm-as %s -o /dev/null 2>&1 | FileCheck %s -check-prefix ERR-AS0
; ERR-AS0: error: '%fnptr' defined with type 'void (i16) addrspace(40)*' but expected 'void (i16)*'
define void @f_named(i16 %n, void (i16) addrspace(40)* %f) addrspace(40) {
entry:
%f.addr = alloca void (i16) addrspace(40)*, align 1
store void (i16) addrspace(40)* %f, void (i16) addrspace(40)** %f.addr
%fnptr = load void (i16) addrspace(40)*, void (i16) addrspace(40)** %f.addr
call void %fnptr(i16 8)
ret void
}
define void @f_numbered(i16 %n, void (i16) addrspace(40)* %f) addrspace(40){
entry:
%f.addr = alloca void (i16) addrspace(40)*, align 1
store void (i16) addrspace(40)* %f, void (i16) addrspace(40)** %f.addr
%0 = load void (i16) addrspace(40)*, void (i16) addrspace(40)** %f.addr
call void %0(i16 8)
ret void
}