Clang¶
This chapter add Cpu0 target to frontend clang.
Cpu0 target¶
exlbt/clang/include/clang/lib/Driver/CMakeLists.txt
ToolChains/Arch/Cpu0.cpp
exlbt/clang/lib/Driver/ToolChains/CommonArgs.cpp
#include "Arch/Cpu0.h"
...
case llvm::Triple::cpu0:
case llvm::Triple::cpu0el: {
StringRef CPUName;
StringRef ABIName;
cpu0::getCpu0CPUAndABI(Args, T, CPUName, ABIName);
return std::string(CPUName);
}
exlbt/clang/lib/Driver/ToolChains/Arch/Cpu0.h
//===--- Cpu0.h - Cpu0-specific Tool Helpers ----------------------*- C++ -*-===//
//
// Part of the LLVM Project, 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
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_CPU0_H
#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_CPU0_H
#include "clang/Driver/Driver.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Option/Option.h"
#include <string>
#include <vector>
namespace clang {
namespace driver {
namespace tools {
namespace cpu0 {
void getCpu0CPUAndABI(const llvm::opt::ArgList &Args,
const llvm::Triple &Triple, StringRef &CPUName,
StringRef &ABIName);
} // end namespace cpu0
} // end namespace target
} // end namespace driver
} // end namespace clang
#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_CPU0_H
exlbt/clang/lib/Driver/ToolChains/Arch/Cpu0.cpp
//===--- Cpu0.cpp - Tools Implementations -----------------------*- C++ -*-===//
//
// Part of the LLVM Project, 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 "Cpu0.h"
#include "ToolChains/CommonArgs.h"
#include "clang/Driver/Driver.h"
#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/Options.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Option/ArgList.h"
using namespace clang::driver;
using namespace clang::driver::tools;
using namespace clang;
using namespace llvm::opt;
// Get CPU and ABI names. They are not independent
// so we have to calculate them together.
void cpu0::getCpu0CPUAndABI(const ArgList &Args, const llvm::Triple &Triple,
StringRef &CPUName, StringRef &ABIName) {
if (Arg *A = Args.getLastArg(clang::driver::options::OPT_march_EQ,
options::OPT_mcpu_EQ))
CPUName = A->getValue();
if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) {
ABIName = A->getValue();
// Convert a GNU style Cpu0 ABI name to the name
// accepted by LLVM Cpu0 backend.
ABIName = llvm::StringSwitch<llvm::StringRef>(ABIName)
.Case("32", "o32")
.Default(ABIName);
}
// Setup default CPU and ABI names.
if (CPUName.empty()) {
switch (Triple.getArch()) {
default:
llvm_unreachable("Unexpected triple arch name");
case llvm::Triple::cpu0:
case llvm::Triple::cpu0el:
CPUName = "cpu032II";
break;
}
}
if (ABIName.empty())
ABIName = "o32";
}
exlbt/clang/include/clang/lib/Basic/CMakeLists.txt
Targets/Cpu0.cpp
exlbt/clang/include/clang/lib/Basic/Targets.cpp
#include "Targets/Cpu0.h"
...
case llvm::Triple::cpu0:
switch (os) {
case llvm::Triple::Linux:
return new LinuxTargetInfo<Cpu0TargetInfo>(Triple, Opts);
case llvm::Triple::RTEMS:
return new RTEMSTargetInfo<Cpu0TargetInfo>(Triple, Opts);
case llvm::Triple::FreeBSD:
return new FreeBSDTargetInfo<Cpu0TargetInfo>(Triple, Opts);
case llvm::Triple::NetBSD:
return new NetBSDTargetInfo<Cpu0TargetInfo>(Triple, Opts);
default:
return new Cpu0TargetInfo(Triple, Opts);
}
case llvm::Triple::cpu0el:
switch (os) {
case llvm::Triple::Linux:
return new LinuxTargetInfo<Cpu0TargetInfo>(Triple, Opts);
case llvm::Triple::RTEMS:
return new RTEMSTargetInfo<Cpu0TargetInfo>(Triple, Opts);
case llvm::Triple::FreeBSD:
return new FreeBSDTargetInfo<Cpu0TargetInfo>(Triple, Opts);
case llvm::Triple::NetBSD:
return new NetBSDTargetInfo<Cpu0TargetInfo>(Triple, Opts);
default:
return new Cpu0TargetInfo(Triple, Opts);
}
exlbt/clang/lib/Basic/Targets/Cpu0.h
//===--- Cpu0.h - Declare Cpu0 target feature support -----------*- C++ -*-===//
//
// Part of the LLVM Project, 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
//
//===----------------------------------------------------------------------===//
//
// This file declares Cpu0 TargetInfo objects.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_LIB_BASIC_TARGETS_CPU0_H
#define LLVM_CLANG_LIB_BASIC_TARGETS_CPU0_H
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/TargetOptions.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Support/Compiler.h"
namespace clang {
namespace targets {
class LLVM_LIBRARY_VISIBILITY Cpu0TargetInfo : public TargetInfo {
void setDataLayout() {
StringRef Layout;
if (ABI == "o32")
Layout = "m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64";
else if (ABI == "n32")
Layout = "m:e-p:32:32-i8:8:32-i16:16:32-i64:64-n32:64-S128";
else if (ABI == "n64")
Layout = "m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128";
else
llvm_unreachable("Invalid ABI");
if (BigEndian)
resetDataLayout(("E-" + Layout).str());
else
resetDataLayout(("e-" + Layout).str());
}
static const Builtin::Info BuiltinInfo[];
std::string CPU;
protected:
std::string ABI;
enum Cpu0FloatABI { HardFloat, SoftFloat } FloatABI;
public:
Cpu0TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opt)
: TargetInfo(Triple) {
TheCXXABI.set(TargetCXXABI::GenericMIPS); // Cpu0 uses Mips ABI
setABI("o32");
CPU = "cpu032II";
}
StringRef getABI() const override { return ABI; }
bool setABI(const std::string &Name) override {
if (Name == "o32") {
ABI = Name;
return true;
}
return false;
}
bool isValidCPUName(StringRef Name) const override;
bool setCPU(const std::string &Name) override {
CPU = Name;
return isValidCPUName(Name);
}
const std::string &getCPU() const { return CPU; }
bool
initFeatureMap(llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags,
StringRef CPU,
const std::vector<std::string> &FeaturesVec) const override {
if (CPU.empty())
CPU = getCPU();
if (CPU == "cpu032II")
Features["HasCmp"] = Features["HasSlt"] = true;
else if (CPU == "cpu032I")
Features["HasCmp"] = true;
else
assert(0 && "incorrect CPU");
return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec);
}
unsigned getISARev() const;
void getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const override;
ArrayRef<Builtin::Info> getTargetBuiltins() const override;
bool hasFeature(StringRef Feature) const override;
BuiltinVaListKind getBuiltinVaListKind() const override {
return TargetInfo::VoidPtrBuiltinVaList;
}
ArrayRef<const char *> getGCCRegNames() const override {
static const char *const GCCRegNames[] = {
// CPU register names
// Must match second column of GCCRegAliases
"$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7", "$8", "$9", "$10",
"$11", "$12", "$13", "$14", "$15",
// Hi/lo and condition register names
"hi", "lo",
};
return llvm::makeArrayRef(GCCRegNames);
}
bool validateAsmConstraint(const char *&Name,
TargetInfo::ConstraintInfo &Info) const override {
switch (*Name) {
default:
return false;
case 'r': // CPU registers.
case 'd': // Equivalent to "r" unless generating MIPS16 code.
case 'y': // Equivalent to "r", backward compatibility only.
//case 'f': // floating-point registers.
case 'c': // $6 for indirect jumps
case 'l': // lo register
case 'x': // hilo register pair
Info.setAllowsRegister();
return true;
case 'I': // Signed 16-bit constant
case 'J': // Integer 0
case 'K': // Unsigned 16-bit constant
case 'L': // Signed 32-bit constant, lower 16-bit zeros (for lui)
case 'M': // Constants not loadable via lui, addiu, or ori
case 'N': // Constant -1 to -65535
case 'O': // A signed 15-bit constant
case 'P': // A constant between 1 go 65535
return true;
case 'R': // An address that can be used in a non-macro load or store
Info.setAllowsMemory();
return true;
case 'Z':
if (Name[1] == 'C') { // An address usable by ll, and sc.
Info.setAllowsMemory();
Name++; // Skip over 'Z'.
return true;
}
return false;
}
}
const char *getClobbers() const override {
// In GCC, $1 is not widely used in generated code (it's used only in a few
// specific situations), so there is no real need for users to add it to
// the clobbers list if they want to use it in their inline assembly code.
//
// In LLVM, $1 is treated as a normal GPR and is always allocatable during
// code generation, so using it in inline assembly without adding it to the
// clobbers list can cause conflicts between the inline assembly code and
// the surrounding generated code.
//
// Another problem is that LLVM is allowed to choose $1 for inline assembly
// operands, which will conflict with the ".set at" assembler option (which
// we use only for inline assembly, in order to maintain compatibility with
// GCC) and will also conflict with the user's usage of $1.
//
// The easiest way to avoid these conflicts and keep $1 as an allocatable
// register for generated code is to automatically clobber $1 for all inline
// assembly code.
//
// FIXME: We should automatically clobber $1 only for inline assembly code
// which actually uses it. This would allow LLVM to use $1 for inline
// assembly operands if the user's assembly code doesn't use it.
return "~{$1}";
}
bool handleTargetFeatures(std::vector<std::string> &Features,
DiagnosticsEngine &Diags) override {
FloatABI = SoftFloat;
for (const auto &Feature : Features) {
if (Feature == "+cpu032I")
setCPU("cpu032I");
else if (Feature == "+cpu032II")
setCPU("cpu032II");
else if (Feature == "+soft-float")
FloatABI = SoftFloat;
}
setDataLayout();
return true;
}
ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override {
static const TargetInfo::GCCRegAlias RegAliases[] = {
{{"at"}, "$1"}, {{"v0"}, "$2"}, {{"v1"}, "$3"},
{{"a0"}, "$4"}, {{"a1"}, "$5"}, {{"t9"}, "$6"},
{{"gp"}, "$11"}, {{"fp"}, "$12"}, {{"sp"}, "$13"},
{{"lr"}, "$14"}, {{"sw"}, "$15"}
};
return llvm::makeArrayRef(RegAliases);
}
bool hasInt128Type() const override {
return false;
}
unsigned getUnwindWordWidth() const override;
bool validateTarget(DiagnosticsEngine &Diags) const override;
bool hasExtIntType() const override { return true; }
};
} // namespace targets
} // namespace clang
#endif // LLVM_CLANG_LIB_BASIC_TARGETS_Cpu0_H
exlbt/clang/lib/Basic/Targets/Cpu0.cpp
//===--- Cpu0.cpp - Implement Cpu0 target feature support -----------------===//
//
// Part of the LLVM Project, 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
//
//===----------------------------------------------------------------------===//
//
// This file implements Cpu0 TargetInfo objects.
//
//===----------------------------------------------------------------------===//
#include "Cpu0.h"
#include "Targets.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/MacroBuilder.h"
#include "clang/Basic/TargetBuiltins.h"
#include "llvm/ADT/StringSwitch.h"
using namespace clang;
using namespace clang::targets;
const Builtin::Info Cpu0TargetInfo::BuiltinInfo[] = {
#define BUILTIN(ID, TYPE, ATTRS) \
{#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr},
#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \
{#ID, TYPE, ATTRS, HEADER, ALL_LANGUAGES, nullptr},
#include "clang/Basic/BuiltinsCpu0.def"
};
static constexpr llvm::StringLiteral ValidCPUNames[] = {
{"cpu032I"}, {"cpu032II"}};
bool Cpu0TargetInfo::isValidCPUName(StringRef Name) const {
return llvm::find(ValidCPUNames, Name) != std::end(ValidCPUNames);
}
unsigned Cpu0TargetInfo::getISARev() const {
return llvm::StringSwitch<unsigned>(getCPU())
.Case("cpu032I", 1)
.Case("cpu032II", 2)
.Default(0);
}
void Cpu0TargetInfo::getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const {
if (BigEndian) {
DefineStd(Builder, "CPU0EB", Opts);
Builder.defineMacro("_CPU0EB");
} else {
DefineStd(Builder, "CPU0EL", Opts);
Builder.defineMacro("_CPU0EL");
}
Builder.defineMacro("__cpu0__");
Builder.defineMacro("_cpu0");
if (Opts.GNUMode)
Builder.defineMacro("cpu0");
if (ABI == "o32" || ABI == "s32") {
Builder.defineMacro("__cpu0", "32");
Builder.defineMacro("_CPU0_ISA", "_CPU0_ISA_CPU032");
} else {
llvm_unreachable("Invalid ABI.");
}
const std::string ISARev = std::to_string(getISARev());
if (!ISARev.empty())
Builder.defineMacro("__cpu0_isa_rev", ISARev);
if (ABI == "o32") {
Builder.defineMacro("__cpu0_o32");
Builder.defineMacro("_ABIO32", "1");
Builder.defineMacro("_CPU0_SIM", "_ABIO32");
} else if (ABI == "s32") {
Builder.defineMacro("__cpu0_n32");
Builder.defineMacro("_ABIS32", "2");
Builder.defineMacro("_CPU0_SIM", "_ABIN32");
} else
llvm_unreachable("Invalid ABI.");
Builder.defineMacro("__REGISTER_PREFIX__", "");
switch (FloatABI) {
case HardFloat:
llvm_unreachable("HardFloat is not support in Cpu0");
break;
case SoftFloat:
Builder.defineMacro("__cpu0_soft_float", Twine(1));
break;
}
}
bool Cpu0TargetInfo::hasFeature(StringRef Feature) const {
return llvm::StringSwitch<bool>(Feature)
.Case("cpu0", true)
.Default(false);
}
ArrayRef<Builtin::Info> Cpu0TargetInfo::getTargetBuiltins() const {
return llvm::makeArrayRef(BuiltinInfo, clang::Cpu0::LastTSBuiltin -
Builtin::FirstTSBuiltin);
}
unsigned Cpu0TargetInfo::getUnwindWordWidth() const {
return llvm::StringSwitch<unsigned>(ABI)
.Cases("o32", "s32", 32)
.Default(getPointerWidth(0));
}
bool Cpu0TargetInfo::validateTarget(DiagnosticsEngine &Diags) const {
if (CPU != "cpu032I" && CPU != "cpu032II") {
Diags.Report(diag::err_target_unknown_cpu) << ABI << CPU;
return false;
}
return true;
}
chungshu@ChungShudeMacBook-Air input % ~/llvm/test/build/bin/clang --help-hidden|grep cpu0
-cpu032II Equivalent to -march=cpu032II
-cpu032I Equivalent to -march=cpu032I
Builtin functions¶
Builtin-function is a function may map to one or more HW instructions for speedup. Cpu0 port compiler-rt’s builtins in the section Compiler-rt’s builtins of chapter Library [1]. Built-in kernels are kernels that are specific to a particular device and provide a mechanism to allow an application developer to leverage special hardware that may be present on the device [2].
exlbt/clang/include/clang/Basic/TargetBuiltins.h
/// CPU0 builtins
namespace Cpu0 {
enum {
LastTIBuiltin = clang::Builtin::FirstTSBuiltin-1,
#define BUILTIN(ID, TYPE, ATTRS) BI##ID,
#include "clang/Basic/BuiltinsCpu0.def"
LastTSBuiltin
};
}
exlbt/clang/include/clang/Basic/BuiltinsCpu0.def
//===-- BuiltinsCpu0.def - Cpu0 Builtin function database --------*- C++ -*-==//
//
// Part of the LLVM Project, 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
//
//===----------------------------------------------------------------------===//
//
// This file defines the CPU0-specific builtin function database. Users of
// this file must define the BUILTIN macro to make use of this information.
//
//===----------------------------------------------------------------------===//
// The format of this database matches clang/Basic/Builtins.def.
// Reference:
// https://github.com/Jonathan2251/lbd/blob/master/lbdex/llvm/modify/llvm/include/llvm/IR/IntrinsicsCpu0.td
BUILTIN(__builtin_cpu0_gcd, "iii", "n")
#undef BUILTIN
chungshu@ChungShudeMacBook-Air CodeGen % pwd
/Users/chungshu/llvm/test/clang/test/CodeGen
chungshu@ChungShudeMacBook-Air CodeGen % ~/llvm/test/build/bin/llvm-lit builtins-cpu0.c
..
-- Testing: 1 tests, 1 workers --
PASS: Clang :: CodeGen/builtins-cpu0.c (1 of 1)
Testing Time: 0.14s
Passed: 1