1 //===--- SemaStmtAsm.cpp - Semantic Analysis for Asm Statements -----------===//
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
7 //===----------------------------------------------------------------------===//
9 // This file implements semantic analysis for inline asm statements.
11 //===----------------------------------------------------------------------===//
13 #include "clang/AST/ExprCXX.h"
14 #include "clang/AST/GlobalDecl.h"
15 #include "clang/AST/RecordLayout.h"
16 #include "clang/AST/TypeLoc.h"
17 #include "clang/Basic/TargetInfo.h"
18 #include "clang/Lex/Preprocessor.h"
19 #include "clang/Sema/Initialization.h"
20 #include "clang/Sema/Lookup.h"
21 #include "clang/Sema/Scope.h"
22 #include "clang/Sema/ScopeInfo.h"
23 #include "clang/Sema/SemaInternal.h"
24 #include "llvm/ADT/ArrayRef.h"
25 #include "llvm/ADT/StringExtras.h"
26 #include "llvm/ADT/StringSet.h"
27 #include "llvm/MC/MCParser/MCAsmParser.h"
29 using namespace clang
;
32 /// Remove the upper-level LValueToRValue cast from an expression.
33 static void removeLValueToRValueCast(Expr
*E
) {
35 Expr
*ExprUnderCast
= nullptr;
36 SmallVector
<Expr
*, 8> ParentsToUpdate
;
39 ParentsToUpdate
.push_back(Parent
);
40 if (auto *ParenE
= dyn_cast
<ParenExpr
>(Parent
)) {
41 Parent
= ParenE
->getSubExpr();
45 Expr
*Child
= nullptr;
46 CastExpr
*ParentCast
= dyn_cast
<CastExpr
>(Parent
);
48 Child
= ParentCast
->getSubExpr();
52 if (auto *CastE
= dyn_cast
<CastExpr
>(Child
))
53 if (CastE
->getCastKind() == CK_LValueToRValue
) {
54 ExprUnderCast
= CastE
->getSubExpr();
55 // LValueToRValue cast inside GCCAsmStmt requires an explicit cast.
56 ParentCast
->setSubExpr(ExprUnderCast
);
62 // Update parent expressions to have same ValueType as the underlying.
63 assert(ExprUnderCast
&&
64 "Should be reachable only if LValueToRValue cast was found!");
65 auto ValueKind
= ExprUnderCast
->getValueKind();
66 for (Expr
*E
: ParentsToUpdate
)
67 E
->setValueKind(ValueKind
);
70 /// Emit a warning about usage of "noop"-like casts for lvalues (GNU extension)
71 /// and fix the argument with removing LValueToRValue cast from the expression.
72 static void emitAndFixInvalidAsmCastLValue(const Expr
*LVal
, Expr
*BadArgument
,
74 if (!S
.getLangOpts().HeinousExtensions
) {
75 S
.Diag(LVal
->getBeginLoc(), diag::err_invalid_asm_cast_lvalue
)
76 << BadArgument
->getSourceRange();
78 S
.Diag(LVal
->getBeginLoc(), diag::warn_invalid_asm_cast_lvalue
)
79 << BadArgument
->getSourceRange();
81 removeLValueToRValueCast(BadArgument
);
84 /// CheckAsmLValue - GNU C has an extremely ugly extension whereby they silently
85 /// ignore "noop" casts in places where an lvalue is required by an inline asm.
86 /// We emulate this behavior when -fheinous-gnu-extensions is specified, but
87 /// provide a strong guidance to not use it.
89 /// This method checks to see if the argument is an acceptable l-value and
90 /// returns false if it is a case we can handle.
91 static bool CheckAsmLValue(Expr
*E
, Sema
&S
) {
92 // Type dependent expressions will be checked during instantiation.
93 if (E
->isTypeDependent())
97 return false; // Cool, this is an lvalue.
99 // Okay, this is not an lvalue, but perhaps it is the result of a cast that we
100 // are supposed to allow.
101 const Expr
*E2
= E
->IgnoreParenNoopCasts(S
.Context
);
102 if (E
!= E2
&& E2
->isLValue()) {
103 emitAndFixInvalidAsmCastLValue(E2
, E
, S
);
104 // Accept, even if we emitted an error diagnostic.
108 // None of the above, just randomly invalid non-lvalue.
112 /// isOperandMentioned - Return true if the specified operand # is mentioned
113 /// anywhere in the decomposed asm string.
115 isOperandMentioned(unsigned OpNo
,
116 ArrayRef
<GCCAsmStmt::AsmStringPiece
> AsmStrPieces
) {
117 for (unsigned p
= 0, e
= AsmStrPieces
.size(); p
!= e
; ++p
) {
118 const GCCAsmStmt::AsmStringPiece
&Piece
= AsmStrPieces
[p
];
119 if (!Piece
.isOperand())
122 // If this is a reference to the input and if the input was the smaller
123 // one, then we have to reject this asm.
124 if (Piece
.getOperandNo() == OpNo
)
130 static bool CheckNakedParmReference(Expr
*E
, Sema
&S
) {
131 FunctionDecl
*Func
= dyn_cast
<FunctionDecl
>(S
.CurContext
);
134 if (!Func
->hasAttr
<NakedAttr
>())
137 SmallVector
<Expr
*, 4> WorkList
;
138 WorkList
.push_back(E
);
139 while (WorkList
.size()) {
140 Expr
*E
= WorkList
.pop_back_val();
141 if (isa
<CXXThisExpr
>(E
)) {
142 S
.Diag(E
->getBeginLoc(), diag::err_asm_naked_this_ref
);
143 S
.Diag(Func
->getAttr
<NakedAttr
>()->getLocation(), diag::note_attribute
);
146 if (DeclRefExpr
*DRE
= dyn_cast
<DeclRefExpr
>(E
)) {
147 if (isa
<ParmVarDecl
>(DRE
->getDecl())) {
148 S
.Diag(DRE
->getBeginLoc(), diag::err_asm_naked_parm_ref
);
149 S
.Diag(Func
->getAttr
<NakedAttr
>()->getLocation(), diag::note_attribute
);
153 for (Stmt
*Child
: E
->children()) {
154 if (Expr
*E
= dyn_cast_or_null
<Expr
>(Child
))
155 WorkList
.push_back(E
);
161 /// Returns true if given expression is not compatible with inline
162 /// assembly's memory constraint; false otherwise.
163 static bool checkExprMemoryConstraintCompat(Sema
&S
, Expr
*E
,
164 TargetInfo::ConstraintInfo
&Info
,
165 bool is_input_expr
) {
171 } EType
= ExprSafeType
;
173 // Bitfields, vector elements and global register variables are not
175 if (E
->refersToBitField())
176 EType
= ExprBitfield
;
177 else if (E
->refersToVectorElement())
178 EType
= ExprVectorElt
;
179 else if (E
->refersToGlobalRegisterVar())
180 EType
= ExprGlobalRegVar
;
182 if (EType
!= ExprSafeType
) {
183 S
.Diag(E
->getBeginLoc(), diag::err_asm_non_addr_value_in_memory_constraint
)
184 << EType
<< is_input_expr
<< Info
.getConstraintStr()
185 << E
->getSourceRange();
192 // Extracting the register name from the Expression value,
193 // if there is no register name to extract, returns ""
194 static StringRef
extractRegisterName(const Expr
*Expression
,
195 const TargetInfo
&Target
) {
196 Expression
= Expression
->IgnoreImpCasts();
197 if (const DeclRefExpr
*AsmDeclRef
= dyn_cast
<DeclRefExpr
>(Expression
)) {
198 // Handle cases where the expression is a variable
199 const VarDecl
*Variable
= dyn_cast
<VarDecl
>(AsmDeclRef
->getDecl());
200 if (Variable
&& Variable
->getStorageClass() == SC_Register
) {
201 if (AsmLabelAttr
*Attr
= Variable
->getAttr
<AsmLabelAttr
>())
202 if (Target
.isValidGCCRegisterName(Attr
->getLabel()))
203 return Target
.getNormalizedGCCRegisterName(Attr
->getLabel(), true);
209 // Checks if there is a conflict between the input and output lists with the
210 // clobbers list. If there's a conflict, returns the location of the
211 // conflicted clobber, else returns nullptr
212 static SourceLocation
213 getClobberConflictLocation(MultiExprArg Exprs
, StringLiteral
**Constraints
,
214 StringLiteral
**Clobbers
, int NumClobbers
,
216 const TargetInfo
&Target
, ASTContext
&Cont
) {
217 llvm::StringSet
<> InOutVars
;
218 // Collect all the input and output registers from the extended asm
219 // statement in order to check for conflicts with the clobber list
220 for (unsigned int i
= 0; i
< Exprs
.size() - NumLabels
; ++i
) {
221 StringRef Constraint
= Constraints
[i
]->getString();
222 StringRef InOutReg
= Target
.getConstraintRegister(
223 Constraint
, extractRegisterName(Exprs
[i
], Target
));
225 InOutVars
.insert(InOutReg
);
227 // Check for each item in the clobber list if it conflicts with the input
229 for (int i
= 0; i
< NumClobbers
; ++i
) {
230 StringRef Clobber
= Clobbers
[i
]->getString();
231 // We only check registers, therefore we don't check cc and memory
233 if (Clobber
== "cc" || Clobber
== "memory" || Clobber
== "unwind")
235 Clobber
= Target
.getNormalizedGCCRegisterName(Clobber
, true);
236 // Go over the output's registers we collected
237 if (InOutVars
.count(Clobber
))
238 return Clobbers
[i
]->getBeginLoc();
240 return SourceLocation();
243 StmtResult
Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc
, bool IsSimple
,
244 bool IsVolatile
, unsigned NumOutputs
,
245 unsigned NumInputs
, IdentifierInfo
**Names
,
246 MultiExprArg constraints
, MultiExprArg Exprs
,
247 Expr
*asmString
, MultiExprArg clobbers
,
249 SourceLocation RParenLoc
) {
250 unsigned NumClobbers
= clobbers
.size();
251 StringLiteral
**Constraints
=
252 reinterpret_cast<StringLiteral
**>(constraints
.data());
253 StringLiteral
*AsmString
= cast
<StringLiteral
>(asmString
);
254 StringLiteral
**Clobbers
= reinterpret_cast<StringLiteral
**>(clobbers
.data());
256 SmallVector
<TargetInfo::ConstraintInfo
, 4> OutputConstraintInfos
;
258 // The parser verifies that there is a string literal here.
259 assert(AsmString
->isOrdinary());
261 FunctionDecl
*FD
= dyn_cast
<FunctionDecl
>(getCurLexicalContext());
262 llvm::StringMap
<bool> FeatureMap
;
263 Context
.getFunctionFeatureMap(FeatureMap
, FD
);
265 for (unsigned i
= 0; i
!= NumOutputs
; i
++) {
266 StringLiteral
*Literal
= Constraints
[i
];
267 assert(Literal
->isOrdinary());
269 StringRef OutputName
;
271 OutputName
= Names
[i
]->getName();
273 TargetInfo::ConstraintInfo
Info(Literal
->getString(), OutputName
);
274 if (!Context
.getTargetInfo().validateOutputConstraint(Info
) &&
275 !(LangOpts
.HIPStdPar
&& LangOpts
.CUDAIsDevice
)) {
276 targetDiag(Literal
->getBeginLoc(),
277 diag::err_asm_invalid_output_constraint
)
278 << Info
.getConstraintStr();
280 GCCAsmStmt(Context
, AsmLoc
, IsSimple
, IsVolatile
, NumOutputs
,
281 NumInputs
, Names
, Constraints
, Exprs
.data(), AsmString
,
282 NumClobbers
, Clobbers
, NumLabels
, RParenLoc
);
285 ExprResult ER
= CheckPlaceholderExpr(Exprs
[i
]);
290 // Check that the output exprs are valid lvalues.
291 Expr
*OutputExpr
= Exprs
[i
];
293 // Referring to parameters is not allowed in naked functions.
294 if (CheckNakedParmReference(OutputExpr
, *this))
297 // Check that the output expression is compatible with memory constraint.
298 if (Info
.allowsMemory() &&
299 checkExprMemoryConstraintCompat(*this, OutputExpr
, Info
, false))
302 // Disallow bit-precise integer types, since the backends tend to have
303 // difficulties with abnormal sizes.
304 if (OutputExpr
->getType()->isBitIntType())
306 Diag(OutputExpr
->getBeginLoc(), diag::err_asm_invalid_type
)
307 << OutputExpr
->getType() << 0 /*Input*/
308 << OutputExpr
->getSourceRange());
310 OutputConstraintInfos
.push_back(Info
);
312 // If this is dependent, just continue.
313 if (OutputExpr
->isTypeDependent())
316 Expr::isModifiableLvalueResult IsLV
=
317 OutputExpr
->isModifiableLvalue(Context
, /*Loc=*/nullptr);
319 case Expr::MLV_Valid
:
320 // Cool, this is an lvalue.
322 case Expr::MLV_ArrayType
:
325 case Expr::MLV_LValueCast
: {
326 const Expr
*LVal
= OutputExpr
->IgnoreParenNoopCasts(Context
);
327 emitAndFixInvalidAsmCastLValue(LVal
, OutputExpr
, *this);
328 // Accept, even if we emitted an error diagnostic.
331 case Expr::MLV_IncompleteType
:
332 case Expr::MLV_IncompleteVoidType
:
333 if (RequireCompleteType(OutputExpr
->getBeginLoc(), Exprs
[i
]->getType(),
334 diag::err_dereference_incomplete_type
))
338 return StmtError(Diag(OutputExpr
->getBeginLoc(),
339 diag::err_asm_invalid_lvalue_in_output
)
340 << OutputExpr
->getSourceRange());
343 unsigned Size
= Context
.getTypeSize(OutputExpr
->getType());
344 if (!Context
.getTargetInfo().validateOutputSize(
345 FeatureMap
, Literal
->getString(), Size
)) {
346 targetDiag(OutputExpr
->getBeginLoc(), diag::err_asm_invalid_output_size
)
347 << Info
.getConstraintStr();
349 GCCAsmStmt(Context
, AsmLoc
, IsSimple
, IsVolatile
, NumOutputs
,
350 NumInputs
, Names
, Constraints
, Exprs
.data(), AsmString
,
351 NumClobbers
, Clobbers
, NumLabels
, RParenLoc
);
355 SmallVector
<TargetInfo::ConstraintInfo
, 4> InputConstraintInfos
;
357 for (unsigned i
= NumOutputs
, e
= NumOutputs
+ NumInputs
; i
!= e
; i
++) {
358 StringLiteral
*Literal
= Constraints
[i
];
359 assert(Literal
->isOrdinary());
363 InputName
= Names
[i
]->getName();
365 TargetInfo::ConstraintInfo
Info(Literal
->getString(), InputName
);
366 if (!Context
.getTargetInfo().validateInputConstraint(OutputConstraintInfos
,
368 targetDiag(Literal
->getBeginLoc(), diag::err_asm_invalid_input_constraint
)
369 << Info
.getConstraintStr();
371 GCCAsmStmt(Context
, AsmLoc
, IsSimple
, IsVolatile
, NumOutputs
,
372 NumInputs
, Names
, Constraints
, Exprs
.data(), AsmString
,
373 NumClobbers
, Clobbers
, NumLabels
, RParenLoc
);
376 ExprResult ER
= CheckPlaceholderExpr(Exprs
[i
]);
381 Expr
*InputExpr
= Exprs
[i
];
383 if (InputExpr
->getType()->isMemberPointerType())
384 return StmtError(Diag(InputExpr
->getBeginLoc(),
385 diag::err_asm_pmf_through_constraint_not_permitted
)
386 << InputExpr
->getSourceRange());
388 // Referring to parameters is not allowed in naked functions.
389 if (CheckNakedParmReference(InputExpr
, *this))
392 // Check that the input expression is compatible with memory constraint.
393 if (Info
.allowsMemory() &&
394 checkExprMemoryConstraintCompat(*this, InputExpr
, Info
, true))
397 // Only allow void types for memory constraints.
398 if (Info
.allowsMemory() && !Info
.allowsRegister()) {
399 if (CheckAsmLValue(InputExpr
, *this))
400 return StmtError(Diag(InputExpr
->getBeginLoc(),
401 diag::err_asm_invalid_lvalue_in_input
)
402 << Info
.getConstraintStr()
403 << InputExpr
->getSourceRange());
405 ExprResult Result
= DefaultFunctionArrayLvalueConversion(Exprs
[i
]);
406 if (Result
.isInvalid())
409 InputExpr
= Exprs
[i
] = Result
.get();
411 if (Info
.requiresImmediateConstant() && !Info
.allowsRegister()) {
412 if (!InputExpr
->isValueDependent()) {
413 Expr::EvalResult EVResult
;
414 if (InputExpr
->EvaluateAsRValue(EVResult
, Context
, true)) {
415 // For compatibility with GCC, we also allow pointers that would be
416 // integral constant expressions if they were cast to int.
417 llvm::APSInt IntResult
;
418 if (EVResult
.Val
.toIntegralConstant(IntResult
, InputExpr
->getType(),
420 if (!Info
.isValidAsmImmediate(IntResult
))
422 Diag(InputExpr
->getBeginLoc(),
423 diag::err_invalid_asm_value_for_constraint
)
424 << toString(IntResult
, 10) << Info
.getConstraintStr()
425 << InputExpr
->getSourceRange());
431 if (Info
.allowsRegister()) {
432 if (InputExpr
->getType()->isVoidType()) {
434 Diag(InputExpr
->getBeginLoc(), diag::err_asm_invalid_type_in_input
)
435 << InputExpr
->getType() << Info
.getConstraintStr()
436 << InputExpr
->getSourceRange());
440 if (InputExpr
->getType()->isBitIntType())
442 Diag(InputExpr
->getBeginLoc(), diag::err_asm_invalid_type
)
443 << InputExpr
->getType() << 1 /*Output*/
444 << InputExpr
->getSourceRange());
446 InputConstraintInfos
.push_back(Info
);
448 const Type
*Ty
= Exprs
[i
]->getType().getTypePtr();
449 if (Ty
->isDependentType())
452 if (!Ty
->isVoidType() || !Info
.allowsMemory())
453 if (RequireCompleteType(InputExpr
->getBeginLoc(), Exprs
[i
]->getType(),
454 diag::err_dereference_incomplete_type
))
457 unsigned Size
= Context
.getTypeSize(Ty
);
458 if (!Context
.getTargetInfo().validateInputSize(FeatureMap
,
459 Literal
->getString(), Size
))
460 return targetDiag(InputExpr
->getBeginLoc(),
461 diag::err_asm_invalid_input_size
)
462 << Info
.getConstraintStr();
465 std::optional
<SourceLocation
> UnwindClobberLoc
;
467 // Check that the clobbers are valid.
468 for (unsigned i
= 0; i
!= NumClobbers
; i
++) {
469 StringLiteral
*Literal
= Clobbers
[i
];
470 assert(Literal
->isOrdinary());
472 StringRef Clobber
= Literal
->getString();
474 if (!Context
.getTargetInfo().isValidClobber(Clobber
)) {
475 targetDiag(Literal
->getBeginLoc(), diag::err_asm_unknown_register_name
)
478 GCCAsmStmt(Context
, AsmLoc
, IsSimple
, IsVolatile
, NumOutputs
,
479 NumInputs
, Names
, Constraints
, Exprs
.data(), AsmString
,
480 NumClobbers
, Clobbers
, NumLabels
, RParenLoc
);
483 if (Clobber
== "unwind") {
484 UnwindClobberLoc
= Literal
->getBeginLoc();
488 // Using unwind clobber and asm-goto together is not supported right now.
489 if (UnwindClobberLoc
&& NumLabels
> 0) {
490 targetDiag(*UnwindClobberLoc
, diag::err_asm_unwind_and_goto
);
492 GCCAsmStmt(Context
, AsmLoc
, IsSimple
, IsVolatile
, NumOutputs
, NumInputs
,
493 Names
, Constraints
, Exprs
.data(), AsmString
, NumClobbers
,
494 Clobbers
, NumLabels
, RParenLoc
);
498 new (Context
) GCCAsmStmt(Context
, AsmLoc
, IsSimple
, IsVolatile
, NumOutputs
,
499 NumInputs
, Names
, Constraints
, Exprs
.data(),
500 AsmString
, NumClobbers
, Clobbers
, NumLabels
,
502 // Validate the asm string, ensuring it makes sense given the operands we
504 SmallVector
<GCCAsmStmt::AsmStringPiece
, 8> Pieces
;
506 if (unsigned DiagID
= NS
->AnalyzeAsmString(Pieces
, Context
, DiagOffs
)) {
507 targetDiag(getLocationOfStringLiteralByte(AsmString
, DiagOffs
), DiagID
)
508 << AsmString
->getSourceRange();
512 // Validate constraints and modifiers.
513 for (unsigned i
= 0, e
= Pieces
.size(); i
!= e
; ++i
) {
514 GCCAsmStmt::AsmStringPiece
&Piece
= Pieces
[i
];
515 if (!Piece
.isOperand()) continue;
517 // Look for the correct constraint index.
518 unsigned ConstraintIdx
= Piece
.getOperandNo();
519 unsigned NumOperands
= NS
->getNumOutputs() + NS
->getNumInputs();
520 // Labels are the last in the Exprs list.
521 if (NS
->isAsmGoto() && ConstraintIdx
>= NumOperands
)
523 // Look for the (ConstraintIdx - NumOperands + 1)th constraint with
525 if (ConstraintIdx
>= NumOperands
) {
526 unsigned I
= 0, E
= NS
->getNumOutputs();
528 for (unsigned Cnt
= ConstraintIdx
- NumOperands
; I
!= E
; ++I
)
529 if (OutputConstraintInfos
[I
].isReadWrite() && Cnt
-- == 0) {
534 assert(I
!= E
&& "Invalid operand number should have been caught in "
535 " AnalyzeAsmString");
538 // Now that we have the right indexes go ahead and check.
539 StringLiteral
*Literal
= Constraints
[ConstraintIdx
];
540 const Type
*Ty
= Exprs
[ConstraintIdx
]->getType().getTypePtr();
541 if (Ty
->isDependentType() || Ty
->isIncompleteType())
544 unsigned Size
= Context
.getTypeSize(Ty
);
545 std::string SuggestedModifier
;
546 if (!Context
.getTargetInfo().validateConstraintModifier(
547 Literal
->getString(), Piece
.getModifier(), Size
,
548 SuggestedModifier
)) {
549 targetDiag(Exprs
[ConstraintIdx
]->getBeginLoc(),
550 diag::warn_asm_mismatched_size_modifier
);
552 if (!SuggestedModifier
.empty()) {
553 auto B
= targetDiag(Piece
.getRange().getBegin(),
554 diag::note_asm_missing_constraint_modifier
)
555 << SuggestedModifier
;
556 SuggestedModifier
= "%" + SuggestedModifier
+ Piece
.getString();
557 B
<< FixItHint::CreateReplacement(Piece
.getRange(), SuggestedModifier
);
562 // Validate tied input operands for type mismatches.
563 unsigned NumAlternatives
= ~0U;
564 for (unsigned i
= 0, e
= OutputConstraintInfos
.size(); i
!= e
; ++i
) {
565 TargetInfo::ConstraintInfo
&Info
= OutputConstraintInfos
[i
];
566 StringRef ConstraintStr
= Info
.getConstraintStr();
567 unsigned AltCount
= ConstraintStr
.count(',') + 1;
568 if (NumAlternatives
== ~0U) {
569 NumAlternatives
= AltCount
;
570 } else if (NumAlternatives
!= AltCount
) {
571 targetDiag(NS
->getOutputExpr(i
)->getBeginLoc(),
572 diag::err_asm_unexpected_constraint_alternatives
)
573 << NumAlternatives
<< AltCount
;
577 SmallVector
<size_t, 4> InputMatchedToOutput(OutputConstraintInfos
.size(),
579 for (unsigned i
= 0, e
= InputConstraintInfos
.size(); i
!= e
; ++i
) {
580 TargetInfo::ConstraintInfo
&Info
= InputConstraintInfos
[i
];
581 StringRef ConstraintStr
= Info
.getConstraintStr();
582 unsigned AltCount
= ConstraintStr
.count(',') + 1;
583 if (NumAlternatives
== ~0U) {
584 NumAlternatives
= AltCount
;
585 } else if (NumAlternatives
!= AltCount
) {
586 targetDiag(NS
->getInputExpr(i
)->getBeginLoc(),
587 diag::err_asm_unexpected_constraint_alternatives
)
588 << NumAlternatives
<< AltCount
;
592 // If this is a tied constraint, verify that the output and input have
593 // either exactly the same type, or that they are int/ptr operands with the
594 // same size (int/long, int*/long, are ok etc).
595 if (!Info
.hasTiedOperand()) continue;
597 unsigned TiedTo
= Info
.getTiedOperand();
598 unsigned InputOpNo
= i
+NumOutputs
;
599 Expr
*OutputExpr
= Exprs
[TiedTo
];
600 Expr
*InputExpr
= Exprs
[InputOpNo
];
602 // Make sure no more than one input constraint matches each output.
603 assert(TiedTo
< InputMatchedToOutput
.size() && "TiedTo value out of range");
604 if (InputMatchedToOutput
[TiedTo
] != ~0U) {
605 targetDiag(NS
->getInputExpr(i
)->getBeginLoc(),
606 diag::err_asm_input_duplicate_match
)
608 targetDiag(NS
->getInputExpr(InputMatchedToOutput
[TiedTo
])->getBeginLoc(),
609 diag::note_asm_input_duplicate_first
)
613 InputMatchedToOutput
[TiedTo
] = i
;
615 if (OutputExpr
->isTypeDependent() || InputExpr
->isTypeDependent())
618 QualType InTy
= InputExpr
->getType();
619 QualType OutTy
= OutputExpr
->getType();
620 if (Context
.hasSameType(InTy
, OutTy
))
621 continue; // All types can be tied to themselves.
623 // Decide if the input and output are in the same domain (integer/ptr or
626 AD_Int
, AD_FP
, AD_Other
627 } InputDomain
, OutputDomain
;
629 if (InTy
->isIntegerType() || InTy
->isPointerType())
630 InputDomain
= AD_Int
;
631 else if (InTy
->isRealFloatingType())
634 InputDomain
= AD_Other
;
636 if (OutTy
->isIntegerType() || OutTy
->isPointerType())
637 OutputDomain
= AD_Int
;
638 else if (OutTy
->isRealFloatingType())
639 OutputDomain
= AD_FP
;
641 OutputDomain
= AD_Other
;
643 // They are ok if they are the same size and in the same domain. This
644 // allows tying things like:
646 // void* to int if they are the same size.
647 // double to long double if they are the same size.
649 uint64_t OutSize
= Context
.getTypeSize(OutTy
);
650 uint64_t InSize
= Context
.getTypeSize(InTy
);
651 if (OutSize
== InSize
&& InputDomain
== OutputDomain
&&
652 InputDomain
!= AD_Other
)
655 // If the smaller input/output operand is not mentioned in the asm string,
656 // then we can promote the smaller one to a larger input and the asm string
658 bool SmallerValueMentioned
= false;
660 // If this is a reference to the input and if the input was the smaller
661 // one, then we have to reject this asm.
662 if (isOperandMentioned(InputOpNo
, Pieces
)) {
663 // This is a use in the asm string of the smaller operand. Since we
664 // codegen this by promoting to a wider value, the asm will get printed
666 SmallerValueMentioned
|= InSize
< OutSize
;
668 if (isOperandMentioned(TiedTo
, Pieces
)) {
669 // If this is a reference to the output, and if the output is the larger
670 // value, then it's ok because we'll promote the input to the larger type.
671 SmallerValueMentioned
|= OutSize
< InSize
;
674 // If the smaller value wasn't mentioned in the asm string, and if the
675 // output was a register, just extend the shorter one to the size of the
677 if (!SmallerValueMentioned
&& InputDomain
!= AD_Other
&&
678 OutputConstraintInfos
[TiedTo
].allowsRegister()) {
679 // FIXME: GCC supports the OutSize to be 128 at maximum. Currently codegen
680 // crash when the size larger than the register size. So we limit it here.
681 if (OutTy
->isStructureType() &&
682 Context
.getIntTypeForBitwidth(OutSize
, /*Signed*/ false).isNull()) {
683 targetDiag(OutputExpr
->getExprLoc(), diag::err_store_value_to_reg
);
690 // Either both of the operands were mentioned or the smaller one was
691 // mentioned. One more special case that we'll allow: if the tied input is
692 // integer, unmentioned, and is a constant, then we'll allow truncating it
693 // down to the size of the destination.
694 if (InputDomain
== AD_Int
&& OutputDomain
== AD_Int
&&
695 !isOperandMentioned(InputOpNo
, Pieces
) &&
696 InputExpr
->isEvaluatable(Context
)) {
698 (OutTy
->isBooleanType() ? CK_IntegralToBoolean
: CK_IntegralCast
);
699 InputExpr
= ImpCastExprToType(InputExpr
, OutTy
, castKind
).get();
700 Exprs
[InputOpNo
] = InputExpr
;
701 NS
->setInputExpr(i
, InputExpr
);
705 targetDiag(InputExpr
->getBeginLoc(), diag::err_asm_tying_incompatible_types
)
706 << InTy
<< OutTy
<< OutputExpr
->getSourceRange()
707 << InputExpr
->getSourceRange();
711 // Check for conflicts between clobber list and input or output lists
712 SourceLocation ConstraintLoc
=
713 getClobberConflictLocation(Exprs
, Constraints
, Clobbers
, NumClobbers
,
715 Context
.getTargetInfo(), Context
);
716 if (ConstraintLoc
.isValid())
717 targetDiag(ConstraintLoc
, diag::error_inoutput_conflict_with_clobber
);
719 // Check for duplicate asm operand name between input, output and label lists.
720 typedef std::pair
<StringRef
, Expr
*> NamedOperand
;
721 SmallVector
<NamedOperand
, 4> NamedOperandList
;
722 for (unsigned i
= 0, e
= NumOutputs
+ NumInputs
+ NumLabels
; i
!= e
; ++i
)
724 NamedOperandList
.emplace_back(
725 std::make_pair(Names
[i
]->getName(), Exprs
[i
]));
726 // Sort NamedOperandList.
727 llvm::stable_sort(NamedOperandList
, llvm::less_first());
728 // Find adjacent duplicate operand.
729 SmallVector
<NamedOperand
, 4>::iterator Found
=
730 std::adjacent_find(begin(NamedOperandList
), end(NamedOperandList
),
731 [](const NamedOperand
&LHS
, const NamedOperand
&RHS
) {
732 return LHS
.first
== RHS
.first
;
734 if (Found
!= NamedOperandList
.end()) {
735 Diag((Found
+ 1)->second
->getBeginLoc(),
736 diag::error_duplicate_asm_operand_name
)
737 << (Found
+ 1)->first
;
738 Diag(Found
->second
->getBeginLoc(), diag::note_duplicate_asm_operand_name
)
743 setFunctionHasBranchIntoScope();
745 CleanupVarDeclMarking();
746 DiscardCleanupsInEvaluationContext();
750 void Sema::FillInlineAsmIdentifierInfo(Expr
*Res
,
751 llvm::InlineAsmIdentifierInfo
&Info
) {
752 QualType T
= Res
->getType();
753 Expr::EvalResult Eval
;
754 if (T
->isFunctionType() || T
->isDependentType())
755 return Info
.setLabel(Res
);
756 if (Res
->isPRValue()) {
757 bool IsEnum
= isa
<clang::EnumType
>(T
);
758 if (DeclRefExpr
*DRE
= dyn_cast
<clang::DeclRefExpr
>(Res
))
759 if (DRE
->getDecl()->getKind() == Decl::EnumConstant
)
761 if (IsEnum
&& Res
->EvaluateAsRValue(Eval
, Context
))
762 return Info
.setEnum(Eval
.Val
.getInt().getSExtValue());
764 return Info
.setLabel(Res
);
766 unsigned Size
= Context
.getTypeSizeInChars(T
).getQuantity();
767 unsigned Type
= Size
;
768 if (const auto *ATy
= Context
.getAsArrayType(T
))
769 Type
= Context
.getTypeSizeInChars(ATy
->getElementType()).getQuantity();
770 bool IsGlobalLV
= false;
771 if (Res
->EvaluateAsLValue(Eval
, Context
))
772 IsGlobalLV
= Eval
.isGlobalLValue();
773 Info
.setVar(Res
, IsGlobalLV
, Size
, Type
);
776 ExprResult
Sema::LookupInlineAsmIdentifier(CXXScopeSpec
&SS
,
777 SourceLocation TemplateKWLoc
,
779 bool IsUnevaluatedContext
) {
781 if (IsUnevaluatedContext
)
782 PushExpressionEvaluationContext(
783 ExpressionEvaluationContext::UnevaluatedAbstract
,
784 ReuseLambdaContextDecl
);
786 ExprResult Result
= ActOnIdExpression(getCurScope(), SS
, TemplateKWLoc
, Id
,
787 /*trailing lparen*/ false,
788 /*is & operand*/ false,
789 /*CorrectionCandidateCallback=*/nullptr,
790 /*IsInlineAsmIdentifier=*/ true);
792 if (IsUnevaluatedContext
)
793 PopExpressionEvaluationContext();
795 if (!Result
.isUsable()) return Result
;
797 Result
= CheckPlaceholderExpr(Result
.get());
798 if (!Result
.isUsable()) return Result
;
800 // Referring to parameters is not allowed in naked functions.
801 if (CheckNakedParmReference(Result
.get(), *this))
804 QualType T
= Result
.get()->getType();
806 if (T
->isDependentType()) {
810 // Any sort of function type is fine.
811 if (T
->isFunctionType()) {
815 // Otherwise, it needs to be a complete type.
816 if (RequireCompleteExprType(Result
.get(), diag::err_asm_incomplete_type
)) {
823 bool Sema::LookupInlineAsmField(StringRef Base
, StringRef Member
,
824 unsigned &Offset
, SourceLocation AsmLoc
) {
826 SmallVector
<StringRef
, 2> Members
;
827 Member
.split(Members
, ".");
829 NamedDecl
*FoundDecl
= nullptr;
831 // MS InlineAsm uses 'this' as a base
832 if (getLangOpts().CPlusPlus
&& Base
.equals("this")) {
833 if (const Type
*PT
= getCurrentThisType().getTypePtrOrNull())
834 FoundDecl
= PT
->getPointeeType()->getAsTagDecl();
836 LookupResult
BaseResult(*this, &Context
.Idents
.get(Base
), SourceLocation(),
838 if (LookupName(BaseResult
, getCurScope()) && BaseResult
.isSingleResult())
839 FoundDecl
= BaseResult
.getFoundDecl();
845 for (StringRef NextMember
: Members
) {
846 const RecordType
*RT
= nullptr;
847 if (VarDecl
*VD
= dyn_cast
<VarDecl
>(FoundDecl
))
848 RT
= VD
->getType()->getAs
<RecordType
>();
849 else if (TypedefNameDecl
*TD
= dyn_cast
<TypedefNameDecl
>(FoundDecl
)) {
850 MarkAnyDeclReferenced(TD
->getLocation(), TD
, /*OdrUse=*/false);
851 // MS InlineAsm often uses struct pointer aliases as a base
852 QualType QT
= TD
->getUnderlyingType();
853 if (const auto *PT
= QT
->getAs
<PointerType
>())
854 QT
= PT
->getPointeeType();
855 RT
= QT
->getAs
<RecordType
>();
856 } else if (TypeDecl
*TD
= dyn_cast
<TypeDecl
>(FoundDecl
))
857 RT
= TD
->getTypeForDecl()->getAs
<RecordType
>();
858 else if (FieldDecl
*TD
= dyn_cast
<FieldDecl
>(FoundDecl
))
859 RT
= TD
->getType()->getAs
<RecordType
>();
863 if (RequireCompleteType(AsmLoc
, QualType(RT
, 0),
864 diag::err_asm_incomplete_type
))
867 LookupResult
FieldResult(*this, &Context
.Idents
.get(NextMember
),
868 SourceLocation(), LookupMemberName
);
870 if (!LookupQualifiedName(FieldResult
, RT
->getDecl()))
873 if (!FieldResult
.isSingleResult())
875 FoundDecl
= FieldResult
.getFoundDecl();
877 // FIXME: Handle IndirectFieldDecl?
878 FieldDecl
*FD
= dyn_cast
<FieldDecl
>(FoundDecl
);
882 const ASTRecordLayout
&RL
= Context
.getASTRecordLayout(RT
->getDecl());
883 unsigned i
= FD
->getFieldIndex();
884 CharUnits Result
= Context
.toCharUnitsFromBits(RL
.getFieldOffset(i
));
885 Offset
+= (unsigned)Result
.getQuantity();
892 Sema::LookupInlineAsmVarDeclField(Expr
*E
, StringRef Member
,
893 SourceLocation AsmLoc
) {
895 QualType T
= E
->getType();
896 if (T
->isDependentType()) {
897 DeclarationNameInfo NameInfo
;
898 NameInfo
.setLoc(AsmLoc
);
899 NameInfo
.setName(&Context
.Idents
.get(Member
));
900 return CXXDependentScopeMemberExpr::Create(
901 Context
, E
, T
, /*IsArrow=*/false, AsmLoc
, NestedNameSpecifierLoc(),
903 /*FirstQualifierFoundInScope=*/nullptr, NameInfo
, /*TemplateArgs=*/nullptr);
906 const RecordType
*RT
= T
->getAs
<RecordType
>();
907 // FIXME: Diagnose this as field access into a scalar type.
911 LookupResult
FieldResult(*this, &Context
.Idents
.get(Member
), AsmLoc
,
914 if (!LookupQualifiedName(FieldResult
, RT
->getDecl()))
917 // Only normal and indirect field results will work.
918 ValueDecl
*FD
= dyn_cast
<FieldDecl
>(FieldResult
.getFoundDecl());
920 FD
= dyn_cast
<IndirectFieldDecl
>(FieldResult
.getFoundDecl());
924 // Make an Expr to thread through OpDecl.
925 ExprResult Result
= BuildMemberReferenceExpr(
926 E
, E
->getType(), AsmLoc
, /*IsArrow=*/false, CXXScopeSpec(),
927 SourceLocation(), nullptr, FieldResult
, nullptr, nullptr);
932 StmtResult
Sema::ActOnMSAsmStmt(SourceLocation AsmLoc
, SourceLocation LBraceLoc
,
933 ArrayRef
<Token
> AsmToks
,
935 unsigned NumOutputs
, unsigned NumInputs
,
936 ArrayRef
<StringRef
> Constraints
,
937 ArrayRef
<StringRef
> Clobbers
,
938 ArrayRef
<Expr
*> Exprs
,
939 SourceLocation EndLoc
) {
940 bool IsSimple
= (NumOutputs
!= 0 || NumInputs
!= 0);
941 setFunctionHasBranchProtectedScope();
943 bool InvalidOperand
= false;
944 for (uint64_t I
= 0; I
< NumOutputs
+ NumInputs
; ++I
) {
946 if (E
->getType()->isBitIntType()) {
947 InvalidOperand
= true;
948 Diag(E
->getBeginLoc(), diag::err_asm_invalid_type
)
949 << E
->getType() << (I
< NumOutputs
)
950 << E
->getSourceRange();
951 } else if (E
->refersToBitField()) {
952 InvalidOperand
= true;
953 FieldDecl
*BitField
= E
->getSourceBitField();
954 Diag(E
->getBeginLoc(), diag::err_ms_asm_bitfield_unsupported
)
955 << E
->getSourceRange();
956 Diag(BitField
->getLocation(), diag::note_bitfield_decl
);
963 new (Context
) MSAsmStmt(Context
, AsmLoc
, LBraceLoc
, IsSimple
,
964 /*IsVolatile*/ true, AsmToks
, NumOutputs
, NumInputs
,
965 Constraints
, Exprs
, AsmString
,
970 LabelDecl
*Sema::GetOrCreateMSAsmLabel(StringRef ExternalLabelName
,
971 SourceLocation Location
,
973 LabelDecl
* Label
= LookupOrCreateLabel(PP
.getIdentifierInfo(ExternalLabelName
),
976 if (Label
->isMSAsmLabel()) {
977 // If we have previously created this label implicitly, mark it as used.
978 Label
->markUsed(Context
);
980 // Otherwise, insert it, but only resolve it if we have seen the label itself.
981 std::string InternalName
;
982 llvm::raw_string_ostream
OS(InternalName
);
983 // Create an internal name for the label. The name should not be a valid
984 // mangled name, and should be unique. We use a dot to make the name an
985 // invalid mangled name. We use LLVM's inline asm ${:uid} escape so that a
986 // unique label is generated each time this blob is emitted, even after
988 OS
<< "__MSASMLABEL_.${:uid}__";
989 for (char C
: ExternalLabelName
) {
991 // We escape '$' in asm strings by replacing it with "$$"
995 Label
->setMSAsmLabel(OS
.str());
998 // The label might have been created implicitly from a previously encountered
999 // goto statement. So, for both newly created and looked up labels, we mark
1000 // them as resolved.
1001 Label
->setMSAsmLabelResolved();
1003 // Adjust their location for being able to generate accurate diagnostics.
1004 Label
->setLocation(Location
);