1259701Sdim//==-- CGFunctionInfo.h - Representation of function argument/return types -==//
2259701Sdim//
3259701Sdim//                     The LLVM Compiler Infrastructure
4259701Sdim//
5259701Sdim// This file is distributed under the University of Illinois Open Source
6259701Sdim// License. See LICENSE.TXT for details.
7259701Sdim//
8259701Sdim//===----------------------------------------------------------------------===//
9259701Sdim//
10259701Sdim// Defines CGFunctionInfo and associated types used in representing the
11259701Sdim// LLVM source types and ABI-coerced types for function arguments and
12259701Sdim// return values.
13259701Sdim//
14259701Sdim//===----------------------------------------------------------------------===//
15259701Sdim
16259701Sdim#ifndef LLVM_CLANG_CODEGEN_FUNCTION_INFO_H
17259701Sdim#define LLVM_CLANG_CODEGEN_FUNCTION_INFO_H
18259701Sdim
19259701Sdim#include "clang/AST/CanonicalType.h"
20259701Sdim#include "clang/AST/Type.h"
21259701Sdim#include "llvm/ADT/FoldingSet.h"
22259701Sdim
23259701Sdim#include <cassert>
24259701Sdim
25259701Sdimnamespace llvm {
26259701Sdim  class Type;
27259701Sdim}
28259701Sdim
29259701Sdimnamespace clang {
30259701Sdimnamespace CodeGen {
31259701Sdim
32259701Sdim/// ABIArgInfo - Helper class to encapsulate information about how a
33259701Sdim/// specific C type should be passed to or returned from a function.
34259701Sdimclass ABIArgInfo {
35259701Sdimpublic:
36259701Sdim  enum Kind {
37259701Sdim    /// Direct - Pass the argument directly using the normal converted LLVM
38259701Sdim    /// type, or by coercing to another specified type stored in
39259701Sdim    /// 'CoerceToType').  If an offset is specified (in UIntData), then the
40259701Sdim    /// argument passed is offset by some number of bytes in the memory
41259701Sdim    /// representation. A dummy argument is emitted before the real argument
42259701Sdim    /// if the specified type stored in "PaddingType" is not zero.
43259701Sdim    Direct,
44259701Sdim
45259701Sdim    /// Extend - Valid only for integer argument types. Same as 'direct'
46259701Sdim    /// but also emit a zero/sign extension attribute.
47259701Sdim    Extend,
48259701Sdim
49259701Sdim    /// Indirect - Pass the argument indirectly via a hidden pointer
50259701Sdim    /// with the specified alignment (0 indicates default alignment).
51259701Sdim    Indirect,
52259701Sdim
53259701Sdim    /// Ignore - Ignore the argument (treat as void). Useful for void and
54259701Sdim    /// empty structs.
55259701Sdim    Ignore,
56259701Sdim
57259701Sdim    /// Expand - Only valid for aggregate argument types. The structure should
58259701Sdim    /// be expanded into consecutive arguments for its constituent fields.
59259701Sdim    /// Currently expand is only allowed on structures whose fields
60259701Sdim    /// are all scalar types or are themselves expandable types.
61259701Sdim    Expand,
62259701Sdim
63259701Sdim    KindFirst=Direct, KindLast=Expand
64259701Sdim  };
65259701Sdim
66259701Sdimprivate:
67259701Sdim  Kind TheKind;
68259701Sdim  llvm::Type *TypeData;
69259701Sdim  llvm::Type *PaddingType;
70259701Sdim  unsigned UIntData;
71259701Sdim  bool BoolData0;
72259701Sdim  bool BoolData1;
73259701Sdim  bool InReg;
74259701Sdim  bool PaddingInReg;
75259701Sdim
76259701Sdim  ABIArgInfo(Kind K, llvm::Type *TD, unsigned UI, bool B0, bool B1, bool IR,
77259701Sdim             bool PIR, llvm::Type* P)
78259701Sdim    : TheKind(K), TypeData(TD), PaddingType(P), UIntData(UI), BoolData0(B0),
79259701Sdim      BoolData1(B1), InReg(IR), PaddingInReg(PIR) {}
80259701Sdim
81259701Sdimpublic:
82259701Sdim  ABIArgInfo() : TheKind(Direct), TypeData(0), UIntData(0) {}
83259701Sdim
84259701Sdim  static ABIArgInfo getDirect(llvm::Type *T = 0, unsigned Offset = 0,
85259701Sdim                              llvm::Type *Padding = 0) {
86259701Sdim    return ABIArgInfo(Direct, T, Offset, false, false, false, false, Padding);
87259701Sdim  }
88259701Sdim  static ABIArgInfo getDirectInReg(llvm::Type *T = 0) {
89259701Sdim    return ABIArgInfo(Direct, T, 0, false, false, true, false, 0);
90259701Sdim  }
91259701Sdim  static ABIArgInfo getExtend(llvm::Type *T = 0) {
92259701Sdim    return ABIArgInfo(Extend, T, 0, false, false, false, false, 0);
93259701Sdim  }
94259701Sdim  static ABIArgInfo getExtendInReg(llvm::Type *T = 0) {
95259701Sdim    return ABIArgInfo(Extend, T, 0, false, false, true, false, 0);
96259701Sdim  }
97259701Sdim  static ABIArgInfo getIgnore() {
98259701Sdim    return ABIArgInfo(Ignore, 0, 0, false, false, false, false, 0);
99259701Sdim  }
100259701Sdim  static ABIArgInfo getIndirect(unsigned Alignment, bool ByVal = true
101259701Sdim                                , bool Realign = false
102259701Sdim                                , llvm::Type *Padding = 0) {
103259701Sdim    return ABIArgInfo(Indirect, 0, Alignment, ByVal, Realign, false, false,
104259701Sdim                      Padding);
105259701Sdim  }
106259701Sdim  static ABIArgInfo getIndirectInReg(unsigned Alignment, bool ByVal = true
107259701Sdim                                , bool Realign = false) {
108259701Sdim    return ABIArgInfo(Indirect, 0, Alignment, ByVal, Realign, true, false, 0);
109259701Sdim  }
110259701Sdim  static ABIArgInfo getExpand() {
111259701Sdim    return ABIArgInfo(Expand, 0, 0, false, false, false, false, 0);
112259701Sdim  }
113259701Sdim  static ABIArgInfo getExpandWithPadding(bool PaddingInReg,
114259701Sdim                                         llvm::Type *Padding) {
115259701Sdim   return ABIArgInfo(Expand, 0, 0, false, false, false, PaddingInReg,
116259701Sdim                     Padding);
117259701Sdim  }
118259701Sdim
119259701Sdim  Kind getKind() const { return TheKind; }
120259701Sdim  bool isDirect() const { return TheKind == Direct; }
121259701Sdim  bool isExtend() const { return TheKind == Extend; }
122259701Sdim  bool isIgnore() const { return TheKind == Ignore; }
123259701Sdim  bool isIndirect() const { return TheKind == Indirect; }
124259701Sdim  bool isExpand() const { return TheKind == Expand; }
125259701Sdim
126259701Sdim  bool canHaveCoerceToType() const {
127259701Sdim    return TheKind == Direct || TheKind == Extend;
128259701Sdim  }
129259701Sdim
130259701Sdim  // Direct/Extend accessors
131259701Sdim  unsigned getDirectOffset() const {
132259701Sdim    assert((isDirect() || isExtend()) && "Not a direct or extend kind");
133259701Sdim    return UIntData;
134259701Sdim  }
135259701Sdim
136259701Sdim  llvm::Type *getPaddingType() const {
137259701Sdim    return PaddingType;
138259701Sdim  }
139259701Sdim
140259701Sdim  bool getPaddingInReg() const {
141259701Sdim    return PaddingInReg;
142259701Sdim  }
143259701Sdim
144259701Sdim  llvm::Type *getCoerceToType() const {
145259701Sdim    assert(canHaveCoerceToType() && "Invalid kind!");
146259701Sdim    return TypeData;
147259701Sdim  }
148259701Sdim
149259701Sdim  void setCoerceToType(llvm::Type *T) {
150259701Sdim    assert(canHaveCoerceToType() && "Invalid kind!");
151259701Sdim    TypeData = T;
152259701Sdim  }
153259701Sdim
154259701Sdim  bool getInReg() const {
155259701Sdim    assert((isDirect() || isExtend() || isIndirect()) && "Invalid kind!");
156259701Sdim    return InReg;
157259701Sdim  }
158259701Sdim
159259701Sdim  // Indirect accessors
160259701Sdim  unsigned getIndirectAlign() const {
161259701Sdim    assert(TheKind == Indirect && "Invalid kind!");
162259701Sdim    return UIntData;
163259701Sdim  }
164259701Sdim
165259701Sdim  bool getIndirectByVal() const {
166259701Sdim    assert(TheKind == Indirect && "Invalid kind!");
167259701Sdim    return BoolData0;
168259701Sdim  }
169259701Sdim
170259701Sdim  bool getIndirectRealign() const {
171259701Sdim    assert(TheKind == Indirect && "Invalid kind!");
172259701Sdim    return BoolData1;
173259701Sdim  }
174259701Sdim
175259701Sdim  void dump() const;
176259701Sdim};
177259701Sdim
178259701Sdim/// A class for recording the number of arguments that a function
179259701Sdim/// signature requires.
180259701Sdimclass RequiredArgs {
181259701Sdim  /// The number of required arguments, or ~0 if the signature does
182259701Sdim  /// not permit optional arguments.
183259701Sdim  unsigned NumRequired;
184259701Sdimpublic:
185259701Sdim  enum All_t { All };
186259701Sdim
187259701Sdim  RequiredArgs(All_t _) : NumRequired(~0U) {}
188259701Sdim  explicit RequiredArgs(unsigned n) : NumRequired(n) {
189259701Sdim    assert(n != ~0U);
190259701Sdim  }
191259701Sdim
192259701Sdim  /// Compute the arguments required by the given formal prototype,
193259701Sdim  /// given that there may be some additional, non-formal arguments
194259701Sdim  /// in play.
195259701Sdim  static RequiredArgs forPrototypePlus(const FunctionProtoType *prototype,
196259701Sdim                                       unsigned additional) {
197259701Sdim    if (!prototype->isVariadic()) return All;
198259701Sdim    return RequiredArgs(prototype->getNumArgs() + additional);
199259701Sdim  }
200259701Sdim
201259701Sdim  static RequiredArgs forPrototype(const FunctionProtoType *prototype) {
202259701Sdim    return forPrototypePlus(prototype, 0);
203259701Sdim  }
204259701Sdim
205259701Sdim  static RequiredArgs forPrototype(CanQual<FunctionProtoType> prototype) {
206259701Sdim    return forPrototype(prototype.getTypePtr());
207259701Sdim  }
208259701Sdim
209259701Sdim  static RequiredArgs forPrototypePlus(CanQual<FunctionProtoType> prototype,
210259701Sdim                                       unsigned additional) {
211259701Sdim    return forPrototypePlus(prototype.getTypePtr(), additional);
212259701Sdim  }
213259701Sdim
214259701Sdim  bool allowsOptionalArgs() const { return NumRequired != ~0U; }
215259701Sdim  unsigned getNumRequiredArgs() const {
216259701Sdim    assert(allowsOptionalArgs());
217259701Sdim    return NumRequired;
218259701Sdim  }
219259701Sdim
220259701Sdim  unsigned getOpaqueData() const { return NumRequired; }
221259701Sdim  static RequiredArgs getFromOpaqueData(unsigned value) {
222259701Sdim    if (value == ~0U) return All;
223259701Sdim    return RequiredArgs(value);
224259701Sdim  }
225259701Sdim};
226259701Sdim
227259701Sdim/// CGFunctionInfo - Class to encapsulate the information about a
228259701Sdim/// function definition.
229259701Sdimclass CGFunctionInfo : public llvm::FoldingSetNode {
230259701Sdim  struct ArgInfo {
231259701Sdim    CanQualType type;
232259701Sdim    ABIArgInfo info;
233259701Sdim  };
234259701Sdim
235259701Sdim  /// The LLVM::CallingConv to use for this function (as specified by the
236259701Sdim  /// user).
237259701Sdim  unsigned CallingConvention : 8;
238259701Sdim
239259701Sdim  /// The LLVM::CallingConv to actually use for this function, which may
240259701Sdim  /// depend on the ABI.
241259701Sdim  unsigned EffectiveCallingConvention : 8;
242259701Sdim
243259701Sdim  /// The clang::CallingConv that this was originally created with.
244259701Sdim  unsigned ASTCallingConvention : 8;
245259701Sdim
246259701Sdim  /// Whether this function is noreturn.
247259701Sdim  unsigned NoReturn : 1;
248259701Sdim
249259701Sdim  /// Whether this function is returns-retained.
250259701Sdim  unsigned ReturnsRetained : 1;
251259701Sdim
252259701Sdim  /// How many arguments to pass inreg.
253259701Sdim  unsigned HasRegParm : 1;
254259701Sdim  unsigned RegParm : 4;
255259701Sdim
256259701Sdim  RequiredArgs Required;
257259701Sdim
258259701Sdim  unsigned NumArgs;
259259701Sdim  ArgInfo *getArgsBuffer() {
260259701Sdim    return reinterpret_cast<ArgInfo*>(this+1);
261259701Sdim  }
262259701Sdim  const ArgInfo *getArgsBuffer() const {
263259701Sdim    return reinterpret_cast<const ArgInfo*>(this + 1);
264259701Sdim  }
265259701Sdim
266259701Sdim  CGFunctionInfo() : Required(RequiredArgs::All) {}
267259701Sdim
268259701Sdimpublic:
269259701Sdim  static CGFunctionInfo *create(unsigned llvmCC,
270259701Sdim                                const FunctionType::ExtInfo &extInfo,
271259701Sdim                                CanQualType resultType,
272259701Sdim                                ArrayRef<CanQualType> argTypes,
273259701Sdim                                RequiredArgs required);
274259701Sdim
275259701Sdim  typedef const ArgInfo *const_arg_iterator;
276259701Sdim  typedef ArgInfo *arg_iterator;
277259701Sdim
278259701Sdim  const_arg_iterator arg_begin() const { return getArgsBuffer() + 1; }
279259701Sdim  const_arg_iterator arg_end() const { return getArgsBuffer() + 1 + NumArgs; }
280259701Sdim  arg_iterator arg_begin() { return getArgsBuffer() + 1; }
281259701Sdim  arg_iterator arg_end() { return getArgsBuffer() + 1 + NumArgs; }
282259701Sdim
283259701Sdim  unsigned  arg_size() const { return NumArgs; }
284259701Sdim
285259701Sdim  bool isVariadic() const { return Required.allowsOptionalArgs(); }
286259701Sdim  RequiredArgs getRequiredArgs() const { return Required; }
287259701Sdim
288259701Sdim  bool isNoReturn() const { return NoReturn; }
289259701Sdim
290259701Sdim  /// In ARC, whether this function retains its return value.  This
291259701Sdim  /// is not always reliable for call sites.
292259701Sdim  bool isReturnsRetained() const { return ReturnsRetained; }
293259701Sdim
294259701Sdim  /// getASTCallingConvention() - Return the AST-specified calling
295259701Sdim  /// convention.
296259701Sdim  CallingConv getASTCallingConvention() const {
297259701Sdim    return CallingConv(ASTCallingConvention);
298259701Sdim  }
299259701Sdim
300259701Sdim  /// getCallingConvention - Return the user specified calling
301259701Sdim  /// convention, which has been translated into an LLVM CC.
302259701Sdim  unsigned getCallingConvention() const { return CallingConvention; }
303259701Sdim
304259701Sdim  /// getEffectiveCallingConvention - Return the actual calling convention to
305259701Sdim  /// use, which may depend on the ABI.
306259701Sdim  unsigned getEffectiveCallingConvention() const {
307259701Sdim    return EffectiveCallingConvention;
308259701Sdim  }
309259701Sdim  void setEffectiveCallingConvention(unsigned Value) {
310259701Sdim    EffectiveCallingConvention = Value;
311259701Sdim  }
312259701Sdim
313259701Sdim  bool getHasRegParm() const { return HasRegParm; }
314259701Sdim  unsigned getRegParm() const { return RegParm; }
315259701Sdim
316259701Sdim  FunctionType::ExtInfo getExtInfo() const {
317259701Sdim    return FunctionType::ExtInfo(isNoReturn(),
318259701Sdim                                 getHasRegParm(), getRegParm(),
319259701Sdim                                 getASTCallingConvention(),
320259701Sdim                                 isReturnsRetained());
321259701Sdim  }
322259701Sdim
323259701Sdim  CanQualType getReturnType() const { return getArgsBuffer()[0].type; }
324259701Sdim
325259701Sdim  ABIArgInfo &getReturnInfo() { return getArgsBuffer()[0].info; }
326259701Sdim  const ABIArgInfo &getReturnInfo() const { return getArgsBuffer()[0].info; }
327259701Sdim
328259701Sdim  void Profile(llvm::FoldingSetNodeID &ID) {
329259701Sdim    ID.AddInteger(getASTCallingConvention());
330259701Sdim    ID.AddBoolean(NoReturn);
331259701Sdim    ID.AddBoolean(ReturnsRetained);
332259701Sdim    ID.AddBoolean(HasRegParm);
333259701Sdim    ID.AddInteger(RegParm);
334259701Sdim    ID.AddInteger(Required.getOpaqueData());
335259701Sdim    getReturnType().Profile(ID);
336259701Sdim    for (arg_iterator it = arg_begin(), ie = arg_end(); it != ie; ++it)
337259701Sdim      it->type.Profile(ID);
338259701Sdim  }
339259701Sdim  static void Profile(llvm::FoldingSetNodeID &ID,
340259701Sdim                      const FunctionType::ExtInfo &info,
341259701Sdim                      RequiredArgs required,
342259701Sdim                      CanQualType resultType,
343259701Sdim                      ArrayRef<CanQualType> argTypes) {
344259701Sdim    ID.AddInteger(info.getCC());
345259701Sdim    ID.AddBoolean(info.getNoReturn());
346259701Sdim    ID.AddBoolean(info.getProducesResult());
347259701Sdim    ID.AddBoolean(info.getHasRegParm());
348259701Sdim    ID.AddInteger(info.getRegParm());
349259701Sdim    ID.AddInteger(required.getOpaqueData());
350259701Sdim    resultType.Profile(ID);
351259701Sdim    for (ArrayRef<CanQualType>::iterator
352259701Sdim           i = argTypes.begin(), e = argTypes.end(); i != e; ++i) {
353259701Sdim      i->Profile(ID);
354259701Sdim    }
355259701Sdim  }
356259701Sdim};
357259701Sdim
358259701Sdim}  // end namespace CodeGen
359259701Sdim}  // end namespace clang
360259701Sdim
361259701Sdim#endif
362