diff options
author | Chris Lattner <sabre@nondot.org> | 2008-03-02 08:07:24 +0000 |
---|---|---|
committer | Chris Lattner <sabre@nondot.org> | 2008-03-02 08:07:24 +0000 |
commit | e05252b4765180b224cc78221e5fc0161873c2f3 (patch) | |
tree | 4d1c667184c274e7aa21525621a5ff1f83f0c1c9 /lib/Target | |
parent | 873570e0ef68bce8cd18d040b15e0bb77724a82a (diff) | |
download | external_llvm-e05252b4765180b224cc78221e5fc0161873c2f3.zip external_llvm-e05252b4765180b224cc78221e5fc0161873c2f3.tar.gz external_llvm-e05252b4765180b224cc78221e5fc0161873c2f3.tar.bz2 |
Several changes:
* Simplify handling of byval, making it easier to understand and more
consistent. This fixes PR2065.
* Clean up and simplify handling of GEPs. I can actually understand it now!
* Implement support for GEP'ing into vectors, this fixes
SingleSource/UnitTests/Vector/build2 among others.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@47818 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Target')
-rw-r--r-- | lib/Target/CBackend/CBackend.cpp | 191 |
1 files changed, 109 insertions, 82 deletions
diff --git a/lib/Target/CBackend/CBackend.cpp b/lib/Target/CBackend/CBackend.cpp index 7fcc3dd..ca00e19 100644 --- a/lib/Target/CBackend/CBackend.cpp +++ b/lib/Target/CBackend/CBackend.cpp @@ -87,7 +87,7 @@ namespace { std::map<const Type *, std::string> TypeNames; std::map<const ConstantFP *, unsigned> FPConstantMap; std::set<Function*> intrinsicPrototypesAlreadyGenerated; - std::set<const Value*> ByValParams; + std::set<const Argument*> ByValParams; public: static char ID; @@ -122,8 +122,8 @@ namespace { delete Mang; FPConstantMap.clear(); TypeNames.clear(); - intrinsicPrototypesAlreadyGenerated.clear(); ByValParams.clear(); + intrinsicPrototypesAlreadyGenerated.clear(); return false; } @@ -139,6 +139,20 @@ namespace { void printStructReturnPointerFunctionType(std::ostream &Out, const ParamAttrsList *PAL, const PointerType *Ty); + + /// writeOperandDeref - Print the result of dereferencing the specified + /// operand with '*'. This is equivalent to printing '*' then using + /// writeOperand, but avoids excess syntax in some cases. + void writeOperandDeref(Value *Operand) { + if (isAddressExposed(Operand)) { + // Already something with an address exposed. + writeOperandInternal(Operand); + } else { + Out << "*("; + writeOperand(Operand); + Out << ")"; + } + } void writeOperand(Value *Operand); void writeOperandRaw(Value *Operand); @@ -170,8 +184,17 @@ namespace { void printConstantWithCast(Constant *CPV, unsigned Opcode); bool printConstExprCast(const ConstantExpr *CE); void printConstantArray(ConstantArray *CPA); - void printConstantVector(ConstantVector *CP); + void printConstantVector(ConstantVector *CV); + /// isAddressExposed - Return true if the specified value's name needs to + /// have its address taken in order to get a C value of the correct type. + /// This happens for global variables, byval parameters, and direct allocas. + bool isAddressExposed(const Value *V) const { + if (const Argument *A = dyn_cast<Argument>(V)) + return ByValParams.count(A); + return isa<GlobalVariable>(V) || isDirectAlloca(V); + } + // isInlinableInst - Attempt to inline instructions into their uses to build // trees as much as possible. To do this, we have to consistently decide // what is acceptable to inline, so that variable declarations don't get @@ -275,8 +298,8 @@ namespace { BasicBlock *Successor, unsigned Indent); void printBranchToBlock(BasicBlock *CurBlock, BasicBlock *SuccBlock, unsigned Indent); - void printIndexingExpression(Value *Ptr, gep_type_iterator I, - gep_type_iterator E); + void printGEPExpression(Value *Ptr, gep_type_iterator I, + gep_type_iterator E); std::string GetValueName(const Value *Operand); }; @@ -772,10 +795,10 @@ void CWriter::printConstant(Constant *CPV) { return; case Instruction::GetElementPtr: - Out << "(&("; - printIndexingExpression(CE->getOperand(0), gep_type_begin(CPV), - gep_type_end(CPV)); - Out << "))"; + Out << "("; + printGEPExpression(CE->getOperand(0), gep_type_begin(CPV), + gep_type_end(CPV)); + Out << ")"; return; case Instruction::Select: Out << '('; @@ -1214,12 +1237,13 @@ void CWriter::writeOperandRaw(Value *Operand) { } void CWriter::writeOperand(Value *Operand) { - if (isa<GlobalVariable>(Operand) || isDirectAlloca(Operand)) + bool isAddressImplicit = isAddressExposed(Operand); + if (isAddressImplicit) Out << "(&"; // Global variables are referenced as their addresses by llvm writeOperandInternal(Operand); - if (isa<GlobalVariable>(Operand) || isDirectAlloca(Operand)) + if (isAddressImplicit) Out << ')'; } @@ -1920,10 +1944,8 @@ void CWriter::printFunctionSignature(const Function *F, bool Prototype) { ArgName = ""; const Type *ArgTy = I->getType(); if (PAL && PAL->paramHasAttr(Idx, ParamAttr::ByVal)) { - assert(isa<PointerType>(ArgTy)); ArgTy = cast<PointerType>(ArgTy)->getElementType(); - const Value *Arg = &(*I); - ByValParams.insert(Arg); + ByValParams.insert(I); } printType(FunctionInnards, ArgTy, /*isSigned=*/PAL && PAL->paramHasAttr(Idx, ParamAttr::SExt), @@ -2430,13 +2452,6 @@ void CWriter::visitCastInst(CastInst &I) { // Make sure we really get a sext from bool by subtracing the bool from 0 Out << "0-"; } - // If it's a byval parameter being casted, then takes its address. - bool isByVal = ByValParams.count(I.getOperand(0)); - if (isByVal) { - assert(I.getOpcode() == Instruction::BitCast && - "ByVal aggregate parameter must ptr type"); - Out << '&'; - } writeOperand(I.getOperand(0)); if (DstTy == Type::Int1Ty && (I.getOpcode() == Instruction::Trunc || @@ -2666,10 +2681,7 @@ void CWriter::visitCallInst(CallInst &I) { bool hasByVal = I.hasByValArgument(); bool isStructRet = I.isStructReturn(); if (isStructRet) { - bool isByVal = ByValParams.count(I.getOperand(1)); - if (!isByVal) Out << "*("; - writeOperand(I.getOperand(1)); - if (!isByVal) Out << ")"; + writeOperandDeref(I.getOperand(1)); Out << " = "; } @@ -2737,16 +2749,10 @@ void CWriter::visitCallInst(CallInst &I) { Out << ')'; } // Check if the argument is expected to be passed by value. - bool isOutByVal = PAL && PAL->paramHasAttr(ArgNo+1, ParamAttr::ByVal); - // Check if this argument itself is passed in by reference. - bool isInByVal = ByValParams.count(*AI); - if (isOutByVal && !isInByVal) - Out << "*("; - else if (!isOutByVal && isInByVal) - Out << "&("; - writeOperand(*AI); - if (isOutByVal ^ isInByVal) - Out << ")"; + if (I.paramHasAttr(ArgNo+1, ParamAttr::ByVal)) + writeOperandDeref(*AI); + else + writeOperand(*AI); PrintedArg = true; } Out << ')'; @@ -2858,7 +2864,7 @@ void CWriter::visitInlineAsm(CallInst &CI) { Out << "__asm__ volatile (\"" << asmstr << "\"\n"; Out << " :"; - for (std::vector<std::pair<std::string, Value*> >::iterator I = Output.begin(), + for (std::vector<std::pair<std::string, Value*> >::iterator I =Output.begin(), E = Output.end(); I != E; ++I) { Out << "\"" << I->first << "\"("; writeOperandRaw(I->second); @@ -2901,61 +2907,85 @@ void CWriter::visitFreeInst(FreeInst &I) { assert(0 && "lowerallocations pass didn't work!"); } -void CWriter::printIndexingExpression(Value *Ptr, gep_type_iterator I, - gep_type_iterator E) { - bool HasImplicitAddress = false; - // If accessing a global value with no indexing, avoid *(&GV) syndrome - if (isa<GlobalValue>(Ptr)) { - HasImplicitAddress = true; - } else if (isDirectAlloca(Ptr)) { - HasImplicitAddress = true; - } - +void CWriter::printGEPExpression(Value *Ptr, gep_type_iterator I, + gep_type_iterator E) { + + // If there are no indices, just print out the pointer. if (I == E) { - if (!HasImplicitAddress) - Out << '*'; // Implicit zero first argument: '*x' is equivalent to 'x[0]' - - writeOperandInternal(Ptr); + writeOperand(Ptr); return; } - - const Constant *CI = dyn_cast<Constant>(I.getOperand()); - if (HasImplicitAddress && (!CI || !CI->isNullValue())) - Out << "(&"; - - writeOperandInternal(Ptr); - - if (HasImplicitAddress && (!CI || !CI->isNullValue())) { - Out << ')'; - HasImplicitAddress = false; // HIA is only true if we haven't addressed yet + + // Find out if the last index is into a vector. If so, we have to print this + // specially. Since vectors can't have elements of indexable type, only the + // last index could possibly be of a vector element. + const VectorType *LastIndexIsVector = 0; + { + for (gep_type_iterator TmpI = I; TmpI != E; ++TmpI) + LastIndexIsVector = dyn_cast<VectorType>(*TmpI); } + + Out << "("; + + // If the last index is into a vector, we can't print it as &a[i][j] because + // we can't index into a vector with j in GCC. Instead, emit this as + // (((float*)&a[i])+j) + if (LastIndexIsVector) { + Out << "(("; + printType(Out, PointerType::getUnqual(LastIndexIsVector->getElementType())); + Out << ")("; + } + + Out << '&'; - assert((!HasImplicitAddress || (CI && CI->isNullValue())) && - "Can only have implicit address with direct accessing"); - - if (HasImplicitAddress) { - ++I; - } else if (CI && CI->isNullValue()) { - gep_type_iterator TmpI = I; ++TmpI; - - // Print out the -> operator if possible... - if (TmpI != E && isa<StructType>(*TmpI)) { - // Check if it's actually an aggregate parameter passed by value. - bool isByVal = ByValParams.count(Ptr); - Out << ((HasImplicitAddress || isByVal) ? "." : "->"); - Out << "field" << cast<ConstantInt>(TmpI.getOperand())->getZExtValue(); - I = ++TmpI; + // If the first index is 0 (very typical) we can do a number of + // simplifications to clean up the code. + Value *FirstOp = I.getOperand(); + if (!isa<Constant>(FirstOp) || !cast<Constant>(FirstOp)->isNullValue()) { + // First index isn't simple, print it the hard way. + writeOperand(Ptr); + } else { + ++I; // Skip the zero index. + + // Okay, emit the first operand. If Ptr is something that is already address + // exposed, like a global, avoid emitting (&foo)[0], just emit foo instead. + if (isAddressExposed(Ptr)) { + writeOperandInternal(Ptr); + } else if (I != E && isa<StructType>(*I)) { + // If we didn't already emit the first operand, see if we can print it as + // P->f instead of "P[0].f" + writeOperand(Ptr); + Out << "->field" << cast<ConstantInt>(I.getOperand())->getZExtValue(); + ++I; // eat the struct index as well. + } else { + // Instead of emitting P[0][1], emit (*P)[1], which is more idiomatic. + Out << "(*"; + writeOperand(Ptr); + Out << ")"; } } - for (; I != E; ++I) + for (; I != E; ++I) { if (isa<StructType>(*I)) { Out << ".field" << cast<ConstantInt>(I.getOperand())->getZExtValue(); - } else { + } else if (!isa<VectorType>(*I)) { Out << '['; writeOperandWithCast(I.getOperand(), Instruction::GetElementPtr); Out << ']'; + } else { + // If the last index is into a vector, then print it out as "+j)". This + // works with the 'LastIndexIsVector' code above. + if (isa<Constant>(I.getOperand()) && + cast<Constant>(I.getOperand())->isNullValue()) { + Out << "))"; // avoid "+0". + } else { + Out << ")+("; + writeOperandWithCast(I.getOperand(), Instruction::GetElementPtr); + Out << "))"; + } } + } + Out << ")"; } void CWriter::writeMemoryAccess(Value *Operand, const Type *OperandType, @@ -2989,14 +3019,12 @@ void CWriter::writeMemoryAccess(Value *Operand, const Type *OperandType, } void CWriter::visitLoadInst(LoadInst &I) { - writeMemoryAccess(I.getOperand(0), I.getType(), I.isVolatile(), I.getAlignment()); } void CWriter::visitStoreInst(StoreInst &I) { - writeMemoryAccess(I.getPointerOperand(), I.getOperand(0)->getType(), I.isVolatile(), I.getAlignment()); Out << " = "; @@ -3018,9 +3046,8 @@ void CWriter::visitStoreInst(StoreInst &I) { } void CWriter::visitGetElementPtrInst(GetElementPtrInst &I) { - Out << '&'; - printIndexingExpression(I.getPointerOperand(), gep_type_begin(I), - gep_type_end(I)); + printGEPExpression(I.getPointerOperand(), gep_type_begin(I), + gep_type_end(I)); } void CWriter::visitVAArgInst(VAArgInst &I) { |