clang 22.0.0git
CIRGenAsm.cpp
Go to the documentation of this file.
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"
15
16using namespace clang;
17using namespace clang::CIRGen;
18using namespace cir;
19
20static 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
29static 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
86mlir::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) {
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) {
126 } else if (hasUnwindClobber) {
128 } else {
130 }
131
133 ia.setOperandAttrsAttr(builder.getArrayAttr(operandAttrs));
134
135 return mlir::success();
136}
static AsmFlavor inferFlavor(const CIRGenModule &cgm, const AsmStmt &s)
Definition: CIRGenAsm.cpp:20
static void collectClobbers(const CIRGenFunction &cgf, const AsmStmt &s, std::string &constraints, bool &hasUnwindClobber, bool &readOnly, bool readNone)
Definition: CIRGenAsm.cpp:29
__device__ __2f16 float __ockl_bool s
AsmStmt is the base class for GCCAsmStmt and MSAsmStmt.
Definition: Stmt.h:3205
const TargetInfo & getTarget() const
mlir::Location getLoc(clang::SourceLocation srcLoc)
Helpers to convert Clang's SourceLocation to a MLIR Location.
mlir::LogicalResult emitAsmStmt(const clang::AsmStmt &s)
Definition: CIRGenAsm.cpp:86
CIRGenModule & getCIRGenModule()
clang::ASTContext & getContext() const
This class organizes the cross-function state that is used while generating CIR code.
Definition: CIRGenModule.h:56
DiagnosticBuilder errorNYI(SourceLocation, llvm::StringRef)
Helpers to emit "not yet implemented" error diagnostics.
clang::DiagnosticsEngine & getDiags() const
Definition: CIRGenModule.h:105
const clang::CodeGenOptions & getCodeGenOpts() const
Definition: CIRGenModule.h:104
DiagnosticBuilder Report(SourceLocation Loc, unsigned DiagID)
Issue the message to the client.
Definition: Diagnostic.h:1529
StringRef getNormalizedGCCRegisterName(StringRef Name, bool ReturnCanonical=false) const
Returns the "normalized" GCC register name.
Definition: TargetInfo.cpp:713
virtual std::string_view getClobbers() const =0
Returns a string of target-specific clobbers, in LLVM format.
virtual bool isSPRegName(StringRef) const
Definition: TargetInfo.h:1107
Definition: ABIArgInfo.h:22
The JSON file list parser is used to communicate input to InstallAPI.
static bool asmMemoryEffects()
static bool asmOutputOperands()
static bool asmInputOperands()
static bool asmUnwindClobber()