1//===- NVPTXUtilities.cpp - Utility Functions -----------------------------===//
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-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file contains miscellaneous utility functions
10//
11//===----------------------------------------------------------------------===//
12
13#include "NVPTXUtilities.h"
14#include "NVVMProperties.h"
15#include "llvm/CodeGen/SelectionDAGNodes.h"
16#include "llvm/IR/Attributes.h"
17#include "llvm/IR/DataLayout.h"
18#include "llvm/IR/Function.h"
19#include "llvm/Support/Alignment.h"
20#include "llvm/Support/CommandLine.h"
21#include <algorithm>
22
23using namespace llvm;
24
25static cl::opt<bool> ForceMinByValParamAlign(
26 "nvptx-force-min-byval-param-align", cl::Hidden,
27 cl::desc("NVPTX Specific: force 4-byte minimal alignment for byval"
28 " params of device functions."),
29 cl::init(Val: false));
30
31Function *llvm::getMaybeBitcastedCallee(const CallBase *CB) {
32 return dyn_cast<Function>(Val: CB->getCalledOperand()->stripPointerCasts());
33}
34
35unsigned llvm::getFromTypeWidthForLoad(const MemSDNode *Mem) {
36 auto TotalWidth = Mem->getMemoryVT().getSizeInBits();
37 auto NumElts = Mem->getNumValues() - 1;
38 auto ElementBitWidth = TotalWidth / NumElts;
39 assert(isPowerOf2_32(ElementBitWidth) && ElementBitWidth >= 8 &&
40 ElementBitWidth <= 128 && TotalWidth <= 256 &&
41 "Invalid width for load");
42 return ElementBitWidth;
43}
44
45Align llvm::getPTXParamTypeAlign(Type *ArgTy, const DataLayout &DL) {
46 // Capping the alignment to 128 bytes as that is the maximum alignment
47 // supported by PTX.
48 return std::min(a: Align(128), b: DL.getABITypeAlign(Ty: ArgTy));
49}
50
51static Align getByValParamAlignFloor(const Function *F) {
52 // Old ptx versions have a bug. When PTX code takes address of
53 // byval parameter with alignment < 4, ptxas generates code to
54 // spill argument into memory. Alas on sm_50+ ptxas generates
55 // SASS code that fails with misaligned access. To work around
56 // the problem, make sure that we align byval parameters by at
57 // least 4. This bug seems to be fixed at least starting from
58 // ptxas > 9.0.
59 // TODO: remove this after verifying the bug is not reproduced
60 // on non-deprecated ptxas versions.
61 const bool ShouldForceMinAlign =
62 ForceMinByValParamAlign && (!F || !isKernelFunction(F: *F));
63 return ShouldForceMinAlign ? Align(4) : Align(1);
64}
65
66Align llvm::getDeviceByValParamAlign(const Function *F, Type *ArgTy,
67 unsigned AttrIdx, const DataLayout &DL) {
68 return std::max(a: getPTXParamAlign(F, Ty: ArgTy, AttrIdx, DL),
69 b: getByValParamAlignFloor(F));
70}
71
72Align llvm::getDeviceByValParamAlign(const CallBase *CB, Type *ArgTy,
73 unsigned AttrIdx, const DataLayout &DL) {
74 Align ParamAlign = getPTXParamAlign(CB, Ty: ArgTy, AttrIdx, DL);
75
76 // For an indirect call getPTXParamAlign can't see the call's own byval
77 // alignment, so fold it in.
78 if (CB && AttrIdx >= AttributeList::FirstArgIndex)
79 ParamAlign = std::max(
80 a: ParamAlign,
81 b: CB->getParamAlign(ArgNo: AttrIdx - AttributeList::FirstArgIndex).valueOrOne());
82
83 return std::max(a: ParamAlign, b: getByValParamAlignFloor(
84 F: CB ? CB->getCalledFunction() : nullptr));
85}
86
87Align llvm::getPTXParamAlign(const Function *F, Type *Ty, unsigned AttrIdx,
88 const DataLayout &DL) {
89 if (F)
90 if (MaybeAlign StackAlign = getStackAlign(F: *F, Index: AttrIdx))
91 return StackAlign.value();
92
93 Align TypeAlign = getPTXParamTypeAlign(ArgTy: Ty, DL);
94 if (F && AttrIdx >= AttributeList::FirstArgIndex) {
95 unsigned ArgNo = AttrIdx - AttributeList::FirstArgIndex;
96 if (F->getAttributes().hasParamAttr(ArgNo, Kind: Attribute::ByVal))
97 return std::max(a: TypeAlign, b: F->getParamAlign(ArgNo).valueOrOne());
98 }
99 return TypeAlign;
100}
101
102Align llvm::getPTXParamAlign(const CallBase *CB, Type *Ty, unsigned Idx,
103 const DataLayout &DL) {
104 if (CB)
105 if (MaybeAlign StackAlign = getStackAlign(*CB, Idx))
106 return StackAlign.value();
107
108 // Otherwise resolve the direct callee and use its parameter alignment.
109 const Function *DirectCallee = CB ? CB->getCalledFunction() : nullptr;
110 if (!DirectCallee && CB)
111 DirectCallee = getMaybeBitcastedCallee(CB);
112
113 return getPTXParamAlign(F: DirectCallee, Ty, AttrIdx: Idx, DL);
114}
115