├── public
├── favicon.ico
├── manifest.json
└── index.html
├── doc
└── SIMD-Visualizer-Demo.gif
├── src
├── ASMComponents
│ ├── UnsupportedCommand.js
│ ├── Function.js
│ ├── ret.js
│ ├── Shift.js
│ ├── Vector.js
│ ├── SequentialComponent.js
│ └── Arithmetic.js
├── css
│ ├── GlobalVariables.css
│ ├── ASMVisualizer.css
│ ├── Vector.css
│ ├── App.css
│ ├── Tabs.css
│ └── ASTVisualizer.css
├── index.css
├── index.js
├── components
│ ├── WaitingScreen.js
│ ├── CodeStatus.js
│ ├── ErrorHandler.js
│ ├── FrontPage.js
│ ├── ButtonPanel.js
│ ├── ASTVisualizer.js
│ ├── ASMVisualizer.js
│ ├── App.js
│ └── ParametersPage.js
├── Utils
│ ├── index.js
│ ├── Compiler.js
│ ├── Tabs.js
│ ├── Registry.js
│ ├── Converter.js
│ └── Parser.js
├── Images
│ ├── Cog.js
│ ├── CProgramming.js
│ ├── c-programming.svg
│ ├── cog.svg
│ ├── cryingboy.svg
│ └── Cryingboy.js
└── serviceWorker.js
├── .gitignore
├── package.json
├── LICENSE
├── README.md
└── .idea
└── workspace.xml
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/piotte13/SIMD-Visualiser/HEAD/public/favicon.ico
--------------------------------------------------------------------------------
/doc/SIMD-Visualizer-Demo.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/piotte13/SIMD-Visualiser/HEAD/doc/SIMD-Visualizer-Demo.gif
--------------------------------------------------------------------------------
/src/ASMComponents/UnsupportedCommand.js:
--------------------------------------------------------------------------------
1 | import React, {Component} from "react";
2 |
3 | export default class UnsupportedCommand extends Component {
4 |
5 | render() {
6 | return (
7 |
Unsupported Command: "{this.props.name}"
8 | );
9 | }
10 | }
--------------------------------------------------------------------------------
/src/css/GlobalVariables.css:
--------------------------------------------------------------------------------
1 | :root {
2 | --main: #2A363B;
3 | --dark-main: #1F292E;
4 | --one: #A7226E;
5 | --two: #EC2049;
6 | --three: #F26B38;
7 | --four: #F7DB4F;
8 | --five: #2F9599;
9 | --gray: #A8A7A7;
10 | --clear-text-color: #FFF;
11 | --dark-text-color: #000
12 | }
--------------------------------------------------------------------------------
/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "SIMD Visualizer",
3 | "name": "The Ultimate SIMD Visualizer",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | }
10 | ],
11 | "start_url": ".",
12 | "display": "standalone",
13 | "theme_color": "#000000",
14 | "background_color": "#ffffff"
15 | }
16 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 |
6 | # testing
7 | /coverage
8 |
9 | # production
10 | /build
11 |
12 | # misc
13 | .DS_Store
14 | .env.local
15 | .env.development.local
16 | .env.test.local
17 | .env.production.local
18 |
19 | npm-debug.log*
20 | yarn-debug.log*
21 | yarn-error.log*
22 |
23 | .idea
24 |
--------------------------------------------------------------------------------
/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | background-color: #F7F7F7;
5 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
6 | "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
7 | sans-serif;
8 | font-size: 16px;
9 | -webkit-font-smoothing: antialiased;
10 | -moz-osx-font-smoothing: grayscale;
11 | }
12 |
13 | code {
14 | font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
15 | monospace;
16 | }
17 |
--------------------------------------------------------------------------------
/src/css/ASMVisualizer.css:
--------------------------------------------------------------------------------
1 | .playback-button {
2 | width: 150px;
3 | /*background-color: var(--three) !important;*/
4 | /*border-color: var(--five) !important;*/
5 | /*color: var(--five) !important;*/
6 | /*#273890*/
7 | }
8 |
9 | .btn-outline-primary {
10 | /*background-color: var(--three) !important;*/
11 | border-color: var(--main) !important;
12 | color: var(--main) !important;
13 | }
14 |
15 | .btn-outline-primary:hover {
16 | color: #fff !important;
17 | background-color: var(--main) !important;
18 | border-color: var(--main) !important;
19 | }
--------------------------------------------------------------------------------
/src/css/Vector.css:
--------------------------------------------------------------------------------
1 | .vector-container {
2 | fill: var(--main);
3 | filter: drop-shadow(3px 3px 2px rgba(42, 54, 59, .5));
4 | -webkit-filter: drop-shadow(3px 3px 2px rgba(42, 54, 59, .5));
5 | }
6 |
7 | .vector-line {
8 | stroke: var(--gray);
9 | stroke-width: 1;
10 | shape-rendering: crispEdges;
11 | }
12 |
13 | .vector-values {
14 | fill: var(--clear-text-color);
15 | text-anchor: middle;
16 | }
17 |
18 | .shift-values-right {
19 | fill: var(--five);
20 | text-anchor: middle;
21 | }
22 |
23 | .shift-values-left {
24 | fill: var(--two);
25 | text-anchor: middle;
26 | }
--------------------------------------------------------------------------------
/src/css/App.css:
--------------------------------------------------------------------------------
1 | .App {
2 | text-align: center;
3 | }
4 |
5 | .react-codemirror2 {
6 | font-size: 24px;
7 | -ms-flex: 1 1;
8 | flex: 1 1;
9 | }
10 |
11 | .react-codemirror2 .CodeMirror {
12 | height: 100%;
13 | }
14 |
15 | .editor-highlighted-background {
16 | background-color: #44535a;
17 | }
18 |
19 | @media (max-width: 700px) {
20 | .react-codemirror2 {
21 | font-size: 13px;
22 | }
23 | }
24 |
25 | strong {
26 | font-weight: 700 !important;
27 | }
28 |
29 | .highlighted-code {
30 | background-color: #44535a;
31 | }
32 |
33 | .sequential-highlighted-code {
34 | background-color: #44535a;
35 | }
--------------------------------------------------------------------------------
/src/css/Tabs.css:
--------------------------------------------------------------------------------
1 | .tabs {
2 | background: #fff;
3 | border: 1px solid #e5e5e5;
4 | border-radius: 3px;
5 | height: 100%;
6 | }
7 |
8 | .tabs__labels {
9 | margin: 0;
10 | padding: 0;
11 | }
12 |
13 | .tabs__labels li {
14 | display: inline-block;
15 | }
16 |
17 | .tabs__labels li a {
18 | padding: 8px 50px;
19 | display: block;
20 | color: #444;
21 | text-decoration: none;
22 | border-bottom: 3px solid #f5f5f5;
23 | }
24 |
25 | .tabs__labels li a.active {
26 | border-bottom-color: var(--five);
27 | transition: all 0.3s ease-out;
28 | }
29 |
30 | .tabs__content {
31 | padding: 25px;
32 | height: calc(100% - 40px);
33 | }
34 |
35 | .tabs__content > div:first-child {
36 | height: 100%;
37 | }
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import './index.css';
4 | import App from './components/App';
5 | import * as serviceWorker from './serviceWorker';
6 | import 'bootstrap/dist/css/bootstrap.min.css';
7 | import {HashRouter, Switch, Route} from "react-router-dom";
8 |
9 | ReactDOM.render(
10 |
11 |
12 |
13 |
14 |
15 | ,
16 | document.getElementById('root')
17 | );
18 |
19 | // If you want your app to work offline and load faster, you can change
20 | // unregister() to register() below. Note this comes with some pitfalls.
21 | // Learn more about service workers: http://bit.ly/CRA-PWA
22 | serviceWorker.unregister();
23 |
--------------------------------------------------------------------------------
/src/components/WaitingScreen.js:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react';
2 | import styled from 'styled-components'
3 | import anime from "animejs";
4 | import SvgCog from "../Images/Cog";
5 |
6 | const Container = styled.div`
7 | height: 40vh;
8 | margin: 30vh auto;
9 | color: var(--dark-main);
10 | text-align: center;
11 | `
12 |
13 | export default class WaitingScreen extends Component {
14 |
15 | constructor() {
16 | super();
17 |
18 | this.cog = React.createRef();
19 | }
20 |
21 | componentDidMount() {
22 | this.cogAnim = anime({
23 | targets: this.cog.current,
24 | loop: true,
25 | rotate: '360deg',
26 | duration: 4000,
27 | easing: 'linear'
28 | })
29 | }
30 |
31 | render() {
32 | return (
33 |
34 |
35 |
36 | );
37 | }
38 | }
--------------------------------------------------------------------------------
/src/Utils/index.js:
--------------------------------------------------------------------------------
1 | export function getFlatColors() {
2 | return {
3 | main: getComputedStyle(document.documentElement).getPropertyValue('--main'),
4 | darkMain: getComputedStyle(document.documentElement).getPropertyValue('--dark-main'),
5 | one: getComputedStyle(document.documentElement).getPropertyValue('--one'),
6 | two: getComputedStyle(document.documentElement).getPropertyValue('--two'),
7 | three: getComputedStyle(document.documentElement).getPropertyValue('--three'),
8 | four: getComputedStyle(document.documentElement).getPropertyValue('--four'),
9 | five: getComputedStyle(document.documentElement).getPropertyValue('--five'),
10 | gray: getComputedStyle(document.documentElement).getPropertyValue('--gray'),
11 | clearTextColor: getComputedStyle(document.documentElement).getPropertyValue('--clear-text-color'),
12 | DarkTextColor: getComputedStyle(document.documentElement).getPropertyValue('--dark-text-color')
13 | }
14 | }
--------------------------------------------------------------------------------
/src/Images/Cog.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | const SvgCog = React.forwardRef((props, ref) => (
4 |
5 |
9 |
10 | ));
11 |
12 | export default SvgCog;
13 |
--------------------------------------------------------------------------------
/src/ASMComponents/Function.js:
--------------------------------------------------------------------------------
1 | import React, {Component} from "react";
2 | import styled from "styled-components";
3 | import Registry from "../Utils/Registry";
4 | import {convert} from "../Utils/Converter";
5 |
6 | const FunctionContainer = styled.div`
7 | `
8 | const FunctionName = styled.div`
9 | font-size: 32px;
10 | font-weight: normal;
11 | color: rgb(72, 72, 72);
12 | margin-bottom: 15px;
13 | text-align: center;
14 | `
15 |
16 | export default class Function extends Component {
17 |
18 | constructor(props) {
19 | super(props);
20 |
21 | //Reset the registry because this is a new function!
22 | Registry.clear();
23 |
24 | props.params.forEach(param => {
25 | Registry.set(param.register, convert(param.value, 'uint', 8, 'uint', param.bitWidth));
26 | })
27 | }
28 |
29 |
30 | render() {
31 | return (
32 |
33 | {this.props.name}
34 |
35 |
36 | );
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/css/ASTVisualizer.css:
--------------------------------------------------------------------------------
1 | @import "GlobalVariables.css";
2 |
3 | .rst__rowContents {
4 | color: var(--clear-text-color);
5 | background-color: var(--main);
6 | border: none;
7 | border-radius: 10px;
8 | min-width: 0px;
9 | padding: 0 5px 0 25px;
10 | }
11 |
12 | .rst__rowTitle {
13 | font-weight: normal;
14 | }
15 |
16 | .Program .rst__rowContents {
17 | background-color: var(--dark-main);
18 | }
19 |
20 | .VariableDeclarator .rst__rowContents {
21 | background-color: var(--five);
22 | }
23 |
24 | .arguments .rst__rowContents {
25 | background-color: var(--three);
26 | }
27 |
28 | .BinaryExpression .rst__rowContents {
29 | background-color: var(--four);
30 | color: var(--dark-text-color);
31 | }
32 |
33 | .UnaryExpression .rst__rowContents {
34 | background-color: var(--four);
35 | color: var(--dark-text-color);
36 | }
37 |
38 | .AssignmentExpression .rst__rowContents {
39 | background-color: var(--four);
40 | color: var(--dark-text-color);
41 | }
42 |
43 | .Identifier .rst__rowContents {
44 | background-color: var(--one);
45 | }
46 |
47 | .Literal .rst__rowContents {
48 | background-color: var(--two);
49 | }
50 |
--------------------------------------------------------------------------------
/src/components/CodeStatus.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import styled from 'styled-components'
3 | import {getFlatColors} from "../Utils";
4 |
5 | const Status = styled.div`
6 | background: ${({bg}) => bg};
7 | display: flex;
8 | justify-content: flex-start;
9 | align-items: center;
10 | font-weight: 300
11 | font-size: 14px;
12 | padding: 5px;
13 | padding-left: 10px;
14 | margin-bottom: 5px;
15 |
16 | > span {
17 | font-weight: 500;
18 | margin-left: 10px;
19 | }
20 |
21 | @media (max-width: 700px) {
22 | font-size: 8px;
23 | }
24 | `
25 |
26 | export default function CodeStatus({status = 'compiles'}) {
27 | let color = '';
28 | let message = '';
29 | if (status === 'compiles') {
30 | color = getFlatColors().five;
31 | message = 'Code status: Compiles..';
32 | }
33 | else if (status === 'error') {
34 | color = getFlatColors().two;
35 | message = 'Code status: Error..';
36 | }
37 | else if (status === 'warning') {
38 | color = getFlatColors().four;
39 | message = 'Code status: warning..';
40 | }
41 |
42 | return (
43 |
44 | {message}
45 |
46 | );
47 | }
--------------------------------------------------------------------------------
/src/Images/CProgramming.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | const SvgCProgramming = React.forwardRef((props, ref) => (
4 |
5 |
6 |
10 |
14 |
18 |
22 |
23 |
24 | ));
25 |
26 | export default SvgCProgramming;
27 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "SIMD-Visualiser",
3 | "version": "0.1.0",
4 | "private": true,
5 | "homepage": "http://piotte13.github.io/SIMD-Visualiser",
6 | "dependencies": {
7 | "acorn": "^6.0.4",
8 | "animejs": "^2.2.0",
9 | "bitly": "^6.0.8",
10 | "bootstrap": "^4.1.3",
11 | "codemirror": "^5.41.0",
12 | "history": "^4.7.2",
13 | "i": "^0.3.6",
14 | "lodash": "^4.17.11",
15 | "node-sass": "^4.10.0",
16 | "npm": "^6.4.1",
17 | "prop-types": "^15.6.2",
18 | "qs": "^6.6.0",
19 | "rc-slider": "^8.6.4",
20 | "react": "^16.6.3",
21 | "react-codemirror2": "^5.1.0",
22 | "react-copy-to-clipboard": "^5.0.1",
23 | "react-dom": "^16.6.0",
24 | "react-rangeslider": "^2.2.0",
25 | "react-router-dom": "^4.3.1",
26 | "react-scripts": "2.0.5",
27 | "react-sortable-tree": "^2.3.0",
28 | "react-transition-group": "^2.5.0",
29 | "reactstrap": "^6.5.0",
30 | "request": "^2.88.0",
31 | "styled-components": "^4.0.2",
32 | "uint32": "^0.2.1"
33 | },
34 | "scripts": {
35 | "start": "react-scripts start",
36 | "build": "react-scripts build",
37 | "test": "react-scripts test",
38 | "eject": "react-scripts eject",
39 | "predeploy": "npm run build",
40 | "deploy": "gh-pages -d build"
41 | },
42 | "eslintConfig": {
43 | "extends": "react-app"
44 | },
45 | "browserslist": [
46 | ">0.2%",
47 | "not dead",
48 | "not ie <= 11",
49 | "not op_mini all"
50 | ],
51 | "devDependencies": {
52 | "gh-pages": "^2.0.1"
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/Utils/Compiler.js:
--------------------------------------------------------------------------------
1 | import * as request from 'request';
2 |
3 |
4 | //Callback must be -> callback(error, asm, ast)
5 | export function compile(code, callback) {
6 | let options = {
7 | url: 'https://godbolt.org/api/compiler/clang700/compile',
8 | method: 'POST',
9 | headers: {
10 | 'content-type': 'application/json'
11 | },
12 | json: true,
13 | body: {
14 | "source": code,
15 | "compiler": "clang700",
16 | "options": {
17 | "userArguments": "-O3 -march=native",
18 | "compilerOptions": {
19 | "produceGccDump": {},
20 | "produceCfg": false,
21 | "produceAst": true
22 | },
23 | "filters": {
24 | "binary": false,
25 | "execute": false,
26 | "labels": true,
27 | "directives": true,
28 | "commentOnly": true,
29 | "trim": true,
30 | "intel": true,
31 | "demangle": true
32 | },
33 | "tools": []
34 | },
35 | "lang": "c++"
36 | }
37 | };
38 | request(options, (error, response, body) => {
39 | if (error) {
40 | alert("oops! https://godbolt.org/ seems to be down! \n You will have to wait my friend.")
41 | callback({}, [], "")
42 | }
43 | else {
44 | callback(body.stderr, body.asm, body.astOutput)
45 | }
46 | })
47 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | BSD 3-Clause License
2 |
3 | Copyright (c) 2018, Jeremie Piotte and Pierre Marie Ntang
4 | All rights reserved.
5 |
6 | Redistribution and use in source and binary forms, with or without
7 | modification, are permitted provided that the following conditions are met:
8 |
9 | * Redistributions of source code must retain the above copyright notice, this
10 | list of conditions and the following disclaimer.
11 |
12 | * Redistributions in binary form must reproduce the above copyright notice,
13 | this list of conditions and the following disclaimer in the documentation
14 | and/or other materials provided with the distribution.
15 |
16 | * Neither the name of the copyright holder nor the names of its
17 | contributors may be used to endorse or promote products derived from
18 | this software without specific prior written permission.
19 |
20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 |
--------------------------------------------------------------------------------
/src/Utils/Tabs.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable jsx-a11y/anchor-is-valid */
2 | import React, {Component} from "react";
3 | import "../css/Tabs.css"
4 |
5 | export class Tabs extends Component {
6 | state = {
7 | selected: this.props.selected
8 | };
9 |
10 | shouldComponentUpdate(nextProps, nextState) {
11 | return this.props !== nextProps || this.state !== nextState;
12 | }
13 |
14 | handleClick = (index, event) => {
15 | event.preventDefault();
16 | this.setState({
17 | selected: index
18 | });
19 | }
20 | _renderTitles = () => {
21 |
22 | return (
23 |
36 | );
37 | };
38 |
39 | _renderContent = () => {
40 | return (
41 |
42 | {this.props.children[this.state.selected]}
43 |
44 | );
45 | };
46 |
47 | render() {
48 | return (
49 |
50 | {this._renderTitles()}
51 | {this._renderContent()}
52 |
53 | );
54 | }
55 | }
56 |
57 | export class Pane extends Component {
58 | render() {
59 | return (
60 |
61 | {this.props.children}
62 |
63 | );
64 | }
65 | };
66 |
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
10 |
14 |
15 |
24 | SIMD Visualizer
25 |
26 |
27 |
28 | You need to enable JavaScript to run this app.
29 |
30 |
31 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/src/Images/c-programming.svg:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
7 |
9 |
11 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/src/ASMComponents/ret.js:
--------------------------------------------------------------------------------
1 | import React, {Component} from "react";
2 | import Registry from "../Utils/Registry";
3 | import Vector from "./Vector";
4 | import anime from 'animejs';
5 |
6 | export default class Ret extends Component {
7 |
8 | static defaultProps = {
9 | type: "uint",
10 | bitWidth: 32,
11 | base: 10,
12 | };
13 |
14 | constructor(props) {
15 | super(props);
16 |
17 | //Ret returns value on top of the stack. For now we will assume the value is always 128 bits... (Xmm)
18 | let returnValue = Registry.get('xmm0');
19 |
20 | this.state = {
21 | returnValue,
22 | };
23 |
24 | this.vector = React.createRef();
25 | this.computeCommand();
26 | }
27 |
28 | getAnimation() {
29 |
30 | //We make an empty timeline because sequentialComponent needs to know when to jump to the next command.
31 | let timeline = anime.timeline({
32 | easing: "linear",
33 | autoplay: false,
34 | });
35 |
36 | timeline
37 | .add({
38 | targets: this.vector.current,
39 | duration: 1000
40 | });
41 |
42 | let eternalGlow = anime.timeline({
43 | easing: "linear",
44 | loop: true,
45 | autoplay: true,
46 | direction: 'alternate'
47 | });
48 |
49 | eternalGlow // Creates the glow arround the returned vector (glowing box shadow)
50 | .add({
51 | targets: this.vector.current,
52 | filter: ["drop-shadow(0px 0px 10px rgba(42, 54, 59, 1))", "drop-shadow(0px 0px 1px rgba(42, 54, 59, .5))"],
53 | duration: 1000
54 | });
55 |
56 | return timeline;
57 | }
58 |
59 | //Compute the command and set the registry.
60 | computeCommand() {
61 |
62 | }
63 |
64 | render() {
65 | let {returnValue} = this.state;
66 | let {type, bitWidth, base} = this.props;
67 |
68 | return (
69 | this.vector = ref}/>
74 | );
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/src/components/ErrorHandler.js:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react';
2 | import styled from "styled-components";
3 | import SvgCryingboy from "../Images/Cryingboy";
4 |
5 | const ErrorPageContainer = styled.div`
6 | padding: 50px;
7 | `
8 |
9 | const TextJumbo = styled.div`
10 | font-size: 60px;
11 | font-weight: 700;
12 | color: rgb(72, 72, 72);
13 | margin-bottom: 15px;
14 | `
15 |
16 | const ErrorMessage = styled.div`
17 | font-size: 32px;
18 | font-weight: normal;
19 | color: rgb(72, 72, 72);
20 | margin-bottom: 15px;
21 | margin-top: 25px;
22 | `
23 |
24 | const ErrorPosition = styled.div`
25 | font-size: 14px;
26 | font-weight: bold;
27 | color: #767676;
28 | margin-bottom: 15px;
29 | margin-top: 25px;
30 | `
31 | const ImageContainer = styled.div`
32 | position: absolute;
33 | bottom: 0;
34 | right: 0;
35 | width: 50vh;
36 | `
37 |
38 | class ErrorHandler extends Component {
39 |
40 | componentDidMount() {
41 | if (this.props.error.length !== 0) {
42 | this.highlightCode();
43 | }
44 | }
45 |
46 | componentWillUnmount() {
47 | this.clearHighlightedCode()
48 | }
49 |
50 | highlightCode = () => {
51 | const line = this.props.error[0].tag.line - 1;
52 | let cm = this.props.cm.current;
53 | if (cm) {
54 | const lineLength = cm.editor.getLine(line).length;
55 | cm.editor.doc.markText({line, ch: 0}, {line, ch: lineLength}, {
56 | className: 'highlighted-code'
57 | });
58 | }
59 | };
60 |
61 | clearHighlightedCode = () => {
62 | let cm = this.props.cm.current;
63 | cm && cm.editor.doc.getAllMarks().forEach((m) => {
64 | m.clear()
65 | })
66 | };
67 |
68 | getErrorMessage = () => {
69 | return this.props.error[0].tag.text;
70 | }
71 | getErrorPosition = () => {
72 | return
73 |
Line: {this.props.error[0].tag.line}
74 |
Column: {this.props.error[0].tag.column}
75 |
76 |
77 | }
78 |
79 | render() {
80 | return (
81 |
82 | Oops!
83 |
84 | {this.getErrorMessage()}
85 |
86 |
87 | {this.getErrorPosition()}
88 |
89 |
90 |
91 |
92 |
93 | );
94 | }
95 | }
96 |
97 | export default ErrorHandler;
--------------------------------------------------------------------------------
/src/Images/cog.svg:
--------------------------------------------------------------------------------
1 |
2 |
17 |
19 |
20 |
22 | image/svg+xml
23 |
25 |
26 |
27 |
28 |
30 |
50 |
53 |
58 |
59 |
60 |
--------------------------------------------------------------------------------
/src/components/FrontPage.js:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react';
2 | import styled from 'styled-components'
3 | import anime from "animejs";
4 | import SvgCProgramming from "../Images/CProgramming";
5 |
6 |
7 | const Image = styled.div`
8 | width: 40vmin;
9 | margin: 8vh auto;
10 | `
11 | const AppTitle = styled.div`
12 | text-align: center;
13 | font-weight: 300;
14 | font-size: calc(12px + 3.6vw);
15 | letter-spacing: 1.8px;
16 | margin-top: 40px;
17 | border: medium none;
18 | margin-bottom: 20px;
19 | `
20 | const AppDescription = styled.div`
21 | text-align: center;
22 | font-weight: 300;
23 | margin: 0px auto;
24 | font-size: calc(8px + 0.91vw);
25 | `
26 | const Container = styled.div`
27 | `
28 |
29 | const GHButton = styled.button`
30 | padding: 3px 10px 3px 8px;
31 | font-size: 16px;
32 | line-height: 22px;
33 | border-radius: 4px;
34 | text-shadow: 0 1px 0 #fff;
35 | white-space: nowrap;
36 | cursor: pointer;
37 | color: #333;
38 | background-repeat: no-repeat;
39 | border: 1px solid #d5d5d5;
40 | font-weight: 700;
41 | vertical-align: top;
42 | margin: 0 10px;
43 |
44 | :hover{
45 | text-decoration: none;
46 | background-color: #ddd;
47 | background-image: -webkit-gradient(linear,left top,left bottom,color-stop(0,#eee),color-stop(100%,#ddd));
48 | background-image: -webkit-linear-gradient(top,#eee 0,#ddd 100%);
49 | background-image: -moz-linear-gradient(top,#eee 0,#ddd 100%);
50 | background-image: -ms-linear-gradient(top,#eee 0,#ddd 100%);
51 | background-image: -o-linear-gradient(top,#eee 0,#ddd 100%);
52 | background-image: linear-gradient(to bottom,#eee 0,#ddd 100%);
53 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#eeeeee', endColorstr='#dddddd', GradientType=0);
54 | border-color: #ccc;
55 | }
56 | `
57 |
58 | const ButtonGroup = styled.div`
59 | margin-top: 40px;
60 | text-align: center;
61 | `
62 |
63 | export default class FrontPage extends Component {
64 | constructor() {
65 | super();
66 |
67 | this.image = React.createRef();
68 | this.imageContainer = React.createRef();
69 | }
70 |
71 | componentDidMount() {
72 | let scaleAnime = anime({
73 | easing: "easeOutCubic",
74 | targets: this.imageContainer.current,
75 | direction: 'alternate',
76 | duration: 2000,
77 | scale: '.9',
78 | loop: true
79 | });
80 |
81 | let spinAnime = anime({
82 | targets: this.image.current,
83 | delay: 6000,
84 | duration: 4000,
85 | rotate: '360deg',
86 | loop: true
87 | })
88 | }
89 |
90 |
91 | render() {
92 | return (
93 |
94 |
95 |
96 |
97 |
98 |
99 | The Ultimate SIMD visualizer
100 |
101 | Built by Jérémie Piotte , Daniel Lemire and Pierre Marie
102 | Ntang
103 |
104 |
105 |
106 | View on GitHub
107 |
108 |
111 |
112 |
113 | )
114 | }
115 | }
--------------------------------------------------------------------------------
/src/Utils/Registry.js:
--------------------------------------------------------------------------------
1 | import * as _ from "lodash";
2 |
3 | export const NB_SIMD_REGISTERS = 32;
4 | export const NB_GP_REGISTERS = 16;
5 | export const ARCHITECTURE_SIZE = 64;
6 | export const VAR_SIZE = 8; //Octets
7 | export const TYPE_LENGTH = {
8 | x: 512 / (4 * VAR_SIZE),
9 | y: 512 / (2 * VAR_SIZE),
10 | z: 512 / VAR_SIZE
11 | };
12 | const isSIMDRegister = /[x-z]mm[0-9]+/;
13 |
14 | //Containing all the names of the general purpose registers classified by their bit width.
15 | const GPRegistersNamesByBitWidth = {
16 | 64: ['rax', 'rbx', 'rcx', 'rdx', 'rsi', 'rdi', 'rbp', 'rsp', 'r8', 'r9', 'r10', 'r11', 'r12', 'r13', 'r14', 'r15'],
17 | 32: ['eax', 'ebx', 'ecx', 'edx', 'esi', 'edi', 'ebp', 'esp', 'r8d', 'r9d', 'r10d', 'r11d', 'r12d', 'r13d', 'r14d', 'r15d'],
18 | 16: ['ax', 'bx', 'cx', 'dx', 'si', 'di', 'bp', 'sp', 'r8w', 'r9w', 'r10w', 'r11w', 'r12w', 'r13w', 'r14w', 'r15w'],
19 | 8: ['al', 'bl', 'cl', 'dl', 'sil', 'dil', 'bpl', 'spl', 'r8b', 'r9b', 'r10b', 'r11b', 'r12b', 'r13b', 'r14b', 'r15b']
20 | };
21 | //Fastcall registers are used to pass parameters to functions.
22 | export const FAST_CALL_REGISTERS = ['rdi', 'rsi', 'rdx', 'rcx', 'r8', 'r9'];
23 |
24 | //A dictionary of general purpose registers. example usage: GPRegistersNameMap["rax"] -> returns: {bitWidth: 64, index: 1}
25 | //index tells us which of the _GPRegisters the given name represents.
26 | const GPRegistersNameMap = {};
27 | _.forIn(GPRegistersNamesByBitWidth, (names, bitWidth) => {
28 | names.forEach((name, index) => {
29 | GPRegistersNameMap[name] = {
30 | bitWidth,
31 | index
32 | }
33 | });
34 | });
35 |
36 | class Registry {
37 | constructor() {
38 | // the array _SIMDRegisters contains NB_REGISTERS arrays
39 | // of size 512 / VAR_SIZE filled with byte-sized values
40 | this._SIMDRegisters = new Array(NB_SIMD_REGISTERS).fill(0).map(() =>
41 | new Array(TYPE_LENGTH["z"]).fill(0).map((val, i) => i)
42 | );
43 |
44 | // the array _GPRegisters (general purpose registers) contains NB_GP_REGISTERS arrays
45 | // of size ARCHITECTURE_SIZE (64) / (8) VAR_SIZE filled with byte-sized values
46 | this._GPRegisters = new Array(NB_GP_REGISTERS).fill(0).map(() =>
47 | new Array(ARCHITECTURE_SIZE / VAR_SIZE).fill(0).map((val, i) => i)
48 | );
49 |
50 | }
51 |
52 | // stores the value in array into the "register" where register is something like xmm0
53 | set = (register, array) => {
54 | if (isSIMDRegister.test(register)) {
55 | const idx = +register.substring(3); // should be the number of the register, between 0 and 32
56 | const type = register[0];// should be x, y, z
57 |
58 | this._SIMDRegisters[idx].splice(0, TYPE_LENGTH[type], ...array);
59 | }
60 | else if (GPRegistersNameMap[register]) {
61 | const {bitWidth, index} = GPRegistersNameMap[register]
62 | this._GPRegisters[index].splice(0, bitWidth / VAR_SIZE, ...array);
63 | }
64 | }
65 | ;
66 |
67 | // get either an x, a y or a z register, where "register" is a string like xmm0
68 | get = (register) => {
69 | if (isSIMDRegister.test(register)) {
70 | const idx = +register.substring(3);// number of the register, should be between 0 and 32 on x64
71 | const type = register[0];// should be x, y or z
72 | //return the last n elements of the register.
73 | return this._SIMDRegisters[idx].slice(0, TYPE_LENGTH[type])// slice apparently copies the value
74 | }
75 |
76 | const {bitWidth, index} = GPRegistersNameMap[register];
77 | if (bitWidth && index)
78 | return this._GPRegisters[index].slice(0, bitWidth / VAR_SIZE);
79 |
80 | else return null;
81 | };
82 |
83 | // clear resets the "registers"
84 | clear = () => {
85 | this._SIMDRegisters.map(() =>
86 | new Array(TYPE_LENGTH["z"]).fill(0).map((val, i) => i));
87 |
88 | this._GPRegisters.map(() =>
89 | new Array(ARCHITECTURE_SIZE / VAR_SIZE).fill(0).map((val, i) => i));
90 | }
91 | }
92 |
93 | const instance = new Registry();
94 | Object.freeze(instance);
95 |
96 | export default instance;
97 |
--------------------------------------------------------------------------------
/src/ASMComponents/Shift.js:
--------------------------------------------------------------------------------
1 | import React, {Component} from "react";
2 | import Registry from "../Utils/Registry";
3 | import Vector from "./Vector";
4 | import * as _ from "lodash";
5 | import anime from 'animejs';
6 |
7 | const SHIFT_INDEX = 2;
8 | const INPUT_INDEX = 1;
9 | const OUTPUT_INDEX = 0;
10 |
11 | export default class Shift extends Component {
12 |
13 | static defaultProps = {
14 | type: "uint",
15 | bitWidth: 32,
16 | base: 16,
17 | direction: 'left',
18 | // if no shiftData provided, default to zeroes.
19 | shiftData: new Array(64).fill(0)
20 | };
21 |
22 | constructor(props) {
23 | super(props);
24 |
25 | let shiftLen = props.params[SHIFT_INDEX];
26 | let input = Registry.get(props.params[INPUT_INDEX]);
27 | const defaultBitWidth = props.defaultValues.length > 0 ? props.defaultValues[0].bitWidth : props.bitWidth;
28 | const defaultBase = props.defaultValues.length > 0 ? props.defaultValues[0].base : props.base;
29 | this.state = {
30 | shiftLen,
31 | input,
32 | output: [],
33 | defaultBitWidth,
34 | defaultBase
35 | };
36 | this.computeCommand();
37 | }
38 |
39 | getAnimation() {
40 | let directionValue = {"right": 1, "left": -1};
41 | let {bitWidth} = this.props;
42 | let {shiftLen, input} = this.state;
43 | //In order to make it responsive, we have to calculate the shift in percentage of the vector length. Clever.
44 | let shiftPercentage = 100 * directionValue[this.props.direction] * shiftLen * bitWidth / (input.length * 8);
45 |
46 | let timeline = anime.timeline({
47 | easing: "easeOutCubic",
48 | loop: false,
49 | autoplay: false
50 | });
51 |
52 | //TODO: Convert the visualisation from the desired visualization bitWidth (from the parameter page) to the command bitWidth (props).
53 | // const nbOfConversion = Math.log2(this.props.bitWidth) - Math.log2(this.state.defaultBitWidth);
54 | //
55 | // _.times(Math.abs(nbOfConversion)).forEach(() => {
56 | // const multiplicative = nbOfConversion > 0 ? 2 : 0.5;
57 | // timeline
58 | // .add({
59 | // duration: 600,
60 | // delay: 300,
61 | // complete: () => {this.setState({defaultBitWidth: this.state.defaultBitWidth * multiplicative})}
62 | // })
63 | // });
64 |
65 | timeline
66 | .add({
67 | targets: this.numbersRef.current,
68 | translateX: `${shiftPercentage}%`,
69 | duration: 2000,
70 | delay: 1000
71 | });
72 |
73 | // _.times(Math.abs(nbOfConversion)).forEach(() => {
74 | // const multiplicative = nbOfConversion < 0 ? 2 : 0.5;
75 | // timeline
76 | // .add({
77 | // duration: 600,
78 | // delay: 300,
79 | // complete: () => {this.setState({defaultBitWidth: this.state.defaultBitWidth * multiplicative})}
80 | // })
81 | // });
82 |
83 | return timeline;
84 | }
85 |
86 | //Compute the command and set the registry.
87 | computeCommand() {
88 | let {params, bitWidth} = this.props;
89 | let shiftLen = params[SHIFT_INDEX] * (bitWidth / 8);
90 | let input = Registry.get(params[INPUT_INDEX]);
91 | let output = _.cloneDeep(input);
92 | output.push(...new Array(shiftLen).fill(0));
93 | output = output.slice(-input.length);
94 | Registry.set(params[OUTPUT_INDEX], output);
95 | }
96 |
97 | render() {
98 | let {input, defaultBitWidth, defaultBase} = this.state;
99 | let {type, bitWidth, base, shiftData} = this.props;
100 |
101 | return (
102 | this.numbersRef = ref}/>
108 | );
109 | }
110 | }
--------------------------------------------------------------------------------
/src/components/ButtonPanel.js:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react';
2 | import styled from 'styled-components'
3 | import CodeStatus from "./CodeStatus";
4 | import {Popover, PopoverBody} from 'reactstrap';
5 | import {BitlyClient} from 'bitly';
6 | import {InputGroup, InputGroupAddon, Button, Input} from 'reactstrap';
7 | import {CopyToClipboard} from 'react-copy-to-clipboard';
8 |
9 | const ButtonPanelContainer = styled.div`
10 | background: #1F292E;
11 | display: flex;
12 | flex-direction: column;
13 | justify-content: space-between;
14 | `
15 |
16 | const Top = styled.div`
17 | padding: 3px;
18 | display: flex;
19 | justify-content: space-between;
20 | align-items: center;
21 | margin: 10px;
22 | `
23 |
24 | const Buttons = styled.div`
25 | width: 100%;
26 | display: flex;
27 | > button {
28 | border: none;
29 | background: none;
30 | color: #fff;
31 | font-size: 18px;
32 | padding: 8px;
33 | text-shadow: -1px -1px 1px rgba(255,255,255,.1), 1px 1px 1px rgba(0,0,0,.5);
34 |
35 | @media (max-width: 700px) {
36 | font-size: 10px;
37 | }
38 | }
39 |
40 | > button:hover {
41 | color: #fff;
42 | cursor: pointer;
43 | }
44 |
45 | > button:disabled {
46 | color: #919191;
47 | }
48 |
49 | > button:active {
50 | color: #fff;
51 | text-shadow: none;
52 | }
53 |
54 | > #sharePopover {
55 | margin-left:auto;
56 | opacity: 0.6;
57 | }
58 |
59 | > #sharePopover:hover {
60 | opacity: 1;
61 | }
62 | `
63 |
64 | export default class ButtonPanel extends Component {
65 |
66 | constructor(props) {
67 | super(props);
68 | this.bitly = new BitlyClient('e17981e1eef5e2ec83995b478b899564448b9496', {});
69 |
70 | this.toggleShare = this.toggleShare.bind(this);
71 | this.state = {
72 | popoverOpen: false,
73 | shareLink: 'Loading...'
74 | };
75 |
76 | this.textAreaRef = React.createRef();
77 | }
78 |
79 | toggleShare() {
80 | let longUrl = this.props.getShareLink();
81 | this.setState({
82 | popoverOpen: !this.state.popoverOpen
83 | });
84 | this.bitly
85 | .shorten(longUrl)
86 | .then((result) => {
87 | this.setState({
88 | shareLink: result.url
89 | });
90 | })
91 | .catch((error) => {
92 | this.setState({
93 | shareLink: longUrl
94 | });
95 | console.error(error);
96 | });
97 |
98 |
99 | }
100 |
101 | render() {
102 | let {visualize, restart, disabled = false, status} = this.props;
103 |
104 | return (
105 |
106 |
107 |
108 | Visualize
109 | Restart
110 |
111 |
112 |
113 |
114 |
115 |
117 |
118 |
119 |
120 |
121 |
122 | this.setState({popoverOpen: false})}>
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 | );
136 | }
137 | }
--------------------------------------------------------------------------------
/src/Utils/Converter.js:
--------------------------------------------------------------------------------
1 | // should be in a distinct file
2 | import uint32 from "uint32";
3 | import * as _ from "lodash";
4 |
5 |
6 | let toUINT = (array, toBitWidth, fromType, fromBitWidth) => {
7 |
8 | let output = [];
9 |
10 | if (toBitWidth === 32) {
11 | // we have four bytes per 32-bit int
12 | output = _.times(array.length / 4).map(i =>
13 | uint32.fromBytesBigEndian(array[4 * i], array[4 * i + 1], array[4 * i + 2], array[4 * i + 3])
14 | );
15 | }
16 |
17 | else if (toBitWidth === 8) {
18 | // Temporary... For testing purposes only. Should and will be perfected.
19 | if (fromBitWidth === 8)
20 | output = array.map(value => Math.abs(value)) //new Uint8Array(array);
21 |
22 | else if (fromBitWidth === 32) {
23 | output = new Array(array.length * 4);
24 | // we have four bytes per 32-bit ints
25 | for (var z = 0; z < array.length; z++) {
26 | output[4 * z] = uint32.getByteBigEndian(array[z], 3);
27 | output[4 * z + 1] = uint32.getByteBigEndian(array[z], 2);
28 | output[4 * z + 2] = uint32.getByteBigEndian(array[z], 1);
29 | output[4 * z + 3] = uint32.getByteBigEndian(array[z], 0);
30 | }
31 | }
32 | }
33 |
34 | return output
35 | };
36 |
37 | let toINT = (array, toBitWidth, fromType, fromBitWidth) => {
38 | // TODO
39 | return array
40 | };
41 |
42 | let toDouble = (array, toBitWidth, fromType, fromBitWidth) => {
43 | // TODO
44 | return array
45 | };
46 |
47 |
48 | export function convert(data, toType, toBitWidth, fromType, fromBitWidth) {
49 | let values = [];
50 |
51 | //if (toBitWidth === 64 || fromBitWidth === 64) return null;
52 |
53 | if (toBitWidth < fromBitWidth) {
54 | _.forEach(data, lane => {
55 | let newLanes = [];
56 |
57 | _.times(fromBitWidth / toBitWidth).forEach(i => {
58 | const mask = _.padEnd("0b", toBitWidth + 2, '1');
59 | newLanes.push((lane >> (i * toBitWidth)) & mask);
60 | });
61 |
62 | _.forEachRight(newLanes, nl => {
63 | values.push(nl)
64 | });
65 | });
66 | }
67 |
68 | //TODO: overflow bug in conversion! see the Arithmetic animation..
69 | else if (toBitWidth > fromBitWidth) {
70 | const newNbOfLanes = (data.length * fromBitWidth) / toBitWidth;
71 | const nbOfOldLanesInOneNewLane = data.length / newNbOfLanes;
72 | _.times(newNbOfLanes).forEach(i => {
73 | const currentPosition = i * nbOfOldLanesInOneNewLane;
74 | const lanesToMerge = _.slice(data, currentPosition, currentPosition + nbOfOldLanesInOneNewLane);
75 | let newLane = 0;
76 | const mask = _.padEnd("0b", fromBitWidth + 2, '1');
77 |
78 | _.forEach(lanesToMerge, (laneToMerge, i) => {
79 | let safeFromBitWidthNumber = laneToMerge & mask;
80 | newLane = (newLane << (i * fromBitWidth)) | safeFromBitWidthNumber;
81 | });
82 |
83 | values.push(newLane);
84 | });
85 | }
86 |
87 | else values = data.slice(0);
88 |
89 | // switch (toType) {
90 | // case "uint":
91 | // values = toUINT(data, toBitWidth, fromType, fromBitWidth);
92 | // break;
93 | // case "int":
94 | // values = toINT(data, toBitWidth, fromType, fromBitWidth);
95 | // break;
96 | // case "double":
97 | // values = toDouble(data, toBitWidth, fromType, fromBitWidth);
98 | // break;
99 | // default:
100 | // values = data.slice(0);
101 | // }
102 |
103 | return values;
104 | }
105 |
106 |
107 | export function convertToStrings(data, toType, toBitWidth, base = 16, precision = 0, fromType = "int", fromBitWidth = 8) {
108 |
109 | let values = convert(data, toType, toBitWidth, fromType, fromBitWidth);
110 | //Convert values to given base representation. Ex: Hex, decimal, binary...
111 |
112 | _.mixin({'toBase': (val, base) => val.toString(base)});
113 |
114 | return values.map(value =>
115 | _.chain(value)
116 | .round(precision)
117 | .toBase(base)
118 | //.padStart(toBitWidth / 4, '0') //to be perfected.
119 | .toUpper()
120 | .value()
121 | );
122 | };
--------------------------------------------------------------------------------
/src/ASMComponents/Vector.js:
--------------------------------------------------------------------------------
1 | import React, {Component} from "react";
2 | import * as _ from "lodash";
3 | import "../css/Vector.css";
4 | import {convertToStrings} from "../Utils/Converter";
5 |
6 | export default class Vector extends Component {
7 |
8 | static defaultProps = {
9 | type: "uint",
10 | bitWidth: 32,
11 | data: [],
12 | base: 10,
13 | shiftData: [],
14 | numbersRef: () => {
15 | },
16 | vectorRef: () => {
17 | }
18 |
19 | };
20 |
21 | constructor(props) {
22 | super(props);
23 |
24 | this.state = {
25 | width: window.innerWidth
26 | };
27 |
28 | this.numbersRef = React.createRef();
29 | this.vectorRef = React.createRef();
30 | props.numbersRef(this.numbersRef);
31 | props.vectorRef(this.vectorRef);
32 | }
33 |
34 | componentDidMount() {
35 | this.updateWidth();
36 | window.addEventListener("resize", this.updateWidth);
37 | }
38 |
39 | componentWillUnmount() {
40 | window.removeEventListener("resize", this.updateWidth);
41 | }
42 |
43 | updateWidth = () => {
44 | this.setState({width: window.innerWidth});
45 | };
46 |
47 | render() {
48 | let {data, shiftData, type, bitWidth, base} = this.props;
49 |
50 | let values = convertToStrings(data, type, bitWidth, base);
51 | let shiftValues = convertToStrings(shiftData, type, bitWidth, base);
52 | let elCount = values.length;
53 | let rectHeight = 50;
54 | let padding = 20;
55 | let rectLen = (this.state.width / 2) - padding - 80;
56 | return (
57 |
59 |
61 | {
62 | _.times(elCount - 1, Number).map(i => {
63 | let x = padding / 2 + (rectLen / elCount) * (i + 1);
64 | return
66 | })
67 | }
68 |
70 |
71 | {
72 | values.map((number, i) => {
73 | const x = (rectLen / elCount) * i;
74 | return (
75 |
76 | {number}
77 |
78 | )
79 | })
80 | }
81 | {
82 | shiftValues.map((number, i) => {
83 | const x = (rectLen / elCount) * i;
84 | const offset = (rectLen / elCount) * shiftValues.length;
85 | return (
86 |
87 |
88 | {shiftValues[i]}
90 |
91 |
92 | {shiftValues[i]}
94 |
95 |
96 | )
97 | })
98 | }
99 |
100 |
101 |
102 | );
103 | }
104 | }
--------------------------------------------------------------------------------
/src/serviceWorker.js:
--------------------------------------------------------------------------------
1 | // This optional code is used to register a service worker.
2 | // register() is not called by default.
3 |
4 | // This lets the app load faster on subsequent visits in production, and gives
5 | // it offline capabilities. However, it also means that developers (and users)
6 | // will only see deployed updates on subsequent visits to a page, after all the
7 | // existing tabs open on the page have been closed, since previously cached
8 | // resources are updated in the background.
9 |
10 | // To learn more about the benefits of this model and instructions on how to
11 | // opt-in, read http://bit.ly/CRA-PWA.
12 |
13 | const isLocalhost = Boolean(
14 | window.location.hostname === 'localhost' ||
15 | // [::1] is the IPv6 localhost address.
16 | window.location.hostname === '[::1]' ||
17 | // 127.0.0.1/8 is considered localhost for IPv4.
18 | window.location.hostname.match(
19 | /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
20 | )
21 | );
22 |
23 | export function register(config) {
24 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
25 | // The URL constructor is available in all browsers that support SW.
26 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location);
27 | if (publicUrl.origin !== window.location.origin) {
28 | // Our service worker won't work if PUBLIC_URL is on a different origin
29 | // from what our page is served on. This might happen if a CDN is used to
30 | // serve assets; see https://github.com/facebook/create-react-app/issues/2374
31 | return;
32 | }
33 |
34 | window.addEventListener('load', () => {
35 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
36 |
37 | if (isLocalhost) {
38 | // This is running on localhost. Let's check if a service worker still exists or not.
39 | checkValidServiceWorker(swUrl, config);
40 |
41 | // Add some additional logging to localhost, pointing developers to the
42 | // service worker/PWA documentation.
43 | navigator.serviceWorker.ready.then(() => {
44 | console.log(
45 | 'This web app is being served cache-first by a service ' +
46 | 'worker. To learn more, visit http://bit.ly/CRA-PWA'
47 | );
48 | });
49 | } else {
50 | // Is not localhost. Just register service worker
51 | registerValidSW(swUrl, config);
52 | }
53 | });
54 | }
55 | }
56 |
57 | function registerValidSW(swUrl, config) {
58 | navigator.serviceWorker
59 | .register(swUrl)
60 | .then(registration => {
61 | registration.onupdatefound = () => {
62 | const installingWorker = registration.installing;
63 | installingWorker.onstatechange = () => {
64 | if (installingWorker.state === 'installed') {
65 | if (navigator.serviceWorker.controller) {
66 | // At this point, the updated precached content has been fetched,
67 | // but the previous service worker will still serve the older
68 | // content until all client tabs are closed.
69 | console.log(
70 | 'New content is available and will be used when all ' +
71 | 'tabs for this page are closed. See http://bit.ly/CRA-PWA.'
72 | );
73 |
74 | // Execute callback
75 | if (config && config.onUpdate) {
76 | config.onUpdate(registration);
77 | }
78 | } else {
79 | // At this point, everything has been precached.
80 | // It's the perfect time to display a
81 | // "Content is cached for offline use." message.
82 | console.log('Content is cached for offline use.');
83 |
84 | // Execute callback
85 | if (config && config.onSuccess) {
86 | config.onSuccess(registration);
87 | }
88 | }
89 | }
90 | };
91 | };
92 | })
93 | .catch(error => {
94 | console.error('Error during service worker registration:', error);
95 | });
96 | }
97 |
98 | function checkValidServiceWorker(swUrl, config) {
99 | // Check if the service worker can be found. If it can't reload the page.
100 | fetch(swUrl)
101 | .then(response => {
102 | // Ensure service worker exists, and that we really are getting a JS file.
103 | if (
104 | response.status === 404 ||
105 | response.headers.get('content-type').indexOf('javascript') === -1
106 | ) {
107 | // No service worker found. Probably a different app. Reload the page.
108 | navigator.serviceWorker.ready.then(registration => {
109 | registration.unregister().then(() => {
110 | window.location.reload();
111 | });
112 | });
113 | } else {
114 | // Service worker found. Proceed as normal.
115 | registerValidSW(swUrl, config);
116 | }
117 | })
118 | .catch(() => {
119 | console.log(
120 | 'No internet connection found. App is running in offline mode.'
121 | );
122 | });
123 | }
124 |
125 | export function unregister() {
126 | if ('serviceWorker' in navigator) {
127 | navigator.serviceWorker.ready.then(registration => {
128 | registration.unregister();
129 | });
130 | }
131 | }
132 |
--------------------------------------------------------------------------------
/src/ASMComponents/SequentialComponent.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import styled from "styled-components";
3 | import anime from 'animejs';
4 |
5 | const Container = styled.div`
6 | margin: 40px 0 20px 0;
7 | opacity: 0;
8 | text-align: center;
9 | pointer-events: none;
10 |
11 | :first-child, last-child{
12 | margin: 20px 0;
13 | }
14 | `
15 |
16 | export default class SequentialComponent extends React.Component {
17 |
18 | constructor() {
19 | super();
20 | this.state = {
21 | touchable: false
22 | };
23 |
24 | // create li DOM reference
25 | this.container = React.createRef();
26 | this.component = React.createRef();
27 |
28 | }
29 |
30 | allAnimationCompleted() {
31 | this.props.onComplete(this.props.index);
32 | //Remove sequential highlight since the component is done animating.
33 | if (this.sequentialHighlight)
34 | this.sequentialHighlight.clear();
35 | }
36 |
37 | componentDidMount() {
38 | this.childAnimation = false;
39 | let c = this.component.current;
40 | if (c && c.getAnimation) {
41 | this.childAnimation = c.getAnimation();
42 | }
43 |
44 | this.animeRef = anime({
45 | targets: this.container.current,
46 | easing: "easeOutCubic",
47 | autoplay: false,
48 | translateY: ['5vh', 0],
49 | duration: 500,
50 | delay: 800,
51 | opacity: 1,
52 | complete: () => {
53 |
54 | if (this.childAnimation) {
55 | this.childAnimation.restart();
56 | this.childAnimation.finished.then(() => {
57 | this.allAnimationCompleted()
58 | this.setState({touchable: true});
59 | });
60 | }
61 | else {
62 | this.setState({touchable: true});
63 | this.allAnimationCompleted();
64 | }
65 | }
66 | });
67 |
68 | if (this.props.shouldBeVisible) {
69 | this.animeRef.restart()
70 | }
71 | }
72 |
73 | componentWillUnmount() {
74 | if (this.sequentialHighlight)
75 | this.sequentialHighlight.clear();
76 |
77 | anime.remove(this.container.current);
78 | }
79 |
80 | componentWillReceiveProps(nextProps) {
81 |
82 | if (this.props.play === true && !nextProps.play) {
83 | if (this.childAnimation) {
84 | this.childAnimation.pause()
85 | }
86 | }
87 | else if (!this.props.play === true && nextProps.play && nextProps.shouldBeVisible) {
88 | if (this.childAnimation) {
89 | this.childAnimation.play()
90 | }
91 | }
92 |
93 | if (!nextProps.shouldBeVisible && this.props.shouldBeVisible) {
94 | //Component is being hidden. Rewind animation.
95 | this.setState({touchable: false});
96 | if (this.sequentialHighlight)
97 | this.sequentialHighlight.clear();
98 | this.animeRef.seek(0);
99 | if (this.childAnimation) {
100 | this.childAnimation.seek(0);
101 | anime.remove(this.childAnimation);
102 | this.childAnimation = this.component.current.getAnimation()
103 | }
104 | }
105 | if (nextProps.shouldBeVisible && !this.props.shouldBeVisible) {
106 | //Start Animation.
107 | this.animeRef.restart();
108 | //Highlight code to show user, which part of the code is being represented by this animation.
109 | this.sequentialHighlight = this.highlightCode();
110 |
111 | }
112 | }
113 |
114 | highlightCode = (isHover = false) => {
115 | let line = this.component.current.props.line;
116 | let cm = this.props.cm.current;
117 | if (line && cm) {
118 | const lineLength = cm.editor.getLine(line).length;
119 | return cm.editor.doc.markText({line, ch: 0}, {line, ch: lineLength}, {
120 | className: isHover ? 'highlighted-code' : 'sequential-highlighted-code'
121 | });
122 | }
123 | return null
124 | };
125 |
126 | onEnter = () => {
127 | this.hoverHighlight = this.highlightCode(true);
128 | if (this.childAnimation) {
129 | this.isLoop = this.childAnimation.loop;
130 | this.childAnimation.loop = true;
131 | this.childAnimation.restart();
132 | }
133 | };
134 |
135 | onLeave = () => {
136 | if (this.hoverHighlight) this.hoverHighlight.clear();
137 | if (this.childAnimation) {
138 | this.childAnimation.loop = this.isLoop;
139 | this.childAnimation.restart();
140 | this.childAnimation.seek(Infinity);
141 | }
142 | }
143 |
144 | render() {
145 | return (
146 |
152 | {React.cloneElement(this.props.component, {ref: this.component})}
153 |
154 | );
155 | }
156 | }
157 |
--------------------------------------------------------------------------------
/src/components/ASTVisualizer.js:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react';
2 | import * as _ from "lodash";
3 | import SortableTree from "react-sortable-tree";
4 | import 'react-sortable-tree/style.css';
5 | import '../css/ASTVisualizer.css'
6 |
7 | let getChildren = (node) => {
8 |
9 | switch (node.type) {
10 |
11 | case 'Program':
12 | return node.body;
13 |
14 | case 'VariableDeclaration':
15 | return node.declarations;
16 |
17 | case 'VariableDeclarator':
18 | return node.init ? [node.id, node.init] : [node.id];
19 |
20 | case 'ExpressionStatement':
21 | return [node.expression];
22 |
23 | case 'BinaryExpression':
24 | return [node.left, node.right];
25 |
26 | case 'AssignmentExpression':
27 | return [node.left, node.right];
28 |
29 | case 'CallExpression':
30 | return [node.callee, {type: 'arguments', arguments: node.arguments}];
31 |
32 | case 'arguments':
33 | return node.arguments;
34 |
35 | case 'MemberExpression':
36 | return [node.object, node.property];
37 |
38 | case 'NewExpression':
39 | return node.arguments;
40 |
41 | case 'ObjectExpression':
42 | return node.properties;
43 |
44 | case 'Property':
45 | return [node.key, node.value];
46 |
47 | case 'FunctionDeclaration':
48 | return [node.body];
49 |
50 | case 'FunctionExpression':
51 | return [node.body];
52 |
53 | case 'BlockStatement':
54 | return node.body;
55 |
56 | case 'ReturnStatement':
57 | return node.argument ? [node.argument] : [];
58 |
59 | case 'UnaryExpression':
60 | return [node.argument];
61 |
62 | case 'IfStatement':
63 | return [node.test, node.consequent];
64 |
65 | case 'ConditionalExpression':
66 | return [node.test, node.consequent, node.alternate];
67 |
68 | default:
69 | return [];
70 | }
71 | };
72 |
73 | let getLabel = (node) => {
74 |
75 | switch (node.type) {
76 |
77 | case 'Identifier':
78 | return node.name;
79 |
80 | case 'Literal':
81 | return node.raw;
82 |
83 | case 'UnaryExpression':
84 | return node.operator;
85 |
86 | case 'BinaryExpression':
87 | return node.operator;
88 |
89 | case 'AssignmentExpression':
90 | return node.operator;
91 |
92 | case 'FunctionDeclaration':
93 | var params1 = _.map(node.params, 'name').join(',');
94 | return 'function ' + (!(!(node.id && node.id.name) && !'')) + '(' + params1 + ')';
95 |
96 | case 'FunctionExpression':
97 | var params2 = _.map(node.params, 'name').join(',');
98 | return 'function ' + (!(!(node.id && node.id.name) && !'')) + '(' + params2 + ')';
99 |
100 | default:
101 | return node.type;
102 | }
103 | };
104 |
105 | class AstVisualizer extends Component {
106 | constructor(props) {
107 | super(props);
108 | this.state = {
109 | treeData: [],
110 | };
111 |
112 | }
113 |
114 | componentDidMount() {
115 | this.setState({treeData: this.buildTree(this.props.ast)})
116 | }
117 |
118 | componentWillReceiveProps(nextProps) {
119 | this.setState({treeData: this.buildTree(nextProps.ast)})
120 | }
121 |
122 | recursiveBuilder = (node) => {
123 | let children = getChildren(node);
124 | let tree = [];
125 | if (children === [])
126 | return children;
127 | children.forEach((child) => {
128 | tree.push({
129 | title: getLabel(child),
130 | children: this.recursiveBuilder(child),
131 | expanded: true,
132 | type: child.type,
133 | start: child.start,
134 | end: child.end
135 | });
136 | });
137 | return tree
138 | };
139 |
140 | buildTree = (ast) => {
141 | let tree = [];
142 | tree.push({
143 | title: getLabel(ast),
144 | children: this.recursiveBuilder(ast),
145 | expanded: true,
146 | type: ast.type,
147 | start: ast.start,
148 | end: ast.end
149 | });
150 | return tree
151 | };
152 |
153 | highlightCode = (start, end) => {
154 | let codeEditor = this.props.cm.current.editor.doc;
155 | const fromIndex = codeEditor.posFromIndex(start);
156 | const toIndex = codeEditor.posFromIndex(end);
157 | codeEditor.markText(fromIndex, toIndex, {
158 | className: 'highlighted-code'
159 | });
160 | };
161 |
162 | clearHighlightedCode = () => {
163 | this.props.cm.current.editor.doc.getAllMarks().forEach((m) => {
164 | m.clear()
165 | })
166 | };
167 |
168 | render() {
169 | return (
170 | this.setState({treeData})}
173 | canDrag={false}
174 | generateNodeProps={({node}) => {
175 | return {
176 | className: node.type,
177 | onMouseEnter: () => this.highlightCode(node.start, node.end),
178 | onMouseLeave: () => this.clearHighlightedCode()
179 | };
180 | }}
181 | />
182 | );
183 | }
184 | }
185 |
186 | export default AstVisualizer;
--------------------------------------------------------------------------------
/src/components/ASMVisualizer.js:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react';
2 | import Ret from "../ASMComponents/ret";
3 | import UnsupportedCommand from "../ASMComponents/UnsupportedCommand";
4 | import Function from "../ASMComponents/Function";
5 | import SequentialComponent from "../ASMComponents/SequentialComponent";
6 | import styled from "styled-components";
7 | import {Row, Col, Button, Container} from 'reactstrap';
8 | import '../css/ASMVisualizer.css'
9 | import Shift from "../ASMComponents/Shift";
10 | import Arithmetic from "../ASMComponents/Arithmetic";
11 | import * as _ from "lodash";
12 |
13 |
14 | const ButtonContainer = styled.div`
15 | text-align: center;
16 | `
17 |
18 | const AnimationContainer = styled.div`
19 | overflow: auto;
20 | height: calc(100% - 40px);
21 | `
22 |
23 | function commandFactory(c) {
24 | switch (c.name) {
25 | case "vpslldq":
26 | return ;
27 | case "vpsrldq":
28 | return ;
29 | case "vpaddd":
30 | return ;
31 | case "ret":
32 | return ;
33 | default:
34 | return
35 | }
36 | }
37 |
38 | class AsmVisualizer extends Component {
39 | constructor(props) {
40 | super(props);
41 | this.state = {
42 | idx: 0,
43 | play: true,
44 | restart: false
45 | };
46 |
47 | }
48 |
49 | componentDidMount() {
50 | this.props.cm.current.editor.doc.getAllMarks().forEach((m) => {
51 | m.clear()
52 | })
53 | }
54 |
55 | buildGraphicStack = () => {
56 | let stack = [];
57 | this.props.asm.forEach((func) => {
58 | let commands = func.body;
59 | stack.push();
60 | commands.forEach(c => {
61 | let command = commandFactory(c);
62 | const defaultValues = _.filter(func.params, param => c.params.some(e => e === param.register));
63 | stack.push(
64 | //c.line - 1 because line number starts at 1 and we need to start at 0.
65 | React.cloneElement(command, {name: c.name, params: c.params, line: c.line - 1, defaultValues})
66 | );
67 | });
68 | });
69 | return stack;
70 | };
71 |
72 | componentDonePlaying(key) {
73 | if (this.state.play) {
74 | let increment = key === this.state.idx ? 1 : 0;
75 | this.setState({idx: this.state.idx + increment});
76 | }
77 | }
78 |
79 | play() {
80 | // if (!this.state.play) {
81 | // this.setState({idx: this.state.idx + 1});
82 | // }
83 | this.setState({play: true})
84 | }
85 |
86 | pause() {
87 | this.setState({play: false})
88 | }
89 |
90 | // forward() {
91 | // this.setState({idx: this.state.idx + 1});
92 | // //this.componentDonePlaying(this.state.idx - 1);
93 | // }
94 |
95 | // backward() {
96 | // this.setState({idx: this.state.idx - 1});
97 | // setTimeout(() => {
98 | // this.componentDonePlaying(this.state.idx);
99 | // })
100 | // }
101 |
102 | restart() {
103 | this.setState({idx: -1});
104 | setTimeout(() => {
105 | this.setState({play: true});
106 | this.componentDonePlaying(-1);
107 | })
108 | }
109 |
110 | getButtons = (play) => {
111 | let buttons = [];
112 | //buttons.push();
113 |
114 | buttons.push({icon: , onClick: this.props.onGoToParameters});
115 |
116 | play === true ?
117 | buttons.push({icon: , onClick: this.pause.bind(this)})
118 | :
119 | buttons.push({icon: , onClick: this.play.bind(this)});
120 |
121 | //buttons.push();
122 | buttons.push({icon: , onClick: this.restart.bind(this)});
123 |
124 | return (
125 |
126 |
127 | {
128 | buttons.map((button, i) => (
129 |
130 |
131 |
133 | {button.icon}
134 |
135 |
136 |
137 | ))
138 | }
139 |
140 |
141 | )
142 | };
143 |
144 | render() {
145 | return (
146 | this.props.asm.length > 0 ?
147 |
148 |
149 | {this.getButtons(this.state.play)}
150 |
151 | {
152 | this.buildGraphicStack().map((func, index) => (
153 | = index}
159 | onComplete={this.componentDonePlaying.bind(this)}
160 | cm={this.props.cm}
161 | />
162 | ))
163 | }
164 |
165 |
166 | :
167 | []
168 | );
169 | }
170 | }
171 |
172 | export default AsmVisualizer;
--------------------------------------------------------------------------------
/src/ASMComponents/Arithmetic.js:
--------------------------------------------------------------------------------
1 | import React, {Component} from "react";
2 | import Vector from "./Vector";
3 | import Registry from "../Utils/Registry";
4 | import {convert} from "../Utils/Converter";
5 | import {Row, Col, Container} from 'reactstrap';
6 | import * as _ from "lodash";
7 |
8 |
9 | import anime from "animejs";
10 | import uint32 from "uint32";
11 |
12 | const INPUT1_INDEX = 1;
13 | const INPUT2_INDEX = 2;
14 | const OUTPUT_INDEX = 0;
15 |
16 | export default class Arithmetic extends Component {
17 | static defaultProps = {
18 | type: "uint",
19 | bitWidth: 32,
20 | base: 16,
21 | operation: 'add',
22 | };
23 |
24 | constructor(props) {
25 | super(props);
26 |
27 | let input1 = Registry.get(props.params[INPUT1_INDEX]);
28 | let input2 = Registry.get(props.params[INPUT2_INDEX]);
29 | let input1_converted = convert(input1, props.type, props.bitWidth, 'uint', 8);
30 | let input2_converted = convert(input2, props.type, props.bitWidth, 'uint', 8);
31 | let output_converted = [];
32 | // why not do the computation in the constructor? This seems simpler. No multiple render calls.
33 |
34 | input1_converted.forEach((val, i) => {
35 | output_converted.push((val + input2_converted[i]) % Math.pow(2, props.bitWidth))
36 | });
37 |
38 | let output = convert(output_converted, 'uint', 8, props.type, props.bitWidth);
39 | Registry.set(props.params[OUTPUT_INDEX], output);
40 |
41 | const defaultBitWidth = props.defaultValues.length > 0 ? props.defaultValues[0].bitWidth : props.bitWidth;
42 | const defaultBase = props.defaultValues.length > 0 ? props.defaultValues[0].base : props.base;
43 |
44 | this.state = {
45 | input1,
46 | input2,
47 | output,
48 | input1_converted,
49 | input2_converted,
50 | output_converted,
51 | defaultBitWidth,
52 | defaultBase,
53 | showOutput: false
54 | };
55 | this.state.output = _.cloneDeep(input1);
56 |
57 | this.vector1 = React.createRef();
58 | this.vector2 = React.createRef();
59 | this.vector3 = React.createRef();
60 | this.vector4 = React.createRef();
61 | this.equals = React.createRef();
62 | }
63 |
64 | getAnimation() {
65 |
66 | let timeline = anime.timeline({
67 | easing: "easeOutCubic",
68 | loop: false,
69 | autoplay: false
70 | });
71 | let {output_converted} = this.state;
72 | let input1_converted = _.cloneDeep(this.state.input1_converted);
73 | let mock = {nextTick: 0, currentTick: 0};
74 |
75 | timeline
76 | .add({
77 | targets: this.equals.current,
78 | opacity: [0, 1],
79 | duration: 500,
80 | offset: 500
81 | })
82 | .add({
83 | targets: this.vector3.current,
84 | translateY: [-95, 0],
85 | duration: 1500,
86 | offset: "+=500"
87 | })
88 | .add({
89 | targets: this.vector4.current,
90 | translateY: [-258, -70],
91 | duration: 1500,
92 | offset: "-=1500"
93 | })
94 | .add({
95 | targets: mock,
96 | //find the maximum difference between input and output. this tells us the range of the animation (number of ticks).
97 | nextTick: _.max(input1_converted.map((v, i) => Math.abs(output_converted[i] - v))),
98 | easing: "linear",
99 | duration: 2000,
100 | round: 1,
101 | offset: "-=200",
102 | begin: () => {
103 | this.setState({output: _.cloneDeep(this.state.input1)});
104 | },
105 | update: (animation) => {
106 | //Update() is not called only upon update of the target... So we need to check if it changed...
107 | if (animation.began && mock.nextTick !== mock.currentTick) {
108 | input1_converted = input1_converted.map((val, i) => {
109 |
110 | //TODO: Temporary disable of the animation... it's broken and I don't have the time to fix it right now
111 | //let diff = output_converted[i] - val;
112 | // if (diff > 0) return val + 1;
113 | // if (diff < 0) return val - 1;
114 | //return val;
115 | return output_converted[i];
116 | });
117 | mock.currentTick = mock.nextTick;
118 | this.setState({output: convert(input1_converted, 'uint', 8, this.props.type, this.props.bitWidth)});
119 |
120 | }
121 | }
122 | });
123 |
124 | return timeline;
125 | }
126 |
127 |
128 | render() {
129 | let {input1, input2, output, defaultBase} = this.state;
130 | let {type, bitWidth, base} = this.props;
131 | let colCount = input1.length * 8 / bitWidth;
132 |
133 | return (
134 |
135 |
this.vector1 = ref}
140 | />
141 |
142 |
143 | {_.times(colCount).map(i => +)}
144 |
145 |
146 | this.vector2 = ref}
151 | />
152 |
153 |
154 |
155 | {_.times(colCount).map(i => =)}
156 |
157 |
158 |
159 | this.vector3 = ref}
164 | />
165 | this.vector4 = ref}
170 | />
171 |
172 | );
173 | }
174 | }
175 |
176 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | # Live Version found here (Proof of concept)
3 | [http://piotte13.github.io/SIMD-Visualiser](http://piotte13.github.io/SIMD-Visualiser)
4 |
5 | 
6 | ( This is a Prototype version, we are still in development! Thanks for your support :-)
7 | # But wait, what is SIMD?
8 | SIMD (pronounced "seem-dee") is short for **Single Instruction/Multiple Data** which is one [classification of computer architectures](https://en.wikipedia.org/wiki/Flynn%27s_taxonomy "classification of computer architectures"). SIMD allows one operation to be performed on multiple data points simultaneously. Data level parallelism improves the performance of many tasks, including 3D graphics and video processing, physics simulations, and cryptography.
9 |
10 | # Why would one need to visualize it?
11 | The first time I saw SIMD code, I almost had a heart attack. My brain was overwhelmed, my stress level rose, my face turned white like a sheet of paper and cold sweats started to flow all over my body. SIMD code is not designed to be easily understood by the human brain: it's made for machines.
12 |
13 | The thing is, we still need SIMD. It's powerful and once you understand what it does, it's quite simple. So, how do we understand what it does then? We visualize it! We make it look simple with animations, colors and graphics!
14 |
15 | Our goal is to experiment with different visualization methods, until we figure out the ones that are so easy to understand that even our grandmothers would think it's a kids play. For now, we think we found a solution that allows anyone with basic computer science knowledge to understand any given SIMD code, quickly and free of hearth attacks.
16 |
17 | # Basic Features
18 | - Graphical Visualization. 🔥🔥
19 | - Abstract Syntax Tree (AST) 🌳🌱
20 | - Write, compile and find bugs in SIMD code. 😮😍
21 |
22 |
23 | # How does it work?
24 | So, you are wondering how we made it, right? Did we hire a magician? Let's see... 😉
25 |
26 | At first thought, parsing C code might seem like a trivial task. But it's not, it's actually laborious, painful and brain twisting... C is a deeply complex language, therefore it cannot be parsed using only regular expressions, we need a lot more fancy techniques and effort. In addition to that, there is no available C code parser written in JavaScript that we could directly use in our project. At least, we did not find any.
27 |
28 | Don't get me wrong, it's totally possible to make one, after all, any kind of compiler has to parse code before it can tweak it and do its thing. That's where things get interesting, compilers like [Clang](https://clang.llvm.org/) already have an integrated parser, and a surprisingly good one, so why try and reinvent the wheel? Why not capitalize on what is already made and use it at our advantage? Well, that is for sure a good point... So, we tried using the compiler and it works like magic. It is fast, efficient and simple to use.
29 |
30 | Thanks to [Matt Godbolt](https://github.com/mattgodbolt/compiler-explorer) and his [Compiler Explorer](https://godbolt.org/), we were able to compile our SIMD code to assembly using any version of Clang through his free and open source REST API. We also discovered that the Clang compiler can produce an [Abstract Syntaxic Tree](https://en.wikipedia.org/wiki/Abstract_syntax_tree) that we can later use as another visualization strategy.
31 |
32 | Okay, now that we have compiled SIMD code, what do we do?
33 |
34 | 1. Parse it.
35 | 2. Draw it.
36 | 3. Animate it.
37 |
38 | Although we skipped the C code parsing using Clang, we still need to parse the assembly code, or else it's useless to us. One particularity of assembly code is that it's easy to parse. In JavaScript jargon, it's as simple as String.split(). But what about the complexity of the code, doesn't assembly add a lot of junk? Well, an interesting feature of compiled SIMD code is that it's quite simple, there is no additional complexity like we would find in assembly generated from traditional C code.
39 |
40 | Here's an example:
41 |
42 | C code (SIMD):
43 | ```
44 | #include
45 |
46 | __m128i PrefixSum(__m128i curr) {
47 | __m128i Add = _mm_slli_si128(curr, 4);
48 | curr = _mm_add_epi32(curr, Add);
49 | Add = _mm_slli_si128(curr, 8);
50 | return _mm_add_epi32(curr, Add);
51 | }
52 | ```
53 |
54 | Assembly:
55 | ```
56 | PrefixSum(long long __vector(2)):
57 | vpslldq xmm1, xmm0, 4
58 | vpaddd xmm0, xmm1, xmm0
59 | vpslldq xmm1, xmm0, 8
60 | vpaddd xmm0, xmm0, xmm1
61 | ret
62 | ```
63 |
64 | Let me explain. The first column of every row represents the name of the command and the subsequent columns represent the arguments or parameters. **xmm**, **ymm** and **zmm** arguments are registry addresses. Essentially, registries are like the variables you would find in C, except there is a finite amount of them and there is no concepts such as scope and lifetime. The first letter (X, Y, Z) represents the size, which would be (128, 256, 512) bits and there is only 32 addresses of registries. Those characteristics makes registries easier to work with, compared to C variables, since a lot of complexity is therefore removed or taken care of by the compiler. To learn more about AVX registry and it's commands, read [this](https://en.wikipedia.org/wiki/Advanced_Vector_Extensions#New_instructions).
65 |
66 | Now that we have parsed every command and their parameters, we can finally start drawing and animating them! To do so, we used [React](https://reactjs.org/) as a JavaScript user interface library and [Anime.js](http://animejs.com/) for the animations.
67 |
68 |
69 | # Development/Contributing
70 | SIMD-Visualizer is a research project and for now, we are a small team! We actively encourage and support contributions. The SIMD-Visualizer source code is released under the BSD License. This license is very simple, and is friendly to all kinds of projects, whether open source or not.
71 |
72 | Feel free to fork and improve/enhance SIMD-Visualizer any way you want. If you feel that the application or the research team will benefit from your changes, please open a pull request.
73 |
74 | ## Available Scripts
75 |
76 | In the project directory, you can run:
77 | ### `npm start`
78 |
79 | Runs the app in the development mode.
80 | Open [http://localhost:3000](http://localhost:3000) to view it in the browser.
81 | The page will reload if you make edits.
82 | You will also see any lint errors in the console.
83 | ### `npm run build`
84 |
85 | Builds the app for production to the `build` folder.
86 | It correctly bundles React in production mode and optimizes the build for the best performance.
87 |
88 | The build is minified and the filenames include the hashes.
89 | Your app is ready to be deployed!
90 |
91 | ### `npm run deploy`
92 |
93 | Deploys application to github-pages. It will build, then push the code to gh-pages branch.
94 |
95 | ### `npm test`
96 |
97 | Launches the test runner in the interactive watch mode.
98 | See the section about [running tests](#running-tests) for more information.
99 |
100 | # Credits
101 |
102 | This project is made possible by [Pierre Marie Ntang](https://github.com/pmntang). It is part of his PhD thesis in congnitive computing at [Université du Québec (TELUQ)](https://www.teluq.ca/site/en/). Many ideas came from his brilliant mind.
103 |
104 | Thanks to [Daniel Lemire](https://github.com/lemire) for his many ideas and his deep knowledge and expertise in SIMD software. He is well known in the open source world as well as the big data community. His work is used by companies such as eBay, Facebook, LinkedIn and Netflix in their data warehouses. Git also uses his techniques to accelerate queries.
105 |
106 | Big thanks to [Matt Godbolt](https://github.com/mattgodbolt/compiler-explorer) for his free and open source REST API of the [Compiler Explorer](https://godbolt.org/), which allows us to use Clang and many other compilers from the browser.
107 |
108 |
109 | # License
110 | The [BSD 3-clause](https://tldrlegal.com/license/bsd-3-clause-license-(revised)) license allows you almost unlimited freedom with the software so long as you include the BSD copyright and license notice in it (found in Fulltext).
111 |
--------------------------------------------------------------------------------
/src/components/App.js:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react';
2 | import {Controlled as CodeMirror} from 'react-codemirror2'
3 | import 'codemirror/lib/codemirror.css'
4 | import 'codemirror/theme/material.css'
5 | import 'codemirror/mode/clike/clike.js'
6 | import 'codemirror/addon/selection/mark-selection.js'
7 | import '../css/App.css';
8 | import styled from 'styled-components'
9 | import ButtonPanel from "./ButtonPanel";
10 | import {generateASM, generateAST} from "../Utils/Parser";
11 | import WaitingScreen from "./WaitingScreen";
12 | import AstVisualizer from "./ASTVisualizer";
13 | import FrontPage from "./FrontPage";
14 | import {compile} from "../Utils/Compiler";
15 | import ErrorHandler from "./ErrorHandler";
16 | import {Pane, Tabs} from "../Utils/Tabs";
17 | import AsmVisualizer from "./ASMVisualizer";
18 | import {createBrowserHistory} from 'history';
19 | import * as qs from 'qs';
20 | import ParametersPage from "./ParametersPage";
21 | import * as _ from "lodash";
22 |
23 |
24 |
25 | const Container = styled.div`
26 | display: flex;
27 | `
28 |
29 | const LeftContainer = styled.div`
30 | display: flex;
31 | flex-direction: column;
32 | height: 100vh
33 | width: 50vw;
34 | overflow: auto;
35 | `
36 |
37 | const RightContainer = styled.div`
38 | width: 50vw;
39 | height: 100vh;
40 | overflow: hidden;
41 | `
42 |
43 | class App extends Component {
44 | constructor(props) {
45 | super(props);
46 | let savedState = localStorage.getItem('app-state');
47 | this.history = createBrowserHistory();
48 | this.state = {
49 | code: `#include \n\n__m128i PrefixSum(__m128i curr) {\n __m128i Add = _mm_slli_si128(curr, 4); \n curr = _mm_add_epi32(curr, Add); \n Add = _mm_slli_si128(curr, 8); \n return _mm_add_epi32(curr, Add); \n}`,
50 | codeWasModifiedSinceLastCompile: true,
51 | disableButtons: false,
52 | status: 'compiles',
53 | compiling: false,
54 | ast: {},
55 | clangAst: {},
56 | asm: [],
57 | error: [],
58 | visualize: false,
59 | parametersChosen: false
60 | };
61 | if (this.props.match.params.code) {
62 | this.state.code = qs.parse(this.props.match.params.code).code
63 | }
64 | else if (savedState) {
65 | // React wants us to mutate the state or it will lose the right reference...
66 | _.assign(this.state, JSON.parse(savedState));
67 | this.state.visualize = false;
68 | this.state.parametersChosen = false;
69 | }
70 |
71 | this.cm = React.createRef();
72 | }
73 |
74 | componentDidUpdate() {
75 | localStorage.setItem("app-state", JSON.stringify(this.state));
76 | }
77 |
78 | handleClear = (clearCode = true) => {
79 | this.setState(({code}) => ({
80 | code: clearCode === true ? '' : code
81 | }));
82 | };
83 |
84 | visualize = () => {
85 | this.setState({compiling: true});
86 | if (this.state.codeWasModifiedSinceLastCompile) {
87 | this.setState((state) => {
88 | Object.keys(state.ast).forEach(k => delete state.ast[k]);
89 | Object.assign(state.ast, generateAST(this.cm.current.editor))
90 | });
91 | compile(this.cm.current.editor.getValue(), (error, asm, ast) => {
92 | if (error.length === 0) {
93 | asm = generateASM(asm);
94 | this.setState((state) => {
95 | state.asm.splice(0, state.asm.length);
96 | asm.forEach(e => {
97 | state.asm.push(e)
98 | });
99 |
100 | return {
101 | compiling: false,
102 | status: 'compiles',
103 | error,
104 | clangAst: ast,
105 | codeWasModifiedSinceLastCompile: false,
106 | visualize: true,
107 | parametersChosen: false
108 | }
109 | });
110 | }
111 | else {
112 | this.setState((state) => {
113 | state.asm.splice(0, state.asm.length);
114 | return {compiling: false, status: 'error', error, clangAst: {}}
115 | });
116 | }
117 | })
118 | }
119 | else {
120 | this.setState({compiling: false, visualize: true})
121 | }
122 | };
123 |
124 | restart = () => {
125 | this.setState((state) => {
126 | Object.keys(state.ast).forEach(k => delete state.ast[k]);
127 | state.asm.splice(0, state.asm.length);
128 | return {
129 | compiling: false,
130 | codeWasModifiedSinceLastCompile: true,
131 | clangAst: {},
132 | error: [],
133 | visualize: false,
134 | parametersChosen: false
135 | }
136 | });
137 | };
138 |
139 | onParametersChosen() {
140 | this.setState({parametersChosen: true});
141 | }
142 |
143 | getShareLink = () => {
144 | //We need to specify the whole URL since we are in dev and bitly cannot work with localhost links.
145 | return 'https://piotte13.github.io/SIMD-Visualiser/#/link/' + qs.stringify({code: this.state.code})
146 | //return window.location.origin + "#/link" + qs.stringify(this.state)
147 | };
148 |
149 | getCodeMirror() {
150 | const {code} = this.state;
151 |
152 | return (
153 | {
164 | this.history.push(this.history.location.pathname);
165 | if (code === '') {
166 | this.handleClear(true);
167 | this.setState({codeWasModifiedSinceLastCompile: true});
168 | } else {
169 | this.setState({code, codeWasModifiedSinceLastCompile: true});
170 | }
171 | }}
172 | onPaste={() => {
173 | this.setState({codeWasModifiedSinceLastCompile: true});
174 | this.handleClear(false)
175 | }}
176 | />
177 | )
178 | }
179 |
180 | render() {
181 | const {disableButtons, status, compiling, error, visualize, parametersChosen} = this.state;
182 |
183 | let rightPage = ;
184 |
185 | if (compiling) {
186 | rightPage = ;
187 | }
188 | else if (error.length > 0) {
189 | rightPage =
190 | }
191 | else if (visualize && parametersChosen) {
192 | rightPage =
193 |
194 | this.setState({parametersChosen: false})}/>
196 |
197 |
198 |
199 |
200 |
201 | }
202 | else if (visualize) {
203 | rightPage =
204 | }
205 |
206 | return (
207 |
208 |
209 |
216 | {
217 | this.getCodeMirror()
218 | }
219 |
220 |
221 | {rightPage}
222 |
223 |
224 | );
225 | }
226 | }
227 |
228 | export default App;
229 |
--------------------------------------------------------------------------------
/src/Images/cryingboy.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
--------------------------------------------------------------------------------
/src/Images/Cryingboy.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | const SvgCryingboy = props => (
4 |
12 |
17 |
21 |
25 |
29 |
33 |
37 |
41 |
45 |
52 |
56 |
60 |
64 |
68 |
72 |
76 |
80 |
84 |
88 |
92 |
94 |
95 |
103 |
111 |
119 |
127 |
135 |
143 |
150 |
154 |
158 |
162 |
166 |
170 |
174 |
178 |
180 |
181 | );
182 |
183 | export default SvgCryingboy;
184 |
--------------------------------------------------------------------------------
/src/components/ParametersPage.js:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react';
2 | import styled from 'styled-components'
3 | import {
4 | Button, Card, CardBody, CardTitle, Row, Col, Container, ButtonGroup
5 | } from 'reactstrap';
6 | import * as _ from "lodash";
7 | import Slider from 'rc-slider';
8 | import 'rc-slider/assets/index.css';
9 | import 'rc-tooltip/assets/bootstrap.css';
10 | import {FAST_CALL_REGISTERS, TYPE_LENGTH} from "../Utils/Registry";
11 | import {convert} from "../Utils/Converter";
12 |
13 | const PageContainer = styled.div`
14 | padding: 50px;
15 | `
16 |
17 | const Title = styled.div`
18 | font-size: 60px;
19 | font-weight: 700;
20 | color: rgb(72, 72, 72);
21 | margin-bottom: 15px;
22 | text-align: center;
23 | `
24 |
25 | const SubmitButton = styled.div`
26 | position: absolute;
27 | bottom: 50px;
28 | left: calc(75% - 55px);
29 | button{font-size: 1.5rem};
30 | `
31 | const FunctionContainer = styled.div`
32 |
33 | `
34 | const FunctionName = styled.div`
35 | text-align: center;
36 | margin-top: 50px;
37 | font-size: 32px;
38 | font-weight: normal;
39 | color: rgb(72, 72, 72);
40 | `
41 |
42 | const ParameterContainer = styled.div`
43 | padding: 20px 0;
44 |
45 | .card-title {
46 | margin-bottom: 0;
47 | height: 100%;
48 | line-height: 1.7rem;
49 | }
50 |
51 | .card-body{
52 | padding: 1rem;
53 |
54 | .row{
55 | margin-bottom: 10px;
56 | }
57 |
58 | `
59 |
60 | const ParameterOptionTitle = styled(Col)`
61 | align-self: center;
62 | height: 1.5rem;
63 | `
64 |
65 | const RandomizeButton = styled.div`
66 | float: right;
67 | cursor: pointer;
68 | color: var(--one);
69 | font-size: 1.7rem;
70 | `
71 |
72 | const VectorContainer = styled(Container)`
73 | width: 96% !important;
74 | height: 50px;
75 | background-color: var(--main);
76 | border-radius: 3px;
77 | //margin: 0 2%;
78 | box-shadow: 3px 3px 2px rgba(0,0,0,.4);
79 |
80 | .row{
81 | height: 100%;
82 |
83 | .col{
84 | text-align: center;
85 | padding: 0;
86 |
87 | input{
88 | width: 100%;
89 | height: 100%;
90 | color: var(--clear-text-color);
91 | text-align: center;
92 | border-radius: 0;
93 | border: none;
94 | background-color: inherit;
95 | border-right: solid 1px var(--gray);
96 | }
97 |
98 | :last-child input{
99 | border-right: none;
100 | }
101 | }
102 | }
103 | }
104 | `;
105 |
106 | export default class ParametersPage extends Component {
107 | constructor(props) {
108 | super(props);
109 | this.setRegistersNamesAndValues();
110 | }
111 |
112 | componentDidMount() {
113 |
114 | }
115 |
116 | setRegistersNamesAndValues() {
117 | this.props.asm.forEach((func, i) => {
118 | let generalPurposeRegisterCount = 0;
119 | let simdRegisterCount = 0;
120 | func.params.forEach((param, j) => {
121 | //if param.lanes === 1, it means we have a general purpose register. (it's not a vector)
122 | if (param.lanes === 1) {
123 | param.register = FAST_CALL_REGISTERS[generalPurposeRegisterCount];
124 | generalPurposeRegisterCount++;
125 | }
126 | else {
127 | //reconstruct the SIMD register name.
128 | param.register = _.invert(TYPE_LENGTH)[(param.bitWidth * param.lanes) / 8] + "mm" + simdRegisterCount;
129 | simdRegisterCount++;
130 | }
131 | this.randomizeRegister(i, j)
132 | })
133 | })
134 | }
135 |
136 | getSliderMarks(paramBitLen) {
137 | //Make sure laneWidth cannot be smaller than 4 bits
138 | paramBitLen = _.max([4, paramBitLen]);
139 | //Make sure laneWidth cannot be bigger than 64 bits
140 | paramBitLen = _.min([paramBitLen, 64]);
141 | const nbOfMarks = Math.log(paramBitLen) / Math.log(2) - 1;
142 | let marks = {};
143 | _.times(nbOfMarks).forEach(i => {
144 | const percentage = 100 * (i + 1) / nbOfMarks;
145 | marks[percentage] = Math.pow(2, i + 2);
146 | });
147 |
148 | return marks
149 | };
150 |
151 | onTypeChange(selected, functionNumber, paramNumber) {
152 | this.props.asm[functionNumber].params[paramNumber].type = selected;
153 | this.forceUpdate();
154 | }
155 |
156 | onWidthChange(newWidth, functionNumber, paramNumber) {
157 | let param = this.props.asm[functionNumber].params[paramNumber];
158 | const bitLen = param.bitWidth * param.lanes;
159 | param.value = convert(param.value, param.type, newWidth, param.type, param.bitWidth);
160 | param.bitWidth = newWidth;
161 | param.lanes = bitLen / newWidth;
162 |
163 | this.forceUpdate();
164 | }
165 |
166 | onBaseChange(selected, functionNumber, paramNumber) {
167 | this.props.asm[functionNumber].params[paramNumber].base = selected;
168 | this.forceUpdate();
169 | }
170 |
171 | onVectorValueChange(val, functionNumber, paramNumber, lane) {
172 | let param = this.props.asm[functionNumber].params[paramNumber];
173 | param.value[lane] = _.min([parseInt(val, param.base), Math.pow(2, param.bitWidth - 1)]);
174 | this.forceUpdate();
175 | }
176 |
177 | randomizeRegister(functionNumber, paramNumber) {
178 | let param = this.props.asm[functionNumber].params[paramNumber];
179 | if (param.lanes === 1) {
180 | param.value = [_.random(1, Math.pow(2, _.min([8, param.bitWidth - 1])))];
181 | }
182 | else {
183 | param.value = new Array(param.lanes).fill(0).map(() => _.random(1, Math.pow(2, _.min([8, param.bitWidth - 1]))));
184 | }
185 | }
186 |
187 | buildContent() {
188 | let content = [];
189 | this.props.asm.forEach((func, i) => {
190 | content.push(
191 |
192 | {func.name}
193 |
194 | {
195 | func.params.map((param, j) => {
196 | const paramBitLen = param.bitWidth * param.lanes;
197 | const marks = this.getSliderMarks(paramBitLen);
198 |
199 |
200 | return
201 |
202 |
203 |
204 | {`Parameter ${j + 1}:`}
205 | {`${paramBitLen} bits`}
206 | {
207 | this.randomizeRegister(i, j);
208 | this.forceUpdate()
209 | }}>
210 |
211 |
212 |
213 |
214 |
215 |
216 | {
217 | param.value.map((val, k) => (
218 |
219 | this.onVectorValueChange(e.target.value, i, j, k)}/>
222 |
223 | ))
224 | }
225 |
226 |
227 |
228 |
229 |
230 | Lane
231 | Width:
232 |
233 | this.onWidthChange(marks[val], i, j)}/>
245 |
246 |
247 |
248 | Type:
249 |
250 |
251 | this.onTypeChange('int', i, j)}
254 | active={param.type === 'int'}>Integer
255 | this.onTypeChange('float', i, j)}
258 | active={param.type === 'float'}>Floating Point
259 |
260 |
261 |
262 |
263 | Base:
264 |
265 |
266 | this.onBaseChange(2, i, j)}
269 | active={param.base === 2}>Binary
270 | this.onBaseChange(10, i, j)}
272 | active={param.base === 10}>Decimal
273 | this.onBaseChange(16, i, j)}
275 | active={param.base === 16}>Hexadecimal
276 |
277 |
278 |
279 |
280 |
281 |
282 |
283 | })
284 | }
285 |
286 | )
287 | });
288 |
289 | return content;
290 | }
291 |
292 | render() {
293 | return (
294 |
295 | Choose your parameters
296 | {
297 | this.buildContent()
298 | }
299 |
300 | Let's go
301 |
302 |
303 | )
304 | }
305 | }
--------------------------------------------------------------------------------
/src/Utils/Parser.js:
--------------------------------------------------------------------------------
1 | //import * as acorn from "acorn";
2 |
3 |
4 | const testASR = `{"type": "Program",\n "start": 0,\n "end": 198,\n "body": [\n {\n "type": "ImportDeclaration",\n "start": 0,\n "end": 20,\n "specifiers": [],\n "source": {\n "type": "Literal",\n "start": 7,\n "end": 20,\n "value": "x86intrin.h",\n "raw": "\\"x86intrin.h\\""\n }\n },\n {\n "type": "FunctionDeclaration",\n "start": 22,\n "end": 198,\n "id": {\n "type": "Identifier",\n "start": 31,\n "end": 40,\n "name": "PrefixSum"\n },\n "generator": false,\n "expression": false,\n "params": [\n {\n "type": "Identifier",\n "start": 41,\n "end": 45,\n "name": "curr"\n }\n ],\n "body": {\n "type": "BlockStatement",\n "start": 47,\n "end": 198,\n "body": [\n {\n "type": "VariableDeclaration",\n "start": 53,\n "end": 87,\n "declarations": [\n {\n "type": "VariableDeclarator",\n "start": 57,\n "end": 86,\n "id": {\n "type": "Identifier",\n "start": 57,\n "end": 60,\n "name": "Add"\n },\n "init": {\n "type": "CallExpression",\n "start": 63,\n "end": 86,\n "callee": {\n "type": "Identifier",\n "start": 63,\n "end": 77,\n "name": "_mm_slli_si128"\n },\n "arguments": [\n {\n "type": "Identifier",\n "start": 78,\n "end": 82,\n "name": "curr"\n },\n {\n "type": "Literal",\n "start": 84,\n "end": 85,\n "value": 4,\n "raw": "4"\n }\n ]\n }\n }\n ],\n "kind": "let"\n },\n {\n "type": "ExpressionStatement",\n "start": 92,\n "end": 124,\n "expression": {\n "type": "AssignmentExpression",\n "start": 92,\n "end": 123,\n "operator": "=",\n "left": {\n "type": "Identifier",\n "start": 92,\n "end": 96,\n "name": "curr"\n },\n "right": {\n "type": "CallExpression",\n "start": 99,\n "end": 123,\n "callee": {\n "type": "Identifier",\n "start": 99,\n "end": 112,\n "name": "_mm_add_epi32"\n },\n "arguments": [\n {\n "type": "Identifier",\n "start": 113,\n "end": 117,\n "name": "curr"\n },\n {\n "type": "Identifier",\n "start": 119,\n "end": 122,\n "name": "Add"\n }\n ]\n }\n }\n },\n {\n "type": "ExpressionStatement",\n "start": 129,\n "end": 159,\n "expression": {\n "type": "AssignmentExpression",\n "start": 129,\n "end": 158,\n "operator": "=",\n "left": {\n "type": "Identifier",\n "start": 129,\n "end": 132,\n "name": "Add"\n },\n "right": {\n "type": "CallExpression",\n "start": 135,\n "end": 158,\n "callee": {\n "type": "Identifier",\n "start": 135,\n "end": 149,\n "name": "_mm_slli_si128"\n },\n "arguments": [\n {\n "type": "Identifier",\n "start": 150,\n "end": 154,\n "name": "curr"\n },\n {\n "type": "Literal",\n "start": 156,\n "end": 157,\n "value": 8,\n "raw": "8"\n }\n ]\n }\n }\n },\n {\n "type": "ReturnStatement",\n "start": 164,\n "end": 196,\n "argument": {\n "type": "CallExpression",\n "start": 171,\n "end": 195,\n "callee": {\n "type": "Identifier",\n "start": 171,\n "end": 184,\n "name": "_mm_add_epi32"\n },\n "arguments": [\n {\n "type": "Identifier",\n "start": 185,\n "end": 189,\n "name": "curr"\n },\n {\n "type": "Identifier",\n "start": 191,\n "end": 194,\n "name": "Add"\n }\n ]\n }\n }\n ]\n }\n }\n ],\n "sourceType": "module"\n}`
5 | class Node {
6 | constructor(type, name, line) {
7 | this.type = type;
8 | this.name = name;
9 | this.line = line;
10 | }
11 | }
12 |
13 | export function generateAST(editor) {
14 | //let code = editor.doc.getValue();
15 | // code = cleanExpression(code);
16 | // let ast = new Node("Program", 0, code.length);
17 | // ast.body = recursiveASTBuilder(code, 0, 0);
18 |
19 | //code = code.replace(new RegExp('int', 'g'), 'let');
20 |
21 | //return acorn.parse(code)
22 |
23 | //Temporary.. We disable AST parsing.. We"ll come back to AST later.
24 | return JSON.parse(testASR)
25 | }
26 |
27 | const getBitWidth = (type) => {
28 | switch (type.replace(/unsigned /g, '')) {
29 | case "long":
30 | case "long long":
31 | case "double":
32 | return 64;
33 | case "float":
34 | case "int":
35 | return 32;
36 | case "short":
37 | return 16;
38 | case "char":
39 | return 8;
40 | default:
41 | console.log(`hmm... I don't know this type: ${type}...`);
42 | return null;
43 | }
44 | };
45 |
46 | const simplifyType = (complexType) => {
47 | if (complexType === 'double' || complexType === 'float')
48 | return 'float';
49 | else
50 | return 'int'
51 | };
52 |
53 | const functionName = /([\w]+)\(.* # @.*/;
54 | const functionParams = /\b[^()]+\((.*)\)$/;
55 | const vectorParam = /(.*)[ ](__vector\(([0-9]+)\))/;
56 |
57 | export function generateASM(rawAsm) {
58 | let asm = [];
59 | let currentFunction = {
60 | body: []
61 | };
62 | rawAsm.forEach(line => {
63 | if (functionName.test(line.text)) {
64 | let name = functionName.exec(line.text)[1];
65 | let func = rawAsm[0].text.replace(/:.*/g, '');
66 | let params = functionParams.exec(func)[1].split(", ");
67 | let parsedParams = [];
68 | params.forEach((p) => {
69 | if (vectorParam.test(p)) {
70 | const parsedParam = vectorParam.exec(p);
71 | parsedParams.push({
72 | lanes: +parsedParam[3],
73 | type: simplifyType(parsedParam[1]),
74 | bitWidth: getBitWidth(parsedParam[1]),
75 | base: 10 //decimal
76 | })
77 | }
78 | else {
79 | parsedParams.push({
80 | lanes: 1,
81 | type: simplifyType(p),
82 | bitWidth: getBitWidth(p),
83 | base: 10 //decimal
84 | })
85 | }
86 | });
87 | currentFunction = new Node("Function", name, 0);
88 | currentFunction.body = [];
89 | currentFunction.params = parsedParams;
90 | asm.push(currentFunction);
91 | }
92 | else if (line.text.length > 0 && line.source) {
93 | // Remove comments, commas, trim it and then split
94 | let command = line.text.trim().replace(/,| #.*/g, '').split(" ");
95 | let name = command[0];
96 | let params = command.slice(1, command.length);
97 |
98 | let node = new Node("Command", name, line.source.line);
99 | node.params = params;
100 | currentFunction.body.push(node);
101 | }
102 | });
103 | return asm
104 | }
105 |
106 |
107 | // function recursiveASTBuilder(code, start) {
108 | // let ast = [];
109 | //
110 | // if (isAssignExpr(code)) {
111 | // let tokens = getAssignExpr(code);
112 | // let end = start + code.length;
113 | // let node = new Node("VariableDeclaration", start, end)
114 | // node.kind = tokens[1];
115 | // console.log(tokens);
116 | // ast.push(node)
117 | // }
118 | // if (isFuncDeclaration(code)) {
119 | // let tokens = getFuncDeclaration(code);
120 | // let end = start + code.length;
121 | // let node = new Node("FunctionDeclaration", start, end)
122 | // ast.push(node)
123 | // }
124 | // if (isFuncCall(code)) {
125 | // let tokens = getFuncCall(code);
126 | // let end = start + code.length;
127 | // let node = new Node("FunctionCall", start, end)
128 | // ast.push(node)
129 | // }
130 | // if (isReturnExpr(code)) {
131 | // let tokens = getReturnExpr(code);
132 | // let end = start + code.length;
133 | // let node = new Node("ReturnExpression", start, end)
134 | // ast.push(node)
135 | // }
136 | //
137 | //
138 | // return ast;
139 | // }
140 | //
141 | // function cleanExpression(s){ //just supress superfluous space and other invisible characters
142 | // return (s.replace(/\s{1,}/g, ' ')).trim();
143 | // }
144 | //
145 | // function extractExpression(s){ //this function extract the different expressions of a given c code, by expression we mean a piece of code situated after a ';' or a '{' and ended either by ';' or by '}'.This extract the expressions at the "same level"
146 | // s=cleanExpression(s);
147 | // var accoladeIndication=0;
148 | // var expresions=[];
149 | // const delimiters=new Set([';', '}']);
150 | // var i=s.indexOf('{')+1,lengthS=s.lastIndexOf('}'); // we first determine the begining and the ending of the piece of c code
151 | // var semicolonPosition=i;
152 | // while(i
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 | mousewheelZoom
276 | highlightRange
277 | ui
278 | getDefaultProps
279 | getInitialState
280 | currentColor
281 | React App
282 | command
283 | onMouseLeave
284 | it it
285 | handleClear
286 | Anime
287 | asmVisualizer
288 | setInterval
289 | cm
290 | onComplete
291 | registry
292 | typeList
293 |
294 |
295 |
296 |
297 |
298 |
299 |
300 |
301 |
302 |
303 |
304 |
305 |
306 |
307 |
308 |
309 |
310 |
311 |
312 |
313 |
314 |
315 |
316 |
317 |
318 |
319 |
320 |
321 |
322 |
323 |
324 |
325 |
326 |
327 |
328 |
329 |
330 |
331 |
332 |
333 |
334 |
335 |
336 |
337 |
338 |
339 |
340 |
341 |
342 |
343 |
344 |
345 |
346 |
347 |
348 |
349 |
350 |
351 |
352 |
353 |
354 |
355 |
356 |
357 |
358 |
359 |
360 |
361 |
362 |
363 | true
364 | DEFINITION_ORDER
365 |
366 |
367 |
368 |
369 |
370 |
371 |
372 |
373 |
374 |
375 |
376 |
377 |
378 |
379 |
380 |
381 |
382 |
383 |
384 |
385 |
386 |
387 |
388 |
389 |
390 |
391 |
392 |
393 |
394 |
395 |
396 |
397 |
398 |
399 |
400 |
401 |
402 |
403 |
404 |
405 |
406 |
407 |
408 |
409 |
410 |
411 |
412 |
413 |
414 |
415 |
416 |
417 |
418 |
419 |
420 |
421 |
422 |
423 |
424 |
425 |
426 |
427 |
428 |
429 |
430 |
431 |
432 |
433 |
434 |
435 |
436 |
437 |
438 |
439 |
440 |
441 |
442 |
443 |
444 |
445 |
446 |
447 |
448 |
449 |
450 |
451 |
452 |
453 |
454 |
455 |
456 |
457 |
458 |
459 |
460 |
461 |
462 |
463 |
464 |
465 |
466 |
467 |
468 |
469 |
470 |
471 |
472 |
473 |
474 |
475 |
476 |
477 |
478 |
479 |
480 |
481 |
482 |
483 |
484 |
485 |
486 |
487 |
488 |
489 |
490 |
491 |
492 |
493 |
494 |
495 |
496 |
497 |
498 |
499 |
500 |
501 |
502 |
503 |
504 |
505 |
506 |
507 |
508 |
509 |
510 |
511 |
512 |
513 |
514 |
515 |
516 |
517 |
518 |
519 |
520 |
521 |
522 |
523 |
524 |
525 |
526 |
527 |
528 |
529 |
530 |
531 |
532 |
533 |
534 |
535 |
536 | 1540841220536
537 |
538 |
539 | 1540841220536
540 |
541 |
542 |
543 |
544 |
545 |
546 |
547 |
548 |
549 |
550 |
551 | 1541192536019
552 |
553 |
554 |
555 | 1541192536020
556 |
557 |
558 | 1541193496916
559 |
560 |
561 |
562 | 1541193496916
563 |
564 |
565 | 1541627074965
566 |
567 |
568 |
569 | 1541627074965
570 |
571 |
572 | 1541693254350
573 |
574 |
575 |
576 | 1541693254350
577 |
578 |
579 | 1541801987700
580 |
581 |
582 |
583 | 1541801987700
584 |
585 |
586 | 1541802241357
587 |
588 |
589 |
590 | 1541802241357
591 |
592 |
593 | 1542741699043
594 |
595 |
596 |
597 | 1542741699043
598 |
599 |
600 | 1542750929919
601 |
602 |
603 |
604 | 1542750929919
605 |
606 |
607 | 1542838532117
608 |
609 |
610 |
611 | 1542838532117
612 |
613 |
614 | 1542839052410
615 |
616 |
617 |
618 | 1542839052410
619 |
620 |
621 | 1543010163681
622 |
623 |
624 |
625 | 1543010163681
626 |
627 |
628 | 1543011067023
629 |
630 |
631 |
632 | 1543011067023
633 |
634 |
635 | 1543011554756
636 |
637 |
638 |
639 | 1543011554756
640 |
641 |
642 | 1543353305606
643 |
644 |
645 |
646 | 1543353305606
647 |
648 |
649 | 1543357976976
650 |
651 |
652 |
653 | 1543357976976
654 |
655 |
656 | 1543519248250
657 |
658 |
659 |
660 | 1543519248250
661 |
662 |
663 | 1543519284231
664 |
665 |
666 |
667 | 1543519284231
668 |
669 |
670 | 1543519602534
671 |
672 |
673 |
674 | 1543519602534
675 |
676 |
677 | 1543520961919
678 |
679 |
680 |
681 | 1543520961919
682 |
683 |
684 | 1543533149725
685 |
686 |
687 |
688 | 1543533149725
689 |
690 |
691 | 1543589099225
692 |
693 |
694 |
695 | 1543589099225
696 |
697 |
698 | 1543589160920
699 |
700 |
701 |
702 | 1543589160920
703 |
704 |
705 | 1543608598160
706 |
707 |
708 |
709 | 1543608598160
710 |
711 |
712 | 1543608615471
713 |
714 |
715 |
716 | 1543608615471
717 |
718 |
719 | 1543878735651
720 |
721 |
722 |
723 | 1543878735652
724 |
725 |
726 | 1543963351575
727 |
728 |
729 |
730 | 1543963351575
731 |
732 |
733 | 1544036546180
734 |
735 |
736 |
737 | 1544036546180
738 |
739 |
740 | 1544038601634
741 |
742 |
743 |
744 | 1544038601634
745 |
746 |
747 | 1544038927180
748 |
749 |
750 |
751 | 1544038927180
752 |
753 |
754 | 1544124788640
755 |
756 |
757 |
758 | 1544124788640
759 |
760 |
761 | 1544124877022
762 |
763 |
764 |
765 | 1544124877022
766 |
767 |
768 | 1544124944301
769 |
770 |
771 |
772 | 1544124944301
773 |
774 |
775 | 1544131011876
776 |
777 |
778 |
779 | 1544131011876
780 |
781 |
782 | 1544143341338
783 |
784 |
785 |
786 | 1544143341338
787 |
788 |
789 | 1544472957463
790 |
791 |
792 |
793 | 1544472957463
794 |
795 |
796 | 1544483032753
797 |
798 |
799 |
800 | 1544483032753
801 |
802 |
803 | 1544553044525
804 |
805 |
806 |
807 | 1544553044525
808 |
809 |
810 | 1544570545980
811 |
812 |
813 |
814 | 1544570545980
815 |
816 |
817 | 1544654680677
818 |
819 |
820 |
821 | 1544654680677
822 |
823 |
824 | 1544832066008
825 |
826 |
827 |
828 | 1544832066008
829 |
830 |
831 | 1545163372962
832 |
833 |
834 |
835 | 1545163372962
836 |
837 |
838 |
839 |
840 |
841 |
842 |
843 |
844 |
845 |
846 |
847 |
848 |
849 |
850 |
851 |
852 |
853 |
854 |
855 |
856 |
857 |
858 |
859 |
860 |
861 |
862 |
863 |
864 |
865 |
866 |
867 |
868 |
869 |
870 |
871 |
872 |
873 |
874 |
875 |
876 |
877 |
878 |
879 |
880 |
881 |
882 |
883 |
884 |
885 |
886 |
887 |
888 |
889 |
890 |
891 |
892 |
893 |
894 |
895 |
896 |
897 |
898 |
899 |
900 |
901 |
902 |
903 |
904 |
905 |
906 |
907 |
908 |
909 |
910 |
911 |
912 |
913 |
914 |
915 |
916 |
917 |
918 |
919 |
920 |
921 |
922 |
923 |
924 |
925 |
926 |
927 |
928 |
929 |
930 |
931 |
932 |
933 |
934 |
935 |
936 |
937 |
938 |
939 |
940 |
941 |
942 |
943 |
944 |
945 |
946 |
947 |
948 |
949 |
950 |
951 |
952 |
953 |
954 |
955 |
956 |
957 |
958 |
959 |
960 |
961 |
962 |
963 |
964 |
965 |
966 |
967 |
968 |
969 |
970 |
971 |
972 |
973 |
974 |
975 |
976 |
977 |
978 |
979 |
980 |
981 |
982 |
983 |
984 |
985 |
986 |
987 |
988 |
989 |
990 |
991 |
992 |
993 |
994 |
995 |
996 |
997 |
998 |
999 |
1000 |
1001 |
1002 |
1003 |
1004 |
1005 |
1006 |
1007 |
1008 |
1009 |
1010 |
1011 |
1012 |
1013 |
1014 |
1015 |
1016 |
1017 |
1018 |
1019 |
1020 |
1021 |
1022 |
1023 |
1024 |
1025 |
1026 |
1027 |
1028 |
1029 |
1030 |
1031 |
1032 |
1033 |
1034 |
1035 |
1036 |
1037 |
1038 |
1039 |
1040 |
1041 |
1042 |
1043 |
1044 |
1045 |
1046 |
1047 |
1048 |
1049 |
1050 |
1051 |
1052 |
1053 |
1054 |
1055 |
1056 |
1057 |
1058 |
1059 |
1060 |
1061 |
1062 |
1063 |
1064 |
1065 |
1066 |
1067 |
1068 |
1069 |
1070 |
1071 |
1072 |
1073 |
1074 |
1075 |
1076 |
1077 |
1078 |
1079 |
1080 |
1081 |
1082 |
1083 |
1084 |
1085 |
1086 |
1087 |
1088 |
1089 |
1090 |
1091 |
1092 |
1093 |
1094 |
1095 |
1096 |
1097 |
1098 |
1099 |
1100 |
1101 |
1102 |
1103 |
1104 |
1105 |
1106 |
1107 |
1108 |
1109 |
1110 |
1111 |
1112 |
1113 |
1114 |
1115 |
1116 |
1117 |
1118 |
1119 |
1120 |
1121 |
1122 |
1123 |
1124 |
1125 |
1126 |
1127 |
1128 |
1129 |
1130 |
1131 |
1132 |
1133 |
1134 |
1135 |
1136 |
1137 |
1138 |
1139 |
1140 |
1141 |
1142 |
1143 |
1144 |
1145 |
1146 |
1147 |
1148 |
1149 |
1150 |
1151 |
1152 |
1153 |
1154 |
1155 |
1156 |
1157 |
1158 |
1159 |
1160 |
1161 |
1162 |
1163 |
1164 |
1165 |
1166 |
1167 |
1168 |
1169 |
1170 |
1171 |
1172 |
1173 |
1174 |
1175 |
1176 |
1177 |
1178 |
1179 |
1180 |
1181 |
1182 |
1183 |
1184 |
1185 |
1186 |
1187 |
1188 |
1189 |
1190 |
1191 |
1192 |
1193 |
1194 |
1195 |
1196 |
1197 |
1198 |
1199 |
1200 |
1201 |
1202 |
1203 |
1204 |
1205 |
1206 |
1207 |
1208 |
1209 |
1210 |
1211 |
1212 |
1213 |
1214 |
1215 |
1216 |
1217 |
1218 |
1219 |
1220 |
1221 |
1222 |
1223 |
1224 |
1225 |
1226 |
1227 |
1228 |
1229 |
1230 |
1231 |
1232 |
1233 |
1234 |
1235 |
1236 |
1237 |
1238 |
1239 |
1240 |
1241 |
1242 |
1243 |
1244 |
1245 |
1246 |
1247 |
1248 |
1249 |
1250 |
1251 |
1252 |
1253 |
1254 |
1255 |
1256 |
1257 |
1258 |
1259 |
1260 |
1261 |
1262 |
1263 |
1264 |
1265 |
1266 |
1267 |
1268 |
1269 |
1270 |
--------------------------------------------------------------------------------