blob: b0a672b6b1052f69d471e91cf52cc0986a6f4618 [file] [log] [blame]
Daniel Dunbar0dbe2272008-09-08 21:33:45 +00001//===----- CGCall.h - Encapsulate calling convention details ----*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// These classes wrap the information about a call or function
11// definition used to handle ABI compliancy.
12//
13//===----------------------------------------------------------------------===//
14
15#include "CGCall.h"
16#include "CodeGenFunction.h"
Daniel Dunbarb7688072008-09-10 00:41:16 +000017#include "CodeGenModule.h"
Daniel Dunbar6b1da0e2008-10-13 17:02:26 +000018#include "clang/Basic/TargetInfo.h"
Daniel Dunbar0dbe2272008-09-08 21:33:45 +000019#include "clang/AST/ASTContext.h"
20#include "clang/AST/Decl.h"
21#include "clang/AST/DeclObjC.h"
Daniel Dunbar56273772008-09-17 00:51:38 +000022#include "llvm/ADT/StringExtras.h"
Devang Pateld0646bd2008-09-24 01:01:36 +000023#include "llvm/Attributes.h"
Daniel Dunbar0dbe2272008-09-08 21:33:45 +000024using namespace clang;
25using namespace CodeGen;
26
27/***/
28
Daniel Dunbar0dbe2272008-09-08 21:33:45 +000029// FIXME: Use iterator and sidestep silly type array creation.
30
Daniel Dunbar45c25ba2008-09-10 04:01:49 +000031CGFunctionInfo::CGFunctionInfo(const FunctionTypeNoProto *FTNP)
32 : IsVariadic(true)
33{
34 ArgTypes.push_back(FTNP->getResultType());
35}
36
37CGFunctionInfo::CGFunctionInfo(const FunctionTypeProto *FTP)
38 : IsVariadic(FTP->isVariadic())
39{
40 ArgTypes.push_back(FTP->getResultType());
41 for (unsigned i = 0, e = FTP->getNumArgs(); i != e; ++i)
42 ArgTypes.push_back(FTP->getArgType(i));
43}
44
45// FIXME: Is there really any reason to have this still?
Daniel Dunbar0dbe2272008-09-08 21:33:45 +000046CGFunctionInfo::CGFunctionInfo(const FunctionDecl *FD)
Daniel Dunbar0dbe2272008-09-08 21:33:45 +000047{
48 const FunctionType *FTy = FD->getType()->getAsFunctionType();
49 const FunctionTypeProto *FTP = dyn_cast<FunctionTypeProto>(FTy);
Daniel Dunbar45c25ba2008-09-10 04:01:49 +000050
Daniel Dunbar0dbe2272008-09-08 21:33:45 +000051 ArgTypes.push_back(FTy->getResultType());
Daniel Dunbar45c25ba2008-09-10 04:01:49 +000052 if (FTP) {
53 IsVariadic = FTP->isVariadic();
Daniel Dunbar0dbe2272008-09-08 21:33:45 +000054 for (unsigned i = 0, e = FTP->getNumArgs(); i != e; ++i)
55 ArgTypes.push_back(FTP->getArgType(i));
Daniel Dunbar45c25ba2008-09-10 04:01:49 +000056 } else {
57 IsVariadic = true;
58 }
Daniel Dunbar0dbe2272008-09-08 21:33:45 +000059}
60
61CGFunctionInfo::CGFunctionInfo(const ObjCMethodDecl *MD,
62 const ASTContext &Context)
Daniel Dunbar45c25ba2008-09-10 04:01:49 +000063 : IsVariadic(MD->isVariadic())
Daniel Dunbar0dbe2272008-09-08 21:33:45 +000064{
65 ArgTypes.push_back(MD->getResultType());
66 ArgTypes.push_back(MD->getSelfDecl()->getType());
67 ArgTypes.push_back(Context.getObjCSelType());
68 for (ObjCMethodDecl::param_const_iterator i = MD->param_begin(),
69 e = MD->param_end(); i != e; ++i)
70 ArgTypes.push_back((*i)->getType());
71}
72
Daniel Dunbar5323a4b2008-09-10 00:32:18 +000073ArgTypeIterator CGFunctionInfo::argtypes_begin() const {
74 return ArgTypes.begin();
75}
76
77ArgTypeIterator CGFunctionInfo::argtypes_end() const {
78 return ArgTypes.end();
Daniel Dunbar0dbe2272008-09-08 21:33:45 +000079}
80
81/***/
82
Daniel Dunbar5323a4b2008-09-10 00:32:18 +000083CGCallInfo::CGCallInfo(QualType _ResultType, const CallArgList &_Args) {
84 ArgTypes.push_back(_ResultType);
85 for (CallArgList::const_iterator i = _Args.begin(), e = _Args.end(); i!=e; ++i)
Daniel Dunbar0dbe2272008-09-08 21:33:45 +000086 ArgTypes.push_back(i->second);
87}
88
Daniel Dunbar5323a4b2008-09-10 00:32:18 +000089ArgTypeIterator CGCallInfo::argtypes_begin() const {
90 return ArgTypes.begin();
91}
92
93ArgTypeIterator CGCallInfo::argtypes_end() const {
94 return ArgTypes.end();
Daniel Dunbar0dbe2272008-09-08 21:33:45 +000095}
Daniel Dunbar17b708d2008-09-09 23:27:19 +000096
97/***/
98
Daniel Dunbar8951dbd2008-09-11 01:48:57 +000099/// ABIArgInfo - Helper class to encapsulate information about how a
100/// specific C type should be passed to or returned from a function.
Daniel Dunbar2c8e0f32008-09-10 02:41:04 +0000101class ABIArgInfo {
102public:
103 enum Kind {
104 Default,
Daniel Dunbar8951dbd2008-09-11 01:48:57 +0000105 StructRet, /// Only valid for aggregate return types.
106
Daniel Dunbar56273772008-09-17 00:51:38 +0000107 Coerce, /// Only valid for aggregate return types, the argument
108 /// should be accessed by coercion to a provided type.
Daniel Dunbar8951dbd2008-09-11 01:48:57 +0000109
110 ByVal, /// Only valid for aggregate argument types. The
111 /// structure should be passed "byval" with the
112 /// specified alignment (0 indicates default
113 /// alignment).
114
115 Expand, /// Only valid for aggregate argument types. The
116 /// structure should be expanded into consecutive
Daniel Dunbar56273772008-09-17 00:51:38 +0000117 /// arguments for its constituent fields. Currently
118 /// expand is only allowed on structures whose fields
119 /// are all scalar types or are themselves expandable
120 /// types.
Daniel Dunbar8951dbd2008-09-11 01:48:57 +0000121
122 KindFirst=Default, KindLast=Expand
Daniel Dunbar2c8e0f32008-09-10 02:41:04 +0000123 };
124
125private:
126 Kind TheKind;
Daniel Dunbar639ffe42008-09-10 07:04:09 +0000127 const llvm::Type *TypeData;
Daniel Dunbar8951dbd2008-09-11 01:48:57 +0000128 unsigned UIntData;
Daniel Dunbar2c8e0f32008-09-10 02:41:04 +0000129
Daniel Dunbar8951dbd2008-09-11 01:48:57 +0000130 ABIArgInfo(Kind K, const llvm::Type *TD=0,
131 unsigned UI=0) : TheKind(K),
132 TypeData(TD),
133 UIntData(0) {}
Daniel Dunbar2c8e0f32008-09-10 02:41:04 +0000134public:
135 static ABIArgInfo getDefault() {
Daniel Dunbar8951dbd2008-09-11 01:48:57 +0000136 return ABIArgInfo(Default);
Daniel Dunbar2c8e0f32008-09-10 02:41:04 +0000137 }
138 static ABIArgInfo getStructRet() {
Daniel Dunbar8951dbd2008-09-11 01:48:57 +0000139 return ABIArgInfo(StructRet);
Daniel Dunbar2c8e0f32008-09-10 02:41:04 +0000140 }
Daniel Dunbar639ffe42008-09-10 07:04:09 +0000141 static ABIArgInfo getCoerce(const llvm::Type *T) {
142 assert(T->isSingleValueType() && "Can only coerce to simple types");
Daniel Dunbar2c8e0f32008-09-10 02:41:04 +0000143 return ABIArgInfo(Coerce, T);
144 }
Daniel Dunbar8951dbd2008-09-11 01:48:57 +0000145 static ABIArgInfo getByVal(unsigned Alignment) {
146 return ABIArgInfo(ByVal, 0, Alignment);
147 }
Daniel Dunbar56273772008-09-17 00:51:38 +0000148 static ABIArgInfo getExpand() {
149 return ABIArgInfo(Expand);
150 }
Daniel Dunbar2c8e0f32008-09-10 02:41:04 +0000151
152 Kind getKind() const { return TheKind; }
153 bool isDefault() const { return TheKind == Default; }
154 bool isStructRet() const { return TheKind == StructRet; }
155 bool isCoerce() const { return TheKind == Coerce; }
Daniel Dunbar8951dbd2008-09-11 01:48:57 +0000156 bool isByVal() const { return TheKind == ByVal; }
Daniel Dunbar56273772008-09-17 00:51:38 +0000157 bool isExpand() const { return TheKind == Expand; }
Daniel Dunbar45c25ba2008-09-10 04:01:49 +0000158
159 // Coerce accessors
Daniel Dunbar639ffe42008-09-10 07:04:09 +0000160 const llvm::Type *getCoerceToType() const {
Daniel Dunbar45c25ba2008-09-10 04:01:49 +0000161 assert(TheKind == Coerce && "Invalid kind!");
162 return TypeData;
163 }
Daniel Dunbar8951dbd2008-09-11 01:48:57 +0000164
165 // ByVal accessors
166 unsigned getByValAlignment() const {
167 assert(TheKind == ByVal && "Invalid kind!");
168 return UIntData;
169 }
Daniel Dunbar2c8e0f32008-09-10 02:41:04 +0000170};
171
172/***/
173
Daniel Dunbar6b1da0e2008-10-13 17:02:26 +0000174/* FIXME: All of this stuff should be part of the target interface
175 somehow. It is currently here because it is not clear how to factor
176 the targets to support this, since the Targets currently live in a
177 layer below types n'stuff.
178 */
179
180/// ABIInfo - Target specific hooks for defining how a type should be
181/// passed or returned from functions.
182class clang::ABIInfo {
183public:
184 virtual ~ABIInfo();
185
186 virtual ABIArgInfo classifyReturnType(QualType RetTy,
187 ASTContext &Context) const = 0;
188
189 virtual ABIArgInfo classifyArgumentType(QualType Ty,
190 ASTContext &Context) const = 0;
191};
192
193ABIInfo::~ABIInfo() {}
194
Daniel Dunbar834af452008-09-17 21:22:33 +0000195/// isEmptyStruct - Return true iff a structure has no non-empty
196/// members. Note that a structure with a flexible array member is not
197/// considered empty.
198static bool isEmptyStruct(QualType T) {
199 const RecordType *RT = T->getAsStructureType();
200 if (!RT)
201 return 0;
202 const RecordDecl *RD = RT->getDecl();
203 if (RD->hasFlexibleArrayMember())
204 return false;
205 for (RecordDecl::field_const_iterator i = RD->field_begin(),
206 e = RD->field_end(); i != e; ++i) {
207 const FieldDecl *FD = *i;
208 if (!isEmptyStruct(FD->getType()))
209 return false;
210 }
211 return true;
212}
213
214/// isSingleElementStruct - Determine if a structure is a "single
215/// element struct", i.e. it has exactly one non-empty field or
216/// exactly one field which is itself a single element
217/// struct. Structures with flexible array members are never
218/// considered single element structs.
219///
220/// \return The field declaration for the single non-empty field, if
221/// it exists.
222static const FieldDecl *isSingleElementStruct(QualType T) {
223 const RecordType *RT = T->getAsStructureType();
224 if (!RT)
225 return 0;
226
227 const RecordDecl *RD = RT->getDecl();
228 if (RD->hasFlexibleArrayMember())
229 return 0;
230
231 const FieldDecl *Found = 0;
232 for (RecordDecl::field_const_iterator i = RD->field_begin(),
233 e = RD->field_end(); i != e; ++i) {
234 const FieldDecl *FD = *i;
235 QualType FT = FD->getType();
236
237 if (isEmptyStruct(FT)) {
238 // Ignore
239 } else if (Found) {
240 return 0;
241 } else if (!CodeGenFunction::hasAggregateLLVMType(FT)) {
242 Found = FD;
243 } else {
244 Found = isSingleElementStruct(FT);
245 if (!Found)
246 return 0;
247 }
248 }
249
250 return Found;
251}
252
253static bool is32Or64BitBasicType(QualType Ty, ASTContext &Context) {
254 if (!Ty->getAsBuiltinType() && !Ty->isPointerType())
255 return false;
256
257 uint64_t Size = Context.getTypeSize(Ty);
258 return Size == 32 || Size == 64;
259}
260
261static bool areAllFields32Or64BitBasicType(const RecordDecl *RD,
262 ASTContext &Context) {
263 for (RecordDecl::field_const_iterator i = RD->field_begin(),
264 e = RD->field_end(); i != e; ++i) {
265 const FieldDecl *FD = *i;
266
267 if (!is32Or64BitBasicType(FD->getType(), Context))
268 return false;
269
270 // If this is a bit-field we need to make sure it is still a
271 // 32-bit or 64-bit type.
272 if (Expr *BW = FD->getBitWidth()) {
273 unsigned Width = BW->getIntegerConstantExprValue(Context).getZExtValue();
274 if (Width <= 16)
275 return false;
276 }
277 }
278 return true;
279}
280
Daniel Dunbar6b1da0e2008-10-13 17:02:26 +0000281namespace {
282/// DefaultABIInfo - The default implementation for ABI specific
283/// details. This implementation provides information which results in
284/// sensible LLVM IR generation, but does not conform to any
285/// particular ABI.
286class DefaultABIInfo : public ABIInfo {
287 virtual ABIArgInfo classifyReturnType(QualType RetTy,
288 ASTContext &Context) const;
289
290 virtual ABIArgInfo classifyArgumentType(QualType RetTy,
291 ASTContext &Context) const;
292};
293
294/// X86_32ABIInfo - The X86-32 ABI information.
295class X86_32ABIInfo : public ABIInfo {
296public:
297 virtual ABIArgInfo classifyReturnType(QualType RetTy,
298 ASTContext &Context) const;
299
300 virtual ABIArgInfo classifyArgumentType(QualType RetTy,
301 ASTContext &Context) const;
302};
303}
304
305ABIArgInfo X86_32ABIInfo::classifyReturnType(QualType RetTy,
306 ASTContext &Context) const {
Daniel Dunbar6660c8a2008-09-11 00:04:36 +0000307 assert(!RetTy->isArrayType() &&
308 "Array types cannot be passed directly.");
Daniel Dunbar2c8e0f32008-09-10 02:41:04 +0000309 if (CodeGenFunction::hasAggregateLLVMType(RetTy)) {
Daniel Dunbar834af452008-09-17 21:22:33 +0000310 // Classify "single element" structs as their element type.
311 const FieldDecl *SeltFD = isSingleElementStruct(RetTy);
312 if (SeltFD) {
313 QualType SeltTy = SeltFD->getType()->getDesugaredType();
314 if (const BuiltinType *BT = SeltTy->getAsBuiltinType()) {
315 // FIXME: This is gross, it would be nice if we could just
316 // pass back SeltTy and have clients deal with it. Is it worth
317 // supporting coerce to both LLVM and clang Types?
318 if (BT->isIntegerType()) {
319 uint64_t Size = Context.getTypeSize(SeltTy);
320 return ABIArgInfo::getCoerce(llvm::IntegerType::get((unsigned) Size));
321 } else if (BT->getKind() == BuiltinType::Float) {
322 return ABIArgInfo::getCoerce(llvm::Type::FloatTy);
323 } else if (BT->getKind() == BuiltinType::Double) {
324 return ABIArgInfo::getCoerce(llvm::Type::DoubleTy);
325 }
326 } else if (SeltTy->isPointerType()) {
327 // FIXME: It would be really nice if this could come out as
328 // the proper pointer type.
329 llvm::Type *PtrTy =
330 llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
331 return ABIArgInfo::getCoerce(PtrTy);
332 }
333 }
334
Daniel Dunbar639ffe42008-09-10 07:04:09 +0000335 uint64_t Size = Context.getTypeSize(RetTy);
336 if (Size == 8) {
337 return ABIArgInfo::getCoerce(llvm::Type::Int8Ty);
338 } else if (Size == 16) {
339 return ABIArgInfo::getCoerce(llvm::Type::Int16Ty);
340 } else if (Size == 32) {
341 return ABIArgInfo::getCoerce(llvm::Type::Int32Ty);
342 } else if (Size == 64) {
343 return ABIArgInfo::getCoerce(llvm::Type::Int64Ty);
344 } else {
345 return ABIArgInfo::getStructRet();
346 }
Daniel Dunbar2c8e0f32008-09-10 02:41:04 +0000347 } else {
348 return ABIArgInfo::getDefault();
349 }
350}
351
Daniel Dunbar6b1da0e2008-10-13 17:02:26 +0000352ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty,
353 ASTContext &Context) const {
Daniel Dunbar8951dbd2008-09-11 01:48:57 +0000354 assert(!Ty->isArrayType() && "Array types cannot be passed directly.");
Daniel Dunbarf0357382008-09-17 20:11:04 +0000355 if (CodeGenFunction::hasAggregateLLVMType(Ty)) {
Daniel Dunbar834af452008-09-17 21:22:33 +0000356 // Structures with flexible arrays are always byval.
357 if (const RecordType *RT = Ty->getAsStructureType())
358 if (RT->getDecl()->hasFlexibleArrayMember())
359 return ABIArgInfo::getByVal(0);
360
361 // Expand empty structs (i.e. ignore)
362 uint64_t Size = Context.getTypeSize(Ty);
363 if (Ty->isStructureType() && Size == 0)
364 return ABIArgInfo::getExpand();
365
366 // Expand structs with size <= 128-bits which consist only of
367 // basic types (int, long long, float, double, xxx*). This is
368 // non-recursive and does not ignore empty fields.
369 if (const RecordType *RT = Ty->getAsStructureType()) {
370 if (Context.getTypeSize(Ty) <= 4*32 &&
371 areAllFields32Or64BitBasicType(RT->getDecl(), Context))
372 return ABIArgInfo::getExpand();
373 }
374
Daniel Dunbar8951dbd2008-09-11 01:48:57 +0000375 return ABIArgInfo::getByVal(0);
376 } else {
377 return ABIArgInfo::getDefault();
378 }
379}
380
Daniel Dunbar6b1da0e2008-10-13 17:02:26 +0000381ABIArgInfo DefaultABIInfo::classifyReturnType(QualType RetTy,
382 ASTContext &Context) const {
383 return ABIArgInfo::getDefault();
384}
385
386ABIArgInfo DefaultABIInfo::classifyArgumentType(QualType Ty,
387 ASTContext &Context) const {
388 assert(!Ty->isArrayType() && "Array types cannot be passed directly.");
389 return ABIArgInfo::getDefault();
390}
391
392const ABIInfo &CodeGenTypes::getABIInfo() const {
393 if (TheABIInfo)
394 return *TheABIInfo;
395
396 // For now we just cache this in the CodeGenTypes and don't bother
397 // to free it.
398 const char *TargetPrefix = getContext().Target.getTargetPrefix();
399 if (strcmp(TargetPrefix, "x86") == 0) {
400 if (getContext().Target.getPointerWidth(0) == 32)
401 return *(TheABIInfo = new X86_32ABIInfo());
402 }
403
404 return *(TheABIInfo = new DefaultABIInfo);
405}
406
407// getABIReturnInfo - Wrap the ABIInfo getABIReturnInfo, altering
408// "default" types to StructRet when appropriate for simplicity.
409static ABIArgInfo getABIReturnInfo(QualType Ty, CodeGenTypes &CGT) {
410 assert(!Ty->isArrayType() &&
411 "Array types cannot be passed directly.");
412 ABIArgInfo Info = CGT.getABIInfo().classifyReturnType(Ty, CGT.getContext());
Daniel Dunbarf0357382008-09-17 20:11:04 +0000413 // Ensure default on aggregate types is StructRet.
414 if (Info.isDefault() && CodeGenFunction::hasAggregateLLVMType(Ty))
415 return ABIArgInfo::getStructRet();
416 return Info;
417}
418
Daniel Dunbar6b1da0e2008-10-13 17:02:26 +0000419// getABIArgumentInfo - Wrap the ABIInfo getABIReturnInfo, altering
420// "default" types to ByVal when appropriate for simplicity.
421static ABIArgInfo getABIArgumentInfo(QualType Ty, CodeGenTypes &CGT) {
422 assert(!Ty->isArrayType() &&
423 "Array types cannot be passed directly.");
424 ABIArgInfo Info = CGT.getABIInfo().classifyArgumentType(Ty, CGT.getContext());
Daniel Dunbarf0357382008-09-17 20:11:04 +0000425 // Ensure default on aggregate types is ByVal.
426 if (Info.isDefault() && CodeGenFunction::hasAggregateLLVMType(Ty))
427 return ABIArgInfo::getByVal(0);
428 return Info;
429}
430
Daniel Dunbar2c8e0f32008-09-10 02:41:04 +0000431/***/
432
Daniel Dunbar56273772008-09-17 00:51:38 +0000433void CodeGenTypes::GetExpandedTypes(QualType Ty,
434 std::vector<const llvm::Type*> &ArgTys) {
435 const RecordType *RT = Ty->getAsStructureType();
436 assert(RT && "Can only expand structure types.");
437 const RecordDecl *RD = RT->getDecl();
438 assert(!RD->hasFlexibleArrayMember() &&
439 "Cannot expand structure with flexible array.");
440
441 for (RecordDecl::field_const_iterator i = RD->field_begin(),
442 e = RD->field_end(); i != e; ++i) {
443 const FieldDecl *FD = *i;
444 assert(!FD->isBitField() &&
445 "Cannot expand structure with bit-field members.");
446
447 QualType FT = FD->getType();
448 if (CodeGenFunction::hasAggregateLLVMType(FT)) {
449 GetExpandedTypes(FT, ArgTys);
450 } else {
451 ArgTys.push_back(ConvertType(FT));
452 }
453 }
454}
455
456llvm::Function::arg_iterator
457CodeGenFunction::ExpandTypeFromArgs(QualType Ty, LValue LV,
458 llvm::Function::arg_iterator AI) {
459 const RecordType *RT = Ty->getAsStructureType();
460 assert(RT && "Can only expand structure types.");
461
462 RecordDecl *RD = RT->getDecl();
463 assert(LV.isSimple() &&
464 "Unexpected non-simple lvalue during struct expansion.");
465 llvm::Value *Addr = LV.getAddress();
466 for (RecordDecl::field_iterator i = RD->field_begin(),
467 e = RD->field_end(); i != e; ++i) {
468 FieldDecl *FD = *i;
469 QualType FT = FD->getType();
470
471 // FIXME: What are the right qualifiers here?
472 LValue LV = EmitLValueForField(Addr, FD, false, 0);
473 if (CodeGenFunction::hasAggregateLLVMType(FT)) {
474 AI = ExpandTypeFromArgs(FT, LV, AI);
475 } else {
476 EmitStoreThroughLValue(RValue::get(AI), LV, FT);
477 ++AI;
478 }
479 }
480
481 return AI;
482}
483
484void
485CodeGenFunction::ExpandTypeToArgs(QualType Ty, RValue RV,
486 llvm::SmallVector<llvm::Value*, 16> &Args) {
487 const RecordType *RT = Ty->getAsStructureType();
488 assert(RT && "Can only expand structure types.");
489
490 RecordDecl *RD = RT->getDecl();
491 assert(RV.isAggregate() && "Unexpected rvalue during struct expansion");
492 llvm::Value *Addr = RV.getAggregateAddr();
493 for (RecordDecl::field_iterator i = RD->field_begin(),
494 e = RD->field_end(); i != e; ++i) {
495 FieldDecl *FD = *i;
496 QualType FT = FD->getType();
497
498 // FIXME: What are the right qualifiers here?
499 LValue LV = EmitLValueForField(Addr, FD, false, 0);
500 if (CodeGenFunction::hasAggregateLLVMType(FT)) {
501 ExpandTypeToArgs(FT, RValue::getAggregate(LV.getAddress()), Args);
502 } else {
503 RValue RV = EmitLoadOfLValue(LV, FT);
504 assert(RV.isScalar() &&
505 "Unexpected non-scalar rvalue during struct expansion.");
506 Args.push_back(RV.getScalarVal());
507 }
508 }
509}
510
511/***/
512
Daniel Dunbar45c25ba2008-09-10 04:01:49 +0000513const llvm::FunctionType *
Daniel Dunbar62d5c1b2008-09-10 07:00:50 +0000514CodeGenTypes::GetFunctionType(const CGCallInfo &CI, bool IsVariadic) {
515 return GetFunctionType(CI.argtypes_begin(), CI.argtypes_end(), IsVariadic);
516}
517
518const llvm::FunctionType *
Daniel Dunbar45c25ba2008-09-10 04:01:49 +0000519CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI) {
Daniel Dunbar62d5c1b2008-09-10 07:00:50 +0000520 return GetFunctionType(FI.argtypes_begin(), FI.argtypes_end(), FI.isVariadic());
521}
522
523const llvm::FunctionType *
524CodeGenTypes::GetFunctionType(ArgTypeIterator begin, ArgTypeIterator end,
525 bool IsVariadic) {
Daniel Dunbar45c25ba2008-09-10 04:01:49 +0000526 std::vector<const llvm::Type*> ArgTys;
527
528 const llvm::Type *ResultType = 0;
529
Daniel Dunbar45c25ba2008-09-10 04:01:49 +0000530 QualType RetTy = *begin;
Daniel Dunbar6b1da0e2008-10-13 17:02:26 +0000531 ABIArgInfo RetAI = getABIReturnInfo(RetTy, *this);
Daniel Dunbar8951dbd2008-09-11 01:48:57 +0000532 switch (RetAI.getKind()) {
533 case ABIArgInfo::ByVal:
534 case ABIArgInfo::Expand:
535 assert(0 && "Invalid ABI kind for return argument");
536
Daniel Dunbar45c25ba2008-09-10 04:01:49 +0000537 case ABIArgInfo::Default:
538 if (RetTy->isVoidType()) {
539 ResultType = llvm::Type::VoidTy;
540 } else {
Daniel Dunbar62d5c1b2008-09-10 07:00:50 +0000541 ResultType = ConvertType(RetTy);
Daniel Dunbar45c25ba2008-09-10 04:01:49 +0000542 }
543 break;
544
545 case ABIArgInfo::StructRet: {
546 ResultType = llvm::Type::VoidTy;
Daniel Dunbar62d5c1b2008-09-10 07:00:50 +0000547 const llvm::Type *STy = ConvertType(RetTy);
Daniel Dunbar45c25ba2008-09-10 04:01:49 +0000548 ArgTys.push_back(llvm::PointerType::get(STy, RetTy.getAddressSpace()));
549 break;
550 }
551
552 case ABIArgInfo::Coerce:
Daniel Dunbar639ffe42008-09-10 07:04:09 +0000553 ResultType = RetAI.getCoerceToType();
Daniel Dunbar45c25ba2008-09-10 04:01:49 +0000554 break;
555 }
556
557 for (++begin; begin != end; ++begin) {
Daniel Dunbar6b1da0e2008-10-13 17:02:26 +0000558 ABIArgInfo AI = getABIArgumentInfo(*begin, *this);
Daniel Dunbar62d5c1b2008-09-10 07:00:50 +0000559 const llvm::Type *Ty = ConvertType(*begin);
Daniel Dunbar8951dbd2008-09-11 01:48:57 +0000560
561 switch (AI.getKind()) {
Daniel Dunbar56273772008-09-17 00:51:38 +0000562 case ABIArgInfo::Coerce:
Daniel Dunbar8951dbd2008-09-11 01:48:57 +0000563 case ABIArgInfo::StructRet:
564 assert(0 && "Invalid ABI kind for non-return argument");
565
566 case ABIArgInfo::ByVal:
Daniel Dunbar45c25ba2008-09-10 04:01:49 +0000567 // byval arguments are always on the stack, which is addr space #0.
568 ArgTys.push_back(llvm::PointerType::getUnqual(Ty));
Daniel Dunbar8951dbd2008-09-11 01:48:57 +0000569 assert(AI.getByValAlignment() == 0 && "FIXME: alignment unhandled");
570 break;
571
572 case ABIArgInfo::Default:
573 ArgTys.push_back(Ty);
574 break;
Daniel Dunbar8951dbd2008-09-11 01:48:57 +0000575
576 case ABIArgInfo::Expand:
Daniel Dunbar56273772008-09-17 00:51:38 +0000577 GetExpandedTypes(*begin, ArgTys);
Daniel Dunbar8951dbd2008-09-11 01:48:57 +0000578 break;
579 }
Daniel Dunbar45c25ba2008-09-10 04:01:49 +0000580 }
581
Daniel Dunbar62d5c1b2008-09-10 07:00:50 +0000582 return llvm::FunctionType::get(ResultType, ArgTys, IsVariadic);
Daniel Dunbar45c25ba2008-09-10 04:01:49 +0000583}
584
Daniel Dunbarb7688072008-09-10 00:41:16 +0000585bool CodeGenModule::ReturnTypeUsesSret(QualType RetTy) {
Daniel Dunbar6b1da0e2008-10-13 17:02:26 +0000586 return getABIReturnInfo(RetTy, getTypes()).isStructRet();
Daniel Dunbar3913f182008-09-09 23:48:28 +0000587}
588
Devang Patel761d7f72008-09-25 21:02:23 +0000589void CodeGenModule::ConstructAttributeList(const Decl *TargetDecl,
Daniel Dunbar2c8e0f32008-09-10 02:41:04 +0000590 ArgTypeIterator begin,
591 ArgTypeIterator end,
Devang Patel761d7f72008-09-25 21:02:23 +0000592 AttributeListType &PAL) {
Daniel Dunbar5323a4b2008-09-10 00:32:18 +0000593 unsigned FuncAttrs = 0;
Devang Patela2c69122008-09-26 22:53:57 +0000594 unsigned RetAttrs = 0;
Daniel Dunbar5323a4b2008-09-10 00:32:18 +0000595
596 if (TargetDecl) {
597 if (TargetDecl->getAttr<NoThrowAttr>())
Devang Patel761d7f72008-09-25 21:02:23 +0000598 FuncAttrs |= llvm::Attribute::NoUnwind;
Daniel Dunbar5323a4b2008-09-10 00:32:18 +0000599 if (TargetDecl->getAttr<NoReturnAttr>())
Devang Patel761d7f72008-09-25 21:02:23 +0000600 FuncAttrs |= llvm::Attribute::NoReturn;
Anders Carlsson232eb7d2008-10-05 23:32:53 +0000601 if (TargetDecl->getAttr<PureAttr>())
602 FuncAttrs |= llvm::Attribute::ReadOnly;
603 if (TargetDecl->getAttr<ConstAttr>())
604 FuncAttrs |= llvm::Attribute::ReadNone;
Daniel Dunbar5323a4b2008-09-10 00:32:18 +0000605 }
606
Daniel Dunbar2c8e0f32008-09-10 02:41:04 +0000607 QualType RetTy = *begin;
Daniel Dunbar5323a4b2008-09-10 00:32:18 +0000608 unsigned Index = 1;
Daniel Dunbar6b1da0e2008-10-13 17:02:26 +0000609 ABIArgInfo RetAI = getABIReturnInfo(RetTy, getTypes());
Daniel Dunbar45c25ba2008-09-10 04:01:49 +0000610 switch (RetAI.getKind()) {
Daniel Dunbar2c8e0f32008-09-10 02:41:04 +0000611 case ABIArgInfo::Default:
612 if (RetTy->isPromotableIntegerType()) {
613 if (RetTy->isSignedIntegerType()) {
Devang Patela2c69122008-09-26 22:53:57 +0000614 RetAttrs |= llvm::Attribute::SExt;
Daniel Dunbar2c8e0f32008-09-10 02:41:04 +0000615 } else if (RetTy->isUnsignedIntegerType()) {
Devang Patela2c69122008-09-26 22:53:57 +0000616 RetAttrs |= llvm::Attribute::ZExt;
Daniel Dunbar2c8e0f32008-09-10 02:41:04 +0000617 }
618 }
619 break;
620
621 case ABIArgInfo::StructRet:
Devang Patel761d7f72008-09-25 21:02:23 +0000622 PAL.push_back(llvm::AttributeWithIndex::get(Index,
623 llvm::Attribute::StructRet|
624 llvm::Attribute::NoAlias));
Daniel Dunbar5323a4b2008-09-10 00:32:18 +0000625 ++Index;
Daniel Dunbar2c8e0f32008-09-10 02:41:04 +0000626 break;
627
628 case ABIArgInfo::Coerce:
Daniel Dunbar2c8e0f32008-09-10 02:41:04 +0000629 break;
Daniel Dunbar8951dbd2008-09-11 01:48:57 +0000630
631 case ABIArgInfo::ByVal:
632 case ABIArgInfo::Expand:
633 assert(0 && "Invalid ABI kind for return argument");
Daniel Dunbar5323a4b2008-09-10 00:32:18 +0000634 }
Daniel Dunbar2c8e0f32008-09-10 02:41:04 +0000635
Devang Patela2c69122008-09-26 22:53:57 +0000636 if (RetAttrs)
637 PAL.push_back(llvm::AttributeWithIndex::get(0, RetAttrs));
Daniel Dunbar56273772008-09-17 00:51:38 +0000638 for (++begin; begin != end; ++begin) {
Daniel Dunbar5323a4b2008-09-10 00:32:18 +0000639 QualType ParamType = *begin;
Devang Patel761d7f72008-09-25 21:02:23 +0000640 unsigned Attributes = 0;
Daniel Dunbar6b1da0e2008-10-13 17:02:26 +0000641 ABIArgInfo AI = getABIArgumentInfo(ParamType, getTypes());
Daniel Dunbar8951dbd2008-09-11 01:48:57 +0000642
643 switch (AI.getKind()) {
644 case ABIArgInfo::StructRet:
Daniel Dunbar56273772008-09-17 00:51:38 +0000645 case ABIArgInfo::Coerce:
Daniel Dunbar8951dbd2008-09-11 01:48:57 +0000646 assert(0 && "Invalid ABI kind for non-return argument");
647
648 case ABIArgInfo::ByVal:
Devang Patel761d7f72008-09-25 21:02:23 +0000649 Attributes |= llvm::Attribute::ByVal;
Daniel Dunbar8951dbd2008-09-11 01:48:57 +0000650 assert(AI.getByValAlignment() == 0 && "FIXME: alignment unhandled");
651 break;
652
653 case ABIArgInfo::Default:
654 if (ParamType->isPromotableIntegerType()) {
655 if (ParamType->isSignedIntegerType()) {
Devang Patel761d7f72008-09-25 21:02:23 +0000656 Attributes |= llvm::Attribute::SExt;
Daniel Dunbar8951dbd2008-09-11 01:48:57 +0000657 } else if (ParamType->isUnsignedIntegerType()) {
Devang Patel761d7f72008-09-25 21:02:23 +0000658 Attributes |= llvm::Attribute::ZExt;
Daniel Dunbar8951dbd2008-09-11 01:48:57 +0000659 }
Daniel Dunbar5323a4b2008-09-10 00:32:18 +0000660 }
Daniel Dunbar8951dbd2008-09-11 01:48:57 +0000661 break;
Daniel Dunbar8951dbd2008-09-11 01:48:57 +0000662
Daniel Dunbar56273772008-09-17 00:51:38 +0000663 case ABIArgInfo::Expand: {
664 std::vector<const llvm::Type*> Tys;
665 // FIXME: This is rather inefficient. Do we ever actually need
666 // to do anything here? The result should be just reconstructed
667 // on the other side, so extension should be a non-issue.
668 getTypes().GetExpandedTypes(ParamType, Tys);
669 Index += Tys.size();
670 continue;
671 }
Daniel Dunbar5323a4b2008-09-10 00:32:18 +0000672 }
Daniel Dunbar8951dbd2008-09-11 01:48:57 +0000673
Devang Patel761d7f72008-09-25 21:02:23 +0000674 if (Attributes)
675 PAL.push_back(llvm::AttributeWithIndex::get(Index, Attributes));
Daniel Dunbar56273772008-09-17 00:51:38 +0000676 ++Index;
Daniel Dunbar5323a4b2008-09-10 00:32:18 +0000677 }
Devang Patela2c69122008-09-26 22:53:57 +0000678 if (FuncAttrs)
679 PAL.push_back(llvm::AttributeWithIndex::get(~0, FuncAttrs));
680
Daniel Dunbar5323a4b2008-09-10 00:32:18 +0000681}
682
Daniel Dunbar17b708d2008-09-09 23:27:19 +0000683void CodeGenFunction::EmitFunctionProlog(llvm::Function *Fn,
684 QualType RetTy,
685 const FunctionArgList &Args) {
686 // Emit allocs for param decls. Give the LLVM Argument nodes names.
687 llvm::Function::arg_iterator AI = Fn->arg_begin();
688
689 // Name the struct return argument.
Daniel Dunbar2c8e0f32008-09-10 02:41:04 +0000690 if (CGM.ReturnTypeUsesSret(RetTy)) {
Daniel Dunbar17b708d2008-09-09 23:27:19 +0000691 AI->setName("agg.result");
692 ++AI;
693 }
694
695 for (FunctionArgList::const_iterator i = Args.begin(), e = Args.end();
Daniel Dunbar56273772008-09-17 00:51:38 +0000696 i != e; ++i) {
Daniel Dunbar17b708d2008-09-09 23:27:19 +0000697 const VarDecl *Arg = i->first;
Daniel Dunbar56273772008-09-17 00:51:38 +0000698 QualType Ty = i->second;
Daniel Dunbar6b1da0e2008-10-13 17:02:26 +0000699 ABIArgInfo ArgI = getABIArgumentInfo(Ty, CGM.getTypes());
Daniel Dunbar8951dbd2008-09-11 01:48:57 +0000700
701 switch (ArgI.getKind()) {
702 case ABIArgInfo::ByVal:
703 case ABIArgInfo::Default: {
704 assert(AI != Fn->arg_end() && "Argument mismatch!");
705 llvm::Value* V = AI;
Daniel Dunbar56273772008-09-17 00:51:38 +0000706 if (!getContext().typesAreCompatible(Ty, Arg->getType())) {
Daniel Dunbar8951dbd2008-09-11 01:48:57 +0000707 // This must be a promotion, for something like
708 // "void a(x) short x; {..."
Daniel Dunbar56273772008-09-17 00:51:38 +0000709 V = EmitScalarConversion(V, Ty, Arg->getType());
Daniel Dunbar17b708d2008-09-09 23:27:19 +0000710 }
Daniel Dunbar8951dbd2008-09-11 01:48:57 +0000711 EmitParmDecl(*Arg, V);
712 break;
713 }
Daniel Dunbar56273772008-09-17 00:51:38 +0000714
715 case ABIArgInfo::Expand: {
716 // If this was structure was expand into multiple arguments then
717 // we need to create a temporary and reconstruct it from the
718 // arguments.
719 std::string Name(Arg->getName());
720 llvm::Value *Temp = CreateTempAlloca(ConvertType(Ty),
721 (Name + ".addr").c_str());
722 // FIXME: What are the right qualifiers here?
723 llvm::Function::arg_iterator End =
724 ExpandTypeFromArgs(Ty, LValue::MakeAddr(Temp,0), AI);
725 EmitParmDecl(*Arg, Temp);
Daniel Dunbar8951dbd2008-09-11 01:48:57 +0000726
Daniel Dunbar56273772008-09-17 00:51:38 +0000727 // Name the arguments used in expansion and increment AI.
728 unsigned Index = 0;
729 for (; AI != End; ++AI, ++Index)
730 AI->setName(Name + "." + llvm::utostr(Index));
731 continue;
732 }
733
Daniel Dunbar8951dbd2008-09-11 01:48:57 +0000734 case ABIArgInfo::Coerce:
Daniel Dunbar8951dbd2008-09-11 01:48:57 +0000735 case ABIArgInfo::StructRet:
736 assert(0 && "Invalid ABI kind for non-return argument");
737 }
Daniel Dunbar56273772008-09-17 00:51:38 +0000738
739 ++AI;
Daniel Dunbar17b708d2008-09-09 23:27:19 +0000740 }
741 assert(AI == Fn->arg_end() && "Argument mismatch!");
742}
743
744void CodeGenFunction::EmitFunctionEpilog(QualType RetTy,
745 llvm::Value *ReturnValue) {
Daniel Dunbar2c8e0f32008-09-10 02:41:04 +0000746 llvm::Value *RV = 0;
747
748 // Functions with no result always return void.
749 if (ReturnValue) {
Daniel Dunbar6b1da0e2008-10-13 17:02:26 +0000750 ABIArgInfo RetAI = getABIReturnInfo(RetTy, CGM.getTypes());
Daniel Dunbar2c8e0f32008-09-10 02:41:04 +0000751
752 switch (RetAI.getKind()) {
753 case ABIArgInfo::StructRet:
Daniel Dunbar17b708d2008-09-09 23:27:19 +0000754 EmitAggregateCopy(CurFn->arg_begin(), ReturnValue, RetTy);
Daniel Dunbar2c8e0f32008-09-10 02:41:04 +0000755 break;
Daniel Dunbar8951dbd2008-09-11 01:48:57 +0000756
Daniel Dunbar2c8e0f32008-09-10 02:41:04 +0000757 case ABIArgInfo::Default:
758 RV = Builder.CreateLoad(ReturnValue);
759 break;
760
Daniel Dunbar639ffe42008-09-10 07:04:09 +0000761 case ABIArgInfo::Coerce: {
762 const llvm::Type *CoerceToPTy =
763 llvm::PointerType::getUnqual(RetAI.getCoerceToType());
764 RV = Builder.CreateLoad(Builder.CreateBitCast(ReturnValue, CoerceToPTy));
Daniel Dunbar8951dbd2008-09-11 01:48:57 +0000765 break;
Daniel Dunbar639ffe42008-09-10 07:04:09 +0000766 }
Daniel Dunbar8951dbd2008-09-11 01:48:57 +0000767
768 case ABIArgInfo::ByVal:
769 case ABIArgInfo::Expand:
770 assert(0 && "Invalid ABI kind for return argument");
Daniel Dunbar17b708d2008-09-09 23:27:19 +0000771 }
772 }
Daniel Dunbar2c8e0f32008-09-10 02:41:04 +0000773
774 if (RV) {
775 Builder.CreateRet(RV);
776 } else {
777 Builder.CreateRetVoid();
778 }
Daniel Dunbar17b708d2008-09-09 23:27:19 +0000779}
780
781RValue CodeGenFunction::EmitCall(llvm::Value *Callee,
Daniel Dunbar2c8e0f32008-09-10 02:41:04 +0000782 QualType RetTy,
Daniel Dunbar17b708d2008-09-09 23:27:19 +0000783 const CallArgList &CallArgs) {
Daniel Dunbar17b708d2008-09-09 23:27:19 +0000784 llvm::SmallVector<llvm::Value*, 16> Args;
Daniel Dunbar17b708d2008-09-09 23:27:19 +0000785
786 // Handle struct-return functions by passing a pointer to the
787 // location that we would like to return into.
Daniel Dunbar6b1da0e2008-10-13 17:02:26 +0000788 ABIArgInfo RetAI = getABIReturnInfo(RetTy, CGM.getTypes());
Daniel Dunbar2c8e0f32008-09-10 02:41:04 +0000789 switch (RetAI.getKind()) {
790 case ABIArgInfo::StructRet:
Daniel Dunbar17b708d2008-09-09 23:27:19 +0000791 // Create a temporary alloca to hold the result of the call. :(
Daniel Dunbar56273772008-09-17 00:51:38 +0000792 Args.push_back(CreateTempAlloca(ConvertType(RetTy)));
Daniel Dunbar2c8e0f32008-09-10 02:41:04 +0000793 break;
794
795 case ABIArgInfo::Default:
Daniel Dunbar2c8e0f32008-09-10 02:41:04 +0000796 case ABIArgInfo::Coerce:
Daniel Dunbar2c8e0f32008-09-10 02:41:04 +0000797 break;
Daniel Dunbar8951dbd2008-09-11 01:48:57 +0000798
799 case ABIArgInfo::ByVal:
800 case ABIArgInfo::Expand:
801 assert(0 && "Invalid ABI kind for return argument");
Daniel Dunbar17b708d2008-09-09 23:27:19 +0000802 }
803
804 for (CallArgList::const_iterator I = CallArgs.begin(), E = CallArgs.end();
805 I != E; ++I) {
Daniel Dunbar6b1da0e2008-10-13 17:02:26 +0000806 ABIArgInfo ArgInfo = getABIArgumentInfo(I->second, CGM.getTypes());
Daniel Dunbar17b708d2008-09-09 23:27:19 +0000807 RValue RV = I->first;
Daniel Dunbar56273772008-09-17 00:51:38 +0000808
809 switch (ArgInfo.getKind()) {
810 case ABIArgInfo::ByVal: // Default is byval
811 case ABIArgInfo::Default:
812 if (RV.isScalar()) {
813 Args.push_back(RV.getScalarVal());
814 } else if (RV.isComplex()) {
815 // Make a temporary alloca to pass the argument.
816 Args.push_back(CreateTempAlloca(ConvertType(I->second)));
817 StoreComplexToAddr(RV.getComplexVal(), Args.back(), false);
818 } else {
819 Args.push_back(RV.getAggregateAddr());
820 }
821 break;
822
823 case ABIArgInfo::StructRet:
824 case ABIArgInfo::Coerce:
825 assert(0 && "Invalid ABI kind for non-return argument");
826 break;
827
828 case ABIArgInfo::Expand:
829 ExpandTypeToArgs(I->second, RV, Args);
830 break;
Daniel Dunbar17b708d2008-09-09 23:27:19 +0000831 }
832 }
833
834 llvm::CallInst *CI = Builder.CreateCall(Callee,&Args[0],&Args[0]+Args.size());
Daniel Dunbar2c8e0f32008-09-10 02:41:04 +0000835 CGCallInfo CallInfo(RetTy, CallArgs);
Daniel Dunbar17b708d2008-09-09 23:27:19 +0000836
Daniel Dunbar5323a4b2008-09-10 00:32:18 +0000837 // FIXME: Provide TargetDecl so nounwind, noreturn, etc, etc get set.
Devang Patel761d7f72008-09-25 21:02:23 +0000838 CodeGen::AttributeListType AttributeList;
839 CGM.ConstructAttributeList(0,
Daniel Dunbarb7688072008-09-10 00:41:16 +0000840 CallInfo.argtypes_begin(), CallInfo.argtypes_end(),
Devang Patel761d7f72008-09-25 21:02:23 +0000841 AttributeList);
842 CI->setAttributes(llvm::AttrListPtr::get(AttributeList.begin(),
843 AttributeList.size()));
Daniel Dunbar17b708d2008-09-09 23:27:19 +0000844
845 if (const llvm::Function *F = dyn_cast<llvm::Function>(Callee))
846 CI->setCallingConv(F->getCallingConv());
847 if (CI->getType() != llvm::Type::VoidTy)
848 CI->setName("call");
Daniel Dunbar2c8e0f32008-09-10 02:41:04 +0000849
850 switch (RetAI.getKind()) {
851 case ABIArgInfo::StructRet:
852 if (RetTy->isAnyComplexType())
Daniel Dunbar56273772008-09-17 00:51:38 +0000853 return RValue::getComplex(LoadComplexFromAddr(Args[0], false));
Daniel Dunbar2c8e0f32008-09-10 02:41:04 +0000854 else
855 // Struct return.
Daniel Dunbar56273772008-09-17 00:51:38 +0000856 return RValue::getAggregate(Args[0]);
Daniel Dunbar8951dbd2008-09-11 01:48:57 +0000857
Daniel Dunbar2c8e0f32008-09-10 02:41:04 +0000858 case ABIArgInfo::Default:
859 return RValue::get(RetTy->isVoidType() ? 0 : CI);
860
Daniel Dunbar639ffe42008-09-10 07:04:09 +0000861 case ABIArgInfo::Coerce: {
862 const llvm::Type *CoerceToPTy =
863 llvm::PointerType::getUnqual(RetAI.getCoerceToType());
864 llvm::Value *V = CreateTempAlloca(ConvertType(RetTy), "tmp");
865 Builder.CreateStore(CI, Builder.CreateBitCast(V, CoerceToPTy));
866 return RValue::getAggregate(V);
867 }
Daniel Dunbar8951dbd2008-09-11 01:48:57 +0000868
869 case ABIArgInfo::ByVal:
870 case ABIArgInfo::Expand:
871 assert(0 && "Invalid ABI kind for return argument");
Daniel Dunbar17b708d2008-09-09 23:27:19 +0000872 }
Daniel Dunbar2c8e0f32008-09-10 02:41:04 +0000873
874 assert(0 && "Unhandled ABIArgInfo::Kind");
875 return RValue::get(0);
Daniel Dunbar17b708d2008-09-09 23:27:19 +0000876}