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

View File

@ -120,7 +120,7 @@ private:
/// function is automatically inserted into the end of the function list for /// function is automatically inserted into the end of the function list for
/// the module. /// the module.
/// ///
Function(FunctionType *Ty, LinkageTypes Linkage, Function(FunctionType *Ty, LinkageTypes Linkage, unsigned AddrSpace,
const Twine &N = "", Module *M = nullptr); const Twine &N = "", Module *M = nullptr);
public: public:
@ -134,10 +134,24 @@ public:
const Function &getFunction() const { return *this; } const Function &getFunction() const { return *this; }
static Function *Create(FunctionType *Ty, LinkageTypes Linkage, static Function *Create(FunctionType *Ty, LinkageTypes Linkage,
const Twine &N = "", Module *M = nullptr) { unsigned AddrSpace, const Twine &N = "",
return new Function(Ty, Linkage, N, M); 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. // Provide fast operand accessors.
DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value);

View File

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

View File

@ -1317,7 +1317,8 @@ bool LLParser::ParseFnAttributeValuePairs(AttrBuilder &B,
static inline GlobalValue *createGlobalFwdRef(Module *M, PointerType *PTy, static inline GlobalValue *createGlobalFwdRef(Module *M, PointerType *PTy,
const std::string &Name) { const std::string &Name) {
if (auto *FT = dyn_cast<FunctionType>(PTy->getElementType())) 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 else
return new GlobalVariable(*M, PTy->getElementType(), false, return new GlobalVariable(*M, PTy->getElementType(), false,
GlobalValue::ExternalWeakLinkage, nullptr, Name, GlobalValue::ExternalWeakLinkage, nullptr, Name,
@ -1325,11 +1326,33 @@ static inline GlobalValue *createGlobalFwdRef(Module *M, PointerType *PTy,
PTy->getAddressSpace()); 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 /// GetGlobalVal - Get a value with the specified name or ID, creating a
/// forward reference record if needed. This can return null if the value /// forward reference record if needed. This can return null if the value
/// exists but does not have the right type. /// exists but does not have the right type.
GlobalValue *LLParser::GetGlobalVal(const std::string &Name, Type *Ty, GlobalValue *LLParser::GetGlobalVal(const std::string &Name, Type *Ty,
LocTy Loc) { LocTy Loc, bool IsCall) {
PointerType *PTy = dyn_cast<PointerType>(Ty); PointerType *PTy = dyn_cast<PointerType>(Ty);
if (!PTy) { if (!PTy) {
Error(Loc, "global variable reference must have pointer type"); 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 we have the value in the symbol table or fwd-ref table, return it.
if (Val) { if (Val)
if (Val->getType() == Ty) return Val; return cast_or_null<GlobalValue>(
Error(Loc, "'@" + Name + "' defined with type '" + checkValidVariableType(Loc, "@" + Name, Ty, Val, IsCall));
getTypeString(Val->getType()) + "'");
return nullptr;
}
// Otherwise, create a new forward reference for this value and remember it. // Otherwise, create a new forward reference for this value and remember it.
GlobalValue *FwdVal = createGlobalFwdRef(M, PTy, Name); GlobalValue *FwdVal = createGlobalFwdRef(M, PTy, Name);
@ -1362,7 +1382,8 @@ GlobalValue *LLParser::GetGlobalVal(const std::string &Name, Type *Ty,
return FwdVal; 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); PointerType *PTy = dyn_cast<PointerType>(Ty);
if (!PTy) { if (!PTy) {
Error(Loc, "global variable reference must have pointer type"); 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 we have the value in the symbol table or fwd-ref table, return it.
if (Val) { if (Val)
if (Val->getType() == Ty) return Val; return cast_or_null<GlobalValue>(
Error(Loc, "'@" + Twine(ID) + "' defined with type '" + checkValidVariableType(Loc, "@" + Twine(ID), Ty, Val, IsCall));
getTypeString(Val->getType()) + "'");
return nullptr;
}
// Otherwise, create a new forward reference for this value and remember it. // Otherwise, create a new forward reference for this value and remember it.
GlobalValue *FwdVal = createGlobalFwdRef(M, PTy, ""); GlobalValue *FwdVal = createGlobalFwdRef(M, PTy, "");
@ -1500,8 +1518,8 @@ bool LLParser::ParseOptionalThreadLocal(GlobalVariable::ThreadLocalMode &TLM) {
/// ParseOptionalAddrSpace /// ParseOptionalAddrSpace
/// := /*empty*/ /// := /*empty*/
/// := 'addrspace' '(' uint32 ')' /// := 'addrspace' '(' uint32 ')'
bool LLParser::ParseOptionalAddrSpace(unsigned &AddrSpace) { bool LLParser::ParseOptionalAddrSpace(unsigned &AddrSpace, unsigned DefaultAS) {
AddrSpace = 0; AddrSpace = DefaultAS;
if (!EatIfPresent(lltok::kw_addrspace)) if (!EatIfPresent(lltok::kw_addrspace))
return false; return false;
return ParseToken(lltok::lparen, "expected '(' in address space") || return ParseToken(lltok::lparen, "expected '(' in address space") ||
@ -2741,19 +2759,6 @@ bool LLParser::PerFunctionState::FinishFunction() {
return false; 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 /// GetVal - Get a value with the specified name or ID, creating a
/// forward reference record if needed. This can return null if the value /// forward reference record if needed. This can return null if the value
/// exists but does not have the right type. /// 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 we have the value in the symbol table or fwd-ref table, return it.
if (Val) { if (Val)
if (isValidVariableType(P.M, Ty, Val, IsCall)) return P.checkValidVariableType(Loc, "%" + Name, 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;
}
// Don't make placeholders with invalid type. // Don't make placeholders with invalid type.
if (!Ty->isFirstClassType()) { 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 we have the value in the symbol table or fwd-ref table, return it.
if (Val) { if (Val)
if (isValidVariableType(P.M, Ty, Val, IsCall)) return P.checkValidVariableType(Loc, "%" + Twine(ID), 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 (!Ty->isFirstClassType()) { if (!Ty->isFirstClassType()) {
P.Error(Loc, "invalid use of a non-first-class type"); 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; return false;
} }
case ValID::t_GlobalName: case ValID::t_GlobalName:
V = GetGlobalVal(ID.StrVal, Ty, ID.Loc); V = GetGlobalVal(ID.StrVal, Ty, ID.Loc, IsCall);
return V == nullptr; return V == nullptr;
case ValID::t_GlobalID: case ValID::t_GlobalID:
V = GetGlobalVal(ID.UIntVal, Ty, ID.Loc); V = GetGlobalVal(ID.UIntVal, Ty, ID.Loc, IsCall);
return V == nullptr; return V == nullptr;
case ValID::t_APSInt: case ValID::t_APSInt:
if (!Ty->isIntegerTy()) if (!Ty->isIntegerTy())
@ -5086,8 +5075,8 @@ bool LLParser::ParseTypeAndBasicBlock(BasicBlock *&BB, LocTy &Loc,
/// FunctionHeader /// FunctionHeader
/// ::= OptionalLinkage OptionalPreemptionSpecifier OptionalVisibility /// ::= OptionalLinkage OptionalPreemptionSpecifier OptionalVisibility
/// OptionalCallingConv OptRetAttrs OptUnnamedAddr Type GlobalName /// OptionalCallingConv OptRetAttrs OptUnnamedAddr Type GlobalName
/// '(' ArgList ')' OptFuncAttrs OptSection OptionalAlign OptGC /// '(' ArgList ')' OptAddrSpace OptFuncAttrs OptSection OptionalAlign
/// OptionalPrefix OptionalPrologue OptPersonalityFn /// OptGC OptionalPrefix OptionalPrologue OptPersonalityFn
bool LLParser::ParseFunctionHeader(Function *&Fn, bool isDefine) { bool LLParser::ParseFunctionHeader(Function *&Fn, bool isDefine) {
// Parse the linkage. // Parse the linkage.
LocTy LinkageLoc = Lex.getLoc(); LocTy LinkageLoc = Lex.getLoc();
@ -5165,6 +5154,7 @@ bool LLParser::ParseFunctionHeader(Function *&Fn, bool isDefine) {
unsigned Alignment; unsigned Alignment;
std::string GC; std::string GC;
GlobalValue::UnnamedAddr UnnamedAddr = GlobalValue::UnnamedAddr::None; GlobalValue::UnnamedAddr UnnamedAddr = GlobalValue::UnnamedAddr::None;
unsigned AddrSpace = 0;
Constant *Prefix = nullptr; Constant *Prefix = nullptr;
Constant *Prologue = nullptr; Constant *Prologue = nullptr;
Constant *PersonalityFn = nullptr; Constant *PersonalityFn = nullptr;
@ -5172,6 +5162,7 @@ bool LLParser::ParseFunctionHeader(Function *&Fn, bool isDefine) {
if (ParseArgumentList(ArgList, isVarArg) || if (ParseArgumentList(ArgList, isVarArg) ||
ParseOptionalUnnamedAddr(UnnamedAddr) || ParseOptionalUnnamedAddr(UnnamedAddr) ||
ParseOptionalProgramAddrSpace(AddrSpace) ||
ParseFnAttributeValuePairs(FuncAttrs, FwdRefAttrGrps, false, ParseFnAttributeValuePairs(FuncAttrs, FwdRefAttrGrps, false,
BuiltinLoc) || BuiltinLoc) ||
(EatIfPresent(lltok::kw_section) && (EatIfPresent(lltok::kw_section) &&
@ -5216,7 +5207,7 @@ bool LLParser::ParseFunctionHeader(Function *&Fn, bool isDefine) {
FunctionType *FT = FunctionType *FT =
FunctionType::get(RetType, ParamTypeList, isVarArg); FunctionType::get(RetType, ParamTypeList, isVarArg);
PointerType *PFT = PointerType::getUnqual(FT); PointerType *PFT = PointerType::get(FT, AddrSpace);
Fn = nullptr; Fn = nullptr;
if (!FunctionName.empty()) { if (!FunctionName.empty()) {
@ -5230,8 +5221,9 @@ bool LLParser::ParseFunctionHeader(Function *&Fn, bool isDefine) {
"function as global value!"); "function as global value!");
if (Fn->getType() != PFT) if (Fn->getType() != PFT)
return Error(FRVI->second.second, "invalid forward reference to " 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); ForwardRefVals.erase(FRVI);
} else if ((Fn = M->getFunction(FunctionName))) { } else if ((Fn = M->getFunction(FunctionName))) {
// Reject redefinitions. // Reject redefinitions.
@ -5249,16 +5241,21 @@ bool LLParser::ParseFunctionHeader(Function *&Fn, bool isDefine) {
Fn = cast<Function>(I->second.first); Fn = cast<Function>(I->second.first);
if (Fn->getType() != PFT) if (Fn->getType() != PFT)
return Error(NameLoc, "type of definition and forward reference of '@" + 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); ForwardRefValIDs.erase(I);
} }
} }
if (!Fn) 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. else // Move the forward-reference to the correct spot in the module.
M->getFunctionList().splice(M->end(), M->getFunctionList(), Fn); M->getFunctionList().splice(M->end(), M->getFunctionList(), Fn);
assert(Fn->getAddressSpace() == AddrSpace && "Created function in wrong AS");
if (FunctionName.empty()) if (FunctionName.empty())
NumberedVals.push_back(Fn); NumberedVals.push_back(Fn);
@ -5777,6 +5774,7 @@ bool LLParser::ParseInvoke(Instruction *&Inst, PerFunctionState &PFS) {
std::vector<unsigned> FwdRefAttrGrps; std::vector<unsigned> FwdRefAttrGrps;
LocTy NoBuiltinLoc; LocTy NoBuiltinLoc;
unsigned CC; unsigned CC;
unsigned InvokeAddrSpace;
Type *RetType = nullptr; Type *RetType = nullptr;
LocTy RetTypeLoc; LocTy RetTypeLoc;
ValID CalleeID; ValID CalleeID;
@ -5785,6 +5783,7 @@ bool LLParser::ParseInvoke(Instruction *&Inst, PerFunctionState &PFS) {
BasicBlock *NormalBB, *UnwindBB; BasicBlock *NormalBB, *UnwindBB;
if (ParseOptionalCallingConv(CC) || ParseOptionalReturnAttrs(RetAttrs) || if (ParseOptionalCallingConv(CC) || ParseOptionalReturnAttrs(RetAttrs) ||
ParseOptionalProgramAddrSpace(InvokeAddrSpace) ||
ParseType(RetType, RetTypeLoc, true /*void allowed*/) || ParseType(RetType, RetTypeLoc, true /*void allowed*/) ||
ParseValID(CalleeID) || ParseParameterList(ArgList, PFS) || ParseValID(CalleeID) || ParseParameterList(ArgList, PFS) ||
ParseFnAttributeValuePairs(FnAttrs, FwdRefAttrGrps, false, ParseFnAttributeValuePairs(FnAttrs, FwdRefAttrGrps, false,
@ -5816,8 +5815,8 @@ bool LLParser::ParseInvoke(Instruction *&Inst, PerFunctionState &PFS) {
// Look up the callee. // Look up the callee.
Value *Callee; Value *Callee;
if (ConvertValIDToValue(PointerType::getUnqual(Ty), CalleeID, Callee, &PFS, if (ConvertValIDToValue(PointerType::get(Ty, InvokeAddrSpace), CalleeID,
/*IsCall=*/true)) Callee, &PFS, /*IsCall=*/true))
return true; return true;
// Set up the Attribute for the function. // Set up the Attribute for the function.
@ -6360,6 +6359,7 @@ bool LLParser::ParseCall(Instruction *&Inst, PerFunctionState &PFS,
AttrBuilder RetAttrs, FnAttrs; AttrBuilder RetAttrs, FnAttrs;
std::vector<unsigned> FwdRefAttrGrps; std::vector<unsigned> FwdRefAttrGrps;
LocTy BuiltinLoc; LocTy BuiltinLoc;
unsigned CallAddrSpace;
unsigned CC; unsigned CC;
Type *RetType = nullptr; Type *RetType = nullptr;
LocTy RetTypeLoc; LocTy RetTypeLoc;
@ -6376,6 +6376,7 @@ bool LLParser::ParseCall(Instruction *&Inst, PerFunctionState &PFS,
FastMathFlags FMF = EatFastMathFlagsIfPresent(); FastMathFlags FMF = EatFastMathFlagsIfPresent();
if (ParseOptionalCallingConv(CC) || ParseOptionalReturnAttrs(RetAttrs) || if (ParseOptionalCallingConv(CC) || ParseOptionalReturnAttrs(RetAttrs) ||
ParseOptionalProgramAddrSpace(CallAddrSpace) ||
ParseType(RetType, RetTypeLoc, true /*void allowed*/) || ParseType(RetType, RetTypeLoc, true /*void allowed*/) ||
ParseValID(CalleeID) || ParseValID(CalleeID) ||
ParseParameterList(ArgList, PFS, TCK == CallInst::TCK_MustTail, ParseParameterList(ArgList, PFS, TCK == CallInst::TCK_MustTail,
@ -6408,8 +6409,8 @@ bool LLParser::ParseCall(Instruction *&Inst, PerFunctionState &PFS,
// Look up the callee. // Look up the callee.
Value *Callee; Value *Callee;
if (ConvertValIDToValue(PointerType::getUnqual(Ty), CalleeID, Callee, &PFS, if (ConvertValIDToValue(PointerType::get(Ty, CallAddrSpace), CalleeID, Callee,
/*IsCall=*/true)) &PFS, /*IsCall=*/true))
return true; return true;
// Set up the Attribute for the function. // 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 /// GetGlobalVal - Get a value with the specified name or ID, creating a
/// forward reference record if needed. This can return null if the value /// forward reference record if needed. This can return null if the value
/// exists but does not have the right type. /// exists but does not have the right type.
GlobalValue *GetGlobalVal(const std::string &Name, Type *Ty, LocTy Loc); GlobalValue *GetGlobalVal(const std::string &N, Type *Ty, LocTy Loc,
GlobalValue *GetGlobalVal(unsigned ID, 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 /// Get a Comdat with the specified name, creating a forward reference
/// record if needed. /// record if needed.
@ -267,7 +268,11 @@ namespace llvm {
bool ParseTLSModel(GlobalVariable::ThreadLocalMode &TLM); bool ParseTLSModel(GlobalVariable::ThreadLocalMode &TLM);
bool ParseOptionalThreadLocal(GlobalVariable::ThreadLocalMode &TLM); bool ParseOptionalThreadLocal(GlobalVariable::ThreadLocalMode &TLM);
bool ParseOptionalUnnamedAddr(GlobalVariable::UnnamedAddr &UnnamedAddr); 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 ParseOptionalParamAttrs(AttrBuilder &B);
bool ParseOptionalReturnAttrs(AttrBuilder &B); bool ParseOptionalReturnAttrs(AttrBuilder &B);
bool ParseOptionalLinkage(unsigned &Res, bool &HasLinkage, bool ParseOptionalLinkage(unsigned &Res, bool &HasLinkage,
@ -448,6 +453,9 @@ namespace llvm {
bool ConvertValIDToValue(Type *Ty, ValID &ID, Value *&V, bool ConvertValIDToValue(Type *Ty, ValID &ID, Value *&V,
PerFunctionState *PFS, bool IsCall); PerFunctionState *PFS, bool IsCall);
Value *checkValidVariableType(LocTy Loc, const Twine &Name, Type *Ty,
Value *Val, bool IsCall);
bool parseConstantValue(Type *Ty, Constant *&C); bool parseConstantValue(Type *Ty, Constant *&C);
bool ParseValue(Type *Ty, Value *&V, PerFunctionState *PFS); bool ParseValue(Type *Ty, Value *&V, PerFunctionState *PFS);
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) { Error BitcodeReader::parseFunctionRecord(ArrayRef<uint64_t> Record) {
// v1: [type, callingconv, isproto, linkage, paramattr, alignment, section, // v1: [type, callingconv, isproto, linkage, paramattr, alignment, section,
// visibility, gc, unnamed_addr, prologuedata, dllstorageclass, comdat, // 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] // v2: [strtab_offset, strtab_size, v1]
StringRef Name; StringRef Name;
std::tie(Name, Record) = readNameFromStrtab(Record); std::tie(Name, Record) = readNameFromStrtab(Record);
@ -2957,8 +2957,12 @@ Error BitcodeReader::parseFunctionRecord(ArrayRef<uint64_t> Record) {
if (CC & ~CallingConv::MaxID) if (CC & ~CallingConv::MaxID)
return error("Invalid calling convention ID"); return error("Invalid calling convention ID");
Function *Func = unsigned AddrSpace = TheModule->getDataLayout().getProgramAddressSpace();
Function::Create(FTy, GlobalValue::ExternalLinkage, Name, TheModule); if (Record.size() > 16)
AddrSpace = Record[16];
Function *Func = Function::Create(FTy, GlobalValue::ExternalLinkage,
AddrSpace, Name, TheModule);
Func->setCallingConv(CC); Func->setCallingConv(CC);
bool isProto = Record[2]; bool isProto = Record[2];

View File

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

View File

@ -3350,6 +3350,13 @@ void AssemblyWriter::printFunction(const Function *F) {
StringRef UA = getUnnamedAddrEncoding(F->getUnnamedAddr()); StringRef UA = getUnnamedAddrEncoding(F->getUnnamedAddr());
if (!UA.empty()) if (!UA.empty())
Out << ' ' << UA; 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)) if (Attrs.hasAttributes(AttributeList::FunctionIndex))
Out << " #" << Machine.getAttributeGroupSlot(Attrs.getFnAttributes()); Out << " #" << Machine.getAttributeGroupSlot(Attrs.getFnAttributes());
if (F->hasSection()) { if (F->hasSection()) {
@ -3487,6 +3494,23 @@ void AssemblyWriter::printInfoComment(const Value &V) {
AnnotationWriter->printInfoComment(V, Out); 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.. // This member is called for each Instruction in a function..
void AssemblyWriter::printInstruction(const Instruction &I) { void AssemblyWriter::printInstruction(const Instruction &I) {
if (AnnotationWriter) AnnotationWriter->emitInstructionAnnot(&I, Out); if (AnnotationWriter) AnnotationWriter->emitInstructionAnnot(&I, Out);
@ -3684,6 +3708,9 @@ void AssemblyWriter::printInstruction(const Instruction &I) {
if (PAL.hasAttributes(AttributeList::ReturnIndex)) if (PAL.hasAttributes(AttributeList::ReturnIndex))
Out << ' ' << PAL.getAsString(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 // 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, // 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. // 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)) if (PAL.hasAttributes(AttributeList::ReturnIndex))
Out << ' ' << PAL.getAsString(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 // 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, // 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. // 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 // the end of the name. Change name from llvm.arm.neon.vclz.* to
// llvm.ctlz.* // llvm.ctlz.*
FunctionType* fType = FunctionType::get(F->getReturnType(), args, false); 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()); "llvm.ctlz." + Name.substr(14), F->getParent());
return true; return true;
} }
@ -480,7 +480,7 @@ static bool UpgradeIntrinsicFunction1(Function *F, Function *&NewFn) {
// Can't use Intrinsic::getDeclaration here as the return types might // Can't use Intrinsic::getDeclaration here as the return types might
// then only be structurally equal. // then only be structurally equal.
FunctionType* fType = FunctionType::get(F->getReturnType(), Tys, false); 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()); "llvm." + Name + ".p0i8", F->getParent());
return true; return true;
} }

View File

@ -203,6 +203,11 @@ unsigned Function::getInstructionCount() {
return NumInstrs; 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() { void Function::removeFromParent() {
getParent()->getFunctionList().remove(getIterator()); getParent()->getFunctionList().remove(getIterator());
} }
@ -215,10 +220,19 @@ void Function::eraseFromParent() {
// Function Implementation // Function Implementation
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
Function::Function(FunctionType *Ty, LinkageTypes Linkage, const Twine &name, static unsigned computeAddrSpace(unsigned AddrSpace, Module *M) {
Module *ParentModule) // 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, : 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()) { NumArgs(Ty->getNumParams()) {
assert(FunctionType::isValidReturnType(getReturnType()) && assert(FunctionType::isValidReturnType(getReturnType()) &&
"invalid return type"); "invalid return type");

View File

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

View File

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

View File

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

View File

@ -235,8 +235,8 @@ Function *llvm::CloneFunction(Function *F, ValueToValueMapTy &VMap,
ArgTypes, F->getFunctionType()->isVarArg()); ArgTypes, F->getFunctionType()->isVarArg());
// Create the new function... // Create the new function...
Function *NewF = Function *NewF = Function::Create(FTy, F->getLinkage(), F->getAddressSpace(),
Function::Create(FTy, F->getLinkage(), F->getName(), F->getParent()); F->getName(), F->getParent());
// Loop over the arguments, copying the names of the mapped arguments over... // Loop over the arguments, copying the names of the mapped arguments over...
Function::arg_iterator DestI = NewF->arg_begin(); 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 // Loop over the functions in the module, making external functions as before
for (const Function &I : M) { for (const Function &I : M) {
Function *NF = Function::Create(cast<FunctionType>(I.getValueType()), Function *NF =
I.getLinkage(), I.getName(), New.get()); Function::Create(cast<FunctionType>(I.getValueType()), I.getLinkage(),
I.getAddressSpace(), I.getName(), New.get());
NF->copyAttributesFrom(&I); NF->copyAttributesFrom(&I);
VMap[&I] = NF; VMap[&I] = NF;
} }
@ -91,8 +92,8 @@ std::unique_ptr<Module> llvm::CloneModule(
GlobalValue *GV; GlobalValue *GV;
if (I->getValueType()->isFunctionTy()) if (I->getValueType()->isFunctionTy())
GV = Function::Create(cast<FunctionType>(I->getValueType()), GV = Function::Create(cast<FunctionType>(I->getValueType()),
GlobalValue::ExternalLinkage, I->getName(), GlobalValue::ExternalLinkage,
New.get()); I->getAddressSpace(), I->getName(), New.get());
else else
GV = new GlobalVariable( GV = new GlobalVariable(
*New, I->getValueType(), false, GlobalValue::ExternalLinkage, *New, I->getValueType(), false, GlobalValue::ExternalLinkage,

View File

@ -670,10 +670,9 @@ Function *CodeExtractor::constructFunction(const ValueSet &inputs,
AllowVarArgs && oldFunction->isVarArg()); AllowVarArgs && oldFunction->isVarArg());
// Create the new function // Create the new function
Function *newFunction = Function::Create(funcType, Function *newFunction = Function::Create(
GlobalValue::InternalLinkage, funcType, GlobalValue::InternalLinkage, oldFunction->getAddressSpace(),
oldFunction->getName() + "_" + oldFunction->getName() + "_" + header->getName(), M);
header->getName(), M);
// If the old function is no-throw, so is the new one. // If the old function is no-throw, so is the new one.
if (oldFunction->doesNotThrow()) if (oldFunction->doesNotThrow())
newFunction->setDoesNotThrow(); 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: 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 ; 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)*) { define i8 @test_unnamed(i8(i32)*, i8(i32) addrspace(42)*) {
%first = call i8 %0(i32 0) ; this is fine ; Calls with explicit address spaces are fine:
%second = call i8 %1(i32 0) ; this is also fine if it's the program AS call addrspace(0) i8 %0(i32 0)
; CHECK: call-nonzero-program-addrspace-2.ll:[[@LINE-1]]:21: error: '%1' defined with type 'i8 (i32) addrspace(200)*' 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 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: 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) { define i8 @test(i8(i32)* %fnptr0, i8(i32) addrspace(42)* %fnptr42) {
%first = call i8 %fnptr0(i32 0) ; this is fine %explicit_as_0 = call addrspace(0) i8 %fnptr0(i32 0)
%second = call i8 %fnptr200(i32 0) ; this is also fine if it's the program AS %explicit_as_42 = call addrspace(42) i8 %fnptr42(i32 0)
; CHECK: call-nonzero-program-addrspace.ll:[[@LINE-1]]:21: error: '%fnptr200' defined with type 'i8 (i32) addrspace(200)*' ; 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 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: 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 ; 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 { define i8 @test_invoke(i8(i32)* %fnptr0, i8(i32) addrspace(200)* %fnptr200) personality i32 (...) addrspace(200)* @__gxx_personality_v0 {
%first = invoke i8 %fnptr0(i32 0) to label %ok unwind label %lpad ; this is fine %explicit_as_0 = invoke addrspace(0) i8 %fnptr0(i32 0) to label %ok unwind label %lpad
%second = invoke i8 %fnptr200(i32 0) to label %ok unwind label %lpad ; this is also fine if it's the program AS %explicit_as_42 = invoke addrspace(200) i8 %fnptr200(i32 0) to label %ok unwind label %lpad
; CHECK: invoke-nonzero-program-addrspace.ll:[[@LINE-1]]:23: error: '%fnptr200' defined with type 'i8 (i32) addrspace(200)*' ; 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: ok:
ret i8 0 ret i8 0
lpad: lpad:
@ -16,3 +19,12 @@ lpad:
} }
declare i32 @__gxx_personality_v0(...) 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
}