1/* 2 * Copyright (c) 2021 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 { 17 expect 18} from 'chai'; 19import 'mocha'; 20import { 21 Inc, 22 Less, 23 Returnundefined, 24 Tonumeric, 25 Imm, 26 Jeqz, 27 Jmp, 28 Label, 29 Lda, 30 Ldai, 31 Sta, 32 VReg, 33 IRNode 34} from "../../src/irnodes"; 35import { checkInstructions, compileMainSnippet } from "../utils/base"; 36import { creatAstFromSnippet } from "../utils/asthelper" 37import { PandaGen } from '../../src/pandagen'; 38 39describe("ForLoopTest", function () { 40 it('forLoopEmpty', function () { 41 let insns = compileMainSnippet("for (;;) {}"); 42 let labelPre = new Label(); 43 let labelPost = new Label(); 44 let labelIncr = new Label(); 45 IRNode.pg = new PandaGen("", creatAstFromSnippet(``), 0, undefined); 46 let expected = [ 47 labelPre, 48 labelIncr, 49 new Jmp(labelPre), 50 labelPost, 51 new Returnundefined() 52 ]; 53 let jumps = insns.filter(item => item instanceof Jmp); 54 55 expect(jumps.length).to.equal(1); 56 57 let jmpLabel = (<Jmp>jumps[0]).getTarget(); 58 59 expect(checkInstructions(insns, expected)).to.be.true; 60 expect(jmpLabel).to.equal(insns[0]); 61 }); 62 63 it('forLoopWithInitializer', function () { 64 let insns = compileMainSnippet("for (let i = 0;;) {}"); 65 let jumps = insns.filter(item => item instanceof Jmp); 66 67 expect(jumps.length).to.equal(1); 68 69 let jmpLabel = (<Jmp>jumps[0]).getTarget(); 70 71 expect(insns[4]).to.equal(jumps[0]); 72 expect(jmpLabel).to.equal(insns[2]); 73 }); 74 75 it('forLoopWithInitializerAndCondition', function () { 76 let insns = compileMainSnippet("for (let i = 0; i < 5;) {}"); 77 let jumps = insns.filter(item => (item instanceof Jmp || item instanceof Jeqz)); 78 79 expect(jumps.length).to.equal(2); 80 81 let jgezLabel = (<Jmp>jumps[0]).getTarget(); 82 let jmpLabel = (<Jmp>jumps[1]).getTarget(); 83 84 expect(jmpLabel).to.equal(insns[2]); 85 expect(jgezLabel).to.equal(insns[10]); 86 87 expect(insns[7]).to.equal(jumps[0]); 88 expect(insns[9]).to.equal(jumps[1]); 89 }); 90 91 it('forLoopWithInitializerAndConditionAndIncrementor', function () { 92 let insns = compileMainSnippet("for (let i = 0; i < 5; i++) {}"); 93 let jumps = insns.filter(item => (item instanceof Jmp || item instanceof Jeqz)); 94 95 expect(jumps.length).to.equal(2); 96 97 let jgezLabel = (<Jmp>jumps[0]).getTarget(); 98 let jmpLabel = (<Jmp>jumps[1]).getTarget(); 99 100 expect(jmpLabel).to.equal(insns[2]); 101 expect(jgezLabel).to.equal(insns[17]); 102 103 expect(insns[7]).to.equal(jumps[0]); 104 expect(insns[16]).to.equal(jumps[1]); 105 }); 106 107 it('forLoopWithContinue', function () { 108 let insns = compileMainSnippet("for (let i = 0; i < 5; ++i) { continue; }"); 109 let i = new VReg(); 110 let lhs = new VReg(); 111 let operand = new VReg(); 112 let labelPre = new Label(); 113 let labelPost = new Label(); 114 let labelIncr = new Label(); 115 IRNode.pg = new PandaGen("", creatAstFromSnippet(``), 0, undefined); 116 let expected = [ 117 // initializer 118 new Ldai(new Imm(0)), 119 new Sta(i), 120 labelPre, 121 // condition 122 new Lda(i), 123 new Sta(lhs), 124 new Ldai(new Imm(5)), 125 new Less(new Imm(0), lhs), 126 new Jeqz(labelPost), 127 // body 128 new Jmp(labelIncr), // continue 129 labelIncr, 130 // incrementor 131 new Lda(i), 132 new Sta(operand), 133 new Lda(operand), 134 new Inc(new Imm(1)), 135 new Sta(i), 136 // jump to the loop header 137 new Jmp(new Label()), 138 labelPost, 139 new Returnundefined() 140 ]; 141 // check the instruction kinds are the same as we expect 142 expect(checkInstructions(insns, expected)).to.be.true; 143 // check continue jumps to the expected instruction 144 let jmp = <Jmp>insns[8]; 145 let targetLabel = (jmp).getTarget(); 146 expect(targetLabel).to.equal(insns[9]); 147 }); 148 149 it('forLoopWithBreak', function () { 150 let insns = compileMainSnippet("for (let i = 0; i < 5; ++i) {break; }"); 151 let i = new VReg(); 152 let lhs = new VReg(); 153 let operand = new VReg(); 154 let labelPre = new Label(); 155 let labelPost = new Label(); 156 let labelIncr = new Label(); 157 IRNode.pg = new PandaGen("", creatAstFromSnippet(``), 0, undefined); 158 let expected = [ 159 // initializer 160 new Ldai(new Imm(0)), 161 new Sta(i), 162 labelPre, 163 // condition 164 new Lda(i), 165 new Sta(lhs), 166 new Ldai(new Imm(5)), 167 new Less(new Imm(0), lhs), 168 new Jeqz(labelPost), 169 // body 170 new Jmp(labelPost), // break 171 // incrementor 172 labelIncr, 173 new Lda(i), 174 new Sta(operand), 175 new Lda(operand), 176 new Inc(new Imm(1)), 177 new Sta(i), 178 // jump to the loop header 179 new Jmp(labelPre), 180 labelPost, 181 new Returnundefined() 182 ]; 183 // check the instruction kinds are the same as we expect 184 expect(checkInstructions(insns, expected)).to.be.true; 185 // check continue jumps to the expected instruction 186 let jmp = <Jmp>insns[8]; 187 let targetLabel = (jmp).getTarget(); 188 expect(targetLabel).to.equal(insns[16]); 189 }); 190}); 191 192describe("LoopWithLabelTests", function () { 193 it('forLoopWithBreakWithLabel', function () { 194 let insns = compileMainSnippet(`loop1: 195 for (let i = 0; i < 5; ++i) { 196 for (let j = 0; j < 6; j++) { 197 break loop1; 198 } 199 }`); 200 let i = new VReg(); 201 let j = new VReg(); 202 let lhs = new VReg(); 203 let labelPre = new Label(); 204 let labelPost = new Label(); 205 let labelIncr = new Label(); 206 let labelPre1 = new Label(); 207 let labelPost1 = new Label(); 208 let labelIncr1 = new Label(); 209 IRNode.pg = new PandaGen("", creatAstFromSnippet(``), 0, undefined); 210 let expected = [ 211 // initializer 212 new Ldai(new Imm(0.0)), 213 new Sta(i), 214 labelPre, 215 // condition 216 new Lda(i), 217 new Sta(lhs), 218 new Ldai(new Imm(5.0)), 219 new Less(new Imm(0), lhs), 220 new Jeqz(labelPost), 221 222 // second for 223 new Ldai(new Imm(0.0)), 224 new Sta(j), 225 labelPre1, 226 // condition 227 new Lda(j), 228 new Sta(lhs), 229 new Ldai(new Imm(6.0)), 230 new Less(new Imm(1), lhs), 231 new Jeqz(labelPost1), 232 new Jmp(labelPost), 233 labelIncr1, 234 // incrementor 235 new Lda(j), 236 new Sta(j), 237 new Lda(j), 238 new Inc(new Imm(2)), 239 new Sta(j), 240 new Lda(j), 241 new Tonumeric(new Imm(3)), 242 // jump to the loop header 243 new Jmp(labelPre1), 244 labelPost1, 245 labelIncr, 246 // incrementor 247 new Lda(i), 248 new Sta(i), 249 new Lda(i), 250 new Inc(new Imm(4)), 251 new Sta(i), 252 // jump to the loop header 253 new Jmp(labelPre), 254 labelPost, 255 new Returnundefined() 256 ]; 257 258 // check the instruction kinds are the same as we expect 259 expect(checkInstructions(insns, expected)).to.be.true; 260 // check break jumps to the expected instruction 261 let jmp = <Jmp>insns[16]; 262 let targetLabel = (jmp).getTarget(); 263 expect(targetLabel).to.equal(insns[34]); 264 }); 265 266 it('forLoopWithContinueWithLabel', function () { 267 let insns = compileMainSnippet(`loop1: 268 loop2: 269 loop3: 270 for (let i = 0; i < 5; ++i) { 271 for (let j = 0; j < 6; j++) { 272 continue loop2; 273 } 274 }`); 275 let i = new VReg(); 276 let j = new VReg(); 277 let lhs = new VReg(); 278 let labelPre = new Label(); 279 let labelPost = new Label(); 280 let labelIncr = new Label(); 281 let labelPre1 = new Label(); 282 let labelPost1 = new Label(); 283 let labelIncr1 = new Label(); 284 IRNode.pg = new PandaGen("", creatAstFromSnippet(``), 0, undefined); 285 let expected = [ 286 // initializer 287 new Ldai(new Imm(0.0)), 288 new Sta(i), 289 labelPre, 290 // condition 291 new Lda(i), 292 new Sta(lhs), 293 new Ldai(new Imm(5.0)), 294 new Less(new Imm(0), lhs), 295 new Jeqz(labelPost), 296 297 // second for 298 new Ldai(new Imm(0.0)), 299 new Sta(j), 300 labelPre1, 301 // condition 302 new Lda(j), 303 new Sta(lhs), 304 new Ldai(new Imm(6.0)), 305 new Less(new Imm(1), lhs), 306 new Jeqz(labelPost1), 307 new Jmp(labelIncr), 308 labelIncr1, 309 // incrementor 310 new Lda(j), 311 new Sta(j), 312 new Lda(j), 313 new Inc(new Imm(2)), 314 new Sta(j), 315 new Lda(j), 316 new Tonumeric(new Imm(3)), 317 // jump to the loop header 318 new Jmp(labelPre1), 319 labelPost1, 320 labelIncr, 321 // incrementor 322 new Lda(i), 323 new Sta(i), 324 new Lda(i), 325 new Inc(new Imm(4)), 326 new Sta(i), 327 // jump to the loop header 328 new Jmp(labelPre), 329 labelPost, 330 new Returnundefined() 331 ]; 332 333 // check the instruction kinds are the same as we expect 334 expect(checkInstructions(insns, expected)).to.be.true; 335 // check break jumps to the expected instruction 336 let jmp = <Jmp>insns[16]; 337 let targetLabel = (jmp).getTarget(); 338 expect(targetLabel).to.equal(insns[27]); 339 }); 340}); 341