Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 55 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
//===----------------------------------------------------------------------===//

#include "Address.h"
#include "CIRGenConstantEmitter.h"
#include "CIRGenFunction.h"
#include "CIRGenModule.h"
#include "CIRGenValue.h"
Expand Down Expand Up @@ -1495,3 +1496,57 @@ cir::AllocaOp CIRGenFunction::createTempAlloca(mlir::Type ty,
emitAlloca(name.str(), ty, loc, CharUnits(), ip, arraySize)
.getDefiningOp());
}

/// Try to emit a reference to the given value without producing it as
/// an l-value. For many cases, this is just an optimization, but it avoids
/// us needing to emit global copies of variables if they're named without
/// triggering a formal use in a context where we can't emit a direct
/// reference to them, for instance if a block or lambda or a member of a
/// local class uses a const int variable or constexpr variable from an
/// enclosing function.
///
/// For named members of enums, this is the only way they are emitted.
CIRGenFunction::ConstantEmission
CIRGenFunction::tryEmitAsConstant(DeclRefExpr *refExpr) {
ValueDecl *value = refExpr->getDecl();

// There is a lot more to do here, but for now only EnumConstantDecl is
// supported.
assert(!cir::MissingFeatures::tryEmitAsConstant());

// The value needs to be an enum constant or a constant variable.
if (!isa<EnumConstantDecl>(value))
return ConstantEmission();

Expr::EvalResult result;
if (!refExpr->EvaluateAsRValue(result, getContext()))
return ConstantEmission();

QualType resultType = refExpr->getType();

// As long as we're only handling EnumConstantDecl, there should be no
// side-effects.
assert(!result.HasSideEffects);

// Emit as a constant.
// FIXME(cir): have emitAbstract build a TypedAttr instead (this requires
// somewhat heavy refactoring...)
mlir::Attribute c = ConstantEmitter(*this).emitAbstract(
refExpr->getLocation(), result.Val, resultType);
mlir::TypedAttr cstToEmit = mlir::dyn_cast_if_present<mlir::TypedAttr>(c);
assert(cstToEmit && "expected a typed attribute");

assert(!cir::MissingFeatures::generateDebugInfo());

return ConstantEmission::forValue(cstToEmit);
}

mlir::Value CIRGenFunction::emitScalarConstant(
const CIRGenFunction::ConstantEmission &constant, Expr *e) {
assert(constant && "not a constant");
if (constant.isReference()) {
cgm.errorNYI(e->getSourceRange(), "emitScalarConstant: reference");
return {};
}
return builder.getConstant(getLoc(e->getSourceRange()), constant.getValue());
}
4 changes: 3 additions & 1 deletion clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,9 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {

// l-values
mlir::Value VisitDeclRefExpr(DeclRefExpr *e) {
assert(!cir::MissingFeatures::tryEmitAsConstant());
if (CIRGenFunction::ConstantEmission constant = cgf.tryEmitAsConstant(e))
return cgf.emitScalarConstant(constant, e);

return emitLoadOfLValue(e);
}

Expand Down
37 changes: 37 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,41 @@ class CIRGenFunction : public CIRGenTypeCache {
/// that we can just remove the code.
bool containsLabel(const clang::Stmt *s, bool ignoreCaseStmts = false);

class ConstantEmission {
// Cannot use mlir::TypedAttr directly here because of bit availability.
llvm::PointerIntPair<mlir::Attribute, 1, bool> valueAndIsReference;
ConstantEmission(mlir::TypedAttr c, bool isReference)
: valueAndIsReference(c, isReference) {}

public:
ConstantEmission() {}
static ConstantEmission forReference(mlir::TypedAttr c) {
return ConstantEmission(c, true);
}
static ConstantEmission forValue(mlir::TypedAttr c) {
return ConstantEmission(c, false);
}

explicit operator bool() const {
return valueAndIsReference.getOpaqueValue() != nullptr;
}

bool isReference() const { return valueAndIsReference.getInt(); }
LValue getReferenceLValue(CIRGenFunction &cgf, Expr *refExpr) const {
assert(isReference());
cgf.cgm.errorNYI(refExpr->getSourceRange(),
"ConstantEmission::getReferenceLValue");
return {};
}

mlir::TypedAttr getValue() const {
assert(!isReference());
return mlir::cast<mlir::TypedAttr>(valueAndIsReference.getPointer());
}
};

ConstantEmission tryEmitAsConstant(DeclRefExpr *refExpr);

struct AutoVarEmission {
const clang::VarDecl *Variable;
/// The address of the alloca for languages with explicit address space
Expand Down Expand Up @@ -840,6 +875,8 @@ class CIRGenFunction : public CIRGenTypeCache {

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

mlir::Value emitScalarConstant(const ConstantEmission &constant, Expr *e);

/// Emit a conversion from the specified type to the specified destination
/// type, both of which are CIR scalar types.
mlir::Value emitScalarConversion(mlir::Value src, clang::QualType srcType,
Expand Down
16 changes: 16 additions & 0 deletions clang/test/CIR/CodeGen/enum.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir
// RUN: FileCheck %s --input-file=%t.cir

enum Numbers {
Zero,
One,
Two,
Three
};

int f() {
return Numbers::One;
}

// CHECK: cir.func{{.*}} @_Z1fv
// CHECK: cir.const #cir.int<1> : !u32i