Skip to content

Commit eba4924

Browse files
Apply code review suggestions and add tests
1 parent a91edc3 commit eba4924

File tree

8 files changed

+173
-79
lines changed

8 files changed

+173
-79
lines changed

clang/lib/CIR/CodeGen/CIRGenExpr.cpp

Lines changed: 18 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "clang/AST/CharUnits.h"
1919
#include "clang/AST/Decl.h"
2020
#include "clang/AST/Expr.h"
21+
#include "clang/AST/ExprCXX.h"
2122
#include "clang/CIR/Dialect/IR/CIRDialect.h"
2223
#include "clang/CIR/MissingFeatures.h"
2324

@@ -479,18 +480,10 @@ void CIRGenFunction::emitIgnoredExpr(const Expr *e) {
479480
mlir::LogicalResult CIRGenFunction::emitIfOnBoolExpr(const Expr *cond,
480481
const Stmt *thenS,
481482
const Stmt *elseS) {
482-
// Attempt to be more accurate as possible with IfOp location, generate
483-
// one fused location that has either 2 or 4 total locations, depending
484-
// on else's availability.
485-
auto getStmtLoc = [this](const Stmt &s) {
486-
return mlir::FusedLoc::get(&getMLIRContext(),
487-
{getLoc(s.getSourceRange().getBegin()),
488-
getLoc(s.getSourceRange().getEnd())});
489-
};
490-
mlir::Location thenLoc = getStmtLoc(*thenS);
483+
mlir::Location thenLoc = getLoc(thenS->getSourceRange());
491484
std::optional<mlir::Location> elseLoc;
492485
if (elseS)
493-
elseLoc = getStmtLoc(*elseS);
486+
elseLoc = getLoc(elseS->getSourceRange());
494487

495488
mlir::LogicalResult resThen = mlir::success(), resElse = mlir::success();
496489
emitIfOnBoolExpr(
@@ -518,7 +511,9 @@ cir::IfOp CIRGenFunction::emitIfOnBoolExpr(
518511
const clang::Expr *cond, BuilderCallbackRef thenBuilder,
519512
mlir::Location thenLoc, BuilderCallbackRef elseBuilder,
520513
std::optional<mlir::Location> elseLoc) {
521-
514+
// Attempt to be as accurate as possible with IfOp location, generate
515+
// one fused location that has either 2 or 4 total locations, depending
516+
// on else's availability.
522517
SmallVector<mlir::Location, 2> ifLocs{thenLoc};
523518
if (elseLoc)
524519
ifLocs.push_back(*elseLoc);
@@ -531,44 +526,34 @@ cir::IfOp CIRGenFunction::emitIfOnBoolExpr(
531526
/*elseBuilder=*/elseBuilder);
532527
}
533528

534-
/// TODO(cir): PGO data
535529
/// TODO(cir): see EmitBranchOnBoolExpr for extra ideas).
536530
mlir::Value CIRGenFunction::emitOpOnBoolExpr(mlir::Location loc,
537531
const Expr *cond) {
538-
// TODO(CIR): scoped ApplyDebugLocation DL(*this, Cond);
539-
// TODO(CIR): __builtin_unpredictable and profile counts?
532+
assert(!cir::MissingFeatures::pgoUse());
533+
assert(!cir::MissingFeatures::generateDebugInfo());
540534
cond = cond->IgnoreParens();
541535

542-
// if (const BinaryOperator *CondBOp = dyn_cast<BinaryOperator>(cond)) {
543-
// llvm_unreachable("binaryoperator ifstmt NYI");
544-
// }
545-
546-
if (const UnaryOperator *CondUOp = dyn_cast<UnaryOperator>(cond)) {
547-
// In LLVM the condition is reversed here for efficient codegen.
548-
// This should be done in CIR prior to LLVM lowering, if we do now
549-
// we can make CIR based diagnostics misleading.
550-
// cir.ternary(!x, t, f) -> cir.ternary(x, f, t)
551-
assert(!cir::MissingFeatures::shouldReverseUnaryCondOnBoolExpr());
552-
}
536+
// In LLVM the condition is reversed here for efficient codegen.
537+
// This should be done in CIR prior to LLVM lowering, if we do now
538+
// we can make CIR based diagnostics misleading.
539+
// cir.ternary(!x, t, f) -> cir.ternary(x, f, t)
540+
assert(!cir::MissingFeatures::shouldReverseUnaryCondOnBoolExpr());
553541

554-
if (const ConditionalOperator *CondOp = dyn_cast<ConditionalOperator>(cond)) {
542+
if (isa<ConditionalOperator>(cond)) {
555543

556544
cgm.errorNYI(cond->getExprLoc(), "Ternary NYI");
557545
assert(!cir::MissingFeatures::ternaryOp());
558546
return createDummyValue(loc, cond->getType());
559547
}
560548

561-
// if (const CXXThrowExpr *Throw = dyn_cast<CXXThrowExpr>(cond)) {
562-
// llvm_unreachable("NYI");
563-
// }
549+
if (isa<CXXThrowExpr>(cond)) {
550+
cgm.errorNYI("NYI");
551+
}
564552

565553
// If the branch has a condition wrapped by __builtin_unpredictable,
566554
// create metadata that specifies that the branch is unpredictable.
567555
// Don't bother if not optimizing because that metadata would not be used.
568-
auto *Call = dyn_cast<CallExpr>(cond->IgnoreImpCasts());
569-
if (Call && cgm.getCodeGenOpts().OptimizationLevel != 0) {
570-
assert(!cir::MissingFeatures::insertBuiltinUnpredictable());
571-
}
556+
assert(!cir::MissingFeatures::insertBuiltinUnpredictable());
572557

573558
// Emit the code with the fully general case.
574559
return evaluateExprAsBool(cond);

clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1487,14 +1487,14 @@ mlir::Value ScalarExprEmitter::VisitUnaryLNot(const UnaryOperator *e) {
14871487
/// If the specified expression does not fold
14881488
/// to a constant, or if it does but contains a label, return false. If it
14891489
/// constant folds return true and set the boolean result in Result.
1490-
bool CIRGenFunction::ConstantFoldsToSimpleInteger(const Expr *Cond,
1491-
bool &ResultBool,
1492-
bool AllowLabels) {
1493-
llvm::APSInt ResultInt;
1494-
if (!ConstantFoldsToSimpleInteger(Cond, ResultInt, AllowLabels))
1490+
bool CIRGenFunction::constantFoldsToSimpleInteger(const Expr *cond,
1491+
bool &resultBool,
1492+
bool allowLabels) {
1493+
llvm::APSInt resultInt;
1494+
if (!constantFoldsToSimpleInteger(cond, resultInt, allowLabels))
14951495
return false;
14961496

1497-
ResultBool = ResultInt.getBoolValue();
1497+
resultBool = resultInt.getBoolValue();
14981498
return true;
14991499
}
15001500

clang/lib/CIR/CodeGen/CIRGenFunction.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ mlir::Location CIRGenFunction::getLoc(mlir::Location lhs, mlir::Location rhs) {
135135
return mlir::FusedLoc::get(locs, metadata, &getMLIRContext());
136136
}
137137

138-
bool CIRGenFunction::ContainsLabel(const Stmt *s, bool ignoreCaseStmts) {
138+
bool CIRGenFunction::containsLabel(const Stmt *s, bool ignoreCaseStmts) {
139139
// Null statement, not a label!
140140
if (!s)
141141
return false;
@@ -160,14 +160,14 @@ bool CIRGenFunction::ContainsLabel(const Stmt *s, bool ignoreCaseStmts) {
160160
// Scan subexpressions for verboten labels.
161161
return std::any_of(s->child_begin(), s->child_end(),
162162
[=](const Stmt *subStmt) {
163-
return ContainsLabel(subStmt, ignoreCaseStmts);
163+
return containsLabel(subStmt, ignoreCaseStmts);
164164
});
165165
}
166166

167167
/// If the specified expression does not fold
168168
/// to a constant, or if it does but contains a label, return false. If it
169169
/// constant folds return true and set the folded value.
170-
bool CIRGenFunction::ConstantFoldsToSimpleInteger(const Expr *cond,
170+
bool CIRGenFunction::constantFoldsToSimpleInteger(const Expr *cond,
171171
llvm::APSInt &resultInt,
172172
bool allowLabels) {
173173
// FIXME: Rename and handle conversion of other evaluatable things
@@ -177,7 +177,7 @@ bool CIRGenFunction::ConstantFoldsToSimpleInteger(const Expr *cond,
177177
return false; // Not foldable, not integer or not fully evaluatable.
178178

179179
llvm::APSInt intValue = result.Val.getInt();
180-
if (!allowLabels && ContainsLabel(cond))
180+
if (!allowLabels && containsLabel(cond))
181181
return false; // Contains a label.
182182

183183
resultInt = intValue;

clang/lib/CIR/CodeGen/CIRGenFunction.h

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -170,16 +170,16 @@ class CIRGenFunction : public CIRGenTypeCache {
170170
/// If the specified expression does not fold to a constant, or if it does but
171171
/// contains a label, return false. If it constant folds return true and set
172172
/// the boolean result in Result.
173-
bool ConstantFoldsToSimpleInteger(const clang::Expr *Cond, bool &ResultBool,
174-
bool AllowLabels = false);
175-
bool ConstantFoldsToSimpleInteger(const clang::Expr *Cond,
176-
llvm::APSInt &ResultInt,
177-
bool AllowLabels = false);
173+
bool constantFoldsToSimpleInteger(const clang::Expr *cond, bool &resultBool,
174+
bool allowLabels = false);
175+
bool constantFoldsToSimpleInteger(const clang::Expr *cond,
176+
llvm::APSInt &resultInt,
177+
bool allowLabels = false);
178178

179179
/// Return true if the statement contains a label in it. If
180180
/// this statement is not executed normally, it not containing a label means
181181
/// that we can just remove the code.
182-
bool ContainsLabel(const clang::Stmt *s, bool IgnoreCaseStmts = false);
182+
bool containsLabel(const clang::Stmt *s, bool ignoreCaseStmts = false);
183183

184184
struct AutoVarEmission {
185185
const clang::VarDecl *Variable;
@@ -474,12 +474,12 @@ class CIRGenFunction : public CIRGenTypeCache {
474474
mlir::LogicalResult emitDeclStmt(const clang::DeclStmt &s);
475475
LValue emitDeclRefLValue(const clang::DeclRefExpr *e);
476476

477-
/// Emit an if on a boolean condition to the specified blocks.
477+
/// Emit an `if` on a boolean condition to the specified blocks.
478478
/// FIXME: Based on the condition, this might try to simplify the codegen of
479-
/// the conditional based on the branch. TrueCount should be the number of
480-
/// times we expect the condition to evaluate to true based on PGO data. We
481-
/// might decide to leave this as a separate pass (see EmitBranchOnBoolExpr
482-
/// for extra ideas).
479+
/// the conditional based on the branch.
480+
/// In the future, we may apply code generation simplifications here,
481+
/// similar to those used in classic LLVM codegen
482+
/// See `EmitBranchOnBoolExpr` for inspiration.
483483
mlir::LogicalResult emitIfOnBoolExpr(const clang::Expr *cond,
484484
const clang::Stmt *thenS,
485485
const clang::Stmt *elseS);

clang/lib/CIR/CodeGen/CIRGenStmt.cpp

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -286,10 +286,10 @@ mlir::LogicalResult CIRGenFunction::emitIfStmt(const IfStmt &s) {
286286
mlir::LogicalResult res = mlir::success();
287287
// The else branch of a consteval if statement is always the only branch
288288
// that can be runtime evaluated.
289-
const Stmt *ConstevalExecuted;
289+
const Stmt *constevalExecuted;
290290
if (s.isConsteval()) {
291-
ConstevalExecuted = s.isNegatedConsteval() ? s.getThen() : s.getElse();
292-
if (!ConstevalExecuted) {
291+
constevalExecuted = s.isNegatedConsteval() ? s.getThen() : s.getElse();
292+
if (!constevalExecuted) {
293293
// No runtime code execution required
294294
return res;
295295
}
@@ -299,7 +299,7 @@ mlir::LogicalResult CIRGenFunction::emitIfStmt(const IfStmt &s) {
299299
// compares unequal to 0. The condition must be a scalar type.
300300
auto ifStmtBuilder = [&]() -> mlir::LogicalResult {
301301
if (s.isConsteval())
302-
return emitStmt(ConstevalExecuted, /*useCurrentScope=*/true);
302+
return emitStmt(constevalExecuted, /*useCurrentScope=*/true);
303303

304304
if (s.getInit())
305305
if (emitStmt(s.getInit(), /*useCurrentScope=*/true).failed())
@@ -308,25 +308,22 @@ mlir::LogicalResult CIRGenFunction::emitIfStmt(const IfStmt &s) {
308308
if (s.getConditionVariable())
309309
emitDecl(*s.getConditionVariable());
310310

311-
// During LLVM codegen, if the condition constant folds and can be elided,
312-
// it tries to avoid emitting the condition and the dead arm of the if/else.
313-
// TODO(cir): we skip this in CIRGen, but should implement this as part of
314-
// SSCP or a specific CIR pass.
315-
bool CondConstant;
316-
if (ConstantFoldsToSimpleInteger(s.getCond(), CondConstant,
311+
// If the condition folds to a constant and this is an 'if constexpr',
312+
// we simplify it early in CIRGen to avoid emitting the full 'if'.
313+
bool condConstant;
314+
if (constantFoldsToSimpleInteger(s.getCond(), condConstant,
317315
s.isConstexpr())) {
318316
if (s.isConstexpr()) {
319317
// Handle "if constexpr" explicitly here to avoid generating some
320318
// ill-formed code since in CIR the "if" is no longer simplified
321319
// in this lambda like in Clang but postponed to other MLIR
322320
// passes.
323-
if (const Stmt *Executed = CondConstant ? s.getThen() : s.getElse())
324-
return emitStmt(Executed, /*useCurrentScope=*/true);
321+
if (const Stmt *executed = condConstant ? s.getThen() : s.getElse())
322+
return emitStmt(executed, /*useCurrentScope=*/true);
325323
// There is nothing to execute at runtime.
326324
// TODO(cir): there is still an empty cir.scope generated by the caller.
327325
return mlir::success();
328326
}
329-
assert(!cir::MissingFeatures::constantFoldsToSimpleInteger());
330327
}
331328

332329
assert(!cir::MissingFeatures::emitCondLikelihoodViaExpectIntrinsic());

clang/lib/CIR/Dialect/IR/CIRDialect.cpp

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -520,7 +520,6 @@ ParseResult cir::IfOp::parse(OpAsmParser &parser, OperationState &result) {
520520
}
521521

522522
void cir::IfOp::print(OpAsmPrinter &p) {
523-
524523
p << " " << getCondition() << " ";
525524
mlir::Region &thenRegion = this->getThenRegion();
526525
p.printRegion(thenRegion,
@@ -563,17 +562,6 @@ void cir::IfOp::getSuccessorRegions(mlir::RegionBranchPoint point,
563562
if (elseRegion->empty())
564563
elseRegion = nullptr;
565564

566-
// Otherwise, the successor is dependent on the condition.
567-
// bool condition;
568-
// if (auto condAttr = operands.front().dyn_cast_or_null<IntegerAttr>()) {
569-
// assert(0 && "not implemented");
570-
// condition = condAttr.getValue().isOneValue();
571-
// Add the successor regions using the condition.
572-
// regions.push_back(RegionSuccessor(condition ? &thenRegion() :
573-
// elseRegion));
574-
// return;
575-
// }
576-
577565
// If the condition isn't constant, both regions may be executed.
578566
regions.push_back(RegionSuccessor(&getThenRegion()));
579567
// If the else region does not exist, it is not a viable successor.
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// RUN: %clang_cc1 -std=c++23 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir
2+
// RUN: FileCheck --input-file=%t.cir %s --check-prefix=CIR
3+
// RUN: %clang_cc1 -std=c++23 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t-cir.ll
4+
// RUN: FileCheck --input-file=%t-cir.ll %s --check-prefix=LLVM
5+
// RUN: %clang_cc1 -std=c++23 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll
6+
// RUN: FileCheck --input-file=%t.ll %s --check-prefix=OGCG
7+
8+
void f() {
9+
int result = 0;
10+
11+
if consteval {
12+
result = 10;
13+
// CIR-NOT: cir.const #cir.int<10> : !s32i
14+
// LLVM-NOT: store i32 10, ptr %1, align 4
15+
// OGCG-NOT: store i32 10, ptr %result, align 4
16+
} else {
17+
result = 20;
18+
// CHECK: cir.const #cir.int<20> : !s32i
19+
// LLVM: store i32 20, ptr %1, align 4
20+
// OGCG: store i32 20, ptr %result, align 4
21+
22+
}
23+
24+
if !consteval {
25+
result = 30;
26+
// CIR: cir.const #cir.int<30> : !s32i
27+
// LLVM: store i32 30, ptr %1, align 4
28+
// OGCG: store i32 30, ptr %result, align 4
29+
} else {
30+
result = 40;
31+
// CIR-NOT: cir.const #cir.int<40> : !s32i
32+
// LLVM-NOT: store i32 40, ptr %1, align 4
33+
// OGCG-NOT: store i32 40, ptr %result, align 4
34+
}
35+
36+
if consteval {
37+
result = 50;
38+
// CIR-NOT: cir.const #cir.int<50> : !s32i
39+
// LLVM-NOT: store i32 50, ptr %1, align 4
40+
// OGCG-NOT: store i32 50, ptr %result, align 4
41+
}
42+
43+
if !consteval {
44+
result = 60;
45+
// CIR: cir.const #cir.int<60> : !s32i
46+
// LLVM: store i32 60, ptr %1, align 4
47+
// OGCG: store i32 60, ptr %result, align 4
48+
}
49+
50+
}

0 commit comments

Comments
 (0)