Skip to content

Commit 4b2cb11

Browse files
mmhaerichkeane
andauthored
[CIR] Upstream lowering of conditional operators to TernaryOp (#138156)
This patch adds visitors for BinLAnd, BinLOr and AbstractConditionalOperator. Note that this patch still lacks visitation of OpaqueValueExpr which is needed for the GNU ?: operator. --------- Co-authored-by: Erich Keane <[email protected]>
1 parent 0107c93 commit 4b2cb11

File tree

11 files changed

+992
-25
lines changed

11 files changed

+992
-25
lines changed

clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,24 @@ class CIRBaseBuilderTy : public mlir::OpBuilder {
300300
return createBinop(loc, lhs, cir::BinOpKind::Or, rhs);
301301
}
302302

303+
mlir::Value createSelect(mlir::Location loc, mlir::Value condition,
304+
mlir::Value trueValue, mlir::Value falseValue) {
305+
assert(trueValue.getType() == falseValue.getType() &&
306+
"trueValue and falseValue should have the same type");
307+
return create<cir::SelectOp>(loc, trueValue.getType(), condition, trueValue,
308+
falseValue);
309+
}
310+
311+
mlir::Value createLogicalAnd(mlir::Location loc, mlir::Value lhs,
312+
mlir::Value rhs) {
313+
return createSelect(loc, lhs, rhs, getBool(false, loc));
314+
}
315+
316+
mlir::Value createLogicalOr(mlir::Location loc, mlir::Value lhs,
317+
mlir::Value rhs) {
318+
return createSelect(loc, lhs, getBool(true, loc), rhs);
319+
}
320+
303321
mlir::Value createMul(mlir::Location loc, mlir::Value lhs, mlir::Value rhs,
304322
OverflowBehavior ob = OverflowBehavior::None) {
305323
auto op =

clang/include/clang/CIR/MissingFeatures.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,8 @@ struct MissingFeatures {
208208
static bool deferredDecls() { return false; }
209209
static bool setTargetAttributes() { return false; }
210210
static bool coverageMapping() { return false; }
211+
static bool peepholeProtection() { return false; }
212+
static bool instrumentation() { return false; }
211213

212214
// Missing types
213215
static bool dataMemberType() { return false; }
@@ -232,8 +234,9 @@ struct MissingFeatures {
232234
static bool ptrDiffOp() { return false; }
233235
static bool ptrStrideOp() { return false; }
234236
static bool switchOp() { return false; }
235-
static bool ternaryOp() { return false; }
237+
static bool throwOp() { return false; }
236238
static bool tryOp() { return false; }
239+
static bool vecTernaryOp() { return false; }
237240
static bool zextOp() { return false; }
238241

239242
// Future CIR attributes

clang/lib/CIR/CodeGen/CIRGenDecl.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,7 @@ CIRGenFunction::emitAutoVarAlloca(const VarDecl &d) {
5050
// A normal fixed sized variable becomes an alloca in the entry block,
5151
mlir::Type allocaTy = convertTypeForMem(ty);
5252
// Create the temp alloca and declare variable using it.
53-
address = createTempAlloca(allocaTy, alignment, loc, d.getName(),
54-
/*insertIntoFnEntryBlock=*/false);
53+
address = createTempAlloca(allocaTy, alignment, loc, d.getName());
5554
declare(address.getPointer(), &d, ty, getLoc(d.getSourceRange()), alignment);
5655

5756
emission.Addr = address;

clang/lib/CIR/CodeGen/CIRGenExpr.cpp

Lines changed: 104 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,15 @@
1515
#include "CIRGenModule.h"
1616
#include "CIRGenValue.h"
1717
#include "mlir/IR/BuiltinAttributes.h"
18+
#include "mlir/IR/Value.h"
1819
#include "clang/AST/Attr.h"
1920
#include "clang/AST/CharUnits.h"
2021
#include "clang/AST/Decl.h"
2122
#include "clang/AST/Expr.h"
2223
#include "clang/AST/ExprCXX.h"
2324
#include "clang/CIR/Dialect/IR/CIRDialect.h"
2425
#include "clang/CIR/MissingFeatures.h"
26+
#include <optional>
2527

2628
using namespace clang;
2729
using namespace clang::CIRGen;
@@ -229,7 +231,7 @@ void CIRGenFunction::emitStoreThroughLValue(RValue src, LValue dst,
229231

230232
static LValue emitGlobalVarDeclLValue(CIRGenFunction &cgf, const Expr *e,
231233
const VarDecl *vd) {
232-
QualType T = e->getType();
234+
QualType t = e->getType();
233235

234236
// If it's thread_local, emit a call to its wrapper function instead.
235237
assert(!cir::MissingFeatures::opGlobalThreadLocal());
@@ -259,7 +261,7 @@ static LValue emitGlobalVarDeclLValue(CIRGenFunction &cgf, const Expr *e,
259261
cgf.cgm.errorNYI(e->getSourceRange(),
260262
"emitGlobalVarDeclLValue: reference type");
261263
else
262-
lv = cgf.makeAddrLValue(addr, T, AlignmentSource::Decl);
264+
lv = cgf.makeAddrLValue(addr, t, AlignmentSource::Decl);
263265
assert(!cir::MissingFeatures::setObjCGCLValueClass());
264266
return lv;
265267
}
@@ -1259,10 +1261,28 @@ mlir::Value CIRGenFunction::emitOpOnBoolExpr(mlir::Location loc,
12591261
// cir.ternary(!x, t, f) -> cir.ternary(x, f, t)
12601262
assert(!cir::MissingFeatures::shouldReverseUnaryCondOnBoolExpr());
12611263

1262-
if (isa<ConditionalOperator>(cond)) {
1263-
cgm.errorNYI(cond->getExprLoc(), "Ternary NYI");
1264-
assert(!cir::MissingFeatures::ternaryOp());
1265-
return createDummyValue(loc, cond->getType());
1264+
if (const ConditionalOperator *condOp = dyn_cast<ConditionalOperator>(cond)) {
1265+
Expr *trueExpr = condOp->getTrueExpr();
1266+
Expr *falseExpr = condOp->getFalseExpr();
1267+
mlir::Value condV = emitOpOnBoolExpr(loc, condOp->getCond());
1268+
1269+
mlir::Value ternaryOpRes =
1270+
builder
1271+
.create<cir::TernaryOp>(
1272+
loc, condV, /*thenBuilder=*/
1273+
[this, trueExpr](mlir::OpBuilder &b, mlir::Location loc) {
1274+
mlir::Value lhs = emitScalarExpr(trueExpr);
1275+
b.create<cir::YieldOp>(loc, lhs);
1276+
},
1277+
/*elseBuilder=*/
1278+
[this, falseExpr](mlir::OpBuilder &b, mlir::Location loc) {
1279+
mlir::Value rhs = emitScalarExpr(falseExpr);
1280+
b.create<cir::YieldOp>(loc, rhs);
1281+
})
1282+
.getResult();
1283+
1284+
return emitScalarConversion(ternaryOpRes, condOp->getType(),
1285+
getContext().BoolTy, condOp->getExprLoc());
12661286
}
12671287

12681288
if (isa<CXXThrowExpr>(cond)) {
@@ -1394,13 +1414,84 @@ mlir::Value CIRGenFunction::createDummyValue(mlir::Location loc,
13941414
return builder.createDummyValue(loc, t, alignment);
13951415
}
13961416

1397-
/// This creates an alloca and inserts it into the entry block if
1398-
/// \p insertIntoFnEntryBlock is true, otherwise it inserts it at the current
1399-
/// insertion point of the builder.
1417+
//===----------------------------------------------------------------------===//
1418+
// CIR builder helpers
1419+
//===----------------------------------------------------------------------===//
1420+
1421+
Address CIRGenFunction::createMemTemp(QualType ty, mlir::Location loc,
1422+
const Twine &name, Address *alloca,
1423+
mlir::OpBuilder::InsertPoint ip) {
1424+
// FIXME: Should we prefer the preferred type alignment here?
1425+
return createMemTemp(ty, getContext().getTypeAlignInChars(ty), loc, name,
1426+
alloca, ip);
1427+
}
1428+
1429+
Address CIRGenFunction::createMemTemp(QualType ty, CharUnits align,
1430+
mlir::Location loc, const Twine &name,
1431+
Address *alloca,
1432+
mlir::OpBuilder::InsertPoint ip) {
1433+
Address result = createTempAlloca(convertTypeForMem(ty), align, loc, name,
1434+
/*ArraySize=*/nullptr, alloca, ip);
1435+
if (ty->isConstantMatrixType()) {
1436+
assert(!cir::MissingFeatures::matrixType());
1437+
cgm.errorNYI(loc, "temporary matrix value");
1438+
}
1439+
return result;
1440+
}
1441+
1442+
/// This creates a alloca and inserts it into the entry block of the
1443+
/// current region.
1444+
Address CIRGenFunction::createTempAllocaWithoutCast(
1445+
mlir::Type ty, CharUnits align, mlir::Location loc, const Twine &name,
1446+
mlir::Value arraySize, mlir::OpBuilder::InsertPoint ip) {
1447+
cir::AllocaOp alloca = ip.isSet()
1448+
? createTempAlloca(ty, loc, name, ip, arraySize)
1449+
: createTempAlloca(ty, loc, name, arraySize);
1450+
alloca.setAlignmentAttr(cgm.getSize(align));
1451+
return Address(alloca, ty, align);
1452+
}
1453+
1454+
/// This creates a alloca and inserts it into the entry block. The alloca is
1455+
/// casted to default address space if necessary.
14001456
Address CIRGenFunction::createTempAlloca(mlir::Type ty, CharUnits align,
14011457
mlir::Location loc, const Twine &name,
1402-
bool insertIntoFnEntryBlock) {
1403-
mlir::Value alloca =
1404-
emitAlloca(name.str(), ty, loc, align, insertIntoFnEntryBlock);
1405-
return Address(alloca, ty, align);
1458+
mlir::Value arraySize,
1459+
Address *allocaAddr,
1460+
mlir::OpBuilder::InsertPoint ip) {
1461+
Address alloca =
1462+
createTempAllocaWithoutCast(ty, align, loc, name, arraySize, ip);
1463+
if (allocaAddr)
1464+
*allocaAddr = alloca;
1465+
mlir::Value v = alloca.getPointer();
1466+
// Alloca always returns a pointer in alloca address space, which may
1467+
// be different from the type defined by the language. For example,
1468+
// in C++ the auto variables are in the default address space. Therefore
1469+
// cast alloca to the default address space when necessary.
1470+
assert(!cir::MissingFeatures::addressSpace());
1471+
return Address(v, ty, align);
1472+
}
1473+
1474+
/// This creates an alloca and inserts it into the entry block if \p ArraySize
1475+
/// is nullptr, otherwise inserts it at the current insertion point of the
1476+
/// builder.
1477+
cir::AllocaOp CIRGenFunction::createTempAlloca(mlir::Type ty,
1478+
mlir::Location loc,
1479+
const Twine &name,
1480+
mlir::Value arraySize,
1481+
bool insertIntoFnEntryBlock) {
1482+
return cast<cir::AllocaOp>(emitAlloca(name.str(), ty, loc, CharUnits(),
1483+
insertIntoFnEntryBlock, arraySize)
1484+
.getDefiningOp());
1485+
}
1486+
1487+
/// This creates an alloca and inserts it into the provided insertion point
1488+
cir::AllocaOp CIRGenFunction::createTempAlloca(mlir::Type ty,
1489+
mlir::Location loc,
1490+
const Twine &name,
1491+
mlir::OpBuilder::InsertPoint ip,
1492+
mlir::Value arraySize) {
1493+
assert(ip.isSet() && "Insertion point is not set");
1494+
return cast<cir::AllocaOp>(
1495+
emitAlloca(name.str(), ty, loc, CharUnits(), ip, arraySize)
1496+
.getDefiningOp());
14061497
}

clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -155,8 +155,7 @@ void AggExprEmitter::emitArrayInit(Address destPtr, cir::ArrayType arrayTy,
155155
// Allocate the temporary variable
156156
// to store the pointer to first unitialized element
157157
const Address tmpAddr = cgf.createTempAlloca(
158-
cirElementPtrType, cgf.getPointerAlign(), loc, "arrayinit.temp",
159-
/*insertIntoFnEntryBlock=*/false);
158+
cirElementPtrType, cgf.getPointerAlign(), loc, "arrayinit.temp");
160159
LValue tmpLV = cgf.makeAddrLValue(tmpAddr, elementPtrType);
161160
cgf.emitStoreThroughLValue(RValue::get(element), tmpLV);
162161

@@ -274,3 +273,11 @@ void AggExprEmitter::visitCXXParenListOrInitListExpr(
274273
void CIRGenFunction::emitAggExpr(const Expr *e, AggValueSlot slot) {
275274
AggExprEmitter(*this, slot).Visit(const_cast<Expr *>(e));
276275
}
276+
277+
LValue CIRGenFunction::emitAggExprToLValue(const Expr *e) {
278+
assert(hasAggregateEvaluationKind(e->getType()) && "Invalid argument!");
279+
Address temp = createMemTemp(e->getType(), getLoc(e->getSourceRange()));
280+
LValue lv = makeAddrLValue(temp, e->getType());
281+
emitAggExpr(e, AggValueSlot::forLValue(lv));
282+
return lv;
283+
}

0 commit comments

Comments
 (0)