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 
26 namespace clang {
27 namespace targets {
28 
29 M68kTargetInfo::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 
63 bool 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 
77 void M68kTargetInfo::getTargetDefines(const LangOptions &Opts,
78                                       MacroBuilder &Builder) const {
79   using llvm::Twine;
80 
81   Builder.defineMacro("__m68k__");
82 
83   Builder.defineMacro("mc68000");
84   Builder.defineMacro("__mc68000");
85   Builder.defineMacro("__mc68000__");
86 
87   // For sub-architecture
88   switch (CPU) {
89   case CK_68010:
90     Builder.defineMacro("mc68010");
91     Builder.defineMacro("__mc68010");
92     Builder.defineMacro("__mc68010__");
93     break;
94   case CK_68020:
95     Builder.defineMacro("mc68020");
96     Builder.defineMacro("__mc68020");
97     Builder.defineMacro("__mc68020__");
98     break;
99   case CK_68030:
100     Builder.defineMacro("mc68030");
101     Builder.defineMacro("__mc68030");
102     Builder.defineMacro("__mc68030__");
103     break;
104   case CK_68040:
105     Builder.defineMacro("mc68040");
106     Builder.defineMacro("__mc68040");
107     Builder.defineMacro("__mc68040__");
108     break;
109   case CK_68060:
110     Builder.defineMacro("mc68060");
111     Builder.defineMacro("__mc68060");
112     Builder.defineMacro("__mc68060__");
113     break;
114   default:
115     break;
116   }
117 
118   if (CPU >= CK_68020) {
119     Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1");
120     Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2");
121     Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4");
122   }
123 
124   // Floating point
125   if (TargetOpts.FeatureMap.lookup("isa-68881") ||
126       TargetOpts.FeatureMap.lookup("isa-68882"))
127     Builder.defineMacro("__HAVE_68881__");
128 }
129 
130 ArrayRef<Builtin::Info> M68kTargetInfo::getTargetBuiltins() const {
131   // FIXME: Implement.
132   return std::nullopt;
133 }
134 
135 bool M68kTargetInfo::hasFeature(StringRef Feature) const {
136   // FIXME elaborate moar
137   return Feature == "M68000";
138 }
139 
140 const char *const M68kTargetInfo::GCCRegNames[] = {
141     "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7",
142     "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7",
143     "pc"};
144 
145 ArrayRef<const char *> M68kTargetInfo::getGCCRegNames() const {
146   return llvm::ArrayRef(GCCRegNames);
147 }
148 
149 ArrayRef<TargetInfo::GCCRegAlias> M68kTargetInfo::getGCCRegAliases() const {
150   // No aliases.
151   return std::nullopt;
152 }
153 
154 bool M68kTargetInfo::validateAsmConstraint(
155     const char *&Name, TargetInfo::ConstraintInfo &info) const {
156   switch (*Name) {
157   case 'a': // address register
158   case 'd': // data register
159     info.setAllowsRegister();
160     return true;
161   case 'I': // constant integer in the range [1,8]
162     info.setRequiresImmediate(1, 8);
163     return true;
164   case 'J': // constant signed 16-bit integer
165     info.setRequiresImmediate(std::numeric_limits<int16_t>::min(),
166                               std::numeric_limits<int16_t>::max());
167     return true;
168   case 'K': // constant that is NOT in the range of [-0x80, 0x80)
169     info.setRequiresImmediate();
170     return true;
171   case 'L': // constant integer in the range [-8,-1]
172     info.setRequiresImmediate(-8, -1);
173     return true;
174   case 'M': // constant that is NOT in the range of [-0x100, 0x100]
175     info.setRequiresImmediate();
176     return true;
177   case 'N': // constant integer in the range [24,31]
178     info.setRequiresImmediate(24, 31);
179     return true;
180   case 'O': // constant integer 16
181     info.setRequiresImmediate(16);
182     return true;
183   case 'P': // constant integer in the range [8,15]
184     info.setRequiresImmediate(8, 15);
185     return true;
186   case 'C':
187     ++Name;
188     switch (*Name) {
189     case '0': // constant integer 0
190       info.setRequiresImmediate(0);
191       return true;
192     case 'i': // constant integer
193     case 'j': // integer constant that doesn't fit in 16 bits
194       info.setRequiresImmediate();
195       return true;
196     default:
197       break;
198     }
199     break;
200   case 'Q': // address register indirect addressing
201   case 'U': // address register indirect w/ constant offset addressing
202     // TODO: Handle 'S' (basically 'm' when pc-rel is enforced) when
203     // '-mpcrel' flag is properly handled by the driver.
204     info.setAllowsMemory();
205     return true;
206   default:
207     break;
208   }
209   return false;
210 }
211 
212 std::optional<std::string>
213 M68kTargetInfo::handleAsmEscapedChar(char EscChar) const {
214   char C;
215   switch (EscChar) {
216   case '.':
217   case '#':
218     C = EscChar;
219     break;
220   case '/':
221     C = '%';
222     break;
223   case '$':
224     C = 's';
225     break;
226   case '&':
227     C = 'd';
228     break;
229   default:
230     return std::nullopt;
231   }
232 
233   return std::string(1, C);
234 }
235 
236 std::string M68kTargetInfo::convertConstraint(const char *&Constraint) const {
237   if (*Constraint == 'C')
238     // Two-character constraint; add "^" hint for later parsing
239     return std::string("^") + std::string(Constraint++, 2);
240 
241   return std::string(1, *Constraint);
242 }
243 
244 std::string_view M68kTargetInfo::getClobbers() const {
245   // FIXME: Is this really right?
246   return "";
247 }
248 
249 TargetInfo::BuiltinVaListKind M68kTargetInfo::getBuiltinVaListKind() const {
250   return TargetInfo::VoidPtrBuiltinVaList;
251 }
252 
253 } // namespace targets
254 } // namespace clang
255