Skip to content

Commit 4ed0ff8

Browse files
authored
[CIR] Add support for using enum constants (llvm#143214)
Although support for declaring enums and using values whose type was an enum was previously upstreamed, we didn't have support for referencing the constant values declared in the enum. This change adds that support.
1 parent 58cce43 commit 4ed0ff8

File tree

4 files changed

+111
-1
lines changed

4 files changed

+111
-1
lines changed

clang/lib/CIR/CodeGen/CIRGenExpr.cpp

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
//===----------------------------------------------------------------------===//
1212

1313
#include "Address.h"
14+
#include "CIRGenConstantEmitter.h"
1415
#include "CIRGenFunction.h"
1516
#include "CIRGenModule.h"
1617
#include "CIRGenValue.h"
@@ -1495,3 +1496,57 @@ cir::AllocaOp CIRGenFunction::createTempAlloca(mlir::Type ty,
14951496
emitAlloca(name.str(), ty, loc, CharUnits(), ip, arraySize)
14961497
.getDefiningOp());
14971498
}
1499+
1500+
/// Try to emit a reference to the given value without producing it as
1501+
/// an l-value. For many cases, this is just an optimization, but it avoids
1502+
/// us needing to emit global copies of variables if they're named without
1503+
/// triggering a formal use in a context where we can't emit a direct
1504+
/// reference to them, for instance if a block or lambda or a member of a
1505+
/// local class uses a const int variable or constexpr variable from an
1506+
/// enclosing function.
1507+
///
1508+
/// For named members of enums, this is the only way they are emitted.
1509+
CIRGenFunction::ConstantEmission
1510+
CIRGenFunction::tryEmitAsConstant(DeclRefExpr *refExpr) {
1511+
ValueDecl *value = refExpr->getDecl();
1512+
1513+
// There is a lot more to do here, but for now only EnumConstantDecl is
1514+
// supported.
1515+
assert(!cir::MissingFeatures::tryEmitAsConstant());
1516+
1517+
// The value needs to be an enum constant or a constant variable.
1518+
if (!isa<EnumConstantDecl>(value))
1519+
return ConstantEmission();
1520+
1521+
Expr::EvalResult result;
1522+
if (!refExpr->EvaluateAsRValue(result, getContext()))
1523+
return ConstantEmission();
1524+
1525+
QualType resultType = refExpr->getType();
1526+
1527+
// As long as we're only handling EnumConstantDecl, there should be no
1528+
// side-effects.
1529+
assert(!result.HasSideEffects);
1530+
1531+
// Emit as a constant.
1532+
// FIXME(cir): have emitAbstract build a TypedAttr instead (this requires
1533+
// somewhat heavy refactoring...)
1534+
mlir::Attribute c = ConstantEmitter(*this).emitAbstract(
1535+
refExpr->getLocation(), result.Val, resultType);
1536+
mlir::TypedAttr cstToEmit = mlir::dyn_cast_if_present<mlir::TypedAttr>(c);
1537+
assert(cstToEmit && "expected a typed attribute");
1538+
1539+
assert(!cir::MissingFeatures::generateDebugInfo());
1540+
1541+
return ConstantEmission::forValue(cstToEmit);
1542+
}
1543+
1544+
mlir::Value CIRGenFunction::emitScalarConstant(
1545+
const CIRGenFunction::ConstantEmission &constant, Expr *e) {
1546+
assert(constant && "not a constant");
1547+
if (constant.isReference()) {
1548+
cgm.errorNYI(e->getSourceRange(), "emitScalarConstant: reference");
1549+
return {};
1550+
}
1551+
return builder.getConstant(getLoc(e->getSourceRange()), constant.getValue());
1552+
}

clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,9 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
140140

141141
// l-values
142142
mlir::Value VisitDeclRefExpr(DeclRefExpr *e) {
143-
assert(!cir::MissingFeatures::tryEmitAsConstant());
143+
if (CIRGenFunction::ConstantEmission constant = cgf.tryEmitAsConstant(e))
144+
return cgf.emitScalarConstant(constant, e);
145+
144146
return emitLoadOfLValue(e);
145147
}
146148

clang/lib/CIR/CodeGen/CIRGenFunction.h

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,41 @@ class CIRGenFunction : public CIRGenTypeCache {
374374
/// that we can just remove the code.
375375
bool containsLabel(const clang::Stmt *s, bool ignoreCaseStmts = false);
376376

377+
class ConstantEmission {
378+
// Cannot use mlir::TypedAttr directly here because of bit availability.
379+
llvm::PointerIntPair<mlir::Attribute, 1, bool> valueAndIsReference;
380+
ConstantEmission(mlir::TypedAttr c, bool isReference)
381+
: valueAndIsReference(c, isReference) {}
382+
383+
public:
384+
ConstantEmission() {}
385+
static ConstantEmission forReference(mlir::TypedAttr c) {
386+
return ConstantEmission(c, true);
387+
}
388+
static ConstantEmission forValue(mlir::TypedAttr c) {
389+
return ConstantEmission(c, false);
390+
}
391+
392+
explicit operator bool() const {
393+
return valueAndIsReference.getOpaqueValue() != nullptr;
394+
}
395+
396+
bool isReference() const { return valueAndIsReference.getInt(); }
397+
LValue getReferenceLValue(CIRGenFunction &cgf, Expr *refExpr) const {
398+
assert(isReference());
399+
cgf.cgm.errorNYI(refExpr->getSourceRange(),
400+
"ConstantEmission::getReferenceLValue");
401+
return {};
402+
}
403+
404+
mlir::TypedAttr getValue() const {
405+
assert(!isReference());
406+
return mlir::cast<mlir::TypedAttr>(valueAndIsReference.getPointer());
407+
}
408+
};
409+
410+
ConstantEmission tryEmitAsConstant(DeclRefExpr *refExpr);
411+
377412
struct AutoVarEmission {
378413
const clang::VarDecl *Variable;
379414
/// The address of the alloca for languages with explicit address space
@@ -840,6 +875,8 @@ class CIRGenFunction : public CIRGenTypeCache {
840875

841876
mlir::LogicalResult emitReturnStmt(const clang::ReturnStmt &s);
842877

878+
mlir::Value emitScalarConstant(const ConstantEmission &constant, Expr *e);
879+
843880
/// Emit a conversion from the specified type to the specified destination
844881
/// type, both of which are CIR scalar types.
845882
mlir::Value emitScalarConversion(mlir::Value src, clang::QualType srcType,

clang/test/CIR/CodeGen/enum.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir
2+
// RUN: FileCheck %s --input-file=%t.cir
3+
4+
enum Numbers {
5+
Zero,
6+
One,
7+
Two,
8+
Three
9+
};
10+
11+
int f() {
12+
return Numbers::One;
13+
}
14+
15+
// CHECK: cir.func{{.*}} @_Z1fv
16+
// CHECK: cir.const #cir.int<1> : !u32i

0 commit comments

Comments
 (0)