1e5dd7070Spatrick //===--- SemaStmtAsm.cpp - Semantic Analysis for Asm Statements -----------===//
2e5dd7070Spatrick //
3e5dd7070Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e5dd7070Spatrick // See https://llvm.org/LICENSE.txt for license information.
5e5dd7070Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e5dd7070Spatrick //
7e5dd7070Spatrick //===----------------------------------------------------------------------===//
8e5dd7070Spatrick //
9e5dd7070Spatrick // This file implements semantic analysis for inline asm statements.
10e5dd7070Spatrick //
11e5dd7070Spatrick //===----------------------------------------------------------------------===//
12e5dd7070Spatrick
13e5dd7070Spatrick #include "clang/AST/ExprCXX.h"
14e5dd7070Spatrick #include "clang/AST/GlobalDecl.h"
15e5dd7070Spatrick #include "clang/AST/RecordLayout.h"
16e5dd7070Spatrick #include "clang/AST/TypeLoc.h"
17e5dd7070Spatrick #include "clang/Basic/TargetInfo.h"
18e5dd7070Spatrick #include "clang/Lex/Preprocessor.h"
19e5dd7070Spatrick #include "clang/Sema/Initialization.h"
20e5dd7070Spatrick #include "clang/Sema/Lookup.h"
21e5dd7070Spatrick #include "clang/Sema/Scope.h"
22e5dd7070Spatrick #include "clang/Sema/ScopeInfo.h"
23e5dd7070Spatrick #include "clang/Sema/SemaInternal.h"
24e5dd7070Spatrick #include "llvm/ADT/ArrayRef.h"
25e5dd7070Spatrick #include "llvm/ADT/StringSet.h"
26e5dd7070Spatrick #include "llvm/MC/MCParser/MCAsmParser.h"
27*12c85518Srobert #include <optional>
28e5dd7070Spatrick using namespace clang;
29e5dd7070Spatrick using namespace sema;
30e5dd7070Spatrick
31e5dd7070Spatrick /// Remove the upper-level LValueToRValue cast from an expression.
removeLValueToRValueCast(Expr * E)32e5dd7070Spatrick static void removeLValueToRValueCast(Expr *E) {
33e5dd7070Spatrick Expr *Parent = E;
34e5dd7070Spatrick Expr *ExprUnderCast = nullptr;
35e5dd7070Spatrick SmallVector<Expr *, 8> ParentsToUpdate;
36e5dd7070Spatrick
37e5dd7070Spatrick while (true) {
38e5dd7070Spatrick ParentsToUpdate.push_back(Parent);
39e5dd7070Spatrick if (auto *ParenE = dyn_cast<ParenExpr>(Parent)) {
40e5dd7070Spatrick Parent = ParenE->getSubExpr();
41e5dd7070Spatrick continue;
42e5dd7070Spatrick }
43e5dd7070Spatrick
44e5dd7070Spatrick Expr *Child = nullptr;
45e5dd7070Spatrick CastExpr *ParentCast = dyn_cast<CastExpr>(Parent);
46e5dd7070Spatrick if (ParentCast)
47e5dd7070Spatrick Child = ParentCast->getSubExpr();
48e5dd7070Spatrick else
49e5dd7070Spatrick return;
50e5dd7070Spatrick
51e5dd7070Spatrick if (auto *CastE = dyn_cast<CastExpr>(Child))
52e5dd7070Spatrick if (CastE->getCastKind() == CK_LValueToRValue) {
53e5dd7070Spatrick ExprUnderCast = CastE->getSubExpr();
54e5dd7070Spatrick // LValueToRValue cast inside GCCAsmStmt requires an explicit cast.
55e5dd7070Spatrick ParentCast->setSubExpr(ExprUnderCast);
56e5dd7070Spatrick break;
57e5dd7070Spatrick }
58e5dd7070Spatrick Parent = Child;
59e5dd7070Spatrick }
60e5dd7070Spatrick
61e5dd7070Spatrick // Update parent expressions to have same ValueType as the underlying.
62e5dd7070Spatrick assert(ExprUnderCast &&
63e5dd7070Spatrick "Should be reachable only if LValueToRValue cast was found!");
64e5dd7070Spatrick auto ValueKind = ExprUnderCast->getValueKind();
65e5dd7070Spatrick for (Expr *E : ParentsToUpdate)
66e5dd7070Spatrick E->setValueKind(ValueKind);
67e5dd7070Spatrick }
68e5dd7070Spatrick
69e5dd7070Spatrick /// Emit a warning about usage of "noop"-like casts for lvalues (GNU extension)
70e5dd7070Spatrick /// and fix the argument with removing LValueToRValue cast from the expression.
emitAndFixInvalidAsmCastLValue(const Expr * LVal,Expr * BadArgument,Sema & S)71e5dd7070Spatrick static void emitAndFixInvalidAsmCastLValue(const Expr *LVal, Expr *BadArgument,
72e5dd7070Spatrick Sema &S) {
73e5dd7070Spatrick if (!S.getLangOpts().HeinousExtensions) {
74e5dd7070Spatrick S.Diag(LVal->getBeginLoc(), diag::err_invalid_asm_cast_lvalue)
75e5dd7070Spatrick << BadArgument->getSourceRange();
76e5dd7070Spatrick } else {
77e5dd7070Spatrick S.Diag(LVal->getBeginLoc(), diag::warn_invalid_asm_cast_lvalue)
78e5dd7070Spatrick << BadArgument->getSourceRange();
79e5dd7070Spatrick }
80e5dd7070Spatrick removeLValueToRValueCast(BadArgument);
81e5dd7070Spatrick }
82e5dd7070Spatrick
83e5dd7070Spatrick /// CheckAsmLValue - GNU C has an extremely ugly extension whereby they silently
84e5dd7070Spatrick /// ignore "noop" casts in places where an lvalue is required by an inline asm.
85e5dd7070Spatrick /// We emulate this behavior when -fheinous-gnu-extensions is specified, but
86e5dd7070Spatrick /// provide a strong guidance to not use it.
87e5dd7070Spatrick ///
88e5dd7070Spatrick /// This method checks to see if the argument is an acceptable l-value and
89e5dd7070Spatrick /// returns false if it is a case we can handle.
CheckAsmLValue(Expr * E,Sema & S)90e5dd7070Spatrick static bool CheckAsmLValue(Expr *E, Sema &S) {
91e5dd7070Spatrick // Type dependent expressions will be checked during instantiation.
92e5dd7070Spatrick if (E->isTypeDependent())
93e5dd7070Spatrick return false;
94e5dd7070Spatrick
95e5dd7070Spatrick if (E->isLValue())
96e5dd7070Spatrick return false; // Cool, this is an lvalue.
97e5dd7070Spatrick
98e5dd7070Spatrick // Okay, this is not an lvalue, but perhaps it is the result of a cast that we
99e5dd7070Spatrick // are supposed to allow.
100e5dd7070Spatrick const Expr *E2 = E->IgnoreParenNoopCasts(S.Context);
101e5dd7070Spatrick if (E != E2 && E2->isLValue()) {
102e5dd7070Spatrick emitAndFixInvalidAsmCastLValue(E2, E, S);
103e5dd7070Spatrick // Accept, even if we emitted an error diagnostic.
104e5dd7070Spatrick return false;
105e5dd7070Spatrick }
106e5dd7070Spatrick
107e5dd7070Spatrick // None of the above, just randomly invalid non-lvalue.
108e5dd7070Spatrick return true;
109e5dd7070Spatrick }
110e5dd7070Spatrick
111e5dd7070Spatrick /// isOperandMentioned - Return true if the specified operand # is mentioned
112e5dd7070Spatrick /// anywhere in the decomposed asm string.
113e5dd7070Spatrick static bool
isOperandMentioned(unsigned OpNo,ArrayRef<GCCAsmStmt::AsmStringPiece> AsmStrPieces)114e5dd7070Spatrick isOperandMentioned(unsigned OpNo,
115e5dd7070Spatrick ArrayRef<GCCAsmStmt::AsmStringPiece> AsmStrPieces) {
116e5dd7070Spatrick for (unsigned p = 0, e = AsmStrPieces.size(); p != e; ++p) {
117e5dd7070Spatrick const GCCAsmStmt::AsmStringPiece &Piece = AsmStrPieces[p];
118e5dd7070Spatrick if (!Piece.isOperand())
119e5dd7070Spatrick continue;
120e5dd7070Spatrick
121e5dd7070Spatrick // If this is a reference to the input and if the input was the smaller
122e5dd7070Spatrick // one, then we have to reject this asm.
123e5dd7070Spatrick if (Piece.getOperandNo() == OpNo)
124e5dd7070Spatrick return true;
125e5dd7070Spatrick }
126e5dd7070Spatrick return false;
127e5dd7070Spatrick }
128e5dd7070Spatrick
CheckNakedParmReference(Expr * E,Sema & S)129e5dd7070Spatrick static bool CheckNakedParmReference(Expr *E, Sema &S) {
130e5dd7070Spatrick FunctionDecl *Func = dyn_cast<FunctionDecl>(S.CurContext);
131e5dd7070Spatrick if (!Func)
132e5dd7070Spatrick return false;
133e5dd7070Spatrick if (!Func->hasAttr<NakedAttr>())
134e5dd7070Spatrick return false;
135e5dd7070Spatrick
136e5dd7070Spatrick SmallVector<Expr*, 4> WorkList;
137e5dd7070Spatrick WorkList.push_back(E);
138e5dd7070Spatrick while (WorkList.size()) {
139e5dd7070Spatrick Expr *E = WorkList.pop_back_val();
140e5dd7070Spatrick if (isa<CXXThisExpr>(E)) {
141e5dd7070Spatrick S.Diag(E->getBeginLoc(), diag::err_asm_naked_this_ref);
142e5dd7070Spatrick S.Diag(Func->getAttr<NakedAttr>()->getLocation(), diag::note_attribute);
143e5dd7070Spatrick return true;
144e5dd7070Spatrick }
145e5dd7070Spatrick if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) {
146e5dd7070Spatrick if (isa<ParmVarDecl>(DRE->getDecl())) {
147e5dd7070Spatrick S.Diag(DRE->getBeginLoc(), diag::err_asm_naked_parm_ref);
148e5dd7070Spatrick S.Diag(Func->getAttr<NakedAttr>()->getLocation(), diag::note_attribute);
149e5dd7070Spatrick return true;
150e5dd7070Spatrick }
151e5dd7070Spatrick }
152e5dd7070Spatrick for (Stmt *Child : E->children()) {
153e5dd7070Spatrick if (Expr *E = dyn_cast_or_null<Expr>(Child))
154e5dd7070Spatrick WorkList.push_back(E);
155e5dd7070Spatrick }
156e5dd7070Spatrick }
157e5dd7070Spatrick return false;
158e5dd7070Spatrick }
159e5dd7070Spatrick
160e5dd7070Spatrick /// Returns true if given expression is not compatible with inline
161e5dd7070Spatrick /// assembly's memory constraint; false otherwise.
checkExprMemoryConstraintCompat(Sema & S,Expr * E,TargetInfo::ConstraintInfo & Info,bool is_input_expr)162e5dd7070Spatrick static bool checkExprMemoryConstraintCompat(Sema &S, Expr *E,
163e5dd7070Spatrick TargetInfo::ConstraintInfo &Info,
164e5dd7070Spatrick bool is_input_expr) {
165e5dd7070Spatrick enum {
166e5dd7070Spatrick ExprBitfield = 0,
167e5dd7070Spatrick ExprVectorElt,
168e5dd7070Spatrick ExprGlobalRegVar,
169e5dd7070Spatrick ExprSafeType
170e5dd7070Spatrick } EType = ExprSafeType;
171e5dd7070Spatrick
172e5dd7070Spatrick // Bitfields, vector elements and global register variables are not
173e5dd7070Spatrick // compatible.
174e5dd7070Spatrick if (E->refersToBitField())
175e5dd7070Spatrick EType = ExprBitfield;
176e5dd7070Spatrick else if (E->refersToVectorElement())
177e5dd7070Spatrick EType = ExprVectorElt;
178e5dd7070Spatrick else if (E->refersToGlobalRegisterVar())
179e5dd7070Spatrick EType = ExprGlobalRegVar;
180e5dd7070Spatrick
181e5dd7070Spatrick if (EType != ExprSafeType) {
182e5dd7070Spatrick S.Diag(E->getBeginLoc(), diag::err_asm_non_addr_value_in_memory_constraint)
183e5dd7070Spatrick << EType << is_input_expr << Info.getConstraintStr()
184e5dd7070Spatrick << E->getSourceRange();
185e5dd7070Spatrick return true;
186e5dd7070Spatrick }
187e5dd7070Spatrick
188e5dd7070Spatrick return false;
189e5dd7070Spatrick }
190e5dd7070Spatrick
191e5dd7070Spatrick // Extracting the register name from the Expression value,
192e5dd7070Spatrick // if there is no register name to extract, returns ""
extractRegisterName(const Expr * Expression,const TargetInfo & Target)193e5dd7070Spatrick static StringRef extractRegisterName(const Expr *Expression,
194e5dd7070Spatrick const TargetInfo &Target) {
195e5dd7070Spatrick Expression = Expression->IgnoreImpCasts();
196e5dd7070Spatrick if (const DeclRefExpr *AsmDeclRef = dyn_cast<DeclRefExpr>(Expression)) {
197e5dd7070Spatrick // Handle cases where the expression is a variable
198e5dd7070Spatrick const VarDecl *Variable = dyn_cast<VarDecl>(AsmDeclRef->getDecl());
199e5dd7070Spatrick if (Variable && Variable->getStorageClass() == SC_Register) {
200e5dd7070Spatrick if (AsmLabelAttr *Attr = Variable->getAttr<AsmLabelAttr>())
201e5dd7070Spatrick if (Target.isValidGCCRegisterName(Attr->getLabel()))
202e5dd7070Spatrick return Target.getNormalizedGCCRegisterName(Attr->getLabel(), true);
203e5dd7070Spatrick }
204e5dd7070Spatrick }
205e5dd7070Spatrick return "";
206e5dd7070Spatrick }
207e5dd7070Spatrick
208e5dd7070Spatrick // Checks if there is a conflict between the input and output lists with the
209e5dd7070Spatrick // clobbers list. If there's a conflict, returns the location of the
210e5dd7070Spatrick // conflicted clobber, else returns nullptr
211e5dd7070Spatrick static SourceLocation
getClobberConflictLocation(MultiExprArg Exprs,StringLiteral ** Constraints,StringLiteral ** Clobbers,int NumClobbers,unsigned NumLabels,const TargetInfo & Target,ASTContext & Cont)212e5dd7070Spatrick getClobberConflictLocation(MultiExprArg Exprs, StringLiteral **Constraints,
213e5dd7070Spatrick StringLiteral **Clobbers, int NumClobbers,
214e5dd7070Spatrick unsigned NumLabels,
215e5dd7070Spatrick const TargetInfo &Target, ASTContext &Cont) {
216e5dd7070Spatrick llvm::StringSet<> InOutVars;
217e5dd7070Spatrick // Collect all the input and output registers from the extended asm
218e5dd7070Spatrick // statement in order to check for conflicts with the clobber list
219e5dd7070Spatrick for (unsigned int i = 0; i < Exprs.size() - NumLabels; ++i) {
220e5dd7070Spatrick StringRef Constraint = Constraints[i]->getString();
221e5dd7070Spatrick StringRef InOutReg = Target.getConstraintRegister(
222e5dd7070Spatrick Constraint, extractRegisterName(Exprs[i], Target));
223e5dd7070Spatrick if (InOutReg != "")
224e5dd7070Spatrick InOutVars.insert(InOutReg);
225e5dd7070Spatrick }
226e5dd7070Spatrick // Check for each item in the clobber list if it conflicts with the input
227e5dd7070Spatrick // or output
228e5dd7070Spatrick for (int i = 0; i < NumClobbers; ++i) {
229e5dd7070Spatrick StringRef Clobber = Clobbers[i]->getString();
230e5dd7070Spatrick // We only check registers, therefore we don't check cc and memory
231e5dd7070Spatrick // clobbers
232a9ac8606Spatrick if (Clobber == "cc" || Clobber == "memory" || Clobber == "unwind")
233e5dd7070Spatrick continue;
234e5dd7070Spatrick Clobber = Target.getNormalizedGCCRegisterName(Clobber, true);
235e5dd7070Spatrick // Go over the output's registers we collected
236e5dd7070Spatrick if (InOutVars.count(Clobber))
237e5dd7070Spatrick return Clobbers[i]->getBeginLoc();
238e5dd7070Spatrick }
239e5dd7070Spatrick return SourceLocation();
240e5dd7070Spatrick }
241e5dd7070Spatrick
ActOnGCCAsmStmt(SourceLocation AsmLoc,bool IsSimple,bool IsVolatile,unsigned NumOutputs,unsigned NumInputs,IdentifierInfo ** Names,MultiExprArg constraints,MultiExprArg Exprs,Expr * asmString,MultiExprArg clobbers,unsigned NumLabels,SourceLocation RParenLoc)242e5dd7070Spatrick StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
243e5dd7070Spatrick bool IsVolatile, unsigned NumOutputs,
244e5dd7070Spatrick unsigned NumInputs, IdentifierInfo **Names,
245e5dd7070Spatrick MultiExprArg constraints, MultiExprArg Exprs,
246e5dd7070Spatrick Expr *asmString, MultiExprArg clobbers,
247e5dd7070Spatrick unsigned NumLabels,
248e5dd7070Spatrick SourceLocation RParenLoc) {
249e5dd7070Spatrick unsigned NumClobbers = clobbers.size();
250e5dd7070Spatrick StringLiteral **Constraints =
251e5dd7070Spatrick reinterpret_cast<StringLiteral**>(constraints.data());
252e5dd7070Spatrick StringLiteral *AsmString = cast<StringLiteral>(asmString);
253e5dd7070Spatrick StringLiteral **Clobbers = reinterpret_cast<StringLiteral**>(clobbers.data());
254e5dd7070Spatrick
255e5dd7070Spatrick SmallVector<TargetInfo::ConstraintInfo, 4> OutputConstraintInfos;
256e5dd7070Spatrick
257e5dd7070Spatrick // The parser verifies that there is a string literal here.
258*12c85518Srobert assert(AsmString->isOrdinary());
259e5dd7070Spatrick
260e5dd7070Spatrick FunctionDecl *FD = dyn_cast<FunctionDecl>(getCurLexicalContext());
261e5dd7070Spatrick llvm::StringMap<bool> FeatureMap;
262e5dd7070Spatrick Context.getFunctionFeatureMap(FeatureMap, FD);
263e5dd7070Spatrick
264e5dd7070Spatrick for (unsigned i = 0; i != NumOutputs; i++) {
265e5dd7070Spatrick StringLiteral *Literal = Constraints[i];
266*12c85518Srobert assert(Literal->isOrdinary());
267e5dd7070Spatrick
268e5dd7070Spatrick StringRef OutputName;
269e5dd7070Spatrick if (Names[i])
270e5dd7070Spatrick OutputName = Names[i]->getName();
271e5dd7070Spatrick
272e5dd7070Spatrick TargetInfo::ConstraintInfo Info(Literal->getString(), OutputName);
273e5dd7070Spatrick if (!Context.getTargetInfo().validateOutputConstraint(Info)) {
274e5dd7070Spatrick targetDiag(Literal->getBeginLoc(),
275e5dd7070Spatrick diag::err_asm_invalid_output_constraint)
276e5dd7070Spatrick << Info.getConstraintStr();
277e5dd7070Spatrick return new (Context)
278e5dd7070Spatrick GCCAsmStmt(Context, AsmLoc, IsSimple, IsVolatile, NumOutputs,
279e5dd7070Spatrick NumInputs, Names, Constraints, Exprs.data(), AsmString,
280e5dd7070Spatrick NumClobbers, Clobbers, NumLabels, RParenLoc);
281e5dd7070Spatrick }
282e5dd7070Spatrick
283e5dd7070Spatrick ExprResult ER = CheckPlaceholderExpr(Exprs[i]);
284e5dd7070Spatrick if (ER.isInvalid())
285e5dd7070Spatrick return StmtError();
286e5dd7070Spatrick Exprs[i] = ER.get();
287e5dd7070Spatrick
288e5dd7070Spatrick // Check that the output exprs are valid lvalues.
289e5dd7070Spatrick Expr *OutputExpr = Exprs[i];
290e5dd7070Spatrick
291e5dd7070Spatrick // Referring to parameters is not allowed in naked functions.
292e5dd7070Spatrick if (CheckNakedParmReference(OutputExpr, *this))
293e5dd7070Spatrick return StmtError();
294e5dd7070Spatrick
295e5dd7070Spatrick // Check that the output expression is compatible with memory constraint.
296e5dd7070Spatrick if (Info.allowsMemory() &&
297e5dd7070Spatrick checkExprMemoryConstraintCompat(*this, OutputExpr, Info, false))
298e5dd7070Spatrick return StmtError();
299e5dd7070Spatrick
300*12c85518Srobert // Disallow bit-precise integer types, since the backends tend to have
301*12c85518Srobert // difficulties with abnormal sizes.
302*12c85518Srobert if (OutputExpr->getType()->isBitIntType())
303ec727ea7Spatrick return StmtError(
304ec727ea7Spatrick Diag(OutputExpr->getBeginLoc(), diag::err_asm_invalid_type)
305ec727ea7Spatrick << OutputExpr->getType() << 0 /*Input*/
306ec727ea7Spatrick << OutputExpr->getSourceRange());
307ec727ea7Spatrick
308e5dd7070Spatrick OutputConstraintInfos.push_back(Info);
309e5dd7070Spatrick
310e5dd7070Spatrick // If this is dependent, just continue.
311e5dd7070Spatrick if (OutputExpr->isTypeDependent())
312e5dd7070Spatrick continue;
313e5dd7070Spatrick
314e5dd7070Spatrick Expr::isModifiableLvalueResult IsLV =
315e5dd7070Spatrick OutputExpr->isModifiableLvalue(Context, /*Loc=*/nullptr);
316e5dd7070Spatrick switch (IsLV) {
317e5dd7070Spatrick case Expr::MLV_Valid:
318e5dd7070Spatrick // Cool, this is an lvalue.
319e5dd7070Spatrick break;
320e5dd7070Spatrick case Expr::MLV_ArrayType:
321e5dd7070Spatrick // This is OK too.
322e5dd7070Spatrick break;
323e5dd7070Spatrick case Expr::MLV_LValueCast: {
324e5dd7070Spatrick const Expr *LVal = OutputExpr->IgnoreParenNoopCasts(Context);
325e5dd7070Spatrick emitAndFixInvalidAsmCastLValue(LVal, OutputExpr, *this);
326e5dd7070Spatrick // Accept, even if we emitted an error diagnostic.
327e5dd7070Spatrick break;
328e5dd7070Spatrick }
329e5dd7070Spatrick case Expr::MLV_IncompleteType:
330e5dd7070Spatrick case Expr::MLV_IncompleteVoidType:
331e5dd7070Spatrick if (RequireCompleteType(OutputExpr->getBeginLoc(), Exprs[i]->getType(),
332e5dd7070Spatrick diag::err_dereference_incomplete_type))
333e5dd7070Spatrick return StmtError();
334*12c85518Srobert [[fallthrough]];
335e5dd7070Spatrick default:
336e5dd7070Spatrick return StmtError(Diag(OutputExpr->getBeginLoc(),
337e5dd7070Spatrick diag::err_asm_invalid_lvalue_in_output)
338e5dd7070Spatrick << OutputExpr->getSourceRange());
339e5dd7070Spatrick }
340e5dd7070Spatrick
341e5dd7070Spatrick unsigned Size = Context.getTypeSize(OutputExpr->getType());
342e5dd7070Spatrick if (!Context.getTargetInfo().validateOutputSize(
343e5dd7070Spatrick FeatureMap, Literal->getString(), Size)) {
344e5dd7070Spatrick targetDiag(OutputExpr->getBeginLoc(), diag::err_asm_invalid_output_size)
345e5dd7070Spatrick << Info.getConstraintStr();
346e5dd7070Spatrick return new (Context)
347e5dd7070Spatrick GCCAsmStmt(Context, AsmLoc, IsSimple, IsVolatile, NumOutputs,
348e5dd7070Spatrick NumInputs, Names, Constraints, Exprs.data(), AsmString,
349e5dd7070Spatrick NumClobbers, Clobbers, NumLabels, RParenLoc);
350e5dd7070Spatrick }
351e5dd7070Spatrick }
352e5dd7070Spatrick
353e5dd7070Spatrick SmallVector<TargetInfo::ConstraintInfo, 4> InputConstraintInfos;
354e5dd7070Spatrick
355e5dd7070Spatrick for (unsigned i = NumOutputs, e = NumOutputs + NumInputs; i != e; i++) {
356e5dd7070Spatrick StringLiteral *Literal = Constraints[i];
357*12c85518Srobert assert(Literal->isOrdinary());
358e5dd7070Spatrick
359e5dd7070Spatrick StringRef InputName;
360e5dd7070Spatrick if (Names[i])
361e5dd7070Spatrick InputName = Names[i]->getName();
362e5dd7070Spatrick
363e5dd7070Spatrick TargetInfo::ConstraintInfo Info(Literal->getString(), InputName);
364e5dd7070Spatrick if (!Context.getTargetInfo().validateInputConstraint(OutputConstraintInfos,
365e5dd7070Spatrick Info)) {
366e5dd7070Spatrick targetDiag(Literal->getBeginLoc(), diag::err_asm_invalid_input_constraint)
367e5dd7070Spatrick << Info.getConstraintStr();
368e5dd7070Spatrick return new (Context)
369e5dd7070Spatrick GCCAsmStmt(Context, AsmLoc, IsSimple, IsVolatile, NumOutputs,
370e5dd7070Spatrick NumInputs, Names, Constraints, Exprs.data(), AsmString,
371e5dd7070Spatrick NumClobbers, Clobbers, NumLabels, RParenLoc);
372e5dd7070Spatrick }
373e5dd7070Spatrick
374e5dd7070Spatrick ExprResult ER = CheckPlaceholderExpr(Exprs[i]);
375e5dd7070Spatrick if (ER.isInvalid())
376e5dd7070Spatrick return StmtError();
377e5dd7070Spatrick Exprs[i] = ER.get();
378e5dd7070Spatrick
379e5dd7070Spatrick Expr *InputExpr = Exprs[i];
380e5dd7070Spatrick
381*12c85518Srobert if (InputExpr->getType()->isMemberPointerType())
382*12c85518Srobert return StmtError(Diag(InputExpr->getBeginLoc(),
383*12c85518Srobert diag::err_asm_pmf_through_constraint_not_permitted)
384*12c85518Srobert << InputExpr->getSourceRange());
385*12c85518Srobert
386e5dd7070Spatrick // Referring to parameters is not allowed in naked functions.
387e5dd7070Spatrick if (CheckNakedParmReference(InputExpr, *this))
388e5dd7070Spatrick return StmtError();
389e5dd7070Spatrick
390e5dd7070Spatrick // Check that the input expression is compatible with memory constraint.
391e5dd7070Spatrick if (Info.allowsMemory() &&
392e5dd7070Spatrick checkExprMemoryConstraintCompat(*this, InputExpr, Info, true))
393e5dd7070Spatrick return StmtError();
394e5dd7070Spatrick
395e5dd7070Spatrick // Only allow void types for memory constraints.
396e5dd7070Spatrick if (Info.allowsMemory() && !Info.allowsRegister()) {
397e5dd7070Spatrick if (CheckAsmLValue(InputExpr, *this))
398e5dd7070Spatrick return StmtError(Diag(InputExpr->getBeginLoc(),
399e5dd7070Spatrick diag::err_asm_invalid_lvalue_in_input)
400e5dd7070Spatrick << Info.getConstraintStr()
401e5dd7070Spatrick << InputExpr->getSourceRange());
402*12c85518Srobert } else {
403*12c85518Srobert ExprResult Result = DefaultFunctionArrayLvalueConversion(Exprs[i]);
404*12c85518Srobert if (Result.isInvalid())
405*12c85518Srobert return StmtError();
406*12c85518Srobert
407*12c85518Srobert InputExpr = Exprs[i] = Result.get();
408*12c85518Srobert
409*12c85518Srobert if (Info.requiresImmediateConstant() && !Info.allowsRegister()) {
410e5dd7070Spatrick if (!InputExpr->isValueDependent()) {
411e5dd7070Spatrick Expr::EvalResult EVResult;
412e5dd7070Spatrick if (InputExpr->EvaluateAsRValue(EVResult, Context, true)) {
413e5dd7070Spatrick // For compatibility with GCC, we also allow pointers that would be
414e5dd7070Spatrick // integral constant expressions if they were cast to int.
415e5dd7070Spatrick llvm::APSInt IntResult;
416e5dd7070Spatrick if (EVResult.Val.toIntegralConstant(IntResult, InputExpr->getType(),
417e5dd7070Spatrick Context))
418e5dd7070Spatrick if (!Info.isValidAsmImmediate(IntResult))
419*12c85518Srobert return StmtError(
420*12c85518Srobert Diag(InputExpr->getBeginLoc(),
421e5dd7070Spatrick diag::err_invalid_asm_value_for_constraint)
422*12c85518Srobert << toString(IntResult, 10) << Info.getConstraintStr()
423e5dd7070Spatrick << InputExpr->getSourceRange());
424e5dd7070Spatrick }
425e5dd7070Spatrick }
426*12c85518Srobert }
427e5dd7070Spatrick }
428e5dd7070Spatrick
429e5dd7070Spatrick if (Info.allowsRegister()) {
430e5dd7070Spatrick if (InputExpr->getType()->isVoidType()) {
431e5dd7070Spatrick return StmtError(
432e5dd7070Spatrick Diag(InputExpr->getBeginLoc(), diag::err_asm_invalid_type_in_input)
433e5dd7070Spatrick << InputExpr->getType() << Info.getConstraintStr()
434e5dd7070Spatrick << InputExpr->getSourceRange());
435e5dd7070Spatrick }
436e5dd7070Spatrick }
437e5dd7070Spatrick
438*12c85518Srobert if (InputExpr->getType()->isBitIntType())
439ec727ea7Spatrick return StmtError(
440ec727ea7Spatrick Diag(InputExpr->getBeginLoc(), diag::err_asm_invalid_type)
441ec727ea7Spatrick << InputExpr->getType() << 1 /*Output*/
442ec727ea7Spatrick << InputExpr->getSourceRange());
443ec727ea7Spatrick
444e5dd7070Spatrick InputConstraintInfos.push_back(Info);
445e5dd7070Spatrick
446e5dd7070Spatrick const Type *Ty = Exprs[i]->getType().getTypePtr();
447e5dd7070Spatrick if (Ty->isDependentType())
448e5dd7070Spatrick continue;
449e5dd7070Spatrick
450e5dd7070Spatrick if (!Ty->isVoidType() || !Info.allowsMemory())
451e5dd7070Spatrick if (RequireCompleteType(InputExpr->getBeginLoc(), Exprs[i]->getType(),
452e5dd7070Spatrick diag::err_dereference_incomplete_type))
453e5dd7070Spatrick return StmtError();
454e5dd7070Spatrick
455e5dd7070Spatrick unsigned Size = Context.getTypeSize(Ty);
456e5dd7070Spatrick if (!Context.getTargetInfo().validateInputSize(FeatureMap,
457e5dd7070Spatrick Literal->getString(), Size))
458a9ac8606Spatrick return targetDiag(InputExpr->getBeginLoc(),
459a9ac8606Spatrick diag::err_asm_invalid_input_size)
460a9ac8606Spatrick << Info.getConstraintStr();
461e5dd7070Spatrick }
462e5dd7070Spatrick
463*12c85518Srobert std::optional<SourceLocation> UnwindClobberLoc;
464a9ac8606Spatrick
465e5dd7070Spatrick // Check that the clobbers are valid.
466e5dd7070Spatrick for (unsigned i = 0; i != NumClobbers; i++) {
467e5dd7070Spatrick StringLiteral *Literal = Clobbers[i];
468*12c85518Srobert assert(Literal->isOrdinary());
469e5dd7070Spatrick
470e5dd7070Spatrick StringRef Clobber = Literal->getString();
471e5dd7070Spatrick
472e5dd7070Spatrick if (!Context.getTargetInfo().isValidClobber(Clobber)) {
473e5dd7070Spatrick targetDiag(Literal->getBeginLoc(), diag::err_asm_unknown_register_name)
474e5dd7070Spatrick << Clobber;
475e5dd7070Spatrick return new (Context)
476e5dd7070Spatrick GCCAsmStmt(Context, AsmLoc, IsSimple, IsVolatile, NumOutputs,
477e5dd7070Spatrick NumInputs, Names, Constraints, Exprs.data(), AsmString,
478e5dd7070Spatrick NumClobbers, Clobbers, NumLabels, RParenLoc);
479e5dd7070Spatrick }
480a9ac8606Spatrick
481a9ac8606Spatrick if (Clobber == "unwind") {
482a9ac8606Spatrick UnwindClobberLoc = Literal->getBeginLoc();
483a9ac8606Spatrick }
484a9ac8606Spatrick }
485a9ac8606Spatrick
486a9ac8606Spatrick // Using unwind clobber and asm-goto together is not supported right now.
487a9ac8606Spatrick if (UnwindClobberLoc && NumLabels > 0) {
488a9ac8606Spatrick targetDiag(*UnwindClobberLoc, diag::err_asm_unwind_and_goto);
489a9ac8606Spatrick return new (Context)
490a9ac8606Spatrick GCCAsmStmt(Context, AsmLoc, IsSimple, IsVolatile, NumOutputs, NumInputs,
491a9ac8606Spatrick Names, Constraints, Exprs.data(), AsmString, NumClobbers,
492a9ac8606Spatrick Clobbers, NumLabels, RParenLoc);
493e5dd7070Spatrick }
494e5dd7070Spatrick
495e5dd7070Spatrick GCCAsmStmt *NS =
496e5dd7070Spatrick new (Context) GCCAsmStmt(Context, AsmLoc, IsSimple, IsVolatile, NumOutputs,
497e5dd7070Spatrick NumInputs, Names, Constraints, Exprs.data(),
498e5dd7070Spatrick AsmString, NumClobbers, Clobbers, NumLabels,
499e5dd7070Spatrick RParenLoc);
500e5dd7070Spatrick // Validate the asm string, ensuring it makes sense given the operands we
501e5dd7070Spatrick // have.
502e5dd7070Spatrick SmallVector<GCCAsmStmt::AsmStringPiece, 8> Pieces;
503e5dd7070Spatrick unsigned DiagOffs;
504e5dd7070Spatrick if (unsigned DiagID = NS->AnalyzeAsmString(Pieces, Context, DiagOffs)) {
505e5dd7070Spatrick targetDiag(getLocationOfStringLiteralByte(AsmString, DiagOffs), DiagID)
506e5dd7070Spatrick << AsmString->getSourceRange();
507e5dd7070Spatrick return NS;
508e5dd7070Spatrick }
509e5dd7070Spatrick
510e5dd7070Spatrick // Validate constraints and modifiers.
511e5dd7070Spatrick for (unsigned i = 0, e = Pieces.size(); i != e; ++i) {
512e5dd7070Spatrick GCCAsmStmt::AsmStringPiece &Piece = Pieces[i];
513e5dd7070Spatrick if (!Piece.isOperand()) continue;
514e5dd7070Spatrick
515e5dd7070Spatrick // Look for the correct constraint index.
516e5dd7070Spatrick unsigned ConstraintIdx = Piece.getOperandNo();
517e5dd7070Spatrick unsigned NumOperands = NS->getNumOutputs() + NS->getNumInputs();
518ec727ea7Spatrick // Labels are the last in the Exprs list.
519ec727ea7Spatrick if (NS->isAsmGoto() && ConstraintIdx >= NumOperands)
520ec727ea7Spatrick continue;
521e5dd7070Spatrick // Look for the (ConstraintIdx - NumOperands + 1)th constraint with
522e5dd7070Spatrick // modifier '+'.
523e5dd7070Spatrick if (ConstraintIdx >= NumOperands) {
524e5dd7070Spatrick unsigned I = 0, E = NS->getNumOutputs();
525e5dd7070Spatrick
526e5dd7070Spatrick for (unsigned Cnt = ConstraintIdx - NumOperands; I != E; ++I)
527e5dd7070Spatrick if (OutputConstraintInfos[I].isReadWrite() && Cnt-- == 0) {
528e5dd7070Spatrick ConstraintIdx = I;
529e5dd7070Spatrick break;
530e5dd7070Spatrick }
531e5dd7070Spatrick
532e5dd7070Spatrick assert(I != E && "Invalid operand number should have been caught in "
533e5dd7070Spatrick " AnalyzeAsmString");
534e5dd7070Spatrick }
535e5dd7070Spatrick
536e5dd7070Spatrick // Now that we have the right indexes go ahead and check.
537e5dd7070Spatrick StringLiteral *Literal = Constraints[ConstraintIdx];
538e5dd7070Spatrick const Type *Ty = Exprs[ConstraintIdx]->getType().getTypePtr();
539e5dd7070Spatrick if (Ty->isDependentType() || Ty->isIncompleteType())
540e5dd7070Spatrick continue;
541e5dd7070Spatrick
542e5dd7070Spatrick unsigned Size = Context.getTypeSize(Ty);
543e5dd7070Spatrick std::string SuggestedModifier;
544e5dd7070Spatrick if (!Context.getTargetInfo().validateConstraintModifier(
545e5dd7070Spatrick Literal->getString(), Piece.getModifier(), Size,
546e5dd7070Spatrick SuggestedModifier)) {
547e5dd7070Spatrick targetDiag(Exprs[ConstraintIdx]->getBeginLoc(),
548e5dd7070Spatrick diag::warn_asm_mismatched_size_modifier);
549e5dd7070Spatrick
550e5dd7070Spatrick if (!SuggestedModifier.empty()) {
551e5dd7070Spatrick auto B = targetDiag(Piece.getRange().getBegin(),
552e5dd7070Spatrick diag::note_asm_missing_constraint_modifier)
553e5dd7070Spatrick << SuggestedModifier;
554e5dd7070Spatrick SuggestedModifier = "%" + SuggestedModifier + Piece.getString();
555e5dd7070Spatrick B << FixItHint::CreateReplacement(Piece.getRange(), SuggestedModifier);
556e5dd7070Spatrick }
557e5dd7070Spatrick }
558e5dd7070Spatrick }
559e5dd7070Spatrick
560e5dd7070Spatrick // Validate tied input operands for type mismatches.
561e5dd7070Spatrick unsigned NumAlternatives = ~0U;
562e5dd7070Spatrick for (unsigned i = 0, e = OutputConstraintInfos.size(); i != e; ++i) {
563e5dd7070Spatrick TargetInfo::ConstraintInfo &Info = OutputConstraintInfos[i];
564e5dd7070Spatrick StringRef ConstraintStr = Info.getConstraintStr();
565e5dd7070Spatrick unsigned AltCount = ConstraintStr.count(',') + 1;
566e5dd7070Spatrick if (NumAlternatives == ~0U) {
567e5dd7070Spatrick NumAlternatives = AltCount;
568e5dd7070Spatrick } else if (NumAlternatives != AltCount) {
569e5dd7070Spatrick targetDiag(NS->getOutputExpr(i)->getBeginLoc(),
570e5dd7070Spatrick diag::err_asm_unexpected_constraint_alternatives)
571e5dd7070Spatrick << NumAlternatives << AltCount;
572e5dd7070Spatrick return NS;
573e5dd7070Spatrick }
574e5dd7070Spatrick }
575e5dd7070Spatrick SmallVector<size_t, 4> InputMatchedToOutput(OutputConstraintInfos.size(),
576e5dd7070Spatrick ~0U);
577e5dd7070Spatrick for (unsigned i = 0, e = InputConstraintInfos.size(); i != e; ++i) {
578e5dd7070Spatrick TargetInfo::ConstraintInfo &Info = InputConstraintInfos[i];
579e5dd7070Spatrick StringRef ConstraintStr = Info.getConstraintStr();
580e5dd7070Spatrick unsigned AltCount = ConstraintStr.count(',') + 1;
581e5dd7070Spatrick if (NumAlternatives == ~0U) {
582e5dd7070Spatrick NumAlternatives = AltCount;
583e5dd7070Spatrick } else if (NumAlternatives != AltCount) {
584e5dd7070Spatrick targetDiag(NS->getInputExpr(i)->getBeginLoc(),
585e5dd7070Spatrick diag::err_asm_unexpected_constraint_alternatives)
586e5dd7070Spatrick << NumAlternatives << AltCount;
587e5dd7070Spatrick return NS;
588e5dd7070Spatrick }
589e5dd7070Spatrick
590e5dd7070Spatrick // If this is a tied constraint, verify that the output and input have
591e5dd7070Spatrick // either exactly the same type, or that they are int/ptr operands with the
592e5dd7070Spatrick // same size (int/long, int*/long, are ok etc).
593e5dd7070Spatrick if (!Info.hasTiedOperand()) continue;
594e5dd7070Spatrick
595e5dd7070Spatrick unsigned TiedTo = Info.getTiedOperand();
596e5dd7070Spatrick unsigned InputOpNo = i+NumOutputs;
597e5dd7070Spatrick Expr *OutputExpr = Exprs[TiedTo];
598e5dd7070Spatrick Expr *InputExpr = Exprs[InputOpNo];
599e5dd7070Spatrick
600e5dd7070Spatrick // Make sure no more than one input constraint matches each output.
601e5dd7070Spatrick assert(TiedTo < InputMatchedToOutput.size() && "TiedTo value out of range");
602e5dd7070Spatrick if (InputMatchedToOutput[TiedTo] != ~0U) {
603e5dd7070Spatrick targetDiag(NS->getInputExpr(i)->getBeginLoc(),
604e5dd7070Spatrick diag::err_asm_input_duplicate_match)
605e5dd7070Spatrick << TiedTo;
606e5dd7070Spatrick targetDiag(NS->getInputExpr(InputMatchedToOutput[TiedTo])->getBeginLoc(),
607e5dd7070Spatrick diag::note_asm_input_duplicate_first)
608e5dd7070Spatrick << TiedTo;
609e5dd7070Spatrick return NS;
610e5dd7070Spatrick }
611e5dd7070Spatrick InputMatchedToOutput[TiedTo] = i;
612e5dd7070Spatrick
613e5dd7070Spatrick if (OutputExpr->isTypeDependent() || InputExpr->isTypeDependent())
614e5dd7070Spatrick continue;
615e5dd7070Spatrick
616e5dd7070Spatrick QualType InTy = InputExpr->getType();
617e5dd7070Spatrick QualType OutTy = OutputExpr->getType();
618e5dd7070Spatrick if (Context.hasSameType(InTy, OutTy))
619e5dd7070Spatrick continue; // All types can be tied to themselves.
620e5dd7070Spatrick
621e5dd7070Spatrick // Decide if the input and output are in the same domain (integer/ptr or
622e5dd7070Spatrick // floating point.
623e5dd7070Spatrick enum AsmDomain {
624e5dd7070Spatrick AD_Int, AD_FP, AD_Other
625e5dd7070Spatrick } InputDomain, OutputDomain;
626e5dd7070Spatrick
627e5dd7070Spatrick if (InTy->isIntegerType() || InTy->isPointerType())
628e5dd7070Spatrick InputDomain = AD_Int;
629e5dd7070Spatrick else if (InTy->isRealFloatingType())
630e5dd7070Spatrick InputDomain = AD_FP;
631e5dd7070Spatrick else
632e5dd7070Spatrick InputDomain = AD_Other;
633e5dd7070Spatrick
634e5dd7070Spatrick if (OutTy->isIntegerType() || OutTy->isPointerType())
635e5dd7070Spatrick OutputDomain = AD_Int;
636e5dd7070Spatrick else if (OutTy->isRealFloatingType())
637e5dd7070Spatrick OutputDomain = AD_FP;
638e5dd7070Spatrick else
639e5dd7070Spatrick OutputDomain = AD_Other;
640e5dd7070Spatrick
641e5dd7070Spatrick // They are ok if they are the same size and in the same domain. This
642e5dd7070Spatrick // allows tying things like:
643e5dd7070Spatrick // void* to int*
644e5dd7070Spatrick // void* to int if they are the same size.
645e5dd7070Spatrick // double to long double if they are the same size.
646e5dd7070Spatrick //
647e5dd7070Spatrick uint64_t OutSize = Context.getTypeSize(OutTy);
648e5dd7070Spatrick uint64_t InSize = Context.getTypeSize(InTy);
649e5dd7070Spatrick if (OutSize == InSize && InputDomain == OutputDomain &&
650e5dd7070Spatrick InputDomain != AD_Other)
651e5dd7070Spatrick continue;
652e5dd7070Spatrick
653e5dd7070Spatrick // If the smaller input/output operand is not mentioned in the asm string,
654e5dd7070Spatrick // then we can promote the smaller one to a larger input and the asm string
655e5dd7070Spatrick // won't notice.
656e5dd7070Spatrick bool SmallerValueMentioned = false;
657e5dd7070Spatrick
658e5dd7070Spatrick // If this is a reference to the input and if the input was the smaller
659e5dd7070Spatrick // one, then we have to reject this asm.
660e5dd7070Spatrick if (isOperandMentioned(InputOpNo, Pieces)) {
661e5dd7070Spatrick // This is a use in the asm string of the smaller operand. Since we
662e5dd7070Spatrick // codegen this by promoting to a wider value, the asm will get printed
663e5dd7070Spatrick // "wrong".
664e5dd7070Spatrick SmallerValueMentioned |= InSize < OutSize;
665e5dd7070Spatrick }
666e5dd7070Spatrick if (isOperandMentioned(TiedTo, Pieces)) {
667e5dd7070Spatrick // If this is a reference to the output, and if the output is the larger
668e5dd7070Spatrick // value, then it's ok because we'll promote the input to the larger type.
669e5dd7070Spatrick SmallerValueMentioned |= OutSize < InSize;
670e5dd7070Spatrick }
671e5dd7070Spatrick
672e5dd7070Spatrick // If the smaller value wasn't mentioned in the asm string, and if the
673e5dd7070Spatrick // output was a register, just extend the shorter one to the size of the
674e5dd7070Spatrick // larger one.
675e5dd7070Spatrick if (!SmallerValueMentioned && InputDomain != AD_Other &&
676*12c85518Srobert OutputConstraintInfos[TiedTo].allowsRegister()) {
677*12c85518Srobert // FIXME: GCC supports the OutSize to be 128 at maximum. Currently codegen
678*12c85518Srobert // crash when the size larger than the register size. So we limit it here.
679*12c85518Srobert if (OutTy->isStructureType() &&
680*12c85518Srobert Context.getIntTypeForBitwidth(OutSize, /*Signed*/ false).isNull()) {
681*12c85518Srobert targetDiag(OutputExpr->getExprLoc(), diag::err_store_value_to_reg);
682*12c85518Srobert return NS;
683*12c85518Srobert }
684*12c85518Srobert
685e5dd7070Spatrick continue;
686*12c85518Srobert }
687e5dd7070Spatrick
688e5dd7070Spatrick // Either both of the operands were mentioned or the smaller one was
689e5dd7070Spatrick // mentioned. One more special case that we'll allow: if the tied input is
690e5dd7070Spatrick // integer, unmentioned, and is a constant, then we'll allow truncating it
691e5dd7070Spatrick // down to the size of the destination.
692e5dd7070Spatrick if (InputDomain == AD_Int && OutputDomain == AD_Int &&
693e5dd7070Spatrick !isOperandMentioned(InputOpNo, Pieces) &&
694e5dd7070Spatrick InputExpr->isEvaluatable(Context)) {
695e5dd7070Spatrick CastKind castKind =
696e5dd7070Spatrick (OutTy->isBooleanType() ? CK_IntegralToBoolean : CK_IntegralCast);
697e5dd7070Spatrick InputExpr = ImpCastExprToType(InputExpr, OutTy, castKind).get();
698e5dd7070Spatrick Exprs[InputOpNo] = InputExpr;
699e5dd7070Spatrick NS->setInputExpr(i, InputExpr);
700e5dd7070Spatrick continue;
701e5dd7070Spatrick }
702e5dd7070Spatrick
703e5dd7070Spatrick targetDiag(InputExpr->getBeginLoc(), diag::err_asm_tying_incompatible_types)
704e5dd7070Spatrick << InTy << OutTy << OutputExpr->getSourceRange()
705e5dd7070Spatrick << InputExpr->getSourceRange();
706e5dd7070Spatrick return NS;
707e5dd7070Spatrick }
708e5dd7070Spatrick
709e5dd7070Spatrick // Check for conflicts between clobber list and input or output lists
710e5dd7070Spatrick SourceLocation ConstraintLoc =
711e5dd7070Spatrick getClobberConflictLocation(Exprs, Constraints, Clobbers, NumClobbers,
712e5dd7070Spatrick NumLabels,
713e5dd7070Spatrick Context.getTargetInfo(), Context);
714e5dd7070Spatrick if (ConstraintLoc.isValid())
715e5dd7070Spatrick targetDiag(ConstraintLoc, diag::error_inoutput_conflict_with_clobber);
716e5dd7070Spatrick
717e5dd7070Spatrick // Check for duplicate asm operand name between input, output and label lists.
718e5dd7070Spatrick typedef std::pair<StringRef , Expr *> NamedOperand;
719e5dd7070Spatrick SmallVector<NamedOperand, 4> NamedOperandList;
720e5dd7070Spatrick for (unsigned i = 0, e = NumOutputs + NumInputs + NumLabels; i != e; ++i)
721e5dd7070Spatrick if (Names[i])
722e5dd7070Spatrick NamedOperandList.emplace_back(
723e5dd7070Spatrick std::make_pair(Names[i]->getName(), Exprs[i]));
724e5dd7070Spatrick // Sort NamedOperandList.
725*12c85518Srobert llvm::stable_sort(NamedOperandList, llvm::less_first());
726e5dd7070Spatrick // Find adjacent duplicate operand.
727e5dd7070Spatrick SmallVector<NamedOperand, 4>::iterator Found =
728e5dd7070Spatrick std::adjacent_find(begin(NamedOperandList), end(NamedOperandList),
729e5dd7070Spatrick [](const NamedOperand &LHS, const NamedOperand &RHS) {
730e5dd7070Spatrick return LHS.first == RHS.first;
731e5dd7070Spatrick });
732e5dd7070Spatrick if (Found != NamedOperandList.end()) {
733e5dd7070Spatrick Diag((Found + 1)->second->getBeginLoc(),
734e5dd7070Spatrick diag::error_duplicate_asm_operand_name)
735e5dd7070Spatrick << (Found + 1)->first;
736e5dd7070Spatrick Diag(Found->second->getBeginLoc(), diag::note_duplicate_asm_operand_name)
737e5dd7070Spatrick << Found->first;
738e5dd7070Spatrick return StmtError();
739e5dd7070Spatrick }
740e5dd7070Spatrick if (NS->isAsmGoto())
741e5dd7070Spatrick setFunctionHasBranchIntoScope();
742*12c85518Srobert
743*12c85518Srobert CleanupVarDeclMarking();
744*12c85518Srobert DiscardCleanupsInEvaluationContext();
745e5dd7070Spatrick return NS;
746e5dd7070Spatrick }
747e5dd7070Spatrick
FillInlineAsmIdentifierInfo(Expr * Res,llvm::InlineAsmIdentifierInfo & Info)748e5dd7070Spatrick void Sema::FillInlineAsmIdentifierInfo(Expr *Res,
749e5dd7070Spatrick llvm::InlineAsmIdentifierInfo &Info) {
750e5dd7070Spatrick QualType T = Res->getType();
751e5dd7070Spatrick Expr::EvalResult Eval;
752e5dd7070Spatrick if (T->isFunctionType() || T->isDependentType())
753e5dd7070Spatrick return Info.setLabel(Res);
754a9ac8606Spatrick if (Res->isPRValue()) {
755e5dd7070Spatrick bool IsEnum = isa<clang::EnumType>(T);
756e5dd7070Spatrick if (DeclRefExpr *DRE = dyn_cast<clang::DeclRefExpr>(Res))
757e5dd7070Spatrick if (DRE->getDecl()->getKind() == Decl::EnumConstant)
758e5dd7070Spatrick IsEnum = true;
759e5dd7070Spatrick if (IsEnum && Res->EvaluateAsRValue(Eval, Context))
760e5dd7070Spatrick return Info.setEnum(Eval.Val.getInt().getSExtValue());
761e5dd7070Spatrick
762e5dd7070Spatrick return Info.setLabel(Res);
763e5dd7070Spatrick }
764e5dd7070Spatrick unsigned Size = Context.getTypeSizeInChars(T).getQuantity();
765e5dd7070Spatrick unsigned Type = Size;
766e5dd7070Spatrick if (const auto *ATy = Context.getAsArrayType(T))
767e5dd7070Spatrick Type = Context.getTypeSizeInChars(ATy->getElementType()).getQuantity();
768e5dd7070Spatrick bool IsGlobalLV = false;
769e5dd7070Spatrick if (Res->EvaluateAsLValue(Eval, Context))
770e5dd7070Spatrick IsGlobalLV = Eval.isGlobalLValue();
771e5dd7070Spatrick Info.setVar(Res, IsGlobalLV, Size, Type);
772e5dd7070Spatrick }
773e5dd7070Spatrick
LookupInlineAsmIdentifier(CXXScopeSpec & SS,SourceLocation TemplateKWLoc,UnqualifiedId & Id,bool IsUnevaluatedContext)774e5dd7070Spatrick ExprResult Sema::LookupInlineAsmIdentifier(CXXScopeSpec &SS,
775e5dd7070Spatrick SourceLocation TemplateKWLoc,
776e5dd7070Spatrick UnqualifiedId &Id,
777e5dd7070Spatrick bool IsUnevaluatedContext) {
778e5dd7070Spatrick
779e5dd7070Spatrick if (IsUnevaluatedContext)
780e5dd7070Spatrick PushExpressionEvaluationContext(
781e5dd7070Spatrick ExpressionEvaluationContext::UnevaluatedAbstract,
782e5dd7070Spatrick ReuseLambdaContextDecl);
783e5dd7070Spatrick
784e5dd7070Spatrick ExprResult Result = ActOnIdExpression(getCurScope(), SS, TemplateKWLoc, Id,
785e5dd7070Spatrick /*trailing lparen*/ false,
786e5dd7070Spatrick /*is & operand*/ false,
787e5dd7070Spatrick /*CorrectionCandidateCallback=*/nullptr,
788e5dd7070Spatrick /*IsInlineAsmIdentifier=*/ true);
789e5dd7070Spatrick
790e5dd7070Spatrick if (IsUnevaluatedContext)
791e5dd7070Spatrick PopExpressionEvaluationContext();
792e5dd7070Spatrick
793e5dd7070Spatrick if (!Result.isUsable()) return Result;
794e5dd7070Spatrick
795e5dd7070Spatrick Result = CheckPlaceholderExpr(Result.get());
796e5dd7070Spatrick if (!Result.isUsable()) return Result;
797e5dd7070Spatrick
798e5dd7070Spatrick // Referring to parameters is not allowed in naked functions.
799e5dd7070Spatrick if (CheckNakedParmReference(Result.get(), *this))
800e5dd7070Spatrick return ExprError();
801e5dd7070Spatrick
802e5dd7070Spatrick QualType T = Result.get()->getType();
803e5dd7070Spatrick
804e5dd7070Spatrick if (T->isDependentType()) {
805e5dd7070Spatrick return Result;
806e5dd7070Spatrick }
807e5dd7070Spatrick
808e5dd7070Spatrick // Any sort of function type is fine.
809e5dd7070Spatrick if (T->isFunctionType()) {
810e5dd7070Spatrick return Result;
811e5dd7070Spatrick }
812e5dd7070Spatrick
813e5dd7070Spatrick // Otherwise, it needs to be a complete type.
814e5dd7070Spatrick if (RequireCompleteExprType(Result.get(), diag::err_asm_incomplete_type)) {
815e5dd7070Spatrick return ExprError();
816e5dd7070Spatrick }
817e5dd7070Spatrick
818e5dd7070Spatrick return Result;
819e5dd7070Spatrick }
820e5dd7070Spatrick
LookupInlineAsmField(StringRef Base,StringRef Member,unsigned & Offset,SourceLocation AsmLoc)821e5dd7070Spatrick bool Sema::LookupInlineAsmField(StringRef Base, StringRef Member,
822e5dd7070Spatrick unsigned &Offset, SourceLocation AsmLoc) {
823e5dd7070Spatrick Offset = 0;
824e5dd7070Spatrick SmallVector<StringRef, 2> Members;
825e5dd7070Spatrick Member.split(Members, ".");
826e5dd7070Spatrick
827e5dd7070Spatrick NamedDecl *FoundDecl = nullptr;
828e5dd7070Spatrick
829e5dd7070Spatrick // MS InlineAsm uses 'this' as a base
830e5dd7070Spatrick if (getLangOpts().CPlusPlus && Base.equals("this")) {
831e5dd7070Spatrick if (const Type *PT = getCurrentThisType().getTypePtrOrNull())
832e5dd7070Spatrick FoundDecl = PT->getPointeeType()->getAsTagDecl();
833e5dd7070Spatrick } else {
834e5dd7070Spatrick LookupResult BaseResult(*this, &Context.Idents.get(Base), SourceLocation(),
835e5dd7070Spatrick LookupOrdinaryName);
836e5dd7070Spatrick if (LookupName(BaseResult, getCurScope()) && BaseResult.isSingleResult())
837e5dd7070Spatrick FoundDecl = BaseResult.getFoundDecl();
838e5dd7070Spatrick }
839e5dd7070Spatrick
840e5dd7070Spatrick if (!FoundDecl)
841e5dd7070Spatrick return true;
842e5dd7070Spatrick
843e5dd7070Spatrick for (StringRef NextMember : Members) {
844e5dd7070Spatrick const RecordType *RT = nullptr;
845e5dd7070Spatrick if (VarDecl *VD = dyn_cast<VarDecl>(FoundDecl))
846e5dd7070Spatrick RT = VD->getType()->getAs<RecordType>();
847e5dd7070Spatrick else if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(FoundDecl)) {
848e5dd7070Spatrick MarkAnyDeclReferenced(TD->getLocation(), TD, /*OdrUse=*/false);
849e5dd7070Spatrick // MS InlineAsm often uses struct pointer aliases as a base
850e5dd7070Spatrick QualType QT = TD->getUnderlyingType();
851e5dd7070Spatrick if (const auto *PT = QT->getAs<PointerType>())
852e5dd7070Spatrick QT = PT->getPointeeType();
853e5dd7070Spatrick RT = QT->getAs<RecordType>();
854e5dd7070Spatrick } else if (TypeDecl *TD = dyn_cast<TypeDecl>(FoundDecl))
855e5dd7070Spatrick RT = TD->getTypeForDecl()->getAs<RecordType>();
856e5dd7070Spatrick else if (FieldDecl *TD = dyn_cast<FieldDecl>(FoundDecl))
857e5dd7070Spatrick RT = TD->getType()->getAs<RecordType>();
858e5dd7070Spatrick if (!RT)
859e5dd7070Spatrick return true;
860e5dd7070Spatrick
861e5dd7070Spatrick if (RequireCompleteType(AsmLoc, QualType(RT, 0),
862e5dd7070Spatrick diag::err_asm_incomplete_type))
863e5dd7070Spatrick return true;
864e5dd7070Spatrick
865e5dd7070Spatrick LookupResult FieldResult(*this, &Context.Idents.get(NextMember),
866e5dd7070Spatrick SourceLocation(), LookupMemberName);
867e5dd7070Spatrick
868e5dd7070Spatrick if (!LookupQualifiedName(FieldResult, RT->getDecl()))
869e5dd7070Spatrick return true;
870e5dd7070Spatrick
871e5dd7070Spatrick if (!FieldResult.isSingleResult())
872e5dd7070Spatrick return true;
873e5dd7070Spatrick FoundDecl = FieldResult.getFoundDecl();
874e5dd7070Spatrick
875e5dd7070Spatrick // FIXME: Handle IndirectFieldDecl?
876e5dd7070Spatrick FieldDecl *FD = dyn_cast<FieldDecl>(FoundDecl);
877e5dd7070Spatrick if (!FD)
878e5dd7070Spatrick return true;
879e5dd7070Spatrick
880e5dd7070Spatrick const ASTRecordLayout &RL = Context.getASTRecordLayout(RT->getDecl());
881e5dd7070Spatrick unsigned i = FD->getFieldIndex();
882e5dd7070Spatrick CharUnits Result = Context.toCharUnitsFromBits(RL.getFieldOffset(i));
883e5dd7070Spatrick Offset += (unsigned)Result.getQuantity();
884e5dd7070Spatrick }
885e5dd7070Spatrick
886e5dd7070Spatrick return false;
887e5dd7070Spatrick }
888e5dd7070Spatrick
889e5dd7070Spatrick ExprResult
LookupInlineAsmVarDeclField(Expr * E,StringRef Member,SourceLocation AsmLoc)890e5dd7070Spatrick Sema::LookupInlineAsmVarDeclField(Expr *E, StringRef Member,
891e5dd7070Spatrick SourceLocation AsmLoc) {
892e5dd7070Spatrick
893e5dd7070Spatrick QualType T = E->getType();
894e5dd7070Spatrick if (T->isDependentType()) {
895e5dd7070Spatrick DeclarationNameInfo NameInfo;
896e5dd7070Spatrick NameInfo.setLoc(AsmLoc);
897e5dd7070Spatrick NameInfo.setName(&Context.Idents.get(Member));
898e5dd7070Spatrick return CXXDependentScopeMemberExpr::Create(
899e5dd7070Spatrick Context, E, T, /*IsArrow=*/false, AsmLoc, NestedNameSpecifierLoc(),
900e5dd7070Spatrick SourceLocation(),
901e5dd7070Spatrick /*FirstQualifierFoundInScope=*/nullptr, NameInfo, /*TemplateArgs=*/nullptr);
902e5dd7070Spatrick }
903e5dd7070Spatrick
904e5dd7070Spatrick const RecordType *RT = T->getAs<RecordType>();
905e5dd7070Spatrick // FIXME: Diagnose this as field access into a scalar type.
906e5dd7070Spatrick if (!RT)
907e5dd7070Spatrick return ExprResult();
908e5dd7070Spatrick
909e5dd7070Spatrick LookupResult FieldResult(*this, &Context.Idents.get(Member), AsmLoc,
910e5dd7070Spatrick LookupMemberName);
911e5dd7070Spatrick
912e5dd7070Spatrick if (!LookupQualifiedName(FieldResult, RT->getDecl()))
913e5dd7070Spatrick return ExprResult();
914e5dd7070Spatrick
915e5dd7070Spatrick // Only normal and indirect field results will work.
916e5dd7070Spatrick ValueDecl *FD = dyn_cast<FieldDecl>(FieldResult.getFoundDecl());
917e5dd7070Spatrick if (!FD)
918e5dd7070Spatrick FD = dyn_cast<IndirectFieldDecl>(FieldResult.getFoundDecl());
919e5dd7070Spatrick if (!FD)
920e5dd7070Spatrick return ExprResult();
921e5dd7070Spatrick
922e5dd7070Spatrick // Make an Expr to thread through OpDecl.
923e5dd7070Spatrick ExprResult Result = BuildMemberReferenceExpr(
924e5dd7070Spatrick E, E->getType(), AsmLoc, /*IsArrow=*/false, CXXScopeSpec(),
925e5dd7070Spatrick SourceLocation(), nullptr, FieldResult, nullptr, nullptr);
926e5dd7070Spatrick
927e5dd7070Spatrick return Result;
928e5dd7070Spatrick }
929e5dd7070Spatrick
ActOnMSAsmStmt(SourceLocation AsmLoc,SourceLocation LBraceLoc,ArrayRef<Token> AsmToks,StringRef AsmString,unsigned NumOutputs,unsigned NumInputs,ArrayRef<StringRef> Constraints,ArrayRef<StringRef> Clobbers,ArrayRef<Expr * > Exprs,SourceLocation EndLoc)930e5dd7070Spatrick StmtResult Sema::ActOnMSAsmStmt(SourceLocation AsmLoc, SourceLocation LBraceLoc,
931e5dd7070Spatrick ArrayRef<Token> AsmToks,
932e5dd7070Spatrick StringRef AsmString,
933e5dd7070Spatrick unsigned NumOutputs, unsigned NumInputs,
934e5dd7070Spatrick ArrayRef<StringRef> Constraints,
935e5dd7070Spatrick ArrayRef<StringRef> Clobbers,
936e5dd7070Spatrick ArrayRef<Expr*> Exprs,
937e5dd7070Spatrick SourceLocation EndLoc) {
938e5dd7070Spatrick bool IsSimple = (NumOutputs != 0 || NumInputs != 0);
939e5dd7070Spatrick setFunctionHasBranchProtectedScope();
940ec727ea7Spatrick
941*12c85518Srobert bool InvalidOperand = false;
942ec727ea7Spatrick for (uint64_t I = 0; I < NumOutputs + NumInputs; ++I) {
943*12c85518Srobert Expr *E = Exprs[I];
944*12c85518Srobert if (E->getType()->isBitIntType()) {
945*12c85518Srobert InvalidOperand = true;
946*12c85518Srobert Diag(E->getBeginLoc(), diag::err_asm_invalid_type)
947*12c85518Srobert << E->getType() << (I < NumOutputs)
948*12c85518Srobert << E->getSourceRange();
949*12c85518Srobert } else if (E->refersToBitField()) {
950*12c85518Srobert InvalidOperand = true;
951*12c85518Srobert FieldDecl *BitField = E->getSourceBitField();
952*12c85518Srobert Diag(E->getBeginLoc(), diag::err_ms_asm_bitfield_unsupported)
953*12c85518Srobert << E->getSourceRange();
954*12c85518Srobert Diag(BitField->getLocation(), diag::note_bitfield_decl);
955ec727ea7Spatrick }
956*12c85518Srobert }
957*12c85518Srobert if (InvalidOperand)
958*12c85518Srobert return StmtError();
959ec727ea7Spatrick
960e5dd7070Spatrick MSAsmStmt *NS =
961e5dd7070Spatrick new (Context) MSAsmStmt(Context, AsmLoc, LBraceLoc, IsSimple,
962e5dd7070Spatrick /*IsVolatile*/ true, AsmToks, NumOutputs, NumInputs,
963e5dd7070Spatrick Constraints, Exprs, AsmString,
964e5dd7070Spatrick Clobbers, EndLoc);
965e5dd7070Spatrick return NS;
966e5dd7070Spatrick }
967e5dd7070Spatrick
GetOrCreateMSAsmLabel(StringRef ExternalLabelName,SourceLocation Location,bool AlwaysCreate)968e5dd7070Spatrick LabelDecl *Sema::GetOrCreateMSAsmLabel(StringRef ExternalLabelName,
969e5dd7070Spatrick SourceLocation Location,
970e5dd7070Spatrick bool AlwaysCreate) {
971e5dd7070Spatrick LabelDecl* Label = LookupOrCreateLabel(PP.getIdentifierInfo(ExternalLabelName),
972e5dd7070Spatrick Location);
973e5dd7070Spatrick
974e5dd7070Spatrick if (Label->isMSAsmLabel()) {
975e5dd7070Spatrick // If we have previously created this label implicitly, mark it as used.
976e5dd7070Spatrick Label->markUsed(Context);
977e5dd7070Spatrick } else {
978e5dd7070Spatrick // Otherwise, insert it, but only resolve it if we have seen the label itself.
979e5dd7070Spatrick std::string InternalName;
980e5dd7070Spatrick llvm::raw_string_ostream OS(InternalName);
981e5dd7070Spatrick // Create an internal name for the label. The name should not be a valid
982e5dd7070Spatrick // mangled name, and should be unique. We use a dot to make the name an
983e5dd7070Spatrick // invalid mangled name. We use LLVM's inline asm ${:uid} escape so that a
984e5dd7070Spatrick // unique label is generated each time this blob is emitted, even after
985e5dd7070Spatrick // inlining or LTO.
986e5dd7070Spatrick OS << "__MSASMLABEL_.${:uid}__";
987e5dd7070Spatrick for (char C : ExternalLabelName) {
988e5dd7070Spatrick OS << C;
989e5dd7070Spatrick // We escape '$' in asm strings by replacing it with "$$"
990e5dd7070Spatrick if (C == '$')
991e5dd7070Spatrick OS << '$';
992e5dd7070Spatrick }
993e5dd7070Spatrick Label->setMSAsmLabel(OS.str());
994e5dd7070Spatrick }
995e5dd7070Spatrick if (AlwaysCreate) {
996e5dd7070Spatrick // The label might have been created implicitly from a previously encountered
997e5dd7070Spatrick // goto statement. So, for both newly created and looked up labels, we mark
998e5dd7070Spatrick // them as resolved.
999e5dd7070Spatrick Label->setMSAsmLabelResolved();
1000e5dd7070Spatrick }
1001e5dd7070Spatrick // Adjust their location for being able to generate accurate diagnostics.
1002e5dd7070Spatrick Label->setLocation(Location);
1003e5dd7070Spatrick
1004e5dd7070Spatrick return Label;
1005e5dd7070Spatrick }
1006