/src/llvm-project/clang/lib/Basic/Targets/M68k.cpp
Line | Count | Source (jump to first uncovered line) |
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 | 0 | : TargetInfo(Triple), TargetOpts(Opts) { |
32 | |
|
33 | 0 | std::string Layout; |
34 | | |
35 | | // M68k is Big Endian |
36 | 0 | Layout += "E"; |
37 | | |
38 | | // FIXME how to wire it with the used object format? |
39 | 0 | Layout += "-m:e"; |
40 | | |
41 | | // M68k pointers are always 32 bit wide even for 16-bit CPUs |
42 | 0 | Layout += "-p:32:16:32"; |
43 | | |
44 | | // M68k integer data types |
45 | 0 | 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 | 0 | 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 | 0 | Layout += "-a:0:16-S16"; |
55 | |
|
56 | 0 | resetDataLayout(Layout); |
57 | |
|
58 | 0 | SizeType = UnsignedInt; |
59 | 0 | PtrDiffType = SignedInt; |
60 | 0 | IntPtrType = SignedInt; |
61 | 0 | } |
62 | | |
63 | 0 | bool M68kTargetInfo::setCPU(const std::string &Name) { |
64 | 0 | StringRef N = Name; |
65 | 0 | CPU = llvm::StringSwitch<CPUKind>(N) |
66 | 0 | .Case("generic", CK_68000) |
67 | 0 | .Case("M68000", CK_68000) |
68 | 0 | .Case("M68010", CK_68010) |
69 | 0 | .Case("M68020", CK_68020) |
70 | 0 | .Case("M68030", CK_68030) |
71 | 0 | .Case("M68040", CK_68040) |
72 | 0 | .Case("M68060", CK_68060) |
73 | 0 | .Default(CK_Unknown); |
74 | 0 | return CPU != CK_Unknown; |
75 | 0 | } |
76 | | |
77 | | void M68kTargetInfo::getTargetDefines(const LangOptions &Opts, |
78 | 0 | MacroBuilder &Builder) const { |
79 | 0 | using llvm::Twine; |
80 | |
|
81 | 0 | Builder.defineMacro("__m68k__"); |
82 | |
|
83 | 0 | DefineStd(Builder, "mc68000", Opts); |
84 | | |
85 | | // For sub-architecture |
86 | 0 | switch (CPU) { |
87 | 0 | case CK_68010: |
88 | 0 | DefineStd(Builder, "mc68010", Opts); |
89 | 0 | break; |
90 | 0 | case CK_68020: |
91 | 0 | DefineStd(Builder, "mc68020", Opts); |
92 | 0 | break; |
93 | 0 | case CK_68030: |
94 | 0 | DefineStd(Builder, "mc68030", Opts); |
95 | 0 | break; |
96 | 0 | case CK_68040: |
97 | 0 | DefineStd(Builder, "mc68040", Opts); |
98 | 0 | break; |
99 | 0 | case CK_68060: |
100 | 0 | DefineStd(Builder, "mc68060", Opts); |
101 | 0 | break; |
102 | 0 | default: |
103 | 0 | break; |
104 | 0 | } |
105 | | |
106 | 0 | if (CPU >= CK_68020) { |
107 | 0 | Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1"); |
108 | 0 | Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2"); |
109 | 0 | Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4"); |
110 | 0 | } |
111 | | |
112 | | // Floating point |
113 | 0 | if (TargetOpts.FeatureMap.lookup("isa-68881") || |
114 | 0 | TargetOpts.FeatureMap.lookup("isa-68882")) |
115 | 0 | Builder.defineMacro("__HAVE_68881__"); |
116 | 0 | } |
117 | | |
118 | 0 | ArrayRef<Builtin::Info> M68kTargetInfo::getTargetBuiltins() const { |
119 | | // FIXME: Implement. |
120 | 0 | return std::nullopt; |
121 | 0 | } |
122 | | |
123 | 0 | bool M68kTargetInfo::hasFeature(StringRef Feature) const { |
124 | | // FIXME elaborate moar |
125 | 0 | return Feature == "M68000"; |
126 | 0 | } |
127 | | |
128 | | const 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 | | |
133 | 0 | ArrayRef<const char *> M68kTargetInfo::getGCCRegNames() const { |
134 | 0 | return llvm::ArrayRef(GCCRegNames); |
135 | 0 | } |
136 | | |
137 | 0 | ArrayRef<TargetInfo::GCCRegAlias> M68kTargetInfo::getGCCRegAliases() const { |
138 | | // No aliases. |
139 | 0 | return std::nullopt; |
140 | 0 | } |
141 | | |
142 | | bool M68kTargetInfo::validateAsmConstraint( |
143 | 0 | const char *&Name, TargetInfo::ConstraintInfo &info) const { |
144 | 0 | switch (*Name) { |
145 | 0 | case 'a': // address register |
146 | 0 | case 'd': // data register |
147 | 0 | info.setAllowsRegister(); |
148 | 0 | return true; |
149 | 0 | case 'I': // constant integer in the range [1,8] |
150 | 0 | info.setRequiresImmediate(1, 8); |
151 | 0 | return true; |
152 | 0 | case 'J': // constant signed 16-bit integer |
153 | 0 | info.setRequiresImmediate(std::numeric_limits<int16_t>::min(), |
154 | 0 | std::numeric_limits<int16_t>::max()); |
155 | 0 | return true; |
156 | 0 | case 'K': // constant that is NOT in the range of [-0x80, 0x80) |
157 | 0 | info.setRequiresImmediate(); |
158 | 0 | return true; |
159 | 0 | case 'L': // constant integer in the range [-8,-1] |
160 | 0 | info.setRequiresImmediate(-8, -1); |
161 | 0 | return true; |
162 | 0 | case 'M': // constant that is NOT in the range of [-0x100, 0x100] |
163 | 0 | info.setRequiresImmediate(); |
164 | 0 | return true; |
165 | 0 | case 'N': // constant integer in the range [24,31] |
166 | 0 | info.setRequiresImmediate(24, 31); |
167 | 0 | return true; |
168 | 0 | case 'O': // constant integer 16 |
169 | 0 | info.setRequiresImmediate(16); |
170 | 0 | return true; |
171 | 0 | case 'P': // constant integer in the range [8,15] |
172 | 0 | info.setRequiresImmediate(8, 15); |
173 | 0 | return true; |
174 | 0 | case 'C': |
175 | 0 | ++Name; |
176 | 0 | switch (*Name) { |
177 | 0 | case '0': // constant integer 0 |
178 | 0 | info.setRequiresImmediate(0); |
179 | 0 | return true; |
180 | 0 | case 'i': // constant integer |
181 | 0 | case 'j': // integer constant that doesn't fit in 16 bits |
182 | 0 | info.setRequiresImmediate(); |
183 | 0 | return true; |
184 | 0 | default: |
185 | 0 | break; |
186 | 0 | } |
187 | 0 | break; |
188 | 0 | case 'Q': // address register indirect addressing |
189 | 0 | 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 | 0 | info.setAllowsMemory(); |
193 | 0 | return true; |
194 | 0 | default: |
195 | 0 | break; |
196 | 0 | } |
197 | 0 | return false; |
198 | 0 | } |
199 | | |
200 | | std::optional<std::string> |
201 | 0 | M68kTargetInfo::handleAsmEscapedChar(char EscChar) const { |
202 | 0 | char C; |
203 | 0 | switch (EscChar) { |
204 | 0 | case '.': |
205 | 0 | case '#': |
206 | 0 | C = EscChar; |
207 | 0 | break; |
208 | 0 | case '/': |
209 | 0 | C = '%'; |
210 | 0 | break; |
211 | 0 | case '$': |
212 | 0 | C = 's'; |
213 | 0 | break; |
214 | 0 | case '&': |
215 | 0 | C = 'd'; |
216 | 0 | break; |
217 | 0 | default: |
218 | 0 | return std::nullopt; |
219 | 0 | } |
220 | | |
221 | 0 | return std::string(1, C); |
222 | 0 | } |
223 | | |
224 | 0 | std::string M68kTargetInfo::convertConstraint(const char *&Constraint) const { |
225 | 0 | if (*Constraint == 'C') |
226 | | // Two-character constraint; add "^" hint for later parsing |
227 | 0 | return std::string("^") + std::string(Constraint++, 2); |
228 | | |
229 | 0 | return std::string(1, *Constraint); |
230 | 0 | } |
231 | | |
232 | 0 | std::string_view M68kTargetInfo::getClobbers() const { |
233 | | // FIXME: Is this really right? |
234 | 0 | return ""; |
235 | 0 | } |
236 | | |
237 | 0 | TargetInfo::BuiltinVaListKind M68kTargetInfo::getBuiltinVaListKind() const { |
238 | 0 | return TargetInfo::VoidPtrBuiltinVaList; |
239 | 0 | } |
240 | | |
241 | | TargetInfo::CallingConvCheckResult |
242 | 0 | M68kTargetInfo::checkCallingConvention(CallingConv CC) const { |
243 | 0 | switch (CC) { |
244 | 0 | case CC_C: |
245 | 0 | case CC_M68kRTD: |
246 | 0 | return CCCR_OK; |
247 | 0 | default: |
248 | 0 | return TargetInfo::checkCallingConvention(CC); |
249 | 0 | } |
250 | 0 | } |
251 | | } // namespace targets |
252 | | } // namespace clang |