From e56d946a383e3a7330c5fe8a8cf8c409174fb774 Mon Sep 17 00:00:00 2001 From: Chris Lattner Date: Sat, 31 May 2008 09:23:55 +0000 Subject: [PATCH] Fix the CBE's handling of instructions whose result is an i1. Previously, we did not truncate the value down to i1 with (x&1). This caused a problem when the computation of x was nontrivial, for example, "add i1 1, 1" would return 2 instead of 0. This makes the testcase compile into: ... llvm_cbe_t = (((llvm_cbe_r == 0u) + (llvm_cbe_r == 0u))&1); llvm_cbe_u = (((unsigned int )(bool )llvm_cbe_t)); ... instead of: ... llvm_cbe_t = ((llvm_cbe_r == 0u) + (llvm_cbe_r == 0u)); llvm_cbe_u = (((unsigned int )(bool )llvm_cbe_t)); ... This fixes a miscompilation of mediabench/adpcm/rawdaudio/rawdaudio and 403.gcc with the CBE, regressions from LLVM 2.2. Tanya, please pull this into the release branch. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@51813 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Target/CBackend/CBackend.cpp | 66 +++++++++++++------ .../CBackend/2008-05-31-BoolOverflow.ll | 14 ++++ 2 files changed, 60 insertions(+), 20 deletions(-) create mode 100644 test/CodeGen/CBackend/2008-05-31-BoolOverflow.ll diff --git a/lib/Target/CBackend/CBackend.cpp b/lib/Target/CBackend/CBackend.cpp index 2ace6ebd8b6..440ce1cb4a4 100644 --- a/lib/Target/CBackend/CBackend.cpp +++ b/lib/Target/CBackend/CBackend.cpp @@ -155,6 +155,7 @@ namespace { void writeOperand(Value *Operand); void writeOperandRaw(Value *Operand); + void writeInstComputationInline(Instruction &I); void writeOperandInternal(Value *Operand); void writeOperandWithCast(Value* Operand, unsigned Opcode); void writeOperandWithCast(Value* Operand, const ICmpInst &I); @@ -1217,12 +1218,32 @@ std::string CWriter::GetValueName(const Value *Operand) { return Name; } +/// writeInstComputationInline - Emit the computation for the specified +/// instruction inline, with no destination provided. +void CWriter::writeInstComputationInline(Instruction &I) { + // If this is a non-trivial bool computation, make sure to truncate down to + // a 1 bit value. This is important because we want "add i1 x, y" to return + // "0" when x and y are true, not "2" for example. + bool NeedBoolTrunc = false; + if (I.getType() == Type::Int1Ty && !isa(I) && !isa(I)) + NeedBoolTrunc = true; + + if (NeedBoolTrunc) + Out << "(("; + + visit(I); + + if (NeedBoolTrunc) + Out << ")&1)"; +} + + void CWriter::writeOperandInternal(Value *Operand) { if (Instruction *I = dyn_cast(Operand)) + // Should we inline this instruction to build a tree? if (isInlinableInst(*I) && !isDirectAlloca(I)) { - // Should we inline this instruction to build a tree? Out << '('; - visit(*I); + writeInstComputationInline(*I); Out << ')'; return; } @@ -2152,12 +2173,12 @@ void CWriter::printBasicBlock(BasicBlock *BB) { outputLValue(II); else Out << " "; - visit(*II); + writeInstComputationInline(*II); Out << ";\n"; } } - // Don't emit prefix or suffix for the terminator... + // Don't emit prefix or suffix for the terminator. visit(*BB->getTerminator()); } @@ -2481,29 +2502,34 @@ static const char * getFloatBitCastField(const Type *Ty) { void CWriter::visitCastInst(CastInst &I) { const Type *DstTy = I.getType(); const Type *SrcTy = I.getOperand(0)->getType(); - Out << '('; if (isFPIntBitCast(I)) { + Out << '('; // These int<->float and long<->double casts need to be handled specially Out << GetValueName(&I) << "__BITCAST_TEMPORARY." << getFloatBitCastField(I.getOperand(0)->getType()) << " = "; writeOperand(I.getOperand(0)); Out << ", " << GetValueName(&I) << "__BITCAST_TEMPORARY." << getFloatBitCastField(I.getType()); - } else { - printCast(I.getOpcode(), SrcTy, DstTy); - if (I.getOpcode() == Instruction::SExt && SrcTy == Type::Int1Ty) { - // Make sure we really get a sext from bool by subtracing the bool from 0 - Out << "0-"; - } - writeOperand(I.getOperand(0)); - if (DstTy == Type::Int1Ty && - (I.getOpcode() == Instruction::Trunc || - I.getOpcode() == Instruction::FPToUI || - I.getOpcode() == Instruction::FPToSI || - I.getOpcode() == Instruction::PtrToInt)) { - // Make sure we really get a trunc to bool by anding the operand with 1 - Out << "&1u"; - } + Out << ')'; + return; + } + + Out << '('; + printCast(I.getOpcode(), SrcTy, DstTy); + + // Make a sext from i1 work by subtracting the i1 from 0 (an int). + if (SrcTy == Type::Int1Ty && I.getOpcode() == Instruction::SExt) + Out << "0-"; + + writeOperand(I.getOperand(0)); + + if (DstTy == Type::Int1Ty && + (I.getOpcode() == Instruction::Trunc || + I.getOpcode() == Instruction::FPToUI || + I.getOpcode() == Instruction::FPToSI || + I.getOpcode() == Instruction::PtrToInt)) { + // Make sure we really get a trunc to bool by anding the operand with 1 + Out << "&1u"; } Out << ')'; } diff --git a/test/CodeGen/CBackend/2008-05-31-BoolOverflow.ll b/test/CodeGen/CBackend/2008-05-31-BoolOverflow.ll new file mode 100644 index 00000000000..52e02590078 --- /dev/null +++ b/test/CodeGen/CBackend/2008-05-31-BoolOverflow.ll @@ -0,0 +1,14 @@ +; RUN: llvm-as < %s | llc -march=c | grep {llvm_cbe_t.*&1} +define i32 @test(i32 %r) { + %s = icmp eq i32 %r, 0 + %t = add i1 %s, %s + %u = zext i1 %t to i32 + br i1 %t, label %A, label %B +A: + + ret i32 %u +B: + + %v = select i1 %t, i32 %r, i32 %u + ret i32 %v +}