source: CLRX/CLRadeonExtender/trunk/amdasm/GCNAsmEncode1.cpp @ 4998

Last change on this file since 4998 was 4998, checked in by matszpk, 11 months ago

CLRadeonExtender: GCNASM: Preliminary support for SMRD 32-bit immediate literal if arch==GCN1.1.

File size: 109.6 KB
Line 
1/*
2 *  CLRadeonExtender - Unofficial OpenCL Radeon Extensions Library
3 *  Copyright (C) 2014-2018 Mateusz Szpakowski
4 *
5 *  This library is free software; you can redistribute it and/or
6 *  modify it under the terms of the GNU Lesser General Public
7 *  License as published by the Free Software Foundation; either
8 *  version 2.1 of the License, or (at your option) any later version.
9 *
10 *  This library is distributed in the hope that it will be useful,
11 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 *  Lesser General Public License for more details.
14 *
15 *  You should have received a copy of the GNU Lesser General Public
16 *  License along with this library; if not, write to the Free Software
17 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
18 */
19
20#include <CLRX/Config.h>
21#include <cstdio>
22#include <vector>
23#include <memory>
24#include <cstring>
25#include <algorithm>
26#include <CLRX/amdasm/Assembler.h>
27#include <CLRX/utils/Utilities.h>
28#include <CLRX/utils/GPUId.h>
29#include <CLRX/amdasm/GCNDefs.h>
30#include "GCNAsmInternals.h"
31
32namespace CLRX
33{
34
35static const uint32_t constImmFloatLiterals[9] = 
36{
37    0x3f000000, 0xbf000000, 0x3f800000, 0xbf800000,
38    0x40000000, 0xc0000000, 0x40800000, 0xc0800000, 0x3e22f983
39};
40
41// used while converting 32-bit SOPx encoding to 64-bit SOPx encoding
42static void tryPromoteConstImmToLiteral(GCNOperand& src0Op, GPUArchMask arch)
43{
44    if (!src0Op.range.isRegVar() && src0Op.range.start>=128 && src0Op.range.start<=208)
45    {
46        // convert integer const immediates
47        src0Op.value = src0Op.range.start<193? src0Op.range.start-128 :
48                192-src0Op.range.start;
49        src0Op.range.start = 255;
50    }
51    else if (!src0Op.range.isRegVar() &&
52            ((src0Op.range.start>=240 && src0Op.range.start<248) ||
53             ((arch&ARCH_GCN_1_2_4_5)!=0 && src0Op.range.start==248)))
54    {
55        // floating point immediates to literal
56        src0Op.value = constImmFloatLiterals[src0Op.range.start-240];
57        src0Op.range.start = 255;
58    }
59}
60
61// check whether reg range can be equal (regvar and registers)
62static inline bool regRangeCanEqual(const RegRange& r1, const RegRange& r2)
63{
64    return r1.regVar==r2.regVar && r1.start==r2.start;
65}
66
67bool GCNAsmUtils::parseSOP2Encoding(Assembler& asmr, const GCNAsmInstruction& gcnInsn,
68                  const char* instrPlace, const char* linePtr, GPUArchMask arch,
69                  std::vector<cxbyte>& output, GCNAssembler::Regs& gcnRegs,
70                  GCNEncSize gcnEncSize)
71{
72    bool good = true;
73    RegRange dstReg(0, 0);
74    GCNAssembler* gcnAsm = static_cast<GCNAssembler*>(asmr.isaAssembler);
75   
76    if ((gcnInsn.mode & GCN_MASK1) != GCN_DST_NONE)
77    {
78        // parse SDST (SGPR)
79        gcnAsm->setCurrentRVU(0);
80        good &= parseSRegRange(asmr, linePtr, dstReg, arch,
81                   (gcnInsn.mode&GCN_REG_DST_64)?2:1, GCNFIELD_SDST, true,
82                   INSTROP_SYMREGRANGE|INSTROP_WRITE);
83        if (!skipRequiredComma(asmr, linePtr))
84            return false;
85    }
86   
87    std::unique_ptr<AsmExpression> src0Expr, src1Expr;
88    // parse SRC0 (can be SGPR or scalar source)
89    GCNOperand src0Op{};
90    gcnAsm->setCurrentRVU(1);
91    good &= parseOperand(asmr, linePtr, src0Op, &src0Expr, arch,
92             (gcnInsn.mode&GCN_REG_SRC0_64)?2:1, INSTROP_SSOURCE|INSTROP_SREGS|
93                         INSTROP_READ, GCNFIELD_SSRC0);
94    if (!skipRequiredComma(asmr, linePtr))
95        return false;
96    GCNOperand src1Op{};
97    // parse SRC1 (can be SGPR or scalar source)
98    gcnAsm->setCurrentRVU(2);
99    good &= parseOperand(asmr, linePtr, src1Op, &src1Expr, arch,
100             (gcnInsn.mode&GCN_REG_SRC1_64)?2:1, INSTROP_SSOURCE|INSTROP_SREGS|
101             (src0Op.range.isVal(255) ? INSTROP_ONLYINLINECONSTS : 0)|INSTROP_READ,
102             GCNFIELD_SSRC1);
103   
104    /// if errors
105    if (!good || !checkGarbagesAtEnd(asmr, linePtr))
106        return false;
107   
108    if (gcnEncSize==GCNEncSize::BIT64)
109    {
110        // try to promote constant immediate to literal
111        tryPromoteConstImmToLiteral(src0Op, arch);
112        tryPromoteConstImmToLiteral(src1Op, arch);
113    }
114    // put data
115    cxuint wordsNum = 1;
116    uint32_t words[2];
117    SLEV(words[0], 0x80000000U | (uint32_t(gcnInsn.code1)<<23) | src0Op.range.bstart() |
118            (src1Op.range.bstart()<<8) | uint32_t(dstReg.bstart())<<16);
119    if (src0Op.range.isVal(255) || src1Op.range.isVal(255))
120    {
121        // put literal value
122        if (src0Expr==nullptr && src1Expr==nullptr)
123            SLEV(words[1], src0Op.range.isVal(255) ? src0Op.value : src1Op.value);
124        else    // zero if unresolved value
125            SLEV(words[1], 0);
126        wordsNum++;
127    }
128    if (!checkGCNEncodingSize(asmr, instrPlace, gcnEncSize, wordsNum))
129        return false;
130    // set expression targets to resolving later
131    if (src0Expr!=nullptr)
132        src0Expr->setTarget(AsmExprTarget(GCNTGT_LITIMM, asmr.currentSection,
133                      output.size()));
134    else if (src1Expr!=nullptr)
135        src1Expr->setTarget(AsmExprTarget(GCNTGT_LITIMM, asmr.currentSection,
136                      output.size()));
137   
138    output.insert(output.end(), reinterpret_cast<cxbyte*>(words), 
139            reinterpret_cast<cxbyte*>(words + wordsNum));
140    // prevent freeing expressions
141    src0Expr.release();
142    src1Expr.release();
143    // update SGPR counting and VCC usage (regflags)
144    if (dstReg && !dstReg.isRegVar())
145    {
146        updateSGPRsNum(gcnRegs.sgprsNum, dstReg.end-1, arch);
147        updateRegFlags(gcnRegs.regFlags, dstReg.start, arch);
148    }
149    if (src0Op.range && !src0Op.range.isRegVar())
150        updateRegFlags(gcnRegs.regFlags, src0Op.range.start, arch);
151    if (src1Op.range && !src1Op.range.isRegVar())
152        updateRegFlags(gcnRegs.regFlags, src1Op.range.start, arch);
153    return true;
154}
155
156bool GCNAsmUtils::parseSOP1Encoding(Assembler& asmr, const GCNAsmInstruction& gcnInsn,
157                  const char* instrPlace, const char* linePtr, GPUArchMask arch,
158                  std::vector<cxbyte>& output, GCNAssembler::Regs& gcnRegs,
159                  GCNEncSize gcnEncSize)
160{
161    bool good = true;
162    GCNAssembler* gcnAsm = static_cast<GCNAssembler*>(asmr.isaAssembler);
163    RegRange dstReg(0, 0);
164   
165    if ((gcnInsn.mode & GCN_MASK1) != GCN_DST_NONE)
166    {
167        // parse SDST (SGPR)
168        gcnAsm->setCurrentRVU(0);
169        good &= parseSRegRange(asmr, linePtr, dstReg, arch,
170                       (gcnInsn.mode&GCN_REG_DST_64)?2:1, GCNFIELD_SDST, true,
171                       INSTROP_SYMREGRANGE|INSTROP_WRITE);
172        if ((gcnInsn.mode & GCN_MASK1) != GCN_SRC_NONE)
173            if (!skipRequiredComma(asmr, linePtr))
174                return false;
175    }
176   
177    GCNOperand src0Op{};
178    std::unique_ptr<AsmExpression> src0Expr;
179    if ((gcnInsn.mode & GCN_MASK1) != GCN_SRC_NONE)
180    {
181        // parse SRC0 (can be SGPR or source scalar, constant or literal)
182        gcnAsm->setCurrentRVU(1);
183        good &= parseOperand(asmr, linePtr, src0Op, &src0Expr, arch,
184                 (gcnInsn.mode&GCN_REG_SRC0_64)?2:1, INSTROP_SSOURCE|INSTROP_SREGS|
185                         INSTROP_READ, GCNFIELD_SSRC0);
186    }
187   
188    /// if errors
189    if (!good || !checkGarbagesAtEnd(asmr, linePtr))
190        return false;
191   
192    if (gcnEncSize==GCNEncSize::BIT64)
193        // try to promote constant immediate to literal
194        tryPromoteConstImmToLiteral(src0Op, arch);
195    cxuint wordsNum = 1;
196    uint32_t words[2];
197    // put instruction word
198    SLEV(words[0], 0xbe800000U | (uint32_t(gcnInsn.code1)<<8) | src0Op.range.bstart() |
199            uint32_t(dstReg.bstart())<<16);
200    if (src0Op.range.start==255)
201    {
202        // put literal
203        if (src0Expr==nullptr)
204            SLEV(words[1], src0Op.value);
205        else    // zero if unresolved value
206            SLEV(words[1], 0);
207        wordsNum++;
208    }
209    if (!checkGCNEncodingSize(asmr, instrPlace, gcnEncSize, wordsNum))
210        return false;
211    // set expression targets
212    if (src0Expr!=nullptr)
213        src0Expr->setTarget(AsmExprTarget(GCNTGT_LITIMM, asmr.currentSection,
214                      output.size()));
215   
216    output.insert(output.end(), reinterpret_cast<cxbyte*>(words), 
217            reinterpret_cast<cxbyte*>(words + wordsNum));
218    // prevent freeing expressions
219    src0Expr.release();
220    // update SGPR counting and VCC usage (regflags)
221    if (dstReg && !dstReg.isRegVar())
222    {
223        updateSGPRsNum(gcnRegs.sgprsNum, dstReg.end-1, arch);
224        updateRegFlags(gcnRegs.regFlags, dstReg.start, arch);
225    }
226    if (src0Op.range && !src0Op.range.isRegVar())
227        updateRegFlags(gcnRegs.regFlags, src0Op.range.start, arch);
228    return true;
229}
230
231// hwreg names sorted by names
232static const std::pair<const char*, cxuint> hwregNamesMap[] =
233{
234    { "gpr_alloc", 5 },
235    { "hw_id", 4 },
236    { "ib_dbg0", 12 },
237    { "ib_dbg1", 13 },
238    { "ib_sts", 7 },
239    { "inst_dw0", 10 },
240    { "inst_dw1", 11 },
241    { "lds_alloc", 6 },
242    { "mode", 1 },
243    { "pc_hi", 9 },
244    { "pc_lo", 8 },
245    { "status", 2 },
246    { "trapsts", 3 }
247};
248
249static const size_t hwregNamesMapSize = sizeof(hwregNamesMap) /
250            sizeof(std::pair<const char*, uint16_t>);
251
252// update SGPR counting and VCC usage (regflags) for GCN 1.4 (VEGA)
253static const std::pair<const char*, cxuint> hwregNamesGCN14Map[] =
254{
255    { "flush_ib", 14 },
256    { "gpr_alloc", 5 },
257    { "hw_id", 4 },
258    { "ib_dbg0", 12 },
259    { "ib_dbg1", 13 },
260    { "ib_sts", 7 },
261    { "inst_dw0", 10 },
262    { "inst_dw1", 11 },
263    { "lds_alloc", 6 },
264    { "mode", 1 },
265    { "pc_hi", 9 },
266    { "pc_lo", 8 },
267    { "sh_mem_bases", 15 },
268    { "sq_shader_tba_hi", 17 },
269    { "sq_shader_tba_lo", 16 },
270    { "sq_shader_tma_hi", 19 },
271    { "sq_shader_tma_lo", 18 },
272    { "status", 2 },
273    { "tba_hi", 17 },
274    { "tba_lo", 16 },
275    { "tma_hi", 19 },
276    { "tma_lo", 18 },
277    { "trapsts", 3 }
278};
279
280static const size_t hwregNamesGCN14MapSize = sizeof(hwregNamesGCN14Map) /
281            sizeof(std::pair<const char*, uint16_t>);
282
283// update SGPR counting and VCC usage (regflags) for GCN 1.4 (VEGA)
284static const std::pair<const char*, cxuint> hwregNamesGCN15Map[] =
285{
286    { "flat_scr_hi", 21 },
287    { "flat_scr_lo", 20 },
288    { "flush_ib", 14 },
289    { "gpr_alloc", 5 },
290    { "hw_id", 4 },
291    { "ib_dbg0", 12 },
292    { "ib_dbg1", 13 },
293    { "ib_sts", 7 },
294    { "inst_dw0", 10 },
295    { "inst_dw1", 11 },
296    { "lds_alloc", 6 },
297    { "mode", 1 },
298    { "pc_hi", 9 },
299    { "pc_lo", 8 },
300    { "pops_packer", 23 },
301    { "sh_mem_bases", 15 },
302    { "sq_shader_tba_hi", 17 },
303    { "sq_shader_tba_lo", 16 },
304    { "sq_shader_tma_hi", 19 },
305    { "sq_shader_tma_lo", 18 },
306    { "status", 2 },
307    { "tba_hi", 17 },
308    { "tba_lo", 16 },
309    { "tma_hi", 19 },
310    { "tma_lo", 18 },
311    { "trapsts", 3 },
312    { "xnack_mask", 22 },
313};
314
315static const size_t hwregNamesGCN15MapSize = sizeof(hwregNamesGCN15Map) /
316            sizeof(std::pair<const char*, uint16_t>);
317
318bool GCNAsmUtils::parseSOPKEncoding(Assembler& asmr, const GCNAsmInstruction& gcnInsn,
319                  const char* instrPlace, const char* linePtr, GPUArchMask arch,
320                  std::vector<cxbyte>& output, GCNAssembler::Regs& gcnRegs,
321                  GCNEncSize gcnEncSize)
322{
323    const char* end = asmr.line+asmr.lineSize;
324    bool good = true;
325    RegRange dstReg(0, 0);
326    GCNAssembler* gcnAsm = static_cast<GCNAssembler*>(asmr.isaAssembler);
327    const bool isGCN14 = (arch & ARCH_GCN_1_4)!=0;
328    const bool isGCN15 = (arch & ARCH_GCN_1_5)!=0;
329   
330    gcnAsm->setCurrentRVU(0);
331    bool doWrite = (gcnInsn.mode&GCN_MASK1) != GCN_DST_SRC &&
332            ((gcnInsn.mode&GCN_MASK1) != GCN_IMM_REL);
333    if ((gcnInsn.mode & GCN_IMM_DST) == 0 && (gcnInsn.mode&GCN_MASK1) != GCN_DST_NONE)
334    {
335        // parse SDST (SGPR)
336        good &= parseSRegRange(asmr, linePtr, dstReg, arch,
337                   (gcnInsn.mode&GCN_REG_DST_64)?2:1, GCNFIELD_SDST, true,
338                   INSTROP_SYMREGRANGE|
339                   (doWrite ? INSTROP_WRITE : INSTROP_READ));
340        if (!skipRequiredComma(asmr, linePtr))
341            return false;
342    }
343   
344    uint16_t imm16 = 0;
345    std::unique_ptr<AsmExpression> imm16Expr;
346   
347    if ((gcnInsn.mode&GCN_MASK1) == GCN_IMM_REL)
348    {
349        // parse relative address
350        uint64_t value = 0;
351        if (!getJumpValueArg(asmr, value, imm16Expr, linePtr))
352            return false;
353        if (imm16Expr==nullptr)
354        {
355            // if resolved at this time
356            int64_t offset = (int64_t(value)-int64_t(output.size())-4);
357            if (offset & 3)
358                ASM_NOTGOOD_BY_ERROR(linePtr, "Jump is not aligned to word!")
359            offset >>= 2;
360            if (offset > INT16_MAX || offset < INT16_MIN)
361                ASM_NOTGOOD_BY_ERROR(linePtr, "Jump out of range")
362            imm16 = offset;
363            // add codeflow entry
364            if (good)
365            {
366                asmr.sections[asmr.currentSection].addCodeFlowEntry({ 
367                    size_t(asmr.currentOutPos), size_t(value),
368                    ((isGCN14 && gcnInsn.code1==21) || (isGCN15 && gcnInsn.code1==22)) ?
369                            AsmCodeFlowType::CALL : AsmCodeFlowType::CJUMP });
370            }
371        }
372    }
373    else if ((gcnInsn.mode&GCN_MASK1) == GCN_IMM_SREG)
374    {
375        // parse hwreg: hwreg(HWREG, bitstart, bitsize)
376        skipSpacesToEnd(linePtr, end);
377        char name[20];
378        const char* funcNamePlace = linePtr;
379        if (!getNameArg(asmr, 20, name, linePtr, "function name", true))
380            return false;
381        toLowerString(name);
382        skipSpacesToEnd(linePtr, end);
383        // if not hwreg
384        if (::strcmp(name, "hwreg")!=0 || linePtr==end || *linePtr!='(')
385            ASM_FAIL_BY_ERROR(funcNamePlace, "Expected hwreg function")
386        ++linePtr;
387        skipSpacesToEnd(linePtr, end);
388        cxuint hwregId = 0;
389        if (linePtr == end || *linePtr!='@')
390        {
391            // parse hwreg by name
392            const char* hwregNamePlace = linePtr;
393            // choose hwReg names map
394            const size_t regMapSize = isGCN15 ? hwregNamesGCN15MapSize :
395                        (isGCN14 ? hwregNamesGCN14MapSize : hwregNamesMapSize);
396            const std::pair<const char*, cxuint>* regMap = isGCN15 ? hwregNamesGCN15Map :
397                        (isGCN14 ? hwregNamesGCN14Map : hwregNamesMap);
398            good &= getEnumeration(asmr, linePtr, "HWRegister",
399                        regMapSize, regMap, hwregId, "hwreg_");
400            if (good && (arch & ARCH_GCN_1_2_4_5) == 0 && hwregId == 13)
401                // if ib_dgb1 in not GCN 1.2
402                ASM_NOTGOOD_BY_ERROR(hwregNamePlace, "Unknown HWRegister")
403        }
404        else
405        {
406            // parametrization (if preceded by '@')
407            linePtr++;
408            good &= parseImm(asmr, linePtr, hwregId, nullptr, 6, WS_UNSIGNED);
409        }
410       
411        if (!skipRequiredComma(asmr, linePtr))
412            return false;
413        uint64_t arg2Value = 0;
414        skipSpacesToEnd(linePtr, end);
415        const char* funcArg2Place = linePtr;
416       
417        // second argument of hwreg
418        if (getAbsoluteValueArg(asmr, arg2Value, linePtr, true))
419        {
420            if (arg2Value >= 32)
421                asmr.printWarning(funcArg2Place, "Second argument out of range (0-31)");
422        }
423        else
424            good = false;
425       
426        if (!skipRequiredComma(asmr, linePtr))
427            return false;
428        uint64_t arg3Value = 0;
429        skipSpacesToEnd(linePtr, end);
430        const char* funcArg3Place = linePtr;
431       
432        // second argument of hwreg
433        if (getAbsoluteValueArg(asmr, arg3Value, linePtr, true))
434        {
435            if (arg3Value >= 33 || arg3Value < 1)
436                asmr.printWarning(funcArg3Place, "Third argument out of range (1-32)");
437        }
438        else
439            good = false;
440       
441        skipSpacesToEnd(linePtr, end);
442        if (linePtr==end || *linePtr!=')')
443            ASM_FAIL_BY_ERROR(linePtr, "Unterminated hwreg function")
444        ++linePtr;
445        imm16 = hwregId | (arg2Value<<6) | ((arg3Value-1)<<11);
446    }
447    else // otherwise we parse expression
448        good &= parseImm(asmr, linePtr, imm16, &imm16Expr);
449   
450    uint32_t imm32 = 0;
451    std::unique_ptr<AsmExpression> imm32Expr;
452    if ((gcnInsn.mode & GCN_IMM_DST) != 0 && (gcnInsn.mode&GCN_MASK1) != GCN_DST_NONE)
453    {
454        // parse SDST as immediate or next source
455        if (!skipRequiredComma(asmr, linePtr))
456            return false;
457        if (gcnInsn.mode & GCN_SOPK_CONST)
458            good &= parseImm(asmr, linePtr, imm32, &imm32Expr);
459        else
460            good &= parseSRegRange(asmr, linePtr, dstReg, arch,
461                   (gcnInsn.mode&GCN_REG_DST_64)?2:1, GCNFIELD_SDST, true,
462                   INSTROP_SYMREGRANGE|INSTROP_READ); // new field!
463    }
464   
465    if (!good || !checkGarbagesAtEnd(asmr, linePtr))
466        return false;
467   
468    const cxuint wordsNum = (gcnInsn.mode & GCN_SOPK_CONST) ? 2 : 1;
469    if (!checkGCNEncodingSize(asmr, instrPlace, gcnEncSize, wordsNum))
470        return false;
471   
472    // put data (instruction words)
473    uint32_t words[2];
474    SLEV(words[0], 0xb0000000U | imm16 | (uint32_t(dstReg.bstart())<<16) |
475                uint32_t(gcnInsn.code1)<<23);
476    if (wordsNum==2)
477        SLEV(words[1], imm32);
478   
479    // setting expresion targets (for immediates)
480    if (imm32Expr!=nullptr)
481        imm32Expr->setTarget(AsmExprTarget(GCNTGT_LITIMM, asmr.currentSection,
482                           output.size()));
483    if (imm16Expr!=nullptr)
484        imm16Expr->setTarget(AsmExprTarget(((gcnInsn.mode&GCN_MASK1) == GCN_IMM_REL) ?
485                GCNTGT_SOPJMP : GCNTGT_SOPKSIMM16, asmr.currentSection, output.size()));
486   
487    output.insert(output.end(), reinterpret_cast<cxbyte*>(words), 
488            reinterpret_cast<cxbyte*>(words + wordsNum));
489    /// prevent freeing expression
490    imm32Expr.release();
491    imm16Expr.release();
492    // update SGPR counting and VCC usage (regflags)
493    if (dstReg && !dstReg.isRegVar() && doWrite && (gcnInsn.mode & GCN_IMM_DST)==0)
494        updateSGPRsNum(gcnRegs.sgprsNum, dstReg.end-1, arch);
495    if (dstReg && !dstReg.isRegVar())
496        updateRegFlags(gcnRegs.regFlags, dstReg.start, arch);
497    return true;
498}
499
500bool GCNAsmUtils::parseSOPCEncoding(Assembler& asmr, const GCNAsmInstruction& gcnInsn,
501                  const char* instrPlace, const char* linePtr, GPUArchMask arch,
502                  std::vector<cxbyte>& output, GCNAssembler::Regs& gcnRegs,
503                  GCNEncSize gcnEncSize)
504{
505    bool good = true;
506    std::unique_ptr<AsmExpression> src0Expr, src1Expr;
507    GCNAssembler* gcnAsm = static_cast<GCNAssembler*>(asmr.isaAssembler);
508    GCNOperand src0Op{};
509   
510    // parse SRC0 (can be SGPR, source scalar, literal or constant
511    gcnAsm->setCurrentRVU(0);
512    good &= parseOperand(asmr, linePtr, src0Op, &src0Expr, arch,
513             (gcnInsn.mode&GCN_REG_SRC0_64)?2:1, INSTROP_SSOURCE|INSTROP_SREGS|
514                     INSTROP_READ, GCNFIELD_SSRC0);
515    if (!skipRequiredComma(asmr, linePtr))
516        return false;
517    GCNOperand src1Op{};
518    if ((gcnInsn.mode & GCN_SRC1_IMM) == 0)
519    {
520        // parse SRC1 (can be SGPR, source scalar, literal or constant
521        gcnAsm->setCurrentRVU(1);
522        good &= parseOperand(asmr, linePtr, src1Op, &src1Expr, arch,
523                 (gcnInsn.mode&GCN_REG_SRC1_64)?2:1, INSTROP_SSOURCE|INSTROP_SREGS|
524                 (src0Op.range.start==255 ? INSTROP_ONLYINLINECONSTS : 0)|INSTROP_READ,
525                         GCNFIELD_SSRC1);
526    }
527    else // immediate
528        good &= parseImm(asmr, linePtr, src1Op.range.start, &src1Expr, 8);
529   
530    /// if errors
531    if (!good || !checkGarbagesAtEnd(asmr, linePtr))
532        return false;
533   
534    if (gcnEncSize==GCNEncSize::BIT64)
535    {
536        // try to promote constant immediate to literal
537        tryPromoteConstImmToLiteral(src0Op, arch);
538        tryPromoteConstImmToLiteral(src1Op, arch);
539    }
540    // put data
541    cxuint wordsNum = 1;
542    uint32_t words[2];
543    SLEV(words[0], 0xbf000000U | (uint32_t(gcnInsn.code1)<<16) | src0Op.range.bstart() |
544            (src1Op.range.bstart()<<8));
545    if (src0Op.range.start==255 ||
546        ((gcnInsn.mode & GCN_SRC1_IMM)==0 && src1Op.range.start==255))
547    {
548        // put literal
549        if (src0Expr==nullptr && src1Expr==nullptr)
550            SLEV(words[1], src0Op.range.isVal(255) ? src0Op.value : src1Op.value);
551        else    // zero if unresolved value
552            SLEV(words[1], 0);
553        wordsNum++;
554    }
555    if (!checkGCNEncodingSize(asmr, instrPlace, gcnEncSize, wordsNum))
556        return false;
557    // set expression targets
558    if (src0Expr!=nullptr)
559        src0Expr->setTarget(AsmExprTarget(GCNTGT_LITIMM, asmr.currentSection,
560                      output.size()));
561    else if (src1Expr!=nullptr)
562        src1Expr->setTarget(AsmExprTarget(
563            ((gcnInsn.mode&GCN_SRC1_IMM)) ? GCNTGT_SOPCIMM8 : GCNTGT_LITIMM,
564            asmr.currentSection, output.size()));
565   
566    output.insert(output.end(), reinterpret_cast<cxbyte*>(words), 
567            reinterpret_cast<cxbyte*>(words + wordsNum));
568    // prevent freeing expressions
569    src0Expr.release();
570    src1Expr.release();
571    // update SGPR counting and VCC usage (regflags)
572    if (src0Op.range && !src0Op.range.isRegVar())
573        updateRegFlags(gcnRegs.regFlags, src0Op.range.start, arch);
574    if (src1Op.range && !src1Op.range.isRegVar())
575        updateRegFlags(gcnRegs.regFlags, src1Op.range.start, arch);
576    return true;
577}
578
579// message names sorted by name
580static const std::pair<const char*, uint16_t> sendMessageNamesMap[] =
581{
582    { "gs", 2 },
583    { "gs_done", 3 },
584    { "interrupt", 1 },
585    { "savewave", 4 },
586    { "sysmsg", 15 },
587    { "system", 15 }
588};
589
590static const size_t sendMessageNamesMapSize = sizeof(sendMessageNamesMap) /
591            sizeof(std::pair<const char*, uint16_t>);
592
593// message names sorted by name for GCN1.4 (VEGA)
594static const std::pair<const char*, uint16_t> sendMessageNamesGCN14Map[] =
595{
596    { "early_prim_dealloc", 8 },
597    { "get_doorbell", 10 },
598    { "gs", 2 },
599    { "gs_alloc_req", 9 },
600    { "gs_done", 3 },
601    { "halt_waves", 6 },
602    { "interrupt", 1 },
603    { "ordered_ps_done", 7 },
604    { "savewave", 4 },
605    { "stall_wave_gen", 5 },
606    { "sysmsg", 15 },
607    { "system", 15 }
608};
609
610static const size_t sendMessageNamesGCN14MapSize = sizeof(sendMessageNamesGCN14Map) /
611            sizeof(std::pair<const char*, uint16_t>);
612
613static const char* sendMsgGSOPTable[] =
614{ "nop", "cut", "emit", "emit_cut" };
615
616static const size_t sendMsgGSOPTableSize = sizeof(sendMsgGSOPTable) / sizeof(const char*);
617
618bool GCNAsmUtils::parseSOPPEncoding(Assembler& asmr, const GCNAsmInstruction& gcnInsn,
619                  const char* instrPlace, const char* linePtr, GPUArchMask arch,
620                  std::vector<cxbyte>& output, GCNAssembler::Regs& gcnRegs,
621                  GCNEncSize gcnEncSize)
622{
623    const char* end = asmr.line+asmr.lineSize;
624    GCNAssembler* gcnAsm = static_cast<GCNAssembler*>(asmr.isaAssembler);
625    bool good = true;
626    const bool isGCN14 = (arch & ARCH_GCN_1_4)!=0;
627    const bool isGCN15 = (arch & ARCH_GCN_1_5)!=0;
628    if (gcnEncSize==GCNEncSize::BIT64)
629        ASM_FAIL_BY_ERROR(instrPlace, "Only 32-bit size for SOPP encoding")
630   
631    uint16_t imm16 = 0;
632    std::unique_ptr<AsmExpression> imm16Expr;
633    switch (gcnInsn.mode&GCN_MASK1)
634    {
635        case GCN_IMM_REL:
636        {
637            // parse relative address
638            uint64_t value = 0;
639            if (!getJumpValueArg(asmr, value, imm16Expr, linePtr))
640                return false;
641            if (imm16Expr==nullptr)
642            {
643                int64_t offset = (int64_t(value)-int64_t(output.size())-4);
644                if (offset & 3)
645                    ASM_NOTGOOD_BY_ERROR(linePtr, "Jump is not aligned to word!")
646                offset >>= 2;
647                if (offset > INT16_MAX || offset < INT16_MIN)
648                    ASM_NOTGOOD_BY_ERROR(linePtr, "Jump out of range")
649                imm16 = offset;
650                Assembler& asmr = gcnAsm->assembler;
651                // add codeflow entry
652                if (good)
653                    asmr.sections[asmr.currentSection].addCodeFlowEntry({ 
654                        size_t(asmr.currentOutPos), size_t(value),
655                        gcnInsn.code1==2 ? AsmCodeFlowType::JUMP :
656                            AsmCodeFlowType::CJUMP });
657            }
658            break;
659        }
660        case GCN_IMM_LOCKS:
661        {
662            /* parse locks for s_waitcnt */
663            char name[20];
664            bool haveLgkmCnt = false;
665            bool haveExpCnt = false;
666            bool haveVMCnt = false;
667            imm16 = isGCN15 ? 0xff7f : (isGCN14 ? 0xcf7f : 0xf7f);
668            while (true)
669            {
670                skipSpacesToEnd(linePtr, end);
671                const char* funcNamePlace = linePtr;
672                name[0] = 0;
673                // get function name
674                good &= getNameArgS(asmr, 20, name, linePtr, "function name", true);
675                toLowerString(name);
676               
677                cxuint bitPos = 0, bitMask = UINT_MAX;
678                bool goodCnt = true;
679                bool doVMCnt = false;
680                // select bitfield for lock
681                if (::strcmp(name, "vmcnt")==0)
682                {
683                    if (haveVMCnt)
684                        asmr.printWarning(funcNamePlace, "vmcnt was already defined");
685                    bitPos = 0;
686                    bitMask = (isGCN14 || isGCN15) ? 63 : 15;
687                    doVMCnt = haveVMCnt = true;
688                }
689                else if (::strcmp(name, "lgkmcnt")==0)
690                {
691                    if (haveLgkmCnt)
692                        asmr.printWarning(funcNamePlace, "lgkmcnt was already defined");
693                    bitPos = 8;
694                    bitMask = isGCN15 ? 63 : 15;
695                    haveLgkmCnt = true;
696                }
697                else if (::strcmp(name, "expcnt")==0)
698                {
699                    if (haveExpCnt)
700                        asmr.printWarning(funcNamePlace, "expcnt was already defined");
701                    bitPos = 4;
702                    bitMask = 7;
703                    haveExpCnt = true;
704                }
705                else
706                    ASM_NOTGOOD_BY_ERROR1(goodCnt = good, funcNamePlace,
707                                    "Expected vmcnt, lgkmcnt or expcnt")
708               
709                skipSpacesToEnd(linePtr, end);
710                if (linePtr==end || *linePtr!='(')
711                {
712                    if (goodCnt) // only if cnt has been parsed (do not duplicate errors)
713                        asmr.printError(funcNamePlace, "Expected vmcnt, lgkmcnt or expcnt");
714                    return false;
715                }
716                skipCharAndSpacesToEnd(linePtr, end);
717                const char* argPlace = linePtr;
718                uint64_t value;
719                // parse value for lock
720                if (getAbsoluteValueArg(asmr, value, linePtr, true))
721                {
722                    if (value > bitMask)
723                        asmr.printWarning(argPlace, "Value out of range");
724                    if ((!isGCN14 && !isGCN15) || !doVMCnt)
725                        imm16 = (imm16 & ~(bitMask<<bitPos)) | ((value&bitMask)<<bitPos);
726                    else // vmcnt for GFX9
727                        imm16 = (imm16 & 0x3ff0) | ((value&15) | ((value&0x30)<<10));
728                }
729                else
730                    good = false;
731                skipSpacesToEnd(linePtr, end);
732                if (linePtr==end || *linePtr!=')')
733                    ASM_FAIL_BY_ERROR(linePtr, "Unterminated function")
734                // ampersand
735                skipCharAndSpacesToEnd(linePtr, end);
736                if (linePtr==end)
737                    break;
738                if (linePtr[0] == '&')
739                    ++linePtr;
740            }
741           
742            if (gcnInsn.code1==12)
743            {
744                // S_WAICTNT
745                uint16_t lgkmCnt = (imm16>>8) & 15;
746                if ((arch & ARCH_HD7X00) != 0)
747                    lgkmCnt = std::min(uint16_t(7), lgkmCnt);
748                const uint16_t expCnt = (imm16>>4) & 7;
749                const uint16_t vmCnt = ((imm16) & 15) + (isGCN14 ? ((imm16>>10)&0x30) : 0);
750                gcnAsm->waitInstr = { output.size(), { vmCnt, lgkmCnt, expCnt } };
751                gcnAsm->hasWaitInstr = true;
752            }
753            break;
754        }
755        case GCN_IMM_MSGS:
756        {
757            char name[25];
758            const char* funcNamePlace = linePtr;
759            if (!getNameArg(asmr, 25, name, linePtr, "function name", true))
760                return false;
761            toLowerString(name);
762            skipSpacesToEnd(linePtr, end);
763            if (::strcmp(name, "sendmsg")!=0 || linePtr==end || *linePtr!='(')
764                ASM_FAIL_BY_ERROR(funcNamePlace, "Expected sendmsg function")
765            skipCharAndSpacesToEnd(linePtr, end);
766           
767            const char* funcArg1Place = linePtr;
768            size_t sendMessage = 0;
769            if (linePtr == end || *linePtr != '@')
770            {
771                // parse message name
772                if (getNameArg(asmr, 25, name, linePtr, "message name", true))
773                {
774                    toLowerString(name);
775                    const size_t msgNameIndex = (::strncmp(name, "msg_", 4) == 0) ? 4 : 0;
776                    // choose message name table
777                    auto msgMap = (isGCN14 || isGCN15) ? sendMessageNamesGCN14Map :
778                            sendMessageNamesMap;
779                    const size_t msgMapSize = (isGCN14 || isGCN15) ?
780                            sendMessageNamesGCN14MapSize : sendMessageNamesMapSize;
781                    // find message name
782                    size_t index = binaryMapFind(msgMap, msgMap + msgMapSize,
783                            name+msgNameIndex, CStringLess()) - msgMap;
784                    if (index != msgMapSize &&
785                        // save_wave only for >=GCN1.2
786                        (msgMap[index].second!=4 || (arch&ARCH_GCN_1_2_4_5)!=0))
787                        sendMessage = msgMap[index].second;
788                    else
789                        ASM_NOTGOOD_BY_ERROR(funcArg1Place, "Unknown message")
790                }
791                else
792                    good = false;
793            }
794            else
795            {
796                // parametrization
797                linePtr++;
798                good &= parseImm(asmr, linePtr, sendMessage, nullptr, 4, WS_UNSIGNED);
799            }
800           
801            cxuint gsopIndex = 0;
802            cxuint streamId = 0;
803            if (sendMessage == 2 || sendMessage == 3)
804            {
805                if (!skipRequiredComma(asmr, linePtr))
806                    return false;
807                skipSpacesToEnd(linePtr, end);
808               
809                // parse GSOP parameter
810                if (linePtr == end || *linePtr != '@')
811                {
812                    const char* funcArg2Place = linePtr;
813                    if (getNameArg(asmr, 20, name, linePtr, "GSOP", true))
814                    {
815                        toLowerString(name);
816                        // handle gs_op prefix
817                        const size_t gsopNameIndex = (::strncmp(name, "gs_op_", 6) == 0)
818                                    ? 6 : 0;
819                        for (gsopIndex = 0; gsopIndex < 4; gsopIndex++)
820                            if (::strcmp(name+gsopNameIndex,
821                                        sendMsgGSOPTable[gsopIndex])==0)
822                                break;
823                        if (gsopIndex==2 && gsopNameIndex==0)
824                        {
825                            /* 'emit-cut' handling */
826                            if (linePtr+4<=end && ::strncasecmp(linePtr, "-cut", 4)==0 &&
827                                (linePtr==end || (!isAlnum(*linePtr) && *linePtr!='_' &&
828                                *linePtr!='$' && *linePtr!='.')))
829                            {
830                                linePtr+=4;
831                                gsopIndex++;
832                            }
833                        }
834                        if (gsopIndex == sendMsgGSOPTableSize)
835                        {
836                            // not found
837                            gsopIndex = 0;
838                            ASM_NOTGOOD_BY_ERROR(funcArg2Place, "Unknown GSOP")
839                        }
840                    }
841                    else
842                        good = false;
843                }
844                else
845                {
846                    // parametrization
847                    linePtr++;
848                    good &= parseImm(asmr, linePtr, gsopIndex, nullptr, 3, WS_UNSIGNED);
849                }
850               
851                if (gsopIndex!=0)
852                {
853                    if (!skipRequiredComma(asmr, linePtr))
854                        return false;
855                   
856                    uint64_t value;
857                    skipSpacesToEnd(linePtr, end);
858                    const char* func3ArgPlace = linePtr;
859                    // parse STREAMID (third argument of sendmsg)
860                    good &= getAbsoluteValueArg(asmr, value, linePtr, true);
861                    if (value > 3)
862                        asmr.printWarning(func3ArgPlace,
863                                  "StreamId (3rd argument) out of range");
864                    streamId = value&3;
865                }
866            }
867            skipSpacesToEnd(linePtr, end);
868            if (linePtr==end || *linePtr!=')')
869                ASM_FAIL_BY_ERROR(linePtr, "Unterminated sendmsg function")
870            ++linePtr;
871            imm16 = sendMessage | (gsopIndex<<4) | (streamId<<8);
872           
873            gcnAsm->delayedOps[0] = { output.size(), nullptr, uint16_t(0), uint16_t(0),
874                    1, GCNDELOP_SENDMSG, GCNDELOP_NONE, cxbyte(0) };
875            break;
876        }
877        case GCN_IMM_NONE:
878            // if s_endpgm or s_endpgm_saved then add 'end' to code flow entries
879            if (gcnInsn.code1 == 1 || gcnInsn.code1 == 27)
880                asmr.sections[asmr.currentSection].addCodeFlowEntry({ 
881                    size_t(asmr.currentOutPos+4), size_t(0), AsmCodeFlowType::END });
882            break;
883        default:
884            good &= parseImm(asmr, linePtr, imm16, &imm16Expr);
885    }
886    /// if errors
887    if (!good || !checkGarbagesAtEnd(asmr, linePtr))
888        return false;
889   
890    // put data (instruction word)
891    uint32_t word;
892    SLEV(word, 0xbf800000U | imm16 | (uint32_t(gcnInsn.code1)<<16));
893   
894    if (imm16Expr!=nullptr)
895        imm16Expr->setTarget(AsmExprTarget(((gcnInsn.mode&GCN_MASK1) == GCN_IMM_REL) ?
896                GCNTGT_SOPJMP : GCNTGT_SOPKSIMM16, asmr.currentSection, output.size()));
897   
898    output.insert(output.end(), reinterpret_cast<cxbyte*>(&word), 
899            reinterpret_cast<cxbyte*>(&word)+4);
900    /// prevent freeing expression
901    imm16Expr.release();
902    return true;
903}
904
905bool GCNAsmUtils::parseSMRDEncoding(Assembler& asmr, const GCNAsmInstruction& gcnInsn,
906                  const char* instrPlace, const char* linePtr, GPUArchMask arch,
907                  std::vector<cxbyte>& output, GCNAssembler::Regs& gcnRegs,
908                  GCNEncSize gcnEncSize)
909{
910    const char* end = asmr.line+asmr.lineSize;
911    bool good = true;
912    if (gcnEncSize==GCNEncSize::BIT64 && (arch & ARCH_HD7X00) != 0)
913        ASM_FAIL_BY_ERROR(instrPlace, "Only 32-bit size for SMRD encoding")
914    GCNAssembler* gcnAsm = static_cast<GCNAssembler*>(asmr.isaAssembler);
915   
916    RegRange dstReg(0, 0);
917    RegRange sbaseReg(0, 0);
918    RegRange soffsetReg(0, 0);
919    uint32_t soffsetVal = 0;
920    bool haveLit = false;
921    std::unique_ptr<AsmExpression> soffsetExpr;
922    const GCNInsnMode mode1 = (gcnInsn.mode & GCN_MASK1);
923    if (mode1 == GCN_SMRD_ONLYDST)
924    {
925        // parse SDST (SGPR)
926        gcnAsm->setCurrentRVU(0);
927        good &= parseSRegRange(asmr, linePtr, dstReg, arch,
928                       (gcnInsn.mode&GCN_REG_DST_64)?2:1, GCNFIELD_SMRD_SDST, true,
929                       INSTROP_SYMREGRANGE|INSTROP_WRITE);
930    }
931    else if (mode1 != GCN_ARG_NONE)
932    {
933        const cxuint dregsNum = 1<<((gcnInsn.mode & GCN_DSIZE_MASK)>>GCN_SHIFT2);
934        // parse SDST (SGPR's (1-16 registers))
935        gcnAsm->setCurrentRVU(0);
936        good &= parseSRegRange(asmr, linePtr, dstReg, arch, dregsNum,
937                   GCNFIELD_SMRD_SDST, true, INSTROP_SYMREGRANGE|INSTROP_WRITE);
938        if (!skipRequiredComma(asmr, linePtr))
939            return false;
940       
941        // parse SBASE (2 or 4 registers)
942        gcnAsm->setCurrentRVU(1);
943        good &= parseSRegRange(asmr, linePtr, sbaseReg, arch,
944                   (gcnInsn.mode&GCN_SBASE4)?4:2, GCNFIELD_SMRD_SBASE, true,
945                   INSTROP_SYMREGRANGE|INSTROP_READ);
946        if (!skipRequiredComma(asmr, linePtr))
947            return false;
948       
949        skipSpacesToEnd(linePtr, end);
950        if (linePtr==end || *linePtr!='@')
951        {
952            // parse SOFFSET (SGPR)
953            gcnAsm->setCurrentRVU(2);
954            good &= parseSRegRange(asmr, linePtr, soffsetReg, arch, 1,
955                       GCNFIELD_SMRD_SOFFSET, false, INSTROP_SYMREGRANGE|INSTROP_READ);
956        }
957        else // '@' prefix (treat next as expression)
958            skipCharAndSpacesToEnd(linePtr, end);
959       
960        if (!soffsetReg)
961        {
962            soffsetReg.start = 255; // indicate an immediate
963            // parse immediate
964            if ((arch & ARCH_HD7X00) != 0)
965                good &= parseImm(asmr, linePtr, soffsetVal, &soffsetExpr, 8, WS_UNSIGNED);
966            else
967                good &= parseSMRDImm(asmr, linePtr, soffsetVal, &soffsetExpr, haveLit);
968        }
969    }
970    /// if errors
971    if (!good || !checkGarbagesAtEnd(asmr, linePtr))
972        return false;
973   
974    if (mode1 != GCN_ARG_NONE)
975        gcnAsm->delayedOps[0] = AsmDelayedOp { output.size(),
976                    gcnAsm->instrRVUs[0].regVar, gcnAsm->instrRVUs[0].rstart,
977                    gcnAsm->instrRVUs[0].rend,
978                    cxbyte(gcnAsm->instrRVUs[0].rend - gcnAsm->instrRVUs[0].rstart),
979                    GCNDELOP_SMEMOP, GCNDELOP_NONE, gcnAsm->instrRVUs[0].rwFlags };
980   
981    const cxuint wordsNum = haveLit ? 2 : 1;
982    if (!checkGCNEncodingSize(asmr, instrPlace, gcnEncSize, wordsNum))
983        return false;
984   
985    if (soffsetExpr!=nullptr)
986        soffsetExpr->setTarget(AsmExprTarget(haveLit ? GCNTGT_LITIMM : GCNTGT_SMRDOFFSET,
987                        asmr.currentSection, output.size()));
988   
989    // put data (instruction word)
990    uint32_t word;
991    SLEV(word, 0xc0000000U | (uint32_t(gcnInsn.code1)<<22) |
992            (uint32_t(dstReg.bstart())<<15) |
993            (haveLit ? 0xff /* have literal */ :
994             ((soffsetReg.isVal(255)) ? 0x100 : 0)) |
995             ((sbaseReg.bstart()&~1U)<<8) |
996            (haveLit ? 0 : ((soffsetReg.isVal(255)) ? soffsetVal : soffsetReg.bstart())));
997    output.insert(output.end(), reinterpret_cast<cxbyte*>(&word),
998            reinterpret_cast<cxbyte*>(&word)+4);
999    uint32_t lit32Val;
1000    SLEV(lit32Val, soffsetVal);
1001    if (haveLit)
1002        output.insert(output.end(), reinterpret_cast<cxbyte*>(&lit32Val),
1003            reinterpret_cast<cxbyte*>(&lit32Val)+4);
1004    /// prevent freeing expression
1005    soffsetExpr.release();
1006   
1007    // update SGPR counting and VCC usage (regflags)
1008    if (dstReg && !dstReg.isRegVar())
1009    {
1010        updateSGPRsNum(gcnRegs.sgprsNum, dstReg.end-1, arch);
1011        updateRegFlags(gcnRegs.regFlags, dstReg.start, arch);
1012    }
1013    if (!sbaseReg.isRegVar())
1014        updateRegFlags(gcnRegs.regFlags, sbaseReg.start, arch);
1015    if (!soffsetReg.isRegVar())
1016        updateRegFlags(gcnRegs.regFlags, soffsetReg.start, arch);
1017    return true;
1018}
1019
1020bool GCNAsmUtils::parseSMEMEncoding(Assembler& asmr, const GCNAsmInstruction& gcnInsn,
1021                  const char* instrPlace, const char* linePtr, GPUArchMask arch,
1022                  std::vector<cxbyte>& output, GCNAssembler::Regs& gcnRegs,
1023                  GCNEncSize gcnEncSize)
1024{
1025    const char* end = asmr.line+asmr.lineSize;
1026    bool good = true;
1027    if (gcnEncSize==GCNEncSize::BIT32)
1028        ASM_FAIL_BY_ERROR(instrPlace, "Only 64-bit size for SMEM encoding")
1029   
1030    GCNAssembler* gcnAsm = static_cast<GCNAssembler*>(asmr.isaAssembler);
1031    RegRange dataReg(0, 0);
1032    RegRange sbaseReg(0, 0);
1033    RegRange soffsetReg(0, 0);
1034    uint32_t soffsetVal = 0;
1035    std::unique_ptr<AsmExpression> soffsetExpr;
1036    std::unique_ptr<AsmExpression> simm7Expr;
1037    const GCNInsnMode mode1 = (gcnInsn.mode & GCN_MASK1);
1038    const bool isGCN14 = (arch & ARCH_GCN_1_4) != 0;
1039    const bool isGCN15 = (arch & ARCH_GCN_1_5) != 0;
1040   
1041    const char* soffsetPlace = nullptr;
1042    AsmSourcePos soffsetPos;
1043   
1044    if (mode1 == GCN_SMRD_ONLYDST)
1045    {
1046        // parse SDST (SGPR)
1047        gcnAsm->setCurrentRVU(0);
1048        good &= parseSRegRange(asmr, linePtr, dataReg, arch,
1049                       (gcnInsn.mode&GCN_REG_DST_64)?2:1, GCNFIELD_SMRD_SDST, true,
1050                       INSTROP_SYMREGRANGE|INSTROP_WRITE);
1051    }
1052    else if (mode1 != GCN_ARG_NONE)
1053    {
1054        const cxuint dregsNum = 1<<((gcnInsn.mode & GCN_DSIZE_MASK)>>GCN_SHIFT2);
1055        // parse SDST (SGPR's (1-16 registers))
1056        gcnAsm->setCurrentRVU(0);
1057        if ((mode1 & GCN_SMEM_NOSDATA) == 0)
1058        {
1059            if ((mode1 & GCN_SMEM_SDATA_IMM)==0)
1060                good &= parseSRegRange(asmr, linePtr, dataReg, arch, dregsNum,
1061                        GCNFIELD_SMRD_SDST, true, INSTROP_SYMREGRANGE|
1062                        ((gcnInsn.mode & GCN_MLOAD) != 0 ? INSTROP_WRITE : INSTROP_READ));
1063            else
1064                good &= parseImm(asmr, linePtr, dataReg.start, &simm7Expr, 7);
1065            if (!skipRequiredComma(asmr, linePtr))
1066                return false;
1067        }
1068       
1069        // parse SBASE (2 or 4 SGPR's)
1070        gcnAsm->setCurrentRVU(1);
1071        good &= parseSRegRange(asmr, linePtr, sbaseReg, arch,
1072                   (gcnInsn.mode&GCN_SBASE4)?4:2, GCNFIELD_SMRD_SBASE, true,
1073                   INSTROP_SYMREGRANGE|INSTROP_READ);
1074        if (!skipRequiredComma(asmr, linePtr))
1075            return false;
1076       
1077        skipSpacesToEnd(linePtr, end);
1078        if (linePtr==end || *linePtr!='@')
1079        {
1080            // parse SOFFSET (SGPR)
1081            gcnAsm->setCurrentRVU(2);
1082            const char* soffsetPlace = linePtr;
1083            good &= parseSRegRange(asmr, linePtr, soffsetReg, arch, 1,
1084                       GCNFIELD_SMRD_SOFFSET, false, INSTROP_SYMREGRANGE|INSTROP_READ);
1085            if (good && (!isGCN14 && !isGCN15) && (gcnInsn.mode & GCN_MLOAD) == 0 &&
1086                    soffsetReg && !soffsetReg.isVal(124))
1087                // if no M0 register
1088                ASM_NOTGOOD_BY_ERROR(soffsetPlace,
1089                        "Store/Atomic SMEM instructions accepts only M0 register")
1090        }
1091        else // '@' prefix (treat next as expression)
1092            skipCharAndSpacesToEnd(linePtr, end);
1093       
1094        if (!soffsetReg)
1095        {
1096            // parse immediate
1097            soffsetReg.start = 255; // indicate an immediate
1098            skipSpacesToEnd(linePtr, end);
1099            soffsetPlace = linePtr;
1100            soffsetPos = asmr.getSourcePos(soffsetPlace);
1101            good &= parseImm(asmr, linePtr, soffsetVal, &soffsetExpr,
1102                        isGCN14 ? 21 : 20, isGCN14 ? WS_BOTH : WS_UNSIGNED);
1103        }
1104    }
1105    bool haveGlc = false;
1106    bool haveNv = false;
1107    bool haveOffset = false;
1108    bool haveDlc = false;
1109    // parse modifiers
1110    while (linePtr != end)
1111    {
1112        skipSpacesToEnd(linePtr, end);
1113        if (linePtr == end)
1114            break;
1115        const char* modPlace = linePtr;
1116        char name[10];
1117        if (getNameArgS(asmr, 10, name, linePtr, "modifier"))
1118        {
1119            toLowerString(name);
1120            if (::strcmp(name, "glc")==0)
1121                good &= parseModEnable(asmr, linePtr, haveGlc, "glc modifier");
1122            else if (::strcmp(name, "dlc")==0)
1123                good &= parseModEnable(asmr, linePtr, haveDlc, "dlc modifier");
1124            else if ((isGCN14 || isGCN15) && ::strcmp(name, "nv")==0)
1125                good &= parseModEnable(asmr, linePtr, haveNv, "nv modifier");
1126            else if (isGCN14 && ::strcmp(name, "offset")==0)
1127            {
1128                // parse offset and it parameter: offset:XXX
1129                if (parseModImm(asmr, linePtr, soffsetVal, &soffsetExpr, "offset",
1130                        21, WS_BOTH))
1131                {
1132                    if (haveOffset)
1133                        asmr.printWarning(modPlace, "Offset is already defined");
1134                    haveOffset = true;
1135                    if (soffsetReg.isVal(255))
1136                        // illegal second offset
1137                        ASM_NOTGOOD_BY_ERROR(modPlace, "Illegal second offset");
1138                }
1139                else
1140                    good = false;
1141            }
1142            else
1143                ASM_NOTGOOD_BY_ERROR(modPlace, "Unknown SMEM modifier")
1144        }
1145        else
1146            good = false;
1147    }
1148    /// if errors
1149    if (!good || !checkGarbagesAtEnd(asmr, linePtr))
1150        return false;
1151   
1152    // set expression target for offsets and immediates
1153    if (soffsetExpr!=nullptr)
1154        soffsetExpr->setTarget(AsmExprTarget(isGCN14 ?
1155                    GCNTGT_SMEMOFFSETVEGA : GCNTGT_SMEMOFFSET,
1156                    asmr.currentSection, output.size()));
1157    if (simm7Expr!=nullptr)
1158        simm7Expr->setTarget(AsmExprTarget(GCNTGT_SMEMIMM, asmr.currentSection,
1159                       output.size()));
1160   
1161    bool dataToRead = false;
1162    bool dataToWrite = false;
1163    if (dataReg)
1164    {
1165        dataToWrite = ((gcnInsn.mode&GCN_MLOAD) != 0 ||
1166                ((gcnInsn.mode&GCN_MATOMIC)!=0 && haveGlc));
1167        dataToRead = (gcnInsn.mode&GCN_MLOAD)==0 || (gcnInsn.mode&GCN_MATOMIC)!=0;
1168    }
1169   
1170    gcnAsm->instrRVUs[0].rwFlags = (dataToRead ? ASMRVU_READ : 0) |
1171            (dataToWrite ? ASMRVU_WRITE : 0);
1172    // check fcmpswap
1173    if ((gcnInsn.mode & GCN_MHALFWRITE) != 0 && dataToWrite &&
1174            gcnAsm->instrRVUs[0].regField != ASMFIELD_NONE)
1175    {
1176        // fix access
1177        AsmRegVarUsage& rvu = gcnAsm->instrRVUs[0];
1178        uint16_t size = rvu.rend-rvu.rstart;
1179        rvu.rend = rvu.rstart + (size>>1);
1180        AsmRegVarUsage& nextRvu = gcnAsm->instrRVUs[3];
1181        nextRvu = rvu;
1182        nextRvu.regField = GCNFIELD_SMRD_SDSTH;
1183        nextRvu.rstart += (size>>1);
1184        nextRvu.rend = rvu.rstart + size;
1185        nextRvu.rwFlags = ASMRVU_READ;
1186        nextRvu.align = 0;
1187    }
1188   
1189    if (mode1 != GCN_ARG_NONE)
1190    {
1191        gcnAsm->delayedOps[0] = AsmDelayedOp { output.size(),
1192                    gcnAsm->instrRVUs[0].regVar, gcnAsm->instrRVUs[0].rstart,
1193                    gcnAsm->instrRVUs[0].rend,
1194                    cxbyte(gcnAsm->instrRVUs[0].rend - gcnAsm->instrRVUs[0].rstart),
1195                    GCNDELOP_SMEMOP, GCNDELOP_NONE, gcnAsm->instrRVUs[0].rwFlags };
1196        if (gcnAsm->instrRVUs[3].regField != ASMFIELD_NONE)
1197            gcnAsm->delayedOps[1] = AsmDelayedOp { output.size(),
1198                    gcnAsm->instrRVUs[3].regVar, gcnAsm->instrRVUs[3].rstart,
1199                    gcnAsm->instrRVUs[3].rend,
1200                    cxbyte(gcnAsm->instrRVUs[0].rend - gcnAsm->instrRVUs[0].rstart),
1201                    GCNDELOP_SMEMOP, GCNDELOP_NONE, gcnAsm->instrRVUs[3].rwFlags };
1202    }
1203   
1204    // put data (2 instruction words)
1205    uint32_t words[2];
1206    const uint32_t encoding = isGCN15 ? 0xf4000000U : 0xc0000000U;
1207    const uint32_t soffsetRegNull = isGCN15 ? 0x7d : 0;
1208    SLEV(words[0], encoding | (uint32_t(gcnInsn.code1)<<18) | (dataReg.bstart()<<6) |
1209            (sbaseReg.bstart()>>1) |
1210            // enable IMM if soffset is immediate or haveOffset with SGPR
1211            ((!isGCN15 && (soffsetReg.isVal(255) || haveOffset)) ? 0x20000 : 0) |
1212            (haveGlc ? 0x10000 : 0) | (haveNv ? 0x8000 : 0) |
1213            (((!isGCN15 && haveOffset) || (isGCN15 && haveDlc)) ? 0x4000 : 0));
1214    SLEV(words[1],
1215            // store IMM OFFSET if offset: or IMM offset instead SGPR
1216            ((isGCN15 || soffsetReg.isVal(255) || haveOffset) ?
1217                                soffsetVal : soffsetReg.bstart()) |
1218            // store SGPR in SOFFSET if have offset and have SGPR offset
1219                (((isGCN15 && !soffsetReg.isVal(255)) ||
1220                        (!isGCN15 && haveOffset && !soffsetReg.isVal(255))) ?
1221                        (soffsetReg.bstart()<<25) : (soffsetRegNull<<25)));
1222   
1223    output.insert(output.end(), reinterpret_cast<cxbyte*>(words), 
1224            reinterpret_cast<cxbyte*>(words+2));
1225    /// prevent freeing expression
1226    soffsetExpr.release();
1227    simm7Expr.release();
1228   
1229    // update SGPR counting and VCC usage (regflags)
1230    if (!dataReg.isRegVar() && dataToWrite)
1231    {
1232        updateSGPRsNum(gcnRegs.sgprsNum, dataReg.end-1, arch);
1233        updateRegFlags(gcnRegs.regFlags, dataReg.start, arch);
1234    }
1235    if (!sbaseReg.isRegVar())
1236        updateRegFlags(gcnRegs.regFlags, sbaseReg.start, arch);
1237    if (!soffsetReg.isRegVar())
1238        updateRegFlags(gcnRegs.regFlags, soffsetReg.start, arch);
1239    return true;
1240}
1241
1242// choose between 64-bit immediate (FP64) and 32-bit immediate
1243static Flags correctOpType(uint32_t regsNum, Flags typeMask)
1244{
1245    return (regsNum==2 && (typeMask==INSTROP_FLOAT || typeMask==INSTROP_INT)) ?
1246        INSTROP_V64BIT : typeMask;
1247}
1248
1249static void encodeVOPWords(uint32_t vop0Word, cxbyte modifiers,
1250        const VOPExtraModifiers& extraMods, const GCNOperand& src0Op,
1251        const GCNOperand& src1Op, uint32_t immValue, GCNInsnMode mode1,
1252        // dstMod - (16bits lower value, 16bit - use dstMod instead std encoding
1253        uint32_t inDstMod, cxuint& wordsNum, uint32_t* words)
1254{
1255    // VOP2 encoding
1256    cxuint src0out = src0Op.range.bstart();
1257    if (extraMods.needSDWA)
1258        src0out = 0xf9;
1259    else if (extraMods.needDPP)
1260        src0out = 0xfa;
1261    else if (extraMods.needDPP8)
1262        src0out = (extraMods.fi ? 0xea : 0xe9);
1263    SLEV(words[0], vop0Word | uint32_t(src0out));
1264    if (extraMods.needSDWA)
1265    {
1266        const uint32_t dstMod = (inDstMod & 0x10000) ? (inDstMod&0xff00) :
1267                    ((uint32_t(extraMods.dstSel)<<8) |
1268                    (uint32_t(extraMods.dstUnused)<<11) |
1269                    ((modifiers & VOP3_CLAMP) ? 0x2000 : 0) |
1270                    (uint32_t(modifiers & 3) << 14));
1271        // if SDWA encoding
1272        SLEV(words[wordsNum++], dstMod | (src0Op.range.bstart()&0xff) |
1273                (uint32_t(extraMods.src0Sel)<<16) |
1274                ((src0Op.vopMods&VOPOP_SEXT) ? (1U<<19) : 0) |
1275                ((src0Op.vopMods&VOPOP_NEG) ? (1U<<20) : 0) |
1276                ((src0Op.vopMods&VOPOP_ABS) ? (1U<<21) : 0) |
1277                (uint32_t(extraMods.src1Sel)<<24) |
1278                ((src1Op.vopMods&VOPOP_SEXT) ? (1U<<27) : 0) |
1279                ((src1Op.vopMods&VOPOP_NEG) ? (1U<<28) : 0) |
1280                ((src1Op.vopMods&VOPOP_ABS) ? (1U<<29) : 0) |
1281                (src0Op.range.isNonVGPR() ? (1U<<23) : 0) |
1282                (src1Op.range.isNonVGPR() ? (1U<<31) : 0));
1283    }
1284    else if (extraMods.needDPP)
1285        // DPP encoding
1286        SLEV(words[wordsNum++], (src0Op.range.bstart()&0xff) | (extraMods.dppCtrl<<8) |
1287                ((modifiers&VOP3_BOUNDCTRL) ? (1U<<19) : 0) |
1288                ((src0Op.vopMods&VOPOP_NEG) ? (1U<<20) : 0) |
1289                ((src0Op.vopMods&VOPOP_ABS) ? (1U<<21) : 0) |
1290                ((src1Op.vopMods&VOPOP_NEG) ? (1U<<22) : 0) |
1291                ((src1Op.vopMods&VOPOP_ABS) ? (1U<<23) : 0) |
1292                (extraMods.fi ? 0x40000U : 0) |
1293                (uint32_t(extraMods.bankMask)<<24) |
1294                (uint32_t(extraMods.rowMask)<<28));
1295    else if (extraMods.needDPP8)
1296        SLEV(words[wordsNum++], (src0Op.range.bstart()&0xff) | (extraMods.dpp8Value<<8));
1297    else if (src0Op.range.isVal(255)) // otherwise we check for immediate/literal value
1298        SLEV(words[wordsNum++], src0Op.value);
1299    else if (src1Op.range.isVal(255))
1300        // literal from SRC1
1301        SLEV(words[wordsNum++], src1Op.value);
1302    else if (mode1 == GCN_ARG1_IMM || mode1 == GCN_ARG2_IMM)
1303        SLEV(words[wordsNum++], immValue);
1304}
1305
1306static void encodeVOP3Words(GPUArchMask arch, const GCNAsmInstruction& gcnInsn,
1307        cxbyte modifiers, VOPOpModifiers opMods, bool haveDstCC,
1308        const RegRange& dstReg, const RegRange& dstCCReg, const RegRange& srcCCReg,
1309        const GCNOperand& src0Op, const GCNOperand& src1Op,
1310        cxuint& wordsNum, uint32_t* words)
1311{
1312    const bool isGCN12 = (arch & ARCH_GCN_1_2_4_5)!=0;
1313    // VOP3 encoding
1314    uint32_t code = (isGCN12) ?
1315            (uint32_t(gcnInsn.code2)<<16) | ((modifiers&VOP3_CLAMP) ? 0x8000 : 0) :
1316            (uint32_t(gcnInsn.code2)<<17) | ((modifiers&VOP3_CLAMP) ? 0x800 : 0);
1317    cxuint encoding = (arch & ARCH_GCN_1_5)!=0 ? 0xd4000000U : 0xd0000000U;
1318    if (haveDstCC) // if VOP3B
1319        SLEV(words[0], encoding | code |
1320            (dstReg.bstart()&0xff) | (uint32_t(dstCCReg.bstart())<<8));
1321    else // if VOP3A
1322        SLEV(words[0], encoding | code | (dstReg.bstart()&0xff) |
1323            ((src0Op.vopMods & VOPOP_ABS) ? 0x100 : 0) |
1324            ((src1Op.vopMods & VOPOP_ABS) ? 0x200 : 0) |
1325            ((opMods.opselMod&15) << 11));
1326    // second dword
1327    SLEV(words[1], src0Op.range.bstart() | (uint32_t(src1Op.range.bstart())<<9) |
1328        (uint32_t(srcCCReg.bstart())<<18) | (uint32_t(modifiers & 3) << 27) |
1329        ((src0Op.vopMods & VOPOP_NEG) ? (1U<<29) : 0) |
1330        ((src1Op.vopMods & VOPOP_NEG) ? (1U<<30) : 0));
1331    wordsNum++;
1332}
1333
1334bool GCNAsmUtils::parseVOP2Encoding(Assembler& asmr, const GCNAsmInstruction& gcnInsn,
1335                  const char* instrPlace, const char* linePtr, GPUArchMask arch,
1336                  std::vector<cxbyte>& output, GCNAssembler::Regs& gcnRegs,
1337                  GCNEncSize gcnEncSize, GCNVOPEnc gcnVOPEnc)
1338{
1339    const char* end = asmr.line+asmr.lineSize;
1340    bool good = true;
1341    const GCNInsnMode mode1 = (gcnInsn.mode & GCN_MASK1);
1342    const GCNInsnMode mode2 = (gcnInsn.mode & GCN_LITMASK);
1343    const bool isGCN12 = (arch & ARCH_GCN_1_2_4_5)!=0;
1344    const bool isGCN14 = (arch & ARCH_GCN_1_4_5)!=0;
1345    const bool isGCN15 = (arch & ARCH_GCN_1_5)!=0;
1346    GCNAssembler* gcnAsm = static_cast<GCNAssembler*>(asmr.isaAssembler);
1347    const bool wave32 = (asmr.codeFlags & ASM_CODE_WAVE32)!=0;
1348   
1349    RegRange dstReg(0, 0);
1350    RegRange dstCCReg(0, 0);
1351    RegRange srcCCReg(0, 0);
1352    gcnAsm->setCurrentRVU(0);
1353    if (mode1 == GCN_DS1_SGPR)
1354        // if SGPRS as destination
1355        good &= parseSRegRange(asmr, linePtr, dstReg, arch,
1356                       (gcnInsn.mode&GCN_REG_DST_64)?2:1, GCNFIELD_VOP_SDST, true,
1357                       INSTROP_SYMREGRANGE|INSTROP_SGPR_UNALIGNED|INSTROP_WRITE);
1358    else
1359    {
1360         // if VGPRS as destination
1361        bool v_mac = ::strncmp(gcnInsn.mnemonic, "v_mac_", 6)==0 ||
1362                // for V_FMAC_F32 (VEGA20)
1363                ::strncmp(gcnInsn.mnemonic, "v_fmac_", 7)==0;
1364        good &= parseVRegRange(asmr, linePtr, dstReg, (gcnInsn.mode&GCN_REG_DST_64)?2:1,
1365                        GCNFIELD_VOP_VDST, true, INSTROP_SYMREGRANGE|INSTROP_WRITE|
1366                              (v_mac?INSTROP_READ:0));
1367    }
1368   
1369    const bool haveDstCC = mode1 == GCN_DS2_VCC || mode1 == GCN_DST_VCC;
1370    const bool haveSrcCC = mode1 == GCN_DS2_VCC || mode1 == GCN_SRC2_VCC;
1371   
1372    const cxuint waveRegSize = (!isGCN15 || !wave32 ||
1373                        (gcnInsn.mode&GCN_VOP_NOWVSZ)!=0) ? 2 : 1;
1374    if (haveDstCC) /* VOP3b */
1375    {
1376        if (!skipRequiredComma(asmr, linePtr))
1377            return false;
1378        // parse SDST (in place VCC) (2 SGPR's)
1379        gcnAsm->setCurrentRVU(1);
1380        good &= parseSRegRange(asmr, linePtr, dstCCReg, arch, waveRegSize,
1381                    GCNFIELD_VOP3_SDST1, true, INSTROP_SYMREGRANGE|INSTROP_SGPR_UNALIGNED|
1382                    INSTROP_WRITE);
1383    }
1384   
1385    GCNOperand src0Op{}, src1Op{};
1386    std::unique_ptr<AsmExpression> src0OpExpr, src1OpExpr;
1387    const Flags literalConstsFlags = (mode2==GCN_FLOATLIT) ? INSTROP_FLOAT :
1388            (mode2==GCN_F16LIT) ? INSTROP_F16 : INSTROP_INT;
1389   
1390    const Flags vopOpModFlags = ((haveDstCC && !isGCN12) ?
1391                    INSTROP_VOP3NEG : INSTROP_VOP3MODS);
1392    if (!skipRequiredComma(asmr, linePtr))
1393        return false;
1394    cxuint regsNum = (gcnInsn.mode&GCN_REG_SRC0_64)?2:1;
1395    // parse SRC0 (can be VGPR, SGPR, scalar source, LDS, literal or constant)
1396    gcnAsm->setCurrentRVU(2);
1397    good &= parseOperand(asmr, linePtr, src0Op, &src0OpExpr, arch, regsNum,
1398            correctOpType(regsNum, literalConstsFlags) | vopOpModFlags |
1399            INSTROP_SGPR_UNALIGNED|INSTROP_VREGS|INSTROP_SSOURCE|INSTROP_SREGS|INSTROP_LDS|
1400            INSTROP_READ, GCNFIELD_VOP_SRC0);
1401   
1402    uint32_t immValue = 0;
1403    std::unique_ptr<AsmExpression> immExpr;
1404    if (mode1 == GCN_ARG1_IMM)
1405    {
1406        // for V_MADMK_FXxx instruction
1407        if (!skipRequiredComma(asmr, linePtr))
1408            return false;
1409        good &= parseLiteralImm(asmr, linePtr, immValue, &immExpr, literalConstsFlags);
1410    }
1411   
1412    if (!skipRequiredComma(asmr, linePtr))
1413        return false;
1414   
1415    bool sgprRegInSrc1 = mode1 == GCN_DS1_SGPR || mode1 == GCN_SRC1_SGPR;
1416    skipSpacesToEnd(linePtr, end);
1417    regsNum = (gcnInsn.mode&GCN_REG_SRC1_64)?2:1;
1418    gcnAsm->setCurrentRVU(3);
1419    // parse SRC1 (can be VGPR, SGPR, scalar source, LDS, literal or constant)
1420    //  except when SGPR for SRC1 when instructions accepts SGPR in this place
1421    good &= parseOperand(asmr, linePtr, src1Op, &src1OpExpr, arch, regsNum,
1422            correctOpType(regsNum, literalConstsFlags) | vopOpModFlags |
1423            (!sgprRegInSrc1 ? INSTROP_VREGS : 0)|INSTROP_SSOURCE|INSTROP_SREGS|
1424            INSTROP_SGPR_UNALIGNED |
1425            (src0Op.range.start==255 ? INSTROP_ONLYINLINECONSTS : 0)|
1426            INSTROP_READ, (!sgprRegInSrc1) ? GCNFIELD_VOP_VSRC1 : GCNFIELD_VOP_SSRC1);
1427   
1428    if (mode1 == GCN_ARG2_IMM)
1429    {
1430        // for V_MADAK_Fxx instruction
1431        if (!skipRequiredComma(asmr, linePtr))
1432            return false;
1433        good &= parseLiteralImm(asmr, linePtr, immValue, &immExpr, literalConstsFlags);
1434    }
1435    else if (haveSrcCC)
1436    {
1437        if (!skipRequiredComma(asmr, linePtr))
1438            return false;
1439        gcnAsm->setCurrentRVU(4);
1440        // parse SSRC (VCC) (2 SGPR's)
1441        good &= parseSRegRange(asmr, linePtr, srcCCReg, arch, waveRegSize,
1442                    GCNFIELD_VOP3_SSRC, true,INSTROP_SYMREGRANGE|INSTROP_UNALIGNED|
1443                    INSTROP_READ);
1444    }
1445   
1446    // modifiers
1447    cxbyte modifiers = 0;
1448    VOPExtraModifiers extraMods{};
1449    VOPOpModifiers opMods{};
1450    good &= parseVOPModifiers(asmr, linePtr, arch, modifiers, opMods, 3,
1451                    (isGCN12) ? &extraMods : nullptr,
1452                    ((!haveDstCC || isGCN12) ? PARSEVOP_WITHCLAMP : 0)|PARSEVOP_WITHSEXT|
1453                    ((isGCN14 && !haveDstCC) ? PARSEVOP_WITHOPSEL : 0));
1454    if (!good || !checkGarbagesAtEnd(asmr, linePtr))
1455        return false;
1456   
1457    // apply VOP modifiers (abs,neg,sext) to operands from modifiers
1458    if (src0Op)
1459        src0Op.vopMods |= ((opMods.absMod&1) ? VOPOP_ABS : 0) |
1460                ((opMods.negMod&1) ? VOPOP_NEG : 0) |
1461                ((opMods.sextMod&1) ? VOPOP_SEXT : 0);
1462    if (src1Op)
1463        src1Op.vopMods |= ((opMods.absMod&2) ? VOPOP_ABS : 0) |
1464                ((opMods.negMod&2) ? VOPOP_NEG : 0) |
1465                ((opMods.sextMod&2) ? VOPOP_SEXT : 0);
1466   
1467    extraMods.needSDWA |= ((src0Op.vopMods | src1Op.vopMods) & VOPOP_SEXT) != 0;
1468    // determine whether VOP3 encoding is needed
1469    bool vop3 = /* src1=sgprs and not (DS1_SGPR|src1_SGPR) */
1470        //((src1Op.range.start<256) ^ sgprRegInSrc1) ||
1471        ((!isGCN14 || !extraMods.needSDWA) &&
1472                (src1Op.range.isNonVGPR() ^ sgprRegInSrc1)) ||
1473        (!isGCN12 && (src0Op.vopMods!=0 || src1Op.vopMods!=0)) ||
1474        (modifiers&~(VOP3_BOUNDCTRL|(extraMods.needSDWA?VOP3_CLAMP:0)|
1475            /* exclude OMOD if RXVEGA and SDWA used */
1476            ((isGCN14 && extraMods.needSDWA) ? 3 : 0)))!=0 ||
1477        /* srcCC!=VCC or dstCC!=VCC */
1478        //(haveDstCC && dstCCReg.start!=106) || (haveSrcCC && srcCCReg.start!=106) ||
1479        (haveDstCC && !dstCCReg.isVal(106)) || (haveSrcCC && !srcCCReg.isVal(106)) ||
1480        ((opMods.opselMod & 15) != 0) || (gcnEncSize==GCNEncSize::BIT64);
1481   
1482    if ((src0Op.range.isVal(255) || src1Op.range.isVal(255)) &&
1483        (src0Op.range.isSGPR() || src0Op.range.isVal(124) ||
1484         src1Op.range.isSGPR() || src1Op.range.isVal(124)))
1485        ASM_FAIL_BY_ERROR(instrPlace, "Literal with SGPR or M0 is illegal")
1486   
1487    AsmRegVarUsage* rvus = gcnAsm->instrRVUs;
1488    if (vop3) // modify fields in reg usage
1489    {
1490        if (rvus[0].regField != ASMFIELD_NONE)
1491            rvus[0].regField = (rvus[0].regField==GCNFIELD_VOP_VDST) ? GCNFIELD_VOP3_VDST :
1492                            GCNFIELD_VOP3_SDST0;
1493        if (rvus[2].regField != ASMFIELD_NONE)
1494            rvus[2].regField = GCNFIELD_VOP3_SRC0;
1495        if (rvus[3].regField != ASMFIELD_NONE)
1496            rvus[3].regField = GCNFIELD_VOP3_SRC1;
1497    }
1498    else
1499    {
1500        // vop2
1501        if (rvus[1].regField != ASMFIELD_NONE)
1502            rvus[1].regField = GCNFIELD_VOP_VCC_SDST1;
1503        if (rvus[4].regField != ASMFIELD_NONE)
1504            rvus[4].regField = GCNFIELD_VOP_VCC_SSRC;
1505    }
1506   
1507    // count number SGPR operands readed by instruction
1508    cxuint sgprsReaded = 0;
1509    if (src0Op.range.isSGPR())
1510        sgprsReaded++;
1511    if (src1Op.range.isSGPR() && !regRangeCanEqual(src0Op.range, src1Op.range))
1512        sgprsReaded++;
1513    if (haveSrcCC)
1514        // check for third operand (SSRC)
1515        if (!regRangeCanEqual(src0Op.range, srcCCReg) &&
1516            !regRangeCanEqual(src1Op.range, srcCCReg))
1517            sgprsReaded++;
1518   
1519    if ((arch & ARCH_GCN_1_5)==0)
1520    {
1521        if (sgprsReaded >= 2)
1522            /* include VCCs (???) */
1523            ASM_FAIL_BY_ERROR(instrPlace, "More than one SGPR to read in instruction")
1524    }
1525    else
1526    {   // NAVI
1527        if (sgprsReaded >= 3)
1528            /* include VCCs (???) */
1529            ASM_FAIL_BY_ERROR(instrPlace, "More than two SGPRs to read in instruction")
1530    }
1531   
1532    const bool needImm = (src0Op.range.start==255 || src1Op.range.start==255 ||
1533             mode1 == GCN_ARG1_IMM || mode1 == GCN_ARG2_IMM);
1534   
1535    bool sextFlags = ((src0Op.vopMods|src1Op.vopMods) & VOPOP_SEXT);
1536    bool absNegFlags = ((src0Op.vopMods|src1Op.vopMods) & (VOPOP_ABS|VOPOP_NEG));
1537    if (isGCN12 && (extraMods.needSDWA || extraMods.needDPP || extraMods.needDPP8 ||
1538                sextFlags || gcnVOPEnc!=GCNVOPEnc::NORMAL))
1539    {
1540        /* if VOP_SDWA or VOP_DPP is required */
1541        if (!checkGCNVOPExtraModifers(asmr, arch, needImm, sextFlags, vop3,
1542                    gcnVOPEnc, src0Op, extraMods, absNegFlags, instrPlace))
1543            return false;
1544        if (gcnAsm->instrRVUs[2].regField != ASMFIELD_NONE)
1545            gcnAsm->instrRVUs[2].regField = GCNFIELD_DPPSDWA_SRC0;
1546       
1547        if (extraMods.needSDWA && isGCN14)
1548        {
1549            // fix for extra type operand from SDWA
1550            if (rvus[2].regField != ASMFIELD_NONE && src0Op.range.isNonVGPR())
1551                rvus[2].regField = GCNFIELD_DPPSDWA_SSRC0;
1552            if (rvus[3].regField != ASMFIELD_NONE && src1Op.range.isNonVGPR())
1553                rvus[3].regField = GCNFIELD_VOP_SSRC1;
1554        }
1555    }
1556    else if (isGCN12 && ((src0Op.vopMods|src1Op.vopMods) & ~VOPOP_SEXT)!=0 && !sextFlags)
1557        // if all pass we check we promote VOP3 if only operand modifiers expect sext()
1558        vop3 = true;
1559   
1560    if (isGCN12 && vop3 && haveDstCC && ((src0Op.vopMods|src1Op.vopMods) & VOPOP_ABS) != 0)
1561        ASM_FAIL_BY_ERROR(instrPlace, "Abs modifier is illegal for VOP3B encoding")
1562    if (vop3 && needImm)
1563        ASM_FAIL_BY_ERROR(instrPlace, "Literal in VOP3 encoding is illegal")
1564   
1565    if (!checkGCNVOPEncoding(asmr, arch, instrPlace, gcnVOPEnc, gcnInsn.mode, &extraMods))
1566        return false;
1567   
1568    if (vop3 && gcnInsn.code2==UINT16_MAX)
1569        ASM_FAIL_BY_ERROR(instrPlace, "No VOP3 encoding for this instruction")
1570   
1571    // set target expressions if needed
1572    if (src0OpExpr!=nullptr)
1573        src0OpExpr->setTarget(AsmExprTarget(GCNTGT_LITIMM, asmr.currentSection,
1574                      output.size()));
1575    if (src1OpExpr!=nullptr)
1576        src1OpExpr->setTarget(AsmExprTarget(GCNTGT_LITIMM, asmr.currentSection,
1577                      output.size()));
1578    if (immExpr!=nullptr)
1579        immExpr->setTarget(AsmExprTarget(GCNTGT_LITIMM, asmr.currentSection,
1580                      output.size()));
1581   
1582    // put data (instruction words)
1583    cxuint wordsNum = 1;
1584    uint32_t words[2];
1585    if (!vop3)
1586        // VOP2 encoding
1587        encodeVOPWords((uint32_t(gcnInsn.code1)<<25) |
1588                (uint32_t(src1Op.range.bstart()&0xff)<<9) |
1589                (uint32_t(dstReg.bstart()&0xff)<<17),
1590                modifiers, extraMods, src0Op, src1Op, immValue, mode1,
1591                0, wordsNum, words);
1592    else
1593        // VOP3 encoding
1594        encodeVOP3Words(arch, gcnInsn, modifiers, opMods, haveDstCC,
1595                dstReg, dstCCReg, srcCCReg, src0Op, src1Op, wordsNum, words);
1596   
1597    if (!checkGCNEncodingSize(asmr, instrPlace, gcnEncSize, wordsNum))
1598        return false;
1599   
1600    output.insert(output.end(), reinterpret_cast<cxbyte*>(words),
1601            reinterpret_cast<cxbyte*>(words + wordsNum));
1602    /// prevent freeing expression
1603    src0OpExpr.release();
1604    src1OpExpr.release();
1605    immExpr.release();
1606    // update register pool (VGPR and SGPR counting)
1607    if (!dstReg.isRegVar())
1608    {
1609        if (dstReg.start>=256)
1610            updateVGPRsNum(gcnRegs.vgprsNum, dstReg.end-257);
1611        else // sgprs
1612        {
1613            updateSGPRsNum(gcnRegs.sgprsNum, dstReg.end-1, arch);
1614            updateRegFlags(gcnRegs.regFlags, dstReg.start, arch);
1615        }
1616    }
1617    // for SRC operands
1618    if (src0Op.range && !src0Op.range.isRegVar())
1619        updateRegFlags(gcnRegs.regFlags, src0Op.range.start, arch);
1620    if (src1Op.range && !src1Op.range.isRegVar())
1621        updateRegFlags(gcnRegs.regFlags, src1Op.range.start, arch);
1622    if (dstCCReg && !dstCCReg.isRegVar())
1623    {
1624        updateSGPRsNum(gcnRegs.sgprsNum, dstCCReg.end-1, arch);
1625        updateRegFlags(gcnRegs.regFlags, dstCCReg.start, arch);
1626    }
1627    if (srcCCReg && !srcCCReg.isRegVar())
1628        updateRegFlags(gcnRegs.regFlags, srcCCReg.start, arch);
1629    return true;
1630}
1631
1632bool GCNAsmUtils::parseVOP1Encoding(Assembler& asmr, const GCNAsmInstruction& gcnInsn,
1633                  const char* instrPlace, const char* linePtr, GPUArchMask arch,
1634                  std::vector<cxbyte>& output, GCNAssembler::Regs& gcnRegs,
1635                  GCNEncSize gcnEncSize, GCNVOPEnc gcnVOPEnc)
1636{
1637    bool good = true;
1638    const GCNInsnMode mode1 = (gcnInsn.mode & GCN_MASK1);
1639    const GCNInsnMode mode2 = (gcnInsn.mode & GCN_LITMASK);
1640    const bool isGCN12 = (arch & ARCH_GCN_1_2_4_5)!=0;
1641    const bool isGCN14 = (arch & ARCH_GCN_1_4_5)!=0;
1642   
1643    GCNAssembler* gcnAsm = static_cast<GCNAssembler*>(asmr.isaAssembler);
1644    RegRange dstReg(0, 0);
1645    GCNOperand src0Op{};
1646    std::unique_ptr<AsmExpression> src0OpExpr;
1647    cxbyte modifiers = 0;
1648    if (mode1 != GCN_VOP_ARG_NONE)
1649    {
1650        gcnAsm->setCurrentRVU(0);
1651        if (mode1 == GCN_DST_SGPR)
1652            // if SGPRS as destination
1653            good &= parseSRegRange(asmr, linePtr, dstReg, arch,
1654                           (gcnInsn.mode&GCN_REG_DST_64)?2:1, GCNFIELD_VOP_SDST, true,
1655                           INSTROP_SYMREGRANGE|INSTROP_SGPR_UNALIGNED|INSTROP_WRITE);
1656        else // if VGPRS as destination
1657            good &= parseVRegRange(asmr, linePtr, dstReg,
1658                       (gcnInsn.mode&GCN_REG_DST_64)?2:1, GCNFIELD_VOP_VDST, true,
1659                                  INSTROP_SYMREGRANGE|INSTROP_WRITE);
1660       
1661        const Flags literalConstsFlags = (mode2==GCN_FLOATLIT) ? INSTROP_FLOAT :
1662                (mode2==GCN_F16LIT) ? INSTROP_F16 : INSTROP_INT;
1663       
1664        if (!skipRequiredComma(asmr, linePtr))
1665            return false;
1666        cxuint regsNum = (gcnInsn.mode&GCN_REG_SRC0_64)?2:1;
1667        gcnAsm->setCurrentRVU(1);
1668        // parse SRC0 (can be VGPR, SGPR, source scalar, literal or cosntant, LDS
1669        good &= parseOperand(asmr, linePtr, src0Op, &src0OpExpr, arch, regsNum,
1670                    correctOpType(regsNum, literalConstsFlags)|INSTROP_VREGS|
1671                    INSTROP_SGPR_UNALIGNED|INSTROP_SSOURCE|INSTROP_SREGS|INSTROP_LDS|
1672                    INSTROP_VOP3MODS|INSTROP_READ, GCNFIELD_VOP_SRC0);
1673    }
1674    // modifiers
1675    VOPExtraModifiers extraMods{};
1676    VOPOpModifiers opMods{};
1677    good &= parseVOPModifiers(asmr, linePtr, arch, modifiers, opMods,
1678                  (mode1!=GCN_VOP_ARG_NONE) ? 2 : 0, (isGCN12)?&extraMods:nullptr,
1679                  PARSEVOP_WITHCLAMP|PARSEVOP_WITHSEXT|
1680                  (isGCN14 ? PARSEVOP_WITHOPSEL : 0), (mode1!=GCN_VOP_ARG_NONE) ? 2 : 0);
1681    if (!good || !checkGarbagesAtEnd(asmr, linePtr))
1682        return false;
1683   
1684    if (src0Op)
1685        src0Op.vopMods |= ((opMods.absMod&1) ? VOPOP_ABS : 0) |
1686                ((opMods.negMod&1) ? VOPOP_NEG : 0) |
1687                ((opMods.sextMod&1) ? VOPOP_SEXT : 0);
1688   
1689    extraMods.needSDWA |= ((src0Op.vopMods) & VOPOP_SEXT) != 0;
1690    // check whether VOP3 encoding is needed
1691    bool vop3 = ((!isGCN12 && src0Op.vopMods!=0) ||
1692            (modifiers&~(VOP3_BOUNDCTRL|(extraMods.needSDWA?VOP3_CLAMP:0)|
1693            /* exclude OMOD if RXVEGA and SDWA used */
1694            ((isGCN14 && extraMods.needSDWA) ? 3 : 0)))!=0) ||
1695            ((opMods.opselMod & 15) != 0) || (gcnEncSize==GCNEncSize::BIT64);
1696    if (vop3) // modify fields in reg usage
1697    {
1698        AsmRegVarUsage* rvus = gcnAsm->instrRVUs;
1699        if (rvus[0].regField != ASMFIELD_NONE)
1700            rvus[0].regField = (rvus[0].regField==GCNFIELD_VOP_VDST) ?
1701                        GCNFIELD_VOP3_VDST : GCNFIELD_VOP3_SDST0;
1702        if (rvus[1].regField != ASMFIELD_NONE)
1703            rvus[1].regField = GCNFIELD_VOP3_SRC0;
1704    }
1705   
1706    bool sextFlags = (src0Op.vopMods & VOPOP_SEXT);
1707    bool absNegFlags = (src0Op.vopMods & (VOPOP_ABS|VOPOP_NEG));
1708    bool needImm = (src0Op && src0Op.range.isVal(255));
1709    if (isGCN12 && (extraMods.needSDWA || extraMods.needDPP || extraMods.needDPP8 ||
1710                sextFlags || gcnVOPEnc!=GCNVOPEnc::NORMAL))
1711    {
1712        /* if VOP_SDWA or VOP_DPP is required */
1713        if (!checkGCNVOPExtraModifers(asmr, arch, needImm, sextFlags, vop3,
1714                    gcnVOPEnc, src0Op, extraMods, absNegFlags, instrPlace))
1715            return false;
1716        if (gcnAsm->instrRVUs[1].regField != ASMFIELD_NONE)
1717            gcnAsm->instrRVUs[1].regField = GCNFIELD_DPPSDWA_SRC0;
1718        if (extraMods.needSDWA && isGCN14)
1719        {
1720            // fix for extra type operand from SDWA
1721            AsmRegVarUsage* rvus = gcnAsm->instrRVUs;
1722            if (rvus[1].regField != ASMFIELD_NONE && src0Op.range.isNonVGPR())
1723                rvus[1].regField = GCNFIELD_DPPSDWA_SSRC0;
1724        }
1725    }
1726    else if (isGCN12 && (src0Op.vopMods & ~VOPOP_SEXT)!=0 && !sextFlags)
1727        // if all pass we check we promote VOP3 if only operand modifiers expect sext()
1728        vop3 = true;
1729   
1730    if (vop3 && src0Op.range.isVal(255))
1731        ASM_FAIL_BY_ERROR(instrPlace, "Literal in VOP3 encoding is illegal")
1732   
1733    if (!checkGCNVOPEncoding(asmr, arch, instrPlace, gcnVOPEnc, gcnInsn.mode, &extraMods))
1734        return false;
1735   
1736    if (src0OpExpr!=nullptr)
1737        src0OpExpr->setTarget(AsmExprTarget(GCNTGT_LITIMM, asmr.currentSection,
1738                      output.size()));
1739   
1740    // put data (instruction word)
1741    cxuint wordsNum = 1;
1742    uint32_t words[2];
1743    if (!vop3)
1744        // VOP1 encoding
1745        encodeVOPWords(0x7e000000U | (uint32_t(gcnInsn.code1)<<9) |
1746                (uint32_t(dstReg.bstart()&0xff)<<17),
1747                modifiers, extraMods, src0Op, GCNOperand{ { 256, 257 } }, 0, mode1,
1748                0, wordsNum, words);
1749    else
1750        // VOP3 encoding
1751        encodeVOP3Words(arch, gcnInsn, modifiers, opMods, false,
1752                dstReg, RegRange{}, RegRange{}, src0Op, GCNOperand{}, wordsNum, words);
1753   
1754    if (!checkGCNEncodingSize(asmr, instrPlace, gcnEncSize, wordsNum))
1755        return false;
1756   
1757    output.insert(output.end(), reinterpret_cast<cxbyte*>(words),
1758            reinterpret_cast<cxbyte*>(words + wordsNum));
1759    /// prevent freeing expression
1760    src0OpExpr.release();
1761    // update register pool (VGPR and SGPR counting)
1762    if (dstReg && !dstReg.isRegVar())
1763    {
1764        if (dstReg.start>=256)
1765            updateVGPRsNum(gcnRegs.vgprsNum, dstReg.end-257);
1766        else // sgprs
1767        {
1768            updateSGPRsNum(gcnRegs.sgprsNum, dstReg.end-1, arch);
1769            updateRegFlags(gcnRegs.regFlags, dstReg.start, arch);
1770        }
1771    }
1772    if (src0Op.range && !src0Op.range.isRegVar())
1773        updateRegFlags(gcnRegs.regFlags, src0Op.range.start, arch);
1774    return true;
1775}
1776
1777bool GCNAsmUtils::parseVOPCEncoding(Assembler& asmr, const GCNAsmInstruction& gcnInsn,
1778                  const char* instrPlace, const char* linePtr, GPUArchMask arch,
1779                  std::vector<cxbyte>& output, GCNAssembler::Regs& gcnRegs,
1780                  GCNEncSize gcnEncSize, GCNVOPEnc gcnVOPEnc)
1781{
1782    bool good = true;
1783    const GCNInsnMode mode2 = (gcnInsn.mode & GCN_MASK2);
1784    const bool isGCN12 = (arch & ARCH_GCN_1_2_4_5)!=0;
1785    const bool isGCN14 = (arch & ARCH_GCN_1_4_5)!=0;
1786    const bool isGCN15 = (arch & ARCH_GCN_1_5)!=0;
1787    const bool wave32 = (asmr.codeFlags & ASM_CODE_WAVE32)!=0;
1788   
1789    GCNAssembler* gcnAsm = static_cast<GCNAssembler*>(asmr.isaAssembler);
1790    RegRange dstReg(0, 0);
1791    GCNOperand src0Op{};
1792    std::unique_ptr<AsmExpression> src0OpExpr;
1793    GCNOperand src1Op{};
1794    std::unique_ptr<AsmExpression> src1OpExpr;
1795    cxbyte modifiers = 0;
1796   
1797    // parse SDST (2 SGPR's)
1798    if ((gcnInsn.mode & GCN_VOPC_NOVCC) == 0)
1799    {
1800        gcnAsm->setCurrentRVU(0);
1801        const cxuint regSize = (!isGCN15 || !wave32 ||
1802                        (gcnInsn.mode&GCN_VOP_NOWVSZ)!=0) ? 2 : 1;
1803        good &= parseSRegRange(asmr, linePtr, dstReg, arch, regSize, GCNFIELD_VOP3_SDST0,
1804                        true, INSTROP_SYMREGRANGE|INSTROP_SGPR_UNALIGNED|INSTROP_WRITE);
1805        if (!skipRequiredComma(asmr, linePtr))
1806            return false;
1807    }
1808   
1809    const Flags literalConstsFlags = (mode2==GCN_FLOATLIT) ? INSTROP_FLOAT :
1810                (mode2==GCN_F16LIT) ? INSTROP_F16 : INSTROP_INT;
1811    cxuint regsNum = (gcnInsn.mode&GCN_REG_SRC0_64)?2:1;
1812    gcnAsm->setCurrentRVU(1);
1813    // parse SRC0 (can VGPR, SGPR, scalar source,literal or constant)
1814    good &= parseOperand(asmr, linePtr, src0Op, &src0OpExpr, arch, regsNum,
1815                    correctOpType(regsNum, literalConstsFlags)|INSTROP_VREGS|
1816                    INSTROP_SGPR_UNALIGNED|INSTROP_SSOURCE|INSTROP_SREGS|INSTROP_LDS|
1817                    INSTROP_VOP3MODS|INSTROP_READ, GCNFIELD_VOP_SRC0);
1818   
1819    if (!skipRequiredComma(asmr, linePtr))
1820        return false;
1821    regsNum = (gcnInsn.mode&GCN_REG_SRC1_64)?2:1;
1822    gcnAsm->setCurrentRVU(2);
1823    // parse SRC1 (can VGPR, SGPR, scalar source,literal or constant)
1824    good &= parseOperand(asmr, linePtr, src1Op, &src1OpExpr, arch, regsNum,
1825                correctOpType(regsNum, literalConstsFlags) | INSTROP_VOP3MODS|
1826                INSTROP_SGPR_UNALIGNED|INSTROP_VREGS|INSTROP_SSOURCE|INSTROP_SREGS|
1827                INSTROP_READ| (src0Op.range.isVal(255) ? INSTROP_ONLYINLINECONSTS : 0),
1828                GCNFIELD_VOP_VSRC1);
1829    // modifiers
1830    VOPExtraModifiers extraMods{};
1831    VOPOpModifiers opMods{};
1832    good &= parseVOPModifiers(asmr, linePtr, arch, modifiers, opMods, 3,
1833                (isGCN12)?&extraMods:nullptr, (isGCN14 ? PARSEVOP_NODSTMODS : 0)|
1834                PARSEVOP_WITHCLAMP|PARSEVOP_WITHSEXT|(isGCN14 ? PARSEVOP_WITHOPSEL : 0));
1835    if (!good || !checkGarbagesAtEnd(asmr, linePtr))
1836        return false;
1837   
1838    // set VOP operand modifiers to src operands
1839    if (src0Op)
1840        src0Op.vopMods |= ((opMods.absMod&1) ? VOPOP_ABS : 0) |
1841                ((opMods.negMod&1) ? VOPOP_NEG : 0) |
1842                ((opMods.sextMod&1) ? VOPOP_SEXT : 0);
1843    if (src1Op)
1844        src1Op.vopMods |= ((opMods.absMod&2) ? VOPOP_ABS : 0) |
1845                ((opMods.negMod&2) ? VOPOP_NEG : 0) |
1846                ((opMods.sextMod&2) ? VOPOP_SEXT : 0);
1847   
1848    const cxuint vccCode = ((gcnInsn.mode & GCN_VOPC_NOVCC) == 0) ? 106 : 0;
1849    // determine whether SDWA is needed or VOP3 encoding needed
1850    extraMods.needSDWA |= ((src0Op.vopMods | src1Op.vopMods) & VOPOP_SEXT) != 0;
1851    bool vop3 = //(dstReg.start!=106) || (src1Op.range.start<256) ||
1852        ((!isGCN14 || !extraMods.needSDWA) && !dstReg.isVal(vccCode)) ||
1853        ((!isGCN14 || !extraMods.needSDWA) && src1Op.range.isNonVGPR()) ||
1854        (!isGCN12 && (src0Op.vopMods!=0 || src1Op.vopMods!=0)) ||
1855        (modifiers&~(VOP3_BOUNDCTRL|(extraMods.needSDWA?VOP3_CLAMP:0)|
1856            /* exclude OMOD if RXVEGA and SDWA used */
1857            ((isGCN14 && extraMods.needSDWA) ? 3 : 0)))!=0 ||
1858        ((opMods.opselMod & 15) != 0) || (gcnEncSize==GCNEncSize::BIT64);
1859   
1860    if ((src0Op.range.isVal(255) || src1Op.range.isVal(255)) &&
1861        (src0Op.range.isSGPR() || src0Op.range.isVal(124) ||
1862         src1Op.range.isSGPR() || src1Op.range.isVal(124)))
1863        ASM_FAIL_BY_ERROR(instrPlace, "Literal with SGPR or M0 is illegal")
1864    if ((arch & ARCH_GCN_1_5) == 0 && src0Op.range.isSGPR() && src1Op.range.isSGPR() &&
1865        !regRangeCanEqual(src0Op.range, src1Op.range))
1866        /* include VCCs (???) */
1867        ASM_FAIL_BY_ERROR(instrPlace, "More than one SGPR to read in instruction")
1868   
1869    AsmRegVarUsage* rvus = gcnAsm->instrRVUs;
1870    if (vop3)
1871    {
1872        // modify fields in reg usage
1873        if (rvus[1].regField != ASMFIELD_NONE)
1874            rvus[1].regField = GCNFIELD_VOP3_SRC0;
1875        if (rvus[2].regField != ASMFIELD_NONE)
1876            rvus[2].regField = GCNFIELD_VOP3_SRC1;
1877    }
1878    else if (rvus[0].regField != ASMFIELD_NONE)
1879        rvus[0].regField = GCNFIELD_VOP_VCC_SDST0;
1880   
1881    const bool needImm = src0Op.range.start==255 || src1Op.range.start==255;
1882   
1883    bool sextFlags = ((src0Op.vopMods|src1Op.vopMods) & VOPOP_SEXT);
1884    bool absNegFlags = (src0Op.vopMods & (VOPOP_ABS|VOPOP_NEG));
1885    if (isGCN12 && (extraMods.needSDWA || extraMods.needDPP || extraMods.needDPP8 ||
1886                sextFlags || gcnVOPEnc!=GCNVOPEnc::NORMAL))
1887    {
1888        /* if VOP_SDWA or VOP_DPP is required */
1889        if (!checkGCNVOPExtraModifers(asmr, arch, needImm, sextFlags, vop3,
1890                    gcnVOPEnc, src0Op, extraMods, absNegFlags, instrPlace))
1891            return false;
1892        if (gcnAsm->instrRVUs[1].regField != ASMFIELD_NONE)
1893            gcnAsm->instrRVUs[1].regField = GCNFIELD_DPPSDWA_SRC0;
1894       
1895        if (extraMods.needSDWA && isGCN14)
1896        {
1897            // fix for extra type operand from SDWA
1898            AsmRegVarUsage* rvus = gcnAsm->instrRVUs;
1899            if (rvus[0].regField != ASMFIELD_NONE)
1900                rvus[0].regField = GCNFIELD_SDWAB_SDST;
1901            if (rvus[1].regField != ASMFIELD_NONE && src0Op.range.isNonVGPR())
1902                rvus[1].regField = GCNFIELD_DPPSDWA_SSRC0;
1903            if (rvus[2].regField != ASMFIELD_NONE && src1Op.range.isNonVGPR())
1904                rvus[2].regField = GCNFIELD_VOP_SSRC1;
1905        }
1906    }
1907    else if (isGCN12 && ((src0Op.vopMods|src1Op.vopMods) & ~VOPOP_SEXT)!=0 && !sextFlags)
1908        // if all pass we check we promote VOP3 if only operand modifiers expect sext()
1909        vop3 = true;
1910   
1911    if (vop3 && (src0Op.range.isVal(255) || src1Op.range.isVal(255)))
1912        ASM_FAIL_BY_ERROR(instrPlace, "Literal in VOP3 encoding is illegal")
1913   
1914    if (!checkGCNVOPEncoding(asmr, arch, instrPlace, gcnVOPEnc, gcnInsn.mode, &extraMods))
1915        return false;
1916   
1917    if (isGCN14 && extraMods.needSDWA && ((modifiers & VOP3_CLAMP)!=0 || (modifiers&3)!=0))
1918        ASM_FAIL_BY_ERROR(instrPlace, "Modifiers CLAMP and OMOD is illegal in SDWAB")
1919   
1920    if (src0OpExpr!=nullptr)
1921        src0OpExpr->setTarget(AsmExprTarget(GCNTGT_LITIMM, asmr.currentSection,
1922                      output.size()));
1923    if (src1OpExpr!=nullptr)
1924        src1OpExpr->setTarget(AsmExprTarget(GCNTGT_LITIMM, asmr.currentSection,
1925                      output.size()));
1926   
1927    // put data (instruction words)
1928    cxuint wordsNum = 1;
1929    uint32_t words[2];
1930    if (!vop3)
1931    {
1932        // VOPC encoding
1933        const uint32_t dstMods = (isGCN14 ? 0x10000 : 0) |
1934                ((isGCN14 && !dstReg.isVal(106)) ? ((dstReg.bstart()|0x80)<<8) : 0);
1935       
1936        encodeVOPWords(0x7c000000U | (uint32_t(gcnInsn.code1)<<17) |
1937                (uint32_t(src1Op.range.bstart()&0xff)<<9),
1938                modifiers, extraMods, src0Op, src1Op, 0, 0,
1939                dstMods, wordsNum, words);
1940    }
1941    else
1942        // VOP3 encoding
1943        encodeVOP3Words(arch, gcnInsn, modifiers, opMods, false,
1944                dstReg, RegRange{}, RegRange{}, src0Op, src1Op, wordsNum, words);
1945   
1946    if (!checkGCNEncodingSize(asmr, instrPlace, gcnEncSize, wordsNum))
1947        return false;
1948    output.insert(output.end(), reinterpret_cast<cxbyte*>(words),
1949            reinterpret_cast<cxbyte*>(words + wordsNum));
1950    /// prevent freeing expression
1951    src0OpExpr.release();
1952    src1OpExpr.release();
1953    // update register pool (VGPR and SGPR counting)
1954    if (dstReg && !dstReg.isRegVar())
1955    {
1956        updateSGPRsNum(gcnRegs.sgprsNum, dstReg.end-1, arch);
1957        updateRegFlags(gcnRegs.regFlags, dstReg.start, arch);
1958    }
1959    if (src0Op.range && !src0Op.range.isRegVar())
1960        updateRegFlags(gcnRegs.regFlags, src0Op.range.start, arch);
1961    if (src1Op.range && !src1Op.range.isRegVar())
1962        updateRegFlags(gcnRegs.regFlags, src1Op.range.start, arch);
1963    return true;
1964}
1965
1966bool GCNAsmUtils::parseVOP3Encoding(Assembler& asmr, const GCNAsmInstruction& gcnInsn,
1967                  const char* instrPlace, const char* linePtr, GPUArchMask arch,
1968                  std::vector<cxbyte>& output, GCNAssembler::Regs& gcnRegs,
1969                  GCNEncSize gcnEncSize, GCNVOPEnc gcnVOPEnc)
1970{
1971    bool good = true;
1972    const GCNInsnMode mode1 = (gcnInsn.mode & GCN_MASK1);
1973    const GCNInsnMode mode2 = (gcnInsn.mode & GCN_MASK2);
1974    const GCNInsnMode fltmode = (gcnInsn.mode & GCN_LITMASK);
1975    const bool isGCN12 = (arch & ARCH_GCN_1_2_4_5)!=0;
1976    const bool isGCN14 = (arch & ARCH_GCN_1_4_5)!=0;
1977    const bool isGCN15 = (arch & ARCH_GCN_1_5)!=0;
1978    const bool vop3p = (gcnInsn.mode & GCN_VOP3_VOP3P) != 0 ||
1979                    (gcnInsn.encoding == GCNENC_VOP3P);
1980    const bool wave32 = (asmr.codeFlags & ASM_CODE_WAVE32)!=0;
1981    if (gcnVOPEnc!=GCNVOPEnc::NORMAL)
1982        ASM_FAIL_BY_ERROR(instrPlace, "DPP and SDWA encoding is illegal for VOP3")
1983   
1984    GCNAssembler* gcnAsm = static_cast<GCNAssembler*>(asmr.isaAssembler);
1985    RegRange dstReg(0, 0);
1986    RegRange sdstReg(0, 0);
1987    GCNOperand src0Op{};
1988    std::unique_ptr<AsmExpression> src0OpExpr;
1989    GCNOperand src1Op{};
1990    std::unique_ptr<AsmExpression> src1OpExpr;
1991    GCNOperand src2Op{};
1992    std::unique_ptr<AsmExpression> src2OpExpr;
1993   
1994    const bool vccImplRead = (gcnInsn.mode & GCN_VCC_IMPL_READ)!=0;
1995    const bool vccImplWrite = (gcnInsn.mode & GCN_VCC_IMPL_WRITE)!=0;
1996   
1997    const bool is128Ops = (gcnInsn.mode & 0x7000) == GCN_VOP3_DS2_128;
1998    bool modHigh = false;
1999    cxbyte modifiers = 0;
2000    const Flags vop3Mods = ((gcnInsn.encoding == GCNENC_VOP3B) ?
2001            INSTROP_VOP3NEG : INSTROP_VOP3MODS | INSTROP_NOSEXT) |
2002            (vop3p ? INSTROP_VOP3P : 0);
2003   
2004    // by default OPSEL_HI is [1,1,1] in vop3p instructions
2005    VOPOpModifiers opMods{ 0, 0, 0, cxbyte(vop3p ? 7<<4 : 0) };
2006    cxuint operands = 1;
2007    const Flags onlyInlineConsts = (!isGCN15) ?
2008                INSTROP_ONLYINLINECONSTS|INSTROP_NOLITERALERROR : 0;
2009   
2010    if (mode1 != GCN_VOP_ARG_NONE)
2011    {
2012        gcnAsm->setCurrentRVU(0);
2013        // parse DST (
2014        if ((gcnInsn.mode&GCN_VOP3_DST_SGPR)==0)
2015            good &= parseVRegRange(asmr, linePtr, dstReg,
2016                       (is128Ops) ? 4 : ((gcnInsn.mode&GCN_REG_DST_64)?2:1),
2017                       GCNFIELD_VOP3_VDST, true, INSTROP_SYMREGRANGE|INSTROP_WRITE);
2018        else // SGPRS as dest
2019            good &= parseSRegRange(asmr, linePtr, dstReg, arch,
2020                       (gcnInsn.mode&GCN_REG_DST_64)?2:1, GCNFIELD_VOP3_SDST0, true,
2021                       INSTROP_SYMREGRANGE|INSTROP_SGPR_UNALIGNED|INSTROP_WRITE);
2022        if (!skipRequiredComma(asmr, linePtr))
2023            return false;
2024       
2025        if (gcnInsn.encoding == GCNENC_VOP3B &&
2026            (mode1 == GCN_DS2_VCC || mode1 == GCN_DST_VCC || mode1 == GCN_DST_VCC_VSRC2 ||
2027             mode1 == GCN_S0EQS12)) /* VOP3b */
2028        {
2029            // SDST (VCC) (2 SGPR's)
2030            gcnAsm->setCurrentRVU(1);
2031            const cxuint regSize = (!isGCN15 || !wave32 ||
2032                        (gcnInsn.mode&GCN_VOP_NOWVSZ)!=0) ? 2 : 1;
2033            good &= parseSRegRange(asmr, linePtr, sdstReg, arch, regSize,
2034                        GCNFIELD_VOP3_SDST1, true, INSTROP_SYMREGRANGE|INSTROP_WRITE|
2035                        INSTROP_SGPR_UNALIGNED);
2036            if (!skipRequiredComma(asmr, linePtr))
2037                return false;
2038        }
2039        else if (vccImplRead)
2040        {
2041            gcnAsm->setCurrentRVU(1);
2042            gcnAsm->setRegVarUsage({ size_t(asmr.currentOutPos), nullptr,
2043                        uint16_t(106), uint16_t(107), GCNFIELD_VOP_VCC_IMPL,
2044                        ASMRVU_READ, 0 });
2045        }
2046        else if (vccImplWrite)
2047        {
2048            gcnAsm->setCurrentRVU(1);
2049            gcnAsm->setRegVarUsage({ size_t(asmr.currentOutPos), nullptr,
2050                        uint16_t(106), uint16_t(107), GCNFIELD_VOP_VCC_IMPL,
2051                        ASMRVU_WRITE, 0 });
2052        }
2053       
2054        const Flags literalConstsFlags = (fltmode==GCN_FLOATLIT) ? INSTROP_FLOAT :
2055                (fltmode==GCN_F16LIT) ? INSTROP_F16 : INSTROP_INT;
2056       
2057        cxuint regsNum;
2058        if (mode2 != GCN_VOP3_VINTRP)
2059        {
2060            // parse SRC0 (can be VGPR, SGPR, scalar source, constant, LDS)
2061            gcnAsm->setCurrentRVU(2);
2062            regsNum = (gcnInsn.mode&GCN_REG_SRC0_64)?2:1;
2063            std::unique_ptr<AsmExpression>* src0OpExprPtr =
2064                                    isGCN15 ? &src0OpExpr : nullptr;
2065            good &= parseOperand(asmr, linePtr, src0Op, src0OpExprPtr, arch, regsNum,
2066                    correctOpType(regsNum, literalConstsFlags)|INSTROP_VREGS|
2067                    INSTROP_SGPR_UNALIGNED|INSTROP_SSOURCE|INSTROP_SREGS|INSTROP_LDS|
2068                    vop3Mods|onlyInlineConsts|INSTROP_READ, GCNFIELD_VOP3_SRC0);
2069            operands++;
2070        }
2071       
2072        if (mode2 == GCN_VOP3_VINTRP)
2073        {
2074            // if VINTRP instruction
2075            gcnAsm->setCurrentRVU(3);
2076            if (mode1 != GCN_P0_P10_P20)
2077            {
2078                good &= parseOperand(asmr, linePtr, src1Op, nullptr, arch, 1,
2079                        INSTROP_VREGS|vop3Mods|INSTROP_READ, GCNFIELD_VOP3_SRC1);
2080            }
2081            else /* P0_P10_P20 */
2082                good &= parseVINTRP0P10P20(asmr, linePtr, src1Op.range);
2083           
2084            if (!skipRequiredComma(asmr, linePtr))
2085                return false;
2086           
2087            cxbyte attr;
2088            good &= parseVINTRPAttr(asmr, linePtr, attr);
2089            attr = ((attr&3)<<6) | ((attr&0xfc)>>2);
2090            src0Op.range = { attr, uint16_t(attr+1) };
2091           
2092            if ((gcnInsn.mode & GCN_VOP3_MASK3) == GCN_VINTRP_SRC2)
2093            {
2094                if (!skipRequiredComma(asmr, linePtr))
2095                    return false;
2096                // parse SRC2 (VGPR, SGPR)
2097                gcnAsm->setCurrentRVU(4);
2098                good &= parseOperand(asmr, linePtr, src2Op, nullptr, arch,
2099                    (gcnInsn.mode&GCN_REG_SRC2_64)?2:1, vop3Mods|INSTROP_SGPR_UNALIGNED|
2100                    INSTROP_VREGS|INSTROP_SREGS|INSTROP_READ, GCNFIELD_VOP3_SRC2);
2101            }
2102            // high and vop3
2103            const char* end = asmr.line+asmr.lineSize;
2104            bool haveOpsel = false;
2105            bool haveNeg = false, haveAbs = false;
2106            // own parse VINTRP modifiers with some VOP3 modifiers
2107            while (true)
2108            {
2109                bool alreadyModDefined = false;
2110                skipSpacesToEnd(linePtr, end);
2111                if (linePtr==end)
2112                    break;
2113                char modName[10];
2114                const char* modPlace = linePtr;
2115                if (!getNameArgS(asmr, 10, modName, linePtr, "VINTRP modifier"))
2116                    continue;
2117                if (::strcmp(modName, "high")==0)
2118                    good &= parseModEnable(asmr, linePtr, modHigh, "high modifier");
2119                else if (::strcmp(modName, "vop3")==0)
2120                {
2121                    bool vop3Mod = false;
2122                    good &= parseModEnable(asmr, linePtr, vop3Mod, "vop3 modifier");
2123                    modifiers = (modifiers & ~VOP3_VOP3) | (vop3Mod ? VOP3_VOP3 : 0);
2124                }
2125                else if (parseSingleOMODCLAMP(asmr, linePtr, modPlace, modName, arch,
2126                        modifiers, opMods, 
2127                        (gcnInsn.mode & GCN_VOP3_MASK3) == GCN_VINTRP_SRC2 ? 4 : 3, PARSEVOP_WITHCLAMP, haveAbs, haveNeg,
2128                        alreadyModDefined, good))
2129                {   // do nothing
2130                }
2131                else if (::strcmp(modName, "op_sel")==0)
2132                {
2133                    // op_sel with boolean array
2134                    uint32_t opselVal = 0;
2135                    if (linePtr!=end && *linePtr==':')
2136                    {
2137                        linePtr++;
2138                        if (parseImmWithBoolArray(asmr, linePtr, opselVal, 4, WS_UNSIGNED))
2139                        {
2140                            opMods.opselMod = opselVal;
2141                            if (haveOpsel)
2142                                asmr.printWarning(modPlace, "Opsel is already defined");
2143                            haveOpsel = true;
2144                            opMods.opselMod = opselVal;
2145                        }
2146                    }
2147                    else
2148                        good = false;
2149                }
2150                else
2151                    ASM_NOTGOOD_BY_ERROR(modPlace, "Unknown VINTRP modifier")
2152            }
2153            if (modHigh)
2154            {
2155                src0Op.range.start+=0x100;
2156                src0Op.range.end+=0x100;
2157            }
2158        }
2159        else if (mode1 != GCN_SRC12_NONE)
2160        {
2161            // if encoding have two or three source operands
2162            if (!skipRequiredComma(asmr, linePtr))
2163                return false;
2164            regsNum = (gcnInsn.mode&GCN_REG_SRC1_64)?2:1;
2165            // parse SRC1 (can be VGPR, SGPR, source scalar, constant)
2166            gcnAsm->setCurrentRVU(3);
2167            std::unique_ptr<AsmExpression>* src1OpExprPtr =
2168                                    isGCN15 ? &src1OpExpr : nullptr;
2169            good &= parseOperand(asmr, linePtr, src1Op, src1OpExprPtr, arch, regsNum,
2170                    correctOpType(regsNum, literalConstsFlags)|INSTROP_VREGS|
2171                    INSTROP_SGPR_UNALIGNED|INSTROP_SSOURCE|INSTROP_SREGS|vop3Mods|
2172                    onlyInlineConsts|INSTROP_READ, GCNFIELD_VOP3_SRC1);
2173            operands++;
2174           
2175            if (mode1 != GCN_SRC2_NONE && mode1 != GCN_DST_VCC)
2176            {
2177                if (!skipRequiredComma(asmr, linePtr))
2178                    return false;
2179                regsNum = (gcnInsn.mode&GCN_REG_SRC2_64)?2:1;
2180                // parse SRC2 (can be VGPR, SGPR, source scalar, constant)
2181                gcnAsm->setCurrentRVU(4);
2182                std::unique_ptr<AsmExpression>* src2OpExprPtr =
2183                                    isGCN15 ? &src2OpExpr : nullptr;
2184                good &= parseOperand(asmr, linePtr, src2Op, src2OpExprPtr, arch,
2185                        is128Ops ? 4 : regsNum,
2186                        correctOpType(regsNum, literalConstsFlags)|INSTROP_SGPR_UNALIGNED|
2187                        INSTROP_VREGS|INSTROP_SSOURCE|INSTROP_SREGS|INSTROP_READ|
2188                        vop3Mods|onlyInlineConsts, GCNFIELD_VOP3_SRC2);
2189                operands++;
2190            }
2191        }
2192    }
2193    // modifiers
2194    if (mode2 != GCN_VOP3_VINTRP)
2195        good &= parseVOPModifiers(asmr, linePtr, arch, modifiers, opMods, operands,
2196                    nullptr, ((isGCN12 || gcnInsn.encoding!=GCNENC_VOP3B) ?
2197                            PARSEVOP_WITHCLAMP : 0) |
2198                    ((isGCN14 && gcnInsn.encoding!=GCNENC_VOP3B) ?
2199                            PARSEVOP_WITHOPSEL : 0) | (vop3p ? PARSEVOP_VOP3P : 0), 3);
2200    if (!good || !checkGarbagesAtEnd(asmr, linePtr))
2201        return false;
2202   
2203    // apply VOP modifiers (abs,neg,sext) to operands from modifiers
2204    if (src0Op)
2205        src0Op.vopMods |= ((opMods.absMod&1) ? VOPOP_ABS : 0) |
2206                ((opMods.negMod&1) ? VOPOP_NEG : 0) |
2207                ((opMods.sextMod&1) ? VOPOP_SEXT : 0);
2208    if (src1Op)
2209        src1Op.vopMods |= ((opMods.absMod&2) ? VOPOP_ABS : 0) |
2210                ((opMods.negMod&2) ? VOPOP_NEG : 0) |
2211                ((opMods.sextMod&2) ? VOPOP_SEXT : 0);
2212    if (src2Op)
2213        src2Op.vopMods |= ((opMods.absMod&4) ? VOPOP_ABS : 0) |
2214                ((opMods.negMod&4) ? VOPOP_NEG : 0);
2215   
2216    if (mode2 != GCN_VOP3_VINTRP)
2217    {
2218        // count SGPR operands readed by instruction
2219        cxuint numSgprToRead = 0;
2220        //if (src0Op.range.start<108)
2221        if (src0Op.range.isSGPR())
2222            numSgprToRead++;
2223        //if (src1Op && src1Op.range.start<108 &&
2224        if (src1Op && src1Op.range.isSGPR() &&
2225                    !regRangeCanEqual(src0Op.range, src1Op.range))
2226            numSgprToRead++;
2227        //if (src2Op && src2Op.range.start<108 &&
2228        if (src2Op && src2Op.range.isSGPR())
2229        {
2230            if (!regRangeCanEqual(src0Op.range, src2Op.range) &&
2231                !regRangeCanEqual(src1Op.range, src2Op.range))
2232                numSgprToRead++;
2233        }
2234       
2235        if ((arch & ARCH_GCN_1_5)==0 && vccImplRead)
2236        {
2237            if (numSgprToRead >= 1)
2238                /* include VCCs (???) */
2239                ASM_FAIL_BY_ERROR(instrPlace, "No SGPR can be readed in vccImplRead")
2240        }
2241        else if ((arch & ARCH_GCN_1_5)==0 ||
2242            // except vccImplReads for NAVI
2243            vccImplRead)
2244        {
2245            if (numSgprToRead >= 2)
2246                /* include VCCs (???) */
2247                ASM_FAIL_BY_ERROR(instrPlace, "More than one SGPR to read in instruction")
2248        }
2249        else
2250        {   // NAVI
2251            if (numSgprToRead >= 3)
2252                /* include VCCs (???) */
2253                ASM_FAIL_BY_ERROR(instrPlace, "More than two SGPRs to read in instruction")
2254        }
2255    }
2256   
2257    if (src0OpExpr!=nullptr)
2258        src0OpExpr->setTarget(AsmExprTarget(GCNTGT_VOP3LITIMM, asmr.currentSection,
2259                      output.size()));
2260    if (src1OpExpr!=nullptr)
2261        src1OpExpr->setTarget(AsmExprTarget(GCNTGT_VOP3LITIMM, asmr.currentSection,
2262                      output.size()));
2263    if (src2OpExpr!=nullptr)
2264        src2OpExpr->setTarget(AsmExprTarget(GCNTGT_VOP3LITIMM, asmr.currentSection,
2265                      output.size()));
2266   
2267    // put data (instruction words)
2268    uint32_t words[3];
2269    cxuint wordsNum = 2;
2270    const uint32_t encoding = (arch & ARCH_GCN_1_5)!=0 ?
2271            (gcnInsn.encoding==GCNENC_VOP3P ? 0xcc000000U : 0xd4000000U) : 0xd0000000U;
2272    if (gcnInsn.encoding == GCNENC_VOP3B)
2273    {
2274        // VOP3B encoding
2275        if (!isGCN12)
2276            SLEV(words[0], encoding | (uint32_t(gcnInsn.code1)<<17) |
2277                (dstReg.bstart()&0xff) | (uint32_t(sdstReg.bstart())<<8));
2278        else
2279            SLEV(words[0], encoding | (uint32_t(gcnInsn.code1)<<16) |
2280                (dstReg.bstart()&0xff) | (uint32_t(sdstReg.bstart())<<8) |
2281                ((modifiers&VOP3_CLAMP) ? 0x8000 : 0));
2282    }
2283    else
2284    {
2285        // VOP3A
2286        if (!isGCN12)
2287            SLEV(words[0], encoding | (uint32_t(gcnInsn.code1)<<17) |
2288                (dstReg.bstart()&0xff) | ((modifiers&VOP3_CLAMP) ? 0x800: 0) |
2289                ((src0Op.vopMods & VOPOP_ABS) ? 0x100 : 0) |
2290                ((src1Op.vopMods & VOPOP_ABS) ? 0x200 : 0) |
2291                ((src2Op.vopMods & VOPOP_ABS) ? 0x400 : 0));
2292        else if (mode2 != GCN_VOP3_VINTRP || mode1 == GCN_NEW_OPCODE ||
2293            (gcnInsn.mode & GCN_VOP3_MASK3) == GCN_VINTRP_SRC2 ||
2294            (modifiers & VOP3_VOP3)!=0 || (src0Op.range.bstart()&0x100)!=0/* high */ ||
2295            (modifiers & (VOP3_CLAMP|3)) != 0 || opMods.opselMod != 0 ||
2296            src1Op.vopMods!=0 || src2Op.vopMods!=0)
2297            // new VOP3 for GCN 1.2
2298            SLEV(words[0], encoding | (uint32_t(gcnInsn.code1)<<16) |
2299                (dstReg.bstart()&0xff) | ((modifiers&VOP3_CLAMP) ? 0x8000: 0) |
2300                (vop3p ? (uint32_t(opMods.negMod>>4) << 8) /* VOP3P NEG_HI */ :
2301                    ((src0Op.vopMods & VOPOP_ABS) ? 0x100 : 0) |
2302                    ((src1Op.vopMods & VOPOP_ABS) ? 0x200 : 0) |
2303                    ((src2Op.vopMods & VOPOP_ABS) ? 0x400 : 0)) |
2304                (((opMods.opselMod & 64) !=0) ? 0x4000 : 0) |
2305                ((opMods.opselMod&15) << 11));
2306        else // VINTRP
2307        {
2308            const uint32_t encoding2 = (arch & ARCH_GCN_1_5)!=0 ?
2309                                    0xc9000000U : 0xd4000000U;
2310            SLEV(words[0], encoding2 | (src1Op.range.bstart()&0xff) |
2311                (uint32_t(src0Op.range.bstart()>>6)<<8) |
2312                (uint32_t(src0Op.range.bstart()&63)<<10) |
2313                (uint32_t(gcnInsn.code2)<<16) | (uint32_t(dstReg.bstart()&0xff)<<18));
2314            // VOP3 VINTRP have only one word instruction
2315            wordsNum--;
2316        }
2317    }
2318    if (wordsNum==2)
2319    {
2320        // second instruction's word
2321        SLEV(words[1], src0Op.range.bstart() | (uint32_t(src1Op.range.bstart())<<9) |
2322                (uint32_t(src2Op.range.bstart())<<18) |
2323                (vop3p ? ((uint32_t(opMods.opselMod>>4)&3)<<27) :
2324                 (uint32_t(modifiers & 3) << 27)) |
2325                /* in VOP3P is also NEG_LO */
2326                ((src0Op.vopMods & VOPOP_NEG) ? (1U<<29) : 0) |
2327                ((src1Op.vopMods & VOPOP_NEG) ? (1U<<30) : 0) |
2328                ((src2Op.vopMods & VOPOP_NEG) ? (1U<<31) : 0));
2329        if (src0Op.range.isVal(255)) // we check for immediate/literal value
2330            SLEV(words[wordsNum++], src0Op.value);
2331        else if (src1Op.range.isVal(255))
2332            // literal from SRC1
2333            SLEV(words[wordsNum++], src1Op.value);
2334        else if (src2Op.range.isVal(255))
2335            // literal from SRC2
2336            SLEV(words[wordsNum++], src2Op.value);
2337    }
2338   
2339    if (!checkGCNEncodingSize(asmr, instrPlace, gcnEncSize, wordsNum))
2340        return false;
2341    output.insert(output.end(), reinterpret_cast<cxbyte*>(words),
2342            reinterpret_cast<cxbyte*>(words + wordsNum));
2343    /// prevent freeing expression
2344    src0OpExpr.release();
2345    src1OpExpr.release();
2346    src2OpExpr.release();
2347   
2348    // update register pool (VGPR and SGPR counting)
2349    if (dstReg && !dstReg.isRegVar())
2350    {
2351        if (dstReg.start>=256)
2352            updateVGPRsNum(gcnRegs.vgprsNum, dstReg.end-257);
2353        else // sgprs
2354        {
2355            updateSGPRsNum(gcnRegs.sgprsNum, dstReg.end-1, arch);
2356            updateRegFlags(gcnRegs.regFlags, dstReg.start, arch);
2357        }
2358    }
2359    if (sdstReg && !sdstReg.isRegVar())
2360    {
2361        updateSGPRsNum(gcnRegs.sgprsNum, sdstReg.end-1, arch);
2362        updateRegFlags(gcnRegs.regFlags, sdstReg.start, arch);
2363    }
2364    if (mode2 != GCN_VOP3_VINTRP)
2365    {
2366        // count for SSRC0 and SSRC1 for VOP3A/B encoding (not VINTRP) ???
2367        if (src0Op.range && !src0Op.range.isRegVar() && src0Op.range.start < 256)
2368            updateRegFlags(gcnRegs.regFlags, src0Op.range.start, arch);
2369        if (src1Op.range && !src1Op.range.isRegVar() && src1Op.range.start < 256)
2370            updateRegFlags(gcnRegs.regFlags, src1Op.range.start, arch);
2371    }
2372    if (src2Op.range && !src2Op.range.isRegVar() && src2Op.range.start < 256)
2373        updateRegFlags(gcnRegs.regFlags, src2Op.range.start, arch);
2374    return true;
2375}
2376
2377bool GCNAsmUtils::parseVINTRPEncoding(Assembler& asmr, const GCNAsmInstruction& gcnInsn,
2378                  const char* instrPlace, const char* linePtr, GPUArchMask arch,
2379                  std::vector<cxbyte>& output, GCNAssembler::Regs& gcnRegs,
2380                  GCNEncSize gcnEncSize, GCNVOPEnc gcnVOPEnc)
2381{
2382    bool good = true;
2383    RegRange dstReg(0, 0);
2384    RegRange srcReg(0, 0);
2385    if (gcnEncSize==GCNEncSize::BIT64)
2386        ASM_FAIL_BY_ERROR(instrPlace, "Only 32-bit size for VINTRP encoding")
2387    if (gcnVOPEnc!=GCNVOPEnc::NORMAL)
2388        ASM_FAIL_BY_ERROR(instrPlace, "DPP and SDWA encoding is illegal for VOP3")
2389   
2390    GCNAssembler* gcnAsm = static_cast<GCNAssembler*>(asmr.isaAssembler);
2391   
2392    // parse DST (VGPR)
2393    gcnAsm->setCurrentRVU(0);
2394    good &= parseVRegRange(asmr, linePtr, dstReg, 1, GCNFIELD_VINTRP_VDST, true,
2395                        INSTROP_SYMREGRANGE|INSTROP_WRITE);
2396    if (!skipRequiredComma(asmr, linePtr))
2397        return false;
2398   
2399    if ((gcnInsn.mode & GCN_MASK1) == GCN_P0_P10_P20)
2400        good &= parseVINTRP0P10P20(asmr, linePtr, srcReg);
2401    else
2402    {
2403        // regular vector register
2404        gcnAsm->setCurrentRVU(1);
2405        good &= parseVRegRange(asmr, linePtr, srcReg, 1, GCNFIELD_VINTRP_VSRC0, true,
2406                        INSTROP_SYMREGRANGE|INSTROP_READ);
2407    }
2408   
2409    if (!skipRequiredComma(asmr, linePtr))
2410        return false;
2411   
2412    cxbyte attrVal;
2413    good &= parseVINTRPAttr(asmr, linePtr, attrVal);
2414   
2415    if (!good || !checkGarbagesAtEnd(asmr, linePtr))
2416        return false;
2417    /* put data (instruction word */
2418    uint32_t word;
2419    SLEV(word, 0xc8000000U | (srcReg.bstart()&0xff) | (uint32_t(attrVal&0xff)<<8) |
2420            (uint32_t(gcnInsn.code1)<<16) | (uint32_t(dstReg.bstart()&0xff)<<18));
2421    output.insert(output.end(), reinterpret_cast<cxbyte*>(&word),
2422            reinterpret_cast<cxbyte*>(&word)+4);
2423    // update register pool (VGPR counting)
2424    if (!dstReg.isRegVar())
2425        updateVGPRsNum(gcnRegs.vgprsNum, dstReg.end-257);
2426    return true;
2427}
2428
2429bool GCNAsmUtils::parseDSEncoding(Assembler& asmr, const GCNAsmInstruction& gcnInsn,
2430                  const char* instrPlace, const char* linePtr, GPUArchMask arch,
2431                  std::vector<cxbyte>& output, GCNAssembler::Regs& gcnRegs,
2432                  GCNEncSize gcnEncSize)
2433{
2434    const char* end = asmr.line+asmr.lineSize;
2435    bool good = true;
2436    if (gcnEncSize==GCNEncSize::BIT32)
2437        ASM_FAIL_BY_ERROR(instrPlace, "Only 64-bit size for DS encoding")
2438    RegRange dstReg(0, 0);
2439    RegRange addrReg(0, 0);
2440    RegRange data0Reg(0, 0), data1Reg(0, 0);
2441   
2442    bool beforeData = false;
2443    bool vdstUsed = false;
2444    cxuint delayRVU = UINT_MAX;
2445    cxuint destDelayRVU = UINT_MAX;
2446    bool secondDelay = false;
2447   
2448    GCNAssembler* gcnAsm = static_cast<GCNAssembler*>(asmr.isaAssembler);
2449   
2450    if (((gcnInsn.mode & GCN_ADDR_SRC) != 0 || (gcnInsn.mode & GCN_ONLYDST) != 0) &&
2451            (gcnInsn.mode & GCN_ONLY_SRC) == 0)
2452    {
2453        /* vdst is dst */
2454        cxuint regsNum = (gcnInsn.mode&GCN_REG_DST_64)?2:1;
2455        if ((gcnInsn.mode&GCN_DS_96) != 0)
2456            regsNum = 3;
2457        if ((gcnInsn.mode&GCN_DS_128) != 0 || (gcnInsn.mode&GCN_DST128) != 0)
2458            regsNum = 4;
2459        gcnAsm->setCurrentRVU(0);
2460        good &= parseVRegRange(asmr, linePtr, dstReg, regsNum, GCNFIELD_DS_VDST, true,
2461                    INSTROP_SYMREGRANGE|INSTROP_WRITE);
2462        vdstUsed = beforeData = true;
2463        destDelayRVU = 0;
2464    }
2465   
2466    if ((gcnInsn.mode & GCN_ONLYDST) == 0 && (gcnInsn.mode & GCN_ONLY_SRC) == 0)
2467    {
2468        // parse ADDR as first (VGPR)
2469        if (vdstUsed)
2470            if (!skipRequiredComma(asmr, linePtr))
2471                return false;
2472        gcnAsm->setCurrentRVU(1);
2473        good &= parseVRegRange(asmr, linePtr, addrReg, 1, GCNFIELD_DS_ADDR, true,
2474                    INSTROP_SYMREGRANGE|INSTROP_READ);
2475        beforeData = true;
2476    }
2477   
2478    const uint16_t srcMode = (gcnInsn.mode & GCN_SRCS_MASK);
2479   
2480    if ((gcnInsn.mode & GCN_ONLYDST) == 0 &&
2481        (gcnInsn.mode & (GCN_ADDR_DST|GCN_ADDR_SRC)) != 0 && srcMode != GCN_NOSRC)
2482    {
2483        /* two vdata */
2484        if (beforeData)
2485            if (!skipRequiredComma(asmr, linePtr))
2486                return false;
2487       
2488        cxuint regsNum = (gcnInsn.mode&GCN_REG_SRC0_64)?2:1;
2489        if ((gcnInsn.mode&GCN_DS_96) != 0)
2490            regsNum = 3;
2491        if ((gcnInsn.mode&GCN_DS_128) != 0)
2492            regsNum = 4;
2493        // parse VDATA0 (VGPR)
2494        gcnAsm->setCurrentRVU(2);
2495        good &= parseVRegRange(asmr, linePtr, data0Reg, regsNum, GCNFIELD_DS_DATA0, true,
2496                    INSTROP_SYMREGRANGE|INSTROP_READ);
2497        if (srcMode == GCN_2SRCS)
2498        {
2499            // instruction have second source
2500            if (!skipRequiredComma(asmr, linePtr))
2501                return false;
2502            // parse VDATA0 (VGPR)
2503            gcnAsm->setCurrentRVU(3);
2504            good &= parseVRegRange(asmr, linePtr, data1Reg,
2505                       (gcnInsn.mode&GCN_REG_SRC1_64)?2:1, GCNFIELD_DS_DATA1, true,
2506                               INSTROP_SYMREGRANGE|INSTROP_READ);
2507            secondDelay = true;
2508        }
2509        delayRVU = 2;
2510    }
2511   
2512    bool haveGds = false;
2513    std::unique_ptr<AsmExpression> offsetExpr, offset2Expr;
2514    char name[10];
2515    uint16_t offset = 0;
2516    cxbyte offset1 = 0, offset2 = 0;
2517    bool haveOffset = false, haveOffset2 = false;
2518    // parse DS modifiers
2519    while (linePtr!=end)
2520    {
2521        skipSpacesToEnd(linePtr, end);
2522        if (linePtr==end)
2523            break;
2524        const char* modPlace = linePtr;
2525        if (!getNameArgS(asmr, 10, name, linePtr, "DS modifier"))
2526        {
2527            good = false;
2528            continue;
2529        }
2530        toLowerString(name);
2531        if (::strcmp(name, "gds")==0)
2532            good &= parseModEnable(asmr, linePtr, haveGds, "gds modifier");
2533        else if ((gcnInsn.mode & GCN_2OFFSETS) == 0) /* single offset */
2534        {
2535            // single offset
2536            if (::strcmp(name, "offset") == 0)
2537            {
2538                if (parseModImm(asmr, linePtr, offset, &offsetExpr, "offset",
2539                            0, WS_UNSIGNED))
2540                {
2541                    // detect multiple occurrences
2542                    if (haveOffset)
2543                        asmr.printWarning(modPlace, "Offset is already defined");
2544                    haveOffset = true;
2545                }
2546                else
2547                    good = false;
2548            }
2549            else
2550                ASM_NOTGOOD_BY_ERROR(modPlace, "Expected 'offset'")
2551        }
2552        else
2553        {
2554            // two offsets (offset0, offset1)
2555            if (::memcmp(name, "offset", 6)==0 &&
2556                (name[6]=='0' || name[6]=='1') && name[7]==0)
2557            {
2558                skipSpacesToEnd(linePtr, end);
2559                if (linePtr!=end && *linePtr==':')
2560                {
2561                    skipCharAndSpacesToEnd(linePtr, end);
2562                    if (name[6]=='0')
2563                    {
2564                        /* offset0 */
2565                        if (parseImm(asmr, linePtr, offset1, &offsetExpr, 0, WS_UNSIGNED))
2566                        {
2567                            // detect multiple occurrences
2568                            if (haveOffset)
2569                                asmr.printWarning(modPlace, "Offset0 is already defined");
2570                            haveOffset = true;
2571                        }
2572                        else
2573                            good = false;
2574                    }
2575                    else
2576                    {
2577                        /* offset1 */
2578                        if (parseImm(asmr, linePtr, offset2, &offset2Expr, 0, WS_UNSIGNED))
2579                        {
2580                            // detect multiple occurrences
2581                            if (haveOffset2)
2582                                asmr.printWarning(modPlace, "Offset1 is already defined");
2583                            haveOffset2 = true;
2584                        }
2585                        else
2586                            good = false;
2587                    }
2588                }
2589                else
2590                    ASM_NOTGOOD_BY_ERROR(linePtr, "Expected ':' before offset")
2591            }
2592            else
2593                ASM_NOTGOOD_BY_ERROR(modPlace,
2594                                "Expected 'offset', 'offset0' or 'offset1'")
2595        }
2596    }
2597   
2598    if ((gcnInsn.mode & GCN_2OFFSETS) != 0)
2599        offset = offset1 | (offset2<<8);
2600   
2601    if (!good || !checkGarbagesAtEnd(asmr, linePtr))
2602        return false;
2603   
2604    // register Delayed results
2605    if (destDelayRVU != UINT_MAX)
2606        gcnAsm->delayedOps[0] = { output.size(), gcnAsm->instrRVUs[destDelayRVU].regVar,
2607                    gcnAsm->instrRVUs[destDelayRVU].rstart,
2608                    gcnAsm->instrRVUs[destDelayRVU].rend,
2609                    1, haveGds ? GCNDELOP_GDSOP : GCNDELOP_LDSOP, GCNDELOP_NONE,
2610                    gcnAsm->instrRVUs[destDelayRVU].rwFlags };
2611   
2612    if (delayRVU != UINT_MAX)
2613    {
2614        gcnAsm->delayedOps[1] = { output.size(), gcnAsm->instrRVUs[delayRVU].regVar,
2615                    gcnAsm->instrRVUs[delayRVU].rstart, gcnAsm->instrRVUs[delayRVU].rend,
2616                    1, haveGds ? GCNDELOP_GDSOP : GCNDELOP_LDSOP,
2617                    haveGds ? GCNDELOP_EXPORT : GCNDELOP_NONE,
2618                    gcnAsm->instrRVUs[delayRVU].rwFlags,
2619                    cxbyte(haveGds ? ASMRVU_READ : 0) };
2620        if (secondDelay)
2621            gcnAsm->delayedOps[2] = { output.size(),
2622                    gcnAsm->instrRVUs[delayRVU+1].regVar,
2623                    gcnAsm->instrRVUs[delayRVU+1].rstart,
2624                    gcnAsm->instrRVUs[delayRVU+1].rend,
2625                    1, haveGds ? GCNDELOP_GDSOP : GCNDELOP_LDSOP,
2626                    haveGds ? GCNDELOP_EXPORT : GCNDELOP_NONE,
2627                    gcnAsm->instrRVUs[delayRVU+1].rwFlags,
2628                    cxbyte(haveGds ? ASMRVU_READ : 0) };
2629    }
2630    if ((gcnInsn.mode & GCN_SRC_ADDR2) != 0)
2631        // register for DS_*_SRC2_* instructions
2632        gcnAsm->delayedOps[0] = { output.size(), nullptr, uint16_t(0), uint16_t(0),
2633                1, haveGds ? GCNDELOP_GDSOP : GCNDELOP_LDSOP,
2634                haveGds ? GCNDELOP_EXPORT : GCNDELOP_NONE, cxbyte(0) };
2635   
2636    if ((gcnInsn.mode&GCN_ONLYGDS) != 0 && !haveGds)
2637        ASM_FAIL_BY_ERROR(instrPlace, "Instruction requires GDS modifier")
2638   
2639    // set target expressions for offsets (if needed)
2640    if (offsetExpr!=nullptr)
2641        offsetExpr->setTarget(AsmExprTarget((gcnInsn.mode & GCN_2OFFSETS) ?
2642                    GCNTGT_DSOFFSET8_0 : GCNTGT_DSOFFSET16, asmr.currentSection,
2643                    output.size()));
2644    if (offset2Expr!=nullptr)
2645        offset2Expr->setTarget(AsmExprTarget(GCNTGT_DSOFFSET8_1, asmr.currentSection,
2646                    output.size()));
2647    // put data (two instruction words)
2648    uint32_t words[2];
2649    if ((arch & ARCH_GCN_1_2_4)==0)
2650        SLEV(words[0], 0xd8000000U | uint32_t(offset) | (haveGds ? 0x20000U : 0U) |
2651                (uint32_t(gcnInsn.code1)<<18));
2652    else
2653        SLEV(words[0], 0xd8000000U | uint32_t(offset) | (haveGds ? 0x10000U : 0U) |
2654                (uint32_t(gcnInsn.code1)<<17));
2655    SLEV(words[1], (addrReg.bstart()&0xff) | (uint32_t(data0Reg.bstart()&0xff)<<8) |
2656            (uint32_t(data1Reg.bstart()&0xff)<<16) | (uint32_t(dstReg.bstart()&0xff)<<24));
2657    output.insert(output.end(), reinterpret_cast<cxbyte*>(words),
2658            reinterpret_cast<cxbyte*>(words + 2));
2659   
2660    offsetExpr.release();
2661    offset2Expr.release();
2662    // update register pool (VGPR counting)
2663    if (dstReg && !dstReg.isRegVar())
2664        updateVGPRsNum(gcnRegs.vgprsNum, dstReg.end-257);
2665    return true;
2666}
2667
2668};
Note: See TracBrowser for help on using the repository browser.