Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/llvm/lib/IR/InlineAsm.cpp
35234 views
1
//===- InlineAsm.cpp - Implement the InlineAsm class ----------------------===//
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 the InlineAsm class.
10
//
11
//===----------------------------------------------------------------------===//
12
13
#include "llvm/IR/InlineAsm.h"
14
#include "ConstantsContext.h"
15
#include "LLVMContextImpl.h"
16
#include "llvm/ADT/StringRef.h"
17
#include "llvm/IR/DerivedTypes.h"
18
#include "llvm/IR/LLVMContext.h"
19
#include "llvm/IR/Value.h"
20
#include "llvm/Support/Casting.h"
21
#include "llvm/Support/Compiler.h"
22
#include "llvm/Support/Errc.h"
23
#include <algorithm>
24
#include <cassert>
25
#include <cctype>
26
#include <cstdlib>
27
28
using namespace llvm;
29
30
InlineAsm::InlineAsm(FunctionType *FTy, const std::string &asmString,
31
const std::string &constraints, bool hasSideEffects,
32
bool isAlignStack, AsmDialect asmDialect, bool canThrow)
33
: Value(PointerType::getUnqual(FTy), Value::InlineAsmVal),
34
AsmString(asmString), Constraints(constraints), FTy(FTy),
35
HasSideEffects(hasSideEffects), IsAlignStack(isAlignStack),
36
Dialect(asmDialect), CanThrow(canThrow) {
37
#ifndef NDEBUG
38
// Do various checks on the constraint string and type.
39
cantFail(verify(getFunctionType(), constraints));
40
#endif
41
}
42
43
InlineAsm *InlineAsm::get(FunctionType *FTy, StringRef AsmString,
44
StringRef Constraints, bool hasSideEffects,
45
bool isAlignStack, AsmDialect asmDialect,
46
bool canThrow) {
47
InlineAsmKeyType Key(AsmString, Constraints, FTy, hasSideEffects,
48
isAlignStack, asmDialect, canThrow);
49
LLVMContextImpl *pImpl = FTy->getContext().pImpl;
50
return pImpl->InlineAsms.getOrCreate(PointerType::getUnqual(FTy), Key);
51
}
52
53
void InlineAsm::destroyConstant() {
54
getType()->getContext().pImpl->InlineAsms.remove(this);
55
delete this;
56
}
57
58
FunctionType *InlineAsm::getFunctionType() const {
59
return FTy;
60
}
61
62
void InlineAsm::collectAsmStrs(SmallVectorImpl<StringRef> &AsmStrs) const {
63
StringRef AsmStr(AsmString);
64
AsmStrs.clear();
65
66
// TODO: 1) Unify delimiter for inline asm, we also meet other delimiters
67
// for example "\0A", ";".
68
// 2) Enhance StringRef. Some of the special delimiter ("\0") can't be
69
// split in StringRef. Also empty StringRef can not call split (will stuck).
70
if (AsmStr.empty())
71
return;
72
AsmStr.split(AsmStrs, "\n\t", -1, false);
73
}
74
75
/// Parse - Analyze the specified string (e.g. "==&{eax}") and fill in the
76
/// fields in this structure. If the constraint string is not understood,
77
/// return true, otherwise return false.
78
bool InlineAsm::ConstraintInfo::Parse(StringRef Str,
79
InlineAsm::ConstraintInfoVector &ConstraintsSoFar) {
80
StringRef::iterator I = Str.begin(), E = Str.end();
81
unsigned multipleAlternativeCount = Str.count('|') + 1;
82
unsigned multipleAlternativeIndex = 0;
83
ConstraintCodeVector *pCodes = &Codes;
84
85
// Initialize
86
isMultipleAlternative = multipleAlternativeCount > 1;
87
if (isMultipleAlternative) {
88
multipleAlternatives.resize(multipleAlternativeCount);
89
pCodes = &multipleAlternatives[0].Codes;
90
}
91
Type = isInput;
92
isEarlyClobber = false;
93
MatchingInput = -1;
94
isCommutative = false;
95
isIndirect = false;
96
currentAlternativeIndex = 0;
97
98
// Parse prefixes.
99
if (*I == '~') {
100
Type = isClobber;
101
++I;
102
103
// '{' must immediately follow '~'.
104
if (I != E && *I != '{')
105
return true;
106
} else if (*I == '=') {
107
++I;
108
Type = isOutput;
109
} else if (*I == '!') {
110
++I;
111
Type = isLabel;
112
}
113
114
if (*I == '*') {
115
isIndirect = true;
116
++I;
117
}
118
119
if (I == E) return true; // Just a prefix, like "==" or "~".
120
121
// Parse the modifiers.
122
bool DoneWithModifiers = false;
123
while (!DoneWithModifiers) {
124
switch (*I) {
125
default:
126
DoneWithModifiers = true;
127
break;
128
case '&': // Early clobber.
129
if (Type != isOutput || // Cannot early clobber anything but output.
130
isEarlyClobber) // Reject &&&&&&
131
return true;
132
isEarlyClobber = true;
133
break;
134
case '%': // Commutative.
135
if (Type == isClobber || // Cannot commute clobbers.
136
isCommutative) // Reject %%%%%
137
return true;
138
isCommutative = true;
139
break;
140
case '#': // Comment.
141
case '*': // Register preferencing.
142
return true; // Not supported.
143
}
144
145
if (!DoneWithModifiers) {
146
++I;
147
if (I == E) return true; // Just prefixes and modifiers!
148
}
149
}
150
151
// Parse the various constraints.
152
while (I != E) {
153
if (*I == '{') { // Physical register reference.
154
// Find the end of the register name.
155
StringRef::iterator ConstraintEnd = std::find(I+1, E, '}');
156
if (ConstraintEnd == E) return true; // "{foo"
157
pCodes->push_back(std::string(StringRef(I, ConstraintEnd + 1 - I)));
158
I = ConstraintEnd+1;
159
} else if (isdigit(static_cast<unsigned char>(*I))) { // Matching Constraint
160
// Maximal munch numbers.
161
StringRef::iterator NumStart = I;
162
while (I != E && isdigit(static_cast<unsigned char>(*I)))
163
++I;
164
pCodes->push_back(std::string(StringRef(NumStart, I - NumStart)));
165
unsigned N = atoi(pCodes->back().c_str());
166
// Check that this is a valid matching constraint!
167
if (N >= ConstraintsSoFar.size() || ConstraintsSoFar[N].Type != isOutput||
168
Type != isInput)
169
return true; // Invalid constraint number.
170
171
// If Operand N already has a matching input, reject this. An output
172
// can't be constrained to the same value as multiple inputs.
173
if (isMultipleAlternative) {
174
if (multipleAlternativeIndex >=
175
ConstraintsSoFar[N].multipleAlternatives.size())
176
return true;
177
InlineAsm::SubConstraintInfo &scInfo =
178
ConstraintsSoFar[N].multipleAlternatives[multipleAlternativeIndex];
179
if (scInfo.MatchingInput != -1)
180
return true;
181
// Note that operand #n has a matching input.
182
scInfo.MatchingInput = ConstraintsSoFar.size();
183
assert(scInfo.MatchingInput >= 0);
184
} else {
185
if (ConstraintsSoFar[N].hasMatchingInput() &&
186
(size_t)ConstraintsSoFar[N].MatchingInput !=
187
ConstraintsSoFar.size())
188
return true;
189
// Note that operand #n has a matching input.
190
ConstraintsSoFar[N].MatchingInput = ConstraintsSoFar.size();
191
assert(ConstraintsSoFar[N].MatchingInput >= 0);
192
}
193
} else if (*I == '|') {
194
multipleAlternativeIndex++;
195
pCodes = &multipleAlternatives[multipleAlternativeIndex].Codes;
196
++I;
197
} else if (*I == '^') {
198
// Multi-letter constraint
199
// FIXME: For now assuming these are 2-character constraints.
200
pCodes->push_back(std::string(StringRef(I + 1, 2)));
201
I += 3;
202
} else if (*I == '@') {
203
// Multi-letter constraint
204
++I;
205
unsigned char C = static_cast<unsigned char>(*I);
206
assert(isdigit(C) && "Expected a digit!");
207
int N = C - '0';
208
assert(N > 0 && "Found a zero letter constraint!");
209
++I;
210
pCodes->push_back(std::string(StringRef(I, N)));
211
I += N;
212
} else {
213
// Single letter constraint.
214
pCodes->push_back(std::string(StringRef(I, 1)));
215
++I;
216
}
217
}
218
219
return false;
220
}
221
222
/// selectAlternative - Point this constraint to the alternative constraint
223
/// indicated by the index.
224
void InlineAsm::ConstraintInfo::selectAlternative(unsigned index) {
225
if (index < multipleAlternatives.size()) {
226
currentAlternativeIndex = index;
227
InlineAsm::SubConstraintInfo &scInfo =
228
multipleAlternatives[currentAlternativeIndex];
229
MatchingInput = scInfo.MatchingInput;
230
Codes = scInfo.Codes;
231
}
232
}
233
234
InlineAsm::ConstraintInfoVector
235
InlineAsm::ParseConstraints(StringRef Constraints) {
236
ConstraintInfoVector Result;
237
238
// Scan the constraints string.
239
for (StringRef::iterator I = Constraints.begin(),
240
E = Constraints.end(); I != E; ) {
241
ConstraintInfo Info;
242
243
// Find the end of this constraint.
244
StringRef::iterator ConstraintEnd = std::find(I, E, ',');
245
246
if (ConstraintEnd == I || // Empty constraint like ",,"
247
Info.Parse(StringRef(I, ConstraintEnd-I), Result)) {
248
Result.clear(); // Erroneous constraint?
249
break;
250
}
251
252
Result.push_back(Info);
253
254
// ConstraintEnd may be either the next comma or the end of the string. In
255
// the former case, we skip the comma.
256
I = ConstraintEnd;
257
if (I != E) {
258
++I;
259
if (I == E) {
260
Result.clear();
261
break;
262
} // don't allow "xyz,"
263
}
264
}
265
266
return Result;
267
}
268
269
static Error makeStringError(const char *Msg) {
270
return createStringError(errc::invalid_argument, Msg);
271
}
272
273
Error InlineAsm::verify(FunctionType *Ty, StringRef ConstStr) {
274
if (Ty->isVarArg())
275
return makeStringError("inline asm cannot be variadic");
276
277
ConstraintInfoVector Constraints = ParseConstraints(ConstStr);
278
279
// Error parsing constraints.
280
if (Constraints.empty() && !ConstStr.empty())
281
return makeStringError("failed to parse constraints");
282
283
unsigned NumOutputs = 0, NumInputs = 0, NumClobbers = 0;
284
unsigned NumIndirect = 0, NumLabels = 0;
285
286
for (const ConstraintInfo &Constraint : Constraints) {
287
switch (Constraint.Type) {
288
case InlineAsm::isOutput:
289
if ((NumInputs-NumIndirect) != 0 || NumClobbers != 0 || NumLabels != 0)
290
return makeStringError("output constraint occurs after input, "
291
"clobber or label constraint");
292
293
if (!Constraint.isIndirect) {
294
++NumOutputs;
295
break;
296
}
297
++NumIndirect;
298
[[fallthrough]]; // We fall through for Indirect Outputs.
299
case InlineAsm::isInput:
300
if (NumClobbers)
301
return makeStringError("input constraint occurs after clobber "
302
"constraint");
303
++NumInputs;
304
break;
305
case InlineAsm::isClobber:
306
++NumClobbers;
307
break;
308
case InlineAsm::isLabel:
309
if (NumClobbers)
310
return makeStringError("label constraint occurs after clobber "
311
"constraint");
312
313
++NumLabels;
314
break;
315
}
316
}
317
318
switch (NumOutputs) {
319
case 0:
320
if (!Ty->getReturnType()->isVoidTy())
321
return makeStringError("inline asm without outputs must return void");
322
break;
323
case 1:
324
if (Ty->getReturnType()->isStructTy())
325
return makeStringError("inline asm with one output cannot return struct");
326
break;
327
default:
328
StructType *STy = dyn_cast<StructType>(Ty->getReturnType());
329
if (!STy || STy->getNumElements() != NumOutputs)
330
return makeStringError("number of output constraints does not match "
331
"number of return struct elements");
332
break;
333
}
334
335
if (Ty->getNumParams() != NumInputs)
336
return makeStringError("number of input constraints does not match number "
337
"of parameters");
338
339
// We don't have access to labels here, NumLabels will be checked separately.
340
return Error::success();
341
}
342
343