diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -368,6 +368,7 @@ def TargetMips32 : TargetArch<["mips", "mipsel"]>; def TargetAnyMips : TargetArch<["mips", "mipsel", "mips64", "mips64el"]>; def TargetMSP430 : TargetArch<["msp430"]>; +def TargetM68k : TargetArch<["m68k"]>; def TargetRISCV : TargetArch<["riscv32", "riscv64"]>; def TargetX86 : TargetArch<["x86"]>; def TargetAnyX86 : TargetArch<["x86", "x86_64"]>; @@ -772,8 +773,9 @@ } def ARMInterrupt : InheritableAttr, TargetSpecificAttr { - // NOTE: If you add any additional spellings, MSP430Interrupt's, - // MipsInterrupt's and AnyX86Interrupt's spellings must match. + // NOTE: If you add any additional spellings, M68kInterrupt's, + // MSP430Interrupt's, MipsInterrupt's and AnyX86Interrupt's spellings + // must match. let Spellings = [GCC<"interrupt">]; let Args = [EnumArgument<"Interrupt", "InterruptType", ["IRQ", "FIQ", "SWI", "ABORT", "UNDEF", ""], @@ -1524,8 +1526,8 @@ } def MSP430Interrupt : InheritableAttr, TargetSpecificAttr { - // NOTE: If you add any additional spellings, ARMInterrupt's, MipsInterrupt's - // and AnyX86Interrupt's spellings must match. + // NOTE: If you add any additional spellings, ARMInterrupt's, M68kInterrupt's, + // MipsInterrupt's and AnyX86Interrupt's spellings must match. let Spellings = [GCC<"interrupt">]; let Args = [UnsignedArgument<"Number">]; let ParseKind = "Interrupt"; @@ -1541,7 +1543,8 @@ def MipsInterrupt : InheritableAttr, TargetSpecificAttr { // NOTE: If you add any additional spellings, ARMInterrupt's, - // MSP430Interrupt's and AnyX86Interrupt's spellings must match. + // M68kInterrupt's, MSP430Interrupt's and AnyX86Interrupt's spellings + // must match. let Spellings = [GCC<"interrupt">]; let Subjects = SubjectList<[Function]>; let Args = [EnumArgument<"Interrupt", "InterruptType", @@ -1573,6 +1576,16 @@ let Documentation = [MipsShortCallStyleDocs]; } +def M68kInterrupt : InheritableAttr, TargetSpecificAttr { + // NOTE: If you add any additional spellings, ARMInterrupt's, MipsInterrupt's + // MSP430Interrupt's and AnyX86Interrupt's spellings must match. + let Spellings = [GNU<"interrupt">]; + let Args = [UnsignedArgument<"Number">]; + let ParseKind = "Interrupt"; + let HasCustomParsing = 1; + let Documentation = [Undocumented]; +} + def Mode : Attr { let Spellings = [GCC<"mode">]; let Subjects = SubjectList<[Var, Enum, TypedefName, Field], ErrorDiag>; @@ -2777,7 +2790,7 @@ def AnyX86Interrupt : InheritableAttr, TargetSpecificAttr { // NOTE: If you add any additional spellings, ARMInterrupt's, - // MSP430Interrupt's and MipsInterrupt's spellings must match. + // M68kInterrupt's, MSP430Interrupt's and MipsInterrupt's spellings must match. let Spellings = [GCC<"interrupt">]; let Subjects = SubjectList<[HasFunctionProto]>; let ParseKind = "Interrupt"; diff --git a/clang/lib/Basic/CMakeLists.txt b/clang/lib/Basic/CMakeLists.txt --- a/clang/lib/Basic/CMakeLists.txt +++ b/clang/lib/Basic/CMakeLists.txt @@ -78,6 +78,7 @@ Targets/Hexagon.cpp Targets/Lanai.cpp Targets/Le64.cpp + Targets/M68k.cpp Targets/MSP430.cpp Targets/Mips.cpp Targets/NVPTX.cpp diff --git a/clang/lib/Basic/Targets.cpp b/clang/lib/Basic/Targets.cpp --- a/clang/lib/Basic/Targets.cpp +++ b/clang/lib/Basic/Targets.cpp @@ -22,6 +22,7 @@ #include "Targets/Hexagon.h" #include "Targets/Lanai.h" #include "Targets/Le64.h" +#include "Targets/M68k.h" #include "Targets/MSP430.h" #include "Targets/Mips.h" #include "Targets/NVPTX.h" @@ -303,6 +304,16 @@ return new MipsTargetInfo(Triple, Opts); } + case llvm::Triple::m68k: + switch (os) { + case llvm::Triple::Linux: + return new LinuxTargetInfo(Triple, Opts); + case llvm::Triple::NetBSD: + return new NetBSDTargetInfo(Triple, Opts); + default: + return new M68kTargetInfo(Triple, Opts); + } + case llvm::Triple::le32: switch (os) { case llvm::Triple::NaCl: diff --git a/clang/lib/Basic/Targets/M68k.h b/clang/lib/Basic/Targets/M68k.h new file mode 100644 --- /dev/null +++ b/clang/lib/Basic/Targets/M68k.h @@ -0,0 +1,57 @@ +//===--- M68k.h - Declare M68k 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 M68k TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_BASIC_TARGETS_M68K_H +#define LLVM_CLANG_LIB_BASIC_TARGETS_M68K_H + +#include "OSTargets.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 M68kTargetInfo : public TargetInfo { + static const char *const GCCRegNames[]; + + enum CPUKind { + CK_Unknown, + CK_68000, + CK_68010, + CK_68020, + CK_68030, + CK_68040, + CK_68060 + } CPU = CK_Unknown; + +public: + M68kTargetInfo(const llvm::Triple &Triple, const TargetOptions &); + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; + ArrayRef getTargetBuiltins() const override; + bool hasFeature(StringRef Feature) const override; + ArrayRef getGCCRegNames() const override; + ArrayRef getGCCRegAliases() const override; + bool validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &info) const override; + const char *getClobbers() const override; + BuiltinVaListKind getBuiltinVaListKind() const override; + bool setCPU(const std::string &Name) override; +}; + +} // namespace targets +} // namespace clang + +#endif diff --git a/clang/lib/Basic/Targets/M68k.cpp b/clang/lib/Basic/Targets/M68k.cpp new file mode 100644 --- /dev/null +++ b/clang/lib/Basic/Targets/M68k.cpp @@ -0,0 +1,168 @@ +//===--- M68k.cpp - Implement M68k targets 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 M68k TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#include "M68k.h" +#include "clang/Basic/Builtins.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/TargetBuiltins.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/Support/TargetParser.h" +#include + +namespace clang { +namespace targets { + +M68kTargetInfo::M68kTargetInfo(const llvm::Triple &Triple, + const TargetOptions &) + : TargetInfo(Triple) { + + std::string Layout = ""; + + // M68k is Big Endian + Layout += "E"; + + // FIXME how to wire it with the used object format? + Layout += "-m:e"; + + // M68k pointers are always 32 bit wide even for 16 bit cpus + Layout += "-p:32:32"; + + // M68k integer data types + Layout += "-i8:8:8-i16:16:16-i32:16:32"; + + // FIXME no floats at the moment + + // The registers can hold 8, 16, 32 bits + Layout += "-n8:16:32"; + + // 16 bit alignment for both stack and aggregate + // in order to conform to ABI used by GCC + Layout += "-a:0:16-S16"; + + resetDataLayout(Layout); + + SizeType = UnsignedInt; + PtrDiffType = SignedInt; + IntPtrType = SignedInt; +} + +bool M68kTargetInfo::setCPU(const std::string &Name) { + StringRef N = Name; + CPU = llvm::StringSwitch(N) + .Case("generic", CK_68000) + .Case("M68000", CK_68000) + .Case("M68010", CK_68010) + .Case("M68020", CK_68020) + .Case("M68030", CK_68030) + .Case("M68040", CK_68040) + .Case("M68060", CK_68060) + .Default(CK_Unknown); + return CPU != CK_Unknown; +} + +void M68kTargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + using llvm::Twine; + + Builder.defineMacro("__m68k__"); + + Builder.defineMacro("mc68000"); + Builder.defineMacro("__mc68000"); + Builder.defineMacro("__mc68000__"); + + // For sub-architecture + switch (CPU) { + case CK_68010: + Builder.defineMacro("mc68010"); + Builder.defineMacro("__mc68010"); + Builder.defineMacro("__mc68010__"); + break; + case CK_68020: + Builder.defineMacro("mc68020"); + Builder.defineMacro("__mc68020"); + Builder.defineMacro("__mc68020__"); + break; + case CK_68030: + Builder.defineMacro("mc68030"); + Builder.defineMacro("__mc68030"); + Builder.defineMacro("__mc68030__"); + break; + case CK_68040: + Builder.defineMacro("mc68040"); + Builder.defineMacro("__mc68040"); + Builder.defineMacro("__mc68040__"); + break; + case CK_68060: + Builder.defineMacro("mc68060"); + Builder.defineMacro("__mc68060"); + Builder.defineMacro("__mc68060__"); + break; + default: + break; + } +} + +ArrayRef M68kTargetInfo::getTargetBuiltins() const { + // FIXME: Implement. + return None; +} + +bool M68kTargetInfo::hasFeature(StringRef Feature) const { + // FIXME elaborate moar + return Feature == "M68000"; +} + +const char *const M68kTargetInfo::GCCRegNames[] = { + "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", + "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7", + "pc"}; + +ArrayRef M68kTargetInfo::getGCCRegNames() const { + return llvm::makeArrayRef(GCCRegNames); +} + +ArrayRef M68kTargetInfo::getGCCRegAliases() const { + // No aliases. + return None; +} + +bool M68kTargetInfo::validateAsmConstraint( + const char *&Name, TargetInfo::ConstraintInfo &info) const { + switch (*Name) { + case 'a': // address register + case 'd': // data register + case 'f': // floating point register + info.setAllowsRegister(); + return true; + case 'K': // the constant 1 + case 'L': // constant -1^20 .. 1^19 + case 'M': // constant 1-4: + return true; + } + // FIXME: Support all constraints like 'N', 'O', 'P', 'R' + return false; +} + +const char *M68kTargetInfo::getClobbers() const { + // FIXME: Is this really right? + return ""; +} + +M68kTargetInfo::BuiltinVaListKind M68kTargetInfo::getBuiltinVaListKind() const { + // FIXME: implement + llvm_unreachable("Not implemented yet"); +} + +} // namespace targets +} // namespace clang diff --git a/clang/lib/CodeGen/TargetInfo.cpp b/clang/lib/CodeGen/TargetInfo.cpp --- a/clang/lib/CodeGen/TargetInfo.cpp +++ b/clang/lib/CodeGen/TargetInfo.cpp @@ -8049,6 +8049,43 @@ return false; } +//===----------------------------------------------------------------------===// +// M68k ABI Implementation +//===----------------------------------------------------------------------===// + +namespace { + +class M68kTargetCodeGenInfo : public TargetCodeGenInfo { +public: + M68kTargetCodeGenInfo(CodeGenTypes &CGT) + : TargetCodeGenInfo(std::make_unique(CGT)) {} + void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV, + CodeGen::CodeGenModule &M) const override; +}; + +} // namespace + +void M68kTargetCodeGenInfo::setTargetAttributes( + const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &M) const { + if (const auto *FD = dyn_cast_or_null(D)) { + if (const auto *attr = FD->getAttr()) { + // Handle 'interrupt' attribute: + llvm::Function *F = cast(GV); + + // Step 1: Set ISR calling convention. + F->setCallingConv(llvm::CallingConv::M68k_INTR); + + // Step 2: Add attributes goodness. + F->addFnAttr(llvm::Attribute::NoInline); + + // Step 3: Emit ISR vector alias. + unsigned Num = attr->getNumber() / 2; + llvm::GlobalAlias::create(llvm::Function::ExternalLinkage, + "__isr_" + Twine(Num), F); + } + } +} + //===----------------------------------------------------------------------===// // AVR ABI Implementation. //===----------------------------------------------------------------------===// @@ -10876,6 +10913,8 @@ case llvm::Triple::le32: return SetCGInfo(new PNaClTargetCodeGenInfo(Types)); + case llvm::Triple::m68k: + return SetCGInfo(new M68kTargetCodeGenInfo(Types)); case llvm::Triple::mips: case llvm::Triple::mipsel: if (Triple.getOS() == llvm::Triple::NaCl) diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -6641,6 +6641,39 @@ D->addAttr(::new (S.Context) MipsInterruptAttr(S.Context, AL, Kind)); } +static void handleM68kInterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (!checkAttributeNumArgs(S, AL, 1)) + return; + + if (!AL.isArgExpr(0)) { + S.Diag(AL.getLoc(), diag::err_attribute_argument_type) + << AL << AANT_ArgumentIntegerConstant; + return; + } + + // FIXME: Check for decl - it should be void ()(void). + + Expr *NumParamsExpr = static_cast(AL.getArgAsExpr(0)); + auto MaybeNumParams = NumParamsExpr->getIntegerConstantExpr(S.Context); + if (!MaybeNumParams) { + S.Diag(AL.getLoc(), diag::err_attribute_argument_type) + << AL << AANT_ArgumentIntegerConstant + << NumParamsExpr->getSourceRange(); + return; + } + + unsigned Num = MaybeNumParams->getLimitedValue(255); + if ((Num & 1) || Num > 30) { + S.Diag(AL.getLoc(), diag::err_attribute_argument_out_of_bounds) + << AL << (int)MaybeNumParams->getSExtValue() + << NumParamsExpr->getSourceRange(); + return; + } + + D->addAttr(::new (S.Context) M68kInterruptAttr(S.Context, AL, Num)); + D->addAttr(UsedAttr::CreateImplicit(S.Context)); +} + static void handleAnyX86InterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // Semantic checks for a function with the 'interrupt' attribute. // a) Must be a function. @@ -6913,6 +6946,9 @@ case llvm::Triple::mips: handleMipsInterruptAttr(S, D, AL); break; + case llvm::Triple::m68k: + handleM68kInterruptAttr(S, D, AL); + break; case llvm::Triple::x86: case llvm::Triple::x86_64: handleAnyX86InterruptAttr(S, D, AL);