blob: 07fb4cf8f15136e0c9d726642003835a65151f13 [file] [log] [blame]
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This contains code to emit Expr nodes as CIR code.
//
//===----------------------------------------------------------------------===//
#include "Address.h"
#include "CIRGenFunction.h"
#include "CIRGenValue.h"
#include "mlir/IR/BuiltinAttributes.h"
#include "clang/AST/Attr.h"
#include "clang/AST/CharUnits.h"
#include "clang/AST/Decl.h"
#include "clang/AST/Expr.h"
#include "clang/CIR/Dialect/IR/CIRDialect.h"
#include "clang/CIR/MissingFeatures.h"
using namespace clang;
using namespace clang::CIRGen;
using namespace cir;
void CIRGenFunction::emitStoreThroughLValue(RValue src, LValue dst,
bool isInit) {
if (!dst.isSimple()) {
cgm.errorNYI(dst.getPointer().getLoc(),
"emitStoreThroughLValue: non-simple lvalue");
return;
}
assert(!cir::MissingFeatures::opLoadStoreObjC());
assert(src.isScalar() && "Can't emit an aggregate store with this method");
emitStoreOfScalar(src.getScalarVal(), dst, isInit);
}
void CIRGenFunction::emitStoreOfScalar(mlir::Value value, Address addr,
bool isVolatile, QualType ty,
bool isInit, bool isNontemporal) {
assert(!cir::MissingFeatures::opLoadStoreThreadLocal());
if (ty->getAs<clang::VectorType>()) {
cgm.errorNYI(addr.getPointer().getLoc(), "emitStoreOfScalar vector type");
return;
}
value = emitToMemory(value, ty);
assert(!cir::MissingFeatures::opLoadStoreAtomic());
// Update the alloca with more info on initialization.
assert(addr.getPointer() && "expected pointer to exist");
auto srcAlloca =
dyn_cast_or_null<cir::AllocaOp>(addr.getPointer().getDefiningOp());
if (currVarDecl && srcAlloca) {
const VarDecl *vd = currVarDecl;
assert(vd && "VarDecl expected");
if (vd->hasInit())
srcAlloca.setInitAttr(mlir::UnitAttr::get(&getMLIRContext()));
}
assert(currSrcLoc && "must pass in source location");
builder.createStore(*currSrcLoc, value, addr.getPointer() /*, isVolatile*/);
if (isNontemporal) {
cgm.errorNYI(addr.getPointer().getLoc(), "emitStoreOfScalar nontemporal");
return;
}
assert(!cir::MissingFeatures::opTBAA());
}
mlir::Value CIRGenFunction::emitToMemory(mlir::Value value, QualType ty) {
// Bool has a different representation in memory than in registers,
// but in ClangIR, it is simply represented as a cir.bool value.
// This function is here as a placeholder for possible future changes.
return value;
}
void CIRGenFunction::emitStoreOfScalar(mlir::Value value, LValue lvalue,
bool isInit) {
if (lvalue.getType()->isConstantMatrixType()) {
assert(0 && "NYI: emitStoreOfScalar constant matrix type");
return;
}
emitStoreOfScalar(value, lvalue.getAddress(), lvalue.isVolatile(),
lvalue.getType(), isInit, /*isNontemporal=*/false);
}
mlir::Value CIRGenFunction::emitLoadOfScalar(LValue lvalue,
SourceLocation loc) {
assert(!cir::MissingFeatures::opLoadStoreThreadLocal());
assert(!cir::MissingFeatures::opLoadEmitScalarRangeCheck());
assert(!cir::MissingFeatures::opLoadBooleanRepresentation());
Address addr = lvalue.getAddress();
mlir::Type eltTy = addr.getElementType();
mlir::Value ptr = addr.getPointer();
if (mlir::isa<cir::VoidType>(eltTy))
cgm.errorNYI(loc, "emitLoadOfScalar: void type");
mlir::Value loadOp = builder.CIRBaseBuilderTy::createLoad(
getLoc(loc), ptr, false /*isVolatile*/);
return loadOp;
}
/// Given an expression that represents a value lvalue, this
/// method emits the address of the lvalue, then loads the result as an rvalue,
/// returning the rvalue.
RValue CIRGenFunction::emitLoadOfLValue(LValue lv, SourceLocation loc) {
assert(!lv.getType()->isFunctionType());
assert(!(lv.getType()->isConstantMatrixType()) && "not implemented");
if (lv.isSimple())
return RValue::get(emitLoadOfScalar(lv, loc));
cgm.errorNYI(loc, "emitLoadOfLValue");
return RValue::get(nullptr);
}
LValue CIRGenFunction::emitDeclRefLValue(const DeclRefExpr *e) {
const NamedDecl *nd = e->getDecl();
QualType ty = e->getType();
assert(e->isNonOdrUse() != NOUR_Unevaluated &&
"should not emit an unevaluated operand");
if (const auto *vd = dyn_cast<VarDecl>(nd)) {
// Checks for omitted feature handling
assert(!cir::MissingFeatures::opAllocaStaticLocal());
assert(!cir::MissingFeatures::opAllocaNonGC());
assert(!cir::MissingFeatures::opAllocaImpreciseLifetime());
assert(!cir::MissingFeatures::opAllocaTLS());
assert(!cir::MissingFeatures::opAllocaOpenMPThreadPrivate());
assert(!cir::MissingFeatures::opAllocaEscapeByReference());
// Check if this is a global variable
if (vd->hasLinkage() || vd->isStaticDataMember())
cgm.errorNYI(vd->getSourceRange(), "emitDeclRefLValue: global variable");
Address addr = Address::invalid();
// The variable should generally be present in the local decl map.
auto iter = LocalDeclMap.find(vd);
if (iter != LocalDeclMap.end()) {
addr = iter->second;
} else {
// Otherwise, it might be static local we haven't emitted yet for some
// reason; most likely, because it's in an outer function.
cgm.errorNYI(vd->getSourceRange(), "emitDeclRefLValue: static local");
}
return LValue::makeAddr(addr, ty);
}
cgm.errorNYI(e->getSourceRange(), "emitDeclRefLValue: unhandled decl type");
return LValue();
}
mlir::Value CIRGenFunction::emitAlloca(StringRef name, mlir::Type ty,
mlir::Location loc,
CharUnits alignment) {
mlir::Block *entryBlock = getCurFunctionEntryBlock();
// CIR uses its own alloca address space rather than follow the target data
// layout like original CodeGen. The data layout awareness should be done in
// the lowering pass instead.
assert(!cir::MissingFeatures::addressSpace());
cir::PointerType localVarPtrTy = builder.getPointerTo(ty);
mlir::IntegerAttr alignIntAttr = cgm.getSize(alignment);
mlir::Value addr;
{
mlir::OpBuilder::InsertionGuard guard(builder);
builder.restoreInsertionPoint(builder.getBestAllocaInsertPoint(entryBlock));
addr = builder.createAlloca(loc, /*addr type*/ localVarPtrTy,
/*var type*/ ty, name, alignIntAttr);
assert(!cir::MissingFeatures::astVarDeclInterface());
}
return addr;
}
/// This creates an alloca and inserts it at the current insertion point of the
/// builder.
Address CIRGenFunction::createTempAlloca(mlir::Type ty, CharUnits align,
mlir::Location loc,
const Twine &name) {
mlir::Value alloca = emitAlloca(name.str(), ty, loc, align);
return Address(alloca, ty, align);
}