Skip to content

Commit db6b7c0

Browse files
authored
[CIR][ABI] Apply CC lowering pass by default (#842)
Before this patch, the CC lowering pass was applied only when explicitly requested by the user. This update changes the default behavior to always apply the CC lowering pass, with an option to disable it using the `-fno-clangir-call-conv-lowering` flag if necessary. The primary objective is to make this pass a mandatory step in the compilation pipeline. This ensures that future contributions correctly implement the CC lowering for both existing and new targets, resulting in more consistent and accurate code generation. From an implementation perspective, several `llvm_unreachable` statements have been substituted with a new `assert_or_abort` macro. This macro can be configured to either trigger a non-blocking assertion or a blocking unreachable statement. This facilitates a test-by-testa incremental development as it does not required you to know which code path a test will trigger an just cause a crash if it does. A few notable changes: - Support multi-block function in CC lowering - Ignore pointer-related CC lowering - Ignore no-proto functions CC lowering - Handle missing type evaluation kinds - Fix CC lowering for function declarations - Unblock indirect function calls - Disable CC lowering pass on several tests
1 parent bcd8e04 commit db6b7c0

32 files changed

+282
-197
lines changed

clang/include/clang/CIR/Dialect/Passes.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ std::unique_ptr<Pass> createGotoSolverPass();
4242
/// Create a pass to lower ABI-independent function definitions/calls.
4343
std::unique_ptr<Pass> createCallConvLoweringPass();
4444

45-
void populateCIRPreLoweringPasses(mlir::OpPassManager &pm);
45+
void populateCIRPreLoweringPasses(mlir::OpPassManager &pm, bool useCCLowering);
4646

4747
//===----------------------------------------------------------------------===//
4848
// Registration

clang/include/clang/CIR/MissingFeatures.h

+41
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,27 @@
1515
#ifndef CLANG_CIR_MISSINGFEATURES_H
1616
#define CLANG_CIR_MISSINGFEATURES_H
1717

18+
constexpr bool cirMissingFeatureAssertionMode =
19+
true; // Change to `false` to use llvm_unreachable
20+
21+
#define NOTE \
22+
" Target lowering is now required. Disable it with " \
23+
"-fno-clangir-call-conv-lowering."
24+
25+
// Special assertion to be used in the target lowering library.
26+
#define cir_tl_assert(cond) assert((cond) && NOTE);
27+
28+
// Some assertions knowingly generate incorrect code. This macro allows us to
29+
// switch between using `assert` and `llvm_unreachable` for these cases.
30+
#define cir_assert_or_abort(cond, msg) \
31+
do { \
32+
if (cirMissingFeatureAssertionMode) { \
33+
assert((cond) && msg NOTE); \
34+
} else { \
35+
llvm_unreachable(msg NOTE); \
36+
} \
37+
} while (0)
38+
1839
namespace cir {
1940

2041
struct MissingFeatures {
@@ -212,6 +233,26 @@ struct MissingFeatures {
212233

213234
//===--- ABI lowering --===//
214235

236+
static bool SPIRVABI() { return false; }
237+
238+
static bool AArch64TypeClassification() { return false; }
239+
240+
static bool X86ArgTypeClassification() { return false; }
241+
static bool X86DefaultABITypeConvertion() { return false; }
242+
static bool X86GetFPTypeAtOffset() { return false; }
243+
static bool X86RetTypeClassification() { return false; }
244+
static bool X86TypeClassification() { return false; }
245+
246+
static bool ABIClangTypeKind() { return false; }
247+
static bool ABIEnterStructForCoercedAccess() { return false; }
248+
static bool ABIFuncPtr() { return false; }
249+
static bool ABIInRegAttribute() { return false; }
250+
static bool ABINestedRecordLayout() { return false; }
251+
static bool ABINoProtoFunctions() { return false; }
252+
static bool ABIParameterCoercion() { return false; }
253+
static bool ABIPointerParameterAttrs() { return false; }
254+
static bool ABITransparentUnionHandling() { return false; }
255+
215256
//-- Missing AST queries
216257

217258
static bool CXXRecordDeclIsEmptyCXX11() { return false; }

clang/include/clang/Driver/Options.td

+7-4
Original file line numberDiff line numberDiff line change
@@ -2978,10 +2978,6 @@ def fclangir_lib_opt : Flag<["-"], "fclangir-lib-opt">,
29782978
Visibility<[ClangOption, CC1Option]>, Group<f_Group>,
29792979
Alias<fclangir_lib_opt_EQ>,
29802980
HelpText<"Enable C/C++ library based optimizations">;
2981-
def fclangir_call_conv_lowering : Flag<["-"], "fclangir-call-conv-lowering">,
2982-
Visibility<[ClangOption, CC1Option]>, Group<f_Group>,
2983-
HelpText<"Enable ClangIR calling convention lowering">,
2984-
MarshallingInfoFlag<FrontendOpts<"ClangIREnableCallConvLowering">>;
29852981
def fclangir_mem2reg : Flag<["-"], "fclangir-mem2reg">,
29862982
Visibility<[ClangOption, CC1Option]>, Group<f_Group>,
29872983
HelpText<"Enable mem2reg on the flat ClangIR">,
@@ -3012,6 +3008,13 @@ defm clangir_analysis_only : BoolFOption<"clangir-analysis-only",
30123008
PosFlag<SetTrue, [], [ClangOption, CC1Option],
30133009
"Enable CIR analysis but keep traditional LLVM codegen (not through CIR)">,
30143010
NegFlag<SetFalse, [], [ClangOption, CC1Option], "">>;
3011+
// FIXME(cir): Remove this option once all pre-existing tests are compatible with
3012+
// the calling convention lowering pass.
3013+
defm clangir_call_conv_lowering : BoolFOption<"clangir-call-conv-lowering",
3014+
FrontendOpts<"ClangIRCallConvLowering">, DefaultTrue,
3015+
PosFlag<SetTrue, [], [ClangOption, CC1Option], "Transform CIR to abide to calling convetions during lowering">,
3016+
NegFlag<SetFalse, [], [ClangOption, CC1Option], "Ignore calling convetion during lowering">,
3017+
BothFlags<[], [ClangOption, CC1Option], "">>;
30153018

30163019
def emit_cir : Flag<["-"], "emit-cir">, Visibility<[CC1Option]>,
30173020
Group<Action_Group>, HelpText<"Build ASTs and then lower to ClangIR, emit the .cir file">;

clang/include/clang/Frontend/FrontendOptions.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -445,7 +445,7 @@ class FrontendOptions {
445445
unsigned ClangIRLibOpt : 1;
446446

447447
// Enable Clang IR call conv lowering pass.
448-
unsigned ClangIREnableCallConvLowering : 1;
448+
unsigned ClangIRCallConvLowering : 1;
449449

450450
// Enable Clang IR mem2reg pass on the flat CIR.
451451
unsigned ClangIREnableMem2Reg : 1;

clang/lib/CIR/CodeGen/CIRPasses.cpp

+4-7
Original file line numberDiff line numberDiff line change
@@ -71,13 +71,8 @@ mlir::LogicalResult runCIRToCIRPasses(
7171

7272
pm.addPass(mlir::createLoweringPreparePass(&astCtx));
7373

74-
// FIXME(cir): This pass should run by default, but it is lacking support for
75-
// several code bits. Once it's more mature, we should fix this.
76-
if (enableCallConvLowering)
77-
pm.addPass(mlir::createCallConvLoweringPass());
78-
7974
if (flattenCIR || enableMem2Reg)
80-
mlir::populateCIRPreLoweringPasses(pm);
75+
mlir::populateCIRPreLoweringPasses(pm, enableCallConvLowering);
8176

8277
if (enableMem2Reg)
8378
pm.addPass(mlir::createMem2Reg());
@@ -97,7 +92,9 @@ mlir::LogicalResult runCIRToCIRPasses(
9792

9893
namespace mlir {
9994

100-
void populateCIRPreLoweringPasses(OpPassManager &pm) {
95+
void populateCIRPreLoweringPasses(OpPassManager &pm, bool useCCLowering) {
96+
if (useCCLowering)
97+
pm.addPass(createCallConvLoweringPass());
10198
pm.addPass(createFlattenCFGPass());
10299
pm.addPass(createGotoSolverPass());
103100
}

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

+7-1
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,14 @@
66
//
77
//===----------------------------------------------------------------------===//
88

9-
109
#include "TargetLowering/LowerModule.h"
1110
#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
1211
#include "mlir/IR/BuiltinOps.h"
1312
#include "mlir/IR/PatternMatch.h"
1413
#include "mlir/Pass/Pass.h"
1514
#include "mlir/Transforms/GreedyPatternRewriteDriver.h"
1615
#include "clang/CIR/Dialect/IR/CIRDialect.h"
16+
#include "clang/CIR/MissingFeatures.h"
1717

1818
#define GEN_PASS_DEF_CALLCONVLOWERING
1919
#include "clang/CIR/Dialect/Passes.h.inc"
@@ -44,6 +44,12 @@ struct CallConvLoweringPattern : public OpRewritePattern<FuncOp> {
4444
auto calls = op.getSymbolUses(module);
4545
if (calls.has_value()) {
4646
for (auto call : calls.value()) {
47+
// FIXME(cir): Function pointers are ignored.
48+
if (isa<GetGlobalOp>(call.getUser())) {
49+
cir_assert_or_abort(!::cir::MissingFeatures::ABIFuncPtr(), "NYI");
50+
continue;
51+
}
52+
4753
auto callOp = cast<CallOp>(call.getUser());
4854
if (lowerModule->rewriteFunctionCall(callOp, op).failed())
4955
return failure();

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ bool ABIInfo::isPromotableIntegerTypeForABI(Type Ty) const {
3737
if (getContext().isPromotableIntegerType(Ty))
3838
return true;
3939

40-
assert(!::cir::MissingFeatures::fixedWidthIntegers());
40+
cir_tl_assert(!::cir::MissingFeatures::fixedWidthIntegers());
4141

4242
return false;
4343
}

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

+4-3
Original file line numberDiff line numberDiff line change
@@ -26,21 +26,22 @@ bool classifyReturnType(const CIRCXXABI &CXXABI, LowerFunctionInfo &FI,
2626
Type Ty = FI.getReturnType();
2727

2828
if (const auto RT = dyn_cast<StructType>(Ty)) {
29-
assert(!::cir::MissingFeatures::isCXXRecordDecl());
29+
cir_tl_assert(!::cir::MissingFeatures::isCXXRecordDecl());
3030
}
3131

3232
return CXXABI.classifyReturnType(FI);
3333
}
3434

3535
bool isAggregateTypeForABI(Type T) {
36-
assert(!::cir::MissingFeatures::functionMemberPointerType());
36+
cir_tl_assert(!::cir::MissingFeatures::functionMemberPointerType());
3737
return !LowerFunction::hasScalarEvaluationKind(T);
3838
}
3939

4040
Type useFirstFieldIfTransparentUnion(Type Ty) {
4141
if (auto RT = dyn_cast<StructType>(Ty)) {
4242
if (RT.isUnion())
43-
llvm_unreachable("NYI");
43+
cir_assert_or_abort(
44+
!::cir::MissingFeatures::ABITransparentUnionHandling(), "NYI");
4445
}
4546
return Ty;
4647
}

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

+10-7
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,10 @@ clang::TypeInfo CIRLowerContext::getTypeInfoImpl(const Type T) const {
5555
} else if (isa<StructType>(T)) {
5656
typeKind = clang::Type::Record;
5757
} else {
58-
llvm_unreachable("Unhandled type class");
58+
cir_assert_or_abort(!::cir::MissingFeatures::ABIClangTypeKind(),
59+
"Unhandled type class");
60+
// FIXME(cir): Completely wrong. Just here to make it non-blocking.
61+
typeKind = clang::Type::Builtin;
5962
}
6063

6164
// FIXME(cir): Here we fetch the width and alignment of a type considering the
@@ -96,10 +99,10 @@ clang::TypeInfo CIRLowerContext::getTypeInfoImpl(const Type T) const {
9699
}
97100
case clang::Type::Record: {
98101
const auto RT = dyn_cast<StructType>(T);
99-
assert(!::cir::MissingFeatures::tagTypeClassAbstraction());
102+
cir_tl_assert(!::cir::MissingFeatures::tagTypeClassAbstraction());
100103

101104
// Only handle TagTypes (names types) for now.
102-
assert(RT.getName() && "Anonymous record is NYI");
105+
cir_tl_assert(RT.getName() && "Anonymous record is NYI");
103106

104107
// NOTE(cir): Clang does some hanlding of invalid tagged declarations here.
105108
// Not sure if this is necessary in CIR.
@@ -111,22 +114,22 @@ clang::TypeInfo CIRLowerContext::getTypeInfoImpl(const Type T) const {
111114
const CIRRecordLayout &Layout = getCIRRecordLayout(RT);
112115
Width = toBits(Layout.getSize());
113116
Align = toBits(Layout.getAlignment());
114-
assert(!::cir::MissingFeatures::recordDeclHasAlignmentAttr());
117+
cir_tl_assert(!::cir::MissingFeatures::recordDeclHasAlignmentAttr());
115118
break;
116119
}
117120
default:
118121
llvm_unreachable("Unhandled type class");
119122
}
120123

121-
assert(llvm::isPowerOf2_32(Align) && "Alignment must be power of 2");
124+
cir_tl_assert(llvm::isPowerOf2_32(Align) && "Alignment must be power of 2");
122125
return clang::TypeInfo(Width, Align, AlignRequirement);
123126
}
124127

125128
Type CIRLowerContext::initBuiltinType(clang::BuiltinType::Kind K) {
126129
Type Ty;
127130

128131
// NOTE(cir): Clang does more stuff here. Not sure if we need to do the same.
129-
assert(!::cir::MissingFeatures::qualifiedTypes());
132+
cir_tl_assert(!::cir::MissingFeatures::qualifiedTypes());
130133
switch (K) {
131134
case clang::BuiltinType::Char_S:
132135
Ty = IntType::get(getMLIRContext(), 8, true);
@@ -141,7 +144,7 @@ Type CIRLowerContext::initBuiltinType(clang::BuiltinType::Kind K) {
141144

142145
void CIRLowerContext::initBuiltinTypes(const clang::TargetInfo &Target,
143146
const clang::TargetInfo *AuxTarget) {
144-
assert((!this->Target || this->Target == &Target) &&
147+
cir_tl_assert((!this->Target || this->Target == &Target) &&
145148
"Incorrect target reinitialization");
146149
this->Target = &Target;
147150
this->AuxTarget = AuxTarget;

clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRRecordLayout.cpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -38,16 +38,16 @@ CIRRecordLayout::CIRRecordLayout(
3838
FieldOffsets.insert(FieldOffsets.end(), fieldoffsets.begin(),
3939
fieldoffsets.end());
4040

41-
assert(!PrimaryBase && "Layout for class with inheritance is NYI");
41+
cir_tl_assert(!PrimaryBase && "Layout for class with inheritance is NYI");
4242
// CXXInfo->PrimaryBase.setPointer(PrimaryBase);
43-
assert(!IsPrimaryBaseVirtual && "Layout for virtual base class is NYI");
43+
cir_tl_assert(!IsPrimaryBaseVirtual && "Layout for virtual base class is NYI");
4444
// CXXInfo->PrimaryBase.setInt(IsPrimaryBaseVirtual);
4545
CXXInfo->NonVirtualSize = nonvirtualsize;
4646
CXXInfo->NonVirtualAlignment = nonvirtualalignment;
4747
CXXInfo->PreferredNVAlignment = preferrednvalignment;
4848
CXXInfo->SizeOfLargestEmptySubobject = SizeOfLargestEmptySubobject;
4949
// FIXME(cir): Initialize base classes offsets.
50-
assert(!::cir::MissingFeatures::getCXXRecordBases());
50+
cir_tl_assert(!::cir::MissingFeatures::getCXXRecordBases());
5151
CXXInfo->HasOwnVFPtr = hasOwnVFPtr;
5252
CXXInfo->VBPtrOffset = vbptroffset;
5353
CXXInfo->HasExtendableVFPtr = hasExtendableVFPtr;

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

+5-5
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ class CIRToCIRArgMapping {
5858
unsigned totalIRArgs() const { return TotalIRArgs; }
5959

6060
bool hasPaddingArg(unsigned ArgNo) const {
61-
assert(ArgNo < ArgInfo.size());
61+
cir_tl_assert(ArgNo < ArgInfo.size());
6262
return ArgInfo[ArgNo].PaddingArgIndex != InvalidIndex;
6363
}
6464

@@ -77,7 +77,7 @@ class CIRToCIRArgMapping {
7777
onlyRequiredArgs ? FI.getNumRequiredArgs() : FI.arg_size();
7878
for (LowerFunctionInfo::const_arg_iterator I = FI.arg_begin();
7979
ArgNo < NumArgs; ++I, ++ArgNo) {
80-
assert(I != FI.arg_end());
80+
cir_tl_assert(I != FI.arg_end());
8181
// Type ArgType = I->type;
8282
const ::cir::ABIArgInfo &AI = I->info;
8383
// Collect data about IR arguments corresponding to Clang argument ArgNo.
@@ -91,7 +91,7 @@ class CIRToCIRArgMapping {
9191
case ::cir::ABIArgInfo::Extend:
9292
case ::cir::ABIArgInfo::Direct: {
9393
// FIXME(cir): handle sseregparm someday...
94-
assert(AI.getCoerceToType() && "Missing coerced type!!");
94+
cir_tl_assert(AI.getCoerceToType() && "Missing coerced type!!");
9595
StructType STy = dyn_cast<StructType>(AI.getCoerceToType());
9696
if (AI.isDirect() && AI.getCanBeFlattened() && STy) {
9797
llvm_unreachable("NYI");
@@ -114,7 +114,7 @@ class CIRToCIRArgMapping {
114114
if (IRArgNo == 1 && SwapThisWithSRet)
115115
IRArgNo++;
116116
}
117-
assert(ArgNo == ArgInfo.size());
117+
cir_tl_assert(ArgNo == ArgInfo.size());
118118

119119
if (::cir::MissingFeatures::inallocaArgs()) {
120120
llvm_unreachable("NYI");
@@ -126,7 +126,7 @@ class CIRToCIRArgMapping {
126126
/// Returns index of first IR argument corresponding to ArgNo, and their
127127
/// quantity.
128128
std::pair<unsigned, unsigned> getIRArgs(unsigned ArgNo) const {
129-
assert(ArgNo < ArgInfo.size());
129+
cir_tl_assert(ArgNo < ArgInfo.size());
130130
return std::make_pair(ArgInfo[ArgNo].FirstArgIndex,
131131
ArgInfo[ArgNo].NumberOfArgs);
132132
}

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

+3-3
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,9 @@ class ItaniumCXXABI : public CIRCXXABI {
4646

4747
// FIXME(cir): This expects a CXXRecordDecl! Not any record type.
4848
RecordArgABI getRecordArgABI(const StructType RD) const override {
49-
assert(!::cir::MissingFeatures::recordDeclIsCXXDecl());
49+
cir_tl_assert(!::cir::MissingFeatures::recordDeclIsCXXDecl());
5050
// If C++ prohibits us from making a copy, pass by address.
51-
assert(!::cir::MissingFeatures::recordDeclCanPassInRegisters());
51+
cir_tl_assert(!::cir::MissingFeatures::recordDeclCanPassInRegisters());
5252
return RAA_Default;
5353
}
5454
};
@@ -76,7 +76,7 @@ CIRCXXABI *CreateItaniumCXXABI(LowerModule &LM) {
7676
case clang::TargetCXXABI::AppleARM64:
7777
// TODO: this isn't quite right, clang uses AppleARM64CXXABI which inherits
7878
// from ARMCXXABI. We'll have to follow suit.
79-
assert(!::cir::MissingFeatures::appleArm64CXXABI());
79+
cir_tl_assert(!::cir::MissingFeatures::appleArm64CXXABI());
8080
return new ItaniumCXXABI(LM, /*UseARMMethodPtrABI=*/true,
8181
/*UseARMGuardVarABI=*/true);
8282

0 commit comments

Comments
 (0)