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