clang 24.0.0git
CIRGenAsm.cpp
Go to the documentation of this file.
1//===--- CIRGenAsm.cpp - Inline Assembly Support for CIR CodeGen ---------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file contains code to emit inline assembly.
10//
11//===----------------------------------------------------------------------===//
12
14
15#include "CIRGenFunction.h"
17
18using namespace clang;
19using namespace clang::CIRGen;
20using namespace cir;
21
22static AsmFlavor inferFlavor(const CIRGenModule &cgm, const AsmStmt &s) {
23 AsmFlavor gnuAsmFlavor =
24 cgm.getCodeGenOpts().getInlineAsmDialect() == CodeGenOptions::IAD_ATT
25 ? AsmFlavor::x86_att
26 : AsmFlavor::x86_intel;
27
28 return isa<MSAsmStmt>(&s) ? AsmFlavor::x86_intel : gnuAsmFlavor;
29}
30
31static void collectClobbers(const CIRGenFunction &cgf, const AsmStmt &s,
32 std::string &constraints, bool &hasUnwindClobber,
33 bool &readOnly, bool readNone) {
34
35 hasUnwindClobber = false;
36 const CIRGenModule &cgm = cgf.getCIRGenModule();
37
38 // Clobbers
39 for (unsigned i = 0, e = s.getNumClobbers(); i != e; i++) {
40 std::string clobber = s.getClobber(i);
41 if (clobber == "memory") {
42 readOnly = readNone = false;
43 } else if (clobber == "unwind") {
44 hasUnwindClobber = true;
45 continue;
46 } else if (clobber != "cc") {
47 clobber = cgf.getTarget().getNormalizedGCCRegisterName(clobber);
48 if (cgm.getCodeGenOpts().StackClashProtector &&
49 cgf.getTarget().isSPRegName(clobber))
50 cgm.getDiags().Report(s.getAsmLoc(),
51 diag::warn_stack_clash_protection_inline_asm);
52 }
53
54 if (isa<MSAsmStmt>(&s)) {
55 if (clobber == "eax" || clobber == "edx") {
56 if (constraints.find("=&A") != std::string::npos)
57 continue;
58 std::string::size_type position1 =
59 constraints.find("={" + clobber + "}");
60 if (position1 != std::string::npos) {
61 constraints.insert(position1 + 1, "&");
62 continue;
63 }
64 std::string::size_type position2 = constraints.find("=A");
65 if (position2 != std::string::npos) {
66 constraints.insert(position2 + 1, "&");
67 continue;
68 }
69 }
70 }
71 if (!constraints.empty())
72 constraints += ',';
73
74 constraints += "~{";
75 constraints += clobber;
76 constraints += '}';
77 }
78
79 // Add machine specific clobbers
80 std::string_view machineClobbers = cgf.getTarget().getClobbers();
81 if (!machineClobbers.empty()) {
82 if (!constraints.empty())
83 constraints += ',';
84 constraints += machineClobbers;
85 }
86}
87
88static void
92
93 for (unsigned i = 0, e = s.getNumOutputs(); i != e; ++i) {
94 StringRef name;
95 if (const GCCAsmStmt *gas = dyn_cast<GCCAsmStmt>(&s))
96 name = gas->getOutputName(i);
98 // `validateOutputConstraint` modifies the `info` object by setting the
99 // read/write, clobber, allows-register, and allows-memory process.
100 bool isValid = cgf.getTarget().validateOutputConstraint(info);
101 (void)isValid;
102 assert(isValid && "Failed to parse output constraint");
103 out.push_back(info);
104 }
105
106 for (unsigned i = 0, e = s.getNumInputs(); i != e; ++i) {
107 StringRef name;
108 if (const GCCAsmStmt *gas = dyn_cast<GCCAsmStmt>(&s))
109 name = gas->getInputName(i);
111 // `validateInputConstraint` modifies the `info` object by setting the
112 // read/write, clobber, allows-register, and allows-memory process.
113 bool isValid = cgf.getTarget().validateInputConstraint(out, info);
114 assert(isValid && "Failed to parse input constraint");
115 (void)isValid;
116 in.push_back(info);
117 }
118}
119
120std::pair<mlir::Value, mlir::Type> CIRGenFunction::emitAsmInputLValue(
121 const TargetInfo::ConstraintInfo &info, LValue inputValue,
122 QualType inputType, std::string &constraintString, SourceLocation loc) {
123
124 if (info.allowsRegister() || !info.allowsMemory()) {
125 if (hasScalarEvaluationKind(inputType))
126 return {emitLoadOfLValue(inputValue, loc).getValue(), mlir::Type()};
127
128 mlir::Type ty = convertType(inputType);
129 uint64_t size = cgm.getDataLayout().getTypeSizeInBits(ty);
130 if ((size <= 64 && llvm::isPowerOf2_64(size)) ||
131 getTargetHooks().isScalarizableAsmOperand(*this, ty)) {
132 ty = cir::IntType::get(&getMLIRContext(), size, false);
133
134 return {builder.createLoad(
135 getLoc(loc),
136 inputValue.getAddress().withElementType(builder, ty)),
137 mlir::Type()};
138 }
139 }
140
141 Address addr = inputValue.getAddress();
142 constraintString += '*';
143 return {addr.getPointer(), addr.getElementType()};
144}
145
146std::pair<mlir::Value, mlir::Type>
148 const Expr *inputExpr,
149 std::string &constraintString) {
150 mlir::Location loc = getLoc(inputExpr->getExprLoc());
151
152 // If this can't be a register or memory, i.e., has to be a constant
153 // (immediate or symbolic), try to emit it as such.
154 if (!info.allowsRegister() && !info.allowsMemory()) {
155 if (info.requiresImmediateConstant()) {
156 Expr::EvalResult evalResult;
157 inputExpr->EvaluateAsRValue(evalResult, getContext(), true);
158
159 llvm::APSInt intResult;
160 if (evalResult.Val.toIntegralConstant(intResult, inputExpr->getType(),
161 getContext()))
162 return {builder.getConstInt(loc, intResult), mlir::Type()};
163 }
164
165 Expr::EvalResult result;
166 if (inputExpr->EvaluateAsInt(result, getContext()))
167 return {builder.getConstInt(loc, result.Val.getInt()), mlir::Type()};
168 }
169
170 if (info.allowsRegister() || !info.allowsMemory())
172 return {emitScalarExpr(inputExpr), mlir::Type()};
173 if (inputExpr->getStmtClass() == Expr::CXXThisExprClass)
174 return {emitScalarExpr(inputExpr), mlir::Type()};
175 inputExpr = inputExpr->IgnoreParenNoopCasts(getContext());
176 LValue dest = emitLValue(inputExpr);
177 return emitAsmInputLValue(info, dest, inputExpr->getType(), constraintString,
178 inputExpr->getExprLoc());
179}
180
181static void emitAsmStores(CIRGenFunction &cgf, const AsmStmt &s,
182 const llvm::ArrayRef<mlir::Value> regResults,
183 const llvm::ArrayRef<mlir::Type> resultRegTypes,
184 const llvm::ArrayRef<mlir::Type> resultTruncRegTypes,
185 const llvm::ArrayRef<LValue> resultRegDests,
186 const llvm::ArrayRef<QualType> resultRegQualTys,
187 const llvm::BitVector &resultTypeRequiresCast,
188 const llvm::BitVector &resultRegIsFlagReg) {
189 CIRGenBuilderTy &builder = cgf.getBuilder();
190 CIRGenModule &cgm = cgf.cgm;
191 mlir::MLIRContext *ctx = builder.getContext();
192
193 assert(regResults.size() == resultRegTypes.size());
194 assert(regResults.size() == resultTruncRegTypes.size());
195 assert(regResults.size() == resultRegDests.size());
196
197 // ResultRegDests can be also populated by addReturnRegisterOutputs() above,
198 // in which case its size may grow.
199 assert(resultTypeRequiresCast.size() <= resultRegDests.size());
200 assert(resultRegIsFlagReg.size() <= resultRegDests.size());
201
202 for (unsigned i = 0, e = regResults.size(); i != e; ++i) {
203 mlir::Value tmp = regResults[i];
204 mlir::Type truncTy = resultTruncRegTypes[i];
205
206 if (i < resultRegIsFlagReg.size() && resultRegIsFlagReg[i])
208
209 // If the result type of the LLVM IR asm doesn't match the result type of
210 // the expression, do the conversion.
211 if (resultRegTypes[i] != truncTy) {
212
213 // Truncate the integer result to the right size, note that TruncTy can be
214 // a pointer.
215 if (mlir::isa<cir::FPTypeInterface>(truncTy)) {
216 tmp = builder.createFloatingCast(tmp, truncTy);
217 } else if (isa<cir::PointerType>(truncTy) &&
218 isa<cir::IntType>(tmp.getType())) {
219 uint64_t resSize = cgm.getDataLayout().getTypeSizeInBits(truncTy);
220 tmp = builder.createIntCast(
221 tmp, cir::IntType::get(ctx, (unsigned)resSize, false));
222 tmp = builder.createIntToPtr(tmp, truncTy);
223 } else if (isa<cir::PointerType>(tmp.getType()) &&
224 isa<cir::IntType>(truncTy)) {
225 uint64_t tmpSize = cgm.getDataLayout().getTypeSizeInBits(tmp.getType());
226 tmp = builder.createPtrToInt(
227 tmp, cir::IntType::get(ctx, (unsigned)tmpSize, false));
228 tmp = builder.createIntCast(tmp, truncTy);
229 } else if (isa<cir::IntType>(truncTy)) {
230 tmp = builder.createIntCast(tmp, truncTy);
231 } else if (isa<cir::VectorType>(truncTy)) {
233 }
234 }
235
236 LValue dest = resultRegDests[i];
237 // ResultTypeRequiresCast elements correspond to the first
238 // ResultTypeRequiresCast.size() elements of RegResults.
239 if ((i < resultTypeRequiresCast.size()) && resultTypeRequiresCast[i]) {
240 unsigned size = cgf.getContext().getTypeSize(resultRegQualTys[i]);
241 Address addr =
242 dest.getAddress().withElementType(builder, resultRegTypes[i]);
243 if (cgm.getTargetCIRGenInfo().isScalarizableAsmOperand(cgf, truncTy)) {
244 builder.createStore(cgf.getLoc(s.getAsmLoc()), tmp, addr);
245 continue;
246 }
247
248 QualType ty =
249 cgf.getContext().getIntTypeForBitwidth(size, /*Signed=*/false);
250 if (ty.isNull()) {
251 const Expr *outExpr = s.getOutputExpr(i);
252 cgm.getDiags().Report(outExpr->getExprLoc(),
253 diag::err_store_value_to_reg);
254 return;
255 }
256 dest = cgf.makeAddrLValue(addr, ty);
257 }
258
259 cgf.emitStoreThroughLValue(RValue::get(tmp), dest);
260 }
261}
262
263mlir::LogicalResult CIRGenFunction::emitAsmStmt(const AsmStmt &s) {
264 FullExprCleanupScope cleanups(*this, &s);
265
266 // Assemble the final asm string.
267 std::string asmString = s.generateAsmString(getContext());
268 SourceLocation srcLoc = s.getAsmLoc();
269 mlir::Location loc = getLoc(srcLoc);
270
271 // Get all the output and input constraints together.
272 SmallVector<TargetInfo::ConstraintInfo> outputConstraintInfos;
273 SmallVector<TargetInfo::ConstraintInfo> inputConstraintInfos;
274 collectInOutConstraintInfos(*this, s, outputConstraintInfos,
275 inputConstraintInfos);
276
277 bool isGCCAsmGoto = false;
278
279 std::string constraints;
280 SmallVector<LValue> resultRegDests;
281 SmallVector<QualType> resultRegQualTys;
282 SmallVector<mlir::Type> resultRegTypes;
283 SmallVector<mlir::Type> resultTruncRegTypes;
285 SmallVector<mlir::Type> argElemTypes;
289 SmallVector<mlir::Value> inOutArgs;
290 llvm::BitVector resultTypeRequiresCast;
291 llvm::BitVector resultRegIsFlagReg;
292
293 // Keep track of input constraints.
294 std::string inOutConstraints;
295 SmallVector<mlir::Type> inOutArgTypes;
296 SmallVector<mlir::Type> inOutArgElemTypes;
297
298 // Keep track of out constraints for tied input operand.
299 SmallVector<std::string> outputConstraints;
300
301 // Keep track of defined physregs.
302 llvm::SmallSet<std::string, 8> physRegOutputs;
303
304 // An inline asm can be marked readonly if it meets the following conditions:
305 // - it doesn't have any sideeffects
306 // - it doesn't clobber memory
307 // - it doesn't return a value by-reference
308 // It can be marked readnone if it doesn't have any input memory constraints
309 // in addition to meeting the conditions listed above.
310 bool readOnly = true, readNone = true;
311
312 std::string outputConstraint;
313 for (unsigned i = 0, e = s.getNumOutputs(); i != e; ++i) {
314 TargetInfo::ConstraintInfo &info = outputConstraintInfos[i];
315
316 // Simplify the output constraint.
317 outputConstraint = s.getOutputConstraint(i);
318 outputConstraint = getTarget().simplifyConstraint(
319 StringRef(outputConstraint).drop_front());
320
321 const Expr *outExpr = s.getOutputExpr(i);
322 outExpr = outExpr->IgnoreParenNoopCasts(getContext());
323
324 std::string gccReg;
325 outputConstraint = s.addVariableConstraints(
326 outputConstraint, *outExpr, getTarget(), info.earlyClobber(),
327 [&](const Stmt *unspStmt, StringRef msg) {
328 cgm.errorUnsupported(unspStmt, msg);
329 },
330 &gccReg);
331
332 // Give an error on multiple outputs to same physreg.
333 if (!gccReg.empty() && !physRegOutputs.insert(gccReg).second)
334 cgm.error(srcLoc, "multiple outputs to hard register: " + gccReg);
335
336 outputConstraints.push_back(outputConstraint);
337 LValue dest = emitLValue(outExpr);
338
339 if (!constraints.empty())
340 constraints += ',';
341
342 // If this is a register output, then make the inline a sm return it
343 // by-value. If this is a memory result, return the value by-reference.
344 QualType qty = outExpr->getType();
345 const bool isScalarOrAggregate =
347 if (!info.allowsMemory() && isScalarOrAggregate) {
348 constraints += "=" + outputConstraint;
349 resultRegQualTys.push_back(qty);
350 resultRegDests.push_back(dest);
351
352 bool isFlagReg = llvm::StringRef(outputConstraint).starts_with("{@cc");
353 resultRegIsFlagReg.push_back(isFlagReg);
354
355 mlir::Type ty = convertTypeForMem(qty);
356 const bool requiresCast =
357 info.allowsRegister() &&
358 (cgm.getTargetCIRGenInfo().isScalarizableAsmOperand(*this, ty) ||
360
361 resultTruncRegTypes.push_back(ty);
362 resultTypeRequiresCast.push_back(requiresCast);
363
364 if (requiresCast) {
365 unsigned size = getContext().getTypeSize(qty);
366 if (size == 0)
367 cgm.error(outExpr->getExprLoc(), "output size should not be zero");
368
369 ty = cir::IntType::get(&getMLIRContext(), size, false);
370 }
371
372 resultRegTypes.push_back(ty);
373 // If this output is tied to an input, and if the input is larger, then
374 // we need to set the actual result type of the inline asm node to be the
375 // same as the input type.
376 if (info.hasMatchingInput()) {
377 unsigned inputNo;
378 for (inputNo = 0; inputNo != s.getNumInputs(); ++inputNo) {
379 TargetInfo::ConstraintInfo &input = inputConstraintInfos[inputNo];
380 if (input.hasTiedOperand() && input.getTiedOperand() == i)
381 break;
382 }
383 assert(inputNo != s.getNumInputs() && "Didn't find matching input!");
384
385 QualType inputTy = s.getInputExpr(inputNo)->getType();
386 QualType outputType = outExpr->getType();
387
388 uint64_t inputSize = getContext().getTypeSize(inputTy);
389 if (getContext().getTypeSize(outputType) < inputSize) {
390 // Form the asm to return the value as a larger integer or fp type.
391 resultRegTypes.back() = convertType(inputTy);
392 }
393
394 if (mlir::Type adjTy = cgm.getTargetCIRGenInfo().adjustInlineAsmType(
395 *this, outputConstraint, resultRegTypes.back()))
396 resultRegTypes.back() = adjTy;
397 else
398 cgm.getDiags().Report(srcLoc, diag::err_asm_invalid_type_in_input)
399 << outExpr->getType() << outputConstraint;
400 }
401
402 // Update largest vector width for any vector types.
404 } else {
405 Address destAddr = dest.getAddress();
406
407 // Matrix types in memory are represented by arrays, but accessed through
408 // vector pointers, with the alignment specified on the access operation.
409 // For inline assembly, update pointer arguments to use vector pointers.
410 // Otherwise there will be a mis-match if the matrix is also an
411 // input-argument which is represented as vector.
412 if (isa<MatrixType>(outExpr->getType().getCanonicalType()))
413 destAddr =
414 destAddr.withElementType(builder, convertType(outExpr->getType()));
415
416 argTypes.push_back(destAddr.getType());
417 argElemTypes.push_back(destAddr.getElementType());
418 outArgs.push_back(destAddr.getPointer());
419 args.push_back(destAddr.getPointer());
420 constraints += "=*";
421 constraints += outputConstraint;
422 readOnly = readNone = false;
423 }
424
425 if (info.isReadWrite()) {
426 inOutConstraints += ',';
427 const Expr *inputExpr = s.getOutputExpr(i);
428
429 // argValue: mlir::Value, argElementType: mlir::Type.
430 auto [argValue, argElementType] =
431 emitAsmInputLValue(info, dest, inputExpr->getType(), inOutConstraints,
432 inputExpr->getExprLoc());
433
434 if (mlir::Type adjTy = getTargetHooks().adjustInlineAsmType(
435 *this, outputConstraint, argValue.getType()))
436 argValue = builder.createBitcast(argValue, adjTy);
437
438 // Update largest vector width for any vector types.
440
441 // Only tie earlyclobber physregs.
442 if (info.allowsRegister() && (gccReg.empty() || info.earlyClobber()))
443 inOutConstraints += llvm::utostr(i);
444 else
445 inOutConstraints += outputConstraint;
446
447 inOutArgTypes.push_back(argValue.getType());
448 inOutArgElemTypes.push_back(argElementType);
449 inOutArgs.push_back(argValue);
450 }
451
452 } // iterate over output operands
453
454 for (unsigned i = 0, e = s.getNumInputs(); i != e; ++i) {
455 TargetInfo::ConstraintInfo &info = inputConstraintInfos[i];
456 const Expr *inputExpr = s.getInputExpr(i);
457
458 if (info.allowsMemory())
459 readNone = false;
460
461 if (!constraints.empty())
462 constraints += ',';
463
464 std::string inputConstraint(s.getInputConstraint(i));
465 inputConstraint =
466 getTarget().simplifyConstraint(inputConstraint, &outputConstraintInfos);
467
468 inputConstraint = s.addVariableConstraints(
469 inputConstraint, *inputExpr->IgnoreParenNoopCasts(getContext()),
470 getTarget(), /*EarlyClobber=*/false,
471 [&](const Stmt *unspStmt, StringRef msg) {
472 cgm.errorUnsupported(unspStmt, msg);
473 });
474
475 std::string replaceConstraint(inputConstraint);
476 // argValue: mlir::Value, argElementType: mlir::Type.
477 auto [argValue, argElemType] = emitAsmInput(info, inputExpr, constraints);
478
479 // If this input argument is tied to a larger output result, extend the
480 // input to be the same size as the output. The LLVM backend wants to see
481 // the input and output of a matching constraint be the same size. Note
482 // that GCC does not define what the top bits are here. We use zext because
483 // that is usually cheaper, but LLVM IR should really get an anyext someday.
484 if (info.hasTiedOperand()) {
485 unsigned output = info.getTiedOperand();
486 QualType outputType = s.getOutputExpr(output)->getType();
487 QualType inputTy = inputExpr->getType();
488
489 if (getContext().getTypeSize(outputType) >
490 getContext().getTypeSize(inputTy)) {
491 // Use ptrtoint as appropriate so that we can do our extension.
492 if (isa<cir::PointerType>(argValue.getType()))
493 argValue = builder.createPtrToInt(argValue, uIntPtrTy);
494 mlir::Type outputTy = convertType(outputType);
495 if (isa<cir::IntType>(outputTy))
496 argValue = builder.createIntCast(argValue, outputTy);
497 else if (isa<cir::PointerType>(outputTy))
498 argValue = builder.createIntCast(argValue, uIntPtrTy);
499 else if (isa<cir::FPTypeInterface>(outputTy))
500 argValue = builder.createFloatingCast(argValue, outputTy);
501 }
502
503 // Deal with the tied operands' constraint code in adjustInlineAsmType.
504 replaceConstraint = outputConstraints[output];
505 }
506
507 if (mlir::Type adjTy = getTargetHooks().adjustInlineAsmType(
508 *this, replaceConstraint, argValue.getType()))
509 argValue = builder.createBitcast(argValue, adjTy);
510 else
511 cgm.getDiags().Report(s.getAsmLoc(), diag::err_asm_invalid_type_in_input)
512 << inputExpr->getType() << inputConstraint;
513
514 // Update largest vector width for any vector types.
516
517 argTypes.push_back(argValue.getType());
518 argElemTypes.push_back(argElemType);
519 inArgs.push_back(argValue);
520 args.push_back(argValue);
521 constraints += inputConstraint;
522 } // iterate over input operands
523
524 // Append the "input" part of inout constraints.
525 for (unsigned i = 0, e = inOutArgs.size(); i != e; ++i) {
526 args.push_back(inOutArgs[i]);
527 argTypes.push_back(inOutArgTypes[i]);
528 argElemTypes.push_back(inOutArgElemTypes[i]);
529 }
530 constraints += inOutConstraints;
531
532 bool hasUnwindClobber = false;
533 collectClobbers(*this, s, constraints, hasUnwindClobber, readOnly, readNone);
534
535 std::array<mlir::ValueRange, 3> operands = {outArgs, inArgs, inOutArgs};
536
537 mlir::Type resultType;
538
539 if (resultRegTypes.size() == 1)
540 resultType = resultRegTypes[0];
541 else if (resultRegTypes.size() > 1)
542 resultType = builder.getAnonRecordTy(
543 resultRegTypes, /*packed=*/false,
544 cir::RecordType::getAllDataKinds(resultRegTypes));
545
546 bool hasSideEffect = s.isVolatile() || s.getNumOutputs() == 0;
547
548 std::vector<mlir::Value> regResults;
549 cir::InlineAsmOp ia = cir::InlineAsmOp::create(
550 builder, getLoc(s.getAsmLoc()), resultType, operands, asmString,
551 constraints, hasSideEffect, inferFlavor(cgm, s), mlir::ArrayAttr());
552
553 if (isGCCAsmGoto) {
555 } else if (hasUnwindClobber) {
557 } else {
559
560 mlir::Value result;
561 if (ia.getNumResults())
562 result = ia.getResult(0);
563
565
566 for (auto [idx, typ] : llvm::enumerate(argElemTypes)) {
567 if (typ) {
568 [[maybe_unused]] mlir::Value op = args[idx];
569 assert(mlir::isa<cir::PointerType>(op.getType()) &&
570 "pointer type expected");
571 assert(cast<cir::PointerType>(op.getType()).getPointee() == typ &&
572 "element type differs from pointee type!");
573
574 operandAttrs.push_back(mlir::UnitAttr::get(&getMLIRContext()));
575 } else {
576 // We need to add an attribute for every arg since later, during
577 // the lowering to LLVM IR the attributes will be assigned to the
578 // CallInsn argument by index, i.e. we can't skip null type here
579 operandAttrs.push_back(mlir::DictionaryAttr::get(&getMLIRContext()));
580 }
581 }
582 assert(args.size() == operandAttrs.size() &&
583 "The number of attributes is not even with the number of operands");
584
585 ia.setOperandAttrsAttr(builder.getArrayAttr(operandAttrs));
586
587 if (resultRegTypes.size() == 1) {
588 regResults.push_back(result);
589 } else if (resultRegTypes.size() > 1) {
590 CharUnits alignment = CharUnits::One();
591 mlir::Value dest =
592 emitAlloca("__asm_result", resultType, loc, alignment, false);
593 Address addr = Address(dest, alignment);
594 builder.createStore(loc, result, addr);
595
596 for (unsigned i = 0, e = resultRegTypes.size(); i != e; ++i) {
597 cir::PointerType typ = builder.getPointerTo(
598 resultRegTypes[i],
599 mlir::cast<cir::PointerType>(dest.getType()).getAddrSpace());
600 cir::GetMemberOp ptr = builder.createGetMember(loc, typ, dest, "", i);
601 cir::LoadOp tmp = builder.createLoad(loc, Address(ptr, alignment));
602 regResults.push_back(tmp);
603 }
604 }
605 }
606
607 emitAsmStores(*this, s, regResults, resultRegTypes, resultTruncRegTypes,
608 resultRegDests, resultRegQualTys, resultTypeRequiresCast,
609 resultRegIsFlagReg);
610
611 return mlir::success();
612}
static AsmFlavor inferFlavor(const CIRGenModule &cgm, const AsmStmt &s)
Definition CIRGenAsm.cpp:22
static void collectInOutConstraintInfos(const CIRGenFunction &cgf, const AsmStmt &s, SmallVectorImpl< TargetInfo::ConstraintInfo > &out, SmallVectorImpl< TargetInfo::ConstraintInfo > &in)
Definition CIRGenAsm.cpp:89
static void collectClobbers(const CIRGenFunction &cgf, const AsmStmt &s, std::string &constraints, bool &hasUnwindClobber, bool &readOnly, bool readNone)
Definition CIRGenAsm.cpp:31
static void emitAsmStores(CIRGenFunction &cgf, const AsmStmt &s, const llvm::ArrayRef< mlir::Value > regResults, const llvm::ArrayRef< mlir::Type > resultRegTypes, const llvm::ArrayRef< mlir::Type > resultTruncRegTypes, const llvm::ArrayRef< LValue > resultRegDests, const llvm::ArrayRef< QualType > resultRegQualTys, const llvm::BitVector &resultTypeRequiresCast, const llvm::BitVector &resultRegIsFlagReg)
mlir::Value createIntToPtr(mlir::Value src, mlir::Type newTy)
mlir::Value createPtrToInt(mlir::Value src, mlir::Type newTy)
mlir::Value createIntCast(mlir::Value src, mlir::Type newTy)
llvm::TypeSize getTypeSizeInBits(mlir::Type ty) const
static llvm::SmallVector< RecordMemberKind > getAllDataKinds(llvm::ArrayRef< mlir::Type > members)
One Data kind per member.
Definition CIRTypes.cpp:151
APSInt & getInt()
Definition APValue.h:573
bool toIntegralConstant(APSInt &Result, QualType SrcTy, const ASTContext &Ctx) const
Try to convert this value to an integral constant.
Definition APValue.cpp:1106
QualType getIntTypeForBitwidth(unsigned DestWidth, unsigned Signed) const
getIntTypeForBitwidth - sets integer QualTy according to specified details: bitwidth,...
uint64_t getTypeSize(QualType T) const
Return the size of the specified (complete) type T, in bits.
AsmStmt is the base class for GCCAsmStmt and MSAsmStmt.
Definition Stmt.h:3290
std::string getInputConstraint(unsigned i) const
getInputConstraint - Return the specified input constraint.
Definition Stmt.cpp:515
bool isVolatile() const
Definition Stmt.h:3326
std::string getOutputConstraint(unsigned i) const
getOutputConstraint - Return the constraint string for the specified output operand.
Definition Stmt.cpp:499
SourceLocation getAsmLoc() const
Definition Stmt.h:3320
const Expr * getInputExpr(unsigned i) const
Definition Stmt.cpp:523
std::string addVariableConstraints(StringRef Constraint, const Expr &AsmExpr, const TargetInfo &Target, bool EarlyClobber, UnsupportedConstraintCallbackTy UnsupportedCB, std::string *GCCReg=nullptr) const
Look at AsmExpr and if it is a variable declared as using a particular register add that as a constra...
Definition Stmt.cpp:459
unsigned getNumClobbers() const
Definition Stmt.h:3381
const Expr * getOutputExpr(unsigned i) const
Definition Stmt.cpp:507
unsigned getNumOutputs() const
Definition Stmt.h:3349
std::string generateAsmString(const ASTContext &C) const
Assemble final IR asm string.
Definition Stmt.cpp:491
unsigned getNumInputs() const
Definition Stmt.h:3371
std::string getClobber(unsigned i) const
Definition Stmt.cpp:531
mlir::Value getPointer() const
Definition Address.h:98
mlir::Type getElementType() const
Definition Address.h:125
Address withElementType(CIRGenBuilderTy &builder, mlir::Type ElemTy) const
Return address with different element type, a bitcast pointer, and the same alignment.
mlir::Type getType() const
Definition Address.h:117
cir::StoreOp createStore(mlir::Location loc, mlir::Value val, Address dst, bool isVolatile=false, bool isNontemporal=false, mlir::IntegerAttr align={}, cir::SyncScopeKindAttr scope={}, cir::MemOrderAttr order={})
mlir::Value createFloatingCast(mlir::Value v, mlir::Type destType)
static bool hasScalarEvaluationKind(clang::QualType type)
mlir::Type convertType(clang::QualType t)
RValue emitLoadOfLValue(LValue lv, SourceLocation loc)
Given an expression that represents a value lvalue, this method emits the address of the lvalue,...
const TargetInfo & getTarget() const
LValue emitLValue(const clang::Expr *e)
Emit code to compute a designator that specifies the location of the expression.
mlir::Location getLoc(clang::SourceLocation srcLoc)
Helpers to convert Clang's SourceLocation to a MLIR Location.
const TargetCIRGenInfo & getTargetHooks() const
mlir::LogicalResult emitAsmStmt(const clang::AsmStmt &s)
std::pair< mlir::Value, mlir::Type > emitAsmInputLValue(const TargetInfo::ConstraintInfo &info, LValue inputValue, QualType inputType, std::string &constraintString, SourceLocation loc)
mlir::Type convertTypeForMem(QualType t)
mlir::Value emitAlloca(llvm::StringRef name, mlir::Type ty, mlir::Location loc, clang::CharUnits alignment, bool insertIntoFnEntryBlock, mlir::Value arraySize=nullptr)
static bool hasAggregateEvaluationKind(clang::QualType type)
mlir::Value emitScalarExpr(const clang::Expr *e, bool ignoreResultAssign=false)
Emit the computation of the specified expression of scalar type.
CIRGenBuilderTy & getBuilder()
mlir::MLIRContext & getMLIRContext()
LValue makeAddrLValue(Address addr, QualType ty, AlignmentSource source=AlignmentSource::Type)
std::pair< mlir::Value, mlir::Type > emitAsmInput(const TargetInfo::ConstraintInfo &info, const Expr *inputExpr, std::string &constraintString)
clang::ASTContext & getContext() const
void emitStoreThroughLValue(RValue src, LValue dst, bool isInit=false)
Store the specified rvalue into the specified lvalue, where both are guaranteed to the have the same ...
This class organizes the cross-function state that is used while generating CIR code.
clang::DiagnosticsEngine & getDiags() const
const cir::CIRDataLayout & getDataLayout() const
const clang::CodeGenOptions & getCodeGenOpts() const
const TargetCIRGenInfo & getTargetCIRGenInfo()
Address getAddress() const
static RValue get(mlir::Value v)
Definition CIRGenValue.h:83
mlir::Value getValue() const
Return the value of this scalar value.
Definition CIRGenValue.h:57
virtual bool isScalarizableAsmOperand(CIRGenFunction &cgf, mlir::Type ty) const
Definition TargetInfo.h:164
This is an opaque type for sizes expressed in character units.
Definition CharUnits.h:38
static CharUnits One()
Construct a CharUnits quantity of one.
Definition CharUnits.h:55
DiagnosticBuilder Report(SourceLocation Loc, unsigned DiagID)
Issue the message to the client.
This represents one expression.
Definition Expr.h:114
bool EvaluateAsInt(EvalResult &Result, const ASTContext &Ctx, SideEffectsKind AllowSideEffects=SE_NoSideEffects, bool InConstantContext=false) const
EvaluateAsInt - Return true if this is a constant which we can fold and convert to an integer,...
Expr * IgnoreParenNoopCasts(const ASTContext &Ctx) LLVM_READONLY
Skip past any parentheses and casts which do not change the value (including ptr->int casts of the sa...
Definition Expr.cpp:3156
bool EvaluateAsRValue(EvalResult &Result, const ASTContext &Ctx, bool InConstantContext=false) const
EvaluateAsRValue - Return true if this is a constant which we can fold to an rvalue using any crazy t...
SourceLocation getExprLoc() const LLVM_READONLY
getExprLoc - Return the preferred location for the arrow when diagnosing a problem with a generic exp...
Definition Expr.cpp:283
QualType getType() const
Definition Expr.h:146
This represents a GCC inline-assembly statement extension.
Definition Stmt.h:3459
A (possibly-)qualified type.
Definition TypeBase.h:938
bool isNull() const
Return true if this QualType doesn't point to a type yet.
Definition TypeBase.h:1005
QualType getCanonicalType() const
Definition TypeBase.h:8630
Encodes a location in the source.
Stmt - This represents one statement.
Definition Stmt.h:85
StmtClass getStmtClass() const
Definition Stmt.h:1504
bool validateInputConstraint(MutableArrayRef< ConstraintInfo > OutputConstraints, ConstraintInfo &info) const
std::string simplifyConstraint(StringRef Constraint, SmallVectorImpl< ConstraintInfo > *OutCons=nullptr) const
StringRef getNormalizedGCCRegisterName(StringRef Name, bool ReturnCanonical=false) const
Returns the "normalized" GCC register name.
bool validateOutputConstraint(ConstraintInfo &Info) const
virtual std::string_view getClobbers() const =0
Returns a string of target-specific clobbers, in LLVM format.
virtual bool isSPRegName(StringRef) const
Top level wrappers for InstallAPI frontend operations.
bool isa(CodeGen::Address addr)
Definition Address.h:330
U cast(CodeGen::Address addr)
Definition Address.h:327
static bool asmMemoryEffects()
static bool asmVectorType()
static bool asmUnwindClobber()
static bool asmLLVMAssume()
EvalResult is a struct with detailed info about an evaluated expression.
Definition Expr.h:667
APValue Val
Val - This is the value the expression can be folded to.
Definition Expr.h:669
bool hasTiedOperand() const
Return true if this input operand is a matching constraint that ties it to an output operand.