1 | //= LoongArchBaseInfo.cpp - Top level definitions for LoongArch MC -*- C++ -*-// |
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 helper functions for the LoongArch target useful for the |
10 | // compiler back-end and the MC libraries. |
11 | // |
12 | //===----------------------------------------------------------------------===// |
13 | |
14 | #include "LoongArchBaseInfo.h" |
15 | #include "LoongArchMCTargetDesc.h" |
16 | #include "llvm/ADT/ArrayRef.h" |
17 | #include "llvm/MC/MCSubtargetInfo.h" |
18 | #include "llvm/Support/ErrorHandling.h" |
19 | #include "llvm/Support/raw_ostream.h" |
20 | #include "llvm/TargetParser/Triple.h" |
21 | |
22 | namespace llvm { |
23 | |
24 | namespace LoongArchABI { |
25 | |
26 | // Check if ABI has been standardized; issue a warning if it hasn't. |
27 | // FIXME: Once all ABIs are standardized, this will be removed. |
28 | static ABI checkABIStandardized(ABI Abi) { |
29 | StringRef ABIName; |
30 | switch (Abi) { |
31 | case ABI_ILP32S: |
32 | ABIName = "ilp32s" ; |
33 | break; |
34 | case ABI_ILP32F: |
35 | ABIName = "ilp32f" ; |
36 | break; |
37 | case ABI_ILP32D: |
38 | ABIName = "ilp32d" ; |
39 | break; |
40 | case ABI_LP64F: |
41 | ABIName = "lp64f" ; |
42 | break; |
43 | case ABI_LP64S: |
44 | case ABI_LP64D: |
45 | return Abi; |
46 | default: |
47 | llvm_unreachable("" ); |
48 | } |
49 | errs() << "warning: '" << ABIName << "' has not been standardized\n" ; |
50 | return Abi; |
51 | } |
52 | |
53 | static ABI getTripleABI(const Triple &TT) { |
54 | bool Is64Bit = TT.isArch64Bit(); |
55 | ABI TripleABI; |
56 | switch (TT.getEnvironment()) { |
57 | case llvm::Triple::EnvironmentType::GNUSF: |
58 | TripleABI = Is64Bit ? ABI_LP64S : ABI_ILP32S; |
59 | break; |
60 | case llvm::Triple::EnvironmentType::GNUF32: |
61 | TripleABI = Is64Bit ? ABI_LP64F : ABI_ILP32F; |
62 | break; |
63 | // Let the fallback case behave like {ILP32,LP64}D. |
64 | case llvm::Triple::EnvironmentType::GNUF64: |
65 | default: |
66 | TripleABI = Is64Bit ? ABI_LP64D : ABI_ILP32D; |
67 | break; |
68 | } |
69 | return TripleABI; |
70 | } |
71 | |
72 | ABI computeTargetABI(const Triple &TT, const FeatureBitset &FeatureBits, |
73 | StringRef ABIName) { |
74 | bool Is64Bit = TT.isArch64Bit(); |
75 | ABI ArgProvidedABI = getTargetABI(ABIName); |
76 | ABI TripleABI = getTripleABI(TT); |
77 | |
78 | auto IsABIValidForFeature = [=](ABI Abi) { |
79 | switch (Abi) { |
80 | default: |
81 | return false; |
82 | case ABI_ILP32S: |
83 | return !Is64Bit; |
84 | case ABI_ILP32F: |
85 | return !Is64Bit && FeatureBits[LoongArch::FeatureBasicF]; |
86 | case ABI_ILP32D: |
87 | return !Is64Bit && FeatureBits[LoongArch::FeatureBasicD]; |
88 | case ABI_LP64S: |
89 | return Is64Bit; |
90 | case ABI_LP64F: |
91 | return Is64Bit && FeatureBits[LoongArch::FeatureBasicF]; |
92 | case ABI_LP64D: |
93 | return Is64Bit && FeatureBits[LoongArch::FeatureBasicD]; |
94 | } |
95 | }; |
96 | |
97 | // 1. If the '-target-abi' is valid, use it. |
98 | if (IsABIValidForFeature(ArgProvidedABI)) { |
99 | if (TT.hasEnvironment() && ArgProvidedABI != TripleABI) |
100 | errs() |
101 | << "warning: triple-implied ABI conflicts with provided target-abi '" |
102 | << ABIName << "', using target-abi\n" ; |
103 | return checkABIStandardized(Abi: ArgProvidedABI); |
104 | } |
105 | |
106 | // 2. If the triple-implied ABI is valid, use it. |
107 | if (IsABIValidForFeature(TripleABI)) { |
108 | // If target-abi is not specified, use the valid triple-implied ABI. |
109 | if (ABIName.empty()) |
110 | return checkABIStandardized(Abi: TripleABI); |
111 | |
112 | switch (ArgProvidedABI) { |
113 | case ABI_Unknown: |
114 | // Fallback to the triple-implied ABI if ABI name is specified but |
115 | // invalid. |
116 | errs() << "warning: the '" << ABIName |
117 | << "' is not a recognized ABI for this target, ignoring and " |
118 | "using triple-implied ABI\n" ; |
119 | return checkABIStandardized(Abi: TripleABI); |
120 | case ABI_ILP32S: |
121 | case ABI_ILP32F: |
122 | case ABI_ILP32D: |
123 | if (Is64Bit) { |
124 | errs() << "warning: 32-bit ABIs are not supported for 64-bit targets, " |
125 | "ignoring and using triple-implied ABI\n" ; |
126 | return checkABIStandardized(Abi: TripleABI); |
127 | } |
128 | break; |
129 | case ABI_LP64S: |
130 | case ABI_LP64F: |
131 | case ABI_LP64D: |
132 | if (!Is64Bit) { |
133 | errs() << "warning: 64-bit ABIs are not supported for 32-bit targets, " |
134 | "ignoring and using triple-implied ABI\n" ; |
135 | return checkABIStandardized(Abi: TripleABI); |
136 | } |
137 | break; |
138 | } |
139 | |
140 | switch (ArgProvidedABI) { |
141 | case ABI_ILP32F: |
142 | case ABI_LP64F: |
143 | errs() << "warning: the '" << ABIName |
144 | << "' ABI can't be used for a target that doesn't support the 'F' " |
145 | "instruction set, ignoring and using triple-implied ABI\n" ; |
146 | break; |
147 | case ABI_ILP32D: |
148 | case ABI_LP64D: |
149 | errs() << "warning: the '" << ABIName |
150 | << "' ABI can't be used for a target that doesn't support the 'D' " |
151 | "instruction set, ignoring and using triple-implied ABI\n" ; |
152 | break; |
153 | default: |
154 | llvm_unreachable("" ); |
155 | } |
156 | return checkABIStandardized(Abi: TripleABI); |
157 | } |
158 | |
159 | // 3. Parse the 'feature-abi', and use it. |
160 | auto GetFeatureABI = [=]() { |
161 | if (FeatureBits[LoongArch::FeatureBasicD]) |
162 | return Is64Bit ? ABI_LP64D : ABI_ILP32D; |
163 | if (FeatureBits[LoongArch::FeatureBasicF]) |
164 | return Is64Bit ? ABI_LP64F : ABI_ILP32F; |
165 | return Is64Bit ? ABI_LP64S : ABI_ILP32S; |
166 | }; |
167 | if (ABIName.empty()) |
168 | errs() << "warning: the triple-implied ABI is invalid, ignoring and using " |
169 | "feature-implied ABI\n" ; |
170 | else |
171 | errs() << "warning: both target-abi and the triple-implied ABI are " |
172 | "invalid, ignoring and using feature-implied ABI\n" ; |
173 | return checkABIStandardized(Abi: GetFeatureABI()); |
174 | } |
175 | |
176 | ABI getTargetABI(StringRef ABIName) { |
177 | auto TargetABI = StringSwitch<ABI>(ABIName) |
178 | .Case(S: "ilp32s" , Value: ABI_ILP32S) |
179 | .Case(S: "ilp32f" , Value: ABI_ILP32F) |
180 | .Case(S: "ilp32d" , Value: ABI_ILP32D) |
181 | .Case(S: "lp64s" , Value: ABI_LP64S) |
182 | .Case(S: "lp64f" , Value: ABI_LP64F) |
183 | .Case(S: "lp64d" , Value: ABI_LP64D) |
184 | .Default(Value: ABI_Unknown); |
185 | return TargetABI; |
186 | } |
187 | |
188 | // To avoid the BP value clobbered by a function call, we need to choose a |
189 | // callee saved register to save the value. The `last` `S` register (s9) is |
190 | // used for FP. So we choose the previous (s8) as BP. |
191 | MCRegister getBPReg() { return LoongArch::R31; } |
192 | |
193 | } // end namespace LoongArchABI |
194 | |
195 | } // end namespace llvm |
196 | |