1//===--- M68k.cpp - Implement M68k targets feature support-------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file implements M68k TargetInfo objects.
10//
11//===----------------------------------------------------------------------===//
12
13#include "M68k.h"
14#include "clang/Basic/Builtins.h"
15#include "clang/Basic/Diagnostic.h"
16#include "clang/Basic/TargetBuiltins.h"
17#include "llvm/ADT/StringExtras.h"
18#include "llvm/ADT/StringRef.h"
19#include "llvm/ADT/StringSwitch.h"
20#include "llvm/TargetParser/TargetParser.h"
21#include <cstdint>
22#include <cstring>
23#include <limits>
24#include <optional>
25
26namespace clang {
27namespace targets {
28
29M68kTargetInfo::M68kTargetInfo(const llvm::Triple &Triple,
30                               const TargetOptions &Opts)
31    : TargetInfo(Triple), TargetOpts(Opts) {
32
33  std::string Layout;
34
35  // M68k is Big Endian
36  Layout += "E";
37
38  // FIXME how to wire it with the used object format?
39  Layout += "-m:e";
40
41  // M68k pointers are always 32 bit wide even for 16-bit CPUs
42  Layout += "-p:32:16:32";
43
44  // M68k integer data types
45  Layout += "-i8:8:8-i16:16:16-i32:16:32";
46
47  // FIXME no floats at the moment
48
49  // The registers can hold 8, 16, 32 bits
50  Layout += "-n8:16:32";
51
52  // 16 bit alignment for both stack and aggregate
53  // in order to conform to ABI used by GCC
54  Layout += "-a:0:16-S16";
55
56  resetDataLayout(Layout);
57
58  SizeType = UnsignedInt;
59  PtrDiffType = SignedInt;
60  IntPtrType = SignedInt;
61}
62
63bool M68kTargetInfo::setCPU(const std::string &Name) {
64  StringRef N = Name;
65  CPU = llvm::StringSwitch<CPUKind>(N)
66            .Case("generic", CK_68000)
67            .Case("M68000", CK_68000)
68            .Case("M68010", CK_68010)
69            .Case("M68020", CK_68020)
70            .Case("M68030", CK_68030)
71            .Case("M68040", CK_68040)
72            .Case("M68060", CK_68060)
73            .Default(CK_Unknown);
74  return CPU != CK_Unknown;
75}
76
77void M68kTargetInfo::getTargetDefines(const LangOptions &Opts,
78                                      MacroBuilder &Builder) const {
79  using llvm::Twine;
80
81  Builder.defineMacro("__m68k__");
82
83  DefineStd(Builder, "mc68000", Opts);
84
85  // For sub-architecture
86  switch (CPU) {
87  case CK_68010:
88    DefineStd(Builder, "mc68010", Opts);
89    break;
90  case CK_68020:
91    DefineStd(Builder, "mc68020", Opts);
92    break;
93  case CK_68030:
94    DefineStd(Builder, "mc68030", Opts);
95    break;
96  case CK_68040:
97    DefineStd(Builder, "mc68040", Opts);
98    break;
99  case CK_68060:
100    DefineStd(Builder, "mc68060", Opts);
101    break;
102  default:
103    break;
104  }
105
106  if (CPU >= CK_68020) {
107    Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1");
108    Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2");
109    Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4");
110  }
111
112  // Floating point
113  if (TargetOpts.FeatureMap.lookup("isa-68881") ||
114      TargetOpts.FeatureMap.lookup("isa-68882"))
115    Builder.defineMacro("__HAVE_68881__");
116}
117
118ArrayRef<Builtin::Info> M68kTargetInfo::getTargetBuiltins() const {
119  // FIXME: Implement.
120  return std::nullopt;
121}
122
123bool M68kTargetInfo::hasFeature(StringRef Feature) const {
124  // FIXME elaborate moar
125  return Feature == "M68000";
126}
127
128const char *const M68kTargetInfo::GCCRegNames[] = {
129    "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7",
130    "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7",
131    "pc"};
132
133ArrayRef<const char *> M68kTargetInfo::getGCCRegNames() const {
134  return llvm::ArrayRef(GCCRegNames);
135}
136
137ArrayRef<TargetInfo::GCCRegAlias> M68kTargetInfo::getGCCRegAliases() const {
138  // No aliases.
139  return std::nullopt;
140}
141
142bool M68kTargetInfo::validateAsmConstraint(
143    const char *&Name, TargetInfo::ConstraintInfo &info) const {
144  switch (*Name) {
145  case 'a': // address register
146  case 'd': // data register
147    info.setAllowsRegister();
148    return true;
149  case 'I': // constant integer in the range [1,8]
150    info.setRequiresImmediate(1, 8);
151    return true;
152  case 'J': // constant signed 16-bit integer
153    info.setRequiresImmediate(std::numeric_limits<int16_t>::min(),
154                              std::numeric_limits<int16_t>::max());
155    return true;
156  case 'K': // constant that is NOT in the range of [-0x80, 0x80)
157    info.setRequiresImmediate();
158    return true;
159  case 'L': // constant integer in the range [-8,-1]
160    info.setRequiresImmediate(-8, -1);
161    return true;
162  case 'M': // constant that is NOT in the range of [-0x100, 0x100]
163    info.setRequiresImmediate();
164    return true;
165  case 'N': // constant integer in the range [24,31]
166    info.setRequiresImmediate(24, 31);
167    return true;
168  case 'O': // constant integer 16
169    info.setRequiresImmediate(16);
170    return true;
171  case 'P': // constant integer in the range [8,15]
172    info.setRequiresImmediate(8, 15);
173    return true;
174  case 'C':
175    ++Name;
176    switch (*Name) {
177    case '0': // constant integer 0
178      info.setRequiresImmediate(0);
179      return true;
180    case 'i': // constant integer
181    case 'j': // integer constant that doesn't fit in 16 bits
182      info.setRequiresImmediate();
183      return true;
184    default:
185      break;
186    }
187    break;
188  case 'Q': // address register indirect addressing
189  case 'U': // address register indirect w/ constant offset addressing
190    // TODO: Handle 'S' (basically 'm' when pc-rel is enforced) when
191    // '-mpcrel' flag is properly handled by the driver.
192    info.setAllowsMemory();
193    return true;
194  default:
195    break;
196  }
197  return false;
198}
199
200std::optional<std::string>
201M68kTargetInfo::handleAsmEscapedChar(char EscChar) const {
202  char C;
203  switch (EscChar) {
204  case '.':
205  case '#':
206    C = EscChar;
207    break;
208  case '/':
209    C = '%';
210    break;
211  case '$':
212    C = 's';
213    break;
214  case '&':
215    C = 'd';
216    break;
217  default:
218    return std::nullopt;
219  }
220
221  return std::string(1, C);
222}
223
224std::string M68kTargetInfo::convertConstraint(const char *&Constraint) const {
225  if (*Constraint == 'C')
226    // Two-character constraint; add "^" hint for later parsing
227    return std::string("^") + std::string(Constraint++, 2);
228
229  return std::string(1, *Constraint);
230}
231
232std::string_view M68kTargetInfo::getClobbers() const {
233  // FIXME: Is this really right?
234  return "";
235}
236
237TargetInfo::BuiltinVaListKind M68kTargetInfo::getBuiltinVaListKind() const {
238  return TargetInfo::VoidPtrBuiltinVaList;
239}
240
241TargetInfo::CallingConvCheckResult
242M68kTargetInfo::checkCallingConvention(CallingConv CC) const {
243  switch (CC) {
244  case CC_C:
245  case CC_M68kRTD:
246    return CCCR_OK;
247  default:
248    return TargetInfo::checkCallingConvention(CC);
249  }
250}
251} // namespace targets
252} // namespace clang
253