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

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

CLRadeonExtender: GCNDisasm: Add support for SMRD immediate 32-bit literal for offset if arch==GCN1.1. Some changes in assembler.

File size: 109.1 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    std::unique_ptr<AsmExpression> soffsetExpr;
921    const GCNInsnMode mode1 = (gcnInsn.mode & GCN_MASK1);
922    if (mode1 == GCN_SMRD_ONLYDST)
923    {
924        // parse SDST (SGPR)
925        gcnAsm->setCurrentRVU(0);
926        good &= parseSRegRange(asmr, linePtr, dstReg, arch,
927                       (gcnInsn.mode&GCN_REG_DST_64)?2:1, GCNFIELD_SMRD_SDST, true,
928                       INSTROP_SYMREGRANGE|INSTROP_WRITE);
929    }
930    else if (mode1 != GCN_ARG_NONE)
931    {
932        const cxuint dregsNum = 1<<((gcnInsn.mode & GCN_DSIZE_MASK)>>GCN_SHIFT2);
933        // parse SDST (SGPR's (1-16 registers))
934        gcnAsm->setCurrentRVU(0);
935        good &= parseSRegRange(asmr, linePtr, dstReg, arch, dregsNum,
936                   GCNFIELD_SMRD_SDST, true, INSTROP_SYMREGRANGE|INSTROP_WRITE);
937        if (!skipRequiredComma(asmr, linePtr))
938            return false;
939       
940        // parse SBASE (2 or 4 registers)
941        gcnAsm->setCurrentRVU(1);
942        good &= parseSRegRange(asmr, linePtr, sbaseReg, arch,
943                   (gcnInsn.mode&GCN_SBASE4)?4:2, GCNFIELD_SMRD_SBASE, true,
944                   INSTROP_SYMREGRANGE|INSTROP_READ);
945        if (!skipRequiredComma(asmr, linePtr))
946            return false;
947       
948        skipSpacesToEnd(linePtr, end);
949        if (linePtr==end || *linePtr!='@')
950        {
951            // parse SOFFSET (SGPR)
952            gcnAsm->setCurrentRVU(2);
953            good &= parseSRegRange(asmr, linePtr, soffsetReg, arch, 1,
954                       GCNFIELD_SMRD_SOFFSET, false, INSTROP_SYMREGRANGE|INSTROP_READ);
955        }
956        else // '@' prefix (treat next as expression)
957            skipCharAndSpacesToEnd(linePtr, end);
958       
959        if (!soffsetReg)
960        {
961            // parse immediate
962            soffsetReg.start = 255; // indicate an immediate
963            good &= parseImm(asmr, linePtr, soffsetVal, &soffsetExpr, 8, WS_UNSIGNED);
964        }
965    }
966    /// if errors
967    if (!good || !checkGarbagesAtEnd(asmr, linePtr))
968        return false;
969   
970    if (mode1 != GCN_ARG_NONE)
971        gcnAsm->delayedOps[0] = AsmDelayedOp { output.size(),
972                    gcnAsm->instrRVUs[0].regVar, gcnAsm->instrRVUs[0].rstart,
973                    gcnAsm->instrRVUs[0].rend,
974                    cxbyte(gcnAsm->instrRVUs[0].rend - gcnAsm->instrRVUs[0].rstart),
975                    GCNDELOP_SMEMOP, GCNDELOP_NONE, gcnAsm->instrRVUs[0].rwFlags };
976   
977    const cxuint wordsNum = 1;
978    if (!checkGCNEncodingSize(asmr, instrPlace, gcnEncSize, wordsNum))
979        return false;
980   
981    if (soffsetExpr!=nullptr)
982        soffsetExpr->setTarget(AsmExprTarget(GCNTGT_SMRDOFFSET, asmr.currentSection,
983                       output.size()));
984   
985    // put data (instruction word)
986    uint32_t word;
987    SLEV(word, 0xc0000000U | (uint32_t(gcnInsn.code1)<<22) |
988            (uint32_t(dstReg.bstart())<<15) |
989            ((sbaseReg.bstart()&~1U)<<8) | ((soffsetReg.isVal(255)) ? 0x100 : 0) |
990            ((soffsetReg.isVal(255)) ? soffsetVal : soffsetReg.bstart()));
991    output.insert(output.end(), reinterpret_cast<cxbyte*>(&word), 
992            reinterpret_cast<cxbyte*>(&word)+4);
993    /// prevent freeing expression
994    soffsetExpr.release();
995   
996    // update SGPR counting and VCC usage (regflags)
997    if (dstReg && !dstReg.isRegVar())
998    {
999        updateSGPRsNum(gcnRegs.sgprsNum, dstReg.end-1, arch);
1000        updateRegFlags(gcnRegs.regFlags, dstReg.start, arch);
1001    }
1002    if (!sbaseReg.isRegVar())
1003        updateRegFlags(gcnRegs.regFlags, sbaseReg.start, arch);
1004    if (!soffsetReg.isRegVar())
1005        updateRegFlags(gcnRegs.regFlags, soffsetReg.start, arch);
1006    return true;
1007}
1008
1009bool GCNAsmUtils::parseSMEMEncoding(Assembler& asmr, const GCNAsmInstruction& gcnInsn,
1010                  const char* instrPlace, const char* linePtr, GPUArchMask arch,
1011                  std::vector<cxbyte>& output, GCNAssembler::Regs& gcnRegs,
1012                  GCNEncSize gcnEncSize)
1013{
1014    const char* end = asmr.line+asmr.lineSize;
1015    bool good = true;
1016    if (gcnEncSize==GCNEncSize::BIT32)
1017        ASM_FAIL_BY_ERROR(instrPlace, "Only 64-bit size for SMEM encoding")
1018   
1019    GCNAssembler* gcnAsm = static_cast<GCNAssembler*>(asmr.isaAssembler);
1020    RegRange dataReg(0, 0);
1021    RegRange sbaseReg(0, 0);
1022    RegRange soffsetReg(0, 0);
1023    uint32_t soffsetVal = 0;
1024    std::unique_ptr<AsmExpression> soffsetExpr;
1025    std::unique_ptr<AsmExpression> simm7Expr;
1026    const GCNInsnMode mode1 = (gcnInsn.mode & GCN_MASK1);
1027    const bool isGCN14 = (arch & ARCH_GCN_1_4) != 0;
1028    const bool isGCN15 = (arch & ARCH_GCN_1_5) != 0;
1029   
1030    const char* soffsetPlace = nullptr;
1031    AsmSourcePos soffsetPos;
1032   
1033    if (mode1 == GCN_SMRD_ONLYDST)
1034    {
1035        // parse SDST (SGPR)
1036        gcnAsm->setCurrentRVU(0);
1037        good &= parseSRegRange(asmr, linePtr, dataReg, arch,
1038                       (gcnInsn.mode&GCN_REG_DST_64)?2:1, GCNFIELD_SMRD_SDST, true,
1039                       INSTROP_SYMREGRANGE|INSTROP_WRITE);
1040    }
1041    else if (mode1 != GCN_ARG_NONE)
1042    {
1043        const cxuint dregsNum = 1<<((gcnInsn.mode & GCN_DSIZE_MASK)>>GCN_SHIFT2);
1044        // parse SDST (SGPR's (1-16 registers))
1045        gcnAsm->setCurrentRVU(0);
1046        if ((mode1 & GCN_SMEM_NOSDATA) == 0)
1047        {
1048            if ((mode1 & GCN_SMEM_SDATA_IMM)==0)
1049                good &= parseSRegRange(asmr, linePtr, dataReg, arch, dregsNum,
1050                        GCNFIELD_SMRD_SDST, true, INSTROP_SYMREGRANGE|
1051                        ((gcnInsn.mode & GCN_MLOAD) != 0 ? INSTROP_WRITE : INSTROP_READ));
1052            else
1053                good &= parseImm(asmr, linePtr, dataReg.start, &simm7Expr, 7);
1054            if (!skipRequiredComma(asmr, linePtr))
1055                return false;
1056        }
1057       
1058        // parse SBASE (2 or 4 SGPR's)
1059        gcnAsm->setCurrentRVU(1);
1060        good &= parseSRegRange(asmr, linePtr, sbaseReg, arch,
1061                   (gcnInsn.mode&GCN_SBASE4)?4:2, GCNFIELD_SMRD_SBASE, true,
1062                   INSTROP_SYMREGRANGE|INSTROP_READ);
1063        if (!skipRequiredComma(asmr, linePtr))
1064            return false;
1065       
1066        skipSpacesToEnd(linePtr, end);
1067        if (linePtr==end || *linePtr!='@')
1068        {
1069            // parse SOFFSET (SGPR)
1070            gcnAsm->setCurrentRVU(2);
1071            const char* soffsetPlace = linePtr;
1072            good &= parseSRegRange(asmr, linePtr, soffsetReg, arch, 1,
1073                       GCNFIELD_SMRD_SOFFSET, false, INSTROP_SYMREGRANGE|INSTROP_READ);
1074            if (good && (!isGCN14 && !isGCN15) && (gcnInsn.mode & GCN_MLOAD) == 0 &&
1075                    soffsetReg && !soffsetReg.isVal(124))
1076                // if no M0 register
1077                ASM_NOTGOOD_BY_ERROR(soffsetPlace,
1078                        "Store/Atomic SMEM instructions accepts only M0 register")
1079        }
1080        else // '@' prefix (treat next as expression)
1081            skipCharAndSpacesToEnd(linePtr, end);
1082       
1083        if (!soffsetReg)
1084        {
1085            // parse immediate
1086            soffsetReg.start = 255; // indicate an immediate
1087            skipSpacesToEnd(linePtr, end);
1088            soffsetPlace = linePtr;
1089            soffsetPos = asmr.getSourcePos(soffsetPlace);
1090            good &= parseImm(asmr, linePtr, soffsetVal, &soffsetExpr,
1091                        isGCN14 ? 21 : 20, isGCN14 ? WS_BOTH : WS_UNSIGNED);
1092        }
1093    }
1094    bool haveGlc = false;
1095    bool haveNv = false;
1096    bool haveOffset = false;
1097    bool haveDlc = false;
1098    // parse modifiers
1099    while (linePtr != end)
1100    {
1101        skipSpacesToEnd(linePtr, end);
1102        if (linePtr == end)
1103            break;
1104        const char* modPlace = linePtr;
1105        char name[10];
1106        if (getNameArgS(asmr, 10, name, linePtr, "modifier"))
1107        {
1108            toLowerString(name);
1109            if (::strcmp(name, "glc")==0)
1110                good &= parseModEnable(asmr, linePtr, haveGlc, "glc modifier");
1111            else if (::strcmp(name, "dlc")==0)
1112                good &= parseModEnable(asmr, linePtr, haveDlc, "dlc modifier");
1113            else if ((isGCN14 || isGCN15) && ::strcmp(name, "nv")==0)
1114                good &= parseModEnable(asmr, linePtr, haveNv, "nv modifier");
1115            else if (isGCN14 && ::strcmp(name, "offset")==0)
1116            {
1117                // parse offset and it parameter: offset:XXX
1118                if (parseModImm(asmr, linePtr, soffsetVal, &soffsetExpr, "offset",
1119                        21, WS_BOTH))
1120                {
1121                    if (haveOffset)
1122                        asmr.printWarning(modPlace, "Offset is already defined");
1123                    haveOffset = true;
1124                    if (soffsetReg.isVal(255))
1125                        // illegal second offset
1126                        ASM_NOTGOOD_BY_ERROR(modPlace, "Illegal second offset");
1127                }
1128                else
1129                    good = false;
1130            }
1131            else
1132                ASM_NOTGOOD_BY_ERROR(modPlace, "Unknown SMEM modifier")
1133        }
1134        else
1135            good = false;
1136    }
1137    /// if errors
1138    if (!good || !checkGarbagesAtEnd(asmr, linePtr))
1139        return false;
1140   
1141    // set expression target for offsets and immediates
1142    if (soffsetExpr!=nullptr)
1143        soffsetExpr->setTarget(AsmExprTarget(isGCN14 ?
1144                    GCNTGT_SMEMOFFSETVEGA : GCNTGT_SMEMOFFSET,
1145                    asmr.currentSection, output.size()));
1146    if (simm7Expr!=nullptr)
1147        simm7Expr->setTarget(AsmExprTarget(GCNTGT_SMEMIMM, asmr.currentSection,
1148                       output.size()));
1149   
1150    bool dataToRead = false;
1151    bool dataToWrite = false;
1152    if (dataReg)
1153    {
1154        dataToWrite = ((gcnInsn.mode&GCN_MLOAD) != 0 ||
1155                ((gcnInsn.mode&GCN_MATOMIC)!=0 && haveGlc));
1156        dataToRead = (gcnInsn.mode&GCN_MLOAD)==0 || (gcnInsn.mode&GCN_MATOMIC)!=0;
1157    }
1158   
1159    gcnAsm->instrRVUs[0].rwFlags = (dataToRead ? ASMRVU_READ : 0) |
1160            (dataToWrite ? ASMRVU_WRITE : 0);
1161    // check fcmpswap
1162    if ((gcnInsn.mode & GCN_MHALFWRITE) != 0 && dataToWrite &&
1163            gcnAsm->instrRVUs[0].regField != ASMFIELD_NONE)
1164    {
1165        // fix access
1166        AsmRegVarUsage& rvu = gcnAsm->instrRVUs[0];
1167        uint16_t size = rvu.rend-rvu.rstart;
1168        rvu.rend = rvu.rstart + (size>>1);
1169        AsmRegVarUsage& nextRvu = gcnAsm->instrRVUs[3];
1170        nextRvu = rvu;
1171        nextRvu.regField = GCNFIELD_SMRD_SDSTH;
1172        nextRvu.rstart += (size>>1);
1173        nextRvu.rend = rvu.rstart + size;
1174        nextRvu.rwFlags = ASMRVU_READ;
1175        nextRvu.align = 0;
1176    }
1177   
1178    if (mode1 != GCN_ARG_NONE)
1179    {
1180        gcnAsm->delayedOps[0] = AsmDelayedOp { output.size(),
1181                    gcnAsm->instrRVUs[0].regVar, gcnAsm->instrRVUs[0].rstart,
1182                    gcnAsm->instrRVUs[0].rend,
1183                    cxbyte(gcnAsm->instrRVUs[0].rend - gcnAsm->instrRVUs[0].rstart),
1184                    GCNDELOP_SMEMOP, GCNDELOP_NONE, gcnAsm->instrRVUs[0].rwFlags };
1185        if (gcnAsm->instrRVUs[3].regField != ASMFIELD_NONE)
1186            gcnAsm->delayedOps[1] = AsmDelayedOp { output.size(),
1187                    gcnAsm->instrRVUs[3].regVar, gcnAsm->instrRVUs[3].rstart,
1188                    gcnAsm->instrRVUs[3].rend,
1189                    cxbyte(gcnAsm->instrRVUs[0].rend - gcnAsm->instrRVUs[0].rstart),
1190                    GCNDELOP_SMEMOP, GCNDELOP_NONE, gcnAsm->instrRVUs[3].rwFlags };
1191    }
1192   
1193    // put data (2 instruction words)
1194    uint32_t words[2];
1195    const uint32_t encoding = isGCN15 ? 0xf4000000U : 0xc0000000U;
1196    const uint32_t soffsetRegNull = isGCN15 ? 0x7d : 0;
1197    SLEV(words[0], encoding | (uint32_t(gcnInsn.code1)<<18) | (dataReg.bstart()<<6) |
1198            (sbaseReg.bstart()>>1) |
1199            // enable IMM if soffset is immediate or haveOffset with SGPR
1200            ((!isGCN15 && (soffsetReg.isVal(255) || haveOffset)) ? 0x20000 : 0) |
1201            (haveGlc ? 0x10000 : 0) | (haveNv ? 0x8000 : 0) |
1202            (((!isGCN15 && haveOffset) || (isGCN15 && haveDlc)) ? 0x4000 : 0));
1203    SLEV(words[1],
1204            // store IMM OFFSET if offset: or IMM offset instead SGPR
1205            ((isGCN15 || soffsetReg.isVal(255) || haveOffset) ?
1206                                soffsetVal : soffsetReg.bstart()) |
1207            // store SGPR in SOFFSET if have offset and have SGPR offset
1208                (((isGCN15 && !soffsetReg.isVal(255)) ||
1209                        (!isGCN15 && haveOffset && !soffsetReg.isVal(255))) ?
1210                        (soffsetReg.bstart()<<25) : (soffsetRegNull<<25)));
1211   
1212    output.insert(output.end(), reinterpret_cast<cxbyte*>(words), 
1213            reinterpret_cast<cxbyte*>(words+2));
1214    /// prevent freeing expression
1215    soffsetExpr.release();
1216    simm7Expr.release();
1217   
1218    // update SGPR counting and VCC usage (regflags)
1219    if (!dataReg.isRegVar() && dataToWrite)
1220    {
1221        updateSGPRsNum(gcnRegs.sgprsNum, dataReg.end-1, arch);
1222        updateRegFlags(gcnRegs.regFlags, dataReg.start, arch);
1223    }
1224    if (!sbaseReg.isRegVar())
1225        updateRegFlags(gcnRegs.regFlags, sbaseReg.start, arch);
1226    if (!soffsetReg.isRegVar())
1227        updateRegFlags(gcnRegs.regFlags, soffsetReg.start, arch);
1228    return true;
1229}
1230
1231// choose between 64-bit immediate (FP64) and 32-bit immediate
1232static Flags correctOpType(uint32_t regsNum, Flags typeMask)
1233{
1234    return (regsNum==2 && (typeMask==INSTROP_FLOAT || typeMask==INSTROP_INT)) ?
1235        INSTROP_V64BIT : typeMask;
1236}
1237
1238static void encodeVOPWords(uint32_t vop0Word, cxbyte modifiers,
1239        const VOPExtraModifiers& extraMods, const GCNOperand& src0Op,
1240        const GCNOperand& src1Op, uint32_t immValue, GCNInsnMode mode1,
1241        // dstMod - (16bits lower value, 16bit - use dstMod instead std encoding
1242        uint32_t inDstMod, cxuint& wordsNum, uint32_t* words)
1243{
1244    // VOP2 encoding
1245    cxuint src0out = src0Op.range.bstart();
1246    if (extraMods.needSDWA)
1247        src0out = 0xf9;
1248    else if (extraMods.needDPP)
1249        src0out = 0xfa;
1250    else if (extraMods.needDPP8)
1251        src0out = (extraMods.fi ? 0xea : 0xe9);
1252    SLEV(words[0], vop0Word | uint32_t(src0out));
1253    if (extraMods.needSDWA)
1254    {
1255        const uint32_t dstMod = (inDstMod & 0x10000) ? (inDstMod&0xff00) :
1256                    ((uint32_t(extraMods.dstSel)<<8) |
1257                    (uint32_t(extraMods.dstUnused)<<11) |
1258                    ((modifiers & VOP3_CLAMP) ? 0x2000 : 0) |
1259                    (uint32_t(modifiers & 3) << 14));
1260        // if SDWA encoding
1261        SLEV(words[wordsNum++], dstMod | (src0Op.range.bstart()&0xff) |
1262                (uint32_t(extraMods.src0Sel)<<16) |
1263                ((src0Op.vopMods&VOPOP_SEXT) ? (1U<<19) : 0) |
1264                ((src0Op.vopMods&VOPOP_NEG) ? (1U<<20) : 0) |
1265                ((src0Op.vopMods&VOPOP_ABS) ? (1U<<21) : 0) |
1266                (uint32_t(extraMods.src1Sel)<<24) |
1267                ((src1Op.vopMods&VOPOP_SEXT) ? (1U<<27) : 0) |
1268                ((src1Op.vopMods&VOPOP_NEG) ? (1U<<28) : 0) |
1269                ((src1Op.vopMods&VOPOP_ABS) ? (1U<<29) : 0) |
1270                (src0Op.range.isNonVGPR() ? (1U<<23) : 0) |
1271                (src1Op.range.isNonVGPR() ? (1U<<31) : 0));
1272    }
1273    else if (extraMods.needDPP)
1274        // DPP encoding
1275        SLEV(words[wordsNum++], (src0Op.range.bstart()&0xff) | (extraMods.dppCtrl<<8) |
1276                ((modifiers&VOP3_BOUNDCTRL) ? (1U<<19) : 0) |
1277                ((src0Op.vopMods&VOPOP_NEG) ? (1U<<20) : 0) |
1278                ((src0Op.vopMods&VOPOP_ABS) ? (1U<<21) : 0) |
1279                ((src1Op.vopMods&VOPOP_NEG) ? (1U<<22) : 0) |
1280                ((src1Op.vopMods&VOPOP_ABS) ? (1U<<23) : 0) |
1281                (extraMods.fi ? 0x40000U : 0) |
1282                (uint32_t(extraMods.bankMask)<<24) |
1283                (uint32_t(extraMods.rowMask)<<28));
1284    else if (extraMods.needDPP8)
1285        SLEV(words[wordsNum++], (src0Op.range.bstart()&0xff) | (extraMods.dpp8Value<<8));
1286    else if (src0Op.range.isVal(255)) // otherwise we check for immediate/literal value
1287        SLEV(words[wordsNum++], src0Op.value);
1288    else if (src1Op.range.isVal(255))
1289        // literal from SRC1
1290        SLEV(words[wordsNum++], src1Op.value);
1291    else if (mode1 == GCN_ARG1_IMM || mode1 == GCN_ARG2_IMM)
1292        SLEV(words[wordsNum++], immValue);
1293}
1294
1295static void encodeVOP3Words(GPUArchMask arch, const GCNAsmInstruction& gcnInsn,
1296        cxbyte modifiers, VOPOpModifiers opMods, bool haveDstCC,
1297        const RegRange& dstReg, const RegRange& dstCCReg, const RegRange& srcCCReg,
1298        const GCNOperand& src0Op, const GCNOperand& src1Op,
1299        cxuint& wordsNum, uint32_t* words)
1300{
1301    const bool isGCN12 = (arch & ARCH_GCN_1_2_4_5)!=0;
1302    // VOP3 encoding
1303    uint32_t code = (isGCN12) ?
1304            (uint32_t(gcnInsn.code2)<<16) | ((modifiers&VOP3_CLAMP) ? 0x8000 : 0) :
1305            (uint32_t(gcnInsn.code2)<<17) | ((modifiers&VOP3_CLAMP) ? 0x800 : 0);
1306    cxuint encoding = (arch & ARCH_GCN_1_5)!=0 ? 0xd4000000U : 0xd0000000U;
1307    if (haveDstCC) // if VOP3B
1308        SLEV(words[0], encoding | code |
1309            (dstReg.bstart()&0xff) | (uint32_t(dstCCReg.bstart())<<8));
1310    else // if VOP3A
1311        SLEV(words[0], encoding | code | (dstReg.bstart()&0xff) |
1312            ((src0Op.vopMods & VOPOP_ABS) ? 0x100 : 0) |
1313            ((src1Op.vopMods & VOPOP_ABS) ? 0x200 : 0) |
1314            ((opMods.opselMod&15) << 11));
1315    // second dword
1316    SLEV(words[1], src0Op.range.bstart() | (uint32_t(src1Op.range.bstart())<<9) |
1317        (uint32_t(srcCCReg.bstart())<<18) | (uint32_t(modifiers & 3) << 27) |
1318        ((src0Op.vopMods & VOPOP_NEG) ? (1U<<29) : 0) |
1319        ((src1Op.vopMods & VOPOP_NEG) ? (1U<<30) : 0));
1320    wordsNum++;
1321}
1322
1323bool GCNAsmUtils::parseVOP2Encoding(Assembler& asmr, const GCNAsmInstruction& gcnInsn,
1324                  const char* instrPlace, const char* linePtr, GPUArchMask arch,
1325                  std::vector<cxbyte>& output, GCNAssembler::Regs& gcnRegs,
1326                  GCNEncSize gcnEncSize, GCNVOPEnc gcnVOPEnc)
1327{
1328    const char* end = asmr.line+asmr.lineSize;
1329    bool good = true;
1330    const GCNInsnMode mode1 = (gcnInsn.mode & GCN_MASK1);
1331    const GCNInsnMode mode2 = (gcnInsn.mode & GCN_LITMASK);
1332    const bool isGCN12 = (arch & ARCH_GCN_1_2_4_5)!=0;
1333    const bool isGCN14 = (arch & ARCH_GCN_1_4_5)!=0;
1334    const bool isGCN15 = (arch & ARCH_GCN_1_5)!=0;
1335    GCNAssembler* gcnAsm = static_cast<GCNAssembler*>(asmr.isaAssembler);
1336    const bool wave32 = (asmr.codeFlags & ASM_CODE_WAVE32)!=0;
1337   
1338    RegRange dstReg(0, 0);
1339    RegRange dstCCReg(0, 0);
1340    RegRange srcCCReg(0, 0);
1341    gcnAsm->setCurrentRVU(0);
1342    if (mode1 == GCN_DS1_SGPR)
1343        // if SGPRS as destination
1344        good &= parseSRegRange(asmr, linePtr, dstReg, arch,
1345                       (gcnInsn.mode&GCN_REG_DST_64)?2:1, GCNFIELD_VOP_SDST, true,
1346                       INSTROP_SYMREGRANGE|INSTROP_SGPR_UNALIGNED|INSTROP_WRITE);
1347    else
1348    {
1349         // if VGPRS as destination
1350        bool v_mac = ::strncmp(gcnInsn.mnemonic, "v_mac_", 6)==0 ||
1351                // for V_FMAC_F32 (VEGA20)
1352                ::strncmp(gcnInsn.mnemonic, "v_fmac_", 7)==0;
1353        good &= parseVRegRange(asmr, linePtr, dstReg, (gcnInsn.mode&GCN_REG_DST_64)?2:1,
1354                        GCNFIELD_VOP_VDST, true, INSTROP_SYMREGRANGE|INSTROP_WRITE|
1355                              (v_mac?INSTROP_READ:0));
1356    }
1357   
1358    const bool haveDstCC = mode1 == GCN_DS2_VCC || mode1 == GCN_DST_VCC;
1359    const bool haveSrcCC = mode1 == GCN_DS2_VCC || mode1 == GCN_SRC2_VCC;
1360   
1361    const cxuint waveRegSize = (!isGCN15 || !wave32 ||
1362                        (gcnInsn.mode&GCN_VOP_NOWVSZ)!=0) ? 2 : 1;
1363    if (haveDstCC) /* VOP3b */
1364    {
1365        if (!skipRequiredComma(asmr, linePtr))
1366            return false;
1367        // parse SDST (in place VCC) (2 SGPR's)
1368        gcnAsm->setCurrentRVU(1);
1369        good &= parseSRegRange(asmr, linePtr, dstCCReg, arch, waveRegSize,
1370                    GCNFIELD_VOP3_SDST1, true, INSTROP_SYMREGRANGE|INSTROP_SGPR_UNALIGNED|
1371                    INSTROP_WRITE);
1372    }
1373   
1374    GCNOperand src0Op{}, src1Op{};
1375    std::unique_ptr<AsmExpression> src0OpExpr, src1OpExpr;
1376    const Flags literalConstsFlags = (mode2==GCN_FLOATLIT) ? INSTROP_FLOAT :
1377            (mode2==GCN_F16LIT) ? INSTROP_F16 : INSTROP_INT;
1378   
1379    const Flags vopOpModFlags = ((haveDstCC && !isGCN12) ?
1380                    INSTROP_VOP3NEG : INSTROP_VOP3MODS);
1381    if (!skipRequiredComma(asmr, linePtr))
1382        return false;
1383    cxuint regsNum = (gcnInsn.mode&GCN_REG_SRC0_64)?2:1;
1384    // parse SRC0 (can be VGPR, SGPR, scalar source, LDS, literal or constant)
1385    gcnAsm->setCurrentRVU(2);
1386    good &= parseOperand(asmr, linePtr, src0Op, &src0OpExpr, arch, regsNum,
1387            correctOpType(regsNum, literalConstsFlags) | vopOpModFlags |
1388            INSTROP_SGPR_UNALIGNED|INSTROP_VREGS|INSTROP_SSOURCE|INSTROP_SREGS|INSTROP_LDS|
1389            INSTROP_READ, GCNFIELD_VOP_SRC0);
1390   
1391    uint32_t immValue = 0;
1392    std::unique_ptr<AsmExpression> immExpr;
1393    if (mode1 == GCN_ARG1_IMM)
1394    {
1395        // for V_MADMK_FXxx instruction
1396        if (!skipRequiredComma(asmr, linePtr))
1397            return false;
1398        good &= parseLiteralImm(asmr, linePtr, immValue, &immExpr, literalConstsFlags);
1399    }
1400   
1401    if (!skipRequiredComma(asmr, linePtr))
1402        return false;
1403   
1404    bool sgprRegInSrc1 = mode1 == GCN_DS1_SGPR || mode1 == GCN_SRC1_SGPR;
1405    skipSpacesToEnd(linePtr, end);
1406    regsNum = (gcnInsn.mode&GCN_REG_SRC1_64)?2:1;
1407    gcnAsm->setCurrentRVU(3);
1408    // parse SRC1 (can be VGPR, SGPR, scalar source, LDS, literal or constant)
1409    //  except when SGPR for SRC1 when instructions accepts SGPR in this place
1410    good &= parseOperand(asmr, linePtr, src1Op, &src1OpExpr, arch, regsNum,
1411            correctOpType(regsNum, literalConstsFlags) | vopOpModFlags |
1412            (!sgprRegInSrc1 ? INSTROP_VREGS : 0)|INSTROP_SSOURCE|INSTROP_SREGS|
1413            INSTROP_SGPR_UNALIGNED |
1414            (src0Op.range.start==255 ? INSTROP_ONLYINLINECONSTS : 0)|
1415            INSTROP_READ, (!sgprRegInSrc1) ? GCNFIELD_VOP_VSRC1 : GCNFIELD_VOP_SSRC1);
1416   
1417    if (mode1 == GCN_ARG2_IMM)
1418    {
1419        // for V_MADAK_Fxx instruction
1420        if (!skipRequiredComma(asmr, linePtr))
1421            return false;
1422        good &= parseLiteralImm(asmr, linePtr, immValue, &immExpr, literalConstsFlags);
1423    }
1424    else if (haveSrcCC)
1425    {
1426        if (!skipRequiredComma(asmr, linePtr))
1427            return false;
1428        gcnAsm->setCurrentRVU(4);
1429        // parse SSRC (VCC) (2 SGPR's)
1430        good &= parseSRegRange(asmr, linePtr, srcCCReg, arch, waveRegSize,
1431                    GCNFIELD_VOP3_SSRC, true,INSTROP_SYMREGRANGE|INSTROP_UNALIGNED|
1432                    INSTROP_READ);
1433    }
1434   
1435    // modifiers
1436    cxbyte modifiers = 0;
1437    VOPExtraModifiers extraMods{};
1438    VOPOpModifiers opMods{};
1439    good &= parseVOPModifiers(asmr, linePtr, arch, modifiers, opMods, 3,
1440                    (isGCN12) ? &extraMods : nullptr,
1441                    ((!haveDstCC || isGCN12) ? PARSEVOP_WITHCLAMP : 0)|PARSEVOP_WITHSEXT|
1442                    ((isGCN14 && !haveDstCC) ? PARSEVOP_WITHOPSEL : 0));
1443    if (!good || !checkGarbagesAtEnd(asmr, linePtr))
1444        return false;
1445   
1446    // apply VOP modifiers (abs,neg,sext) to operands from modifiers
1447    if (src0Op)
1448        src0Op.vopMods |= ((opMods.absMod&1) ? VOPOP_ABS : 0) |
1449                ((opMods.negMod&1) ? VOPOP_NEG : 0) |
1450                ((opMods.sextMod&1) ? VOPOP_SEXT : 0);
1451    if (src1Op)
1452        src1Op.vopMods |= ((opMods.absMod&2) ? VOPOP_ABS : 0) |
1453                ((opMods.negMod&2) ? VOPOP_NEG : 0) |
1454                ((opMods.sextMod&2) ? VOPOP_SEXT : 0);
1455   
1456    extraMods.needSDWA |= ((src0Op.vopMods | src1Op.vopMods) & VOPOP_SEXT) != 0;
1457    // determine whether VOP3 encoding is needed
1458    bool vop3 = /* src1=sgprs and not (DS1_SGPR|src1_SGPR) */
1459        //((src1Op.range.start<256) ^ sgprRegInSrc1) ||
1460        ((!isGCN14 || !extraMods.needSDWA) &&
1461                (src1Op.range.isNonVGPR() ^ sgprRegInSrc1)) ||
1462        (!isGCN12 && (src0Op.vopMods!=0 || src1Op.vopMods!=0)) ||
1463        (modifiers&~(VOP3_BOUNDCTRL|(extraMods.needSDWA?VOP3_CLAMP:0)|
1464            /* exclude OMOD if RXVEGA and SDWA used */
1465            ((isGCN14 && extraMods.needSDWA) ? 3 : 0)))!=0 ||
1466        /* srcCC!=VCC or dstCC!=VCC */
1467        //(haveDstCC && dstCCReg.start!=106) || (haveSrcCC && srcCCReg.start!=106) ||
1468        (haveDstCC && !dstCCReg.isVal(106)) || (haveSrcCC && !srcCCReg.isVal(106)) ||
1469        ((opMods.opselMod & 15) != 0) || (gcnEncSize==GCNEncSize::BIT64);
1470   
1471    if ((src0Op.range.isVal(255) || src1Op.range.isVal(255)) &&
1472        (src0Op.range.isSGPR() || src0Op.range.isVal(124) ||
1473         src1Op.range.isSGPR() || src1Op.range.isVal(124)))
1474        ASM_FAIL_BY_ERROR(instrPlace, "Literal with SGPR or M0 is illegal")
1475   
1476    AsmRegVarUsage* rvus = gcnAsm->instrRVUs;
1477    if (vop3) // modify fields in reg usage
1478    {
1479        if (rvus[0].regField != ASMFIELD_NONE)
1480            rvus[0].regField = (rvus[0].regField==GCNFIELD_VOP_VDST) ? GCNFIELD_VOP3_VDST :
1481                            GCNFIELD_VOP3_SDST0;
1482        if (rvus[2].regField != ASMFIELD_NONE)
1483            rvus[2].regField = GCNFIELD_VOP3_SRC0;
1484        if (rvus[3].regField != ASMFIELD_NONE)
1485            rvus[3].regField = GCNFIELD_VOP3_SRC1;
1486    }
1487    else
1488    {
1489        // vop2
1490        if (rvus[1].regField != ASMFIELD_NONE)
1491            rvus[1].regField = GCNFIELD_VOP_VCC_SDST1;
1492        if (rvus[4].regField != ASMFIELD_NONE)
1493            rvus[4].regField = GCNFIELD_VOP_VCC_SSRC;
1494    }
1495   
1496    // count number SGPR operands readed by instruction
1497    cxuint sgprsReaded = 0;
1498    if (src0Op.range.isSGPR())
1499        sgprsReaded++;
1500    if (src1Op.range.isSGPR() && !regRangeCanEqual(src0Op.range, src1Op.range))
1501        sgprsReaded++;
1502    if (haveSrcCC)
1503        // check for third operand (SSRC)
1504        if (!regRangeCanEqual(src0Op.range, srcCCReg) &&
1505            !regRangeCanEqual(src1Op.range, srcCCReg))
1506            sgprsReaded++;
1507   
1508    if ((arch & ARCH_GCN_1_5)==0)
1509    {
1510        if (sgprsReaded >= 2)
1511            /* include VCCs (???) */
1512            ASM_FAIL_BY_ERROR(instrPlace, "More than one SGPR to read in instruction")
1513    }
1514    else
1515    {   // NAVI
1516        if (sgprsReaded >= 3)
1517            /* include VCCs (???) */
1518            ASM_FAIL_BY_ERROR(instrPlace, "More than two SGPRs to read in instruction")
1519    }
1520   
1521    const bool needImm = (src0Op.range.start==255 || src1Op.range.start==255 ||
1522             mode1 == GCN_ARG1_IMM || mode1 == GCN_ARG2_IMM);
1523   
1524    bool sextFlags = ((src0Op.vopMods|src1Op.vopMods) & VOPOP_SEXT);
1525    bool absNegFlags = ((src0Op.vopMods|src1Op.vopMods) & (VOPOP_ABS|VOPOP_NEG));
1526    if (isGCN12 && (extraMods.needSDWA || extraMods.needDPP || extraMods.needDPP8 ||
1527                sextFlags || gcnVOPEnc!=GCNVOPEnc::NORMAL))
1528    {
1529        /* if VOP_SDWA or VOP_DPP is required */
1530        if (!checkGCNVOPExtraModifers(asmr, arch, needImm, sextFlags, vop3,
1531                    gcnVOPEnc, src0Op, extraMods, absNegFlags, instrPlace))
1532            return false;
1533        if (gcnAsm->instrRVUs[2].regField != ASMFIELD_NONE)
1534            gcnAsm->instrRVUs[2].regField = GCNFIELD_DPPSDWA_SRC0;
1535       
1536        if (extraMods.needSDWA && isGCN14)
1537        {
1538            // fix for extra type operand from SDWA
1539            if (rvus[2].regField != ASMFIELD_NONE && src0Op.range.isNonVGPR())
1540                rvus[2].regField = GCNFIELD_DPPSDWA_SSRC0;
1541            if (rvus[3].regField != ASMFIELD_NONE && src1Op.range.isNonVGPR())
1542                rvus[3].regField = GCNFIELD_VOP_SSRC1;
1543        }
1544    }
1545    else if (isGCN12 && ((src0Op.vopMods|src1Op.vopMods) & ~VOPOP_SEXT)!=0 && !sextFlags)
1546        // if all pass we check we promote VOP3 if only operand modifiers expect sext()
1547        vop3 = true;
1548   
1549    if (isGCN12 && vop3 && haveDstCC && ((src0Op.vopMods|src1Op.vopMods) & VOPOP_ABS) != 0)
1550        ASM_FAIL_BY_ERROR(instrPlace, "Abs modifier is illegal for VOP3B encoding")
1551    if (vop3 && needImm)
1552        ASM_FAIL_BY_ERROR(instrPlace, "Literal in VOP3 encoding is illegal")
1553   
1554    if (!checkGCNVOPEncoding(asmr, arch, instrPlace, gcnVOPEnc, gcnInsn.mode, &extraMods))
1555        return false;
1556   
1557    if (vop3 && gcnInsn.code2==UINT16_MAX)
1558        ASM_FAIL_BY_ERROR(instrPlace, "No VOP3 encoding for this instruction")
1559   
1560    // set target expressions if needed
1561    if (src0OpExpr!=nullptr)
1562        src0OpExpr->setTarget(AsmExprTarget(GCNTGT_LITIMM, asmr.currentSection,
1563                      output.size()));
1564    if (src1OpExpr!=nullptr)
1565        src1OpExpr->setTarget(AsmExprTarget(GCNTGT_LITIMM, asmr.currentSection,
1566                      output.size()));
1567    if (immExpr!=nullptr)
1568        immExpr->setTarget(AsmExprTarget(GCNTGT_LITIMM, asmr.currentSection,
1569                      output.size()));
1570   
1571    // put data (instruction words)
1572    cxuint wordsNum = 1;
1573    uint32_t words[2];
1574    if (!vop3)
1575        // VOP2 encoding
1576        encodeVOPWords((uint32_t(gcnInsn.code1)<<25) |
1577                (uint32_t(src1Op.range.bstart()&0xff)<<9) |
1578                (uint32_t(dstReg.bstart()&0xff)<<17),
1579                modifiers, extraMods, src0Op, src1Op, immValue, mode1,
1580                0, wordsNum, words);
1581    else
1582        // VOP3 encoding
1583        encodeVOP3Words(arch, gcnInsn, modifiers, opMods, haveDstCC,
1584                dstReg, dstCCReg, srcCCReg, src0Op, src1Op, wordsNum, words);
1585   
1586    if (!checkGCNEncodingSize(asmr, instrPlace, gcnEncSize, wordsNum))
1587        return false;
1588   
1589    output.insert(output.end(), reinterpret_cast<cxbyte*>(words),
1590            reinterpret_cast<cxbyte*>(words + wordsNum));
1591    /// prevent freeing expression
1592    src0OpExpr.release();
1593    src1OpExpr.release();
1594    immExpr.release();
1595    // update register pool (VGPR and SGPR counting)
1596    if (!dstReg.isRegVar())
1597    {
1598        if (dstReg.start>=256)
1599            updateVGPRsNum(gcnRegs.vgprsNum, dstReg.end-257);
1600        else // sgprs
1601        {
1602            updateSGPRsNum(gcnRegs.sgprsNum, dstReg.end-1, arch);
1603            updateRegFlags(gcnRegs.regFlags, dstReg.start, arch);
1604        }
1605    }
1606    // for SRC operands
1607    if (src0Op.range && !src0Op.range.isRegVar())
1608        updateRegFlags(gcnRegs.regFlags, src0Op.range.start, arch);
1609    if (src1Op.range && !src1Op.range.isRegVar())
1610        updateRegFlags(gcnRegs.regFlags, src1Op.range.start, arch);
1611    if (dstCCReg && !dstCCReg.isRegVar())
1612    {
1613        updateSGPRsNum(gcnRegs.sgprsNum, dstCCReg.end-1, arch);
1614        updateRegFlags(gcnRegs.regFlags, dstCCReg.start, arch);
1615    }
1616    if (srcCCReg && !srcCCReg.isRegVar())
1617        updateRegFlags(gcnRegs.regFlags, srcCCReg.start, arch);
1618    return true;
1619}
1620
1621bool GCNAsmUtils::parseVOP1Encoding(Assembler& asmr, const GCNAsmInstruction& gcnInsn,
1622                  const char* instrPlace, const char* linePtr, GPUArchMask arch,
1623                  std::vector<cxbyte>& output, GCNAssembler::Regs& gcnRegs,
1624                  GCNEncSize gcnEncSize, GCNVOPEnc gcnVOPEnc)
1625{
1626    bool good = true;
1627    const GCNInsnMode mode1 = (gcnInsn.mode & GCN_MASK1);
1628    const GCNInsnMode mode2 = (gcnInsn.mode & GCN_LITMASK);
1629    const bool isGCN12 = (arch & ARCH_GCN_1_2_4_5)!=0;
1630    const bool isGCN14 = (arch & ARCH_GCN_1_4_5)!=0;
1631   
1632    GCNAssembler* gcnAsm = static_cast<GCNAssembler*>(asmr.isaAssembler);
1633    RegRange dstReg(0, 0);
1634    GCNOperand src0Op{};
1635    std::unique_ptr<AsmExpression> src0OpExpr;
1636    cxbyte modifiers = 0;
1637    if (mode1 != GCN_VOP_ARG_NONE)
1638    {
1639        gcnAsm->setCurrentRVU(0);
1640        if (mode1 == GCN_DST_SGPR)
1641            // if SGPRS as destination
1642            good &= parseSRegRange(asmr, linePtr, dstReg, arch,
1643                           (gcnInsn.mode&GCN_REG_DST_64)?2:1, GCNFIELD_VOP_SDST, true,
1644                           INSTROP_SYMREGRANGE|INSTROP_SGPR_UNALIGNED|INSTROP_WRITE);
1645        else // if VGPRS as destination
1646            good &= parseVRegRange(asmr, linePtr, dstReg,
1647                       (gcnInsn.mode&GCN_REG_DST_64)?2:1, GCNFIELD_VOP_VDST, true,
1648                                  INSTROP_SYMREGRANGE|INSTROP_WRITE);
1649       
1650        const Flags literalConstsFlags = (mode2==GCN_FLOATLIT) ? INSTROP_FLOAT :
1651                (mode2==GCN_F16LIT) ? INSTROP_F16 : INSTROP_INT;
1652       
1653        if (!skipRequiredComma(asmr, linePtr))
1654            return false;
1655        cxuint regsNum = (gcnInsn.mode&GCN_REG_SRC0_64)?2:1;
1656        gcnAsm->setCurrentRVU(1);
1657        // parse SRC0 (can be VGPR, SGPR, source scalar, literal or cosntant, LDS
1658        good &= parseOperand(asmr, linePtr, src0Op, &src0OpExpr, arch, regsNum,
1659                    correctOpType(regsNum, literalConstsFlags)|INSTROP_VREGS|
1660                    INSTROP_SGPR_UNALIGNED|INSTROP_SSOURCE|INSTROP_SREGS|INSTROP_LDS|
1661                    INSTROP_VOP3MODS|INSTROP_READ, GCNFIELD_VOP_SRC0);
1662    }
1663    // modifiers
1664    VOPExtraModifiers extraMods{};
1665    VOPOpModifiers opMods{};
1666    good &= parseVOPModifiers(asmr, linePtr, arch, modifiers, opMods,
1667                  (mode1!=GCN_VOP_ARG_NONE) ? 2 : 0, (isGCN12)?&extraMods:nullptr,
1668                  PARSEVOP_WITHCLAMP|PARSEVOP_WITHSEXT|
1669                  (isGCN14 ? PARSEVOP_WITHOPSEL : 0), (mode1!=GCN_VOP_ARG_NONE) ? 2 : 0);
1670    if (!good || !checkGarbagesAtEnd(asmr, linePtr))
1671        return false;
1672   
1673    if (src0Op)
1674        src0Op.vopMods |= ((opMods.absMod&1) ? VOPOP_ABS : 0) |
1675                ((opMods.negMod&1) ? VOPOP_NEG : 0) |
1676                ((opMods.sextMod&1) ? VOPOP_SEXT : 0);
1677   
1678    extraMods.needSDWA |= ((src0Op.vopMods) & VOPOP_SEXT) != 0;
1679    // check whether VOP3 encoding is needed
1680    bool vop3 = ((!isGCN12 && src0Op.vopMods!=0) ||
1681            (modifiers&~(VOP3_BOUNDCTRL|(extraMods.needSDWA?VOP3_CLAMP:0)|
1682            /* exclude OMOD if RXVEGA and SDWA used */
1683            ((isGCN14 && extraMods.needSDWA) ? 3 : 0)))!=0) ||
1684            ((opMods.opselMod & 15) != 0) || (gcnEncSize==GCNEncSize::BIT64);
1685    if (vop3) // modify fields in reg usage
1686    {
1687        AsmRegVarUsage* rvus = gcnAsm->instrRVUs;
1688        if (rvus[0].regField != ASMFIELD_NONE)
1689            rvus[0].regField = (rvus[0].regField==GCNFIELD_VOP_VDST) ?
1690                        GCNFIELD_VOP3_VDST : GCNFIELD_VOP3_SDST0;
1691        if (rvus[1].regField != ASMFIELD_NONE)
1692            rvus[1].regField = GCNFIELD_VOP3_SRC0;
1693    }
1694   
1695    bool sextFlags = (src0Op.vopMods & VOPOP_SEXT);
1696    bool absNegFlags = (src0Op.vopMods & (VOPOP_ABS|VOPOP_NEG));
1697    bool needImm = (src0Op && src0Op.range.isVal(255));
1698    if (isGCN12 && (extraMods.needSDWA || extraMods.needDPP || extraMods.needDPP8 ||
1699                sextFlags || gcnVOPEnc!=GCNVOPEnc::NORMAL))
1700    {
1701        /* if VOP_SDWA or VOP_DPP is required */
1702        if (!checkGCNVOPExtraModifers(asmr, arch, needImm, sextFlags, vop3,
1703                    gcnVOPEnc, src0Op, extraMods, absNegFlags, instrPlace))
1704            return false;
1705        if (gcnAsm->instrRVUs[1].regField != ASMFIELD_NONE)
1706            gcnAsm->instrRVUs[1].regField = GCNFIELD_DPPSDWA_SRC0;
1707        if (extraMods.needSDWA && isGCN14)
1708        {
1709            // fix for extra type operand from SDWA
1710            AsmRegVarUsage* rvus = gcnAsm->instrRVUs;
1711            if (rvus[1].regField != ASMFIELD_NONE && src0Op.range.isNonVGPR())
1712                rvus[1].regField = GCNFIELD_DPPSDWA_SSRC0;
1713        }
1714    }
1715    else if (isGCN12 && (src0Op.vopMods & ~VOPOP_SEXT)!=0 && !sextFlags)
1716        // if all pass we check we promote VOP3 if only operand modifiers expect sext()
1717        vop3 = true;
1718   
1719    if (vop3 && src0Op.range.isVal(255))
1720        ASM_FAIL_BY_ERROR(instrPlace, "Literal in VOP3 encoding is illegal")
1721   
1722    if (!checkGCNVOPEncoding(asmr, arch, instrPlace, gcnVOPEnc, gcnInsn.mode, &extraMods))
1723        return false;
1724   
1725    if (src0OpExpr!=nullptr)
1726        src0OpExpr->setTarget(AsmExprTarget(GCNTGT_LITIMM, asmr.currentSection,
1727                      output.size()));
1728   
1729    // put data (instruction word)
1730    cxuint wordsNum = 1;
1731    uint32_t words[2];
1732    if (!vop3)
1733        // VOP1 encoding
1734        encodeVOPWords(0x7e000000U | (uint32_t(gcnInsn.code1)<<9) |
1735                (uint32_t(dstReg.bstart()&0xff)<<17),
1736                modifiers, extraMods, src0Op, GCNOperand{ { 256, 257 } }, 0, mode1,
1737                0, wordsNum, words);
1738    else
1739        // VOP3 encoding
1740        encodeVOP3Words(arch, gcnInsn, modifiers, opMods, false,
1741                dstReg, RegRange{}, RegRange{}, src0Op, GCNOperand{}, wordsNum, words);
1742   
1743    if (!checkGCNEncodingSize(asmr, instrPlace, gcnEncSize, wordsNum))
1744        return false;
1745   
1746    output.insert(output.end(), reinterpret_cast<cxbyte*>(words),
1747            reinterpret_cast<cxbyte*>(words + wordsNum));
1748    /// prevent freeing expression
1749    src0OpExpr.release();
1750    // update register pool (VGPR and SGPR counting)
1751    if (dstReg && !dstReg.isRegVar())
1752    {
1753        if (dstReg.start>=256)
1754            updateVGPRsNum(gcnRegs.vgprsNum, dstReg.end-257);
1755        else // sgprs
1756        {
1757            updateSGPRsNum(gcnRegs.sgprsNum, dstReg.end-1, arch);
1758            updateRegFlags(gcnRegs.regFlags, dstReg.start, arch);
1759        }
1760    }
1761    if (src0Op.range && !src0Op.range.isRegVar())
1762        updateRegFlags(gcnRegs.regFlags, src0Op.range.start, arch);
1763    return true;
1764}
1765
1766bool GCNAsmUtils::parseVOPCEncoding(Assembler& asmr, const GCNAsmInstruction& gcnInsn,
1767                  const char* instrPlace, const char* linePtr, GPUArchMask arch,
1768                  std::vector<cxbyte>& output, GCNAssembler::Regs& gcnRegs,
1769                  GCNEncSize gcnEncSize, GCNVOPEnc gcnVOPEnc)
1770{
1771    bool good = true;
1772    const GCNInsnMode mode2 = (gcnInsn.mode & GCN_MASK2);
1773    const bool isGCN12 = (arch & ARCH_GCN_1_2_4_5)!=0;
1774    const bool isGCN14 = (arch & ARCH_GCN_1_4_5)!=0;
1775    const bool isGCN15 = (arch & ARCH_GCN_1_5)!=0;
1776    const bool wave32 = (asmr.codeFlags & ASM_CODE_WAVE32)!=0;
1777   
1778    GCNAssembler* gcnAsm = static_cast<GCNAssembler*>(asmr.isaAssembler);
1779    RegRange dstReg(0, 0);
1780    GCNOperand src0Op{};
1781    std::unique_ptr<AsmExpression> src0OpExpr;
1782    GCNOperand src1Op{};
1783    std::unique_ptr<AsmExpression> src1OpExpr;
1784    cxbyte modifiers = 0;
1785   
1786    // parse SDST (2 SGPR's)
1787    if ((gcnInsn.mode & GCN_VOPC_NOVCC) == 0)
1788    {
1789        gcnAsm->setCurrentRVU(0);
1790        const cxuint regSize = (!isGCN15 || !wave32 ||
1791                        (gcnInsn.mode&GCN_VOP_NOWVSZ)!=0) ? 2 : 1;
1792        good &= parseSRegRange(asmr, linePtr, dstReg, arch, regSize, GCNFIELD_VOP3_SDST0,
1793                        true, INSTROP_SYMREGRANGE|INSTROP_SGPR_UNALIGNED|INSTROP_WRITE);
1794        if (!skipRequiredComma(asmr, linePtr))
1795            return false;
1796    }
1797   
1798    const Flags literalConstsFlags = (mode2==GCN_FLOATLIT) ? INSTROP_FLOAT :
1799                (mode2==GCN_F16LIT) ? INSTROP_F16 : INSTROP_INT;
1800    cxuint regsNum = (gcnInsn.mode&GCN_REG_SRC0_64)?2:1;
1801    gcnAsm->setCurrentRVU(1);
1802    // parse SRC0 (can VGPR, SGPR, scalar source,literal or constant)
1803    good &= parseOperand(asmr, linePtr, src0Op, &src0OpExpr, arch, regsNum,
1804                    correctOpType(regsNum, literalConstsFlags)|INSTROP_VREGS|
1805                    INSTROP_SGPR_UNALIGNED|INSTROP_SSOURCE|INSTROP_SREGS|INSTROP_LDS|
1806                    INSTROP_VOP3MODS|INSTROP_READ, GCNFIELD_VOP_SRC0);
1807   
1808    if (!skipRequiredComma(asmr, linePtr))
1809        return false;
1810    regsNum = (gcnInsn.mode&GCN_REG_SRC1_64)?2:1;
1811    gcnAsm->setCurrentRVU(2);
1812    // parse SRC1 (can VGPR, SGPR, scalar source,literal or constant)
1813    good &= parseOperand(asmr, linePtr, src1Op, &src1OpExpr, arch, regsNum,
1814                correctOpType(regsNum, literalConstsFlags) | INSTROP_VOP3MODS|
1815                INSTROP_SGPR_UNALIGNED|INSTROP_VREGS|INSTROP_SSOURCE|INSTROP_SREGS|
1816                INSTROP_READ| (src0Op.range.isVal(255) ? INSTROP_ONLYINLINECONSTS : 0),
1817                GCNFIELD_VOP_VSRC1);
1818    // modifiers
1819    VOPExtraModifiers extraMods{};
1820    VOPOpModifiers opMods{};
1821    good &= parseVOPModifiers(asmr, linePtr, arch, modifiers, opMods, 3,
1822                (isGCN12)?&extraMods:nullptr, (isGCN14 ? PARSEVOP_NODSTMODS : 0)|
1823                PARSEVOP_WITHCLAMP|PARSEVOP_WITHSEXT|(isGCN14 ? PARSEVOP_WITHOPSEL : 0));
1824    if (!good || !checkGarbagesAtEnd(asmr, linePtr))
1825        return false;
1826   
1827    // set VOP operand modifiers to src operands
1828    if (src0Op)
1829        src0Op.vopMods |= ((opMods.absMod&1) ? VOPOP_ABS : 0) |
1830                ((opMods.negMod&1) ? VOPOP_NEG : 0) |
1831                ((opMods.sextMod&1) ? VOPOP_SEXT : 0);
1832    if (src1Op)
1833        src1Op.vopMods |= ((opMods.absMod&2) ? VOPOP_ABS : 0) |
1834                ((opMods.negMod&2) ? VOPOP_NEG : 0) |
1835                ((opMods.sextMod&2) ? VOPOP_SEXT : 0);
1836   
1837    const cxuint vccCode = ((gcnInsn.mode & GCN_VOPC_NOVCC) == 0) ? 106 : 0;
1838    // determine whether SDWA is needed or VOP3 encoding needed
1839    extraMods.needSDWA |= ((src0Op.vopMods | src1Op.vopMods) & VOPOP_SEXT) != 0;
1840    bool vop3 = //(dstReg.start!=106) || (src1Op.range.start<256) ||
1841        ((!isGCN14 || !extraMods.needSDWA) && !dstReg.isVal(vccCode)) ||
1842        ((!isGCN14 || !extraMods.needSDWA) && src1Op.range.isNonVGPR()) ||
1843        (!isGCN12 && (src0Op.vopMods!=0 || src1Op.vopMods!=0)) ||
1844        (modifiers&~(VOP3_BOUNDCTRL|(extraMods.needSDWA?VOP3_CLAMP:0)|
1845            /* exclude OMOD if RXVEGA and SDWA used */
1846            ((isGCN14 && extraMods.needSDWA) ? 3 : 0)))!=0 ||
1847        ((opMods.opselMod & 15) != 0) || (gcnEncSize==GCNEncSize::BIT64);
1848   
1849    if ((src0Op.range.isVal(255) || src1Op.range.isVal(255)) &&
1850        (src0Op.range.isSGPR() || src0Op.range.isVal(124) ||
1851         src1Op.range.isSGPR() || src1Op.range.isVal(124)))
1852        ASM_FAIL_BY_ERROR(instrPlace, "Literal with SGPR or M0 is illegal")
1853    if ((arch & ARCH_GCN_1_5) == 0 && src0Op.range.isSGPR() && src1Op.range.isSGPR() &&
1854        !regRangeCanEqual(src0Op.range, src1Op.range))
1855        /* include VCCs (???) */
1856        ASM_FAIL_BY_ERROR(instrPlace, "More than one SGPR to read in instruction")
1857   
1858    AsmRegVarUsage* rvus = gcnAsm->instrRVUs;
1859    if (vop3)
1860    {
1861        // modify fields in reg usage
1862        if (rvus[1].regField != ASMFIELD_NONE)
1863            rvus[1].regField = GCNFIELD_VOP3_SRC0;
1864        if (rvus[2].regField != ASMFIELD_NONE)
1865            rvus[2].regField = GCNFIELD_VOP3_SRC1;
1866    }
1867    else if (rvus[0].regField != ASMFIELD_NONE)
1868        rvus[0].regField = GCNFIELD_VOP_VCC_SDST0;
1869   
1870    const bool needImm = src0Op.range.start==255 || src1Op.range.start==255;
1871   
1872    bool sextFlags = ((src0Op.vopMods|src1Op.vopMods) & VOPOP_SEXT);
1873    bool absNegFlags = (src0Op.vopMods & (VOPOP_ABS|VOPOP_NEG));
1874    if (isGCN12 && (extraMods.needSDWA || extraMods.needDPP || extraMods.needDPP8 ||
1875                sextFlags || gcnVOPEnc!=GCNVOPEnc::NORMAL))
1876    {
1877        /* if VOP_SDWA or VOP_DPP is required */
1878        if (!checkGCNVOPExtraModifers(asmr, arch, needImm, sextFlags, vop3,
1879                    gcnVOPEnc, src0Op, extraMods, absNegFlags, instrPlace))
1880            return false;
1881        if (gcnAsm->instrRVUs[1].regField != ASMFIELD_NONE)
1882            gcnAsm->instrRVUs[1].regField = GCNFIELD_DPPSDWA_SRC0;
1883       
1884        if (extraMods.needSDWA && isGCN14)
1885        {
1886            // fix for extra type operand from SDWA
1887            AsmRegVarUsage* rvus = gcnAsm->instrRVUs;
1888            if (rvus[0].regField != ASMFIELD_NONE)
1889                rvus[0].regField = GCNFIELD_SDWAB_SDST;
1890            if (rvus[1].regField != ASMFIELD_NONE && src0Op.range.isNonVGPR())
1891                rvus[1].regField = GCNFIELD_DPPSDWA_SSRC0;
1892            if (rvus[2].regField != ASMFIELD_NONE && src1Op.range.isNonVGPR())
1893                rvus[2].regField = GCNFIELD_VOP_SSRC1;
1894        }
1895    }
1896    else if (isGCN12 && ((src0Op.vopMods|src1Op.vopMods) & ~VOPOP_SEXT)!=0 && !sextFlags)
1897        // if all pass we check we promote VOP3 if only operand modifiers expect sext()
1898        vop3 = true;
1899   
1900    if (vop3 && (src0Op.range.isVal(255) || src1Op.range.isVal(255)))
1901        ASM_FAIL_BY_ERROR(instrPlace, "Literal in VOP3 encoding is illegal")
1902   
1903    if (!checkGCNVOPEncoding(asmr, arch, instrPlace, gcnVOPEnc, gcnInsn.mode, &extraMods))
1904        return false;
1905   
1906    if (isGCN14 && extraMods.needSDWA && ((modifiers & VOP3_CLAMP)!=0 || (modifiers&3)!=0))
1907        ASM_FAIL_BY_ERROR(instrPlace, "Modifiers CLAMP and OMOD is illegal in SDWAB")
1908   
1909    if (src0OpExpr!=nullptr)
1910        src0OpExpr->setTarget(AsmExprTarget(GCNTGT_LITIMM, asmr.currentSection,
1911                      output.size()));
1912    if (src1OpExpr!=nullptr)
1913        src1OpExpr->setTarget(AsmExprTarget(GCNTGT_LITIMM, asmr.currentSection,
1914                      output.size()));
1915   
1916    // put data (instruction words)
1917    cxuint wordsNum = 1;
1918    uint32_t words[2];
1919    if (!vop3)
1920    {
1921        // VOPC encoding
1922        const uint32_t dstMods = (isGCN14 ? 0x10000 : 0) |
1923                ((isGCN14 && !dstReg.isVal(106)) ? ((dstReg.bstart()|0x80)<<8) : 0);
1924       
1925        encodeVOPWords(0x7c000000U | (uint32_t(gcnInsn.code1)<<17) |
1926                (uint32_t(src1Op.range.bstart()&0xff)<<9),
1927                modifiers, extraMods, src0Op, src1Op, 0, 0,
1928                dstMods, wordsNum, words);
1929    }
1930    else
1931        // VOP3 encoding
1932        encodeVOP3Words(arch, gcnInsn, modifiers, opMods, false,
1933                dstReg, RegRange{}, RegRange{}, src0Op, src1Op, wordsNum, words);
1934   
1935    if (!checkGCNEncodingSize(asmr, instrPlace, gcnEncSize, wordsNum))
1936        return false;
1937    output.insert(output.end(), reinterpret_cast<cxbyte*>(words),
1938            reinterpret_cast<cxbyte*>(words + wordsNum));
1939    /// prevent freeing expression
1940    src0OpExpr.release();
1941    src1OpExpr.release();
1942    // update register pool (VGPR and SGPR counting)
1943    if (dstReg && !dstReg.isRegVar())
1944    {
1945        updateSGPRsNum(gcnRegs.sgprsNum, dstReg.end-1, arch);
1946        updateRegFlags(gcnRegs.regFlags, dstReg.start, arch);
1947    }
1948    if (src0Op.range && !src0Op.range.isRegVar())
1949        updateRegFlags(gcnRegs.regFlags, src0Op.range.start, arch);
1950    if (src1Op.range && !src1Op.range.isRegVar())
1951        updateRegFlags(gcnRegs.regFlags, src1Op.range.start, arch);
1952    return true;
1953}
1954
1955bool GCNAsmUtils::parseVOP3Encoding(Assembler& asmr, const GCNAsmInstruction& gcnInsn,
1956                  const char* instrPlace, const char* linePtr, GPUArchMask arch,
1957                  std::vector<cxbyte>& output, GCNAssembler::Regs& gcnRegs,
1958                  GCNEncSize gcnEncSize, GCNVOPEnc gcnVOPEnc)
1959{
1960    bool good = true;
1961    const GCNInsnMode mode1 = (gcnInsn.mode & GCN_MASK1);
1962    const GCNInsnMode mode2 = (gcnInsn.mode & GCN_MASK2);
1963    const GCNInsnMode fltmode = (gcnInsn.mode & GCN_LITMASK);
1964    const bool isGCN12 = (arch & ARCH_GCN_1_2_4_5)!=0;
1965    const bool isGCN14 = (arch & ARCH_GCN_1_4_5)!=0;
1966    const bool isGCN15 = (arch & ARCH_GCN_1_5)!=0;
1967    const bool vop3p = (gcnInsn.mode & GCN_VOP3_VOP3P) != 0 ||
1968                    (gcnInsn.encoding == GCNENC_VOP3P);
1969    const bool wave32 = (asmr.codeFlags & ASM_CODE_WAVE32)!=0;
1970    if (gcnVOPEnc!=GCNVOPEnc::NORMAL)
1971        ASM_FAIL_BY_ERROR(instrPlace, "DPP and SDWA encoding is illegal for VOP3")
1972   
1973    GCNAssembler* gcnAsm = static_cast<GCNAssembler*>(asmr.isaAssembler);
1974    RegRange dstReg(0, 0);
1975    RegRange sdstReg(0, 0);
1976    GCNOperand src0Op{};
1977    std::unique_ptr<AsmExpression> src0OpExpr;
1978    GCNOperand src1Op{};
1979    std::unique_ptr<AsmExpression> src1OpExpr;
1980    GCNOperand src2Op{};
1981    std::unique_ptr<AsmExpression> src2OpExpr;
1982   
1983    const bool vccImplRead = (gcnInsn.mode & GCN_VCC_IMPL_READ)!=0;
1984    const bool vccImplWrite = (gcnInsn.mode & GCN_VCC_IMPL_WRITE)!=0;
1985   
1986    const bool is128Ops = (gcnInsn.mode & 0x7000) == GCN_VOP3_DS2_128;
1987    bool modHigh = false;
1988    cxbyte modifiers = 0;
1989    const Flags vop3Mods = ((gcnInsn.encoding == GCNENC_VOP3B) ?
1990            INSTROP_VOP3NEG : INSTROP_VOP3MODS | INSTROP_NOSEXT) |
1991            (vop3p ? INSTROP_VOP3P : 0);
1992   
1993    // by default OPSEL_HI is [1,1,1] in vop3p instructions
1994    VOPOpModifiers opMods{ 0, 0, 0, cxbyte(vop3p ? 7<<4 : 0) };
1995    cxuint operands = 1;
1996    const Flags onlyInlineConsts = (!isGCN15) ?
1997                INSTROP_ONLYINLINECONSTS|INSTROP_NOLITERALERROR : 0;
1998   
1999    if (mode1 != GCN_VOP_ARG_NONE)
2000    {
2001        gcnAsm->setCurrentRVU(0);
2002        // parse DST (
2003        if ((gcnInsn.mode&GCN_VOP3_DST_SGPR)==0)
2004            good &= parseVRegRange(asmr, linePtr, dstReg,
2005                       (is128Ops) ? 4 : ((gcnInsn.mode&GCN_REG_DST_64)?2:1),
2006                       GCNFIELD_VOP3_VDST, true, INSTROP_SYMREGRANGE|INSTROP_WRITE);
2007        else // SGPRS as dest
2008            good &= parseSRegRange(asmr, linePtr, dstReg, arch,
2009                       (gcnInsn.mode&GCN_REG_DST_64)?2:1, GCNFIELD_VOP3_SDST0, true,
2010                       INSTROP_SYMREGRANGE|INSTROP_SGPR_UNALIGNED|INSTROP_WRITE);
2011        if (!skipRequiredComma(asmr, linePtr))
2012            return false;
2013       
2014        if (gcnInsn.encoding == GCNENC_VOP3B &&
2015            (mode1 == GCN_DS2_VCC || mode1 == GCN_DST_VCC || mode1 == GCN_DST_VCC_VSRC2 ||
2016             mode1 == GCN_S0EQS12)) /* VOP3b */
2017        {
2018            // SDST (VCC) (2 SGPR's)
2019            gcnAsm->setCurrentRVU(1);
2020            const cxuint regSize = (!isGCN15 || !wave32 ||
2021                        (gcnInsn.mode&GCN_VOP_NOWVSZ)!=0) ? 2 : 1;
2022            good &= parseSRegRange(asmr, linePtr, sdstReg, arch, regSize,
2023                        GCNFIELD_VOP3_SDST1, true, INSTROP_SYMREGRANGE|INSTROP_WRITE|
2024                        INSTROP_SGPR_UNALIGNED);
2025            if (!skipRequiredComma(asmr, linePtr))
2026                return false;
2027        }
2028        else if (vccImplRead)
2029        {
2030            gcnAsm->setCurrentRVU(1);
2031            gcnAsm->setRegVarUsage({ size_t(asmr.currentOutPos), nullptr,
2032                        uint16_t(106), uint16_t(107), GCNFIELD_VOP_VCC_IMPL,
2033                        ASMRVU_READ, 0 });
2034        }
2035        else if (vccImplWrite)
2036        {
2037            gcnAsm->setCurrentRVU(1);
2038            gcnAsm->setRegVarUsage({ size_t(asmr.currentOutPos), nullptr,
2039                        uint16_t(106), uint16_t(107), GCNFIELD_VOP_VCC_IMPL,
2040                        ASMRVU_WRITE, 0 });
2041        }
2042       
2043        const Flags literalConstsFlags = (fltmode==GCN_FLOATLIT) ? INSTROP_FLOAT :
2044                (fltmode==GCN_F16LIT) ? INSTROP_F16 : INSTROP_INT;
2045       
2046        cxuint regsNum;
2047        if (mode2 != GCN_VOP3_VINTRP)
2048        {
2049            // parse SRC0 (can be VGPR, SGPR, scalar source, constant, LDS)
2050            gcnAsm->setCurrentRVU(2);
2051            regsNum = (gcnInsn.mode&GCN_REG_SRC0_64)?2:1;
2052            std::unique_ptr<AsmExpression>* src0OpExprPtr =
2053                                    isGCN15 ? &src0OpExpr : nullptr;
2054            good &= parseOperand(asmr, linePtr, src0Op, src0OpExprPtr, arch, regsNum,
2055                    correctOpType(regsNum, literalConstsFlags)|INSTROP_VREGS|
2056                    INSTROP_SGPR_UNALIGNED|INSTROP_SSOURCE|INSTROP_SREGS|INSTROP_LDS|
2057                    vop3Mods|onlyInlineConsts|INSTROP_READ, GCNFIELD_VOP3_SRC0);
2058            operands++;
2059        }
2060       
2061        if (mode2 == GCN_VOP3_VINTRP)
2062        {
2063            // if VINTRP instruction
2064            gcnAsm->setCurrentRVU(3);
2065            if (mode1 != GCN_P0_P10_P20)
2066            {
2067                good &= parseOperand(asmr, linePtr, src1Op, nullptr, arch, 1,
2068                        INSTROP_VREGS|vop3Mods|INSTROP_READ, GCNFIELD_VOP3_SRC1);
2069            }
2070            else /* P0_P10_P20 */
2071                good &= parseVINTRP0P10P20(asmr, linePtr, src1Op.range);
2072           
2073            if (!skipRequiredComma(asmr, linePtr))
2074                return false;
2075           
2076            cxbyte attr;
2077            good &= parseVINTRPAttr(asmr, linePtr, attr);
2078            attr = ((attr&3)<<6) | ((attr&0xfc)>>2);
2079            src0Op.range = { attr, uint16_t(attr+1) };
2080           
2081            if ((gcnInsn.mode & GCN_VOP3_MASK3) == GCN_VINTRP_SRC2)
2082            {
2083                if (!skipRequiredComma(asmr, linePtr))
2084                    return false;
2085                // parse SRC2 (VGPR, SGPR)
2086                gcnAsm->setCurrentRVU(4);
2087                good &= parseOperand(asmr, linePtr, src2Op, nullptr, arch,
2088                    (gcnInsn.mode&GCN_REG_SRC2_64)?2:1, vop3Mods|INSTROP_SGPR_UNALIGNED|
2089                    INSTROP_VREGS|INSTROP_SREGS|INSTROP_READ, GCNFIELD_VOP3_SRC2);
2090            }
2091            // high and vop3
2092            const char* end = asmr.line+asmr.lineSize;
2093            bool haveOpsel = false;
2094            bool haveNeg = false, haveAbs = false;
2095            // own parse VINTRP modifiers with some VOP3 modifiers
2096            while (true)
2097            {
2098                bool alreadyModDefined = false;
2099                skipSpacesToEnd(linePtr, end);
2100                if (linePtr==end)
2101                    break;
2102                char modName[10];
2103                const char* modPlace = linePtr;
2104                if (!getNameArgS(asmr, 10, modName, linePtr, "VINTRP modifier"))
2105                    continue;
2106                if (::strcmp(modName, "high")==0)
2107                    good &= parseModEnable(asmr, linePtr, modHigh, "high modifier");
2108                else if (::strcmp(modName, "vop3")==0)
2109                {
2110                    bool vop3Mod = false;
2111                    good &= parseModEnable(asmr, linePtr, vop3Mod, "vop3 modifier");
2112                    modifiers = (modifiers & ~VOP3_VOP3) | (vop3Mod ? VOP3_VOP3 : 0);
2113                }
2114                else if (parseSingleOMODCLAMP(asmr, linePtr, modPlace, modName, arch,
2115                        modifiers, opMods, 
2116                        (gcnInsn.mode & GCN_VOP3_MASK3) == GCN_VINTRP_SRC2 ? 4 : 3, PARSEVOP_WITHCLAMP, haveAbs, haveNeg,
2117                        alreadyModDefined, good))
2118                {   // do nothing
2119                }
2120                else if (::strcmp(modName, "op_sel")==0)
2121                {
2122                    // op_sel with boolean array
2123                    uint32_t opselVal = 0;
2124                    if (linePtr!=end && *linePtr==':')
2125                    {
2126                        linePtr++;
2127                        if (parseImmWithBoolArray(asmr, linePtr, opselVal, 4, WS_UNSIGNED))
2128                        {
2129                            opMods.opselMod = opselVal;
2130                            if (haveOpsel)
2131                                asmr.printWarning(modPlace, "Opsel is already defined");
2132                            haveOpsel = true;
2133                            opMods.opselMod = opselVal;
2134                        }
2135                    }
2136                    else
2137                        good = false;
2138                }
2139                else
2140                    ASM_NOTGOOD_BY_ERROR(modPlace, "Unknown VINTRP modifier")
2141            }
2142            if (modHigh)
2143            {
2144                src0Op.range.start+=0x100;
2145                src0Op.range.end+=0x100;
2146            }
2147        }
2148        else if (mode1 != GCN_SRC12_NONE)
2149        {
2150            // if encoding have two or three source operands
2151            if (!skipRequiredComma(asmr, linePtr))
2152                return false;
2153            regsNum = (gcnInsn.mode&GCN_REG_SRC1_64)?2:1;
2154            // parse SRC1 (can be VGPR, SGPR, source scalar, constant)
2155            gcnAsm->setCurrentRVU(3);
2156            std::unique_ptr<AsmExpression>* src1OpExprPtr =
2157                                    isGCN15 ? &src1OpExpr : nullptr;
2158            good &= parseOperand(asmr, linePtr, src1Op, src1OpExprPtr, arch, regsNum,
2159                    correctOpType(regsNum, literalConstsFlags)|INSTROP_VREGS|
2160                    INSTROP_SGPR_UNALIGNED|INSTROP_SSOURCE|INSTROP_SREGS|vop3Mods|
2161                    onlyInlineConsts|INSTROP_READ, GCNFIELD_VOP3_SRC1);
2162            operands++;
2163           
2164            if (mode1 != GCN_SRC2_NONE && mode1 != GCN_DST_VCC)
2165            {
2166                if (!skipRequiredComma(asmr, linePtr))
2167                    return false;
2168                regsNum = (gcnInsn.mode&GCN_REG_SRC2_64)?2:1;
2169                // parse SRC2 (can be VGPR, SGPR, source scalar, constant)
2170                gcnAsm->setCurrentRVU(4);
2171                std::unique_ptr<AsmExpression>* src2OpExprPtr =
2172                                    isGCN15 ? &src2OpExpr : nullptr;
2173                good &= parseOperand(asmr, linePtr, src2Op, src2OpExprPtr, arch,
2174                        is128Ops ? 4 : regsNum,
2175                        correctOpType(regsNum, literalConstsFlags)|INSTROP_SGPR_UNALIGNED|
2176                        INSTROP_VREGS|INSTROP_SSOURCE|INSTROP_SREGS|INSTROP_READ|
2177                        vop3Mods|onlyInlineConsts, GCNFIELD_VOP3_SRC2);
2178                operands++;
2179            }
2180        }
2181    }
2182    // modifiers
2183    if (mode2 != GCN_VOP3_VINTRP)
2184        good &= parseVOPModifiers(asmr, linePtr, arch, modifiers, opMods, operands,
2185                    nullptr, ((isGCN12 || gcnInsn.encoding!=GCNENC_VOP3B) ?
2186                            PARSEVOP_WITHCLAMP : 0) |
2187                    ((isGCN14 && gcnInsn.encoding!=GCNENC_VOP3B) ?
2188                            PARSEVOP_WITHOPSEL : 0) | (vop3p ? PARSEVOP_VOP3P : 0), 3);
2189    if (!good || !checkGarbagesAtEnd(asmr, linePtr))
2190        return false;
2191   
2192    // apply VOP modifiers (abs,neg,sext) to operands from modifiers
2193    if (src0Op)
2194        src0Op.vopMods |= ((opMods.absMod&1) ? VOPOP_ABS : 0) |
2195                ((opMods.negMod&1) ? VOPOP_NEG : 0) |
2196                ((opMods.sextMod&1) ? VOPOP_SEXT : 0);
2197    if (src1Op)
2198        src1Op.vopMods |= ((opMods.absMod&2) ? VOPOP_ABS : 0) |
2199                ((opMods.negMod&2) ? VOPOP_NEG : 0) |
2200                ((opMods.sextMod&2) ? VOPOP_SEXT : 0);
2201    if (src2Op)
2202        src2Op.vopMods |= ((opMods.absMod&4) ? VOPOP_ABS : 0) |
2203                ((opMods.negMod&4) ? VOPOP_NEG : 0);
2204   
2205    if (mode2 != GCN_VOP3_VINTRP)
2206    {
2207        // count SGPR operands readed by instruction
2208        cxuint numSgprToRead = 0;
2209        //if (src0Op.range.start<108)
2210        if (src0Op.range.isSGPR())
2211            numSgprToRead++;
2212        //if (src1Op && src1Op.range.start<108 &&
2213        if (src1Op && src1Op.range.isSGPR() &&
2214                    !regRangeCanEqual(src0Op.range, src1Op.range))
2215            numSgprToRead++;
2216        //if (src2Op && src2Op.range.start<108 &&
2217        if (src2Op && src2Op.range.isSGPR())
2218        {
2219            if (!regRangeCanEqual(src0Op.range, src2Op.range) &&
2220                !regRangeCanEqual(src1Op.range, src2Op.range))
2221                numSgprToRead++;
2222        }
2223       
2224        if ((arch & ARCH_GCN_1_5)==0 && vccImplRead)
2225        {
2226            if (numSgprToRead >= 1)
2227                /* include VCCs (???) */
2228                ASM_FAIL_BY_ERROR(instrPlace, "No SGPR can be readed in vccImplRead")
2229        }
2230        else if ((arch & ARCH_GCN_1_5)==0 ||
2231            // except vccImplReads for NAVI
2232            vccImplRead)
2233        {
2234            if (numSgprToRead >= 2)
2235                /* include VCCs (???) */
2236                ASM_FAIL_BY_ERROR(instrPlace, "More than one SGPR to read in instruction")
2237        }
2238        else
2239        {   // NAVI
2240            if (numSgprToRead >= 3)
2241                /* include VCCs (???) */
2242                ASM_FAIL_BY_ERROR(instrPlace, "More than two SGPRs to read in instruction")
2243        }
2244    }
2245   
2246    if (src0OpExpr!=nullptr)
2247        src0OpExpr->setTarget(AsmExprTarget(GCNTGT_VOP3LITIMM, asmr.currentSection,
2248                      output.size()));
2249    if (src1OpExpr!=nullptr)
2250        src1OpExpr->setTarget(AsmExprTarget(GCNTGT_VOP3LITIMM, asmr.currentSection,
2251                      output.size()));
2252    if (src2OpExpr!=nullptr)
2253        src2OpExpr->setTarget(AsmExprTarget(GCNTGT_VOP3LITIMM, asmr.currentSection,
2254                      output.size()));
2255   
2256    // put data (instruction words)
2257    uint32_t words[3];
2258    cxuint wordsNum = 2;
2259    const uint32_t encoding = (arch & ARCH_GCN_1_5)!=0 ?
2260            (gcnInsn.encoding==GCNENC_VOP3P ? 0xcc000000U : 0xd4000000U) : 0xd0000000U;
2261    if (gcnInsn.encoding == GCNENC_VOP3B)
2262    {
2263        // VOP3B encoding
2264        if (!isGCN12)
2265            SLEV(words[0], encoding | (uint32_t(gcnInsn.code1)<<17) |
2266                (dstReg.bstart()&0xff) | (uint32_t(sdstReg.bstart())<<8));
2267        else
2268            SLEV(words[0], encoding | (uint32_t(gcnInsn.code1)<<16) |
2269                (dstReg.bstart()&0xff) | (uint32_t(sdstReg.bstart())<<8) |
2270                ((modifiers&VOP3_CLAMP) ? 0x8000 : 0));
2271    }
2272    else
2273    {
2274        // VOP3A
2275        if (!isGCN12)
2276            SLEV(words[0], encoding | (uint32_t(gcnInsn.code1)<<17) |
2277                (dstReg.bstart()&0xff) | ((modifiers&VOP3_CLAMP) ? 0x800: 0) |
2278                ((src0Op.vopMods & VOPOP_ABS) ? 0x100 : 0) |
2279                ((src1Op.vopMods & VOPOP_ABS) ? 0x200 : 0) |
2280                ((src2Op.vopMods & VOPOP_ABS) ? 0x400 : 0));
2281        else if (mode2 != GCN_VOP3_VINTRP || mode1 == GCN_NEW_OPCODE ||
2282            (gcnInsn.mode & GCN_VOP3_MASK3) == GCN_VINTRP_SRC2 ||
2283            (modifiers & VOP3_VOP3)!=0 || (src0Op.range.bstart()&0x100)!=0/* high */ ||
2284            (modifiers & (VOP3_CLAMP|3)) != 0 || opMods.opselMod != 0 ||
2285            src1Op.vopMods!=0 || src2Op.vopMods!=0)
2286            // new VOP3 for GCN 1.2
2287            SLEV(words[0], encoding | (uint32_t(gcnInsn.code1)<<16) |
2288                (dstReg.bstart()&0xff) | ((modifiers&VOP3_CLAMP) ? 0x8000: 0) |
2289                (vop3p ? (uint32_t(opMods.negMod>>4) << 8) /* VOP3P NEG_HI */ :
2290                    ((src0Op.vopMods & VOPOP_ABS) ? 0x100 : 0) |
2291                    ((src1Op.vopMods & VOPOP_ABS) ? 0x200 : 0) |
2292                    ((src2Op.vopMods & VOPOP_ABS) ? 0x400 : 0)) |
2293                (((opMods.opselMod & 64) !=0) ? 0x4000 : 0) |
2294                ((opMods.opselMod&15) << 11));
2295        else // VINTRP
2296        {
2297            const uint32_t encoding2 = (arch & ARCH_GCN_1_5)!=0 ?
2298                                    0xc9000000U : 0xd4000000U;
2299            SLEV(words[0], encoding2 | (src1Op.range.bstart()&0xff) |
2300                (uint32_t(src0Op.range.bstart()>>6)<<8) |
2301                (uint32_t(src0Op.range.bstart()&63)<<10) |
2302                (uint32_t(gcnInsn.code2)<<16) | (uint32_t(dstReg.bstart()&0xff)<<18));
2303            // VOP3 VINTRP have only one word instruction
2304            wordsNum--;
2305        }
2306    }
2307    if (wordsNum==2)
2308    {
2309        // second instruction's word
2310        SLEV(words[1], src0Op.range.bstart() | (uint32_t(src1Op.range.bstart())<<9) |
2311                (uint32_t(src2Op.range.bstart())<<18) |
2312                (vop3p ? ((uint32_t(opMods.opselMod>>4)&3)<<27) :
2313                 (uint32_t(modifiers & 3) << 27)) |
2314                /* in VOP3P is also NEG_LO */
2315                ((src0Op.vopMods & VOPOP_NEG) ? (1U<<29) : 0) |
2316                ((src1Op.vopMods & VOPOP_NEG) ? (1U<<30) : 0) |
2317                ((src2Op.vopMods & VOPOP_NEG) ? (1U<<31) : 0));
2318        if (src0Op.range.isVal(255)) // we check for immediate/literal value
2319            SLEV(words[wordsNum++], src0Op.value);
2320        else if (src1Op.range.isVal(255))
2321            // literal from SRC1
2322            SLEV(words[wordsNum++], src1Op.value);
2323        else if (src2Op.range.isVal(255))
2324            // literal from SRC2
2325            SLEV(words[wordsNum++], src2Op.value);
2326    }
2327   
2328    if (!checkGCNEncodingSize(asmr, instrPlace, gcnEncSize, wordsNum))
2329        return false;
2330    output.insert(output.end(), reinterpret_cast<cxbyte*>(words),
2331            reinterpret_cast<cxbyte*>(words + wordsNum));
2332    /// prevent freeing expression
2333    src0OpExpr.release();
2334    src1OpExpr.release();
2335    src2OpExpr.release();
2336   
2337    // update register pool (VGPR and SGPR counting)
2338    if (dstReg && !dstReg.isRegVar())
2339    {
2340        if (dstReg.start>=256)
2341            updateVGPRsNum(gcnRegs.vgprsNum, dstReg.end-257);
2342        else // sgprs
2343        {
2344            updateSGPRsNum(gcnRegs.sgprsNum, dstReg.end-1, arch);
2345            updateRegFlags(gcnRegs.regFlags, dstReg.start, arch);
2346        }
2347    }
2348    if (sdstReg && !sdstReg.isRegVar())
2349    {
2350        updateSGPRsNum(gcnRegs.sgprsNum, sdstReg.end-1, arch);
2351        updateRegFlags(gcnRegs.regFlags, sdstReg.start, arch);
2352    }
2353    if (mode2 != GCN_VOP3_VINTRP)
2354    {
2355        // count for SSRC0 and SSRC1 for VOP3A/B encoding (not VINTRP) ???
2356        if (src0Op.range && !src0Op.range.isRegVar() && src0Op.range.start < 256)
2357            updateRegFlags(gcnRegs.regFlags, src0Op.range.start, arch);
2358        if (src1Op.range && !src1Op.range.isRegVar() && src1Op.range.start < 256)
2359            updateRegFlags(gcnRegs.regFlags, src1Op.range.start, arch);
2360    }
2361    if (src2Op.range && !src2Op.range.isRegVar() && src2Op.range.start < 256)
2362        updateRegFlags(gcnRegs.regFlags, src2Op.range.start, arch);
2363    return true;
2364}
2365
2366bool GCNAsmUtils::parseVINTRPEncoding(Assembler& asmr, const GCNAsmInstruction& gcnInsn,
2367                  const char* instrPlace, const char* linePtr, GPUArchMask arch,
2368                  std::vector<cxbyte>& output, GCNAssembler::Regs& gcnRegs,
2369                  GCNEncSize gcnEncSize, GCNVOPEnc gcnVOPEnc)
2370{
2371    bool good = true;
2372    RegRange dstReg(0, 0);
2373    RegRange srcReg(0, 0);
2374    if (gcnEncSize==GCNEncSize::BIT64)
2375        ASM_FAIL_BY_ERROR(instrPlace, "Only 32-bit size for VINTRP encoding")
2376    if (gcnVOPEnc!=GCNVOPEnc::NORMAL)
2377        ASM_FAIL_BY_ERROR(instrPlace, "DPP and SDWA encoding is illegal for VOP3")
2378   
2379    GCNAssembler* gcnAsm = static_cast<GCNAssembler*>(asmr.isaAssembler);
2380   
2381    // parse DST (VGPR)
2382    gcnAsm->setCurrentRVU(0);
2383    good &= parseVRegRange(asmr, linePtr, dstReg, 1, GCNFIELD_VINTRP_VDST, true,
2384                        INSTROP_SYMREGRANGE|INSTROP_WRITE);
2385    if (!skipRequiredComma(asmr, linePtr))
2386        return false;
2387   
2388    if ((gcnInsn.mode & GCN_MASK1) == GCN_P0_P10_P20)
2389        good &= parseVINTRP0P10P20(asmr, linePtr, srcReg);
2390    else
2391    {
2392        // regular vector register
2393        gcnAsm->setCurrentRVU(1);
2394        good &= parseVRegRange(asmr, linePtr, srcReg, 1, GCNFIELD_VINTRP_VSRC0, true,
2395                        INSTROP_SYMREGRANGE|INSTROP_READ);
2396    }
2397   
2398    if (!skipRequiredComma(asmr, linePtr))
2399        return false;
2400   
2401    cxbyte attrVal;
2402    good &= parseVINTRPAttr(asmr, linePtr, attrVal);
2403   
2404    if (!good || !checkGarbagesAtEnd(asmr, linePtr))
2405        return false;
2406    /* put data (instruction word */
2407    uint32_t word;
2408    SLEV(word, 0xc8000000U | (srcReg.bstart()&0xff) | (uint32_t(attrVal&0xff)<<8) |
2409            (uint32_t(gcnInsn.code1)<<16) | (uint32_t(dstReg.bstart()&0xff)<<18));
2410    output.insert(output.end(), reinterpret_cast<cxbyte*>(&word),
2411            reinterpret_cast<cxbyte*>(&word)+4);
2412    // update register pool (VGPR counting)
2413    if (!dstReg.isRegVar())
2414        updateVGPRsNum(gcnRegs.vgprsNum, dstReg.end-257);
2415    return true;
2416}
2417
2418bool GCNAsmUtils::parseDSEncoding(Assembler& asmr, const GCNAsmInstruction& gcnInsn,
2419                  const char* instrPlace, const char* linePtr, GPUArchMask arch,
2420                  std::vector<cxbyte>& output, GCNAssembler::Regs& gcnRegs,
2421                  GCNEncSize gcnEncSize)
2422{
2423    const char* end = asmr.line+asmr.lineSize;
2424    bool good = true;
2425    if (gcnEncSize==GCNEncSize::BIT32)
2426        ASM_FAIL_BY_ERROR(instrPlace, "Only 64-bit size for DS encoding")
2427    RegRange dstReg(0, 0);
2428    RegRange addrReg(0, 0);
2429    RegRange data0Reg(0, 0), data1Reg(0, 0);
2430   
2431    bool beforeData = false;
2432    bool vdstUsed = false;
2433    cxuint delayRVU = UINT_MAX;
2434    cxuint destDelayRVU = UINT_MAX;
2435    bool secondDelay = false;
2436   
2437    GCNAssembler* gcnAsm = static_cast<GCNAssembler*>(asmr.isaAssembler);
2438   
2439    if (((gcnInsn.mode & GCN_ADDR_SRC) != 0 || (gcnInsn.mode & GCN_ONLYDST) != 0) &&
2440            (gcnInsn.mode & GCN_ONLY_SRC) == 0)
2441    {
2442        /* vdst is dst */
2443        cxuint regsNum = (gcnInsn.mode&GCN_REG_DST_64)?2:1;
2444        if ((gcnInsn.mode&GCN_DS_96) != 0)
2445            regsNum = 3;
2446        if ((gcnInsn.mode&GCN_DS_128) != 0 || (gcnInsn.mode&GCN_DST128) != 0)
2447            regsNum = 4;
2448        gcnAsm->setCurrentRVU(0);
2449        good &= parseVRegRange(asmr, linePtr, dstReg, regsNum, GCNFIELD_DS_VDST, true,
2450                    INSTROP_SYMREGRANGE|INSTROP_WRITE);
2451        vdstUsed = beforeData = true;
2452        destDelayRVU = 0;
2453    }
2454   
2455    if ((gcnInsn.mode & GCN_ONLYDST) == 0 && (gcnInsn.mode & GCN_ONLY_SRC) == 0)
2456    {
2457        // parse ADDR as first (VGPR)
2458        if (vdstUsed)
2459            if (!skipRequiredComma(asmr, linePtr))
2460                return false;
2461        gcnAsm->setCurrentRVU(1);
2462        good &= parseVRegRange(asmr, linePtr, addrReg, 1, GCNFIELD_DS_ADDR, true,
2463                    INSTROP_SYMREGRANGE|INSTROP_READ);
2464        beforeData = true;
2465    }
2466   
2467    const uint16_t srcMode = (gcnInsn.mode & GCN_SRCS_MASK);
2468   
2469    if ((gcnInsn.mode & GCN_ONLYDST) == 0 &&
2470        (gcnInsn.mode & (GCN_ADDR_DST|GCN_ADDR_SRC)) != 0 && srcMode != GCN_NOSRC)
2471    {
2472        /* two vdata */
2473        if (beforeData)
2474            if (!skipRequiredComma(asmr, linePtr))
2475                return false;
2476       
2477        cxuint regsNum = (gcnInsn.mode&GCN_REG_SRC0_64)?2:1;
2478        if ((gcnInsn.mode&GCN_DS_96) != 0)
2479            regsNum = 3;
2480        if ((gcnInsn.mode&GCN_DS_128) != 0)
2481            regsNum = 4;
2482        // parse VDATA0 (VGPR)
2483        gcnAsm->setCurrentRVU(2);
2484        good &= parseVRegRange(asmr, linePtr, data0Reg, regsNum, GCNFIELD_DS_DATA0, true,
2485                    INSTROP_SYMREGRANGE|INSTROP_READ);
2486        if (srcMode == GCN_2SRCS)
2487        {
2488            // instruction have second source
2489            if (!skipRequiredComma(asmr, linePtr))
2490                return false;
2491            // parse VDATA0 (VGPR)
2492            gcnAsm->setCurrentRVU(3);
2493            good &= parseVRegRange(asmr, linePtr, data1Reg,
2494                       (gcnInsn.mode&GCN_REG_SRC1_64)?2:1, GCNFIELD_DS_DATA1, true,
2495                               INSTROP_SYMREGRANGE|INSTROP_READ);
2496            secondDelay = true;
2497        }
2498        delayRVU = 2;
2499    }
2500   
2501    bool haveGds = false;
2502    std::unique_ptr<AsmExpression> offsetExpr, offset2Expr;
2503    char name[10];
2504    uint16_t offset = 0;
2505    cxbyte offset1 = 0, offset2 = 0;
2506    bool haveOffset = false, haveOffset2 = false;
2507    // parse DS modifiers
2508    while (linePtr!=end)
2509    {
2510        skipSpacesToEnd(linePtr, end);
2511        if (linePtr==end)
2512            break;
2513        const char* modPlace = linePtr;
2514        if (!getNameArgS(asmr, 10, name, linePtr, "DS modifier"))
2515        {
2516            good = false;
2517            continue;
2518        }
2519        toLowerString(name);
2520        if (::strcmp(name, "gds")==0)
2521            good &= parseModEnable(asmr, linePtr, haveGds, "gds modifier");
2522        else if ((gcnInsn.mode & GCN_2OFFSETS) == 0) /* single offset */
2523        {
2524            // single offset
2525            if (::strcmp(name, "offset") == 0)
2526            {
2527                if (parseModImm(asmr, linePtr, offset, &offsetExpr, "offset",
2528                            0, WS_UNSIGNED))
2529                {
2530                    // detect multiple occurrences
2531                    if (haveOffset)
2532                        asmr.printWarning(modPlace, "Offset is already defined");
2533                    haveOffset = true;
2534                }
2535                else
2536                    good = false;
2537            }
2538            else
2539                ASM_NOTGOOD_BY_ERROR(modPlace, "Expected 'offset'")
2540        }
2541        else
2542        {
2543            // two offsets (offset0, offset1)
2544            if (::memcmp(name, "offset", 6)==0 &&
2545                (name[6]=='0' || name[6]=='1') && name[7]==0)
2546            {
2547                skipSpacesToEnd(linePtr, end);
2548                if (linePtr!=end && *linePtr==':')
2549                {
2550                    skipCharAndSpacesToEnd(linePtr, end);
2551                    if (name[6]=='0')
2552                    {
2553                        /* offset0 */
2554                        if (parseImm(asmr, linePtr, offset1, &offsetExpr, 0, WS_UNSIGNED))
2555                        {
2556                            // detect multiple occurrences
2557                            if (haveOffset)
2558                                asmr.printWarning(modPlace, "Offset0 is already defined");
2559                            haveOffset = true;
2560                        }
2561                        else
2562                            good = false;
2563                    }
2564                    else
2565                    {
2566                        /* offset1 */
2567                        if (parseImm(asmr, linePtr, offset2, &offset2Expr, 0, WS_UNSIGNED))
2568                        {
2569                            // detect multiple occurrences
2570                            if (haveOffset2)
2571                                asmr.printWarning(modPlace, "Offset1 is already defined");
2572                            haveOffset2 = true;
2573                        }
2574                        else
2575                            good = false;
2576                    }
2577                }
2578                else
2579                    ASM_NOTGOOD_BY_ERROR(linePtr, "Expected ':' before offset")
2580            }
2581            else
2582                ASM_NOTGOOD_BY_ERROR(modPlace,
2583                                "Expected 'offset', 'offset0' or 'offset1'")
2584        }
2585    }
2586   
2587    if ((gcnInsn.mode & GCN_2OFFSETS) != 0)
2588        offset = offset1 | (offset2<<8);
2589   
2590    if (!good || !checkGarbagesAtEnd(asmr, linePtr))
2591        return false;
2592   
2593    // register Delayed results
2594    if (destDelayRVU != UINT_MAX)
2595        gcnAsm->delayedOps[0] = { output.size(), gcnAsm->instrRVUs[destDelayRVU].regVar,
2596                    gcnAsm->instrRVUs[destDelayRVU].rstart,
2597                    gcnAsm->instrRVUs[destDelayRVU].rend,
2598                    1, haveGds ? GCNDELOP_GDSOP : GCNDELOP_LDSOP, GCNDELOP_NONE,
2599                    gcnAsm->instrRVUs[destDelayRVU].rwFlags };
2600   
2601    if (delayRVU != UINT_MAX)
2602    {
2603        gcnAsm->delayedOps[1] = { output.size(), gcnAsm->instrRVUs[delayRVU].regVar,
2604                    gcnAsm->instrRVUs[delayRVU].rstart, gcnAsm->instrRVUs[delayRVU].rend,
2605                    1, haveGds ? GCNDELOP_GDSOP : GCNDELOP_LDSOP,
2606                    haveGds ? GCNDELOP_EXPORT : GCNDELOP_NONE,
2607                    gcnAsm->instrRVUs[delayRVU].rwFlags,
2608                    cxbyte(haveGds ? ASMRVU_READ : 0) };
2609        if (secondDelay)
2610            gcnAsm->delayedOps[2] = { output.size(),
2611                    gcnAsm->instrRVUs[delayRVU+1].regVar,
2612                    gcnAsm->instrRVUs[delayRVU+1].rstart,
2613                    gcnAsm->instrRVUs[delayRVU+1].rend,
2614                    1, haveGds ? GCNDELOP_GDSOP : GCNDELOP_LDSOP,
2615                    haveGds ? GCNDELOP_EXPORT : GCNDELOP_NONE,
2616                    gcnAsm->instrRVUs[delayRVU+1].rwFlags,
2617                    cxbyte(haveGds ? ASMRVU_READ : 0) };
2618    }
2619    if ((gcnInsn.mode & GCN_SRC_ADDR2) != 0)
2620        // register for DS_*_SRC2_* instructions
2621        gcnAsm->delayedOps[0] = { output.size(), nullptr, uint16_t(0), uint16_t(0),
2622                1, haveGds ? GCNDELOP_GDSOP : GCNDELOP_LDSOP,
2623                haveGds ? GCNDELOP_EXPORT : GCNDELOP_NONE, cxbyte(0) };
2624   
2625    if ((gcnInsn.mode&GCN_ONLYGDS) != 0 && !haveGds)
2626        ASM_FAIL_BY_ERROR(instrPlace, "Instruction requires GDS modifier")
2627   
2628    // set target expressions for offsets (if needed)
2629    if (offsetExpr!=nullptr)
2630        offsetExpr->setTarget(AsmExprTarget((gcnInsn.mode & GCN_2OFFSETS) ?
2631                    GCNTGT_DSOFFSET8_0 : GCNTGT_DSOFFSET16, asmr.currentSection,
2632                    output.size()));
2633    if (offset2Expr!=nullptr)
2634        offset2Expr->setTarget(AsmExprTarget(GCNTGT_DSOFFSET8_1, asmr.currentSection,
2635                    output.size()));
2636    // put data (two instruction words)
2637    uint32_t words[2];
2638    if ((arch & ARCH_GCN_1_2_4)==0)
2639        SLEV(words[0], 0xd8000000U | uint32_t(offset) | (haveGds ? 0x20000U : 0U) |
2640                (uint32_t(gcnInsn.code1)<<18));
2641    else
2642        SLEV(words[0], 0xd8000000U | uint32_t(offset) | (haveGds ? 0x10000U : 0U) |
2643                (uint32_t(gcnInsn.code1)<<17));
2644    SLEV(words[1], (addrReg.bstart()&0xff) | (uint32_t(data0Reg.bstart()&0xff)<<8) |
2645            (uint32_t(data1Reg.bstart()&0xff)<<16) | (uint32_t(dstReg.bstart()&0xff)<<24));
2646    output.insert(output.end(), reinterpret_cast<cxbyte*>(words),
2647            reinterpret_cast<cxbyte*>(words + 2));
2648   
2649    offsetExpr.release();
2650    offset2Expr.release();
2651    // update register pool (VGPR counting)
2652    if (dstReg && !dstReg.isRegVar())
2653        updateVGPRsNum(gcnRegs.vgprsNum, dstReg.end-257);
2654    return true;
2655}
2656
2657};
Note: See TracBrowser for help on using the repository browser.