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