diff --git a/src/environment/llvm-prefix.ts b/src/environment/llvm-prefix.ts deleted file mode 100644 index 1af4b92..0000000 --- a/src/environment/llvm-prefix.ts +++ /dev/null @@ -1,28 +0,0 @@ -import path from "path"; - -export interface Toolchain { - /** - * C compiler. - */ - CC: string; - - /** - * C++ compiler. - */ - CXX: string; - - /** - * Fortran compiler. - */ - FC: string; -}; - -export function llvmToolchain(prefix: string) { - const bin = path.resolve(prefix, "bin"); - return { - CC: path.resolve(bin, "clang"), - CXX: path.resolve(bin, "clang++"), - FC: path.resolve(bin, "flang"), - LLVM_EXTRACT: path.resolve(bin, "llvm-extract"), - }; -} diff --git a/src/toolchain/index.ts b/src/toolchain/index.ts new file mode 100644 index 0000000..9098a0e --- /dev/null +++ b/src/toolchain/index.ts @@ -0,0 +1,115 @@ +import { spawn } from 'child_process'; +import { promisifySpawn } from 'lyc/cli'; +import { generalCommand, extractCommand } from 'lyc/commands/compiler'; +import path from 'path'; + +export interface Toolchain { + /** + * C compiler. + */ + CC: string; + + /** + * C++ compiler. + */ + CXX: string; + + /** + * Fortran compiler. + */ + FC: string; +}; + +export interface LLVMToolchain extends Toolchain { + /** + * An llvm tooling that may extract part of LLVM IR. + */ + LLVM_EXTRACT: string; +} + +export function llvmToolchain(prefix: string) { + const bin = path.resolve(prefix, "bin"); + return { + CC: path.resolve(bin, "clang"), + CXX: path.resolve(bin, "clang++"), + FC: path.resolve(bin, "flang"), + LLVM_EXTRACT: path.resolve(bin, "llvm-extract"), + }; +} + +/** + * Give an LLVM toolchain, and a desired IR, a list of function names. + * Generate a function that takes vFnPath and sFnPath, used for path calculation. + */ +export function reduceIR(llvmTC: LLVMToolchain, IR: string) { + const objFlags = [ + ...generalCommand({ + outputKind: 'object', + }), + '-x', 'ir', + // Read from stdin. + '-', + ]; + + return { + mkFnObjects: async (fnList: string[], vFnPath: (fn: string) => string, sFnPath: (fn: string) => string) => { + // Parse the IR with all function names + // For each function, extract it. + await Promise.all(fnList.map(fn => { + const proc = spawn(llvmTC.LLVM_EXTRACT, [ + ...extractCommand({ + func: [fn], + asm: true, + input: '-', + output: '-', + }), + ]); + + // Write IR and close stdin + proc.stdin.write(IR); + proc.stdin.end(); + + const compileVector = spawn(llvmTC.FC, [ + ...objFlags, + ...generalCommand({ output: vFnPath(fn), }), + '-msimd', + ]); + + const compileScalar = spawn(llvmTC.FC, [ + ...objFlags, + ...generalCommand({ output: sFnPath(fn) }), + ]); + + proc.stdout.pipe(compileVector.stdin); + proc.stdout.pipe(compileScalar.stdin); + + return Promise.all([proc, compileScalar, compileScalar].map(promisifySpawn)); + })); + }, + mkGlobalObject: async (globalPath: string) => { + const proc = spawn(llvmTC.LLVM_EXTRACT, [ + ...extractCommand({ + asm: true, + input: "-", + output: "-", + }), + // Extract all global variables. + "-rglob", + ".*", + ], { stdio: ['pipe', 'pipe', 'inherit'] }); + + // Write IR and close stdin + proc.stdin.write(IR); + proc.stdin.end(); + + const compileScalar = spawn(llvmTC.FC, [ + ...objFlags, + ...generalCommand({ output: globalPath }), + ], { stdio: ['pipe', 'inherit', 'inherit'] }); + + proc.stdout.pipe(compileScalar.stdin); + + return Promise.all([proc, compileScalar].map(promisifySpawn)); + } + }; +}