Skip to content

Commit 85614e1

Browse files
authored
[CIR] Upstream initial function call support (#134673)
This patch upstreams initial support for making function calls in CIR. Function arguments and return values are not included to keep the patch small for review. Related to #132487
1 parent 4b267bb commit 85614e1

File tree

18 files changed

+580
-1
lines changed

18 files changed

+580
-1
lines changed

clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,19 @@ class CIRBaseBuilderTy : public mlir::OpBuilder {
201201
return create<cir::PtrStrideOp>(loc, base.getType(), base, stride);
202202
}
203203

204+
//===--------------------------------------------------------------------===//
205+
// Call operators
206+
//===--------------------------------------------------------------------===//
207+
208+
cir::CallOp createCallOp(mlir::Location loc, mlir::SymbolRefAttr callee) {
209+
auto op = create<cir::CallOp>(loc, callee);
210+
return op;
211+
}
212+
213+
cir::CallOp createCallOp(mlir::Location loc, cir::FuncOp callee) {
214+
return createCallOp(loc, mlir::SymbolRefAttr::get(callee));
215+
}
216+
204217
//===--------------------------------------------------------------------===//
205218
// Cast/Conversion Operators
206219
//===--------------------------------------------------------------------===//

clang/include/clang/CIR/Dialect/IR/CIROps.td

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1342,6 +1342,48 @@ def FuncOp : CIR_Op<"func", [
13421342
let hasVerifier = 1;
13431343
}
13441344

1345+
//===----------------------------------------------------------------------===//
1346+
// CallOp
1347+
//===----------------------------------------------------------------------===//
1348+
1349+
class CIR_CallOpBase<string mnemonic, list<Trait> extra_traits = []>
1350+
: Op<CIR_Dialect, mnemonic,
1351+
!listconcat(extra_traits,
1352+
[DeclareOpInterfaceMethods<CIRCallOpInterface>,
1353+
DeclareOpInterfaceMethods<SymbolUserOpInterface>])> {
1354+
let hasCustomAssemblyFormat = 1;
1355+
let skipDefaultBuilders = 1;
1356+
let hasVerifier = 0;
1357+
1358+
// TODO(cir): for now cir.call is just a tiny shell of what it will become.
1359+
// More attributes, arguments, and properties will be added in the future as
1360+
// the upstreaming process moves on. The verifiers is also missing for now,
1361+
// will add in the future.
1362+
1363+
dag commonArgs = (ins FlatSymbolRefAttr:$callee);
1364+
}
1365+
1366+
def CallOp : CIR_CallOpBase<"call", [NoRegionArguments]> {
1367+
let summary = "call a function";
1368+
let description = [{
1369+
The `cir.call` operation represents a direct call to a function that is
1370+
within the same symbol scope as the call. The callee is encoded as a symbol
1371+
reference attribute named `callee`.
1372+
1373+
Example:
1374+
1375+
```mlir
1376+
%0 = cir.call @foo()
1377+
```
1378+
}];
1379+
1380+
let arguments = commonArgs;
1381+
1382+
let builders = [OpBuilder<(ins "mlir::SymbolRefAttr":$callee), [{
1383+
$_state.addAttribute("callee", callee);
1384+
}]>];
1385+
}
1386+
13451387
//===----------------------------------------------------------------------===//
13461388
// UnreachableOp
13471389
//===----------------------------------------------------------------------===//

clang/include/clang/CIR/Interfaces/CIROpInterfaces.td

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,17 @@
1515

1616
include "mlir/IR/OpBase.td"
1717
include "mlir/IR/SymbolInterfaces.td"
18+
include "mlir/Interfaces/CallInterfaces.td"
1819

1920
let cppNamespace = "::cir" in {
21+
// The CIRCallOpInterface must be used instead of CallOpInterface when looking
22+
// at arguments and other bits of CallOp. This creates a level of abstraction
23+
// that's useful for handling indirect calls and other details.
24+
def CIRCallOpInterface : OpInterface<"CIRCallOpInterface", []> {
25+
// Currently we don't have any methods defined in CIRCallOpInterface. We'll
26+
// add more methods as the upstreaming proceeds.
27+
}
28+
2029
def CIRGlobalValueInterface
2130
: OpInterface<"CIRGlobalValueInterface", [Symbol]> {
2231

clang/include/clang/CIR/MissingFeatures.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,24 @@ struct MissingFeatures {
7272
static bool opFuncLinkage() { return false; }
7373
static bool opFuncVisibility() { return false; }
7474

75+
// CallOp handling
76+
static bool opCallBuiltinFunc() { return false; }
77+
static bool opCallPseudoDtor() { return false; }
78+
static bool opCallArgs() { return false; }
79+
static bool opCallReturn() { return false; }
80+
static bool opCallArgEvaluationOrder() { return false; }
81+
static bool opCallCallConv() { return false; }
82+
static bool opCallSideEffect() { return false; }
83+
static bool opCallChainCall() { return false; }
84+
static bool opCallNoPrototypeFunc() { return false; }
85+
static bool opCallMustTail() { return false; }
86+
static bool opCallIndirect() { return false; }
87+
static bool opCallVirtual() { return false; }
88+
static bool opCallInAlloca() { return false; }
89+
static bool opCallAttrs() { return false; }
90+
static bool opCallSurroundingTry() { return false; }
91+
static bool opCallASTAttr() { return false; }
92+
7593
// ScopeOp handling
7694
static bool opScopeCleanupRegion() { return false; }
7795

@@ -90,7 +108,10 @@ struct MissingFeatures {
90108
static bool lowerModeOptLevel() { return false; }
91109
static bool opTBAA() { return false; }
92110
static bool objCLifetime() { return false; }
111+
static bool objCBlocks() { return false; }
93112
static bool emitNullabilityCheck() { return false; }
113+
static bool emitLValueAlignmentAssumption() { return false; }
114+
static bool emitLifetimeMarkers() { return false; }
94115
static bool astVarDeclInterface() { return false; }
95116
static bool stackSaveOp() { return false; }
96117
static bool aggValueSlot() { return false; }
@@ -113,6 +134,8 @@ struct MissingFeatures {
113134
static bool incrementProfileCounter() { return false; }
114135
static bool insertBuiltinUnpredictable() { return false; }
115136
static bool objCGC() { return false; }
137+
static bool weakRefReference() { return false; }
138+
static bool hip() { return false; }
116139

117140
// Missing types
118141
static bool dataMemberType() { return false; }
@@ -132,6 +155,7 @@ struct MissingFeatures {
132155
static bool complexImagOp() { return false; }
133156
static bool complexRealOp() { return false; }
134157
static bool ifOp() { return false; }
158+
static bool invokeOp() { return false; }
135159
static bool labelOp() { return false; }
136160
static bool ptrDiffOp() { return false; }
137161
static bool ptrStrideOp() { return false; }

clang/lib/CIR/CodeGen/CIRGenCall.cpp

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
//===--- CIRGenCall.cpp - Encapsulate calling convention details ----------===//
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+
// These classes wrap the information about a call or function definition used
10+
// to handle ABI compliancy.
11+
//
12+
//===----------------------------------------------------------------------===//
13+
14+
#include "CIRGenCall.h"
15+
#include "CIRGenFunction.h"
16+
#include "clang/CIR/MissingFeatures.h"
17+
18+
using namespace clang;
19+
using namespace clang::CIRGen;
20+
21+
CIRGenFunctionInfo *CIRGenFunctionInfo::create() {
22+
// For now we just create an empty CIRGenFunctionInfo.
23+
CIRGenFunctionInfo *fi = new CIRGenFunctionInfo();
24+
return fi;
25+
}
26+
27+
CIRGenCallee CIRGenCallee::prepareConcreteCallee(CIRGenFunction &cgf) const {
28+
assert(!cir::MissingFeatures::opCallVirtual());
29+
return *this;
30+
}
31+
32+
static const CIRGenFunctionInfo &arrangeFreeFunctionLikeCall(CIRGenTypes &cgt) {
33+
assert(!cir::MissingFeatures::opCallArgs());
34+
return cgt.arrangeCIRFunctionInfo();
35+
}
36+
37+
const CIRGenFunctionInfo &CIRGenTypes::arrangeFreeFunctionCall() {
38+
return arrangeFreeFunctionLikeCall(*this);
39+
}
40+
41+
static cir::CIRCallOpInterface emitCallLikeOp(CIRGenFunction &cgf,
42+
mlir::Location callLoc,
43+
cir::FuncOp directFuncOp) {
44+
CIRGenBuilderTy &builder = cgf.getBuilder();
45+
46+
assert(!cir::MissingFeatures::opCallSurroundingTry());
47+
assert(!cir::MissingFeatures::invokeOp());
48+
49+
assert(builder.getInsertionBlock() && "expected valid basic block");
50+
assert(!cir::MissingFeatures::opCallIndirect());
51+
52+
return builder.createCallOp(callLoc, directFuncOp);
53+
}
54+
55+
RValue CIRGenFunction::emitCall(const CIRGenFunctionInfo &funcInfo,
56+
const CIRGenCallee &callee,
57+
cir::CIRCallOpInterface *callOp,
58+
mlir::Location loc) {
59+
assert(!cir::MissingFeatures::opCallArgs());
60+
assert(!cir::MissingFeatures::emitLifetimeMarkers());
61+
62+
const CIRGenCallee &concreteCallee = callee.prepareConcreteCallee(*this);
63+
mlir::Operation *calleePtr = concreteCallee.getFunctionPointer();
64+
65+
assert(!cir::MissingFeatures::opCallInAlloca());
66+
67+
mlir::NamedAttrList attrs;
68+
StringRef funcName;
69+
if (auto calleeFuncOp = dyn_cast<cir::FuncOp>(calleePtr))
70+
funcName = calleeFuncOp.getName();
71+
72+
assert(!cir::MissingFeatures::opCallCallConv());
73+
assert(!cir::MissingFeatures::opCallSideEffect());
74+
assert(!cir::MissingFeatures::opCallAttrs());
75+
76+
assert(!cir::MissingFeatures::invokeOp());
77+
78+
auto directFuncOp = dyn_cast<cir::FuncOp>(calleePtr);
79+
assert(!cir::MissingFeatures::opCallIndirect());
80+
assert(!cir::MissingFeatures::opCallAttrs());
81+
82+
cir::CIRCallOpInterface theCall = emitCallLikeOp(*this, loc, directFuncOp);
83+
84+
if (callOp)
85+
*callOp = theCall;
86+
87+
assert(!cir::MissingFeatures::opCallMustTail());
88+
assert(!cir::MissingFeatures::opCallReturn());
89+
90+
// For now we just return nothing because we don't have support for return
91+
// values yet.
92+
RValue ret = RValue::get(nullptr);
93+
94+
return ret;
95+
}

clang/lib/CIR/CodeGen/CIRGenCall.h

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,73 @@
1414
#ifndef CLANG_LIB_CODEGEN_CIRGENCALL_H
1515
#define CLANG_LIB_CODEGEN_CIRGENCALL_H
1616

17+
#include "mlir/IR/Operation.h"
1718
#include "clang/AST/GlobalDecl.h"
1819
#include "llvm/ADT/SmallVector.h"
1920

2021
namespace clang::CIRGen {
2122

23+
class CIRGenFunction;
24+
25+
/// Abstract information about a function or function prototype.
26+
class CIRGenCalleeInfo {
27+
clang::GlobalDecl calleeDecl;
28+
29+
public:
30+
explicit CIRGenCalleeInfo() : calleeDecl() {}
31+
CIRGenCalleeInfo(clang::GlobalDecl calleeDecl) : calleeDecl(calleeDecl) {}
32+
};
33+
34+
class CIRGenCallee {
35+
enum class SpecialKind : uintptr_t {
36+
Invalid,
37+
38+
Last = Invalid,
39+
};
40+
41+
SpecialKind kindOrFunctionPtr;
42+
43+
union {
44+
CIRGenCalleeInfo abstractInfo;
45+
};
46+
47+
public:
48+
CIRGenCallee() : kindOrFunctionPtr(SpecialKind::Invalid) {}
49+
50+
CIRGenCallee(const CIRGenCalleeInfo &abstractInfo, mlir::Operation *funcPtr)
51+
: kindOrFunctionPtr(SpecialKind(reinterpret_cast<uintptr_t>(funcPtr))),
52+
abstractInfo(abstractInfo) {
53+
assert(funcPtr && "configuring callee without function pointer");
54+
}
55+
56+
static CIRGenCallee
57+
forDirect(mlir::Operation *funcPtr,
58+
const CIRGenCalleeInfo &abstractInfo = CIRGenCalleeInfo()) {
59+
return CIRGenCallee(abstractInfo, funcPtr);
60+
}
61+
62+
bool isOrdinary() const {
63+
return uintptr_t(kindOrFunctionPtr) > uintptr_t(SpecialKind::Last);
64+
}
65+
66+
/// If this is a delayed callee computation of some sort, prepare a concrete
67+
/// callee
68+
CIRGenCallee prepareConcreteCallee(CIRGenFunction &cgf) const;
69+
70+
mlir::Operation *getFunctionPointer() const {
71+
assert(isOrdinary());
72+
return reinterpret_cast<mlir::Operation *>(kindOrFunctionPtr);
73+
}
74+
};
75+
2276
/// Type for representing both the decl and type of parameters to a function.
2377
/// The decl must be either a ParmVarDecl or ImplicitParamDecl.
2478
class FunctionArgList : public llvm::SmallVector<const clang::VarDecl *, 16> {};
2579

80+
struct CallArg {};
81+
82+
class CallArgList : public llvm::SmallVector<CallArg, 8> {};
83+
2684
} // namespace clang::CIRGen
2785

2886
#endif // CLANG_LIB_CODEGEN_CIRGENCALL_H

0 commit comments

Comments
 (0)