23 AsmFlavor gnuAsmFlavor =
26 : AsmFlavor::x86_intel;
32 std::string &constraints,
bool &hasUnwindClobber,
33 bool &readOnly,
bool readNone) {
35 hasUnwindClobber =
false;
41 if (clobber ==
"memory") {
42 readOnly = readNone =
false;
43 }
else if (clobber ==
"unwind") {
44 hasUnwindClobber =
true;
46 }
else if (clobber !=
"cc") {
51 diag::warn_stack_clash_protection_inline_asm);
55 if (clobber ==
"eax" || clobber ==
"edx") {
56 if (constraints.find(
"=&A") != std::string::npos)
58 std::string::size_type position1 =
59 constraints.find(
"={" + clobber +
"}");
60 if (position1 != std::string::npos) {
61 constraints.insert(position1 + 1,
"&");
64 std::string::size_type position2 = constraints.find(
"=A");
65 if (position2 != std::string::npos) {
66 constraints.insert(position2 + 1,
"&");
71 if (!constraints.empty())
75 constraints += clobber;
81 if (!machineClobbers.empty()) {
82 if (!constraints.empty())
84 constraints += machineClobbers;
95 if (
const GCCAsmStmt *gas = dyn_cast<GCCAsmStmt>(&s))
96 name = gas->getOutputName(i);
102 assert(isValid &&
"Failed to parse output constraint");
106 for (
unsigned i = 0, e = s.
getNumInputs(); i != e; ++i) {
108 if (
const GCCAsmStmt *gas = dyn_cast<GCCAsmStmt>(&s))
109 name = gas->getInputName(i);
114 assert(isValid &&
"Failed to parse input constraint");
129 uint64_t size =
cgm.getDataLayout().getTypeSizeInBits(ty);
130 if ((size <= 64 && llvm::isPowerOf2_64(size)) ||
134 return {builder.createLoad(
142 constraintString +=
'*';
146std::pair<mlir::Value, mlir::Type>
148 const Expr *inputExpr,
149 std::string &constraintString) {
159 llvm::APSInt intResult;
162 return {builder.getConstInt(loc, intResult), mlir::Type()};
167 return {builder.getConstInt(loc, result.
Val.
getInt()), mlir::Type()};
173 if (inputExpr->
getStmtClass() == Expr::CXXThisExprClass)
187 const llvm::BitVector &resultTypeRequiresCast,
188 const llvm::BitVector &resultRegIsFlagReg) {
191 mlir::MLIRContext *ctx = builder.getContext();
193 assert(regResults.size() == resultRegTypes.size());
194 assert(regResults.size() == resultTruncRegTypes.size());
195 assert(regResults.size() == resultRegDests.size());
199 assert(resultTypeRequiresCast.size() <= resultRegDests.size());
200 assert(resultRegIsFlagReg.size() <= resultRegDests.size());
202 for (
unsigned i = 0, e = regResults.size(); i != e; ++i) {
203 mlir::Value tmp = regResults[i];
204 mlir::Type truncTy = resultTruncRegTypes[i];
206 if (i < resultRegIsFlagReg.size() && resultRegIsFlagReg[i])
211 if (resultRegTypes[i] != truncTy) {
215 if (mlir::isa<cir::FPTypeInterface>(truncTy)) {
221 tmp, cir::IntType::get(ctx, (
unsigned)resSize,
false));
227 tmp, cir::IntType::get(ctx, (
unsigned)tmpSize,
false));
236 LValue dest = resultRegDests[i];
239 if ((i < resultTypeRequiresCast.size()) && resultTypeRequiresCast[i]) {
242 dest.getAddress().withElementType(builder, resultRegTypes[i]);
253 diag::err_store_value_to_reg);
267 mlir::Location loc =
getLoc(srcLoc);
273 inputConstraintInfos);
275 bool isGCCAsmGoto =
false;
277 std::string constraints;
288 llvm::BitVector resultTypeRequiresCast;
289 llvm::BitVector resultRegIsFlagReg;
292 std::string inOutConstraints;
300 llvm::SmallSet<std::string, 8> physRegOutputs;
308 bool readOnly =
true, readNone =
true;
310 std::string outputConstraint;
317 StringRef(outputConstraint).drop_front());
325 [&](
const Stmt *unspStmt, StringRef msg) {
326 cgm.errorUnsupported(unspStmt, msg);
331 if (!gccReg.empty() && !physRegOutputs.insert(gccReg).second)
332 cgm.error(srcLoc,
"multiple outputs to hard register: " + gccReg);
334 outputConstraints.push_back(outputConstraint);
337 if (!constraints.empty())
343 const bool isScalarOrAggregate =
346 constraints +=
"=" + outputConstraint;
347 resultRegQualTys.push_back(qty);
348 resultRegDests.push_back(dest);
350 bool isFlagReg = llvm::StringRef(outputConstraint).starts_with(
"{@cc");
351 resultRegIsFlagReg.push_back(isFlagReg);
354 const bool requiresCast =
356 (
cgm.getTargetCIRGenInfo().isScalarizableAsmOperand(*
this, ty) ||
359 resultTruncRegTypes.push_back(ty);
360 resultTypeRequiresCast.push_back(requiresCast);
365 cgm.error(outExpr->
getExprLoc(),
"output size should not be zero");
370 resultRegTypes.push_back(ty);
376 for (inputNo = 0; inputNo != s.
getNumInputs(); ++inputNo) {
381 assert(inputNo != s.
getNumInputs() &&
"Didn't find matching input!");
387 if (
getContext().getTypeSize(outputType) < inputSize) {
392 if (mlir::Type adjTy =
cgm.getTargetCIRGenInfo().adjustInlineAsmType(
393 *
this, outputConstraint, resultRegTypes.back()))
394 resultRegTypes.back() = adjTy;
396 cgm.getDiags().Report(srcLoc, diag::err_asm_invalid_type_in_input)
397 << outExpr->
getType() << outputConstraint;
414 argTypes.push_back(destAddr.
getType());
419 constraints += outputConstraint;
420 readOnly = readNone =
false;
424 inOutConstraints +=
',';
428 auto [argValue, argElementType] =
433 *
this, outputConstraint, argValue.getType()))
434 argValue = builder.createBitcast(argValue, adjTy);
441 inOutConstraints += llvm::utostr(i);
443 inOutConstraints += outputConstraint;
445 inOutArgTypes.push_back(argValue.getType());
446 inOutArgElemTypes.push_back(argElementType);
447 inOutArgs.push_back(argValue);
452 for (
unsigned i = 0, e = s.
getNumInputs(); i != e; ++i) {
459 if (!constraints.empty())
469 [&](
const Stmt *unspStmt, StringRef msg) {
470 cgm.errorUnsupported(unspStmt, msg);
473 std::string replaceConstraint(inputConstraint);
475 auto [argValue, argElemType] =
emitAsmInput(info, inputExpr, constraints);
491 argValue = builder.createPtrToInt(argValue,
uIntPtrTy);
494 argValue = builder.createIntCast(argValue, outputTy);
496 argValue = builder.createIntCast(argValue,
uIntPtrTy);
498 argValue = builder.createFloatingCast(argValue, outputTy);
502 replaceConstraint = outputConstraints[output];
506 *
this, replaceConstraint, argValue.getType()))
507 argValue = builder.createBitcast(argValue, adjTy);
509 cgm.getDiags().Report(s.
getAsmLoc(), diag::err_asm_invalid_type_in_input)
510 << inputExpr->
getType() << inputConstraint;
515 argTypes.push_back(argValue.getType());
516 argElemTypes.push_back(argElemType);
517 inArgs.push_back(argValue);
518 args.push_back(argValue);
519 constraints += inputConstraint;
523 for (
unsigned i = 0, e = inOutArgs.size(); i != e; ++i) {
524 args.push_back(inOutArgs[i]);
525 argTypes.push_back(inOutArgTypes[i]);
526 argElemTypes.push_back(inOutArgElemTypes[i]);
528 constraints += inOutConstraints;
530 bool hasUnwindClobber =
false;
531 collectClobbers(*
this, s, constraints, hasUnwindClobber, readOnly, readNone);
533 std::array<mlir::ValueRange, 3> operands = {outArgs, inArgs, inOutArgs};
535 mlir::Type resultType;
537 if (resultRegTypes.size() == 1)
538 resultType = resultRegTypes[0];
539 else if (resultRegTypes.size() > 1)
540 resultType = builder.getAnonRecordTy(resultRegTypes,
false,
545 std::vector<mlir::Value> regResults;
546 cir::InlineAsmOp ia = cir::InlineAsmOp::create(
548 constraints, hasSideEffect,
inferFlavor(
cgm, s), mlir::ArrayAttr());
552 }
else if (hasUnwindClobber) {
558 if (ia.getNumResults())
559 result = ia.getResult(0);
563 for (
auto [idx, typ] : llvm::enumerate(argElemTypes)) {
565 [[maybe_unused]] mlir::Value op = args[idx];
566 assert(mlir::isa<cir::PointerType>(op.getType()) &&
567 "pointer type expected");
569 "element type differs from pointee type!");
576 operandAttrs.push_back(mlir::DictionaryAttr::get(&
getMLIRContext()));
579 assert(args.size() == operandAttrs.size() &&
580 "The number of attributes is not even with the number of operands");
582 ia.setOperandAttrsAttr(builder.getArrayAttr(operandAttrs));
584 if (resultRegTypes.size() == 1) {
585 regResults.push_back(result);
586 }
else if (resultRegTypes.size() > 1) {
589 emitAlloca(
"__asm_result", resultType, loc, alignment,
false);
591 builder.createStore(loc, result, addr);
593 for (
unsigned i = 0, e = resultRegTypes.size(); i != e; ++i) {
594 cir::PointerType typ = builder.getPointerTo(resultRegTypes[i]);
595 cir::GetMemberOp ptr = builder.createGetMember(loc, typ, dest,
"", i);
596 cir::LoadOp tmp = builder.createLoad(loc,
Address(ptr, alignment));
597 regResults.push_back(tmp);
602 emitAsmStores(*
this, s, regResults, resultRegTypes, resultTruncRegTypes,
603 resultRegDests, resultRegQualTys, resultTypeRequiresCast,
606 return mlir::success();
static AsmFlavor inferFlavor(const CIRGenModule &cgm, const AsmStmt &s)
static void collectInOutConstraintInfos(const CIRGenFunction &cgf, const AsmStmt &s, SmallVectorImpl< TargetInfo::ConstraintInfo > &out, SmallVectorImpl< TargetInfo::ConstraintInfo > &in)
static void collectClobbers(const CIRGenFunction &cgf, const AsmStmt &s, std::string &constraints, bool &hasUnwindClobber, bool &readOnly, bool readNone)
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
bool toIntegralConstant(APSInt &Result, QualType SrcTy, const ASTContext &Ctx) const
Try to convert this value to an integral constant.
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.
std::string getInputConstraint(unsigned i) const
getInputConstraint - Return the specified input constraint.
std::string getOutputConstraint(unsigned i) const
getOutputConstraint - Return the constraint string for the specified output operand.
SourceLocation getAsmLoc() const
const Expr * getInputExpr(unsigned i) const
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...
unsigned getNumClobbers() const
const Expr * getOutputExpr(unsigned i) const
unsigned getNumOutputs() const
std::string generateAsmString(const ASTContext &C) const
Assemble final IR asm string.
unsigned getNumInputs() const
std::string getClobber(unsigned i) const
mlir::Value getPointer() const
mlir::Type getElementType() const
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
mlir::Value createFloatingCast(mlir::Value v, mlir::Type destType)
cir::StoreOp createStore(mlir::Location loc, mlir::Value val, Address dst, bool isVolatile=false, mlir::IntegerAttr align={}, cir::SyncScopeKindAttr scope={}, cir::MemOrderAttr order={})
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()
CIRGenModule & getCIRGenModule()
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)
mlir::Value getValue() const
Return the value of this scalar value.
virtual bool isScalarizableAsmOperand(CIRGenFunction &cgf, mlir::Type ty) const
CharUnits - This is an opaque type for sizes expressed in character units.
static CharUnits One()
One - Construct a CharUnits quantity of one.
DiagnosticBuilder Report(SourceLocation Loc, unsigned DiagID)
Issue the message to the client.
This represents one expression.
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...
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...
This represents a GCC inline-assembly statement extension.
A (possibly-)qualified type.
bool isNull() const
Return true if this QualType doesn't point to a type yet.
QualType getCanonicalType() const
Encodes a location in the source.
Stmt - This represents one statement.
StmtClass getStmtClass() const
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
The JSON file list parser is used to communicate input to InstallAPI.
bool isa(CodeGen::Address addr)
U cast(CodeGen::Address addr)
static bool asmMemoryEffects()
static bool asmVectorType()
static bool asmUnwindClobber()
static bool asmLLVMAssume()
EvalResult is a struct with detailed info about an evaluated expression.
APValue Val
Val - This is the value the expression can be folded to.
bool hasMatchingInput() const
Return true if this output operand has a matching (tied) input operand.
unsigned getTiedOperand() const
bool allowsMemory() const
bool requiresImmediateConstant() const
bool hasTiedOperand() const
Return true if this input operand is a matching constraint that ties it to an output operand.
bool allowsRegister() const