Merge branch 'main' into armcom11and12

This commit is contained in:
Patrick Quist
2023-11-10 12:19:14 +01:00
committed by GitHub
105 changed files with 10770 additions and 2363 deletions

View File

@@ -3,7 +3,7 @@
set -eo pipefail
# when in a VS Code or GitHub Codespaces devcontainer
if [ -n "${REMOTE_CONTAINERS}" ]; then
if [ -n "${REMOTE_CONTAINERS}" ] || [ -n "${CODESPACES}" ]; then
this_dir=$(cd -P -- "$(dirname -- "$(command -v -- "$0")")" && pwd -P)
workspace_root=$(realpath ${this_dir}/..)

4
.github/labeler.yml vendored
View File

@@ -174,6 +174,10 @@ lang-swift:
lang-snowball:
- lib/compilers/snowball.ts
- etc/config/snowball.*.properties
lang-tablegen:
- lib/compilers/tablegen.ts
- etc/config/tablegen.*.properties
- static/modes/tablegen-mode.ts
lang-toit:
- lib/compilers/toit.ts
- etc/config/toit.*.properties

View File

@@ -5,15 +5,26 @@
# Compiler Explorer
Is an interactive compiler exploration website. Edit code in C, C++, C#, F#, Rust, Go, D, Haskell,
Swift, Pascal, [ispc](https://ispc.github.io/), Python, Java, or any of the other [30+ supported languages](https://godbolt.org/api/languages) components, and see how that code looks after being compiled in real
time.
Is an interactive compiler exploration website. Edit code in C, C++, C#, F#, Rust, Go, D, Haskell, Swift, Pascal,
[ispc](https://ispc.github.io/), Python, Java, or any of the other
[30+ supported languages](https://godbolt.org/api/languages) components, and see how that code looks after being
compiled in real time.
[Bug Report](https://github.com/compiler-explorer/compiler-explorer/issues/new?assignees=&labels=bug&projects=&template=bug_report.yml&title=%5BBUG%5D%3A+) · [Compiler Request](https://github.com/compiler-explorer/compiler-explorer/issues/new?assignees=&labels=request%2Cnew-compilers&projects=&template=compiler_request.yml&title=%5BCOMPILER+REQUEST%5D%3A+) · [Feature Request](https://github.com/compiler-explorer/compiler-explorer/issues/new?assignees=&labels=request&projects=&template=feature_request.yml&title=%5BREQUEST%5D%3A+) · [Language Request](https://github.com/compiler-explorer/compiler-explorer/issues/new?assignees=&labels=request%2Cnew-language&projects=&template=language_request.yml&title=%5BLANGUAGE+REQUEST%5D%3A+) · [Library Request](https://github.com/compiler-explorer/compiler-explorer/issues/new?assignees=&labels=request%2Cnew-libs&projects=&template=library_request.yml&title=%5BLIB+REQUEST%5D%3A+) · [Report Vulnerability](https://github.com/compiler-explorer/compiler-explorer/security/advisories/new)
[Bug Report](https://github.com/compiler-explorer/compiler-explorer/issues/new?assignees=&labels=bug&projects=&template=bug_report.yml&title=%5BBUG%5D%3A+)
·
[Compiler Request](https://github.com/compiler-explorer/compiler-explorer/issues/new?assignees=&labels=request%2Cnew-compilers&projects=&template=compiler_request.yml&title=%5BCOMPILER+REQUEST%5D%3A+)
·
[Feature Request](https://github.com/compiler-explorer/compiler-explorer/issues/new?assignees=&labels=request&projects=&template=feature_request.yml&title=%5BREQUEST%5D%3A+)
·
[Language Request](https://github.com/compiler-explorer/compiler-explorer/issues/new?assignees=&labels=request%2Cnew-language&projects=&template=language_request.yml&title=%5BLANGUAGE+REQUEST%5D%3A+)
·
[Library Request](https://github.com/compiler-explorer/compiler-explorer/issues/new?assignees=&labels=request%2Cnew-libs&projects=&template=library_request.yml&title=%5BLIB+REQUEST%5D%3A+)
· [Report Vulnerability](https://github.com/compiler-explorer/compiler-explorer/security/advisories/new)
# Overview
Multiple compilers are supported for each language, many different tools and visualizations are available, and the UI layout is configurable (thanks to [GoldenLayout](https://www.golden-layout.com/)).
Multiple compilers are supported for each language, many different tools and visualizations are available, and the UI
layout is configurable (thanks to [GoldenLayout](https://www.golden-layout.com/)).
Try out at [godbolt.org](https://godbolt.org), or [run your own local instance](#running-a-local-instance). An overview
of what the site lets you achieve, why it's useful, and how to use it is

View File

@@ -99,7 +99,18 @@ Execution Only request example:
"userArguments": "-O3",
"executeParameters": {
"args": ["arg1", "arg2"],
"stdin": "hello, world!"
"stdin": "hello, world!",
"runtimeTools": [
{
"name": "env",
"options": [
{
"name": "MYENV",
"value": "123"
}
]
}
]
},
"compilerOptions": {
"executorRequest": true

View File

@@ -137,20 +137,20 @@ group.gnuasriscv32.compilers=gnuasriscv32g820:gnuasriscv32g1020:gnuasriscv32g114
group.gnuasriscv32.groupName=RISC-V (32-bits) binutils
group.gnuasriscv32.baseName=RISC-V (32-bits) binutils
compiler.gnuasriscv32g820.exe=/opt/compiler-explorer/riscv32/gcc-8.2.0/riscv32-unknown-linux-gnu/bin/riscv32-unknown-linux-gnu-as
compiler.gnuasriscv32g820.exe=/opt/compiler-explorer/riscv32/gcc-8.2.0/riscv32-unknown-elf/bin/riscv32-unknown-elf-as
compiler.gnuasriscv32g820.name=RISC-V binutils 2.31.1
compiler.gnuasriscv32g820.semver=2.31.1
compiler.gnuasriscv32g820.objdumper=/opt/compiler-explorer/riscv32/gcc-8.2.0/riscv32-unknown-linux-gnu/bin/riscv32-unknown-linux-gnu-objdump
compiler.gnuasriscv32g820.objdumper=/opt/compiler-explorer/riscv32/gcc-8.2.0/riscv32-unknown-elf/bin/riscv32-unknown-elf-objdump
compiler.gnuasriscv32g1020.exe=/opt/compiler-explorer/riscv32/gcc-10.2.0/riscv32-unknown-linux-gnu/bin/riscv32-unknown-linux-gnu-as
compiler.gnuasriscv32g1020.exe=/opt/compiler-explorer/riscv32/gcc-10.2.0/riscv32-unknown-elf/bin/riscv32-unknown-elf-as
compiler.gnuasriscv32g1020.name=RISC-V binutils 2.35.1
compiler.gnuasriscv32g1020.semver=2.35.1
compiler.gnuasriscv32g1020.objdumper=/opt/compiler-explorer/riscv32/gcc-10.2.0/riscv32-unknown-linux-gnu/bin/riscv32-unknown-linux-gnu-objdump
compiler.gnuasriscv32g1020.objdumper=/opt/compiler-explorer/riscv32/gcc-10.2.0/riscv32-unknown-elf/bin/riscv32-unknown-elf-objdump
compiler.gnuasriscv32g1140.exe=/opt/compiler-explorer/riscv32/gcc-11.4.0/riscv32-unknown-linux-gnu/bin/riscv32-unknown-linux-gnu-as
compiler.gnuasriscv32g1140.exe=/opt/compiler-explorer/riscv32/gcc-11.4.0/riscv32-unknown-elf/bin/riscv32-unknown-elf-as
compiler.gnuasriscv32g1140.name=RISC-V binutils 2.37.0
compiler.gnuasriscv32g1140.semver=2.37.0
compiler.gnuasriscv32g1140.objdumper=/opt/compiler-explorer/riscv32/gcc-11.4.0/riscv32-unknown-linux-gnu/bin/riscv32-unknown-linux-gnu-objdump
compiler.gnuasriscv32g1140.objdumper=/opt/compiler-explorer/riscv32/gcc-11.4.0/riscv32-unknown-elf/bin/riscv32-unknown-elf-objdump
compiler.gnuasriscv32g1320.exe=/opt/compiler-explorer/riscv32/gcc-13.2.0/riscv32-unknown-linux-gnu/bin/riscv32-unknown-linux-gnu-as
compiler.gnuasriscv32g1320.name=RISC-V binutils 2.38.0

View File

@@ -17,7 +17,7 @@ llvmDisassembler=/opt/compiler-explorer/clang-14.0.0/bin/llvm-dis
###############################
# GCC for x86
group.gcc86.compilers=g412:g447:g453:g464:g471:g472:g473:g474:g481:g482:g483:g484:g485:g490:g491:g492:g493:g494:g510:g520:g530:g540:g550:g6:g62:g63:g64:g71:g72:g73:g74:g75:g81:g82:g83:g84:g85:g91:g92:g93:g94:g95:g101:g102:g103:g104:g105:g111:g112:g113:g114:g121:g122:g123:g131:g132:gsnapshot:gcontracts-trunk:gcontract-labels-trunk:gcxx-modules-trunk:gcxx-coroutines-trunk:gcc-embed-trunk:gcc-static-analysis-trunk
group.gcc86.compilers=g412:g447:g453:g464:g471:g472:g473:g474:g481:g482:g483:g484:g485:g490:g491:g492:g493:g494:g510:g520:g530:g540:g550:g6:g62:g63:g64:g71:g72:g73:g74:g75:g81:g82:g83:g84:g85:g91:g92:g93:g94:g95:g101:g102:g103:g104:g105:g111:g112:g113:g114:g121:g122:g123:g131:g132:gsnapshot:gcontracts-trunk:gcontract-labels-trunk:gcontracts-nonattr-trunk:gcxx-modules-trunk:gcxx-coroutines-trunk:gcc-embed-trunk:gcc-static-analysis-trunk
group.gcc86.groupName=GCC x86-64
group.gcc86.instructionSet=amd64
group.gcc86.baseName=x86-64 gcc
@@ -174,6 +174,12 @@ compiler.gcontract-labels-trunk.objdumper=/opt/compiler-explorer/gcc-snapshot/bi
compiler.gcontract-labels-trunk.semver=(contract labels)
compiler.gcontract-labels-trunk.isNightly=true
compiler.gcontract-labels-trunk.notification=Experimental Contract Label Support; see <a href="https://github.com/lock3/gcc/wiki" target="_blank" rel="noopener noreferrer">Lock3's repository wiki<sup><small class="fas fa-external-link-alt opens-new-window" title="Opens in a new window"></small></sup></a>
compiler.gcontracts-nonattr-trunk.exe=/opt/compiler-explorer/gcc-contracts-nonattr-trunk/bin/g++
compiler.gcontracts-nonattr-trunk.demangler=/opt/compiler-explorer/gcc-snapshot/bin/c++filt
compiler.gcontracts-nonattr-trunk.objdumper=/opt/compiler-explorer/gcc-snapshot/bin/objdump
compiler.gcontracts-nonattr-trunk.semver=(contracts natural syntax)
compiler.gcontracts-nonattr-trunk.isNightly=true
compiler.gcontracts-nonattr-trunk.notification=Experimental Contract Natural Syntax Support; see <a href="https://open-std.org/JTC1/SC22/WG21/docs/papers/2023/p2961r0.pdf" target="_blank" rel="noopener noreferrer">P2961R0<sup><small class="fas fa-external-link-alt opens-new-window" title="Opens in a new window"></small></sup></a>
compiler.gcxx-modules-trunk.exe=/opt/compiler-explorer/gcc-cxx-modules-trunk/bin/g++
compiler.gcxx-modules-trunk.demangler=/opt/compiler-explorer/gcc-snapshot/bin/c++filt
compiler.gcxx-modules-trunk.objdumper=/opt/compiler-explorer/gcc-snapshot/bin/objdump
@@ -720,7 +726,7 @@ compiler.armv8-clang-trunk.options=-target aarch64-linux-gnu --gcc-toolchain=/op
compiler.armv8-full-clang-trunk.exe=/opt/compiler-explorer/clang-trunk/bin/clang++
compiler.armv8-full-clang-trunk.demangler=/opt/compiler-explorer/gcc-snapshot/bin/c++filt
compiler.armv8-full-clang-trunk.objdumper=/opt/compiler-explorer/arm64/gcc-10.2.0/aarch64-unknown-linux-gnu/aarch64-unknown-linux-gnu/bin/objdump
compiler.armv8-full-clang-trunk.semver=(trunk, all architectural features)
compiler.armv8-full-clang-trunk.semver=(all architectural features, trunk)
compiler.armv8-full-clang-trunk.isNightly=true
# Arm v8-a with all supported architectural features
compiler.armv8-full-clang-trunk.options=-target aarch64-linux-gnu --gcc-toolchain=/opt/compiler-explorer/arm64/gcc-12.2.0/aarch64-unknown-linux-gnu --sysroot=/opt/compiler-explorer/arm64/gcc-12.2.0/aarch64-unknown-linux-gnu/aarch64-unknown-linux-gnu/sysroot -march=armv8.8-a+crypto+profile+rng+memtag+sve2+sve2-bitperm+sve2-sm4+sve2-aes+sve2-sha3+tme+brbe+f32mm+f64mm+fp16fml+ls64+sme+sme-f64f64+sme-i16i64+sme2
@@ -3698,9 +3704,9 @@ libs.libbpf.liblink=bpf:dl:m
libs.libbpf.description=Libbpf supports building BPF CO-RE-enabled applications
libs.libbpf.url=https://github.com/libbpf/libbpf
libs.libbpf.versions.100.version=1.0.0
libs.libbpf.versions.100.path=/opt/compiler-explorer/libs/libbpf/v1.0.0/include
libs.libbpf.versions.100.path=/opt/compiler-explorer/libs/libbpf/v1.0.0/include:/opt/compiler-explorer/libs/libbpf/v1.0.0/src
libs.libbpf.versions.122.version=1.2.2
libs.libbpf.versions.122.path=/opt/compiler-explorer/libs/libbpf/v1.2.2/include
libs.libbpf.versions.122.path=/opt/compiler-explorer/libs/libbpf/v1.2.2/include:/opt/compiler-explorer/libs/libbpf/v1.2.2/src
libs.libguarded.name=CsLibGuarded
libs.libguarded.versions=trunk:110
@@ -3990,11 +3996,13 @@ libs.qt.url=https://www.qt.io
libs.qt.packagedheaders=true
libs.qt.liblink=Qt6Core
libs.qt.options=-DQT_NO_VERSION_TAGGING
libs.qt.versions=642:652
libs.qt.versions=642:652:660
libs.qt.versions.642.version=6.4.2
libs.qt.versions.642.path=/app/qt/include/QtCore
libs.qt.versions.652.version=6.5.2
libs.qt.versions.652.path=/app/qt/include/QtCore
libs.qt.versions.660.version=6.6.0
libs.qt.versions.660.path=/app/qt/include/QtCore
libs.rangesv3.name=range-v3
libs.rangesv3.versions=trunk:030:035:036:091:0100:0110:0120
@@ -4049,10 +4057,14 @@ libs.scnlib.versions.04.path=/opt/compiler-explorer/libs/scnlib/refs/tags/v0.4/i
libs.seastar.name=Seastar
libs.seastar.description=SeaStar is an event-driven framework allowing you to write non-blocking, asynchronous code in a relatively straightforward manner.
libs.seastar.versions=180
libs.seastar.versions=trunk:180:2211
libs.seastar.url=http://seastar.io
libs.seastar.versions.180.version=18.08.0
libs.seastar.versions.180.path=/opt/compiler-explorer/libs/seastar/seastar-18.08.0
libs.seastar.versions.2211.version=22.11.0
libs.seastar.versions.2211.path=/opt/compiler-explorer/libs/seastar/seastar-22.11.0/include
libs.seastar.versions.trunk.version=trunk
libs.seastar.versions.trunk.path=/opt/compiler-explorer/libs/seastar/trunk/include
libs.seqan3.name=SeqAn3
libs.seqan3.description=A modern C++ library for sequence analysis.
@@ -4223,8 +4235,10 @@ libs.tomlplusplus.versions.124.version=1.2.4
libs.tomlplusplus.versions.124.path=/opt/compiler-explorer/libs/tomlplusplus/v1.2.4/include
libs.trompeloeil.name=trompeloeil
libs.trompeloeil.versions=45:44:43:42:41:40:39:38:37:36:35:34:33:32:31:30:29:28
libs.trompeloeil.versions=46:45:44:43:42:41:40:39:38:37:36:35:34:33:32:31:30:29:28
libs.trompeloeil.url=https://github.com/rollbear/trompeloeil
libs.trompeloeil.versions.46.path=/opt/compiler-explorer/libs/trompeloeil/v46/include
libs.trompeloeil.versions.46.version=v46
libs.trompeloeil.versions.45.path=/opt/compiler-explorer/libs/trompeloeil/v45/include
libs.trompeloeil.versions.45.version=v45
libs.trompeloeil.versions.44.path=/opt/compiler-explorer/libs/trompeloeil/v44/include
@@ -4520,7 +4534,7 @@ tools.llvm-mcatrunk.name=llvm-mca (trunk)
tools.llvm-mcatrunk.exe=/opt/compiler-explorer/clang-trunk/bin/llvm-mca
tools.llvm-mcatrunk.type=postcompilation
tools.llvm-mcatrunk.class=llvm-mca-tool
tools.llvm-mcatrunk.exclude=avr:rv32:arm:aarch:mips:msp:ppc:cl19:cl_new:djggp
tools.llvm-mcatrunk.exclude=avr:rv32:arm:mips:msp:ppc:cl19:cl_new:djggp
tools.llvm-mcatrunk.stdinHint=disabled
tools.osacatrunk.name=OSACA (0.5.2)

View File

@@ -545,7 +545,7 @@ compiler.armv8-cclang-trunk.isNightly=true
# Arm v8-a
compiler.armv8-cclang-trunk.options=-target aarch64-linux-gnu --gcc-toolchain=/opt/compiler-explorer/arm64/gcc-12.2.0/aarch64-unknown-linux-gnu --sysroot=/opt/compiler-explorer/arm64/gcc-12.2.0/aarch64-unknown-linux-gnu/aarch64-unknown-linux-gnu/sysroot
compiler.armv8-full-cclang-trunk.name=armv8-a clang (trunk, all architectural features)
compiler.armv8-full-cclang-trunk.name=armv8-a clang (all architectural features, trunk)
compiler.armv8-full-cclang-trunk.exe=/opt/compiler-explorer/clang-trunk/bin/clang
compiler.armv8-full-cclang-trunk.demangler=/opt/compiler-explorer/gcc-snapshot/bin/c++filt
compiler.armv8-full-cclang-trunk.objdumper=/opt/compiler-explorer/arm64/gcc-10.2.0/aarch64-unknown-linux-gnu/aarch64-unknown-linux-gnu/bin/objdump
@@ -2736,9 +2736,9 @@ libs.libbpf.liblink=bpf:dl:m
libs.libbpf.description=Libbpf supports building BPF CO-RE-enabled applications
libs.libbpf.url=https://github.com/libbpf/libbpf
libs.libbpf.versions.100.version=1.0.0
libs.libbpf.versions.100.path=/opt/compiler-explorer/libs/libbpf/v1.0.0/include
libs.libbpf.versions.100.path=/opt/compiler-explorer/libs/libbpf/v1.0.0/include:/opt/compiler-explorer/libs/libbpf/v1.0.0/src
libs.libbpf.versions.122.version=1.2.2
libs.libbpf.versions.122.path=/opt/compiler-explorer/libs/libbpf/v1.2.2/include
libs.libbpf.versions.122.path=/opt/compiler-explorer/libs/libbpf/v1.2.2/include:/opt/compiler-explorer/libs/libbpf/v1.2.2/src
libs.lua.name=Lua
libs.lua.versions=535:540

View File

@@ -1003,8 +1003,10 @@ libs.tomlplusplus.versions.124.version=1.2.4
libs.tomlplusplus.versions.124.path=/opt/compiler-explorer/libs/tomlplusplus/v1.2.4/include
libs.trompeloeil.name=trompeloeil
libs.trompeloeil.versions=45:44:43:42:41:40:39:38:37:36:35:34:33:32:31:30:29:28
libs.trompeloeil.versions=46:45:44:43:42:41:40:39:38:37:36:35:34:33:32:31:30:29:28
libs.trompeloeil.url=https://github.com/rollbear/trompeloeil
libs.trompeloeil.versions.46.path=/opt/compiler-explorer/libs/trompeloeil/v46/include
libs.trompeloeil.versions.46.version=v46
libs.trompeloeil.versions.45.path=/opt/compiler-explorer/libs/trompeloeil/v45/include
libs.trompeloeil.versions.45.version=v45
libs.trompeloeil.versions.44.path=/opt/compiler-explorer/libs/trompeloeil/v44/include

View File

@@ -40,6 +40,8 @@ cmake=/opt/compiler-explorer/cmake/bin/cmake
useninja=false
ld=/usr/bin/ld
readelf=/usr/bin/readelf
mkfifo=/usr/bin/mkfifo
heaptrackPath=/opt/compiler-explorer/heaptrack-v1.3.0
formatters=clangformat:rustfmt:gofmt:dartformat:vfmt
formatter.clangformat.name=clang-format

View File

@@ -50,6 +50,8 @@ cmake=cmake
useninja=false
ld=ld
readelf=readelf
mkfifo=/usr/bin/mkfifo
heaptrackPath=
# set this true to keep temporary folders for a while for debugging purposes
delayCleanupTemp=false

View File

@@ -171,7 +171,7 @@ compiler.armv8-cpp4oclclang-trunk-assertions.isNightly=true
# Arm v8-a
compiler.armv8-cpp4oclclang-trunk-assertions.options=-target aarch64-linux-gnu --gcc-toolchain=/opt/compiler-explorer/arm64/gcc-12.2.0/aarch64-unknown-linux-gnu --sysroot=/opt/compiler-explorer/arm64/gcc-12.2.0/aarch64-unknown-linux-gnu/aarch64-unknown-linux-gnu/sysroot
compiler.armv8-full-cpp4oclclang-trunk.name=armv8-a clang (trunk, all architectural features)
compiler.armv8-full-cpp4oclclang-trunk.name=armv8-a clang (all architectural features, trunk)
compiler.armv8-full-cpp4oclclang-trunk.exe=/opt/compiler-explorer/clang-trunk/bin/clang
compiler.armv8-full-cpp4oclclang-trunk.demangler=/opt/compiler-explorer/gcc-snapshot/bin/c++filt
compiler.armv8-full-cpp4oclclang-trunk.objdumper=/opt/compiler-explorer/gcc-snapshot/bin/objdump

View File

@@ -3,6 +3,7 @@ compilers=&dxc:&rga:&clang
defaultCompiler=dxc_default
supportsBinary=false
compilerType=hlsl
instructionSet=llvm
group.dxc.compilers=dxc_default
compiler.dxc_default.exe=/usr/dxc-artifacts/bin/dxc

View File

@@ -1,9 +1,9 @@
compilers=&kotlin
compilerType=kotlin
versionFlag=-version
objdumper=/opt/compiler-explorer/jdk-19.0.2/bin/javap
objdumper=/opt/compiler-explorer/jdk-21.0.0/bin/javap
instructionSet=java
defaultCompiler=kotlinc1900
defaultCompiler=kotlinc1920
demangler=
postProcess=
options=
@@ -12,7 +12,7 @@ needsMulti=false
supportsExecute=true
interpreted=true
group.kotlin.compilers=kotlinc1400:kotlinc1410:kotlinc1420:kotlinc1421:kotlinc1430:kotlinc1431:kotlinc1432:kotlinc1500:kotlinc1510:kotlinc1520:kotlinc1521:kotlinc1530:kotlinc1531:kotlinc1600:kotlinc1610:kotlinc1620:kotlinc1700:kotlinc1800:kotlinc1810:kotlinc1820:kotlinc1900
group.kotlin.compilers=kotlinc1400:kotlinc1410:kotlinc1420:kotlinc1421:kotlinc1430:kotlinc1431:kotlinc1432:kotlinc1500:kotlinc1510:kotlinc1520:kotlinc1521:kotlinc1530:kotlinc1531:kotlinc1600:kotlinc1610:kotlinc1620:kotlinc1700:kotlinc1800:kotlinc1810:kotlinc1820:kotlinc1900:kotlinc1910:kotlinc1920
group.kotlin.groupName=Kotlin
group.kotlin.baseName=kotlinc
group.kotlin.isSemVer=true
@@ -103,3 +103,11 @@ compiler.kotlinc1900.exe=/opt/compiler-explorer/kotlin-jvm-1.9.0/bin/kotlinc-jvm
compiler.kotlinc1900.semver=1.9.0
compiler.kotlinc1900.java_home=/opt/compiler-explorer/jdk-20.0.0
compiler.kotlinc1900.runtime=/opt/compiler-explorer/jdk-20.0.0/bin/java
compiler.kotlinc1910.exe=/opt/compiler-explorer/kotlin-jvm-1.9.10/bin/kotlinc-jvm
compiler.kotlinc1910.semver=1.9.10
compiler.kotlinc1910.java_home=/opt/compiler-explorer/jdk-20.0.0
compiler.kotlinc1910.runtime=/opt/compiler-explorer/jdk-20.0.0/bin/java
compiler.kotlinc1920.exe=/opt/compiler-explorer/kotlin-jvm-1.9.20/bin/kotlinc-jvm
compiler.kotlinc1920.semver=1.9.20
compiler.kotlinc1920.java_home=/opt/compiler-explorer/jdk-21.0.0
compiler.kotlinc1920.runtime=/opt/compiler-explorer/jdk-21.0.0/bin/java

View File

@@ -1,20 +1,24 @@
compilers=&nim
defaultCompiler=nim160
demangler=/opt/compiler-explorer/gcc-9.2.0/bin/c++filt
objdumper=/opt/compiler-explorer/gcc-9.2.0/bin/objdump
defaultCompiler=nim200
demangler=/opt/compiler-explorer/gcc-13.1.0/bin/c++filt
objdumper=/opt/compiler-explorer/gcc-13.1.0/bin/objdump
supportsBinary=true
supportsExecute=false
compilerType=nim
binaryHideFuncRe=^(__.*|_(init|start|fini)|(de)?register_tm_clones|call_gmon_start|frame_dummy|.plt.*|.*@plt|_dl_relocate_static_pie)$
group.nim.compilers=nim160:nim148:nim146:nim144:nim142:nim120:nim106:nim104:nimtrunk
group.nim.compilers=nim200:nim1616:nim160:nim148:nim146:nim144:nim142:nim120:nim106:nim104:nimtrunk
group.nim.isSemVer=true
group.nim.baseName=nim
group.nim.licenseLink=https://github.com/nim-lang/Nim/blob/devel/copying.txt
group.nim.licenseName=MIT License
group.nim.licensePreamble=Copyright (C) 2006-2022 Andreas Rumpf. All rights reserved.
group.nim.licensePreamble=Copyright (C) 2006-2023 Andreas Rumpf. All rights reserved.
compiler.nim200.semver=2.0.0
compiler.nim200.exe=/opt/compiler-explorer/nim-2.0.0/bin/nim
compiler.nim1616.semver=1.6.16
compiler.nim1616.exe=/opt/compiler-explorer/nim-1.6.16/bin/nim
compiler.nim160.semver=1.6.0
compiler.nim160.exe=/opt/compiler-explorer/nim-1.6.0/bin/nim
compiler.nim148.semver=1.4.8

View File

@@ -1587,8 +1587,10 @@ libs.tomlplusplus.versions.124.version=1.2.4
libs.tomlplusplus.versions.124.path=/opt/compiler-explorer/libs/tomlplusplus/v1.2.4/include
libs.trompeloeil.name=trompeloeil
libs.trompeloeil.versions=45:44:43:42:41:40:39:38:37:36:35:34:33:32:31:30:29:28
libs.trompeloeil.versions=46:45:44:43:42:41:40:39:38:37:36:35:34:33:32:31:30:29:28
libs.trompeloeil.url=https://github.com/rollbear/trompeloeil
libs.trompeloeil.versions.46.path=/opt/compiler-explorer/libs/trompeloeil/v46/include
libs.trompeloeil.versions.46.version=v46
libs.trompeloeil.versions.45.path=/opt/compiler-explorer/libs/trompeloeil/v45/include
libs.trompeloeil.versions.45.version=v45
libs.trompeloeil.versions.44.path=/opt/compiler-explorer/libs/trompeloeil/v44/include

View File

@@ -192,7 +192,7 @@ compiler.armv8-oclcclang-trunk-assertions.semver=(assertions trunk)
# Arm v8-a
compiler.armv8-oclcclang-trunk-assertions.options=-target aarch64-linux-gnu --gcc-toolchain=/opt/compiler-explorer/arm64/gcc-12.2.0/aarch64-unknown-linux-gnu --sysroot=/opt/compiler-explorer/arm64/gcc-12.2.0/aarch64-unknown-linux-gnu/aarch64-unknown-linux-gnu/sysroot
compiler.armv8-full-oclcclang-trunk.name=armv8-a clang (trunk, all architectural features)
compiler.armv8-full-oclcclang-trunk.name=armv8-a clang (all architectural features, trunk)
compiler.armv8-full-oclcclang-trunk.exe=/opt/compiler-explorer/clang-trunk/bin/clang
compiler.armv8-full-oclcclang-trunk.demangler=/opt/compiler-explorer/gcc-snapshot/bin/c++filt
compiler.armv8-full-oclcclang-trunk.objdumper=/opt/compiler-explorer/gcc-snapshot/bin/objdump

View File

@@ -1,7 +1,7 @@
compilers=&solc
defaultCompiler=solc0813
defaultCompiler=solc0821
group.solc.compilers=solc036:solc0426:solc0517:solc0612:solc076:solc0813
group.solc.compilers=solc036:solc0426:solc0517:solc0612:solc076:solc0821
group.solc.compilerType=solidity
group.solc.supportsBinary=false
group.solc.instructionSet=evm
@@ -20,9 +20,9 @@ compiler.solc0612.name=solc 0.6.12
compiler.solc076.exe=/opt/compiler-explorer/solc-0.7.6/solc
compiler.solc076.semver=0.7.6
compiler.solc076.name=solc 0.7.6
compiler.solc0813.exe=/opt/compiler-explorer/solc-0.8.13/solc
compiler.solc0813.semver=0.8.13
compiler.solc0813.name=solc 0.8.13
compiler.solc0821.exe=/opt/compiler-explorer/solc-0.8.21/solc
compiler.solc0821.semver=0.8.21
compiler.solc0821.name=solc 0.8.21
#################################
#################################

View File

@@ -12,15 +12,6 @@ levels:
priority: 100
topIconShowEvery: 3
statsId: solid_sands
- name: Intel
description: We engineer solutions for our customers greatest challenges with reliable, cloud to edge computing, inspired by Moores Law.
icon: https://static.ce-cdn.net/intel/logo-classicblue-3000px-single-colour.png
img: https://static.ce-cdn.net/intel/logo-classicblue-3000px.png
url: https://intel.com/
priority: 400
topIconShowEvery: 1
sideBySide: true
statsId: intel
- name: Sonar
description: Analyze your C and C++ projects with just one click. Free for open-source projects
img: https://static.ce-cdn.net/sonar/sonarcloud-2.png
@@ -445,3 +436,10 @@ levels:
- dvirtz
- ezki
- Patrick Eads
- Ivan Pribec
- Ben Sunshine-Hill
- Sam Mish
- Aleš Křivák
- Elias Nodland
- Andy Bell
- lv426

View File

@@ -0,0 +1,26 @@
compilers=&llvmtblgen
defaultCompiler=llvmtblgen1701
compilerType=tablegen
supportsBinary=false
supportsExecute=false
group.llvmtblgen.compilers=llvmtblgen_trunk:llvmtblgen1701
group.llvmtblgen.groupName=LLVM TableGen
group.llvmtblgen.baseName=LLVM TableGen
group.llvmtblgen.isSemVer=true
group.llvmtblgen.compilerType=tablegen
group.llvmtblgen.licenseName=LLVM Apache 2
group.llvmtblgen.licenseLink=https://github.com/llvm/llvm-project/blob/main/LICENSE.TXT
group.llvmtblgen.licensePreamble=The LLVM Project is under the Apache License v2.0 with LLVM Exceptions
group.llvmtblgen.supportsBinaryObject=false
group.llvmtblgen.supportsBinary=false
group.llvmtblgen.compilerCategories=tablegen
compiler.llvmtblgen_trunk.exe=/opt/compiler-explorer/clang-trunk/bin/llvm-tblgen
compiler.llvmtblgen_trunk.semver=(trunk)
compiler.llvmtblgen_trunk.isNightly=true
compiler.llvmtblgen_trunk.includePath=/opt/compiler-explorer/clang-trunk/include/
compiler.llvmtblgen1701.exe=/opt/compiler-explorer/clang-17.0.1/bin/llvm-tblgen
compiler.llvmtblgen1701.semver=17.0.1
compiler.llvmtblgen1701.includePath=/opt/compiler-explorer/clang-17.0.1/include/

View File

@@ -0,0 +1,8 @@
compilerType=tablegen
compilers=llvmtblgen
defaultCompiler=llvmtblgen
supportsBinary=false
supportsExecute=false
compiler.llvmtblgen.exe=/usr/bin/llvm-tblgen
compiler.llvmtblgen.name=llvm-tblgen

View File

@@ -8,6 +8,7 @@ all: \
$(GEN_DIR)/asm-docs-evm.ts \
$(GEN_DIR)/asm-docs-java.ts \
$(GEN_DIR)/asm-docs-llvm.ts \
$(GEN_DIR)/asm-docs-riscv64.ts
$(GEN_DIR)/asm-docs-ptx.ts \
$(GEN_DIR)/asm-docs-sass.ts \
$(GEN_DIR)/asm-docs-python.ts
@@ -34,3 +35,5 @@ $(GEN_DIR)/asm-docs-sass.ts: docenizer-ptx-sass.py
python3 $< -o $@
$(GEN_DIR)/asm-docs-python.ts: docenizer-python.py
python3 $< -o $@
$(GEN_DIR)/asm-docs-riscv64.ts: docenizer-riscv64.py
python3 $< -o $@

View File

@@ -0,0 +1,138 @@
#!/usr/bin/env python3
import argparse
import json
from urllib import request
from urllib import parse
import requests
import yaml
import sys
import re
#opcodes_yaml = "https://five-embeddev.github.io/riscv-docs-html/opcodes.yaml"
opcodes_yaml = "https://five-embeddev.github.io/riscv-docs-html/opcodes.yaml"
htmlhost = "https://five-embeddev.github.io/riscv-docs-html/"
parser = argparse.ArgumentParser(description='Scrape the five-embeddev quick reference page and generate the riscv documentation')
parser.add_argument('-i', '--opcode-data', type=str, help='Input opcode data in YAML format.',
default=opcodes_yaml)
parser.add_argument('-o', '--outputpath', type=str, help='Final path of the .ts file. Default is ./asm-docs-riscv64.ts',
default='./asm-docs-riscv64.ts')
def bold_keyword(text, keyword):
for keywordr in (keyword.upper(), keyword.lower()):
rer = re.compile(f"\\b{keywordr}\\b")
text,_ = re.subn(rer,f"<b>{keywordr}</b>",text)
return text
class operation:
def __init__(self, yaml_record, yaml_data):
opcode = yaml_record['opcode'][0].upper()
# Remove "@" and "c." from opcode
# These are
self.opcode = opcode
self.opcode_alias = None
if 'opcode_alias' in yaml_record:
self.opcode_alias = yaml_record['opcode_alias'].upper()
tool_opcode_args = opcode + " " + ', '.join(yaml_record['opcode_args']) + "\n"
html_opcode_args = f"<span class=\"opcode\"><b>{opcode}</b> {', '.join(yaml_record['opcode_args'])}</span>"
# What ISA does this opcode belong to?
# Is is a psuedo opcode?
group=""
if 'main_desc' in yaml_record:
group += yaml_record['main_desc']
if 'psuedo' == yaml_record['opcode_group']:
group += "(pseudo)"
html_code = ""
text_code = ""
html_group = f"<br><div><b>ISA</b>: {group}</div>"
if 'psuedo_to_base' in yaml_record:
html_code += "<br><div><b>Equivalent ASM:</b><pre>"
html_code += "\n".join(yaml_record['psuedo_to_base'])
html_code += "</pre></div>"
text_code += "Equivalent ASM:\n\n" + "\n".join(yaml_record['psuedo_to_base'])
if 'main_url_base' in yaml_record:
main_url_base = yaml_record['main_url_base']
main_desc = yaml_record['main_desc']
main_id = yaml_record['main_id']
opcode_descs = yaml_record['desc'][main_desc][main_id]['text']
tool_desc = "\n".join(opcode_descs) + "\n\n" + text_code + "\n\n(ISA: " + group + ")"
html_desc = "<br><div>" + "<br>".join([bold_keyword(x,opcode) for x in opcode_descs]) + "</div>"
self.url = htmlhost + main_url_base + main_id
self.tooltip = tool_desc
# extract all elements under the second column and the third column which are td
# and put them into a new div tag
self.html = "<div>" + html_opcode_args + html_desc + html_code + html_group + "</div>"
elif 'psuedo_to_base' in yaml_record:
self.url = htmlhost
self.tooltip = "Psuedo Instruction.\n\n" + text_code + "\n\n"
self.html = "<div>" + html_opcode_args + html_code + html_group + "</div>"
else:
self.url = htmlhost
self.tooltip = "\n\n(ISA: " + group + ")"
self.html = "<div>" + html_opcode_args + html_group + "</div>"
def __str__(self):
dic = {
# no opcode here
"tooltip": self.tooltip,
"url": self.url,
"html": self.html
}
return json.dumps(dic, indent=16, separators=(',', ': '), sort_keys=True)
if __name__ == '__main__':
args = parser.parse_args()
yaml_text=None
try:
if args.opcode_data[:4] == "http":
r = requests.get(args.opcode_data)
r.encoding = 'utf-8'
yaml_text = r.text
else:
with open(args.opcode_data, 'r') as fin :
yaml_text=fin.read()
except:
print("ERROR: Loading YAML file or URL: " + args.opcode_data + ":")
print(exc)
sys.exit(-1)
yaml_data=None
try:
yaml_data = yaml.safe_load(yaml_text)
except yaml.YAMLError as exc:
print("ERROR: Parsing YAML file: " + args.opcode_data + ":")
print(exc)
sys.exit(-1)
with open(args.outputpath, "w") as output:
output.write("""
import {AssemblyInstructionInfo} from '../base.js';
export function getAsmOpcode(opcode: string | undefined): AssemblyInstructionInfo | undefined {
if (!opcode) return;
switch (opcode.toUpperCase()) {
""".lstrip())
for record in [operation(o, yaml_data) for o in yaml_data['opcodes'].values()]:
# for each opcode
output.write(f' case "{record.opcode}":\n')
if record.opcode_alias:
output.write(f' case "{record.opcode_alias}":\n')
output.write(f' return {str(record)[:-1]} }};\n\n')
output.write("""
}
}
""")

View File

@@ -0,0 +1,8 @@
class Register<int _size, string _alias=""> {
int size = _size;
string alias = _alias;
}
def X0: Register<8> {}
def X29: Register<8, "frame pointer"> {}

View File

@@ -0,0 +1,20 @@
// This example uses the Searchable Tables backend, aka --gen-searchable-tables.
// To choose the backend, select it as the "Action" in the "Overrides" menu,
// or add "--gen-searchable-tables" to the compiler options.
// For more details:
// https://llvm.org/docs/TableGen/BackEnds.html#searchabletables-reference
include "llvm/TableGen/SearchableTable.td"
class Pair<string name, int value> : SearchableTable {
let SearchableFields = ["Name", "Value"];
let EnumValueField = "Value";
string Name = name;
bits<2> Value = value;
}
def : Pair<"Example 0", 0b00>;
def : Pair<"Example 1", 0b01>;
def : Pair<"Example 2", 0b10>;
def : Pair<"Example 3", 0b11>;

View File

@@ -31,4 +31,5 @@ export {LLVMDocumentationProvider} from './llvm.js';
export {Mos6502DocumentationProvider} from './mos6502.js';
export {PTXDocumentationProvider} from './ptx.js';
export {PythonDocumentationProvider} from './python.js';
export {Riscv64DocumentationProvider} from './riscv64.js';
export {SASSDocumentationProvider} from './sass.js';

6472
lib/asm-docs/generated/asm-docs-riscv64.ts generated Normal file

File diff suppressed because it is too large Load Diff

35
lib/asm-docs/riscv64.ts Normal file
View File

@@ -0,0 +1,35 @@
// Copyright (c) 2022, 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 {AssemblyInstructionInfo, BaseAssemblyDocumentationProvider} from './base.js';
import {getAsmOpcode} from './generated/asm-docs-riscv64.js';
export class Riscv64DocumentationProvider extends BaseAssemblyDocumentationProvider {
public static get key() {
return 'riscv64';
}
public override getInstructionInformation(instruction: string): AssemblyInstructionInfo | null {
return getAsmOpcode(instruction) || null;
}
}

View File

@@ -48,16 +48,19 @@ import type {
LLVMOptPipelineOutput,
} from '../types/compilation/llvm-opt-pipeline-output.interfaces.js';
import type {CompilerInfo, ICompiler, PreliminaryCompilerInfo} from '../types/compiler.interfaces.js';
import type {
import {
BasicExecutionResult,
ConfiguredRuntimeTool,
ConfiguredRuntimeTools,
ExecutableExecutionOptions,
RuntimeToolType,
UnprocessedExecResult,
} from '../types/execution/execution.interfaces.js';
import type {CompilerOutputOptions, ParseFiltersAndOutputOptions} from '../types/features/filters.interfaces.js';
import type {Language} from '../types/languages.interfaces.js';
import type {Library, LibraryVersion, SelectedLibraryVersion} from '../types/libraries/libraries.interfaces.js';
import type {ResultLine} from '../types/resultline/resultline.interfaces.js';
import type {Artifact, ToolResult, ToolTypeKey} from '../types/tool.interfaces.js';
import {ArtifactType, type Artifact, type ToolResult, type ToolTypeKey} from '../types/tool.interfaces.js';
import {BuildEnvSetupBase, getBuildEnvTypeByKey} from './buildenvsetup/index.js';
import type {BuildEnvDownloadInfo} from './buildenvsetup/buildenv.interfaces.js';
@@ -108,6 +111,10 @@ import {LLVMIrBackendOptions} from '../types/compilation/ir.interfaces.js';
import {ParsedAsmResultLine} from '../types/asmresult/asmresult.interfaces.js';
import {unique} from '../shared/common-utils.js';
import {ClientOptionsType, OptionsHandlerLibrary, VersionInfo} from './options-handler.js';
import {HeaptrackWrapper} from './runtime-tools/heaptrack-wrapper.js';
import {propsFor} from './properties.js';
import stream from 'node:stream';
import {SentryCapture} from './sentry.js';
const compilationTimeHistogram = new PromClient.Histogram({
name: 'ce_base_compiler_compilation_duration_seconds',
@@ -172,6 +179,8 @@ export class BaseCompiler implements ICompiler {
protected externalparser: null | ExternalParserBase;
protected supportedLibraries?: Record<string, Library>;
protected packager: Packager;
protected executionType: string;
protected sandboxType: string;
protected defaultRpathFlag: string = '-Wl,-rpath,';
private static objdumpAndParseCounter = new PromClient.Counter({
name: 'ce_objdumpandparsetime_total',
@@ -211,6 +220,10 @@ export class BaseCompiler implements ICompiler {
this.compiler.disabledFilters = (this.compiler.disabledFilters as any).split(',');
}
const execProps = propsFor('execution');
this.executionType = execProps('executionType', 'none');
this.sandboxType = execProps('sandboxType', 'none');
this.asm = new AsmParser(this.compilerProps);
const irDemangler = new LLVMIRDemangler(this.compiler.demangler, this);
this.llvmIr = new LlvmIrParser(this.compilerProps, irDemangler);
@@ -563,6 +576,22 @@ export class BaseCompiler implements ICompiler {
};
}
processUserExecutableExecutionResult(
input: UnprocessedExecResult,
stdErrlineParseOptions: utils.LineParseOptions,
): BasicExecutionResult {
const start = performance.now();
const stdout = utils.parseOutput(input.stdout, undefined, undefined, []);
const stderr = utils.parseOutput(input.stderr, undefined, undefined, stdErrlineParseOptions);
const end = performance.now();
return {
...input,
stdout,
stderr,
processExecutionResultTime: end - start,
};
}
getEmptyExecutionResult(): BasicExecutionResult {
return {
code: -1,
@@ -585,16 +614,69 @@ export class BaseCompiler implements ICompiler {
};
}
async execBinary(
executable,
maxSize,
protected setEnvironmentVariablesFromRuntime(
configuredTools: ConfiguredRuntimeTools,
execOptions: ExecutionOptions,
) {
for (const runtime of configuredTools) {
if (runtime.name === RuntimeToolType.env) {
for (const env of runtime.options) {
if (!execOptions.env) execOptions.env = {};
execOptions.env[env.name] = env.value;
}
}
}
}
protected async execBinaryMaybeWrapped(
executable: string,
args: string[],
execOptions: ExecutionOptions,
executeParameters: ExecutableExecutionOptions,
homeDir,
homeDir: string,
): Promise<BasicExecutionResult> {
let runWithHeaptrack: ConfiguredRuntimeTool | undefined = undefined;
if (!execOptions.env) execOptions.env = {};
if (executeParameters.runtimeTools) {
this.setEnvironmentVariablesFromRuntime(executeParameters.runtimeTools, execOptions);
for (const runtime of executeParameters.runtimeTools) {
if (runtime.name === RuntimeToolType.heaptrack) {
runWithHeaptrack = runtime;
}
}
}
if (runWithHeaptrack && HeaptrackWrapper.isSupported(this.env)) {
const wrapper = new HeaptrackWrapper(
homeDir,
exec.sandbox,
this.exec,
runWithHeaptrack.options,
this.env.ceProps,
this.sandboxType,
);
const execResult: UnprocessedExecResult = await wrapper.exec(executable, args, execOptions);
return this.processUserExecutableExecutionResult(execResult, [utils.LineParseOption.AtFileLine]);
} else {
const execResult: UnprocessedExecResult = await exec.sandbox(executable, args, execOptions);
return this.processUserExecutableExecutionResult(execResult, []);
}
}
async execBinary(
executable: string,
maxSize: number,
executeParameters: ExecutableExecutionOptions,
homeDir: string,
): Promise<BasicExecutionResult> {
// We might want to save this in the compilation environment once execution is made available
const timeoutMs = this.env.ceProps('binaryExecTimeoutMs', 2000);
try {
const execResult: UnprocessedExecResult = await exec.sandbox(executable, executeParameters.args, {
const execOptions: ExecutionOptions = {
maxOutput: maxSize,
timeoutMs: timeoutMs,
ldPath: _.union(this.compiler.ldPath, executeParameters.ldPath),
@@ -602,9 +684,15 @@ export class BaseCompiler implements ICompiler {
env: executeParameters.env,
customCwd: homeDir,
appHome: homeDir,
});
};
return this.processExecutionResult(execResult);
return this.execBinaryMaybeWrapped(
executable,
executeParameters.args,
execOptions,
executeParameters,
homeDir,
);
} catch (err: UnprocessedExecResult | any) {
if (err.code && err.stderr) {
return this.processExecutionResult(err);
@@ -624,7 +712,7 @@ export class BaseCompiler implements ICompiler {
}
getGccDumpFileName(outputFilename: string) {
return outputFilename.replace(path.extname(outputFilename), '.dump');
return utils.changeExtension(outputFilename, '.dump');
}
getGccDumpOptions(gccDumpOptions, outputFilename: string) {
@@ -840,7 +928,7 @@ export class BaseCompiler implements ICompiler {
return sortedlinks;
}
getStaticLibraryLinks(libraries: CompileChildLibraries[]) {
getStaticLibraryLinks(libraries: CompileChildLibraries[]): string[] {
const linkFlag = this.compiler.linkFlag || '-l';
return this.getSortedStaticLibraries(libraries)
@@ -868,11 +956,11 @@ export class BaseCompiler implements ICompiler {
.filter(link => link) as string[];
}
getSharedLibraryPaths(libraries: CompileChildLibraries[]) {
getSharedLibraryPaths(libraries: CompileChildLibraries[]): string[] {
return libraries
.map(selectedLib => {
const foundVersion = this.findLibVersion(selectedLib);
if (!foundVersion) return false;
if (!foundVersion) return [];
const paths = [...foundVersion.libpath];
if (this.buildenvsetup && !this.buildenvsetup.extractAllToRoot) {
@@ -887,7 +975,7 @@ export class BaseCompiler implements ICompiler {
libraries: CompileChildLibraries[],
libDownloadPath?: string,
toolchainPath?: string,
) {
): string[] {
const pathFlag = this.compiler.rpathFlag || this.defaultRpathFlag;
const libPathFlag = this.compiler.libpathFlag || '-L';
@@ -907,10 +995,10 @@ export class BaseCompiler implements ICompiler {
toolchainLibraryPaths.map(path => pathFlag + path),
this.getSharedLibraryPaths(libraries).map(path => pathFlag + path),
this.getSharedLibraryPaths(libraries).map(path => libPathFlag + path),
) as string[];
);
}
protected getSharedLibraryPathsAsLdLibraryPaths(libraries) {
protected getSharedLibraryPathsAsLdLibraryPaths(libraries): string[] {
let paths = '';
if (!this.alwaysResetLdPath) {
paths = process.env.LD_LIBRARY_PATH || '';
@@ -919,10 +1007,10 @@ export class BaseCompiler implements ICompiler {
paths.split(path.delimiter).filter(p => !!p),
this.compiler.ldPath,
this.getSharedLibraryPaths(libraries),
) as string[];
);
}
getSharedLibraryPathsAsLdLibraryPathsForExecution(libraries) {
getSharedLibraryPathsAsLdLibraryPathsForExecution(libraries): string[] {
let paths = '';
if (!this.alwaysResetLdPath) {
paths = process.env.LD_LIBRARY_PATH || '';
@@ -1393,27 +1481,27 @@ export class BaseCompiler implements ICompiler {
}
getRustMacroExpansionOutputFilename(inputFilename) {
return inputFilename.replace(path.extname(inputFilename), '.expanded.rs');
return utils.changeExtension(inputFilename, '.expanded.rs');
}
getRustHirOutputFilename(inputFilename) {
return inputFilename.replace(path.extname(inputFilename), '.hir');
return utils.changeExtension(inputFilename, '.hir');
}
getRustMirOutputFilename(outputFilename) {
return outputFilename.replace(path.extname(outputFilename), '.mir');
return utils.changeExtension(outputFilename, '.mir');
}
getHaskellCoreOutputFilename(inputFilename) {
return inputFilename.replace(path.extname(inputFilename), '.dump-simpl');
return utils.changeExtension(inputFilename, '.dump-simpl');
}
getHaskellStgOutputFilename(inputFilename) {
return inputFilename.replace(path.extname(inputFilename), '.dump-stg-final');
return utils.changeExtension(inputFilename, '.dump-stg-final');
}
getHaskellCmmOutputFilename(inputFilename) {
return inputFilename.replace(path.extname(inputFilename), '.dump-cmm');
return utils.changeExtension(inputFilename, '.dump-cmm');
}
// Currently called for getting macro expansion and HIR.
@@ -1486,7 +1574,7 @@ export class BaseCompiler implements ICompiler {
getIrOutputFilename(inputFilename: string, filters: ParseFiltersAndOutputOptions): string {
// filters are passed because rust needs to know whether a binary is being produced or not
return inputFilename.replace(path.extname(inputFilename), '.ll');
return utils.changeExtension(inputFilename, '.ll');
}
getOutputFilename(dirPath: string, outputFilebase: string, key?: any): string {
@@ -1848,26 +1936,32 @@ export class BaseCompiler implements ICompiler {
runExecutable(executable: string, executeParameters: ExecutableExecutionOptions, homeDir) {
const maxExecOutputSize = this.env.ceProps('max-executable-output-size', 32 * 1024);
const execOptionsCopy: ExecutableExecutionOptions = JSON.parse(
JSON.stringify(executeParameters),
) as ExecutableExecutionOptions;
// Hardcoded fix for #2339. Ideally I'd have a config option for this, but for now this is plenty good enough.
executeParameters.env = {
execOptionsCopy.env = {
ASAN_OPTIONS: 'color=always',
UBSAN_OPTIONS: 'color=always',
MSAN_OPTIONS: 'color=always',
LSAN_OPTIONS: 'color=always',
...executeParameters.env,
};
if (this.compiler.executionWrapper) {
executeParameters.args = [...this.compiler.executionWrapperArgs, executable, ...executeParameters.args];
execOptionsCopy.args = [...this.compiler.executionWrapperArgs, executable, ...execOptionsCopy.args];
executable = this.compiler.executionWrapper;
}
return this.execBinary(executable, maxExecOutputSize, executeParameters, homeDir);
return this.execBinary(executable, maxExecOutputSize, execOptionsCopy, homeDir);
}
protected fixExecuteParametersForInterpreting(executeParameters, outputFilename, key) {
executeParameters.args.unshift(outputFilename);
}
async handleInterpreting(key, executeParameters): Promise<CompilationResult> {
async handleInterpreting(key, executeParameters: ExecutableExecutionOptions): Promise<CompilationResult> {
const source = key.source;
const dirPath = await this.newTempDir();
const outputFilename = this.getExecutableFilename(dirPath, this.outputFilebase);
@@ -1898,7 +1992,11 @@ export class BaseCompiler implements ICompiler {
};
}
async doExecution(key, executeParameters, bypassCache: BypassCache): Promise<CompilationResult> {
async doExecution(
key,
executeParameters: ExecutableExecutionOptions,
bypassCache: BypassCache,
): Promise<CompilationResult> {
if (this.compiler.interpreted) {
return this.handleInterpreting(key, executeParameters);
}
@@ -1949,7 +2047,27 @@ export class BaseCompiler implements ICompiler {
};
}
async handleExecution(key, executeParameters, bypassCache: BypassCache): Promise<CompilationResult> {
async addHeaptrackResults(result: CompilationResult, dirPath?: string) {
let dirPathToUse: string = '';
if (dirPath) {
dirPathToUse = dirPath;
} else if (result.buildResult && result.buildResult.dirPath) {
dirPathToUse = result.buildResult.dirPath;
}
if (dirPathToUse === '') return;
const flamegraphFilepath = path.join(dirPathToUse, HeaptrackWrapper.FlamegraphFilename);
if (await utils.fileExists(flamegraphFilepath)) {
await this.addArtifactToResult(result, flamegraphFilepath, ArtifactType.heaptracktxt, 'Heaptrack results');
}
}
async handleExecution(
key,
executeParameters: ExecutableExecutionOptions,
bypassCache: BypassCache,
): Promise<CompilationResult> {
// stringify now so shallow copying isn't a problem, I think the executeParameters get modified
const execKey = JSON.stringify({key, executeParameters});
if (!bypassExecutionCache(bypassCache)) {
@@ -1960,6 +2078,15 @@ export class BaseCompiler implements ICompiler {
}
const result = await this.doExecution(key, executeParameters, bypassCache);
if (executeParameters.runtimeTools) {
for (const runtime of executeParameters.runtimeTools) {
if (runtime.name === RuntimeToolType.heaptrack) {
await this.addHeaptrackResults(result);
}
}
}
if (!bypassExecutionCache(bypassCache)) {
await this.env.cachePut(execKey, result, undefined);
}
@@ -1977,7 +2104,7 @@ export class BaseCompiler implements ICompiler {
cacheKey.api = 'cmake';
if (cacheKey.filters) delete cacheKey.filters.execute;
delete cacheKey.executionParameters;
delete cacheKey.executeParameters;
delete cacheKey.tools;
return cacheKey;
@@ -2366,7 +2493,7 @@ export class BaseCompiler implements ICompiler {
}
async cmake(files, key, bypassCache: BypassCache) {
// key = {source, options, backendOptions, filters, bypassCache, tools, executionParameters, libraries};
// key = {source, options, backendOptions, filters, bypassCache, tools, executeParameters, libraries};
if (!this.compiler.supportsBinary) {
const errorResult: CompilationResult = {
@@ -2390,10 +2517,12 @@ export class BaseCompiler implements ICompiler {
const toolchainPath = this.getDefaultOrOverridenToolchainPath(key.backendOptions.overrides || []);
const doExecute = key.filters.execute;
const executeParameters: ExecutableExecutionOptions = {
const executeOptions: ExecutableExecutionOptions = {
args: key.executeParameters.args || [],
stdin: key.executeParameters.stdin || '',
ldPath: this.getSharedLibraryPathsAsLdLibraryPaths(key.libraries),
args: key.executionParameters.args || [],
stdin: key.executionParameters.stdin || '',
runtimeTools: key.executeParameters?.runtimeTools || [],
env: {},
};
@@ -2511,8 +2640,16 @@ export class BaseCompiler implements ICompiler {
fullResult.result.dirPath = dirPath;
if (this.compiler.supportsExecute && doExecute) {
fullResult.execResult = await this.runExecutable(outputFilename, executeParameters, dirPath);
fullResult.execResult = await this.runExecutable(outputFilename, executeOptions, dirPath);
fullResult.didExecute = true;
if (executeOptions.runtimeTools) {
for (const runtime of executeOptions.runtimeTools) {
if (runtime.name === RuntimeToolType.heaptrack) {
await this.addHeaptrackResults(fullResult, dirPath);
}
}
}
}
const optOutput = undefined;
@@ -2521,7 +2658,7 @@ export class BaseCompiler implements ICompiler {
fullResult.result,
false,
cacheKey,
[],
executeOptions,
key.tools,
cacheKey.backendOptions,
cacheKey.filters,
@@ -2584,7 +2721,7 @@ export class BaseCompiler implements ICompiler {
filters,
bypassCache: BypassCache,
tools,
executionParameters,
executeParameters,
libraries: CompileChildLibraries[],
files,
) {
@@ -2601,9 +2738,12 @@ export class BaseCompiler implements ICompiler {
this.fixFiltersBeforeCacheKey(filters, options, files);
const executeParameters = {
args: executionParameters.args || [],
stdin: executionParameters.stdin || '',
const executeOptions: ExecutableExecutionOptions = {
args: executeParameters.args || [],
stdin: executeParameters.stdin || '',
ldPath: [],
env: {},
runtimeTools: executeParameters.runtimeTools || [],
};
const key = this.getCacheKey(source, options, backendOptions, filters, tools, libraries, files);
@@ -2631,7 +2771,7 @@ export class BaseCompiler implements ICompiler {
async () => {
const start = performance.now();
executionQueueTimeHistogram.observe((start - queueTime) / 1000);
const res = await this.handleExecution(key, executeParameters, bypassCache);
const res = await this.handleExecution(key, executeOptions, bypassCache);
executionTimeHistogram.observe((performance.now() - start) / 1000);
return res;
},
@@ -2654,7 +2794,7 @@ export class BaseCompiler implements ICompiler {
source = this.preProcess(source, filters);
if (backendOptions.executorRequest) {
const execResult = await this.handleExecution(key, executeParameters, bypassCache);
const execResult = await this.handleExecution(key, executeOptions, bypassCache);
if (execResult && execResult.buildResult) {
this.doTempfolderCleanup(execResult.buildResult);
}
@@ -2686,7 +2826,7 @@ export class BaseCompiler implements ICompiler {
result,
doExecute,
key,
executeParameters,
executeOptions,
tools,
backendOptions,
filters,
@@ -2707,7 +2847,7 @@ export class BaseCompiler implements ICompiler {
result,
doExecute,
key,
executeParameters,
executeOptions: ExecutableExecutionOptions,
tools,
backendOptions,
filters,
@@ -2719,7 +2859,7 @@ export class BaseCompiler implements ICompiler {
) {
// Start the execution as soon as we can, but only await it at the end.
const execPromise =
doExecute && result.code === 0 ? this.handleExecution(key, executeParameters, bypassCache) : null;
doExecute && result.code === 0 ? this.handleExecution(key, executeOptions, bypassCache) : null;
if (result.hasOptOutput) {
delete result.optPath;
@@ -2812,9 +2952,16 @@ export class BaseCompiler implements ICompiler {
async processOptOutput(optPath: string) {
const output: compilerOptInfo.LLVMOptInfo[] = [];
const optStream = fs
.createReadStream(optPath, {encoding: 'utf8'})
.pipe(new compilerOptInfo.LLVMOptTransformer());
const optStream = stream.pipeline(
fs.createReadStream(optPath, {encoding: 'utf8'}),
new compilerOptInfo.LLVMOptTransformer(),
async err => {
if (err) {
logger.error(`Error handling opt output: ${err}`);
SentryCapture(err, `Error handling opt output: ${await fs.readFile(optPath, 'utf-8')}`);
}
},
);
for await (const opt of optStream as AsyncIterable<compilerOptInfo.LLVMOptInfo>) {
if (opt.DebugLoc && opt.DebugLoc.File && opt.DebugLoc.File.includes(this.compileFilename)) {
@@ -3151,6 +3298,33 @@ but nothing was dumped. Possible causes are:
return await parser.getPossibleStdvers(this);
}
async populatePossibleRuntimeTools() {
this.compiler.possibleRuntimeTools = [];
if (HeaptrackWrapper.isSupported(this.env)) {
this.compiler.possibleRuntimeTools.push({
name: RuntimeToolType.heaptrack,
description:
'Heaptrack gets loaded into your code and collects the heap allocations, ' +
"we'll display them in a flamegraph.",
possibleOptions: [
{
name: 'graph',
possibleValues: ['yes'],
},
{
name: 'summary',
possibleValues: ['stderr'],
},
{
name: 'details',
possibleValues: ['stderr'],
},
],
});
}
}
async populatePossibleOverrides() {
const targets = await this.getTargetsAsOverrideValues();
if (targets.length > 0) {
@@ -3269,6 +3443,7 @@ but nothing was dumped. Possible causes are:
const initResult = await this.getArgumentParser().parse(this);
await this.populatePossibleOverrides();
await this.populatePossibleRuntimeTools();
logger.info(`${compiler} ${version} is ready`);
return initResult;

View File

@@ -86,14 +86,14 @@ export class BaseCFGParser {
while (first !== last) {
if (this.isFunctionEnd(asmArr[first].text)) {
fnRange.end = first;
result.push(_.clone(fnRange));
if (fnRange.end > fnRange.start + 1) result.push(_.clone(fnRange));
fnRange.start = first;
}
++first;
}
fnRange.end = last;
result.push(_.clone(fnRange));
if (fnRange.end > fnRange.start + 1) result.push(_.clone(fnRange));
return result;
}
@@ -130,7 +130,7 @@ export class BaseCFGParser {
}
protected isFunctionName(line: AssemblyLine) {
return line.text.trim().indexOf('.') !== 0;
return line.text.trim().indexOf('.') !== 0 || line.text.startsWith('.omp_');
}
protected getAsmDirective(txt: string) {
@@ -167,7 +167,7 @@ export class BaseCFGParser {
}
protected isFunctionEnd(x: string) {
return x[0] !== ' ' && x[0] !== '.' && x.includes(':');
return x[0] !== ' ' && (x[0] !== '.' || x.startsWith('.omp_')) && x.includes(':');
}
protected isBasicBlockEnd(inst: string, prevInst: string) {

View File

@@ -136,27 +136,47 @@ export class LlvmIrCfgParser extends BaseCFGParser {
while (lastInst >= bb.start && asmArr[lastInst].text === '') {
lastInst--;
}
// Ad-hoc handling of a few known cases where LLVM splits a single instruction over multiple lines.
const terminatingInstruction = (() => {
if (asmArr[lastInst].text.trim().startsWith(']')) {
// Llvm likes to split switches over multiple lines
// Llvm likes to split switches over multiple lines:
// switch i32 %0, label %5 [
// i32 14, label %7
// i32 60, label %2
// i32 12, label %3
// i32 4, label %4
// ], !dbg !60
// This is somewhat hacky. I'm not sure if there are other cases where this can happen, but for
// now just handling this.
const end = lastInst--;
while (!asmArr[lastInst].text.includes('[')) {
lastInst--;
}
return this.concatInstructions(asmArr, lastInst, end + 1);
} else if (
lastInst >= 1 &&
asmArr[lastInst].text.includes('unwind label') &&
asmArr[lastInst - 1].text.trim().includes('invoke ')
) {
// Handle multi-line `invoke` like:
// invoke void @__cxa_throw(ptr nonnull %exception, ptr nonnull @typeinfo for int, ptr null) #3
// to label %unreachable unwind label %lpad
return this.concatInstructions(asmArr, lastInst - 1, lastInst + 1);
} else if (
lastInst >= 1 &&
asmArr[lastInst - 1].text.includes('landingpad') &&
asmArr[lastInst].text.includes('catch')
) {
// Handle multi-line `landingpad` like:
// %0 = landingpad { ptr, i32 }
// catch ptr null
return this.concatInstructions(asmArr, lastInst - 1, lastInst + 1);
} else {
return asmArr[lastInst].text;
}
})();
const terminator = terminatingInstruction.trim().split(' ')[0];
const terminator = terminatingInstruction.includes('invoke ')
? 'invoke'
: terminatingInstruction.trim().split(' ')[0];
const labels = [...terminatingInstruction.matchAll(this.labelReference)].map(m => m[1]);
switch (terminator) {
case 'ret':

View File

@@ -77,9 +77,9 @@ export class ArmInstructionSetInfo extends BaseInstructionSetInfo {
static returnInstruction = new RegExp(
'(?:' +
[`bx`, `ret`].map(re => `(?:${re})`).join('|') +
')\\b.+' +
`|pop\\s*\\{(?:r(?:\\d{2,}|[4-9]),\\s*)*pc\\}.+` +
`|mov\\s*pc\\s*,.+`,
')\\b.*' +
`|pop\\s*\\{(?:r(?:\\d{2,}|[4-9]),\\s*)*pc\\}.*` +
`|mov\\s*pc\\s*,.*`,
);
static override get key(): InstructionSet[] {
@@ -96,8 +96,8 @@ export class ArmInstructionSetInfo extends BaseInstructionSetInfo {
override getInstructionType(instruction: string) {
const opcode = instruction.trim().split(' ')[0].toLowerCase();
if (opcode.match(ArmInstructionSetInfo.unconditionalJumps)) return InstructionType.jmp;
else if (opcode.match(ArmInstructionSetInfo.conditionalJumps)) return InstructionType.conditionalJmpInst;
if (opcode.match(ArmInstructionSetInfo.conditionalJumps)) return InstructionType.conditionalJmpInst;
else if (opcode.match(ArmInstructionSetInfo.unconditionalJumps)) return InstructionType.jmp;
else if (instruction.trim().toLocaleLowerCase().match(ArmInstructionSetInfo.returnInstruction)) {
return InstructionType.retInst;
} else {

View File

@@ -37,9 +37,11 @@ export class BaseInstructionSetInfo {
}
isJmpInstruction(x: string) {
return x.trim()[0] === 'j'
|| !!x.match(/\bb\.*(eq|ne|cs|hs|cc|lo|hi|ls|ge|lt|gt|le|rge|rlt)?\b/)
|| !!x.match(/(?:tbnz|tbz|cbnz|cbz)/);
return (
x.trim()[0] === 'j' ||
!!x.match(/\bb\.*(eq|ne|cs|hs|cc|lo|hi|ls|ge|lt|gt|le|rge|rlt)?\b/) ||
!!x.match(/(?:tbnz|tbz|cbnz|cbz)/)
);
}
getInstructionType(inst: string) {

View File

@@ -38,8 +38,10 @@ export class ClientStateNormalizer {
setFilterSettingsFromComponent(compiler, component) {
compiler.filters.binary = component.componentState.filters.binary;
compiler.filters.binaryObject = component.componentState.filters.binaryObject;
compiler.filters.execute = component.componentState.filters.execute;
compiler.filters.labels = component.componentState.filters.labels;
compiler.filters.libraryCode = component.componentState.filters.libraryCode;
compiler.filters.directives = component.componentState.filters.directives;
compiler.filters.commentOnly = component.componentState.filters.commentOnly;
compiler.filters.trim = component.componentState.filters.trim;

View File

@@ -24,12 +24,14 @@
export class ClientStateCompilerOptions {
binary = false;
binaryObject = false;
commentOnly = true;
demangle = true;
directives = true;
execute = false;
intel = true;
labels = true;
libraryCode = false;
trim = false;
debugCalls = false;
@@ -39,12 +41,14 @@ export class ClientStateCompilerOptions {
fromJsonData(jsondata) {
if (jsondata.binary !== undefined) this.binary = jsondata.binary;
if (jsondata.binaryObject !== undefined) this.binaryObject = jsondata.binaryObject;
if (jsondata.commentOnly !== undefined) this.commentOnly = jsondata.commentOnly;
if (jsondata.demangle !== undefined) this.demangle = jsondata.demangle;
if (jsondata.directives !== undefined) this.directives = jsondata.directives;
if (jsondata.execute !== undefined) this.execute = jsondata.execute;
if (jsondata.intel !== undefined) this.intel = jsondata.intel;
if (jsondata.labels !== undefined) this.labels = jsondata.labels;
if (jsondata.libraryCode !== undefined) this.libraryCode = jsondata.libraryCode;
if (jsondata.trim !== undefined) this.trim = jsondata.trim;
if (jsondata.debugCalls !== undefined) this.debugCalls = jsondata.debugCalls;
}

View File

@@ -347,6 +347,7 @@ export class CompilerFinder {
preamble: props<string>('licensePreamble'),
},
possibleOverrides: [],
possibleRuntimeTools: [],
$order: undefined as unknown as number, // TODO(jeremy-rifkin): Very dirty
};

View File

@@ -106,6 +106,7 @@ export {SdccCompiler} from './sdcc.js';
export {SolidityCompiler} from './solidity.js';
export {SPIRVCompiler} from './spirv.js';
export {SwiftCompiler} from './swift.js';
export {TableGenCompiler} from './tablegen.js';
export {TenDRACompiler} from './tendra.js';
export {TIC2000} from './tic2000.js';
export {TinyCCompiler} from './tinyc.js';

View File

@@ -889,6 +889,41 @@ export class CrystalParser extends BaseParser {
}
}
export class TableGenParser extends BaseParser {
static async getPossibleActions(compiler): Promise<CompilerOverrideOptions> {
const result = await compiler.execCompilerCached(compiler.compiler.exe, ['--help']);
return this.extractPossibleActions(utils.splitLines(result.stdout));
}
static extractPossibleActions(lines: string[]): CompilerOverrideOptions {
const actions: CompilerOverrideOptions = [];
let found_actions = false;
for (const line of lines) {
// Action options are in a section with this header.
if (line.indexOf('Action to perform:') !== -1) {
found_actions = true;
} else if (found_actions) {
// Actions are indented 6 spaces. The description follows after
// a dash, for example:
// <6 spaces>--do-thing - Description of thing.
const action_match = line.match(/^ {6}(--[^\s]+)\s+-\s+(.+)$/);
// The end of the option section is an option indented only 2 spaces.
if (action_match == null) {
break;
}
actions.push({
name: action_match[1].substr(2) + ': ' + action_match[2],
value: action_match[1],
});
}
}
return actions;
}
}
export class TypeScriptNativeParser extends BaseParser {
static override async parse(compiler) {
await this.getOptions(compiler, '--help');

View File

@@ -25,6 +25,7 @@
import type {PreliminaryCompilerInfo} from '../../types/compiler.interfaces.js';
import type {ParseFiltersAndOutputOptions} from '../../types/features/filters.interfaces.js';
import {BaseCompiler} from '../base-compiler.js';
import {changeExtension} from '../utils.js';
export class CL430Compiler extends BaseCompiler {
static get key() {
@@ -52,7 +53,7 @@ export class CL430Compiler extends BaseCompiler {
'--keep_asm',
'--asm_extension=.s',
'--output_file',
this.filename(outputFilename.replace('.s', '')),
this.filename(changeExtension(outputFilename, '')),
];
}
}

View File

@@ -77,12 +77,7 @@ export class ClangCompiler extends BaseCompiler {
async addTimeTraceToResult(result: CompilationResult, dirPath: string, outputFilename: string) {
let timeTraceJson = '';
const outputExt = path.extname(outputFilename);
if (outputExt) {
timeTraceJson = outputFilename.replace(outputExt, '.json');
} else {
timeTraceJson += '.json';
}
timeTraceJson = utils.changeExtension(outputFilename, '.json');
const jsonFilepath = path.join(dirPath, timeTraceJson);
if (await utils.fileExists(jsonFilepath)) {
this.addArtifactToResult(

View File

@@ -27,10 +27,8 @@ import path from 'path';
import fs from 'fs-extra';
import type {ExecutionOptions} from '../../types/compilation/compilation.interfaces.js';
import type {PreliminaryCompilerInfo} from '../../types/compiler.interfaces.js';
import type {ParseFiltersAndOutputOptions} from '../../types/features/filters.interfaces.js';
import {BaseCompiler} from '../base-compiler.js';
import {propsFor} from '../properties.js';
import * as utils from '../utils.js';
export class CleanCompiler extends BaseCompiler {
@@ -38,14 +36,6 @@ export class CleanCompiler extends BaseCompiler {
return 'clean';
}
executionType: string;
constructor(compiler: PreliminaryCompilerInfo, env) {
super(compiler, env);
const execProps = propsFor('execution');
this.executionType = execProps('executionType', 'none');
}
override optionsForFilter(filters: ParseFiltersAndOutputOptions) {
if (filters.binary) {
return [];

View File

@@ -29,14 +29,12 @@ import _ from 'underscore';
import type {CompilationResult, ExecutionOptions} from '../../types/compilation/compilation.interfaces.js';
import type {PreliminaryCompilerInfo} from '../../types/compiler.interfaces.js';
import type {
BasicExecutionResult,
ExecutableExecutionOptions,
UnprocessedExecResult,
import {
type BasicExecutionResult,
type ExecutableExecutionOptions,
} from '../../types/execution/execution.interfaces.js';
import type {ParseFiltersAndOutputOptions} from '../../types/features/filters.interfaces.js';
import {BaseCompiler} from '../base-compiler.js';
import * as exec from '../exec.js';
import {DotNetAsmParser} from '../parsers/asm-parser-dotnet.js';
import * as utils from '../utils.js';
@@ -54,8 +52,6 @@ class DotNetCompiler extends BaseCompiler {
private readonly crossgen2Path: string;
private readonly sdkMajorVersion: number;
private versionString: string;
constructor(compilerInfo: PreliminaryCompilerInfo, env) {
super(compilerInfo, env);
@@ -71,9 +67,8 @@ class DotNetCompiler extends BaseCompiler {
this.langVersion = this.compilerProps<string>(`compiler.${this.compiler.id}.langVersion`);
this.corerunPath = path.join(this.clrBuildDir, 'corerun');
this.crossgen2Path = path.join(this.clrBuildDir, 'crossgen2', 'crossgen2');
this.crossgen2Path = path.join(this.clrBuildDir, 'crossgen2', 'crossgen2.dll');
this.asm = new DotNetAsmParser();
this.versionString = '';
this.disassemblyLoaderPath = path.join(this.clrBuildDir, 'DisassemblyLoader', 'DisassemblyLoader.dll');
}
@@ -301,8 +296,6 @@ class DotNetCompiler extends BaseCompiler {
const toolOptions: string[] = [
'--codegenopt',
this.sdkMajorVersion === 6 ? 'NgenDisasm=*' : 'JitDisasm=*',
'--codegenopt',
this.sdkMajorVersion < 8 ? 'JitDiffableDasm=1' : 'JitDisasmDiffable=1',
'--parallelism', '1',
];
const toolSwitches: string[] = [];
@@ -315,9 +308,9 @@ class DotNetCompiler extends BaseCompiler {
'DOTNET_JitDisasm=*',
'DOTNET_JitDisasmAssemblies=CompilerExplorer',
'DOTNET_TieredCompilation=0',
this.sdkMajorVersion < 8 ? 'DOTNET_JitDiffableDasm=1' : 'DOTNET_JitDisasmDiffable=1',
];
let isAot = false;
let overrideDiffable = false;
let isCrossgen2 = this.sdkMajorVersion === 6;
while (options.length > 0) {
@@ -338,6 +331,9 @@ class DotNetCompiler extends BaseCompiler {
) {
continue;
}
if (normalizedName === 'DOTNET_JITDIFFABLEDASM' || normalizedName === 'DOTNET_JITDISASMDIFFABLE') {
overrideDiffable = true;
}
envVarFileContents.push(envVar);
}
} else if (currentOption === '-p' || currentOption === '--property') {
@@ -357,10 +353,25 @@ class DotNetCompiler extends BaseCompiler {
const value = options.shift();
if (value) {
toolOptions.push(currentOption, value);
const normalizedValue = value.trim().toUpperCase();
if (
(currentOption === '--codegenopt' || currentOption === '--codegen-options') &&
(normalizedValue.startsWith('JITDIFFABLEDASM=') ||
normalizedValue.startsWith('JITDISASMDIFFABLE='))
) {
overrideDiffable = true;
}
}
}
}
if (!overrideDiffable) {
toolOptions.push('--codegenopt', this.sdkMajorVersion < 8 ? 'JitDiffableDasm=1' : 'JitDisasmDiffable=1');
envVarFileContents.push(
this.sdkMajorVersion < 8 ? 'DOTNET_JitDiffableDasm=1' : 'DOTNET_JitDisasmDiffable=1',
);
}
this.setCompilerExecOptions(execOptions, programDir);
let compilerResult;
@@ -384,6 +395,7 @@ class DotNetCompiler extends BaseCompiler {
if (isCrossgen2) {
const crossgen2Result = await this.runCrossgen2(
compiler,
execOptions,
this.clrBuildDir,
programDllPath,
@@ -423,9 +435,9 @@ class DotNetCompiler extends BaseCompiler {
override async execBinary(
executable: string,
maxSize: number | undefined,
maxSize: number,
executeParameters: ExecutableExecutionOptions,
homeDir: string | undefined,
homeDir: string,
): Promise<BasicExecutionResult> {
const programDir = path.dirname(executable);
const programOutputPath = path.join(programDir, 'bin', this.buildConfig, this.targetFramework);
@@ -443,9 +455,8 @@ class DotNetCompiler extends BaseCompiler {
execOptions.input = executeParameters.stdin;
const execArgs = ['-p', 'System.Runtime.TieredCompilation=false', programDllPath, ...executeParameters.args];
try {
const execResult: UnprocessedExecResult = await exec.sandbox(this.corerunPath, execArgs, execOptions);
return this.processExecutionResult(execResult);
} catch (err: UnprocessedExecResult | any) {
return this.execBinaryMaybeWrapped(this.corerunPath, execArgs, execOptions, executeParameters, homeDir);
} catch (err: any) {
if (err.code && err.stderr) {
return this.processExecutionResult(err);
} else {
@@ -459,15 +470,13 @@ class DotNetCompiler extends BaseCompiler {
}
}
async checkRuntimeVersion() {
if (!this.versionString) {
const versionFilePath = `${this.clrBuildDir}/version.txt`;
if (fs.existsSync(versionFilePath)) {
const versionString = await fs.readFile(versionFilePath);
this.versionString = versionString.toString();
} else {
this.versionString = '<unknown version>';
}
async getRuntimeVersion() {
const versionFilePath = `${this.clrBuildDir}/version.txt`;
if (fs.existsSync(versionFilePath)) {
const versionString = await fs.readFile(versionFilePath);
return versionString.toString();
} else {
return '<unknown version>';
}
}
@@ -479,8 +488,6 @@ class DotNetCompiler extends BaseCompiler {
options: string[],
outputPath: string,
) {
await this.checkRuntimeVersion();
const corerunOptions = ['--clr-path', coreRoot, '--env', envPath].concat([
...options,
this.disassemblyLoaderPath,
@@ -491,13 +498,16 @@ class DotNetCompiler extends BaseCompiler {
await fs.writeFile(
outputPath,
`// coreclr ${this.versionString}\n\n${result.stdout.map(o => o.text).reduce((a, n) => `${a}\n${n}`, '')}`,
`// coreclr ${await this.getRuntimeVersion()}\n\n${result.stdout
.map(o => o.text)
.reduce((a, n) => `${a}\n${n}`, '')}`,
);
return result;
}
async runCrossgen2(
compiler: string,
execOptions: ExecutionOptions,
bclPath: string,
dllPath: string,
@@ -505,22 +515,21 @@ class DotNetCompiler extends BaseCompiler {
toolSwitches: string[],
outputPath: string,
) {
await this.checkRuntimeVersion();
// prettier-ignore
const crossgen2Options = [
this.crossgen2Path,
'-r', path.join(bclPath, '/'),
'-r', this.disassemblyLoaderPath,
dllPath,
'-o', `${AssemblyName}.r2r.dll`,
].concat(toolOptions).concat(toolSwitches);
const compilerExecResult = await this.exec(this.crossgen2Path, crossgen2Options, execOptions);
const compilerExecResult = await this.exec(compiler, crossgen2Options, execOptions);
const result = this.transformToCompilationResult(compilerExecResult, dllPath);
await fs.writeFile(
outputPath,
`// crossgen2 ${this.versionString}\n\n${result.stdout
`// crossgen2 ${await this.getRuntimeVersion()}\n\n${result.stdout
.map(o => o.text)
.reduce((a, n) => `${a}\n${n}`, '')}`,
);

View File

@@ -67,7 +67,7 @@ export class FakeCompiler implements ICompiler {
return null;
}
compile(source, options, backendOptions, filters, bypassCache, tools, executionParameters, libraries, files) {
compile(source, options, backendOptions, filters, bypassCache, tools, executeParameters, libraries, files) {
const inputBody = {
input: {
source: source,

View File

@@ -22,7 +22,6 @@
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
import path from 'path';
import _ from 'underscore';
import type {ParseFiltersAndOutputOptions} from '../../types/features/filters.interfaces.js';
@@ -40,6 +39,10 @@ export class HLSLCompiler extends BaseCompiler {
this.compiler.supportsIntel = false;
this.spirvAsm = new SPIRVAsmParser(this.compilerProps);
this.compiler.supportsLLVMOptPipelineView = true;
this.compiler.llvmOptArg = ['-print-before-all', '-print-after-all'];
this.compiler.llvmOptNoDiscardValueNamesArg = [];
}
override async generateAST(inputFilename, options) {
@@ -91,10 +94,6 @@ export class HLSLCompiler extends BaseCompiler {
return options;
}
override getIrOutputFilename(inputFilename: string) {
return this.getOutputFilename(path.dirname(inputFilename), this.outputFilebase).replace('.s', '.dxil');
}
override async processAsm(result, filters, options) {
if (this.isSpirv(result.asm)) {
return this.spirvAsm.processAsm(result.asm, filters);

View File

@@ -36,6 +36,7 @@ import * as utils from '../utils.js';
import {JavaParser} from './argument-parsers.js';
import {BypassCache} from '../../types/compilation/compilation.interfaces.js';
import {ExecutableExecutionOptions} from '../../types/execution/execution.interfaces.js';
export class JavaCompiler extends BaseCompiler {
static get key() {
@@ -128,7 +129,7 @@ export class JavaCompiler extends BaseCompiler {
return ['-Xlint:all', '-encoding', 'utf8'];
}
override async handleInterpreting(key, executeParameters) {
override async handleInterpreting(key, executeParameters: ExecutableExecutionOptions) {
const compileResult = await this.getOrBuildExecutable(key, BypassCache.None);
if (compileResult.code === 0) {
executeParameters.args = [

View File

@@ -24,6 +24,7 @@
import {BypassCache} from '../../types/compilation/compilation.interfaces.js';
import type {PreliminaryCompilerInfo} from '../../types/compiler.interfaces.js';
import {ExecutableExecutionOptions} from '../../types/execution/execution.interfaces.js';
import type {ParseFiltersAndOutputOptions} from '../../types/features/filters.interfaces.js';
import {KotlinParser} from './argument-parsers.js';
@@ -94,7 +95,7 @@ export class KotlinCompiler extends JavaCompiler {
*
* TODO(supergrecko): Find a better fix than this bandaid for execution
*/
override async handleInterpreting(key, executeParameters) {
override async handleInterpreting(key, executeParameters: ExecutableExecutionOptions) {
const alteredKey = {
...key,
options: ['-include-runtime', '-d', 'example.jar'],

View File

@@ -185,7 +185,7 @@ export class SPIRVCompiler extends BaseCompiler {
const index = newOptions.indexOf(outputFile);
if (index !== -1) {
newOptions[index] = inputFilename.replace(path.extname(inputFilename), '.ll');
newOptions[index] = utils.changeExtension(inputFilename, '.ll');
}
return super.runCompiler(compiler, newOptions, inputFilename, execOptions);

50
lib/compilers/tablegen.ts Normal file
View File

@@ -0,0 +1,50 @@
import {BaseCompiler} from '../base-compiler.js';
import type {ParseFiltersAndOutputOptions} from '../../types/features/filters.interfaces.js';
import {TableGenParser} from './argument-parsers.js';
import {CompilerOverrideType} from '../../types/compilation/compiler-overrides.interfaces.js';
export class TableGenCompiler extends BaseCompiler {
static get key() {
return 'tablegen';
}
override optionsForFilter(filters: ParseFiltersAndOutputOptions, outputFilename: string) {
const options: string[] = ['-o', outputFilename];
if (this.compiler.includePath) {
options.push(`-I${this.compiler.includePath}`);
}
return options;
}
override isCfgCompiler() {
return false;
}
override getArgumentParser() {
return TableGenParser;
}
override async populatePossibleOverrides() {
const possibleActions = await TableGenParser.getPossibleActions(this);
if (possibleActions.length > 0) {
this.compiler.possibleOverrides?.push({
name: CompilerOverrideType.action,
display_title: 'Action',
description:
'The action to perform, which is the backend you wish to ' +
'run. By default, the records are just printed as text. ' +
'Many backends expect to find certain classes and defnitions ' +
'in your source code. You may find details of those in the ' +
'<a href="https://llvm.org/docs/TableGen/BackEnds.html" target="_blank">documentation</a>, ' +
'but if not, refer to use of the backend in the ' +
'<a href="https://github.com/llvm/llvm-project" target="_blank">LLVM Project</a> ' +
'by searching for the command line name e.g. "gen-attrs".',
flags: ['<value>'],
values: possibleActions,
default: '--print-records',
});
}
await super.populatePossibleOverrides();
}
}

View File

@@ -29,9 +29,10 @@ import type {PreliminaryCompilerInfo} from '../../types/compiler.interfaces.js';
import type {ParseFiltersAndOutputOptions} from '../../types/features/filters.interfaces.js';
import {LLVMIrBackendOptions} from '../../types/compilation/ir.interfaces.js';
import {BaseCompiler} from '../base-compiler.js';
import {asSafeVer} from '../utils.js';
import {asSafeVer, changeExtension} from '../utils.js';
import {TypeScriptNativeParser} from './argument-parsers.js';
import {ExecutableExecutionOptions} from '../../types/execution/execution.interfaces.js';
export class TypeScriptNativeCompiler extends BaseCompiler {
static get key() {
@@ -88,7 +89,7 @@ export class TypeScriptNativeCompiler extends BaseCompiler {
const outputFilename = this.getOutputFilename(path.dirname(inputFilename), this.outputFilebase);
// As per #4054, if we are asked for binary mode, the output will be in the .s file, no .ll will be emited
if (!filters.binary) {
return outputFilename.replace('.s', '.ll');
return changeExtension(outputFilename, '.ll');
}
return outputFilename;
}
@@ -116,7 +117,7 @@ export class TypeScriptNativeCompiler extends BaseCompiler {
return this.llvmIr.process(output.stderr.map(l => l.text).join('\n'), irOptions);
}
override async handleInterpreting(key, executeParameters) {
override async handleInterpreting(key, executeParameters: ExecutableExecutionOptions) {
executeParameters.args = [
'--emit=jit',
this.tscSharedLib ? '--shared-libs=' + this.tscSharedLib : '-nogc',

View File

@@ -79,6 +79,10 @@ export class BaseDemangler extends AsmRegex {
this.compiler = compiler;
}
public canDemangle() {
return !!this.demanglerExe;
}
// Iterates over the labels, demangle the label names and updates the start and
// end position of the label.
protected demangleLabels(labels, tree: PrefixTree) {

View File

@@ -386,6 +386,7 @@ export async function sandbox(
const type = execProps('sandboxType', 'firejail');
const dispatchEntry = sandboxDispatchTable[type];
if (!dispatchEntry) throw new Error(`Bad sandbox type ${type}`);
if (!command) throw new Error(`No executable provided`);
return await dispatchEntry(command, args, options);
}
@@ -596,5 +597,6 @@ export async function execute(
const type = execProps('executionType', 'none');
const dispatchEntry = executeDispatchTable[type];
if (!dispatchEntry) throw new Error(`Bad sandbox type ${type}`);
if (!command) throw new Error(`No executable provided`);
return await dispatchEntry(command, args, options);
}

View File

@@ -22,7 +22,7 @@
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
import {BypassCache} from '../../types/compilation/compilation.interfaces.js';
import {BypassCache, ExecutionParams} from '../../types/compilation/compilation.interfaces.js';
// IF YOU MODIFY ANYTHING HERE PLEASE UPDATE THE DOCUMENTATION!
@@ -36,16 +36,11 @@ export type CompileRequestQueryArgs = {
skipPopArgs?: string;
};
export type ExecutionRequestParams = {
args?: string | string[];
stdin?: string;
};
// TODO find more types for these.
export type CompilationRequestArgs = {
userArguments: string;
compilerOptions: Record<string, any>;
executeParameters: ExecutionRequestParams;
executeParameters: ExecutionParams;
filters: Record<string, boolean>;
tools: any;
libraries: any[];

View File

@@ -42,12 +42,7 @@ import {logger} from '../logger.js';
import {PropertyGetter} from '../properties.interfaces.js';
import * as utils from '../utils.js';
import {
CompileRequestJsonBody,
CompileRequestQueryArgs,
CompileRequestTextBody,
ExecutionRequestParams,
} from './compile.interfaces.js';
import {CompileRequestJsonBody, CompileRequestQueryArgs, CompileRequestTextBody} from './compile.interfaces.js';
import {remove} from '../../shared/common-utils.js';
import {CompilerOverrideOptions} from '../../types/compilation/compiler-overrides.interfaces.js';
import {BypassCache, CompileChildLibraries, ExecutionParams} from '../../types/compilation/compilation.interfaces.js';
@@ -92,7 +87,7 @@ type ParsedRequest = {
filters: ParseFiltersAndOutputOptions;
bypassCache: BypassCache;
tools: any;
executionParameters: ExecutionParams;
executeParameters: ExecutionParams;
libraries: CompileChildLibraries[];
};
@@ -353,7 +348,7 @@ export class CompileHandler {
filters: ParseFiltersAndOutputOptions,
bypassCache = BypassCache.None,
tools;
const execReqParams: ExecutionRequestParams = {};
const execReqParams: ExecutionParams = {};
let libraries: any[] = [];
// IF YOU MODIFY ANYTHING HERE PLEASE UPDATE THE DOCUMENTATION!
if (req.is('json')) {
@@ -366,6 +361,7 @@ export class CompileHandler {
const execParams = requestOptions.executeParameters || {};
execReqParams.args = execParams.args;
execReqParams.stdin = execParams.stdin;
execReqParams.runtimeTools = execParams.runtimeTools;
backendOptions = requestOptions.compilerOptions || {};
filters = {...compiler.getDefaultFilters(), ...requestOptions.filters};
tools = requestOptions.tools;
@@ -410,11 +406,12 @@ export class CompileHandler {
backendOptions.skipAsm = query.skipAsm === 'true';
backendOptions.skipPopArgs = query.skipPopArgs === 'true';
}
const executionParameters: ExecutionParams = {
const executeParameters: ExecutionParams = {
args: Array.isArray(execReqParams.args)
? execReqParams.args || ''
: utils.splitArguments(execReqParams.args),
stdin: execReqParams.stdin || '',
runtimeTools: execReqParams.runtimeTools || [],
};
tools = tools || [];
@@ -433,7 +430,7 @@ export class CompileHandler {
filters,
bypassCache,
tools,
executionParameters,
executeParameters,
libraries,
};
}
@@ -539,7 +536,7 @@ export class CompileHandler {
return this.handleApiError(error, res, next);
}
const {source, options, backendOptions, filters, bypassCache, tools, executionParameters, libraries} =
const {source, options, backendOptions, filters, bypassCache, tools, executeParameters, libraries} =
parsedRequest;
let files;
@@ -563,17 +560,7 @@ export class CompileHandler {
this.compileCounter.inc({language: compiler.lang.id});
// eslint-disable-next-line promise/catch-or-return
compiler
.compile(
source,
options,
backendOptions,
filters,
bypassCache,
tools,
executionParameters,
libraries,
files,
)
.compile(source, options, backendOptions, filters, bypassCache, tools, executeParameters, libraries, files)
.then(
result => {
if (result.didExecute || (result.execResult && result.execResult.didExecute))

View File

@@ -637,6 +637,17 @@ const definitions: Record<LanguageKey, LanguageDefinition> = {
previewFilter: null,
monacoDisassembly: null,
},
tablegen: {
name: 'LLVM TableGen',
monaco: 'tablegen',
extensions: ['.td'],
alias: [],
logoUrl: 'llvm.png',
logoUrlDark: null,
formatter: null,
previewFilter: null,
monacoDisassembly: null,
},
toit: {
name: 'Toit',
monaco: 'toit',

View File

@@ -242,7 +242,7 @@ export class LlvmIrParser {
};
}
if (options.demangle) {
if (options.demangle && this.irDemangler.canDemangle()) {
return {
asm: (await this.irDemangler.process({asm: result})).asm,
languageId: 'llvm-ir',

View File

@@ -86,9 +86,14 @@ export class LLVMOptTransformer extends Transform {
}
override _transform(chunk: any, encoding: string, done: TransformCallback) {
this._buffer += chunk.toString();
//buffer until we have a start and end if at any time i care about improving performance stash the offset
this.processBuffer();
// See https://stackoverflow.com/a/40928431/390318 - we have to catch all exceptions here
try {
this._buffer += chunk.toString();
this.processBuffer();
} catch (exception) {
done(exception as Error);
return;
}
done();
}

25
lib/runtime-tools/_all.ts Normal file
View File

@@ -0,0 +1,25 @@
// Copyright (c) 2023, 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.
export {HeaptrackWrapper} from './heaptrack-wrapper.js';

View File

@@ -0,0 +1,52 @@
// Copyright (c) 2023, 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 {RuntimeToolOptions, TypicalExecutionFunc} from '../../types/execution/execution.interfaces.js';
export class BaseRuntimeTool {
protected dirPath: string;
protected sandboxFunc: TypicalExecutionFunc;
protected execFunc: TypicalExecutionFunc;
protected options: RuntimeToolOptions;
protected sandboxType: string;
constructor(
dirPath: string,
sandboxFunc: TypicalExecutionFunc,
execFunc: TypicalExecutionFunc,
options: RuntimeToolOptions,
sandboxType: string,
) {
this.dirPath = dirPath;
this.sandboxFunc = sandboxFunc;
this.execFunc = execFunc;
this.options = options;
this.sandboxType = sandboxType;
}
protected getOptionValue(name: string): string | undefined {
const option = this.options.find(opt => opt.name === name);
if (option) return option.value;
}
}

View File

@@ -0,0 +1,191 @@
// Copyright (c) 2023, 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 * as path from 'path';
import {ExecutionOptions} from '../../types/compilation/compilation.interfaces.js';
import {
RuntimeToolOptions,
TypicalExecutionFunc,
UnprocessedExecResult,
} from '../../types/execution/execution.interfaces.js';
import {O_NONBLOCK, O_RDWR} from 'constants';
import * as fs from 'fs';
import * as net from 'net';
import {pipeline} from 'stream';
import {unwrap} from '../assert.js';
import {logger} from '../logger.js';
import {executeDirect} from '../exec.js';
import {PropertyGetter} from '../properties.interfaces.js';
import {BaseRuntimeTool} from './base-runtime-tool.js';
import {CompilationEnvironment} from '../compilation-env.js';
export class HeaptrackWrapper extends BaseRuntimeTool {
private rawOutput: string;
private pipe: string;
private interpretedPath: string;
private heaptrackPath: string;
private mkfifoPath: string;
private preload: string;
private interpreter: string;
private printer: string;
public static FlamegraphFilename = 'heaptrack.flamegraph.txt';
constructor(
dirPath: string,
sandboxFunc: TypicalExecutionFunc,
execFunc: TypicalExecutionFunc,
options: RuntimeToolOptions,
ceProps: PropertyGetter,
sandboxType: string,
) {
super(dirPath, sandboxFunc, execFunc, options, sandboxType);
this.mkfifoPath = ceProps('mkfifo', '/usr/bin/mkfifo');
this.pipe = path.join(this.dirPath, 'heaptrack_fifo');
this.rawOutput = path.join(this.dirPath, 'heaptrack_raw.txt');
this.interpretedPath = path.join(this.dirPath, 'heaptrack_interpreted.txt');
this.heaptrackPath = ceProps('heaptrackPath', '');
this.preload = path.join(this.heaptrackPath, 'lib/libheaptrack_preload.so');
this.interpreter = path.join(this.heaptrackPath, 'libexec/heaptrack_interpret');
this.printer = path.join(this.heaptrackPath, 'bin/heaptrack_print');
}
public static isSupported(compiler: CompilationEnvironment) {
return process.platform !== 'win32' && compiler.ceProps('heaptrackPath', '') !== '';
}
private async mkfifo(path: string, rights: number) {
await executeDirect(this.mkfifoPath, ['-m', rights.toString(8), path], {});
}
private async makePipe() {
await this.mkfifo(this.pipe, 0o666);
}
private addToEnv(execOptions: ExecutionOptions) {
if (!execOptions.env) execOptions.env = {};
if (execOptions.env.LD_PRELOAD) {
execOptions.env.LD_PRELOAD = this.preload + ':' + execOptions.env.LD_PRELOAD;
} else {
execOptions.env.LD_PRELOAD = this.preload;
}
if (this.sandboxType === 'nsjail') {
execOptions.env.DUMP_HEAPTRACK_OUTPUT = '/app/heaptrack_fifo';
} else {
execOptions.env.DUMP_HEAPTRACK_OUTPUT = this.pipe;
}
}
private async interpret(execOptions: ExecutionOptions): Promise<UnprocessedExecResult> {
return this.execFunc(this.interpreter, [this.rawOutput], execOptions);
}
private async finishPipesAndStreams(fd: number, file: fs.WriteStream, socket: net.Socket) {
socket.push(null);
await new Promise(resolve => socket.end(() => resolve(true)));
await new Promise(resolve => file.end(() => resolve(true)));
file.write(Buffer.from([0]));
socket.resetAndDestroy();
socket.unref();
await new Promise(resolve => {
file.close(err => {
if (err) logger.error('Error while closing heaptrack log: ', err);
resolve(true);
});
});
await new Promise(resolve => fs.close(fd, () => resolve(true)));
}
private async interpretAndSave(execOptions: ExecutionOptions, result: UnprocessedExecResult) {
const dirPath = unwrap(execOptions.appHome);
execOptions.input = fs.readFileSync(this.rawOutput).toString('utf8');
const interpretResults = await this.interpret(execOptions);
if (this.getOptionValue('summary') === 'stderr') {
result.stderr += interpretResults.stderr;
}
fs.writeFileSync(this.interpretedPath, interpretResults.stdout);
}
private async saveFlamegraph(execOptions: ExecutionOptions, result: UnprocessedExecResult) {
const args = [this.interpretedPath];
if (this.getOptionValue('graph') === 'yes') {
const flamesFilepath = path.join(this.dirPath, HeaptrackWrapper.FlamegraphFilename);
args.push('-F', flamesFilepath);
}
const printResults = await this.execFunc(this.printer, args, execOptions);
if (printResults.stderr) result.stderr += printResults.stderr;
if (this.getOptionValue('details') === 'stderr') {
result.stderr += printResults.stdout;
}
}
public async exec(filepath: string, args: string[], execOptions: ExecutionOptions): Promise<UnprocessedExecResult> {
const dirPath = unwrap(execOptions.appHome);
const runOptions = JSON.parse(JSON.stringify(execOptions));
const interpretOptions = JSON.parse(JSON.stringify(execOptions));
this.addToEnv(runOptions);
await this.makePipe();
const fd = fs.openSync(this.pipe, O_NONBLOCK | O_RDWR);
const socket = new net.Socket({fd, readable: true, writable: true});
const file = fs.createWriteStream(this.rawOutput);
pipeline(socket, file, err => {
if (err) {
logger.error('Error during heaptrack pipeline: ', err);
}
});
const result = await this.sandboxFunc(filepath, args, runOptions);
await this.finishPipesAndStreams(fd, file, socket);
fs.unlinkSync(this.pipe);
await this.interpretAndSave(interpretOptions, result);
await this.saveFlamegraph(execOptions, result);
return result;
}
}

View File

@@ -74,6 +74,12 @@ export function maskRootdir(filepath: string): string {
}
}
export function changeExtension(filename: string, newExtension: string): string {
const lastDot = filename.lastIndexOf('.');
if (lastDot === -1) return filename + newExtension;
return filename.substring(0, lastDot) + newExtension;
}
const ansiColoursRe = /\x1B\[[\d;]*[Km]/g;
function _parseOutputLine(line: string, inputFilename?: string, pathPrefix?: string) {
@@ -98,40 +104,103 @@ function parseSeverity(message: string): number {
const SOURCE_RE = /^\s*<source>[(:](\d+)(:?,?(\d+):?)?[):]*\s*(.*)/;
const SOURCE_WITH_FILENAME = /^\s*([\w.]*)[(:](\d+)(:?,?(\d+):?)?[):]*\s*(.*)/;
const ATFILELINE_RE = /\s*at ([\w-/.]*):(\d+)/;
export function parseOutput(lines: string, inputFilename?: string, pathPrefix?: string): ResultLine[] {
export enum LineParseOption {
SourceMasking,
RootMasking,
SourceWithLineMessage,
FileWithLineMessage,
AtFileLine,
}
export type LineParseOptions = LineParseOption[];
export const DefaultLineParseOptions = [
LineParseOption.SourceMasking,
LineParseOption.RootMasking,
LineParseOption.SourceWithLineMessage,
LineParseOption.FileWithLineMessage,
];
function applyParse_SourceWithLine(lineObj: ResultLine, filteredLine: string, inputFilename?: string) {
const match = filteredLine.match(SOURCE_RE);
if (match) {
const message = match[4].trim();
lineObj.tag = {
line: parseInt(match[1]),
column: parseInt(match[3] || '0'),
text: message,
severity: parseSeverity(message),
file: inputFilename ? path.basename(inputFilename) : undefined,
};
}
}
function applyParse_FileWithLine(lineObj: ResultLine, filteredLine: string) {
const match = filteredLine.match(SOURCE_WITH_FILENAME);
if (match) {
const message = match[5].trim();
lineObj.tag = {
file: match[1],
line: parseInt(match[2]),
column: parseInt(match[4] || '0'),
text: message,
severity: parseSeverity(message),
};
}
}
function applyParse_AtFileLine(lineObj: ResultLine, filteredLine: string) {
const match = filteredLine.match(ATFILELINE_RE);
if (match) {
if (match[1].startsWith('/app/')) {
lineObj.tag = {
file: match[1].replace(/^\/app\//, ''),
line: parseInt(match[2]),
column: 0,
text: filteredLine,
severity: 3,
};
} else if (!match[1].startsWith('/')) {
lineObj.tag = {
file: match[1],
line: parseInt(match[2]),
column: 0,
text: filteredLine,
severity: 3,
};
}
}
}
export function parseOutput(
lines: string,
inputFilename?: string,
pathPrefix?: string,
options: LineParseOptions = DefaultLineParseOptions,
): ResultLine[] {
const result: ResultLine[] = [];
eachLine(lines, line => {
line = _parseOutputLine(line, inputFilename, pathPrefix);
if (!inputFilename) {
if (options.includes(LineParseOption.SourceMasking)) {
line = _parseOutputLine(line, inputFilename, pathPrefix);
}
if (!inputFilename && options.includes(LineParseOption.RootMasking)) {
line = maskRootdir(line);
}
if (line !== null) {
const lineObj: ResultLine = {text: line};
const filteredline = line.replace(ansiColoursRe, '');
let match = filteredline.match(SOURCE_RE);
if (match) {
const message = match[4].trim();
lineObj.tag = {
line: parseInt(match[1]),
column: parseInt(match[3] || '0'),
text: message,
severity: parseSeverity(message),
file: inputFilename ? path.basename(inputFilename) : undefined,
};
} else {
match = filteredline.match(SOURCE_WITH_FILENAME);
if (match) {
const message = match[5].trim();
lineObj.tag = {
file: match[1],
line: parseInt(match[2]),
column: parseInt(match[4] || '0'),
text: message,
severity: parseSeverity(message),
};
}
}
const filteredLine = line.replace(ansiColoursRe, '');
if (options.includes(LineParseOption.SourceWithLineMessage))
applyParse_SourceWithLine(lineObj, filteredLine, inputFilename);
if (!lineObj.tag && options.includes(LineParseOption.FileWithLineMessage))
applyParse_FileWithLine(lineObj, filteredLine);
if (!lineObj.tag && options.includes(LineParseOption.AtFileLine))
applyParse_AtFileLine(lineObj, filteredLine);
result.push(lineObj);
}
});

3313
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -27,7 +27,7 @@
"@orchidjs/sifter": "^1.0.3",
"@sentry/browser": "^7.28.1",
"@sentry/node": "^7.28.1",
"@types/morgan": "^1.9.6",
"@types/morgan": "^1.9.8",
"big-integer": "^1.6.51",
"body-parser": "^1.20.2",
"bootstrap": "^4.6.2",
@@ -38,7 +38,7 @@
"copy-webpack-plugin": "^11.0.0",
"cross-env": "^7.0.3",
"eslint-plugin-header": "^3.1.1",
"eslint-plugin-prettier": "^5.0.0",
"eslint-plugin-prettier": "^5.0.1",
"events": "^3.3.0",
"express": "^4.18.2",
"file-saver": "^2.0.5",
@@ -46,11 +46,9 @@
"golden-layout": "^1.5.9",
"http-proxy": "^1.18.1",
"husky": "^8.0.3",
"husky-init": "^8.0.0",
"jquery": "^3.6.0",
"js-cookie": "^3.0.1",
"jquery": "^3.7.1",
"js-cookie": "^3.0.5",
"jszip": "^3.7.1",
"lodash": "^4.17.21",
"lodash.clonedeep": "^4.5.0",
"lru-cache": "^10.0.0",
"lz-string": "^1.4.4",
@@ -63,9 +61,8 @@
"path-browserify": "^1.0.1",
"popper.js": "^1.16.1",
"profanities": "^3.0.1",
"prom-client": "^14.0.1",
"prom-client": "^15.0.0",
"pug": "^3.0.2",
"qs": "^6.11.0",
"request": "^2.88.2",
"response-time": "^2.3.2",
"sanitize-filename": "^1.6.3",
@@ -80,7 +77,6 @@
"tree-kill": "^1.2.2",
"triple-beam": "^1.3.0",
"ts-node": "^10.4.0",
"tslib": "^2.3.1",
"underscore": "^1.13.2",
"url-join": "^5.0.0",
"whatwg-fetch": "^3.6.2",
@@ -92,31 +88,29 @@
"yaml": "^2.2.2"
},
"devDependencies": {
"@babel/preset-typescript": "^7.23.0",
"@smithy/util-stream": "^2.0.15",
"@types/body-parser": "^1.19.3",
"@babel/preset-typescript": "^7.23.2",
"@smithy/util-stream": "^2.0.17",
"@types/body-parser": "^1.19.5",
"@types/bootstrap": "^5.1.6",
"@types/chai": "^4.3.6",
"@types/chai-as-promised": "^7.1.6",
"@types/express": "^4.17.18",
"@types/file-saver": "^2.0.5",
"@types/fs-extra": "^11.0.2",
"@types/http-proxy": "^1.17.12",
"@types/jquery": "^3.5.10",
"@types/js-cookie": "^3.0.2",
"@types/mocha": "^10.0.2",
"@types/node-targz": "^0.2.1",
"@types/nopt": "^3.0.30",
"@types/qs": "^6.9.7",
"@types/request": "^2.48.9",
"@types/chai": "^4.3.9",
"@types/chai-as-promised": "^7.1.8",
"@types/express": "^4.17.20",
"@types/file-saver": "^2.0.6",
"@types/fs-extra": "^11.0.3",
"@types/http-proxy": "^1.17.13",
"@types/jquery": "^3.5.26",
"@types/js-cookie": "^3.0.5",
"@types/mocha": "^10.0.3",
"@types/node-targz": "^0.2.3",
"@types/nopt": "^3.0.31",
"@types/request": "^2.48.11",
"@types/shell-quote": "^1.7.1",
"@types/tar-fs": "^2.0.2",
"@types/temp": "^0.9.2",
"@types/temp": "^0.9.3",
"@types/underscore": "^1.11.4",
"@types/webpack-env": "^1.18.2",
"@types/webpack-env": "^1.18.3",
"@typescript-eslint/eslint-plugin": "^6.7.5",
"@typescript-eslint/parser": "^6.7.5",
"approvals": "^6.2.2",
"approvals": "^6.2.4",
"aws-sdk-client-mock": "^3.0.0",
"c8": "^8.0.1",
"chai": "^4.3.10",
@@ -126,41 +120,39 @@
"codecov": "^3.8.3",
"css-loader": "^6.8.1",
"css-minimizer-webpack-plugin": "^5.0.1",
"cypress": "^13.3.0",
"cypress": "^13.4.0",
"deep-equal-in-any-order": "^2.0.6",
"eslint": "^8.51.0",
"eslint-config-prettier": "^9.0.0",
"eslint-formatter-github": "^1.1.4",
"eslint-import-resolver-typescript": "^3.6.1",
"eslint-plugin-import": "^2.28.1",
"eslint-plugin-import": "^2.29.0",
"eslint-plugin-jsdoc": "^46.8.2",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-promise": "^6.1.1",
"eslint-plugin-requirejs": "^4.0.1",
"eslint-plugin-sonarjs": "^0.21.0",
"eslint-plugin-unicorn": "^48.0.1",
"eslint-plugin-unicorn": "^49.0.0",
"eslint-plugin-unused-imports": "^3.0.0",
"file-loader": "^6.2.0",
"lint-staged": "^14.0.1",
"lint-staged": "^15.0.2",
"mini-css-extract-plugin": "^2.7.6",
"mocha": "^10.2.0",
"mock-fs": "^5.2.0",
"monaco-editor-webpack-plugin": "^7.1.0",
"nock": "^13.3.3",
"nock": "^13.3.6",
"prettier": "^3.0.3",
"sass": "^1.69.1",
"sass": "^1.69.4",
"sass-loader": "^13.3.2",
"sinon": "^16.1.0",
"sinon": "^17.0.0",
"source-map-loader": "^4.0.1",
"supervisor": "^0.12.0",
"terser-webpack-plugin": "^5.3.9",
"ts-loader": "^9.5.0",
"typescript": "^4.9.5",
"url-loader": "^4.1.1",
"webpack": "^5.88.2",
"webpack-cli": "^5.1.4",
"webpack-dev-middleware": "^6.1.1",
"webpack-dev-server": "^4.15.1",
"webpack-manifest-plugin": "^5.0.0"
},
"mocha": {

View File

@@ -23,10 +23,12 @@
// POSSIBILITY OF SUCH DAMAGE.
import type {ConfiguredOverrides} from './compilation/compiler-overrides.interfaces.js';
import type {ConfiguredRuntimeTools} from './execution/execution.interfaces.js';
import type {CompilerState} from './panes/compiler.interfaces.js';
import type {ExecutorState} from './panes/executor.interfaces.js';
export interface ICompilerShared {
updateState(state: CompilerState | ExecutorState);
getOverrides(): ConfiguredOverrides | undefined;
getRuntimeTools(): ConfiguredRuntimeTools | undefined;
}

View File

@@ -27,11 +27,15 @@ import {CompilerOverridesWidget} from './widgets/compiler-overrides.js';
import type {CompilerState} from './panes/compiler.interfaces.js';
import type {ConfiguredOverrides} from './compilation/compiler-overrides.interfaces.js';
import type {ExecutorState} from './panes/executor.interfaces.js';
import {RuntimeToolsWidget} from './widgets/runtime-tools.js';
import {ConfiguredRuntimeTools} from './execution/execution.interfaces.js';
export class CompilerShared implements ICompilerShared {
private domRoot: JQuery<HTMLElement>;
private overridesButton: JQuery<HTMLElement>;
private overridesWidget: CompilerOverridesWidget;
private runtimeToolsButton: JQuery<HTMLElement>;
private runtimeToolsWidget?: RuntimeToolsWidget;
constructor(domRoot: JQuery, onChange: () => void) {
this.domRoot = domRoot;
@@ -43,6 +47,10 @@ export class CompilerShared implements ICompilerShared {
return this.overridesWidget.get();
}
public getRuntimeTools(): ConfiguredRuntimeTools | undefined {
return this.runtimeToolsWidget?.get();
}
public updateState(state: CompilerState | ExecutorState) {
this.overridesWidget.setCompiler(state.compiler, state.lang);
@@ -51,17 +59,37 @@ export class CompilerShared implements ICompilerShared {
} else {
this.overridesWidget.setDefaults();
}
if (this.runtimeToolsWidget) {
this.runtimeToolsWidget.setCompiler(state.compiler, state.lang);
if (state.runtimeTools) {
this.runtimeToolsWidget.set(state.runtimeTools);
} else {
this.runtimeToolsWidget.setDefaults();
}
}
}
private initButtons(onChange: () => void) {
this.overridesButton = this.domRoot.find('.btn.show-overrides');
this.overridesWidget = new CompilerOverridesWidget(this.domRoot, this.overridesButton, onChange);
this.runtimeToolsButton = this.domRoot.find('.btn.show-runtime-tools');
if (this.runtimeToolsButton.length > 0) {
this.runtimeToolsWidget = new RuntimeToolsWidget(this.domRoot, this.runtimeToolsButton, onChange);
}
}
private initCallbacks() {
this.overridesButton.on('click', () => {
this.overridesWidget.show();
});
if (this.runtimeToolsButton.length > 0) {
this.runtimeToolsButton.on('click', () => {
this.runtimeToolsWidget?.show();
});
}
}
}

View File

@@ -27,6 +27,8 @@ import {CfgState} from './panes/cfg-view.interfaces.js';
import {LLVMOptPipelineViewState} from './panes/llvm-opt-pipeline.interfaces.js';
import {GccDumpViewState} from './panes/gccdump-view.interfaces.js';
import {ConfiguredOverrides} from './compilation/compiler-overrides.interfaces.js';
import {ConfiguredRuntimeTools} from './execution/execution.interfaces.js';
import {IrState} from './panes/ir-view.interfaces.js';
export const COMPILER_COMPONENT_NAME = 'compiler';
export const EXECUTOR_COMPONENT_NAME = 'executor';
export const EDITOR_COMPONENT_NAME = 'codeEditor';
@@ -93,6 +95,7 @@ export type PopulatedExecutorState = StateWithLanguage &
compilationPanelShown: boolean;
compilerOutShown: boolean;
overrides?: ConfiguredOverrides;
runtimeTools?: ConfiguredRuntimeTools;
};
export type ExecutorForTreeState = StateWithLanguage &
StateWithTree & {
@@ -202,13 +205,13 @@ export type PopulatedConformanceViewState = {
};
export type EmptyIrViewState = EmptyState;
export type PopulatedIrViewState = StateWithId & {
editorid: number;
treeid: number;
source: string;
irOutput: unknown;
compilerName: string;
};
export type PopulatedIrViewState = StateWithId &
IrState & {
editorid: number;
treeid: number;
source: string;
compilerName: string;
};
export type EmptyLLVMOptPipelineViewState = EmptyState;
export type PopulatedLLVMOptPipelineViewState = StateWithId &

View File

@@ -108,6 +108,7 @@ import {
EmptyStackUsageViewState,
} from './components.interfaces.js';
import {ConfiguredOverrides} from './compilation/compiler-overrides.interfaces.js';
import {ConfiguredRuntimeTools} from './execution/execution.interfaces.js';
/** Get an empty compiler component. */
export function getCompiler(editorId: number, lang: string): ComponentConfig<EmptyCompilerState> {
@@ -186,6 +187,7 @@ export function getExecutorWith(
compilerArgs,
treeId: number,
overrides?: ConfiguredOverrides,
runtimeTools?: ConfiguredRuntimeTools,
): ComponentConfig<PopulatedExecutorState> {
return {
type: 'component',
@@ -200,6 +202,7 @@ export function getExecutorWith(
compilationPanelShown: true,
compilerOutShown: true,
overrides: overrides,
runtimeTools: runtimeTools,
},
};
}

View File

@@ -59,6 +59,7 @@ import './ocaml-mode';
import './openclc-mode';
import './ptx-mode';
import './spirv-mode';
import './tablegen-mode';
import './v-mode';
import './vala-mode';
import './zig-mode';

View File

@@ -138,9 +138,9 @@ function definition(): monaco.languages.IMonarchLanguage {
[/./, 'invalid', '@pop'],
];
cppfront.tokenizer.parse_cpp2_character_literal = [
[/'[^\\']'/, 'string', '@pop'],
[/(')(@escapes)(')/, ['string', 'string.escape', {token: 'string', next: '@pop'}]],
[/'/, 'string.invalid', '@pop'],
[/./, 'invalid', '@pop'],
];
cppfront.at_cpp2_literal_keyword = /(?:nullptr|true|false)\b/;
cppfront.at_cpp2_literal = /\d|'|@at_cpp2_literal_keyword|@at_cpp2_string_literal/; // No `.`; `.0` isn't Cpp2.
@@ -193,6 +193,15 @@ function definition(): monaco.languages.IMonarchLanguage {
},
},
],
[
/@at_cpp2_contract_kind/,
{
cases: {
'$S2==contract_kind': {token: 'keyword.contract-kind', next: '@pop'},
'@': {token: '@rematch', switchTo: 'parse_cpp2_non_operator_identifier.$S2'},
},
},
],
[/./, {token: '@rematch', switchTo: 'parse_cpp2_non_operator_identifier.$S2'}],
];
cppfront.tokenizer.parse_cpp2_non_operator_identifier = [
@@ -237,7 +246,7 @@ function definition(): monaco.languages.IMonarchLanguage {
cppfront.at_cpp2_type_id =
/@at_cpp2_type_qualifier|@at_cpp2_non_operator_id_expression|@at_cpp2_function_type_id/;
cppfront.at_cpp2_function_type_id =
/\(\s*(?:(?:@at_cpp2_parameter_direction\s+)?@at_cpp2_non_operator_identifier\s*)?@at_cpp2_unnamed_declaration_head/;
/\(\s*\)|\(\s*(?:(?:@at_cpp2_parameter_direction\s+)?@at_cpp2_non_operator_identifier\s*)?@at_cpp2_unnamed_declaration_head/;
cppfront.tokenizer.parse_cpp2_type_id = [
[/@at_cpp2_type_qualifier/, '@rematch', 'parse_cpp2_type_qualifier_seq'],
[/@at_cpp2_keyword_type|_\b/, 'keyword.type.contextual', '@pop'],
@@ -432,6 +441,13 @@ function definition(): monaco.languages.IMonarchLanguage {
[/./, '@rematch', '@pop'],
];
cppfront.tokenizer.parse_cpp2_using_statement = [
{include: '@whitespace'},
[/using\b/, 'keyword.using'],
[/namespace\b/, 'keyword.namespace'],
[/./, {token: '@rematch', switchTo: 'parse_cpp2_id_expression'}],
];
cppfront.tokenizer.parse_cpp2_alternative = [
{include: '@whitespace'},
[
@@ -535,51 +551,17 @@ function definition(): monaco.languages.IMonarchLanguage {
],
];
cppfront.tokenizer.parse_cpp2_contract_string_literal = [
{include: '@whitespace'},
[/@at_cpp2_string_literal/, {token: '@rematch', switchTo: 'parse_cpp2_string_literal'}],
[/./, 'invalid', '@pop'],
];
cppfront.tokenizer.parse_cpp2_contract_logical_or_expression = [
{include: '@whitespace'},
[/@at_cpp2_expression/, '@rematch', 'parse_cpp2_logical_or_expression'],
[/,/, {token: 'delimiter', switchTo: 'parse_cpp2_contract_string_literal'}],
[/\]/, '@rematch', '@pop'],
[/./, 'invalid', '@pop'],
];
cppfront.tokenizer.parse_cpp2_contract_colon = [
{include: '@whitespace'},
[/:/, {token: 'delimiter.contract-colon', switchTo: 'parse_cpp2_contract_logical_or_expression'}],
[/./, 'invalid', '@pop'],
];
cppfront.tokenizer.parse_cpp2_contract_id_expression = [
{include: '@whitespace'},
[/(?:Default|Bounds|Null|Type|Testing)\b/, {token: 'constant', switchTo: 'parse_cpp2_contract_colon'}],
[/@at_cpp2_non_operator_id_expression/, '@rematch', 'parse_cpp2_id_expression'],
[/./, {token: '@rematch', switchTo: 'parse_cpp2_contract_colon'}],
];
cppfront.at_cpp2_contract_kind = /(?:pre|post|assert)\b/;
cppfront.tokenizer.parse_cpp2_contract_kind = [
{include: '@whitespace'},
[/@at_cpp2_contract_kind/, {token: 'keyword.contract-kind', switchTo: 'parse_cpp2_contract_id_expression'}],
[/./, 'invalid', '@pop'],
];
cppfront.tokenizer.parse_cpp2_contract_body = [
[/./, {token: '@rematch', switchTo: 'parse_cpp2_contract_kind'}],
];
cppfront.tokenizer.parse_cpp2_contract = [
[
/\[/,
{
token: '@rematch',
switchTo: 'parse_cpp2_balanced_squares.parse_cpp2_balanced_squares.parse_cpp2_contract_body',
},
],
[/@at_cpp2_contract_kind/, '@rematch', 'parse_cpp2_id_expression.contract_kind'],
[/\(/, {token: '@rematch', switchTo: 'parse_cpp2_expression_list'}],
[/./, '@rematch', '@pop'],
];
cppfront.tokenizer.parse_cpp2_statement = [
{include: '@whitespace'},
[/if\b/, {token: '@rematch', switchTo: 'parse_cpp2_selection_statement'}],
[/using\b/, {token: '@rematch', switchTo: 'parse_cpp2_using_statement'}],
[/inspect\b/, {token: '@rematch', switchTo: 'parse_cpp2_inspect_expression'}],
[/return\b/, {token: '@rematch', switchTo: 'parse_cpp2_return_statement'}],
[/@at_cpp2_jump_statement/, {token: '@rematch', switchTo: 'parse_cpp2_jump_statement'}],
@@ -587,7 +569,7 @@ function definition(): monaco.languages.IMonarchLanguage {
[/{/, {token: '@rematch', switchTo: 'parse_cpp2_compound_statement'}],
[/@at_cpp2_declaration_head/, {token: '@rematch', switchTo: 'parse_cpp2_declaration.definition'}],
[/@at_cpp2_parameterized_statement/, {token: '@rematch', switchTo: 'parse_cpp2_parameterized_statement'}],
[/\[/, {token: '@rematch', switchTo: 'parse_cpp2_contract'}],
[/@at_cpp2_contract_kind/, {token: '@rematch', switchTo: 'parse_cpp2_contract'}],
[/./, {token: '@rematch', switchTo: 'parse_cpp2_expression_statement.$S2'}],
];
}
@@ -678,25 +660,21 @@ function definition(): monaco.languages.IMonarchLanguage {
[/->/, 'invalid', '@pop'],
];
cppfront.tokenizer.parse_cpp2_contract_seq = [
{include: '@whitespace'},
[/\[/, '@rematch', 'parse_cpp2_contract'],
[/./, '@rematch', '@pop'],
];
cppfront.tokenizer.parse_cpp2_full_function_type = [
{include: '@whitespace'},
[/throws\b/, 'keyword'],
[/->/, '@rematch', 'parse_cpp2_return_list'],
[/\[/, '@rematch', 'parse_cpp2_contract_seq'],
[/@at_cpp2_contract_kind/, '@rematch', 'parse_cpp2_contract'],
[/./, '@rematch', '@pop'],
];
cppfront.at_cpp2_function_type_id_tail = /throws\b|->|@at_cpp2_contract_kind/;
cppfront.tokenizer.parse_cpp2_terse_function = [
{include: '@whitespace'},
[/\(/, '@rematch', 'parse_cpp2_parameter_declaration_list'],
[/throws\b|->|\[/, {token: '@rematch', switchTo: 'parse_cpp2_full_function_type'}],
[/@at_cpp2_function_type_id_tail/, {token: '@rematch', switchTo: 'parse_cpp2_full_function_type'}],
[/requires\b|==?|;/, '@rematch', '@pop'],
[/@at_cpp2_expression/, {token: '@rematch', switchTo: 'parse_cpp2_expression'}],
[/./, '@rematch', '@pop'],
];
cppfront.tokenizer.parse_cpp2_function_type = [
[/./, {token: '@rematch', switchTo: 'parse_cpp2_terse_function'}],
@@ -727,7 +705,15 @@ function definition(): monaco.languages.IMonarchLanguage {
},
],
[/==?/, {token: 'delimiter', switchTo: 'parse_cpp2_declaration_initializer.$S2'}],
[/;/, 'delimiter', '@pop'],
[
/;/,
{
cases: {
'$S2==expression': {token: '@rematch', next: '@pop'},
'@': {token: 'delimiter', next: '@pop'},
},
},
],
[/./, '@rematch', '@pop'],
];

View File

@@ -0,0 +1,194 @@
// Copyright (c) 2023, 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 * as monaco from 'monaco-editor';
export function definition(): monaco.languages.IMonarchLanguage {
return {
keywords: [
'assert',
'class',
'code',
'def',
'dump',
'else',
'false',
'foreach',
'defm',
'defset',
'defvar',
'field',
'if',
'in',
'include',
'let',
'multiclass',
'then',
'true',
],
standardTypes: ['bit', 'int', 'string', 'dag', 'bits', 'list'],
operators: [
'!add',
'!and',
'!cast',
'!con',
'!cond',
'!dag',
'!div',
'!empty',
'!eq',
'!exists',
'!filter',
'!find',
'!foldl',
'!foreach',
'!ge',
'!getdagarg',
'!getdagname',
'!getdagop',
'!gt',
'!head',
'!if',
'!interleave',
'!isa',
'!le',
'!listconcat',
'!listremove',
'!listsplat',
'!logtwo',
'!lt',
'!mul',
'!ne',
'!not',
'!or',
'!range',
'!repr',
'!setdagarg',
'!setdagname',
'!setdagop',
'!shl',
'!size',
'!sra',
'!srl',
'!strconcat',
'!sub',
'!subst',
'!substr',
'!tail',
'!tolower',
'!toupper',
'!xor',
],
brackets: [
{
open: '(',
close: ')',
token: 'delimiter.parenthesis',
},
{
open: '[',
close: ']',
token: 'delimiter.square',
},
{
open: '<',
close: '>',
token: 'delimiter.angle',
},
],
symbols: /[=><!~&|+\-*/^]+/,
delimiters: /[;=.:,`]/,
escapes: /\\(?:[abfnrtv\\'\n\r]|x[0-9A-Fa-f]{2}|[0-7]{3}|u[0-9A-Fa-f]{4}|U[0-9A-Fa-f]{8}|N\{\w+\})/,
tokenizer: {
root: [
[
/[a-zA-Z_][a-zA-Z0-9_]*/,
{
cases: {
'@standardTypes': 'type',
'@keywords': 'keyword',
'@default': 'identifier',
},
},
],
{include: '@whitespace'},
[/[()[\]<>]/, '@brackets'],
// Numbers
[/0x([abcdef]|[ABCDEF]|\d)+/, 'number.hex'],
[/0b[01]+1/, 'number.binary'],
// Decimal may have + or - in front.
[/[-+]?\d+/, 'number'],
// Strings
[/"([^"\\]|\\.)*$/, 'string.invalid'], // non-teminated string
[/"/, 'string', '@string'],
[
/@delimiters/,
{
cases: {
'@keywords': 'keyword',
'@default': 'delimiter',
},
},
],
],
whitespace: [
[/[ \t\r\n]+/, 'white'],
[/\/\*/, 'comment', '@comment'],
[/\/\+/, 'comment', '@nestingcomment'],
[/\/\/.*$/, 'comment'],
],
comment: [
[/[^/*]+/, 'comment'],
[/\*\//, 'comment', '@pop'],
[/[/*]/, 'comment'],
],
nestingcomment: [
[/[^/+]+/, 'comment'],
[/\/\+/, 'comment', '@push'],
[/\/\+/, 'comment.invalid'],
[/\+\//, 'comment', '@pop'],
[/[/+]/, 'comment'],
],
string: [
[/[^\\"]+/, 'string'],
[/@escapes/, 'string.escape'],
[/\\./, 'string.escape.invalid'],
[/"/, 'string', '@pop'],
],
},
};
}
monaco.languages.register({id: 'tablegen'});
monaco.languages.setMonarchTokensProvider('tablegen', definition());
export {};

View File

@@ -23,6 +23,7 @@
// POSSIBILITY OF SUCH DAMAGE.
import type {ConfiguredOverrides} from '../compilation/compiler-overrides.interfaces.js';
import {ConfiguredRuntimeTools} from '../execution/execution.interfaces.js';
import {WidgetState} from '../widgets/libs-widget.interfaces.js';
import {MonacoPaneState} from './pane.interfaces.js';
@@ -36,6 +37,7 @@ export type CompilerState = WidgetState & {
wantOptInfo?: boolean;
lang?: string;
overrides?: ConfiguredOverrides;
runtimeTools?: ConfiguredRuntimeTools;
};
// TODO(jeremy-rifkin): This omit is ugly. There should be a better way to do this.

View File

@@ -679,6 +679,7 @@ export class Compiler extends MonacoPane<monaco.editor.IStandaloneCodeEditor, Co
currentState.options,
treeId ?? 0,
currentState.overrides,
currentState.runtimeTools,
);
};
@@ -1281,6 +1282,7 @@ export class Compiler extends MonacoPane<monaco.editor.IStandaloneCodeEditor, Co
executeParameters: {
args: '',
stdin: '',
runtimeTools: this.getCurrentState().runtimeTools,
},
};
@@ -1768,14 +1770,46 @@ export class Compiler extends MonacoPane<monaco.editor.IStandaloneCodeEditor, Co
} else if (artifact.type === ArtifactType.smsrom) {
this.emulateMiracleSMS(artifact.content);
} else if (artifact.type === ArtifactType.timetrace) {
this.offerViewInPerfetto(artifact);
this.offerViewInSpeedscope(artifact);
} else if (artifact.type === ArtifactType.c64prg) {
this.emulateC64Prg(artifact);
} else if (artifact.type === ArtifactType.heaptracktxt) {
this.offerViewInSpeedscope(artifact);
}
}
}
}
offerViewInSpeedscope(artifact: Artifact): void {
this.alertSystem.notify(
'Click ' +
'<a target="_blank" id="download_link" style="cursor:pointer;" click="javascript:;">here</a>' +
' to view ' +
artifact.title +
' in Speedscope',
{
group: artifact.type,
collapseSimilar: false,
dismissTime: 10000,
onBeforeShow: function (elem) {
elem.find('#download_link').on('click', () => {
const tmstr = Date.now();
const live_url = 'https://static.ce-cdn.net/speedscope/index.html';
const speedscope_url =
live_url +
'?' +
tmstr +
'#customFilename=' +
artifact.name +
'&b64data=' +
artifact.content;
window.open(speedscope_url);
});
},
},
);
}
offerViewInPerfetto(artifact: Artifact): void {
this.alertSystem.notify(
'Click ' +
@@ -1784,8 +1818,8 @@ export class Compiler extends MonacoPane<monaco.editor.IStandaloneCodeEditor, Co
artifact.title +
' in Perfetto',
{
group: 'emulation',
collapseSimilar: true,
group: artifact.type,
collapseSimilar: false,
dismissTime: 10000,
onBeforeShow: function (elem) {
elem.find('#download_link').on('click', () => {
@@ -3202,6 +3236,7 @@ export class Compiler extends MonacoPane<monaco.editor.IStandaloneCodeEditor, Co
flagsViewOpen: this.flagsViewOpen,
deviceViewOpen: this.deviceViewOpen,
overrides: this.compilerShared.getOverrides(),
runtimeTools: this.compilerShared.getRuntimeTools(),
};
this.paneRenaming.addState(state);
this.fontScale.addState(state);

View File

@@ -41,7 +41,7 @@ import '../formatter-registry';
import '../modes/_all';
import {MonacoPane} from './pane.js';
import {Hub} from '../hub.js';
import {MonacoPaneState} from './pane.interfaces.js';
import {MonacoPaneState, PaneState} from './pane.interfaces.js';
import {Container} from 'golden-layout';
import {EditorState, LanguageSelectData} from './editor.interfaces.js';
import {Language, LanguageKey} from '../../types/languages.interfaces.js';
@@ -165,6 +165,15 @@ export class Editor extends MonacoPane<monaco.editor.IStandaloneCodeEditor, Edit
// });
}
override initializeCompilerInfo(state: PaneState) {
this.compilerInfo = {
compilerId: 0,
compilerName: '',
editorId: 0,
treeId: 0,
};
}
override initializeDefaults(): void {
this.ourCompilers = {};
this.ourExecutors = {};

View File

@@ -22,7 +22,8 @@
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
import type {ConfiguredOverrides} from '../compilation/compiler-overrides.interfaces.js';
import type {ConfiguredOverrides} from '../../types/compilation/compiler-overrides.interfaces.js';
import type {ConfiguredRuntimeTools} from '../../types/execution/execution.interfaces.js';
import type {WidgetState} from '../widgets/libs-widget.interfaces.js';
export type ExecutorState = WidgetState & {
@@ -40,4 +41,5 @@ export type ExecutorState = WidgetState & {
lang?: string;
compiler: string;
overrides?: ConfiguredOverrides;
runtimeTools?: ConfiguredRuntimeTools;
};

View File

@@ -61,6 +61,7 @@ import {CompilerShared} from '../compiler-shared.js';
import {LangInfo} from './compiler-request.interfaces.js';
import {escapeHTML} from '../../shared/common-utils.js';
import {CompilerVersionInfo, setCompilerVersionPopoverForPane} from '../widgets/compiler-version-info.js';
import {Artifact, ArtifactType} from '../../types/tool.interfaces.js';
const languages = options.languages;
@@ -190,6 +191,15 @@ export class Executor extends Pane<ExecutorState> {
}
}
override initializeCompilerInfo(state: PaneState) {
this.compilerInfo = {
compilerId: 0,
compilerName: '',
editorId: state.editorid,
treeId: state.treeid,
};
}
override initializeStateDependentProperties(state: PaneState & ExecutorState) {
this.sourceTreeId = state.tree ?? null;
this.settings = Settings.getStoredSettings();
@@ -279,6 +289,7 @@ export class Executor extends Pane<ExecutorState> {
executeParameters: {
args: this.executionArguments,
stdin: this.executionStdin,
runtimeTools: this.compilerShared.getRuntimeTools(),
},
compilerOptions: {
executorRequest: true,
@@ -678,6 +689,48 @@ export class Executor extends Pane<ExecutorState> {
if (this.currentLangId)
this.eventHub.emit('executeResult', this.id, this.compiler, result, languages[this.currentLangId]);
this.offerFilesIfPossible(result);
}
offerFilesIfPossible(result: CompilationResult) {
if (result.artifacts) {
for (const artifact of result.artifacts) {
if (artifact.type === ArtifactType.heaptracktxt) {
this.offerViewInSpeedscope(artifact);
}
}
}
}
offerViewInSpeedscope(artifact: Artifact): void {
this.alertSystem.notify(
'Click ' +
'<a target="_blank" id="download_link" style="cursor:pointer;" click="javascript:;">here</a>' +
' to view ' +
artifact.title +
' in Speedscope',
{
group: artifact.type,
collapseSimilar: false,
dismissTime: 10000,
onBeforeShow: function (elem) {
elem.find('#download_link').on('click', () => {
const tmstr = Date.now();
const live_url = 'https://static.ce-cdn.net/speedscope/index.html';
const speedscope_url =
live_url +
'?' +
tmstr +
'#customFilename=' +
artifact.name +
'&b64data=' +
artifact.content;
window.open(speedscope_url);
});
},
},
);
}
onCompileResponse(request: CompilationRequest, result: CompilationResult, cached: boolean): void {
@@ -973,35 +1026,34 @@ export class Executor extends Pane<ExecutorState> {
return this.settings.executorCompileOnChange;
}
onOptionsChange(options: string): void {
this.options = options;
doTypicalOnChange() {
this.updateState();
if (this.shouldEmitExecutionOnFieldChange()) {
this.compile();
}
}
onOptionsChange(options: string): void {
this.options = options;
this.doTypicalOnChange();
}
onExecArgsChange(args: string): void {
this.executionArguments = args;
this.updateState();
if (this.shouldEmitExecutionOnFieldChange()) {
this.compile();
}
this.doTypicalOnChange();
}
onCompilerOverridesChange(): void {
this.updateState();
if (this.shouldEmitExecutionOnFieldChange()) {
this.compile();
}
this.doTypicalOnChange();
}
onRuntimeToolsChange(): void {
this.doTypicalOnChange();
}
onExecStdinChange(newStdin: string): void {
this.executionStdin = newStdin;
this.updateState();
if (this.shouldEmitExecutionOnFieldChange()) {
this.compile();
}
this.doTypicalOnChange();
}
onRequestCompilation(editorId: number | boolean, treeId: number | boolean): void {
@@ -1086,6 +1138,7 @@ export class Executor extends Pane<ExecutorState> {
stdinPanelShown: !this.panelStdin.hasClass('d-none'),
wrap: this.toggleWrapButton.get().wrap,
overrides: this.compilerShared.getOverrides(),
runtimeTools: this.compilerShared.getRuntimeTools(),
};
this.paneRenaming.addState(state);

View File

@@ -129,6 +129,14 @@ export class Ir extends MonacoPane<monaco.editor.IStandaloneCodeEditor, IrState>
});
}
override getCurrentState() {
return {
...this.options.get(),
...this.filters.get(),
...super.getCurrentState(),
};
}
override registerEditorActions(): void {
this.editor.addAction({
id: 'viewsource',

View File

@@ -171,7 +171,9 @@ export class Output extends Pane<OutputState> {
}
addOutputLines(result: CompilationResult) {
const stdout = result.stdout;
// When MS upgrade to a server version later than Nov 11, 2022 (the merge of PR #4278)
// the `undefined` check can be removed.
const stdout = (result.stdout as any) !== undefined ? result.stdout : [];
const stderr = result.stderr;
for (const obj of stdout.concat(stderr)) {
const lineNumber = obj.tag ? obj.tag.line : obj.line;

View File

@@ -371,6 +371,8 @@ pre.content.wrap * {
.toast {
max-width: 100% !important;
// Not set in Bootstrap 4, remove once we upgrade
z-index: 1090;
}
.toast-header .close {
@@ -378,6 +380,10 @@ pre.content.wrap * {
margin-right: 5px;
}
.toast a {
text-decoration: underline !important;
}
.font-size-list {
min-width: 43px !important;
max-height: 70% !important;
@@ -691,10 +697,6 @@ div.populararguments div.dropdown-menu {
overflow-y: scroll;
}
#overrides-selection .override-search-button {
margin-left: 10px;
}
#overrides-selection .overrides-how-to-use {
font-size: smaller;
}
@@ -742,6 +744,72 @@ div.populararguments div.dropdown-menu {
display: none;
}
#runtimetools-selection .modal-body {
overflow-y: scroll;
}
#runtimetools-selection .runtimetools-how-to-use {
font-size: smaller;
}
#runtimetools-selection .runtimetools-selected-col {
padding: 0 15px 0 0;
min-width: 250px;
max-width: 250px;
}
#runtimetools-selection .runtimetools-results-col {
padding: 0 0 0 0;
min-width: 450px;
max-width: 650px;
}
#runtimetools-selection .runtimetool-results-items .card {
margin-bottom: 3px;
}
#runtimetools-selection.mobile .runtimetools-results-col {
min-width: 250px;
max-width: 450px;
}
#runtimetools-selection .runtimetools-results-col span.override {
float: right;
}
#runtimetools-selection .runtimetools-results-col span.override-fav {
float: right;
}
#runtimetools-selection .runtimetools-favorites-col {
padding: 0 0 0 15px;
min-width: 325px;
max-width: 350px;
}
#runtimetools-selection .runtimetools-favorites-col button {
width: 300px;
}
#runtimetools-selection.mobile .runtimetools-favorites-col {
display: none;
}
#runtimetools-selection .runtime-tool-option {
line-height: 35px;
}
#runtimetools-selection .tool-option-name {
display: inline-block;
min-width: 150px;
}
#runtimetools-selection .tool-option-select {
min-width: 100px;
}
#runtimetools-selection .tool-fav {
float: right;
}
.ces-content-root {
min-height: 100px;
max-height: calc(

View File

@@ -0,0 +1,412 @@
// Copyright (c) 2023, 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 $ from 'jquery';
import {options} from '../options.js';
import {CompilerInfo} from '../compiler.interfaces.js';
import {assert} from '../assert.js';
import {localStorage} from '../local.js';
import {
ConfiguredRuntimeTool,
ConfiguredRuntimeTools,
PossibleRuntimeTools,
RuntimeToolOption,
RuntimeToolOptions,
RuntimeToolType,
} from '../../types/execution/execution.interfaces.js';
const FAV_RUNTIMETOOLS_STORE_KEY = 'favruntimetools';
export type RuntimeToolsChangeCallback = () => void;
type FavRuntimeTool = {
name: RuntimeToolType;
options: string;
meta: string;
};
type FavRuntimeTools = FavRuntimeTool[];
export class RuntimeToolsWidget {
private domRoot: JQuery;
private popupDomRoot: JQuery<HTMLElement>;
private envVarsInput: JQuery<HTMLElement>;
private dropdownButton: JQuery;
private onChangeCallback: RuntimeToolsChangeCallback;
private configured: ConfiguredRuntimeTools = [];
private compiler: CompilerInfo | undefined;
private possibleTools: PossibleRuntimeTools;
constructor(domRoot: JQuery, dropdownButton: JQuery, onChangeCallback: RuntimeToolsChangeCallback) {
this.domRoot = domRoot;
this.popupDomRoot = $('#runtimetools-selection');
this.dropdownButton = dropdownButton;
this.envVarsInput = this.popupDomRoot.find('.envvars');
this.onChangeCallback = onChangeCallback;
this.possibleTools = [];
}
private loadStateFromUI(): ConfiguredRuntimeTools {
const tools: ConfiguredRuntimeTools = [];
const envOverrides = this.getEnvOverrides();
if (envOverrides.length > 0) {
tools.push({
name: RuntimeToolType.env,
options: envOverrides,
});
}
const selects = this.popupDomRoot.find('select');
for (const select of selects) {
const jqSelect = $(select);
const rawName = jqSelect.data('tool-name');
const optionName = jqSelect.data('tool-option');
const val = jqSelect.val();
if (val) {
const name = rawName as RuntimeToolType;
assert(name !== RuntimeToolType.env);
let tool = tools.find(tool => tool.name === name);
if (!tool) {
tool = {
name: name,
options: [],
};
tools.push(tool);
}
const option: RuntimeToolOption = {
name: optionName,
value: (val || '') as string,
};
tool.options.push(option);
}
}
return tools;
}
private optionsToString(options: RuntimeToolOptions): string {
return options.map(env => `${env.name}=${env.value}`).join('\n');
}
private stringToOptions(options: string): RuntimeToolOptions {
return options
.split('\n')
.map(env => {
const arr = env.split('=');
if (arr[0]) {
return {
name: arr[0],
value: arr[1],
};
} else {
return false;
}
})
.filter(Boolean) as RuntimeToolOptions;
}
private getEnvOverrides(): RuntimeToolOptions {
return this.stringToOptions(this.envVarsInput.val() as string);
}
private selectOverrideFromFave(event) {
const elem = $(event.target).parent();
const name = elem.data('ov-name');
const optionsStr = elem.data('ov-options');
const options = this.stringToOptions(optionsStr);
const tool = this.possibleTools.find(ov => ov.name === name);
if (tool) {
const configuredTools = this.loadStateFromUI();
let configuredTool = configuredTools.find(t => t.name === name);
if (!configuredTool) {
configuredTool = {
name: name,
options: [],
};
configuredTools.push(configuredTool);
}
configuredTool.options = options;
this.loadStateIntoUI(configuredTools);
}
}
private newFavoriteOverrideDiv(fave: FavRuntimeTool) {
const div = $('#overrides-favorite-tpl').children().clone();
const prefix = fave.name + ': ';
div.find('.overrides-name').html(prefix + fave.options.replace(/\n/g, ', '));
div.data('ov-name', fave.name);
div.data('ov-options', fave.options);
div.on('click', this.selectOverrideFromFave.bind(this));
return div;
}
private loadFavoritesIntoUI() {
const favoritesDiv = this.popupDomRoot.find('.runtimetools-favorites');
favoritesDiv.html('');
const faves = this.getFavorites();
for (const fave of faves) {
const div: any = this.newFavoriteOverrideDiv(fave);
favoritesDiv.append(div);
}
}
private addToFavorites(override: ConfiguredRuntimeTool) {
if (override.name === RuntimeToolType.env) return;
const faves = this.getFavorites();
const fave: FavRuntimeTool = {
name: override.name,
options: this.optionsToString(override.options),
meta: this.compiler?.baseName || this.compiler?.groupName || this.compiler?.name || this.compiler?.id || '',
};
faves.push(fave);
this.setFavorites(faves);
}
private removeFromFavorites(override: ConfiguredRuntimeTool) {
if (override.name === RuntimeToolType.env) return;
const overrideOptions = this.optionsToString(override.options);
const faves = this.getFavorites();
const faveIdx = faves.findIndex(f => f.name === override.name && f.options === overrideOptions);
if (faveIdx !== -1) {
faves.splice(faveIdx, 1);
this.setFavorites(faves);
}
}
private isAFavorite(override: ConfiguredRuntimeTool) {
if (override.name === RuntimeToolType.env) return false;
const overrideOptions = this.optionsToString(override.options);
const faves = this.getFavorites();
const fave = faves.find(f => f.name === override.name && f.options === overrideOptions);
return !!fave;
}
private cap(text: string) {
if (text.length > 0) {
return text[0].toUpperCase() + text.substring(1);
}
return '';
}
private loadStateIntoUI(configured: ConfiguredRuntimeTools) {
this.envVarsInput.val('');
for (const config of configured) {
if (config.name === RuntimeToolType.env) {
this.envVarsInput.val(this.optionsToString(config.options));
}
}
const container = this.popupDomRoot.find('.possible-runtimetools');
container.html('');
this.possibleTools = this.compiler?.possibleRuntimeTools || [];
for (const possibleTool of this.possibleTools) {
const card = $('#possible-runtime-tool').children().clone();
card.find('.tool-name').html(this.cap(possibleTool.name));
card.find('.tool-description').html(possibleTool.description);
const toolOptionsDiv = card.find('.tool-options');
const faveButton = card.find('.tool-fav-button');
faveButton.hide();
const faveStar = faveButton.find('.tool-fav-btn-icon');
const config = configured.find(c => c.name === possibleTool.name);
for (const toolOption of possibleTool.possibleOptions) {
const optionDiv = $('#possible-runtime-tool-option').children().clone();
optionDiv.attr('name', toolOption.name);
const display_text = this.cap(toolOption.name);
optionDiv.find('.tool-option-name').html(display_text);
const select = optionDiv.find('select');
select.data('tool-name', possibleTool.name);
select.data('tool-option', toolOption.name);
const option = $('<option />');
option.html('');
option.val('');
select.append(option);
for (const toolOptionValue of toolOption.possibleValues) {
const option = $('<option />');
option.html(toolOptionValue);
option.val(toolOptionValue);
if (config) {
const found = config.options.find(
configuredOption =>
configuredOption.name === toolOption.name && configuredOption.value === toolOptionValue,
);
if (found) option.attr('selected', 'selected');
}
select.append(option);
}
select.off('change').on('change', () => {
const name = possibleTool.name;
assert(name !== RuntimeToolType.env);
const configured = this.loadStateFromUI();
const configuredTool = configured.find(tool => tool.name === name);
if (configuredTool) {
if (this.isAFavorite(configuredTool)) {
faveStar.removeClass('far').addClass('fas');
} else {
faveStar.removeClass('fas').addClass('far');
}
if (configuredTool.options.length !== 0) {
faveButton.show();
} else {
faveButton.hide();
}
} else {
faveStar.removeClass('fas').addClass('far');
}
});
toolOptionsDiv.append(optionDiv);
}
if (config && this.isAFavorite(config)) {
faveStar.removeClass('far').addClass('fas');
}
faveButton.show();
faveButton.on('click', () => {
const name = possibleTool.name;
assert(name !== RuntimeToolType.env);
const configured = this.loadStateFromUI();
const configuredTool = configured.find(tool => tool.name === name);
if (configuredTool) {
if (this.isAFavorite(configuredTool)) {
this.removeFromFavorites(configuredTool);
faveStar.removeClass('fas').addClass('far');
} else {
this.addToFavorites(configuredTool);
faveStar.removeClass('far').addClass('fas');
}
}
this.loadFavoritesIntoUI();
});
container.append(card);
}
this.loadFavoritesIntoUI();
}
set(configured: ConfiguredRuntimeTools) {
this.configured = configured;
this.updateButton();
}
setDefaults() {
this.configured = [];
this.updateButton();
}
setCompiler(compilerId: string, languageId?: string) {
this.compiler = options.compilers.find(c => c.id === compilerId);
}
get(): ConfiguredRuntimeTools | undefined {
if (this.compiler) {
return this.configured;
} else {
return undefined;
}
}
private getFavorites(): FavRuntimeTools {
return JSON.parse(localStorage.get(FAV_RUNTIMETOOLS_STORE_KEY, '[]'));
}
private setFavorites(faves: FavRuntimeTools) {
localStorage.set(FAV_RUNTIMETOOLS_STORE_KEY, JSON.stringify(faves));
}
private updateButton() {
const selected = this.get();
if (selected && selected.length > 0) {
this.dropdownButton
.addClass('btn-success')
.removeClass('btn-light')
.prop(
'title',
'Current tools:\n' +
selected
.map(ov => {
return '- ' + ov.name;
})
.join('\n'),
);
} else {
this.dropdownButton.removeClass('btn-success').addClass('btn-light').prop('title', 'Overrides');
}
}
show() {
this.loadStateIntoUI(this.configured);
const lastOverrides = JSON.stringify(this.configured);
const popup = this.popupDomRoot.modal();
// popup is shared, so clear the events first
popup.off('hidden.bs.modal').on('hidden.bs.modal', () => {
this.configured = this.loadStateFromUI();
const newOverrides = JSON.stringify(this.configured);
if (lastOverrides !== newOverrides) {
this.updateButton();
this.onChangeCallback();
}
});
}
}

View File

@@ -197,7 +197,7 @@ ${' '.repeat(65530)}x
ret
`;
const output = parser.process(asm, filters);
parseInt(unwrap(output.parsingTime)).should.be.lessThan(200); // reported as ms, generous timeout for ci runner
parseInt(unwrap(output.parsingTime)).should.be.lessThan(500); // reported as ms, generous timeout for ci runner
});
});
@@ -226,6 +226,6 @@ ${' '.repeat(65530)}x
ret
`;
const output = parser.process(asm, filters);
parseInt(unwrap(output.parsingTime)).should.be.lessThan(200); // reported as ms, generous timeout for ci runner
parseInt(unwrap(output.parsingTime)).should.be.lessThan(500); // reported as ms, generous timeout for ci runner
});
});

View File

@@ -23,7 +23,7 @@
// POSSIBILITY OF SUCH DAMAGE.
import './utils.js';
import {DescribeInstancesCommand, EC2} from '@aws-sdk/client-ec2';
import {DescribeInstancesCommand, EC2, Instance} from '@aws-sdk/client-ec2';
import {GetParametersCommand, SSM} from '@aws-sdk/client-ssm';
import {mockClient} from 'aws-sdk-client-mock';
@@ -69,7 +69,7 @@ describe('AWS instance fetcher tests', () => {
mockEC2.on(DescribeInstancesCommand).resolves({
Reservations: [
{
Instances: [instanceA, instanceB, instanceC, instanceD],
Instances: [instanceA, instanceB, instanceC, instanceD] as Instance[],
},
],
});

365
test/cfg-cases/cfg-llvmir.invoke.json generated Normal file
View File

@@ -0,0 +1,365 @@
{
"asm": [
{
"text": "define dso_local noundef i32 @f(int)(i32 noundef %n) personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {",
"scope": "!10",
"source": {
"file": null,
"line": 3
}
},
{
"text": "entry:"
},
{
"text": " %retval = alloca i32, align 4"
},
{
"text": " %n.addr = alloca i32, align 4"
},
{
"text": " %a = alloca i32, align 4"
},
{
"text": " %exn.slot = alloca i8*, align 8"
},
{
"text": " %ehselector.slot = alloca i32, align 4"
},
{
"text": " store i32 %n, i32* %n.addr, align 4"
},
{
"text": " %0 = load i32, i32* %n.addr, align 4",
"scope": "!21",
"source": {
"file": null,
"line": 6,
"column": 19
}
},
{
"text": " %call = invoke noundef i32 @g(int)(i32 noundef %0)"
},
{
"text": " to label %invoke.cont unwind label %lpad",
"scope": "!22",
"source": {
"file": null,
"line": 6,
"column": 17
}
},
{
"text": ""
},
{
"text": "invoke.cont:"
},
{
"text": " store i32 %call, i32* %a, align 4",
"scope": "!20",
"source": {
"file": null,
"line": 6,
"column": 13
}
},
{
"text": " %1 = load i32, i32* %a, align 4",
"scope": "!23",
"source": {
"file": null,
"line": 7,
"column": 16
}
},
{
"text": " store i32 %1, i32* %retval, align 4",
"scope": "!24",
"source": {
"file": null,
"line": 7,
"column": 9
}
},
{
"text": " br label %return",
"scope": "!24",
"source": {
"file": null,
"line": 7,
"column": 9
}
},
{
"text": ""
},
{
"text": "lpad:"
},
{
"text": " %2 = landingpad { i8*, i32 }"
},
{
"text": " catch i8* null",
"scope": "!25",
"source": {
"file": null,
"line": 13,
"column": 1
}
},
{
"text": " %3 = extractvalue { i8*, i32 } %2, 0",
"scope": "!25",
"source": {
"file": null,
"line": 13,
"column": 1
}
},
{
"text": " store i8* %3, i8** %exn.slot, align 8",
"scope": "!25",
"source": {
"file": null,
"line": 13,
"column": 1
}
},
{
"text": " %4 = extractvalue { i8*, i32 } %2, 1",
"scope": "!25",
"source": {
"file": null,
"line": 13,
"column": 1
}
},
{
"text": " store i32 %4, i32* %ehselector.slot, align 4",
"scope": "!25",
"source": {
"file": null,
"line": 13,
"column": 1
}
},
{
"text": " br label %catch",
"scope": "!25",
"source": {
"file": null,
"line": 13,
"column": 1
}
},
{
"text": ""
},
{
"text": "catch:"
},
{
"text": " %exn = load i8*, i8** %exn.slot, align 8",
"scope": "!26",
"source": {
"file": null,
"line": 8,
"column": 5
}
},
{
"text": " %5 = call i8* @__cxa_begin_catch(i8* %exn) #4",
"scope": "!26",
"source": {
"file": null,
"line": 8,
"column": 5
}
},
{
"text": " %6 = load i32, i32* %n.addr, align 4",
"scope": "!27",
"source": {
"file": null,
"line": 11,
"column": 16
}
},
{
"text": " store i32 %6, i32* %retval, align 4",
"scope": "!29",
"source": {
"file": null,
"line": 11,
"column": 9
}
},
{
"text": " call void @__cxa_end_catch()",
"scope": "!30",
"source": {
"file": null,
"line": 12,
"column": 5
}
},
{
"text": " br label %return"
},
{
"text": ""
},
{
"text": "try.cont:"
},
{
"text": " call void @llvm.trap()",
"scope": "!30",
"source": {
"file": null,
"line": 12,
"column": 5
}
},
{
"text": " unreachable",
"scope": "!30",
"source": {
"file": null,
"line": 12,
"column": 5
}
},
{
"text": ""
},
{
"text": "return:"
},
{
"text": " %7 = load i32, i32* %retval, align 4",
"scope": "!31",
"source": {
"file": null,
"line": 13,
"column": 1
}
},
{
"text": " ret i32 %7",
"scope": "!31",
"source": {
"file": null,
"line": 13,
"column": 1
}
},
{
"text": "}"
},
{
"text": ""
},
{
"text": "declare void @llvm.dbg.declare(metadata, metadata, metadata) #1"
},
{
"text": ""
},
{
"text": "declare noundef i32 @g(int)(i32 noundef) #2"
},
{
"text": ""
},
{
"text": "declare i32 @__gxx_personality_v0(...)"
},
{
"text": ""
},
{
"text": "declare i8* @__cxa_begin_catch(i8*)"
},
{
"text": ""
},
{
"text": "declare void @__cxa_end_catch()"
},
{
"text": ""
},
{
"text": "declare void @llvm.trap() #3"
},
{
"text": ""
}
],
"cfg": {
"f(int)(i32 noundef %n) personality i8* bitcast (i32 ": {
"nodes": [
{
"id": "f(int)(i32 noundef %n) personality i8* bitcast (i32 ",
"label": "f(int)(i32 noundef %n) personality i8* bitcast (i32 :\n %retval = alloca i32, align 4\n %n.addr = alloca i32, align 4\n %a = alloca i32, align 4\n %exn.slot = alloca i8*, align 8\n %ehselector.slot = alloca i32, align 4\n store i32 %n, i32* %n.addr, align 4\n %0 = load i32, i32* %n.addr, align 4\n %call = invoke noundef i32 @g(int)(i32 noundef %0)\n to label %invoke.cont unwind label %lpad"
},
{
"id": "invoke.cont",
"label": "invoke.cont:\n store i32 %call, i32* %a, align 4\n %1 = load i32, i32* %a, align 4\n store i32 %1, i32* %retval, align 4\n br label %return"
},
{
"id": "lpad",
"label": "lpad:\n %2 = landingpad { i8*, i32 }\n catch i8* null\n %3 = extractvalue { i8*, i32 } %2, 0\n store i8* %3, i8** %exn.slot, align 8\n %4 = extractvalue { i8*, i32 } %2, 1\n store i32 %4, i32* %ehselector.slot, align 4\n br label %catch"
},
{
"id": "catch",
"label": "catch:\n %exn = load i8*, i8** %exn.slot, align 8\n %5 = call i8* @__cxa_begin_catch(i8* %exn) #4\n %6 = load i32, i32* %n.addr, align 4\n store i32 %6, i32* %retval, align 4\n call void @__cxa_end_catch()\n br label %return"
},
{
"id": "try.cont",
"label": "try.cont:\n call void @llvm.trap()\n unreachable"
},
{
"id": "return",
"label": "return:\n %7 = load i32, i32* %retval, align 4\n ret i32 %7"
}
],
"edges": [
{
"from": "f(int)(i32 noundef %n) personality i8* bitcast (i32 ",
"to": "invoke.cont",
"arrows": "to",
"color": "green"
},
{
"from": "f(int)(i32 noundef %n) personality i8* bitcast (i32 ",
"to": "lpad",
"arrows": "to",
"color": "grey"
},
{
"from": "invoke.cont",
"to": "return",
"arrows": "to",
"color": "blue"
},
{
"from": "lpad",
"to": "catch",
"arrows": "to",
"color": "blue"
},
{
"from": "catch",
"to": "return",
"arrows": "to",
"color": "blue"
}
]
}
}
}

352
test/cfg-cases/cfg-llvmir.loop.json generated Normal file
View File

@@ -0,0 +1,352 @@
{
"asm": [
{
"text": "define dso_local noundef i32 @foo(int*, int*, int)(i32* noundef %a, i32* noundef %b, i32 noundef %size) {",
"scope": "!10",
"source": {
"file": null,
"line": 2
}
},
{
"text": "entry:"
},
{
"text": " %a.addr = alloca i32*, align 8"
},
{
"text": " %b.addr = alloca i32*, align 8"
},
{
"text": " %size.addr = alloca i32, align 4"
},
{
"text": " %i = alloca i32, align 4"
},
{
"text": " store i32* %a, i32** %a.addr, align 8"
},
{
"text": " store i32* %b, i32** %b.addr, align 8"
},
{
"text": " store i32 %size, i32* %size.addr, align 4"
},
{
"text": " store i32 0, i32* %i, align 4",
"scope": "!25",
"source": {
"file": null,
"line": 3,
"column": 13
}
},
{
"text": " br label %for.cond",
"scope": "!26",
"source": {
"file": null,
"line": 3,
"column": 9
}
},
{
"text": ""
},
{
"text": "for.cond:"
},
{
"text": " %0 = load i32, i32* %i, align 4",
"scope": "!27",
"source": {
"file": null,
"line": 3,
"column": 18
}
},
{
"text": " %1 = load i32, i32* %size.addr, align 4",
"scope": "!29",
"source": {
"file": null,
"line": 3,
"column": 20
}
},
{
"text": " %cmp = icmp slt i32 %0, %1",
"scope": "!30",
"source": {
"file": null,
"line": 3,
"column": 19
}
},
{
"text": " br i1 %cmp, label %for.body, label %for.end",
"scope": "!31",
"source": {
"file": null,
"line": 3,
"column": 5
}
},
{
"text": ""
},
{
"text": "for.body:"
},
{
"text": " %2 = load i32*, i32** %b.addr, align 8",
"scope": "!32",
"source": {
"file": null,
"line": 4,
"column": 16
}
},
{
"text": " %3 = load i32, i32* %i, align 4",
"scope": "!33",
"source": {
"file": null,
"line": 4,
"column": 18
}
},
{
"text": " %idxprom = sext i32 %3 to i64",
"scope": "!32",
"source": {
"file": null,
"line": 4,
"column": 16
}
},
{
"text": " %arrayidx = getelementptr inbounds i32, i32* %2, i64 %idxprom",
"scope": "!32",
"source": {
"file": null,
"line": 4,
"column": 16
}
},
{
"text": " %4 = load i32, i32* %arrayidx, align 4",
"scope": "!32",
"source": {
"file": null,
"line": 4,
"column": 16
}
},
{
"text": " %add = add nsw i32 %4, 12",
"scope": "!34",
"source": {
"file": null,
"line": 4,
"column": 21
}
},
{
"text": " %5 = load i32*, i32** %a.addr, align 8",
"scope": "!35",
"source": {
"file": null,
"line": 4,
"column": 9
}
},
{
"text": " %6 = load i32, i32* %i, align 4",
"scope": "!36",
"source": {
"file": null,
"line": 4,
"column": 11
}
},
{
"text": " %idxprom1 = sext i32 %6 to i64",
"scope": "!35",
"source": {
"file": null,
"line": 4,
"column": 9
}
},
{
"text": " %arrayidx2 = getelementptr inbounds i32, i32* %5, i64 %idxprom1",
"scope": "!35",
"source": {
"file": null,
"line": 4,
"column": 9
}
},
{
"text": " store i32 %add, i32* %arrayidx2, align 4",
"scope": "!37",
"source": {
"file": null,
"line": 4,
"column": 14
}
},
{
"text": " br label %for.inc",
"scope": "!35",
"source": {
"file": null,
"line": 4,
"column": 9
}
},
{
"text": ""
},
{
"text": "for.inc:"
},
{
"text": " %7 = load i32, i32* %i, align 4",
"scope": "!38",
"source": {
"file": null,
"line": 3,
"column": 26
}
},
{
"text": " %inc = add nsw i32 %7, 1",
"scope": "!38",
"source": {
"file": null,
"line": 3,
"column": 26
}
},
{
"text": " store i32 %inc, i32* %i, align 4",
"scope": "!38",
"source": {
"file": null,
"line": 3,
"column": 26
}
},
{
"text": " br label %for.cond",
"scope": "!39",
"source": {
"file": null,
"line": 3,
"column": 5
}
},
{
"text": ""
},
{
"text": "for.end:"
},
{
"text": " call void @llvm.trap()",
"scope": "!41",
"source": {
"file": null,
"line": 4,
"column": 23
}
},
{
"text": " unreachable",
"scope": "!41",
"source": {
"file": null,
"line": 4,
"column": 23
}
},
{
"text": "}"
},
{
"text": ""
},
{
"text": "declare void @llvm.dbg.declare(metadata, metadata, metadata) #1"
},
{
"text": ""
},
{
"text": "declare void @llvm.trap() #2"
},
{
"text": ""
}
],
"cfg": {
"foo(int*, int*, int)": {
"nodes": [
{
"id": "foo(int*, int*, int)",
"label": "foo(int*, int*, int):\n %a.addr = alloca i32*, align 8\n %b.addr = alloca i32*, align 8\n %size.addr = alloca i32, align 4\n %i = alloca i32, align 4\n store i32* %a, i32** %a.addr, align 8\n store i32* %b, i32** %b.addr, align 8\n store i32 %size, i32* %size.addr, align 4\n store i32 0, i32* %i, align 4\n br label %for.cond"
},
{
"id": "for.cond",
"label": "for.cond:\n %0 = load i32, i32* %i, align 4\n %1 = load i32, i32* %size.addr, align 4\n %cmp = icmp slt i32 %0, %1\n br i1 %cmp, label %for.body, label %for.end"
},
{
"id": "for.body",
"label": "for.body:\n %2 = load i32*, i32** %b.addr, align 8\n %3 = load i32, i32* %i, align 4\n %idxprom = sext i32 %3 to i64\n %arrayidx = getelementptr inbounds i32, i32* %2, i64 %idxprom\n %4 = load i32, i32* %arrayidx, align 4\n %add = add nsw i32 %4, 12\n %5 = load i32*, i32** %a.addr, align 8\n %6 = load i32, i32* %i, align 4\n %idxprom1 = sext i32 %6 to i64\n %arrayidx2 = getelementptr inbounds i32, i32* %5, i64 %idxprom1\n store i32 %add, i32* %arrayidx2, align 4\n br label %for.inc"
},
{
"id": "for.inc",
"label": "for.inc:\n %7 = load i32, i32* %i, align 4\n %inc = add nsw i32 %7, 1\n store i32 %inc, i32* %i, align 4\n br label %for.cond"
},
{
"id": "for.end",
"label": "for.end:\n call void @llvm.trap()\n unreachable"
}
],
"edges": [
{
"from": "foo(int*, int*, int)",
"to": "for.cond",
"arrows": "to",
"color": "blue"
},
{
"from": "for.cond",
"to": "for.body",
"arrows": "to",
"color": "green"
},
{
"from": "for.cond",
"to": "for.end",
"arrows": "to",
"color": "red"
},
{
"from": "for.body",
"to": "for.inc",
"arrows": "to",
"color": "blue"
},
{
"from": "for.inc",
"to": "for.cond",
"arrows": "to",
"color": "blue"
}
]
}
}
}

View File

@@ -26,7 +26,7 @@ import * as cfg from '../lib/cfg/cfg.js';
import {fs, makeFakeCompilerInfo, path, resolvePathFromTestRoot} from './utils.js';
async function DoCfgTest(cfgArg, filename) {
async function DoCfgTest(cfgArg, filename, isLlvmIr = false) {
const contents = await fs.readJson(filename, 'utf8');
const structure = cfg.generateStructure(
makeFakeCompilerInfo({
@@ -34,7 +34,7 @@ async function DoCfgTest(cfgArg, filename) {
version: cfgArg,
}),
contents.asm,
false,
isLlvmIr,
);
structure.should.deep.equal(contents.cfg);
}
@@ -69,4 +69,12 @@ describe('Cfg test cases', () => {
});
}
});
describe('llvmir', () => {
for (const filename of files.filter(x => x.includes('llvmir'))) {
it(filename, async () => {
await DoCfgTest('clang', path.join(testcasespath, filename), true);
});
}
});
});

View File

@@ -29,6 +29,7 @@ import {
GCCParser,
ICCParser,
PascalParser,
TableGenParser,
VCParser,
} from '../../lib/compilers/argument-parsers.js';
import {FakeCompiler} from '../../lib/compilers/fake-for-test.js';
@@ -272,3 +273,28 @@ describe('ICC argument parser', () => {
]);
});
});
describe('TableGen argument parser', () => {
it('Should extract actions', () => {
const lines = [
'USAGE: llvm-tblgen [options] <input file>',
'',
'OPTIONS:',
'',
'General options:',
'',
' -D <macro name> - Name of the macro...',
' Action to perform:',
' --gen-attrs - Generate attributes',
' --print-detailed-records - Print full details...',
' --gen-x86-mnemonic-tables - Generate X86...',
' --no-warn-on-unused-template-args - Disable...',
];
const actions = TableGenParser.extractPossibleActions(lines);
actions.should.deep.equal([
{name: 'gen-attrs: Generate attributes', value: '--gen-attrs'},
{name: 'print-detailed-records: Print full details...', value: '--print-detailed-records'},
{name: 'gen-x86-mnemonic-tables: Generate X86...', value: '--gen-x86-mnemonic-tables'},
]);
});
});

View File

@@ -363,8 +363,9 @@ describe('Compiler tests', () => {
res.body.input.options.should.deep.equals({
backendOptions: {},
bypassCache: BypassCache.None,
executionParameters: {
executeParameters: {
args: [],
runtimeTools: [],
stdin: '',
},
filters: {

View File

@@ -19,6 +19,8 @@
import * as stream from 'stream';
import {YAMLParseError} from 'yaml';
import {LLVMOptTransformer} from '../lib/llvm-opt-transformer.js';
describe('LLVM opt transformer', () => {
@@ -94,4 +96,22 @@ Args:
},
]);
});
it('should error with unparseable yaml data', async () => {
const doc = `--- !Analysis
broken: not a yaml doc
broken: duplicate key makes this invalid
...
`;
const readString = new stream.PassThrough();
readString.push(doc);
readString.end();
return (async () => {
const optStream = stream.pipeline(readString, new LLVMOptTransformer(), res => {
return res;
});
for await (const _ of optStream) {
// just consume
}
})().should.be.rejectedWith(YAMLParseError);
});
});

View File

@@ -12,12 +12,14 @@
"options": "-O3",
"filters": {
"binary": false,
"binaryObject": false,
"commentOnly": true,
"demangle": true,
"directives": true,
"execute": false,
"intel": true,
"labels": true,
"libraryCode": false,
"debugCalls": false,
"trim": false
},
@@ -30,12 +32,14 @@
"options": "-O2",
"filters": {
"binary": false,
"binaryObject": false,
"commentOnly": true,
"demangle": true,
"directives": true,
"execute": false,
"intel": true,
"labels": true,
"libraryCode": false,
"debugCalls": false,
"trim": false
},

View File

@@ -16,6 +16,7 @@
"intel": true,
"labels": true,
"debugCalls": false,
"libraryCode": false,
"trim": false
},
"id": "g92",
@@ -43,12 +44,14 @@
"tools": [],
"filters": {
"binary": false,
"binaryObject": false,
"commentOnly": true,
"demangle": true,
"directives": true,
"execute": false,
"intel": true,
"labels": true,
"libraryCode": false,
"debugCalls": false,
"trim": false
}

View File

@@ -18,6 +18,7 @@
"execute": false,
"intel": true,
"labels": true,
"libraryCode": true,
"debugCalls": false,
"trim": false
},
@@ -39,12 +40,14 @@
"options": "",
"filters": {
"binary": false,
"binaryObject": false,
"commentOnly": true,
"demangle": true,
"directives": true,
"execute": false,
"intel": true,
"labels": true,
"libraryCode": false,
"debugCalls": false,
"trim": false
},

View File

@@ -18,6 +18,7 @@
"execute": true,
"intel": true,
"labels": true,
"libraryCode": true,
"debugCalls": false,
"trim": true
},

View File

@@ -72,6 +72,7 @@
"execute": true,
"intel": true,
"labels": true,
"libraryCode": true,
"debugCalls": false,
"trim": false
},

View File

@@ -111,12 +111,14 @@
"options": "-g -O3 -flto",
"filters": {
"binary": false,
"binaryObject": false,
"commentOnly": true,
"demangle": true,
"directives": true,
"execute": false,
"intel": true,
"labels": true,
"libraryCode": false,
"debugCalls": false,
"trim": false
},

View File

@@ -166,12 +166,14 @@
"compiler": "g103",
"filters": {
"binary": true,
"binaryObject": false,
"commentOnly": true,
"demangle": true,
"directives": true,
"execute": false,
"intel": true,
"labels": true,
"libraryCode": false,
"debugCalls": false,
"trim": false
},

View File

@@ -100,6 +100,7 @@
"execute": false,
"intel": true,
"labels": true,
"libraryCode": true,
"debugCalls": false,
"trim": false
},

View File

@@ -29,7 +29,7 @@ import type {PPOptions} from '../../static/panes/pp-view.interfaces.js';
import {suCodeEntry} from '../../static/panes/stack-usage-view.interfaces.js';
import {ParsedAsmResultLine} from '../asmresult/asmresult.interfaces.js';
import {CompilerInfo} from '../compiler.interfaces.js';
import {BasicExecutionResult} from '../execution/execution.interfaces.js';
import {BasicExecutionResult, ConfiguredRuntimeTools} from '../execution/execution.interfaces.js';
import {ParseFiltersAndOutputOptions} from '../features/filters.interfaces.js';
import {ResultLine} from '../resultline/resultline.interfaces.js';
import {Artifact, ToolResult} from '../tool.interfaces.js';
@@ -46,8 +46,9 @@ export type ActiveTools = {
};
export type ExecutionParams = {
args: string[] | string;
stdin: string;
args?: string[] | string;
stdin?: string;
runtimeTools?: ConfiguredRuntimeTools;
};
export type CompileChildLibraries = {

View File

@@ -30,6 +30,7 @@ export enum CompilerOverrideType {
env = 'env',
edition = 'edition',
stdver = 'stdver',
action = 'action',
}
export type CompilerOverrideTypes = Set<CompilerOverrideType>;

View File

@@ -25,6 +25,7 @@
import {BypassCache} from './compilation/compilation.interfaces.js';
import {AllCompilerOverrideOptions} from './compilation/compiler-overrides.interfaces.js';
import {ICompilerArguments} from './compiler-arguments.interfaces.js';
import {PossibleRuntimeTools} from './execution/execution.interfaces.js';
import {InstructionSet} from './instructionsets.js';
import {Language, LanguageKey} from './languages.interfaces.js';
import {Library} from './libraries/libraries.interfaces.js';
@@ -124,6 +125,7 @@ export type CompilerInfo = {
path: string;
};
possibleOverrides?: AllCompilerOverrideOptions;
possibleRuntimeTools?: PossibleRuntimeTools;
disabledFilters: string[];
optArg?: string;
stackUsageArg?: string;
@@ -148,7 +150,7 @@ export type PreliminaryCompilerInfo = Omit<CompilerInfo, 'version' | 'fullVersio
export interface ICompiler {
possibleArguments: ICompilerArguments;
lang: Language;
compile(source, options, backendOptions, filters, bypassCache, tools, executionParameters, libraries, files);
compile(source, options, backendOptions, filters, bypassCache, tools, executeParameters, libraries, files);
cmake(files, key, bypassCache: BypassCache);
initialise(mtime: Date, clientOptions, isPrediscovered: boolean);
getInfo(): CompilerInfo;

View File

@@ -31,9 +31,41 @@ export type BasicExecutionResult = {
timedOut: boolean;
};
export enum RuntimeToolType {
env = 'env',
heaptrack = 'heaptrack',
}
export type RuntimeToolOption = {
name: string;
value: string;
};
export type PossibleRuntimeToolOption = {
name: string;
possibleValues: string[];
};
export type PossibleRuntimeTool = {
name: RuntimeToolType;
description: string;
possibleOptions: PossibleRuntimeToolOption[];
};
export type PossibleRuntimeTools = PossibleRuntimeTool[];
export type RuntimeToolOptions = RuntimeToolOption[];
export type ConfiguredRuntimeTool = {
name: RuntimeToolType;
options: RuntimeToolOptions;
};
export type ConfiguredRuntimeTools = ConfiguredRuntimeTool[];
export type ExecutableExecutionOptions = {
args: string[];
stdin: string;
ldPath: string[];
env: any;
env: Record<string, string>;
runtimeTools?: ConfiguredRuntimeTools;
};

View File

@@ -78,6 +78,7 @@ export type LanguageKey =
| 'scala'
| 'solidity'
| 'swift'
| 'tablegen'
| 'toit'
| 'typescript'
| 'v'

View File

@@ -58,6 +58,7 @@ export enum ArtifactType {
smsrom = 'smsrom',
timetrace = 'timetracejson',
c64prg = 'c64prg',
heaptracktxt = 'heaptracktxt',
}
export type Artifact = {

View File

@@ -25,6 +25,8 @@ include library-selection
include overrides-selection
include runtimetools-selection
include timing
include jsbeebemu

Some files were not shown because too many files have changed in this diff Show More