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