137 lines
4.5 KiB
C++

//===--- CIRGenAsm.cpp - Inline Assembly Support for CIR CodeGen ---------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file contains code to emit inline assembly.
//
//===----------------------------------------------------------------------===//
#include "CIRGenFunction.h"
#include "clang/CIR/MissingFeatures.h"
using namespace clang;
using namespace clang::CIRGen;
using namespace cir;
static AsmFlavor inferFlavor(const CIRGenModule &cgm, const AsmStmt &s) {
AsmFlavor gnuAsmFlavor =
cgm.getCodeGenOpts().getInlineAsmDialect() == CodeGenOptions::IAD_ATT
? AsmFlavor::x86_att
: AsmFlavor::x86_intel;
return isa<MSAsmStmt>(&s) ? AsmFlavor::x86_intel : gnuAsmFlavor;
}
static void collectClobbers(const CIRGenFunction &cgf, const AsmStmt &s,
std::string &constraints, bool &hasUnwindClobber,
bool &readOnly, bool readNone) {
hasUnwindClobber = false;
const CIRGenModule &cgm = cgf.getCIRGenModule();
// Clobbers
for (unsigned i = 0, e = s.getNumClobbers(); i != e; i++) {
std::string clobber = s.getClobber(i);
if (clobber == "memory") {
readOnly = readNone = false;
} else if (clobber == "unwind") {
hasUnwindClobber = true;
continue;
} else if (clobber != "cc") {
clobber = cgf.getTarget().getNormalizedGCCRegisterName(clobber);
if (cgm.getCodeGenOpts().StackClashProtector &&
cgf.getTarget().isSPRegName(clobber))
cgm.getDiags().Report(s.getAsmLoc(),
diag::warn_stack_clash_protection_inline_asm);
}
if (isa<MSAsmStmt>(&s)) {
if (clobber == "eax" || clobber == "edx") {
if (constraints.find("=&A") != std::string::npos)
continue;
std::string::size_type position1 =
constraints.find("={" + clobber + "}");
if (position1 != std::string::npos) {
constraints.insert(position1 + 1, "&");
continue;
}
std::string::size_type position2 = constraints.find("=A");
if (position2 != std::string::npos) {
constraints.insert(position2 + 1, "&");
continue;
}
}
}
if (!constraints.empty())
constraints += ',';
constraints += "~{";
constraints += clobber;
constraints += '}';
}
// Add machine specific clobbers
std::string_view machineClobbers = cgf.getTarget().getClobbers();
if (!machineClobbers.empty()) {
if (!constraints.empty())
constraints += ',';
constraints += machineClobbers;
}
}
mlir::LogicalResult CIRGenFunction::emitAsmStmt(const AsmStmt &s) {
// Assemble the final asm string.
std::string asmString = s.generateAsmString(getContext());
bool isGCCAsmGoto = false;
std::string constraints;
std::vector<mlir::Value> outArgs;
std::vector<mlir::Value> inArgs;
std::vector<mlir::Value> inOutArgs;
// An inline asm can be marked readonly if it meets the following conditions:
// - it doesn't have any sideeffects
// - it doesn't clobber memory
// - it doesn't return a value by-reference
// It can be marked readnone if it doesn't have any input memory constraints
// in addition to meeting the conditions listed above.
bool readOnly = true, readNone = true;
if (s.getNumInputs() != 0 || s.getNumOutputs() != 0) {
assert(!cir::MissingFeatures::asmInputOperands());
assert(!cir::MissingFeatures::asmOutputOperands());
cgm.errorNYI(s.getAsmLoc(), "asm with operands");
}
bool hasUnwindClobber = false;
collectClobbers(*this, s, constraints, hasUnwindClobber, readOnly, readNone);
std::array<mlir::ValueRange, 3> operands = {outArgs, inArgs, inOutArgs};
mlir::Type resultType;
bool hasSideEffect = s.isVolatile() || s.getNumOutputs() == 0;
cir::InlineAsmOp ia = builder.create<cir::InlineAsmOp>(
getLoc(s.getAsmLoc()), resultType, operands, asmString, constraints,
hasSideEffect, inferFlavor(cgm, s), mlir::ArrayAttr());
if (isGCCAsmGoto) {
assert(!cir::MissingFeatures::asmGoto());
} else if (hasUnwindClobber) {
assert(!cir::MissingFeatures::asmUnwindClobber());
} else {
assert(!cir::MissingFeatures::asmMemoryEffects());
}
llvm::SmallVector<mlir::Attribute> operandAttrs;
ia.setOperandAttrsAttr(builder.getArrayAttr(operandAttrs));
return mlir::success();
}