Skip to content

Commit cc68e45

Browse files
authored
[CIR] Implement codegen for inline assembly without input and output operands (#153546)
- Part of #153267 https://github.com/llvm/clangir/blob/main/clang/lib/CIR/CodeGen/CIRAsm.cpp
1 parent be3fd6a commit cc68e45

File tree

7 files changed

+172
-2
lines changed

7 files changed

+172
-2
lines changed

clang/include/clang/CIR/MissingFeatures.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,12 @@ struct MissingFeatures {
175175
static bool aggValueSlotVolatile() { return false; }
176176
static bool alignCXXRecordDecl() { return false; }
177177
static bool armComputeVolatileBitfields() { return false; }
178+
static bool asmGoto() { return false; }
179+
static bool asmInputOperands() { return false; }
178180
static bool asmLabelAttr() { return false; }
181+
static bool asmMemoryEffects() { return false; }
182+
static bool asmOutputOperands() { return false; }
183+
static bool asmUnwindClobber() { return false; }
179184
static bool assignMemcpyizer() { return false; }
180185
static bool astVarDeclInterface() { return false; }
181186
static bool attributeBuiltin() { return false; }

clang/lib/CIR/CodeGen/CIRGenAsm.cpp

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 "CIRGenFunction.h"
14+
#include "clang/CIR/MissingFeatures.h"
15+
16+
using namespace clang;
17+
using namespace clang::CIRGen;
18+
using namespace cir;
19+
20+
static AsmFlavor inferFlavor(const CIRGenModule &cgm, const AsmStmt &s) {
21+
AsmFlavor gnuAsmFlavor =
22+
cgm.getCodeGenOpts().getInlineAsmDialect() == CodeGenOptions::IAD_ATT
23+
? AsmFlavor::x86_att
24+
: AsmFlavor::x86_intel;
25+
26+
return isa<MSAsmStmt>(&s) ? AsmFlavor::x86_intel : gnuAsmFlavor;
27+
}
28+
29+
static void collectClobbers(const CIRGenFunction &cgf, const AsmStmt &s,
30+
std::string &constraints, bool &hasUnwindClobber,
31+
bool &readOnly, bool readNone) {
32+
33+
hasUnwindClobber = false;
34+
const CIRGenModule &cgm = cgf.getCIRGenModule();
35+
36+
// Clobbers
37+
for (unsigned i = 0, e = s.getNumClobbers(); i != e; i++) {
38+
std::string clobber = s.getClobber(i);
39+
if (clobber == "memory") {
40+
readOnly = readNone = false;
41+
} else if (clobber == "unwind") {
42+
hasUnwindClobber = true;
43+
continue;
44+
} else if (clobber != "cc") {
45+
clobber = cgf.getTarget().getNormalizedGCCRegisterName(clobber);
46+
if (cgm.getCodeGenOpts().StackClashProtector &&
47+
cgf.getTarget().isSPRegName(clobber))
48+
cgm.getDiags().Report(s.getAsmLoc(),
49+
diag::warn_stack_clash_protection_inline_asm);
50+
}
51+
52+
if (isa<MSAsmStmt>(&s)) {
53+
if (clobber == "eax" || clobber == "edx") {
54+
if (constraints.find("=&A") != std::string::npos)
55+
continue;
56+
std::string::size_type position1 =
57+
constraints.find("={" + clobber + "}");
58+
if (position1 != std::string::npos) {
59+
constraints.insert(position1 + 1, "&");
60+
continue;
61+
}
62+
std::string::size_type position2 = constraints.find("=A");
63+
if (position2 != std::string::npos) {
64+
constraints.insert(position2 + 1, "&");
65+
continue;
66+
}
67+
}
68+
}
69+
if (!constraints.empty())
70+
constraints += ',';
71+
72+
constraints += "~{";
73+
constraints += clobber;
74+
constraints += '}';
75+
}
76+
77+
// Add machine specific clobbers
78+
std::string_view machineClobbers = cgf.getTarget().getClobbers();
79+
if (!machineClobbers.empty()) {
80+
if (!constraints.empty())
81+
constraints += ',';
82+
constraints += machineClobbers;
83+
}
84+
}
85+
86+
mlir::LogicalResult CIRGenFunction::emitAsmStmt(const AsmStmt &s) {
87+
// Assemble the final asm string.
88+
std::string asmString = s.generateAsmString(getContext());
89+
90+
bool isGCCAsmGoto = false;
91+
92+
std::string constraints;
93+
std::vector<mlir::Value> outArgs;
94+
std::vector<mlir::Value> inArgs;
95+
std::vector<mlir::Value> inOutArgs;
96+
97+
// An inline asm can be marked readonly if it meets the following conditions:
98+
// - it doesn't have any sideeffects
99+
// - it doesn't clobber memory
100+
// - it doesn't return a value by-reference
101+
// It can be marked readnone if it doesn't have any input memory constraints
102+
// in addition to meeting the conditions listed above.
103+
bool readOnly = true, readNone = true;
104+
105+
if (s.getNumInputs() != 0 || s.getNumOutputs() != 0) {
106+
assert(!cir::MissingFeatures::asmInputOperands());
107+
assert(!cir::MissingFeatures::asmOutputOperands());
108+
cgm.errorNYI(s.getAsmLoc(), "asm with operands");
109+
}
110+
111+
bool hasUnwindClobber = false;
112+
collectClobbers(*this, s, constraints, hasUnwindClobber, readOnly, readNone);
113+
114+
std::array<mlir::ValueRange, 3> operands = {outArgs, inArgs, inOutArgs};
115+
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 (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
@@ -954,6 +954,8 @@ class CIRGenFunction : public CIRGenTypeCache {
954954

955955
Address emitArrayToPointerDecay(const Expr *array);
956956

957+
mlir::LogicalResult emitAsmStmt(const clang::AsmStmt &s);
958+
957959
RValue emitAtomicExpr(AtomicExpr *e);
958960
void emitAtomicInit(Expr *init, LValue dest);
959961

clang/lib/CIR/CodeGen/CIRGenModule.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ class CIRGenModule : public CIRGenTypeCache {
102102
clang::ASTContext &getASTContext() const { return astContext; }
103103
const clang::TargetInfo &getTarget() const { return target; }
104104
const clang::CodeGenOptions &getCodeGenOpts() const { return codeGenOpts; }
105+
clang::DiagnosticsEngine &getDiags() const { return diags; }
105106
CIRGenTypes &getTypes() { return genTypes; }
106107
const clang::LangOptions &getLangOpts() const { return langOpts; }
107108

clang/lib/CIR/CodeGen/CIRGenStmt.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,9 @@ mlir::LogicalResult CIRGenFunction::emitStmt(const Stmt *s,
132132
return emitOpenACCCacheConstruct(cast<OpenACCCacheConstruct>(*s));
133133
case Stmt::OpenACCAtomicConstructClass:
134134
return emitOpenACCAtomicConstruct(cast<OpenACCAtomicConstruct>(*s));
135+
case Stmt::GCCAsmStmtClass:
136+
case Stmt::MSAsmStmtClass:
137+
return emitAsmStmt(cast<AsmStmt>(*s));
135138
case Stmt::OMPScopeDirectiveClass:
136139
case Stmt::OMPErrorDirectiveClass:
137140
case Stmt::LabelStmtClass:
@@ -145,8 +148,6 @@ mlir::LogicalResult CIRGenFunction::emitStmt(const Stmt *s,
145148
case Stmt::CoreturnStmtClass:
146149
case Stmt::CXXTryStmtClass:
147150
case Stmt::IndirectGotoStmtClass:
148-
case Stmt::GCCAsmStmtClass:
149-
case Stmt::MSAsmStmtClass:
150151
case Stmt::OMPParallelDirectiveClass:
151152
case Stmt::OMPTaskwaitDirectiveClass:
152153
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

clang/test/CIR/CodeGen/inline-asm.c

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
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: out = [],
9+
// CIR: in = [],
10+
// CIR: in_out = [],
11+
// CIR: {"" "~{dirflag},~{fpsr},~{flags}"}) side_effects
12+
// LLVM: call void asm sideeffect "", "~{dirflag},~{fpsr},~{flags}"()
13+
__asm__ volatile("" : : : );
14+
}
15+
16+
void f2() {
17+
// CIR: cir.asm(x86_att,
18+
// CIR: out = [],
19+
// CIR: in = [],
20+
// CIR: in_out = [],
21+
// CIR: {"nop" "~{dirflag},~{fpsr},~{flags}"}) side_effects
22+
// LLVM: call void asm sideeffect "nop", "~{dirflag},~{fpsr},~{flags}"()
23+
__asm__ volatile("nop" : : : );
24+
}

0 commit comments

Comments
 (0)