mirror of
https://github.com/compiler-explorer/compiler-explorer.git
synced 2025-12-27 10:33:59 -05:00
Add Resolc 0.4.0 compiler for Solidity and Yul (#8164)
## What
Adds [Revive's Resolc](https://github.com/paritytech/revive) compiler
for compiling Solidity and Yul (Solidity IR) to RISC-V and PolkaVM
assembly.
### Main Additions
- [x] Implement new `ResolcCompiler`
- [x] Implement Yul language definition and config for Monaco
- [x] Add Resolc as a compiler for the Solidity and Yul languages
- The `ResolcCompiler` handles both kinds of language input
- [x] Implement initial `PolkaVMAsmParser` (no source mappings)
- [x] Enable viewing LLVM IR in a supplementary view
- [x] Implement a new LLVM IR backend option for toggling between
optimized and unoptimized ll
- Affects non-resolc files ([see
commit](606bab9a59))
- Disabled by default
- (Enable by setting `this.compiler.supportsIrViewOptToggleOption =
true` in a compiler's constructor)
- The compiler's `getIrOutputFilename()` will receive the LLVM IR
backend options
### CE Infra
Accompanying CE Infra PR:
https://github.com/compiler-explorer/infra/pull/1855
## Overall Usage
### Steps
(See screenshots)
* Choose between two input languages:
* Solidity
* Yul (Solidity IR)
* Choose a Resolc compiler
* View assembly:
* PolkaVM assembly (if enabling "Compile to binary")
* RISC-V (64 bits) assembly
* View intermediate results:
* Optimized LLVM IR (if enabling "Show Optimized" in the LLVM IR view)
* Unoptimized LLVM IR
### Notes
Source mappings currently only exist between:
- Yul and RISC-V
- Yul and LLVM-IR
## Screenshots
<img width="1502" height="903" alt="CE Yul RISC-V LLVM IR"
src="https://github.com/user-attachments/assets/7503b9b5-0f2c-4ddf-9405-669e4bdcd02d"
/>
<img width="1502" height="903" alt="CE Solidity PolkaVM"
src="https://github.com/user-attachments/assets/eeb51c99-3eaa-4dda-b13c-ac7783e66cb8"
/>
---------
Co-authored-by: Matt Godbolt <matt@godbolt.org>
This commit is contained in:
@@ -25,7 +25,11 @@
|
||||
import {describe, expect, it} from 'vitest';
|
||||
import {AsmParser} from '../lib/parsers/asm-parser.js';
|
||||
import {MlirAsmParser} from '../lib/parsers/asm-parser-mlir.js';
|
||||
import {PolkaVMAsmParser} from '../lib/parsers/asm-parser-polkavm.js';
|
||||
import {PTXAsmParser} from '../lib/parsers/asm-parser-ptx.js';
|
||||
import {ResolcRiscVAsmParser} from '../lib/parsers/asm-parser-resolc-riscv.js';
|
||||
import type {ParsedAsmResult} from '../types/asmresult/asmresult.interfaces.js';
|
||||
import type {ParseFiltersAndOutputOptions} from '../types/features/filters.interfaces.js';
|
||||
|
||||
describe('AsmParser tests', () => {
|
||||
const parser = new AsmParser();
|
||||
@@ -293,3 +297,191 @@ module {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('ResolcRiscVAsmParser tests', () => {
|
||||
const parser = new ResolcRiscVAsmParser();
|
||||
|
||||
function expectParsedAsmResult(result: ParsedAsmResult, expected: ParsedAsmResult): void {
|
||||
expect(result.labelDefinitions).toEqual(expected.labelDefinitions);
|
||||
expect(result.asm.length).toEqual(expected.asm.length);
|
||||
for (let i = 0; i < result.asm.length; i++) {
|
||||
expect(result.asm[i]).toMatchObject(expected.asm[i]);
|
||||
}
|
||||
}
|
||||
|
||||
it.skipIf(process.platform === 'win32')('should identify RISC-V instruction info and source line numbers', () => {
|
||||
const filters: Partial<ParseFiltersAndOutputOptions> = {binaryObject: true};
|
||||
const riscv = `
|
||||
000000000000027a <__entry>:
|
||||
; __entry():
|
||||
; path/to/example.sol.Square.yul:1
|
||||
27a: 41 11 addi sp, sp, -0x10
|
||||
|
||||
000000000000028c <.Lpcrel_hi4>:
|
||||
; .Lpcrel_hi4():
|
||||
28c: 97 05 00 00 auipc a1, 0x0
|
||||
; path/to/example.sol.Square.yul:1
|
||||
2a8: 1d 71 addi sp, sp, -0x60
|
||||
2aa: 86 ec sd ra, 0x58(sp)
|
||||
; path/to/example.sol.Square.yul:7
|
||||
2ca: e7 80 00 00 jalr ra <.Lpcrel_hi4+0x3a>`;
|
||||
|
||||
const expected: ParsedAsmResult = {
|
||||
asm: [
|
||||
{
|
||||
text: '__entry:',
|
||||
source: null,
|
||||
},
|
||||
{
|
||||
text: ' addi sp, sp, -0x10',
|
||||
address: 0x27a,
|
||||
opcodes: ['41', '11'],
|
||||
source: {
|
||||
line: 1,
|
||||
file: null,
|
||||
},
|
||||
},
|
||||
{
|
||||
text: '.Lpcrel_hi4:',
|
||||
source: null,
|
||||
},
|
||||
{
|
||||
text: ' auipc a1, 0x0',
|
||||
address: 0x28c,
|
||||
opcodes: ['97', '05', '00', '00'],
|
||||
source: {
|
||||
line: 1,
|
||||
file: null,
|
||||
},
|
||||
},
|
||||
{
|
||||
text: ' addi sp, sp, -0x60',
|
||||
address: 0x2a8,
|
||||
opcodes: ['1d', '71'],
|
||||
source: {
|
||||
line: 1,
|
||||
file: null,
|
||||
},
|
||||
},
|
||||
{
|
||||
text: ' sd ra, 0x58(sp)',
|
||||
address: 0x2aa,
|
||||
opcodes: ['86', 'ec'],
|
||||
source: {
|
||||
line: 1,
|
||||
file: null,
|
||||
},
|
||||
},
|
||||
{
|
||||
text: ' jalr ra <.Lpcrel_hi4+0x3a>',
|
||||
address: 0x2ca,
|
||||
opcodes: ['e7', '80', '00', '00'],
|
||||
source: {
|
||||
line: 7,
|
||||
file: null,
|
||||
},
|
||||
},
|
||||
],
|
||||
labelDefinitions: {
|
||||
__entry: 1,
|
||||
['.Lpcrel_hi4']: 3,
|
||||
},
|
||||
};
|
||||
|
||||
const result = parser.processAsm(riscv, filters);
|
||||
expectParsedAsmResult(result, expected);
|
||||
});
|
||||
});
|
||||
|
||||
describe('PolkaVMAsmParser tests', () => {
|
||||
const parser = new PolkaVMAsmParser();
|
||||
|
||||
function expectParsedAsmResult(result: ParsedAsmResult, expected: ParsedAsmResult): void {
|
||||
expect(result.labelDefinitions).toEqual(expected.labelDefinitions);
|
||||
expect(result.asm.length).toEqual(expected.asm.length);
|
||||
for (let i = 0; i < result.asm.length; i++) {
|
||||
expect(result.asm[i]).toMatchObject(expected.asm[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// Note: We currently have no source mappings from PVM.
|
||||
it('should identify PVM instruction info', () => {
|
||||
const filters: Partial<ParseFiltersAndOutputOptions> = {
|
||||
binaryObject: false,
|
||||
commentOnly: false,
|
||||
};
|
||||
const pvm = `
|
||||
// Code size = 1078 bytes
|
||||
|
||||
<__entry>:
|
||||
: @0 (gas: 6)
|
||||
0: sp = sp + 0xfffffffffffffff0
|
||||
3: u64 [sp + 0x8] = ra
|
||||
6: u64 [sp] = s0
|
||||
8: s0 = a0 & 0x1
|
||||
11: ecalli 2 // 'call_data_size'
|
||||
13: fallthrough
|
||||
: @1 (gas: 2)
|
||||
14: u32 [0x20000] = a0`;
|
||||
|
||||
const expected: ParsedAsmResult = {
|
||||
asm: [
|
||||
{
|
||||
text: '// Code size = 1078 bytes',
|
||||
source: null,
|
||||
},
|
||||
{
|
||||
text: '__entry:',
|
||||
source: null,
|
||||
},
|
||||
{
|
||||
text: ' @0 (gas: 6)',
|
||||
source: null,
|
||||
},
|
||||
{
|
||||
text: ' sp = sp + 0xfffffffffffffff0',
|
||||
address: 0,
|
||||
source: null,
|
||||
},
|
||||
{
|
||||
text: ' u64 [sp + 0x8] = ra',
|
||||
address: 3,
|
||||
source: null,
|
||||
},
|
||||
{
|
||||
text: ' u64 [sp] = s0',
|
||||
address: 6,
|
||||
source: null,
|
||||
},
|
||||
{
|
||||
text: ' s0 = a0 & 0x1',
|
||||
address: 8,
|
||||
source: null,
|
||||
},
|
||||
{
|
||||
text: " ecalli 2 // 'call_data_size'",
|
||||
address: 11,
|
||||
source: null,
|
||||
},
|
||||
{
|
||||
text: ' fallthrough',
|
||||
address: 13,
|
||||
source: null,
|
||||
},
|
||||
{
|
||||
text: ' @1 (gas: 2)',
|
||||
source: null,
|
||||
},
|
||||
{
|
||||
text: ' u32 [0x20000] = a0',
|
||||
address: 14,
|
||||
source: null,
|
||||
},
|
||||
],
|
||||
labelDefinitions: {__entry: 2},
|
||||
};
|
||||
|
||||
const result = parser.process(pvm, filters);
|
||||
expectParsedAsmResult(result, expected);
|
||||
});
|
||||
});
|
||||
|
||||
307
test/resolc-tests.ts
Normal file
307
test/resolc-tests.ts
Normal file
@@ -0,0 +1,307 @@
|
||||
// Copyright (c) 2025, 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 path from 'node:path';
|
||||
|
||||
import {beforeAll, describe, expect, it} from 'vitest';
|
||||
|
||||
import type {CompilationEnvironment} from '../lib/compilation-env.js';
|
||||
import {ResolcParser} from '../lib/compilers/argument-parsers.js';
|
||||
import {ResolcCompiler} from '../lib/compilers/index.js';
|
||||
import type {ParsedAsmResult, ParsedAsmResultLine} from '../types/asmresult/asmresult.interfaces.js';
|
||||
import type {CompilerInfo} from '../types/compiler.interfaces.js';
|
||||
import type {ParseFiltersAndOutputOptions} from '../types/features/filters.interfaces.js';
|
||||
import type {LanguageKey} from '../types/languages.interfaces.js';
|
||||
import {makeCompilationEnvironment, makeFakeCompilerInfo, makeFakeLlvmIrBackendOptions} from './utils.js';
|
||||
|
||||
const languages = {
|
||||
solidity: {id: 'solidity' as LanguageKey},
|
||||
yul: {id: 'yul' as LanguageKey},
|
||||
};
|
||||
|
||||
describe('Resolc', () => {
|
||||
let env: CompilationEnvironment;
|
||||
const expectedSolcExe = '/opt/compiler-explorer/solc-0.8.30/solc';
|
||||
|
||||
beforeAll(() => {
|
||||
env = makeCompilationEnvironment({languages});
|
||||
});
|
||||
|
||||
function makeCompiler(compilerInfo: Partial<CompilerInfo>): ResolcCompiler {
|
||||
return new ResolcCompiler(makeFakeCompilerInfo(compilerInfo), env);
|
||||
}
|
||||
|
||||
function expectCorrectOutputFilenames(
|
||||
compiler: ResolcCompiler,
|
||||
inputFilename: string,
|
||||
expectedFilenameWithoutExtension: string,
|
||||
): void {
|
||||
const defaultOutputFilename = `${expectedFilenameWithoutExtension}.pvmasm`;
|
||||
expect(compiler.getOutputFilename(path.normalize('test/resolc'))).toEqual(defaultOutputFilename);
|
||||
|
||||
let llvmIrBackendOptions = makeFakeLlvmIrBackendOptions({showOptimized: true});
|
||||
expect(compiler.getIrOutputFilename(inputFilename, undefined, llvmIrBackendOptions)).toEqual(
|
||||
`${expectedFilenameWithoutExtension}.optimized.ll`,
|
||||
);
|
||||
|
||||
llvmIrBackendOptions = makeFakeLlvmIrBackendOptions({showOptimized: false});
|
||||
expect(compiler.getIrOutputFilename(inputFilename, undefined, llvmIrBackendOptions)).toEqual(
|
||||
`${expectedFilenameWithoutExtension}.unoptimized.ll`,
|
||||
);
|
||||
|
||||
expect(compiler.getObjdumpOutputFilename(defaultOutputFilename)).toEqual(
|
||||
`${expectedFilenameWithoutExtension}.o`,
|
||||
);
|
||||
}
|
||||
|
||||
describe('Common', () => {
|
||||
it('should return correct key', () => {
|
||||
expect(ResolcCompiler.key).toEqual('resolc');
|
||||
});
|
||||
|
||||
it('should return Solc executable dependency path', () => {
|
||||
expect(ResolcCompiler.solcExe).toEqual(expectedSolcExe);
|
||||
});
|
||||
});
|
||||
|
||||
describe('From Solidity', () => {
|
||||
const compilerInfo = {
|
||||
exe: 'resolc',
|
||||
lang: languages.solidity.id,
|
||||
};
|
||||
|
||||
it('should instantiate successfully', () => {
|
||||
const compiler = makeCompiler(compilerInfo);
|
||||
expect(compiler.lang.id).toEqual(compilerInfo.lang);
|
||||
});
|
||||
|
||||
it('should use Resolc argument parser', () => {
|
||||
const compiler = makeCompiler(compilerInfo);
|
||||
expect(compiler.getArgumentParserClass()).toBe(ResolcParser);
|
||||
});
|
||||
|
||||
it('should use debug options', () => {
|
||||
const compiler = makeCompiler(compilerInfo);
|
||||
expect(compiler.optionsForFilter({})).toEqual([
|
||||
'-g',
|
||||
'--solc',
|
||||
expectedSolcExe,
|
||||
'--overwrite',
|
||||
'--debug-output-dir',
|
||||
'artifacts',
|
||||
]);
|
||||
});
|
||||
|
||||
it('should generate output filenames', () => {
|
||||
const compiler = makeCompiler(compilerInfo);
|
||||
const filenameWithoutExtension = path.normalize('test/resolc/artifacts/test_resolc_example.sol.Square');
|
||||
const inputFilename = path.normalize('test/resolc/example.sol');
|
||||
expectCorrectOutputFilenames(compiler, inputFilename, filenameWithoutExtension);
|
||||
});
|
||||
|
||||
describe('To RISC-V', () => {
|
||||
const filters: Partial<ParseFiltersAndOutputOptions> = {
|
||||
binaryObject: true,
|
||||
libraryCode: true,
|
||||
};
|
||||
|
||||
function getExpectedParsedOutputHeader(): ParsedAsmResultLine[] {
|
||||
const header =
|
||||
'; RISC-V (64 bits) Assembly:\n' +
|
||||
'; --------------------------\n' +
|
||||
'; To see the PolkaVM assembly instead,\n' +
|
||||
'; enable "Compile to binary object".\n' +
|
||||
'; --------------------------';
|
||||
|
||||
return header.split('\n').map(line => ({text: line}));
|
||||
}
|
||||
|
||||
it('should remove orphaned labels', async () => {
|
||||
const compiler = makeCompiler(compilerInfo);
|
||||
|
||||
const parsedAsm: ParsedAsmResult = {
|
||||
asm: [
|
||||
{
|
||||
// Orphan
|
||||
text: 'memmove:',
|
||||
},
|
||||
{
|
||||
// Orphan
|
||||
text: '.LBB34_5:',
|
||||
},
|
||||
{
|
||||
// Orphan
|
||||
text: 'memset:',
|
||||
},
|
||||
{
|
||||
// Orphan
|
||||
text: '.LBB35_2:',
|
||||
},
|
||||
{
|
||||
text: '__entry:',
|
||||
},
|
||||
{
|
||||
text: ' addi sp, sp, -0x10',
|
||||
},
|
||||
{
|
||||
text: ' sd ra, 0x8(sp)',
|
||||
},
|
||||
{
|
||||
// Orphan
|
||||
text: '__last:',
|
||||
},
|
||||
],
|
||||
labelDefinitions: {
|
||||
memmove: 1,
|
||||
['.LBB34_5']: 2,
|
||||
memset: 3,
|
||||
['.LBB35_2']: 4,
|
||||
__entry: 5,
|
||||
__last: 8,
|
||||
},
|
||||
};
|
||||
|
||||
const expected: ParsedAsmResult = {
|
||||
asm: [
|
||||
...getExpectedParsedOutputHeader(),
|
||||
{
|
||||
text: '__entry:',
|
||||
},
|
||||
{
|
||||
text: ' addi sp, sp, -0x10',
|
||||
},
|
||||
{
|
||||
text: ' sd ra, 0x8(sp)',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const result = await compiler.postProcessAsm(parsedAsm, filters);
|
||||
expect(result.asm.length).toEqual(expected.asm.length);
|
||||
expect(result.asm).toMatchObject(expected.asm);
|
||||
});
|
||||
|
||||
it('should remove invalid Solidity <--> RISC-V source mappings', async () => {
|
||||
const compiler = makeCompiler(compilerInfo);
|
||||
|
||||
const parsedAsm: ParsedAsmResult = {
|
||||
asm: [
|
||||
{
|
||||
text: '.Lpcrel_hi4:',
|
||||
source: null,
|
||||
},
|
||||
{
|
||||
text: ' auipc a1, 0x0',
|
||||
source: null,
|
||||
},
|
||||
{
|
||||
text: ' addi sp, sp, -0x60',
|
||||
source: {
|
||||
line: 1,
|
||||
file: null,
|
||||
},
|
||||
},
|
||||
{
|
||||
text: ' sd ra, 0x58(sp)',
|
||||
source: {
|
||||
line: 1,
|
||||
file: null,
|
||||
},
|
||||
},
|
||||
{
|
||||
text: ' jalr ra <.Lpcrel_hi4+0x3a>',
|
||||
source: {
|
||||
line: 7,
|
||||
file: null,
|
||||
},
|
||||
},
|
||||
],
|
||||
labelDefinitions: {['.Lpcrel_hi4']: 1},
|
||||
};
|
||||
|
||||
const expected: ParsedAsmResult = {
|
||||
asm: [
|
||||
...getExpectedParsedOutputHeader(),
|
||||
{
|
||||
text: '.Lpcrel_hi4:',
|
||||
source: null,
|
||||
},
|
||||
{
|
||||
text: ' auipc a1, 0x0',
|
||||
source: null,
|
||||
},
|
||||
{
|
||||
text: ' addi sp, sp, -0x60',
|
||||
source: null,
|
||||
},
|
||||
{
|
||||
text: ' sd ra, 0x58(sp)',
|
||||
source: null,
|
||||
},
|
||||
{
|
||||
text: ' jalr ra <.Lpcrel_hi4+0x3a>',
|
||||
source: null,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const result = await compiler.postProcessAsm(parsedAsm, filters);
|
||||
expect(result.asm.length).toEqual(expected.asm.length);
|
||||
expect(result.asm).toMatchObject(expected.asm);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('From Yul', () => {
|
||||
const compilerInfo = {
|
||||
exe: 'resolc',
|
||||
lang: languages.yul.id,
|
||||
};
|
||||
|
||||
it('should instantiate successfully', () => {
|
||||
const compiler = makeCompiler(compilerInfo);
|
||||
expect(compiler.lang.id).toEqual(compilerInfo.lang);
|
||||
});
|
||||
|
||||
it('should use debug options', () => {
|
||||
const compiler = makeCompiler(compilerInfo);
|
||||
expect(compiler.optionsForFilter({})).toEqual([
|
||||
'-g',
|
||||
'--solc',
|
||||
expectedSolcExe,
|
||||
'--overwrite',
|
||||
'--debug-output-dir',
|
||||
'artifacts',
|
||||
'--yul',
|
||||
]);
|
||||
});
|
||||
|
||||
it('should generate output filenames', () => {
|
||||
const compiler = makeCompiler(compilerInfo);
|
||||
const filenameWithoutExtension = path.normalize('test/resolc/artifacts/test_resolc_example.yul.Square');
|
||||
const inputFilename = path.normalize('test/resolc/example.yul');
|
||||
expectCorrectOutputFilenames(compiler, inputFilename, filenameWithoutExtension);
|
||||
});
|
||||
});
|
||||
});
|
||||
8
test/resolc/example.sol
Normal file
8
test/resolc/example.sol
Normal file
@@ -0,0 +1,8 @@
|
||||
// SPDX-License-Identifier: UNLICENSED
|
||||
pragma solidity >=0.4.0;
|
||||
|
||||
contract Square {
|
||||
function square(uint32 num) public pure returns (uint32) {
|
||||
return num * num;
|
||||
}
|
||||
}
|
||||
43
test/resolc/example.yul
Normal file
43
test/resolc/example.yul
Normal file
@@ -0,0 +1,43 @@
|
||||
object "Square" {
|
||||
code {
|
||||
{
|
||||
let _1 := memoryguard(0x80)
|
||||
mstore(64, _1)
|
||||
if callvalue() { revert(0, 0) }
|
||||
let _2 := datasize("Square_deployed")
|
||||
codecopy(_1, dataoffset("Square_deployed"), _2)
|
||||
return(_1, _2)
|
||||
}
|
||||
}
|
||||
object "Square_deployed" {
|
||||
code {
|
||||
{
|
||||
let _1 := memoryguard(0x80)
|
||||
mstore(64, _1)
|
||||
if iszero(lt(calldatasize(), 4))
|
||||
{
|
||||
if eq(0xd27b3841, shr(224, calldataload(0)))
|
||||
{
|
||||
if callvalue() { revert(0, 0) }
|
||||
if slt(add(calldatasize(), not(3)), 32) { revert(0, 0) }
|
||||
let value := calldataload(4)
|
||||
let _2 := and(value, 0xffffffff)
|
||||
if iszero(eq(value, _2)) { revert(0, 0) }
|
||||
let product_raw := mul(_2, _2)
|
||||
let product := and(product_raw, 0xffffffff)
|
||||
if iszero(eq(product, product_raw))
|
||||
{
|
||||
mstore(0, shl(224, 0x4e487b71))
|
||||
mstore(4, 0x11)
|
||||
revert(0, 0x24)
|
||||
}
|
||||
mstore(_1, product)
|
||||
return(_1, 32)
|
||||
}
|
||||
}
|
||||
revert(0, 0)
|
||||
}
|
||||
}
|
||||
data ".metadata" hex"a26469706673582212209b2b1b86ce0e1a75faa800884ba155bd6bc6a6bc71f210370f818535dcfc5ee364736f6c634300081e0033"
|
||||
}
|
||||
}
|
||||
@@ -40,6 +40,11 @@ import {AsmEWAVRParser} from '../lib/parsers/asm-parser-ewavr.js';
|
||||
import {PTXAsmParser} from '../lib/parsers/asm-parser-ptx.js';
|
||||
import {SassAsmParser} from '../lib/parsers/asm-parser-sass.js';
|
||||
import {VcAsmParser} from '../lib/parsers/asm-parser-vc.js';
|
||||
import {CompilerProps, fakeProps} from '../lib/properties.js';
|
||||
import {LLVMIrBackendOptions} from '../types/compilation/ir.interfaces.js';
|
||||
import {CompilerInfo} from '../types/compiler.interfaces.js';
|
||||
import {ParseFiltersAndOutputOptions} from '../types/features/filters.interfaces.js';
|
||||
import {Language} from '../types/languages.interfaces.js';
|
||||
|
||||
// Test helper class that extends AsmParser to allow setting protected properties for testing
|
||||
class AsmParserForTest extends AsmParser {
|
||||
@@ -48,11 +53,6 @@ class AsmParserForTest extends AsmParser {
|
||||
}
|
||||
}
|
||||
|
||||
import {CompilerProps, fakeProps} from '../lib/properties.js';
|
||||
import {CompilerInfo} from '../types/compiler.interfaces.js';
|
||||
import {ParseFiltersAndOutputOptions} from '../types/features/filters.interfaces.js';
|
||||
import {Language} from '../types/languages.interfaces.js';
|
||||
|
||||
function ensureTempCleanup() {
|
||||
// Sometimes we're called from inside a test, sometimes from outside. Handle both.
|
||||
afterEach(async () => await temp.cleanup());
|
||||
@@ -85,6 +85,10 @@ export function makeFakeParseFiltersAndOutputOptions(
|
||||
return options as ParseFiltersAndOutputOptions;
|
||||
}
|
||||
|
||||
export function makeFakeLlvmIrBackendOptions(options: Partial<LLVMIrBackendOptions>): LLVMIrBackendOptions {
|
||||
return options as LLVMIrBackendOptions;
|
||||
}
|
||||
|
||||
// This combines a should assert and a type guard
|
||||
// Example:
|
||||
//
|
||||
|
||||
Reference in New Issue
Block a user