Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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 "clang/Basic/DiagnosticSema.h"
#include "llvm/ADT/StringExtras.h"

#include "CIRGenFunction.h"
#include "TargetInfo.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 clobberStr = s.getClobber(i);
StringRef clobber{clobberStr};
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.str() + "}");
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());

std::string constraints;

// 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);

llvm::SmallVector<mlir::ValueRange, 8> operands;
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 (false /*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
18 changes: 18 additions & 0 deletions clang/test/CIR/CodeGen/inline-asm.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// 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: {"" "~{dirflag},~{fpsr},~{flags}"}) side_effects
// LLVM: call void asm sideeffect "", "~{dirflag},~{fpsr},~{flags}"()
__asm__ volatile("" : : : );
}

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