mirror of
https://github.com/RPCS3/llvm.git
synced 2026-07-18 21:24:32 -04:00
[AMDGPU] Update assembler for HSA Code Object v3
Update AMDGPU assembler syntax behind the code-object-v3 feature: * Replace/rename most AMDGPU assembler directives/symbols and document them. * Provide more diagnostics (e.g. values out of range, missing values, repeated values). * Provide path for backwards compatibility, even with underlying descriptor changes. Differential Revision: https://reviews.llvm.org/D47736 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@335281 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
+253
-93
@@ -696,7 +696,7 @@ Additional note records can be present.
|
||||
Specifies extensible metadata associated with the code objects executed on HSA
|
||||
[HSA]_ compatible runtimes such as AMD's ROCm [AMD-ROCm]_. It is required when
|
||||
the target triple OS is ``amdhsa`` (see :ref:`amdgpu-target-triples`). See
|
||||
:ref:`amdgpu-amdhsa-hsa-code-object-metadata` for the syntax of the code
|
||||
:ref:`amdgpu-amdhsa-code-object-metadata` for the syntax of the code
|
||||
object metadata string.
|
||||
|
||||
.. _amdgpu-symbols:
|
||||
@@ -954,7 +954,7 @@ AMDHSA
|
||||
This section provides code conventions used when the target triple OS is
|
||||
``amdhsa`` (see :ref:`amdgpu-target-triples`).
|
||||
|
||||
.. _amdgpu-amdhsa-hsa-code-object-metadata:
|
||||
.. _amdgpu-amdhsa-code-object-target-identification:
|
||||
|
||||
Code Object Target Identification
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
@@ -984,6 +984,8 @@ For example:
|
||||
|
||||
``"amdgcn-amd-amdhsa--gfx902+xnack"``
|
||||
|
||||
.. _amdgpu-amdhsa-code-object-metadata:
|
||||
|
||||
Code Object Metadata
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -1465,7 +1467,7 @@ CPU host program, or from an HSA kernel executing on a GPU.
|
||||
such as grid and work-group size, together with information from the code
|
||||
object about the kernel, such as segment sizes. The ROCm runtime queries on
|
||||
the kernel symbol can be used to obtain the code object values which are
|
||||
recorded in the :ref:`amdgpu-amdhsa-hsa-code-object-metadata`.
|
||||
recorded in the :ref:`amdgpu-amdhsa-code-object-metadata`.
|
||||
7. CP executes micro-code and is responsible for detecting and setting up the
|
||||
GPU to execute the wavefronts of a kernel dispatch.
|
||||
8. CP ensures that when the a wavefront starts executing the kernel machine
|
||||
@@ -1599,7 +1601,8 @@ that implements the kernel.
|
||||
Kernel Descriptor for GFX6-GFX9
|
||||
+++++++++++++++++++++++++++++++
|
||||
|
||||
CP microcode requires the Kernel descritor to be allocated on 64 byte alignment.
|
||||
CP microcode requires the Kernel descriptor to be allocated on 64 byte
|
||||
alignment.
|
||||
|
||||
.. table:: Kernel Descriptor for GFX6-GFX9
|
||||
:name: amdgpu-amdhsa-kernel-descriptor-gfx6-gfx9-table
|
||||
@@ -1680,42 +1683,86 @@ CP microcode requires the Kernel descritor to be allocated on 64 byte alignment.
|
||||
======= ======= =============================== ===========================================================================
|
||||
Bits Size Field Name Description
|
||||
======= ======= =============================== ===========================================================================
|
||||
5:0 6 bits GRANULATED_WORKITEM_VGPR_COUNT Number of vector registers
|
||||
used by each work-item,
|
||||
5:0 6 bits GRANULATED_WORKITEM_VGPR_COUNT Number of vector register
|
||||
blocks used by each work-item;
|
||||
granularity is device
|
||||
specific:
|
||||
|
||||
GFX6-GFX9
|
||||
- max_vgpr 1..256
|
||||
- roundup((max_vgpg + 1)
|
||||
/ 4) - 1
|
||||
- vgprs_used 0..256
|
||||
- max(0, ceil(vgprs_used / 4) - 1)
|
||||
|
||||
Where vgprs_used is defined
|
||||
as the highest VGPR number
|
||||
explicitly referenced plus
|
||||
one.
|
||||
|
||||
Used by CP to set up
|
||||
``COMPUTE_PGM_RSRC1.VGPRS``.
|
||||
9:6 4 bits GRANULATED_WAVEFRONT_SGPR_COUNT Number of scalar registers
|
||||
used by a wavefront,
|
||||
|
||||
The
|
||||
:ref:`amdgpu-assembler`
|
||||
calculates this
|
||||
automatically for the
|
||||
selected processor from
|
||||
values provided to the
|
||||
`.amdhsa_kernel` directive
|
||||
by the
|
||||
`.amdhsa_next_free_vgpr`
|
||||
nested directive (see
|
||||
:ref:`amdhsa-kernel-directives-table`).
|
||||
9:6 4 bits GRANULATED_WAVEFRONT_SGPR_COUNT Number of scalar register
|
||||
blocks used by a wavefront;
|
||||
granularity is device
|
||||
specific:
|
||||
|
||||
GFX6-GFX8
|
||||
- max_sgpr 1..112
|
||||
- roundup((max_sgpg + 1)
|
||||
/ 8) - 1
|
||||
- sgprs_used 0..112
|
||||
- max(0, ceil(sgprs_used / 8) - 1)
|
||||
GFX9
|
||||
- max_sgpr 1..112
|
||||
- roundup((max_sgpg + 1)
|
||||
/ 16) - 1
|
||||
- sgprs_used 0..112
|
||||
- 2 * max(0, ceil(sgprs_used / 16) - 1)
|
||||
|
||||
Includes the special SGPRs
|
||||
for VCC, Flat Scratch (for
|
||||
GFX7 onwards) and XNACK
|
||||
(for GFX8 onwards). It does
|
||||
not include the 16 SGPR
|
||||
added if a trap handler is
|
||||
Where sgprs_used is
|
||||
defined as the highest
|
||||
SGPR number explicitly
|
||||
referenced plus one, plus
|
||||
a target-specific number
|
||||
of additional special
|
||||
SGPRs for VCC,
|
||||
FLAT_SCRATCH (GFX7+) and
|
||||
XNACK_MASK (GFX8+), and
|
||||
any additional
|
||||
target-specific
|
||||
limitations. It does not
|
||||
include the 16 SGPRs added
|
||||
if a trap handler is
|
||||
enabled.
|
||||
|
||||
The target-specific
|
||||
limitations and special
|
||||
SGPR layout are defined in
|
||||
the hardware
|
||||
documentation, which can
|
||||
be found in the
|
||||
:ref:`amdgpu-processors`
|
||||
table.
|
||||
|
||||
Used by CP to set up
|
||||
``COMPUTE_PGM_RSRC1.SGPRS``.
|
||||
|
||||
The
|
||||
:ref:`amdgpu-assembler`
|
||||
calculates this
|
||||
automatically for the
|
||||
selected processor from
|
||||
values provided to the
|
||||
`.amdhsa_kernel` directive
|
||||
by the
|
||||
`.amdhsa_next_free_sgpr`
|
||||
and `.amdhsa_reserve_*`
|
||||
nested directives (see
|
||||
:ref:`amdhsa-kernel-directives-table`).
|
||||
11:10 2 bits PRIORITY Must be 0.
|
||||
|
||||
Start executing wavefront
|
||||
@@ -3994,7 +4041,7 @@ When the language is OpenCL the following differences occur:
|
||||
arguments for the AMDHSA OS (see
|
||||
:ref:`opencl-kernel-implicit-arguments-appended-for-amdhsa-os-table`).
|
||||
3. Additional metadata is generated
|
||||
(see :ref:`amdgpu-amdhsa-hsa-code-object-metadata`).
|
||||
(see :ref:`amdgpu-amdhsa-code-object-metadata`).
|
||||
|
||||
.. table:: OpenCL kernel implicit arguments appended for AMDHSA OS
|
||||
:name: opencl-kernel-implicit-arguments-appended-for-amdhsa-os-table
|
||||
@@ -4022,6 +4069,8 @@ When the language is HCC the following differences occur:
|
||||
|
||||
1. The HSA memory model is used (see :ref:`amdgpu-amdhsa-memory-model`).
|
||||
|
||||
.. _amdgpu-assembler:
|
||||
|
||||
Assembler
|
||||
---------
|
||||
|
||||
@@ -4254,97 +4303,208 @@ VOP_SDWA examples:
|
||||
|
||||
For full list of supported instructions, refer to "Vector ALU instructions".
|
||||
|
||||
HSA Code Object Directives
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Predefined Symbols
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
AMDGPU ABI defines auxiliary data in output code object. In assembly source,
|
||||
one can specify them with assembler directives.
|
||||
The AMDGPU assembler defines and updates some symbols automatically. These
|
||||
symbols do not affect code generation.
|
||||
|
||||
.hsa_code_object_version major, minor
|
||||
+++++++++++++++++++++++++++++++++++++
|
||||
.amdgcn.gfx_generation_number
|
||||
+++++++++++++++++++++++++++++
|
||||
|
||||
*major* and *minor* are integers that specify the version of the HSA code
|
||||
object that will be generated by the assembler.
|
||||
Set to the GFX generation number of the target being assembled for. For
|
||||
example, when assembling for a "GFX9" target this will be set to the integer
|
||||
value "9". The possible GFX generation numbers are presented in
|
||||
:ref:`amdgpu-processors`.
|
||||
|
||||
.hsa_code_object_isa [major, minor, stepping, vendor, arch]
|
||||
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
.amdgcn.next_free_vgpr
|
||||
++++++++++++++++++++++
|
||||
|
||||
Set to zero before assembly begins. At each instruction, if the current value
|
||||
of this symbol is less than or equal to the maximum VGPR number explicitly
|
||||
referenced within that instruction then the symbol value is updated to equal
|
||||
that VGPR number plus one.
|
||||
|
||||
*major*, *minor*, and *stepping* are all integers that describe the instruction
|
||||
set architecture (ISA) version of the assembly program.
|
||||
May be used to set the `.amdhsa_next_free_vpgr` directive in
|
||||
:ref:`amdhsa-kernel-directives-table`.
|
||||
|
||||
*vendor* and *arch* are quoted strings. *vendor* should always be equal to
|
||||
"AMD" and *arch* should always be equal to "AMDGPU".
|
||||
May be set at any time, e.g. manually set to zero at the start of each kernel.
|
||||
|
||||
By default, the assembler will derive the ISA version, *vendor*, and *arch*
|
||||
from the value of the -mcpu option that is passed to the assembler.
|
||||
.amdgcn.next_free_sgpr
|
||||
++++++++++++++++++++++
|
||||
|
||||
.amdgpu_hsa_kernel (name)
|
||||
+++++++++++++++++++++++++
|
||||
Set to zero before assembly begins. At each instruction, if the current value
|
||||
of this symbol is less than or equal the maximum SGPR number explicitly
|
||||
referenced within that instruction then the symbol value is updated to equal
|
||||
that SGPR number plus one.
|
||||
|
||||
This directives specifies that the symbol with given name is a kernel entry point
|
||||
(label) and the object should contain corresponding symbol of type STT_AMDGPU_HSA_KERNEL.
|
||||
May be used to set the `.amdhsa_next_free_spgr` directive in
|
||||
:ref:`amdhsa-kernel-directives-table`.
|
||||
|
||||
.amd_kernel_code_t
|
||||
++++++++++++++++++
|
||||
May be set at any time, e.g. manually set to zero at the start of each kernel.
|
||||
|
||||
This directive marks the beginning of a list of key / value pairs that are used
|
||||
to specify the amd_kernel_code_t object that will be emitted by the assembler.
|
||||
The list must be terminated by the *.end_amd_kernel_code_t* directive. For
|
||||
any amd_kernel_code_t values that are unspecified a default value will be
|
||||
used. The default value for all keys is 0, with the following exceptions:
|
||||
Code Object Directives
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
- *kernel_code_version_major* defaults to 1.
|
||||
- *machine_kind* defaults to 1.
|
||||
- *machine_version_major*, *machine_version_minor*, and
|
||||
*machine_version_stepping* are derived from the value of the -mcpu option
|
||||
that is passed to the assembler.
|
||||
- *kernel_code_entry_byte_offset* defaults to 256.
|
||||
- *wavefront_size* defaults to 6.
|
||||
- *kernarg_segment_alignment*, *group_segment_alignment*, and
|
||||
*private_segment_alignment* default to 4. Note that alignments are specified
|
||||
as a power of two, so a value of **n** means an alignment of 2^ **n**.
|
||||
Directives which begin with ``.amdgcn`` are valid for all ``amdgcn``
|
||||
architecture processors, and are not OS-specific. Directives which begin with
|
||||
``.amdhsa`` are specific to ``amdgcn`` architecture processors when the
|
||||
``amdhsa`` OS is specified. See :ref:`amdgpu-target-triples` and
|
||||
:ref:`amdgpu-processors`.
|
||||
|
||||
The *.amd_kernel_code_t* directive must be placed immediately after the
|
||||
function label and before any instructions.
|
||||
.amdgcn_target <target>
|
||||
+++++++++++++++++++++++
|
||||
|
||||
For a full list of amd_kernel_code_t keys, refer to AMDGPU ABI document,
|
||||
comments in lib/Target/AMDGPU/AmdKernelCodeT.h and test/CodeGen/AMDGPU/hsa.s.
|
||||
Optional directive which declares the target supported by the containing
|
||||
assembler source file. Valid values are described in
|
||||
:ref:`amdgpu-amdhsa-code-object-target-identification`. Used by the assembler
|
||||
to validate command-line options such as ``-triple``, ``-mcpu``, and those
|
||||
which specify target features.
|
||||
|
||||
Here is an example of a minimal amd_kernel_code_t specification:
|
||||
.amdhsa_kernel <name>
|
||||
+++++++++++++++++++++
|
||||
|
||||
.. code-block:: none
|
||||
Creates a correctly aligned AMDHSA kernel descriptor and a symbol,
|
||||
``<name>.kd``, in the current location of the current section. Only valid when
|
||||
the OS is ``amdhsa``. ``<name>`` must be a symbol that labels the first
|
||||
instruction to execute, and does not need to be previously defined.
|
||||
|
||||
.hsa_code_object_version 1,0
|
||||
.hsa_code_object_isa
|
||||
Marks the beginning of a list of directives used to generate the bytes of a
|
||||
kernel descriptor, as described in :ref:`amdgpu-amdhsa-kernel-descriptor`.
|
||||
Directives which may appear in this list are described in
|
||||
:ref:`amdhsa-kernel-directives-table`. Directives may appear in any order, must
|
||||
be valid for the target being assembled for, and cannot be repeated. Directives
|
||||
support the range of values specified by the field they reference in
|
||||
:ref:`amdgpu-amdhsa-kernel-descriptor`. If a directive is not specified, it is
|
||||
assumed to have its default value, unless it is marked as "Required", in which
|
||||
case it is an error to omit the directive. This list of directives is
|
||||
terminated by an ``.end_amdhsa_kernel`` directive.
|
||||
|
||||
.hsatext
|
||||
.globl hello_world
|
||||
.p2align 8
|
||||
.amdgpu_hsa_kernel hello_world
|
||||
.. table:: AMDHSA Kernel Assembler Directives
|
||||
:name: amdhsa-kernel-directives-table
|
||||
|
||||
hello_world:
|
||||
======================================================== ================ ============ ===================
|
||||
Directive Default Supported On Description
|
||||
======================================================== ================ ============ ===================
|
||||
``.amdhsa_group_segment_fixed_size`` 0 GFX6-GFX9 Controls GROUP_SEGMENT_FIXED_SIZE in
|
||||
:ref:`amdgpu-amdhsa-kernel-descriptor-gfx6-gfx9-table`.
|
||||
``.amdhsa_private_segment_fixed_size`` 0 GFX6-GFX9 Controls PRIVATE_SEGMENT_FIXED_SIZE in
|
||||
:ref:`amdgpu-amdhsa-kernel-descriptor-gfx6-gfx9-table`.
|
||||
``.amdhsa_user_sgpr_private_segment_buffer`` 0 GFX6-GFX9 Controls ENABLE_SGPR_PRIVATE_SEGMENT_BUFFER in
|
||||
:ref:`amdgpu-amdhsa-kernel-descriptor-gfx6-gfx9-table`.
|
||||
``.amdhsa_user_sgpr_dispatch_ptr`` 0 GFX6-GFX9 Controls ENABLE_SGPR_DISPATCH_PTR in
|
||||
:ref:`amdgpu-amdhsa-kernel-descriptor-gfx6-gfx9-table`.
|
||||
``.amdhsa_user_sgpr_queue_ptr`` 0 GFX6-GFX9 Controls ENABLE_SGPR_QUEUE_PTR in
|
||||
:ref:`amdgpu-amdhsa-kernel-descriptor-gfx6-gfx9-table`.
|
||||
``.amdhsa_user_sgpr_kernarg_segment_ptr`` 0 GFX6-GFX9 Controls ENABLE_SGPR_KERNARG_SEGMENT_PTR in
|
||||
:ref:`amdgpu-amdhsa-kernel-descriptor-gfx6-gfx9-table`.
|
||||
``.amdhsa_user_sgpr_dispatch_id`` 0 GFX6-GFX9 Controls ENABLE_SGPR_DISPATCH_ID in
|
||||
:ref:`amdgpu-amdhsa-kernel-descriptor-gfx6-gfx9-table`.
|
||||
``.amdhsa_user_sgpr_flat_scratch_init`` 0 GFX6-GFX9 Controls ENABLE_SGPR_FLAT_SCRATCH_INIT in
|
||||
:ref:`amdgpu-amdhsa-kernel-descriptor-gfx6-gfx9-table`.
|
||||
``.amdhsa_user_sgpr_private_segment_size`` 0 GFX6-GFX9 Controls ENABLE_SGPR_PRIVATE_SEGMENT_SIZE in
|
||||
:ref:`amdgpu-amdhsa-kernel-descriptor-gfx6-gfx9-table`.
|
||||
``.amdhsa_system_sgpr_private_segment_wavefront_offset`` 0 GFX6-GFX9 Controls ENABLE_SGPR_PRIVATE_SEGMENT_WAVEFRONT_OFFSET in
|
||||
:ref:`amdgpu-amdhsa-compute_pgm_rsrc2-gfx6-gfx9-table`.
|
||||
``.amdhsa_system_sgpr_workgroup_id_x`` 1 GFX6-GFX9 Controls ENABLE_SGPR_WORKGROUP_ID_X in
|
||||
:ref:`amdgpu-amdhsa-compute_pgm_rsrc2-gfx6-gfx9-table`.
|
||||
``.amdhsa_system_sgpr_workgroup_id_y`` 0 GFX6-GFX9 Controls ENABLE_SGPR_WORKGROUP_ID_Y in
|
||||
:ref:`amdgpu-amdhsa-compute_pgm_rsrc2-gfx6-gfx9-table`.
|
||||
``.amdhsa_system_sgpr_workgroup_id_z`` 0 GFX6-GFX9 Controls ENABLE_SGPR_WORKGROUP_ID_Z in
|
||||
:ref:`amdgpu-amdhsa-compute_pgm_rsrc2-gfx6-gfx9-table`.
|
||||
``.amdhsa_system_sgpr_workgroup_info`` 0 GFX6-GFX9 Controls ENABLE_SGPR_WORKGROUP_INFO in
|
||||
:ref:`amdgpu-amdhsa-compute_pgm_rsrc2-gfx6-gfx9-table`.
|
||||
``.amdhsa_system_vgpr_workitem_id`` 0 GFX6-GFX9 Controls ENABLE_VGPR_WORKITEM_ID in
|
||||
:ref:`amdgpu-amdhsa-compute_pgm_rsrc2-gfx6-gfx9-table`.
|
||||
Possible values are defined in
|
||||
:ref:`amdgpu-amdhsa-system-vgpr-work-item-id-enumeration-values-table`.
|
||||
``.amdhsa_next_free_vgpr`` Required GFX6-GFX9 Maximum VGPR number explicitly referenced, plus one.
|
||||
Used to calculate GRANULATED_WORKITEM_VGPR_COUNT in
|
||||
:ref:`amdgpu-amdhsa-compute_pgm_rsrc1-gfx6-gfx9-table`.
|
||||
``.amdhsa_next_free_sgpr`` Required GFX6-GFX9 Maximum SGPR number explicitly referenced, plus one.
|
||||
Used to calculate GRANULATED_WAVEFRONT_SGPR_COUNT in
|
||||
:ref:`amdgpu-amdhsa-compute_pgm_rsrc1-gfx6-gfx9-table`.
|
||||
``.amdhsa_reserve_vcc`` 1 GFX6-GFX9 Whether the kernel may use the special VCC SGPR.
|
||||
Used to calculate GRANULATED_WAVEFRONT_SGPR_COUNT in
|
||||
:ref:`amdgpu-amdhsa-compute_pgm_rsrc1-gfx6-gfx9-table`.
|
||||
``.amdhsa_reserve_flat_scratch`` 1 GFX7-GFX9 Whether the kernel may use flat instructions to access
|
||||
scratch memory. Used to calculate
|
||||
GRANULATED_WAVEFRONT_SGPR_COUNT in
|
||||
:ref:`amdgpu-amdhsa-compute_pgm_rsrc1-gfx6-gfx9-table`.
|
||||
``.amdhsa_reserve_xnack_mask`` Target GFX8-GFX9 Whether the kernel may trigger XNACK replay.
|
||||
Feature Used to calculate GRANULATED_WAVEFRONT_SGPR_COUNT in
|
||||
Specific :ref:`amdgpu-amdhsa-compute_pgm_rsrc1-gfx6-gfx9-table`.
|
||||
(+xnack)
|
||||
``.amdhsa_float_round_mode_32`` 0 GFX6-GFX9 Controls FLOAT_ROUND_MODE_32 in
|
||||
:ref:`amdgpu-amdhsa-compute_pgm_rsrc1-gfx6-gfx9-table`.
|
||||
Possible values are defined in
|
||||
:ref:`amdgpu-amdhsa-floating-point-rounding-mode-enumeration-values-table`.
|
||||
``.amdhsa_float_round_mode_16_64`` 0 GFX6-GFX9 Controls FLOAT_ROUND_MODE_16_64 in
|
||||
:ref:`amdgpu-amdhsa-compute_pgm_rsrc1-gfx6-gfx9-table`.
|
||||
Possible values are defined in
|
||||
:ref:`amdgpu-amdhsa-floating-point-rounding-mode-enumeration-values-table`.
|
||||
``.amdhsa_float_denorm_mode_32`` 0 GFX6-GFX9 Controls FLOAT_DENORM_MODE_32 in
|
||||
:ref:`amdgpu-amdhsa-compute_pgm_rsrc1-gfx6-gfx9-table`.
|
||||
Possible values are defined in
|
||||
:ref:`amdgpu-amdhsa-floating-point-denorm-mode-enumeration-values-table`.
|
||||
``.amdhsa_float_denorm_mode_16_64`` 3 GFX6-GFX9 Controls FLOAT_DENORM_MODE_16_64 in
|
||||
:ref:`amdgpu-amdhsa-compute_pgm_rsrc1-gfx6-gfx9-table`.
|
||||
Possible values are defined in
|
||||
:ref:`amdgpu-amdhsa-floating-point-denorm-mode-enumeration-values-table`.
|
||||
``.amdhsa_dx10_clamp`` 1 GFX6-GFX9 Controls ENABLE_DX10_CLAMP in
|
||||
:ref:`amdgpu-amdhsa-compute_pgm_rsrc1-gfx6-gfx9-table`.
|
||||
``.amdhsa_ieee_mode`` 1 GFX6-GFX9 Controls ENABLE_IEEE_MODE in
|
||||
:ref:`amdgpu-amdhsa-compute_pgm_rsrc1-gfx6-gfx9-table`.
|
||||
``.amdhsa_fp16_overflow`` 0 GFX9 Controls FP16_OVFL in
|
||||
:ref:`amdgpu-amdhsa-compute_pgm_rsrc1-gfx6-gfx9-table`.
|
||||
``.amdhsa_exception_fp_ieee_invalid_op`` 0 GFX6-GFX9 Controls ENABLE_EXCEPTION_IEEE_754_FP_INVALID_OPERATION in
|
||||
:ref:`amdgpu-amdhsa-compute_pgm_rsrc2-gfx6-gfx9-table`.
|
||||
``.amdhsa_exception_fp_denorm_src`` 0 GFX6-GFX9 Controls ENABLE_EXCEPTION_FP_DENORMAL_SOURCE in
|
||||
:ref:`amdgpu-amdhsa-compute_pgm_rsrc2-gfx6-gfx9-table`.
|
||||
``.amdhsa_exception_fp_ieee_div_zero`` 0 GFX6-GFX9 Controls ENABLE_EXCEPTION_IEEE_754_FP_DIVISION_BY_ZERO in
|
||||
:ref:`amdgpu-amdhsa-compute_pgm_rsrc2-gfx6-gfx9-table`.
|
||||
``.amdhsa_exception_fp_ieee_overflow`` 0 GFX6-GFX9 Controls ENABLE_EXCEPTION_IEEE_754_FP_OVERFLOW in
|
||||
:ref:`amdgpu-amdhsa-compute_pgm_rsrc2-gfx6-gfx9-table`.
|
||||
``.amdhsa_exception_fp_ieee_underflow`` 0 GFX6-GFX9 Controls ENABLE_EXCEPTION_IEEE_754_FP_UNDERFLOW in
|
||||
:ref:`amdgpu-amdhsa-compute_pgm_rsrc2-gfx6-gfx9-table`.
|
||||
``.amdhsa_exception_fp_ieee_inexact`` 0 GFX6-GFX9 Controls ENABLE_EXCEPTION_IEEE_754_FP_INEXACT in
|
||||
:ref:`amdgpu-amdhsa-compute_pgm_rsrc2-gfx6-gfx9-table`.
|
||||
``.amdhsa_exception_int_div_zero`` 0 GFX6-GFX9 Controls ENABLE_EXCEPTION_INT_DIVIDE_BY_ZERO in
|
||||
:ref:`amdgpu-amdhsa-compute_pgm_rsrc2-gfx6-gfx9-table`.
|
||||
======================================================== ================ ============ ===================
|
||||
|
||||
.amd_kernel_code_t
|
||||
enable_sgpr_kernarg_segment_ptr = 1
|
||||
is_ptr64 = 1
|
||||
compute_pgm_rsrc1_vgprs = 0
|
||||
compute_pgm_rsrc1_sgprs = 0
|
||||
compute_pgm_rsrc2_user_sgpr = 2
|
||||
kernarg_segment_byte_size = 8
|
||||
wavefront_sgpr_count = 2
|
||||
workitem_vgpr_count = 3
|
||||
.end_amd_kernel_code_t
|
||||
Example HSA Source Code
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Here is an example of a minimal assembly source file, defining one HSA kernel:
|
||||
|
||||
.. code-block:: nasm
|
||||
|
||||
.amdgcn_target "amdgcn-amd-amdhsa--gfx900+xnack" // optional
|
||||
|
||||
.text
|
||||
.globl hello_world
|
||||
.p2align 8
|
||||
.type hello_world,@function
|
||||
hello_world:
|
||||
s_load_dwordx2 s[0:1], s[0:1] 0x0
|
||||
v_mov_b32 v0, 3.14159
|
||||
s_waitcnt lgkmcnt(0)
|
||||
v_mov_b32 v1, s0
|
||||
v_mov_b32 v2, s1
|
||||
flat_store_dword v[1:2], v0
|
||||
s_endpgm
|
||||
.Lfunc_end0:
|
||||
.size hello_world, .Lfunc_end0-hello_world
|
||||
|
||||
.rodata
|
||||
.p2align 6
|
||||
.amdhsa_kernel hello_world
|
||||
.amdhsa_user_sgpr_kernarg_segment_ptr 1
|
||||
.amdhsa_next_free_vgpr .amdgcn.next_free_vgpr
|
||||
.amdhsa_next_free_sgpr .amdgcn.next_free_sgpr
|
||||
.end_amdhsa_kernel
|
||||
|
||||
s_load_dwordx2 s[0:1], s[0:1] 0x0
|
||||
v_mov_b32 v0, 3.14159
|
||||
s_waitcnt lgkmcnt(0)
|
||||
v_mov_b32 v1, s0
|
||||
v_mov_b32 v2, s1
|
||||
flat_store_dword v[1:2], v0
|
||||
s_endpgm
|
||||
.Lfunc_end0:
|
||||
.size hello_world, .Lfunc_end0-hello_world
|
||||
|
||||
Additional Documentation
|
||||
========================
|
||||
|
||||
@@ -237,7 +237,14 @@ void AMDGPUAsmPrinter::EmitFunctionBodyEnd() {
|
||||
SmallString<128> KernelName;
|
||||
getNameWithPrefix(KernelName, &MF->getFunction());
|
||||
getTargetStreamer()->EmitAmdhsaKernelDescriptor(
|
||||
KernelName, getAmdhsaKernelDescriptor(*MF, CurrentProgramInfo));
|
||||
*getSTI(), KernelName, getAmdhsaKernelDescriptor(*MF, CurrentProgramInfo),
|
||||
CurrentProgramInfo.NumVGPRsForWavesPerEU,
|
||||
CurrentProgramInfo.NumSGPRsForWavesPerEU -
|
||||
IsaInfo::getNumExtraSGPRs(getSTI()->getFeatureBits(),
|
||||
CurrentProgramInfo.VCCUsed,
|
||||
CurrentProgramInfo.FlatUsed),
|
||||
CurrentProgramInfo.VCCUsed, CurrentProgramInfo.FlatUsed,
|
||||
hasXNACK(*getSTI()));
|
||||
|
||||
Streamer.PopSection();
|
||||
}
|
||||
@@ -559,30 +566,10 @@ static bool hasAnyNonFlatUseOfReg(const MachineRegisterInfo &MRI,
|
||||
return false;
|
||||
}
|
||||
|
||||
static unsigned getNumExtraSGPRs(const SISubtarget &ST,
|
||||
bool VCCUsed,
|
||||
bool FlatScrUsed) {
|
||||
unsigned ExtraSGPRs = 0;
|
||||
if (VCCUsed)
|
||||
ExtraSGPRs = 2;
|
||||
|
||||
if (ST.getGeneration() < SISubtarget::VOLCANIC_ISLANDS) {
|
||||
if (FlatScrUsed)
|
||||
ExtraSGPRs = 4;
|
||||
} else {
|
||||
if (ST.isXNACKEnabled())
|
||||
ExtraSGPRs = 4;
|
||||
|
||||
if (FlatScrUsed)
|
||||
ExtraSGPRs = 6;
|
||||
}
|
||||
|
||||
return ExtraSGPRs;
|
||||
}
|
||||
|
||||
int32_t AMDGPUAsmPrinter::SIFunctionResourceInfo::getTotalNumSGPRs(
|
||||
const SISubtarget &ST) const {
|
||||
return NumExplicitSGPR + getNumExtraSGPRs(ST, UsesVCC, UsesFlatScratch);
|
||||
return NumExplicitSGPR + IsaInfo::getNumExtraSGPRs(ST.getFeatureBits(),
|
||||
UsesVCC, UsesFlatScratch);
|
||||
}
|
||||
|
||||
AMDGPUAsmPrinter::SIFunctionResourceInfo AMDGPUAsmPrinter::analyzeResourceUsage(
|
||||
@@ -777,8 +764,9 @@ AMDGPUAsmPrinter::SIFunctionResourceInfo AMDGPUAsmPrinter::analyzeResourceUsage(
|
||||
// conservative guesses.
|
||||
|
||||
// 48 SGPRs - vcc, - flat_scr, -xnack
|
||||
int MaxSGPRGuess = 47 - getNumExtraSGPRs(ST, true,
|
||||
ST.hasFlatAddressSpace());
|
||||
int MaxSGPRGuess =
|
||||
47 - IsaInfo::getNumExtraSGPRs(ST.getFeatureBits(), true,
|
||||
ST.hasFlatAddressSpace());
|
||||
MaxSGPR = std::max(MaxSGPR, MaxSGPRGuess);
|
||||
MaxVGPR = std::max(MaxVGPR, 23);
|
||||
|
||||
@@ -838,9 +826,11 @@ void AMDGPUAsmPrinter::getSIProgramInfo(SIProgramInfo &ProgInfo,
|
||||
const SIInstrInfo *TII = STM.getInstrInfo();
|
||||
const SIRegisterInfo *RI = &TII->getRegisterInfo();
|
||||
|
||||
unsigned ExtraSGPRs = getNumExtraSGPRs(STM,
|
||||
ProgInfo.VCCUsed,
|
||||
ProgInfo.FlatUsed);
|
||||
// TODO(scott.linder): The calculations related to SGPR/VGPR blocks are
|
||||
// duplicated in part in AMDGPUAsmParser::calculateGPRBlocks, and could be
|
||||
// unified.
|
||||
unsigned ExtraSGPRs = IsaInfo::getNumExtraSGPRs(
|
||||
STM.getFeatureBits(), ProgInfo.VCCUsed, ProgInfo.FlatUsed);
|
||||
unsigned ExtraVGPRs = STM.getReservedNumVGPRs(MF);
|
||||
|
||||
// Check the addressable register limit before we add ExtraSGPRs.
|
||||
@@ -923,15 +913,10 @@ void AMDGPUAsmPrinter::getSIProgramInfo(SIProgramInfo &ProgInfo,
|
||||
Ctx.diagnose(Diag);
|
||||
}
|
||||
|
||||
// SGPRBlocks is actual number of SGPR blocks minus 1.
|
||||
ProgInfo.SGPRBlocks = alignTo(ProgInfo.NumSGPRsForWavesPerEU,
|
||||
STM.getSGPREncodingGranule());
|
||||
ProgInfo.SGPRBlocks = ProgInfo.SGPRBlocks / STM.getSGPREncodingGranule() - 1;
|
||||
|
||||
// VGPRBlocks is actual number of VGPR blocks minus 1.
|
||||
ProgInfo.VGPRBlocks = alignTo(ProgInfo.NumVGPRsForWavesPerEU,
|
||||
STM.getVGPREncodingGranule());
|
||||
ProgInfo.VGPRBlocks = ProgInfo.VGPRBlocks / STM.getVGPREncodingGranule() - 1;
|
||||
ProgInfo.SGPRBlocks = IsaInfo::getNumSGPRBlocks(
|
||||
STM.getFeatureBits(), ProgInfo.NumSGPRsForWavesPerEU);
|
||||
ProgInfo.VGPRBlocks = IsaInfo::getNumVGPRBlocks(
|
||||
STM.getFeatureBits(), ProgInfo.NumVGPRsForWavesPerEU);
|
||||
|
||||
// Record first reserved VGPR and number of reserved VGPRs.
|
||||
ProgInfo.ReservedVGPRFirst = STM.debuggerReserveRegs() ? ProgInfo.NumVGPR : 0;
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
#include "llvm/MC/MCSubtargetInfo.h"
|
||||
#include "llvm/MC/MCSymbol.h"
|
||||
#include "llvm/Support/AMDGPUMetadata.h"
|
||||
#include "llvm/Support/AMDHSAKernelDescriptor.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
@@ -61,6 +62,7 @@
|
||||
|
||||
using namespace llvm;
|
||||
using namespace llvm::AMDGPU;
|
||||
using namespace llvm::amdhsa;
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -845,6 +847,27 @@ class AMDGPUAsmParser : public MCTargetAsmParser {
|
||||
|
||||
private:
|
||||
bool ParseAsAbsoluteExpression(uint32_t &Ret);
|
||||
bool OutOfRangeError(SMRange Range);
|
||||
/// Calculate VGPR/SGPR blocks required for given target, reserved
|
||||
/// registers, and user-specified NextFreeXGPR values.
|
||||
///
|
||||
/// \param Features [in] Target features, used for bug corrections.
|
||||
/// \param VCCUsed [in] Whether VCC special SGPR is reserved.
|
||||
/// \param FlatScrUsed [in] Whether FLAT_SCRATCH special SGPR is reserved.
|
||||
/// \param XNACKUsed [in] Whether XNACK_MASK special SGPR is reserved.
|
||||
/// \param NextFreeVGPR [in] Max VGPR number referenced, plus one.
|
||||
/// \param VGPRRange [in] Token range, used for VGPR diagnostics.
|
||||
/// \param NextFreeSGPR [in] Max SGPR number referenced, plus one.
|
||||
/// \param SGPRRange [in] Token range, used for SGPR diagnostics.
|
||||
/// \param VGPRBlocks [out] Result VGPR block count.
|
||||
/// \param SGPRBlocks [out] Result SGPR block count.
|
||||
bool calculateGPRBlocks(const FeatureBitset &Features, bool VCCUsed,
|
||||
bool FlatScrUsed, bool XNACKUsed,
|
||||
unsigned NextFreeVGPR, SMRange VGPRRange,
|
||||
unsigned NextFreeSGPR, SMRange SGPRRange,
|
||||
unsigned &VGPRBlocks, unsigned &SGPRBlocks);
|
||||
bool ParseDirectiveAMDGCNTarget();
|
||||
bool ParseDirectiveAMDHSAKernel();
|
||||
bool ParseDirectiveMajorMinor(uint32_t &Major, uint32_t &Minor);
|
||||
bool ParseDirectiveHSACodeObjectVersion();
|
||||
bool ParseDirectiveHSACodeObjectISA();
|
||||
@@ -863,6 +886,10 @@ private:
|
||||
bool ParseAMDGPURegister(RegisterKind& RegKind, unsigned& Reg,
|
||||
unsigned& RegNum, unsigned& RegWidth,
|
||||
unsigned *DwordRegIndex);
|
||||
Optional<StringRef> getGprCountSymbolName(RegisterKind RegKind);
|
||||
void initializeGprCountSymbol(RegisterKind RegKind);
|
||||
bool updateGprCountSymbols(RegisterKind RegKind, unsigned DwordRegIndex,
|
||||
unsigned RegWidth);
|
||||
void cvtMubufImpl(MCInst &Inst, const OperandVector &Operands,
|
||||
bool IsAtomic, bool IsAtomicReturn, bool IsLds = false);
|
||||
void cvtDSImpl(MCInst &Inst, const OperandVector &Operands,
|
||||
@@ -896,15 +923,25 @@ public:
|
||||
AMDGPU::IsaInfo::IsaVersion ISA =
|
||||
AMDGPU::IsaInfo::getIsaVersion(getFeatureBits());
|
||||
MCContext &Ctx = getContext();
|
||||
MCSymbol *Sym =
|
||||
Ctx.getOrCreateSymbol(Twine(".option.machine_version_major"));
|
||||
Sym->setVariableValue(MCConstantExpr::create(ISA.Major, Ctx));
|
||||
Sym = Ctx.getOrCreateSymbol(Twine(".option.machine_version_minor"));
|
||||
Sym->setVariableValue(MCConstantExpr::create(ISA.Minor, Ctx));
|
||||
Sym = Ctx.getOrCreateSymbol(Twine(".option.machine_version_stepping"));
|
||||
Sym->setVariableValue(MCConstantExpr::create(ISA.Stepping, Ctx));
|
||||
if (ISA.Major >= 6 && AMDGPU::IsaInfo::hasCodeObjectV3(&getSTI())) {
|
||||
MCSymbol *Sym =
|
||||
Ctx.getOrCreateSymbol(Twine(".amdgcn.gfx_generation_number"));
|
||||
Sym->setVariableValue(MCConstantExpr::create(ISA.Major, Ctx));
|
||||
} else {
|
||||
MCSymbol *Sym =
|
||||
Ctx.getOrCreateSymbol(Twine(".option.machine_version_major"));
|
||||
Sym->setVariableValue(MCConstantExpr::create(ISA.Major, Ctx));
|
||||
Sym = Ctx.getOrCreateSymbol(Twine(".option.machine_version_minor"));
|
||||
Sym->setVariableValue(MCConstantExpr::create(ISA.Minor, Ctx));
|
||||
Sym = Ctx.getOrCreateSymbol(Twine(".option.machine_version_stepping"));
|
||||
Sym->setVariableValue(MCConstantExpr::create(ISA.Stepping, Ctx));
|
||||
}
|
||||
if (ISA.Major >= 6 && AMDGPU::IsaInfo::hasCodeObjectV3(&getSTI())) {
|
||||
initializeGprCountSymbol(IS_VGPR);
|
||||
initializeGprCountSymbol(IS_SGPR);
|
||||
} else
|
||||
KernelScope.initialize(getContext());
|
||||
}
|
||||
KernelScope.initialize(getContext());
|
||||
}
|
||||
|
||||
bool hasXNACK() const {
|
||||
@@ -1769,6 +1806,54 @@ bool AMDGPUAsmParser::ParseAMDGPURegister(RegisterKind &RegKind, unsigned &Reg,
|
||||
return true;
|
||||
}
|
||||
|
||||
Optional<StringRef>
|
||||
AMDGPUAsmParser::getGprCountSymbolName(RegisterKind RegKind) {
|
||||
switch (RegKind) {
|
||||
case IS_VGPR:
|
||||
return StringRef(".amdgcn.next_free_vgpr");
|
||||
case IS_SGPR:
|
||||
return StringRef(".amdgcn.next_free_sgpr");
|
||||
default:
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
||||
void AMDGPUAsmParser::initializeGprCountSymbol(RegisterKind RegKind) {
|
||||
auto SymbolName = getGprCountSymbolName(RegKind);
|
||||
assert(SymbolName && "initializing invalid register kind");
|
||||
MCSymbol *Sym = getContext().getOrCreateSymbol(*SymbolName);
|
||||
Sym->setVariableValue(MCConstantExpr::create(0, getContext()));
|
||||
}
|
||||
|
||||
bool AMDGPUAsmParser::updateGprCountSymbols(RegisterKind RegKind,
|
||||
unsigned DwordRegIndex,
|
||||
unsigned RegWidth) {
|
||||
// Symbols are only defined for GCN targets
|
||||
if (AMDGPU::IsaInfo::getIsaVersion(getFeatureBits()).Major < 6)
|
||||
return true;
|
||||
|
||||
auto SymbolName = getGprCountSymbolName(RegKind);
|
||||
if (!SymbolName)
|
||||
return true;
|
||||
MCSymbol *Sym = getContext().getOrCreateSymbol(*SymbolName);
|
||||
|
||||
int64_t NewMax = DwordRegIndex + RegWidth - 1;
|
||||
int64_t OldCount;
|
||||
|
||||
if (!Sym->isVariable())
|
||||
return !Error(getParser().getTok().getLoc(),
|
||||
".amdgcn.next_free_{v,s}gpr symbols must be variable");
|
||||
if (!Sym->getVariableValue(false)->evaluateAsAbsolute(OldCount))
|
||||
return !Error(
|
||||
getParser().getTok().getLoc(),
|
||||
".amdgcn.next_free_{v,s}gpr symbols must be absolute expressions");
|
||||
|
||||
if (OldCount <= NewMax)
|
||||
Sym->setVariableValue(MCConstantExpr::create(NewMax + 1, getContext()));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::unique_ptr<AMDGPUOperand> AMDGPUAsmParser::parseRegister() {
|
||||
const auto &Tok = Parser.getTok();
|
||||
SMLoc StartLoc = Tok.getLoc();
|
||||
@@ -1779,7 +1864,11 @@ std::unique_ptr<AMDGPUOperand> AMDGPUAsmParser::parseRegister() {
|
||||
if (!ParseAMDGPURegister(RegKind, Reg, RegNum, RegWidth, &DwordRegIndex)) {
|
||||
return nullptr;
|
||||
}
|
||||
KernelScope.usesRegister(RegKind, DwordRegIndex, RegWidth);
|
||||
if (AMDGPU::IsaInfo::hasCodeObjectV3(&getSTI())) {
|
||||
if (!updateGprCountSymbols(RegKind, DwordRegIndex, RegWidth))
|
||||
return nullptr;
|
||||
} else
|
||||
KernelScope.usesRegister(RegKind, DwordRegIndex, RegWidth);
|
||||
return AMDGPUOperand::CreateReg(this, Reg, StartLoc, EndLoc, false);
|
||||
}
|
||||
|
||||
@@ -2538,6 +2627,320 @@ bool AMDGPUAsmParser::ParseDirectiveMajorMinor(uint32_t &Major,
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AMDGPUAsmParser::ParseDirectiveAMDGCNTarget() {
|
||||
if (getSTI().getTargetTriple().getArch() != Triple::amdgcn)
|
||||
return TokError("directive only supported for amdgcn architecture");
|
||||
|
||||
std::string Target;
|
||||
|
||||
SMLoc TargetStart = getTok().getLoc();
|
||||
if (getParser().parseEscapedString(Target))
|
||||
return true;
|
||||
SMRange TargetRange = SMRange(TargetStart, getTok().getLoc());
|
||||
|
||||
std::string ExpectedTarget;
|
||||
raw_string_ostream ExpectedTargetOS(ExpectedTarget);
|
||||
IsaInfo::streamIsaVersion(&getSTI(), ExpectedTargetOS);
|
||||
|
||||
if (Target != ExpectedTargetOS.str())
|
||||
return getParser().Error(TargetRange.Start, "target must match options",
|
||||
TargetRange);
|
||||
|
||||
getTargetStreamer().EmitDirectiveAMDGCNTarget(Target);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AMDGPUAsmParser::OutOfRangeError(SMRange Range) {
|
||||
return getParser().Error(Range.Start, "value out of range", Range);
|
||||
}
|
||||
|
||||
bool AMDGPUAsmParser::calculateGPRBlocks(
|
||||
const FeatureBitset &Features, bool VCCUsed, bool FlatScrUsed,
|
||||
bool XNACKUsed, unsigned NextFreeVGPR, SMRange VGPRRange,
|
||||
unsigned NextFreeSGPR, SMRange SGPRRange, unsigned &VGPRBlocks,
|
||||
unsigned &SGPRBlocks) {
|
||||
// TODO(scott.linder): These calculations are duplicated from
|
||||
// AMDGPUAsmPrinter::getSIProgramInfo and could be unified.
|
||||
IsaInfo::IsaVersion Version = IsaInfo::getIsaVersion(Features);
|
||||
|
||||
unsigned NumVGPRs = NextFreeVGPR;
|
||||
unsigned NumSGPRs = NextFreeSGPR;
|
||||
unsigned MaxAddressableNumSGPRs = IsaInfo::getAddressableNumSGPRs(Features);
|
||||
|
||||
if (Version.Major >= 8 && !Features.test(FeatureSGPRInitBug) &&
|
||||
NumSGPRs > MaxAddressableNumSGPRs)
|
||||
return OutOfRangeError(SGPRRange);
|
||||
|
||||
NumSGPRs +=
|
||||
IsaInfo::getNumExtraSGPRs(Features, VCCUsed, FlatScrUsed, XNACKUsed);
|
||||
|
||||
if ((Version.Major <= 7 || Features.test(FeatureSGPRInitBug)) &&
|
||||
NumSGPRs > MaxAddressableNumSGPRs)
|
||||
return OutOfRangeError(SGPRRange);
|
||||
|
||||
if (Features.test(FeatureSGPRInitBug))
|
||||
NumSGPRs = IsaInfo::FIXED_NUM_SGPRS_FOR_INIT_BUG;
|
||||
|
||||
VGPRBlocks = IsaInfo::getNumVGPRBlocks(Features, NumVGPRs);
|
||||
SGPRBlocks = IsaInfo::getNumSGPRBlocks(Features, NumSGPRs);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AMDGPUAsmParser::ParseDirectiveAMDHSAKernel() {
|
||||
if (getSTI().getTargetTriple().getArch() != Triple::amdgcn)
|
||||
return TokError("directive only supported for amdgcn architecture");
|
||||
|
||||
if (getSTI().getTargetTriple().getOS() != Triple::AMDHSA)
|
||||
return TokError("directive only supported for amdhsa OS");
|
||||
|
||||
StringRef KernelName;
|
||||
if (getParser().parseIdentifier(KernelName))
|
||||
return true;
|
||||
|
||||
kernel_descriptor_t KD = getDefaultAmdhsaKernelDescriptor();
|
||||
|
||||
StringSet<> Seen;
|
||||
|
||||
IsaInfo::IsaVersion IVersion =
|
||||
IsaInfo::getIsaVersion(getSTI().getFeatureBits());
|
||||
|
||||
SMRange VGPRRange;
|
||||
uint64_t NextFreeVGPR = 0;
|
||||
SMRange SGPRRange;
|
||||
uint64_t NextFreeSGPR = 0;
|
||||
unsigned UserSGPRCount = 0;
|
||||
bool ReserveVCC = true;
|
||||
bool ReserveFlatScr = true;
|
||||
bool ReserveXNACK = hasXNACK();
|
||||
|
||||
while (true) {
|
||||
while (getLexer().is(AsmToken::EndOfStatement))
|
||||
Lex();
|
||||
|
||||
if (getLexer().isNot(AsmToken::Identifier))
|
||||
return TokError("expected .amdhsa_ directive or .end_amdhsa_kernel");
|
||||
|
||||
StringRef ID = getTok().getIdentifier();
|
||||
SMRange IDRange = getTok().getLocRange();
|
||||
Lex();
|
||||
|
||||
if (ID == ".end_amdhsa_kernel")
|
||||
break;
|
||||
|
||||
if (Seen.find(ID) != Seen.end())
|
||||
return TokError(".amdhsa_ directives cannot be repeated");
|
||||
Seen.insert(ID);
|
||||
|
||||
SMLoc ValStart = getTok().getLoc();
|
||||
int64_t IVal;
|
||||
if (getParser().parseAbsoluteExpression(IVal))
|
||||
return true;
|
||||
SMLoc ValEnd = getTok().getLoc();
|
||||
SMRange ValRange = SMRange(ValStart, ValEnd);
|
||||
|
||||
if (IVal < 0)
|
||||
return OutOfRangeError(ValRange);
|
||||
|
||||
uint64_t Val = IVal;
|
||||
|
||||
#define PARSE_BITS_ENTRY(FIELD, ENTRY, VALUE, RANGE) \
|
||||
if (!isUInt<ENTRY##_WIDTH>(VALUE)) \
|
||||
return OutOfRangeError(RANGE); \
|
||||
AMDHSA_BITS_SET(FIELD, ENTRY, VALUE);
|
||||
|
||||
if (ID == ".amdhsa_group_segment_fixed_size") {
|
||||
if (!isUInt<sizeof(KD.group_segment_fixed_size) * CHAR_BIT>(Val))
|
||||
return OutOfRangeError(ValRange);
|
||||
KD.group_segment_fixed_size = Val;
|
||||
} else if (ID == ".amdhsa_private_segment_fixed_size") {
|
||||
if (!isUInt<sizeof(KD.private_segment_fixed_size) * CHAR_BIT>(Val))
|
||||
return OutOfRangeError(ValRange);
|
||||
KD.private_segment_fixed_size = Val;
|
||||
} else if (ID == ".amdhsa_user_sgpr_private_segment_buffer") {
|
||||
PARSE_BITS_ENTRY(KD.kernel_code_properties,
|
||||
KERNEL_CODE_PROPERTY_ENABLE_SGPR_PRIVATE_SEGMENT_BUFFER,
|
||||
Val, ValRange);
|
||||
UserSGPRCount++;
|
||||
} else if (ID == ".amdhsa_user_sgpr_dispatch_ptr") {
|
||||
PARSE_BITS_ENTRY(KD.kernel_code_properties,
|
||||
KERNEL_CODE_PROPERTY_ENABLE_SGPR_DISPATCH_PTR, Val,
|
||||
ValRange);
|
||||
UserSGPRCount++;
|
||||
} else if (ID == ".amdhsa_user_sgpr_queue_ptr") {
|
||||
PARSE_BITS_ENTRY(KD.kernel_code_properties,
|
||||
KERNEL_CODE_PROPERTY_ENABLE_SGPR_QUEUE_PTR, Val,
|
||||
ValRange);
|
||||
UserSGPRCount++;
|
||||
} else if (ID == ".amdhsa_user_sgpr_kernarg_segment_ptr") {
|
||||
PARSE_BITS_ENTRY(KD.kernel_code_properties,
|
||||
KERNEL_CODE_PROPERTY_ENABLE_SGPR_KERNARG_SEGMENT_PTR,
|
||||
Val, ValRange);
|
||||
UserSGPRCount++;
|
||||
} else if (ID == ".amdhsa_user_sgpr_dispatch_id") {
|
||||
PARSE_BITS_ENTRY(KD.kernel_code_properties,
|
||||
KERNEL_CODE_PROPERTY_ENABLE_SGPR_DISPATCH_ID, Val,
|
||||
ValRange);
|
||||
UserSGPRCount++;
|
||||
} else if (ID == ".amdhsa_user_sgpr_flat_scratch_init") {
|
||||
PARSE_BITS_ENTRY(KD.kernel_code_properties,
|
||||
KERNEL_CODE_PROPERTY_ENABLE_SGPR_FLAT_SCRATCH_INIT, Val,
|
||||
ValRange);
|
||||
UserSGPRCount++;
|
||||
} else if (ID == ".amdhsa_user_sgpr_private_segment_size") {
|
||||
PARSE_BITS_ENTRY(KD.kernel_code_properties,
|
||||
KERNEL_CODE_PROPERTY_ENABLE_SGPR_PRIVATE_SEGMENT_SIZE,
|
||||
Val, ValRange);
|
||||
UserSGPRCount++;
|
||||
} else if (ID == ".amdhsa_system_sgpr_private_segment_wavefront_offset") {
|
||||
PARSE_BITS_ENTRY(
|
||||
KD.compute_pgm_rsrc2,
|
||||
COMPUTE_PGM_RSRC2_ENABLE_SGPR_PRIVATE_SEGMENT_WAVEFRONT_OFFSET, Val,
|
||||
ValRange);
|
||||
} else if (ID == ".amdhsa_system_sgpr_workgroup_id_x") {
|
||||
PARSE_BITS_ENTRY(KD.compute_pgm_rsrc2,
|
||||
COMPUTE_PGM_RSRC2_ENABLE_SGPR_WORKGROUP_ID_X, Val,
|
||||
ValRange);
|
||||
} else if (ID == ".amdhsa_system_sgpr_workgroup_id_y") {
|
||||
PARSE_BITS_ENTRY(KD.compute_pgm_rsrc2,
|
||||
COMPUTE_PGM_RSRC2_ENABLE_SGPR_WORKGROUP_ID_Y, Val,
|
||||
ValRange);
|
||||
} else if (ID == ".amdhsa_system_sgpr_workgroup_id_z") {
|
||||
PARSE_BITS_ENTRY(KD.compute_pgm_rsrc2,
|
||||
COMPUTE_PGM_RSRC2_ENABLE_SGPR_WORKGROUP_ID_Z, Val,
|
||||
ValRange);
|
||||
} else if (ID == ".amdhsa_system_sgpr_workgroup_info") {
|
||||
PARSE_BITS_ENTRY(KD.compute_pgm_rsrc2,
|
||||
COMPUTE_PGM_RSRC2_ENABLE_SGPR_WORKGROUP_INFO, Val,
|
||||
ValRange);
|
||||
} else if (ID == ".amdhsa_system_vgpr_workitem_id") {
|
||||
PARSE_BITS_ENTRY(KD.compute_pgm_rsrc2,
|
||||
COMPUTE_PGM_RSRC2_ENABLE_VGPR_WORKITEM_ID, Val,
|
||||
ValRange);
|
||||
} else if (ID == ".amdhsa_next_free_vgpr") {
|
||||
VGPRRange = ValRange;
|
||||
NextFreeVGPR = Val;
|
||||
} else if (ID == ".amdhsa_next_free_sgpr") {
|
||||
SGPRRange = ValRange;
|
||||
NextFreeSGPR = Val;
|
||||
} else if (ID == ".amdhsa_reserve_vcc") {
|
||||
if (!isUInt<1>(Val))
|
||||
return OutOfRangeError(ValRange);
|
||||
ReserveVCC = Val;
|
||||
} else if (ID == ".amdhsa_reserve_flat_scratch") {
|
||||
if (IVersion.Major < 7)
|
||||
return getParser().Error(IDRange.Start, "directive requires gfx7+",
|
||||
IDRange);
|
||||
if (!isUInt<1>(Val))
|
||||
return OutOfRangeError(ValRange);
|
||||
ReserveFlatScr = Val;
|
||||
} else if (ID == ".amdhsa_reserve_xnack_mask") {
|
||||
if (IVersion.Major < 8)
|
||||
return getParser().Error(IDRange.Start, "directive requires gfx8+",
|
||||
IDRange);
|
||||
if (!isUInt<1>(Val))
|
||||
return OutOfRangeError(ValRange);
|
||||
ReserveXNACK = Val;
|
||||
} else if (ID == ".amdhsa_float_round_mode_32") {
|
||||
PARSE_BITS_ENTRY(KD.compute_pgm_rsrc1,
|
||||
COMPUTE_PGM_RSRC1_FLOAT_ROUND_MODE_32, Val, ValRange);
|
||||
} else if (ID == ".amdhsa_float_round_mode_16_64") {
|
||||
PARSE_BITS_ENTRY(KD.compute_pgm_rsrc1,
|
||||
COMPUTE_PGM_RSRC1_FLOAT_ROUND_MODE_16_64, Val, ValRange);
|
||||
} else if (ID == ".amdhsa_float_denorm_mode_32") {
|
||||
PARSE_BITS_ENTRY(KD.compute_pgm_rsrc1,
|
||||
COMPUTE_PGM_RSRC1_FLOAT_DENORM_MODE_32, Val, ValRange);
|
||||
} else if (ID == ".amdhsa_float_denorm_mode_16_64") {
|
||||
PARSE_BITS_ENTRY(KD.compute_pgm_rsrc1,
|
||||
COMPUTE_PGM_RSRC1_FLOAT_DENORM_MODE_16_64, Val,
|
||||
ValRange);
|
||||
} else if (ID == ".amdhsa_dx10_clamp") {
|
||||
PARSE_BITS_ENTRY(KD.compute_pgm_rsrc1,
|
||||
COMPUTE_PGM_RSRC1_ENABLE_DX10_CLAMP, Val, ValRange);
|
||||
} else if (ID == ".amdhsa_ieee_mode") {
|
||||
PARSE_BITS_ENTRY(KD.compute_pgm_rsrc1, COMPUTE_PGM_RSRC1_ENABLE_IEEE_MODE,
|
||||
Val, ValRange);
|
||||
} else if (ID == ".amdhsa_fp16_overflow") {
|
||||
if (IVersion.Major < 9)
|
||||
return getParser().Error(IDRange.Start, "directive requires gfx9+",
|
||||
IDRange);
|
||||
PARSE_BITS_ENTRY(KD.compute_pgm_rsrc1, COMPUTE_PGM_RSRC1_FP16_OVFL, Val,
|
||||
ValRange);
|
||||
} else if (ID == ".amdhsa_exception_fp_ieee_invalid_op") {
|
||||
PARSE_BITS_ENTRY(
|
||||
KD.compute_pgm_rsrc2,
|
||||
COMPUTE_PGM_RSRC2_ENABLE_EXCEPTION_IEEE_754_FP_INVALID_OPERATION, Val,
|
||||
ValRange);
|
||||
} else if (ID == ".amdhsa_exception_fp_denorm_src") {
|
||||
PARSE_BITS_ENTRY(KD.compute_pgm_rsrc2,
|
||||
COMPUTE_PGM_RSRC2_ENABLE_EXCEPTION_FP_DENORMAL_SOURCE,
|
||||
Val, ValRange);
|
||||
} else if (ID == ".amdhsa_exception_fp_ieee_div_zero") {
|
||||
PARSE_BITS_ENTRY(
|
||||
KD.compute_pgm_rsrc2,
|
||||
COMPUTE_PGM_RSRC2_ENABLE_EXCEPTION_IEEE_754_FP_DIVISION_BY_ZERO, Val,
|
||||
ValRange);
|
||||
} else if (ID == ".amdhsa_exception_fp_ieee_overflow") {
|
||||
PARSE_BITS_ENTRY(KD.compute_pgm_rsrc2,
|
||||
COMPUTE_PGM_RSRC2_ENABLE_EXCEPTION_IEEE_754_FP_OVERFLOW,
|
||||
Val, ValRange);
|
||||
} else if (ID == ".amdhsa_exception_fp_ieee_underflow") {
|
||||
PARSE_BITS_ENTRY(KD.compute_pgm_rsrc2,
|
||||
COMPUTE_PGM_RSRC2_ENABLE_EXCEPTION_IEEE_754_FP_UNDERFLOW,
|
||||
Val, ValRange);
|
||||
} else if (ID == ".amdhsa_exception_fp_ieee_inexact") {
|
||||
PARSE_BITS_ENTRY(KD.compute_pgm_rsrc2,
|
||||
COMPUTE_PGM_RSRC2_ENABLE_EXCEPTION_IEEE_754_FP_INEXACT,
|
||||
Val, ValRange);
|
||||
} else if (ID == ".amdhsa_exception_int_div_zero") {
|
||||
PARSE_BITS_ENTRY(KD.compute_pgm_rsrc2,
|
||||
COMPUTE_PGM_RSRC2_ENABLE_EXCEPTION_INT_DIVIDE_BY_ZERO,
|
||||
Val, ValRange);
|
||||
} else {
|
||||
return getParser().Error(IDRange.Start,
|
||||
"unknown .amdhsa_kernel directive", IDRange);
|
||||
}
|
||||
|
||||
#undef PARSE_BITS_ENTRY
|
||||
}
|
||||
|
||||
if (Seen.find(".amdhsa_next_free_vgpr") == Seen.end())
|
||||
return TokError(".amdhsa_next_free_vgpr directive is required");
|
||||
|
||||
if (Seen.find(".amdhsa_next_free_sgpr") == Seen.end())
|
||||
return TokError(".amdhsa_next_free_sgpr directive is required");
|
||||
|
||||
unsigned VGPRBlocks;
|
||||
unsigned SGPRBlocks;
|
||||
if (calculateGPRBlocks(getFeatureBits(), ReserveVCC, ReserveFlatScr,
|
||||
ReserveXNACK, NextFreeVGPR, VGPRRange, NextFreeSGPR,
|
||||
SGPRRange, VGPRBlocks, SGPRBlocks))
|
||||
return true;
|
||||
|
||||
if (!isUInt<COMPUTE_PGM_RSRC1_GRANULATED_WORKITEM_VGPR_COUNT_WIDTH>(
|
||||
VGPRBlocks))
|
||||
return OutOfRangeError(VGPRRange);
|
||||
AMDHSA_BITS_SET(KD.compute_pgm_rsrc1,
|
||||
COMPUTE_PGM_RSRC1_GRANULATED_WORKITEM_VGPR_COUNT, VGPRBlocks);
|
||||
|
||||
if (!isUInt<COMPUTE_PGM_RSRC1_GRANULATED_WAVEFRONT_SGPR_COUNT_WIDTH>(
|
||||
SGPRBlocks))
|
||||
return OutOfRangeError(SGPRRange);
|
||||
AMDHSA_BITS_SET(KD.compute_pgm_rsrc1,
|
||||
COMPUTE_PGM_RSRC1_GRANULATED_WAVEFRONT_SGPR_COUNT,
|
||||
SGPRBlocks);
|
||||
|
||||
if (!isUInt<COMPUTE_PGM_RSRC2_USER_SGPR_COUNT_WIDTH>(UserSGPRCount))
|
||||
return TokError("too many user SGPRs enabled");
|
||||
AMDHSA_BITS_SET(KD.compute_pgm_rsrc2, COMPUTE_PGM_RSRC2_USER_SGPR_COUNT,
|
||||
UserSGPRCount);
|
||||
|
||||
getTargetStreamer().EmitAmdhsaKernelDescriptor(
|
||||
getSTI(), KernelName, KD, NextFreeVGPR, NextFreeSGPR, ReserveVCC,
|
||||
ReserveFlatScr, ReserveXNACK);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AMDGPUAsmParser::ParseDirectiveHSACodeObjectVersion() {
|
||||
uint32_t Major;
|
||||
uint32_t Minor;
|
||||
@@ -2657,7 +3060,8 @@ bool AMDGPUAsmParser::ParseDirectiveAMDGPUHsaKernel() {
|
||||
getTargetStreamer().EmitAMDGPUSymbolType(KernelName,
|
||||
ELF::STT_AMDGPU_HSA_KERNEL);
|
||||
Lex();
|
||||
KernelScope.initialize(getContext());
|
||||
if (!AMDGPU::IsaInfo::hasCodeObjectV3(&getSTI()))
|
||||
KernelScope.initialize(getContext());
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -2761,20 +3165,28 @@ bool AMDGPUAsmParser::ParseDirectivePALMetadata() {
|
||||
bool AMDGPUAsmParser::ParseDirective(AsmToken DirectiveID) {
|
||||
StringRef IDVal = DirectiveID.getString();
|
||||
|
||||
if (IDVal == ".hsa_code_object_version")
|
||||
return ParseDirectiveHSACodeObjectVersion();
|
||||
if (AMDGPU::IsaInfo::hasCodeObjectV3(&getSTI())) {
|
||||
if (IDVal == ".amdgcn_target")
|
||||
return ParseDirectiveAMDGCNTarget();
|
||||
|
||||
if (IDVal == ".hsa_code_object_isa")
|
||||
return ParseDirectiveHSACodeObjectISA();
|
||||
if (IDVal == ".amdhsa_kernel")
|
||||
return ParseDirectiveAMDHSAKernel();
|
||||
} else {
|
||||
if (IDVal == ".hsa_code_object_version")
|
||||
return ParseDirectiveHSACodeObjectVersion();
|
||||
|
||||
if (IDVal == ".amd_kernel_code_t")
|
||||
return ParseDirectiveAMDKernelCodeT();
|
||||
if (IDVal == ".hsa_code_object_isa")
|
||||
return ParseDirectiveHSACodeObjectISA();
|
||||
|
||||
if (IDVal == ".amdgpu_hsa_kernel")
|
||||
return ParseDirectiveAMDGPUHsaKernel();
|
||||
if (IDVal == ".amd_kernel_code_t")
|
||||
return ParseDirectiveAMDKernelCodeT();
|
||||
|
||||
if (IDVal == ".amd_amdgpu_isa")
|
||||
return ParseDirectiveISAVersion();
|
||||
if (IDVal == ".amdgpu_hsa_kernel")
|
||||
return ParseDirectiveAMDGPUHsaKernel();
|
||||
|
||||
if (IDVal == ".amd_amdgpu_isa")
|
||||
return ParseDirectiveISAVersion();
|
||||
}
|
||||
|
||||
if (IDVal == AMDGPU::HSAMD::AssemblerDirectiveBegin)
|
||||
return ParseDirectiveHSAMetadata();
|
||||
|
||||
@@ -133,9 +133,12 @@ AMDGPUTargetAsmStreamer::AMDGPUTargetAsmStreamer(MCStreamer &S,
|
||||
formatted_raw_ostream &OS)
|
||||
: AMDGPUTargetStreamer(S), OS(OS) { }
|
||||
|
||||
void
|
||||
AMDGPUTargetAsmStreamer::EmitDirectiveHSACodeObjectVersion(uint32_t Major,
|
||||
uint32_t Minor) {
|
||||
void AMDGPUTargetAsmStreamer::EmitDirectiveAMDGCNTarget(StringRef Target) {
|
||||
OS << "\t.amdgcn_target \"" << Target << "\"\n";
|
||||
}
|
||||
|
||||
void AMDGPUTargetAsmStreamer::EmitDirectiveHSACodeObjectVersion(
|
||||
uint32_t Major, uint32_t Minor) {
|
||||
OS << "\t.hsa_code_object_version " <<
|
||||
Twine(Major) << "," << Twine(Minor) << '\n';
|
||||
}
|
||||
@@ -197,9 +200,135 @@ bool AMDGPUTargetAsmStreamer::EmitPALMetadata(
|
||||
}
|
||||
|
||||
void AMDGPUTargetAsmStreamer::EmitAmdhsaKernelDescriptor(
|
||||
StringRef KernelName,
|
||||
const amdhsa::kernel_descriptor_t &KernelDescriptor) {
|
||||
// FIXME: not supported yet.
|
||||
const MCSubtargetInfo &STI, StringRef KernelName,
|
||||
const amdhsa::kernel_descriptor_t &KD, uint64_t NextVGPR, uint64_t NextSGPR,
|
||||
bool ReserveVCC, bool ReserveFlatScr, bool ReserveXNACK) {
|
||||
amdhsa::kernel_descriptor_t DefaultKD = getDefaultAmdhsaKernelDescriptor();
|
||||
|
||||
IsaInfo::IsaVersion IVersion = IsaInfo::getIsaVersion(STI.getFeatureBits());
|
||||
|
||||
OS << "\t.amdhsa_kernel " << KernelName << '\n';
|
||||
|
||||
#define PRINT_IF_NOT_DEFAULT(STREAM, DIRECTIVE, KERNEL_DESC, \
|
||||
DEFAULT_KERNEL_DESC, MEMBER_NAME, FIELD_NAME) \
|
||||
if (AMDHSA_BITS_GET(KERNEL_DESC.MEMBER_NAME, FIELD_NAME) != \
|
||||
AMDHSA_BITS_GET(DEFAULT_KERNEL_DESC.MEMBER_NAME, FIELD_NAME)) \
|
||||
STREAM << "\t\t" << DIRECTIVE << " " \
|
||||
<< AMDHSA_BITS_GET(KERNEL_DESC.MEMBER_NAME, FIELD_NAME) << '\n';
|
||||
|
||||
if (KD.group_segment_fixed_size != DefaultKD.group_segment_fixed_size)
|
||||
OS << "\t\t.amdhsa_group_segment_fixed_size " << KD.group_segment_fixed_size
|
||||
<< '\n';
|
||||
if (KD.private_segment_fixed_size != DefaultKD.private_segment_fixed_size)
|
||||
OS << "\t\t.amdhsa_private_segment_fixed_size "
|
||||
<< KD.private_segment_fixed_size << '\n';
|
||||
|
||||
PRINT_IF_NOT_DEFAULT(
|
||||
OS, ".amdhsa_user_sgpr_private_segment_buffer", KD, DefaultKD,
|
||||
kernel_code_properties,
|
||||
amdhsa::KERNEL_CODE_PROPERTY_ENABLE_SGPR_PRIVATE_SEGMENT_BUFFER);
|
||||
PRINT_IF_NOT_DEFAULT(OS, ".amdhsa_user_sgpr_dispatch_ptr", KD, DefaultKD,
|
||||
kernel_code_properties,
|
||||
amdhsa::KERNEL_CODE_PROPERTY_ENABLE_SGPR_DISPATCH_PTR);
|
||||
PRINT_IF_NOT_DEFAULT(OS, ".amdhsa_user_sgpr_queue_ptr", KD, DefaultKD,
|
||||
kernel_code_properties,
|
||||
amdhsa::KERNEL_CODE_PROPERTY_ENABLE_SGPR_QUEUE_PTR);
|
||||
PRINT_IF_NOT_DEFAULT(
|
||||
OS, ".amdhsa_user_sgpr_kernarg_segment_ptr", KD, DefaultKD,
|
||||
kernel_code_properties,
|
||||
amdhsa::KERNEL_CODE_PROPERTY_ENABLE_SGPR_KERNARG_SEGMENT_PTR);
|
||||
PRINT_IF_NOT_DEFAULT(OS, ".amdhsa_user_sgpr_dispatch_id", KD, DefaultKD,
|
||||
kernel_code_properties,
|
||||
amdhsa::KERNEL_CODE_PROPERTY_ENABLE_SGPR_DISPATCH_ID);
|
||||
PRINT_IF_NOT_DEFAULT(
|
||||
OS, ".amdhsa_user_sgpr_flat_scratch_init", KD, DefaultKD,
|
||||
kernel_code_properties,
|
||||
amdhsa::KERNEL_CODE_PROPERTY_ENABLE_SGPR_FLAT_SCRATCH_INIT);
|
||||
PRINT_IF_NOT_DEFAULT(
|
||||
OS, ".amdhsa_user_sgpr_private_segment_size", KD, DefaultKD,
|
||||
kernel_code_properties,
|
||||
amdhsa::KERNEL_CODE_PROPERTY_ENABLE_SGPR_PRIVATE_SEGMENT_SIZE);
|
||||
PRINT_IF_NOT_DEFAULT(
|
||||
OS, ".amdhsa_system_sgpr_private_segment_wavefront_offset", KD, DefaultKD,
|
||||
compute_pgm_rsrc2,
|
||||
amdhsa::COMPUTE_PGM_RSRC2_ENABLE_SGPR_PRIVATE_SEGMENT_WAVEFRONT_OFFSET);
|
||||
PRINT_IF_NOT_DEFAULT(OS, ".amdhsa_system_sgpr_workgroup_id_x", KD, DefaultKD,
|
||||
compute_pgm_rsrc2,
|
||||
amdhsa::COMPUTE_PGM_RSRC2_ENABLE_SGPR_WORKGROUP_ID_X);
|
||||
PRINT_IF_NOT_DEFAULT(OS, ".amdhsa_system_sgpr_workgroup_id_y", KD, DefaultKD,
|
||||
compute_pgm_rsrc2,
|
||||
amdhsa::COMPUTE_PGM_RSRC2_ENABLE_SGPR_WORKGROUP_ID_Y);
|
||||
PRINT_IF_NOT_DEFAULT(OS, ".amdhsa_system_sgpr_workgroup_id_z", KD, DefaultKD,
|
||||
compute_pgm_rsrc2,
|
||||
amdhsa::COMPUTE_PGM_RSRC2_ENABLE_SGPR_WORKGROUP_ID_Z);
|
||||
PRINT_IF_NOT_DEFAULT(OS, ".amdhsa_system_sgpr_workgroup_info", KD, DefaultKD,
|
||||
compute_pgm_rsrc2,
|
||||
amdhsa::COMPUTE_PGM_RSRC2_ENABLE_SGPR_WORKGROUP_INFO);
|
||||
PRINT_IF_NOT_DEFAULT(OS, ".amdhsa_system_vgpr_workitem_id", KD, DefaultKD,
|
||||
compute_pgm_rsrc2,
|
||||
amdhsa::COMPUTE_PGM_RSRC2_ENABLE_VGPR_WORKITEM_ID);
|
||||
|
||||
// These directives are required.
|
||||
OS << "\t\t.amdhsa_next_free_vgpr " << NextVGPR << '\n';
|
||||
OS << "\t\t.amdhsa_next_free_sgpr " << NextSGPR << '\n';
|
||||
|
||||
if (!ReserveVCC)
|
||||
OS << "\t\t.amdhsa_reserve_vcc " << ReserveVCC << '\n';
|
||||
if (IVersion.Major >= 7 && !ReserveFlatScr)
|
||||
OS << "\t\t.amdhsa_reserve_flat_scratch " << ReserveFlatScr << '\n';
|
||||
if (IVersion.Major >= 8 && ReserveXNACK != hasXNACK(STI))
|
||||
OS << "\t\t.amdhsa_reserve_xnack_mask " << ReserveXNACK << '\n';
|
||||
|
||||
PRINT_IF_NOT_DEFAULT(OS, ".amdhsa_float_round_mode_32", KD, DefaultKD,
|
||||
compute_pgm_rsrc1,
|
||||
amdhsa::COMPUTE_PGM_RSRC1_FLOAT_ROUND_MODE_32);
|
||||
PRINT_IF_NOT_DEFAULT(OS, ".amdhsa_float_round_mode_16_64", KD, DefaultKD,
|
||||
compute_pgm_rsrc1,
|
||||
amdhsa::COMPUTE_PGM_RSRC1_FLOAT_ROUND_MODE_16_64);
|
||||
PRINT_IF_NOT_DEFAULT(OS, ".amdhsa_float_denorm_mode_32", KD, DefaultKD,
|
||||
compute_pgm_rsrc1,
|
||||
amdhsa::COMPUTE_PGM_RSRC1_FLOAT_DENORM_MODE_32);
|
||||
PRINT_IF_NOT_DEFAULT(OS, ".amdhsa_float_denorm_mode_16_64", KD, DefaultKD,
|
||||
compute_pgm_rsrc1,
|
||||
amdhsa::COMPUTE_PGM_RSRC1_FLOAT_DENORM_MODE_16_64);
|
||||
PRINT_IF_NOT_DEFAULT(OS, ".amdhsa_dx10_clamp", KD, DefaultKD,
|
||||
compute_pgm_rsrc1,
|
||||
amdhsa::COMPUTE_PGM_RSRC1_ENABLE_DX10_CLAMP);
|
||||
PRINT_IF_NOT_DEFAULT(OS, ".amdhsa_ieee_mode", KD, DefaultKD,
|
||||
compute_pgm_rsrc1,
|
||||
amdhsa::COMPUTE_PGM_RSRC1_ENABLE_IEEE_MODE);
|
||||
if (IVersion.Major >= 9)
|
||||
PRINT_IF_NOT_DEFAULT(OS, ".amdhsa_fp16_overflow", KD, DefaultKD,
|
||||
compute_pgm_rsrc1,
|
||||
amdhsa::COMPUTE_PGM_RSRC1_FP16_OVFL);
|
||||
PRINT_IF_NOT_DEFAULT(
|
||||
OS, ".amdhsa_exception_fp_ieee_invalid_op", KD, DefaultKD,
|
||||
compute_pgm_rsrc2,
|
||||
amdhsa::COMPUTE_PGM_RSRC2_ENABLE_EXCEPTION_IEEE_754_FP_INVALID_OPERATION);
|
||||
PRINT_IF_NOT_DEFAULT(
|
||||
OS, ".amdhsa_exception_fp_denorm_src", KD, DefaultKD, compute_pgm_rsrc2,
|
||||
amdhsa::COMPUTE_PGM_RSRC2_ENABLE_EXCEPTION_FP_DENORMAL_SOURCE);
|
||||
PRINT_IF_NOT_DEFAULT(
|
||||
OS, ".amdhsa_exception_fp_ieee_div_zero", KD, DefaultKD,
|
||||
compute_pgm_rsrc2,
|
||||
amdhsa::COMPUTE_PGM_RSRC2_ENABLE_EXCEPTION_IEEE_754_FP_DIVISION_BY_ZERO);
|
||||
PRINT_IF_NOT_DEFAULT(
|
||||
OS, ".amdhsa_exception_fp_ieee_overflow", KD, DefaultKD,
|
||||
compute_pgm_rsrc2,
|
||||
amdhsa::COMPUTE_PGM_RSRC2_ENABLE_EXCEPTION_IEEE_754_FP_OVERFLOW);
|
||||
PRINT_IF_NOT_DEFAULT(
|
||||
OS, ".amdhsa_exception_fp_ieee_underflow", KD, DefaultKD,
|
||||
compute_pgm_rsrc2,
|
||||
amdhsa::COMPUTE_PGM_RSRC2_ENABLE_EXCEPTION_IEEE_754_FP_UNDERFLOW);
|
||||
PRINT_IF_NOT_DEFAULT(
|
||||
OS, ".amdhsa_exception_fp_ieee_inexact", KD, DefaultKD, compute_pgm_rsrc2,
|
||||
amdhsa::COMPUTE_PGM_RSRC2_ENABLE_EXCEPTION_IEEE_754_FP_INEXACT);
|
||||
PRINT_IF_NOT_DEFAULT(
|
||||
OS, ".amdhsa_exception_int_div_zero", KD, DefaultKD, compute_pgm_rsrc2,
|
||||
amdhsa::COMPUTE_PGM_RSRC2_ENABLE_EXCEPTION_INT_DIVIDE_BY_ZERO);
|
||||
#undef PRINT_IF_NOT_DEFAULT
|
||||
|
||||
OS << "\t.end_amdhsa_kernel\n";
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
@@ -247,9 +376,10 @@ void AMDGPUTargetELFStreamer::EmitAMDGPUNote(
|
||||
S.PopSection();
|
||||
}
|
||||
|
||||
void
|
||||
AMDGPUTargetELFStreamer::EmitDirectiveHSACodeObjectVersion(uint32_t Major,
|
||||
uint32_t Minor) {
|
||||
void AMDGPUTargetELFStreamer::EmitDirectiveAMDGCNTarget(StringRef Target) {}
|
||||
|
||||
void AMDGPUTargetELFStreamer::EmitDirectiveHSACodeObjectVersion(
|
||||
uint32_t Major, uint32_t Minor) {
|
||||
|
||||
EmitAMDGPUNote(
|
||||
MCConstantExpr::create(8, getContext()),
|
||||
@@ -370,8 +500,10 @@ bool AMDGPUTargetELFStreamer::EmitPALMetadata(
|
||||
}
|
||||
|
||||
void AMDGPUTargetELFStreamer::EmitAmdhsaKernelDescriptor(
|
||||
StringRef KernelName,
|
||||
const amdhsa::kernel_descriptor_t &KernelDescriptor) {
|
||||
const MCSubtargetInfo &STI, StringRef KernelName,
|
||||
const amdhsa::kernel_descriptor_t &KernelDescriptor, uint64_t NextVGPR,
|
||||
uint64_t NextSGPR, bool ReserveVCC, bool ReserveFlatScr,
|
||||
bool ReserveXNACK) {
|
||||
auto &Streamer = getStreamer();
|
||||
auto &Context = Streamer.getContext();
|
||||
|
||||
|
||||
@@ -40,6 +40,8 @@ public:
|
||||
|
||||
AMDGPUTargetStreamer(MCStreamer &S) : MCTargetStreamer(S) {}
|
||||
|
||||
virtual void EmitDirectiveAMDGCNTarget(StringRef Target) = 0;
|
||||
|
||||
virtual void EmitDirectiveHSACodeObjectVersion(uint32_t Major,
|
||||
uint32_t Minor) = 0;
|
||||
|
||||
@@ -65,14 +67,19 @@ public:
|
||||
virtual bool EmitPALMetadata(const AMDGPU::PALMD::Metadata &PALMetadata) = 0;
|
||||
|
||||
virtual void EmitAmdhsaKernelDescriptor(
|
||||
StringRef KernelName,
|
||||
const amdhsa::kernel_descriptor_t &KernelDescriptor) = 0;
|
||||
const MCSubtargetInfo &STI, StringRef KernelName,
|
||||
const amdhsa::kernel_descriptor_t &KernelDescriptor, uint64_t NextVGPR,
|
||||
uint64_t NextSGPR, bool ReserveVCC, bool ReserveFlatScr,
|
||||
bool ReserveXNACK) = 0;
|
||||
};
|
||||
|
||||
class AMDGPUTargetAsmStreamer final : public AMDGPUTargetStreamer {
|
||||
formatted_raw_ostream &OS;
|
||||
public:
|
||||
AMDGPUTargetAsmStreamer(MCStreamer &S, formatted_raw_ostream &OS);
|
||||
|
||||
void EmitDirectiveAMDGCNTarget(StringRef Target) override;
|
||||
|
||||
void EmitDirectiveHSACodeObjectVersion(uint32_t Major,
|
||||
uint32_t Minor) override;
|
||||
|
||||
@@ -94,8 +101,10 @@ public:
|
||||
bool EmitPALMetadata(const AMDGPU::PALMD::Metadata &PALMetadata) override;
|
||||
|
||||
void EmitAmdhsaKernelDescriptor(
|
||||
StringRef KernelName,
|
||||
const amdhsa::kernel_descriptor_t &KernelDescriptor) override;
|
||||
const MCSubtargetInfo &STI, StringRef KernelName,
|
||||
const amdhsa::kernel_descriptor_t &KernelDescriptor, uint64_t NextVGPR,
|
||||
uint64_t NextSGPR, bool ReserveVCC, bool ReserveFlatScr,
|
||||
bool ReserveXNACK) override;
|
||||
};
|
||||
|
||||
class AMDGPUTargetELFStreamer final : public AMDGPUTargetStreamer {
|
||||
@@ -109,6 +118,8 @@ public:
|
||||
|
||||
MCELFStreamer &getStreamer();
|
||||
|
||||
void EmitDirectiveAMDGCNTarget(StringRef Target) override;
|
||||
|
||||
void EmitDirectiveHSACodeObjectVersion(uint32_t Major,
|
||||
uint32_t Minor) override;
|
||||
|
||||
@@ -130,8 +141,10 @@ public:
|
||||
bool EmitPALMetadata(const AMDGPU::PALMD::Metadata &PALMetadata) override;
|
||||
|
||||
void EmitAmdhsaKernelDescriptor(
|
||||
StringRef KernelName,
|
||||
const amdhsa::kernel_descriptor_t &KernelDescriptor) override;
|
||||
const MCSubtargetInfo &STI, StringRef KernelName,
|
||||
const amdhsa::kernel_descriptor_t &KernelDescriptor, uint64_t NextVGPR,
|
||||
uint64_t NextSGPR, bool ReserveVCC, bool ReserveFlatScr,
|
||||
bool ReserveXNACK) override;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -198,6 +198,10 @@ void streamIsaVersion(const MCSubtargetInfo *STI, raw_ostream &Stream) {
|
||||
<< ISAVersion.Major
|
||||
<< ISAVersion.Minor
|
||||
<< ISAVersion.Stepping;
|
||||
|
||||
if (hasXNACK(*STI))
|
||||
Stream << "+xnack";
|
||||
|
||||
Stream.flush();
|
||||
}
|
||||
|
||||
@@ -334,6 +338,39 @@ unsigned getMaxNumSGPRs(const FeatureBitset &Features, unsigned WavesPerEU,
|
||||
return std::min(MaxNumSGPRs, AddressableNumSGPRs);
|
||||
}
|
||||
|
||||
unsigned getNumExtraSGPRs(const FeatureBitset &Features, bool VCCUsed,
|
||||
bool FlatScrUsed, bool XNACKUsed) {
|
||||
unsigned ExtraSGPRs = 0;
|
||||
if (VCCUsed)
|
||||
ExtraSGPRs = 2;
|
||||
|
||||
IsaVersion Version = getIsaVersion(Features);
|
||||
if (Version.Major < 8) {
|
||||
if (FlatScrUsed)
|
||||
ExtraSGPRs = 4;
|
||||
} else {
|
||||
if (XNACKUsed)
|
||||
ExtraSGPRs = 4;
|
||||
|
||||
if (FlatScrUsed)
|
||||
ExtraSGPRs = 6;
|
||||
}
|
||||
|
||||
return ExtraSGPRs;
|
||||
}
|
||||
|
||||
unsigned getNumExtraSGPRs(const FeatureBitset &Features, bool VCCUsed,
|
||||
bool FlatScrUsed) {
|
||||
return getNumExtraSGPRs(Features, VCCUsed, FlatScrUsed,
|
||||
Features[AMDGPU::FeatureXNACK]);
|
||||
}
|
||||
|
||||
unsigned getNumSGPRBlocks(const FeatureBitset &Features, unsigned NumSGPRs) {
|
||||
NumSGPRs = alignTo(std::max(1u, NumSGPRs), getSGPREncodingGranule(Features));
|
||||
// SGPRBlocks is actual number of SGPR blocks minus 1.
|
||||
return NumSGPRs / getSGPREncodingGranule(Features) - 1;
|
||||
}
|
||||
|
||||
unsigned getVGPRAllocGranule(const FeatureBitset &Features) {
|
||||
return 4;
|
||||
}
|
||||
@@ -370,6 +407,12 @@ unsigned getMaxNumVGPRs(const FeatureBitset &Features, unsigned WavesPerEU) {
|
||||
return std::min(MaxNumVGPRs, AddressableNumVGPRs);
|
||||
}
|
||||
|
||||
unsigned getNumVGPRBlocks(const FeatureBitset &Features, unsigned NumVGPRs) {
|
||||
NumVGPRs = alignTo(std::max(1u, NumVGPRs), getVGPREncodingGranule(Features));
|
||||
// VGPRBlocks is actual number of VGPR blocks minus 1.
|
||||
return NumVGPRs / getVGPREncodingGranule(Features) - 1;
|
||||
}
|
||||
|
||||
} // end namespace IsaInfo
|
||||
|
||||
void initDefaultAMDKernelCodeT(amd_kernel_code_t &Header,
|
||||
@@ -399,6 +442,21 @@ void initDefaultAMDKernelCodeT(amd_kernel_code_t &Header,
|
||||
Header.private_segment_alignment = 4;
|
||||
}
|
||||
|
||||
amdhsa::kernel_descriptor_t getDefaultAmdhsaKernelDescriptor() {
|
||||
amdhsa::kernel_descriptor_t KD;
|
||||
memset(&KD, 0, sizeof(KD));
|
||||
AMDHSA_BITS_SET(KD.compute_pgm_rsrc1,
|
||||
amdhsa::COMPUTE_PGM_RSRC1_FLOAT_DENORM_MODE_16_64,
|
||||
amdhsa::FLOAT_DENORM_MODE_FLUSH_NONE);
|
||||
AMDHSA_BITS_SET(KD.compute_pgm_rsrc1,
|
||||
amdhsa::COMPUTE_PGM_RSRC1_ENABLE_DX10_CLAMP, 1);
|
||||
AMDHSA_BITS_SET(KD.compute_pgm_rsrc1,
|
||||
amdhsa::COMPUTE_PGM_RSRC1_ENABLE_IEEE_MODE, 1);
|
||||
AMDHSA_BITS_SET(KD.compute_pgm_rsrc2,
|
||||
amdhsa::COMPUTE_PGM_RSRC2_ENABLE_SGPR_WORKGROUP_ID_X, 1);
|
||||
return KD;
|
||||
}
|
||||
|
||||
bool isGroupSegment(const GlobalValue *GV) {
|
||||
return GV->getType()->getAddressSpace() == AMDGPUAS::LOCAL_ADDRESS;
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/IR/CallingConv.h"
|
||||
#include "llvm/MC/MCInstrDesc.h"
|
||||
#include "llvm/Support/AMDHSAKernelDescriptor.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include <cstdint>
|
||||
@@ -28,12 +29,12 @@ class Argument;
|
||||
class FeatureBitset;
|
||||
class Function;
|
||||
class GlobalValue;
|
||||
class MachineMemOperand;
|
||||
class MCContext;
|
||||
class MCRegisterClass;
|
||||
class MCRegisterInfo;
|
||||
class MCSection;
|
||||
class MCSubtargetInfo;
|
||||
class MachineMemOperand;
|
||||
class Triple;
|
||||
|
||||
namespace AMDGPU {
|
||||
@@ -138,6 +139,22 @@ unsigned getMinNumSGPRs(const FeatureBitset &Features, unsigned WavesPerEU);
|
||||
unsigned getMaxNumSGPRs(const FeatureBitset &Features, unsigned WavesPerEU,
|
||||
bool Addressable);
|
||||
|
||||
/// \returns Number of extra SGPRs implicitly required by given subtarget \p
|
||||
/// Features when the given special registers are used.
|
||||
unsigned getNumExtraSGPRs(const FeatureBitset &Features, bool VCCUsed,
|
||||
bool FlatScrUsed, bool XNACKUsed);
|
||||
|
||||
/// \returns Number of extra SGPRs implicitly required by given subtarget \p
|
||||
/// Features when the given special registers are used. XNACK is inferred from
|
||||
/// \p Features.
|
||||
unsigned getNumExtraSGPRs(const FeatureBitset &Features, bool VCCUsed,
|
||||
bool FlatScrUsed);
|
||||
|
||||
/// \returns Number of SGPR blocks needed for given subtarget \p Features when
|
||||
/// \p NumSGPRs are used. \p NumSGPRs should already include any special
|
||||
/// register counts.
|
||||
unsigned getNumSGPRBlocks(const FeatureBitset &Features, unsigned NumSGPRs);
|
||||
|
||||
/// \returns VGPR allocation granularity for given subtarget \p Features.
|
||||
unsigned getVGPRAllocGranule(const FeatureBitset &Features);
|
||||
|
||||
@@ -158,6 +175,10 @@ unsigned getMinNumVGPRs(const FeatureBitset &Features, unsigned WavesPerEU);
|
||||
/// execution unit requirement for given subtarget \p Features.
|
||||
unsigned getMaxNumVGPRs(const FeatureBitset &Features, unsigned WavesPerEU);
|
||||
|
||||
/// \returns Number of VGPR blocks needed for given subtarget \p Features when
|
||||
/// \p NumVGPRs are used.
|
||||
unsigned getNumVGPRBlocks(const FeatureBitset &Features, unsigned NumSGPRs);
|
||||
|
||||
} // end namespace IsaInfo
|
||||
|
||||
LLVM_READONLY
|
||||
@@ -203,6 +224,8 @@ int getMCOpcode(uint16_t Opcode, unsigned Gen);
|
||||
void initDefaultAMDKernelCodeT(amd_kernel_code_t &Header,
|
||||
const FeatureBitset &Features);
|
||||
|
||||
amdhsa::kernel_descriptor_t getDefaultAmdhsaKernelDescriptor();
|
||||
|
||||
bool isGroupSegment(const GlobalValue *GV);
|
||||
bool isGlobalSegment(const GlobalValue *GV);
|
||||
bool isReadOnlySegment(const GlobalValue *GV);
|
||||
|
||||
@@ -5,11 +5,29 @@
|
||||
; OSABI-AMDHSA-ASM: s_endpgm
|
||||
; OSABI-AMDHSA-ASM: .section .rodata,#alloc
|
||||
; OSABI-AMDHSA-ASM: .p2align 6
|
||||
; OSABI-AMDHSA-ASM: .amdhsa_kernel fadd
|
||||
; OSABI-AMDHSA-ASM: .amdhsa_user_sgpr_private_segment_buffer 1
|
||||
; OSABI-AMDHSA-ASM: .amdhsa_user_sgpr_kernarg_segment_ptr 1
|
||||
; OSABI-AMDHSA-ASM: .amdhsa_next_free_vgpr 3
|
||||
; OSABI-AMDHSA-ASM: .amdhsa_next_free_sgpr 6
|
||||
; OSABI-AMDHSA-ASM: .amdhsa_reserve_vcc 0
|
||||
; OSABI-AMDHSA-ASM: .amdhsa_reserve_flat_scratch 0
|
||||
; OSABI-AMDHSA-ASM: .end_amdhsa_kernel
|
||||
; OSABI-AMDHSA-ASM: .text
|
||||
|
||||
; ALL-ASM-LABEL: {{^}}fsub:
|
||||
; OSABI-AMDHSA-ASM: s_endpgm
|
||||
; OSABI-AMDHSA-ASM: .section .rodata,#alloc
|
||||
; OSABI-AMDHSA-ASM: .p2align 6
|
||||
; OSABI-AMDHSA-ASM: .amdhsa_kernel fsub
|
||||
; OSABI-AMDHSA-ASM: .amdhsa_user_sgpr_private_segment_buffer 1
|
||||
; OSABI-AMDHSA-ASM: .amdhsa_user_sgpr_kernarg_segment_ptr 1
|
||||
; OSABI-AMDHSA-ASM: .amdhsa_next_free_vgpr 3
|
||||
; OSABI-AMDHSA-ASM: .amdhsa_next_free_sgpr 6
|
||||
; OSABI-AMDHSA-ASM: .amdhsa_reserve_vcc 0
|
||||
; OSABI-AMDHSA-ASM: .amdhsa_reserve_flat_scratch 0
|
||||
; OSABI-AMDHSA-ASM: .end_amdhsa_kernel
|
||||
; OSABI-AMDHSA-ASM: .text
|
||||
|
||||
; OSABI-AMDHSA-ASM-NOT: .hsa_code_object_version
|
||||
; OSABI-AMDHSA-ASM-NOT: .hsa_code_object_isa
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
// RUN: not llvm-mc -mattr=+code-object-v3 -triple amdgcn-amd-amdhsa -mcpu=gfx803 -mattr=+xnack -show-encoding %s 2>&1 >/dev/null | FileCheck %s
|
||||
// RUN: not llvm-mc -mattr=+code-object-v3 -triple amdgcn-amd- -mcpu=gfx803 -mattr=+xnack -show-encoding %s 2>&1 >/dev/null | FileCheck %s --check-prefix=NOT-AMDHSA
|
||||
|
||||
.text
|
||||
|
||||
.amdgcn_target "amdgcn--amdhsa-gfx803+xnack"
|
||||
// CHECK: error: target must match options
|
||||
|
||||
.amdhsa_kernel
|
||||
// CHECK: error: unknown directive
|
||||
.end_amdhsa_kernel
|
||||
|
||||
.amdhsa_kernel foo
|
||||
.amdhsa_group_segment_fixed_size -1
|
||||
// CHECK: error: value out of range
|
||||
.end_amdhsa_kernel
|
||||
|
||||
.amdhsa_kernel foo
|
||||
.amdhsa_group_segment_fixed_size 10000000000 + 1
|
||||
// CHECK: error: value out of range
|
||||
.end_amdhsa_kernel
|
||||
|
||||
.amdhsa_kernel foo
|
||||
// NOT-AMDHSA: error: directive only supported for amdhsa OS
|
||||
.end_amdhsa_kernel
|
||||
|
||||
.amdhsa_kernel foo
|
||||
.amdhsa_group_segment_fixed_size 1
|
||||
.amdhsa_group_segment_fixed_size 1
|
||||
// CHECK: error: .amdhsa_ directives cannot be repeated
|
||||
.end_amdhsa_kernel
|
||||
|
||||
.amdhsa_kernel foo
|
||||
// CHECK: error: .amdhsa_next_free_vgpr directive is required
|
||||
.end_amdhsa_kernel
|
||||
|
||||
.amdhsa_kernel foo
|
||||
.amdhsa_next_free_vgpr 0
|
||||
// CHECK: error: .amdhsa_next_free_sgpr directive is required
|
||||
.end_amdhsa_kernel
|
||||
|
||||
.amdhsa_kernel foo
|
||||
1
|
||||
// CHECK: error: expected .amdhsa_ directive or .end_amdhsa_kernel
|
||||
.end_amdhsa_kernel
|
||||
|
||||
.set .amdgcn.next_free_vgpr, "foo"
|
||||
v_mov_b32_e32 v0, s0
|
||||
// CHECK: error: .amdgcn.next_free_{v,s}gpr symbols must be absolute expressions
|
||||
@@ -0,0 +1,26 @@
|
||||
// RUN: llvm-mc -mattr=+code-object-v3 -triple amdgcn-amd-amdhsa -mcpu=gfx802 -filetype=obj < %s > %t
|
||||
// RUN: llvm-objdump -s -j .rodata %t | FileCheck --check-prefix=OBJDUMP %s
|
||||
|
||||
// Check that SGPR init bug on gfx803 is corrected by the assembler, setting
|
||||
// GRANULATED_WAVEFRONT_SGPR_COUNT to 11.
|
||||
|
||||
// OBJDUMP: Contents of section .rodata
|
||||
// OBJDUMP-NEXT: 0000 00000000 00000000 00000000 00000000
|
||||
// OBJDUMP-NEXT: 0010 00000000 00000000 00000000 00000000
|
||||
// OBJDUMP-NEXT: 0020 00000000 00000000 00000000 00000000
|
||||
// OBJDUMP-NEXT: 0030 c002ac00 80000000 00000000 00000000
|
||||
|
||||
.text
|
||||
|
||||
.amdgcn_target "amdgcn-amd-amdhsa--gfx802"
|
||||
|
||||
.p2align 8
|
||||
minimal:
|
||||
s_endpgm
|
||||
|
||||
.rodata
|
||||
|
||||
.amdhsa_kernel minimal
|
||||
.amdhsa_next_free_vgpr 0
|
||||
.amdhsa_next_free_sgpr 0
|
||||
.end_amdhsa_kernel
|
||||
@@ -0,0 +1,212 @@
|
||||
// RUN: llvm-mc -mattr=+code-object-v3 -triple amdgcn-amd-amdhsa -mcpu=gfx900 -mattr=+xnack < %s | FileCheck --check-prefix=ASM %s
|
||||
// RUN: llvm-mc -mattr=+code-object-v3 -triple amdgcn-amd-amdhsa -mcpu=gfx900 -mattr=+xnack -filetype=obj < %s > %t
|
||||
// RUN: llvm-readobj -elf-output-style=GNU -sections -symbols -relocations %t | FileCheck --check-prefix=READOBJ %s
|
||||
// RUN: llvm-objdump -s -j .rodata %t | FileCheck --check-prefix=OBJDUMP %s
|
||||
|
||||
// READOBJ: Section Headers
|
||||
// READOBJ: .text PROGBITS {{[0-9a-f]+}} {{[0-9a-f]+}} {{[0-9a-f]+}} {{[0-9]+}} AX {{[0-9]+}} {{[0-9]+}} 256
|
||||
// READOBJ: .rodata PROGBITS {{[0-9a-f]+}} {{[0-9a-f]+}} 0000c0 {{[0-9]+}} A {{[0-9]+}} {{[0-9]+}} 64
|
||||
|
||||
// READOBJ: Relocation section '.rela.rodata' at offset
|
||||
// READOBJ: 0000000000000010 {{[0-9a-f]+}}00000005 R_AMDGPU_REL64 0000000000000000 .text + 10
|
||||
// READOBJ: 0000000000000050 {{[0-9a-f]+}}00000005 R_AMDGPU_REL64 0000000000000000 .text + 110
|
||||
// READOBJ: 0000000000000090 {{[0-9a-f]+}}00000005 R_AMDGPU_REL64 0000000000000000 .text + 210
|
||||
|
||||
// READOBJ: Symbol table '.symtab' contains {{[0-9]+}} entries:
|
||||
// READOBJ: {{[0-9]+}}: 0000000000000100 0 FUNC LOCAL DEFAULT 2 complete
|
||||
// READOBJ: {{[0-9]+}}: 0000000000000000 0 FUNC LOCAL DEFAULT 2 minimal
|
||||
// READOBJ: {{[0-9]+}}: 0000000000000200 0 FUNC LOCAL DEFAULT 2 special_sgpr
|
||||
// READOBJ: {{[0-9]+}}: 0000000000000040 64 OBJECT GLOBAL DEFAULT 3 complete.kd
|
||||
// READOBJ: {{[0-9]+}}: 0000000000000000 64 OBJECT GLOBAL DEFAULT 3 minimal.kd
|
||||
// READOBJ: {{[0-9]+}}: 0000000000000080 64 OBJECT GLOBAL DEFAULT 3 special_sgpr.kd
|
||||
|
||||
// OBJDUMP: Contents of section .rodata
|
||||
// Note, relocation for KERNEL_CODE_ENTRY_BYTE_OFFSET is not resolved here.
|
||||
// minimal
|
||||
// OBJDUMP-NEXT: 0000 00000000 00000000 00000000 00000000
|
||||
// OBJDUMP-NEXT: 0010 00000000 00000000 00000000 00000000
|
||||
// OBJDUMP-NEXT: 0020 00000000 00000000 00000000 00000000
|
||||
// OBJDUMP-NEXT: 0030 0000ac00 80000000 00000000 00000000
|
||||
// complete
|
||||
// OBJDUMP-NEXT: 0040 01000000 01000000 00000000 00000000
|
||||
// OBJDUMP-NEXT: 0050 00000000 00000000 00000000 00000000
|
||||
// OBJDUMP-NEXT: 0060 00000000 00000000 00000000 00000000
|
||||
// OBJDUMP-NEXT: 0070 c2500104 0f0f007f 7f000000 00000000
|
||||
// special_sgpr
|
||||
// OBJDUMP-NEXT: 0080 00000000 00000000 00000000 00000000
|
||||
// OBJDUMP-NEXT: 0090 00000000 00000000 00000000 00000000
|
||||
// OBJDUMP-NEXT: 00a0 00000000 00000000 00000000 00000000
|
||||
// OBJDUMP-NEXT: 00b0 00010000 80000000 00000000 00000000
|
||||
|
||||
.text
|
||||
// ASM: .text
|
||||
|
||||
.amdgcn_target "amdgcn-amd-amdhsa--gfx900+xnack"
|
||||
// ASM: .amdgcn_target "amdgcn-amd-amdhsa--gfx900+xnack"
|
||||
|
||||
.p2align 8
|
||||
.type minimal,@function
|
||||
minimal:
|
||||
s_endpgm
|
||||
|
||||
.p2align 8
|
||||
.type complete,@function
|
||||
complete:
|
||||
s_endpgm
|
||||
|
||||
.p2align 8
|
||||
.type special_sgpr,@function
|
||||
special_sgpr:
|
||||
s_endpgm
|
||||
|
||||
.rodata
|
||||
// ASM: .rodata
|
||||
|
||||
// Test that only specifying required directives is allowed, and that defaulted
|
||||
// values are omitted.
|
||||
.p2align 6
|
||||
.amdhsa_kernel minimal
|
||||
.amdhsa_next_free_vgpr 0
|
||||
.amdhsa_next_free_sgpr 0
|
||||
.end_amdhsa_kernel
|
||||
|
||||
// ASM: .amdhsa_kernel minimal
|
||||
// ASM-NEXT: .amdhsa_next_free_vgpr 0
|
||||
// ASM-NEXT: .amdhsa_next_free_sgpr 0
|
||||
// ASM-NEXT: .end_amdhsa_kernel
|
||||
|
||||
// Test that we can specify all available directives with non-default values.
|
||||
.p2align 6
|
||||
.amdhsa_kernel complete
|
||||
.amdhsa_group_segment_fixed_size 1
|
||||
.amdhsa_private_segment_fixed_size 1
|
||||
.amdhsa_user_sgpr_private_segment_buffer 1
|
||||
.amdhsa_user_sgpr_dispatch_ptr 1
|
||||
.amdhsa_user_sgpr_queue_ptr 1
|
||||
.amdhsa_user_sgpr_kernarg_segment_ptr 1
|
||||
.amdhsa_user_sgpr_dispatch_id 1
|
||||
.amdhsa_user_sgpr_flat_scratch_init 1
|
||||
.amdhsa_user_sgpr_private_segment_size 1
|
||||
.amdhsa_system_sgpr_private_segment_wavefront_offset 1
|
||||
.amdhsa_system_sgpr_workgroup_id_x 0
|
||||
.amdhsa_system_sgpr_workgroup_id_y 1
|
||||
.amdhsa_system_sgpr_workgroup_id_z 1
|
||||
.amdhsa_system_sgpr_workgroup_info 1
|
||||
.amdhsa_system_vgpr_workitem_id 1
|
||||
.amdhsa_next_free_vgpr 9
|
||||
.amdhsa_next_free_sgpr 27
|
||||
.amdhsa_reserve_vcc 0
|
||||
.amdhsa_reserve_flat_scratch 0
|
||||
.amdhsa_reserve_xnack_mask 0
|
||||
.amdhsa_float_round_mode_32 1
|
||||
.amdhsa_float_round_mode_16_64 1
|
||||
.amdhsa_float_denorm_mode_32 1
|
||||
.amdhsa_float_denorm_mode_16_64 0
|
||||
.amdhsa_dx10_clamp 0
|
||||
.amdhsa_ieee_mode 0
|
||||
.amdhsa_fp16_overflow 1
|
||||
.amdhsa_exception_fp_ieee_invalid_op 1
|
||||
.amdhsa_exception_fp_denorm_src 1
|
||||
.amdhsa_exception_fp_ieee_div_zero 1
|
||||
.amdhsa_exception_fp_ieee_overflow 1
|
||||
.amdhsa_exception_fp_ieee_underflow 1
|
||||
.amdhsa_exception_fp_ieee_inexact 1
|
||||
.amdhsa_exception_int_div_zero 1
|
||||
.end_amdhsa_kernel
|
||||
|
||||
// ASM: .amdhsa_kernel complete
|
||||
// ASM-NEXT: .amdhsa_group_segment_fixed_size 1
|
||||
// ASM-NEXT: .amdhsa_private_segment_fixed_size 1
|
||||
// ASM-NEXT: .amdhsa_user_sgpr_private_segment_buffer 1
|
||||
// ASM-NEXT: .amdhsa_user_sgpr_dispatch_ptr 1
|
||||
// ASM-NEXT: .amdhsa_user_sgpr_queue_ptr 1
|
||||
// ASM-NEXT: .amdhsa_user_sgpr_kernarg_segment_ptr 1
|
||||
// ASM-NEXT: .amdhsa_user_sgpr_dispatch_id 1
|
||||
// ASM-NEXT: .amdhsa_user_sgpr_flat_scratch_init 1
|
||||
// ASM-NEXT: .amdhsa_user_sgpr_private_segment_size 1
|
||||
// ASM-NEXT: .amdhsa_system_sgpr_private_segment_wavefront_offset 1
|
||||
// ASM-NEXT: .amdhsa_system_sgpr_workgroup_id_x 0
|
||||
// ASM-NEXT: .amdhsa_system_sgpr_workgroup_id_y 1
|
||||
// ASM-NEXT: .amdhsa_system_sgpr_workgroup_id_z 1
|
||||
// ASM-NEXT: .amdhsa_system_sgpr_workgroup_info 1
|
||||
// ASM-NEXT: .amdhsa_system_vgpr_workitem_id 1
|
||||
// ASM-NEXT: .amdhsa_next_free_vgpr 9
|
||||
// ASM-NEXT: .amdhsa_next_free_sgpr 27
|
||||
// ASM-NEXT: .amdhsa_reserve_vcc 0
|
||||
// ASM-NEXT: .amdhsa_reserve_flat_scratch 0
|
||||
// ASM-NEXT: .amdhsa_reserve_xnack_mask 0
|
||||
// ASM-NEXT: .amdhsa_float_round_mode_32 1
|
||||
// ASM-NEXT: .amdhsa_float_round_mode_16_64 1
|
||||
// ASM-NEXT: .amdhsa_float_denorm_mode_32 1
|
||||
// ASM-NEXT: .amdhsa_float_denorm_mode_16_64 0
|
||||
// ASM-NEXT: .amdhsa_dx10_clamp 0
|
||||
// ASM-NEXT: .amdhsa_ieee_mode 0
|
||||
// ASM-NEXT: .amdhsa_fp16_overflow 1
|
||||
// ASM-NEXT: .amdhsa_exception_fp_ieee_invalid_op 1
|
||||
// ASM-NEXT: .amdhsa_exception_fp_denorm_src 1
|
||||
// ASM-NEXT: .amdhsa_exception_fp_ieee_div_zero 1
|
||||
// ASM-NEXT: .amdhsa_exception_fp_ieee_overflow 1
|
||||
// ASM-NEXT: .amdhsa_exception_fp_ieee_underflow 1
|
||||
// ASM-NEXT: .amdhsa_exception_fp_ieee_inexact 1
|
||||
// ASM-NEXT: .amdhsa_exception_int_div_zero 1
|
||||
// ASM-NEXT: .end_amdhsa_kernel
|
||||
|
||||
// Test that we are including special SGPR usage in the granulated count.
|
||||
.p2align 6
|
||||
.amdhsa_kernel special_sgpr
|
||||
// Same next_free_sgpr as "complete", but...
|
||||
.amdhsa_next_free_sgpr 27
|
||||
// ...on GFX9 this should require an additional 6 SGPRs, pushing us from
|
||||
// 3 granules to 4
|
||||
.amdhsa_reserve_flat_scratch 1
|
||||
|
||||
.amdhsa_reserve_vcc 0
|
||||
.amdhsa_reserve_xnack_mask 0
|
||||
|
||||
.amdhsa_float_denorm_mode_16_64 0
|
||||
.amdhsa_dx10_clamp 0
|
||||
.amdhsa_ieee_mode 0
|
||||
.amdhsa_next_free_vgpr 0
|
||||
.end_amdhsa_kernel
|
||||
|
||||
// ASM: .amdhsa_kernel special_sgpr
|
||||
// ASM-NEXT: .amdhsa_next_free_vgpr 0
|
||||
// ASM-NEXT: .amdhsa_next_free_sgpr 27
|
||||
// ASM-NEXT: .amdhsa_reserve_vcc 0
|
||||
// ASM-NEXT: .amdhsa_reserve_xnack_mask 0
|
||||
// ASM-NEXT: .amdhsa_float_denorm_mode_16_64 0
|
||||
// ASM-NEXT: .amdhsa_dx10_clamp 0
|
||||
// ASM-NEXT: .amdhsa_ieee_mode 0
|
||||
// ASM-NEXT: .end_amdhsa_kernel
|
||||
|
||||
.section .foo
|
||||
|
||||
.byte .amdgcn.gfx_generation_number
|
||||
// ASM: .byte 9
|
||||
|
||||
.byte .amdgcn.next_free_vgpr
|
||||
// ASM: .byte 0
|
||||
.byte .amdgcn.next_free_sgpr
|
||||
// ASM: .byte 0
|
||||
|
||||
v_mov_b32_e32 v7, s10
|
||||
|
||||
.byte .amdgcn.next_free_vgpr
|
||||
// ASM: .byte 8
|
||||
.byte .amdgcn.next_free_sgpr
|
||||
// ASM: .byte 11
|
||||
|
||||
.set .amdgcn.next_free_vgpr, 0
|
||||
.set .amdgcn.next_free_sgpr, 0
|
||||
|
||||
.byte .amdgcn.next_free_vgpr
|
||||
// ASM: .byte 0
|
||||
.byte .amdgcn.next_free_sgpr
|
||||
// ASM: .byte 0
|
||||
|
||||
v_mov_b32_e32 v16, s3
|
||||
|
||||
.byte .amdgcn.next_free_vgpr
|
||||
// ASM: .byte 17
|
||||
.byte .amdgcn.next_free_sgpr
|
||||
// ASM: .byte 4
|
||||
Reference in New Issue
Block a user