clang 24.0.0git
CIRPasses.cpp
Go to the documentation of this file.
1//===----------------------------------------------------------------------===//
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 implements machinery for any CIR <-> CIR passes used by clang.
10//
11//===----------------------------------------------------------------------===//
12
13#include "mlir/IR/BuiltinOps.h"
14#include "mlir/Pass/PassManager.h"
18#include "llvm/Support/TimeProfiler.h"
19#include "llvm/TargetParser/Triple.h"
20
21namespace cir {
22
23/// Map a target triple to the ABI target that drives CallConvLowering.
24/// Returns None for targets whose calling convention is not yet implemented.
25static CallConvTarget getCallConvTarget(const llvm::Triple &triple) {
26 // Windows is not supported. UEFI shares its convention.
27 if (triple.getArch() == llvm::Triple::x86_64 && !triple.isOSWindowsOrUEFI())
30}
31
32/// The AVX level the classifier uses to size a native vector, read from the
33/// target ABI name.
34static llvm::abi::X86AVXABILevel getX86AVXABILevel(llvm::StringRef abi) {
35 if (abi == "avx512")
36 return llvm::abi::X86AVXABILevel::AVX512;
37 if (abi == "avx")
38 return llvm::abi::X86AVXABILevel::AVX;
39 return llvm::abi::X86AVXABILevel::None;
40}
41
42/// Whether `__attribute__((target(...)))` on a function may raise its AVX ABI
43/// level above the command line's. A target that opts out, and any ABI older
44/// than the rule, stay at the module level.
45static bool allowsX86TargetAttrAvx(const llvm::Triple &triple,
47 return !triple.isPS() && compat > clang::LangOptions::ClangABI::Ver23;
48}
49
50/// The x86_64 ABI-compatibility flags, derived from the target and the
51/// requested compatibility version. Every flag defaults to true in the ABI
52/// library, which is not what any target computes: Clang11Compat is false for a
53/// modern Linux target, so leaving it at the default classifies a union larger
54/// than an eightbyte as though every member spanned its size.
55static llvm::abi::X86ABICompatInfo
56getX86ABICompatInfo(const llvm::Triple &triple,
58 llvm::abi::X86ABICompatInfo abiCompat;
59 abiCompat.HonorsRevision98 = !triple.isOSDarwin();
60 abiCompat.ClassifyIntegerMMXAsSSE =
61 compat > clang::LangOptions::ClangABI::Ver3_8 && !triple.isOSDarwin() &&
62 !triple.isPS() && !triple.isOSFreeBSD();
63 abiCompat.PassInt128VectorsInMem =
64 compat > clang::LangOptions::ClangABI::Ver9 &&
65 (triple.isOSLinux() || triple.isOSNetBSD());
66 abiCompat.ReturnCXXRecordGreaterThan128InMem =
67 compat > clang::LangOptions::ClangABI::Ver20 && !triple.isPS();
68 abiCompat.Clang11Compat =
69 compat <= clang::LangOptions::ClangABI::Ver11 || triple.isPS();
70 return abiCompat;
71}
72
73mlir::LogicalResult
74runCIRToCIRPasses(mlir::ModuleOp theModule, mlir::MLIRContext &mlirContext,
75 bool enableVerifier, bool enableIdiomRecognizer,
76 bool enableCIRSimplify, bool enableLibOpt,
77 llvm::StringRef libOptOptions, bool enableCallConvLowering) {
78
79 llvm::TimeTraceScope scope("CIR To CIR Passes");
80
81 std::optional<llvm::Triple> triple = cir::getTripleFromModule(theModule);
82 if (!triple)
83 return theModule.emitError()
84 << "missing '" << cir::CIRDialect::getTripleAttrName()
85 << "' attribute";
86
87 auto abiAttr = theModule->getAttrOfType<mlir::StringAttr>(
88 cir::CIRDialect::getTargetABIAttrName());
89 if (!abiAttr)
90 return theModule.emitError()
91 << "missing '" << cir::CIRDialect::getTargetABIAttrName()
92 << "' attribute";
93
94 mlir::PassManager pm(&mlirContext);
96
97 if (enableCIRSimplify)
98 pm.addPass(mlir::createCIRSimplifyPass());
99
100 if (enableIdiomRecognizer)
102
103 if (enableLibOpt) {
104 auto libOptPass = mlir::createLibOptPass();
105 auto errorHandler = [](const llvm::Twine &) -> mlir::LogicalResult {
106 return mlir::LogicalResult::failure();
107 };
108
109 if (libOptPass->initializeOptions(libOptOptions, errorHandler).failed())
110 return mlir::failure();
111
112 pm.addPass(std::move(libOptPass));
113 }
114
115 pm.addPass(mlir::createTargetLoweringPass());
116 pm.addPass(mlir::createCXXABILoweringPass());
117
118 // LoweringPrepare synthesizes calls to runtime helpers such as __divsc3, and
119 // outlines dynamic global initializers into functions. It must run before
120 // CallConvLowering so the classifier sees them, otherwise their signatures
121 // go unclassified and caller and callee disagree on the ABI.
123
124 if (enableCallConvLowering) {
125 // CallConvLowering rewrites signatures and call sites using the classifier,
126 // so it must run after CXXABILowering has lowered C++ ABI types to plain
127 // records the classifier can handle. Only the x86_64 System V classifier
128 // is implemented; other targets are left unchanged.
129 CallConvTarget target = getCallConvTarget(*triple);
130 if (target != CallConvTarget::None) {
131 // Source the ABI-compatibility version from the module's serialized
132 // #cir.lowering_options so a reloaded .cir classifies the same way
133 // it was compiled, without a live clang::LangOptions. CIRGen sets this
134 // attribute at module construction; if it is absent fall back to the
135 // LangOptions default, matching how LowerModule reads the same attribute.
136 auto compat = clang::LangOptions::ClangABI::Latest;
137 if (auto loweringLangOpts =
138 theModule->getAttrOfType<cir::LoweringOptionsAttr>(
139 cir::CIRDialect::getLoweringOptionsAttrName()))
140 compat = static_cast<clang::LangOptions::ClangABI>(
141 loweringLangOpts.getClangAbiCompat());
143 target, getX86AVXABILevel(abiAttr.getValue()),
144 allowsX86TargetAttrAvx(*triple, compat),
145 getX86ABICompatInfo(*triple, compat)));
146 }
147 }
148
149 pm.enableVerifier(enableVerifier);
150 (void)mlir::applyPassManagerCLOptions(pm);
151 return pm.run(theModule);
152}
153
154} // namespace cir
155
156namespace mlir {
157
158void populateCIRPreLoweringPasses(OpPassManager &pm) {
159 pm.addPass(createHoistAllocasPass());
160 pm.addPass(createCIRFlattenCFGPass());
161 pm.addPass(createCIREHABILoweringPass());
162 pm.addPass(createGotoSolverPass());
163 pm.addPass(createCIRFoldEmptyBranchesPass());
164}
165
166} // namespace mlir
Defines the clang::LangOptions interface.
ClangABI
Clang versions with different platform ABI conformance.
static bool allowsX86TargetAttrAvx(const llvm::Triple &triple, clang::LangOptions::ClangABI compat)
Whether __attribute__((target(...))) on a function may raise its AVX ABI level above the command line...
Definition CIRPasses.cpp:45
static CallConvTarget getCallConvTarget(const llvm::Triple &triple)
Map a target triple to the ABI target that drives CallConvLowering.
Definition CIRPasses.cpp:25
mlir::LogicalResult runCIRToCIRPasses(mlir::ModuleOp theModule, mlir::MLIRContext &mlirCtx, bool enableVerifier, bool enableIdiomRecognizer, bool enableCIRSimplify, bool enableLibOpt, llvm::StringRef libOptOptions, bool enableCallConvLowering)
Definition CIRPasses.cpp:74
static llvm::abi::X86AVXABILevel getX86AVXABILevel(llvm::StringRef abi)
The AVX level the classifier uses to size a native vector, read from the target ABI name.
Definition CIRPasses.cpp:34
static llvm::abi::X86ABICompatInfo getX86ABICompatInfo(const llvm::Triple &triple, clang::LangOptions::ClangABI compat)
The x86_64 ABI-compatibility flags, derived from the target and the requested compatibility version.
Definition CIRPasses.cpp:56
std::optional< llvm::Triple > getTripleFromModule(mlir::ModuleOp mod)
Attempts to construct an llvm::Triple from a module's cir.triple attribute.
CallConvTarget
The ABI target whose calling-convention rules drive CallConvLowering.
Definition Passes.h:23
std::unique_ptr< Pass > createCallConvLoweringPass()
std::unique_ptr< Pass > createCIREHABILoweringPass()
std::unique_ptr< Pass > createCIRCanonicalizePass()
std::unique_ptr< Pass > createCIRFlattenCFGPass()
std::unique_ptr< Pass > createLibOptPass()
Definition LibOpt.cpp:73
std::unique_ptr< Pass > createIdiomRecognizerPass()
void populateCIRPreLoweringPasses(mlir::OpPassManager &pm)
std::unique_ptr< Pass > createTargetLoweringPass()
std::unique_ptr< Pass > createGotoSolverPass()
std::unique_ptr< Pass > createLoweringPreparePass()
std::unique_ptr< Pass > createCIRSimplifyPass()
std::unique_ptr< Pass > createCXXABILoweringPass()
std::unique_ptr< Pass > createHoistAllocasPass()
std::unique_ptr< Pass > createCIRFoldEmptyBranchesPass()