Skip to content

Commit

Permalink
[CIR][ABI][NFC] Add CC lowering for void CallOps (#668)
Browse files Browse the repository at this point in the history
This patch implements the lowering of function calls that receive and
return void. In practice, nothing has to be done (at least for the x86
ABI), so this case is used as a primer for the target lowering library
since it helps populate the base logic for handling calling convention
lowering of function calls.
  • Loading branch information
sitio-couto authored Jun 11, 2024
1 parent 5e9148f commit 66bb15b
Show file tree
Hide file tree
Showing 31 changed files with 850 additions and 42 deletions.
13 changes: 13 additions & 0 deletions clang/include/clang/CIR/Dialect/IR/CIRDataLayout.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "mlir/Dialect/DLTI/DLTI.h"
#include "mlir/IR/BuiltinOps.h"
#include "clang/CIR/Dialect/IR/CIRTypes.h"
#include "llvm/ADT/StringRef.h"

namespace cir {

Expand All @@ -24,6 +25,18 @@ class CIRDataLayout {
public:
mlir::DataLayout layout;

/// Constructs a DataLayout from a specification string. See reset().
explicit CIRDataLayout(llvm::StringRef dataLayout, mlir::ModuleOp module)
: layout(module) {
reset(dataLayout);
}

/// Parse a data layout string (with fallback to default values).
void reset(llvm::StringRef dataLayout);

// Free all internal data structures.
void clear();

CIRDataLayout(mlir::ModuleOp modOp);
bool isBigEndian() const { return bigEndian; }

Expand Down
37 changes: 37 additions & 0 deletions clang/include/clang/CIR/FnInfoOpts.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#ifndef CIR_FNINFOOPTS_H
#define CIR_FNINFOOPTS_H

#include "llvm/ADT/STLForwardCompat.h"

namespace cir {

enum class FnInfoOpts {
None = 0,
IsInstanceMethod = 1 << 0,
IsChainCall = 1 << 1,
IsDelegateCall = 1 << 2,
};

inline FnInfoOpts operator|(FnInfoOpts A, FnInfoOpts B) {
return static_cast<FnInfoOpts>(llvm::to_underlying(A) |
llvm::to_underlying(B));
}

inline FnInfoOpts operator&(FnInfoOpts A, FnInfoOpts B) {
return static_cast<FnInfoOpts>(llvm::to_underlying(A) &
llvm::to_underlying(B));
}

inline FnInfoOpts operator|=(FnInfoOpts A, FnInfoOpts B) {
A = A | B;
return A;
}

inline FnInfoOpts operator&=(FnInfoOpts A, FnInfoOpts B) {
A = A & B;
return A;
}

} // namespace cir

#endif // CIR_FNINFOOPTS_H
37 changes: 31 additions & 6 deletions clang/include/clang/CIR/MissingFeatures.h
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,6 @@ struct MissingFeatures {
static bool zeroInitializer() { return false; }
static bool targetCodeGenInfoIsProtoCallVariadic() { return false; }
static bool targetCodeGenInfoGetNullPointer() { return false; }
static bool chainCalls() { return false; }
static bool operandBundles() { return false; }
static bool exceptions() { return false; }
static bool metaDataNode() { return false; }
Expand Down Expand Up @@ -190,24 +189,50 @@ struct MissingFeatures {

//===--- ABI lowering --===//

//-- Missing AST queries

static bool recordDeclCanPassInRegisters() { return false; }

//-- Missing types

static bool vectorType() { return false; }

//-- Other missing features

// Calls with a static chain pointer argument may be optimized (p.e. freeing
// up argument registers), but we do not yet track such cases.
static bool chainCall() { return false; }

// ABI-lowering has special handling for regcall calling convention (tries to
// pass every argument in regs). We don't support it just yet.
static bool regCall() { return false; }

// Some ABIs (e.g. x86) require special handling for returning large structs
// by value. The sret argument parameter aids in this, but it is current NYI.
static bool sretArgs() { return false; }

// Inalloca parameter attributes are mostly used for Windows x86_32 ABI. We
// do not yet support this yet.
static bool inallocaArgs() { return false; }

// Parameters may have additional attributes (e.g. [[noescape]]) that affect
// the compiler. This is not yet supported in CIR.
static bool extParamInfo() { return true; }
static bool extParamInfo() { return false; }

// LangOpts may affect lowering, but we do not carry this information into CIR
// just yet. Right now, it only instantiates the default lang options.
static bool langOpts() { return true; }
static bool langOpts() { return false; }

// Several type qualifiers are not yet supported in CIR, but important when
// evaluating ABI-specific lowering.
static bool qualifiedTypes() { return true; }
static bool qualifiedTypes() { return false; }

// We're ignoring several details regarding ABI-halding for Swift.
static bool swift() { return true; }
static bool swift() { return false; }

// Despite carrying some information about variadics, we are currently
// ignoring this to focus only on the code necessary to lower non-variadics.
static bool variadicFunctions() { return true; }
static bool variadicFunctions() { return false; }
};

} // namespace cir
Expand Down
32 changes: 32 additions & 0 deletions clang/include/clang/CIR/Target/x86.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
//==-- x86.h - Definitions common to all x86 ABI variants ------------------==//
//
// 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
//
//===----------------------------------------------------------------------===//
//
// Definitions common to any X86 ABI implementation.
//
//===----------------------------------------------------------------------===//

#ifndef CIR_X86_H
#define CIR_X86_H

namespace cir {

// Possible argument classifications according to the x86 ABI documentation.
enum X86ArgClass {
Integer = 0,
SSE,
SSEUp,
X87,
X87Up,
ComplexX87,
NoClass,
Memory
};

} // namespace cir

#endif // CIR_X86_H
1 change: 1 addition & 0 deletions clang/lib/CIR/CodeGen/CIRGenCall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include "clang/AST/GlobalDecl.h"
#include "clang/CIR/Dialect/IR/CIRDialect.h"
#include "clang/CIR/Dialect/IR/CIRTypes.h"
#include "clang/CIR/FnInfoOpts.h"
#include "llvm/Support/ErrorHandling.h"
#include <cassert>

Expand Down
7 changes: 0 additions & 7 deletions clang/lib/CIR/CodeGen/CIRGenCall.h
Original file line number Diff line number Diff line change
Expand Up @@ -290,13 +290,6 @@ class ReturnValueSlot {
Address getAddress() const { return Addr; }
};

enum class FnInfoOpts {
None = 0,
IsInstanceMethod = 1 << 0,
IsChainCall = 1 << 1,
IsDelegateCall = 1 << 2,
};

} // namespace cir

#endif
2 changes: 1 addition & 1 deletion clang/lib/CIR/CodeGen/CIRGenExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1435,7 +1435,7 @@ RValue CIRGenFunction::buildCall(clang::QualType CalleeType,
// Chain calls use the same code path to add the inviisble chain parameter to
// the function type.
if (isa<FunctionNoProtoType>(FnType) || Chain) {
assert(!MissingFeatures::chainCalls());
assert(!MissingFeatures::chainCall());
assert(!MissingFeatures::addressSpace());
auto CalleeTy = getTypes().GetFunctionType(FnInfo);
// get non-variadic function type
Expand Down
1 change: 1 addition & 0 deletions clang/lib/CIR/CodeGen/CIRGenTypes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "clang/AST/GlobalDecl.h"
#include "clang/AST/RecordLayout.h"
#include "clang/CIR/Dialect/IR/CIRTypes.h"
#include "clang/CIR/FnInfoOpts.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/ErrorHandling.h"
Expand Down
1 change: 1 addition & 0 deletions clang/lib/CIR/CodeGen/CIRGenTypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "clang/AST/Type.h"
#include "clang/Basic/ABI.h"
#include "clang/CIR/Dialect/IR/CIRTypes.h"
#include "clang/CIR/FnInfoOpts.h"

#include "llvm/ADT/SmallPtrSet.h"

Expand Down
4 changes: 4 additions & 0 deletions clang/lib/CIR/CodeGen/CIRRecordLayoutBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -748,3 +748,7 @@ CIRDataLayout::CIRDataLayout(mlir::ModuleOp modOp) : layout{modOp} {
}
}
}

void CIRDataLayout::reset(StringRef Desc) { clear(); }

void CIRDataLayout::clear() {}
12 changes: 2 additions & 10 deletions clang/lib/CIR/CodeGen/TargetInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "CallingConv.h"

#include "clang/Basic/TargetInfo.h"
#include "clang/CIR/Target/x86.h"

using namespace cir;
using namespace clang;
Expand Down Expand Up @@ -79,16 +80,7 @@ namespace {
enum class X86AVXABILevel { None, AVX, AVX512 };

class X86_64ABIInfo : public ABIInfo {
enum Class {
Integer = 0,
SSE,
SSEUp,
X87,
X87Up,
ComplexX87,
NoClass,
Memory
};
using Class = X86ArgClass;

// X86AVXABILevel AVXLevel;
// Some ABIs (e.g. X32 ABI and Native Client OS) use 32 bit pointers on 64-bit
Expand Down
18 changes: 17 additions & 1 deletion clang/lib/CIR/Dialect/Transforms/CallConvLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ LowerModule createLowerModule(FuncOp op, PatternRewriter &rewriter) {
// FIXME(cir): This just uses the default language options. We need to account
// for custom options.
// Create context.
assert(::cir::MissingFeatures::langOpts());
assert(!::cir::MissingFeatures::langOpts());
clang::LangOptions langOpts;
auto context = CIRLowerContext(module.getContext(), langOpts);
context.initBuiltinTypes(*targetInfo);
Expand All @@ -64,11 +64,27 @@ struct CallConvLoweringPattern : public OpRewritePattern<FuncOp> {

LogicalResult matchAndRewrite(FuncOp op,
PatternRewriter &rewriter) const final {
const auto module = op->getParentOfType<mlir::ModuleOp>();

if (!op.getAst())
return op.emitError("function has no AST information");

LowerModule lowerModule = createLowerModule(op, rewriter);

// Rewrite function calls before definitions. This should be done before
// lowering the definition.
auto calls = op.getSymbolUses(module);
if (calls.has_value()) {
for (auto call : calls.value()) {
auto callOp = cast<CallOp>(call.getUser());
if (lowerModule.rewriteFunctionCall(callOp, op).failed())
return failure();
}
}

// Rewrite function definition.
// FIXME(cir): This is a workaround to avoid an infinite loop in the driver.
rewriter.replaceOp(op, rewriter.clone(*op));
return success();
}
};
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/CIR/Dialect/Transforms/TargetLowering/ABIInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,16 @@
//===----------------------------------------------------------------------===//

#include "ABIInfo.h"
#include "CIRCXXABI.h"
#include "LowerTypes.h"

namespace mlir {
namespace cir {

// Pin the vtable to this file.
ABIInfo::~ABIInfo() = default;

CIRCXXABI &ABIInfo::getCXXABI() const { return LT.getCXXABI(); }

} // namespace cir
} // namespace mlir
6 changes: 6 additions & 0 deletions clang/lib/CIR/Dialect/Transforms/TargetLowering/ABIInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
#ifndef LLVM_CLANG_LIB_CIR_DIALECT_TRANSFORMS_TARGETLOWERING_ABIINFO_H
#define LLVM_CLANG_LIB_CIR_DIALECT_TRANSFORMS_TARGETLOWERING_ABIINFO_H

#include "CIRCXXABI.h"
#include "LowerFunctionInfo.h"
#include "llvm/IR/CallingConv.h"

namespace mlir {
Expand All @@ -32,6 +34,10 @@ class ABIInfo {
public:
ABIInfo(LowerTypes &LT) : LT(LT), RuntimeCC(llvm::CallingConv::C) {}
virtual ~ABIInfo();

CIRCXXABI &getCXXABI() const;

virtual void computeInfo(LowerFunctionInfo &FI) const = 0;
};

} // namespace cir
Expand Down
22 changes: 22 additions & 0 deletions clang/lib/CIR/Dialect/Transforms/TargetLowering/ABIInfoImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,25 @@
// adapted to operate on the CIR dialect, however.
//
//===----------------------------------------------------------------------===//

#include "ABIInfo.h"
#include "CIRCXXABI.h"
#include "LowerFunctionInfo.h"
#include "llvm/Support/ErrorHandling.h"

namespace mlir {
namespace cir {

bool classifyReturnType(const CIRCXXABI &CXXABI, LowerFunctionInfo &FI,
const ABIInfo &Info) {
Type Ty = FI.getReturnType();

if (const auto RT = Ty.dyn_cast<StructType>()) {
llvm_unreachable("NYI");
}

return CXXABI.classifyReturnType(FI);
}

} // namespace cir
} // namespace mlir
11 changes: 10 additions & 1 deletion clang/lib/CIR/Dialect/Transforms/TargetLowering/ABIInfoImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,17 @@
#ifndef LLVM_CLANG_LIB_CIR_DIALECT_TRANSFORMS_TARGETLOWERING_ABIINFOIMPL_H
#define LLVM_CLANG_LIB_CIR_DIALECT_TRANSFORMS_TARGETLOWERING_ABIINFOIMPL_H

#include "ABIInfo.h"
#include "CIRCXXABI.h"
#include "LowerFunctionInfo.h"

namespace mlir {
namespace cir {} // namespace cir
namespace cir {

bool classifyReturnType(const CIRCXXABI &CXXABI, LowerFunctionInfo &FI,
const ABIInfo &Info);

} // namespace cir
} // namespace mlir

#endif // LLVM_CLANG_LIB_CIR_DIALECT_TRANSFORMS_TARGETLOWERING_ABIINFOIMPL_H
5 changes: 5 additions & 0 deletions clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRCXXABI.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#ifndef LLVM_CLANG_LIB_CIR_DIALECT_TRANSFORMS_TARGETLOWERING_CIRCXXABI_H
#define LLVM_CLANG_LIB_CIR_DIALECT_TRANSFORMS_TARGETLOWERING_CIRCXXABI_H

#include "LowerFunctionInfo.h"
#include "mlir/IR/Value.h"
#include "clang/CIR/Dialect/Builder/CIRBaseBuilder.h"
#include "clang/CIR/Dialect/IR/CIRDataLayout.h"
Expand All @@ -34,6 +35,10 @@ class CIRCXXABI {

public:
virtual ~CIRCXXABI();

/// If the C++ ABI requires the given type be returned in a particular way,
/// this method sets RetAI and returns true.
virtual bool classifyReturnType(LowerFunctionInfo &FI) const = 0;
};

/// Creates an Itanium-family ABI.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ Type CIRLowerContext::initBuiltinType(clang::BuiltinType::Kind K) {
Type Ty;

// NOTE(cir): Clang does more stuff here. Not sure if we need to do the same.
assert(::cir::MissingFeatures::qualifiedTypes());
assert(!::cir::MissingFeatures::qualifiedTypes());
switch (K) {
case clang::BuiltinType::Char_S:
Ty = IntType::get(getMLIRContext(), 8, true);
Expand Down
Loading

0 comments on commit 66bb15b

Please sign in to comment.