CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
1052 lines
60 KiB
Python
1052 lines
60 KiB
Python
################################################################################
|
|
#
|
|
# Copyright (C) 2022-2026 Advanced Micro Devices, Inc. All rights reserved.
|
|
#
|
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
# of this software and associated documentation files (the "Software"), to deal
|
|
# in the Software without restriction, including without limitation the rights
|
|
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
# copies of the Software, and to permit persons to whom the Software is
|
|
# furnished to do so, subject to the following conditions:
|
|
#
|
|
# The above copyright notice and this permission notice shall be included in
|
|
# all copies or substantial portions of the Software.
|
|
#
|
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
# SOFTWARE.
|
|
#
|
|
################################################################################
|
|
|
|
from rocisa.code import Module, Label
|
|
from rocisa.container import sgpr, vgpr, ContinuousRegister
|
|
from rocisa.instruction import SMovB32, SMovB64, SNop, VAddU32, VAndB32, VMovB32, VLShiftLeftB32, VLShiftRightB32
|
|
from rocisa.functions import vectorStaticRemainder, \
|
|
vectorStaticDivideAndRemainder, vectorStaticDivide, vectorStaticMultiply, \
|
|
vectorStaticMultiplyAdd
|
|
|
|
from ..Component import LraTileAssignment, LraTileProperties, LocalRead
|
|
from ..Common import roundUp, log2, ceilDivide
|
|
from ..Common.DataType import DataType
|
|
from dataclasses import dataclass
|
|
|
|
@dataclass
|
|
class LraTilePropertiesMFMA(LraTileProperties):
|
|
dividendForKId: int
|
|
num1DBlocks: int
|
|
num1DWaves: int
|
|
dividedForBlkId: int
|
|
dividedForWaveId: int
|
|
vectorWidth: int
|
|
maxKId: int
|
|
|
|
class LraTileAssignmentVALU(LraTileAssignment):
|
|
kernel = {"EnableMatrixInstruction": False}
|
|
|
|
"""
|
|
Local Read Addresses: Tile Assignment
|
|
"""
|
|
def __call__(self, writer, kernel, tP):
|
|
module = Module("LraTileAssignmentVALU")
|
|
|
|
# allocate resources
|
|
qReg = writer.vgprPool.checkOut(1, tag="LraTileAssignmentVALU_qReg") # quotient
|
|
rReg = writer.vgprPool.checkOut(1, tag="LraTileAssignmentVALU_rReg") # remainder
|
|
# dot2: currently only support unroll major LDS
|
|
tc = tP["tensorChar"]
|
|
umlds = kernel["UnrollMajorLDS%s" % tc]
|
|
LdsPad = kernel["LdsPad%s" % tc] if kernel["LdsBlockSizePerPad%s" % tc] == 0 else 0
|
|
strideTile = kernel["_DepthU%s"%tc] + LdsPad if umlds else 1
|
|
tmpVgpr = writer.vgprPool.checkOutAligned(2,2, tag="LraTileAssignmentVALU_tmpVgpr")
|
|
tmpVgprRes = ContinuousRegister(tmpVgpr, 2)
|
|
|
|
with writer.allocTmpSgpr(1, tag="LraTileAssignmentVALU_tmpSgprInfo") as tmpSgprInfo:
|
|
if tP["tileIdx"] == 0:
|
|
# kStr += "%slr%s = serial %% SG%s%s%s" \
|
|
# % (writer.commentPrefix, tP["tileChar"], tP["tileChar"], \
|
|
# writer.commentSuffix, writer.endLine)
|
|
|
|
# constant
|
|
dividendReg = "Serial" # local serial
|
|
divisor = kernel["SubGroup0"]
|
|
# dot2: waveSplitK
|
|
if kernel["UseDotInstruction"]:
|
|
if kernel["NumWaveSplitK"] > 1:
|
|
newSerial = writer.vgprPool.checkOut(1,"newSerial")
|
|
module.add(vectorStaticDivide(newSerial, dividendReg, kernel["NumWaveSplitK"], tmpVgprRes, \
|
|
"Divided by NumWaveSplitK(%u)" % kernel["NumWaveSplitK"]))
|
|
# generate instruction
|
|
module.add(vectorStaticDivideAndRemainder(qReg, rReg, newSerial, divisor, tmpVgprRes))
|
|
# tile offset
|
|
module.add(vectorStaticMultiply(vgpr(rReg), vgpr(rReg), strideTile, tmpSgprInfo, \
|
|
"1. M offset: mOffset = mIdx * mStride(%u)" % strideTile))
|
|
writer.vgprPool.checkIn(newSerial)
|
|
else:
|
|
module.add(vectorStaticDivideAndRemainder(qReg, rReg, dividendReg, divisor, tmpVgprRes))
|
|
# tile offset
|
|
module.add(vectorStaticMultiply(vgpr(rReg), vgpr(rReg), strideTile, tmpSgprInfo, \
|
|
"1. M offset: mOffset = mIdx * mStride(%u)" % strideTile))
|
|
else:
|
|
module.add(vectorStaticDivideAndRemainder(qReg, rReg, dividendReg, divisor, tmpVgprRes))
|
|
|
|
# release and return resource
|
|
tP["gpr"]["lro"] = rReg
|
|
writer.tmplro = qReg
|
|
else:
|
|
# kStr += "%slr%s = (serial / SG%s) %% SG%s%s%s" \
|
|
# % (writer.commentPrefix, tP["tileChar"], tP["tileChar"], \
|
|
# tP["tileChar"], writer.commentSuffix, writer.endLine)
|
|
|
|
# constant
|
|
divisor = kernel["SubGroup1"]
|
|
dividendReg = writer.tmplro
|
|
# generate instruction
|
|
module.add(vectorStaticDivideAndRemainder(qReg, rReg, dividendReg, divisor, tmpVgprRes))
|
|
|
|
if kernel["UseDotInstruction"]:
|
|
# tile offset
|
|
module.add(vectorStaticMultiply(vgpr(rReg), vgpr(rReg), strideTile, tmpSgprInfo, \
|
|
"1. N offset: nOffset = nIdx * nStride(%u)" % strideTile))
|
|
|
|
# release and return resource
|
|
tP["gpr"]["lro"] = rReg
|
|
|
|
writer.vgprPool.checkIn(writer.tmplro) # old
|
|
writer.vgprPool.checkIn(qReg)
|
|
|
|
writer.vgprPool.checkIn(tmpVgpr)
|
|
|
|
return module
|
|
|
|
class LraTileAssignmentTransposedMFMA(LraTileAssignment):
|
|
kernel = {"EnableMatrixInstruction": True,
|
|
"DirectToVgprA": False,
|
|
"DirectToVgprB": False,
|
|
"ProblemType": {
|
|
"DataType": DataType("b")
|
|
}}
|
|
asmCaps = {
|
|
"HasLDSTrB128B16": True
|
|
}
|
|
|
|
NUM_CONT_READ_ELEMENTS = 8
|
|
NUM_READ_ELEMENT_PER_THREAD = 16
|
|
NUM_UNROLLED_STRIDE_ELEMENTS = NUM_CONT_READ_ELEMENTS * 2
|
|
|
|
def __call__(self, writer, kernel, tP):
|
|
if not tP["enableLDSTr"]:
|
|
comp = LraTileAssignmentMFMA()
|
|
return comp(writer, kernel, tP)
|
|
elif tP["isM"]:
|
|
comp = LraTileAssignmentTransposedMFMAB8()
|
|
return comp(writer, kernel, tP)
|
|
|
|
dividendReg = "Serial"
|
|
module = Module("LraTileAssignmentTransposedMFMA")
|
|
module.addComment0("lr%s" % tP["tileChar"])
|
|
# alloc vgpr
|
|
tReg = writer.vgprPool.checkOut(1,"tReg") # remainder
|
|
kReg = writer.vgprPool.checkOut(1,"kReg") # remainder
|
|
tmpVgpr = writer.vgprPool.checkOutAligned(2, 2, tag="LraTileAssignmentTransposedMFMA_tmpVgpr")
|
|
tmpVgprRes = ContinuousRegister(tmpVgpr, 2)
|
|
|
|
# alloc vgpr
|
|
dummy = writer.vgprPool.checkOut(1, "dummy")
|
|
sReg = writer.vgprPool.checkOut(1, "sReg") # remainder
|
|
mReg = writer.vgprPool.checkOut(1, "mReg") # remainder
|
|
|
|
# get constant parameter
|
|
tc = tP["tensorChar"]
|
|
tile01 = tP["tile01Idx"]
|
|
waveWidth = writer.states.kernel["WavefrontSize"]
|
|
#FIXME: tail loop with transposed load b128
|
|
|
|
isSparseDenseMatrix = False
|
|
if kernel["ProblemType"]["Sparse"]:
|
|
if (kernel["ProblemType"]["Sparse"] == 1 and tP["isB"]) or (kernel["ProblemType"]["Sparse"] == 2 and tP["isA"]):
|
|
isSparseDenseMatrix = True
|
|
ldsPad = kernel["LdsPad%s" % tc] if kernel["LdsBlockSizePerPad%s" % tc] == 0 else 0
|
|
|
|
# parameter for get each type index
|
|
matrixInstT = min(kernel["MatrixInstM"], kernel["MatrixInstN"])
|
|
numTileInInst = (kernel["MatrixInstM"] if (tile01 == 0) else kernel["MatrixInstN"]) // matrixInstT
|
|
dividendForKId = matrixInstT * kernel["MatrixInstB"]
|
|
num1DBlocks = kernel["MatrixInstBM"] if (tile01 == 0) else kernel["MatrixInstBN"]
|
|
num1DWaves = kernel["MIWaveGroup"][0] if (tile01 == 0) else kernel["MIWaveGroup"][1]
|
|
if kernel["SourceSwap"]:
|
|
dividedForBlkId = matrixInstT if (tile01 == 0) else (matrixInstT * kernel["MatrixInstBM"])
|
|
else:
|
|
dividedForBlkId = (kernel["MatrixInstN"] * kernel["MatrixInstBN"]) if (tile01 == 0) else kernel["MatrixInstN"]
|
|
|
|
dividedForWaveId = waveWidth if (tile01 == 0) else (waveWidth * kernel["MIWaveGroup"][0])
|
|
vectorWidth = kernel["VectorWidth%s"%tc]
|
|
maxKId = waveWidth // ((matrixInstT if (tile01 == 0) else kernel["MatrixInstN"]) * kernel["MatrixInstB"])
|
|
writer.states.lraTileProperties[tile01] = LraTilePropertiesMFMA(dividendForKId=dividendForKId, \
|
|
num1DBlocks=num1DBlocks, \
|
|
num1DWaves=num1DWaves, \
|
|
dividedForBlkId=dividedForBlkId, \
|
|
dividedForWaveId = dividedForWaveId, \
|
|
vectorWidth=vectorWidth, \
|
|
maxKId=maxKId)
|
|
|
|
# strider for each type of index
|
|
mt = kernel["MacroTile%u" % tile01]
|
|
strideTile = int(int(tP["localReadInstruction"].blockWidth * writer.states.bpr) // tP["bpeDS"])
|
|
strideUnroll = mt + ldsPad
|
|
strideWave = numTileInInst * matrixInstT * vectorWidth
|
|
|
|
with writer.allocTmpSgpr(1, tag="LraTileAssignmentTransposedMFMA_tmpSgprInfo") as tmpSgprInfo:
|
|
# tile offset = (wtId%16)//8*8
|
|
module.add(vectorStaticRemainder(dummy, kReg, dividendReg, waveWidth, tmpVgprRes, tmpSgprInfo, \
|
|
"0. thread id in wave: wtid = tid %% wavelength(%u)" % waveWidth))
|
|
#FIXME: calculate this
|
|
module.add(vectorStaticRemainder(dummy, tReg, kReg, self.NUM_READ_ELEMENT_PER_THREAD, tmpVgprRes, tmpSgprInfo, "tileOffset=wtId%16"))
|
|
module.add(vectorStaticDivide(tReg, tReg, self.NUM_CONT_READ_ELEMENTS, tmpVgprRes, f"tileOffset//={self.NUM_CONT_READ_ELEMENTS}"))
|
|
module.add(vectorStaticMultiply(vgpr(tReg), vgpr(tReg), strideTile, tmpSgprInfo, \
|
|
"tileOffset*=strideTile(%u)" % strideTile))
|
|
# block offset
|
|
# removed, wmma has only single block
|
|
|
|
#FIXME: should apply along k-dir?
|
|
module.add(vectorStaticMultiply(vgpr(tReg), vgpr(tReg), vectorWidth, tmpSgprInfo, \
|
|
"4. apply VectorWidth: bnOffset = bnOffset * vw(%u)" % vectorWidth))
|
|
|
|
# unroll offset
|
|
module.add(vectorStaticRemainder(dummy, kReg, dividendReg, waveWidth, tmpVgprRes, tmpSgprInfo, "wtId=tid%wavelen"))
|
|
module.add(vectorStaticDivide(kReg, kReg, self.NUM_UNROLLED_STRIDE_ELEMENTS, tmpSgprInfo, f"kOffset=wtId//{self.NUM_UNROLLED_STRIDE_ELEMENTS}"))
|
|
if isSparseDenseMatrix:
|
|
# Dense matrix of SPARSE are interleaved format, so we need to multiply by 2
|
|
module.add(vectorStaticMultiply(vgpr(mReg), vgpr(kReg), self.NUM_CONT_READ_ELEMENTS * 2, tmpSgprInfo, f"kOffset*=2x{self.NUM_CONT_READ_ELEMENTS}"))
|
|
else:
|
|
module.add(vectorStaticMultiply(vgpr(mReg), vgpr(kReg), self.NUM_CONT_READ_ELEMENTS, tmpSgprInfo, f"kOffset*={self.NUM_CONT_READ_ELEMENTS}"))
|
|
module.add(vectorStaticRemainder(dummy, kReg, dividendReg, waveWidth, tmpVgprRes, tmpSgprInfo, "wtId=tid%wavelen"))
|
|
module.add(vectorStaticRemainder(dummy, kReg, kReg, self.NUM_CONT_READ_ELEMENTS, tmpVgprRes, tmpSgprInfo, f"ktOffset=wtid%{self.NUM_CONT_READ_ELEMENTS}"))
|
|
module.add(VAddU32(vgpr(mReg), vgpr(mReg), vgpr(kReg), "kOffset+=ktOffset"))
|
|
module.add(vectorStaticMultiply(vgpr(mReg), vgpr(mReg), strideUnroll, tmpSgprInfo, "kOffset*=stride"))
|
|
module.add(VAddU32(vgpr(tReg), vgpr(tReg), vgpr(mReg), "lrOffset = kOffset + tileOffset"))
|
|
|
|
# wave offset
|
|
if num1DWaves > 1:
|
|
module.add(vectorStaticDivide(dummy, dividendReg, dividedForWaveId, tmpVgprRes, \
|
|
"7. wave offset in N dimen: wtid = tid / dividedForWaveId(%u)" % dividedForWaveId))
|
|
module.add(vectorStaticRemainder(dummy, dummy, dummy, num1DWaves, tmpVgprRes, tmpSgprInfo, \
|
|
"7. wave offset in M dimen: wtid0 = wtid / num1DWaves(%u)" % num1DWaves))
|
|
module.add(vectorStaticMultiplyAdd(vgpr(tReg), vgpr(dummy), strideWave, vgpr(tReg), tmpSgprInfo, \
|
|
"7. wave offset in M dimen: wOffset = wtid0 * W0Stride(%u); 7. final local read offset: flrOffset = lrOffset + WOffset" % strideWave))
|
|
|
|
tP["gpr"]["lro"] = tReg
|
|
# release register
|
|
writer.vgprPool.checkIn(dummy)
|
|
writer.vgprPool.checkIn(sReg)
|
|
writer.vgprPool.checkIn(mReg)
|
|
writer.vgprPool.checkIn(kReg)
|
|
writer.vgprPool.checkIn(tmpVgpr)
|
|
|
|
return module
|
|
|
|
class LraTileAssignmentTransposedMFMAFP32(LraTileAssignmentTransposedMFMA):
|
|
kernel = {"EnableMatrixInstruction": True,
|
|
"DirectToVgprA": False,
|
|
"DirectToVgprB": False,
|
|
"ProblemType": {
|
|
"DataType": DataType("s")
|
|
}}
|
|
|
|
class LraTileAssignmentTransposedMFMAFP16(LraTileAssignmentTransposedMFMA):
|
|
kernel = {"EnableMatrixInstruction": True,
|
|
"DirectToVgprA": False,
|
|
"DirectToVgprB": False,
|
|
"ProblemType": {
|
|
"DataType": DataType("h")
|
|
}}
|
|
asmCaps = {
|
|
"HasLDSTrB128B16": True
|
|
}
|
|
|
|
class LraTileAssignmentTransposedMFMAB8(LraTileAssignmentTransposedMFMA):
|
|
kernel = {"EnableMatrixInstruction": True,
|
|
"DirectToVgprA": False,
|
|
"DirectToVgprB": False,
|
|
"ProblemType": {
|
|
"DataType": DataType("I8")
|
|
}}
|
|
asmCaps = {
|
|
"HasLDSTrB64B8": True
|
|
}
|
|
NUM_CONT_READ_ELEMENTS = 4
|
|
NUM_READ_ELEMENT_PER_THREAD = 8
|
|
NUM_UNROLLED_STRIDE_ELEMENTS = 16
|
|
|
|
def __call__(self, writer, kernel, tP):
|
|
if not tP["enableLDSTr"]:
|
|
comp = LraTileAssignmentMFMA()
|
|
return comp(writer, kernel, tP)
|
|
|
|
dividendReg = "Serial"
|
|
module = Module("LraTileAssignmentTransposedMFMA")
|
|
module.addComment0("lr%s" % tP["tileChar"])
|
|
# alloc vgpr
|
|
tReg = writer.vgprPool.checkOut(1,"tReg") # remainder
|
|
kReg = writer.vgprPool.checkOut(1,"kReg") # remainder
|
|
tmpVgpr = writer.vgprPool.checkOutAligned(2, 2, tag="LraTileAssignmentTransposedMFMAB8_tmpVgpr")
|
|
tmpVgprRes = ContinuousRegister(tmpVgpr, 2)
|
|
|
|
# alloc vgpr
|
|
dummy = writer.vgprPool.checkOut(1, "dummy")
|
|
sReg = writer.vgprPool.checkOut(1, "sReg") # remainder
|
|
mReg = writer.vgprPool.checkOut(1, "mReg") # remainder
|
|
|
|
# get constant parameter
|
|
tc = tP["tensorChar"]
|
|
tile01 = tP["tile01Idx"]
|
|
waveWidth = writer.states.kernel["WavefrontSize"]
|
|
#FIXME: tail loop with transposed load b128
|
|
|
|
isSparseDenseMatrix = False
|
|
if kernel["ProblemType"]["Sparse"]:
|
|
if (kernel["ProblemType"]["Sparse"] == 1 and tP["isB"]) or (kernel["ProblemType"]["Sparse"] == 2 and tP["isA"]):
|
|
isSparseDenseMatrix = True
|
|
ldsPad = kernel["LdsPad%s" % tc] if kernel["LdsBlockSizePerPad%s" % tc] == 0 else 0
|
|
|
|
# parameter for get each type index
|
|
matrixInstT = min(kernel["MatrixInstM"], kernel["MatrixInstN"])
|
|
numTileInInst = (kernel["MatrixInstM"] if (tile01 == 0) else kernel["MatrixInstN"]) // matrixInstT
|
|
dividendForKId = matrixInstT * kernel["MatrixInstB"]
|
|
num1DBlocks = kernel["MatrixInstBM"] if (tile01 == 0) else kernel["MatrixInstBN"]
|
|
num1DWaves = kernel["MIWaveGroup"][0] if (tile01 == 0) else kernel["MIWaveGroup"][1]
|
|
if kernel["SourceSwap"]:
|
|
dividedForBlkId = matrixInstT if (tile01 == 0) else (matrixInstT * kernel["MatrixInstBM"])
|
|
else:
|
|
dividedForBlkId = (kernel["MatrixInstN"] * kernel["MatrixInstBN"]) if (tile01 == 0) else kernel["MatrixInstN"]
|
|
|
|
dividedForWaveId = waveWidth if (tile01 == 0) else (waveWidth * kernel["MIWaveGroup"][0])
|
|
vectorWidth = kernel["VectorWidth%s"%tc]
|
|
maxKId = waveWidth // ((matrixInstT if (tile01 == 0) else kernel["MatrixInstN"]) * kernel["MatrixInstB"])
|
|
writer.states.lraTileProperties[tile01] = LraTilePropertiesMFMA(dividendForKId=dividendForKId, \
|
|
num1DBlocks=num1DBlocks, \
|
|
num1DWaves=num1DWaves, \
|
|
dividedForBlkId=dividedForBlkId, \
|
|
dividedForWaveId = dividedForWaveId, \
|
|
vectorWidth=vectorWidth, \
|
|
maxKId=maxKId)
|
|
|
|
# strider for each type of index
|
|
mt = kernel["MacroTile%u" % tile01]
|
|
strideTile = int(int(tP["localReadInstruction"].blockWidth * writer.states.bpr) // tP["bpeDS"])
|
|
strideUnroll = mt + ldsPad
|
|
strideWave = numTileInInst * matrixInstT * vectorWidth
|
|
|
|
with writer.allocTmpSgpr(1, tag="LraTileAssignmentTransposedMFMAB8_tmpSgprInfo") as tmpSgprInfo:
|
|
# tile offset = (wtId%8)//4*8
|
|
module.add(vectorStaticRemainder(dummy, kReg, dividendReg, waveWidth, tmpVgprRes, tmpSgprInfo, \
|
|
"0. thread id in wave: wtid = tid %% wavelength(%u)" % waveWidth))
|
|
#FIXME: calculate this
|
|
module.add(vectorStaticRemainder(dummy, tReg, kReg, self.NUM_READ_ELEMENT_PER_THREAD, tmpVgprRes, tmpSgprInfo, "tileOffset=wtId%8"))
|
|
module.add(vectorStaticDivide(tReg, tReg, self.NUM_CONT_READ_ELEMENTS, tmpSgprInfo, f"tileOffset//={self.NUM_CONT_READ_ELEMENTS}"))
|
|
module.add(vectorStaticMultiply(vgpr(tReg), vgpr(tReg), strideTile, tmpSgprInfo, \
|
|
"tileOffset*=strideTile(%u)" % strideTile))
|
|
# block offset
|
|
# removed, wmma has only single block
|
|
|
|
#FIXME: should apply along k-dir?
|
|
module.add(vectorStaticMultiply(vgpr(tReg), vgpr(tReg), vectorWidth, tmpSgprInfo, \
|
|
"4. apply VectorWidth: bnOffset = bnOffset * vw(%u)" % vectorWidth))
|
|
|
|
if tP["isM"]:
|
|
# multiplyBy:
|
|
# 2 : t8-t15 will read the same block as the t0-t7. t0-t7 reads 0-63
|
|
# 1 : t8-t15 will read the next block. t0-t7 reads 0-63 and t8-t15 read 64-127
|
|
# TODO Should have wider local read to let t8-t15 read the next iter's data and remove the muliplyBy=1 case.
|
|
multiplyBy = 1 if kernel["MIInputPerThread%s"%tc] * tP["bpeDS"] // writer.states.bpr == 2 else 2
|
|
strideK = self.NUM_UNROLLED_STRIDE_ELEMENTS // self.NUM_READ_ELEMENT_PER_THREAD * self.NUM_CONT_READ_ELEMENTS * multiplyBy
|
|
module.add(vectorStaticRemainder(dummy, sReg, kReg, self.NUM_CONT_READ_ELEMENTS, tmpVgprRes, tmpSgprInfo, f"5.1 kOffset = wtId % {self.NUM_CONT_READ_ELEMENTS}"))
|
|
module.add(vectorStaticDivide(mReg, kReg, strideK , tmpSgprInfo, f"5. blockOffset = wtId / strideK({strideK})"))
|
|
|
|
module.add(vectorStaticMultiplyAdd(vgpr(kReg), vgpr(mReg), self.NUM_CONT_READ_ELEMENTS, vgpr(sReg), tmpSgprInfo,f"5.3 kOffset = kOffset + blockOffset * {self.NUM_CONT_READ_ELEMENTS}"))
|
|
module.add(vectorStaticMultiply(vgpr(kReg), vgpr(kReg), strideUnroll, tmpSgprInfo, f"6.1 lrOffset = kOffset * strideUnroll({strideUnroll})"))
|
|
module.add(VAddU32(vgpr(tReg), vgpr(tReg), vgpr(kReg), "6.2 lrOffset = lrOffset + tileOffset"))
|
|
else:
|
|
# unroll offset
|
|
module.add(vectorStaticRemainder(dummy, kReg, dividendReg, waveWidth, tmpVgprRes, tmpSgprInfo, "wtId=tid%wavelen"))
|
|
module.add(vectorStaticDivide(kReg, kReg, self.NUM_UNROLLED_STRIDE_ELEMENTS, tmpSgprInfo, f"kOffset=wtId//{self.NUM_UNROLLED_STRIDE_ELEMENTS}"))
|
|
if isSparseDenseMatrix:
|
|
# Dense matrix of SPARSE are interleaved format, so we need to multiply by 2
|
|
module.add(vectorStaticMultiply(vgpr(mReg), vgpr(kReg), self.NUM_UNROLLED_STRIDE_ELEMENTS*2, tmpSgprInfo, f"kOffset*={self.NUM_UNROLLED_STRIDE_ELEMENTS}x2"))
|
|
else:
|
|
module.add(vectorStaticMultiply(vgpr(mReg), vgpr(kReg), self.NUM_UNROLLED_STRIDE_ELEMENTS, tmpSgprInfo, f"kOffset*={self.NUM_UNROLLED_STRIDE_ELEMENTS}"))
|
|
module.add(vectorStaticRemainder(dummy, kReg, dividendReg, waveWidth, tmpVgprRes, tmpSgprInfo, "wtId=tid%wavelen"))
|
|
module.add(vectorStaticRemainder(dummy, kReg, dividendReg, self.NUM_UNROLLED_STRIDE_ELEMENTS, tmpVgprRes, tmpSgprInfo, "ktOffset=wtId%16"))
|
|
module.add(vectorStaticDivide(kReg, kReg, self.NUM_READ_ELEMENT_PER_THREAD, tmpSgprInfo, f"kOffset=ktOffset//{self.NUM_READ_ELEMENT_PER_THREAD}"))
|
|
module.add(vectorStaticMultiply(vgpr(kReg), vgpr(kReg), self.NUM_CONT_READ_ELEMENTS, tmpSgprInfo, f"ktOffset*={self.NUM_CONT_READ_ELEMENTS}"))
|
|
module.add(VAddU32(vgpr(mReg), vgpr(mReg), vgpr(kReg), "kOffset+=ktOffset"))
|
|
module.add(vectorStaticRemainder(dummy, kReg, dividendReg, waveWidth, tmpVgprRes, tmpSgprInfo, "wtId=tid%wavelen"))
|
|
module.add(vectorStaticRemainder(dummy, kReg, kReg, self.NUM_CONT_READ_ELEMENTS, tmpVgprRes, tmpSgprInfo, f"ktOffset=wtid%{self.NUM_CONT_READ_ELEMENTS}"))
|
|
module.add(VAddU32(vgpr(mReg), vgpr(mReg), vgpr(kReg), "kOffset+=ktOffset"))
|
|
module.add(vectorStaticMultiply(vgpr(mReg), vgpr(mReg), strideUnroll, tmpSgprInfo, "kOffset*=stride"))
|
|
module.add(VAddU32(vgpr(tReg), vgpr(tReg), vgpr(mReg), "lrOffset = kOffset + tileOffset"))
|
|
|
|
# wave offset
|
|
if num1DWaves > 1:
|
|
module.add(vectorStaticDivide(dummy, dividendReg, dividedForWaveId, tmpVgprRes, \
|
|
"7. wave offset in N dimen: wtid = tid / dividedForWaveId(%u)" % dividedForWaveId))
|
|
module.add(vectorStaticRemainder(dummy, dummy, dummy, num1DWaves, tmpVgprRes, tmpSgprInfo, \
|
|
"7. wave offset in M dimen: wtid0 = wtid / num1DWaves(%u)" % num1DWaves))
|
|
module.add(vectorStaticMultiplyAdd(vgpr(tReg), vgpr(dummy), strideWave, vgpr(tReg), tmpSgprInfo, \
|
|
"7. wave offset in M dimen: wOffset = wtid0 * W0Stride(%u); 7. final local read offset: flrOffset = lrOffset + WOffset" % strideWave))
|
|
|
|
tP["gpr"]["lro"] = tReg
|
|
# release register
|
|
writer.vgprPool.checkIn(dummy)
|
|
writer.vgprPool.checkIn(sReg)
|
|
writer.vgprPool.checkIn(mReg)
|
|
writer.vgprPool.checkIn(kReg)
|
|
writer.vgprPool.checkIn(tmpVgpr)
|
|
|
|
return module
|
|
|
|
class LraTileAssignmentTransposedMFMA_FP8(LraTileAssignmentTransposedMFMAB8):
|
|
kernel = {"EnableMatrixInstruction": True,
|
|
"DirectToVgprA": False,
|
|
"DirectToVgprB": False,
|
|
"ProblemType": {
|
|
"DataType": DataType("F8"),
|
|
"isMixMode": False,
|
|
}}
|
|
asmCaps = {
|
|
"HasLDSTrB64B8": True
|
|
}
|
|
|
|
class LraTileAssignmentTransposedMFMA_BF8(LraTileAssignmentTransposedMFMA_FP8):
|
|
kernel = {"EnableMatrixInstruction": True,
|
|
"DirectToVgprA": False,
|
|
"DirectToVgprB": False,
|
|
"ProblemType": {
|
|
"DataType": DataType("B8"),
|
|
"isMixMode": False,
|
|
}}
|
|
asmCaps = {
|
|
"HasLDSTrB64B8": True
|
|
}
|
|
|
|
class LraTileAssignmentTransposedMFMA_FP8BF8(LraTileAssignmentTransposedMFMA_FP8):
|
|
kernel = {"EnableMatrixInstruction": True,
|
|
"DirectToVgprA": False,
|
|
"DirectToVgprB": False,
|
|
"ProblemType": {
|
|
"DataType": DataType("F8B8"),
|
|
"isMixMode": False,
|
|
}}
|
|
asmCaps = {
|
|
"HasLDSTrB64B8": True
|
|
}
|
|
|
|
class LraTileAssignmentTransposedMFMA_BF8FP8(LraTileAssignmentTransposedMFMA_FP8):
|
|
kernel = {"EnableMatrixInstruction": True,
|
|
"DirectToVgprA": False,
|
|
"DirectToVgprB": False,
|
|
"ProblemType": {
|
|
"DataType": DataType("B8F8"),
|
|
"isMixMode": False,
|
|
}}
|
|
asmCaps = {
|
|
"HasLDSTrB64B8": True
|
|
}
|
|
|
|
class LraTileAssignmentTransposedMFMAMixMode(LraTileAssignmentTransposedMFMAB8):
|
|
kernel = {"EnableMatrixInstruction": True,
|
|
"DirectToVgprA": False,
|
|
"DirectToVgprB": False,
|
|
"ProblemType": {
|
|
"isMixMode": True,
|
|
}}
|
|
asmCaps = {
|
|
"HasLDSTrB64B8": True,
|
|
"HasLDSTrB64B4": True,
|
|
"HasLDSTrB96B6": True,
|
|
}
|
|
def __call__(self, writer, kernel, tP):
|
|
# TODO: check correctness of this condition
|
|
tc = tP["tensorChar"]
|
|
MacDataType = f"MacDataType{tc}" if(tc=="A" or tc=="B") else "DataType"
|
|
if not tP["enableLDSTr"]:
|
|
comp = LraTileAssignmentMFMA()
|
|
return comp(writer, kernel, tP)
|
|
if kernel["ProblemType"][MacDataType].numBytes() == 0.5:
|
|
comp = LraTileAssignmentTransposedMFMAF4()
|
|
return comp(writer, kernel, tP)
|
|
if kernel["ProblemType"][MacDataType].numBytes() == 0.75:
|
|
comp = LraTileAssignmentTransposedMFMAF6()
|
|
return comp(writer, kernel, tP)
|
|
if kernel["ProblemType"][MacDataType].numBytes() == 1:
|
|
comp = LraTileAssignmentTransposedMFMAB8()
|
|
return comp(writer, kernel, tP)
|
|
comp = LraTileAssignmentTransposedMFMAB8()
|
|
return comp(writer, kernel, tP)
|
|
|
|
class LraTileAssignmentTransposedMFMAF4(LraTileAssignmentTransposedMFMA):
|
|
kernel = {"EnableMatrixInstruction": True,
|
|
"DirectToVgprA": False,
|
|
"DirectToVgprB": False,
|
|
"ProblemType": {
|
|
"DataType": DataType("F4"),
|
|
"isMixMode": False,
|
|
}}
|
|
asmCaps = {
|
|
"HasLDSTrB64B4": True
|
|
}
|
|
|
|
NUM_CONT_READ_ELEMENTS = 8
|
|
NUM_READ_ELEMENT_PER_THREAD = 16
|
|
NUM_UNROLLED_STRIDE_ELEMENTS = 32
|
|
|
|
def __call__(self, writer, kernel, tP):
|
|
if not tP["enableLDSTr"]:
|
|
comp = LraTileAssignmentMFMA()
|
|
return comp(writer, kernel, tP)
|
|
|
|
dividendReg = "Serial"
|
|
module = Module("LraTileAssignmentTransposedMFMA")
|
|
module.addComment0("lr%s" % tP["tileChar"])
|
|
# alloc vgpr
|
|
tReg = writer.vgprPool.checkOut(1,"tReg") # remainder
|
|
kReg = writer.vgprPool.checkOut(1,"kReg") # remainder
|
|
tmpVgpr = writer.vgprPool.checkOutAligned(2, 2, tag="LraTileAssignmentTransposedMFMAF4_tmpVgpr")
|
|
tmpVgprRes = ContinuousRegister(tmpVgpr, 2)
|
|
|
|
# alloc vgpr
|
|
dummy = writer.vgprPool.checkOut(1, "dummy")
|
|
sReg = writer.vgprPool.checkOut(1, "sReg") # remainder
|
|
mReg = writer.vgprPool.checkOut(1, "mReg") # remainder
|
|
|
|
# get constant parameter
|
|
tc = tP["tensorChar"]
|
|
tile01 = tP["tile01Idx"]
|
|
waveWidth = writer.states.kernel["WavefrontSize"]
|
|
#FIXME: tail loop with transposed load b128
|
|
|
|
ldsPad = kernel["LdsPad%s" % tc] if kernel["LdsBlockSizePerPad%s" % tc] == 0 else 0
|
|
|
|
# parameter for get each type index
|
|
matrixInstT = (kernel["MatrixInstM"] if (tile01 == 0) else kernel["MatrixInstN"])
|
|
matrixInstTO = min(kernel["MatrixInstM"], kernel["MatrixInstN"])
|
|
matrixInstTO = matrixInstT if ("MXS" in tc) else matrixInstTO
|
|
numTileInInst = matrixInstT // matrixInstTO
|
|
|
|
dividendForKId = kernel["MatrixInstM"] * kernel["MatrixInstB"]
|
|
num1DBlocks = kernel["MatrixInstBM"] if (tile01 == 0) else kernel["MatrixInstBN"]
|
|
num1DWaves = kernel["MIWaveGroup"][0] if (tile01 == 0) else kernel["MIWaveGroup"][1]
|
|
if kernel["SourceSwap"]:
|
|
dividedForBlkId = matrixInstTO if (tile01 == 0) else (matrixInstTO * kernel["MatrixInstBM"])
|
|
else:
|
|
dividedForBlkId = (matrixInstTO * kernel["MatrixInstBN"]) if (tile01 == 0) else matrixInstTO
|
|
dividedForWaveId = waveWidth if (tile01 == 0) else (waveWidth * kernel["MIWaveGroup"][0])
|
|
vectorWidth = kernel["VectorWidth%s"%tc]
|
|
maxKId = waveWidth // (matrixInstTO * kernel["MatrixInstB"])
|
|
writer.states.lraTileProperties[tile01] = LraTilePropertiesMFMA(dividendForKId=dividendForKId, \
|
|
num1DBlocks=num1DBlocks, \
|
|
num1DWaves=num1DWaves, \
|
|
dividedForBlkId=dividedForBlkId, \
|
|
dividedForWaveId = dividedForWaveId, \
|
|
vectorWidth=vectorWidth, \
|
|
maxKId=maxKId)
|
|
|
|
# strider for each type of index
|
|
mt = kernel["MacroTile%u" % tile01]
|
|
strideUnroll = mt + ldsPad
|
|
strideWave = matrixInstT * vectorWidth
|
|
|
|
with writer.allocTmpSgpr(1, tag="LraTileAssignmentTransposedMFMAF4_tmpSgprInfo") as tmpSgprInfo:
|
|
module.add(vectorStaticRemainder(dummy, kReg, dividendReg, waveWidth, tmpVgprRes, tmpSgprInfo, "wtId=tid%wavelen"))
|
|
# calc col index
|
|
module.add(vectorStaticDivide(sReg, kReg, self.NUM_READ_ELEMENT_PER_THREAD, tmpVgprRes, f"s=wtid//{self.NUM_READ_ELEMENT_PER_THREAD}"))
|
|
module.add(vectorStaticMultiply(vgpr(sReg), vgpr(sReg), self.NUM_CONT_READ_ELEMENTS, tmpSgprInfo, comment=f"s*={self.NUM_CONT_READ_ELEMENTS}"))
|
|
module.add(vectorStaticRemainder(dummy, mReg, kReg, self.NUM_READ_ELEMENT_PER_THREAD, tmpVgprRes, tmpSgprInfo, comment=f"m=wtid%{self.NUM_READ_ELEMENT_PER_THREAD}"))
|
|
module.add(vectorStaticDivide(mReg, mReg, self.NUM_CONT_READ_ELEMENTS, tmpVgprRes, comment=f"m/={self.NUM_CONT_READ_ELEMENTS}"))
|
|
module.add(vectorStaticMultiply(vgpr(mReg), vgpr(mReg), self.NUM_UNROLLED_STRIDE_ELEMENTS, tmpSgprInfo, comment=f"m*={self.NUM_UNROLLED_STRIDE_ELEMENTS}"))
|
|
module.add(VAddU32(vgpr(tReg), vgpr(sReg), vgpr(mReg), "t=s+m"))
|
|
module.add(vectorStaticRemainder(dummy, kReg, kReg, self.NUM_CONT_READ_ELEMENTS, tmpVgprRes, tmpSgprInfo, comment=f"k=k%{self.NUM_CONT_READ_ELEMENTS}"))
|
|
module.add(VAddU32(vgpr(tReg), vgpr(tReg), vgpr(kReg), "t+=k"))
|
|
module.add(vectorStaticMultiply(vgpr(tReg), vgpr(tReg), strideUnroll, tmpSgprInfo, f"t*=strideUnroll({strideUnroll})"))
|
|
|
|
# wave offset
|
|
if num1DWaves > 1:
|
|
module.add(vectorStaticDivide(dummy, dividendReg, dividedForWaveId, tmpVgprRes, \
|
|
"7. wave offset in N dimen: wtid = tid / dividedForWaveId(%u)" % dividedForWaveId))
|
|
module.add(vectorStaticRemainder(dummy, dummy, dummy, num1DWaves, tmpVgprRes, tmpSgprInfo, \
|
|
"7. wave offset in M dimen: wtid0 = wtid / num1DWaves(%u)" % num1DWaves))
|
|
module.add(vectorStaticMultiplyAdd(vgpr(tReg), vgpr(dummy), strideWave, vgpr(tReg), tmpSgprInfo, \
|
|
"7. wave offset in M dimen: wOffset = wtid0 * W0Stride(%u); 7. final local read offset: flrOffset = lrOffset + WOffset" % strideWave))
|
|
|
|
tP["gpr"]["lro"] = tReg
|
|
# release register
|
|
writer.vgprPool.checkIn(dummy)
|
|
writer.vgprPool.checkIn(sReg)
|
|
writer.vgprPool.checkIn(mReg)
|
|
writer.vgprPool.checkIn(kReg)
|
|
writer.vgprPool.checkIn(tmpVgpr)
|
|
|
|
return module
|
|
|
|
class LraTileAssignmentTransposedMFMAF6(LraTileAssignmentTransposedMFMA):
|
|
kernel = {"EnableMatrixInstruction": True,
|
|
"DirectToVgprA": False,
|
|
"DirectToVgprB": False,
|
|
"ProblemType": {
|
|
"DataType": DataType("F6"),
|
|
"isMixMode": False,
|
|
}}
|
|
asmCaps = {
|
|
"HasLDSTrB96B6": True
|
|
}
|
|
|
|
NUM_CONT_READ_ELEMENTS = 8
|
|
NUM_READ_ELEMENT_PER_THREAD = 4
|
|
NUM_UNROLLED_STRIDE_ELEMENTS = 32
|
|
|
|
def __call__(self, writer, kernel, tP):
|
|
if not tP["enableLDSTr"]:
|
|
comp = LraTileAssignmentMFMA()
|
|
return comp(writer, kernel, tP)
|
|
|
|
dividendReg = "Serial"
|
|
module = Module("LraTileAssignmentTransposedMFMA")
|
|
module.addComment0("lr%s" % tP["tileChar"])
|
|
# alloc vgpr
|
|
tReg = writer.vgprPool.checkOut(1,"tReg") # remainder
|
|
kReg = writer.vgprPool.checkOut(1,"kReg") # remainder
|
|
tmpVgpr = writer.vgprPool.checkOutAligned(2, 2, tag="LraTileAssignmentTransposedMFMAF6_tmpVgpr")
|
|
tmpVgprRes = ContinuousRegister(tmpVgpr, 2)
|
|
|
|
# alloc vgpr
|
|
dummy = writer.vgprPool.checkOut(1, "dummy")
|
|
sReg = writer.vgprPool.checkOut(1, "sReg") # remainder
|
|
mReg = writer.vgprPool.checkOut(1, "mReg") # remainder
|
|
|
|
# get constant parameter
|
|
tc = tP["tensorChar"]
|
|
tile01 = tP["tile01Idx"]
|
|
waveWidth = writer.states.kernel["WavefrontSize"]
|
|
#FIXME: tail loop with transposed load b128
|
|
|
|
ldsPad = kernel["LdsPad%s" % tc] if kernel["LdsBlockSizePerPad%s" % tc] == 0 else 0
|
|
|
|
# parameter for get each type index
|
|
dividendForKId = kernel["MatrixInstM"] * kernel["MatrixInstB"]
|
|
num1DBlocks = kernel["MatrixInstBM"] if (tile01 == 0) else kernel["MatrixInstBN"]
|
|
num1DWaves = kernel["MIWaveGroup"][0] if (tile01 == 0) else kernel["MIWaveGroup"][1]
|
|
if kernel["SourceSwap"]:
|
|
dividedForBlkId = kernel["MatrixInstM"] if (tile01 == 0) else (kernel["MatrixInstM"] * kernel["MatrixInstBM"])
|
|
else:
|
|
dividedForBlkId = (kernel["MatrixInstN"] * kernel["MatrixInstBN"]) if (tile01 == 0) else kernel["MatrixInstN"]
|
|
dividedForWaveId = waveWidth if (tile01 == 0) else (waveWidth * kernel["MIWaveGroup"][0])
|
|
vectorWidth = kernel["VectorWidth%s"%tc]
|
|
maxKId = waveWidth // ((kernel["MatrixInstM"] if (tile01 == 0) else kernel["MatrixInstN"]) * kernel["MatrixInstB"])
|
|
writer.states.lraTileProperties[tile01] = LraTilePropertiesMFMA(dividendForKId=dividendForKId, \
|
|
num1DBlocks=num1DBlocks, \
|
|
num1DWaves=num1DWaves, \
|
|
dividedForBlkId=dividedForBlkId, \
|
|
dividedForWaveId = dividedForWaveId, \
|
|
vectorWidth=vectorWidth, \
|
|
maxKId=maxKId)
|
|
|
|
# strider for each type of index
|
|
mt = kernel["MacroTile%u" % tile01]
|
|
strideUnroll = mt + ldsPad
|
|
strideWave = kernel["MatrixInstM"] * vectorWidth
|
|
|
|
with writer.allocTmpSgpr(1, tag="LraTileAssignmentTransposedMFMAF6_tmpSgprInfo") as tmpSgprInfo:
|
|
module.add(vectorStaticRemainder(dummy, kReg, dividendReg, waveWidth, tmpVgprRes, tmpSgprInfo, "wtId(k)=tid%wavelen"))
|
|
# calc col index
|
|
# col = (wtId % 8) // 4 * 32 + (wtId // 8) * 4 + wtId % 4
|
|
module.add(vectorStaticRemainder(dummy, sReg, kReg, self.NUM_CONT_READ_ELEMENTS, tmpVgprRes, tmpSgprInfo, comment=f"s=wtId%{self.NUM_CONT_READ_ELEMENTS}"))
|
|
module.add(vectorStaticDivide(sReg, sReg, self.NUM_READ_ELEMENT_PER_THREAD, tmpVgprRes, f"s//={self.NUM_READ_ELEMENT_PER_THREAD}"))
|
|
module.add(vectorStaticMultiply(vgpr(tReg), vgpr(sReg), self.NUM_UNROLLED_STRIDE_ELEMENTS, tmpSgprInfo, comment=f"t=s*{self.NUM_UNROLLED_STRIDE_ELEMENTS}"))
|
|
|
|
module.add(vectorStaticDivide(sReg, kReg, self.NUM_CONT_READ_ELEMENTS, tmpVgprRes, comment=f"s=k//{self.NUM_CONT_READ_ELEMENTS}"))
|
|
module.add(vectorStaticMultiply(vgpr(sReg), vgpr(sReg), self.NUM_READ_ELEMENT_PER_THREAD, tmpSgprInfo, comment=f"s*={self.NUM_READ_ELEMENT_PER_THREAD}"))
|
|
module.add(VAddU32(vgpr(tReg), vgpr(tReg), vgpr(sReg), "t+=s"))
|
|
module.add(vectorStaticRemainder(dummy, kReg, kReg, self.NUM_READ_ELEMENT_PER_THREAD, tmpVgprRes, tmpSgprInfo, comment=f"k=k%{self.NUM_READ_ELEMENT_PER_THREAD}"))
|
|
module.add(VAddU32(vgpr(tReg), vgpr(tReg), vgpr(kReg), "t+=k"))
|
|
module.add(vectorStaticMultiply(vgpr(tReg), vgpr(tReg), strideUnroll, tmpSgprInfo, f"t*=strideUnroll({strideUnroll})"))
|
|
|
|
# wave offset
|
|
if num1DWaves > 1:
|
|
module.add(vectorStaticDivide(dummy, dividendReg, dividedForWaveId, tmpVgprRes, \
|
|
"7. wave offset in N dimen: wtid = tid / dividedForWaveId(%u)" % dividedForWaveId))
|
|
module.add(vectorStaticRemainder(dummy, dummy, dummy, num1DWaves, tmpVgprRes, tmpSgprInfo, \
|
|
"7. wave offset in M dimen: wtid0 = wtid / num1DWaves(%u)" % num1DWaves))
|
|
module.add(vectorStaticMultiplyAdd(vgpr(tReg), vgpr(dummy), strideWave, vgpr(tReg), tmpSgprInfo, \
|
|
"7. wave offset in M dimen: wOffset = wtid0 * W0Stride(%u); 7. final local read offset: flrOffset = lrOffset + WOffset" % strideWave))
|
|
|
|
tP["gpr"]["lro"] = tReg
|
|
# release register
|
|
writer.vgprPool.checkIn(dummy)
|
|
writer.vgprPool.checkIn(sReg)
|
|
writer.vgprPool.checkIn(mReg)
|
|
writer.vgprPool.checkIn(kReg)
|
|
writer.vgprPool.checkIn(tmpVgpr)
|
|
|
|
return module
|
|
|
|
class LraTileAssignmentTransposedMFMAB6(LraTileAssignmentTransposedMFMAF6):
|
|
kernel = {"EnableMatrixInstruction": True,
|
|
"DirectToVgprA": False,
|
|
"DirectToVgprB": False,
|
|
"ProblemType": {
|
|
"DataType": DataType("B6"),
|
|
"isMixMode": False,
|
|
}}
|
|
asmCaps = {
|
|
"HasLDSTrB96B6": True
|
|
}
|
|
|
|
class LraTileAssignmentMFMA(LraTileAssignment):
|
|
kernel = {"EnableMatrixInstruction": True, }
|
|
asmCaps = {
|
|
"HasLDSTrB128B16": False
|
|
}
|
|
|
|
"""
|
|
Local Read Addresses: Tile Assignment A/B
|
|
"""
|
|
def __call__(self, writer, kernel, tP):
|
|
module = Module("LraTileAssignmentMFMA")
|
|
module.addComment0("lr%s" % tP["tileChar"])
|
|
# alloc vgpr
|
|
tReg = writer.vgprPool.checkOut(1,"tReg") # remainder
|
|
kReg = writer.vgprPool.checkOut(1,"kReg") # remainder
|
|
tmpVgpr = writer.vgprPool.checkOutAligned(2,2, tag="LraTileAssignmentMFMA_tmpVgpr")
|
|
tmpVgprRes = ContinuousRegister(tmpVgpr, 2)
|
|
|
|
module.add(self.LraTileAssignmentCode(writer, kernel, tP, tReg, kReg, tmpVgprRes))
|
|
|
|
# release register
|
|
tP["gpr"]["lro"] = tReg
|
|
writer.vgprPool.checkIn(kReg)
|
|
writer.vgprPool.checkIn(tmpVgpr)
|
|
|
|
return module
|
|
|
|
def LraTileAssignmentCode(self, writer, kernel, tP, tReg, kReg, tmpVgprRes, dividendReg="Serial", isDTVAB=False):
|
|
module = Module("LraTileAssignmentCode")
|
|
|
|
# alloc vgpr
|
|
enableLDSTr = tP["enableLDSTr"]
|
|
dummy = writer.vgprPool.checkOut(1,"dummy")
|
|
mReg = writer.vgprPool.checkOut(1,"mReg") # remainder
|
|
if enableLDSTr:
|
|
sReg = writer.vgprPool.checkOut(1,"sReg") # remainder
|
|
|
|
# get constant parameter
|
|
tc = tP["tensorChar"]
|
|
tile01 = tP["tile01Idx"]
|
|
# tileSpan is the ds_load-halving gate: it MUST match LocalRead.getMxsTileSpanInfo
|
|
# exactly so the load layout produced here agrees with the packed VGPR layout /
|
|
# matrix_*_scale:N select the WMMA emits. Rather than re-deriving the gate (which
|
|
# risks drift, and previously mixed tc[3]-aliased MIWaveTile/VectorWidth with
|
|
# tile01-indexed MatrixInst), call getMxsTileSpanInfo as the single source of truth.
|
|
# It internally requires: MXS tensor, HasWMMA_V3 + InMemorySwizzle, ratio >= 2 and
|
|
# even, and the tile-axis matrix-instr size at the wave midpoint. Wave-count neutral.
|
|
#
|
|
# tileSpanWaveSplit adds MIWaveGroup>1 and picks between the two load layouts (both put
|
|
# block 2g in the lower half-wave and partner block 2g+1 in the upper half-wave):
|
|
# - MIWaveGroup==1 (tileSpan and not tileSpanWaveSplit): non-split. nIdx = wtid, so a
|
|
# single wave's lanes 0..MI-1 / MI..2MI-1 directly cover the two blocks; no hi offset.
|
|
# - MIWaveGroup>1 (tileSpanWaveSplit): wave-split. nIdx = wtid % MI, and the num1DWaves>1
|
|
# hiOffset path below explicitly places the partner block into the upper half-wave.
|
|
tileSpan = LocalRead.find(writer).getMxsTileSpanInfo(kernel, tc, tile01, writer.states.asmCaps) is not None
|
|
tileSpanWaveSplit = tileSpan and (kernel["MIWaveGroup"][tile01] > 1)
|
|
|
|
waveWidth = writer.states.kernel["WavefrontSize"]
|
|
|
|
noUnrollOffset = writer.states.asmCaps["HasWMMA_V1"] or ("MXS" in tc)
|
|
isgfx950 = kernel["ISA"][:2] == (9, 5)
|
|
isgfx950mx = isgfx950 and ("MXS" in tc)
|
|
# workaround for gfx950
|
|
# force noUnrollOffset=False for MX
|
|
if isgfx950:
|
|
noUnrollOffset = False
|
|
|
|
lrvw = kernel["LocalReadVectorWidthMXS"] if ("MXS" in tc) else kernel[f"LocalReadVectorWidth{tc}"]
|
|
inputPerThread = lrvw if not writer.states.inTailLoop else kernel["MIInputPerThread%s"%tc]
|
|
# workaround for gfx950 + fp4
|
|
# use MIInputPerThread if lrvw < MIInputPerThread
|
|
if isgfx950 and tP["bpeDS"] == 0.5 and lrvw < kernel["MIInputPerThread%s"%tc]:
|
|
inputPerThread = kernel["MIInputPerThread%s"%tc]
|
|
LdsPad = kernel["LdsPad%s" % tc] if kernel["LdsBlockSizePerPad%s" % tc] == 0 else 0
|
|
|
|
# parameter for get each type index
|
|
matrixInstT = (kernel["MatrixInstM"] if (tile01 == 0) else kernel["MatrixInstN"])
|
|
matrixInstTO = min(kernel["MatrixInstM"], kernel["MatrixInstN"])
|
|
matrixInstTO = matrixInstT if ("MXS" in tc) else matrixInstTO
|
|
numTileInInst = matrixInstT // matrixInstTO
|
|
|
|
dividendForKId = matrixInstTO * kernel["MatrixInstB"]
|
|
num1DBlocks = kernel["MatrixInstBM"] if (tile01 == 0) else kernel["MatrixInstBN"]
|
|
num1DWaves = kernel["MIWaveGroup"][0] if (tile01 == 0) else kernel["MIWaveGroup"][1]
|
|
if kernel["SourceSwap"]:
|
|
dividedForBlkId = matrixInstTO if (tile01 == 0) else (matrixInstTO * kernel["MatrixInstBM"])
|
|
else:
|
|
dividedForBlkId = (matrixInstTO * kernel["MatrixInstBN"]) if (tile01 == 0) else matrixInstTO
|
|
dividedForWaveId = waveWidth if (tile01 == 0) else (waveWidth * kernel["MIWaveGroup"][0])
|
|
vectorWidth = kernel["VectorWidth%s"%tc]
|
|
if isDTVAB:
|
|
if tP["tlu"]:
|
|
# DTV + TLU case, glvw and vw are applied to the same direction. No need to apply both.
|
|
# non TLU case, glvw and vw are applied to the different direction. We need to apply vw here.
|
|
vectorWidth = 1
|
|
maxKId = waveWidth // (matrixInstTO * kernel["MatrixInstB"])
|
|
writer.states.lraTileProperties[tile01] = LraTilePropertiesMFMA(dividendForKId=dividendForKId, \
|
|
num1DBlocks=num1DBlocks, \
|
|
num1DWaves=num1DWaves, \
|
|
dividedForBlkId=dividedForBlkId, \
|
|
dividedForWaveId = dividedForWaveId, \
|
|
vectorWidth=vectorWidth, \
|
|
maxKId=maxKId)
|
|
|
|
abmatrixinfo = writer.states.a if tc == 'A' else writer.states.b
|
|
perpStride = abmatrixinfo.gNLCPerpStride
|
|
permBlock = abmatrixinfo.gNLCPermBlock
|
|
perpBlockSize = abmatrixinfo.gRDtlSwizzlePerpBlockSize
|
|
|
|
# strider for each type of index
|
|
umlds = kernel["UnrollMajorLDS%s" % tc]
|
|
mt = kernel["MacroTile%u" % tile01]
|
|
if ("MXS" in tc):
|
|
subTc = tc[3]
|
|
# MX scale LDS tile-stride, gated by MXScaleFormat:
|
|
# - Swizzled (HostPreSwizzle/InMemorySwizzle): MatrixInstK/MXBlock (= MX-unit)
|
|
# - NoSwizzle (canonical): _DepthU_MXS (= K-scales per M)
|
|
mxScaleFormat = kernel.get("MXScaleFormat", "NoSwizzle")
|
|
isMxSwizzled = mxScaleFormat in ("InMemorySwizzle", "HostPreSwizzle")
|
|
if isMxSwizzled:
|
|
strideTile = kernel["MatrixInstK"] // kernel["ProblemType"][f"MXBlock{subTc}"]
|
|
else:
|
|
strideTile = kernel["_DepthU%s"%tc] + LdsPad if umlds else 1
|
|
elif enableLDSTr:
|
|
strideTile = 4
|
|
else:
|
|
strideTile = kernel["_DepthU%s"%tc] + LdsPad if umlds else 1
|
|
if isDTVAB:
|
|
strideTile = 1 # DTV case. Actual stride will be applied later.
|
|
|
|
strideK = inputPerThread if umlds else (mt + LdsPad) * inputPerThread
|
|
if enableLDSTr:
|
|
if kernel["UseGeneralizedNLCOne%s"%tc] and perpStride > 1:
|
|
strideK = 8
|
|
strideK1 = mt+LdsPad
|
|
elif kernel["ProblemType"]["Sparse"]:
|
|
if tP["isM"]:
|
|
strideK //= 4
|
|
# special case for new F8 MFMA, need to exclude wmma_v3
|
|
elif kernel["ProblemType"]["DataType"].is8bitFloat() and kernel["MatrixInstK"] > 32 and (not writer.states.asmCaps["HasWMMA_V3"]) and (not isgfx950mx):
|
|
if umlds:
|
|
strideK = 16
|
|
else:
|
|
strideK = (mt + LdsPad) * 16
|
|
elif kernel["UseF32XEmulation"] and not (kernel["MatrixInstM"] == 16 and kernel["MatrixInstK"] == 16):
|
|
if umlds:
|
|
strideK = 4
|
|
else:
|
|
strideK = (mt + LdsPad) * 4
|
|
# sparse
|
|
if writer.states.asmCaps["HasSWMMAC"] and writer.states.asmCaps["HasSWMMAC_gfx1250"]:
|
|
if (kernel["ProblemType"]["Sparse"] == 1 and tP["isB"]) or (kernel["ProblemType"]["Sparse"] == 2 and tP["isA"]) or tP["isM"]:
|
|
strideK *= 2
|
|
|
|
strideBlock = matrixInstT * strideTile
|
|
if ("MXS" in tc):
|
|
strideWave = matrixInstT * num1DBlocks * strideTile * vectorWidth
|
|
elif enableLDSTr:
|
|
strideWave = matrixInstT * vectorWidth
|
|
else:
|
|
strideWave = matrixInstT * num1DBlocks * strideTile * vectorWidth
|
|
|
|
# When one wave's read spans a whole LDS component, the component jump lives in the wave
|
|
# stride. A narrower VW straddles components; then LocalRead applies the jump instead, so
|
|
# keep the baseline wave stride. A/B only: MX scales keep their own stride (relocated, not split).
|
|
segILWaveSpansComp = False
|
|
if kernel.get("LDSSegmentInterleave") == 1 and tc in ("A", "B"):
|
|
_compCols = kernel["MacroTile%u" % tile01] // (kernel["NumWaves"] // 2)
|
|
segILWaveSpansComp = min(kernel["MatrixInstM"], kernel["MatrixInstN"]) * vectorWidth >= _compCols
|
|
if segILWaveSpansComp:
|
|
strideWave = kernel["LDSSegInterleaveOffsets"]["readWaveStride"]
|
|
|
|
lsu = kernel["LocalSplitU"]
|
|
|
|
if isDTVAB:
|
|
strideTile = 1 # DTV case. Actual stride will be applied later.
|
|
|
|
def perpPerm(vgprReg):
|
|
reMap0 = writer.vgprPool.checkOut(1, tag="perpPerm_reMap0")
|
|
reMap1 = writer.vgprPool.checkOut(1, tag="perpPerm_reMap1")
|
|
perpStrideInv = permBlock // perpStride
|
|
|
|
module.addComment0("Computing strided(%u) perp indicies"%perpStrideInv)
|
|
module.add(VAndB32(dst=vgpr(reMap0), src0=(permBlock // perpStrideInv - 1), src1=vgpr(vgprReg), comment="r0 = I %% (%u // %u)"%(permBlock, perpStrideInv)))
|
|
module.add(VLShiftLeftB32(dst=vgpr(reMap0), shiftHex=log2(perpStrideInv), src=vgpr(reMap0), comment="r0 = %u * r0"%(perpStrideInv)))
|
|
module.addComment0("Computing r1 = (I %% %u) // (%u // %u)"%(permBlock, permBlock, perpStrideInv))
|
|
module.add(VAndB32(dst=vgpr(reMap1), src0=(permBlock - 1), src1=vgpr(vgprReg), comment="r1 = I %% (%u)"%(permBlock)))
|
|
module.add(VLShiftRightB32(dst=vgpr(reMap1), shiftHex=log2(permBlock // perpStrideInv), src=vgpr(reMap1), comment="r1 = (r1) // (%u // %u)"%(permBlock, perpStrideInv)))
|
|
module.add(VAddU32(dst=vgpr(reMap0), src0=vgpr(reMap0), src1=vgpr(reMap1), comment="r0 = r0 + r1" ))
|
|
|
|
module.add(VLShiftRightB32(dst=vgpr(reMap1), shiftHex=log2(permBlock), src=vgpr(vgprReg), comment="r1 = I // %u"%(permBlock)))
|
|
module.add(vectorStaticMultiplyAdd(vgpr(vgprReg), vgpr(reMap1), permBlock, vgpr(reMap0), None))
|
|
|
|
module.addComment0("Done computing strided(%u) perp indices"%perpStrideInv)
|
|
writer.vgprPool.checkIn(reMap0)
|
|
writer.vgprPool.checkIn(reMap1)
|
|
|
|
with writer.allocTmpSgpr(1, tag="LraTileAssignmentMFMA_tmpSgprInfo") as tmpSgprInfo:
|
|
|
|
if perpBlockSize > 0:
|
|
rotVgpr = writer.vgprPool.checkOut(1, tag="perpPerm_rotVgpr") # remainder
|
|
|
|
# tile offset
|
|
if tileSpan:
|
|
kReg = tReg
|
|
module.add(vectorStaticRemainder(dummy, kReg, dividendReg, waveWidth, tmpVgprRes, tmpSgprInfo, \
|
|
"0. thread id in wave: wtid = tid %% wavelength(%u)" % waveWidth))
|
|
if enableLDSTr:
|
|
module.add(vectorStaticRemainder(dummy, tReg, kReg, 4, tmpVgprRes, tmpSgprInfo, \
|
|
"1. N offset: nIdx = wtid %% 4"))
|
|
module.add(vectorStaticRemainder(dummy, sReg, kReg, dividendForKId, tmpVgprRes, tmpSgprInfo, \
|
|
"1. N offset: nIdx = wtid %% MI_M(%d)"%dividendForKId))
|
|
module.add(vectorStaticDivide(sReg, sReg, 16, tmpVgprRes, \
|
|
"1. thread id in wave: k1Idx = mtid // 16"))
|
|
module.add(vectorStaticMultiply(vgpr(sReg), vgpr(sReg), 16, tmpSgprInfo, \
|
|
"1. K1 offset: lrK1Offset = k1Idx * mStride(%u)" % (strideK1)))
|
|
|
|
else:
|
|
if not tileSpan or tileSpanWaveSplit:
|
|
# Base layout and TileSpan wave-split both wrap nIdx at MI. In the wave-split case
|
|
# the lower/upper half-wave share nIdx and the upper half-wave grabs the partner
|
|
# block via the hi offset added after the wave offset below.
|
|
module.add(vectorStaticRemainder(dummy, tReg, kReg, matrixInstTO, tmpVgprRes, tmpSgprInfo, \
|
|
"1. N offset: nIdx = wtid %% MI_N(%u)" % matrixInstTO))
|
|
else:
|
|
# TileSpan non-split (MIWaveGroup==1): one thread per M/N, nIdx = wtid (no wrap),
|
|
# so lanes 0..MI-1 vs MI..2MI-1 already carry block 2g / partner 2g+1 in the
|
|
# lower/upper half-wave of a single ds_load; no hi offset needed.
|
|
module.addComment0("N offset: nIdx = wtid")
|
|
|
|
applyVWCalcEarly = perpStride > 1 and kernel["ProblemType"]["TLU%s"%tc] == 0 and kernel["ProblemType"]["DataType"].numBytes() != 2
|
|
if applyVWCalcEarly:
|
|
# Apply vector width calc before we apply permutation to perp dim
|
|
module.add(vectorStaticMultiply(vgpr(tReg), vgpr(tReg), vectorWidth, tmpSgprInfo, \
|
|
"1. apply VectorWidth: bnOffset = bnOffset * vw(%u)" % vectorWidth))
|
|
perpPerm(tReg)
|
|
|
|
module.add(vectorStaticMultiply(vgpr(tReg), vgpr(tReg), strideTile, tmpSgprInfo, \
|
|
"1. N offset: nOffset = nIdx * nStride(%u)" % strideTile))
|
|
if enableLDSTr:
|
|
module.add(VAddU32(dst=vgpr(tReg), src0=vgpr(sReg), src1=vgpr(tReg), \
|
|
comment="1. offset in wave: lrOffset = bnOffset + lrKOffset"))
|
|
# block offset
|
|
if num1DBlocks > 1:
|
|
module.add(vectorStaticDivide(dummy, kReg, dividedForBlkId, tmpVgprRes, \
|
|
"2. block offset: bnIdx = wtid / dividedForBlkId(%u)" % dividedForBlkId))
|
|
module.add(vectorStaticRemainder(dummy, dummy, dummy, num1DBlocks, tmpVgprRes, tmpSgprInfo, \
|
|
"2. block offset: bnIdx = bnIdx %% num1DBlocks(%u)" % num1DBlocks))
|
|
module.add(vectorStaticMultiplyAdd(vgpr(tReg), vgpr(dummy), strideBlock, vgpr(tReg), tmpSgprInfo, \
|
|
"2. block offset: bnOffset = bnIdx * strideBlock(%u); 3. add N and block offset: bnOffset = block and N offset" % strideBlock))
|
|
else:
|
|
module.addComment0("Skip. 2. block offset: bnOffset = 0 when num1DBlocks = 1")
|
|
|
|
if not applyVWCalcEarly:
|
|
module.add(vectorStaticMultiply(vgpr(tReg), vgpr(tReg), vectorWidth, tmpSgprInfo, \
|
|
"4. apply VectorWidth: bnOffset = bnOffset * vw(%u)" % vectorWidth))
|
|
|
|
if perpBlockSize > 0:
|
|
# Moved here since we need to wait until vectorwidth calculation is applied
|
|
module.add(vectorStaticDivide(rotVgpr, tReg, perpBlockSize * strideTile, tmpVgprRes, \
|
|
"Test rotating"))
|
|
|
|
# unroll offset
|
|
#if isMfma and (dividendForKId != waveWidth):
|
|
if not noUnrollOffset:
|
|
if (dividendForKId != waveWidth) and (not isDTVAB):
|
|
if enableLDSTr:
|
|
module.add(vectorStaticRemainder(dummy, mReg, kReg, 16, tmpVgprRes, tmpSgprInfo, \
|
|
"5.1 thread id in wave: mtid = wtid %% 16"))
|
|
module.add(vectorStaticDivide(mReg, mReg, 4, tmpVgprRes, \
|
|
"5.2 thread id in wave: k1Idx = mtid // 4"))
|
|
if (dividendForKId != waveWidth) or isDTVAB:
|
|
# DTVAB case, add this regardless of dividendForKId != waveWidth
|
|
module.add(vectorStaticDivide(kReg, kReg, dividendForKId, tmpVgprRes, \
|
|
"5. K offset: kIdx = wtid / (MIN(%u) * MIBB(%u))" % (matrixInstTO, kernel["MatrixInstB"])))
|
|
|
|
if perpBlockSize > 0:
|
|
module.add(VAddU32(dst=vgpr(kReg), src0=vgpr(kReg), src1=vgpr(rotVgpr), \
|
|
comment="rotate"))
|
|
module.add(VAndB32(dst=vgpr(kReg), src0=(abmatrixinfo.gRDtlSwizzleParaBlockSize - 1), src1=vgpr(kReg), \
|
|
comment="rotate: numThreadsCoalesced: %u"%(abmatrixinfo.gRDtlSwizzleParaBlockSize)))
|
|
if (dividendForKId != waveWidth) and (not isDTVAB):
|
|
|
|
if enableLDSTr:
|
|
module.add(vectorStaticMultiply(vgpr(kReg), vgpr(kReg), strideK, tmpSgprInfo, \
|
|
"5. K offset: lrKOffset = kIdx * mStride(%u)" % (strideK)))
|
|
|
|
if perpStride == 1:
|
|
module.add(vectorStaticMultiply(vgpr(mReg), vgpr(mReg), strideK1, tmpSgprInfo, \
|
|
"5.1 K1 offset: lrK1Offset = k1Idx * mStride(%u)" % (strideK1)))
|
|
module.add(VAddU32(dst=vgpr(kReg), src0=vgpr(mReg), src1=vgpr(kReg), \
|
|
comment="5.1 offset in wave: lrOffset = bnOffset + lrKOffset"))
|
|
else:
|
|
module.add(VAddU32(dst=vgpr(kReg), src0=vgpr(mReg), src1=vgpr(kReg), \
|
|
comment="5.1 offset in wave: lrOffset = bnOffset + lrKOffset"))
|
|
# Apply permutation to perpendicular dim
|
|
if perpStride > 1:
|
|
perpPerm(kReg)
|
|
module.add(vectorStaticMultiply(vgpr(kReg), vgpr(kReg), strideK1, tmpSgprInfo, \
|
|
"5.2 K1 offset: lrK1Offset = k1Idx * mStride(%u)" % (strideK1)))
|
|
module.add(VAddU32(dst=vgpr(tReg), src0=vgpr(kReg), src1=vgpr(tReg), \
|
|
comment="6. offset in wave: lrOffset = bnOffset + lrKOffset"))
|
|
else:
|
|
module.add(vectorStaticMultiplyAdd(vgpr(tReg), vgpr(kReg), strideK, vgpr(tReg), tmpSgprInfo, \
|
|
"5. K offset: lrKOffset = kIdx * mStride(%u); 6. offset in wave: lrOffset = bnOffset + lrKOffset" % (strideK)))
|
|
|
|
# wave offset
|
|
if num1DWaves > 1:
|
|
module.add(vectorStaticDivide(dummy, dividendReg, dividedForWaveId, tmpVgprRes, \
|
|
"7. wave offset in N dimen: wtid = tid / dividedForWaveId(%u)" % dividedForWaveId))
|
|
module.add(vectorStaticRemainder(dummy, dummy, dummy, num1DWaves, tmpVgprRes, tmpSgprInfo, \
|
|
"7. wave offset in M dimen: wtid0 = wtid / num1DWaves(%u)" % num1DWaves))
|
|
if kernel.get("LDSSegmentInterleave") == 1 and kernel["LDSSegInterleaveOffsets"].get("footprintPacked") and segILWaveSpansComp:
|
|
# wave spans a whole component: stash its component jump; added post-pad in lraFinalOffset.
|
|
segOff = writer.vgprPool.checkOut(1, tag="segWaveByteOff")
|
|
module.add(vectorStaticMultiply(vgpr(segOff), vgpr(dummy), kernel["LDSSegInterleaveOffsets"]["writeStrideBytes"], tmpSgprInfo, \
|
|
"seg interleave: component byte offset = wtid0 * (fA+fB)"))
|
|
tP["gpr"]["segWaveByteOff"] = segOff
|
|
else:
|
|
module.add(vectorStaticMultiplyAdd(vgpr(tReg), vgpr(dummy), strideWave, vgpr(tReg), tmpSgprInfo, \
|
|
"7. wave offset in M dimen: wOffset = wtid0 * W0Stride(%u); 7. final local read offset: flrOffset = lrOffset + WOffset" % strideWave))
|
|
if tileSpanWaveSplit:
|
|
# TileSpan wave-split: the upper half-wave reads the partner scale block
|
|
# @+hiOffset. Bake it into the per-lane address so a single ds_load holds
|
|
# both blocks (lower/upper half-wave), which the WMMA then selects between
|
|
# via matrix_{a,b}_scale. hiOffset = full tile-half span in bytes.
|
|
hiOffset = matrixInstT * num1DBlocks * num1DWaves * vectorWidth * strideTile
|
|
# axis-neutral: tile01==0 -> M axis (MXSA), tile01==1 -> N axis (MXSB)
|
|
tileDim = "M" if tile01 == 0 else "N"
|
|
module.add(vectorStaticDivide(dummy, dividendReg, matrixInstTO, tmpVgprRes, \
|
|
"8. (TileSpan wave-split) hiSel = tid / MI_dim(%u)" % matrixInstTO))
|
|
module.add(VAndB32(dst=vgpr(dummy), src0=1, src1=vgpr(dummy), \
|
|
comment="8. (TileSpan wave-split) hi = (tid / MI_dim) & 1 (lower/upper half-wave)"))
|
|
module.add(vectorStaticMultiplyAdd(vgpr(tReg), vgpr(dummy), hiOffset, vgpr(tReg), tmpSgprInfo, \
|
|
"8. (TileSpan wave-split) wave offset in %s dimen: wOffset += hi * hiOffset(%u); upper half-wave grabs partner block" % (tileDim, hiOffset)))
|
|
if perpBlockSize > 0:
|
|
writer.vgprPool.checkIn(rotVgpr)
|
|
|
|
# release register
|
|
writer.vgprPool.checkIn(dummy)
|
|
writer.vgprPool.checkIn(mReg)
|
|
if enableLDSTr:
|
|
writer.vgprPool.checkIn(sReg)
|
|
|
|
return module
|