• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16import { expect } from 'chai';
17import 'mocha';
18import * as ts from "typescript";
19import {
20    Callrange,
21    Returnundefined,
22    Imm,
23    IRNode,
24    Jmp,
25    Label,
26    Ldai,
27    Lda,
28    Ldglobalvar,
29    Mov,
30    Sta,
31    Throw,
32    VReg
33} from "../src/irnodes";
34import { PandaGen } from "../src/pandagen";
35import { CacheExpander } from "../src/pass/cacheExpander";
36import { RegAlloc } from "../src/regAllocator";
37import { basicChecker, checkInstructions, compileAllSnippet, SnippetCompiler } from "./utils/base";
38import { creatAstFromSnippet } from "./utils/asthelper";
39
40function checkRegisterNumber(left: IRNode, right: IRNode): boolean {
41    if (!basicChecker(left, right)) {
42        return false;
43    }
44    let lo = left.operands;
45    let ro = right.operands;
46    if (lo.length !== ro.length) {
47        return false;
48    }
49    for (let i = 0; i < lo.length; ++i) {
50        let l = lo[i];
51        let r = ro[i];
52        if (l instanceof VReg && r instanceof VReg) {
53            if (!((<VReg>l).num === (<VReg>r).num)) {
54                return false;
55            }
56        }
57    }
58    return true;
59}
60describe("RegAllocator", function () {
61    it("make spill for Dst register & Src register", function () {
62        let string = "function test() {";
63        for (let i = 0; i < 256; ++i) {
64            string += "let a" + i + " = " + i + ";";
65        }
66        string += "a255;}";
67
68        let snippetCompiler = new SnippetCompiler();
69        snippetCompiler.compile(string, [new CacheExpander(), new RegAlloc()]);
70        let insns = snippetCompiler.getPandaGenByName("UnitTest.test").getInsns();
71
72        IRNode.pg = new PandaGen("", creatAstFromSnippet(""), 0, undefined);
73        IRNode.pg.updateIcSize(0);
74
75        let v = [];
76        for (let i = 0; i < 260; ++i) {
77            v[i] = new VReg();
78            v[i].num = i;
79        }
80
81        let expected: IRNode[] = [
82            new Ldai(new Imm(252)),
83            new Sta(v[0]),
84            new Mov(v[256], v[0]),
85            new Ldai(new Imm(253)),
86            new Sta(v[0]),
87            new Mov(v[257], v[0]),
88            new Ldai(new Imm(254)),
89            new Sta(v[0]),
90            new Mov(v[258], v[0]),
91            new Ldai(new Imm(255)),
92            new Sta(v[0]),
93            new Mov(v[259], v[0]),
94            // load a255
95            new Mov(v[0], v[259]),
96            new Lda(v[0]),
97            new Returnundefined()
98        ]
99
100        expect(checkInstructions(insns.slice(insns.length - 15), expected, checkRegisterNumber)).to.be.true;
101    });
102
103    it("make spill for SrcDst register", function () {
104        /* the only possible instruction whose operand register type could be SrcDstVReg is INCI,
105         * but we do not use it at all by now
106         */
107        expect(true).to.be.true;
108    });
109
110    it("make spill for CalliRange", function () {
111        /* since the bitwidth for CalliRange source register is 16 now, we do not need to make spill at all.
112           but in case later 16 might be changed to 8, then spill operation will be needed in some cases. this testcase is designed
113           for 8bits constraints.
114        */
115        let string = "function test() {";
116        for (let i = 0; i < 256; ++i) {
117            string += "let a" + i + " = " + i + ";";
118        }
119        string += "test(a252, a253, a254, a255);}";
120
121        let snippetCompiler = new SnippetCompiler();
122        snippetCompiler.compile(string, [new CacheExpander(), new RegAlloc()]);
123        let insns = snippetCompiler.getPandaGenByName("UnitTest.test").getInsns();
124
125        IRNode.pg = new PandaGen("", creatAstFromSnippet(""), 0, undefined);
126        IRNode.pg.updateIcSize(0);
127        let v = [];
128        for (let i = 0; i < 268; ++i) {
129            v[i] = new VReg();
130            v[i].num = i;
131        }
132        let expected = [
133            new Ldai(new Imm(252)),
134            new Sta(v[0]),
135            new Mov(v[259], v[0]),
136            new Ldai(new Imm(253)),
137            new Sta(v[0]),
138            new Mov(v[260], v[0]),
139            new Ldai(new Imm(254)),
140            new Sta(v[0]),
141            new Mov(v[261], v[0]),
142            new Ldai(new Imm(255)),
143            new Sta(v[0]),
144            new Mov(v[262], v[0]),
145            new Ldglobalvar(new Imm(0), "test"),
146            new Sta(v[0]),
147            new Mov(v[263], v[0]),
148            // call test with [a252, a253, a254, a255]
149            new Mov(v[0], v[259]),
150            new Lda(v[0]),
151            new Sta(v[0]),
152            new Mov(v[264], v[0]),
153            new Mov(v[0], v[260]),
154            new Lda(v[0]),
155            new Sta(v[0]),
156            new Mov(v[265], v[0]),
157            new Mov(v[0], v[261]),
158            new Lda(v[0]),
159            new Sta(v[0]),
160            new Mov(v[266], v[0]),
161            new Mov(v[0], v[262]),
162            new Lda(v[0]),
163            new Sta(v[0]),
164            new Mov(v[267], v[0]),
165            new Mov(v[0], v[263]),
166            new Lda(v[0]),
167            new Mov(v[0], v[264]),
168            new Mov(v[1], v[265]),
169            new Mov(v[2], v[266]),
170            new Mov(v[3], v[267]),
171            new Callrange(new Imm(1), new Imm(4), [v[0], v[1], v[2], v[3]]),
172            new Returnundefined(),
173        ];
174
175        expect(checkInstructions(insns.slice(insns.length - 39), expected, checkRegisterNumber)).to.be.true;
176    });
177
178    it("make spill for control-flow change", function () {
179        let string = "function test() {";
180        for (let i = 0; i < 256; ++i) {
181            string += "let a" + i + " = " + i + ";";
182        }
183        string += `try { throw a0; } catch { a0 }};`;
184
185        let snippetCompiler = new SnippetCompiler();
186        snippetCompiler.compile(string, [new CacheExpander(), new RegAlloc()]);
187        let insns = snippetCompiler.getPandaGenByName("UnitTest.test").getInsns();
188
189        IRNode.pg = new PandaGen("", creatAstFromSnippet(""), 0, undefined);
190        IRNode.pg.updateIcSize(0);
191        let v = [];
192        for (let i = 0; i < 261; ++i) {
193            v[i] = new VReg();
194            v[i].num = i;
195        }
196        let tryBeginLabel = new Label();
197        let tryEndLabel = new Label();
198        let catchBeginLabel = new Label();
199        let catchEndLabel = new Label();
200
201        let expected = [
202            new Ldai(new Imm(252)),
203            new Sta(v[0]),
204            new Mov(v[256], v[0]),
205            new Ldai(new Imm(253)),
206            new Sta(v[0]),
207            new Mov(v[257], v[0]),
208            new Ldai(new Imm(254)),
209            new Sta(v[0]),
210            new Mov(v[258], v[0]),
211            new Ldai(new Imm(255)),
212            new Sta(v[0]),
213            new Mov(v[259], v[0]),
214            tryBeginLabel,
215            new Lda(v[4]),
216            new Throw(),
217            tryEndLabel,
218            new Jmp(catchEndLabel),
219            catchBeginLabel,
220            new Lda(v[4]),
221            catchEndLabel,
222            new Returnundefined(),
223        ];
224
225        expect(checkInstructions(insns.slice(insns.length - 21), expected, checkRegisterNumber)).to.be.true;
226    });
227
228    it("VReg sequence of CalliDynRange is not continuous", function () {
229        let pandaGen = new PandaGen('', creatAstFromSnippet(""), 0);
230        let para1 = pandaGen.getTemp();
231        let para2 = pandaGen.getTemp();
232        let para3 = pandaGen.getTemp();
233        let para4 = pandaGen.getTemp();
234        let para5 = pandaGen.getTemp();
235        let para6 = pandaGen.getTemp();
236
237        pandaGen.call(ts.createNode(0), [para1, para2, para3, para4, para5, para6], false);
238
239        pandaGen.freeTemps(para1, para3, para2);
240
241        try {
242            new RegAlloc().run(pandaGen);
243        } catch (err) {
244            expect(true).to.be.true;
245            return;
246        }
247        expect(true).to.be.false;
248    });
249
250    it("VReg sequence of DynRange is not continuous", function () {
251        let pandaGen = new PandaGen('', creatAstFromSnippet(""), 0);
252        let para1 = pandaGen.getTemp();
253        let para2 = pandaGen.getTemp();
254        let para3 = pandaGen.getTemp();
255
256        pandaGen.getInsns().push(new Callrange(new Imm(0), new Imm(3), [para1, para2, para3]));
257
258        pandaGen.freeTemps(para1, para3, para2);
259
260        try {
261            new RegAlloc().run(pandaGen);
262        } catch (err) {
263            expect(true).to.be.true;
264            return;
265        }
266        expect(true).to.be.false;
267    });
268});
269