diff options
author | Jeremy Rifkin <51220084+jeremy-rifkin@users.noreply.github.com> | 2023-06-17 19:41:26 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-06-17 19:41:26 -0400 |
commit | 42ea9cc128ced1061f7f15c003d9c6b271367b2b (patch) | |
tree | 557ee99f4cc6c3ad708f6f1cdbcfd9666903d09f | |
parent | da064506f30038f4df217bdccccf90d089f0d591 (diff) | |
download | compiler-explorer-gh-7811.tar.gz compiler-explorer-gh-7811.zip |
General work on solidifying the instruction set system (#5156)gh-7811
Mainly type work
-rw-r--r-- | etc/scripts/docenizers/docenizer-arm.py | 4 | ||||
-rw-r--r-- | lib/assert.ts | 16 | ||||
-rw-r--r-- | lib/cfg/cfg.ts | 2 | ||||
-rw-r--r-- | lib/compiler-finder.ts | 10 | ||||
-rw-r--r-- | lib/global.ts | 33 | ||||
-rw-r--r-- | lib/instructionsets.ts | 68 | ||||
-rw-r--r-- | static/panes/compiler.ts | 18 | ||||
-rw-r--r-- | static/panes/device-view.ts | 6 | ||||
-rw-r--r-- | types/compiler.interfaces.ts | 3 | ||||
-rw-r--r-- | types/features/assembly-documentation.interfaces.ts | 16 | ||||
-rw-r--r-- | types/instructionsets.ts | 61 |
11 files changed, 190 insertions, 47 deletions
diff --git a/etc/scripts/docenizers/docenizer-arm.py b/etc/scripts/docenizers/docenizer-arm.py index cee8e1b51..dbf9c8a24 100644 --- a/etc/scripts/docenizers/docenizer-arm.py +++ b/etc/scripts/docenizers/docenizer-arm.py @@ -32,7 +32,7 @@ STRIP_SUFFIX = re.compile(r'\s*(\(.*\))?\s*(--.*)?') FLDMX_RE = re.compile(r'^(FLDM)(\*)(X)') FLDMX_SET = set(['DB', 'IA']) -#arm64 +#aarch64 CONDITION_RE = re.compile(r'^([A-Z][A-Z0-9]*\.?)(cond|<cc>)()') CONDITION_SET = set(['EQ', 'NE', 'CS', 'CC', 'MI', 'PL', 'VS', 'VC', 'HI', 'LS', 'GE', 'LT', 'GT', 'LE', 'AL']) FRINT_RE = re.compile(r'^(FRINT)(<r>)()') @@ -184,7 +184,7 @@ def docenizer(): print("Called with: {}".format(args)) with open(args.configfile) as f: - config = Config(**json.load(f)) + config = Config(**json.load(f)) print("Use configs: {}".format(json.dumps(config, default=lambda o: o.__dict__))) # If we don't have the html folder already... if not os.path.isdir(os.path.join(args.inputfolder, config.archive.subdir)): diff --git a/lib/assert.ts b/lib/assert.ts index 204d0c8da..658034bb7 100644 --- a/lib/assert.ts +++ b/lib/assert.ts @@ -28,9 +28,19 @@ import path from 'path'; import {parse} from './stacktrace.js'; import {isString} from './common-utils.js'; -function check_path(parent: string, directory: string) { +const filePrefix = 'file://'; + +function removeFileProtocol(path: string) { + if (path.startsWith(filePrefix)) { + return path.slice(filePrefix.length); + } else { + return path; + } +} + +function check_path(parent: URL, directory: string) { // https://stackoverflow.com/a/45242825/15675011 - const relative = path.relative(parent, directory); + const relative = path.relative(parent.pathname, directory); if (relative && !relative.startsWith('..') && !path.isAbsolute(relative)) { return relative; } else { @@ -45,7 +55,7 @@ function get_diagnostic() { const invoker_frame = trace[3]; if (invoker_frame.fileName && invoker_frame.lineNumber) { // Just out of an abundance of caution... - const relative = check_path(global.ce_base_directory, invoker_frame.fileName); + const relative = check_path(global.ce_base_directory, removeFileProtocol(invoker_frame.fileName)); if (relative) { try { const file = fs.readFileSync(invoker_frame.fileName, 'utf8'); diff --git a/lib/cfg/cfg.ts b/lib/cfg/cfg.ts index 4053e1235..b74140f04 100644 --- a/lib/cfg/cfg.ts +++ b/lib/cfg/cfg.ts @@ -54,7 +54,7 @@ export function generateStructure(compilerInfo: CompilerInfo, asmArr: ResultLine // figure out what we're working with const isa = isLlvmIr ? 'llvmir' : compilerInfo.instructionSet; const compilerGroup = isLlvmIr ? 'llvmir' : isLLVMBased(compilerInfo) ? 'clang' : compilerInfo.group; - const instructionSet = new (getInstructionSetByKey(isa))(); + const instructionSet = new (getInstructionSetByKey(isa ?? 'base'))(); const parser = new (getParserByKey(compilerGroup))(instructionSet); const code = parser.filterData(asmArr); diff --git a/lib/compiler-finder.ts b/lib/compiler-finder.ts index d7deec7c8..6a4a1b134 100644 --- a/lib/compiler-finder.ts +++ b/lib/compiler-finder.ts @@ -34,7 +34,7 @@ import urljoin from 'url-join'; import type {CompilerInfo, PreliminaryCompilerInfo} from '../types/compiler.interfaces.js'; import type {Language, LanguageKey} from '../types/languages.interfaces.js'; -import {unwrap} from './assert.js'; +import {unwrap, assert} from './assert.js'; import {InstanceFetcher} from './aws.js'; import {CompileHandler} from './handlers/compile.js'; import {logger} from './logger.js'; @@ -43,6 +43,7 @@ import {CompilerProps} from './properties.js'; import type {PropertyGetter} from './properties.interfaces.js'; import {basic_comparator, remove} from './common-utils.js'; import {getPossibleGccToolchainsFromCompilerInfo} from './toolchain-utils.js'; +import {InstructionSet, InstructionSetsList} from '../types/instructionsets.js'; const sleep = promisify(setTimeout); @@ -258,6 +259,11 @@ export class CompilerFinder { })(); const exe = props('exe', compilerId); const exePath = path.dirname(exe); + const instructionSet = props<string | number>('instructionSet', '').toString() as InstructionSet | ''; + assert( + instructionSet === '' || InstructionSetsList.includes(instructionSet), + `Unexpected instruction set ${instructionSet} ${compilerId}`, + ); const compilerInfo: PreliminaryCompilerInfo = { id: compilerId, exe: exe, @@ -281,7 +287,7 @@ export class CompilerFinder { objdumperArgs: splitArrayPropsOrEmpty('objdumperArgs', '|'), intelAsm: props('intelAsm', ''), supportsAsmDocs: props('supportsAsmDocs', true), - instructionSet: props<string | number>('instructionSet', '').toString(), + instructionSet: instructionSet === '' ? null : instructionSet, needsMulti: !!props('needsMulti', true), adarts: props('adarts', ''), supportsDemangle: !!demangler, diff --git a/lib/global.ts b/lib/global.ts new file mode 100644 index 000000000..9ab786f66 --- /dev/null +++ b/lib/global.ts @@ -0,0 +1,33 @@ +// 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. + +declare global { + // var is required + // eslint-disable-next-line no-var + var ce_base_directory: URL; +} + +// Necessary because we're not exporting any actual symbols from this file +// See https://www.typescriptlang.org/docs/handbook/declaration-files/templates/global-modifying-module-d-ts.html +export {}; diff --git a/lib/instructionsets.ts b/lib/instructionsets.ts index 1b101b66a..4471d01be 100644 --- a/lib/instructionsets.ts +++ b/lib/instructionsets.ts @@ -22,14 +22,16 @@ // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. +import {InstructionSet} from '../types/instructionsets.js'; + type InstructionSetMethod = { target: string[]; path: string[]; }; export class InstructionSets { - private defaultInstructionset = 'amd64'; - private supported: Record<string, InstructionSetMethod> = {}; + private defaultInstructionset: InstructionSet = 'amd64'; + private supported: Record<InstructionSet, InstructionSetMethod>; constructor() { this.supported = { @@ -85,7 +87,7 @@ export class InstructionSets { target: ['rv32'], path: ['/riscv32-'], }, - sh : { + sh: { target: ['sh'], path: ['/sh-'], }, @@ -109,7 +111,7 @@ export class InstructionSets { target: ['wasm64'], path: [], }, - xstensa: { + xtensa: { target: ['xtensa'], path: ['/xtensa-'], }, @@ -121,14 +123,60 @@ export class InstructionSets { target: [], path: [], }, + java: { + target: [], + path: [], + }, + llvm: { + target: [], + path: [], + }, + python: { + target: [], + path: [], + }, + ptx: { + target: [], + path: [], + }, + amd64: { + target: [], + path: [], + }, + evm: { + target: [], + path: [], + }, + mos6502: { + target: [], + path: [], + }, + sass: { + target: [], + path: [], + }, + beam: { + target: [], + path: [], + }, + hook: { + target: [], + path: [], + }, + spirv: { + target: [], + path: [], + }, }; } - async getCompilerInstructionSetHint(compilerArch: string | boolean, exe: string): Promise<string> { + async getCompilerInstructionSetHint(compilerArch: string | boolean, exe: string): Promise<InstructionSet> { return new Promise(resolve => { if (compilerArch && typeof compilerArch === 'string') { - for (const instructionSet in this.supported) { - const method = this.supported[instructionSet]; + for (const [instructionSet, method] of Object.entries(this.supported) as [ + InstructionSet, + InstructionSetMethod, + ][]) { for (const target of method.target) { if (compilerArch.includes(target)) { resolve(instructionSet); @@ -137,8 +185,10 @@ export class InstructionSets { } } } else { - for (const instructionSet in this.supported) { - const method = this.supported[instructionSet]; + for (const [instructionSet, method] of Object.entries(this.supported) as [ + InstructionSet, + InstructionSetMethod, + ][]) { for (const path of method.path) { if (exe.includes(path)) { resolve(instructionSet); diff --git a/static/panes/compiler.ts b/static/panes/compiler.ts index 2b4002a7c..d990cf613 100644 --- a/static/panes/compiler.ts +++ b/static/panes/compiler.ts @@ -72,13 +72,13 @@ import IEditorMouseEvent = editor.IEditorMouseEvent; import {Tool, ArtifactType, Artifact} from '../../types/tool.interfaces.js'; import {assert, unwrap, unwrapString} from '../assert.js'; import {CompilerOutputOptions} from '../../types/features/filters.interfaces.js'; -import {AssemblyDocumentationInstructionSet} from '../../types/features/assembly-documentation.interfaces.js'; import {SourceAndFiles} from '../download-service.js'; import fileSaver = require('file-saver'); import {ICompilerShared} from '../compiler-shared.interfaces.js'; import {CompilerShared} from '../compiler-shared.js'; import {SentryCapture} from '../sentry.js'; import {LLVMIrBackendOptions} from '../compilation/ir.interfaces.js'; +import {InstructionSet} from '../instructionsets.js'; const toolIcons = require.context('../../views/resources/logos', false, /\.(png|svg)$/); @@ -3420,8 +3420,8 @@ export class Compiler extends MonacoPane<monaco.editor.IStandaloneCodeEditor, Co view.setBigUint64(0, BigInt(numericValue.toString()), true); if (numericValue.bitLength().lesserOrEquals(32)) result += ' = ' + view.getFloat32(0, true).toPrecision(9) + 'f'; - else // only subnormal doubles and zero may have upper 32 bits all 0, assume unlikely to be double - result += ' = ' + view.getFloat64(0, true).toPrecision(17); + // only subnormal doubles and zero may have upper 32 bits all 0, assume unlikely to be double + else result += ' = ' + view.getFloat64(0, true).toPrecision(17); // Printable ASCII character. if (numericValue.greaterOrEquals(0x20) && numericValue.lesserOrEquals(0x7e)) { @@ -3434,7 +3434,7 @@ export class Compiler extends MonacoPane<monaco.editor.IStandaloneCodeEditor, Co public static async getAsmInfo( opcode: string, - instructionSet: AssemblyDocumentationInstructionSet, + instructionSet: InstructionSet, ): Promise<AssemblyInstructionInfo | undefined> { const cacheName = `asm/${instructionSet}/${opcode}`; const cached = OpcodeCache.get(cacheName); @@ -3552,10 +3552,7 @@ export class Compiler extends MonacoPane<monaco.editor.IStandaloneCodeEditor, Co this.isWordAsmKeyword(e.target.position.lineNumber, currentWord) ) { try { - const response = await Compiler.getAsmInfo( - currentWord.word, - this.compiler.instructionSet as AssemblyDocumentationInstructionSet, - ); + const response = await Compiler.getAsmInfo(currentWord.word, unwrap(this.compiler.instructionSet)); if (!response) return; this.decorations.asmToolTip = [ { @@ -3631,10 +3628,7 @@ export class Compiler extends MonacoPane<monaco.editor.IStandaloneCodeEditor, Co try { if (this.compiler?.supportsAsmDocs) { - const asmHelp = await Compiler.getAsmInfo( - word.word, - this.compiler.instructionSet as AssemblyDocumentationInstructionSet, - ); + const asmHelp = await Compiler.getAsmInfo(word.word, unwrap(this.compiler.instructionSet)); if (asmHelp) { this.alertSystem.alert(opcode + ' help', asmHelp.html + appendInfo(asmHelp.url), { onClose: () => { diff --git a/static/panes/device-view.ts b/static/panes/device-view.ts index 5d1cd7f06..0f271bd98 100644 --- a/static/panes/device-view.ts +++ b/static/panes/device-view.ts @@ -38,9 +38,9 @@ import {CompilerInfo} from '../../types/compiler.interfaces.js'; import {CompilationResult} from '../../types/compilation/compilation.interfaces.js'; import {ResultLine} from '../../types/resultline/resultline.interfaces.js'; import {assert} from '../assert.js'; -import {AssemblyDocumentationInstructionSet} from '../../types/features/assembly-documentation.interfaces'; import {Alert} from '../widgets/alert'; import {Compiler} from './compiler'; +import {InstructionSet} from '../instructionsets.js'; export class DeviceAsm extends MonacoPane<monaco.editor.IStandaloneCodeEditor, DeviceAsmState> { private decorations: Record<string, monaco.editor.IModelDeltaDecoration[]>; @@ -172,7 +172,7 @@ export class DeviceAsm extends MonacoPane<monaco.editor.IStandaloneCodeEditor, D try { const asmHelp = await Compiler.getAsmInfo( word.word, - this.selectedDevice.split(' ')[0].toLowerCase() as AssemblyDocumentationInstructionSet, + this.selectedDevice.split(' ')[0].toLowerCase() as InstructionSet, ); if (asmHelp) { this.alertSystem.alert(opcode + ' help', asmHelp.html + appendInfo(asmHelp.url), { @@ -435,7 +435,7 @@ export class DeviceAsm extends MonacoPane<monaco.editor.IStandaloneCodeEditor, D try { const response = await Compiler.getAsmInfo( currentWord.word, - this.selectedDevice.split(' ')[0].toLowerCase() as AssemblyDocumentationInstructionSet, + this.selectedDevice.split(' ')[0].toLowerCase() as InstructionSet, ); if (!response) return; this.decorations.asmToolTip = [ diff --git a/types/compiler.interfaces.ts b/types/compiler.interfaces.ts index e641f3529..30f4b272d 100644 --- a/types/compiler.interfaces.ts +++ b/types/compiler.interfaces.ts @@ -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 {InstructionSet} from './instructionsets.js'; import {Language, LanguageKey} from './languages.interfaces.js'; import {Library} from './libraries/libraries.interfaces.js'; import {Tool, ToolInfo} from './tool.interfaces.js'; @@ -54,7 +55,7 @@ export type CompilerInfo = { objdumperArgs: string[]; intelAsm: string; supportsAsmDocs: boolean; - instructionSet: string; + instructionSet: InstructionSet | null; needsMulti: boolean; adarts: string; supportsDeviceAsmView?: boolean; diff --git a/types/features/assembly-documentation.interfaces.ts b/types/features/assembly-documentation.interfaces.ts index 1f46d1dad..fce10a592 100644 --- a/types/features/assembly-documentation.interfaces.ts +++ b/types/features/assembly-documentation.interfaces.ts @@ -23,23 +23,11 @@ // POSSIBILITY OF SUCH DAMAGE. import {AssemblyInstructionInfo} from '../../lib/asm-docs/base.js'; - -export type AssemblyDocumentationInstructionSet = - | 'amd64' - | 'arm32' - | 'arm64' - | 'avr' - | 'evm' - | 'java' - | 'llvm' - | 'mos6502' - | 'ptx' - | 'python' - | 'sass'; +import {InstructionSet} from '../instructionsets.js'; export interface AssemblyDocumentationRequest { /** Specifies which instruction set to look for */ - instructionSet: AssemblyDocumentationInstructionSet; + instructionSet: InstructionSet; /** Instruction set opcode to look for */ opcode: string; } diff --git a/types/instructionsets.ts b/types/instructionsets.ts new file mode 100644 index 000000000..95ee773c0 --- /dev/null +++ b/types/instructionsets.ts @@ -0,0 +1,61 @@ +// 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 const InstructionSetsList = [ + '6502', + 'aarch64', + 'amd64', + 'arm32', + 'avr', + 'beam', + 'c6x', + 'ebpf', + 'evm', + 'hook', + 'java', + 'kvx', + 'llvm', + 'loongarch', + 'mips', + 'mos6502', + 'mrisc32', + 'msp430', + 'powerpc', + 'ptx', + 'python', + 'riscv32', + 'riscv64', + 's390x', + 'sass', + 'sh', + 'sparc', + 'spirv', + 'vax', + 'wasm32', + 'wasm64', + 'xtensa', + 'z80', +] as const; + +export type InstructionSet = (typeof InstructionSetsList)[number]; |