Implementing the driver integration within clang – Beyond Instruction Selection-1

Integrating a new target into the clang frontend
In the previous chapters, we developed the M88k target’s backend implementation within LLVM. To complete the compiler implementation for the M88k target, we will investigate connecting our new target to the frontend by adding a clang implementation for our M88k target.
Implementing the driver integration within clang
Let’s start by adding driver integration into clang for M88k:

  1. The first change we will be making is inside the clang/include/clang/Basic/TargetInfo.h file. The BuiltinVaListKind enum lists the different kinds of __builtin_va_list types for each target, which is used for variadic functions support, so a corresponding type for M88k is added:

enum BuiltinVaListKind {
. . .
// typedef struct __va_list_tag {
// int __va_arg;
// int *__va_stk;
// int *__va_reg;
//} va_list;
M88kBuiltinVaList
};

  1. Next, we must add a new header file, clang/lib/Basic/Targets/M88k.h. This file is a header for the M88k target feature support within the frontend. The first step is to define a new macro, to prevent multiple inclusive of the same header files, types, variables, and more. We must also include various headers that we require for the implementation to follow:

ifndef LLVM_CLANG_LIB_BASIC_TARGETS_M88K_H
define LLVM_CLANG_LIB_BASIC_TARGETS_M88K_H
include “OSTargets.h”
include “clang/Basic/TargetInfo.h”
include “clang/Basic/TargetOptions.h”
include “llvm/Support/Compiler.h”
include “llvm/TargetParser/Triple.h”

  1. The methods we will declare will be added to the clang and targets namespaces accordingly, much like the other targets within llvm-project:

namespace clang {
namespace targets {

  1. Let’s declare the actual M88kTargetInfo class now, and have it extend the original TargetInfo class. This class is marked with LLVM_LIBRARY_VISIBILITY because if this class is linked to a shared library, this attribute allows the M88kTargetInfo class to only be visible from within the library, and inaccessible externally:

class LLVM_LIBRARY_VISIBILITY M88kTargetInfo: public TargetInfo {

  1. Additionally, we must declare two variables – an array of characters to represent the register names and an enum value containing the type of CPUs available in the M88k target that can be selected. The default CPU that we set is the CK_Unknown CPU. Later, we will see that this can be overwritten by user options: static const char *const GCCRegNames[];
    enum CPUKind { CK_Unknown, CK_88000, CK_88100, CK_88110 } CPU = CK_Unknown;
  2. After, we begin by declaring the public methods that will be needed in our class implementation. Aside from the constructor of our class, we define various getter methods. This includes methods that get target-specific define values, ones that get a list of built-ins supported by the target, methods that return the GCC register names along with their aliases, and finally, a method that returns our M88k BuiltinVaListKind that we previously added to clang/include/clang/Basic/TargetInfo.h:

public:
M88kTargetInfo(const llvm::Triple &Triple, const TargetOptions &);
void getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const override;
ArrayRef getTargetBuiltins() const override;
ArrayRef getGCCRegNames() const override;
ArrayRef getGCCRegAliases() const override;
BuiltinVaListKind getBuiltinVaListKind() const override {
return TargetInfo::M88kBuiltinVaList;
}

Leave a Reply

Your email address will not be published. Required fields are marked *