brintos

brintos / llvm-project-archived public Read only

0
0
Text · 16.2 KiB · 97a9300 Raw
423 lines · cpp
1//===- Hexagon.cpp --------------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "ABIInfoImpl.h"10#include "TargetInfo.h"11 12using namespace clang;13using namespace clang::CodeGen;14 15//===----------------------------------------------------------------------===//16// Hexagon ABI Implementation17//===----------------------------------------------------------------------===//18 19namespace {20 21class HexagonABIInfo : public DefaultABIInfo {22public:23  HexagonABIInfo(CodeGenTypes &CGT) : DefaultABIInfo(CGT) {}24 25private:26  ABIArgInfo classifyReturnType(QualType RetTy) const;27  ABIArgInfo classifyArgumentType(QualType RetTy) const;28  ABIArgInfo classifyArgumentType(QualType RetTy, unsigned *RegsLeft) const;29 30  void computeInfo(CGFunctionInfo &FI) const override;31 32  RValue EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty,33                   AggValueSlot Slot) const override;34  Address EmitVAArgFromMemory(CodeGenFunction &CFG, Address VAListAddr,35                              QualType Ty) const;36  Address EmitVAArgForHexagon(CodeGenFunction &CFG, Address VAListAddr,37                              QualType Ty) const;38  Address EmitVAArgForHexagonLinux(CodeGenFunction &CFG, Address VAListAddr,39                                   QualType Ty) const;40};41 42class HexagonTargetCodeGenInfo : public TargetCodeGenInfo {43public:44  HexagonTargetCodeGenInfo(CodeGenTypes &CGT)45      : TargetCodeGenInfo(std::make_unique<HexagonABIInfo>(CGT)) {}46 47  int getDwarfEHStackPointer(CodeGen::CodeGenModule &M) const override {48    return 29;49  }50 51  void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV,52                           CodeGen::CodeGenModule &GCM) const override {53    if (GV->isDeclaration())54      return;55    const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D);56    if (!FD)57      return;58  }59};60 61} // namespace62 63void HexagonABIInfo::computeInfo(CGFunctionInfo &FI) const {64  unsigned RegsLeft = 6;65  if (!getCXXABI().classifyReturnType(FI))66    FI.getReturnInfo() = classifyReturnType(FI.getReturnType());67  for (auto &I : FI.arguments())68    I.info = classifyArgumentType(I.type, &RegsLeft);69}70 71static bool HexagonAdjustRegsLeft(uint64_t Size, unsigned *RegsLeft) {72  assert(Size <= 64 && "Not expecting to pass arguments larger than 64 bits"73                       " through registers");74 75  if (*RegsLeft == 0)76    return false;77 78  if (Size <= 32) {79    (*RegsLeft)--;80    return true;81  }82 83  if (2 <= (*RegsLeft & (~1U))) {84    *RegsLeft = (*RegsLeft & (~1U)) - 2;85    return true;86  }87 88  // Next available register was r5 but candidate was greater than 32-bits so it89  // has to go on the stack. However we still consume r590  if (*RegsLeft == 1)91    *RegsLeft = 0;92 93  return false;94}95 96ABIArgInfo HexagonABIInfo::classifyArgumentType(QualType Ty,97                                                unsigned *RegsLeft) const {98  if (!isAggregateTypeForABI(Ty)) {99    // Treat an enum type as its underlying type.100    if (const auto *ED = Ty->getAsEnumDecl())101      Ty = ED->getIntegerType();102 103    uint64_t Size = getContext().getTypeSize(Ty);104    if (Size <= 64)105      HexagonAdjustRegsLeft(Size, RegsLeft);106 107    if (Size > 64 && Ty->isBitIntType())108      return getNaturalAlignIndirect(Ty, getDataLayout().getAllocaAddrSpace(),109                                     /*ByVal=*/true);110 111    return isPromotableIntegerTypeForABI(Ty) ? ABIArgInfo::getExtend(Ty)112                                             : ABIArgInfo::getDirect();113  }114 115  if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI()))116    return getNaturalAlignIndirect(Ty, getDataLayout().getAllocaAddrSpace(),117                                   RAA == CGCXXABI::RAA_DirectInMemory);118 119  // Ignore empty records.120  if (isEmptyRecord(getContext(), Ty, true))121    return ABIArgInfo::getIgnore();122 123  uint64_t Size = getContext().getTypeSize(Ty);124  unsigned Align = getContext().getTypeAlign(Ty);125 126  if (Size > 64)127    return getNaturalAlignIndirect(Ty, getDataLayout().getAllocaAddrSpace(),128                                   /*ByVal=*/true);129 130  if (HexagonAdjustRegsLeft(Size, RegsLeft))131    Align = Size <= 32 ? 32 : 64;132  if (Size <= Align) {133    // Pass in the smallest viable integer type.134    Size = llvm::bit_ceil(Size);135    return ABIArgInfo::getDirect(llvm::Type::getIntNTy(getVMContext(), Size));136  }137  return DefaultABIInfo::classifyArgumentType(Ty);138}139 140ABIArgInfo HexagonABIInfo::classifyReturnType(QualType RetTy) const {141  if (RetTy->isVoidType())142    return ABIArgInfo::getIgnore();143 144  const TargetInfo &T = CGT.getTarget();145  uint64_t Size = getContext().getTypeSize(RetTy);146 147  if (RetTy->getAs<VectorType>()) {148    // HVX vectors are returned in vector registers or register pairs.149    if (T.hasFeature("hvx")) {150      assert(T.hasFeature("hvx-length64b") || T.hasFeature("hvx-length128b"));151      uint64_t VecSize = T.hasFeature("hvx-length64b") ? 64*8 : 128*8;152      if (Size == VecSize || Size == 2*VecSize)153        return ABIArgInfo::getDirectInReg();154    }155    // Large vector types should be returned via memory.156    if (Size > 64)157      return getNaturalAlignIndirect(RetTy,158                                     getDataLayout().getAllocaAddrSpace());159  }160 161  if (!isAggregateTypeForABI(RetTy)) {162    // Treat an enum type as its underlying type.163    if (const auto *ED = RetTy->getAsEnumDecl())164      RetTy = ED->getIntegerType();165 166    if (Size > 64 && RetTy->isBitIntType())167      return getNaturalAlignIndirect(168          RetTy, getDataLayout().getAllocaAddrSpace(), /*ByVal=*/false);169 170    return isPromotableIntegerTypeForABI(RetTy) ? ABIArgInfo::getExtend(RetTy)171                                                : ABIArgInfo::getDirect();172  }173 174  if (isEmptyRecord(getContext(), RetTy, true))175    return ABIArgInfo::getIgnore();176 177  // Aggregates <= 8 bytes are returned in registers, other aggregates178  // are returned indirectly.179  if (Size <= 64) {180    // Return in the smallest viable integer type.181    Size = llvm::bit_ceil(Size);182    return ABIArgInfo::getDirect(llvm::Type::getIntNTy(getVMContext(), Size));183  }184  return getNaturalAlignIndirect(RetTy, getDataLayout().getAllocaAddrSpace(),185                                 /*ByVal=*/true);186}187 188Address HexagonABIInfo::EmitVAArgFromMemory(CodeGenFunction &CGF,189                                            Address VAListAddr,190                                            QualType Ty) const {191  // Load the overflow area pointer.192  Address __overflow_area_pointer_p =193      CGF.Builder.CreateStructGEP(VAListAddr, 2, "__overflow_area_pointer_p");194  llvm::Value *__overflow_area_pointer = CGF.Builder.CreateLoad(195      __overflow_area_pointer_p, "__overflow_area_pointer");196 197  uint64_t Align = CGF.getContext().getTypeAlign(Ty) / 8;198  if (Align > 4) {199    // Alignment should be a power of 2.200    assert((Align & (Align - 1)) == 0 && "Alignment is not power of 2!");201 202    // overflow_arg_area = (overflow_arg_area + align - 1) & -align;203    llvm::Value *Offset = llvm::ConstantInt::get(CGF.Int64Ty, Align - 1);204 205    // Add offset to the current pointer to access the argument.206    __overflow_area_pointer =207        CGF.Builder.CreateGEP(CGF.Int8Ty, __overflow_area_pointer, Offset);208    llvm::Value *AsInt =209        CGF.Builder.CreatePtrToInt(__overflow_area_pointer, CGF.Int32Ty);210 211    // Create a mask which should be "AND"ed212    // with (overflow_arg_area + align - 1)213    llvm::Value *Mask = llvm::ConstantInt::get(CGF.Int32Ty, -(int)Align);214    __overflow_area_pointer = CGF.Builder.CreateIntToPtr(215        CGF.Builder.CreateAnd(AsInt, Mask), __overflow_area_pointer->getType(),216        "__overflow_area_pointer.align");217  }218 219  // Get the type of the argument from memory and bitcast220  // overflow area pointer to the argument type.221  llvm::Type *PTy = CGF.ConvertTypeForMem(Ty);222  Address AddrTyped =223      Address(__overflow_area_pointer, PTy, CharUnits::fromQuantity(Align));224 225  // Round up to the minimum stack alignment for varargs which is 4 bytes.226  uint64_t Offset = llvm::alignTo(CGF.getContext().getTypeSize(Ty) / 8, 4);227 228  __overflow_area_pointer = CGF.Builder.CreateGEP(229      CGF.Int8Ty, __overflow_area_pointer,230      llvm::ConstantInt::get(CGF.Int32Ty, Offset),231      "__overflow_area_pointer.next");232  CGF.Builder.CreateStore(__overflow_area_pointer, __overflow_area_pointer_p);233 234  return AddrTyped;235}236 237Address HexagonABIInfo::EmitVAArgForHexagon(CodeGenFunction &CGF,238                                            Address VAListAddr,239                                            QualType Ty) const {240  // FIXME: Need to handle alignment241  llvm::Type *BP = CGF.Int8PtrTy;242  CGBuilderTy &Builder = CGF.Builder;243  Address VAListAddrAsBPP = VAListAddr.withElementType(BP);244  llvm::Value *Addr = Builder.CreateLoad(VAListAddrAsBPP, "ap.cur");245  // Handle address alignment for type alignment > 32 bits246  uint64_t TyAlign = CGF.getContext().getTypeAlign(Ty) / 8;247  if (TyAlign > 4) {248    assert((TyAlign & (TyAlign - 1)) == 0 && "Alignment is not power of 2!");249    llvm::Value *AddrAsInt = Builder.CreatePtrToInt(Addr, CGF.Int32Ty);250    AddrAsInt = Builder.CreateAdd(AddrAsInt, Builder.getInt32(TyAlign - 1));251    AddrAsInt = Builder.CreateAnd(AddrAsInt, Builder.getInt32(~(TyAlign - 1)));252    Addr = Builder.CreateIntToPtr(AddrAsInt, BP);253  }254  Address AddrTyped =255      Address(Addr, CGF.ConvertType(Ty), CharUnits::fromQuantity(TyAlign));256 257  uint64_t Offset = llvm::alignTo(CGF.getContext().getTypeSize(Ty) / 8, 4);258  llvm::Value *NextAddr = Builder.CreateGEP(259      CGF.Int8Ty, Addr, llvm::ConstantInt::get(CGF.Int32Ty, Offset), "ap.next");260  Builder.CreateStore(NextAddr, VAListAddrAsBPP);261 262  return AddrTyped;263}264 265Address HexagonABIInfo::EmitVAArgForHexagonLinux(CodeGenFunction &CGF,266                                                 Address VAListAddr,267                                                 QualType Ty) const {268  int ArgSize = CGF.getContext().getTypeSize(Ty) / 8;269 270  if (ArgSize > 8)271    return EmitVAArgFromMemory(CGF, VAListAddr, Ty);272 273  // Here we have check if the argument is in register area or274  // in overflow area.275  // If the saved register area pointer + argsize rounded up to alignment >276  // saved register area end pointer, argument is in overflow area.277  unsigned RegsLeft = 6;278  Ty = CGF.getContext().getCanonicalType(Ty);279  (void)classifyArgumentType(Ty, &RegsLeft);280 281  llvm::BasicBlock *MaybeRegBlock = CGF.createBasicBlock("vaarg.maybe_reg");282  llvm::BasicBlock *InRegBlock = CGF.createBasicBlock("vaarg.in_reg");283  llvm::BasicBlock *OnStackBlock = CGF.createBasicBlock("vaarg.on_stack");284  llvm::BasicBlock *ContBlock = CGF.createBasicBlock("vaarg.end");285 286  // Get rounded size of the argument.GCC does not allow vararg of287  // size < 4 bytes. We follow the same logic here.288  ArgSize = (CGF.getContext().getTypeSize(Ty) <= 32) ? 4 : 8;289  int ArgAlign = (CGF.getContext().getTypeSize(Ty) <= 32) ? 4 : 8;290 291  // Argument may be in saved register area292  CGF.EmitBlock(MaybeRegBlock);293 294  // Load the current saved register area pointer.295  Address __current_saved_reg_area_pointer_p = CGF.Builder.CreateStructGEP(296      VAListAddr, 0, "__current_saved_reg_area_pointer_p");297  llvm::Value *__current_saved_reg_area_pointer = CGF.Builder.CreateLoad(298      __current_saved_reg_area_pointer_p, "__current_saved_reg_area_pointer");299 300  // Load the saved register area end pointer.301  Address __saved_reg_area_end_pointer_p = CGF.Builder.CreateStructGEP(302      VAListAddr, 1, "__saved_reg_area_end_pointer_p");303  llvm::Value *__saved_reg_area_end_pointer = CGF.Builder.CreateLoad(304      __saved_reg_area_end_pointer_p, "__saved_reg_area_end_pointer");305 306  // If the size of argument is > 4 bytes, check if the stack307  // location is aligned to 8 bytes308  if (ArgAlign > 4) {309 310    llvm::Value *__current_saved_reg_area_pointer_int =311        CGF.Builder.CreatePtrToInt(__current_saved_reg_area_pointer,312                                   CGF.Int32Ty);313 314    __current_saved_reg_area_pointer_int = CGF.Builder.CreateAdd(315        __current_saved_reg_area_pointer_int,316        llvm::ConstantInt::get(CGF.Int32Ty, (ArgAlign - 1)),317        "align_current_saved_reg_area_pointer");318 319    __current_saved_reg_area_pointer_int =320        CGF.Builder.CreateAnd(__current_saved_reg_area_pointer_int,321                              llvm::ConstantInt::get(CGF.Int32Ty, -ArgAlign),322                              "align_current_saved_reg_area_pointer");323 324    __current_saved_reg_area_pointer =325        CGF.Builder.CreateIntToPtr(__current_saved_reg_area_pointer_int,326                                   __current_saved_reg_area_pointer->getType(),327                                   "align_current_saved_reg_area_pointer");328  }329 330  llvm::Value *__new_saved_reg_area_pointer =331      CGF.Builder.CreateGEP(CGF.Int8Ty, __current_saved_reg_area_pointer,332                            llvm::ConstantInt::get(CGF.Int32Ty, ArgSize),333                            "__new_saved_reg_area_pointer");334 335  llvm::Value *UsingStack = nullptr;336  UsingStack = CGF.Builder.CreateICmpSGT(__new_saved_reg_area_pointer,337                                         __saved_reg_area_end_pointer);338 339  CGF.Builder.CreateCondBr(UsingStack, OnStackBlock, InRegBlock);340 341  // Argument in saved register area342  // Implement the block where argument is in register saved area343  CGF.EmitBlock(InRegBlock);344 345  CGF.Builder.CreateStore(__new_saved_reg_area_pointer,346                          __current_saved_reg_area_pointer_p);347 348  CGF.EmitBranch(ContBlock);349 350  // Argument in overflow area351  // Implement the block where the argument is in overflow area.352  CGF.EmitBlock(OnStackBlock);353 354  // Load the overflow area pointer355  Address __overflow_area_pointer_p =356      CGF.Builder.CreateStructGEP(VAListAddr, 2, "__overflow_area_pointer_p");357  llvm::Value *__overflow_area_pointer = CGF.Builder.CreateLoad(358      __overflow_area_pointer_p, "__overflow_area_pointer");359 360  // Align the overflow area pointer according to the alignment of the argument361  if (ArgAlign > 4) {362    llvm::Value *__overflow_area_pointer_int =363        CGF.Builder.CreatePtrToInt(__overflow_area_pointer, CGF.Int32Ty);364 365    __overflow_area_pointer_int =366        CGF.Builder.CreateAdd(__overflow_area_pointer_int,367                              llvm::ConstantInt::get(CGF.Int32Ty, ArgAlign - 1),368                              "align_overflow_area_pointer");369 370    __overflow_area_pointer_int =371        CGF.Builder.CreateAnd(__overflow_area_pointer_int,372                              llvm::ConstantInt::get(CGF.Int32Ty, -ArgAlign),373                              "align_overflow_area_pointer");374 375    __overflow_area_pointer = CGF.Builder.CreateIntToPtr(376        __overflow_area_pointer_int, __overflow_area_pointer->getType(),377        "align_overflow_area_pointer");378  }379 380  // Get the pointer for next argument in overflow area and store it381  // to overflow area pointer.382  llvm::Value *__new_overflow_area_pointer = CGF.Builder.CreateGEP(383      CGF.Int8Ty, __overflow_area_pointer,384      llvm::ConstantInt::get(CGF.Int32Ty, ArgSize),385      "__overflow_area_pointer.next");386 387  CGF.Builder.CreateStore(__new_overflow_area_pointer,388                          __overflow_area_pointer_p);389 390  CGF.Builder.CreateStore(__new_overflow_area_pointer,391                          __current_saved_reg_area_pointer_p);392 393  CGF.EmitBranch(ContBlock);394  // Get the correct pointer to load the variable argument395  // Implement the ContBlock396  CGF.EmitBlock(ContBlock);397 398  llvm::Type *MemTy = CGF.ConvertTypeForMem(Ty);399  llvm::PHINode *ArgAddr = CGF.Builder.CreatePHI(400      llvm::PointerType::getUnqual(MemTy->getContext()), 2, "vaarg.addr");401  ArgAddr->addIncoming(__current_saved_reg_area_pointer, InRegBlock);402  ArgAddr->addIncoming(__overflow_area_pointer, OnStackBlock);403 404  return Address(ArgAddr, MemTy, CharUnits::fromQuantity(ArgAlign));405}406 407RValue HexagonABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,408                                 QualType Ty, AggValueSlot Slot) const {409 410  if (getTarget().getTriple().isMusl())411    return CGF.EmitLoadOfAnyValue(412        CGF.MakeAddrLValue(EmitVAArgForHexagonLinux(CGF, VAListAddr, Ty), Ty),413        Slot);414 415  return CGF.EmitLoadOfAnyValue(416      CGF.MakeAddrLValue(EmitVAArgForHexagon(CGF, VAListAddr, Ty), Ty), Slot);417}418 419std::unique_ptr<TargetCodeGenInfo>420CodeGen::createHexagonTargetCodeGenInfo(CodeGenModule &CGM) {421  return std::make_unique<HexagonTargetCodeGenInfo>(CGM.getTypes());422}423