mirror of
https://github.com/RPCS3/llvm.git
synced 2024-12-02 00:37:09 +00:00
For PR950:
Replace the REM instruction with UREM, SREM and FREM. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@31369 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
0ac6757586
commit
0a783f783c
@ -80,7 +80,9 @@
|
||||
<li><a href="#i_udiv">'<tt>udiv</tt>' Instruction</a></li>
|
||||
<li><a href="#i_sdiv">'<tt>sdiv</tt>' Instruction</a></li>
|
||||
<li><a href="#i_fdiv">'<tt>fdiv</tt>' Instruction</a></li>
|
||||
<li><a href="#i_rem">'<tt>rem</tt>' Instruction</a></li>
|
||||
<li><a href="#i_urem">'<tt>urem</tt>' Instruction</a></li>
|
||||
<li><a href="#i_srem">'<tt>srem</tt>' Instruction</a></li>
|
||||
<li><a href="#i_frem">'<tt>frem</tt>' Instruction</a></li>
|
||||
<li><a href="#i_setcc">'<tt>set<i>cc</i></tt>' Instructions</a></li>
|
||||
</ol>
|
||||
</li>
|
||||
@ -1699,30 +1701,72 @@ versions of the values in which case the elements must be floating point.</p>
|
||||
</pre>
|
||||
</div>
|
||||
<!-- _______________________________________________________________________ -->
|
||||
<div class="doc_subsubsection"> <a name="i_rem">'<tt>rem</tt>'
|
||||
<div class="doc_subsubsection"> <a name="i_urem">'<tt>urem</tt>' Instruction</a>
|
||||
</div>
|
||||
<div class="doc_text">
|
||||
<h5>Syntax:</h5>
|
||||
<pre> <result> = urem <ty> <var1>, <var2> <i>; yields {ty}:result</i>
|
||||
</pre>
|
||||
<h5>Overview:</h5>
|
||||
<p>The '<tt>urem</tt>' instruction returns the remainder from the
|
||||
unsigned division of its two arguments.</p>
|
||||
<h5>Arguments:</h5>
|
||||
<p>The two arguments to the '<tt>urem</tt>' instruction must be
|
||||
<a href="#t_integer">integer</a> values. Both arguments must have identical
|
||||
types.</p>
|
||||
<h5>Semantics:</h5>
|
||||
<p>This instruction returns the unsigned integer <i>remainder</i> of a division.
|
||||
This instruction always performs an unsigned division to get the remainder,
|
||||
regardless of whether the arguments are unsigned or not.</p>
|
||||
<h5>Example:</h5>
|
||||
<pre> <result> = urem uint 4, %var <i>; yields {uint}:result = 4 % %var</i>
|
||||
</pre>
|
||||
|
||||
</div>
|
||||
<!-- _______________________________________________________________________ -->
|
||||
<div class="doc_subsubsection"> <a name="i_srem">'<tt>srem</tt>'
|
||||
Instruction</a> </div>
|
||||
<div class="doc_text">
|
||||
<h5>Syntax:</h5>
|
||||
<pre> <result> = rem <ty> <var1>, <var2> <i>; yields {ty}:result</i>
|
||||
<pre> <result> = srem <ty> <var1>, <var2> <i>; yields {ty}:result</i>
|
||||
</pre>
|
||||
<h5>Overview:</h5>
|
||||
<p>The '<tt>rem</tt>' instruction returns the remainder from the
|
||||
division of its two operands.</p>
|
||||
<p>The '<tt>srem</tt>' instruction returns the remainder from the
|
||||
signed division of its two operands.</p>
|
||||
<h5>Arguments:</h5>
|
||||
<p>The two arguments to the '<tt>rem</tt>' instruction must be either <a
|
||||
href="#t_integer">integer</a> or <a href="#t_floating">floating point</a>
|
||||
values.
|
||||
This instruction can also take <a href="#t_packed">packed</a> versions of the values.
|
||||
Both arguments must have identical types.</p>
|
||||
<p>The two arguments to the '<tt>srem</tt>' instruction must be
|
||||
<a href="#t_integer">integer</a> values. Both arguments must have identical
|
||||
types.</p>
|
||||
<h5>Semantics:</h5>
|
||||
<p>This returns the <i>remainder</i> of a division (where the result
|
||||
<p>This instruction returns the <i>remainder</i> of a division (where the result
|
||||
has the same sign as the divisor), not the <i>modulus</i> (where the
|
||||
result has the same sign as the dividend) of a value. For more
|
||||
information about the difference, see <a
|
||||
href="http://mathforum.org/dr.math/problems/anne.4.28.99.html">The
|
||||
Math Forum</a>.</p>
|
||||
<h5>Example:</h5>
|
||||
<pre> <result> = rem int 4, %var <i>; yields {int}:result = 4 % %var</i>
|
||||
<pre> <result> = srem int 4, %var <i>; yields {int}:result = 4 % %var</i>
|
||||
</pre>
|
||||
|
||||
</div>
|
||||
<!-- _______________________________________________________________________ -->
|
||||
<div class="doc_subsubsection"> <a name="i_frem">'<tt>frem</tt>'
|
||||
Instruction</a> </div>
|
||||
<div class="doc_text">
|
||||
<h5>Syntax:</h5>
|
||||
<pre> <result> = frem <ty> <var1>, <var2> <i>; yields {ty}:result</i>
|
||||
</pre>
|
||||
<h5>Overview:</h5>
|
||||
<p>The '<tt>frem</tt>' instruction returns the remainder from the
|
||||
division of its two operands.</p>
|
||||
<h5>Arguments:</h5>
|
||||
<p>The two arguments to the '<tt>frem</tt>' instruction must be
|
||||
<a href="#t_floating">floating point</a> values. Both arguments must have
|
||||
identical types.</p>
|
||||
<h5>Semantics:</h5>
|
||||
<p>This instruction returns the <i>remainder</i> of a division.</p>
|
||||
<h5>Example:</h5>
|
||||
<pre> <result> = frem float 4.0, %var <i>; yields {float}:result = 4.0 % %var</i>
|
||||
</pre>
|
||||
|
||||
</div>
|
||||
|
@ -551,7 +551,9 @@ public:
|
||||
static Constant *getUDiv(Constant *C1, Constant *C2);
|
||||
static Constant *getSDiv(Constant *C1, Constant *C2);
|
||||
static Constant *getFDiv(Constant *C1, Constant *C2);
|
||||
static Constant *getRem(Constant *C1, Constant *C2);
|
||||
static Constant *getURem(Constant *C1, Constant *C2); // unsigned rem
|
||||
static Constant *getSRem(Constant *C1, Constant *C2); // signed rem
|
||||
static Constant *getFRem(Constant *C1, Constant *C2);
|
||||
static Constant *getAnd(Constant *C1, Constant *C2);
|
||||
static Constant *getOr(Constant *C1, Constant *C2);
|
||||
static Constant *getXor(Constant *C1, Constant *C2);
|
||||
|
@ -90,53 +90,55 @@ HANDLE_TERM_INST ( 6, Unreachable, UnreachableInst)
|
||||
|
||||
// Standard binary operators...
|
||||
FIRST_BINARY_INST( 7)
|
||||
HANDLE_BINARY_INST( 7, Add , BinaryOperator)
|
||||
HANDLE_BINARY_INST( 8, Sub , BinaryOperator)
|
||||
HANDLE_BINARY_INST( 9, Mul , BinaryOperator)
|
||||
HANDLE_BINARY_INST(10, UDiv , BinaryOperator)
|
||||
HANDLE_BINARY_INST(11, SDiv , BinaryOperator)
|
||||
HANDLE_BINARY_INST(12, FDiv , BinaryOperator)
|
||||
HANDLE_BINARY_INST(13, Rem , BinaryOperator)
|
||||
HANDLE_BINARY_INST( 7, Add , BinaryOperator)
|
||||
HANDLE_BINARY_INST( 8, Sub , BinaryOperator)
|
||||
HANDLE_BINARY_INST( 9, Mul , BinaryOperator)
|
||||
HANDLE_BINARY_INST(10, UDiv , BinaryOperator)
|
||||
HANDLE_BINARY_INST(11, SDiv , BinaryOperator)
|
||||
HANDLE_BINARY_INST(12, FDiv , BinaryOperator)
|
||||
HANDLE_BINARY_INST(13, URem , BinaryOperator)
|
||||
HANDLE_BINARY_INST(14, SRem , BinaryOperator)
|
||||
HANDLE_BINARY_INST(15, FRem , BinaryOperator)
|
||||
|
||||
// Logical operators...
|
||||
HANDLE_BINARY_INST(14, And , BinaryOperator)
|
||||
HANDLE_BINARY_INST(15, Or , BinaryOperator)
|
||||
HANDLE_BINARY_INST(16, Xor , BinaryOperator)
|
||||
HANDLE_BINARY_INST(16, And , BinaryOperator)
|
||||
HANDLE_BINARY_INST(17, Or , BinaryOperator)
|
||||
HANDLE_BINARY_INST(18, Xor , BinaryOperator)
|
||||
|
||||
// Binary comparison operators...
|
||||
HANDLE_BINARY_INST(17, SetEQ , SetCondInst)
|
||||
HANDLE_BINARY_INST(18, SetNE , SetCondInst)
|
||||
HANDLE_BINARY_INST(19, SetLE , SetCondInst)
|
||||
HANDLE_BINARY_INST(20, SetGE , SetCondInst)
|
||||
HANDLE_BINARY_INST(21, SetLT , SetCondInst)
|
||||
HANDLE_BINARY_INST(22, SetGT , SetCondInst)
|
||||
LAST_BINARY_INST(22)
|
||||
HANDLE_BINARY_INST(19, SetEQ , SetCondInst)
|
||||
HANDLE_BINARY_INST(20, SetNE , SetCondInst)
|
||||
HANDLE_BINARY_INST(21, SetLE , SetCondInst)
|
||||
HANDLE_BINARY_INST(22, SetGE , SetCondInst)
|
||||
HANDLE_BINARY_INST(23, SetLT , SetCondInst)
|
||||
HANDLE_BINARY_INST(24, SetGT , SetCondInst)
|
||||
LAST_BINARY_INST(24)
|
||||
|
||||
// Memory operators...
|
||||
FIRST_MEMORY_INST(23)
|
||||
HANDLE_MEMORY_INST(23, Malloc, MallocInst) // Heap management instructions
|
||||
HANDLE_MEMORY_INST(24, Free , FreeInst )
|
||||
HANDLE_MEMORY_INST(25, Alloca, AllocaInst) // Stack management
|
||||
HANDLE_MEMORY_INST(26, Load , LoadInst ) // Memory manipulation instrs
|
||||
HANDLE_MEMORY_INST(27, Store , StoreInst )
|
||||
HANDLE_MEMORY_INST(28, GetElementPtr, GetElementPtrInst)
|
||||
LAST_MEMORY_INST(28)
|
||||
FIRST_MEMORY_INST(25)
|
||||
HANDLE_MEMORY_INST(25, Malloc, MallocInst) // Heap management instructions
|
||||
HANDLE_MEMORY_INST(26, Free , FreeInst )
|
||||
HANDLE_MEMORY_INST(27, Alloca, AllocaInst) // Stack management
|
||||
HANDLE_MEMORY_INST(28, Load , LoadInst ) // Memory manipulation instrs
|
||||
HANDLE_MEMORY_INST(29, Store , StoreInst )
|
||||
HANDLE_MEMORY_INST(30, GetElementPtr, GetElementPtrInst)
|
||||
LAST_MEMORY_INST(30)
|
||||
|
||||
// Other operators...
|
||||
FIRST_OTHER_INST(29)
|
||||
HANDLE_OTHER_INST(29, PHI , PHINode ) // PHI node instruction
|
||||
HANDLE_OTHER_INST(30, Cast , CastInst ) // Type cast
|
||||
HANDLE_OTHER_INST(31, Call , CallInst ) // Call a function
|
||||
HANDLE_OTHER_INST(32, Shl , ShiftInst ) // Shift operations
|
||||
HANDLE_OTHER_INST(33, Shr , ShiftInst )
|
||||
HANDLE_OTHER_INST(34, Select , SelectInst ) // select instruction
|
||||
HANDLE_OTHER_INST(35, UserOp1, Instruction) // May be used internally in a pass
|
||||
HANDLE_OTHER_INST(36, UserOp2, Instruction)
|
||||
HANDLE_OTHER_INST(37, VAArg , VAArgInst ) // vaarg instruction
|
||||
HANDLE_OTHER_INST(38, ExtractElement, ExtractElementInst)// extract from vector.
|
||||
HANDLE_OTHER_INST(39, InsertElement, InsertElementInst) // insert into vector
|
||||
HANDLE_OTHER_INST(40, ShuffleVector, ShuffleVectorInst) // shuffle two vectors.
|
||||
LAST_OTHER_INST(40)
|
||||
FIRST_OTHER_INST(31)
|
||||
HANDLE_OTHER_INST(31, PHI , PHINode ) // PHI node instruction
|
||||
HANDLE_OTHER_INST(32, Cast , CastInst ) // Type cast
|
||||
HANDLE_OTHER_INST(33, Call , CallInst ) // Call a function
|
||||
HANDLE_OTHER_INST(34, Shl , ShiftInst ) // Shift operations
|
||||
HANDLE_OTHER_INST(35, Shr , ShiftInst )
|
||||
HANDLE_OTHER_INST(36, Select , SelectInst ) // select instruction
|
||||
HANDLE_OTHER_INST(37, UserOp1, Instruction) // May be used internally in a pass
|
||||
HANDLE_OTHER_INST(38, UserOp2, Instruction)
|
||||
HANDLE_OTHER_INST(39, VAArg , VAArgInst ) // vaarg instruction
|
||||
HANDLE_OTHER_INST(40, ExtractElement, ExtractElementInst)// extract from vector.
|
||||
HANDLE_OTHER_INST(41, InsertElement, InsertElementInst) // insert into vector
|
||||
HANDLE_OTHER_INST(42, ShuffleVector, ShuffleVectorInst) // shuffle two vectors.
|
||||
LAST_OTHER_INST(42)
|
||||
|
||||
#undef FIRST_TERM_INST
|
||||
#undef HANDLE_TERM_INST
|
||||
|
@ -130,9 +130,21 @@ inline BinaryOp_match<LHS, RHS, Instruction::FDiv> m_FDiv(const LHS &L,
|
||||
}
|
||||
|
||||
template<typename LHS, typename RHS>
|
||||
inline BinaryOp_match<LHS, RHS, Instruction::Rem> m_Rem(const LHS &L,
|
||||
inline BinaryOp_match<LHS, RHS, Instruction::URem> m_URem(const LHS &L,
|
||||
const RHS &R) {
|
||||
return BinaryOp_match<LHS, RHS, Instruction::URem>(L, R);
|
||||
}
|
||||
|
||||
template<typename LHS, typename RHS>
|
||||
inline BinaryOp_match<LHS, RHS, Instruction::SRem> m_SRem(const LHS &L,
|
||||
const RHS &R) {
|
||||
return BinaryOp_match<LHS, RHS, Instruction::SRem>(L, R);
|
||||
}
|
||||
|
||||
template<typename LHS, typename RHS>
|
||||
inline BinaryOp_match<LHS, RHS, Instruction::FRem> m_FRem(const LHS &L,
|
||||
const RHS &R) {
|
||||
return BinaryOp_match<LHS, RHS, Instruction::Rem>(L, R);
|
||||
return BinaryOp_match<LHS, RHS, Instruction::FRem>(L, R);
|
||||
}
|
||||
|
||||
template<typename LHS, typename RHS>
|
||||
|
@ -2147,7 +2147,7 @@ SCEVHandle ScalarEvolutionsImpl::HowFarToZero(SCEV *V, const Loop *L) {
|
||||
if (SCEVConstant *StartC = dyn_cast<SCEVConstant>(Start)) {
|
||||
ConstantInt *StartCC = StartC->getValue();
|
||||
Constant *StartNegC = ConstantExpr::getNeg(StartCC);
|
||||
Constant *Rem = ConstantExpr::getRem(StartNegC, StepC->getValue());
|
||||
Constant *Rem = ConstantExpr::getSRem(StartNegC, StepC->getValue());
|
||||
if (Rem->isNullValue()) {
|
||||
Constant *Result =ConstantExpr::getSDiv(StartNegC,StepC->getValue());
|
||||
return SCEVUnknown::get(Result);
|
||||
|
@ -261,7 +261,10 @@ div { RET_TOK_OBSOLETE(BinaryOpVal, UDiv, UDIV); }
|
||||
udiv { RET_TOK(BinaryOpVal, UDiv, UDIV); }
|
||||
sdiv { RET_TOK(BinaryOpVal, SDiv, SDIV); }
|
||||
fdiv { RET_TOK(BinaryOpVal, FDiv, FDIV); }
|
||||
rem { RET_TOK(BinaryOpVal, Rem, REM); }
|
||||
rem { RET_TOK_OBSOLETE(BinaryOpVal, URem, UREM); }
|
||||
urem { RET_TOK(BinaryOpVal, URem, UREM); }
|
||||
srem { RET_TOK(BinaryOpVal, SRem, SREM); }
|
||||
frem { RET_TOK(BinaryOpVal, FRem, FREM); }
|
||||
and { RET_TOK(BinaryOpVal, And, AND); }
|
||||
or { RET_TOK(BinaryOpVal, Or , OR ); }
|
||||
xor { RET_TOK(BinaryOpVal, Xor, XOR); }
|
||||
|
@ -836,7 +836,7 @@ sanitizeOpCode(OpcodeInfo<Instruction::BinaryOps> &OI, const PATypeHolder& PATy)
|
||||
// Depending on the opcode ..
|
||||
switch (OI.opcode) {
|
||||
default:
|
||||
GenerateError("Invalid Obsolete OpCode");
|
||||
GenerateError("Invalid obsolete opCode (check Lexer.l)");
|
||||
break;
|
||||
case Instruction::UDiv:
|
||||
// Handle cases where the opcode needs to change
|
||||
@ -845,12 +845,17 @@ sanitizeOpCode(OpcodeInfo<Instruction::BinaryOps> &OI, const PATypeHolder& PATy)
|
||||
else if (Ty->isSigned())
|
||||
OI.opcode = Instruction::SDiv;
|
||||
break;
|
||||
case Instruction::URem:
|
||||
if (Ty->isFloatingPoint())
|
||||
OI.opcode = Instruction::FRem;
|
||||
else if (Ty->isSigned())
|
||||
OI.opcode = Instruction::SRem;
|
||||
break;
|
||||
}
|
||||
// Its not obsolete any more, we fixed it.
|
||||
OI.obsolete = false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// common code from the two 'RunVMAsmParser' functions
|
||||
static Module* RunParser(Module * M) {
|
||||
|
||||
@ -1113,7 +1118,7 @@ Module *llvm::RunVMAsmParser(const char * AsmString, Module * M) {
|
||||
|
||||
// Binary Operators
|
||||
%type <BinaryOpVal> ArithmeticOps LogicalOps SetCondOps // Binops Subcatagories
|
||||
%token <BinaryOpVal> ADD SUB MUL UDIV SDIV FDIV REM AND OR XOR
|
||||
%token <BinaryOpVal> ADD SUB MUL UDIV SDIV FDIV UREM SREM FREM AND OR XOR
|
||||
%token <BinaryOpVal> SETLE SETGE SETLT SETGT SETEQ SETNE // Binary Comparators
|
||||
|
||||
// Memory Instructions
|
||||
@ -1151,7 +1156,7 @@ EINT64VAL : EUINT64VAL {
|
||||
// Operations that are notably excluded from this list include:
|
||||
// RET, BR, & SWITCH because they end basic blocks and are treated specially.
|
||||
//
|
||||
ArithmeticOps: ADD | SUB | MUL | UDIV | SDIV | FDIV | REM ;
|
||||
ArithmeticOps: ADD | SUB | MUL | UDIV | SDIV | FDIV | UREM | SREM | FREM;
|
||||
LogicalOps : AND | OR | XOR;
|
||||
SetCondOps : SETLE | SETGE | SETLT | SETGT | SETEQ | SETNE;
|
||||
|
||||
@ -2465,8 +2470,11 @@ InstVal : ArithmeticOps Types ValueRef ',' ValueRef {
|
||||
!isa<PackedType>((*$2).get()))
|
||||
GEN_ERROR(
|
||||
"Arithmetic operator requires integer, FP, or packed operands!");
|
||||
if (isa<PackedType>((*$2).get()) && $1.opcode == Instruction::Rem)
|
||||
GEN_ERROR("Rem not supported on packed types!");
|
||||
if (isa<PackedType>((*$2).get()) &&
|
||||
($1.opcode == Instruction::URem ||
|
||||
$1.opcode == Instruction::SRem ||
|
||||
$1.opcode == Instruction::FRem))
|
||||
GEN_ERROR("U/S/FRem not supported on packed types!");
|
||||
// Upgrade the opcode from obsolete versions before we do anything with it.
|
||||
sanitizeOpCode($1,*$2);
|
||||
CHECK_FOR_ERROR;
|
||||
|
@ -652,7 +652,14 @@ BytecodeReader::handleObsoleteOpcodes(
|
||||
break;
|
||||
|
||||
case 11: // Rem
|
||||
Opcode = Instruction::Rem;
|
||||
// As with "Div", make the signed/unsigned or floating point Rem
|
||||
// instruction choice based on the type of the operands.
|
||||
if (iType == 10 || iType == 11)
|
||||
Opcode = Instruction::FRem;
|
||||
else if (iType >= 2 && iType <= 9 && iType % 2 != 0)
|
||||
Opcode = Instruction::SRem;
|
||||
else
|
||||
Opcode = Instruction::URem;
|
||||
break;
|
||||
case 12: // And
|
||||
Opcode = Instruction::And;
|
||||
@ -1654,18 +1661,16 @@ inline unsigned fixCEOpcodes(
|
||||
else
|
||||
Opcode = Instruction::UDiv;
|
||||
break;
|
||||
|
||||
case 11: // Rem
|
||||
// As with "Div", make the signed/unsigned Rem instruction choice based
|
||||
// on the type of the instruction.
|
||||
// As with "Div", make the signed/unsigned or floating point Rem
|
||||
// instruction choice based on the type of the operands.
|
||||
if (ArgVec[0]->getType()->isFloatingPoint())
|
||||
Opcode = Instruction::Rem;
|
||||
Opcode = Instruction::FRem;
|
||||
else if (ArgVec[0]->getType()->isSigned())
|
||||
Opcode = Instruction::Rem;
|
||||
Opcode = Instruction::SRem;
|
||||
else
|
||||
Opcode = Instruction::Rem;
|
||||
Opcode = Instruction::URem;
|
||||
break;
|
||||
|
||||
case 12: // And
|
||||
Opcode = Instruction::And;
|
||||
break;
|
||||
|
@ -528,16 +528,12 @@ public:
|
||||
else
|
||||
visitIntBinary(I, ISD::MUL, ISD::VMUL);
|
||||
}
|
||||
void visitURem(User &I) { visitIntBinary(I, ISD::UREM, 0); }
|
||||
void visitSRem(User &I) { visitIntBinary(I, ISD::SREM, 0); }
|
||||
void visitFRem(User &I) { visitFPBinary (I, ISD::FREM, 0); }
|
||||
void visitUDiv(User &I) { visitIntBinary(I, ISD::UDIV, ISD::VUDIV); }
|
||||
void visitSDiv(User &I) { visitIntBinary(I, ISD::SDIV, ISD::VSDIV); }
|
||||
void visitFDiv(User &I) { visitFPBinary(I, ISD::FDIV, ISD::VSDIV); }
|
||||
void visitRem(User &I) {
|
||||
const Type *Ty = I.getType();
|
||||
if (Ty->isFloatingPoint())
|
||||
visitFPBinary(I, ISD::FREM, 0);
|
||||
else
|
||||
visitIntBinary(I, Ty->isSigned() ? ISD::SREM : ISD::UREM, 0);
|
||||
}
|
||||
void visitFDiv(User &I) { visitFPBinary (I, ISD::FDIV, ISD::VSDIV); }
|
||||
void visitAnd(User &I) { visitIntBinary(I, ISD::AND, ISD::VAND); }
|
||||
void visitOr (User &I) { visitIntBinary(I, ISD::OR, ISD::VOR); }
|
||||
void visitXor(User &I) { visitIntBinary(I, ISD::XOR, ISD::VXOR); }
|
||||
|
@ -48,6 +48,12 @@ static GenericValue executeSDivInst(GenericValue Src1, GenericValue Src2,
|
||||
const Type *Ty);
|
||||
static GenericValue executeFDivInst(GenericValue Src1, GenericValue Src2,
|
||||
const Type *Ty);
|
||||
static GenericValue executeURemInst(GenericValue Src1, GenericValue Src2,
|
||||
const Type *Ty);
|
||||
static GenericValue executeSRemInst(GenericValue Src1, GenericValue Src2,
|
||||
const Type *Ty);
|
||||
static GenericValue executeFRemInst(GenericValue Src1, GenericValue Src2,
|
||||
const Type *Ty);
|
||||
static GenericValue executeAndInst(GenericValue Src1, GenericValue Src2,
|
||||
const Type *Ty);
|
||||
static GenericValue executeOrInst(GenericValue Src1, GenericValue Src2,
|
||||
@ -105,10 +111,18 @@ GenericValue Interpreter::getConstantExprValue (ConstantExpr *CE,
|
||||
return executeFDivInst(getOperandValue(CE->getOperand(0), SF),
|
||||
getOperandValue(CE->getOperand(1), SF),
|
||||
CE->getOperand(0)->getType());
|
||||
case Instruction::Rem:
|
||||
return executeRemInst(getOperandValue(CE->getOperand(0), SF),
|
||||
case Instruction::URem:
|
||||
return executeURemInst(getOperandValue(CE->getOperand(0), SF),
|
||||
getOperandValue(CE->getOperand(1), SF),
|
||||
CE->getOperand(0)->getType());
|
||||
case Instruction::SRem:
|
||||
return executeSRemInst(getOperandValue(CE->getOperand(0), SF),
|
||||
getOperandValue(CE->getOperand(1), SF),
|
||||
CE->getOperand(0)->getType());
|
||||
case Instruction::FRem:
|
||||
return executeFRemInst(getOperandValue(CE->getOperand(0), SF),
|
||||
getOperandValue(CE->getOperand(1), SF),
|
||||
CE->getOperand(0)->getType());
|
||||
case Instruction::And:
|
||||
return executeAndInst(getOperandValue(CE->getOperand(0), SF),
|
||||
getOperandValue(CE->getOperand(1), SF),
|
||||
@ -300,18 +314,40 @@ static GenericValue executeFDivInst(GenericValue Src1, GenericValue Src2,
|
||||
return Dest;
|
||||
}
|
||||
|
||||
static GenericValue executeRemInst(GenericValue Src1, GenericValue Src2,
|
||||
static GenericValue executeURemInst(GenericValue Src1, GenericValue Src2,
|
||||
const Type *Ty) {
|
||||
GenericValue Dest;
|
||||
switch (Ty->getTypeID()) {
|
||||
IMPLEMENT_SIGNLESS_BINOP(%, UByte, SByte);
|
||||
IMPLEMENT_SIGNLESS_BINOP(%, UShort, Short);
|
||||
IMPLEMENT_SIGNLESS_BINOP(%, UInt, Int);
|
||||
IMPLEMENT_SIGNLESS_BINOP(%, ULong, Long);
|
||||
default:
|
||||
std::cout << "Unhandled type for URem instruction: " << *Ty << "\n";
|
||||
abort();
|
||||
}
|
||||
return Dest;
|
||||
}
|
||||
|
||||
static GenericValue executeSRemInst(GenericValue Src1, GenericValue Src2,
|
||||
const Type *Ty) {
|
||||
GenericValue Dest;
|
||||
switch (Ty->getTypeID()) {
|
||||
IMPLEMENT_SIGNLESS_BINOP(%, SByte, UByte);
|
||||
IMPLEMENT_SIGNLESS_BINOP(%, Short, UShort);
|
||||
IMPLEMENT_SIGNLESS_BINOP(%, Int, UInt);
|
||||
IMPLEMENT_SIGNLESS_BINOP(%, Long, ULong);
|
||||
default:
|
||||
std::cout << "Unhandled type for Rem instruction: " << *Ty << "\n";
|
||||
abort();
|
||||
}
|
||||
return Dest;
|
||||
}
|
||||
|
||||
static GenericValue executeFRemInst(GenericValue Src1, GenericValue Src2,
|
||||
const Type *Ty) {
|
||||
GenericValue Dest;
|
||||
switch (Ty->getTypeID()) {
|
||||
IMPLEMENT_BINARY_OPERATOR(%, UByte);
|
||||
IMPLEMENT_BINARY_OPERATOR(%, SByte);
|
||||
IMPLEMENT_BINARY_OPERATOR(%, UShort);
|
||||
IMPLEMENT_BINARY_OPERATOR(%, Short);
|
||||
IMPLEMENT_BINARY_OPERATOR(%, UInt);
|
||||
IMPLEMENT_BINARY_OPERATOR(%, Int);
|
||||
IMPLEMENT_BINARY_OPERATOR(%, ULong);
|
||||
IMPLEMENT_BINARY_OPERATOR(%, Long);
|
||||
case Type::FloatTyID:
|
||||
Dest.FloatVal = fmod(Src1.FloatVal, Src2.FloatVal);
|
||||
break;
|
||||
@ -544,7 +580,9 @@ void Interpreter::visitBinaryOperator(BinaryOperator &I) {
|
||||
case Instruction::UDiv: R = executeUDivInst (Src1, Src2, Ty); break;
|
||||
case Instruction::SDiv: R = executeSDivInst (Src1, Src2, Ty); break;
|
||||
case Instruction::FDiv: R = executeFDivInst (Src1, Src2, Ty); break;
|
||||
case Instruction::Rem: R = executeRemInst (Src1, Src2, Ty); break;
|
||||
case Instruction::URem: R = executeURemInst (Src1, Src2, Ty); break;
|
||||
case Instruction::SRem: R = executeSRemInst (Src1, Src2, Ty); break;
|
||||
case Instruction::FRem: R = executeFRemInst (Src1, Src2, Ty); break;
|
||||
case Instruction::And: R = executeAndInst (Src1, Src2, Ty); break;
|
||||
case Instruction::Or: R = executeOrInst (Src1, Src2, Ty); break;
|
||||
case Instruction::Xor: R = executeXorInst (Src1, Src2, Ty); break;
|
||||
|
@ -593,7 +593,9 @@ void CWriter::printConstant(Constant *CPV) {
|
||||
case Instruction::SDiv:
|
||||
case Instruction::UDiv:
|
||||
case Instruction::FDiv:
|
||||
case Instruction::Rem:
|
||||
case Instruction::URem:
|
||||
case Instruction::SRem:
|
||||
case Instruction::FRem:
|
||||
case Instruction::And:
|
||||
case Instruction::Or:
|
||||
case Instruction::Xor:
|
||||
@ -613,10 +615,12 @@ void CWriter::printConstant(Constant *CPV) {
|
||||
case Instruction::Add: Out << " + "; break;
|
||||
case Instruction::Sub: Out << " - "; break;
|
||||
case Instruction::Mul: Out << " * "; break;
|
||||
case Instruction::URem:
|
||||
case Instruction::SRem:
|
||||
case Instruction::FRem: 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;
|
||||
case Instruction::Xor: Out << " ^ "; break;
|
||||
@ -825,8 +829,12 @@ 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;
|
||||
case Instruction::UDiv:
|
||||
case Instruction::URem:
|
||||
Result = Ty->isSigned(); break;
|
||||
case Instruction::SDiv:
|
||||
case Instruction::SRem:
|
||||
Result = Ty->isUnsigned(); break;
|
||||
default: break;
|
||||
}
|
||||
if (Result) {
|
||||
@ -856,13 +864,16 @@ void CWriter::printConstantWithCast(Constant* CPV, unsigned Opcode) {
|
||||
// for most instructions, it doesn't matter
|
||||
break;
|
||||
case Instruction::UDiv:
|
||||
// For UDiv to have unsigned operands
|
||||
case Instruction::URem:
|
||||
// For UDiv/URem get correct type
|
||||
if (OpTy->isSigned()) {
|
||||
OpTy = OpTy->getUnsignedVersion();
|
||||
shouldCast = true;
|
||||
}
|
||||
break;
|
||||
case Instruction::SDiv:
|
||||
case Instruction::SRem:
|
||||
// For SDiv/SRem get correct type
|
||||
if (OpTy->isUnsigned()) {
|
||||
OpTy = OpTy->getSignedVersion();
|
||||
shouldCast = true;
|
||||
@ -919,8 +930,12 @@ 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;
|
||||
case Instruction::UDiv:
|
||||
case Instruction::URem:
|
||||
Result = Ty->isSigned(); break;
|
||||
case Instruction::SDiv:
|
||||
case Instruction::SRem:
|
||||
Result = Ty->isUnsigned(); break;
|
||||
default: break;
|
||||
}
|
||||
if (Result) {
|
||||
@ -950,6 +965,7 @@ void CWriter::writeOperandWithCast(Value* Operand, unsigned Opcode) {
|
||||
// for most instructions, it doesn't matter
|
||||
break;
|
||||
case Instruction::UDiv:
|
||||
case Instruction::URem:
|
||||
// For UDiv to have unsigned operands
|
||||
if (OpTy->isSigned()) {
|
||||
OpTy = OpTy->getUnsignedVersion();
|
||||
@ -957,6 +973,7 @@ void CWriter::writeOperandWithCast(Value* Operand, unsigned Opcode) {
|
||||
}
|
||||
break;
|
||||
case Instruction::SDiv:
|
||||
case Instruction::SRem:
|
||||
if (OpTy->isUnsigned()) {
|
||||
OpTy = OpTy->getSignedVersion();
|
||||
shouldCast = true;
|
||||
@ -1774,8 +1791,7 @@ void CWriter::visitBinaryOperator(Instruction &I) {
|
||||
Out << "-(";
|
||||
writeOperand(BinaryOperator::getNegArgument(cast<BinaryOperator>(&I)));
|
||||
Out << ")";
|
||||
} else if (I.getOpcode() == Instruction::Rem &&
|
||||
I.getType()->isFloatingPoint()) {
|
||||
} else if (I.getOpcode() == Instruction::FRem) {
|
||||
// Output a call to fmod/fmodf instead of emitting a%b
|
||||
if (I.getType() == Type::FloatTy)
|
||||
Out << "fmodf(";
|
||||
@ -1800,10 +1816,12 @@ void CWriter::visitBinaryOperator(Instruction &I) {
|
||||
case Instruction::Add: Out << " + "; break;
|
||||
case Instruction::Sub: Out << " - "; break;
|
||||
case Instruction::Mul: Out << '*'; break;
|
||||
case Instruction::URem:
|
||||
case Instruction::SRem:
|
||||
case Instruction::FRem: 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;
|
||||
case Instruction::Xor: Out << " ^ "; break;
|
||||
|
@ -593,7 +593,9 @@ void CWriter::printConstant(Constant *CPV) {
|
||||
case Instruction::SDiv:
|
||||
case Instruction::UDiv:
|
||||
case Instruction::FDiv:
|
||||
case Instruction::Rem:
|
||||
case Instruction::URem:
|
||||
case Instruction::SRem:
|
||||
case Instruction::FRem:
|
||||
case Instruction::And:
|
||||
case Instruction::Or:
|
||||
case Instruction::Xor:
|
||||
@ -613,10 +615,12 @@ void CWriter::printConstant(Constant *CPV) {
|
||||
case Instruction::Add: Out << " + "; break;
|
||||
case Instruction::Sub: Out << " - "; break;
|
||||
case Instruction::Mul: Out << " * "; break;
|
||||
case Instruction::URem:
|
||||
case Instruction::SRem:
|
||||
case Instruction::FRem: 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;
|
||||
case Instruction::Xor: Out << " ^ "; break;
|
||||
@ -825,8 +829,12 @@ 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;
|
||||
case Instruction::UDiv:
|
||||
case Instruction::URem:
|
||||
Result = Ty->isSigned(); break;
|
||||
case Instruction::SDiv:
|
||||
case Instruction::SRem:
|
||||
Result = Ty->isUnsigned(); break;
|
||||
default: break;
|
||||
}
|
||||
if (Result) {
|
||||
@ -856,13 +864,16 @@ void CWriter::printConstantWithCast(Constant* CPV, unsigned Opcode) {
|
||||
// for most instructions, it doesn't matter
|
||||
break;
|
||||
case Instruction::UDiv:
|
||||
// For UDiv to have unsigned operands
|
||||
case Instruction::URem:
|
||||
// For UDiv/URem get correct type
|
||||
if (OpTy->isSigned()) {
|
||||
OpTy = OpTy->getUnsignedVersion();
|
||||
shouldCast = true;
|
||||
}
|
||||
break;
|
||||
case Instruction::SDiv:
|
||||
case Instruction::SRem:
|
||||
// For SDiv/SRem get correct type
|
||||
if (OpTy->isUnsigned()) {
|
||||
OpTy = OpTy->getSignedVersion();
|
||||
shouldCast = true;
|
||||
@ -919,8 +930,12 @@ 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;
|
||||
case Instruction::UDiv:
|
||||
case Instruction::URem:
|
||||
Result = Ty->isSigned(); break;
|
||||
case Instruction::SDiv:
|
||||
case Instruction::SRem:
|
||||
Result = Ty->isUnsigned(); break;
|
||||
default: break;
|
||||
}
|
||||
if (Result) {
|
||||
@ -950,6 +965,7 @@ void CWriter::writeOperandWithCast(Value* Operand, unsigned Opcode) {
|
||||
// for most instructions, it doesn't matter
|
||||
break;
|
||||
case Instruction::UDiv:
|
||||
case Instruction::URem:
|
||||
// For UDiv to have unsigned operands
|
||||
if (OpTy->isSigned()) {
|
||||
OpTy = OpTy->getUnsignedVersion();
|
||||
@ -957,6 +973,7 @@ void CWriter::writeOperandWithCast(Value* Operand, unsigned Opcode) {
|
||||
}
|
||||
break;
|
||||
case Instruction::SDiv:
|
||||
case Instruction::SRem:
|
||||
if (OpTy->isUnsigned()) {
|
||||
OpTy = OpTy->getSignedVersion();
|
||||
shouldCast = true;
|
||||
@ -1774,8 +1791,7 @@ void CWriter::visitBinaryOperator(Instruction &I) {
|
||||
Out << "-(";
|
||||
writeOperand(BinaryOperator::getNegArgument(cast<BinaryOperator>(&I)));
|
||||
Out << ")";
|
||||
} else if (I.getOpcode() == Instruction::Rem &&
|
||||
I.getType()->isFloatingPoint()) {
|
||||
} else if (I.getOpcode() == Instruction::FRem) {
|
||||
// Output a call to fmod/fmodf instead of emitting a%b
|
||||
if (I.getType() == Type::FloatTy)
|
||||
Out << "fmodf(";
|
||||
@ -1800,10 +1816,12 @@ void CWriter::visitBinaryOperator(Instruction &I) {
|
||||
case Instruction::Add: Out << " + "; break;
|
||||
case Instruction::Sub: Out << " - "; break;
|
||||
case Instruction::Mul: Out << '*'; break;
|
||||
case Instruction::URem:
|
||||
case Instruction::SRem:
|
||||
case Instruction::FRem: 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;
|
||||
case Instruction::Xor: Out << " ^ "; break;
|
||||
|
@ -131,12 +131,16 @@ namespace {
|
||||
Instruction *visitAdd(BinaryOperator &I);
|
||||
Instruction *visitSub(BinaryOperator &I);
|
||||
Instruction *visitMul(BinaryOperator &I);
|
||||
Instruction *visitURem(BinaryOperator &I);
|
||||
Instruction *visitSRem(BinaryOperator &I);
|
||||
Instruction *visitFRem(BinaryOperator &I);
|
||||
Instruction *commonRemTransforms(BinaryOperator &I);
|
||||
Instruction *commonIRemTransforms(BinaryOperator &I);
|
||||
Instruction *commonDivTransforms(BinaryOperator &I);
|
||||
Instruction *commonIDivTransforms(BinaryOperator &I);
|
||||
Instruction *visitUDiv(BinaryOperator &I);
|
||||
Instruction *visitSDiv(BinaryOperator &I);
|
||||
Instruction *visitFDiv(BinaryOperator &I);
|
||||
Instruction *visitRem(BinaryOperator &I);
|
||||
Instruction *visitAnd(BinaryOperator &I);
|
||||
Instruction *visitOr (BinaryOperator &I);
|
||||
Instruction *visitXor(BinaryOperator &I);
|
||||
@ -2412,9 +2416,13 @@ static Constant *GetFactor(Value *V) {
|
||||
return Result;
|
||||
}
|
||||
|
||||
Instruction *InstCombiner::visitRem(BinaryOperator &I) {
|
||||
/// This function implements the transforms on rem instructions that work
|
||||
/// regardless of the kind of rem instruction it is (urem, srem, or frem). It
|
||||
/// is used by the visitors to those instructions.
|
||||
/// @brief Transforms common to all three rem instructions
|
||||
Instruction *InstCombiner::commonRemTransforms(BinaryOperator &I) {
|
||||
Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1);
|
||||
|
||||
|
||||
// 0 % X == 0, we don't need to preserve faults!
|
||||
if (Constant *LHS = dyn_cast<Constant>(Op0))
|
||||
if (LHS->isNullValue())
|
||||
@ -2424,34 +2432,52 @@ Instruction *InstCombiner::visitRem(BinaryOperator &I) {
|
||||
return ReplaceInstUsesWith(I, Constant::getNullValue(I.getType()));
|
||||
if (isa<UndefValue>(Op1))
|
||||
return ReplaceInstUsesWith(I, Op1); // X % undef -> undef
|
||||
|
||||
if (I.getType()->isSigned()) {
|
||||
if (Value *RHSNeg = dyn_castNegVal(Op1))
|
||||
if (!isa<ConstantInt>(RHSNeg) || !RHSNeg->getType()->isSigned() ||
|
||||
cast<ConstantInt>(RHSNeg)->getSExtValue() > 0) {
|
||||
// X % -Y -> X % Y
|
||||
AddUsesToWorkList(I);
|
||||
I.setOperand(1, RHSNeg);
|
||||
|
||||
// Handle cases involving: rem X, (select Cond, Y, Z)
|
||||
if (SelectInst *SI = dyn_cast<SelectInst>(Op1)) {
|
||||
// rem X, (Cond ? 0 : Y) -> rem X, Y. If the rem and the select are in
|
||||
// the same basic block, then we replace the select with Y, and the
|
||||
// condition of the select with false (if the cond value is in the same
|
||||
// BB). If the select has uses other than the div, this allows them to be
|
||||
// simplified also.
|
||||
if (Constant *ST = dyn_cast<Constant>(SI->getOperand(1)))
|
||||
if (ST->isNullValue()) {
|
||||
Instruction *CondI = dyn_cast<Instruction>(SI->getOperand(0));
|
||||
if (CondI && CondI->getParent() == I.getParent())
|
||||
UpdateValueUsesWith(CondI, ConstantBool::getFalse());
|
||||
else if (I.getParent() != SI->getParent() || SI->hasOneUse())
|
||||
I.setOperand(1, SI->getOperand(2));
|
||||
else
|
||||
UpdateValueUsesWith(SI, SI->getOperand(2));
|
||||
return &I;
|
||||
}
|
||||
// Likewise for: rem X, (Cond ? Y : 0) -> rem X, Y
|
||||
if (Constant *ST = dyn_cast<Constant>(SI->getOperand(2)))
|
||||
if (ST->isNullValue()) {
|
||||
Instruction *CondI = dyn_cast<Instruction>(SI->getOperand(0));
|
||||
if (CondI && CondI->getParent() == I.getParent())
|
||||
UpdateValueUsesWith(CondI, ConstantBool::getTrue());
|
||||
else if (I.getParent() != SI->getParent() || SI->hasOneUse())
|
||||
I.setOperand(1, SI->getOperand(1));
|
||||
else
|
||||
UpdateValueUsesWith(SI, SI->getOperand(1));
|
||||
return &I;
|
||||
}
|
||||
|
||||
// If the top bits of both operands are zero (i.e. we can prove they are
|
||||
// unsigned inputs), turn this into a urem.
|
||||
uint64_t Mask = 1ULL << (I.getType()->getPrimitiveSizeInBits()-1);
|
||||
if (MaskedValueIsZero(Op1, Mask) && MaskedValueIsZero(Op0, Mask)) {
|
||||
const Type *NTy = Op0->getType()->getUnsignedVersion();
|
||||
Value *LHS = InsertCastBefore(Op0, NTy, I);
|
||||
Value *RHS;
|
||||
if (Constant *R = dyn_cast<Constant>(Op1))
|
||||
RHS = ConstantExpr::getCast(R, NTy);
|
||||
else
|
||||
RHS = InsertCastBefore(Op1, NTy, I);
|
||||
Instruction *Rem = BinaryOperator::createRem(LHS, RHS, I.getName());
|
||||
InsertNewInstBefore(Rem, I);
|
||||
return new CastInst(Rem, I.getType());
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// This function implements the transforms common to both integer remainder
|
||||
/// instructions (urem and srem). It is called by the visitors to those integer
|
||||
/// remainder instructions.
|
||||
/// @brief Common integer remainder transforms
|
||||
Instruction *InstCombiner::commonIRemTransforms(BinaryOperator &I) {
|
||||
Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1);
|
||||
|
||||
if (Instruction *common = commonRemTransforms(I))
|
||||
return common;
|
||||
|
||||
if (ConstantInt *RHS = dyn_cast<ConstantInt>(Op1)) {
|
||||
// X % 0 == undef, we don't need to preserve faults!
|
||||
if (RHS->equalsInt(0))
|
||||
@ -2460,13 +2486,6 @@ Instruction *InstCombiner::visitRem(BinaryOperator &I) {
|
||||
if (RHS->equalsInt(1)) // X % 1 == 0
|
||||
return ReplaceInstUsesWith(I, Constant::getNullValue(I.getType()));
|
||||
|
||||
// Check to see if this is an unsigned remainder with an exact power of 2,
|
||||
// if so, convert to a bitwise and.
|
||||
if (ConstantInt *C = dyn_cast<ConstantInt>(RHS))
|
||||
if (RHS->getType()->isUnsigned())
|
||||
if (isPowerOf2_64(C->getZExtValue()))
|
||||
return BinaryOperator::createAnd(Op0, SubOne(C));
|
||||
|
||||
if (Instruction *Op0I = dyn_cast<Instruction>(Op0)) {
|
||||
if (SelectInst *SI = dyn_cast<SelectInst>(Op0I)) {
|
||||
if (Instruction *R = FoldOpIntoSelect(I, SI, this))
|
||||
@ -2475,19 +2494,34 @@ Instruction *InstCombiner::visitRem(BinaryOperator &I) {
|
||||
if (Instruction *NV = FoldOpIntoPhi(I))
|
||||
return NV;
|
||||
}
|
||||
|
||||
// X*C1%C2 --> 0 iff C1%C2 == 0
|
||||
if (ConstantExpr::getRem(GetFactor(Op0I), RHS)->isNullValue())
|
||||
// (X * C1) % C2 --> 0 iff C1 % C2 == 0
|
||||
if (ConstantExpr::getSRem(GetFactor(Op0I), RHS)->isNullValue())
|
||||
return ReplaceInstUsesWith(I, Constant::getNullValue(I.getType()));
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Instruction *InstCombiner::visitURem(BinaryOperator &I) {
|
||||
Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1);
|
||||
|
||||
if (Instruction *common = commonIRemTransforms(I))
|
||||
return common;
|
||||
|
||||
if (ConstantInt *RHS = dyn_cast<ConstantInt>(Op1)) {
|
||||
// X urem C^2 -> X and C
|
||||
// Check to see if this is an unsigned remainder with an exact power of 2,
|
||||
// if so, convert to a bitwise and.
|
||||
if (ConstantInt *C = dyn_cast<ConstantInt>(RHS))
|
||||
if (isPowerOf2_64(C->getZExtValue()))
|
||||
return BinaryOperator::createAnd(Op0, SubOne(C));
|
||||
}
|
||||
|
||||
if (Instruction *RHSI = dyn_cast<Instruction>(I.getOperand(1))) {
|
||||
// Turn A % (C << N), where C is 2^k, into A & ((C << N)-1) [urem only].
|
||||
if (I.getType()->isUnsigned() &&
|
||||
RHSI->getOpcode() == Instruction::Shl &&
|
||||
isa<ConstantInt>(RHSI->getOperand(0)) &&
|
||||
RHSI->getOperand(0)->getType()->isUnsigned()) {
|
||||
// Turn A % (C << N), where C is 2^k, into A & ((C << N)-1)
|
||||
if (RHSI->getOpcode() == Instruction::Shl &&
|
||||
isa<ConstantInt>(RHSI->getOperand(0))) {
|
||||
unsigned C1 = cast<ConstantInt>(RHSI->getOperand(0))->getZExtValue();
|
||||
if (isPowerOf2_64(C1)) {
|
||||
Constant *N1 = ConstantInt::getAllOnesValue(I.getType());
|
||||
@ -2496,61 +2530,60 @@ Instruction *InstCombiner::visitRem(BinaryOperator &I) {
|
||||
return BinaryOperator::createAnd(Op0, Add);
|
||||
}
|
||||
}
|
||||
|
||||
// If this is 'urem X, (Cond ? C1, C2)' where C1&C2 are powers of two,
|
||||
// transform this into: '(Cond ? (urem X, C1) : (urem X, C2))'.
|
||||
if (SelectInst *SI = dyn_cast<SelectInst>(Op1)) {
|
||||
// rem X, (Cond ? 0 : Y) -> rem X, Y. If the rem and the select are in
|
||||
// the same basic block, then we replace the select with Y, and the
|
||||
// condition of the select with false (if the cond value is in the same
|
||||
// BB). If the select has uses other than the div, this allows them to be
|
||||
// simplified also.
|
||||
if (Constant *ST = dyn_cast<Constant>(SI->getOperand(1)))
|
||||
if (ST->isNullValue()) {
|
||||
Instruction *CondI = dyn_cast<Instruction>(SI->getOperand(0));
|
||||
if (CondI && CondI->getParent() == I.getParent())
|
||||
UpdateValueUsesWith(CondI, ConstantBool::getFalse());
|
||||
else if (I.getParent() != SI->getParent() || SI->hasOneUse())
|
||||
I.setOperand(1, SI->getOperand(2));
|
||||
else
|
||||
UpdateValueUsesWith(SI, SI->getOperand(2));
|
||||
return &I;
|
||||
}
|
||||
// Likewise for: rem X, (Cond ? Y : 0) -> rem X, Y
|
||||
if (Constant *ST = dyn_cast<Constant>(SI->getOperand(2)))
|
||||
if (ST->isNullValue()) {
|
||||
Instruction *CondI = dyn_cast<Instruction>(SI->getOperand(0));
|
||||
if (CondI && CondI->getParent() == I.getParent())
|
||||
UpdateValueUsesWith(CondI, ConstantBool::getTrue());
|
||||
else if (I.getParent() != SI->getParent() || SI->hasOneUse())
|
||||
I.setOperand(1, SI->getOperand(1));
|
||||
else
|
||||
UpdateValueUsesWith(SI, SI->getOperand(1));
|
||||
return &I;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (ConstantInt *STO = dyn_cast<ConstantInt>(SI->getOperand(1)))
|
||||
if (ConstantInt *SFO = dyn_cast<ConstantInt>(SI->getOperand(2)))
|
||||
if (STO->getType()->isUnsigned() && SFO->getType()->isUnsigned()) {
|
||||
// STO == 0 and SFO == 0 handled above.
|
||||
if (isPowerOf2_64(STO->getZExtValue()) &&
|
||||
isPowerOf2_64(SFO->getZExtValue())) {
|
||||
Value *TrueAnd = InsertNewInstBefore(
|
||||
BinaryOperator::createAnd(Op0, SubOne(STO), SI->getName()+".t"),
|
||||
I);
|
||||
Value *FalseAnd = InsertNewInstBefore(
|
||||
BinaryOperator::createAnd(Op0, SubOne(SFO), SI->getName()+".f"),
|
||||
I);
|
||||
return new SelectInst(SI->getOperand(0), TrueAnd, FalseAnd);
|
||||
}
|
||||
}
|
||||
}
|
||||
// urem X, (select Cond, 2^C1, 2^C2) --> select Cond, (and X, C1), (and X, C2)
|
||||
// where C1&C2 are powers of two.
|
||||
if (SelectInst *SI = dyn_cast<SelectInst>(Op1)) {
|
||||
if (ConstantInt *STO = dyn_cast<ConstantInt>(SI->getOperand(1)))
|
||||
if (ConstantInt *SFO = dyn_cast<ConstantInt>(SI->getOperand(2))) {
|
||||
// STO == 0 and SFO == 0 handled above.
|
||||
if (isPowerOf2_64(STO->getZExtValue()) &&
|
||||
isPowerOf2_64(SFO->getZExtValue())) {
|
||||
Value *TrueAnd = InsertNewInstBefore(
|
||||
BinaryOperator::createAnd(Op0, SubOne(STO), SI->getName()+".t"), I);
|
||||
Value *FalseAnd = InsertNewInstBefore(
|
||||
BinaryOperator::createAnd(Op0, SubOne(SFO), SI->getName()+".f"), I);
|
||||
return new SelectInst(SI->getOperand(0), TrueAnd, FalseAnd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Instruction *InstCombiner::visitSRem(BinaryOperator &I) {
|
||||
Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1);
|
||||
|
||||
if (Instruction *common = commonIRemTransforms(I))
|
||||
return common;
|
||||
|
||||
if (Value *RHSNeg = dyn_castNegVal(Op1))
|
||||
if (!isa<ConstantInt>(RHSNeg) ||
|
||||
cast<ConstantInt>(RHSNeg)->getSExtValue() > 0) {
|
||||
// X % -Y -> X % Y
|
||||
AddUsesToWorkList(I);
|
||||
I.setOperand(1, RHSNeg);
|
||||
return &I;
|
||||
}
|
||||
|
||||
// If the top bits of both operands are zero (i.e. we can prove they are
|
||||
// unsigned inputs), turn this into a urem.
|
||||
uint64_t Mask = 1ULL << (I.getType()->getPrimitiveSizeInBits()-1);
|
||||
if (MaskedValueIsZero(Op1, Mask) && MaskedValueIsZero(Op0, Mask)) {
|
||||
// X srem Y -> X urem Y, iff X and Y don't have sign bit set
|
||||
return BinaryOperator::createURem(Op0, Op1, I.getName());
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Instruction *InstCombiner::visitFRem(BinaryOperator &I) {
|
||||
Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1);
|
||||
|
||||
return commonRemTransforms(I);
|
||||
}
|
||||
|
||||
// isMaxValueMinusOne - return true if this is Max-1
|
||||
static bool isMaxValueMinusOne(const ConstantInt *C) {
|
||||
if (C->getType()->isUnsigned())
|
||||
@ -4568,40 +4601,16 @@ Instruction *InstCombiner::visitSetCondInst(SetCondInst &I) {
|
||||
// the second operand is a constant, simplify a bit.
|
||||
if (BinaryOperator *BO = dyn_cast<BinaryOperator>(Op0)) {
|
||||
switch (BO->getOpcode()) {
|
||||
#if 0
|
||||
case Instruction::SRem:
|
||||
// If we have a signed (X % (2^c)) == 0, turn it into an unsigned one.
|
||||
if (CI->isNullValue() && isa<ConstantInt>(BO->getOperand(1)) &&
|
||||
BO->hasOneUse()) {
|
||||
int64_t V = cast<ConstantInt>(BO->getOperand(1))->getSExtValue();
|
||||
if (V > 1 && isPowerOf2_64(V)) {
|
||||
Value *NewRem = InsertNewInstBefore(
|
||||
BinaryOperator::createURem(BO->getOperand(0),
|
||||
BO->getOperand(1),
|
||||
BO->getName()), I);
|
||||
return BinaryOperator::create(
|
||||
I.getOpcode(), NewRem,
|
||||
Constant::getNullValue(NewRem->getType()));
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
case Instruction::Rem:
|
||||
// If we have a signed (X % (2^c)) == 0, turn it into an unsigned one.
|
||||
if (CI->isNullValue() && isa<ConstantInt>(BO->getOperand(1)) &&
|
||||
BO->hasOneUse() && BO->getOperand(1)->getType()->isSigned()) {
|
||||
int64_t V = cast<ConstantInt>(BO->getOperand(1))->getSExtValue();
|
||||
if (V > 1 && isPowerOf2_64(V)) {
|
||||
unsigned L2 = Log2_64(V);
|
||||
const Type *UTy = BO->getType()->getUnsignedVersion();
|
||||
Value *NewX = InsertNewInstBefore(new CastInst(BO->getOperand(0),
|
||||
UTy, "tmp"), I);
|
||||
Constant *RHSCst = ConstantInt::get(UTy, 1ULL << L2);
|
||||
Value *NewRem =InsertNewInstBefore(BinaryOperator::createRem(NewX,
|
||||
RHSCst, BO->getName()), I);
|
||||
Value *NewRem = InsertNewInstBefore(BinaryOperator::createURem(
|
||||
BO->getOperand(0), BO->getOperand(1), BO->getName()), I);
|
||||
return BinaryOperator::create(I.getOpcode(), NewRem,
|
||||
Constant::getNullValue(UTy));
|
||||
Constant::getNullValue(BO->getType()));
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -5766,6 +5775,8 @@ Instruction *InstCombiner::visitCastInst(CastInst &CI) {
|
||||
break;
|
||||
case Instruction::SDiv:
|
||||
case Instruction::UDiv:
|
||||
case Instruction::SRem:
|
||||
case Instruction::URem:
|
||||
// If we are just changing the sign, rewrite.
|
||||
if (DestBitSize == SrcBitSize) {
|
||||
// Don't insert two casts if they cannot be eliminated. We allow two
|
||||
|
@ -788,10 +788,12 @@ void PredicateSimplifier::Forwards::visitBinaryOperator(BinaryOperator &BO) {
|
||||
Instruction::BinaryOps ops = BO.getOpcode();
|
||||
|
||||
switch (ops) {
|
||||
case Instruction::URem:
|
||||
case Instruction::SRem:
|
||||
case Instruction::UDiv:
|
||||
case Instruction::SDiv:
|
||||
case Instruction::FDiv:
|
||||
case Instruction::Rem: {
|
||||
case Instruction::FRem: {
|
||||
Value *Divisor = BO.getOperand(1);
|
||||
KP.addNotEqual(Constant::getNullValue(Divisor->getType()), Divisor);
|
||||
break;
|
||||
|
@ -116,7 +116,9 @@ static bool isUnmovableInstruction(Instruction *I) {
|
||||
I->getOpcode() == Instruction::UDiv ||
|
||||
I->getOpcode() == Instruction::SDiv ||
|
||||
I->getOpcode() == Instruction::FDiv ||
|
||||
I->getOpcode() == Instruction::Rem)
|
||||
I->getOpcode() == Instruction::URem ||
|
||||
I->getOpcode() == Instruction::SRem ||
|
||||
I->getOpcode() == Instruction::FRem)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
@ -40,10 +40,12 @@ namespace {
|
||||
virtual Constant *add(const Constant *V1, const Constant *V2) const = 0;
|
||||
virtual Constant *sub(const Constant *V1, const Constant *V2) const = 0;
|
||||
virtual Constant *mul(const Constant *V1, const Constant *V2) const = 0;
|
||||
virtual Constant *urem(const Constant *V1, const Constant *V2) const = 0;
|
||||
virtual Constant *srem(const Constant *V1, const Constant *V2) const = 0;
|
||||
virtual Constant *frem(const Constant *V1, const Constant *V2) const = 0;
|
||||
virtual Constant *udiv(const Constant *V1, const Constant *V2) const = 0;
|
||||
virtual Constant *sdiv(const Constant *V1, const Constant *V2) const = 0;
|
||||
virtual Constant *fdiv(const Constant *V1, const Constant *V2) const = 0;
|
||||
virtual Constant *rem(const Constant *V1, const Constant *V2) const = 0;
|
||||
virtual Constant *op_and(const Constant *V1, const Constant *V2) const = 0;
|
||||
virtual Constant *op_or (const Constant *V1, const Constant *V2) const = 0;
|
||||
virtual Constant *op_xor(const Constant *V1, const Constant *V2) const = 0;
|
||||
@ -117,8 +119,14 @@ class VISIBILITY_HIDDEN TemplateRules : public ConstRules {
|
||||
virtual Constant *fdiv(const Constant *V1, const Constant *V2) const {
|
||||
return SubClassName::FDiv((const ArgType *)V1, (const ArgType *)V2);
|
||||
}
|
||||
virtual Constant *rem(const Constant *V1, const Constant *V2) const {
|
||||
return SubClassName::Rem((const ArgType *)V1, (const ArgType *)V2);
|
||||
virtual Constant *urem(const Constant *V1, const Constant *V2) const {
|
||||
return SubClassName::URem((const ArgType *)V1, (const ArgType *)V2);
|
||||
}
|
||||
virtual Constant *srem(const Constant *V1, const Constant *V2) const {
|
||||
return SubClassName::SRem((const ArgType *)V1, (const ArgType *)V2);
|
||||
}
|
||||
virtual Constant *frem(const Constant *V1, const Constant *V2) const {
|
||||
return SubClassName::FRem((const ArgType *)V1, (const ArgType *)V2);
|
||||
}
|
||||
virtual Constant *op_and(const Constant *V1, const Constant *V2) const {
|
||||
return SubClassName::And((const ArgType *)V1, (const ArgType *)V2);
|
||||
@ -192,7 +200,9 @@ class VISIBILITY_HIDDEN TemplateRules : public ConstRules {
|
||||
static Constant *SDiv(const ArgType *V1, const ArgType *V2) { return 0; }
|
||||
static Constant *UDiv(const ArgType *V1, const ArgType *V2) { return 0; }
|
||||
static Constant *FDiv(const ArgType *V1, const ArgType *V2) { return 0; }
|
||||
static Constant *Rem (const ArgType *V1, const ArgType *V2) { return 0; }
|
||||
static Constant *URem(const ArgType *V1, const ArgType *V2) { return 0; }
|
||||
static Constant *SRem(const ArgType *V1, const ArgType *V2) { return 0; }
|
||||
static Constant *FRem(const ArgType *V1, const ArgType *V2) { return 0; }
|
||||
static Constant *And (const ArgType *V1, const ArgType *V2) { return 0; }
|
||||
static Constant *Or (const ArgType *V1, const ArgType *V2) { return 0; }
|
||||
static Constant *Xor (const ArgType *V1, const ArgType *V2) { return 0; }
|
||||
@ -392,8 +402,14 @@ struct VISIBILITY_HIDDEN ConstantPackedRules
|
||||
static Constant *FDiv(const ConstantPacked *V1, const ConstantPacked *V2) {
|
||||
return EvalVectorOp(V1, V2, ConstantExpr::getFDiv);
|
||||
}
|
||||
static Constant *Rem(const ConstantPacked *V1, const ConstantPacked *V2) {
|
||||
return EvalVectorOp(V1, V2, ConstantExpr::getRem);
|
||||
static Constant *URem(const ConstantPacked *V1, const ConstantPacked *V2) {
|
||||
return EvalVectorOp(V1, V2, ConstantExpr::getURem);
|
||||
}
|
||||
static Constant *SRem(const ConstantPacked *V1, const ConstantPacked *V2) {
|
||||
return EvalVectorOp(V1, V2, ConstantExpr::getSRem);
|
||||
}
|
||||
static Constant *FRem(const ConstantPacked *V1, const ConstantPacked *V2) {
|
||||
return EvalVectorOp(V1, V2, ConstantExpr::getFRem);
|
||||
}
|
||||
static Constant *And(const ConstantPacked *V1, const ConstantPacked *V2) {
|
||||
return EvalVectorOp(V1, V2, ConstantExpr::getAnd);
|
||||
@ -510,30 +526,36 @@ struct VISIBILITY_HIDDEN DirectIntRules
|
||||
#undef DEF_CAST
|
||||
|
||||
static Constant *UDiv(const ConstantInt *V1, const ConstantInt *V2) {
|
||||
if (V2->isNullValue())
|
||||
if (V2->isNullValue()) // X / 0
|
||||
return 0;
|
||||
BuiltinType R = (BuiltinType)(V1->getZExtValue() / V2->getZExtValue());
|
||||
return ConstantInt::get(*Ty, R);
|
||||
}
|
||||
|
||||
static Constant *SDiv(const ConstantInt *V1, const ConstantInt *V2) {
|
||||
if (V2->isNullValue())
|
||||
if (V2->isNullValue()) // X / 0
|
||||
return 0;
|
||||
if (V2->isAllOnesValue() && // MIN_INT / -1
|
||||
(BuiltinType)V1->getSExtValue() == -(BuiltinType)V1->getSExtValue())
|
||||
return 0;
|
||||
BuiltinType R =
|
||||
(BuiltinType)(V1->getSExtValue() / V2->getSExtValue());
|
||||
BuiltinType R = (BuiltinType)(V1->getSExtValue() / V2->getSExtValue());
|
||||
return ConstantInt::get(*Ty, R);
|
||||
}
|
||||
|
||||
static Constant *Rem(const ConstantInt *V1, const ConstantInt *V2) {
|
||||
static Constant *URem(const ConstantInt *V1,
|
||||
const ConstantInt *V2) {
|
||||
if (V2->isNullValue()) return 0; // X / 0
|
||||
if (V2->isAllOnesValue() && // MIN_INT / -1
|
||||
(BuiltinType)V1->getZExtValue() == -(BuiltinType)V1->getZExtValue())
|
||||
BuiltinType R = (BuiltinType)(V1->getZExtValue() % V2->getZExtValue());
|
||||
return ConstantInt::get(*Ty, R);
|
||||
}
|
||||
|
||||
static Constant *SRem(const ConstantInt *V1,
|
||||
const ConstantInt *V2) {
|
||||
if (V2->isNullValue()) return 0; // X % 0
|
||||
if (V2->isAllOnesValue() && // MIN_INT % -1
|
||||
(BuiltinType)V1->getSExtValue() == -(BuiltinType)V1->getSExtValue())
|
||||
return 0;
|
||||
BuiltinType R =
|
||||
(BuiltinType)V1->getZExtValue() % (BuiltinType)V2->getZExtValue();
|
||||
BuiltinType R = (BuiltinType)(V1->getSExtValue() % V2->getSExtValue());
|
||||
return ConstantInt::get(*Ty, R);
|
||||
}
|
||||
|
||||
@ -632,7 +654,7 @@ struct VISIBILITY_HIDDEN DirectFPRules
|
||||
DEF_CAST(Double, ConstantFP , double)
|
||||
#undef DEF_CAST
|
||||
|
||||
static Constant *Rem(const ConstantFP *V1, const ConstantFP *V2) {
|
||||
static Constant *FRem(const ConstantFP *V1, const ConstantFP *V2) {
|
||||
if (V2->isNullValue()) return 0;
|
||||
BuiltinType Result = std::fmod((BuiltinType)V1->getValue(),
|
||||
(BuiltinType)V2->getValue());
|
||||
@ -1250,7 +1272,9 @@ Constant *llvm::ConstantFoldBinaryInstruction(unsigned Opcode,
|
||||
case Instruction::UDiv: C = ConstRules::get(V1, V2).udiv(V1, V2); break;
|
||||
case Instruction::SDiv: C = ConstRules::get(V1, V2).sdiv(V1, V2); break;
|
||||
case Instruction::FDiv: C = ConstRules::get(V1, V2).fdiv(V1, V2); break;
|
||||
case Instruction::Rem: C = ConstRules::get(V1, V2).rem(V1, V2); break;
|
||||
case Instruction::URem: C = ConstRules::get(V1, V2).urem(V1, V2); break;
|
||||
case Instruction::SRem: C = ConstRules::get(V1, V2).srem(V1, V2); break;
|
||||
case Instruction::FRem: C = ConstRules::get(V1, V2).frem(V1, V2); break;
|
||||
case Instruction::And: C = ConstRules::get(V1, V2).op_and(V1, V2); break;
|
||||
case Instruction::Or: C = ConstRules::get(V1, V2).op_or (V1, V2); break;
|
||||
case Instruction::Xor: C = ConstRules::get(V1, V2).op_xor(V1, V2); break;
|
||||
@ -1335,25 +1359,26 @@ Constant *llvm::ConstantFoldBinaryInstruction(unsigned Opcode,
|
||||
case Instruction::UDiv:
|
||||
case Instruction::SDiv:
|
||||
case Instruction::FDiv:
|
||||
case Instruction::Rem:
|
||||
if (!isa<UndefValue>(V2)) // undef/X -> 0
|
||||
case Instruction::URem:
|
||||
case Instruction::SRem:
|
||||
case Instruction::FRem:
|
||||
if (!isa<UndefValue>(V2)) // undef / X -> 0
|
||||
return Constant::getNullValue(V1->getType());
|
||||
return const_cast<Constant*>(V2); // X/undef -> undef
|
||||
case Instruction::Or: // X|undef -> -1
|
||||
return const_cast<Constant*>(V2); // X / undef -> undef
|
||||
case Instruction::Or: // X | undef -> -1
|
||||
return ConstantInt::getAllOnesValue(V1->getType());
|
||||
case Instruction::Shr:
|
||||
if (!isa<UndefValue>(V2)) {
|
||||
if (!isa<UndefValue>(V2)) {
|
||||
if (V1->getType()->isSigned())
|
||||
return const_cast<Constant*>(V1); // undef >>s X -> undef
|
||||
return const_cast<Constant*>(V1); // undef >>s X -> undef
|
||||
// undef >>u X -> 0
|
||||
} else if (isa<UndefValue>(V1)) {
|
||||
return const_cast<Constant*>(V1); // undef >> undef -> undef
|
||||
return const_cast<Constant*>(V1); // undef >> undef -> undef
|
||||
} else {
|
||||
if (V1->getType()->isSigned())
|
||||
return const_cast<Constant*>(V1); // X >>s undef -> X
|
||||
// X >>u undef -> 0
|
||||
return const_cast<Constant*>(V1); // X >>s undef -> X
|
||||
}
|
||||
return Constant::getNullValue(V1->getType());
|
||||
return Constant::getNullValue(V1->getType());// X >>u undef -> 0
|
||||
|
||||
case Instruction::Shl:
|
||||
// undef << X -> 0 X << undef -> 0
|
||||
@ -1366,10 +1391,6 @@ Constant *llvm::ConstantFoldBinaryInstruction(unsigned Opcode,
|
||||
// There are many possible foldings we could do here. We should probably
|
||||
// at least fold add of a pointer with an integer into the appropriate
|
||||
// getelementptr. This will improve alias analysis a bit.
|
||||
|
||||
|
||||
|
||||
|
||||
} else {
|
||||
// Just implement a couple of simple identities.
|
||||
switch (Opcode) {
|
||||
@ -1391,10 +1412,11 @@ Constant *llvm::ConstantFoldBinaryInstruction(unsigned Opcode,
|
||||
if (CI->getZExtValue() == 1)
|
||||
return const_cast<Constant*>(V1); // X / 1 == X
|
||||
break;
|
||||
case Instruction::Rem:
|
||||
case Instruction::URem:
|
||||
case Instruction::SRem:
|
||||
if (const ConstantInt *CI = dyn_cast<ConstantInt>(V2))
|
||||
if (CI->getZExtValue() == 1)
|
||||
return Constant::getNullValue(CI->getType()); // X % 1 == 0
|
||||
return Constant::getNullValue(CI->getType()); // X % 1 == 0
|
||||
break;
|
||||
case Instruction::And:
|
||||
if (cast<ConstantIntegral>(V2)->isAllOnesValue())
|
||||
@ -1450,7 +1472,9 @@ Constant *llvm::ConstantFoldBinaryInstruction(unsigned Opcode,
|
||||
case Instruction::SDiv:
|
||||
case Instruction::UDiv:
|
||||
case Instruction::FDiv:
|
||||
case Instruction::Rem:
|
||||
case Instruction::URem:
|
||||
case Instruction::SRem:
|
||||
case Instruction::FRem:
|
||||
default: // These instructions cannot be flopped around.
|
||||
break;
|
||||
}
|
||||
|
@ -78,7 +78,9 @@ bool Constant::canTrap() const {
|
||||
case Instruction::UDiv:
|
||||
case Instruction::SDiv:
|
||||
case Instruction::FDiv:
|
||||
case Instruction::Rem:
|
||||
case Instruction::URem:
|
||||
case Instruction::SRem:
|
||||
case Instruction::FRem:
|
||||
// Div and rem can trap if the RHS is not known to be non-zero.
|
||||
if (!isa<ConstantInt>(getOperand(1)) || getOperand(1)->isNullValue())
|
||||
return true;
|
||||
@ -457,8 +459,14 @@ Constant *ConstantExpr::getSDiv(Constant *C1, Constant *C2) {
|
||||
Constant *ConstantExpr::getFDiv(Constant *C1, Constant *C2) {
|
||||
return get(Instruction::FDiv, C1, C2);
|
||||
}
|
||||
Constant *ConstantExpr::getRem(Constant *C1, Constant *C2) {
|
||||
return get(Instruction::Rem, C1, C2);
|
||||
Constant *ConstantExpr::getURem(Constant *C1, Constant *C2) {
|
||||
return get(Instruction::URem, C1, C2);
|
||||
}
|
||||
Constant *ConstantExpr::getSRem(Constant *C1, Constant *C2) {
|
||||
return get(Instruction::SRem, C1, C2);
|
||||
}
|
||||
Constant *ConstantExpr::getFRem(Constant *C1, Constant *C2) {
|
||||
return get(Instruction::FRem, C1, C2);
|
||||
}
|
||||
Constant *ConstantExpr::getAnd(Constant *C1, Constant *C2) {
|
||||
return get(Instruction::And, C1, C2);
|
||||
@ -1362,7 +1370,7 @@ namespace llvm {
|
||||
break;
|
||||
default:
|
||||
assert(OldC->getOpcode() >= Instruction::BinaryOpsBegin &&
|
||||
OldC->getOpcode() < Instruction::BinaryOpsEnd);
|
||||
OldC->getOpcode() < Instruction::BinaryOpsEnd);
|
||||
New = ConstantExpr::getTy(NewTy, OldC->getOpcode(), OldC->getOperand(0),
|
||||
OldC->getOperand(1));
|
||||
break;
|
||||
@ -1448,8 +1456,8 @@ Constant *ConstantExpr::getTy(const Type *ReqTy, unsigned Opcode,
|
||||
if (Opcode == Instruction::Shl || Opcode == Instruction::Shr)
|
||||
return getShiftTy(ReqTy, Opcode, C1, C2);
|
||||
// Check the operands for consistency first
|
||||
assert((Opcode >= Instruction::BinaryOpsBegin &&
|
||||
Opcode < Instruction::BinaryOpsEnd) &&
|
||||
assert(Opcode >= Instruction::BinaryOpsBegin &&
|
||||
Opcode < Instruction::BinaryOpsEnd &&
|
||||
"Invalid opcode in binary constant expression");
|
||||
assert(C1->getType() == C2->getType() &&
|
||||
"Operand types in binary constant expression should match");
|
||||
@ -1467,15 +1475,14 @@ Constant *ConstantExpr::getTy(const Type *ReqTy, unsigned Opcode,
|
||||
Constant *ConstantExpr::get(unsigned Opcode, Constant *C1, Constant *C2) {
|
||||
#ifndef NDEBUG
|
||||
switch (Opcode) {
|
||||
case Instruction::Add: case Instruction::Sub:
|
||||
case Instruction::Add:
|
||||
case Instruction::Sub:
|
||||
case Instruction::Mul:
|
||||
case Instruction::Rem:
|
||||
assert(C1->getType() == C2->getType() && "Op types should be identical!");
|
||||
assert((C1->getType()->isInteger() || C1->getType()->isFloatingPoint() ||
|
||||
isa<PackedType>(C1->getType())) &&
|
||||
"Tried to create an arithmetic operation on a non-arithmetic type!");
|
||||
break;
|
||||
|
||||
case Instruction::UDiv:
|
||||
case Instruction::SDiv:
|
||||
assert(C1->getType() == C2->getType() && "Op types should be identical!");
|
||||
@ -1489,6 +1496,19 @@ Constant *ConstantExpr::get(unsigned Opcode, Constant *C1, Constant *C2) {
|
||||
&& cast<PackedType>(C1->getType())->getElementType()->isFloatingPoint()))
|
||||
&& "Tried to create an arithmetic operation on a non-arithmetic type!");
|
||||
break;
|
||||
case Instruction::URem:
|
||||
case Instruction::SRem:
|
||||
assert(C1->getType() == C2->getType() && "Op types should be identical!");
|
||||
assert((C1->getType()->isInteger() || (isa<PackedType>(C1->getType()) &&
|
||||
cast<PackedType>(C1->getType())->getElementType()->isInteger())) &&
|
||||
"Tried to create an arithmetic operation on a non-arithmetic type!");
|
||||
break;
|
||||
case Instruction::FRem:
|
||||
assert(C1->getType() == C2->getType() && "Op types should be identical!");
|
||||
assert((C1->getType()->isFloatingPoint() || (isa<PackedType>(C1->getType())
|
||||
&& cast<PackedType>(C1->getType())->getElementType()->isFloatingPoint()))
|
||||
&& "Tried to create an arithmetic operation on a non-arithmetic type!");
|
||||
break;
|
||||
case Instruction::And:
|
||||
case Instruction::Or:
|
||||
case Instruction::Xor:
|
||||
|
@ -97,7 +97,9 @@ const char *Instruction::getOpcodeName(unsigned OpCode) {
|
||||
case UDiv: return "udiv";
|
||||
case SDiv: return "sdiv";
|
||||
case FDiv: return "fdiv";
|
||||
case Rem: return "rem";
|
||||
case URem: return "urem";
|
||||
case SRem: return "srem";
|
||||
case FRem: return "frem";
|
||||
|
||||
// Logical operators...
|
||||
case And: return "and";
|
||||
@ -227,7 +229,9 @@ bool Instruction::isTrapping(unsigned op) {
|
||||
case UDiv:
|
||||
case SDiv:
|
||||
case FDiv:
|
||||
case Rem:
|
||||
case URem:
|
||||
case SRem:
|
||||
case FRem:
|
||||
case Load:
|
||||
case Store:
|
||||
case Call:
|
||||
|
@ -1023,7 +1023,6 @@ void BinaryOperator::init(BinaryOps iType)
|
||||
switch (iType) {
|
||||
case Add: case Sub:
|
||||
case Mul:
|
||||
case Rem:
|
||||
assert(getType() == LHS->getType() &&
|
||||
"Arithmetic operation should return same type as operands!");
|
||||
assert((getType()->isInteger() || getType()->isFloatingPoint() ||
|
||||
@ -1045,7 +1044,21 @@ void BinaryOperator::init(BinaryOps iType)
|
||||
cast<PackedType>(getType())->getElementType()->isFloatingPoint()))
|
||||
&& "Incorrect operand type (not floating point) for FDIV");
|
||||
break;
|
||||
|
||||
case URem:
|
||||
case SRem:
|
||||
assert(getType() == LHS->getType() &&
|
||||
"Arithmetic operation should return same type as operands!");
|
||||
assert((getType()->isInteger() || (isa<PackedType>(getType()) &&
|
||||
cast<PackedType>(getType())->getElementType()->isInteger())) &&
|
||||
"Incorrect operand type (not integer) for S/UREM");
|
||||
break;
|
||||
case FRem:
|
||||
assert(getType() == LHS->getType() &&
|
||||
"Arithmetic operation should return same type as operands!");
|
||||
assert((getType()->isFloatingPoint() || (isa<PackedType>(getType()) &&
|
||||
cast<PackedType>(getType())->getElementType()->isFloatingPoint()))
|
||||
&& "Incorrect operand type (not floating point) for FREM");
|
||||
break;
|
||||
case And: case Or:
|
||||
case Xor:
|
||||
assert(getType() == LHS->getType() &&
|
||||
|
@ -1052,7 +1052,7 @@ StackerCompiler::handle_word( int tkn )
|
||||
LoadInst* op1 = cast<LoadInst>(pop_integer(bb));
|
||||
LoadInst* op2 = cast<LoadInst>(pop_integer(bb));
|
||||
BinaryOperator* divop =
|
||||
BinaryOperator::create( Instruction::Rem, op1, op2);
|
||||
BinaryOperator::create( Instruction::SRem, op1, op2);
|
||||
bb->getInstList().push_back( divop );
|
||||
push_value( bb, divop );
|
||||
break;
|
||||
|
@ -776,7 +776,9 @@ void CppWriter::printConstant(const Constant *CV) {
|
||||
case Instruction::UDiv: Out << "getUDiv"; break;
|
||||
case Instruction::SDiv: Out << "getSDiv"; break;
|
||||
case Instruction::FDiv: Out << "getFDiv"; break;
|
||||
case Instruction::Rem: Out << "getRem"; break;
|
||||
case Instruction::URem: Out << "getURem"; break;
|
||||
case Instruction::SRem: Out << "getSRem"; break;
|
||||
case Instruction::FRem: Out << "getFRem"; break;
|
||||
case Instruction::And: Out << "getAnd"; break;
|
||||
case Instruction::Or: Out << "getOr"; break;
|
||||
case Instruction::Xor: Out << "getXor"; break;
|
||||
@ -1026,7 +1028,9 @@ CppWriter::printInstruction(const Instruction *I, const std::string& bbname) {
|
||||
case Instruction::UDiv:
|
||||
case Instruction::SDiv:
|
||||
case Instruction::FDiv:
|
||||
case Instruction::Rem:
|
||||
case Instruction::URem:
|
||||
case Instruction::SRem:
|
||||
case Instruction::FRem:
|
||||
case Instruction::And:
|
||||
case Instruction::Or:
|
||||
case Instruction::Xor:
|
||||
@ -1040,7 +1044,9 @@ CppWriter::printInstruction(const Instruction *I, const std::string& bbname) {
|
||||
case Instruction::UDiv:Out << "Instruction::UDiv"; break;
|
||||
case Instruction::SDiv:Out << "Instruction::SDiv"; break;
|
||||
case Instruction::FDiv:Out << "Instruction::FDiv"; break;
|
||||
case Instruction::Rem: Out << "Instruction::Rem"; break;
|
||||
case Instruction::URem:Out << "Instruction::URem"; break;
|
||||
case Instruction::SRem:Out << "Instruction::SRem"; break;
|
||||
case Instruction::FRem:Out << "Instruction::FRem"; break;
|
||||
case Instruction::And: Out << "Instruction::And"; break;
|
||||
case Instruction::Or: Out << "Instruction::Or"; break;
|
||||
case Instruction::Xor: Out << "Instruction::Xor"; break;
|
||||
|
Loading…
Reference in New Issue
Block a user