All, Attached is my patch for llvm-gcc-4.0. This rearranges the attribute processing a bit and centralizes the K&R stuff in the FunctionTypeConverter. The methods to convert a function type now take an extra ParamAttrsList parameter that is generated for use with Functions and call sites. This goes in conjunction with the previous patch to llvm for PR1146 (sent a few days ago).
This is passing tests so I thought I'd send it out for review. I'll commit this later today if it passes muster. Reid.
Index: gcc/llvm-backend.cpp =================================================================== --- gcc/llvm-backend.cpp (revision 40580) +++ gcc/llvm-backend.cpp (working copy) @@ -987,10 +987,12 @@ Function *FnEntry = TheModule->getFunction(Name); if (FnEntry == 0) { unsigned CC; + const ParamAttrsList *PAL = 0; const FunctionType *Ty = - TheTypeConverter->ConvertFunctionType(TREE_TYPE(decl), NULL, CC); + TheTypeConverter->ConvertFunctionType(TREE_TYPE(decl), NULL, CC, PAL); FnEntry = new Function(Ty, Function::ExternalLinkage, Name, TheModule); FnEntry->setCallingConv(CC); + FnEntry->setParamAttrs(PAL); // Check for external weak linkage if (DECL_EXTERNAL(decl) && DECL_WEAK(decl)) Index: gcc/llvm-convert.cpp =================================================================== --- gcc/llvm-convert.cpp (revision 40580) +++ gcc/llvm-convert.cpp (working copy) @@ -503,11 +503,12 @@ // allows C functions declared as "T foo() {}" to be treated like // "T foo(void) {}" and allows us to handle functions with K&R-style // definitions correctly. + const ParamAttrsList *PAL = 0; if (TYPE_ARG_TYPES(TREE_TYPE(FnDecl)) == 0) { FTy = TheTypeConverter->ConvertArgListToFnType(TREE_TYPE(TREE_TYPE(FnDecl)), DECL_ARGUMENTS(FnDecl), static_chain, - CallingConv); + CallingConv, PAL); #ifdef TARGET_ADJUST_LLVM_CC TARGET_ADJUST_LLVM_CC(CallingConv, TREE_TYPE(FnDecl)); #endif @@ -515,7 +516,7 @@ // Otherwise, just get the type from the function itself. FTy = TheTypeConverter->ConvertFunctionType(TREE_TYPE(FnDecl), static_chain, - CallingConv); + CallingConv, PAL); } // If we've already seen this function and created a prototype, and if the @@ -525,6 +526,7 @@ Fn = cast<Function>(DECL_LLVM(FnDecl)); assert(Fn->getCallingConv() == CallingConv && "Calling convention disagreement between prototype and impl!"); + // The visibility can be changed from the last time we've seen this // function. Set to current. if (TREE_PUBLIC(FnDecl)) { @@ -566,6 +568,9 @@ // The function should not already have a body. assert(Fn->empty() && "Function expanded multiple times!"); + // Assign the parameter attributes that the function should use. + Fn->setParamAttrs(PAL); + // Compute the linkage that the function should get. if (!TREE_PUBLIC(FnDecl) /*|| lang_hooks.llvm_is_in_anon(subr)*/) { Fn->setLinkage(Function::InternalLinkage); @@ -2535,6 +2540,7 @@ return Res; } + const ParamAttrsList *PAL = 0; Value *Callee = Emit(TREE_OPERAND(exp, 0), 0); if (TREE_OPERAND(exp, 2)) { @@ -2547,12 +2553,12 @@ unsigned CallingConv; const Type *Ty = TheTypeConverter->ConvertFunctionType(function_type, static_chain, - CallingConv); + CallingConv, PAL); Callee = CastToType(Instruction::BitCast, Callee, PointerType::get(Ty)); } //EmitCall(exp, DestLoc); - Value *Result = EmitCallOf(Callee, exp, DestLoc); + Value *Result = EmitCallOf(Callee, exp, DestLoc, PAL); // If the function has the volatile bit set, then it is a "noreturn" function. // Output an unreachable instruction right after the function to prevent LLVM @@ -2611,7 +2617,7 @@ /// HandleScalarResult - This callback is invoked if the function returns a /// simple scalar result value. - void HandleScalarResult(const Type *RetTy) { + void HandleScalarResult(const Type *RetTy, tree treeTy) { // There is nothing to do here if we return a scalar or void. assert(DestLoc == 0 && "Call returns a scalar but caller expects aggregate!"); @@ -2678,7 +2684,8 @@ /// EmitCallOf - Emit a call to the specified callee with the operands specified /// in the CALL_EXP 'exp'. If the result of the call is a scalar, return the /// result, otherwise store it in DestLoc. -Value *TreeToLLVM::EmitCallOf(Value *Callee, tree exp, Value *DestLoc) { +Value *TreeToLLVM::EmitCallOf(Value *Callee, tree exp, Value *DestLoc, + const ParamAttrsList *PAL) { // Determine if we need to generate an invoke instruction (instead of a simple // call) and if so, what the exception destination will be. BasicBlock *UnwindBlock = 0; @@ -2764,13 +2771,19 @@ Value *Call; if (!UnwindBlock) { - Call = Builder.CreateCall(Callee, &CallOperands[0], CallOperands.size()); - cast<CallInst>(Call)->setCallingConv(CallingConvention); + CallInst *CI = + Builder.CreateCall(Callee, &CallOperands[0], CallOperands.size()); + CI->setCallingConv(CallingConvention); + CI->setParamAttrs(PAL); + Call = CI; } else { BasicBlock *NextBlock = new BasicBlock("invcont"); - Call = Builder.CreateInvoke(Callee, NextBlock, UnwindBlock, - &CallOperands[0], CallOperands.size()); - cast<InvokeInst>(Call)->setCallingConv(CallingConvention); + InvokeInst *II = + Builder.CreateInvoke(Callee, NextBlock, UnwindBlock, &CallOperands[0], + CallOperands.size()); + II->setCallingConv(CallingConvention); + II->setParamAttrs(PAL); + Call = II; // Lazily create an unwind block for this scope, which we can emit a fixup // branch in. @@ -2786,7 +2799,7 @@ EmitBranchInternal(UnwindBlock, true); } - cast<InvokeInst>(Call)->setUnwindDest(CurrentEHScopes.back().UnwindBlock); + II->setUnwindDest(CurrentEHScopes.back().UnwindBlock); EmitBlock(NextBlock); } @@ -4183,7 +4196,7 @@ Intrinsic::getDeclaration(TheModule, IntrinsicID); } - Result = EmitCallOf(TargetBuiltinCache[FnCode], exp, DestLoc); + Result = EmitCallOf(TargetBuiltinCache[FnCode], exp, DestLoc, /*PAL=*/0); return true; } Index: gcc/llvm-internal.h =================================================================== --- gcc/llvm-internal.h (revision 40580) +++ gcc/llvm-internal.h (working copy) @@ -140,7 +140,8 @@ /// it also returns the function's LLVM calling convention. const FunctionType *ConvertFunctionType(tree_node *type, tree_node *static_chain, - unsigned &CallingConv); + unsigned &CallingConv, + const ParamAttrsList *&PAL); /// ConvertArgListToFnType - Given a DECL_ARGUMENTS list on an GCC tree, /// return the LLVM type corresponding to the function. This is useful for @@ -148,7 +149,8 @@ const FunctionType *ConvertArgListToFnType(tree_node *retty, tree_node *arglist, tree_node *static_chain, - unsigned &CallingConv); + unsigned &CallingConv, + const ParamAttrsList *&PAL); private: const Type *ConvertRECORD(tree_node *type, tree_node *orig_type); @@ -512,7 +514,8 @@ Value *EmitADDR_EXPR(tree_node *exp); Value *EmitOBJ_TYPE_REF(tree_node *exp); Value *EmitCALL_EXPR(tree_node *exp, Value *DestLoc); - Value *EmitCallOf(Value *Callee, tree_node *exp, Value *DestLoc); + Value *EmitCallOf(Value *Callee, tree_node *exp, Value *DestLoc, + const ParamAttrsList *); Value *EmitMODIFY_EXPR(tree_node *exp, Value *DestLoc); Value *EmitNOP_EXPR(tree_node *exp, Value *DestLoc); Value *EmitCONVERT_EXPR(tree_node *exp, Value *DestLoc); Index: gcc/llvm-types.cpp =================================================================== --- gcc/llvm-types.cpp (revision 40580) +++ gcc/llvm-types.cpp (working copy) @@ -785,7 +785,9 @@ return Ty; unsigned CallingConv; - return TypeDB.setType(type, ConvertFunctionType(type, NULL, CallingConv)); + const ParamAttrsList *PAL = 0; + return TypeDB.setType(type, ConvertFunctionType(type, NULL, CallingConv, + PAL)); } case ARRAY_TYPE: { if (const Type *Ty = GET_TYPE_LLVM(type)) @@ -843,6 +845,7 @@ class FunctionTypeConversion : public DefaultABIClient { const Type *&RetTy; std::vector<const Type*> &ArgTypes; + ParamAttrsVector ParamAttrs; unsigned &CallingConv; bool isStructRet; bool KNRPromotion; @@ -854,12 +857,37 @@ isStructRet = false; } + const ParamAttrsList* getParamAttrs() const { + if (ParamAttrs.empty()) + return 0; + return ParamAttrsList::get(ParamAttrs); + } + + void addAttributes(unsigned index, uint16_t Attrs) { + if (Attrs != ParamAttr::None) { + for (unsigned i = 0; i < ParamAttrs.size(); ++i) { + if (ParamAttrs[i].index == index) { + ParamAttrs[i].attrs |= Attrs; + break; + } + } + } + } + bool isStructReturn() const { return isStructRet; } /// HandleScalarResult - This callback is invoked if the function returns a /// simple scalar result value. - void HandleScalarResult(const Type *RetTy) { + void HandleScalarResult(const Type *RetTy, tree treeTy) { this->RetTy = RetTy; + if (KNRPromotion && isa<IntegerType>(RetTy)) { + if (TREE_INT_CST_LOW(TYPE_SIZE(treeTy)) < INT_TYPE_SIZE) { + if (TYPE_UNSIGNED(treeTy) || TREE_CODE(treeTy) == BOOLEAN_TYPE) + ParamAttrs.push_back(ParamAttrsWithIndex::get(0, ParamAttr::ZExt)); + else + ParamAttrs.push_back(ParamAttrsWithIndex::get(0, ParamAttr::SExt)); + } + } } /// HandleAggregateResultAsScalar - This callback is invoked if the function @@ -881,33 +909,54 @@ // In any case, there is a dummy shadow argument though! ArgTypes.push_back(PtrArgTy); + + // Set the StructRet attribute for this argument. + unsigned argIndex = ArgTypes.size(); + assert(argIndex == 1 && "StructRet only applicable to first argument"); + ParamAttrs.push_back( + ParamAttrsWithIndex::get(argIndex, ParamAttr::StructRet)); - // Also, switch the to C Struct Return. + // Make a note that this is a structure return function. isStructRet = true; } void HandleScalarArgument(const llvm::Type *LLVMTy, tree type) { + // If this function type is using K&R promotion then adjust the type + bool extend = false; if (KNRPromotion) { if (LLVMTy == Type::FloatTy) LLVMTy = Type::DoubleTy; else if (LLVMTy == Type::Int16Ty || LLVMTy == Type::Int8Ty || - LLVMTy == Type::Int1Ty) + LLVMTy == Type::Int1Ty) { LLVMTy = Type::Int32Ty; + } } + + // Add the argument type ArgTypes.push_back(LLVMTy); + + // If we extended the argument then add the attribute to make sure + // the callers extend too. + if (extend) { + unsigned argNo = ArgTypes.size(); + if (TYPE_UNSIGNED(type) || TREE_CODE(type) == BOOLEAN_TYPE) + ParamAttrs.push_back(ParamAttrsWithIndex::get(argNo,ParamAttr::ZExt)); + else + ParamAttrs.push_back(ParamAttrsWithIndex::get(argNo,ParamAttr::SExt)); + } } }; } -/// ConvertParamListToLLVMSignature - This method is used to build the argument -/// type list for K&R prototyped functions. In this case, we have to figure out +/// ConvertArgListToFnType - This method is used to build the argument type +/// list for K&R prototyped functions. In this case, we have to figure out /// the type list (to build a FunctionType) from the actual DECL_ARGUMENTS list /// for the function. This method takes the DECL_ARGUMENTS list (Args), and /// fills in Result with the argument types for the function. It returns the /// specified result type for the function. const FunctionType *TypeConverter:: ConvertArgListToFnType(tree ReturnType, tree Args, tree static_chain, - unsigned &CallingConv) { + unsigned &CallingConv, const ParamAttrsList *&PAL) { std::vector<const Type*> ArgTys; const Type *RetTy; @@ -920,18 +969,26 @@ // Pass the static chain as the first parameter. ABIConverter.HandleArgument(TREE_TYPE(static_chain)); - for (; Args && TREE_TYPE(Args) != void_type_node; Args = TREE_CHAIN(Args)) + for (; Args && TREE_TYPE(Args) != void_type_node; Args = TREE_CHAIN(Args)) { + tree ArgTy = TREE_TYPE(Args); ABIConverter.HandleArgument(TREE_TYPE(Args)); + } - return FunctionType::get(RetTy, ArgTys, false, 0); + // Extract the Parameter Attributes that were accumulated. + PAL = Client.getParamAttrs(); + + return FunctionType::get(RetTy, ArgTys, false); } const FunctionType *TypeConverter::ConvertFunctionType(tree type, tree static_chain, - unsigned &CallingConv) { + unsigned &CallingConv, + const ParamAttrsList*&PAL + ) { const Type *RetTy = 0; std::vector<const Type*> ArgTypes; bool isVarArg = false; + PAL = 0; FunctionTypeConversion Client(RetTy, ArgTypes, CallingConv, false/*not K&R*/); TheLLVMABI<FunctionTypeConversion> ABIConverter(Client); @@ -942,32 +999,11 @@ TARGET_ADJUST_LLVM_CC(CallingConv, type); #endif - // Compute whether the result needs to be zext or sext'd, adding an attribute - // if so. - ParamAttrsVector Attrs; - if (isa<IntegerType>(RetTy)) { - uint16_t RAttributes = ParamAttr::None; - tree ResultTy = TREE_TYPE(type); - if (TREE_INT_CST_LOW(TYPE_SIZE(ResultTy)) < INT_TYPE_SIZE) { - if (TYPE_UNSIGNED(ResultTy) || TREE_CODE(ResultTy) == BOOLEAN_TYPE) - Attrs.push_back(ParamAttrsWithIndex::get(0, ParamAttr::ZExt)); - else - Attrs.push_back(ParamAttrsWithIndex::get(0, ParamAttr::SExt)); - } - } - - // If this is a struct-return function, the dest loc is passed in as a - // pointer. Mark that pointer as structret. - if (ABIConverter.isStructReturn()) - Attrs.push_back(ParamAttrsWithIndex::get(ArgTypes.size(), - ParamAttr::StructRet)); - if (static_chain) { // Pass the static chain as the first parameter. ABIConverter.HandleArgument(TREE_TYPE(static_chain)); // Mark it as the chain argument. - Attrs.push_back(ParamAttrsWithIndex::get(ArgTypes.size(), - ParamAttr::Nest)); + Client.addAttributes(ArgTypes.size(), ParamAttr::Nest); } // If the target has regparam parameters, allow it to inspect the function @@ -996,21 +1032,9 @@ ABIConverter.HandleArgument(ArgTy); - // Determine if there are any attributes for this param. - - // Compute zext/sext attributes. - unsigned Attributes = ParamAttr::None; - if (TREE_CODE(ArgTy) == BOOLEAN_TYPE) { - if (TREE_INT_CST_LOW(TYPE_SIZE(ArgTy)) < INT_TYPE_SIZE) - Attributes |= ParamAttr::ZExt; - } else if (TREE_CODE(ArgTy) == INTEGER_TYPE && - TREE_INT_CST_LOW(TYPE_SIZE(ArgTy)) < INT_TYPE_SIZE) { - if (TYPE_UNSIGNED(ArgTy)) - Attributes |= ParamAttr::ZExt; - else - Attributes |= ParamAttr::SExt; - } - + // Declare attribute cache for LLVM_TARGET_ENABLE_REGPARM + uint16_t Attributes = ParamAttr::None; + #ifdef LLVM_TARGET_ENABLE_REGPARM // Allow the target to mark this as inreg. if (TREE_CODE(ArgTy) == INTEGER_TYPE || TREE_CODE(ArgTy) == POINTER_TYPE) @@ -1020,20 +1044,18 @@ #endif // LLVM_TARGET_ENABLE_REGPARM if (Attributes != ParamAttr::None) - Attrs.push_back(ParamAttrsWithIndex::get(ArgTypes.size(), Attributes)); + Client.addAttributes(ArgTypes.size(), Attributes); } // If the argument list ends with a void type node, it isn't vararg. isVarArg = (Args == 0); assert(RetTy && "Return type not specified!"); - // Only instantiate the parameter attributes if we got some. - ParamAttrsList *PAL = 0; - if (!Attrs.empty()) - PAL = ParamAttrsList::get(Attrs); + // Get the accumulated parameter attributes (if any). + PAL = Client.getParamAttrs(); // Finally, make the function type - return FunctionType::get(RetTy, ArgTypes, isVarArg, PAL); + return FunctionType::get(RetTy, ArgTypes, isVarArg); } //===----------------------------------------------------------------------===// Index: gcc/llvm-abi.h =================================================================== --- gcc/llvm-abi.h (revision 40580) +++ gcc/llvm-abi.h (working copy) @@ -52,7 +52,7 @@ /// HandleScalarResult - This callback is invoked if the function returns a /// simple scalar result value. - void HandleScalarResult(const Type *RetTy) {} + void HandleScalarResult(const Type *RetTy, tree treeTy) {} /// HandleAggregateResultAsScalar - This callback is invoked if the function /// returns an aggregate value by bit converting it to the specified scalar @@ -150,7 +150,7 @@ const Type *Ty = ConvertType(type); if (Ty->isFirstClassType() || Ty == Type::VoidTy) { // Return scalar values normally. - C.HandleScalarResult(Ty); + C.HandleScalarResult(Ty, type); } else if (TYPE_SIZE(type) && TREE_CODE(TYPE_SIZE(type)) == INTEGER_CST && !aggregate_value_p(type, current_function_decl) && // FIXME: this is a hack around returning 'complex double' by-val
_______________________________________________ llvm-commits mailing list llvm-commits@cs.uiuc.edu http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits