Skip to content

Commit

Permalink
AMDGPU: Bring HSA metadata on par with the specification
Browse files Browse the repository at this point in the history
Differential Revision: https://reviews.llvm.org/D38753


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@315821 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
kzhuravl committed Oct 14, 2017
1 parent 7032e50 commit 5556d84
Show file tree
Hide file tree
Showing 19 changed files with 428 additions and 337 deletions.
7 changes: 4 additions & 3 deletions docs/AMDGPUUsage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -889,7 +889,7 @@ non-AMD key names should be prefixed by "*vendor-name*.".
See
:ref:`amdgpu-amdhsa-code-object-kernel-attribute-metadata-mapping-table`
for the mapping definition.
"Arguments" sequence of Sequence of mappings of the
"Args" sequence of Sequence of mappings of the
mapping kernel arguments. See
:ref:`amdgpu-amdhsa-code-object-kernel-argument-metadata-mapping-table`
for the definition of the mapping.
Expand Down Expand Up @@ -1099,7 +1099,7 @@ non-AMD key names should be prefixed by "*vendor-name*.".
.. TODO
Does this apply to
GlobalBuffer?
"ActualAcc" string The actual memory accesses
"ActualAccQual" string The actual memory accesses
performed by the kernel on the
kernel argument. Only present if
"ValueKind" is "GlobalBuffer",
Expand Down Expand Up @@ -1224,7 +1224,8 @@ non-AMD key names should be prefixed by "*vendor-name*.".
=================================== ============== ========= ==============
String Key Value Type Required? Description
=================================== ============== ========= ==============
"DebuggerABIVersion" string
"DebuggerABIVersion" sequence of
2 integers
"ReservedNumVGPRs" integer
"ReservedFirstVGPR" integer
"PrivateSegmentBufferSGPR" integer
Expand Down
119 changes: 64 additions & 55 deletions include/llvm/Support/AMDGPUMetadata.h
Original file line number Diff line number Diff line change
Expand Up @@ -133,13 +133,13 @@ struct Metadata final {

/// \returns True if kernel attributes metadata is empty, false otherwise.
bool empty() const {
return mReqdWorkGroupSize.empty() && mWorkGroupSizeHint.empty() &&
mVecTypeHint.empty() && mRuntimeHandle.empty();
return !notEmpty();
}

/// \returns True if kernel attributes metadata is not empty, false otherwise.
bool notEmpty() const {
return !empty();
return !mReqdWorkGroupSize.empty() || !mWorkGroupSizeHint.empty() ||
!mVecTypeHint.empty() || !mRuntimeHandle.empty();
}
};

Expand All @@ -151,6 +151,10 @@ struct Metadata final {
namespace Arg {

namespace Key {
/// \brief Key for Kernel::Arg::Metadata::mName.
constexpr char Name[] = "Name";
/// \brief Key for Kernel::Arg::Metadata::mTypeName.
constexpr char TypeName[] = "TypeName";
/// \brief Key for Kernel::Arg::Metadata::mSize.
constexpr char Size[] = "Size";
/// \brief Key for Kernel::Arg::Metadata::mAlign.
Expand All @@ -161,26 +165,28 @@ constexpr char ValueKind[] = "ValueKind";
constexpr char ValueType[] = "ValueType";
/// \brief Key for Kernel::Arg::Metadata::mPointeeAlign.
constexpr char PointeeAlign[] = "PointeeAlign";
/// \brief Key for Kernel::Arg::Metadata::mAccQual.
constexpr char AccQual[] = "AccQual";
/// \brief Key for Kernel::Arg::Metadata::mAddrSpaceQual.
constexpr char AddrSpaceQual[] = "AddrSpaceQual";
/// \brief Key for Kernel::Arg::Metadata::mAccQual.
constexpr char AccQual[] = "AccQual";
/// \brief Key for Kernel::Arg::Metadata::mActualAccQual.
constexpr char ActualAccQual[] = "ActualAccQual";
/// \brief Key for Kernel::Arg::Metadata::mIsConst.
constexpr char IsConst[] = "IsConst";
/// \brief Key for Kernel::Arg::Metadata::mIsPipe.
constexpr char IsPipe[] = "IsPipe";
/// \brief Key for Kernel::Arg::Metadata::mIsRestrict.
constexpr char IsRestrict[] = "IsRestrict";
/// \brief Key for Kernel::Arg::Metadata::mIsVolatile.
constexpr char IsVolatile[] = "IsVolatile";
/// \brief Key for Kernel::Arg::Metadata::mName.
constexpr char Name[] = "Name";
/// \brief Key for Kernel::Arg::Metadata::mTypeName.
constexpr char TypeName[] = "TypeName";
/// \brief Key for Kernel::Arg::Metadata::mIsPipe.
constexpr char IsPipe[] = "IsPipe";
} // end namespace Key

/// \brief In-memory representation of kernel argument metadata.
struct Metadata final {
/// \brief Name. Optional.
std::string mName = std::string();
/// \brief Type name. Optional.
std::string mTypeName = std::string();
/// \brief Size in bytes. Required.
uint32_t mSize = 0;
/// \brief Alignment in bytes. Required.
Expand All @@ -191,22 +197,20 @@ struct Metadata final {
ValueType mValueType = ValueType::Unknown;
/// \brief Pointee alignment in bytes. Optional.
uint32_t mPointeeAlign = 0;
/// \brief Access qualifier. Optional.
AccessQualifier mAccQual = AccessQualifier::Unknown;
/// \brief Address space qualifier. Optional.
AddressSpaceQualifier mAddrSpaceQual = AddressSpaceQualifier::Unknown;
/// \brief Access qualifier. Optional.
AccessQualifier mAccQual = AccessQualifier::Unknown;
/// \brief Actual access qualifier. Optional.
AccessQualifier mActualAccQual = AccessQualifier::Unknown;
/// \brief True if 'const' qualifier is specified. Optional.
bool mIsConst = false;
/// \brief True if 'pipe' qualifier is specified. Optional.
bool mIsPipe = false;
/// \brief True if 'restrict' qualifier is specified. Optional.
bool mIsRestrict = false;
/// \brief True if 'volatile' qualifier is specified. Optional.
bool mIsVolatile = false;
/// \brief Name. Optional.
std::string mName = std::string();
/// \brief Type name. Optional.
std::string mTypeName = std::string();
/// \brief True if 'pipe' qualifier is specified. Optional.
bool mIsPipe = false;

/// \brief Default constructor.
Metadata() = default;
Expand All @@ -222,51 +226,55 @@ namespace CodeProps {
namespace Key {
/// \brief Key for Kernel::CodeProps::Metadata::mKernargSegmentSize.
constexpr char KernargSegmentSize[] = "KernargSegmentSize";
/// \brief Key for Kernel::CodeProps::Metadata::mWorkgroupGroupSegmentSize.
constexpr char WorkgroupGroupSegmentSize[] = "WorkgroupGroupSegmentSize";
/// \brief Key for Kernel::CodeProps::Metadata::mWorkitemPrivateSegmentSize.
constexpr char WorkitemPrivateSegmentSize[] = "WorkitemPrivateSegmentSize";
/// \brief Key for Kernel::CodeProps::Metadata::mWavefrontNumSGPRs.
constexpr char WavefrontNumSGPRs[] = "WavefrontNumSGPRs";
/// \brief Key for Kernel::CodeProps::Metadata::mWorkitemNumVGPRs.
constexpr char WorkitemNumVGPRs[] = "WorkitemNumVGPRs";
/// \brief Key for Kernel::CodeProps::Metadata::mGroupSegmentFixedSize.
constexpr char GroupSegmentFixedSize[] = "GroupSegmentFixedSize";
/// \brief Key for Kernel::CodeProps::Metadata::mPrivateSegmentFixedSize.
constexpr char PrivateSegmentFixedSize[] = "PrivateSegmentFixedSize";
/// \brief Key for Kernel::CodeProps::Metadata::mKernargSegmentAlign.
constexpr char KernargSegmentAlign[] = "KernargSegmentAlign";
/// \brief Key for Kernel::CodeProps::Metadata::mGroupSegmentAlign.
constexpr char GroupSegmentAlign[] = "GroupSegmentAlign";
/// \brief Key for Kernel::CodeProps::Metadata::mPrivateSegmentAlign.
constexpr char PrivateSegmentAlign[] = "PrivateSegmentAlign";
/// \brief Key for Kernel::CodeProps::Metadata::mWavefrontSize.
constexpr char WavefrontSize[] = "WavefrontSize";
/// \brief Key for Kernel::CodeProps::Metadata::mNumSGPRs.
constexpr char NumSGPRs[] = "NumSGPRs";
/// \brief Key for Kernel::CodeProps::Metadata::mNumVGPRs.
constexpr char NumVGPRs[] = "NumVGPRs";
/// \brief Key for Kernel::CodeProps::Metadata::mMaxFlatWorkgroupSize.
constexpr char MaxFlatWorkgroupSize[] = "MaxFlatWorkgroupSize";
/// \brief Key for Kernel::CodeProps::Metadata::mIsDynamicCallStack.
constexpr char IsDynamicCallStack[] = "IsDynamicCallStack";
/// \brief Key for Kernel::CodeProps::Metadata::mIsXNACKEnabled.
constexpr char IsXNACKEnabled[] = "IsXNACKEnabled";
} // end namespace Key

/// \brief In-memory representation of kernel code properties metadata.
struct Metadata final {
/// \brief Size in bytes of the kernarg segment memory. Kernarg segment memory
/// holds the values of the arguments to the kernel. Optional.
/// holds the values of the arguments to the kernel. Required.
uint64_t mKernargSegmentSize = 0;
/// \brief Size in bytes of the group segment memory required by a workgroup.
/// This value does not include any dynamically allocated group segment memory
/// that may be added when the kernel is dispatched. Optional.
uint32_t mWorkgroupGroupSegmentSize = 0;
/// that may be added when the kernel is dispatched. Required.
uint32_t mGroupSegmentFixedSize = 0;
/// \brief Size in bytes of the private segment memory required by a workitem.
/// Private segment memory includes arg, spill and private segments. Optional.
uint32_t mWorkitemPrivateSegmentSize = 0;
/// Private segment memory includes arg, spill and private segments. Required.
uint32_t mPrivateSegmentFixedSize = 0;
/// \brief Maximum byte alignment of variables used by the kernel in the
/// kernarg memory segment. Required.
uint32_t mKernargSegmentAlign = 0;
/// \brief Wavefront size. Required.
uint32_t mWavefrontSize = 0;
/// \brief Total number of SGPRs used by a wavefront. Optional.
uint16_t mWavefrontNumSGPRs = 0;
uint16_t mNumSGPRs = 0;
/// \brief Total number of VGPRs used by a workitem. Optional.
uint16_t mWorkitemNumVGPRs = 0;
/// \brief Maximum byte alignment of variables used by the kernel in the
/// kernarg memory segment. Expressed as a power of two. Optional.
uint8_t mKernargSegmentAlign = 0;
/// \brief Maximum byte alignment of variables used by the kernel in the
/// group memory segment. Expressed as a power of two. Optional.
uint8_t mGroupSegmentAlign = 0;
/// \brief Maximum byte alignment of variables used by the kernel in the
/// private memory segment. Expressed as a power of two. Optional.
uint8_t mPrivateSegmentAlign = 0;
/// \brief Wavefront size. Expressed as a power of two. Optional.
uint8_t mWavefrontSize = 0;
uint16_t mNumVGPRs = 0;
/// \brief Maximum flat work-group size supported by the kernel. Optional.
uint32_t mMaxFlatWorkgroupSize = 0;
/// \brief True if the generated machine code is using a dynamically sized
/// call stack. Optional.
bool mIsDynamicCallStack = false;
/// \brief True if the generated machine code is capable of supporting XNACK.
/// Optional.
bool mIsXNACKEnabled = false;

/// \brief Default constructor.
Metadata() = default;
Expand All @@ -280,10 +288,7 @@ struct Metadata final {
/// \returns True if kernel code properties metadata is not empty, false
/// otherwise.
bool notEmpty() const {
return mKernargSegmentSize || mWorkgroupGroupSegmentSize ||
mWorkitemPrivateSegmentSize || mWavefrontNumSGPRs ||
mWorkitemNumVGPRs || mKernargSegmentAlign || mGroupSegmentAlign ||
mPrivateSegmentAlign || mWavefrontSize;
return true;
}
};

Expand Down Expand Up @@ -349,6 +354,8 @@ struct Metadata final {
namespace Key {
/// \brief Key for Kernel::Metadata::mName.
constexpr char Name[] = "Name";
/// \brief Key for Kernel::Metadata::mSymbolName.
constexpr char SymbolName[] = "SymbolName";
/// \brief Key for Kernel::Metadata::mLanguage.
constexpr char Language[] = "Language";
/// \brief Key for Kernel::Metadata::mLanguageVersion.
Expand All @@ -365,8 +372,10 @@ constexpr char DebugProps[] = "DebugProps";

/// \brief In-memory representation of kernel metadata.
struct Metadata final {
/// \brief Name. Required.
/// \brief Kernel source name. Required.
std::string mName = std::string();
/// \brief Kernel descriptor name. Required.
std::string mSymbolName = std::string();
/// \brief Language. Optional.
std::string mLanguage = std::string();
/// \brief Language version. Optional.
Expand Down Expand Up @@ -401,7 +410,7 @@ struct Metadata final {
std::vector<uint32_t> mVersion = std::vector<uint32_t>();
/// \brief Printf metadata. Optional.
std::vector<std::string> mPrintf = std::vector<std::string>();
/// \brief Kernels metadata. Optional.
/// \brief Kernels metadata. Required.
std::vector<Kernel::Metadata> mKernels = std::vector<Kernel::Metadata>();

/// \brief Default constructor.
Expand Down
51 changes: 28 additions & 23 deletions lib/Support/AMDGPUMetadata.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,46 +104,50 @@ struct MappingTraits<Kernel::Attrs::Metadata> {
template <>
struct MappingTraits<Kernel::Arg::Metadata> {
static void mapping(IO &YIO, Kernel::Arg::Metadata &MD) {
YIO.mapOptional(Kernel::Arg::Key::Name, MD.mName, std::string());
YIO.mapOptional(Kernel::Arg::Key::TypeName, MD.mTypeName, std::string());
YIO.mapRequired(Kernel::Arg::Key::Size, MD.mSize);
YIO.mapRequired(Kernel::Arg::Key::Align, MD.mAlign);
YIO.mapRequired(Kernel::Arg::Key::ValueKind, MD.mValueKind);
YIO.mapRequired(Kernel::Arg::Key::ValueType, MD.mValueType);
YIO.mapOptional(Kernel::Arg::Key::PointeeAlign, MD.mPointeeAlign,
uint32_t(0));
YIO.mapOptional(Kernel::Arg::Key::AccQual, MD.mAccQual,
AccessQualifier::Unknown);
YIO.mapOptional(Kernel::Arg::Key::AddrSpaceQual, MD.mAddrSpaceQual,
AddressSpaceQualifier::Unknown);
YIO.mapOptional(Kernel::Arg::Key::AccQual, MD.mAccQual,
AccessQualifier::Unknown);
YIO.mapOptional(Kernel::Arg::Key::ActualAccQual, MD.mActualAccQual,
AccessQualifier::Unknown);
YIO.mapOptional(Kernel::Arg::Key::IsConst, MD.mIsConst, false);
YIO.mapOptional(Kernel::Arg::Key::IsPipe, MD.mIsPipe, false);
YIO.mapOptional(Kernel::Arg::Key::IsRestrict, MD.mIsRestrict, false);
YIO.mapOptional(Kernel::Arg::Key::IsVolatile, MD.mIsVolatile, false);
YIO.mapOptional(Kernel::Arg::Key::Name, MD.mName, std::string());
YIO.mapOptional(Kernel::Arg::Key::TypeName, MD.mTypeName, std::string());
YIO.mapOptional(Kernel::Arg::Key::IsPipe, MD.mIsPipe, false);
}
};

template <>
struct MappingTraits<Kernel::CodeProps::Metadata> {
static void mapping(IO &YIO, Kernel::CodeProps::Metadata &MD) {
YIO.mapOptional(Kernel::CodeProps::Key::KernargSegmentSize,
MD.mKernargSegmentSize, uint64_t(0));
YIO.mapOptional(Kernel::CodeProps::Key::WorkgroupGroupSegmentSize,
MD.mWorkgroupGroupSegmentSize, uint32_t(0));
YIO.mapOptional(Kernel::CodeProps::Key::WorkitemPrivateSegmentSize,
MD.mWorkitemPrivateSegmentSize, uint32_t(0));
YIO.mapOptional(Kernel::CodeProps::Key::WavefrontNumSGPRs,
MD.mWavefrontNumSGPRs, uint16_t(0));
YIO.mapOptional(Kernel::CodeProps::Key::WorkitemNumVGPRs,
MD.mWorkitemNumVGPRs, uint16_t(0));
YIO.mapOptional(Kernel::CodeProps::Key::KernargSegmentAlign,
MD.mKernargSegmentAlign, uint8_t(0));
YIO.mapOptional(Kernel::CodeProps::Key::GroupSegmentAlign,
MD.mGroupSegmentAlign, uint8_t(0));
YIO.mapOptional(Kernel::CodeProps::Key::PrivateSegmentAlign,
MD.mPrivateSegmentAlign, uint8_t(0));
YIO.mapOptional(Kernel::CodeProps::Key::WavefrontSize,
MD.mWavefrontSize, uint8_t(0));
YIO.mapRequired(Kernel::CodeProps::Key::KernargSegmentSize,
MD.mKernargSegmentSize);
YIO.mapRequired(Kernel::CodeProps::Key::GroupSegmentFixedSize,
MD.mGroupSegmentFixedSize);
YIO.mapRequired(Kernel::CodeProps::Key::PrivateSegmentFixedSize,
MD.mPrivateSegmentFixedSize);
YIO.mapRequired(Kernel::CodeProps::Key::KernargSegmentAlign,
MD.mKernargSegmentAlign);
YIO.mapRequired(Kernel::CodeProps::Key::WavefrontSize,
MD.mWavefrontSize);
YIO.mapOptional(Kernel::CodeProps::Key::NumSGPRs,
MD.mNumSGPRs, uint16_t(0));
YIO.mapOptional(Kernel::CodeProps::Key::NumVGPRs,
MD.mNumVGPRs, uint16_t(0));
YIO.mapOptional(Kernel::CodeProps::Key::MaxFlatWorkgroupSize,
MD.mMaxFlatWorkgroupSize, uint32_t(0));
YIO.mapOptional(Kernel::CodeProps::Key::IsDynamicCallStack,
MD.mIsDynamicCallStack, false);
YIO.mapOptional(Kernel::CodeProps::Key::IsXNACKEnabled,
MD.mIsXNACKEnabled, false);
}
};

Expand All @@ -167,6 +171,7 @@ template <>
struct MappingTraits<Kernel::Metadata> {
static void mapping(IO &YIO, Kernel::Metadata &MD) {
YIO.mapRequired(Kernel::Key::Name, MD.mName);
YIO.mapRequired(Kernel::Key::SymbolName, MD.mSymbolName);
YIO.mapOptional(Kernel::Key::Language, MD.mLanguage, std::string());
YIO.mapOptional(Kernel::Key::LanguageVersion, MD.mLanguageVersion,
std::vector<uint32_t>());
Expand Down
51 changes: 50 additions & 1 deletion lib/Target/AMDGPU/AMDGPUAsmPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,9 @@ void AMDGPUAsmPrinter::EmitFunctionBodyStart() {
if (TM.getTargetTriple().getOS() != Triple::AMDHSA)
return;

HSAMetadataStream.emitKernel(*MF->getFunction(), KernelCode);
HSAMetadataStream.emitKernel(*MF->getFunction(),
getHSACodeProps(*MF, CurrentProgramInfo),
getHSADebugProps(*MF, CurrentProgramInfo));
}

void AMDGPUAsmPrinter::EmitFunctionEntryLabel() {
Expand Down Expand Up @@ -1155,6 +1157,53 @@ void AMDGPUAsmPrinter::getAmdKernelCode(amd_kernel_code_t &Out,
}
}

AMDGPU::HSAMD::Kernel::CodeProps::Metadata AMDGPUAsmPrinter::getHSACodeProps(
const MachineFunction &MF,
const SIProgramInfo &ProgramInfo) const {
const SISubtarget &STM = MF.getSubtarget<SISubtarget>();
const SIMachineFunctionInfo &MFI = *MF.getInfo<SIMachineFunctionInfo>();
HSAMD::Kernel::CodeProps::Metadata HSACodeProps;

HSACodeProps.mKernargSegmentSize =
STM.getKernArgSegmentSize(MF, MFI.getABIArgOffset());
HSACodeProps.mGroupSegmentFixedSize = ProgramInfo.LDSSize;
HSACodeProps.mPrivateSegmentFixedSize = ProgramInfo.ScratchSize;
HSACodeProps.mKernargSegmentAlign =
std::max(uint32_t(4), MFI.getMaxKernArgAlign());
HSACodeProps.mWavefrontSize = STM.getWavefrontSize();
HSACodeProps.mNumSGPRs = CurrentProgramInfo.NumSGPR;
HSACodeProps.mNumVGPRs = CurrentProgramInfo.NumVGPR;
// TODO: Emit HSACodeProps.mMaxFlatWorkgroupSize.
HSACodeProps.mIsDynamicCallStack = ProgramInfo.DynamicCallStack;
HSACodeProps.mIsXNACKEnabled = STM.isXNACKEnabled();

return HSACodeProps;
}

AMDGPU::HSAMD::Kernel::DebugProps::Metadata AMDGPUAsmPrinter::getHSADebugProps(
const MachineFunction &MF,
const SIProgramInfo &ProgramInfo) const {
const SISubtarget &STM = MF.getSubtarget<SISubtarget>();
HSAMD::Kernel::DebugProps::Metadata HSADebugProps;

if (!STM.debuggerSupported())
return HSADebugProps;

HSADebugProps.mDebuggerABIVersion.push_back(1);
HSADebugProps.mDebuggerABIVersion.push_back(0);
HSADebugProps.mReservedNumVGPRs = ProgramInfo.ReservedVGPRCount;
HSADebugProps.mReservedFirstVGPR = ProgramInfo.ReservedVGPRFirst;

if (STM.debuggerEmitPrologue()) {
HSADebugProps.mPrivateSegmentBufferSGPR =
ProgramInfo.DebuggerPrivateSegmentBufferSGPR;
HSADebugProps.mWavefrontPrivateSegmentOffsetSGPR =
ProgramInfo.DebuggerWavefrontPrivateSegmentOffsetSGPR;
}

return HSADebugProps;
}

bool AMDGPUAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
unsigned AsmVariant,
const char *ExtraCode, raw_ostream &O) {
Expand Down
Loading

0 comments on commit 5556d84

Please sign in to comment.