void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI, const Decl *TargetDecl, AttributeListType &PAL, unsigned &CallingConv) { unsigned FuncAttrs = 0; unsigned RetAttrs = 0; CallingConv = FI.getEffectiveCallingConvention(); // FIXME: handle sseregparm someday... if (TargetDecl) { if (TargetDecl->hasAttr<NoThrowAttr>()) FuncAttrs |= llvm::Attribute::NoUnwind; if (TargetDecl->hasAttr<NoReturnAttr>()) FuncAttrs |= llvm::Attribute::NoReturn; if (TargetDecl->hasAttr<ConstAttr>()) FuncAttrs |= llvm::Attribute::ReadNone; else if (TargetDecl->hasAttr<PureAttr>()) FuncAttrs |= llvm::Attribute::ReadOnly; if (TargetDecl->hasAttr<MallocAttr>()) RetAttrs |= llvm::Attribute::NoAlias; } if (CodeGenOpts.OptimizeSize) FuncAttrs |= llvm::Attribute::OptimizeForSize; if (CodeGenOpts.DisableRedZone) FuncAttrs |= llvm::Attribute::NoRedZone; if (CodeGenOpts.NoImplicitFloat) FuncAttrs |= llvm::Attribute::NoImplicitFloat; QualType RetTy = FI.getReturnType(); unsigned Index = 1; const ABIArgInfo &RetAI = FI.getReturnInfo(); switch (RetAI.getKind()) { case ABIArgInfo::Extend: if (RetTy->isSignedIntegerType()) { RetAttrs |= llvm::Attribute::SExt; } else if (RetTy->isUnsignedIntegerType()) { RetAttrs |= llvm::Attribute::ZExt; } // FALLTHROUGH case ABIArgInfo::Direct: break; case ABIArgInfo::Indirect: PAL.push_back(llvm::AttributeWithIndex::get(Index, llvm::Attribute::StructRet | llvm::Attribute::NoAlias)); ++Index; // sret disables readnone and readonly FuncAttrs &= ~(llvm::Attribute::ReadOnly | llvm::Attribute::ReadNone); break; case ABIArgInfo::Ignore: case ABIArgInfo::Coerce: break; case ABIArgInfo::Expand: assert(0 && "Invalid ABI kind for return argument"); } if (RetAttrs) PAL.push_back(llvm::AttributeWithIndex::get(0, RetAttrs)); // FIXME: we need to honour command line settings also... // FIXME: RegParm should be reduced in case of nested functions and/or global // register variable. signed RegParm = 0; if (TargetDecl) if (const RegparmAttr *RegParmAttr = TargetDecl->getAttr<RegparmAttr>()) RegParm = RegParmAttr->getNumParams(); unsigned PointerWidth = getContext().Target.getPointerWidth(0); for (CGFunctionInfo::const_arg_iterator it = FI.arg_begin(), ie = FI.arg_end(); it != ie; ++it) { QualType ParamType = it->type; const ABIArgInfo &AI = it->info; unsigned Attributes = 0; switch (AI.getKind()) { case ABIArgInfo::Coerce: break; case ABIArgInfo::Indirect: if (AI.getIndirectByVal()) Attributes |= llvm::Attribute::ByVal; Attributes |= llvm::Attribute::constructAlignmentFromInt(AI.getIndirectAlign()); // byval disables readnone and readonly. FuncAttrs &= ~(llvm::Attribute::ReadOnly | llvm::Attribute::ReadNone); break; case ABIArgInfo::Extend: if (ParamType->isSignedIntegerType()) { Attributes |= llvm::Attribute::SExt; } else if (ParamType->isUnsignedIntegerType()) { Attributes |= llvm::Attribute::ZExt; } // FALLS THROUGH case ABIArgInfo::Direct: if (RegParm > 0 && (ParamType->isIntegerType() || ParamType->isPointerType())) { RegParm -= (Context.getTypeSize(ParamType) + PointerWidth - 1) / PointerWidth; if (RegParm >= 0) Attributes |= llvm::Attribute::InReg; } // FIXME: handle sseregparm someday... break; case ABIArgInfo::Ignore: // Skip increment, no matching LLVM parameter. continue; case ABIArgInfo::Expand: { std::vector<const llvm::Type*> Tys; // FIXME: This is rather inefficient. Do we ever actually need to do // anything here? The result should be just reconstructed on the other // side, so extension should be a non-issue. getTypes().GetExpandedTypes(ParamType, Tys); Index += Tys.size(); continue; } } if (Attributes) PAL.push_back(llvm::AttributeWithIndex::get(Index, Attributes)); ++Index; } if (FuncAttrs) PAL.push_back(llvm::AttributeWithIndex::get(~0, FuncAttrs)); }