diff options
author | Reid Spencer <rspencer@reidspencer.com> | 2006-10-26 06:15:43 +0000 |
---|---|---|
committer | Reid Spencer <rspencer@reidspencer.com> | 2006-10-26 06:15:43 +0000 |
commit | 1628cec4d7fce310d9cde0bcc73997e5a71692c4 (patch) | |
tree | 6dff5a70de8406b153e32fdd2d60c782d6202f63 /lib/Target/CBackend/Writer.cpp | |
parent | 7043d00750c558a518d08a638638ebe4d241f159 (diff) |
For PR950:
Make necessary changes to support DIV -> [SUF]Div. This changes llvm to
have three division instructions: signed, unsigned, floating point. The
bytecode and assembler are bacwards compatible, however.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@31195 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Target/CBackend/Writer.cpp')
-rw-r--r-- | lib/Target/CBackend/Writer.cpp | 168 |
1 files changed, 161 insertions, 7 deletions
diff --git a/lib/Target/CBackend/Writer.cpp b/lib/Target/CBackend/Writer.cpp index bc2f7bd5f1..eb7b4e3813 100644 --- a/lib/Target/CBackend/Writer.cpp +++ b/lib/Target/CBackend/Writer.cpp @@ -121,6 +121,8 @@ namespace { void writeOperand(Value *Operand); void writeOperandInternal(Value *Operand); + void writeOperandWithCast(Value* Operand, unsigned Opcode); + bool writeInstructionCast(const Instruction &I); private : void lowerIntrinsics(Function &F); @@ -136,6 +138,8 @@ namespace { void printLoop(Loop *L); void printConstant(Constant *CPV); + void printConstantWithCast(Constant *CPV, unsigned Opcode); + bool printConstExprCast(const ConstantExpr *CE); void printConstantArray(ConstantArray *CPA); void printConstantPacked(ConstantPacked *CP); @@ -586,7 +590,9 @@ void CWriter::printConstant(Constant *CPV) { case Instruction::Add: case Instruction::Sub: case Instruction::Mul: - case Instruction::Div: + case Instruction::SDiv: + case Instruction::UDiv: + case Instruction::FDiv: case Instruction::Rem: case Instruction::And: case Instruction::Or: @@ -600,12 +606,15 @@ void CWriter::printConstant(Constant *CPV) { case Instruction::Shl: case Instruction::Shr: Out << '('; - printConstant(CE->getOperand(0)); + bool NeedsClosingParens = printConstExprCast(CE); + printConstantWithCast(CE->getOperand(0), CE->getOpcode()); switch (CE->getOpcode()) { case Instruction::Add: Out << " + "; break; case Instruction::Sub: Out << " - "; break; case Instruction::Mul: Out << " * "; break; - case Instruction::Div: Out << " / "; break; + case Instruction::UDiv: + case Instruction::SDiv: + case Instruction::FDiv: Out << " / "; break; case Instruction::Rem: Out << " % "; break; case Instruction::And: Out << " & "; break; case Instruction::Or: Out << " | "; break; @@ -620,7 +629,9 @@ void CWriter::printConstant(Constant *CPV) { case Instruction::Shr: Out << " >> "; break; default: assert(0 && "Illegal opcode here!"); } - printConstant(CE->getOperand(1)); + printConstantWithCast(CE->getOperand(1), CE->getOpcode()); + if (NeedsClosingParens) + Out << "))"; Out << ')'; return; @@ -805,6 +816,71 @@ void CWriter::printConstant(Constant *CPV) { } } +// Some constant expressions need to be casted back to the original types +// because their operands were casted to the expected type. This function takes +// care of detecting that case and printing the cast for the ConstantExpr. +bool CWriter::printConstExprCast(const ConstantExpr* CE) { + bool Result = false; + const Type* Ty = CE->getOperand(0)->getType(); + switch (CE->getOpcode()) { + case Instruction::UDiv: Result = Ty->isSigned(); break; + case Instruction::SDiv: Result = Ty->isUnsigned(); break; + default: break; + } + if (Result) { + Out << "(("; + printType(Out, Ty); + Out << ")("; + } + return Result; +} + +// Print a constant assuming that it is the operand for a given Opcode. The +// opcodes that care about sign need to cast their operands to the expected +// type before the operation proceeds. This function does the casting. +void CWriter::printConstantWithCast(Constant* CPV, unsigned Opcode) { + + // Extract the operand's type, we'll need it. + const Type* OpTy = CPV->getType(); + + // Indicate whether to do the cast or not. + bool shouldCast = false; + + // Based on the Opcode for which this Constant is being written, determine + // the new type to which the operand should be casted by setting the value + // of OpTy. If we change OpTy, also set shouldCast to true. + switch (Opcode) { + default: + // for most instructions, it doesn't matter + break; + case Instruction::UDiv: + // For UDiv to have unsigned operands + if (OpTy->isSigned()) { + OpTy = OpTy->getUnsignedVersion(); + shouldCast = true; + } + break; + case Instruction::SDiv: + if (OpTy->isUnsigned()) { + OpTy = OpTy->getSignedVersion(); + shouldCast = true; + } + break; + } + + // Write out the casted constnat if we should, otherwise just write the + // operand. + if (shouldCast) { + Out << "(("; + printType(Out, OpTy); + Out << ")"; + printConstant(CPV); + Out << ")"; + } else + writeOperand(CPV); + +} + void CWriter::writeOperandInternal(Value *Operand) { if (Instruction *I = dyn_cast<Instruction>(Operand)) if (isInlinableInst(*I) && !isDirectAlloca(I)) { @@ -833,6 +909,72 @@ void CWriter::writeOperand(Value *Operand) { Out << ')'; } +// Some instructions need to have their result value casted back to the +// original types because their operands were casted to the expected type. +// This function takes care of detecting that case and printing the cast +// for the Instruction. +bool CWriter::writeInstructionCast(const Instruction &I) { + bool Result = false; + const Type* Ty = I.getOperand(0)->getType(); + switch (I.getOpcode()) { + case Instruction::UDiv: Result = Ty->isSigned(); break; + case Instruction::SDiv: Result = Ty->isUnsigned(); break; + default: break; + } + if (Result) { + Out << "(("; + printType(Out, Ty); + Out << ")("; + } + return Result; +} + +// Write the operand with a cast to another type based on the Opcode being used. +// This will be used in cases where an instruction has specific type +// requirements (usually signedness) for its operands. +void CWriter::writeOperandWithCast(Value* Operand, unsigned Opcode) { + + // Extract the operand's type, we'll need it. + const Type* OpTy = Operand->getType(); + + // Indicate whether to do the cast or not. + bool shouldCast = false; + + // Based on the Opcode for which this Operand is being written, determine + // the new type to which the operand should be casted by setting the value + // of OpTy. If we change OpTy, also set shouldCast to true. + switch (Opcode) { + default: + // for most instructions, it doesn't matter + break; + case Instruction::UDiv: + // For UDiv to have unsigned operands + if (OpTy->isSigned()) { + OpTy = OpTy->getUnsignedVersion(); + shouldCast = true; + } + break; + case Instruction::SDiv: + if (OpTy->isUnsigned()) { + OpTy = OpTy->getSignedVersion(); + shouldCast = true; + } + break; + } + + // Write out the casted operand if we should, otherwise just write the + // operand. + if (shouldCast) { + Out << "(("; + printType(Out, OpTy); + Out << ")"; + writeOperand(Operand); + Out << ")"; + } else + writeOperand(Operand); + +} + // generateCompilerSpecificCode - This is where we add conditional compilation // directives to cater to specific compilers as need be. // @@ -1642,13 +1784,23 @@ void CWriter::visitBinaryOperator(Instruction &I) { writeOperand(I.getOperand(1)); Out << ")"; } else { - writeOperand(I.getOperand(0)); + + // Write out the cast of the instruction's value back to the proper type + // if necessary. + bool NeedsClosingParens = writeInstructionCast(I); + + // Certain instructions require the operand to be forced to a specific type + // so we use writeOperandWithCast here instead of writeOperand. Similarly + // below for operand 1 + writeOperandWithCast(I.getOperand(0), I.getOpcode()); switch (I.getOpcode()) { case Instruction::Add: Out << " + "; break; case Instruction::Sub: Out << " - "; break; case Instruction::Mul: Out << '*'; break; - case Instruction::Div: Out << '/'; break; + case Instruction::UDiv: + case Instruction::SDiv: + case Instruction::FDiv: Out << '/'; break; case Instruction::Rem: Out << '%'; break; case Instruction::And: Out << " & "; break; case Instruction::Or: Out << " | "; break; @@ -1664,7 +1816,9 @@ void CWriter::visitBinaryOperator(Instruction &I) { default: std::cerr << "Invalid operator type!" << I; abort(); } - writeOperand(I.getOperand(1)); + writeOperandWithCast(I.getOperand(1), I.getOpcode()); + if (NeedsClosingParens) + Out << "))"; } if (needsCast) { |