mirror of
https://github.com/intel/llvm.git
synced 2026-01-26 03:56:16 +08:00
Ref commit in incubator: ee17ff67f3e567585db991cdad1159520c516bb4 There is a minor change in the assumption for emitting a direct callee. In incubator, `bool hasAttributeNoBuiltin = false` (`llvm-project/clang/lib/CIR/CodeGen/CIRGenExpr.cpp:1671`), while in upstream, it's true, therefore, the call to finite(...) is not converted to a builtin anymore. Fixes #163892
639 lines
25 KiB
C++
639 lines
25 KiB
C++
//===----------------------------------------------------------------------===//
|
|
//
|
|
// 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef LLVM_CLANG_LIB_CIR_CODEGEN_CIRGENBUILDER_H
|
|
#define LLVM_CLANG_LIB_CIR_CODEGEN_CIRGENBUILDER_H
|
|
|
|
#include "Address.h"
|
|
#include "CIRGenRecordLayout.h"
|
|
#include "CIRGenTypeCache.h"
|
|
#include "mlir/IR/Attributes.h"
|
|
#include "mlir/IR/BuiltinAttributes.h"
|
|
#include "mlir/Support/LLVM.h"
|
|
#include "clang/CIR/Dialect/IR/CIRDataLayout.h"
|
|
#include "clang/CIR/MissingFeatures.h"
|
|
|
|
#include "clang/CIR/Dialect/Builder/CIRBaseBuilder.h"
|
|
#include "clang/CIR/MissingFeatures.h"
|
|
#include "llvm/ADT/APFloat.h"
|
|
#include "llvm/ADT/STLExtras.h"
|
|
|
|
namespace clang::CIRGen {
|
|
|
|
class CIRGenBuilderTy : public cir::CIRBaseBuilderTy {
|
|
const CIRGenTypeCache &typeCache;
|
|
llvm::StringMap<unsigned> recordNames;
|
|
llvm::StringMap<unsigned> globalsVersioning;
|
|
|
|
public:
|
|
CIRGenBuilderTy(mlir::MLIRContext &mlirContext, const CIRGenTypeCache &tc)
|
|
: CIRBaseBuilderTy(mlirContext), typeCache(tc) {}
|
|
|
|
/// Get a cir::ConstArrayAttr for a string literal.
|
|
/// Note: This is different from what is returned by
|
|
/// mlir::Builder::getStringAttr() which is an mlir::StringAttr.
|
|
mlir::Attribute getString(llvm::StringRef str, mlir::Type eltTy,
|
|
std::optional<size_t> size) {
|
|
size_t finalSize = size.value_or(str.size());
|
|
|
|
size_t lastNonZeroPos = str.find_last_not_of('\0');
|
|
// If the string is full of null bytes, emit a #cir.zero rather than
|
|
// a #cir.const_array.
|
|
if (lastNonZeroPos == llvm::StringRef::npos) {
|
|
auto arrayTy = cir::ArrayType::get(eltTy, finalSize);
|
|
return cir::ZeroAttr::get(arrayTy);
|
|
}
|
|
// We emit trailing zeros only if there are multiple trailing zeros.
|
|
size_t trailingZerosNum = 0;
|
|
if (finalSize > lastNonZeroPos + 2)
|
|
trailingZerosNum = finalSize - lastNonZeroPos - 1;
|
|
auto truncatedArrayTy =
|
|
cir::ArrayType::get(eltTy, finalSize - trailingZerosNum);
|
|
auto fullArrayTy = cir::ArrayType::get(eltTy, finalSize);
|
|
return cir::ConstArrayAttr::get(
|
|
fullArrayTy,
|
|
mlir::StringAttr::get(str.drop_back(trailingZerosNum),
|
|
truncatedArrayTy),
|
|
trailingZerosNum);
|
|
}
|
|
|
|
cir::ConstArrayAttr getConstArray(mlir::Attribute attrs,
|
|
cir::ArrayType arrayTy) const {
|
|
return cir::ConstArrayAttr::get(arrayTy, attrs);
|
|
}
|
|
|
|
mlir::Attribute getConstRecordOrZeroAttr(mlir::ArrayAttr arrayAttr,
|
|
bool packed = false,
|
|
bool padded = false,
|
|
mlir::Type type = {});
|
|
|
|
cir::ConstRecordAttr getAnonConstRecord(mlir::ArrayAttr arrayAttr,
|
|
bool packed = false,
|
|
bool padded = false,
|
|
mlir::Type ty = {}) {
|
|
llvm::SmallVector<mlir::Type, 4> members;
|
|
for (auto &f : arrayAttr) {
|
|
auto ta = mlir::cast<mlir::TypedAttr>(f);
|
|
members.push_back(ta.getType());
|
|
}
|
|
|
|
if (!ty)
|
|
ty = getAnonRecordTy(members, packed, padded);
|
|
|
|
auto sTy = mlir::cast<cir::RecordType>(ty);
|
|
return cir::ConstRecordAttr::get(sTy, arrayAttr);
|
|
}
|
|
|
|
cir::TypeInfoAttr getTypeInfo(mlir::ArrayAttr fieldsAttr) {
|
|
cir::ConstRecordAttr anonRecord = getAnonConstRecord(fieldsAttr);
|
|
return cir::TypeInfoAttr::get(anonRecord.getType(), fieldsAttr);
|
|
}
|
|
|
|
std::string getUniqueAnonRecordName() { return getUniqueRecordName("anon"); }
|
|
|
|
std::string getUniqueRecordName(const std::string &baseName) {
|
|
auto it = recordNames.find(baseName);
|
|
if (it == recordNames.end()) {
|
|
recordNames[baseName] = 0;
|
|
return baseName;
|
|
}
|
|
|
|
return baseName + "." + std::to_string(recordNames[baseName]++);
|
|
}
|
|
|
|
cir::LongDoubleType getLongDoubleTy(const llvm::fltSemantics &format) const {
|
|
if (&format == &llvm::APFloat::IEEEdouble())
|
|
return cir::LongDoubleType::get(getContext(), typeCache.doubleTy);
|
|
if (&format == &llvm::APFloat::x87DoubleExtended())
|
|
return cir::LongDoubleType::get(getContext(), typeCache.fP80Ty);
|
|
if (&format == &llvm::APFloat::IEEEquad())
|
|
return cir::LongDoubleType::get(getContext(), typeCache.fP128Ty);
|
|
if (&format == &llvm::APFloat::PPCDoubleDouble())
|
|
llvm_unreachable("NYI: PPC double-double format for long double");
|
|
llvm_unreachable("Unsupported format for long double");
|
|
}
|
|
|
|
mlir::Type getPtrToVPtrType() {
|
|
return getPointerTo(cir::VPtrType::get(getContext()));
|
|
}
|
|
|
|
cir::FuncType getFuncType(llvm::ArrayRef<mlir::Type> params, mlir::Type retTy,
|
|
bool isVarArg = false) {
|
|
return cir::FuncType::get(params, retTy, isVarArg);
|
|
}
|
|
|
|
/// Get a CIR record kind from a AST declaration tag.
|
|
cir::RecordType::RecordKind getRecordKind(const clang::TagTypeKind kind) {
|
|
switch (kind) {
|
|
case clang::TagTypeKind::Class:
|
|
return cir::RecordType::Class;
|
|
case clang::TagTypeKind::Struct:
|
|
return cir::RecordType::Struct;
|
|
case clang::TagTypeKind::Union:
|
|
return cir::RecordType::Union;
|
|
case clang::TagTypeKind::Interface:
|
|
llvm_unreachable("interface records are NYI");
|
|
case clang::TagTypeKind::Enum:
|
|
llvm_unreachable("enums are not records");
|
|
}
|
|
llvm_unreachable("Unsupported record kind");
|
|
}
|
|
|
|
/// Get a CIR named record type.
|
|
///
|
|
/// If a record already exists and is complete, but the client tries to fetch
|
|
/// it with a different set of attributes, this method will crash.
|
|
cir::RecordType getCompleteNamedRecordType(llvm::ArrayRef<mlir::Type> members,
|
|
bool packed, bool padded,
|
|
llvm::StringRef name) {
|
|
const auto nameAttr = getStringAttr(name);
|
|
auto kind = cir::RecordType::RecordKind::Struct;
|
|
assert(!cir::MissingFeatures::astRecordDeclAttr());
|
|
|
|
// Create or get the record.
|
|
auto type =
|
|
getType<cir::RecordType>(members, nameAttr, packed, padded, kind);
|
|
|
|
// If we found an existing type, verify that either it is incomplete or
|
|
// it matches the requested attributes.
|
|
assert(!type.isIncomplete() ||
|
|
(type.getMembers() == members && type.getPacked() == packed &&
|
|
type.getPadded() == padded));
|
|
|
|
// Complete an incomplete record or ensure the existing complete record
|
|
// matches the requested attributes.
|
|
type.complete(members, packed, padded);
|
|
|
|
return type;
|
|
}
|
|
|
|
cir::RecordType getCompleteRecordType(mlir::ArrayAttr fields,
|
|
bool packed = false,
|
|
bool padded = false,
|
|
llvm::StringRef name = "");
|
|
|
|
/// Get an incomplete CIR struct type. If we have a complete record
|
|
/// declaration, we may create an incomplete type and then add the
|
|
/// members, so \p rd here may be complete.
|
|
cir::RecordType getIncompleteRecordTy(llvm::StringRef name,
|
|
const clang::RecordDecl *rd) {
|
|
const mlir::StringAttr nameAttr = getStringAttr(name);
|
|
cir::RecordType::RecordKind kind = cir::RecordType::RecordKind::Struct;
|
|
if (rd)
|
|
kind = getRecordKind(rd->getTagKind());
|
|
return getType<cir::RecordType>(nameAttr, kind);
|
|
}
|
|
|
|
// Return true if the value is a null constant such as null pointer, (+0.0)
|
|
// for floating-point or zero initializer
|
|
bool isNullValue(mlir::Attribute attr) const {
|
|
if (mlir::isa<cir::ZeroAttr>(attr))
|
|
return true;
|
|
|
|
if (const auto ptrVal = mlir::dyn_cast<cir::ConstPtrAttr>(attr))
|
|
return ptrVal.isNullValue();
|
|
|
|
if (const auto intVal = mlir::dyn_cast<cir::IntAttr>(attr))
|
|
return intVal.isNullValue();
|
|
|
|
if (const auto boolVal = mlir::dyn_cast<cir::BoolAttr>(attr))
|
|
return !boolVal.getValue();
|
|
|
|
if (auto fpAttr = mlir::dyn_cast<cir::FPAttr>(attr)) {
|
|
auto fpVal = fpAttr.getValue();
|
|
bool ignored;
|
|
llvm::APFloat fv(+0.0);
|
|
fv.convert(fpVal.getSemantics(), llvm::APFloat::rmNearestTiesToEven,
|
|
&ignored);
|
|
return fv.bitwiseIsEqual(fpVal);
|
|
}
|
|
if (const auto recordVal = mlir::dyn_cast<cir::ConstRecordAttr>(attr)) {
|
|
for (const auto elt : recordVal.getMembers()) {
|
|
// FIXME(cir): the record's ID should not be considered a member.
|
|
if (mlir::isa<mlir::StringAttr>(elt))
|
|
continue;
|
|
if (!isNullValue(elt))
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
if (const auto arrayVal = mlir::dyn_cast<cir::ConstArrayAttr>(attr)) {
|
|
if (mlir::isa<mlir::StringAttr>(arrayVal.getElts()))
|
|
return false;
|
|
|
|
return llvm::all_of(
|
|
mlir::cast<mlir::ArrayAttr>(arrayVal.getElts()),
|
|
[&](const mlir::Attribute &elt) { return isNullValue(elt); });
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//
|
|
// Type helpers
|
|
// ------------
|
|
//
|
|
cir::IntType getUIntNTy(int n) {
|
|
switch (n) {
|
|
case 8:
|
|
return getUInt8Ty();
|
|
case 16:
|
|
return getUInt16Ty();
|
|
case 32:
|
|
return getUInt32Ty();
|
|
case 64:
|
|
return getUInt64Ty();
|
|
default:
|
|
return cir::IntType::get(getContext(), n, false);
|
|
}
|
|
}
|
|
|
|
cir::IntType getSIntNTy(int n) {
|
|
switch (n) {
|
|
case 8:
|
|
return getSInt8Ty();
|
|
case 16:
|
|
return getSInt16Ty();
|
|
case 32:
|
|
return getSInt32Ty();
|
|
case 64:
|
|
return getSInt64Ty();
|
|
default:
|
|
return cir::IntType::get(getContext(), n, true);
|
|
}
|
|
}
|
|
|
|
cir::VoidType getVoidTy() { return typeCache.voidTy; }
|
|
|
|
cir::IntType getSInt8Ty() { return typeCache.sInt8Ty; }
|
|
cir::IntType getSInt16Ty() { return typeCache.sInt16Ty; }
|
|
cir::IntType getSInt32Ty() { return typeCache.sInt32Ty; }
|
|
cir::IntType getSInt64Ty() { return typeCache.sInt64Ty; }
|
|
|
|
cir::IntType getUInt8Ty() { return typeCache.uInt8Ty; }
|
|
cir::IntType getUInt16Ty() { return typeCache.uInt16Ty; }
|
|
cir::IntType getUInt32Ty() { return typeCache.uInt32Ty; }
|
|
cir::IntType getUInt64Ty() { return typeCache.uInt64Ty; }
|
|
|
|
cir::ConstantOp getConstInt(mlir::Location loc, llvm::APSInt intVal);
|
|
|
|
cir::ConstantOp getConstInt(mlir::Location loc, llvm::APInt intVal);
|
|
|
|
cir::ConstantOp getConstInt(mlir::Location loc, mlir::Type t, uint64_t c);
|
|
|
|
cir::ConstantOp getConstFP(mlir::Location loc, mlir::Type t,
|
|
llvm::APFloat fpVal);
|
|
|
|
bool isInt8Ty(mlir::Type i) {
|
|
return i == typeCache.uInt8Ty || i == typeCache.sInt8Ty;
|
|
}
|
|
bool isInt16Ty(mlir::Type i) {
|
|
return i == typeCache.uInt16Ty || i == typeCache.sInt16Ty;
|
|
}
|
|
bool isInt32Ty(mlir::Type i) {
|
|
return i == typeCache.uInt32Ty || i == typeCache.sInt32Ty;
|
|
}
|
|
bool isInt64Ty(mlir::Type i) {
|
|
return i == typeCache.uInt64Ty || i == typeCache.sInt64Ty;
|
|
}
|
|
bool isInt(mlir::Type i) { return mlir::isa<cir::IntType>(i); }
|
|
|
|
// Fetch the type representing a pointer to unsigned int8 values.
|
|
cir::PointerType getUInt8PtrTy() { return typeCache.uInt8PtrTy; }
|
|
|
|
/// Get a CIR anonymous record type.
|
|
cir::RecordType getAnonRecordTy(llvm::ArrayRef<mlir::Type> members,
|
|
bool packed = false, bool padded = false) {
|
|
assert(!cir::MissingFeatures::astRecordDeclAttr());
|
|
auto kind = cir::RecordType::RecordKind::Struct;
|
|
return getType<cir::RecordType>(members, packed, padded, kind);
|
|
}
|
|
|
|
//
|
|
// Constant creation helpers
|
|
// -------------------------
|
|
//
|
|
cir::ConstantOp getSInt32(int32_t c, mlir::Location loc) {
|
|
return getConstantInt(loc, getSInt32Ty(), c);
|
|
}
|
|
cir::ConstantOp getUInt32(uint32_t c, mlir::Location loc) {
|
|
return getConstantInt(loc, getUInt32Ty(), c);
|
|
}
|
|
cir::ConstantOp getSInt64(uint64_t c, mlir::Location loc) {
|
|
return getConstantInt(loc, getSInt64Ty(), c);
|
|
}
|
|
cir::ConstantOp getUInt64(uint64_t c, mlir::Location loc) {
|
|
return getConstantInt(loc, getUInt64Ty(), c);
|
|
}
|
|
|
|
mlir::Value createNeg(mlir::Value value) {
|
|
|
|
if (auto intTy = mlir::dyn_cast<cir::IntType>(value.getType())) {
|
|
// Source is a unsigned integer: first cast it to signed.
|
|
if (intTy.isUnsigned())
|
|
value = createIntCast(value, getSIntNTy(intTy.getWidth()));
|
|
return cir::UnaryOp::create(*this, value.getLoc(), value.getType(),
|
|
cir::UnaryOpKind::Minus, value);
|
|
}
|
|
|
|
llvm_unreachable("negation for the given type is NYI");
|
|
}
|
|
|
|
cir::IsFPClassOp createIsFPClass(mlir::Location loc, mlir::Value src,
|
|
cir::FPClassTest flags) {
|
|
return cir::IsFPClassOp::create(*this, loc, src, flags);
|
|
}
|
|
|
|
// TODO: split this to createFPExt/createFPTrunc when we have dedicated cast
|
|
// operations.
|
|
mlir::Value createFloatingCast(mlir::Value v, mlir::Type destType) {
|
|
assert(!cir::MissingFeatures::fpConstraints());
|
|
|
|
return cir::CastOp::create(*this, v.getLoc(), destType,
|
|
cir::CastKind::floating, v);
|
|
}
|
|
|
|
mlir::Value createFSub(mlir::Location loc, mlir::Value lhs, mlir::Value rhs) {
|
|
assert(!cir::MissingFeatures::metaDataNode());
|
|
assert(!cir::MissingFeatures::fpConstraints());
|
|
assert(!cir::MissingFeatures::fastMathFlags());
|
|
|
|
return cir::BinOp::create(*this, loc, cir::BinOpKind::Sub, lhs, rhs);
|
|
}
|
|
|
|
mlir::Value createFAdd(mlir::Location loc, mlir::Value lhs, mlir::Value rhs) {
|
|
assert(!cir::MissingFeatures::metaDataNode());
|
|
assert(!cir::MissingFeatures::fpConstraints());
|
|
assert(!cir::MissingFeatures::fastMathFlags());
|
|
|
|
return cir::BinOp::create(*this, loc, cir::BinOpKind::Add, lhs, rhs);
|
|
}
|
|
mlir::Value createFMul(mlir::Location loc, mlir::Value lhs, mlir::Value rhs) {
|
|
assert(!cir::MissingFeatures::metaDataNode());
|
|
assert(!cir::MissingFeatures::fpConstraints());
|
|
assert(!cir::MissingFeatures::fastMathFlags());
|
|
|
|
return cir::BinOp::create(*this, loc, cir::BinOpKind::Mul, lhs, rhs);
|
|
}
|
|
mlir::Value createFDiv(mlir::Location loc, mlir::Value lhs, mlir::Value rhs) {
|
|
assert(!cir::MissingFeatures::metaDataNode());
|
|
assert(!cir::MissingFeatures::fpConstraints());
|
|
assert(!cir::MissingFeatures::fastMathFlags());
|
|
|
|
return cir::BinOp::create(*this, loc, cir::BinOpKind::Div, lhs, rhs);
|
|
}
|
|
|
|
mlir::Value createDynCast(mlir::Location loc, mlir::Value src,
|
|
cir::PointerType destType, bool isRefCast,
|
|
cir::DynamicCastInfoAttr info) {
|
|
auto castKind =
|
|
isRefCast ? cir::DynamicCastKind::Ref : cir::DynamicCastKind::Ptr;
|
|
return cir::DynamicCastOp::create(*this, loc, destType, castKind, src, info,
|
|
/*relative_layout=*/false);
|
|
}
|
|
|
|
mlir::Value createDynCastToVoid(mlir::Location loc, mlir::Value src,
|
|
bool vtableUseRelativeLayout) {
|
|
// TODO(cir): consider address space here.
|
|
assert(!cir::MissingFeatures::addressSpace());
|
|
cir::PointerType destTy = getVoidPtrTy();
|
|
return cir::DynamicCastOp::create(
|
|
*this, loc, destTy, cir::DynamicCastKind::Ptr, src,
|
|
cir::DynamicCastInfoAttr{}, vtableUseRelativeLayout);
|
|
}
|
|
|
|
Address createBaseClassAddr(mlir::Location loc, Address addr,
|
|
mlir::Type destType, unsigned offset,
|
|
bool assumeNotNull) {
|
|
if (destType == addr.getElementType())
|
|
return addr;
|
|
|
|
auto ptrTy = getPointerTo(destType);
|
|
auto baseAddr =
|
|
cir::BaseClassAddrOp::create(*this, loc, ptrTy, addr.getPointer(),
|
|
mlir::APInt(64, offset), assumeNotNull);
|
|
return Address(baseAddr, destType, addr.getAlignment());
|
|
}
|
|
|
|
Address createDerivedClassAddr(mlir::Location loc, Address addr,
|
|
mlir::Type destType, unsigned offset,
|
|
bool assumeNotNull) {
|
|
if (destType == addr.getElementType())
|
|
return addr;
|
|
|
|
cir::PointerType ptrTy = getPointerTo(destType);
|
|
auto derivedAddr =
|
|
cir::DerivedClassAddrOp::create(*this, loc, ptrTy, addr.getPointer(),
|
|
mlir::APInt(64, offset), assumeNotNull);
|
|
return Address(derivedAddr, destType, addr.getAlignment());
|
|
}
|
|
|
|
mlir::Value createVTTAddrPoint(mlir::Location loc, mlir::Type retTy,
|
|
mlir::Value addr, uint64_t offset) {
|
|
return cir::VTTAddrPointOp::create(*this, loc, retTy,
|
|
mlir::FlatSymbolRefAttr{}, addr, offset);
|
|
}
|
|
|
|
mlir::Value createVTTAddrPoint(mlir::Location loc, mlir::Type retTy,
|
|
mlir::FlatSymbolRefAttr sym, uint64_t offset) {
|
|
return cir::VTTAddrPointOp::create(*this, loc, retTy, sym, mlir::Value{},
|
|
offset);
|
|
}
|
|
|
|
/// Cast the element type of the given address to a different type,
|
|
/// preserving information like the alignment.
|
|
Address createElementBitCast(mlir::Location loc, Address addr,
|
|
mlir::Type destType) {
|
|
if (destType == addr.getElementType())
|
|
return addr;
|
|
|
|
auto ptrTy = getPointerTo(destType);
|
|
return Address(createBitcast(loc, addr.getPointer(), ptrTy), destType,
|
|
addr.getAlignment());
|
|
}
|
|
|
|
cir::LoadOp createLoad(mlir::Location loc, Address addr,
|
|
bool isVolatile = false) {
|
|
mlir::IntegerAttr align = getAlignmentAttr(addr.getAlignment());
|
|
return cir::LoadOp::create(*this, loc, addr.getPointer(), /*isDeref=*/false,
|
|
isVolatile, /*alignment=*/align,
|
|
/*mem_order=*/cir::MemOrderAttr{});
|
|
}
|
|
|
|
cir::LoadOp createAlignedLoad(mlir::Location loc, mlir::Type ty,
|
|
mlir::Value ptr, llvm::MaybeAlign align) {
|
|
if (ty != mlir::cast<cir::PointerType>(ptr.getType()).getPointee())
|
|
ptr = createPtrBitcast(ptr, ty);
|
|
uint64_t alignment = align ? align->value() : 0;
|
|
mlir::IntegerAttr alignAttr = getAlignmentAttr(alignment);
|
|
return cir::LoadOp::create(*this, loc, ptr, /*isDeref=*/false,
|
|
/*isVolatile=*/false, alignAttr,
|
|
/*mem_order=*/cir::MemOrderAttr{});
|
|
}
|
|
|
|
cir::LoadOp
|
|
createAlignedLoad(mlir::Location loc, mlir::Type ty, mlir::Value ptr,
|
|
clang::CharUnits align = clang::CharUnits::One()) {
|
|
return createAlignedLoad(loc, ty, ptr, align.getAsAlign());
|
|
}
|
|
|
|
cir::StoreOp createStore(mlir::Location loc, mlir::Value val, Address dst,
|
|
bool isVolatile = false,
|
|
mlir::IntegerAttr align = {},
|
|
cir::MemOrderAttr order = {}) {
|
|
if (!align)
|
|
align = getAlignmentAttr(dst.getAlignment());
|
|
return CIRBaseBuilderTy::createStore(loc, val, dst.getPointer(), isVolatile,
|
|
align, order);
|
|
}
|
|
|
|
/// Create a cir.complex.real_ptr operation that derives a pointer to the real
|
|
/// part of the complex value pointed to by the specified pointer value.
|
|
mlir::Value createComplexRealPtr(mlir::Location loc, mlir::Value value) {
|
|
auto srcPtrTy = mlir::cast<cir::PointerType>(value.getType());
|
|
auto srcComplexTy = mlir::cast<cir::ComplexType>(srcPtrTy.getPointee());
|
|
return cir::ComplexRealPtrOp::create(
|
|
*this, loc, getPointerTo(srcComplexTy.getElementType()), value);
|
|
}
|
|
|
|
Address createComplexRealPtr(mlir::Location loc, Address addr) {
|
|
return Address{createComplexRealPtr(loc, addr.getPointer()),
|
|
addr.getAlignment()};
|
|
}
|
|
|
|
/// Create a cir.complex.imag_ptr operation that derives a pointer to the
|
|
/// imaginary part of the complex value pointed to by the specified pointer
|
|
/// value.
|
|
mlir::Value createComplexImagPtr(mlir::Location loc, mlir::Value value) {
|
|
auto srcPtrTy = mlir::cast<cir::PointerType>(value.getType());
|
|
auto srcComplexTy = mlir::cast<cir::ComplexType>(srcPtrTy.getPointee());
|
|
return cir::ComplexImagPtrOp::create(
|
|
*this, loc, getPointerTo(srcComplexTy.getElementType()), value);
|
|
}
|
|
|
|
Address createComplexImagPtr(mlir::Location loc, Address addr) {
|
|
return Address{createComplexImagPtr(loc, addr.getPointer()),
|
|
addr.getAlignment()};
|
|
}
|
|
|
|
/// Create a cir.ptr_stride operation to get access to an array element.
|
|
/// \p idx is the index of the element to access, \p shouldDecay is true if
|
|
/// the result should decay to a pointer to the element type.
|
|
mlir::Value getArrayElement(mlir::Location arrayLocBegin,
|
|
mlir::Location arrayLocEnd, mlir::Value arrayPtr,
|
|
mlir::Type eltTy, mlir::Value idx,
|
|
bool shouldDecay);
|
|
|
|
/// Returns a decayed pointer to the first element of the array
|
|
/// pointed to by \p arrayPtr.
|
|
mlir::Value maybeBuildArrayDecay(mlir::Location loc, mlir::Value arrayPtr,
|
|
mlir::Type eltTy);
|
|
|
|
// Convert byte offset to sequence of high-level indices suitable for
|
|
// GlobalViewAttr. Ideally we shouldn't deal with low-level offsets at all
|
|
// but currently some parts of Clang AST, which we don't want to touch just
|
|
// yet, return them.
|
|
void computeGlobalViewIndicesFromFlatOffset(
|
|
int64_t offset, mlir::Type ty, cir::CIRDataLayout layout,
|
|
llvm::SmallVectorImpl<int64_t> &indices);
|
|
|
|
/// Creates a versioned global variable. If the symbol is already taken, an ID
|
|
/// will be appended to the symbol. The returned global must always be queried
|
|
/// for its name so it can be referenced correctly.
|
|
[[nodiscard]] cir::GlobalOp
|
|
createVersionedGlobal(mlir::ModuleOp module, mlir::Location loc,
|
|
mlir::StringRef name, mlir::Type type, bool isConstant,
|
|
cir::GlobalLinkageKind linkage) {
|
|
// Create a unique name if the given name is already taken.
|
|
std::string uniqueName;
|
|
if (unsigned version = globalsVersioning[name.str()]++)
|
|
uniqueName = name.str() + "." + std::to_string(version);
|
|
else
|
|
uniqueName = name.str();
|
|
|
|
return createGlobal(module, loc, uniqueName, type, isConstant, linkage);
|
|
}
|
|
|
|
cir::StackSaveOp createStackSave(mlir::Location loc, mlir::Type ty) {
|
|
return cir::StackSaveOp::create(*this, loc, ty);
|
|
}
|
|
|
|
cir::StackRestoreOp createStackRestore(mlir::Location loc, mlir::Value v) {
|
|
return cir::StackRestoreOp::create(*this, loc, v);
|
|
}
|
|
|
|
mlir::Value createSetBitfield(mlir::Location loc, mlir::Type resultType,
|
|
Address dstAddr, mlir::Type storageType,
|
|
mlir::Value src, const CIRGenBitFieldInfo &info,
|
|
bool isLvalueVolatile, bool useVolatile) {
|
|
unsigned offset = useVolatile ? info.volatileOffset : info.offset;
|
|
|
|
// If using AAPCS and the field is volatile, load with the size of the
|
|
// declared field
|
|
storageType =
|
|
useVolatile ? cir::IntType::get(storageType.getContext(),
|
|
info.volatileStorageSize, info.isSigned)
|
|
: storageType;
|
|
return cir::SetBitfieldOp::create(
|
|
*this, loc, resultType, dstAddr.getPointer(), storageType, src,
|
|
info.name, info.size, offset, info.isSigned, isLvalueVolatile,
|
|
dstAddr.getAlignment().getAsAlign().value());
|
|
}
|
|
|
|
mlir::Value createGetBitfield(mlir::Location loc, mlir::Type resultType,
|
|
Address addr, mlir::Type storageType,
|
|
const CIRGenBitFieldInfo &info,
|
|
bool isLvalueVolatile, bool useVolatile) {
|
|
unsigned offset = useVolatile ? info.volatileOffset : info.offset;
|
|
|
|
// If using AAPCS and the field is volatile, load with the size of the
|
|
// declared field
|
|
storageType =
|
|
useVolatile ? cir::IntType::get(storageType.getContext(),
|
|
info.volatileStorageSize, info.isSigned)
|
|
: storageType;
|
|
return cir::GetBitfieldOp::create(*this, loc, resultType, addr.getPointer(),
|
|
storageType, info.name, info.size, offset,
|
|
info.isSigned, isLvalueVolatile,
|
|
addr.getAlignment().getAsAlign().value());
|
|
}
|
|
|
|
cir::VecShuffleOp
|
|
createVecShuffle(mlir::Location loc, mlir::Value vec1, mlir::Value vec2,
|
|
llvm::ArrayRef<mlir::Attribute> maskAttrs) {
|
|
auto vecType = mlir::cast<cir::VectorType>(vec1.getType());
|
|
auto resultTy = cir::VectorType::get(getContext(), vecType.getElementType(),
|
|
maskAttrs.size());
|
|
return cir::VecShuffleOp::create(*this, loc, resultTy, vec1, vec2,
|
|
getArrayAttr(maskAttrs));
|
|
}
|
|
|
|
cir::VecShuffleOp createVecShuffle(mlir::Location loc, mlir::Value vec1,
|
|
mlir::Value vec2,
|
|
llvm::ArrayRef<int64_t> mask) {
|
|
auto maskAttrs = llvm::to_vector_of<mlir::Attribute>(
|
|
llvm::map_range(mask, [&](int32_t idx) {
|
|
return cir::IntAttr::get(getSInt32Ty(), idx);
|
|
}));
|
|
return createVecShuffle(loc, vec1, vec2, maskAttrs);
|
|
}
|
|
|
|
cir::VecShuffleOp createVecShuffle(mlir::Location loc, mlir::Value vec1,
|
|
llvm::ArrayRef<int64_t> mask) {
|
|
/// Create a unary shuffle. The second vector operand of the IR instruction
|
|
/// is poison.
|
|
cir::ConstantOp poison =
|
|
getConstant(loc, cir::PoisonAttr::get(vec1.getType()));
|
|
return createVecShuffle(loc, vec1, poison, mask);
|
|
}
|
|
};
|
|
|
|
} // namespace clang::CIRGen
|
|
|
|
#endif
|