Skip to content

Commit ef52e5c

Browse files
committed
[CIR] Implement codegen for inline assembly without input and output operands
1 parent ecea64a commit ef52e5c

File tree

6 files changed

+165
-2
lines changed

6 files changed

+165
-2
lines changed

clang/include/clang/CIR/MissingFeatures.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,12 @@ struct MissingFeatures {
179179
static bool aggValueSlotVolatile() { return false; }
180180
static bool alignCXXRecordDecl() { return false; }
181181
static bool armComputeVolatileBitfields() { return false; }
182+
static bool asmGoto() { return false; }
183+
static bool asmInputOperands() { return false; }
182184
static bool asmLabelAttr() { return false; }
185+
static bool asmMemoryEffects() { return false; }
186+
static bool asmOutputOperands() { return false; }
187+
static bool asmUnwindClobber() { return false; }
183188
static bool assignMemcpyizer() { return false; }
184189
static bool astVarDeclInterface() { return false; }
185190
static bool attributeBuiltin() { return false; }
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
//===--- CIRGenAsm.cpp - Inline Assembly Support for CIR CodeGen ---------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// This file contains code to emit inline assembly.
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#include "clang/Basic/DiagnosticSema.h"
14+
#include "llvm/ADT/StringExtras.h"
15+
16+
#include "CIRGenFunction.h"
17+
#include "TargetInfo.h"
18+
#include "clang/CIR/MissingFeatures.h"
19+
20+
using namespace clang;
21+
using namespace clang::CIRGen;
22+
using namespace cir;
23+
24+
static AsmFlavor inferFlavor(const CIRGenModule &cgm, const AsmStmt &s) {
25+
AsmFlavor gnuAsmFlavor =
26+
cgm.getCodeGenOpts().getInlineAsmDialect() == CodeGenOptions::IAD_ATT
27+
? AsmFlavor::x86_att
28+
: AsmFlavor::x86_intel;
29+
30+
return isa<MSAsmStmt>(&s) ? AsmFlavor::x86_intel : gnuAsmFlavor;
31+
}
32+
33+
static void collectClobbers(const CIRGenFunction &cgf, const AsmStmt &s,
34+
std::string &constraints, bool &hasUnwindClobber,
35+
bool &readOnly, bool readNone) {
36+
37+
hasUnwindClobber = false;
38+
const CIRGenModule &cgm = cgf.getCIRGenModule();
39+
40+
// Clobbers
41+
for (unsigned i = 0, e = s.getNumClobbers(); i != e; i++) {
42+
std::string clobberStr = s.getClobber(i);
43+
StringRef clobber{clobberStr};
44+
if (clobber == "memory")
45+
readOnly = readNone = false;
46+
else if (clobber == "unwind") {
47+
hasUnwindClobber = true;
48+
continue;
49+
} else if (clobber != "cc") {
50+
clobber = cgf.getTarget().getNormalizedGCCRegisterName(clobber);
51+
if (cgm.getCodeGenOpts().StackClashProtector &&
52+
cgf.getTarget().isSPRegName(clobber)) {
53+
cgm.getDiags().Report(s.getAsmLoc(),
54+
diag::warn_stack_clash_protection_inline_asm);
55+
}
56+
}
57+
58+
if (isa<MSAsmStmt>(&s)) {
59+
if (clobber == "eax" || clobber == "edx") {
60+
if (constraints.find("=&A") != std::string::npos)
61+
continue;
62+
std::string::size_type position1 =
63+
constraints.find("={" + clobber.str() + "}");
64+
if (position1 != std::string::npos) {
65+
constraints.insert(position1 + 1, "&");
66+
continue;
67+
}
68+
std::string::size_type position2 = constraints.find("=A");
69+
if (position2 != std::string::npos) {
70+
constraints.insert(position2 + 1, "&");
71+
continue;
72+
}
73+
}
74+
}
75+
if (!constraints.empty())
76+
constraints += ',';
77+
78+
constraints += "~{";
79+
constraints += clobber;
80+
constraints += '}';
81+
}
82+
83+
// Add machine specific clobbers
84+
std::string_view machineClobbers = cgf.getTarget().getClobbers();
85+
if (!machineClobbers.empty()) {
86+
if (!constraints.empty())
87+
constraints += ',';
88+
constraints += machineClobbers;
89+
}
90+
}
91+
92+
mlir::LogicalResult CIRGenFunction::emitAsmStmt(const AsmStmt &s) {
93+
// Assemble the final asm string.
94+
std::string asmString = s.generateAsmString(getContext());
95+
96+
std::string constraints;
97+
98+
// An inline asm can be marked readonly if it meets the following conditions:
99+
// - it doesn't have any sideeffects
100+
// - it doesn't clobber memory
101+
// - it doesn't return a value by-reference
102+
// It can be marked readnone if it doesn't have any input memory constraints
103+
// in addition to meeting the conditions listed above.
104+
bool readOnly = true, readNone = true;
105+
106+
if (s.getNumInputs() != 0 || s.getNumOutputs() != 0) {
107+
assert(!cir::MissingFeatures::asmInputOperands());
108+
assert(!cir::MissingFeatures::asmOutputOperands());
109+
cgm.errorNYI(s.getAsmLoc(), "asm with operands");
110+
}
111+
112+
bool hasUnwindClobber = false;
113+
collectClobbers(*this, s, constraints, hasUnwindClobber, readOnly, readNone);
114+
115+
llvm::SmallVector<mlir::ValueRange, 8> operands;
116+
mlir::Type resultType;
117+
118+
bool hasSideEffect = s.isVolatile() || s.getNumOutputs() == 0;
119+
120+
cir::InlineAsmOp ia = builder.create<cir::InlineAsmOp>(
121+
getLoc(s.getAsmLoc()), resultType, operands, asmString, constraints,
122+
hasSideEffect, inferFlavor(cgm, s), mlir::ArrayAttr());
123+
124+
if (false /*IsGCCAsmGoto*/) {
125+
assert(!cir::MissingFeatures::asmGoto());
126+
} else if (hasUnwindClobber) {
127+
assert(!cir::MissingFeatures::asmUnwindClobber());
128+
} else {
129+
assert(!cir::MissingFeatures::asmMemoryEffects());
130+
}
131+
132+
llvm::SmallVector<mlir::Attribute> operandAttrs;
133+
ia.setOperandAttrsAttr(builder.getArrayAttr(operandAttrs));
134+
135+
return mlir::success();
136+
}

clang/lib/CIR/CodeGen/CIRGenFunction.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -926,6 +926,8 @@ class CIRGenFunction : public CIRGenTypeCache {
926926

927927
Address emitArrayToPointerDecay(const Expr *array);
928928

929+
mlir::LogicalResult emitAsmStmt(const clang::AsmStmt &s);
930+
929931
RValue emitAtomicExpr(AtomicExpr *e);
930932
void emitAtomicInit(Expr *init, LValue dest);
931933

clang/lib/CIR/CodeGen/CIRGenStmt.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,9 @@ mlir::LogicalResult CIRGenFunction::emitStmt(const Stmt *s,
130130
return emitOpenACCCacheConstruct(cast<OpenACCCacheConstruct>(*s));
131131
case Stmt::OpenACCAtomicConstructClass:
132132
return emitOpenACCAtomicConstruct(cast<OpenACCAtomicConstruct>(*s));
133+
case Stmt::GCCAsmStmtClass:
134+
case Stmt::MSAsmStmtClass:
135+
return emitAsmStmt(cast<AsmStmt>(*s));
133136
case Stmt::OMPScopeDirectiveClass:
134137
case Stmt::OMPErrorDirectiveClass:
135138
case Stmt::LabelStmtClass:
@@ -143,8 +146,6 @@ mlir::LogicalResult CIRGenFunction::emitStmt(const Stmt *s,
143146
case Stmt::CoreturnStmtClass:
144147
case Stmt::CXXTryStmtClass:
145148
case Stmt::IndirectGotoStmtClass:
146-
case Stmt::GCCAsmStmtClass:
147-
case Stmt::MSAsmStmtClass:
148149
case Stmt::OMPParallelDirectiveClass:
149150
case Stmt::OMPTaskwaitDirectiveClass:
150151
case Stmt::OMPTaskyieldDirectiveClass:

clang/lib/CIR/CodeGen/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ get_property(dialect_libs GLOBAL PROPERTY MLIR_DIALECT_LIBS)
88

99
add_clang_library(clangCIR
1010
CIRGenerator.cpp
11+
CIRGenAsm.cpp
1112
CIRGenAtomic.cpp
1213
CIRGenBuilder.cpp
1314
CIRGenCall.cpp
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-cir %s -o %t.cir
2+
// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR
3+
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t-cir.ll
4+
// RUN: FileCheck --input-file=%t-cir.ll %s --check-prefix=LLVM
5+
6+
void f1() {
7+
// CIR: cir.asm(x86_att,
8+
// CIR: {"" "~{dirflag},~{fpsr},~{flags}"}) side_effects
9+
// LLVM: call void asm sideeffect "", "~{dirflag},~{fpsr},~{flags}"()
10+
__asm__ volatile("" : : : );
11+
}
12+
13+
void f2() {
14+
// CIR: cir.asm(x86_att,
15+
// CIR: {"nop" "~{dirflag},~{fpsr},~{flags}"}) side_effects
16+
// LLVM: call void asm sideeffect "nop", "~{dirflag},~{fpsr},~{flags}"()
17+
__asm__ volatile("nop" : : : );
18+
}

0 commit comments

Comments
 (0)