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