Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions clang/include/clang/CIR/MissingFeatures.h
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,12 @@ struct MissingFeatures {
static bool aggValueSlotVolatile() { return false; }
static bool alignCXXRecordDecl() { return false; }
static bool armComputeVolatileBitfields() { return false; }
static bool asmGoto() { return false; }
static bool asmInputOperands() { return false; }
static bool asmLabelAttr() { return false; }
static bool asmMemoryEffects() { return false; }
static bool asmOutputOperands() { return false; }
static bool asmUnwindClobber() { return false; }
static bool assignMemcpyizer() { return false; }
static bool astVarDeclInterface() { return false; }
static bool attributeBuiltin() { return false; }
Expand Down
136 changes: 136 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenAsm.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
//===--- 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();
}
2 changes: 2 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -942,6 +942,8 @@ class CIRGenFunction : public CIRGenTypeCache {

Address emitArrayToPointerDecay(const Expr *array);

mlir::LogicalResult emitAsmStmt(const clang::AsmStmt &s);

RValue emitAtomicExpr(AtomicExpr *e);
void emitAtomicInit(Expr *init, LValue dest);

Expand Down
1 change: 1 addition & 0 deletions clang/lib/CIR/CodeGen/CIRGenModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ class CIRGenModule : public CIRGenTypeCache {
clang::ASTContext &getASTContext() const { return astContext; }
const clang::TargetInfo &getTarget() const { return target; }
const clang::CodeGenOptions &getCodeGenOpts() const { return codeGenOpts; }
clang::DiagnosticsEngine &getDiags() const { return diags; }
CIRGenTypes &getTypes() { return genTypes; }
const clang::LangOptions &getLangOpts() const { return langOpts; }

Expand Down
5 changes: 3 additions & 2 deletions clang/lib/CIR/CodeGen/CIRGenStmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,9 @@ mlir::LogicalResult CIRGenFunction::emitStmt(const Stmt *s,
return emitOpenACCCacheConstruct(cast<OpenACCCacheConstruct>(*s));
case Stmt::OpenACCAtomicConstructClass:
return emitOpenACCAtomicConstruct(cast<OpenACCAtomicConstruct>(*s));
case Stmt::GCCAsmStmtClass:
case Stmt::MSAsmStmtClass:
return emitAsmStmt(cast<AsmStmt>(*s));
case Stmt::OMPScopeDirectiveClass:
case Stmt::OMPErrorDirectiveClass:
case Stmt::LabelStmtClass:
Expand All @@ -145,8 +148,6 @@ mlir::LogicalResult CIRGenFunction::emitStmt(const Stmt *s,
case Stmt::CoreturnStmtClass:
case Stmt::CXXTryStmtClass:
case Stmt::IndirectGotoStmtClass:
case Stmt::GCCAsmStmtClass:
case Stmt::MSAsmStmtClass:
case Stmt::OMPParallelDirectiveClass:
case Stmt::OMPTaskwaitDirectiveClass:
case Stmt::OMPTaskyieldDirectiveClass:
Expand Down
1 change: 1 addition & 0 deletions clang/lib/CIR/CodeGen/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ get_property(dialect_libs GLOBAL PROPERTY MLIR_DIALECT_LIBS)

add_clang_library(clangCIR
CIRGenerator.cpp
CIRGenAsm.cpp
CIRGenAtomic.cpp
CIRGenBuilder.cpp
CIRGenCall.cpp
Expand Down
24 changes: 24 additions & 0 deletions clang/test/CIR/CodeGen/inline-asm.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-cir %s -o %t.cir
// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t-cir.ll
// RUN: FileCheck --input-file=%t-cir.ll %s --check-prefix=LLVM

void f1() {
// CIR: cir.asm(x86_att,
// CIR: out = [],
// CIR: in = [],
// CIR: in_out = [],
// CIR: {"" "~{dirflag},~{fpsr},~{flags}"}) side_effects
// LLVM: call void asm sideeffect "", "~{dirflag},~{fpsr},~{flags}"()
__asm__ volatile("" : : : );
}

void f2() {
// CIR: cir.asm(x86_att,
// CIR: out = [],
// CIR: in = [],
// CIR: in_out = [],
// CIR: {"nop" "~{dirflag},~{fpsr},~{flags}"}) side_effects
// LLVM: call void asm sideeffect "nop", "~{dirflag},~{fpsr},~{flags}"()
__asm__ volatile("nop" : : : );
}