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 EcmaCallirangedyn, 22 EcmaReturnundefined, 23 EcmaStlettoglobalrecord, 24 EcmaTryldglobalbyname, 25 Imm, 26 IRNode, 27 LdaiDyn, 28 ResultType, 29 StaDyn, 30 VReg 31} from "../src/irnodes"; 32import { PandaGen } from "../src/pandagen"; 33import { CacheExpander } from "../src/pass/cacheExpander"; 34import { RegAlloc } from "../src/regAllocator"; 35import { basicChecker, checkInstructions, compileAllSnippet } from "./utils/base"; 36 37 38function checkRegisterNumber(left: IRNode, right: IRNode): boolean { 39 if (!basicChecker(left, right)) { 40 return false; 41 } 42 let lo = left.operands; 43 let ro = right.operands; 44 if (lo.length !== ro.length) { 45 return false; 46 } 47 for (let i = 0; i < lo.length; ++i) { 48 let l = lo[i]; 49 let r = ro[i]; 50 if (l instanceof VReg && r instanceof VReg) { 51 if (!((<VReg>l).num == (<VReg>r).num)) { 52 return false; 53 } 54 } 55 } 56 return true; 57} 58describe("RegAllocator", function () { 59 it("make spill for Src register", function () { 60 let string: string = ""; 61 for (let i = 0; i < 256; ++i) { 62 string += "let a" + i + " = " + i + ";"; 63 } 64 string += "a255;"; 65 66 let pgs = compileAllSnippet(string, [new CacheExpander(), new RegAlloc()]); 67 let insns = pgs[0].getInsns(); 68 69 let expected: IRNode[] = [ 70 new LdaiDyn(new Imm(252)), 71 new EcmaStlettoglobalrecord('a252'), 72 new LdaiDyn(new Imm(253)), 73 new EcmaStlettoglobalrecord('a253'), 74 new LdaiDyn(new Imm(254)), 75 new EcmaStlettoglobalrecord('a254'), 76 new LdaiDyn(new Imm(255)), 77 new EcmaStlettoglobalrecord('a255'), 78 new EcmaTryldglobalbyname('a255'), 79 new EcmaReturnundefined() 80 ] 81 82 expect(checkInstructions(insns.slice(insns.length - 10), expected, checkRegisterNumber)).to.be.true; 83 }); 84 85 it("make spill for SrcDst register", function () { 86 /* the only possible instruction whose operand register type could be SrcDstVReg is INCI, 87 * but we do not use it at all by now 88 */ 89 expect(true).to.be.true; 90 }); 91 92 it("make spill for CalliDynRange", function () { 93 /* since the bitwidth for CalliDynRange source register is 16 now, we do not need to make spill at all. 94 but later 16 might be changed to 8, then spill operation will be needed in some cases. this testcase is designed 95 for 8bits constraints. 96 */ 97 let string = ""; 98 for (let i = 0; i < 256; ++i) { 99 string += "let a" + i + " = " + i + ";"; 100 } 101 string += "call(a252, a253, a254, a255);"; 102 let pgs = compileAllSnippet(string, [new CacheExpander(), new RegAlloc()]); 103 let insns = pgs[0].getInsns(); 104 let v = []; 105 for (let i = 0; i < 8; ++i) { 106 v[i] = new VReg(); 107 v[i].num = i; 108 } 109 let expected = [ 110 new LdaiDyn(new Imm(252)), 111 new EcmaStlettoglobalrecord('a252'), 112 new LdaiDyn(new Imm(253)), 113 new EcmaStlettoglobalrecord('a253'), 114 new LdaiDyn(new Imm(254)), 115 new EcmaStlettoglobalrecord('a254'), 116 new LdaiDyn(new Imm(255)), 117 new EcmaStlettoglobalrecord('a255'), 118 new EcmaTryldglobalbyname('call'), 119 new StaDyn(v[3]), 120 new EcmaTryldglobalbyname('a252'), 121 new StaDyn(v[4]), 122 new EcmaTryldglobalbyname('a253'), 123 new StaDyn(v[5]), 124 new EcmaTryldglobalbyname('a254'), 125 new StaDyn(v[6]), 126 new EcmaTryldglobalbyname('a255'), 127 new StaDyn(v[7]), 128 new EcmaCallirangedyn(new Imm(4), [v[3],v[4],v[5],v[6],v[7]]), 129 new EcmaReturnundefined(), 130 ]; 131 expect(checkInstructions(insns.slice(insns.length - 20), expected, checkRegisterNumber)).to.be.true; 132 }); 133 134 it("VReg sequence of CalliDynRange is not continuous", function () { 135 let pandaGen = new PandaGen('', 0); 136 137 let para1 = pandaGen.getTemp(); 138 let para2 = pandaGen.getTemp(); 139 let para3 = pandaGen.getTemp(); 140 let para4 = pandaGen.getTemp(); 141 let para5 = pandaGen.getTemp(); 142 let para6 = pandaGen.getTemp(); 143 144 pandaGen.call(ts.createNode(0), [para1, para2, para3, para4, para5, para6], false); 145 146 pandaGen.freeTemps(para1, para3, para2); 147 148 try { 149 new RegAlloc().run(pandaGen); 150 } catch (err) { 151 expect(true).to.be.true; 152 return; 153 } 154 expect(true).to.be.false; 155 }); 156 157 it("VReg sequence of DynRange is not continuous", function () { 158 let pandaGen = new PandaGen('', 0); 159 160 let para1 = pandaGen.getTemp(); 161 let para2 = pandaGen.getTemp(); 162 let para3 = pandaGen.getTemp(); 163 164 pandaGen.getInsns().push(new CallRange('test', [para1, para2, para3])) 165 166 pandaGen.freeTemps(para1, para3, para2); 167 168 try { 169 new RegAlloc().run(pandaGen); 170 } catch (err) { 171 expect(true).to.be.true; 172 return; 173 } 174 expect(true).to.be.false; 175 }); 176}); 177