Skip to content

Commit

Permalink
Adding parameter attributes to some IGC intrinsics
Browse files Browse the repository at this point in the history
This change is to retain information about pointee types for particular arguments in some IGC intrinsics.
  • Loading branch information
krystian-andrzejewski authored and igcbot committed Dec 9, 2024
1 parent f477776 commit 115cf8c
Show file tree
Hide file tree
Showing 9 changed files with 162 additions and 34 deletions.
84 changes: 68 additions & 16 deletions IGC/GenISAIntrinsics/GenIntrinsicFunctions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,23 +101,27 @@ class IntrinsicFunctionImp : public llvm::Function
return false;
}

static IntrinsicFunctionImp<id>* Get(llvm::Module& module, const llvm::ArrayRef<llvm::Type*>& overloadedTypes)
static IntrinsicFunctionImp<id>* Get(llvm::Module& module, const llvm::ArrayRef<llvm::Type*>& overloadedTypes, const llvm::ArrayRef<llvm::Type*>& overloadedPointeeTys)
{
return llvm::cast<IntrinsicFunctionImp<id>>(GetDeclaration(module, overloadedTypes));
return llvm::cast<IntrinsicFunctionImp<id>>(GetDeclaration(module, overloadedTypes, overloadedPointeeTys));
}

static llvm::Function* GetDeclaration(llvm::Module& module, const llvm::ArrayRef<llvm::Type*>& overloadedTypes)
static llvm::Function* GetDeclaration(llvm::Module& module, const llvm::ArrayRef<llvm::Type*>& overloadedTypes, const llvm::ArrayRef<llvm::Type*>& overloadedPointeeTys)
{
return GetOrInsert(module, overloadedTypes);
return GetOrInsert(module, overloadedTypes, overloadedPointeeTys);
}

static std::string GetName(const llvm::ArrayRef<llvm::Type*>& overloadedTypes)
static std::string GetName(const llvm::ArrayRef<llvm::Type*>& overloadedTypes, const llvm::ArrayRef<llvm::Type*>& overloadedPointeeTys)
{
std::string result = IntrinsicDefinitionT::scFunctionRootName;
for (unsigned i = 0; i < overloadedTypes.size(); ++i)
{
result += "." + getMangledTypeStr(overloadedTypes[i]);
}
for (unsigned i = 0; i < overloadedPointeeTys.size(); ++i)
{
result += "." + getMangledTypeStr(overloadedPointeeTys[i]);
}
return result;
}

Expand All @@ -139,12 +143,12 @@ class IntrinsicFunctionImp : public llvm::Function

private:

static llvm::Function* GetOrInsert(llvm::Module& module, const llvm::ArrayRef<llvm::Type*>& overloadedTypes)
static llvm::Function* GetOrInsert(llvm::Module& module, const llvm::ArrayRef<llvm::Type*>& overloadedTypes, const llvm::ArrayRef<llvm::Type*>& overloadedPointeeTys)
{
llvm::LLVMContext& ctx = module.getContext();
std::string funcName = GetName(overloadedTypes);
std::string funcName = GetName(overloadedTypes, overloadedPointeeTys);
llvm::FunctionType* pFuncType = GetType(ctx, overloadedTypes);
llvm::AttributeList attribs = GetAttributeList(ctx);
llvm::AttributeList attribs = GetAttributeList(ctx, overloadedPointeeTys);
// There can never be multiple globals with the same name of different types,
// because intrinsics must be a specific type.
IGCLLVM::Module& M = static_cast<IGCLLVM::Module&>(module);
Expand Down Expand Up @@ -201,7 +205,7 @@ class IntrinsicFunctionImp : public llvm::Function
{
for (uint8_t i = 0; i < numArguments; i++)
{
RetrieveType(i + 1, IntrinsicDefinitionT::scArgumentTypes[i]);
RetrieveType(i + 1, IntrinsicDefinitionT::scArguments[i].m_Type);
}
}
// IGC_ASSERT(overloadedTypeIndex == overloadedTypes.size());
Expand All @@ -218,16 +222,64 @@ class IntrinsicFunctionImp : public llvm::Function
return llvm::FunctionType::get(resultTy, argTys, false);
}

static llvm::AttributeList GetAttributeList(llvm::LLVMContext& ctx)
static llvm::AttributeList GetAttributeList(llvm::LLVMContext& ctx, const llvm::ArrayRef<llvm::Type*>& overloadedPointeeTys)
{
// 1. Instantiate regular attributes for the given intrinsic
constexpr auto& attributeKinds = IntrinsicDefinitionT::scAttributeKinds;
auto mainAttrList = llvm::AttributeList::get(
ctx, llvm::AttributeList::FunctionIndex, attributeKinds);
// 2. Gather the memory attribute(s) in a separate routine
auto memoryAB = IntrinsicDefinitionT::scMemoryEffects.getAsAttrBuilder(ctx);
// Return a merged collection
return mainAttrList.addFnAttributes(ctx, memoryAB);
mainAttrList = mainAttrList.addFnAttributes(ctx, memoryAB);
// 3. Gather parameter attributes
uint8_t overloadedTypeIndex = 0;
auto RetrieveParamAttr = [&overloadedTypeIndex, &ctx, &overloadedPointeeTys, &mainAttrList](uint8_t index, const ArgumentDescription& arg)
{
if (arg.m_AttrKind == llvm::Attribute::None)
{
return;
}
IGC_ASSERT_MESSAGE(
arg.m_AttrKind == llvm::Attribute::ByRef ||
arg.m_AttrKind == llvm::Attribute::ByVal ||
arg.m_AttrKind == llvm::Attribute::StructRet,
"Used an invalid(?) parameter attribute kind");
switch (arg.m_Type.m_ID)
{
case TypeID::Pointer:
{
llvm::Type* pointeeType = nullptr;
if (overloadedTypeIndex < overloadedPointeeTys.size() && arg.m_Type.IsOverloadable())
{
pointeeType = overloadedPointeeTys[overloadedTypeIndex++];
}
else
{
pointeeType = arg.m_Type.m_Pointer.m_Type.GetType(ctx);
}

if (pointeeType != nullptr)
{
mainAttrList = mainAttrList.addParamAttribute(ctx, { index }, llvm::Attribute::get(ctx, arg.m_AttrKind, pointeeType));
}
break;
}
default:
IGC_ASSERT_MESSAGE(0, "A parameter attribute used for non-pointer function argument.");
break;
}
};

constexpr uint8_t numArguments = static_cast<uint8_t>(Argument::Count);
if constexpr (numArguments > 0)
{
for (uint8_t i = 0; i < numArguments; i++)
{
RetrieveParamAttr(i, IntrinsicDefinitionT::scArguments[i]);
}
}

return mainAttrList;
}
};

Expand All @@ -245,14 +297,14 @@ static constexpr auto GetDeclarationFuncArray()
return GetDeclarationFuncArrayImp(seq);
}

llvm::Function* GetDeclaration(llvm::Module* pModule, llvm::GenISAIntrinsic::ID id, llvm::ArrayRef<llvm::Type*> overloadedTys)
llvm::Function* GetDeclaration(llvm::Module* pModule, llvm::GenISAIntrinsic::ID id, llvm::ArrayRef<llvm::Type*> overloadedTys, llvm::ArrayRef<llvm::Type*> overloadedPointeeTys)
{
constexpr auto funcArray = GetDeclarationFuncArray();
llvm::Function* pResult = nullptr;
uint32_t index = static_cast<uint32_t>(id) - scBeginIntrinsicIndex;
if (index < funcArray.size())
{
pResult = funcArray[index](*pModule, overloadedTys);
pResult = funcArray[index](*pModule, overloadedTys, overloadedPointeeTys);
}
return pResult;
}
Expand All @@ -271,14 +323,14 @@ static constexpr auto GetNameFuncArray()
return GetNameFuncArrayImp(seq);
}

std::string GetName(llvm::GenISAIntrinsic::ID id, llvm::ArrayRef<llvm::Type*> overloadedTys)
std::string GetName(llvm::GenISAIntrinsic::ID id, llvm::ArrayRef<llvm::Type*> overloadedTys, llvm::ArrayRef<llvm::Type*> overloadedPointeeTys)
{
constexpr auto funcArray = GetNameFuncArray();
std::string result;
uint32_t index = static_cast<uint32_t>(id) - scBeginIntrinsicIndex;
if (index < funcArray.size())
{
result = funcArray[index](overloadedTys);
result = funcArray[index](overloadedTys, overloadedPointeeTys);
}
return result;
}
Expand Down
4 changes: 2 additions & 2 deletions IGC/GenISAIntrinsics/GenIntrinsicFunctions.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,10 @@ std::string getMangledTypeStr(llvm::Type* Ty);

const char* GetIntrinsicPrefixName();

std::string GetName(llvm::GenISAIntrinsic::ID id, llvm::ArrayRef<llvm::Type*> OverloadedTys);
std::string GetName(llvm::GenISAIntrinsic::ID id, llvm::ArrayRef<llvm::Type*> OverloadedTys, llvm::ArrayRef<llvm::Type*> overloadedPointeeTys);

llvm::GenISAIntrinsic::IntrinsicComments GetIntrinsicComments(llvm::GenISAIntrinsic::ID id);

llvm::Function* GetDeclaration(llvm::Module* pModule, llvm::GenISAIntrinsic::ID id, llvm::ArrayRef<llvm::Type*> overloadedTys);
llvm::Function* GetDeclaration(llvm::Module* pModule, llvm::GenISAIntrinsic::ID id, llvm::ArrayRef<llvm::Type*> overloadedTys, llvm::ArrayRef<llvm::Type*> overloadedPointeeTys);

} // namespace IGC
8 changes: 4 additions & 4 deletions IGC/GenISAIntrinsics/GenIntrinsics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,19 +75,19 @@ namespace llvm
namespace GenISAIntrinsic
{

std::string getName(ID id, ArrayRef<Type*> OverloadedTys /*= None*/)
std::string getName(ID id, ArrayRef<Type*> OverloadedTys /*= None*/, ArrayRef<Type*> OverloadedPointeeTys /*= None*/)
{
return IGC::GetName(id, OverloadedTys);
return IGC::GetName(id, OverloadedTys, OverloadedPointeeTys);
}

IntrinsicComments getIntrinsicComments(ID id)
{
return IGC::GetIntrinsicComments(id);
}

Function* getDeclaration(Module* M, ID id, ArrayRef<Type*> OverloadedTys /*= None*/)
Function* getDeclaration(Module* M, ID id, ArrayRef<Type*> OverloadedTys /*= None*/, ArrayRef<Type*> OverloadedPointeeTys /*= None*/)
{
return IGC::GetDeclaration(M, id, OverloadedTys);
return IGC::GetDeclaration(M, id, OverloadedTys, OverloadedPointeeTys);
}

ID getIntrinsicID(const Function* F, bool useContextWrapper /*= true*/)
Expand Down
6 changes: 3 additions & 3 deletions IGC/GenISAIntrinsics/GenIntrinsics.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ namespace GenISAIntrinsic

/// Intrinsic::getName(ID) - Return the LLVM name for an intrinsic, such as
/// "llvm.ppc.altivec.lvx".
std::string getName(ID id, ArrayRef<Type*> Tys = {});
std::string getName(ID id, ArrayRef<Type*> Tys = {}, ArrayRef<Type*> OverloadedPointeeTys = {});


struct IntrinsicComments
Expand Down Expand Up @@ -53,9 +53,9 @@ IntrinsicComments getIntrinsicComments(ID id);
/// Type Ts[2]{int2, int2}: to resolve to the first instance.
/// Type Ts[2]{int4, int4}: to resolve to the second.
#if defined(ANDROID) || defined(__linux__)
__attribute__ ((visibility ("default"))) Function *getDeclaration(Module *M, ID id, ArrayRef<Type*> OverloadedTys = {});
__attribute__ ((visibility ("default"))) Function *getDeclaration(Module *M, ID id, ArrayRef<Type*> OverloadedTys = {}, ArrayRef<Type*> OverloadedPointeeTys = {});
#else
Function *getDeclaration(Module *M, ID id, ArrayRef<Type*> OverloadedTys = {});
Function *getDeclaration(Module *M, ID id, ArrayRef<Type*> OverloadedTys = {}, ArrayRef<Type*> OverloadedPointeeTys = {});
#endif

//Override of isIntrinsic method defined in Function.h
Expand Down
13 changes: 13 additions & 0 deletions IGC/GenISAIntrinsics/LlvmTypesMapping.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ SPDX-License-Identifier: MIT

#include "common/LLVMWarningsPush.hpp"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/IR/Attributes.h"
#include "common/LLVMWarningsPop.hpp"

namespace llvm
Expand Down Expand Up @@ -409,6 +410,18 @@ struct TypeDescription
const TypeID m_ID;
};

struct ArgumentDescription
{
constexpr ArgumentDescription(const TypeDescription& type, llvm::Attribute::AttrKind attrKind = llvm::Attribute::None) :
m_Type(type),
m_AttrKind(attrKind)
{
}

const TypeDescription& m_Type;
llvm::Attribute::AttrKind m_AttrKind;
};

constexpr bool IsOverloadable(const TypeDescription& type)
{
return type.IsOverloadable();
Expand Down
47 changes: 43 additions & 4 deletions IGC/GenISAIntrinsics/generator/Intrinsic_definition_objects.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,36 @@ def AttributeID_constructor(loader, node):

yaml.SafeLoader.add_constructor(u'!AttributeID', AttributeID_constructor)

class ParamAttributeID(Enum):
ByRef = 0
ByVal = 1
StructRet = 2

def __str__(self):
return self.name

def __repr__(self):
return '%s("%s")' % (self.__class__.__name__, self)

@classmethod
def from_str(cls, value : str):
for key, val in cls.__members__.items():
if key == value:
return val
else:
raise ValueError("{value} is not present in {cls.__name__}")

def ParamAttributeID_representer(dumper, data):
return dumper.represent_scalar(u'!ParamAttributeID', u'%s' % str(data), style='"')

yaml.add_representer(ParamAttributeID, ParamAttributeID_representer)

def ParamAttributeID_constructor(loader, node):
value = loader.construct_scalar(node)
return ParamAttributeID.from_str(value)

yaml.SafeLoader.add_constructor(u'!ParamAttributeID', ParamAttributeID_constructor)

class MemoryLocation(Enum):
ArgMem = 0
InaccessibleMem = 1
Expand Down Expand Up @@ -460,27 +490,36 @@ def from_yaml(cls, loader, node):
arg_dict = loader.construct_mapping(node, deep=True)
return cls(**arg_dict)

def __init__(self, name : str, type_definition : TypeDefinition, comment : str):
def __init__(self, name : str, type_definition : TypeDefinition, comment : str, param_attr : ParamAttributeID = None):
self.name = name
self.type_definition = type_definition
self.comment = QuotedString(comment)
if param_attr:
self.param_attr = param_attr

def __repr__(self):
return "%s(name=%r, type_definition=%r, comment=%r)" % (
self.__class__.__name__, self.name, self.type_definition, self.comment)
repr_str = "name=%r" % (self.name)
repr_str += ", type_definition=%r" % (self.type_definition)
repr_str += ", comment=%r" % (self.comment)
if hasattr(self, 'param_attr'):
repr_str += ", param_attr=%r" % str(self.param_attr)
return "%s(%r)" % (
self.__class__.__name__, repr_str)

def to_dict(self):
res = {
"name": self.name,
"type_definition": self.type_definition.to_dict(),
"comment": self.comment
}
if hasattr(self, 'param_attr'):
res["param_attr"] = str(self.param_attr)
return res

@staticmethod
def from_dict(json_dct : dict):
type_definition = TypeDefinition.from_dict(json_dct['type_definition'])
return ArgumentDefinition(json_dct['name'], type_definition, json_dct['comment'])
return ArgumentDefinition(json_dct['name'], type_definition, json_dct['comment'], json_dct['param_attr'])

class MemoryRestriction(SafeYAMLObject):

Expand Down
19 changes: 16 additions & 3 deletions IGC/GenISAIntrinsics/generator/Intrinsic_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,10 +122,16 @@ def get_type_definition(type_def):
output = "AnyTypeHolderT<>"
return output

@staticmethod
def get_argument_type_entry(type_def, is_last):
output = IntrinsicFormatter.get_type_definition(type_def)
@classmethod
def get_argument_entry(cls, arg, is_last):
output = cls.get_type_definition(arg.type_definition)
output = "{}::scType".format(output)
if hasattr(arg, 'param_attr'):
# a param attribute is supported only for pointer function arguments to preserve their pointee types
if arg.type_definition.ID != TypeID.Pointer:
sys.exit(1)
output += ", {}".format(cls.get_attribute_entry(arg.param_attr, is_last=True))
output = "ArgumentDescription({})".format(output)
if not is_last:
output = "{},".format(output)
return output
Expand All @@ -151,6 +157,13 @@ def get_attribute_entry(attribute, is_last):
output = "{},".format(output)
return output

@staticmethod
def get_param_attribute_entry(param_attribute, is_last):
output = 'std::make_pair(llvm::Attribute::{}, {})'.format(param_attribute.name, param_attribute.index)
if not is_last:
output = "{},".format(output)
return output

@staticmethod
def get_memory_effects_instance(memory_restriction : MemoryRestriction):
modref_arg = "IGCLLVM::ModRefInfo::{}".format(memory_restriction.memory_access)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10929,6 +10929,7 @@ intrinsics:
name: Arg2
type_definition: *p_any_
comment: "User defined intersection attributes struct"
param_attr: !ParamAttributeID "ByRef"
attributes:
- !AttributeID "NoUnwind"
- !<IntrinsicDefinition>
Expand Down
Loading

0 comments on commit 115cf8c

Please sign in to comment.