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