Skip to content
Draft
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
81 changes: 81 additions & 0 deletions clang/include/clang/CodeGen/QualTypeMapper.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
//==---- QualTypeMapper.h - Maps Clang QualType to LLVMABI Types -----------==//
//
// 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
//
//===----------------------------------------------------------------------===//
///
/// \file
/// Maps Clang QualType instances to corresponding LLVM ABI type
/// representations. This mapper translates high-level type information from the
/// AST into low-level ABI-specific types that encode size, alignment, and
/// layout details required for code generation and cross-language
/// interoperability.
///
//===----------------------------------------------------------------------===//
#ifndef CLANG_CODEGEN_QUALTYPE_MAPPER_H
#define CLANG_CODEGEN_QUALTYPE_MAPPER_H

#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/AST/Type.h"
#include "clang/AST/TypeOrdering.h"
#include "llvm/ABI/Types.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/Support/Allocator.h"

namespace clang {
namespace CodeGen {

class QualTypeMapper {
private:
clang::ASTContext &ASTCtx;
llvm::abi::TypeBuilder Builder;

llvm::DenseMap<QualType, const llvm::abi::Type *> TypeCache;

const llvm::abi::Type *convertBuiltinType(const clang::BuiltinType *BT);
const llvm::abi::Type *convertPointerType(const clang::PointerType *PT);
const llvm::abi::Type *convertArrayType(const clang::ArrayType *AT);
const llvm::abi::Type *convertVectorType(const clang::VectorType *VT);
const llvm::abi::Type *convertRecordType(const clang::RecordType *RT);
const llvm::abi::Type *convertEnumType(const clang::EnumType *ET);
const llvm::abi::Type *convertReferenceType(const ReferenceType *RT);
const llvm::abi::Type *convertComplexType(const ComplexType *CT);
const llvm::abi::Type *
convertMemberPointerType(const clang::MemberPointerType *MPT);
const llvm::abi::Type *convertMatrixType(const ConstantMatrixType *MT);

const llvm::abi::RecordType *convertStructType(const clang::RecordDecl *RD);
const llvm::abi::RecordType *convertUnionType(const clang::RecordDecl *RD,
bool IsTransparent = false);
const llvm::abi::Type *createPointerTypeForPointee(QualType PointeeType);
const llvm::abi::RecordType *convertCXXRecordType(const CXXRecordDecl *RD,
bool CanPassInRegs);

void computeFieldInfo(const clang::RecordDecl *RD,
SmallVectorImpl<llvm::abi::FieldInfo> &Fields,
const clang::ASTRecordLayout &Layout);

llvm::TypeSize getTypeSize(clang::QualType QT) const;
llvm::Align getTypeAlign(clang::QualType QT) const;
llvm::Align getPreferredTypeAlign(QualType QT) const;
uint64_t getPointerSize() const;
uint64_t getPointerAlign() const;

public:
explicit QualTypeMapper(clang::ASTContext &Ctx, llvm::BumpPtrAllocator &Alloc)
: ASTCtx(Ctx), Builder(Alloc) {}

const llvm::abi::Type *convertType(clang::QualType QT);

void clearCache() { TypeCache.clear(); }

llvm::abi::TypeBuilder getTypeBuilder() { return Builder; }
};

} // namespace CodeGen
} // namespace clang

#endif // CLANG_CODEGEN_QUALTYPE_MAPPER_H
248 changes: 241 additions & 7 deletions clang/lib/CodeGen/CGCall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,11 @@
#include "clang/Basic/CodeGenOptions.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/CodeGen/CGFunctionInfo.h"
#include "clang/CodeGen/QualTypeMapper.h"
#include "clang/CodeGen/SwiftCallingConv.h"
#include "llvm/ABI/ABIFunctionInfo.h"
#include "llvm/ABI/ABITypeMapper.h"
#include "llvm/ABI/Types.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Analysis/ValueTracking.h"
#include "llvm/IR/Assumptions.h"
Expand All @@ -42,6 +46,7 @@
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/Type.h"
#include "llvm/TargetParser/Triple.h"
#include "llvm/Transforms/Utils/Local.h"
#include <optional>
using namespace clang;
Expand Down Expand Up @@ -825,6 +830,196 @@ void computeSPIRKernelABIInfo(CodeGenModule &CGM, CGFunctionInfo &FI);
}
} // namespace clang

static QualType getIntegerTypeForExtension(ASTContext &Ctx, llvm::Type *LLVMTy,
bool IsSigned) {
if (auto *IntTy = dyn_cast<llvm::IntegerType>(LLVMTy)) {
unsigned BitWidth = IntTy->getBitWidth();
return Ctx.getIntTypeForBitwidth(BitWidth, IsSigned);
}
return QualType();
}

static bool shouldSignExtend(QualType Ty) {
if (Ty->isSignedIntegerType() || Ty->isEnumeralType()) {
if (const EnumType *ET = Ty->getAs<EnumType>()) {
return ET->getOriginalDecl()->getIntegerType()->isSignedIntegerType();
}
return true;
}
return false;
}

ABIArgInfo CodeGenTypes::convertABIArgInfo(const llvm::abi::ABIArgInfo &AbiInfo,
QualType type) {
ABIArgInfo result;

// To maintain coherence with clang's current impl.
if (type->isConstantMatrixType()) {
const auto *MT = type->getAs<ConstantMatrixType>();
unsigned NumElements = MT->getNumRows() * MT->getNumColumns();
llvm::Type *ElementType = ConvertType(MT->getElementType());
llvm::Type *VectorType = llvm::VectorType::get(
ElementType, llvm::ElementCount::getFixed(NumElements));

result = ABIArgInfo::getDirect(VectorType);
return result;
}
switch (AbiInfo.getKind()) {
case llvm::abi::ABIArgInfo::Direct: {
llvm::Type *CoercedType = nullptr;
if (AbiInfo.getCoerceToType())
CoercedType = ReverseMapper.convertType(AbiInfo.getCoerceToType());
if (!CoercedType)
CoercedType = ConvertType(type);

llvm::Type *PaddingType = nullptr;
if (AbiInfo.getPaddingType())
PaddingType = ReverseMapper.convertType(AbiInfo.getPaddingType());

result = ABIArgInfo::getDirect(CoercedType, AbiInfo.getDirectOffset(),
PaddingType, AbiInfo.getCanBeFlattened(),
AbiInfo.getDirectAlign());

if (AbiInfo.isInReg())
result.setInReg(true);
if (AbiInfo.hasPaddingInReg())
result.setPaddingInReg(true);
break;
}
case llvm::abi::ABIArgInfo::Extend: {
llvm::Type *CoercedType = nullptr;
QualType ExtendType = type;

if (AbiInfo.getCoerceToType()) {
CoercedType = ReverseMapper.convertType(AbiInfo.getCoerceToType());

if (CoercedType && CoercedType->isIntegerTy()) {
bool IsSigned = AbiInfo.isSignExt() ||
(AbiInfo.isNoExt() && shouldSignExtend(type));
ExtendType =
getIntegerTypeForExtension(getContext(), CoercedType, IsSigned);

if (ExtendType.isNull()) {
ExtendType = type;
if (type->isUnionType() || !type->isIntegralOrEnumerationType()) {
unsigned BitWidth =
cast<llvm::IntegerType>(CoercedType)->getBitWidth();
ExtendType = getContext().getIntTypeForBitwidth(BitWidth, IsSigned);
}
}
}
}

if (!CoercedType)
CoercedType = ConvertType(type);

if (!ExtendType->isIntegralOrEnumerationType()) {
if (CoercedType && CoercedType->isIntegerTy()) {
unsigned BitWidth = cast<llvm::IntegerType>(CoercedType)->getBitWidth();
bool IsSigned = AbiInfo.isSignExt() || shouldSignExtend(type);
ExtendType = getContext().getIntTypeForBitwidth(BitWidth, IsSigned);
} else {
ExtendType = getContext().IntTy;
}
}

if (AbiInfo.isSignExt()) {
result = ABIArgInfo::getSignExtend(ExtendType, CoercedType);
} else if (AbiInfo.isZeroExt()) {
result = ABIArgInfo::getZeroExtend(ExtendType, CoercedType);
} else {
result = ABIArgInfo::getExtend(ExtendType, CoercedType);
}

if (AbiInfo.isInReg())
result.setInReg(true);
break;
}
case llvm::abi::ABIArgInfo::Indirect: {
CharUnits Alignment = CharUnits::fromQuantity(AbiInfo.getIndirectAlign());

llvm::Type *PaddingType = nullptr;
if (AbiInfo.getPaddingType())
PaddingType = ReverseMapper.convertType(AbiInfo.getPaddingType());

result = ABIArgInfo::getIndirect(Alignment, AbiInfo.getIndirectAddrSpace(),
AbiInfo.getIndirectByVal(),
AbiInfo.getIndirectRealign(), PaddingType);

if (AbiInfo.isInReg())
result.setInReg(true);
if (AbiInfo.isSRetAfterThis())
result.setSRetAfterThis(true);
break;
}
case llvm::abi::ABIArgInfo::IndirectAliased: {
CharUnits Alignment = CharUnits::fromQuantity(AbiInfo.getIndirectAlign());

llvm::Type *PaddingType = nullptr;
if (AbiInfo.getPaddingType())
PaddingType = ReverseMapper.convertType(AbiInfo.getPaddingType());

result = ABIArgInfo::getIndirectAliased(
Alignment, AbiInfo.getIndirectAddrSpace(), AbiInfo.getIndirectRealign(),
PaddingType);
break;
}

case llvm::abi::ABIArgInfo::Ignore: {
result = ABIArgInfo::getIgnore();
break;
}

case llvm::abi::ABIArgInfo::Expand: {
llvm::Type *PaddingType = nullptr;
if (AbiInfo.getPaddingType())
PaddingType = ReverseMapper.convertType(AbiInfo.getPaddingType());

if (PaddingType) {
result = ABIArgInfo::getExpandWithPadding(AbiInfo.hasPaddingInReg(),
PaddingType);
} else {
result = ABIArgInfo::getExpand();
}
break;
}

case llvm::abi::ABIArgInfo::CoerceAndExpand: {
llvm::Type *CoerceType = nullptr;
llvm::Type *UnpaddedType = nullptr;

if (AbiInfo.getCoerceToType())
CoerceType = ReverseMapper.convertType(AbiInfo.getCoerceToType());
if (AbiInfo.getUnpaddedCoerceAndExpandType())
UnpaddedType =
ReverseMapper.convertType(AbiInfo.getUnpaddedCoerceAndExpandType());

if (!CoerceType)
CoerceType = ConvertType(type);
if (!UnpaddedType)
UnpaddedType = CoerceType;

llvm::StructType *CoerceStructType = dyn_cast<llvm::StructType>(CoerceType);
if (!CoerceStructType) {
CoerceStructType = llvm::StructType::get(CoerceType->getContext());
}

result = ABIArgInfo::getCoerceAndExpand(CoerceStructType, UnpaddedType);
break;
}

case llvm::abi::ABIArgInfo::InAlloca: {
result = ABIArgInfo::getInAlloca(AbiInfo.getInAllocaFieldIndex(),
AbiInfo.getInAllocaIndirect());
if (AbiInfo.getInAllocaSRet())
result.setInAllocaSRet(true);
break;
}
}

return result;
}

/// Arrange the argument and result information for an abstract value
/// of a given function type. This is the method which all of the
/// above functions ultimately defer to.
Expand Down Expand Up @@ -857,7 +1052,9 @@ const CGFunctionInfo &CodeGenTypes::arrangeLLVMFunctionInfo(
// Construct the function info. We co-allocate the ArgInfos.
FI = CGFunctionInfo::create(CC, isInstanceMethod, isChainCall, isDelegateCall,
info, paramInfos, resultType, argTypes, required);

FunctionInfos.InsertNode(FI, insertPos);
std::unique_ptr<llvm::abi::ABIFunctionInfo> tempFI;

bool inserted = FunctionsBeingProcessed.insert(FI).second;
(void)inserted;
Expand All @@ -871,20 +1068,57 @@ const CGFunctionInfo &CodeGenTypes::arrangeLLVMFunctionInfo(
} else if (info.getCC() == CC_Swift || info.getCC() == CC_SwiftAsync) {
swiftcall::computeABIInfo(CGM, *FI);
} else {
CGM.getABIInfo().computeInfo(*FI);
if (CGM.shouldUseLLVMABI() &&
(CC == llvm::CallingConv::X86_64_SysV || CC == llvm::CallingConv::C)) {
SmallVector<const llvm::abi::Type *, 8> MappedArgTypes;
for (CanQualType ArgType : argTypes)
MappedArgTypes.push_back(Mapper.convertType(ArgType));
tempFI.reset(llvm::abi::ABIFunctionInfo::create(
CC, Mapper.convertType(resultType), MappedArgTypes));

CGM.fetchABIInfo(TB).computeInfo(*tempFI);
} else
CGM.getABIInfo().computeInfo(*FI);
}

// Loop over all of the computed argument and return value info. If any of
// them are direct or extend without a specified coerce type, specify the
// default now.
ABIArgInfo &retInfo = FI->getReturnInfo();
if (retInfo.canHaveCoerceToType() && retInfo.getCoerceToType() == nullptr)
retInfo.setCoerceToType(ConvertType(FI->getReturnType()));
if (CGM.shouldUseLLVMABI() &&
(CC == llvm::CallingConv::X86_64_SysV || CC == llvm::CallingConv::C) &&
tempFI) {

const auto &abiRetInfo = tempFI->getReturnInfo();
ABIArgInfo &cgRetInfo = FI->getReturnInfo();

for (auto &I : FI->arguments())
if (I.info.canHaveCoerceToType() && I.info.getCoerceToType() == nullptr)
I.info.setCoerceToType(ConvertType(I.type));
cgRetInfo = convertABIArgInfo(abiRetInfo, FI->getReturnType());

unsigned numArgs = std::min(FI->arg_size(), tempFI->getNumArgs());
unsigned argIndex = 0;

for (auto &cgArg : FI->arguments()) {
if (argIndex >= numArgs)
break;

const auto &abiArgInfo = tempFI->getArgInfo(argIndex);
cgArg.info = convertABIArgInfo(abiArgInfo.ArgInfo, cgArg.type);

if (abiArgInfo.ArgInfo.isInReg())
cgArg.info.setInReg(true);

argIndex++;
}
} else {
// Non-BPF/SysV path: handle coerce types for direct/extend cases
ABIArgInfo &retInfo = FI->getReturnInfo();
if (retInfo.canHaveCoerceToType() && retInfo.getCoerceToType() == nullptr)
retInfo.setCoerceToType(ConvertType(FI->getReturnType()));

for (auto &I : FI->arguments()) {
if (I.info.canHaveCoerceToType() && I.info.getCoerceToType() == nullptr)
I.info.setCoerceToType(ConvertType(I.type));
}
}
bool erased = FunctionsBeingProcessed.erase(FI);
(void)erased;
assert(erased && "Not in set?");
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/CodeGen/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
set(LLVM_LINK_COMPONENTS
AggressiveInstCombine
ABI
Analysis
BitReader
BitWriter
Expand Down Expand Up @@ -115,6 +116,7 @@ add_clang_library(clangCodeGen
ModuleBuilder.cpp
ObjectFilePCHContainerWriter.cpp
PatternInit.cpp
QualTypeMapper.cpp
SanitizerMetadata.cpp
SwiftCallingConv.cpp
TargetBuiltins/ARM.cpp
Expand Down
Loading