From 4394d5146799bc920911e9456bc21a604848a8c2 Mon Sep 17 00:00:00 2001 From: Chris Lattner Date: Sat, 13 Nov 2004 22:21:56 +0000 Subject: [PATCH] Hack around stupidity in GCC, fixing Burg with the CBE and CBackend/2004-11-13-FunctionPointerCast.llx git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@17710 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Target/CBackend/CBackend.cpp | 65 +++++++++++++++++++++++++++----- lib/Target/CBackend/Writer.cpp | 65 +++++++++++++++++++++++++++----- 2 files changed, 112 insertions(+), 18 deletions(-) diff --git a/lib/Target/CBackend/CBackend.cpp b/lib/Target/CBackend/CBackend.cpp index 3fec86a81d5..4e8b631ad5c 100644 --- a/lib/Target/CBackend/CBackend.cpp +++ b/lib/Target/CBackend/CBackend.cpp @@ -182,7 +182,6 @@ namespace { void visitCastInst (CastInst &I); void visitSelectInst(SelectInst &I); void visitCallInst (CallInst &I); - void visitCallSite (CallSite CS); void visitShiftInst(ShiftInst &I) { visitBinaryOperator(I); } void visitMallocInst(MallocInst &I); @@ -1466,23 +1465,71 @@ void CWriter::visitCallInst(CallInst &I) { return; } } - visitCallSite(&I); -} -void CWriter::visitCallSite(CallSite CS) { - const PointerType *PTy = cast(CS.getCalledValue()->getType()); + Value *Callee = I.getCalledValue(); + + // GCC is really a PITA. It does not permit codegening casts of functions to + // function pointers if they are in a call (it generates a trap instruction + // instead!). We work around this by inserting a cast to void* in between the + // function and the function pointer cast. Unfortunately, we can't just form + // the constant expression here, because the folder will immediately nuke it. + // + // Note finally, that this is completely unsafe. ANSI C does not guarantee + // that void* and function pointers have the same size. :( To deal with this + // in the common case, we handle casts where the number of arguments passed + // match exactly. + // + bool WroteCallee = false; + if (ConstantExpr *CE = dyn_cast(Callee)) + if (CE->getOpcode() == Instruction::Cast) + if (Function *RF = dyn_cast(CE->getOperand(0))) { + const FunctionType *RFTy = RF->getFunctionType(); + if (RFTy->getNumParams() == I.getNumOperands()-1) { + // If the call site expects a value, and the actual callee doesn't + // provide one, return 0. + if (I.getType() != Type::VoidTy && + RFTy->getReturnType() == Type::VoidTy) + Out << "0 /*actual callee doesn't return value*/; "; + Callee = RF; + } else { + // Ok, just cast the pointer type. + Out << "(("; + printType(Out, CE->getType()); + Out << ")(void*)"; + printConstant(RF); + Out << ")"; + WroteCallee = true; + } + } + + const PointerType *PTy = cast(Callee->getType()); const FunctionType *FTy = cast(PTy->getElementType()); const Type *RetTy = FTy->getReturnType(); - writeOperand(CS.getCalledValue()); + if (!WroteCallee) writeOperand(Callee); Out << "("; - if (CS.arg_begin() != CS.arg_end()) { - CallSite::arg_iterator AI = CS.arg_begin(), AE = CS.arg_end(); + unsigned NumDeclaredParams = FTy->getNumParams(); + + if (I.getNumOperands() != 1) { + CallSite::arg_iterator AI = I.op_begin()+1, AE = I.op_end(); + if (NumDeclaredParams && (*AI)->getType() != FTy->getParamType(0)) { + Out << "("; + printType(Out, FTy->getParamType(0)); + Out << ")"; + } + writeOperand(*AI); - for (++AI; AI != AE; ++AI) { + unsigned ArgNo; + for (ArgNo = 1, ++AI; AI != AE; ++AI, ++ArgNo) { Out << ", "; + if (ArgNo < NumDeclaredParams && + (*AI)->getType() != FTy->getParamType(ArgNo)) { + Out << "("; + printType(Out, FTy->getParamType(ArgNo)); + Out << ")"; + } writeOperand(*AI); } } diff --git a/lib/Target/CBackend/Writer.cpp b/lib/Target/CBackend/Writer.cpp index 3fec86a81d5..4e8b631ad5c 100644 --- a/lib/Target/CBackend/Writer.cpp +++ b/lib/Target/CBackend/Writer.cpp @@ -182,7 +182,6 @@ namespace { void visitCastInst (CastInst &I); void visitSelectInst(SelectInst &I); void visitCallInst (CallInst &I); - void visitCallSite (CallSite CS); void visitShiftInst(ShiftInst &I) { visitBinaryOperator(I); } void visitMallocInst(MallocInst &I); @@ -1466,23 +1465,71 @@ void CWriter::visitCallInst(CallInst &I) { return; } } - visitCallSite(&I); -} -void CWriter::visitCallSite(CallSite CS) { - const PointerType *PTy = cast(CS.getCalledValue()->getType()); + Value *Callee = I.getCalledValue(); + + // GCC is really a PITA. It does not permit codegening casts of functions to + // function pointers if they are in a call (it generates a trap instruction + // instead!). We work around this by inserting a cast to void* in between the + // function and the function pointer cast. Unfortunately, we can't just form + // the constant expression here, because the folder will immediately nuke it. + // + // Note finally, that this is completely unsafe. ANSI C does not guarantee + // that void* and function pointers have the same size. :( To deal with this + // in the common case, we handle casts where the number of arguments passed + // match exactly. + // + bool WroteCallee = false; + if (ConstantExpr *CE = dyn_cast(Callee)) + if (CE->getOpcode() == Instruction::Cast) + if (Function *RF = dyn_cast(CE->getOperand(0))) { + const FunctionType *RFTy = RF->getFunctionType(); + if (RFTy->getNumParams() == I.getNumOperands()-1) { + // If the call site expects a value, and the actual callee doesn't + // provide one, return 0. + if (I.getType() != Type::VoidTy && + RFTy->getReturnType() == Type::VoidTy) + Out << "0 /*actual callee doesn't return value*/; "; + Callee = RF; + } else { + // Ok, just cast the pointer type. + Out << "(("; + printType(Out, CE->getType()); + Out << ")(void*)"; + printConstant(RF); + Out << ")"; + WroteCallee = true; + } + } + + const PointerType *PTy = cast(Callee->getType()); const FunctionType *FTy = cast(PTy->getElementType()); const Type *RetTy = FTy->getReturnType(); - writeOperand(CS.getCalledValue()); + if (!WroteCallee) writeOperand(Callee); Out << "("; - if (CS.arg_begin() != CS.arg_end()) { - CallSite::arg_iterator AI = CS.arg_begin(), AE = CS.arg_end(); + unsigned NumDeclaredParams = FTy->getNumParams(); + + if (I.getNumOperands() != 1) { + CallSite::arg_iterator AI = I.op_begin()+1, AE = I.op_end(); + if (NumDeclaredParams && (*AI)->getType() != FTy->getParamType(0)) { + Out << "("; + printType(Out, FTy->getParamType(0)); + Out << ")"; + } + writeOperand(*AI); - for (++AI; AI != AE; ++AI) { + unsigned ArgNo; + for (ArgNo = 1, ++AI; AI != AE; ++AI, ++ArgNo) { Out << ", "; + if (ArgNo < NumDeclaredParams && + (*AI)->getType() != FTy->getParamType(ArgNo)) { + Out << "("; + printType(Out, FTy->getParamType(ArgNo)); + Out << ")"; + } writeOperand(*AI); } }