source: CLRX/CLRadeonExtender/trunk/tests/amdasm/AsmRegAlloc3.cpp @ 4042

Last change on this file since 4042 was 4042, checked in by matszpk, 4 months ago

CLRadeonExtender: AsmRegAlloc?: Fixed segfaults if regular register used in destination (liveness and ssaIdIndex was not allocated in this case).
Add new testcase (single liveness with many regions).

File size: 16.6 KB
Line 
1/*
2 *  CLRadeonExtender - Unofficial OpenCL Radeon Extensions Library
3 *  Copyright (C) 2014-2018 Mateusz Szpakowski
4 *
5 *  This library is free software; you can redistribute it and/or
6 *  modify it under the terms of the GNU Lesser General Public
7 *  License as published by the Free Software Foundation; either
8 *  version 2.1 of the License, or (at your option) any later version.
9 *
10 *  This library is distributed in the hope that it will be useful,
11 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 *  Lesser General Public License for more details.
14 *
15 *  You should have received a copy of the GNU Lesser General Public
16 *  License along with this library; if not, write to the Free Software
17 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
18 */
19
20#include <CLRX/Config.h>
21#include <algorithm>
22#include <iostream>
23#include <sstream>
24#include <string>
25#include <vector>
26#include <cstring>
27#include <CLRX/utils/Utilities.h>
28#include <CLRX/amdasm/Assembler.h>
29#include <CLRX/utils/Containers.h>
30#include "../TestUtils.h"
31#include "AsmRegAlloc.h"
32
33using namespace CLRX;
34
35typedef AsmRegAllocator::OutLiveness OutLiveness;
36typedef AsmRegAllocator::LinearDep LinearDep;
37typedef AsmRegAllocator::VarIndexMap VarIndexMap;
38
39struct LinearDep2
40{
41    cxbyte align;
42    Array<size_t> prevVidxes;
43    Array<size_t> nextVidxes;
44};
45
46struct AsmLivenessesCase
47{
48    const char* input;
49    Array<OutLiveness> livenesses[MAX_REGTYPES_NUM];
50    Array<std::pair<size_t, LinearDep2> > linearDepMaps[MAX_REGTYPES_NUM];
51    bool good;
52    const char* errorMessages;
53};
54
55static const AsmLivenessesCase createLivenessesCasesTbl[] =
56{
57#if 0
58    {   // 0 - simple case
59        R"ffDXD(.regvar sa:s:8, va:v:10
60        s_mov_b32 sa[4], sa[2]  # 0
61        s_add_u32 sa[4], sa[4], s3
62        v_xor_b32 va[4], va[2], v3
63)ffDXD",
64        {   // livenesses
65            {   // for SGPRs
66                { { 0, 5 } }, // S3
67                { { 0, 1 } }, // sa[2]'0
68                { { 1, 5 } }, // sa[4]'0
69                { { 5, 6 } }  // sa[4]'1
70            },
71            {   // for VGPRs
72                { { 0, 9 } }, // V3
73                { { 0, 9 } }, // va[2]'0
74                { { 9, 10 } } // va[4]'0 : out of range code block
75            },
76            { },
77            { }
78        },
79        { },  // linearDepMaps
80        true, ""
81    },
82    {   // 1 - simple case 2
83        R"ffDXD(.regvar sa:s:8, va:v:10
84        s_mov_b32 sa[4], sa[2]  # 0
85        s_add_u32 sa[4], sa[4], s3
86        v_xor_b32 va[4], va[2], v3
87        s_endpgm
88)ffDXD",
89        {   // livenesses
90            {   // for SGPRs
91                { { 0, 5 } }, // S3
92                { { 0, 1 } }, // sa[2]'0
93                { { 1, 5 } }, // sa[4]'0
94                { { 5, 6 } }  // sa[4]'1
95            },
96            {   // for VGPRs
97                { { 0, 9 } }, // V3
98                { { 0, 9 } }, // va[2]'0
99                { { 9, 10 } } // va[4]'0 : out of range code block
100            },
101            { },
102            { }
103        },
104        { },  // linearDepMaps
105        true, ""
106    },
107    {   // 2 - simple case (linear dep)
108        R"ffDXD(.regvar sa:s:8, va:v:10
109        .regvar sbuf:s:4, rbx4:v:6
110        s_mov_b64 sa[4:5], sa[2:3]  # 0
111        s_and_b64 sa[4:5], sa[4:5], s[4:5]
112        v_add_f64 va[4:5], va[2:3], v[3:4]
113        buffer_load_dwordx4 rbx4[1:5], va[6], sbuf[0:3], sa[7] idxen offset:603 tfe
114)ffDXD",
115        {   // livenesses
116            {   // for SGPRs
117                { { 0, 5 } }, // S4
118                { { 0, 5 } }, // S5
119                { { 0, 1 } }, // sa[2]'0
120                { { 0, 1 } }, // sa[3]'0
121                { { 1, 5 } }, // sa[4]'0
122                { { 5, 6 } }, // sa[4]'1
123                { { 1, 5 } }, // sa[5]'0
124                { { 5, 6 } }, // sa[5]'1
125                { { 0, 17 } }, // sa[7]'0
126                { { 0, 17 } }, // sbuf[0]'0
127                { { 0, 17 } }, // sbuf[1]'0
128                { { 0, 17 } }, // sbuf[2]'0
129                { { 0, 17 } }, // sbuf[3]'0
130            },
131            {   // for VGPRs
132                { { 0, 9 } }, // V3
133                { { 0, 9 } }, // V4
134                { { 17, 18 } }, // rbx4[1]'0
135                { { 17, 18 } }, // rbx4[2]'0
136                { { 17, 18 } }, // rbx4[3]'0
137                { { 17, 18 } }, // rbx4[4]'0
138                { { 0, 17 } }, // rbx4[5]'0: tfe - read before write
139                { { 0, 9 } }, // va[2]'0
140                { { 0, 9 } }, // va[3]'0
141                { { 9, 10 } }, // va[4]'0 : out of range code block
142                { { 9, 10 } }, // va[5]'0 : out of range code block
143                { { 0, 17 } } // va[6]'0
144            },
145            { },
146            { }
147        },
148        {   // linearDepMaps
149            {   // for SGPRs
150                { 0, { 0, { }, { 1 } } },  // S4
151                { 1, { 0, { 0 }, { } } },  // S5
152                { 2, { 2, { }, { 3 } } },  // sa[2]'0
153                { 3, { 0, { 2 }, { } } },  // sa[3]'0
154                { 4, { 2, { }, { 6 } } },  // sa[4]'0
155                { 5, { 2, { }, { 7, 7 } } },  // sa[4]'1
156                { 6, { 0, { 4 }, { } } },  // sa[5]'0
157                { 7, { 0, { 5, 5 }, { } } },   // sa[5]'1
158                { 9, { 4, { }, { 10 } } }, // sbuf[0]'0
159                { 10, { 0, { 9 }, { 11 } } }, // sbuf[1]'0
160                { 11, { 0, { 10 }, { 12 } } }, // sbuf[2]'0
161                { 12, { 0, { 11 }, { } } }  // sbuf[3]'0
162            },
163            {   // for VGPRs
164                { 0, { 0, { }, { 1 } } },  // V3
165                { 1, { 0, { 0 }, { } } },  // V4
166                { 2, { 1, { }, { 3 } } }, // rbx4[1]'0
167                { 3, { 0, { 2 }, { 4 } } }, // rbx4[2]'0
168                { 4, { 0, { 3 }, { 5 } } }, // rbx4[3]'0
169                { 5, { 0, { 4 }, { 6 } } }, // rbx4[4]'0
170                { 6, { 0, { 5 }, { } } }, // rbx4[5]'0
171                { 7, { 1, { }, { 8 } } },  // va[2]'0
172                { 8, { 0, { 7 }, { } } },  // va[3]'0
173                { 9, { 1, { }, { 10 } } },  // va[4]'0
174                { 10, { 0, { 9 }, { } } }  // va[5]'0
175            },
176            { },
177            { }
178        },
179        true, ""
180    },
181    {   // 3 - next simple case
182        R"ffDXD(.regvar sa:s:8, va:v:10
183        s_mov_b32 sa[4], sa[2]  # 0
184        s_add_u32 sa[4], sa[4], s3
185        v_xor_b32 va[4], va[2], v3
186        v_mov_b32 va[3], 1.45s
187        v_mov_b32 va[6], -7.45s
188        v_lshlrev_b32 va[5], sa[4], va[4]
189        v_mac_f32 va[3], va[6], v0
190        s_mul_i32 sa[7], sa[2], sa[3]
191        v_mac_f32 va[3], va[7], v0
192        s_endpgm
193)ffDXD",
194        {   // livenesses
195            {   // for SGPRs
196                { { 0, 5 } }, // 0: S3
197                { { 0, 37 } }, // 1: sa[2]'0
198                { { 0, 37 } }, // 2: sa[3]'0
199                { { 1, 5 } }, // 3: sa[4]'0
200                { { 5, 29 } }, // 4: sa[4]'1
201                { { 37, 38 } }  // 5: sa[7]'0
202            },
203            {   // for VGPRs
204                { { 0, 41 } }, // 0: v0
205                { { 0, 9 } }, // 1: v3
206                { { 0, 9 } }, // 2: va[2]'0
207                { { 13, 41 } }, // 3: va[3]'0
208                { { 9, 29 } }, // 4: va[4]'0
209                { { 29, 30 } }, // 5: va[5]'0
210                { { 21, 33 } }, // 6: va[6]'0
211                { { 0, 41 } }  // 7: va[7]'0
212            },
213            { },
214            { }
215        },
216        { }, // linearDepMaps
217        true, ""
218    },
219#endif
220    {   // 4 - next test case
221        R"ffDXD(.regvar sa:s:8, va:v:10
222        s_mov_b32 sa[4], sa[2]  # 0
223        s_add_u32 sa[4], sa[4], s3  # 4
224       
225        v_xor_b32 v4, va[2], v3         # 8
226        v_xor_b32 va[5], v4, va[5]      # 12
227       
228        s_sub_u32 sa[4], sa[4], sa[3]   # 16
229       
230        v_xor_b32 v4, va[5], v3         # 20
231        v_xor_b32 va[6], v4, va[6]      # 24
232       
233        s_mul_i32 sa[4], sa[4], sa[1]   # 28
234        s_mul_i32 sa[4], sa[4], sa[0]   # 32
235       
236        v_xor_b32 v4, va[6], v3         # 36
237        v_xor_b32 va[7], v4, va[7]      # 40
238)ffDXD",
239        {   // livenesses
240            {   // for SGPRs
241                { { 0, 5 } },   // 0: S3
242                { { 0, 33 } },  // 1: sa[0]'0
243                { { 0, 29 } },  // 2: sa[1]'0
244                { { 0, 1 } },   // 3: sa[2]'0
245                { { 0, 17 } },  // 4: sa[3]'0
246                { { 1, 5 } },   // 5: sa[4]'0
247                { { 5, 17 } },  // 6: sa[4]'1
248                { { 17, 29 } }, // 7: sa[4]'2
249                { { 29, 33 } }, // 8: sa[4]'3
250                { { 33, 34 } }  // 9: sa[4]'4
251            },
252            {   // for VGPRs
253                { { 0, 37 } },   // 0: v3
254                { { 9, 13 }, { 21, 25 }, { 37, 41 } }, // 1: v4
255                { { 0, 9 } },    // 2: va[2]'0
256                { { 0, 13 } },   // 3: va[5]'0
257                { { 13, 21 } },  // 4: va[5]'1
258                { { 0, 25 } },   // 5: va[6]'0
259                { { 25, 37 } },  // 6: va[6]'1
260                { { 0, 41 } },   // 7: va[7]'0
261                { { 41, 42 } }   // 8: va[7]'1
262            },
263            { },
264            { }
265        },
266        { }, // linearDepMaps
267        true, ""
268    }
269};
270
271static TestSingleVReg getTestSingleVReg(const AsmSingleVReg& vr,
272        const std::unordered_map<const AsmRegVar*, CString>& rvMap)
273{
274    if (vr.regVar == nullptr)
275        return { "", vr.index };
276   
277    auto it = rvMap.find(vr.regVar);
278    if (it == rvMap.end())
279        throw Exception("getTestSingleVReg: RegVar not found!!");
280    return { it->second, vr.index };
281}
282
283static void testCreateLivenessesCase(cxuint i, const AsmLivenessesCase& testCase)
284{
285    std::istringstream input(testCase.input);
286    std::ostringstream errorStream;
287   
288    Assembler assembler("test.s", input,
289                    (ASM_ALL&~ASM_ALTMACRO) | ASM_TESTRUN | ASM_TESTRESOLVE,
290                    BinaryFormat::RAWCODE, GPUDeviceType::CAPE_VERDE, errorStream);
291    bool good = assembler.assemble();
292    if (assembler.getSections().size()<1)
293    {
294        std::ostringstream oss;
295        oss << "FAILED for " << " testAsmLivenesses#" << i;
296        throw Exception(oss.str());
297    }
298    const AsmSection& section = assembler.getSections()[0];
299   
300    AsmRegAllocator regAlloc(assembler);
301   
302    regAlloc.createCodeStructure(section.codeFlow, section.getSize(),
303                            section.content.data());
304    regAlloc.createSSAData(*section.usageHandler);
305    regAlloc.applySSAReplaces();
306    regAlloc.createLivenesses(*section.usageHandler);
307   
308    std::ostringstream oss;
309    oss << " testAsmLivenesses case#" << i;
310    const std::string testCaseName = oss.str();
311   
312    assertValue<bool>("testAsmLivenesses", testCaseName+".good",
313                      testCase.good, good);
314    assertString("testAsmLivenesses", testCaseName+".errorMessages",
315              testCase.errorMessages, errorStream.str());
316   
317    std::unordered_map<const AsmRegVar*, CString> regVarNamesMap;
318    for (const auto& rvEntry: assembler.getRegVarMap())
319        regVarNamesMap.insert(std::make_pair(&rvEntry.second, rvEntry.first));
320   
321    // generate livenesses indices conversion table
322    const VarIndexMap* vregIndexMaps = regAlloc.getVregIndexMaps();
323   
324    std::vector<size_t> lvIndexCvtTables[MAX_REGTYPES_NUM];
325    std::vector<size_t> revLvIndexCvtTables[MAX_REGTYPES_NUM];
326    for (size_t r = 0; r < MAX_REGTYPES_NUM; r++)
327    {
328        const VarIndexMap& vregIndexMap = vregIndexMaps[r];
329        Array<std::pair<TestSingleVReg, const std::vector<size_t>*> > outVregIdxMap(
330                    vregIndexMap.size());
331       
332        size_t j = 0;
333        for (const auto& entry: vregIndexMap)
334        {
335            TestSingleVReg vreg = getTestSingleVReg(entry.first, regVarNamesMap);
336            outVregIdxMap[j++] = std::make_pair(vreg, &entry.second);
337        }
338        mapSort(outVregIdxMap.begin(), outVregIdxMap.end());
339       
340        std::vector<size_t>& lvIndexCvtTable = lvIndexCvtTables[r];
341        std::vector<size_t>& revLvIndexCvtTable = revLvIndexCvtTables[r];
342        // generate livenessCvt table
343        for (const auto& entry: outVregIdxMap)
344            for (size_t v: *entry.second)
345                if (v != SIZE_MAX)
346                {
347                    /*std::cout << "lvidx: " << v << ": " << entry.first.name << ":" <<
348                            entry.first.index << std::endl;*/
349                    size_t j = lvIndexCvtTable.size();
350                    lvIndexCvtTable.push_back(v);
351                    if (v+1 > revLvIndexCvtTable.size())
352                        revLvIndexCvtTable.resize(v+1);
353                    revLvIndexCvtTable[v] = j;
354                }
355    }
356   
357    const Array<OutLiveness>* resLivenesses = regAlloc.getOutLivenesses();
358    for (size_t r = 0; r < MAX_REGTYPES_NUM; r++)
359    {
360        std::ostringstream rOss;
361        rOss << "live.regtype#" << r;
362        rOss.flush();
363        std::string rtname(rOss.str());
364       
365        assertValue("testAsmLivenesses", testCaseName + rtname + ".size",
366                    testCase.livenesses[r].size(), resLivenesses[r].size());
367       
368        for (size_t li = 0; li < resLivenesses[r].size(); li++)
369        {
370            std::ostringstream lOss;
371            lOss << ".liveness#" << li;
372            lOss.flush();
373            std::string lvname(rtname + lOss.str());
374            const OutLiveness& expLv = testCase.livenesses[r][li];
375            const OutLiveness& resLv = resLivenesses[r][lvIndexCvtTables[r][li]];
376           
377            // checking liveness
378            assertValue("testAsmLivenesses", testCaseName + lvname + ".size",
379                    expLv.size(), resLv.size());
380            for (size_t k = 0; k < resLv.size(); k++)
381            {
382                std::ostringstream regOss;
383                regOss << ".reg#" << k;
384                regOss.flush();
385                std::string regname(lvname + regOss.str());
386                assertValue("testAsmLivenesses", testCaseName + regname + ".first",
387                    expLv[k].first, resLv[k].first);
388                assertValue("testAsmLivenesses", testCaseName + regname + ".second",
389                    expLv[k].second, resLv[k].second);
390            }
391        }
392    }
393   
394    const std::unordered_map<size_t, LinearDep>* resLinearDepMaps =
395                regAlloc.getLinearDepMaps();
396    for (size_t r = 0; r < MAX_REGTYPES_NUM; r++)
397    {
398        std::ostringstream rOss;
399        rOss << "lndep.regtype#" << r;
400        rOss.flush();
401        std::string rtname(rOss.str());
402       
403        assertValue("testAsmLivenesses", testCaseName + rtname + ".size",
404                    testCase.linearDepMaps[r].size(), resLinearDepMaps[r].size());
405       
406        for (size_t di = 0; di < testCase.linearDepMaps[r].size(); di++)
407        {
408            std::ostringstream lOss;
409            lOss << ".lndep#" << di;
410            lOss.flush();
411            std::string ldname(rtname + lOss.str());
412            const auto& expLinearDepEntry = testCase.linearDepMaps[r][di];
413            auto rlit = resLinearDepMaps[r].find(
414                            lvIndexCvtTables[r][expLinearDepEntry.first]);
415           
416            std::ostringstream vOss;
417            vOss << expLinearDepEntry.first;
418            vOss.flush();
419            assertTrue("testAsmLivenesses", testCaseName + ldname + ".key=" + vOss.str(),
420                        rlit != resLinearDepMaps[r].end());
421            const LinearDep2& expLinearDep = expLinearDepEntry.second;
422            const LinearDep& resLinearDep = rlit->second;
423           
424            assertValue("testAsmLivenesses", testCaseName + ldname + ".align",
425                        cxuint(expLinearDep.align), cxuint(resLinearDep.align));
426           
427            Array<size_t> resPrevVidxes(resLinearDep.prevVidxes.size());
428            // convert to res ssaIdIndices
429            for (size_t k = 0; k < resLinearDep.prevVidxes.size(); k++)
430                resPrevVidxes[k] = revLvIndexCvtTables[r][resLinearDep.prevVidxes[k]];
431           
432            assertArray("testAsmLivenesses", testCaseName + ldname + ".prevVidxes",
433                        expLinearDep.prevVidxes, resPrevVidxes);
434           
435            Array<size_t> resNextVidxes(resLinearDep.nextVidxes.size());
436            // convert to res ssaIdIndices
437            for (size_t k = 0; k < resLinearDep.nextVidxes.size(); k++)
438                resNextVidxes[k] = revLvIndexCvtTables[r][resLinearDep.nextVidxes[k]];
439           
440            assertArray("testAsmLivenesses", testCaseName + ldname + ".nextVidxes",
441                        expLinearDep.nextVidxes, resNextVidxes);
442        }
443    }
444}
445
446int main(int argc, const char** argv)
447{
448    int retVal = 0;
449    for (size_t i = 0; i < sizeof(createLivenessesCasesTbl)/sizeof(AsmLivenessesCase); i++)
450        try
451        { testCreateLivenessesCase(i, createLivenessesCasesTbl[i]); }
452        catch(const std::exception& ex)
453        {
454            std::cerr << ex.what() << std::endl;
455            retVal = 1;
456        }
457    return retVal;
458}
Note: See TracBrowser for help on using the repository browser.