The final portion of the M88k target integration within clang will be to implement toolchain support for our target. Like before, we’ll need to create a header file for toolchain support. We call this header clang/lib/Driver/ToolChains/Arch/M88k.h:
- First, we must define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_M88K_H to prevent multiple inclusion later, and also add any necessary headers for later use. Following this, we must declare the clang, driver, tools, and m88k namespaces, with each nesting inside the other:
ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_M88K_H
define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_M88K_H
include “clang/Driver/Driver.h”
include “llvm/ADT/StringRef.h”
include “llvm/Option/Option.h”
include
include
namespace clang {
namespace driver {
namespace tools {
namespace m88k {
- Next, we must declare an enum value that depicts the floating-point ABI, which is for soft and hard floating points. This means that floating-point computations can either be done by the floating-point hardware itself, which is fast, or through software emulation, which would be slower:
enum class FloatABI { Invalid, Soft, Hard, };
- Following this, we must add definitions to get the float ABI through the driver, and the CPU through clang’s -mcpu= and -mtune= options. We must also declare a function that retrieves the target features from the driver:
FloatABI getM88kFloatABI(const Driver &D, const llvm::opt::ArgList &Args);
StringRef getM88kTargetCPU(const llvm::opt::ArgList &Args);
StringRef getM88kTuneCPU(const llvm::opt::ArgList &Args);
void getM88kTargetFeatures(const Driver &D, const llvm::Triple &Triple, const llvm::opt::ArgList &Args, std::vector &Features);
- Finally, we conclude the header file by ending the namespaces and the macro that we originally defined:
} // end namespace m88k
} // end namespace tools
} // end namespace driver
} // end namespace clang
endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_M88K_H
The last file we will implement is the C++ implementation for the toolchain support, within clang/lib/Driver/ToolChains/Arch/M88k.cpp:
- Once again, we’ll begin the implementation by including the necessary headers and namespaces that we will use later. We must also include the M88k.h header that we created earlier:
include “M88k.h”
include “ToolChains/CommonArgs.h”
include “clang/Driver/Driver.h”
include “clang/Driver/DriverDiagnostic.h”
include “clang/Driver/Options.h”
include “llvm/ADT/SmallVector.h”
include “llvm/ADT/StringSwitch.h”
include “llvm/Option/ArgList.h”
include “llvm/Support/Host.h”
include “llvm/Support/Regex.h”
include
using namespace clang::driver;
using namespace clang::driver::tools;
using namespace clang;
using namespace llvm::opt;
- The normalizeCPU() function is implemented next, which processes the CPU name into the -mcpu= option in clang. As we can see, each CPU name has several accepted variations. Furthermore, when a user specifies -mcpu=native, it allows them to compile for the current host’s CPU type:
static StringRef normalizeCPU(StringRef CPUName) {
if (CPUName == “native”) {
StringRef CPU = std::string(llvm::sys::getHostCPUName());
if (!CPU.empty() && CPU != “generic”)
return CPU;
}
return llvm::StringSwitch(CPUName)
.Cases(“mc88000”, “m88000”, “88000”, “generic”, “mc88000”)
.Cases(“mc88100”, “m88100”, “88100”, “mc88100”)
.Cases(“mc88110”, “m88110”, “88110”, “mc88110”)
.Default(CPUName);
}