Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 884d069

Browse files
sitio-coutolanza
authored andcommittedOct 12, 2024
[CIR][ABI] Replay TargetLowering library reverted commits (#697)
Essentially re-applies #668 and #678, but also includes #687 which patched build introduced by the other two PRs. Closes #691
1 parent fa22600 commit 884d069

34 files changed

+1305
-61
lines changed
 

‎clang/include/clang/CIR/Dialect/IR/CIRDataLayout.h

+14
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "mlir/Dialect/DLTI/DLTI.h"
1616
#include "mlir/IR/BuiltinOps.h"
1717
#include "clang/CIR/Dialect/IR/CIRTypes.h"
18+
#include "llvm/ADT/StringRef.h"
1819

1920
namespace cir {
2021

@@ -24,7 +25,20 @@ class CIRDataLayout {
2425
public:
2526
mlir::DataLayout layout;
2627

28+
/// Constructs a DataLayout from a specification string. See reset().
29+
explicit CIRDataLayout(llvm::StringRef dataLayout, mlir::ModuleOp module)
30+
: layout(module) {
31+
reset(dataLayout);
32+
}
33+
34+
/// Parse a data layout string (with fallback to default values).
35+
void reset(llvm::StringRef dataLayout);
36+
37+
// Free all internal data structures.
38+
void clear();
39+
2740
CIRDataLayout(mlir::ModuleOp modOp);
41+
2842
bool isBigEndian() const { return bigEndian; }
2943

3044
// `useABI` is `true` if not using prefered alignment.

‎clang/include/clang/CIR/FnInfoOpts.h

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
#ifndef CIR_FNINFOOPTS_H
2+
#define CIR_FNINFOOPTS_H
3+
4+
#include "llvm/ADT/STLForwardCompat.h"
5+
6+
namespace cir {
7+
8+
enum class FnInfoOpts {
9+
None = 0,
10+
IsInstanceMethod = 1 << 0,
11+
IsChainCall = 1 << 1,
12+
IsDelegateCall = 1 << 2,
13+
};
14+
15+
inline FnInfoOpts operator|(FnInfoOpts A, FnInfoOpts B) {
16+
return static_cast<FnInfoOpts>(llvm::to_underlying(A) |
17+
llvm::to_underlying(B));
18+
}
19+
20+
inline FnInfoOpts operator&(FnInfoOpts A, FnInfoOpts B) {
21+
return static_cast<FnInfoOpts>(llvm::to_underlying(A) &
22+
llvm::to_underlying(B));
23+
}
24+
25+
inline FnInfoOpts operator|=(FnInfoOpts A, FnInfoOpts B) {
26+
A = A | B;
27+
return A;
28+
}
29+
30+
inline FnInfoOpts operator&=(FnInfoOpts A, FnInfoOpts B) {
31+
A = A & B;
32+
return A;
33+
}
34+
35+
} // namespace cir
36+
37+
#endif // CIR_FNINFOOPTS_H

‎clang/include/clang/CIR/MissingFeatures.h

+42-6
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,6 @@ struct MissingFeatures {
156156
static bool zeroInitializer() { return false; }
157157
static bool targetCodeGenInfoIsProtoCallVariadic() { return false; }
158158
static bool targetCodeGenInfoGetNullPointer() { return false; }
159-
static bool chainCalls() { return false; }
160159
static bool operandBundles() { return false; }
161160
static bool exceptions() { return false; }
162161
static bool metaDataNode() { return false; }
@@ -190,24 +189,61 @@ struct MissingFeatures {
190189

191190
//===--- ABI lowering --===//
192191

192+
//-- Missing AST queries
193+
194+
static bool recordDeclCanPassInRegisters() { return false; }
195+
static bool funcDeclIsCXXConstructorDecl() { return false; }
196+
static bool funcDeclIsCXXDestructorDecl() { return false; }
197+
static bool funcDeclIsCXXMethodDecl() { return false; }
198+
static bool funcDeclIsInlineBuiltinDeclaration() { return false; }
199+
static bool funcDeclIsReplaceableGlobalAllocationFunction() { return false; }
200+
static bool qualTypeIsReferenceType() { return false; }
201+
202+
//-- Missing types
203+
204+
static bool vectorType() { return false; }
205+
206+
//-- Missing LLVM attributes
207+
208+
static bool noReturn() { return false; }
209+
static bool csmeCall() { return false; }
210+
211+
//-- Other missing features
212+
213+
// Calls with a static chain pointer argument may be optimized (p.e. freeing
214+
// up argument registers), but we do not yet track such cases.
215+
static bool chainCall() { return false; }
216+
217+
// ABI-lowering has special handling for regcall calling convention (tries to
218+
// pass every argument in regs). We don't support it just yet.
219+
static bool regCall() { return false; }
220+
221+
// Some ABIs (e.g. x86) require special handling for returning large structs
222+
// by value. The sret argument parameter aids in this, but it is current NYI.
223+
static bool sretArgs() { return false; }
224+
225+
// Inalloca parameter attributes are mostly used for Windows x86_32 ABI. We
226+
// do not yet support this yet.
227+
static bool inallocaArgs() { return false; }
228+
193229
// Parameters may have additional attributes (e.g. [[noescape]]) that affect
194230
// the compiler. This is not yet supported in CIR.
195-
static bool extParamInfo() { return true; }
231+
static bool extParamInfo() { return false; }
196232

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

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

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

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

213249
} // namespace cir

‎clang/include/clang/CIR/Target/x86.h

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
//==-- x86.h - Definitions common to all x86 ABI variants ------------------==//
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+
// Definitions common to any X86 ABI implementation.
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef CIR_X86_H
14+
#define CIR_X86_H
15+
16+
namespace cir {
17+
18+
// Possible argument classifications according to the x86 ABI documentation.
19+
enum X86ArgClass {
20+
Integer = 0,
21+
SSE,
22+
SSEUp,
23+
X87,
24+
X87Up,
25+
ComplexX87,
26+
NoClass,
27+
Memory
28+
};
29+
30+
} // namespace cir
31+
32+
#endif // CIR_X86_H

‎clang/lib/Basic/Targets.h

-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
namespace clang {
2424
namespace targets {
2525

26-
LLVM_LIBRARY_VISIBILITY
2726
std::unique_ptr<clang::TargetInfo>
2827
AllocateTarget(const llvm::Triple &Triple, const clang::TargetOptions &Opts);
2928

‎clang/lib/CIR/CodeGen/CIRGenCall.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "clang/AST/GlobalDecl.h"
2424
#include "clang/CIR/Dialect/IR/CIRDialect.h"
2525
#include "clang/CIR/Dialect/IR/CIRTypes.h"
26+
#include "clang/CIR/FnInfoOpts.h"
2627
#include "llvm/Support/ErrorHandling.h"
2728
#include <cassert>
2829

‎clang/lib/CIR/CodeGen/CIRGenCall.h

-7
Original file line numberDiff line numberDiff line change
@@ -290,13 +290,6 @@ class ReturnValueSlot {
290290
Address getAddress() const { return Addr; }
291291
};
292292

293-
enum class FnInfoOpts {
294-
None = 0,
295-
IsInstanceMethod = 1 << 0,
296-
IsChainCall = 1 << 1,
297-
IsDelegateCall = 1 << 2,
298-
};
299-
300293
} // namespace cir
301294

302295
#endif

‎clang/lib/CIR/CodeGen/CIRGenExpr.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -1435,7 +1435,7 @@ RValue CIRGenFunction::buildCall(clang::QualType CalleeType,
14351435
// Chain calls use the same code path to add the inviisble chain parameter to
14361436
// the function type.
14371437
if (isa<FunctionNoProtoType>(FnType) || Chain) {
1438-
assert(!MissingFeatures::chainCalls());
1438+
assert(!MissingFeatures::chainCall());
14391439
assert(!MissingFeatures::addressSpace());
14401440
auto CalleeTy = getTypes().GetFunctionType(FnInfo);
14411441
// get non-variadic function type

‎clang/lib/CIR/CodeGen/CIRGenTypes.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "clang/AST/GlobalDecl.h"
1717
#include "clang/AST/RecordLayout.h"
1818
#include "clang/CIR/Dialect/IR/CIRTypes.h"
19+
#include "clang/CIR/FnInfoOpts.h"
1920
#include "llvm/ADT/STLExtras.h"
2021
#include "llvm/Support/Casting.h"
2122
#include "llvm/Support/ErrorHandling.h"

‎clang/lib/CIR/CodeGen/CIRGenTypes.h

+1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "clang/AST/Type.h"
2323
#include "clang/Basic/ABI.h"
2424
#include "clang/CIR/Dialect/IR/CIRTypes.h"
25+
#include "clang/CIR/FnInfoOpts.h"
2526

2627
#include "llvm/ADT/SmallPtrSet.h"
2728

‎clang/lib/CIR/CodeGen/TargetInfo.cpp

+2-10
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include "CallingConv.h"
77

88
#include "clang/Basic/TargetInfo.h"
9+
#include "clang/CIR/Target/x86.h"
910

1011
using namespace cir;
1112
using namespace clang;
@@ -79,16 +80,7 @@ namespace {
7980
enum class X86AVXABILevel { None, AVX, AVX512 };
8081

8182
class X86_64ABIInfo : public ABIInfo {
82-
enum Class {
83-
Integer = 0,
84-
SSE,
85-
SSEUp,
86-
X87,
87-
X87Up,
88-
ComplexX87,
89-
NoClass,
90-
Memory
91-
};
83+
using Class = X86ArgClass;
9284

9385
// X86AVXABILevel AVXLevel;
9486
// Some ABIs (e.g. X32 ABI and Native Client OS) use 32 bit pointers on 64-bit

‎clang/lib/CIR/Dialect/IR/CIRDataLayout.cpp

+6-13
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,8 @@
1-
//===- CIRDialect.cpp - MLIR CIR ops implementation -----------------------===//
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 defines the CIR DataLayout class and its functions.
10-
//
11-
//===----------------------------------------------------------------------===//a
12-
//
13-
141
#include "clang/CIR/Dialect/IR/CIRDataLayout.h"
2+
#include "llvm/ADT/StringRef.h"
153

164
namespace cir {
5+
176
CIRDataLayout::CIRDataLayout(mlir::ModuleOp modOp) : layout{modOp} {
187
auto dlSpec = modOp->getAttr(mlir::DLTIDialect::kDataLayoutAttrName)
198
.dyn_cast<mlir::DataLayoutSpecAttr>();
@@ -40,4 +29,8 @@ CIRDataLayout::CIRDataLayout(mlir::ModuleOp modOp) : layout{modOp} {
4029
}
4130
}
4231

32+
void CIRDataLayout::reset(llvm::StringRef Desc) { clear(); }
33+
34+
void CIRDataLayout::clear() {}
35+
4336
} // namespace cir

‎clang/lib/CIR/Dialect/IR/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ add_clang_library(MLIRCIR
1717
LINK_LIBS PUBLIC
1818
MLIRIR
1919
MLIRCIRInterfaces
20+
MLIRDLTIDialect
2021
MLIRDataLayoutInterfaces
2122
MLIRFuncDialect
2223
MLIRLoopLikeInterface

‎clang/lib/CIR/Dialect/Transforms/CallConvLowering.cpp

+19-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ LowerModule createLowerModule(FuncOp op, PatternRewriter &rewriter) {
4545
// FIXME(cir): This just uses the default language options. We need to account
4646
// for custom options.
4747
// Create context.
48-
assert(::cir::MissingFeatures::langOpts());
48+
assert(!::cir::MissingFeatures::langOpts());
4949
clang::LangOptions langOpts;
5050
auto context = CIRLowerContext(module.getContext(), langOpts);
5151
context.initBuiltinTypes(*targetInfo);
@@ -64,11 +64,29 @@ struct CallConvLoweringPattern : public OpRewritePattern<FuncOp> {
6464

6565
LogicalResult matchAndRewrite(FuncOp op,
6666
PatternRewriter &rewriter) const final {
67+
const auto module = op->getParentOfType<mlir::ModuleOp>();
68+
6769
if (!op.getAst())
6870
return op.emitError("function has no AST information");
6971

7072
LowerModule lowerModule = createLowerModule(op, rewriter);
7173

74+
// Rewrite function calls before definitions. This should be done before
75+
// lowering the definition.
76+
auto calls = op.getSymbolUses(module);
77+
if (calls.has_value()) {
78+
for (auto call : calls.value()) {
79+
auto callOp = cast<CallOp>(call.getUser());
80+
if (lowerModule.rewriteFunctionCall(callOp, op).failed())
81+
return failure();
82+
}
83+
}
84+
85+
// TODO(cir): Instead of re-emmiting every load and store, bitcast arguments
86+
// and return values to their ABI-specific counterparts when possible.
87+
if (lowerModule.rewriteFunctionDefinition(op).failed())
88+
return failure();
89+
7290
return success();
7391
}
7492
};

‎clang/lib/CIR/Dialect/Transforms/TargetLowering/ABIInfo.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,16 @@
1212
//===----------------------------------------------------------------------===//
1313

1414
#include "ABIInfo.h"
15+
#include "CIRCXXABI.h"
16+
#include "LowerTypes.h"
1517

1618
namespace mlir {
1719
namespace cir {
1820

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

24+
CIRCXXABI &ABIInfo::getCXXABI() const { return LT.getCXXABI(); }
25+
2226
} // namespace cir
2327
} // namespace mlir

‎clang/lib/CIR/Dialect/Transforms/TargetLowering/ABIInfo.h

+6
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
#ifndef LLVM_CLANG_LIB_CIR_DIALECT_TRANSFORMS_TARGETLOWERING_ABIINFO_H
1515
#define LLVM_CLANG_LIB_CIR_DIALECT_TRANSFORMS_TARGETLOWERING_ABIINFO_H
1616

17+
#include "CIRCXXABI.h"
18+
#include "LowerFunctionInfo.h"
1719
#include "llvm/IR/CallingConv.h"
1820

1921
namespace mlir {
@@ -32,6 +34,10 @@ class ABIInfo {
3234
public:
3335
ABIInfo(LowerTypes &LT) : LT(LT), RuntimeCC(llvm::CallingConv::C) {}
3436
virtual ~ABIInfo();
37+
38+
CIRCXXABI &getCXXABI() const;
39+
40+
virtual void computeInfo(LowerFunctionInfo &FI) const = 0;
3541
};
3642

3743
} // namespace cir

‎clang/lib/CIR/Dialect/Transforms/TargetLowering/ABIInfoImpl.cpp

+22
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,25 @@
1010
// adapted to operate on the CIR dialect, however.
1111
//
1212
//===----------------------------------------------------------------------===//
13+
14+
#include "ABIInfo.h"
15+
#include "CIRCXXABI.h"
16+
#include "LowerFunctionInfo.h"
17+
#include "llvm/Support/ErrorHandling.h"
18+
19+
namespace mlir {
20+
namespace cir {
21+
22+
bool classifyReturnType(const CIRCXXABI &CXXABI, LowerFunctionInfo &FI,
23+
const ABIInfo &Info) {
24+
Type Ty = FI.getReturnType();
25+
26+
if (const auto RT = Ty.dyn_cast<StructType>()) {
27+
llvm_unreachable("NYI");
28+
}
29+
30+
return CXXABI.classifyReturnType(FI);
31+
}
32+
33+
} // namespace cir
34+
} // namespace mlir

‎clang/lib/CIR/Dialect/Transforms/TargetLowering/ABIInfoImpl.h

+10-1
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,17 @@
1414
#ifndef LLVM_CLANG_LIB_CIR_DIALECT_TRANSFORMS_TARGETLOWERING_ABIINFOIMPL_H
1515
#define LLVM_CLANG_LIB_CIR_DIALECT_TRANSFORMS_TARGETLOWERING_ABIINFOIMPL_H
1616

17+
#include "ABIInfo.h"
18+
#include "CIRCXXABI.h"
19+
#include "LowerFunctionInfo.h"
20+
1721
namespace mlir {
18-
namespace cir {} // namespace cir
22+
namespace cir {
23+
24+
bool classifyReturnType(const CIRCXXABI &CXXABI, LowerFunctionInfo &FI,
25+
const ABIInfo &Info);
26+
27+
} // namespace cir
1928
} // namespace mlir
2029

2130
#endif // LLVM_CLANG_LIB_CIR_DIALECT_TRANSFORMS_TARGETLOWERING_ABIINFOIMPL_H

‎clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRCXXABI.h

+5
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#ifndef LLVM_CLANG_LIB_CIR_DIALECT_TRANSFORMS_TARGETLOWERING_CIRCXXABI_H
1515
#define LLVM_CLANG_LIB_CIR_DIALECT_TRANSFORMS_TARGETLOWERING_CIRCXXABI_H
1616

17+
#include "LowerFunctionInfo.h"
1718
#include "mlir/IR/Value.h"
1819
#include "clang/CIR/Dialect/Builder/CIRBaseBuilder.h"
1920
#include "clang/CIR/Dialect/IR/CIRDataLayout.h"
@@ -34,6 +35,10 @@ class CIRCXXABI {
3435

3536
public:
3637
virtual ~CIRCXXABI();
38+
39+
/// If the C++ ABI requires the given type be returned in a particular way,
40+
/// this method sets RetAI and returns true.
41+
virtual bool classifyReturnType(LowerFunctionInfo &FI) const = 0;
3742
};
3843

3944
/// Creates an Itanium-family ABI.

‎clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRLowerContext.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ Type CIRLowerContext::initBuiltinType(clang::BuiltinType::Kind K) {
3131
Type Ty;
3232

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

‎clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRToCIRArgMapping.h

+31-2
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,10 @@
1717
#define LLVM_CLANG_LIB_CIR_DIALECT_TRANSFORMS_TARGETLOWERING_CIRTOCIRARGMAPPING_H
1818

1919
#include "CIRLowerContext.h"
20-
#include "LoweringFunctionInfo.h"
20+
#include "LowerFunctionInfo.h"
21+
#include "clang/CIR/ABIArgInfo.h"
2122
#include "llvm/ADT/SmallVector.h"
23+
#include "llvm/Support/ErrorHandling.h"
2224

2325
namespace mlir {
2426
namespace cir {
@@ -49,9 +51,36 @@ class CIRToCIRArgMapping {
4951
public:
5052
CIRToCIRArgMapping(const CIRLowerContext &context,
5153
const LowerFunctionInfo &FI, bool onlyRequiredArgs = false)
52-
: ArgInfo(onlyRequiredArgs ? FI.getNumRequiredArgs() : FI.arg_size()) {};
54+
: ArgInfo(onlyRequiredArgs ? FI.getNumRequiredArgs() : FI.arg_size()) {
55+
construct(context, FI, onlyRequiredArgs);
56+
};
5357

5458
unsigned totalIRArgs() const { return TotalIRArgs; }
59+
60+
void construct(const CIRLowerContext &context, const LowerFunctionInfo &FI,
61+
bool onlyRequiredArgs = false) {
62+
unsigned IRArgNo = 0;
63+
const ::cir::ABIArgInfo &RetAI = FI.getReturnInfo();
64+
65+
if (RetAI.getKind() == ::cir::ABIArgInfo::Indirect) {
66+
llvm_unreachable("NYI");
67+
}
68+
69+
unsigned ArgNo = 0;
70+
unsigned NumArgs =
71+
onlyRequiredArgs ? FI.getNumRequiredArgs() : FI.arg_size();
72+
for (LowerFunctionInfo::const_arg_iterator _ = FI.arg_begin();
73+
ArgNo < NumArgs; ++_, ++ArgNo) {
74+
llvm_unreachable("NYI");
75+
}
76+
assert(ArgNo == ArgInfo.size());
77+
78+
if (::cir::MissingFeatures::inallocaArgs()) {
79+
llvm_unreachable("NYI");
80+
}
81+
82+
TotalIRArgs = IRArgNo;
83+
}
5584
};
5685

5786
} // namespace cir

‎clang/lib/CIR/Dialect/Transforms/TargetLowering/CMakeLists.txt

+4-1
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,15 @@ add_clang_library(TargetLowering
1717
Targets/LoweringPrepareItaniumCXXABI.cpp
1818

1919
DEPENDS
20+
clangBasic
2021

2122
LINK_LIBS PUBLIC
2223

24+
clangBasic
25+
LLVMTargetParser
2326
MLIRIR
2427
MLIRPass
25-
28+
MLIRDLTIDialect
2629
MLIRCIR
2730
MLIRCIRInterfaces
2831
)

‎clang/lib/CIR/Dialect/Transforms/TargetLowering/ItaniumCXXABI.cpp

+14
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,24 @@ class ItaniumCXXABI : public CIRCXXABI {
3232

3333
public:
3434
ItaniumCXXABI(LowerModule &LM) : CIRCXXABI(LM) {}
35+
36+
bool classifyReturnType(LowerFunctionInfo &FI) const override;
3537
};
3638

3739
} // namespace
3840

41+
bool ItaniumCXXABI::classifyReturnType(LowerFunctionInfo &FI) const {
42+
const StructType RD = FI.getReturnType().dyn_cast<StructType>();
43+
if (!RD)
44+
return false;
45+
46+
// If C++ prohibits us from making a copy, return by address.
47+
if (::cir::MissingFeatures::recordDeclCanPassInRegisters())
48+
llvm_unreachable("NYI");
49+
50+
return false;
51+
}
52+
3953
CIRCXXABI *CreateItaniumCXXABI(LowerModule &LM) {
4054
switch (LM.getCXXABIKind()) {
4155
case clang::TargetCXXABI::GenericItanium:
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,273 @@
1+
#include "LowerCall.h"
2+
#include "CIRToCIRArgMapping.h"
3+
#include "LowerFunctionInfo.h"
4+
#include "LowerModule.h"
5+
#include "LowerTypes.h"
6+
#include "clang/CIR/FnInfoOpts.h"
7+
#include "clang/CIR/MissingFeatures.h"
8+
#include "llvm/Support/ErrorHandling.h"
9+
10+
using namespace mlir;
11+
using namespace mlir::cir;
12+
13+
using ABIArgInfo = ::cir::ABIArgInfo;
14+
using FnInfoOpts = ::cir::FnInfoOpts;
15+
using MissingFeatures = ::cir::MissingFeatures;
16+
17+
namespace {
18+
19+
/// Arrange a call as unto a free function, except possibly with an
20+
/// additional number of formal parameters considered required.
21+
const LowerFunctionInfo &
22+
arrangeFreeFunctionLikeCall(LowerTypes &LT, LowerModule &LM,
23+
const OperandRange &args, const FuncType fnType,
24+
unsigned numExtraRequiredArgs, bool chainCall) {
25+
assert(args.size() >= numExtraRequiredArgs);
26+
27+
assert(!::cir::MissingFeatures::extParamInfo());
28+
29+
// In most cases, there are no optional arguments.
30+
RequiredArgs required = RequiredArgs::All;
31+
32+
// If we have a variadic prototype, the required arguments are the
33+
// extra prefix plus the arguments in the prototype.
34+
// FIXME(cir): Properly check if function is no-proto.
35+
if (/*IsPrototypedFunction=*/true) {
36+
if (fnType.isVarArg())
37+
llvm_unreachable("NYI");
38+
39+
if (::cir::MissingFeatures::extParamInfo())
40+
llvm_unreachable("NYI");
41+
}
42+
43+
// TODO(cir): There's some CC stuff related to no-proto functions here, but
44+
// I'm skipping it since it requires CodeGen info. Maybe we can embbed this
45+
// information in the FuncOp during CIRGen.
46+
47+
assert(!::cir::MissingFeatures::chainCall() && !chainCall && "NYI");
48+
FnInfoOpts opts = chainCall ? FnInfoOpts::IsChainCall : FnInfoOpts::None;
49+
return LT.arrangeLLVMFunctionInfo(fnType.getReturnType(), opts,
50+
fnType.getInputs(), required);
51+
}
52+
53+
/// Adds the formal parameters in FPT to the given prefix. If any parameter in
54+
/// FPT has pass_object_size attrs, then we'll add parameters for those, too.
55+
static void appendParameterTypes(SmallVectorImpl<Type> &prefix, FuncType fnTy) {
56+
// Fast path: don't touch param info if we don't need to.
57+
if (/*!fnTy->hasExtParameterInfos()=*/true) {
58+
prefix.append(fnTy.getInputs().begin(), fnTy.getInputs().end());
59+
return;
60+
}
61+
62+
assert(MissingFeatures::extParamInfo());
63+
llvm_unreachable("NYI");
64+
}
65+
66+
/// Arrange the LLVM function layout for a value of the given function
67+
/// type, on top of any implicit parameters already stored.
68+
///
69+
/// \param CGT - Abstraction for lowering CIR types.
70+
/// \param instanceMethod - Whether the function is an instance method.
71+
/// \param prefix - List of implicit parameters to be prepended (e.g. 'this').
72+
/// \param FTP - ABI-agnostic function type.
73+
static const LowerFunctionInfo &
74+
arrangeCIRFunctionInfo(LowerTypes &CGT, bool instanceMethod,
75+
SmallVectorImpl<mlir::Type> &prefix, FuncType fnTy) {
76+
assert(!MissingFeatures::extParamInfo());
77+
RequiredArgs Required = RequiredArgs::forPrototypePlus(fnTy, prefix.size());
78+
// FIXME: Kill copy.
79+
appendParameterTypes(prefix, fnTy);
80+
assert(!MissingFeatures::qualifiedTypes());
81+
Type resultType = fnTy.getReturnType();
82+
83+
FnInfoOpts opts =
84+
instanceMethod ? FnInfoOpts::IsInstanceMethod : FnInfoOpts::None;
85+
return CGT.arrangeLLVMFunctionInfo(resultType, opts, prefix, Required);
86+
}
87+
88+
} // namespace
89+
90+
/// Update function with ABI-specific attributes.
91+
///
92+
/// NOTE(cir): Partially copies CodeGenModule::ConstructAttributeList, but
93+
/// focuses on ABI/Target-related attributes.
94+
void LowerModule::constructAttributeList(StringRef Name,
95+
const LowerFunctionInfo &FI,
96+
FuncOp CalleeInfo, FuncOp newFn,
97+
unsigned &CallingConv,
98+
bool AttrOnCallSite, bool IsThunk) {
99+
// Collect function IR attributes from the CC lowering.
100+
// We'll collect the paramete and result attributes later.
101+
// FIXME(cir): Codegen differentiates between CallConv and EffectiveCallConv,
102+
// but I don't think we need to do this here.
103+
CallingConv = FI.getCallingConvention();
104+
// FIXME(cir): No-return should probably be set in CIRGen (ABI-agnostic).
105+
if (MissingFeatures::noReturn())
106+
llvm_unreachable("NYI");
107+
if (MissingFeatures::csmeCall())
108+
llvm_unreachable("NYI");
109+
110+
// TODO(cir): Implement AddAttributesFromFunctionProtoType here.
111+
// TODO(cir): Implement AddAttributesFromOMPAssumes here.
112+
assert(!MissingFeatures::openMP());
113+
114+
// TODO(cir): Skipping a bunch of AST queries here. We will need to partially
115+
// implement some of them as this section sets target-specific attributes
116+
// too.
117+
// if (TargetDecl) {
118+
// [...]
119+
// }
120+
121+
// NOTE(cir): The original code adds default and no-builtin attributes here as
122+
// well. AFAIK, these are ABI/Target-agnostic, so it would be better handled
123+
// in CIRGen. Regardless, I'm leaving this comment here as a heads up.
124+
125+
// Override some default IR attributes based on declaration-specific
126+
// information.
127+
// NOTE(cir): Skipping another set of AST queries here.
128+
129+
// Collect attributes from arguments and return values.
130+
CIRToCIRArgMapping IRFunctionArgs(getContext(), FI);
131+
132+
const ABIArgInfo &RetAI = FI.getReturnInfo();
133+
134+
// TODO(cir): No-undef attribute for return values partially depends on
135+
// ABI-specific information. Maybe we should include it here.
136+
137+
switch (RetAI.getKind()) {
138+
case ABIArgInfo::Ignore:
139+
break;
140+
default:
141+
llvm_unreachable("Missing ABIArgInfo::Kind");
142+
}
143+
144+
if (!IsThunk) {
145+
if (MissingFeatures::qualTypeIsReferenceType()) {
146+
llvm_unreachable("NYI");
147+
}
148+
}
149+
150+
// Attach attributes to sret.
151+
if (MissingFeatures::sretArgs()) {
152+
llvm_unreachable("sret is NYI");
153+
}
154+
155+
// Attach attributes to inalloca arguments.
156+
if (MissingFeatures::inallocaArgs()) {
157+
llvm_unreachable("inalloca is NYI");
158+
}
159+
160+
// Apply `nonnull`, `dereferencable(N)` and `align N` to the `this` argument,
161+
// unless this is a thunk function.
162+
// FIXME: fix this properly, https://reviews.llvm.org/D100388
163+
if (MissingFeatures::funcDeclIsCXXMethodDecl() ||
164+
MissingFeatures::inallocaArgs()) {
165+
llvm_unreachable("`this` argument attributes are NYI");
166+
}
167+
168+
unsigned ArgNo = 0;
169+
for (LowerFunctionInfo::const_arg_iterator I = FI.arg_begin(),
170+
E = FI.arg_end();
171+
I != E; ++I, ++ArgNo) {
172+
llvm_unreachable("NYI");
173+
}
174+
assert(ArgNo == FI.arg_size());
175+
}
176+
177+
/// Arrange the argument and result information for the declaration or
178+
/// definition of the given function.
179+
const LowerFunctionInfo &LowerTypes::arrangeFunctionDeclaration(FuncOp fnOp) {
180+
if (MissingFeatures::funcDeclIsCXXMethodDecl())
181+
llvm_unreachable("NYI");
182+
183+
assert(!MissingFeatures::qualifiedTypes());
184+
FuncType FTy = fnOp.getFunctionType();
185+
186+
assert(!MissingFeatures::CUDA());
187+
188+
// When declaring a function without a prototype, always use a
189+
// non-variadic type.
190+
if (fnOp.getNoProto()) {
191+
llvm_unreachable("NYI");
192+
}
193+
194+
return arrangeFreeFunctionType(FTy);
195+
}
196+
197+
/// Figure out the rules for calling a function with the given formal
198+
/// type using the given arguments. The arguments are necessary
199+
/// because the function might be unprototyped, in which case it's
200+
/// target-dependent in crazy ways.
201+
const LowerFunctionInfo &
202+
LowerTypes::arrangeFreeFunctionCall(const OperandRange args,
203+
const FuncType fnType, bool chainCall) {
204+
return arrangeFreeFunctionLikeCall(*this, LM, args, fnType, chainCall ? 1 : 0,
205+
chainCall);
206+
}
207+
208+
/// Arrange the argument and result information for the declaration or
209+
/// definition of the given function.
210+
const LowerFunctionInfo &LowerTypes::arrangeFreeFunctionType(FuncType FTy) {
211+
SmallVector<mlir::Type, 16> argTypes;
212+
return ::arrangeCIRFunctionInfo(*this, /*instanceMethod=*/false, argTypes,
213+
FTy);
214+
}
215+
216+
/// Arrange the argument and result information for the declaration or
217+
/// definition of the given function.
218+
const LowerFunctionInfo &LowerTypes::arrangeGlobalDeclaration(FuncOp fnOp) {
219+
if (MissingFeatures::funcDeclIsCXXConstructorDecl() ||
220+
MissingFeatures::funcDeclIsCXXDestructorDecl())
221+
llvm_unreachable("NYI");
222+
223+
return arrangeFunctionDeclaration(fnOp);
224+
}
225+
226+
/// Arrange the argument and result information for an abstract value
227+
/// of a given function type. This is the method which all of the
228+
/// above functions ultimately defer to.
229+
///
230+
/// \param resultType - ABI-agnostic CIR result type.
231+
/// \param opts - Options to control the arrangement.
232+
/// \param argTypes - ABI-agnostic CIR argument types.
233+
/// \param required - Information about required/optional arguments.
234+
const LowerFunctionInfo &
235+
LowerTypes::arrangeLLVMFunctionInfo(Type resultType, FnInfoOpts opts,
236+
ArrayRef<Type> argTypes,
237+
RequiredArgs required) {
238+
assert(!::cir::MissingFeatures::qualifiedTypes());
239+
240+
LowerFunctionInfo *FI = nullptr;
241+
242+
// FIXME(cir): Allow user-defined CCs (e.g. __attribute__((vectorcall))).
243+
assert(!::cir::MissingFeatures::extParamInfo());
244+
unsigned CC = clangCallConvToLLVMCallConv(clang::CallingConv::CC_C);
245+
246+
// Construct the function info. We co-allocate the ArgInfos.
247+
// NOTE(cir): This initial function info might hold incorrect data.
248+
FI = LowerFunctionInfo::create(
249+
CC, /*isInstanceMethod=*/false, /*isChainCall=*/false,
250+
/*isDelegateCall=*/false, resultType, argTypes, required);
251+
252+
// Compute ABI information.
253+
if (CC == llvm::CallingConv::SPIR_KERNEL) {
254+
llvm_unreachable("NYI");
255+
} else if (::cir::MissingFeatures::extParamInfo()) {
256+
llvm_unreachable("NYI");
257+
} else {
258+
// NOTE(cir): This corects the initial function info data.
259+
getABIInfo().computeInfo(*FI); // FIXME(cir): Args should be set to null.
260+
}
261+
262+
// Loop over all of the computed argument and return value info. If any of
263+
// them are direct or extend without a specified coerce type, specify the
264+
// default now.
265+
::cir::ABIArgInfo &retInfo = FI->getReturnInfo();
266+
if (retInfo.canHaveCoerceToType() && retInfo.getCoerceToType() == nullptr)
267+
llvm_unreachable("NYI");
268+
269+
for (auto &_ : FI->arguments())
270+
llvm_unreachable("NYI");
271+
272+
return *FI;
273+
}

‎clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerCall.h

+2
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ namespace cir {
2222
/// Contains the address where the return value of a function can be stored, and
2323
/// whether the address is volatile or not.
2424
class ReturnValueSlot {
25+
// FIXME(cir): We should be able to query this directly from CIR at some
26+
// point. This class can then be removed.
2527
Value Addr = {};
2628

2729
// Return value slot flags

‎clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerFunction.cpp

+333
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,20 @@
1212
//===----------------------------------------------------------------------===//
1313

1414
#include "LowerFunction.h"
15+
#include "CIRToCIRArgMapping.h"
1516
#include "LowerCall.h"
17+
#include "LowerFunctionInfo.h"
1618
#include "LowerModule.h"
19+
#include "mlir/IR/MLIRContext.h"
1720
#include "mlir/IR/PatternMatch.h"
1821
#include "mlir/Support/LogicalResult.h"
22+
#include "clang/CIR/ABIArgInfo.h"
23+
#include "clang/CIR/Dialect/IR/CIRAttrs.h"
1924
#include "clang/CIR/Dialect/IR/CIRDialect.h"
25+
#include "clang/CIR/MissingFeatures.h"
26+
#include "llvm/Support/ErrorHandling.h"
27+
28+
using ABIArgInfo = ::cir::ABIArgInfo;
2029

2130
namespace mlir {
2231
namespace cir {
@@ -32,5 +41,329 @@ LowerFunction::LowerFunction(LowerModule &LM, PatternRewriter &rewriter,
3241
: Target(LM.getTarget()), rewriter(rewriter), SrcFn(srcFn), callOp(callOp),
3342
LM(LM) {}
3443

44+
/// This method has partial parity with CodeGenFunction::EmitFunctionProlog from
45+
/// the original codegen. However, it focuses on the ABI-specific details. On
46+
/// top of that, it is also responsible for rewriting the original function.
47+
LogicalResult
48+
LowerFunction::buildFunctionProlog(const LowerFunctionInfo &FI, FuncOp Fn,
49+
MutableArrayRef<BlockArgument> Args) {
50+
// NOTE(cir): Skipping naked and implicit-return-zero functions here. These
51+
// are dealt with in CIRGen.
52+
53+
CIRToCIRArgMapping IRFunctionArgs(LM.getContext(), FI);
54+
assert(Fn.getNumArguments() == IRFunctionArgs.totalIRArgs());
55+
56+
// If we're using inalloca, all the memory arguments are GEPs off of the last
57+
// parameter, which is a pointer to the complete memory area.
58+
assert(!::cir::MissingFeatures::inallocaArgs());
59+
60+
// Name the struct return parameter.
61+
assert(!::cir::MissingFeatures::sretArgs());
62+
63+
// Track if we received the parameter as a pointer (indirect, byval, or
64+
// inalloca). If already have a pointer, EmitParmDecl doesn't need to copy it
65+
// into a local alloca for us.
66+
SmallVector<Value, 8> ArgVals;
67+
ArgVals.reserve(Args.size());
68+
69+
// Create a pointer value for every parameter declaration. This usually
70+
// entails copying one or more LLVM IR arguments into an alloca. Don't push
71+
// any cleanups or do anything that might unwind. We do that separately, so
72+
// we can push the cleanups in the correct order for the ABI.
73+
assert(FI.arg_size() == Args.size());
74+
unsigned ArgNo = 0;
75+
LowerFunctionInfo::const_arg_iterator info_it = FI.arg_begin();
76+
for (MutableArrayRef<BlockArgument>::const_iterator i = Args.begin(),
77+
e = Args.end();
78+
i != e; ++i, ++info_it, ++ArgNo) {
79+
llvm_unreachable("NYI");
80+
}
81+
82+
if (getTarget().getCXXABI().areArgsDestroyedLeftToRightInCallee()) {
83+
llvm_unreachable("NYI");
84+
} else {
85+
// FIXME(cir): In the original codegen, EmitParamDecl is called here. It is
86+
// likely that said function considers ABI details during emission, so we
87+
// migth have to add a counter part here. Currently, it is not needed.
88+
}
89+
90+
return success();
91+
}
92+
93+
LogicalResult LowerFunction::buildFunctionEpilog(const LowerFunctionInfo &FI) {
94+
const ABIArgInfo &RetAI = FI.getReturnInfo();
95+
96+
switch (RetAI.getKind()) {
97+
98+
case ABIArgInfo::Ignore:
99+
break;
100+
101+
default:
102+
llvm_unreachable("Unhandled ABIArgInfo::Kind");
103+
}
104+
105+
return success();
106+
}
107+
108+
/// Generate code for a function based on the ABI-specific information.
109+
///
110+
/// This method has partial parity with CodeGenFunction::GenerateCode, but it
111+
/// focuses on the ABI-specific details. So a lot of codegen stuff is removed.
112+
LogicalResult LowerFunction::generateCode(FuncOp oldFn, FuncOp newFn,
113+
const LowerFunctionInfo &FnInfo) {
114+
assert(newFn && "generating code for null Function");
115+
auto Args = oldFn.getArguments();
116+
117+
// Emit the ABI-specific function prologue.
118+
assert(newFn.empty() && "Function already has a body");
119+
rewriter.setInsertionPointToEnd(newFn.addEntryBlock());
120+
if (buildFunctionProlog(FnInfo, newFn, oldFn.getArguments()).failed())
121+
return failure();
122+
123+
// Ensure that old ABI-agnostic arguments uses were replaced.
124+
const auto hasNoUses = [](Value val) { return val.getUses().empty(); };
125+
assert(std::all_of(Args.begin(), Args.end(), hasNoUses) && "Missing RAUW?");
126+
127+
// Migrate function body to new ABI-aware function.
128+
assert(oldFn.getBody().hasOneBlock() &&
129+
"Multiple blocks in original function not supported");
130+
131+
// Move old function body to new function.
132+
// FIXME(cir): The merge below is not very good: will not work if SrcFn has
133+
// multiple blocks and it mixes the new and old prologues.
134+
rewriter.mergeBlocks(&oldFn.getBody().front(), &newFn.getBody().front(),
135+
newFn.getArguments());
136+
137+
// FIXME(cir): What about saving parameters for corotines? Should we do
138+
// something about it in this pass? If the change with the calling
139+
// convention, we might have to handle this here.
140+
141+
// Emit the standard function epilogue.
142+
if (buildFunctionEpilog(FnInfo).failed())
143+
return failure();
144+
145+
return success();
146+
}
147+
148+
/// Rewrite a call operation to abide to the ABI calling convention.
149+
///
150+
/// FIXME(cir): This method has partial parity to CodeGenFunction's
151+
/// EmitCallEpxr method defined in CGExpr.cpp. This could likely be
152+
/// removed in favor of a more direct approach.
153+
LogicalResult LowerFunction::rewriteCallOp(CallOp op,
154+
ReturnValueSlot retValSlot) {
155+
156+
// TODO(cir): Check if BlockCall, CXXMemberCall, CUDAKernelCall, or
157+
// CXXOperatorMember require special handling here. These should be handled in
158+
// CIRGen, unless there is call conv or ABI-specific stuff to be handled, them
159+
// we should do it here.
160+
161+
// TODO(cir): Also check if Builtin and CXXPeseudoDtor need special handling
162+
// here. These should be handled in CIRGen, unless there is call conv or
163+
// ABI-specific stuff to be handled, them we should do it here.
164+
165+
// NOTE(cir): There is no direct way to fetch the function type from the
166+
// CallOp, so we fetch it from the source function. This assumes the function
167+
// definition has not yet been lowered.
168+
assert(SrcFn && "No source function");
169+
auto fnType = SrcFn.getFunctionType();
170+
171+
// Rewrite the call operation to abide to the ABI calling convention.
172+
auto Ret = rewriteCallOp(fnType, SrcFn, op, retValSlot);
173+
174+
// Replace the original call result with the new one.
175+
if (Ret)
176+
rewriter.replaceAllUsesWith(op.getResult(), Ret);
177+
178+
return success();
179+
}
180+
181+
/// Rewrite a call operation to abide to the ABI calling convention.
182+
///
183+
/// FIXME(cir): This method has partial parity to CodeGenFunction's EmitCall
184+
/// method defined in CGExpr.cpp. This could likely be removed in favor of a
185+
/// more direct approach since most of the code here is exclusively CodeGen.
186+
Value LowerFunction::rewriteCallOp(FuncType calleeTy, FuncOp origCallee,
187+
CallOp callOp, ReturnValueSlot retValSlot,
188+
Value Chain) {
189+
// NOTE(cir): Skip a bunch of function pointer stuff and AST declaration
190+
// asserts. Also skip sanitizers, as these should likely be handled at
191+
// CIRGen.
192+
CallArgList Args;
193+
if (Chain)
194+
llvm_unreachable("NYI");
195+
196+
// NOTE(cir): Call args were already emitted in CIRGen. Skip the evaluation
197+
// order done in CIRGen and just fetch the exiting arguments here.
198+
Args = callOp.getArgOperands();
199+
200+
const LowerFunctionInfo &FnInfo = LM.getTypes().arrangeFreeFunctionCall(
201+
callOp.getArgOperands(), calleeTy, /*chainCall=*/false);
202+
203+
// C99 6.5.2.2p6:
204+
// If the expression that denotes the called function has a type
205+
// that does not include a prototype, [the default argument
206+
// promotions are performed]. If the number of arguments does not
207+
// equal the number of parameters, the behavior is undefined. If
208+
// the function is defined with a type that includes a prototype,
209+
// and either the prototype ends with an ellipsis (, ...) or the
210+
// types of the arguments after promotion are not compatible with
211+
// the types of the parameters, the behavior is undefined. If the
212+
// function is defined with a type that does not include a
213+
// prototype, and the types of the arguments after promotion are
214+
// not compatible with those of the parameters after promotion,
215+
// the behavior is undefined [except in some trivial cases].
216+
// That is, in the general case, we should assume that a call
217+
// through an unprototyped function type works like a *non-variadic*
218+
// call. The way we make this work is to cast to the exact type
219+
// of the promoted arguments.
220+
//
221+
// Chain calls use this same code path to add the invisible chain parameter
222+
// to the function type.
223+
if (origCallee.getNoProto() || Chain) {
224+
llvm_unreachable("NYI");
225+
}
226+
227+
assert(!::cir::MissingFeatures::CUDA());
228+
229+
// TODO(cir): LLVM IR has the concept of "CallBase", which is a base class for
230+
// all types of calls. Perhaps we should have a CIR interface to mimic this
231+
// class.
232+
CallOp CallOrInvoke = {};
233+
Value CallResult = {};
234+
rewriteCallOp(FnInfo, origCallee, callOp, retValSlot, Args, CallOrInvoke,
235+
/*isMustTail=*/false, callOp.getLoc());
236+
237+
// NOTE(cir): Skipping debug stuff here.
238+
239+
return CallResult;
240+
}
241+
242+
// NOTE(cir): This method has partial parity to CodeGenFunction's EmitCall
243+
// method in CGCall.cpp. When incrementing it, use the original codegen as a
244+
// reference: add ABI-specific stuff and skip codegen stuff.
245+
Value LowerFunction::rewriteCallOp(const LowerFunctionInfo &CallInfo,
246+
FuncOp Callee, CallOp Caller,
247+
ReturnValueSlot ReturnValue,
248+
CallArgList &CallArgs, CallOp CallOrInvoke,
249+
bool isMustTail, Location loc) {
250+
// FIXME: We no longer need the types from CallArgs; lift up and simplify.
251+
252+
// Handle struct-return functions by passing a pointer to the
253+
// location that we would like to return into.
254+
Type RetTy = CallInfo.getReturnType(); // ABI-agnostic type.
255+
const ::cir::ABIArgInfo &RetAI = CallInfo.getReturnInfo();
256+
257+
FuncType IRFuncTy = LM.getTypes().getFunctionType(CallInfo);
258+
259+
// NOTE(cir): Some target/ABI related checks happen here. I'm skipping them
260+
// under the assumption that they are handled in CIRGen.
261+
262+
// 1. Set up the arguments.
263+
264+
// If we're using inalloca, insert the allocation after the stack save.
265+
// FIXME: Do this earlier rather than hacking it in here!
266+
if (StructType ArgStruct = CallInfo.getArgStruct()) {
267+
llvm_unreachable("NYI");
268+
}
269+
270+
CIRToCIRArgMapping IRFunctionArgs(LM.getContext(), CallInfo);
271+
SmallVector<Value, 16> IRCallArgs(IRFunctionArgs.totalIRArgs());
272+
273+
// If the call returns a temporary with struct return, create a temporary
274+
// alloca to hold the result, unless one is given to us.
275+
if (RetAI.isIndirect() || RetAI.isCoerceAndExpand() || RetAI.isInAlloca()) {
276+
llvm_unreachable("NYI");
277+
}
278+
279+
assert(!::cir::MissingFeatures::swift());
280+
281+
// NOTE(cir): Skipping lifetime markers here.
282+
283+
// Translate all of the arguments as necessary to match the IR lowering.
284+
assert(CallInfo.arg_size() == CallArgs.size() &&
285+
"Mismatch between function signature & arguments.");
286+
unsigned ArgNo = 0;
287+
LowerFunctionInfo::const_arg_iterator info_it = CallInfo.arg_begin();
288+
for (auto I = CallArgs.begin(), E = CallArgs.end(); I != E;
289+
++I, ++info_it, ++ArgNo) {
290+
llvm_unreachable("NYI");
291+
}
292+
293+
// 2. Prepare the function pointer.
294+
// NOTE(cir): This is not needed for CIR.
295+
296+
// 3. Perform the actual call.
297+
298+
// NOTE(cir): CIRGen handle when to "deactive" cleanups. We also skip some
299+
// debugging stuff here.
300+
301+
// Update the largest vector width if any arguments have vector types.
302+
assert(!::cir::MissingFeatures::vectorType());
303+
304+
// Compute the calling convention and attributes.
305+
306+
// FIXME(cir): Skipping call attributes for now. Not sure if we have to do
307+
// this at all since we already do it for the function definition.
308+
309+
// FIXME(cir): Implement the required procedures for strictfp function and
310+
// fast-math.
311+
312+
// FIXME(cir): Add missing call-site attributes here if they are
313+
// ABI/target-specific, otherwise, do it in CIRGen.
314+
315+
// NOTE(cir): Deciding whether to use Call or Invoke is done in CIRGen.
316+
317+
// Rewrite the actual call operation.
318+
// TODO(cir): Handle other types of CIR calls (e.g. cir.try_call).
319+
// NOTE(cir): We don't know if the callee was already lowered, so we only
320+
// fetch the name from the callee, while the return type is fetch from the
321+
// lowering types manager.
322+
CallOp newCallOp = rewriter.create<CallOp>(
323+
loc, Caller.getCalleeAttr(), IRFuncTy.getReturnType(), IRCallArgs);
324+
auto extraAttrs =
325+
rewriter.getAttr<ExtraFuncAttributesAttr>(rewriter.getDictionaryAttr({}));
326+
newCallOp->setAttr("extra_attrs", extraAttrs);
327+
328+
assert(!::cir::MissingFeatures::vectorType());
329+
330+
// NOTE(cir): Skipping some ObjC, tail-call, debug, and attribute stuff here.
331+
332+
// 4. Finish the call.
333+
334+
// NOTE(cir): Skipping no-return, isMustTail, swift error handling, and
335+
// writebacks here. These should be handled in CIRGen, I think.
336+
337+
// Convert return value from ABI-agnostic to ABI-aware.
338+
Value Ret = [&] {
339+
// NOTE(cir): CIRGen already handled the emission of the return value. We
340+
// need only to handle the ABI-specific to ABI-agnostic cast here.
341+
switch (RetAI.getKind()) {
342+
case ::cir::ABIArgInfo::Ignore:
343+
// If we are ignoring an argument that had a result, make sure to
344+
// construct the appropriate return value for our caller.
345+
return getUndefRValue(RetTy);
346+
default:
347+
llvm::errs() << "Unhandled ABIArgInfo kind: " << RetAI.getKind() << "\n";
348+
llvm_unreachable("NYI");
349+
}
350+
}();
351+
352+
// NOTE(cir): Skipping Emissions, lifetime markers, and dtors here that should
353+
// be handled in CIRGen.
354+
355+
return Ret;
356+
}
357+
358+
// NOTE(cir): This method has partial parity to CodeGenFunction's GetUndefRValue
359+
// defined in CGExpr.cpp.
360+
Value LowerFunction::getUndefRValue(Type Ty) {
361+
if (Ty.isa<VoidType>())
362+
return nullptr;
363+
364+
llvm::outs() << "Missing undef handler for value type: " << Ty << "\n";
365+
llvm_unreachable("NYI");
366+
}
367+
35368
} // namespace cir
36369
} // namespace mlir

‎clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerFunction.h

+30
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
namespace mlir {
2626
namespace cir {
2727

28+
using CallArgList = SmallVector<Value, 8>;
29+
2830
class LowerFunction {
2931
LowerFunction(const LowerFunction &) = delete;
3032
void operator=(const LowerFunction &) = delete;
@@ -50,6 +52,34 @@ class LowerFunction {
5052
~LowerFunction() = default;
5153

5254
LowerModule &LM; // Per-module state.
55+
56+
const clang::TargetInfo &getTarget() const { return Target; }
57+
58+
// Build ABI/Target-specific function prologue.
59+
LogicalResult buildFunctionProlog(const LowerFunctionInfo &FI, FuncOp Fn,
60+
MutableArrayRef<BlockArgument> Args);
61+
62+
// Build ABI/Target-specific function epilogue.
63+
LogicalResult buildFunctionEpilog(const LowerFunctionInfo &FI);
64+
65+
// Parity with CodeGenFunction::GenerateCode. Keep in mind that several
66+
// sections in the original function are focused on codegen unrelated to the
67+
// ABI. Such sections are handled in CIR's codegen, not here.
68+
LogicalResult generateCode(FuncOp oldFn, FuncOp newFn,
69+
const LowerFunctionInfo &FnInfo);
70+
71+
/// Rewrite a call operation to abide to the ABI calling convention.
72+
LogicalResult rewriteCallOp(CallOp op,
73+
ReturnValueSlot retValSlot = ReturnValueSlot());
74+
Value rewriteCallOp(FuncType calleeTy, FuncOp origCallee, CallOp callOp,
75+
ReturnValueSlot retValSlot, Value Chain = nullptr);
76+
Value rewriteCallOp(const LowerFunctionInfo &CallInfo, FuncOp Callee,
77+
CallOp Caller, ReturnValueSlot ReturnValue,
78+
CallArgList &CallArgs, CallOp CallOrInvoke,
79+
bool isMustTail, Location loc);
80+
81+
/// Get an appropriate 'undef' value for the given type.
82+
Value getUndefRValue(Type Ty);
5383
};
5484

5585
} // namespace cir

‎clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerFunctionInfo.h

+44-2
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "clang/CIR/ABIArgInfo.h"
1919
#include "clang/CIR/Dialect/IR/CIRTypes.h"
2020
#include "clang/CIR/MissingFeatures.h"
21+
#include "llvm/ADT/ArrayRef.h"
2122
#include "llvm/Support/TrailingObjects.h"
2223

2324
namespace mlir {
@@ -36,6 +37,19 @@ class RequiredArgs {
3637
RequiredArgs(All_t _) : NumRequired(~0U) {}
3738
explicit RequiredArgs(unsigned n) : NumRequired(n) { assert(n != ~0U); }
3839

40+
/// Compute the arguments required by the given formal prototype,
41+
/// given that there may be some additional, non-formal arguments
42+
/// in play.
43+
///
44+
/// If FD is not null, this will consider pass_object_size params in FD.
45+
static RequiredArgs forPrototypePlus(const FuncType prototype,
46+
unsigned additional) {
47+
if (!prototype.isVarArg())
48+
return All;
49+
50+
llvm_unreachable("Variadic function is NYI");
51+
}
52+
3953
bool allowsOptionalArgs() const { return NumRequired != ~0U; }
4054
};
4155

@@ -46,6 +60,8 @@ struct LowerFunctionInfoArgInfo {
4660
::cir::ABIArgInfo info; // ABI-specific information.
4761
};
4862

63+
// FIXME(cir): We could likely encode this information within CIR/MLIR, allowing
64+
// us to eliminate this class.
4965
class LowerFunctionInfo final
5066
: private llvm::TrailingObjects<LowerFunctionInfo,
5167
LowerFunctionInfoArgInfo> {
@@ -89,7 +105,7 @@ class LowerFunctionInfo final
89105
ArrayRef<mlir::Type> argTypes,
90106
RequiredArgs required) {
91107
// TODO(cir): Add assertions?
92-
assert(::cir::MissingFeatures::extParamInfo());
108+
assert(!::cir::MissingFeatures::extParamInfo());
93109
void *buffer = operator new(totalSizeToAlloc<ArgInfo>(argTypes.size() + 1));
94110

95111
LowerFunctionInfo *FI = new (buffer) LowerFunctionInfo();
@@ -115,17 +131,43 @@ class LowerFunctionInfo final
115131
return NumArgs + 1;
116132
}
117133

134+
typedef const ArgInfo *const_arg_iterator;
135+
typedef ArgInfo *arg_iterator;
136+
137+
MutableArrayRef<ArgInfo> arguments() {
138+
return MutableArrayRef<ArgInfo>(arg_begin(), NumArgs);
139+
}
140+
141+
const_arg_iterator arg_begin() const { return getArgsBuffer() + 1; }
142+
const_arg_iterator arg_end() const { return getArgsBuffer() + 1 + NumArgs; }
143+
arg_iterator arg_begin() { return getArgsBuffer() + 1; }
144+
arg_iterator arg_end() { return getArgsBuffer() + 1 + NumArgs; }
145+
118146
unsigned arg_size() const { return NumArgs; }
119147

120148
bool isVariadic() const {
121-
assert(::cir::MissingFeatures::variadicFunctions());
149+
assert(!::cir::MissingFeatures::variadicFunctions());
122150
return false;
123151
}
124152
unsigned getNumRequiredArgs() const {
125153
if (isVariadic())
126154
llvm_unreachable("NYI");
127155
return arg_size();
128156
}
157+
158+
Type getReturnType() const { return getArgsBuffer()[0].type; }
159+
160+
::cir::ABIArgInfo &getReturnInfo() { return getArgsBuffer()[0].info; }
161+
const ::cir::ABIArgInfo &getReturnInfo() const {
162+
return getArgsBuffer()[0].info;
163+
}
164+
165+
/// Return the user specified callingconvention, which has been translated
166+
/// into an LLVM CC.
167+
unsigned getCallingConvention() const { return CallingConvention; }
168+
169+
/// Get the struct type used to represent all the arguments in memory.
170+
StructType getArgStruct() const { return ArgStruct; }
129171
};
130172

131173
} // namespace cir

‎clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerModule.cpp

+115-6
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,16 @@
1313

1414
#include "LowerModule.h"
1515
#include "CIRLowerContext.h"
16+
#include "LowerFunction.h"
1617
#include "TargetInfo.h"
1718
#include "mlir/IR/Attributes.h"
1819
#include "mlir/IR/BuiltinAttributes.h"
1920
#include "mlir/IR/PatternMatch.h"
2021
#include "mlir/Support/LogicalResult.h"
2122
#include "llvm/Support/ErrorHandling.h"
2223

24+
using MissingFeatures = ::cir::MissingFeatures;
25+
2326
namespace mlir {
2427
namespace cir {
2528

@@ -74,17 +77,123 @@ const TargetLoweringInfo &LowerModule::getTargetLoweringInfo() {
7477
return *TheTargetCodeGenInfo;
7578
}
7679

77-
LogicalResult LowerModule::rewriteGlobalFunctionDefinition(FuncOp op,
78-
LowerModule &state) {
80+
void LowerModule::setCIRFunctionAttributes(FuncOp GD,
81+
const LowerFunctionInfo &Info,
82+
FuncOp F, bool IsThunk) {
83+
unsigned CallingConv;
84+
// NOTE(cir): The method below will update the F function in-place with the
85+
// proper attributes.
86+
constructAttributeList(GD.getName(), Info, GD, F, CallingConv,
87+
/*AttrOnCallSite=*/false, IsThunk);
88+
// TODO(cir): Set Function's calling convention.
89+
}
90+
91+
/// Set function attributes for a function declaration.
92+
///
93+
/// This method is based on CodeGenModule::SetFunctionAttributes but it
94+
/// altered to consider only the ABI/Target-related bits.
95+
void LowerModule::setFunctionAttributes(FuncOp oldFn, FuncOp newFn,
96+
bool IsIncompleteFunction,
97+
bool IsThunk) {
98+
99+
// TODO(cir): There's some special handling from attributes related to LLVM
100+
// intrinsics. Should we do that here as well?
101+
102+
// Setup target-specific attributes.
103+
if (!IsIncompleteFunction)
104+
setCIRFunctionAttributes(oldFn, getTypes().arrangeGlobalDeclaration(oldFn),
105+
newFn, IsThunk);
106+
107+
// TODO(cir): Handle attributes for returned "this" objects.
108+
109+
// NOTE(cir): Skipping some linkage and other global value attributes here as
110+
// it might be better for CIRGen to handle them.
111+
112+
// TODO(cir): Skipping section attributes here.
113+
114+
// TODO(cir): Skipping error attributes here.
115+
116+
// If we plan on emitting this inline builtin, we can't treat it as a builtin.
117+
if (MissingFeatures::funcDeclIsInlineBuiltinDeclaration()) {
118+
llvm_unreachable("NYI");
119+
}
120+
121+
if (MissingFeatures::funcDeclIsReplaceableGlobalAllocationFunction()) {
122+
llvm_unreachable("NYI");
123+
}
124+
125+
if (MissingFeatures::funcDeclIsCXXConstructorDecl() ||
126+
MissingFeatures::funcDeclIsCXXDestructorDecl())
127+
llvm_unreachable("NYI");
128+
else if (MissingFeatures::funcDeclIsCXXMethodDecl())
129+
llvm_unreachable("NYI");
130+
131+
// NOTE(cir) Skipping emissions that depend on codegen options, as well as
132+
// sanitizers handling here. Do this in CIRGen.
133+
134+
if (MissingFeatures::langOpts() && MissingFeatures::openMP())
135+
llvm_unreachable("NYI");
136+
137+
// NOTE(cir): Skipping more things here that depend on codegen options.
138+
139+
if (MissingFeatures::extParamInfo()) {
140+
llvm_unreachable("NYI");
141+
}
142+
}
143+
144+
/// Rewrites an existing function to conform to the ABI.
145+
///
146+
/// This method is based on CodeGenModule::EmitGlobalFunctionDefinition but it
147+
/// considerably simplified as it tries to remove any CodeGen related code.
148+
LogicalResult LowerModule::rewriteFunctionDefinition(FuncOp op) {
79149
mlir::OpBuilder::InsertionGuard guard(rewriter);
80150
rewriter.setInsertionPoint(op);
81-
return failure();
151+
152+
// Get ABI/target-specific function information.
153+
const LowerFunctionInfo &FI = this->getTypes().arrangeGlobalDeclaration(op);
154+
155+
// Get ABI/target-specific function type.
156+
FuncType Ty = this->getTypes().getFunctionType(FI);
157+
158+
// NOTE(cir): Skipping getAddrOfFunction and getOrCreateCIRFunction methods
159+
// here, as they are mostly codegen logic.
160+
161+
// Create a new function with the ABI-specific types.
162+
FuncOp newFn = cast<FuncOp>(rewriter.cloneWithoutRegions(op));
163+
newFn.setType(Ty);
164+
165+
// NOTE(cir): The clone above will preserve any existing attributes. If there
166+
// are high-level attributes that ought to be dropped, do it here.
167+
168+
// Set up ABI-specific function attributes.
169+
setFunctionAttributes(op, newFn, false, /*IsThunk=*/false);
170+
if (MissingFeatures::extParamInfo()) {
171+
llvm_unreachable("ExtraAttrs are NYI");
172+
}
173+
174+
if (LowerFunction(*this, rewriter, op, newFn)
175+
.generateCode(op, newFn, FI)
176+
.failed())
177+
return failure();
178+
179+
// Erase original ABI-agnostic function.
180+
rewriter.eraseOp(op);
181+
return success();
82182
}
83183

84-
LogicalResult LowerModule::rewriteFunctionCall(CallOp caller, FuncOp callee) {
184+
LogicalResult LowerModule::rewriteFunctionCall(CallOp callOp, FuncOp funcOp) {
85185
mlir::OpBuilder::InsertionGuard guard(rewriter);
86-
rewriter.setInsertionPoint(caller);
87-
return failure();
186+
rewriter.setInsertionPoint(callOp);
187+
188+
// Create a new function with the ABI-specific calling convention.
189+
if (LowerFunction(*this, rewriter, funcOp, callOp)
190+
.rewriteCallOp(callOp)
191+
.failed())
192+
return failure();
193+
194+
// Erase original ABI-agnostic call.
195+
rewriter.eraseOp(callOp);
196+
return success();
88197
}
89198

90199
} // namespace cir

‎clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerModule.h

+23-3
Original file line numberDiff line numberDiff line change
@@ -60,15 +60,35 @@ class LowerModule {
6060
// FIXME(cir): This would be in ASTContext, not CodeGenModule.
6161
clang::TargetCXXABI::Kind getCXXABIKind() const {
6262
auto kind = getTarget().getCXXABI().getKind();
63-
assert(::cir::MissingFeatures::langOpts());
63+
assert(!::cir::MissingFeatures::langOpts());
6464
return kind;
6565
}
6666

67+
void
68+
constructAttributeList(StringRef Name, const LowerFunctionInfo &FI,
69+
FuncOp CalleeInfo, // TODO(cir): Implement CalleeInfo?
70+
FuncOp newFn, unsigned &CallingConv,
71+
bool AttrOnCallSite, bool IsThunk);
72+
73+
void setCIRFunctionAttributes(FuncOp GD, const LowerFunctionInfo &Info,
74+
FuncOp F, bool IsThunk);
75+
76+
/// Set function attributes for a function declaration.
77+
void setFunctionAttributes(FuncOp oldFn, FuncOp newFn,
78+
bool IsIncompleteFunction, bool IsThunk);
79+
80+
// Create a CIR FuncOp with with the given signature.
81+
FuncOp createCIRFunction(
82+
StringRef MangledName, FuncType Ty, FuncOp D, bool ForVTable,
83+
bool DontDefer = false, bool IsThunk = false,
84+
ArrayRef<Attribute> = {}, // TODO(cir): __attribute__(()) stuff.
85+
bool IsForDefinition = false);
86+
6787
// Rewrite CIR FuncOp to match the target ABI.
68-
LogicalResult rewriteGlobalFunctionDefinition(FuncOp op, LowerModule &state);
88+
LogicalResult rewriteFunctionDefinition(FuncOp op);
6989

7090
// Rewrite CIR CallOp to match the target ABI.
71-
LogicalResult rewriteFunctionCall(CallOp caller, FuncOp callee);
91+
LogicalResult rewriteFunctionCall(CallOp callOp, FuncOp funcOp);
7292
};
7393

7494
} // namespace cir

‎clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerTypes.cpp

+48-2
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,59 @@
1212
//===----------------------------------------------------------------------===//
1313

1414
#include "LowerTypes.h"
15+
#include "CIRToCIRArgMapping.h"
1516
#include "LowerModule.h"
1617
#include "mlir/Support/LLVM.h"
18+
#include "clang/CIR/ABIArgInfo.h"
19+
#include "clang/CIR/MissingFeatures.h"
20+
#include "llvm/Support/ErrorHandling.h"
1721

1822
using namespace ::mlir::cir;
1923

24+
unsigned LowerTypes::clangCallConvToLLVMCallConv(clang::CallingConv CC) {
25+
switch (CC) {
26+
case clang::CC_C:
27+
return llvm::CallingConv::C;
28+
default:
29+
llvm_unreachable("calling convention NYI");
30+
}
31+
}
32+
2033
LowerTypes::LowerTypes(LowerModule &LM, StringRef DLString)
21-
: LM(LM), queries(LM.getContext()), Target(LM.getTarget()),
34+
: LM(LM), context(LM.getContext()), Target(LM.getTarget()),
2235
CXXABI(LM.getCXXABI()),
2336
TheABIInfo(LM.getTargetLoweringInfo().getABIInfo()),
24-
mlirContext(LM.getMLIRContext()), DL(LM.getModule()) {}
37+
mlirContext(LM.getMLIRContext()), DL(DLString, LM.getModule()) {}
38+
39+
/// Return the ABI-specific function type for a CIR function type.
40+
FuncType LowerTypes::getFunctionType(const LowerFunctionInfo &FI) {
41+
42+
mlir::Type resultType = {};
43+
const ::cir::ABIArgInfo &retAI = FI.getReturnInfo();
44+
switch (retAI.getKind()) {
45+
case ::cir::ABIArgInfo::Ignore:
46+
resultType = VoidType::get(getMLIRContext());
47+
break;
48+
default:
49+
llvm_unreachable("Missing ABIArgInfo::Kind");
50+
}
51+
52+
CIRToCIRArgMapping IRFunctionArgs(getContext(), FI, true);
53+
SmallVector<Type, 8> ArgTypes(IRFunctionArgs.totalIRArgs());
54+
55+
// Add type for sret argument.
56+
assert(!::cir::MissingFeatures::sretArgs());
57+
58+
// Add type for inalloca argument.
59+
assert(!::cir::MissingFeatures::inallocaArgs());
60+
61+
// Add in all of the required arguments.
62+
unsigned ArgNo = 0;
63+
LowerFunctionInfo::const_arg_iterator it = FI.arg_begin(),
64+
ie = it + FI.getNumRequiredArgs();
65+
for (; it != ie; ++it, ++ArgNo) {
66+
llvm_unreachable("NYI");
67+
}
68+
69+
return FuncType::get(getMLIRContext(), ArgTypes, resultType, FI.isVariadic());
70+
}

‎clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerTypes.h

+40-1
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,12 @@
1717
#include "ABIInfo.h"
1818
#include "CIRCXXABI.h"
1919
#include "CIRLowerContext.h"
20+
#include "LowerCall.h"
2021
#include "mlir/IR/MLIRContext.h"
22+
#include "clang/Basic/Specifiers.h"
2123
#include "clang/CIR/Dialect/IR/CIRDataLayout.h"
24+
#include "clang/CIR/Dialect/IR/CIRDialect.h"
25+
#include "clang/CIR/FnInfoOpts.h"
2226

2327
namespace mlir {
2428
namespace cir {
@@ -33,7 +37,7 @@ class LowerTypes {
3337

3438
private:
3539
LowerModule &LM;
36-
CIRLowerContext &queries;
40+
CIRLowerContext &context;
3741
const clang::TargetInfo &Target;
3842
CIRCXXABI &CXXABI;
3943

@@ -46,11 +50,46 @@ class LowerTypes {
4650

4751
::cir::CIRDataLayout DL;
4852

53+
const ABIInfo &getABIInfo() const { return TheABIInfo; }
54+
4955
public:
5056
LowerTypes(LowerModule &LM, StringRef DLString);
5157
~LowerTypes() = default;
5258

5359
LowerModule &getLM() const { return LM; }
60+
CIRCXXABI &getCXXABI() const { return CXXABI; }
61+
CIRLowerContext &getContext() { return context; }
62+
MLIRContext *getMLIRContext() { return mlirContext; }
63+
64+
/// Convert clang calling convention to LLVM callilng convention.
65+
unsigned clangCallConvToLLVMCallConv(clang::CallingConv CC);
66+
67+
/// Free functions are functions that are compatible with an ordinary
68+
/// C function pointer type.
69+
/// FIXME(cir): Does the "free function" concept makes sense here?
70+
const LowerFunctionInfo &arrangeFunctionDeclaration(FuncOp fnOp);
71+
const LowerFunctionInfo &arrangeFreeFunctionCall(const OperandRange args,
72+
const FuncType fnType,
73+
bool chainCall);
74+
const LowerFunctionInfo &arrangeFreeFunctionType(FuncType FTy);
75+
76+
const LowerFunctionInfo &arrangeGlobalDeclaration(FuncOp fnOp);
77+
78+
/// Arrange the argument and result information for an abstract value
79+
/// of a given function type. This is the method which all of the
80+
/// above functions ultimately defer to.
81+
///
82+
/// \param resultType - ABI-agnostic CIR result type.
83+
/// \param opts - Options to control the arrangement.
84+
/// \param argTypes - ABI-agnostic CIR argument types.
85+
/// \param required - Information about required/optional arguments.
86+
const LowerFunctionInfo &arrangeLLVMFunctionInfo(Type resultType,
87+
::cir::FnInfoOpts opts,
88+
ArrayRef<Type> argTypes,
89+
RequiredArgs required);
90+
91+
/// Return the ABI-specific function type for a CIR function type.
92+
FuncType getFunctionType(const LowerFunctionInfo &FI);
5493
};
5594

5695
} // namespace cir

‎clang/lib/CIR/Dialect/Transforms/TargetLowering/Targets/X86.cpp

+138-1
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,164 @@
1+
2+
#include "clang/CIR/Target/x86.h"
13
#include "ABIInfo.h"
4+
#include "ABIInfoImpl.h"
25
#include "LowerModule.h"
36
#include "LowerTypes.h"
47
#include "TargetInfo.h"
8+
#include "clang/CIR/ABIArgInfo.h"
59
#include "clang/CIR/MissingFeatures.h"
10+
#include "llvm/Support/ErrorHandling.h"
611
#include <memory>
712

813
namespace mlir {
914
namespace cir {
1015

1116
class X86_64ABIInfo : public ABIInfo {
17+
using Class = ::cir::X86ArgClass;
18+
19+
/// Determine the x86_64 register classes in which the given type T should be
20+
/// passed.
21+
///
22+
/// \param Lo - The classification for the parts of the type
23+
/// residing in the low word of the containing object.
24+
///
25+
/// \param Hi - The classification for the parts of the type
26+
/// residing in the high word of the containing object.
27+
///
28+
/// \param OffsetBase - The bit offset of this type in the
29+
/// containing object. Some parameters are classified different
30+
/// depending on whether they straddle an eightbyte boundary.
31+
///
32+
/// \param isNamedArg - Whether the argument in question is a "named"
33+
/// argument, as used in AMD64-ABI 3.5.7.
34+
///
35+
/// \param IsRegCall - Whether the calling conversion is regcall.
36+
///
37+
/// If a word is unused its result will be NoClass; if a type should
38+
/// be passed in Memory then at least the classification of \arg Lo
39+
/// will be Memory.
40+
///
41+
/// The \arg Lo class will be NoClass iff the argument is ignored.
42+
///
43+
/// If the \arg Lo class is ComplexX87, then the \arg Hi class will
44+
/// also be ComplexX87.
45+
void classify(Type T, uint64_t OffsetBase, Class &Lo, Class &Hi,
46+
bool isNamedArg, bool IsRegCall = false) const;
1247

1348
public:
1449
X86_64ABIInfo(LowerTypes &CGT, X86AVXABILevel AVXLevel) : ABIInfo(CGT) {}
50+
51+
::cir::ABIArgInfo classifyReturnType(Type RetTy) const;
52+
53+
void computeInfo(LowerFunctionInfo &FI) const override;
1554
};
1655

1756
class X86_64TargetLoweringInfo : public TargetLoweringInfo {
1857
public:
1958
X86_64TargetLoweringInfo(LowerTypes &LM, X86AVXABILevel AVXLevel)
2059
: TargetLoweringInfo(std::make_unique<X86_64ABIInfo>(LM, AVXLevel)) {
21-
assert(::cir::MissingFeatures::swift());
60+
assert(!::cir::MissingFeatures::swift());
2261
}
2362
};
2463

64+
void X86_64ABIInfo::classify(Type Ty, uint64_t OffsetBase, Class &Lo, Class &Hi,
65+
bool isNamedArg, bool IsRegCall) const {
66+
// FIXME: This code can be simplified by introducing a simple value class
67+
// for Class pairs with appropriate constructor methods for the various
68+
// situations.
69+
70+
// FIXME: Some of the split computations are wrong; unaligned vectors
71+
// shouldn't be passed in registers for example, so there is no chance they
72+
// can straddle an eightbyte. Verify & simplify.
73+
74+
Lo = Hi = Class::NoClass;
75+
76+
Class &Current = OffsetBase < 64 ? Lo : Hi;
77+
Current = Class::Memory;
78+
79+
// FIXME(cir): There's currently no direct way to identify if a type is a
80+
// builtin.
81+
if (/*isBuitinType=*/true) {
82+
if (Ty.isa<VoidType>()) {
83+
Current = Class::NoClass;
84+
} else {
85+
llvm::outs() << "Missing X86 classification for type " << Ty << "\n";
86+
llvm_unreachable("NYI");
87+
}
88+
// FIXME: _Decimal32 and _Decimal64 are SSE.
89+
// FIXME: _float128 and _Decimal128 are (SSE, SSEUp).
90+
return;
91+
}
92+
93+
llvm::outs() << "Missing X86 classification for non-builtin types\n";
94+
llvm_unreachable("NYI");
95+
}
96+
97+
::cir::ABIArgInfo X86_64ABIInfo::classifyReturnType(Type RetTy) const {
98+
// AMD64-ABI 3.2.3p4: Rule 1. Classify the return type with the
99+
// classification algorithm.
100+
X86_64ABIInfo::Class Lo, Hi;
101+
classify(RetTy, 0, Lo, Hi, true);
102+
103+
// Check some invariants.
104+
assert((Hi != Class::Memory || Lo == Class::Memory) &&
105+
"Invalid memory classification.");
106+
assert((Hi != Class::SSEUp || Lo == Class::SSE) &&
107+
"Invalid SSEUp classification.");
108+
109+
switch (Lo) {
110+
case Class::NoClass:
111+
if (Hi == Class::NoClass)
112+
return ::cir::ABIArgInfo::getIgnore();
113+
break;
114+
default:
115+
llvm_unreachable("NYI");
116+
}
117+
118+
llvm_unreachable("NYI");
119+
}
120+
121+
void X86_64ABIInfo::computeInfo(LowerFunctionInfo &FI) const {
122+
const unsigned CallingConv = FI.getCallingConvention();
123+
// It is possible to force Win64 calling convention on any x86_64 target by
124+
// using __attribute__((ms_abi)). In such case to correctly emit Win64
125+
// compatible code delegate this call to WinX86_64ABIInfo::computeInfo.
126+
if (CallingConv == llvm::CallingConv::Win64) {
127+
llvm_unreachable("Win64 CC is NYI");
128+
}
129+
130+
bool IsRegCall = CallingConv == llvm::CallingConv::X86_RegCall;
131+
132+
// Keep track of the number of assigned registers.
133+
unsigned NeededSSE = 0, MaxVectorWidth = 0;
134+
135+
if (!::mlir::cir::classifyReturnType(getCXXABI(), FI, *this)) {
136+
if (IsRegCall || ::cir::MissingFeatures::regCall()) {
137+
llvm_unreachable("RegCall is NYI");
138+
} else
139+
FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
140+
}
141+
142+
// If the return value is indirect, then the hidden argument is consuming
143+
// one integer register.
144+
if (FI.getReturnInfo().isIndirect())
145+
llvm_unreachable("NYI");
146+
else if (NeededSSE && MaxVectorWidth)
147+
llvm_unreachable("NYI");
148+
149+
// The chain argument effectively gives us another free register.
150+
if (::cir::MissingFeatures::chainCall())
151+
llvm_unreachable("NYI");
152+
153+
// AMD64-ABI 3.2.3p3: Once arguments are classified, the registers
154+
// get assigned (in left-to-right order) for passing as follows...
155+
unsigned ArgNo = 0;
156+
for (LowerFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end();
157+
it != ie; ++it, ++ArgNo) {
158+
llvm_unreachable("NYI");
159+
}
160+
}
161+
25162
std::unique_ptr<TargetLoweringInfo>
26163
createX86_64TargetLoweringInfo(LowerModule &LM, X86AVXABILevel AVXLevel) {
27164
return std::make_unique<X86_64TargetLoweringInfo>(LM.getTypes(), AVXLevel);
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fclangir -fclangir-call-conv-lowering -emit-cir -mmlir --mlir-print-ir-after=cir-call-conv-lowering %s -o %t.cir
22
// RUN: FileCheck --input-file=%t.cir %s
33

4-
// Just check if the pass is called for now.
5-
// CHECK: module
4+
// CHECK: @_Z4Voidv()
5+
void Void(void) {
6+
// CHECK: cir.call @_Z4Voidv() : () -> ()
7+
Void();
8+
}

0 commit comments

Comments
 (0)
Please sign in to comment.