| //------------------------------------------------------------------------------------------------------- |
| // Copyright (C) Microsoft. All rights reserved. |
| // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. |
| //------------------------------------------------------------------------------------------------------- |
| |
| // Compares the value set by interpreter with the jitted code |
| // need to run with -mic:1 -off:simplejit -off:jitloopbody -off:inline -off:globopt:1.18-1.30 |
| // Run locally with -trace:memop -trace:bailout to help find bugs |
| |
| let testCases = [ |
| function() { |
| return { |
| start: 0, |
| end: 100, |
| test: function testBasic(a, src) { |
| for(let i = 0; i < 100; i++) { |
| a[i] = src[i]; |
| } |
| } |
| }; |
| }, |
| function() { |
| return { |
| start: 0, |
| end: 100, |
| test: function testChangedIndex(a, src) { |
| // This is an invalid memcopy |
| for(let i = 0; i < 100;) { |
| a[i] = src[++i]; |
| } |
| } |
| }; |
| }, |
| function() { |
| let src = new Array(100); |
| for(let i = 0; i < 100; ++i) { |
| src[i] = i; |
| } |
| return { |
| start: 0, |
| end: 100, |
| test: function testLdSlot(a) { |
| // Invalid pattern, src is not considered invariant |
| for(let i = 0; i < 100; ++i) { |
| a[i] = src[i]; |
| } |
| } |
| }; |
| }, |
| function() { |
| let start = 5, end = 101; |
| return { |
| start: start, |
| end: end, |
| size: end, |
| test: function testReverse(a, src) { |
| for(let i = 100; i >= 5; i--) { |
| a[i] = src[i]; |
| } |
| } |
| }; |
| }, |
| function() { |
| let results = []; |
| let start = 0, end = 10; |
| return { |
| start: start, |
| end: end, |
| runner: function testMultipleMemcopy(arrayGen, src) { |
| let a = arrayGen(), b = arrayGen(), c = arrayGen(); |
| // Currently this is not a valid memcopy pattern (would it be more performant?) |
| for(let i = 0; i < 10; i++) { |
| a[i] = b[i] = c[i] = src[i]; |
| } |
| results.push([a, b, c]); |
| }, |
| check: function() { |
| let base = results[0]; |
| for(let i = 1; i < results.length; ++i) { |
| for(let j = 0; j < 3; ++j) { |
| compareResult("testMultipleMemcopy", base[j], results[i][j], start, end); |
| } |
| } |
| } |
| }; |
| }, |
| function() { |
| return { |
| start: 0, |
| end: 10, |
| test: function preIncr(a, src) { |
| let ri = -1; |
| for(let i = 0; i < 10; ++i) { |
| a[++ri] = src[ri]; |
| } |
| } |
| }; |
| }, |
| function() { |
| return { |
| start: -50, |
| end: 10, |
| loop: 10, // Run this a few times to cause rejit, |
| test: function testNegativeStartIndex(a, src) { |
| for(let i = -50; i < 10; i++) { |
| // This should bailout on MemOp because the index will be negative |
| a[i] = src[i]; |
| } |
| } |
| }; |
| }, |
| function() { |
| return { |
| start: 0, |
| end: 128, |
| test: function bug4468518(a, src) { |
| let x = 0; |
| for(let i = 0; i < 128; i++) { |
| let m = src[i]; |
| x += m; |
| a[i] = m; |
| } |
| return x; |
| } |
| }; |
| } |
| ]; |
| |
| let passed = true; |
| function compareResult(name, a, b, start, end, start2) { |
| for(let i = start, j = start2 || start; i < end; ++i, ++j) { |
| if(a[i] !== b[j]) { |
| print(`Error ${name}: a[${i}](${a[i]}) !== b[${j}](${b[j]})`); |
| passed = false; |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| const isFloatTest = WScript.Arguments[0] === "float"; |
| |
| function makeArray(size = 10) { |
| let a = new Array(size); |
| for(let i = 0; i < size; ++i) { |
| a[i] = isFloatTest ? 0.5 : 0; |
| } |
| if (isFloatTest) { |
| return eval(`[${a.join(", ")}]`); |
| } |
| return a; |
| } |
| |
| let arrayGenerators = [ |
| makeArray, |
| ]; |
| |
| function makeFloatArray(size = 10) { |
| const arrayValues = new Array(size); |
| for(let i = 0; i < size; ++i) { |
| arrayValues[i] = Math.random() / Math.random() * (Math.random() < 0.2 ? -1 : 1); |
| } |
| return eval(`[${arrayValues.join(", ")}]`); |
| } |
| |
| function makeSource(size = 10) { |
| if (isFloatTest) return makeFloatArray(size); |
| let s = new Array(size); |
| for(let i = 0; i < size; ++i) { |
| s[i] = i; |
| } |
| return s; |
| } |
| |
| for(let testCase of testCases) { |
| let results = []; |
| let testInfo = testCase(); |
| let name = testInfo.runner && testInfo.runner.name || testInfo.test && testInfo.test.name || "Unknown"; |
| |
| let src; |
| if(!testInfo.makeSource) { |
| if (testInfo.size !== undefined) { |
| src = makeSource(testInfo.size); |
| } else if( |
| testInfo.start !== undefined && |
| testInfo.end !== undefined |
| ) { |
| src = makeSource(testInfo.end - testInfo.start); |
| } |
| } |
| function run(gen) { |
| if(testInfo.makeSource) { |
| src = testInfo.makeSource(); |
| } |
| |
| if(testInfo.runner) { |
| let result = testInfo.runner(gen, src); |
| results.push(result); |
| } else { |
| let newArray = gen(testInfo.size || testInfo.end - testInfo.start); |
| testInfo.test(newArray, src); |
| results.push(newArray); |
| } |
| } |
| |
| // Run once for the interpreter |
| run(makeArray); |
| for(let gen of arrayGenerators) { |
| if(testInfo.loop | 0) { |
| for(let i = 0; i < testInfo.loop; ++i) { |
| run(gen); |
| } |
| } else { |
| run(gen); |
| } |
| } |
| |
| |
| if(testInfo.check) { |
| testInfo.check(results); |
| } else { |
| let base = results[0]; // result from the interpreter |
| for(let i = 1; i < results.length; ++i) { |
| compareResult(name, base, results[i], testInfo.start, testInfo.end); |
| } |
| } |
| } |
| |
| if(passed) { |
| print("PASSED"); |
| } else { |
| print("FAILED"); |
| } |
| |