1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | #include "clang/AST/ExprCXX.h" |
14 | #include "clang/AST/RecordLayout.h" |
15 | #include "clang/AST/TypeLoc.h" |
16 | #include "clang/Basic/TargetInfo.h" |
17 | #include "clang/Lex/Preprocessor.h" |
18 | #include "clang/Sema/Initialization.h" |
19 | #include "clang/Sema/Lookup.h" |
20 | #include "clang/Sema/Scope.h" |
21 | #include "clang/Sema/ScopeInfo.h" |
22 | #include "clang/Sema/SemaInternal.h" |
23 | #include "llvm/ADT/ArrayRef.h" |
24 | #include "llvm/ADT/StringSet.h" |
25 | #include "llvm/MC/MCParser/MCAsmParser.h" |
26 | using namespace clang; |
27 | using namespace sema; |
28 | |
29 | |
30 | static void removeLValueToRValueCast(Expr *E) { |
31 | Expr *Parent = E; |
32 | Expr *ExprUnderCast = nullptr; |
33 | SmallVector<Expr *, 8> ParentsToUpdate; |
34 | |
35 | while (true) { |
36 | ParentsToUpdate.push_back(Parent); |
37 | if (auto *ParenE = dyn_cast<ParenExpr>(Parent)) { |
38 | Parent = ParenE->getSubExpr(); |
39 | continue; |
40 | } |
41 | |
42 | Expr *Child = nullptr; |
43 | CastExpr *ParentCast = dyn_cast<CastExpr>(Parent); |
44 | if (ParentCast) |
45 | Child = ParentCast->getSubExpr(); |
46 | else |
47 | return; |
48 | |
49 | if (auto *CastE = dyn_cast<CastExpr>(Child)) |
50 | if (CastE->getCastKind() == CK_LValueToRValue) { |
51 | ExprUnderCast = CastE->getSubExpr(); |
52 | |
53 | ParentCast->setSubExpr(ExprUnderCast); |
54 | break; |
55 | } |
56 | Parent = Child; |
57 | } |
58 | |
59 | |
60 | (0) . __assert_fail ("ExprUnderCast && \"Should be reachable only if LValueToRValue cast was found!\"", "/home/seafit/code_projects/clang_source/clang/lib/Sema/SemaStmtAsm.cpp", 61, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(ExprUnderCast && |
61 | (0) . __assert_fail ("ExprUnderCast && \"Should be reachable only if LValueToRValue cast was found!\"", "/home/seafit/code_projects/clang_source/clang/lib/Sema/SemaStmtAsm.cpp", 61, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true"> "Should be reachable only if LValueToRValue cast was found!"); |
62 | auto ValueKind = ExprUnderCast->getValueKind(); |
63 | for (Expr *E : ParentsToUpdate) |
64 | E->setValueKind(ValueKind); |
65 | } |
66 | |
67 | |
68 | |
69 | static void emitAndFixInvalidAsmCastLValue(const Expr *LVal, Expr *BadArgument, |
70 | Sema &S) { |
71 | if (!S.getLangOpts().HeinousExtensions) { |
72 | S.Diag(LVal->getBeginLoc(), diag::err_invalid_asm_cast_lvalue) |
73 | << BadArgument->getSourceRange(); |
74 | } else { |
75 | S.Diag(LVal->getBeginLoc(), diag::warn_invalid_asm_cast_lvalue) |
76 | << BadArgument->getSourceRange(); |
77 | } |
78 | removeLValueToRValueCast(BadArgument); |
79 | } |
80 | |
81 | |
82 | |
83 | |
84 | |
85 | |
86 | |
87 | |
88 | static bool CheckAsmLValue(Expr *E, Sema &S) { |
89 | |
90 | if (E->isTypeDependent()) |
91 | return false; |
92 | |
93 | if (E->isLValue()) |
94 | return false; |
95 | |
96 | |
97 | |
98 | const Expr *E2 = E->IgnoreParenNoopCasts(S.Context); |
99 | if (E != E2 && E2->isLValue()) { |
100 | emitAndFixInvalidAsmCastLValue(E2, E, S); |
101 | |
102 | return false; |
103 | } |
104 | |
105 | |
106 | return true; |
107 | } |
108 | |
109 | |
110 | |
111 | static bool |
112 | isOperandMentioned(unsigned OpNo, |
113 | ArrayRef<GCCAsmStmt::AsmStringPiece> AsmStrPieces) { |
114 | for (unsigned p = 0, e = AsmStrPieces.size(); p != e; ++p) { |
115 | const GCCAsmStmt::AsmStringPiece &Piece = AsmStrPieces[p]; |
116 | if (!Piece.isOperand()) |
117 | continue; |
118 | |
119 | |
120 | |
121 | if (Piece.getOperandNo() == OpNo) |
122 | return true; |
123 | } |
124 | return false; |
125 | } |
126 | |
127 | static bool CheckNakedParmReference(Expr *E, Sema &S) { |
128 | FunctionDecl *Func = dyn_cast<FunctionDecl>(S.CurContext); |
129 | if (!Func) |
130 | return false; |
131 | if (!Func->hasAttr<NakedAttr>()) |
132 | return false; |
133 | |
134 | SmallVector<Expr*, 4> WorkList; |
135 | WorkList.push_back(E); |
136 | while (WorkList.size()) { |
137 | Expr *E = WorkList.pop_back_val(); |
138 | if (isa<CXXThisExpr>(E)) { |
139 | S.Diag(E->getBeginLoc(), diag::err_asm_naked_this_ref); |
140 | S.Diag(Func->getAttr<NakedAttr>()->getLocation(), diag::note_attribute); |
141 | return true; |
142 | } |
143 | if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) { |
144 | if (isa<ParmVarDecl>(DRE->getDecl())) { |
145 | S.Diag(DRE->getBeginLoc(), diag::err_asm_naked_parm_ref); |
146 | S.Diag(Func->getAttr<NakedAttr>()->getLocation(), diag::note_attribute); |
147 | return true; |
148 | } |
149 | } |
150 | for (Stmt *Child : E->children()) { |
151 | if (Expr *E = dyn_cast_or_null<Expr>(Child)) |
152 | WorkList.push_back(E); |
153 | } |
154 | } |
155 | return false; |
156 | } |
157 | |
158 | |
159 | |
160 | static bool checkExprMemoryConstraintCompat(Sema &S, Expr *E, |
161 | TargetInfo::ConstraintInfo &Info, |
162 | bool is_input_expr) { |
163 | enum { |
164 | ExprBitfield = 0, |
165 | ExprVectorElt, |
166 | ExprGlobalRegVar, |
167 | ExprSafeType |
168 | } EType = ExprSafeType; |
169 | |
170 | |
171 | |
172 | if (E->refersToBitField()) |
173 | EType = ExprBitfield; |
174 | else if (E->refersToVectorElement()) |
175 | EType = ExprVectorElt; |
176 | else if (E->refersToGlobalRegisterVar()) |
177 | EType = ExprGlobalRegVar; |
178 | |
179 | if (EType != ExprSafeType) { |
180 | S.Diag(E->getBeginLoc(), diag::err_asm_non_addr_value_in_memory_constraint) |
181 | << EType << is_input_expr << Info.getConstraintStr() |
182 | << E->getSourceRange(); |
183 | return true; |
184 | } |
185 | |
186 | return false; |
187 | } |
188 | |
189 | |
190 | |
191 | static StringRef (const Expr *Expression, |
192 | const TargetInfo &Target) { |
193 | Expression = Expression->IgnoreImpCasts(); |
194 | if (const DeclRefExpr *AsmDeclRef = dyn_cast<DeclRefExpr>(Expression)) { |
195 | |
196 | const VarDecl *Variable = dyn_cast<VarDecl>(AsmDeclRef->getDecl()); |
197 | if (Variable && Variable->getStorageClass() == SC_Register) { |
198 | if (AsmLabelAttr *Attr = Variable->getAttr<AsmLabelAttr>()) |
199 | if (Target.isValidGCCRegisterName(Attr->getLabel())) |
200 | return Target.getNormalizedGCCRegisterName(Attr->getLabel(), true); |
201 | } |
202 | } |
203 | return ""; |
204 | } |
205 | |
206 | |
207 | |
208 | |
209 | static SourceLocation |
210 | getClobberConflictLocation(MultiExprArg Exprs, StringLiteral **Constraints, |
211 | StringLiteral **Clobbers, int NumClobbers, |
212 | const TargetInfo &Target, ASTContext &Cont) { |
213 | llvm::StringSet<> InOutVars; |
214 | |
215 | |
216 | for (unsigned int i = 0; i < Exprs.size(); ++i) { |
217 | StringRef Constraint = Constraints[i]->getString(); |
218 | StringRef InOutReg = Target.getConstraintRegister( |
219 | Constraint, extractRegisterName(Exprs[i], Target)); |
220 | if (InOutReg != "") |
221 | InOutVars.insert(InOutReg); |
222 | } |
223 | |
224 | |
225 | for (int i = 0; i < NumClobbers; ++i) { |
226 | StringRef Clobber = Clobbers[i]->getString(); |
227 | |
228 | |
229 | if (Clobber == "cc" || Clobber == "memory") |
230 | continue; |
231 | Clobber = Target.getNormalizedGCCRegisterName(Clobber, true); |
232 | |
233 | if (InOutVars.count(Clobber)) |
234 | return Clobbers[i]->getBeginLoc(); |
235 | } |
236 | return SourceLocation(); |
237 | } |
238 | |
239 | StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple, |
240 | bool IsVolatile, unsigned NumOutputs, |
241 | unsigned NumInputs, IdentifierInfo **Names, |
242 | MultiExprArg constraints, MultiExprArg Exprs, |
243 | Expr *asmString, MultiExprArg clobbers, |
244 | SourceLocation RParenLoc) { |
245 | unsigned NumClobbers = clobbers.size(); |
246 | StringLiteral **Constraints = |
247 | reinterpret_cast<StringLiteral**>(constraints.data()); |
248 | StringLiteral *AsmString = cast<StringLiteral>(asmString); |
249 | StringLiteral **Clobbers = reinterpret_cast<StringLiteral**>(clobbers.data()); |
250 | |
251 | SmallVector<TargetInfo::ConstraintInfo, 4> OutputConstraintInfos; |
252 | |
253 | |
254 | isAscii()", "/home/seafit/code_projects/clang_source/clang/lib/Sema/SemaStmtAsm.cpp", 254, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(AsmString->isAscii()); |
255 | |
256 | for (unsigned i = 0; i != NumOutputs; i++) { |
257 | StringLiteral *Literal = Constraints[i]; |
258 | isAscii()", "/home/seafit/code_projects/clang_source/clang/lib/Sema/SemaStmtAsm.cpp", 258, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(Literal->isAscii()); |
259 | |
260 | StringRef OutputName; |
261 | if (Names[i]) |
262 | OutputName = Names[i]->getName(); |
263 | |
264 | TargetInfo::ConstraintInfo Info(Literal->getString(), OutputName); |
265 | if (!Context.getTargetInfo().validateOutputConstraint(Info)) { |
266 | targetDiag(Literal->getBeginLoc(), |
267 | diag::err_asm_invalid_output_constraint) |
268 | << Info.getConstraintStr(); |
269 | return new (Context) |
270 | GCCAsmStmt(Context, AsmLoc, IsSimple, IsVolatile, NumOutputs, |
271 | NumInputs, Names, Constraints, Exprs.data(), AsmString, |
272 | NumClobbers, Clobbers, RParenLoc); |
273 | } |
274 | |
275 | ExprResult ER = CheckPlaceholderExpr(Exprs[i]); |
276 | if (ER.isInvalid()) |
277 | return StmtError(); |
278 | Exprs[i] = ER.get(); |
279 | |
280 | |
281 | Expr *OutputExpr = Exprs[i]; |
282 | |
283 | |
284 | if (CheckNakedParmReference(OutputExpr, *this)) |
285 | return StmtError(); |
286 | |
287 | |
288 | if (Info.allowsMemory() && |
289 | checkExprMemoryConstraintCompat(*this, OutputExpr, Info, false)) |
290 | return StmtError(); |
291 | |
292 | OutputConstraintInfos.push_back(Info); |
293 | |
294 | |
295 | if (OutputExpr->isTypeDependent()) |
296 | continue; |
297 | |
298 | Expr::isModifiableLvalueResult IsLV = |
299 | OutputExpr->isModifiableLvalue(Context, ); |
300 | switch (IsLV) { |
301 | case Expr::MLV_Valid: |
302 | |
303 | break; |
304 | case Expr::MLV_ArrayType: |
305 | |
306 | break; |
307 | case Expr::MLV_LValueCast: { |
308 | const Expr *LVal = OutputExpr->IgnoreParenNoopCasts(Context); |
309 | emitAndFixInvalidAsmCastLValue(LVal, OutputExpr, *this); |
310 | |
311 | break; |
312 | } |
313 | case Expr::MLV_IncompleteType: |
314 | case Expr::MLV_IncompleteVoidType: |
315 | if (RequireCompleteType(OutputExpr->getBeginLoc(), Exprs[i]->getType(), |
316 | diag::err_dereference_incomplete_type)) |
317 | return StmtError(); |
318 | LLVM_FALLTHROUGH; |
319 | default: |
320 | return StmtError(Diag(OutputExpr->getBeginLoc(), |
321 | diag::err_asm_invalid_lvalue_in_output) |
322 | << OutputExpr->getSourceRange()); |
323 | } |
324 | |
325 | unsigned Size = Context.getTypeSize(OutputExpr->getType()); |
326 | if (!Context.getTargetInfo().validateOutputSize(Literal->getString(), |
327 | Size)) { |
328 | targetDiag(OutputExpr->getBeginLoc(), diag::err_asm_invalid_output_size) |
329 | << Info.getConstraintStr(); |
330 | return new (Context) |
331 | GCCAsmStmt(Context, AsmLoc, IsSimple, IsVolatile, NumOutputs, |
332 | NumInputs, Names, Constraints, Exprs.data(), AsmString, |
333 | NumClobbers, Clobbers, RParenLoc); |
334 | } |
335 | } |
336 | |
337 | SmallVector<TargetInfo::ConstraintInfo, 4> InputConstraintInfos; |
338 | |
339 | for (unsigned i = NumOutputs, e = NumOutputs + NumInputs; i != e; i++) { |
340 | StringLiteral *Literal = Constraints[i]; |
341 | isAscii()", "/home/seafit/code_projects/clang_source/clang/lib/Sema/SemaStmtAsm.cpp", 341, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(Literal->isAscii()); |
342 | |
343 | StringRef InputName; |
344 | if (Names[i]) |
345 | InputName = Names[i]->getName(); |
346 | |
347 | TargetInfo::ConstraintInfo Info(Literal->getString(), InputName); |
348 | if (!Context.getTargetInfo().validateInputConstraint(OutputConstraintInfos, |
349 | Info)) { |
350 | targetDiag(Literal->getBeginLoc(), diag::err_asm_invalid_input_constraint) |
351 | << Info.getConstraintStr(); |
352 | return new (Context) |
353 | GCCAsmStmt(Context, AsmLoc, IsSimple, IsVolatile, NumOutputs, |
354 | NumInputs, Names, Constraints, Exprs.data(), AsmString, |
355 | NumClobbers, Clobbers, RParenLoc); |
356 | } |
357 | |
358 | ExprResult ER = CheckPlaceholderExpr(Exprs[i]); |
359 | if (ER.isInvalid()) |
360 | return StmtError(); |
361 | Exprs[i] = ER.get(); |
362 | |
363 | Expr *InputExpr = Exprs[i]; |
364 | |
365 | |
366 | if (CheckNakedParmReference(InputExpr, *this)) |
367 | return StmtError(); |
368 | |
369 | |
370 | if (Info.allowsMemory() && |
371 | checkExprMemoryConstraintCompat(*this, InputExpr, Info, true)) |
372 | return StmtError(); |
373 | |
374 | |
375 | if (Info.allowsMemory() && !Info.allowsRegister()) { |
376 | if (CheckAsmLValue(InputExpr, *this)) |
377 | return StmtError(Diag(InputExpr->getBeginLoc(), |
378 | diag::err_asm_invalid_lvalue_in_input) |
379 | << Info.getConstraintStr() |
380 | << InputExpr->getSourceRange()); |
381 | } else if (Info.requiresImmediateConstant() && !Info.allowsRegister()) { |
382 | if (!InputExpr->isValueDependent()) { |
383 | Expr::EvalResult EVResult; |
384 | if (!InputExpr->EvaluateAsRValue(EVResult, Context, true)) |
385 | return StmtError( |
386 | Diag(InputExpr->getBeginLoc(), diag::err_asm_immediate_expected) |
387 | << Info.getConstraintStr() << InputExpr->getSourceRange()); |
388 | |
389 | |
390 | |
391 | llvm::APSInt IntResult; |
392 | if (!EVResult.Val.toIntegralConstant(IntResult, InputExpr->getType(), |
393 | Context)) |
394 | return StmtError( |
395 | Diag(InputExpr->getBeginLoc(), diag::err_asm_immediate_expected) |
396 | << Info.getConstraintStr() << InputExpr->getSourceRange()); |
397 | |
398 | if (!Info.isValidAsmImmediate(IntResult)) |
399 | return StmtError(Diag(InputExpr->getBeginLoc(), |
400 | diag::err_invalid_asm_value_for_constraint) |
401 | << IntResult.toString(10) << Info.getConstraintStr() |
402 | << InputExpr->getSourceRange()); |
403 | } |
404 | |
405 | } else { |
406 | ExprResult Result = DefaultFunctionArrayLvalueConversion(Exprs[i]); |
407 | if (Result.isInvalid()) |
408 | return StmtError(); |
409 | |
410 | Exprs[i] = Result.get(); |
411 | } |
412 | |
413 | if (Info.allowsRegister()) { |
414 | if (InputExpr->getType()->isVoidType()) { |
415 | return StmtError( |
416 | Diag(InputExpr->getBeginLoc(), diag::err_asm_invalid_type_in_input) |
417 | << InputExpr->getType() << Info.getConstraintStr() |
418 | << InputExpr->getSourceRange()); |
419 | } |
420 | } |
421 | |
422 | InputConstraintInfos.push_back(Info); |
423 | |
424 | const Type *Ty = Exprs[i]->getType().getTypePtr(); |
425 | if (Ty->isDependentType()) |
426 | continue; |
427 | |
428 | if (!Ty->isVoidType() || !Info.allowsMemory()) |
429 | if (RequireCompleteType(InputExpr->getBeginLoc(), Exprs[i]->getType(), |
430 | diag::err_dereference_incomplete_type)) |
431 | return StmtError(); |
432 | |
433 | unsigned Size = Context.getTypeSize(Ty); |
434 | if (!Context.getTargetInfo().validateInputSize(Literal->getString(), |
435 | Size)) |
436 | return StmtResult( |
437 | targetDiag(InputExpr->getBeginLoc(), diag::err_asm_invalid_input_size) |
438 | << Info.getConstraintStr()); |
439 | } |
440 | |
441 | |
442 | for (unsigned i = 0; i != NumClobbers; i++) { |
443 | StringLiteral *Literal = Clobbers[i]; |
444 | isAscii()", "/home/seafit/code_projects/clang_source/clang/lib/Sema/SemaStmtAsm.cpp", 444, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(Literal->isAscii()); |
445 | |
446 | StringRef Clobber = Literal->getString(); |
447 | |
448 | if (!Context.getTargetInfo().isValidClobber(Clobber)) { |
449 | targetDiag(Literal->getBeginLoc(), diag::err_asm_unknown_register_name) |
450 | << Clobber; |
451 | return new (Context) |
452 | GCCAsmStmt(Context, AsmLoc, IsSimple, IsVolatile, NumOutputs, |
453 | NumInputs, Names, Constraints, Exprs.data(), AsmString, |
454 | NumClobbers, Clobbers, RParenLoc); |
455 | } |
456 | } |
457 | |
458 | GCCAsmStmt *NS = |
459 | new (Context) GCCAsmStmt(Context, AsmLoc, IsSimple, IsVolatile, NumOutputs, |
460 | NumInputs, Names, Constraints, Exprs.data(), |
461 | AsmString, NumClobbers, Clobbers, RParenLoc); |
462 | |
463 | |
464 | SmallVector<GCCAsmStmt::AsmStringPiece, 8> Pieces; |
465 | unsigned DiagOffs; |
466 | if (unsigned DiagID = NS->AnalyzeAsmString(Pieces, Context, DiagOffs)) { |
467 | targetDiag(getLocationOfStringLiteralByte(AsmString, DiagOffs), DiagID) |
468 | << AsmString->getSourceRange(); |
469 | return NS; |
470 | } |
471 | |
472 | |
473 | for (unsigned i = 0, e = Pieces.size(); i != e; ++i) { |
474 | GCCAsmStmt::AsmStringPiece &Piece = Pieces[i]; |
475 | if (!Piece.isOperand()) continue; |
476 | |
477 | |
478 | unsigned ConstraintIdx = Piece.getOperandNo(); |
479 | unsigned NumOperands = NS->getNumOutputs() + NS->getNumInputs(); |
480 | |
481 | |
482 | |
483 | if (ConstraintIdx >= NumOperands) { |
484 | unsigned I = 0, E = NS->getNumOutputs(); |
485 | |
486 | for (unsigned Cnt = ConstraintIdx - NumOperands; I != E; ++I) |
487 | if (OutputConstraintInfos[I].isReadWrite() && Cnt-- == 0) { |
488 | ConstraintIdx = I; |
489 | break; |
490 | } |
491 | |
492 | (0) . __assert_fail ("I != E && \"Invalid operand number should have been caught in \" \" AnalyzeAsmString\"", "/home/seafit/code_projects/clang_source/clang/lib/Sema/SemaStmtAsm.cpp", 493, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(I != E && "Invalid operand number should have been caught in " |
493 | (0) . __assert_fail ("I != E && \"Invalid operand number should have been caught in \" \" AnalyzeAsmString\"", "/home/seafit/code_projects/clang_source/clang/lib/Sema/SemaStmtAsm.cpp", 493, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true"> " AnalyzeAsmString"); |
494 | } |
495 | |
496 | |
497 | StringLiteral *Literal = Constraints[ConstraintIdx]; |
498 | const Type *Ty = Exprs[ConstraintIdx]->getType().getTypePtr(); |
499 | if (Ty->isDependentType() || Ty->isIncompleteType()) |
500 | continue; |
501 | |
502 | unsigned Size = Context.getTypeSize(Ty); |
503 | std::string SuggestedModifier; |
504 | if (!Context.getTargetInfo().validateConstraintModifier( |
505 | Literal->getString(), Piece.getModifier(), Size, |
506 | SuggestedModifier)) { |
507 | targetDiag(Exprs[ConstraintIdx]->getBeginLoc(), |
508 | diag::warn_asm_mismatched_size_modifier); |
509 | |
510 | if (!SuggestedModifier.empty()) { |
511 | auto B = targetDiag(Piece.getRange().getBegin(), |
512 | diag::note_asm_missing_constraint_modifier) |
513 | << SuggestedModifier; |
514 | SuggestedModifier = "%" + SuggestedModifier + Piece.getString(); |
515 | B << FixItHint::CreateReplacement(Piece.getRange(), SuggestedModifier); |
516 | } |
517 | } |
518 | } |
519 | |
520 | |
521 | unsigned NumAlternatives = ~0U; |
522 | for (unsigned i = 0, e = OutputConstraintInfos.size(); i != e; ++i) { |
523 | TargetInfo::ConstraintInfo &Info = OutputConstraintInfos[i]; |
524 | StringRef ConstraintStr = Info.getConstraintStr(); |
525 | unsigned AltCount = ConstraintStr.count(',') + 1; |
526 | if (NumAlternatives == ~0U) { |
527 | NumAlternatives = AltCount; |
528 | } else if (NumAlternatives != AltCount) { |
529 | targetDiag(NS->getOutputExpr(i)->getBeginLoc(), |
530 | diag::err_asm_unexpected_constraint_alternatives) |
531 | << NumAlternatives << AltCount; |
532 | return NS; |
533 | } |
534 | } |
535 | SmallVector<size_t, 4> InputMatchedToOutput(OutputConstraintInfos.size(), |
536 | ~0U); |
537 | for (unsigned i = 0, e = InputConstraintInfos.size(); i != e; ++i) { |
538 | TargetInfo::ConstraintInfo &Info = InputConstraintInfos[i]; |
539 | StringRef ConstraintStr = Info.getConstraintStr(); |
540 | unsigned AltCount = ConstraintStr.count(',') + 1; |
541 | if (NumAlternatives == ~0U) { |
542 | NumAlternatives = AltCount; |
543 | } else if (NumAlternatives != AltCount) { |
544 | targetDiag(NS->getInputExpr(i)->getBeginLoc(), |
545 | diag::err_asm_unexpected_constraint_alternatives) |
546 | << NumAlternatives << AltCount; |
547 | return NS; |
548 | } |
549 | |
550 | |
551 | |
552 | |
553 | if (!Info.hasTiedOperand()) continue; |
554 | |
555 | unsigned TiedTo = Info.getTiedOperand(); |
556 | unsigned InputOpNo = i+NumOutputs; |
557 | Expr *OutputExpr = Exprs[TiedTo]; |
558 | Expr *InputExpr = Exprs[InputOpNo]; |
559 | |
560 | |
561 | (0) . __assert_fail ("TiedTo < InputMatchedToOutput.size() && \"TiedTo value out of range\"", "/home/seafit/code_projects/clang_source/clang/lib/Sema/SemaStmtAsm.cpp", 561, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(TiedTo < InputMatchedToOutput.size() && "TiedTo value out of range"); |
562 | if (InputMatchedToOutput[TiedTo] != ~0U) { |
563 | targetDiag(NS->getInputExpr(i)->getBeginLoc(), |
564 | diag::err_asm_input_duplicate_match) |
565 | << TiedTo; |
566 | targetDiag(NS->getInputExpr(InputMatchedToOutput[TiedTo])->getBeginLoc(), |
567 | diag::note_asm_input_duplicate_first) |
568 | << TiedTo; |
569 | return NS; |
570 | } |
571 | InputMatchedToOutput[TiedTo] = i; |
572 | |
573 | if (OutputExpr->isTypeDependent() || InputExpr->isTypeDependent()) |
574 | continue; |
575 | |
576 | QualType InTy = InputExpr->getType(); |
577 | QualType OutTy = OutputExpr->getType(); |
578 | if (Context.hasSameType(InTy, OutTy)) |
579 | continue; |
580 | |
581 | |
582 | |
583 | enum AsmDomain { |
584 | AD_Int, AD_FP, AD_Other |
585 | } InputDomain, OutputDomain; |
586 | |
587 | if (InTy->isIntegerType() || InTy->isPointerType()) |
588 | InputDomain = AD_Int; |
589 | else if (InTy->isRealFloatingType()) |
590 | InputDomain = AD_FP; |
591 | else |
592 | InputDomain = AD_Other; |
593 | |
594 | if (OutTy->isIntegerType() || OutTy->isPointerType()) |
595 | OutputDomain = AD_Int; |
596 | else if (OutTy->isRealFloatingType()) |
597 | OutputDomain = AD_FP; |
598 | else |
599 | OutputDomain = AD_Other; |
600 | |
601 | |
602 | |
603 | |
604 | |
605 | |
606 | |
607 | uint64_t OutSize = Context.getTypeSize(OutTy); |
608 | uint64_t InSize = Context.getTypeSize(InTy); |
609 | if (OutSize == InSize && InputDomain == OutputDomain && |
610 | InputDomain != AD_Other) |
611 | continue; |
612 | |
613 | |
614 | |
615 | |
616 | bool SmallerValueMentioned = false; |
617 | |
618 | |
619 | |
620 | if (isOperandMentioned(InputOpNo, Pieces)) { |
621 | |
622 | |
623 | |
624 | SmallerValueMentioned |= InSize < OutSize; |
625 | } |
626 | if (isOperandMentioned(TiedTo, Pieces)) { |
627 | |
628 | |
629 | SmallerValueMentioned |= OutSize < InSize; |
630 | } |
631 | |
632 | |
633 | |
634 | |
635 | if (!SmallerValueMentioned && InputDomain != AD_Other && |
636 | OutputConstraintInfos[TiedTo].allowsRegister()) |
637 | continue; |
638 | |
639 | |
640 | |
641 | |
642 | |
643 | if (InputDomain == AD_Int && OutputDomain == AD_Int && |
644 | !isOperandMentioned(InputOpNo, Pieces) && |
645 | InputExpr->isEvaluatable(Context)) { |
646 | CastKind castKind = |
647 | (OutTy->isBooleanType() ? CK_IntegralToBoolean : CK_IntegralCast); |
648 | InputExpr = ImpCastExprToType(InputExpr, OutTy, castKind).get(); |
649 | Exprs[InputOpNo] = InputExpr; |
650 | NS->setInputExpr(i, InputExpr); |
651 | continue; |
652 | } |
653 | |
654 | targetDiag(InputExpr->getBeginLoc(), diag::err_asm_tying_incompatible_types) |
655 | << InTy << OutTy << OutputExpr->getSourceRange() |
656 | << InputExpr->getSourceRange(); |
657 | return NS; |
658 | } |
659 | |
660 | |
661 | SourceLocation ConstraintLoc = |
662 | getClobberConflictLocation(Exprs, Constraints, Clobbers, NumClobbers, |
663 | Context.getTargetInfo(), Context); |
664 | if (ConstraintLoc.isValid()) |
665 | targetDiag(ConstraintLoc, diag::error_inoutput_conflict_with_clobber); |
666 | |
667 | return NS; |
668 | } |
669 | |
670 | void Sema::FillInlineAsmIdentifierInfo(Expr *Res, |
671 | llvm::InlineAsmIdentifierInfo &Info) { |
672 | QualType T = Res->getType(); |
673 | Expr::EvalResult Eval; |
674 | if (T->isFunctionType() || T->isDependentType()) |
675 | return Info.setLabel(Res); |
676 | if (Res->isRValue()) { |
677 | if (isa<clang::EnumType>(T) && Res->EvaluateAsRValue(Eval, Context)) |
678 | return Info.setEnum(Eval.Val.getInt().getSExtValue()); |
679 | return Info.setLabel(Res); |
680 | } |
681 | unsigned Size = Context.getTypeSizeInChars(T).getQuantity(); |
682 | unsigned Type = Size; |
683 | if (const auto *ATy = Context.getAsArrayType(T)) |
684 | Type = Context.getTypeSizeInChars(ATy->getElementType()).getQuantity(); |
685 | bool IsGlobalLV = false; |
686 | if (Res->EvaluateAsLValue(Eval, Context)) |
687 | IsGlobalLV = Eval.isGlobalLValue(); |
688 | Info.setVar(Res, IsGlobalLV, Size, Type); |
689 | } |
690 | |
691 | ExprResult Sema::LookupInlineAsmIdentifier(CXXScopeSpec &SS, |
692 | SourceLocation TemplateKWLoc, |
693 | UnqualifiedId &Id, |
694 | bool IsUnevaluatedContext) { |
695 | |
696 | if (IsUnevaluatedContext) |
697 | PushExpressionEvaluationContext( |
698 | ExpressionEvaluationContext::UnevaluatedAbstract, |
699 | ReuseLambdaContextDecl); |
700 | |
701 | ExprResult Result = ActOnIdExpression(getCurScope(), SS, TemplateKWLoc, Id, |
702 | false, |
703 | false, |
704 | , |
705 | true); |
706 | |
707 | if (IsUnevaluatedContext) |
708 | PopExpressionEvaluationContext(); |
709 | |
710 | if (!Result.isUsable()) return Result; |
711 | |
712 | Result = CheckPlaceholderExpr(Result.get()); |
713 | if (!Result.isUsable()) return Result; |
714 | |
715 | |
716 | if (CheckNakedParmReference(Result.get(), *this)) |
717 | return ExprError(); |
718 | |
719 | QualType T = Result.get()->getType(); |
720 | |
721 | if (T->isDependentType()) { |
722 | return Result; |
723 | } |
724 | |
725 | |
726 | if (T->isFunctionType()) { |
727 | return Result; |
728 | } |
729 | |
730 | |
731 | if (RequireCompleteExprType(Result.get(), diag::err_asm_incomplete_type)) { |
732 | return ExprError(); |
733 | } |
734 | |
735 | return Result; |
736 | } |
737 | |
738 | bool Sema::LookupInlineAsmField(StringRef Base, StringRef Member, |
739 | unsigned &Offset, SourceLocation AsmLoc) { |
740 | Offset = 0; |
741 | SmallVector<StringRef, 2> Members; |
742 | Member.split(Members, "."); |
743 | |
744 | NamedDecl *FoundDecl = nullptr; |
745 | |
746 | |
747 | if (getLangOpts().CPlusPlus && Base.equals("this")) { |
748 | if (const Type *PT = getCurrentThisType().getTypePtrOrNull()) |
749 | FoundDecl = PT->getPointeeType()->getAsTagDecl(); |
750 | } else { |
751 | LookupResult BaseResult(*this, &Context.Idents.get(Base), SourceLocation(), |
752 | LookupOrdinaryName); |
753 | if (LookupName(BaseResult, getCurScope()) && BaseResult.isSingleResult()) |
754 | FoundDecl = BaseResult.getFoundDecl(); |
755 | } |
756 | |
757 | if (!FoundDecl) |
758 | return true; |
759 | |
760 | for (StringRef NextMember : Members) { |
761 | const RecordType *RT = nullptr; |
762 | if (VarDecl *VD = dyn_cast<VarDecl>(FoundDecl)) |
763 | RT = VD->getType()->getAs<RecordType>(); |
764 | else if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(FoundDecl)) { |
765 | MarkAnyDeclReferenced(TD->getLocation(), TD, ); |
766 | |
767 | QualType QT = TD->getUnderlyingType(); |
768 | if (const auto *PT = QT->getAs<PointerType>()) |
769 | QT = PT->getPointeeType(); |
770 | RT = QT->getAs<RecordType>(); |
771 | } else if (TypeDecl *TD = dyn_cast<TypeDecl>(FoundDecl)) |
772 | RT = TD->getTypeForDecl()->getAs<RecordType>(); |
773 | else if (FieldDecl *TD = dyn_cast<FieldDecl>(FoundDecl)) |
774 | RT = TD->getType()->getAs<RecordType>(); |
775 | if (!RT) |
776 | return true; |
777 | |
778 | if (RequireCompleteType(AsmLoc, QualType(RT, 0), |
779 | diag::err_asm_incomplete_type)) |
780 | return true; |
781 | |
782 | LookupResult FieldResult(*this, &Context.Idents.get(NextMember), |
783 | SourceLocation(), LookupMemberName); |
784 | |
785 | if (!LookupQualifiedName(FieldResult, RT->getDecl())) |
786 | return true; |
787 | |
788 | if (!FieldResult.isSingleResult()) |
789 | return true; |
790 | FoundDecl = FieldResult.getFoundDecl(); |
791 | |
792 | |
793 | FieldDecl *FD = dyn_cast<FieldDecl>(FoundDecl); |
794 | if (!FD) |
795 | return true; |
796 | |
797 | const ASTRecordLayout &RL = Context.getASTRecordLayout(RT->getDecl()); |
798 | unsigned i = FD->getFieldIndex(); |
799 | CharUnits Result = Context.toCharUnitsFromBits(RL.getFieldOffset(i)); |
800 | Offset += (unsigned)Result.getQuantity(); |
801 | } |
802 | |
803 | return false; |
804 | } |
805 | |
806 | ExprResult |
807 | Sema::LookupInlineAsmVarDeclField(Expr *E, StringRef Member, |
808 | SourceLocation AsmLoc) { |
809 | |
810 | QualType T = E->getType(); |
811 | if (T->isDependentType()) { |
812 | DeclarationNameInfo NameInfo; |
813 | NameInfo.setLoc(AsmLoc); |
814 | NameInfo.setName(&Context.Idents.get(Member)); |
815 | return CXXDependentScopeMemberExpr::Create( |
816 | Context, E, T, , AsmLoc, NestedNameSpecifierLoc(), |
817 | SourceLocation(), |
818 | , NameInfo, ); |
819 | } |
820 | |
821 | const RecordType *RT = T->getAs<RecordType>(); |
822 | |
823 | if (!RT) |
824 | return ExprResult(); |
825 | |
826 | LookupResult FieldResult(*this, &Context.Idents.get(Member), AsmLoc, |
827 | LookupMemberName); |
828 | |
829 | if (!LookupQualifiedName(FieldResult, RT->getDecl())) |
830 | return ExprResult(); |
831 | |
832 | |
833 | ValueDecl *FD = dyn_cast<FieldDecl>(FieldResult.getFoundDecl()); |
834 | if (!FD) |
835 | FD = dyn_cast<IndirectFieldDecl>(FieldResult.getFoundDecl()); |
836 | if (!FD) |
837 | return ExprResult(); |
838 | |
839 | |
840 | ExprResult Result = BuildMemberReferenceExpr( |
841 | E, E->getType(), AsmLoc, , CXXScopeSpec(), |
842 | SourceLocation(), nullptr, FieldResult, nullptr, nullptr); |
843 | |
844 | return Result; |
845 | } |
846 | |
847 | StmtResult Sema::ActOnMSAsmStmt(SourceLocation AsmLoc, SourceLocation LBraceLoc, |
848 | ArrayRef<Token> AsmToks, |
849 | StringRef AsmString, |
850 | unsigned NumOutputs, unsigned NumInputs, |
851 | ArrayRef<StringRef> Constraints, |
852 | ArrayRef<StringRef> Clobbers, |
853 | ArrayRef<Expr*> Exprs, |
854 | SourceLocation EndLoc) { |
855 | bool IsSimple = (NumOutputs != 0 || NumInputs != 0); |
856 | setFunctionHasBranchProtectedScope(); |
857 | MSAsmStmt *NS = |
858 | new (Context) MSAsmStmt(Context, AsmLoc, LBraceLoc, IsSimple, |
859 | true, AsmToks, NumOutputs, NumInputs, |
860 | Constraints, Exprs, AsmString, |
861 | Clobbers, EndLoc); |
862 | return NS; |
863 | } |
864 | |
865 | LabelDecl *Sema::GetOrCreateMSAsmLabel(StringRef ExternalLabelName, |
866 | SourceLocation Location, |
867 | bool AlwaysCreate) { |
868 | LabelDecl* Label = LookupOrCreateLabel(PP.getIdentifierInfo(ExternalLabelName), |
869 | Location); |
870 | |
871 | if (Label->isMSAsmLabel()) { |
872 | |
873 | Label->markUsed(Context); |
874 | } else { |
875 | |
876 | std::string InternalName; |
877 | llvm::raw_string_ostream OS(InternalName); |
878 | |
879 | |
880 | |
881 | |
882 | |
883 | OS << "__MSASMLABEL_.${:uid}__"; |
884 | for (char C : ExternalLabelName) { |
885 | OS << C; |
886 | |
887 | if (C == '$') |
888 | OS << '$'; |
889 | } |
890 | Label->setMSAsmLabel(OS.str()); |
891 | } |
892 | if (AlwaysCreate) { |
893 | |
894 | |
895 | |
896 | Label->setMSAsmLabelResolved(); |
897 | } |
898 | |
899 | Label->setLocation(Location); |
900 | |
901 | return Label; |
902 | } |
903 | |