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

Last change on this file since 4967 was 4967, checked in by matszpk, 13 months ago

CLRadeonExtender: Asm: Replace wave32 by codeFlags.

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