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

  1. The constructor for the M88kTargetInfo class concludes by setting the various variable types as signed long long, unsigned long, or signed int: IntMaxType = SignedLongLong;
    Int64Type = SignedLongLong;
    SizeType = UnsignedLong;
    PtrDiffType = SignedInt;
    IntPtrType = SignedInt;
    }
  2. After that, the function to set the CPU for the target is implemented. This function takes a string and sets the CPU to be the particular CPU string that is supplied by the user within llvm::StringSwitch, which is essentially just a regular switch but specifically for strings with LLVM. We can see that there are three supported CPU types on the M88k target, and there is a CK_Unknown type for if the supplied string does not match any of the expected types:

bool M88kTargetInfo::setCPU(const std::string &Name) {
StringRef N = Name;
CPU = llvm::StringSwitch(N)
.Case(“generic”, CK_88000)
.Case(“mc88000”, CK_88000)
.Case(“mc88100”, CK_88100)
.Case(“mc88110”, CK_88110)
.Default(CK_Unknown);
return CPU != CK_Unknown;
}

  1. It was previously stated that there are three supported and valid CPU types on the M88k target: mc88000, mc88100, and mc88110, with the generic type simply being the mc88000 CPU. We must implement the following functions to enforce these valid CPUs within clang. First, we must declare an array of strings, ValidCPUNames[], to denote the valid CPU names on M88k. Secondly, the fillValidCPUList() method populates the array of valid CPU names into a vector. This vector is then used in the isValidCPUName() method, to check whether a particular CPU name supplied is indeed valid for our M88k target:

static constexpr llvm::StringLiteral ValidCPUNames[] = {
{“generic”}, {“mc88000”}, {“mc88100”}, {“mc88110”}};
void M88kTargetInfo::fillValidCPUList(
SmallVectorImpl &Values) const {
Values.append(std::begin(ValidCPUNames), std::end(ValidCPUNames));
}
bool M88kTargetInfo::isValidCPUName(StringRef Name) const {
return llvm::is_contained(ValidCPUNames, Name);
}

  1. Next, the getTargetDefines() method is implemented. This function defines the macros that are necessary for the frontend, such as the valid CPU types. Aside from the m88k and __m88k macros, we must also define corresponding CPU macros for the valid CPUs:

void M88kTargetInfo::getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const {
using llvm::Twine;
Builder.defineMacro(“m88k“);
Builder.defineMacro(“m88k”); switch (CPU) { // For sub-architecture case CK_88000: Builder.defineMacro(“__mc88000“);
break;
case CK_88100:
Builder.defineMacro(“mc88100“);
break;
case CK_88110:
Builder.defineMacro(“mc88110“);
break;
default:
break;
}
}

  1. The next few functions are stub functions but are required for the frontend for basic support. This includes the functions to get builtins from a target and a function to query the target if a specific feature of the target is supported. For now, we’ll leave them unimplemented and set default return values for these functions so that they can be implemented later:

ArrayRef M88kTargetInfo::getTargetBuiltins() const {
return std::nullopt;
}
bool M88kTargetInfo::hasFeature(StringRef Feature) const {
return Feature == “M88000”;
}

Leave a Reply

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