
- Part of #153267 https://github.com/llvm/clangir/blob/main/clang/lib/CIR/CodeGen/CIRAsm.cpp
137 lines
4.5 KiB
C++
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();
|
|
}
|