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

Last change on this file since 4037 was 4037, checked in by matszpk, 8 months ago

CLRadeonExtender: AsmRegAlloc3: add new simple testcase.

File size: 15.1 KB
Line 
1/*
2 *  CLRadeonExtender - Unofficial OpenCL Radeon Extensions Library
3 *  Copyright (C) 2014-2018 Mateusz Szpakowski
4 *
5 *  This library is free software; you can redistribute it and/or
6 *  modify it under the terms of the GNU Lesser General Public
7 *  License as published by the Free Software Foundation; either
8 *  version 2.1 of the License, or (at your option) any later version.
9 *
10 *  This library is distributed in the hope that it will be useful,
11 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 *  Lesser General Public License for more details.
14 *
15 *  You should have received a copy of the GNU Lesser General Public
16 *  License along with this library; if not, write to the Free Software
17 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
18 */
19
20#include <CLRX/Config.h>
21#include <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, 0 } }, // sa[2]'0
68                { { 4, 5 } }, // sa[4]'0
69                { { 8, 9 } }  // sa[4]'1
70            },
71            {   // for VGPRs
72                { { 0, 9 } }, // V3
73                { { 0, 9 } }, // va[2]'0
74                { { SIZE_MAX-1, SIZE_MAX } } // 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, 0 } }, // sa[2]'0
93                { { 4, 5 } }, // sa[4]'0
94                { { 8, 9 } }  // sa[4]'1
95            },
96            {   // for VGPRs
97                { { 0, 9 } }, // V3
98                { { 0, 9 } }, // va[2]'0
99                { { 12, 13 } } // 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, 0 } }, // sa[2]'0
120                { { 0, 0 } }, // sa[3]'0
121                { { 4, 5 } }, // sa[4]'0
122                { { 8, 9 } }, // sa[4]'1
123                { { 4, 5 } }, // sa[5]'0
124                { { 8, 9 } }, // 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                { { SIZE_MAX-1, SIZE_MAX } }, // rbx4[1]'0
135                { { SIZE_MAX-1, SIZE_MAX } }, // rbx4[2]'0
136                { { SIZE_MAX-1, SIZE_MAX } }, // rbx4[3]'0
137                { { SIZE_MAX-1, SIZE_MAX } }, // 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                { { 16, 17 } }, // va[4]'0 : out of range code block
142                { { 16, 17 } }, // 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#endif
182    {   // 3 - next simple case
183        R"ffDXD(.regvar sa:s:8, va:v:10
184        s_mov_b32 sa[4], sa[2]  # 0
185        s_add_u32 sa[4], sa[4], s3
186        v_xor_b32 va[4], va[2], v3
187        v_mov_b32 va[3], 1.45s
188        v_mov_b32 va[6], -7.45s
189        v_lshlrev_b32 va[5], sa[4], va[4]
190        v_mac_f32 va[3], va[6], v0
191        s_mul_i32 sa[7], sa[2], sa[3]
192        v_mac_f32 va[3], va[7], v0
193        s_endpgm
194)ffDXD",
195        {   // livenesses
196            {   // for SGPRs
197                { { 0, 5 } }, // 0: S3
198                { { 0, 37 } }, // 1: sa[2]'0
199                { { 0, 37 } }, // 2: sa[3]'0
200                { { 4, 5 } }, // 3: sa[4]'0
201                { { 8, 29 } }, // 4: sa[4]'1
202                { { 40, 41 } }  // 5: sa[7]'0
203            },
204            {   // for VGPRs
205                { { 0, 41 } }, // 0: v0
206                { { 0, 9 } }, // 1: v3
207                { { 0, 9 } }, // 2: va[2]'0
208                { { 20, 41 } }, // 3: va[3]'0
209                { { 12, 29 } }, // 4: va[4]'0
210                { { 32, 33 } }, // 5: va[5]'0
211                { { 28, 33 } }, // 6: va[6]'0
212                { { 0, 41 } }  // 7: va[7]'0
213            },
214            { },
215            { }
216        },
217        {
218        },
219        true, ""
220    }
221};
222
223static TestSingleVReg getTestSingleVReg(const AsmSingleVReg& vr,
224        const std::unordered_map<const AsmRegVar*, CString>& rvMap)
225{
226    if (vr.regVar == nullptr)
227        return { "", vr.index };
228   
229    auto it = rvMap.find(vr.regVar);
230    if (it == rvMap.end())
231        throw Exception("getTestSingleVReg: RegVar not found!!");
232    return { it->second, vr.index };
233}
234
235static void testCreateLivenessesCase(cxuint i, const AsmLivenessesCase& testCase)
236{
237    std::istringstream input(testCase.input);
238    std::ostringstream errorStream;
239   
240    Assembler assembler("test.s", input,
241                    (ASM_ALL&~ASM_ALTMACRO) | ASM_TESTRUN | ASM_TESTRESOLVE,
242                    BinaryFormat::RAWCODE, GPUDeviceType::CAPE_VERDE, errorStream);
243    bool good = assembler.assemble();
244    if (assembler.getSections().size()<1)
245    {
246        std::ostringstream oss;
247        oss << "FAILED for " << " testAsmLivenesses#" << i;
248        throw Exception(oss.str());
249    }
250    const AsmSection& section = assembler.getSections()[0];
251   
252    AsmRegAllocator regAlloc(assembler);
253   
254    regAlloc.createCodeStructure(section.codeFlow, section.getSize(),
255                            section.content.data());
256    regAlloc.createSSAData(*section.usageHandler);
257    regAlloc.applySSAReplaces();
258    regAlloc.createLivenesses(*section.usageHandler, section.getSize(),
259                            section.content.data());
260   
261    std::ostringstream oss;
262    oss << " testAsmLivenesses case#" << i;
263    const std::string testCaseName = oss.str();
264   
265    assertValue<bool>("testAsmLivenesses", testCaseName+".good",
266                      testCase.good, good);
267    assertString("testAsmLivenesses", testCaseName+".errorMessages",
268              testCase.errorMessages, errorStream.str());
269   
270    std::unordered_map<const AsmRegVar*, CString> regVarNamesMap;
271    for (const auto& rvEntry: assembler.getRegVarMap())
272        regVarNamesMap.insert(std::make_pair(&rvEntry.second, rvEntry.first));
273   
274    // generate livenesses indices conversion table
275    const VarIndexMap* vregIndexMaps = regAlloc.getVregIndexMaps();
276   
277    std::vector<size_t> lvIndexCvtTables[MAX_REGTYPES_NUM];
278    std::vector<size_t> revLvIndexCvtTables[MAX_REGTYPES_NUM];
279    for (size_t r = 0; r < MAX_REGTYPES_NUM; r++)
280    {
281        const VarIndexMap& vregIndexMap = vregIndexMaps[r];
282        Array<std::pair<TestSingleVReg, const std::vector<size_t>*> > outVregIdxMap(
283                    vregIndexMap.size());
284       
285        size_t j = 0;
286        for (const auto& entry: vregIndexMap)
287        {
288            TestSingleVReg vreg = getTestSingleVReg(entry.first, regVarNamesMap);
289            outVregIdxMap[j++] = std::make_pair(vreg, &entry.second);
290        }
291        mapSort(outVregIdxMap.begin(), outVregIdxMap.end());
292       
293        std::vector<size_t>& lvIndexCvtTable = lvIndexCvtTables[r];
294        std::vector<size_t>& revLvIndexCvtTable = revLvIndexCvtTables[r];
295        // generate livenessCvt table
296        for (const auto& entry: outVregIdxMap)
297            for (size_t v: *entry.second)
298                if (v != SIZE_MAX)
299                {
300                    /*std::cout << "lvidx: " << v << ": " << entry.first.name << ":" <<
301                            entry.first.index << std::endl;*/
302                    size_t j = lvIndexCvtTable.size();
303                    lvIndexCvtTable.push_back(v);
304                    if (v+1 > revLvIndexCvtTable.size())
305                        revLvIndexCvtTable.resize(v+1);
306                    revLvIndexCvtTable[v] = j;
307                }
308    }
309   
310    const Array<OutLiveness>* resLivenesses = regAlloc.getOutLivenesses();
311    for (size_t r = 0; r < MAX_REGTYPES_NUM; r++)
312    {
313        std::ostringstream rOss;
314        rOss << "live.regtype#" << r;
315        rOss.flush();
316        std::string rtname(rOss.str());
317       
318        assertValue("testAsmLivenesses", testCaseName + rtname + ".size",
319                    testCase.livenesses[r].size(), resLivenesses[r].size());
320       
321        for (size_t li = 0; li < resLivenesses[r].size(); li++)
322        {
323            std::ostringstream lOss;
324            lOss << ".liveness#" << li;
325            lOss.flush();
326            std::string lvname(rtname + lOss.str());
327            const OutLiveness& expLv = testCase.livenesses[r][li];
328            const OutLiveness& resLv = resLivenesses[r][lvIndexCvtTables[r][li]];
329           
330            // checking liveness
331            assertValue("testAsmLivenesses", testCaseName + lvname + ".size",
332                    expLv.size(), resLv.size());
333            for (size_t k = 0; k < resLv.size(); k++)
334            {
335                std::ostringstream regOss;
336                regOss << ".reg#" << k;
337                regOss.flush();
338                std::string regname(lvname + regOss.str());
339                assertValue("testAsmLivenesses", testCaseName + regname + ".first",
340                    expLv[k].first, resLv[k].first);
341                assertValue("testAsmLivenesses", testCaseName + regname + ".second",
342                    expLv[k].second, resLv[k].second);
343            }
344        }
345    }
346   
347    const std::unordered_map<size_t, LinearDep>* resLinearDepMaps =
348                regAlloc.getLinearDepMaps();
349    for (size_t r = 0; r < MAX_REGTYPES_NUM; r++)
350    {
351        std::ostringstream rOss;
352        rOss << "lndep.regtype#" << r;
353        rOss.flush();
354        std::string rtname(rOss.str());
355       
356        assertValue("testAsmLivenesses", testCaseName + rtname + ".size",
357                    testCase.linearDepMaps[r].size(), resLinearDepMaps[r].size());
358       
359        for (size_t di = 0; di < testCase.linearDepMaps[r].size(); di++)
360        {
361            std::ostringstream lOss;
362            lOss << ".lndep#" << di;
363            lOss.flush();
364            std::string ldname(rtname + lOss.str());
365            const auto& expLinearDepEntry = testCase.linearDepMaps[r][di];
366            auto rlit = resLinearDepMaps[r].find(
367                            lvIndexCvtTables[r][expLinearDepEntry.first]);
368           
369            std::ostringstream vOss;
370            vOss << expLinearDepEntry.first;
371            vOss.flush();
372            assertTrue("testAsmLivenesses", testCaseName + ldname + ".key=" + vOss.str(),
373                        rlit != resLinearDepMaps[r].end());
374            const LinearDep2& expLinearDep = expLinearDepEntry.second;
375            const LinearDep& resLinearDep = rlit->second;
376           
377            assertValue("testAsmLivenesses", testCaseName + ldname + ".align",
378                        cxuint(expLinearDep.align), cxuint(resLinearDep.align));
379           
380            Array<size_t> resPrevVidxes(resLinearDep.prevVidxes.size());
381            // convert to res ssaIdIndices
382            for (size_t k = 0; k < resLinearDep.prevVidxes.size(); k++)
383                resPrevVidxes[k] = revLvIndexCvtTables[r][resLinearDep.prevVidxes[k]];
384           
385            assertArray("testAsmLivenesses", testCaseName + ldname + ".prevVidxes",
386                        expLinearDep.prevVidxes, resPrevVidxes);
387           
388            Array<size_t> resNextVidxes(resLinearDep.nextVidxes.size());
389            // convert to res ssaIdIndices
390            for (size_t k = 0; k < resLinearDep.nextVidxes.size(); k++)
391                resNextVidxes[k] = revLvIndexCvtTables[r][resLinearDep.nextVidxes[k]];
392           
393            assertArray("testAsmLivenesses", testCaseName + ldname + ".nextVidxes",
394                        expLinearDep.nextVidxes, resNextVidxes);
395        }
396    }
397}
398
399int main(int argc, const char** argv)
400{
401    int retVal = 0;
402    for (size_t i = 0; i < sizeof(createLivenessesCasesTbl)/sizeof(AsmLivenessesCase); i++)
403        try
404        { testCreateLivenessesCase(i, createLivenessesCasesTbl[i]); }
405        catch(const std::exception& ex)
406        {
407            std::cerr << ex.what() << std::endl;
408            retVal = 1;
409        }
410    return retVal;
411}
Note: See TracBrowser for help on using the repository browser.