Skip to content

Commit

Permalink
Add Julia (#4595)
Browse files Browse the repository at this point in the history
  • Loading branch information
aw32 authored and mattgodbolt committed Jan 24, 2023
1 parent 68713f6 commit f6469b1
Show file tree
Hide file tree
Showing 11 changed files with 312 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .github/labeler.yml
Expand Up @@ -101,6 +101,9 @@ lang-mlir:
lang-java:
- lib/compilers/java.js
- etc/config/java.*.properties
lang-julia:
- lib/compilers/julia.js
- etc/config/julia.*.properties
lang-kotlin:
- lib/compilers/kotlin.js
- etc/config/kotlin.*.properties
Expand Down
14 changes: 14 additions & 0 deletions etc/config/julia.amazon.properties
@@ -0,0 +1,14 @@
# Default settings for Julia
compilers=&julia
defaultCompiler=julia_1_8_5
compilerType=julia

group.julia.compilers=julia_1_8_5:julia_1_7_3
group.julia.isSemVer=true
group.julia.baseName=Julia
compiler.julia_1_8_5.exe=/opt/compiler-explorer/julia-1.8.5/bin/julia
compiler.julia_1_8_5.semver=1.8.5
compiler.julia_1_8_5.alias=julia_1_8_5
compiler.julia_1_7_3.exe=/opt/compiler-explorer/julia-1.7.3/bin/julia
compiler.julia_1_7_3.semver=1.7.3
compiler.julia_1_7_3.alias=julia_1_7_3
6 changes: 6 additions & 0 deletions etc/config/julia.defaults.properties
@@ -0,0 +1,6 @@
# Default settings for Julia
compilers=julia
defaultCompiler=julia
compilerType=julia
interpreted=true
supportsBinary=false
121 changes: 121 additions & 0 deletions etc/scripts/julia_wrapper.jl
@@ -0,0 +1,121 @@
doc = """Julia wrapper.
Usage:
julia_wrapper.jl <input_code> <output_path> [--format=<fmt>] [--debuginfo=<info>] [--optimize] [--verbose]
julia_wrapper.jl --help
Options:
-h --help Show this screen.
--format=<fmt> Set output format (One of "lowered", "typed", "warntype", "llvm", "native") [default: native]
lowered
typed
warntype
llvm
native
--debuginfo=<info> Controls amount of generated metadata (One of "default", "none") [default: default]
--optimize Sets whether "llvm" output should be optimized or not.
--verbose Prints some process info
"""

using InteractiveUtils

if length(ARGS) < 2
println(doc)
exit(1)
end

if length(ARGS) > 3 && ARGS[3] == "--help"
println(doc)
end

input_file = popfirst!(ARGS)
output_path = popfirst!(ARGS)
format = "native"
debuginfo = :default
optimize = false
verbose = false

for x in ARGS
if startswith(x, "--format=")
global format = x[10:end]
end
if startswith(x, "--debuginfo=")
if x[13:end] == "none"
global debuginfo = :none
end
end
if x == "--optimize"
global optimize = true
end
if x == "--verbose"
global verbose = true
end
end

# Include user code into module
m = Module(:Godbolt)
Base.include(m, input_file)

# Find functions and method specializations
m_methods = Any[]
for name in names(m, all=true)
local fun = getfield(m, name)
if fun isa Function
if verbose
println("Function: ", fun)
end
for me in methods(fun)
for s in me.specializations
if s != nothing
me_types = getindex(s.specTypes.parameters, 2:length(s.specTypes.parameters))
push!(m_methods, (fun, me_types, me))
if verbose
println(" Method types: ", me_types)
end
end
end
end
end
end

# Open output file
open(output_path, "w") do io
# For all found methods
for (me_fun, me_types, me) in m_methods
io_buf = IOBuffer() # string buffer
if format == "typed"
ir, retval = InteractiveUtils.code_typed(me_fun, me_types, debuginfo=debuginfo)[1]
Base.IRShow.show_ir(io_buf, ir)
elseif format == "lowered"
cl = Base.code_lowered(me_fun, me_types, debuginfo=debuginfo)
print(io_buf, cl)
elseif format == "llvm"
InteractiveUtils.code_llvm(io_buf, me_fun, me_types, optimize=optimize, debuginfo=debuginfo)
elseif format == "native"
InteractiveUtils.code_native(io_buf, me_fun, me_types, debuginfo=debuginfo)
elseif format == "warntype"
InteractiveUtils.code_warntype(io_buf, me_fun, me_types, debuginfo=debuginfo)
end
code = String(take!(io_buf))
line_num = count("\n",code)
# Print first line: <[source code line] [number of output lines] [function name] [method types]>
write(io, "<")
print(io, me.line)
print(io, " ")
print(io, line_num)
print(io, " ")
print(io, me_fun)
write(io, " ")
for i in 1:length(me_types)
print(io, me_types[i])
if i < length(me_types)
write(io, ", ")
end
end
write(io, ">\n")
# Print code for this method
write(io, code)
write(io, "\n")
end
end
exit(0)
5 changes: 5 additions & 0 deletions examples/julia/default.jl
@@ -0,0 +1,5 @@
function square(x)
return x * x
end

precompile(square, (Int32,))
1 change: 1 addition & 0 deletions lib/compilers/_all.js
Expand Up @@ -64,6 +64,7 @@ export {HookCompiler} from './hook';
export {ISPCCompiler} from './ispc';
export {JaktCompiler} from './jakt';
export {JavaCompiler} from './java';
export {JuliaCompiler} from './julia';
export {KotlinCompiler} from './kotlin';
export {LDCCompiler} from './ldc';
export {LLCCompiler} from './llc';
Expand Down
141 changes: 141 additions & 0 deletions lib/compilers/julia.ts
@@ -0,0 +1,141 @@
// Copyright (c) 2018, 2023, Elliot Saba & Compiler Explorer Authors
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

import e from 'express';
import fs from 'fs';
import path from 'path';

import {ParsedAsmResultLine} from '../../types/asmresult/asmresult.interfaces';
import {CompilationResult, ExecutionOptions} from '../../types/compilation/compilation.interfaces';
import {BaseCompiler} from '../base-compiler';
import {logger} from '../logger';
import * as utils from '../utils';

import {BaseParser} from './argument-parsers';

export class JuliaCompiler extends BaseCompiler {
private compilerWrapperPath: string;

static get key() {
return 'julia';
}

constructor(info, env) {
super(info, env);
this.compiler.demangler = '';
this.demanglerClass = null;
this.compilerWrapperPath =
this.compilerProps('compilerWrapper', '') ||
utils.resolvePathFromAppRoot('etc', 'scripts', 'julia_wrapper.jl');
}

// No demangling for now
override postProcessAsm(result) {
return result;
}

override getSharedLibraryPathsAsArguments() {
return [];
}

override processAsm(result, filters, options) {
const lineRe = /^<(\d+) (\d+) ([^ ]+) ([^>]*)>$/;
const bytecodeLines = result.asm.split('\n');
const bytecodeResult: ParsedAsmResultLine[] = [];
// Every method block starts with a introductory line
// <[source code line] [output line number] [function name] [method types]>
// Check for the starting line, add the method block, skip other lines
let i = 0;
while (i < bytecodeLines.length) {
const line = bytecodeLines[i];
const match = line.match(lineRe);

if (match) {
const source = parseInt(match[1]);
let linenum = parseInt(match[2]);
linenum = Math.min(linenum, bytecodeLines.length);
const funname = match[3];
const types = match[4];
let j = 0;
bytecodeResult.push({text: '<' + funname + ' ' + types + '>', source: {line: source, file: null}});
while (j < linenum) {
bytecodeResult.push({text: bytecodeLines[i + 1 + j], source: {line: source, file: null}});
j++;
}
bytecodeResult.push({text: '', source: {file: null}});
i += linenum + 1;
continue;
}
i++;
}
return {asm: bytecodeResult};
}

override optionsForFilter(filters, outputFilename) {
return [];
}

override getArgumentParser() {
return BaseParser;
}

override fixExecuteParametersForInterpreting(executeParameters, outputFilename, key) {
super.fixExecuteParametersForInterpreting(executeParameters, outputFilename, key);
executeParameters.args.unshift('--');
}

override async runCompiler(
compiler: string,
options: string[],
inputFilename: string,
execOptions: ExecutionOptions,
): Promise<CompilationResult> {
if (!execOptions) {
execOptions = this.getDefaultExecOptions();
}

const dirPath = path.dirname(inputFilename);

if (!execOptions.customCwd) {
execOptions.customCwd = dirPath;
}

// compiler wrapper, then input should be first argument, not last
const wrapperOptions = options.filter(opt => opt !== inputFilename);

const juliaOptions = [this.compilerWrapperPath, '--'];
if (options.includes('-h') || options.includes('--help')) {
juliaOptions.push('--help');
} else {
wrapperOptions.unshift(inputFilename, this.getOutputFilename(dirPath, this.outputFilebase));
juliaOptions.push(...wrapperOptions);
}

const execResult = await this.exec(compiler, juliaOptions, execOptions);
return {
compilationOptions: juliaOptions,
...this.transformToCompilationResult(execResult, inputFilename),
};
}
}
11 changes: 11 additions & 0 deletions lib/languages.ts
Expand Up @@ -385,6 +385,17 @@ const definitions: Record<LanguageKey, LanguageDefinition> = {
previewFilter: null,
monacoDisassembly: null,
},
julia: {
name: 'Julia',
monaco: 'julia',
extensions: ['.jl'],
alias: [],
logoUrl: 'julia.svg',
logoUrlDark: null,
formatter: null,
previewFilter: null,
monacoDisassembly: null,
},
kotlin: {
name: 'Kotlin',
monaco: 'kotlin',
Expand Down
1 change: 1 addition & 0 deletions types/languages.interfaces.ts
Expand Up @@ -53,6 +53,7 @@ export type LanguageKey =
| 'ispc'
| 'jakt'
| 'java'
| 'julia'
| 'kotlin'
| 'llvm'
| 'mlir'
Expand Down
8 changes: 8 additions & 0 deletions views/resources/logos/julia.svg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions webpack.config.esm.js
Expand Up @@ -67,6 +67,7 @@ const plugins = [
'rust',
'swift',
'java',
'julia',
'kotlin',
'scala',
'ruby',
Expand Down

0 comments on commit f6469b1

Please sign in to comment.