brintos

brintos / llvm-project-archived public Read only

0
0
Text · 7.1 KiB · 5a067f8 Raw
174 lines · cpp
1//===--------------------------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with4// LLVM Exceptions.5// See https://llvm.org/LICENSE.txt for license information.6// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception7//8//===--------------------------------------------------------------------===//9//10// This file provides Itanium C++ ABI specific code11// that is used during LLVMIR lowering prepare.12//13//===--------------------------------------------------------------------===//14 15#include "LoweringPrepareCXXABI.h"16#include "mlir/IR/BuiltinAttributes.h"17#include "mlir/IR/Value.h"18#include "mlir/IR/ValueRange.h"19#include "clang/Basic/TargetInfo.h"20#include "clang/CIR/Dialect/Builder/CIRBaseBuilder.h"21#include "clang/CIR/Dialect/IR/CIRAttrs.h"22#include "clang/CIR/Dialect/IR/CIRDataLayout.h"23#include "clang/CIR/Dialect/IR/CIRDialect.h"24#include "clang/CIR/MissingFeatures.h"25 26class LoweringPrepareItaniumCXXABI : public cir::LoweringPrepareCXXABI {27public:28  mlir::Value lowerDynamicCast(cir::CIRBaseBuilderTy &builder,29                               clang::ASTContext &astCtx,30                               cir::DynamicCastOp op) override;31};32 33cir::LoweringPrepareCXXABI *cir::LoweringPrepareCXXABI::createItaniumABI() {34  return new LoweringPrepareItaniumCXXABI();35}36 37static void buildBadCastCall(cir::CIRBaseBuilderTy &builder, mlir::Location loc,38                             mlir::FlatSymbolRefAttr badCastFuncRef) {39  builder.createCallOp(loc, badCastFuncRef, cir::VoidType(),40                       mlir::ValueRange{});41  // TODO(cir): Set the 'noreturn' attribute on the function.42  assert(!cir::MissingFeatures::opFuncNoReturn());43  cir::UnreachableOp::create(builder, loc);44  builder.clearInsertionPoint();45}46 47static mlir::Value48buildDynamicCastAfterNullCheck(cir::CIRBaseBuilderTy &builder,49                               cir::DynamicCastOp op) {50  mlir::Location loc = op->getLoc();51  mlir::Value srcValue = op.getSrc();52  cir::DynamicCastInfoAttr castInfo = op.getInfo().value();53 54  // TODO(cir): consider address space55  assert(!cir::MissingFeatures::addressSpace());56 57  mlir::Value srcPtr = builder.createBitcast(srcValue, builder.getVoidPtrTy());58  cir::ConstantOp srcRtti = builder.getConstant(loc, castInfo.getSrcRtti());59  cir::ConstantOp destRtti = builder.getConstant(loc, castInfo.getDestRtti());60  cir::ConstantOp offsetHint =61      builder.getConstant(loc, castInfo.getOffsetHint());62 63  mlir::FlatSymbolRefAttr dynCastFuncRef = castInfo.getRuntimeFunc();64  mlir::Value dynCastFuncArgs[4] = {srcPtr, srcRtti, destRtti, offsetHint};65 66  mlir::Value castedPtr =67      builder68          .createCallOp(loc, dynCastFuncRef, builder.getVoidPtrTy(),69                        dynCastFuncArgs)70          .getResult();71 72  assert(mlir::isa<cir::PointerType>(castedPtr.getType()) &&73         "the return value of __dynamic_cast should be a ptr");74 75  /// C++ [expr.dynamic.cast]p9:76  ///   A failed cast to reference type throws std::bad_cast77  if (op.isRefCast()) {78    // Emit a cir.if that checks the casted value.79    mlir::Value castedValueIsNull = builder.createPtrIsNull(castedPtr);80    cir::IfOp::create(builder, loc, castedValueIsNull, false,81                      [&](mlir::OpBuilder &, mlir::Location) {82                        buildBadCastCall(builder, loc,83                                         castInfo.getBadCastFunc());84                      });85  }86 87  // Note that castedPtr is a void*. Cast it to a pointer to the destination88  // type before return.89  return builder.createBitcast(castedPtr, op.getType());90}91 92static mlir::Value93buildDynamicCastToVoidAfterNullCheck(cir::CIRBaseBuilderTy &builder,94                                     clang::ASTContext &astCtx,95                                     cir::DynamicCastOp op) {96  mlir::Location loc = op.getLoc();97  bool vtableUsesRelativeLayout = op.getRelativeLayout();98 99  // TODO(cir): consider address space in this function.100  assert(!cir::MissingFeatures::addressSpace());101 102  mlir::Type vtableElemTy;103  uint64_t vtableElemAlign;104  if (vtableUsesRelativeLayout) {105    vtableElemTy = builder.getSIntNTy(32);106    vtableElemAlign = 4;107  } else {108    const auto &targetInfo = astCtx.getTargetInfo();109    auto ptrdiffTy = targetInfo.getPtrDiffType(clang::LangAS::Default);110    bool ptrdiffTyIsSigned = clang::TargetInfo::isTypeSigned(ptrdiffTy);111    uint64_t ptrdiffTyWidth = targetInfo.getTypeWidth(ptrdiffTy);112 113    vtableElemTy = cir::IntType::get(builder.getContext(), ptrdiffTyWidth,114                                     ptrdiffTyIsSigned);115    vtableElemAlign =116        llvm::divideCeil(targetInfo.getPointerAlign(clang::LangAS::Default), 8);117  }118 119  // Access vtable to get the offset from the given object to its containing120  // complete object.121  // TODO: Add a specialized operation to get the object offset?122  auto vptrTy = cir::VPtrType::get(builder.getContext());123  cir::PointerType vptrPtrTy = builder.getPointerTo(vptrTy);124  auto vptrPtr =125      cir::VTableGetVPtrOp::create(builder, loc, vptrPtrTy, op.getSrc());126  mlir::Value vptr = builder.createLoad(loc, vptrPtr);127  mlir::Value elementPtr =128      builder.createBitcast(vptr, builder.getPointerTo(vtableElemTy));129  mlir::Value minusTwo = builder.getSignedInt(loc, -2, 64);130  auto offsetToTopSlotPtr = cir::PtrStrideOp::create(131      builder, loc, builder.getPointerTo(vtableElemTy), elementPtr, minusTwo);132  mlir::Value offsetToTop =133      builder.createAlignedLoad(loc, offsetToTopSlotPtr, vtableElemAlign);134 135  // Add the offset to the given pointer to get the cast result.136  // Cast the input pointer to a uint8_t* to allow pointer arithmetic.137  cir::PointerType u8PtrTy = builder.getPointerTo(builder.getUIntNTy(8));138  mlir::Value srcBytePtr = builder.createBitcast(op.getSrc(), u8PtrTy);139  auto dstBytePtr =140      cir::PtrStrideOp::create(builder, loc, u8PtrTy, srcBytePtr, offsetToTop);141  // Cast the result to a void*.142  return builder.createBitcast(dstBytePtr, builder.getVoidPtrTy());143}144 145mlir::Value146LoweringPrepareItaniumCXXABI::lowerDynamicCast(cir::CIRBaseBuilderTy &builder,147                                               clang::ASTContext &astCtx,148                                               cir::DynamicCastOp op) {149  mlir::Location loc = op->getLoc();150  mlir::Value srcValue = op.getSrc();151 152  assert(!cir::MissingFeatures::emitTypeCheck());153 154  if (op.isRefCast())155    return buildDynamicCastAfterNullCheck(builder, op);156 157  mlir::Value srcValueIsNotNull = builder.createPtrToBoolCast(srcValue);158  return cir::TernaryOp::create(159             builder, loc, srcValueIsNotNull,160             [&](mlir::OpBuilder &, mlir::Location) {161               mlir::Value castedValue =162                   op.isCastToVoid()163                       ? buildDynamicCastToVoidAfterNullCheck(builder, astCtx,164                                                              op)165                       : buildDynamicCastAfterNullCheck(builder, op);166               builder.createYield(loc, castedValue);167             },168             [&](mlir::OpBuilder &, mlir::Location) {169               builder.createYield(170                   loc, builder.getNullPtr(op.getType(), loc).getResult());171             })172      .getResult();173}174