mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-21 12:56:52 +00:00
[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
This commit is contained in:
parent
4b267bb7c2
commit
85614e160b
clang
include/clang/CIR
lib/CIR
CodeGen
CIRGenCall.cppCIRGenCall.hCIRGenExpr.cppCIRGenExprScalar.cppCIRGenFunction.hCIRGenFunctionInfo.hCIRGenModule.cppCIRGenModule.hCIRGenTypes.cppCIRGenTypes.hCMakeLists.txt
Dialect/IR
test/CIR
@ -201,6 +201,19 @@ public:
|
||||
return create<cir::PtrStrideOp>(loc, base.getType(), base, stride);
|
||||
}
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Call operators
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
cir::CallOp createCallOp(mlir::Location loc, mlir::SymbolRefAttr callee) {
|
||||
auto op = create<cir::CallOp>(loc, callee);
|
||||
return op;
|
||||
}
|
||||
|
||||
cir::CallOp createCallOp(mlir::Location loc, cir::FuncOp callee) {
|
||||
return createCallOp(loc, mlir::SymbolRefAttr::get(callee));
|
||||
}
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Cast/Conversion Operators
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
@ -1342,6 +1342,48 @@ def FuncOp : CIR_Op<"func", [
|
||||
let hasVerifier = 1;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// CallOp
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
class CIR_CallOpBase<string mnemonic, list<Trait> extra_traits = []>
|
||||
: Op<CIR_Dialect, mnemonic,
|
||||
!listconcat(extra_traits,
|
||||
[DeclareOpInterfaceMethods<CIRCallOpInterface>,
|
||||
DeclareOpInterfaceMethods<SymbolUserOpInterface>])> {
|
||||
let hasCustomAssemblyFormat = 1;
|
||||
let skipDefaultBuilders = 1;
|
||||
let hasVerifier = 0;
|
||||
|
||||
// TODO(cir): for now cir.call is just a tiny shell of what it will become.
|
||||
// More attributes, arguments, and properties will be added in the future as
|
||||
// the upstreaming process moves on. The verifiers is also missing for now,
|
||||
// will add in the future.
|
||||
|
||||
dag commonArgs = (ins FlatSymbolRefAttr:$callee);
|
||||
}
|
||||
|
||||
def CallOp : CIR_CallOpBase<"call", [NoRegionArguments]> {
|
||||
let summary = "call a function";
|
||||
let description = [{
|
||||
The `cir.call` operation represents a direct call to a function that is
|
||||
within the same symbol scope as the call. The callee is encoded as a symbol
|
||||
reference attribute named `callee`.
|
||||
|
||||
Example:
|
||||
|
||||
```mlir
|
||||
%0 = cir.call @foo()
|
||||
```
|
||||
}];
|
||||
|
||||
let arguments = commonArgs;
|
||||
|
||||
let builders = [OpBuilder<(ins "mlir::SymbolRefAttr":$callee), [{
|
||||
$_state.addAttribute("callee", callee);
|
||||
}]>];
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// UnreachableOp
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -15,8 +15,17 @@
|
||||
|
||||
include "mlir/IR/OpBase.td"
|
||||
include "mlir/IR/SymbolInterfaces.td"
|
||||
include "mlir/Interfaces/CallInterfaces.td"
|
||||
|
||||
let cppNamespace = "::cir" in {
|
||||
// The CIRCallOpInterface must be used instead of CallOpInterface when looking
|
||||
// at arguments and other bits of CallOp. This creates a level of abstraction
|
||||
// that's useful for handling indirect calls and other details.
|
||||
def CIRCallOpInterface : OpInterface<"CIRCallOpInterface", []> {
|
||||
// Currently we don't have any methods defined in CIRCallOpInterface. We'll
|
||||
// add more methods as the upstreaming proceeds.
|
||||
}
|
||||
|
||||
def CIRGlobalValueInterface
|
||||
: OpInterface<"CIRGlobalValueInterface", [Symbol]> {
|
||||
|
||||
|
@ -72,6 +72,24 @@ struct MissingFeatures {
|
||||
static bool opFuncLinkage() { return false; }
|
||||
static bool opFuncVisibility() { return false; }
|
||||
|
||||
// CallOp handling
|
||||
static bool opCallBuiltinFunc() { return false; }
|
||||
static bool opCallPseudoDtor() { return false; }
|
||||
static bool opCallArgs() { return false; }
|
||||
static bool opCallReturn() { return false; }
|
||||
static bool opCallArgEvaluationOrder() { return false; }
|
||||
static bool opCallCallConv() { return false; }
|
||||
static bool opCallSideEffect() { return false; }
|
||||
static bool opCallChainCall() { return false; }
|
||||
static bool opCallNoPrototypeFunc() { return false; }
|
||||
static bool opCallMustTail() { return false; }
|
||||
static bool opCallIndirect() { return false; }
|
||||
static bool opCallVirtual() { return false; }
|
||||
static bool opCallInAlloca() { return false; }
|
||||
static bool opCallAttrs() { return false; }
|
||||
static bool opCallSurroundingTry() { return false; }
|
||||
static bool opCallASTAttr() { return false; }
|
||||
|
||||
// ScopeOp handling
|
||||
static bool opScopeCleanupRegion() { return false; }
|
||||
|
||||
@ -90,7 +108,10 @@ struct MissingFeatures {
|
||||
static bool lowerModeOptLevel() { return false; }
|
||||
static bool opTBAA() { return false; }
|
||||
static bool objCLifetime() { return false; }
|
||||
static bool objCBlocks() { return false; }
|
||||
static bool emitNullabilityCheck() { return false; }
|
||||
static bool emitLValueAlignmentAssumption() { return false; }
|
||||
static bool emitLifetimeMarkers() { return false; }
|
||||
static bool astVarDeclInterface() { return false; }
|
||||
static bool stackSaveOp() { return false; }
|
||||
static bool aggValueSlot() { return false; }
|
||||
@ -113,6 +134,8 @@ struct MissingFeatures {
|
||||
static bool incrementProfileCounter() { return false; }
|
||||
static bool insertBuiltinUnpredictable() { return false; }
|
||||
static bool objCGC() { return false; }
|
||||
static bool weakRefReference() { return false; }
|
||||
static bool hip() { return false; }
|
||||
|
||||
// Missing types
|
||||
static bool dataMemberType() { return false; }
|
||||
@ -132,6 +155,7 @@ struct MissingFeatures {
|
||||
static bool complexImagOp() { return false; }
|
||||
static bool complexRealOp() { return false; }
|
||||
static bool ifOp() { return false; }
|
||||
static bool invokeOp() { return false; }
|
||||
static bool labelOp() { return false; }
|
||||
static bool ptrDiffOp() { return false; }
|
||||
static bool ptrStrideOp() { return false; }
|
||||
|
95
clang/lib/CIR/CodeGen/CIRGenCall.cpp
Normal file
95
clang/lib/CIR/CodeGen/CIRGenCall.cpp
Normal file
@ -0,0 +1,95 @@
|
||||
//===--- CIRGenCall.cpp - Encapsulate calling convention details ----------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// These classes wrap the information about a call or function definition used
|
||||
// to handle ABI compliancy.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "CIRGenCall.h"
|
||||
#include "CIRGenFunction.h"
|
||||
#include "clang/CIR/MissingFeatures.h"
|
||||
|
||||
using namespace clang;
|
||||
using namespace clang::CIRGen;
|
||||
|
||||
CIRGenFunctionInfo *CIRGenFunctionInfo::create() {
|
||||
// For now we just create an empty CIRGenFunctionInfo.
|
||||
CIRGenFunctionInfo *fi = new CIRGenFunctionInfo();
|
||||
return fi;
|
||||
}
|
||||
|
||||
CIRGenCallee CIRGenCallee::prepareConcreteCallee(CIRGenFunction &cgf) const {
|
||||
assert(!cir::MissingFeatures::opCallVirtual());
|
||||
return *this;
|
||||
}
|
||||
|
||||
static const CIRGenFunctionInfo &arrangeFreeFunctionLikeCall(CIRGenTypes &cgt) {
|
||||
assert(!cir::MissingFeatures::opCallArgs());
|
||||
return cgt.arrangeCIRFunctionInfo();
|
||||
}
|
||||
|
||||
const CIRGenFunctionInfo &CIRGenTypes::arrangeFreeFunctionCall() {
|
||||
return arrangeFreeFunctionLikeCall(*this);
|
||||
}
|
||||
|
||||
static cir::CIRCallOpInterface emitCallLikeOp(CIRGenFunction &cgf,
|
||||
mlir::Location callLoc,
|
||||
cir::FuncOp directFuncOp) {
|
||||
CIRGenBuilderTy &builder = cgf.getBuilder();
|
||||
|
||||
assert(!cir::MissingFeatures::opCallSurroundingTry());
|
||||
assert(!cir::MissingFeatures::invokeOp());
|
||||
|
||||
assert(builder.getInsertionBlock() && "expected valid basic block");
|
||||
assert(!cir::MissingFeatures::opCallIndirect());
|
||||
|
||||
return builder.createCallOp(callLoc, directFuncOp);
|
||||
}
|
||||
|
||||
RValue CIRGenFunction::emitCall(const CIRGenFunctionInfo &funcInfo,
|
||||
const CIRGenCallee &callee,
|
||||
cir::CIRCallOpInterface *callOp,
|
||||
mlir::Location loc) {
|
||||
assert(!cir::MissingFeatures::opCallArgs());
|
||||
assert(!cir::MissingFeatures::emitLifetimeMarkers());
|
||||
|
||||
const CIRGenCallee &concreteCallee = callee.prepareConcreteCallee(*this);
|
||||
mlir::Operation *calleePtr = concreteCallee.getFunctionPointer();
|
||||
|
||||
assert(!cir::MissingFeatures::opCallInAlloca());
|
||||
|
||||
mlir::NamedAttrList attrs;
|
||||
StringRef funcName;
|
||||
if (auto calleeFuncOp = dyn_cast<cir::FuncOp>(calleePtr))
|
||||
funcName = calleeFuncOp.getName();
|
||||
|
||||
assert(!cir::MissingFeatures::opCallCallConv());
|
||||
assert(!cir::MissingFeatures::opCallSideEffect());
|
||||
assert(!cir::MissingFeatures::opCallAttrs());
|
||||
|
||||
assert(!cir::MissingFeatures::invokeOp());
|
||||
|
||||
auto directFuncOp = dyn_cast<cir::FuncOp>(calleePtr);
|
||||
assert(!cir::MissingFeatures::opCallIndirect());
|
||||
assert(!cir::MissingFeatures::opCallAttrs());
|
||||
|
||||
cir::CIRCallOpInterface theCall = emitCallLikeOp(*this, loc, directFuncOp);
|
||||
|
||||
if (callOp)
|
||||
*callOp = theCall;
|
||||
|
||||
assert(!cir::MissingFeatures::opCallMustTail());
|
||||
assert(!cir::MissingFeatures::opCallReturn());
|
||||
|
||||
// For now we just return nothing because we don't have support for return
|
||||
// values yet.
|
||||
RValue ret = RValue::get(nullptr);
|
||||
|
||||
return ret;
|
||||
}
|
@ -14,15 +14,73 @@
|
||||
#ifndef CLANG_LIB_CODEGEN_CIRGENCALL_H
|
||||
#define CLANG_LIB_CODEGEN_CIRGENCALL_H
|
||||
|
||||
#include "mlir/IR/Operation.h"
|
||||
#include "clang/AST/GlobalDecl.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
|
||||
namespace clang::CIRGen {
|
||||
|
||||
class CIRGenFunction;
|
||||
|
||||
/// Abstract information about a function or function prototype.
|
||||
class CIRGenCalleeInfo {
|
||||
clang::GlobalDecl calleeDecl;
|
||||
|
||||
public:
|
||||
explicit CIRGenCalleeInfo() : calleeDecl() {}
|
||||
CIRGenCalleeInfo(clang::GlobalDecl calleeDecl) : calleeDecl(calleeDecl) {}
|
||||
};
|
||||
|
||||
class CIRGenCallee {
|
||||
enum class SpecialKind : uintptr_t {
|
||||
Invalid,
|
||||
|
||||
Last = Invalid,
|
||||
};
|
||||
|
||||
SpecialKind kindOrFunctionPtr;
|
||||
|
||||
union {
|
||||
CIRGenCalleeInfo abstractInfo;
|
||||
};
|
||||
|
||||
public:
|
||||
CIRGenCallee() : kindOrFunctionPtr(SpecialKind::Invalid) {}
|
||||
|
||||
CIRGenCallee(const CIRGenCalleeInfo &abstractInfo, mlir::Operation *funcPtr)
|
||||
: kindOrFunctionPtr(SpecialKind(reinterpret_cast<uintptr_t>(funcPtr))),
|
||||
abstractInfo(abstractInfo) {
|
||||
assert(funcPtr && "configuring callee without function pointer");
|
||||
}
|
||||
|
||||
static CIRGenCallee
|
||||
forDirect(mlir::Operation *funcPtr,
|
||||
const CIRGenCalleeInfo &abstractInfo = CIRGenCalleeInfo()) {
|
||||
return CIRGenCallee(abstractInfo, funcPtr);
|
||||
}
|
||||
|
||||
bool isOrdinary() const {
|
||||
return uintptr_t(kindOrFunctionPtr) > uintptr_t(SpecialKind::Last);
|
||||
}
|
||||
|
||||
/// If this is a delayed callee computation of some sort, prepare a concrete
|
||||
/// callee
|
||||
CIRGenCallee prepareConcreteCallee(CIRGenFunction &cgf) const;
|
||||
|
||||
mlir::Operation *getFunctionPointer() const {
|
||||
assert(isOrdinary());
|
||||
return reinterpret_cast<mlir::Operation *>(kindOrFunctionPtr);
|
||||
}
|
||||
};
|
||||
|
||||
/// Type for representing both the decl and type of parameters to a function.
|
||||
/// The decl must be either a ParmVarDecl or ImplicitParamDecl.
|
||||
class FunctionArgList : public llvm::SmallVector<const clang::VarDecl *, 16> {};
|
||||
|
||||
struct CallArg {};
|
||||
|
||||
class CallArgList : public llvm::SmallVector<CallArg, 8> {};
|
||||
|
||||
} // namespace clang::CIRGen
|
||||
|
||||
#endif // CLANG_LIB_CODEGEN_CIRGENCALL_H
|
||||
|
@ -465,6 +465,107 @@ RValue CIRGenFunction::emitAnyExpr(const Expr *e) {
|
||||
llvm_unreachable("bad evaluation kind");
|
||||
}
|
||||
|
||||
static cir::FuncOp emitFunctionDeclPointer(CIRGenModule &cgm, GlobalDecl gd) {
|
||||
assert(!cir::MissingFeatures::weakRefReference());
|
||||
return cgm.getAddrOfFunction(gd);
|
||||
}
|
||||
|
||||
static CIRGenCallee emitDirectCallee(CIRGenModule &cgm, GlobalDecl gd) {
|
||||
assert(!cir::MissingFeatures::opCallBuiltinFunc());
|
||||
|
||||
cir::FuncOp callee = emitFunctionDeclPointer(cgm, gd);
|
||||
|
||||
assert(!cir::MissingFeatures::hip());
|
||||
|
||||
return CIRGenCallee::forDirect(callee, gd);
|
||||
}
|
||||
|
||||
RValue CIRGenFunction::emitCall(clang::QualType calleeTy,
|
||||
const CIRGenCallee &callee,
|
||||
const clang::CallExpr *e) {
|
||||
// Get the actual function type. The callee type will always be a pointer to
|
||||
// function type or a block pointer type.
|
||||
assert(calleeTy->isFunctionPointerType() &&
|
||||
"Callee must have function pointer type!");
|
||||
|
||||
calleeTy = getContext().getCanonicalType(calleeTy);
|
||||
|
||||
if (getLangOpts().CPlusPlus)
|
||||
assert(!cir::MissingFeatures::sanitizers());
|
||||
|
||||
assert(!cir::MissingFeatures::sanitizers());
|
||||
assert(!cir::MissingFeatures::opCallArgs());
|
||||
|
||||
const CIRGenFunctionInfo &funcInfo = cgm.getTypes().arrangeFreeFunctionCall();
|
||||
|
||||
assert(!cir::MissingFeatures::opCallNoPrototypeFunc());
|
||||
assert(!cir::MissingFeatures::opCallChainCall());
|
||||
assert(!cir::MissingFeatures::hip());
|
||||
assert(!cir::MissingFeatures::opCallMustTail());
|
||||
|
||||
cir::CIRCallOpInterface callOp;
|
||||
RValue callResult =
|
||||
emitCall(funcInfo, callee, &callOp, getLoc(e->getExprLoc()));
|
||||
|
||||
assert(!cir::MissingFeatures::generateDebugInfo());
|
||||
|
||||
return callResult;
|
||||
}
|
||||
|
||||
CIRGenCallee CIRGenFunction::emitCallee(const clang::Expr *e) {
|
||||
e = e->IgnoreParens();
|
||||
|
||||
// Look through function-to-pointer decay.
|
||||
if (const auto *implicitCast = dyn_cast<ImplicitCastExpr>(e)) {
|
||||
if (implicitCast->getCastKind() == CK_FunctionToPointerDecay ||
|
||||
implicitCast->getCastKind() == CK_BuiltinFnToFnPtr) {
|
||||
return emitCallee(implicitCast->getSubExpr());
|
||||
}
|
||||
} else if (const auto *declRef = dyn_cast<DeclRefExpr>(e)) {
|
||||
// Resolve direct calls.
|
||||
if (const auto *funcDecl = dyn_cast<FunctionDecl>(declRef->getDecl()))
|
||||
return emitDirectCallee(cgm, funcDecl);
|
||||
}
|
||||
|
||||
cgm.errorNYI(e->getSourceRange(), "Unsupported callee kind");
|
||||
return {};
|
||||
}
|
||||
|
||||
RValue CIRGenFunction::emitCallExpr(const clang::CallExpr *e) {
|
||||
assert(!cir::MissingFeatures::objCBlocks());
|
||||
|
||||
if (isa<CXXMemberCallExpr>(e)) {
|
||||
cgm.errorNYI(e->getSourceRange(), "call to member function");
|
||||
return RValue::get(nullptr);
|
||||
}
|
||||
|
||||
if (isa<CUDAKernelCallExpr>(e)) {
|
||||
cgm.errorNYI(e->getSourceRange(), "call to CUDA kernel");
|
||||
return RValue::get(nullptr);
|
||||
}
|
||||
|
||||
if (const auto *operatorCall = dyn_cast<CXXOperatorCallExpr>(e)) {
|
||||
if (isa_and_nonnull<CXXMethodDecl>(operatorCall->getCalleeDecl())) {
|
||||
cgm.errorNYI(e->getSourceRange(), "call to member operator");
|
||||
return RValue::get(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
CIRGenCallee callee = emitCallee(e->getCallee());
|
||||
|
||||
if (e->getBuiltinCallee()) {
|
||||
cgm.errorNYI(e->getSourceRange(), "call to builtin functions");
|
||||
}
|
||||
assert(!cir::MissingFeatures::opCallBuiltinFunc());
|
||||
|
||||
if (isa<CXXPseudoDestructorExpr>(e->getCallee())) {
|
||||
cgm.errorNYI(e->getSourceRange(), "call to pseudo destructor");
|
||||
}
|
||||
assert(!cir::MissingFeatures::opCallPseudoDtor());
|
||||
|
||||
return emitCall(e->getCallee()->getType(), callee, e);
|
||||
}
|
||||
|
||||
/// Emit code to compute the specified expression, ignoring the result.
|
||||
void CIRGenFunction::emitIgnoredExpr(const Expr *e) {
|
||||
if (e->isPRValue()) {
|
||||
|
@ -156,6 +156,7 @@ public:
|
||||
}
|
||||
|
||||
mlir::Value VisitCastExpr(CastExpr *e);
|
||||
mlir::Value VisitCallExpr(const CallExpr *e);
|
||||
|
||||
mlir::Value VisitExplicitCastExpr(ExplicitCastExpr *e) {
|
||||
return VisitCastExpr(e);
|
||||
@ -1447,6 +1448,18 @@ mlir::Value ScalarExprEmitter::VisitCastExpr(CastExpr *ce) {
|
||||
return {};
|
||||
}
|
||||
|
||||
mlir::Value ScalarExprEmitter::VisitCallExpr(const CallExpr *e) {
|
||||
if (e->getCallReturnType(cgf.getContext())->isReferenceType()) {
|
||||
cgf.getCIRGenModule().errorNYI(
|
||||
e->getSourceRange(), "call to function with non-void return type");
|
||||
return {};
|
||||
}
|
||||
|
||||
auto v = cgf.emitCallExpr(e).getScalarVal();
|
||||
assert(!cir::MissingFeatures::emitLValueAlignmentAssumption());
|
||||
return v;
|
||||
}
|
||||
|
||||
mlir::Value CIRGenFunction::emitScalarConversion(mlir::Value src,
|
||||
QualType srcTy, QualType dstTy,
|
||||
SourceLocation loc) {
|
||||
|
@ -161,6 +161,16 @@ public:
|
||||
|
||||
const clang::LangOptions &getLangOpts() const { return cgm.getLangOpts(); }
|
||||
|
||||
/// An abstract representation of regular/ObjC call/message targets.
|
||||
class AbstractCallee {
|
||||
/// The function declaration of the callee.
|
||||
const clang::Decl *calleeDecl;
|
||||
|
||||
public:
|
||||
AbstractCallee() : calleeDecl(nullptr) {}
|
||||
AbstractCallee(const clang::FunctionDecl *fd) : calleeDecl(fd) {}
|
||||
};
|
||||
|
||||
void finishFunction(SourceLocation endLoc);
|
||||
|
||||
/// Determine whether the given initializer is trivial in the sense
|
||||
@ -437,6 +447,15 @@ public:
|
||||
LValue emitBinaryOperatorLValue(const BinaryOperator *e);
|
||||
|
||||
mlir::LogicalResult emitBreakStmt(const clang::BreakStmt &s);
|
||||
|
||||
RValue emitCall(const CIRGenFunctionInfo &funcInfo,
|
||||
const CIRGenCallee &callee, cir::CIRCallOpInterface *callOp,
|
||||
mlir::Location loc);
|
||||
RValue emitCall(clang::QualType calleeTy, const CIRGenCallee &callee,
|
||||
const clang::CallExpr *e);
|
||||
RValue emitCallExpr(const clang::CallExpr *e);
|
||||
CIRGenCallee emitCallee(const clang::Expr *e);
|
||||
|
||||
mlir::LogicalResult emitContinueStmt(const clang::ContinueStmt &s);
|
||||
mlir::LogicalResult emitDoStmt(const clang::DoStmt &s);
|
||||
|
||||
|
35
clang/lib/CIR/CodeGen/CIRGenFunctionInfo.h
Normal file
35
clang/lib/CIR/CodeGen/CIRGenFunctionInfo.h
Normal file
@ -0,0 +1,35 @@
|
||||
//==-- CIRGenFunctionInfo.h - Representation of fn argument/return types ---==//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Defines CIRGenFunctionInfo and associated types used in representing the
|
||||
// CIR source types and ABI-coerced types for function arguments and
|
||||
// return values.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_CIR_CIRGENFUNCTIONINFO_H
|
||||
#define LLVM_CLANG_CIR_CIRGENFUNCTIONINFO_H
|
||||
|
||||
#include "llvm/ADT/FoldingSet.h"
|
||||
|
||||
namespace clang::CIRGen {
|
||||
|
||||
class CIRGenFunctionInfo final : public llvm::FoldingSetNode {
|
||||
public:
|
||||
static CIRGenFunctionInfo *create();
|
||||
|
||||
// This function has to be CamelCase because llvm::FoldingSet requires so.
|
||||
// NOLINTNEXTLINE(readability-identifier-naming)
|
||||
static void Profile(llvm::FoldingSetNodeID &id) {
|
||||
// We don't have anything to profile yet.
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace clang::CIRGen
|
||||
|
||||
#endif
|
@ -194,10 +194,12 @@ void CIRGenModule::emitGlobalFunctionDefinition(clang::GlobalDecl gd,
|
||||
}
|
||||
|
||||
CIRGenFunction cgf(*this, builder);
|
||||
curCGF = &cgf;
|
||||
{
|
||||
mlir::OpBuilder::InsertionGuard guard(builder);
|
||||
cgf.generateCode(gd, funcOp, funcType);
|
||||
}
|
||||
curCGF = nullptr;
|
||||
}
|
||||
|
||||
void CIRGenModule::emitGlobalVarDefinition(const clang::VarDecl *vd,
|
||||
@ -533,8 +535,18 @@ CIRGenModule::createCIRFunction(mlir::Location loc, StringRef name,
|
||||
{
|
||||
mlir::OpBuilder::InsertionGuard guard(builder);
|
||||
|
||||
// Some global emissions are triggered while emitting a function, e.g.
|
||||
// void s() { x.method() }
|
||||
//
|
||||
// Be sure to insert a new function before a current one.
|
||||
CIRGenFunction *cgf = this->curCGF;
|
||||
if (cgf)
|
||||
builder.setInsertionPoint(cgf->curFn);
|
||||
|
||||
func = builder.create<cir::FuncOp>(loc, name, funcType);
|
||||
theModule.push_back(func);
|
||||
|
||||
if (!cgf)
|
||||
theModule.push_back(func);
|
||||
}
|
||||
return func;
|
||||
}
|
||||
|
@ -42,6 +42,8 @@ class VarDecl;
|
||||
|
||||
namespace CIRGen {
|
||||
|
||||
class CIRGenFunction;
|
||||
|
||||
enum ForDefinition_t : bool { NotForDefinition = false, ForDefinition = true };
|
||||
|
||||
/// This class organizes the cross-function state that is used while generating
|
||||
@ -76,6 +78,10 @@ private:
|
||||
|
||||
CIRGenTypes genTypes;
|
||||
|
||||
/// Per-function codegen information. Updated everytime emitCIR is called
|
||||
/// for FunctionDecls's.
|
||||
CIRGenFunction *curCGF = nullptr;
|
||||
|
||||
public:
|
||||
mlir::ModuleOp getModule() const { return theModule; }
|
||||
CIRGenBuilderTy &getBuilder() { return builder; }
|
||||
|
@ -289,3 +289,33 @@ bool CIRGenTypes::isZeroInitializable(clang::QualType t) {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const CIRGenFunctionInfo &CIRGenTypes::arrangeCIRFunctionInfo() {
|
||||
// Lookup or create unique function info.
|
||||
llvm::FoldingSetNodeID id;
|
||||
CIRGenFunctionInfo::Profile(id);
|
||||
|
||||
void *insertPos = nullptr;
|
||||
CIRGenFunctionInfo *fi = functionInfos.FindNodeOrInsertPos(id, insertPos);
|
||||
if (fi)
|
||||
return *fi;
|
||||
|
||||
assert(!cir::MissingFeatures::opCallCallConv());
|
||||
|
||||
// Construction the function info. We co-allocate the ArgInfos.
|
||||
fi = CIRGenFunctionInfo::create();
|
||||
functionInfos.InsertNode(fi, insertPos);
|
||||
|
||||
bool inserted = functionsBeingProcessed.insert(fi).second;
|
||||
(void)inserted;
|
||||
assert(inserted && "Are functions being processed recursively?");
|
||||
|
||||
assert(!cir::MissingFeatures::opCallCallConv());
|
||||
assert(!cir::MissingFeatures::opCallArgs());
|
||||
|
||||
bool erased = functionsBeingProcessed.erase(fi);
|
||||
(void)erased;
|
||||
assert(erased && "Not in set?");
|
||||
|
||||
return *fi;
|
||||
}
|
||||
|
@ -13,6 +13,7 @@
|
||||
#ifndef LLVM_CLANG_LIB_CODEGEN_CODEGENTYPES_H
|
||||
#define LLVM_CLANG_LIB_CODEGEN_CODEGENTYPES_H
|
||||
|
||||
#include "CIRGenFunctionInfo.h"
|
||||
#include "clang/CIR/Dialect/IR/CIRTypes.h"
|
||||
|
||||
#include "clang/AST/Type.h"
|
||||
@ -33,6 +34,7 @@ class Type;
|
||||
|
||||
namespace clang::CIRGen {
|
||||
|
||||
class CallArgList;
|
||||
class CIRGenBuilderTy;
|
||||
class CIRGenModule;
|
||||
|
||||
@ -43,6 +45,11 @@ class CIRGenTypes {
|
||||
clang::ASTContext &astContext;
|
||||
CIRGenBuilderTy &builder;
|
||||
|
||||
/// Hold memoized CIRGenFunctionInfo results
|
||||
llvm::FoldingSet<CIRGenFunctionInfo> functionInfos;
|
||||
|
||||
llvm::SmallPtrSet<const CIRGenFunctionInfo *, 4> functionsBeingProcessed;
|
||||
|
||||
/// Heper for convertType.
|
||||
mlir::Type convertFunctionTypeInternal(clang::QualType ft);
|
||||
|
||||
@ -75,6 +82,10 @@ public:
|
||||
/// Return whether a type can be zero-initialized (in the C++ sense) with an
|
||||
/// LLVM zeroinitializer.
|
||||
bool isZeroInitializable(clang::QualType ty);
|
||||
|
||||
const CIRGenFunctionInfo &arrangeFreeFunctionCall();
|
||||
|
||||
const CIRGenFunctionInfo &arrangeCIRFunctionInfo();
|
||||
};
|
||||
|
||||
} // namespace clang::CIRGen
|
||||
|
@ -8,6 +8,7 @@ get_property(dialect_libs GLOBAL PROPERTY MLIR_DIALECT_LIBS)
|
||||
|
||||
add_clang_library(clangCIR
|
||||
CIRGenerator.cpp
|
||||
CIRGenCall.cpp
|
||||
CIRGenDecl.cpp
|
||||
CIRGenDeclOpenACC.cpp
|
||||
CIRGenExpr.cpp
|
||||
|
@ -442,6 +442,90 @@ OpFoldResult cir::CastOp::fold(FoldAdaptor adaptor) {
|
||||
return tryFoldCastChain(*this);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// CallOp
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
static mlir::ParseResult parseCallCommon(mlir::OpAsmParser &parser,
|
||||
mlir::OperationState &result) {
|
||||
mlir::FlatSymbolRefAttr calleeAttr;
|
||||
|
||||
if (!parser.parseOptionalAttribute(calleeAttr, "callee", result.attributes)
|
||||
.has_value())
|
||||
return mlir::failure();
|
||||
|
||||
if (parser.parseLParen())
|
||||
return mlir::failure();
|
||||
|
||||
// TODO(cir): parse argument list here
|
||||
assert(!cir::MissingFeatures::opCallArgs());
|
||||
|
||||
if (parser.parseRParen())
|
||||
return mlir::failure();
|
||||
|
||||
if (parser.parseOptionalAttrDict(result.attributes))
|
||||
return ::mlir::failure();
|
||||
|
||||
if (parser.parseColon())
|
||||
return ::mlir::failure();
|
||||
|
||||
mlir::FunctionType opsFnTy;
|
||||
if (parser.parseType(opsFnTy))
|
||||
return mlir::failure();
|
||||
|
||||
return mlir::success();
|
||||
}
|
||||
|
||||
static void printCallCommon(mlir::Operation *op,
|
||||
mlir::FlatSymbolRefAttr calleeSym,
|
||||
mlir::OpAsmPrinter &printer) {
|
||||
printer << ' ';
|
||||
|
||||
printer.printAttributeWithoutType(calleeSym);
|
||||
printer << "(";
|
||||
// TODO(cir): print call args here
|
||||
assert(!cir::MissingFeatures::opCallArgs());
|
||||
printer << ")";
|
||||
|
||||
printer.printOptionalAttrDict(op->getAttrs(), {"callee"});
|
||||
|
||||
printer << " : ";
|
||||
printer.printFunctionalType(op->getOperands().getTypes(),
|
||||
op->getResultTypes());
|
||||
}
|
||||
|
||||
mlir::ParseResult cir::CallOp::parse(mlir::OpAsmParser &parser,
|
||||
mlir::OperationState &result) {
|
||||
return parseCallCommon(parser, result);
|
||||
}
|
||||
|
||||
void cir::CallOp::print(mlir::OpAsmPrinter &p) {
|
||||
printCallCommon(*this, getCalleeAttr(), p);
|
||||
}
|
||||
|
||||
static LogicalResult
|
||||
verifyCallCommInSymbolUses(mlir::Operation *op,
|
||||
SymbolTableCollection &symbolTable) {
|
||||
auto fnAttr = op->getAttrOfType<FlatSymbolRefAttr>("callee");
|
||||
if (!fnAttr)
|
||||
return mlir::failure();
|
||||
|
||||
auto fn = symbolTable.lookupNearestSymbolFrom<cir::FuncOp>(op, fnAttr);
|
||||
if (!fn)
|
||||
return op->emitOpError() << "'" << fnAttr.getValue()
|
||||
<< "' does not reference a valid function";
|
||||
|
||||
// TODO(cir): verify function arguments and return type
|
||||
assert(!cir::MissingFeatures::opCallArgs());
|
||||
|
||||
return mlir::success();
|
||||
}
|
||||
|
||||
LogicalResult
|
||||
cir::CallOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
|
||||
return verifyCallCommInSymbolUses(*this, symbolTable);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// ReturnOp
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
9
clang/test/CIR/CodeGen/call.cpp
Normal file
9
clang/test/CIR/CodeGen/call.cpp
Normal file
@ -0,0 +1,9 @@
|
||||
// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o - 2>&1 | FileCheck %s
|
||||
|
||||
void f1();
|
||||
void f2() {
|
||||
f1();
|
||||
}
|
||||
|
||||
// CHECK-LABEL: cir.func @f2
|
||||
// CHECK: cir.call @f1() : () -> ()
|
17
clang/test/CIR/IR/call.cir
Normal file
17
clang/test/CIR/IR/call.cir
Normal file
@ -0,0 +1,17 @@
|
||||
// RUN: cir-opt %s | FileCheck %s
|
||||
|
||||
module {
|
||||
|
||||
cir.func @f1()
|
||||
|
||||
cir.func @f2() {
|
||||
cir.call @f1() : () -> ()
|
||||
cir.return
|
||||
}
|
||||
|
||||
// CHECK: cir.func @f2() {
|
||||
// CHECK-NEXT: cir.call @f1() : () -> ()
|
||||
// CHECK-NEXT: cir.return
|
||||
// CHECK-NEXT: }
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user