blob: 2937fefc354efddb736a001989db7ab560e0987e [file] [log] [blame]
// Copyright 2023 The IREE Authors
//
// Licensed under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#include "compiler/plugins/target/MetalSPIRV/MSLToMetalLib.h"
#include <stdlib.h>
#include "llvm/ADT/Twine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/FileUtilities.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_ostream.h"
#include "mlir/Support/LogicalResult.h"
#define DEBUG_TYPE "iree-msl-to-metal-lib"
namespace mlir::iree_compiler::IREE::HAL {
/// Returns the command to compile the given MSL source file into Metal library.
static std::string getMetalCompileCommand(MetalTargetPlatform platform,
llvm::StringRef mslFile,
llvm::StringRef libFile) {
const char *sdk = "";
switch (platform) {
case MetalTargetPlatform::macOS:
sdk = "macosx";
break;
case MetalTargetPlatform::iOS:
sdk = "iphoneos";
break;
case MetalTargetPlatform::iOSSimulator:
sdk = "iphonesimulator";
break;
}
// Metal shader offline compilation involves two steps:
// 1. Compile the MSL source code into an Apple IR (AIR) file,
// 2. Compile the AIR file into a Metal library.
return llvm::Twine("xcrun -sdk ")
.concat(sdk)
.concat(" metal -c ")
.concat(mslFile)
.concat(" -o - | xcrun -sdk ")
.concat(sdk)
.concat(" metallib - -o ")
.concat(libFile)
.str();
}
/// Returns the given command via system shell.
static LogicalResult runSystemCommand(llvm::StringRef command) {
LLVM_DEBUG(llvm::dbgs() << "Running system command: '" << command << "'\n");
int exitCode = system(command.data());
if (exitCode == 0)
return success();
llvm::errs() << "Failed to run system command '" << command
<< "' with error code: " << exitCode << "\n";
return failure();
}
std::unique_ptr<llvm::MemoryBuffer>
compileMSLToMetalLib(MetalTargetPlatform targetPlatform,
llvm::StringRef mslCode, llvm::StringRef entryPoint) {
llvm::SmallString<32> mslFile, airFile, libFile;
int mslFd = 0;
llvm::sys::fs::createTemporaryFile(entryPoint, "metal", mslFd, mslFile);
llvm::sys::fs::createTemporaryFile(entryPoint, "metallib", libFile);
llvm::FileRemover mslRemover(mslFile.c_str());
llvm::FileRemover libRemover(libFile.c_str());
{ // Write input MSL code to the temporary file.
llvm::raw_fd_ostream inputStream(mslFd, /*shouldClose=*/true);
inputStream << mslCode << "\n";
}
std::string command =
getMetalCompileCommand(targetPlatform, mslFile, libFile);
if (failed(runSystemCommand(command)))
return nullptr;
auto fileOrErr =
llvm::MemoryBuffer::getFileOrSTDIN(libFile, /*isText=*/false);
if (std::error_code error = fileOrErr.getError()) {
llvm::errs() << "Failed to open generated metallib file '" << libFile
<< "' with error: " << error.message();
return nullptr;
}
return std::move(*fileOrErr);
}
} // namespace mlir::iree_compiler::IREE::HAL