1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-10-19 02:52:53 +02:00

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.

llvm-svn: 31195
This commit is contained in:
Reid Spencer 2006-10-26 06:15:43 +00:00
parent e7580b4a17
commit 6833ffe8b8
31 changed files with 2925 additions and 1937 deletions

View File

@ -77,7 +77,9 @@
<li><a href="#i_add">'<tt>add</tt>' Instruction</a></li>
<li><a href="#i_sub">'<tt>sub</tt>' Instruction</a></li>
<li><a href="#i_mul">'<tt>mul</tt>' Instruction</a></li>
<li><a href="#i_div">'<tt>div</tt>' Instruction</a></li>
<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_setcc">'<tt>set<i>cc</i></tt>' Instructions</a></li>
</ol>
@ -1630,26 +1632,70 @@ action is taken based on the type of the operand.</p>
</pre>
</div>
<!-- _______________________________________________________________________ -->
<div class="doc_subsubsection"> <a name="i_div">'<tt>div</tt>'
<div class="doc_subsubsection"> <a name="i_udiv">'<tt>udiv</tt>' Instruction
</a></div>
<div class="doc_text">
<h5>Syntax:</h5>
<pre> &lt;result&gt; = udiv &lt;ty&gt; &lt;var1&gt;, &lt;var2&gt; <i>; yields {ty}:result</i>
</pre>
<h5>Overview:</h5>
<p>The '<tt>udiv</tt>' instruction returns the quotient of its two
operands.</p>
<h5>Arguments:</h5>
<p>The two arguments to the '<tt>udiv</tt>' instruction must be
<a href="#t_integer">integer</a> values. Both arguments must have identical
types. This instruction can also take <a href="#t_packed">packed</a> versions
of the values in which case the elements must be integers.</p>
<h5>Semantics:</h5>
<p>The value produced is the unsigned integer quotient of the two operands. This
instruction always performs an unsigned division operation, regardless of
whether the arguments are unsigned or not.</p>
<h5>Example:</h5>
<pre> &lt;result&gt; = udiv uint 4, %var <i>; yields {uint}:result = 4 / %var</i>
</pre>
</div>
<!-- _______________________________________________________________________ -->
<div class="doc_subsubsection"> <a name="i_sdiv">'<tt>sdiv</tt>' Instruction
</a> </div>
<div class="doc_text">
<h5>Syntax:</h5>
<pre> &lt;result&gt; = sdiv &lt;ty&gt; &lt;var1&gt;, &lt;var2&gt; <i>; yields {ty}:result</i>
</pre>
<h5>Overview:</h5>
<p>The '<tt>sdiv</tt>' instruction returns the quotient of its two
operands.</p>
<h5>Arguments:</h5>
<p>The two arguments to the '<tt>sdiv</tt>' instruction must be
<a href="#t_integer">integer</a> values. Both arguments must have identical
types. This instruction can also take <a href="#t_packed">packed</a> versions
of the values in which case the elements must be integers.</p>
<h5>Semantics:</h5>
<p>The value produced is the signed integer quotient of the two operands. This
instruction always performs a signed division operation, regardless of whether
the arguments are signed or not.</p>
<h5>Example:</h5>
<pre> &lt;result&gt; = sdiv int 4, %var <i>; yields {int}:result = 4 / %var</i>
</pre>
</div>
<!-- _______________________________________________________________________ -->
<div class="doc_subsubsection"> <a name="i_fdiv">'<tt>fdiv</tt>'
Instruction</a> </div>
<div class="doc_text">
<h5>Syntax:</h5>
<pre> &lt;result&gt; = div &lt;ty&gt; &lt;var1&gt;, &lt;var2&gt; <i>; yields {ty}:result</i>
<pre> &lt;result&gt; = fdiv &lt;ty&gt; &lt;var1&gt;, &lt;var2&gt; <i>; yields {ty}:result</i>
</pre>
<h5>Overview:</h5>
<p>The '<tt>div</tt>' instruction returns the quotient of its two
<p>The '<tt>fdiv</tt>' instruction returns the quotient of its two
operands.</p>
<h5>Arguments:</h5>
<p>The two arguments to the '<tt>div</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>div</tt>' instruction must be
<a href="#t_floating">floating point</a> values. Both arguments must have
identical types. This instruction can also take <a href="#t_packed">packed</a>
versions of the values in which case the elements must be floating point.</p>
<h5>Semantics:</h5>
<p>The value produced is the integer or floating point quotient of the
two operands.</p>
<p>The value produced is the floating point quotient of the two operands.</p>
<h5>Example:</h5>
<pre> &lt;result&gt; = div int 4, %var <i>; yields {int}:result = 4 / %var</i>
<pre> &lt;result&gt; = fdiv float 4.0, %var <i>; yields {float}:result = 4.0 / %var</i>
</pre>
</div>
<!-- _______________________________________________________________________ -->

View File

@ -140,7 +140,7 @@ namespace llvm {
const Type *Ty = S->getType();
Value *LHS = expandInTy(S->getLHS(), Ty);
Value *RHS = expandInTy(S->getRHS(), Ty);
return BinaryOperator::createDiv(LHS, RHS, "tmp.", InsertPt);
return BinaryOperator::createSDiv(LHS, RHS, "tmp.", InsertPt);
}
Value *visitAddRecExpr(SCEVAddRecExpr *S);

View File

@ -293,7 +293,7 @@ namespace llvm {
//===--------------------------------------------------------------------===//
/// SCEVSDivExpr - This class represents a binary unsigned division operation.
/// SCEVSDivExpr - This class represents a binary signed division operation.
///
class SCEVSDivExpr : public SCEV {
SCEVHandle LHS, RHS;

View File

@ -543,7 +543,9 @@ public:
static Constant *getAdd(Constant *C1, Constant *C2);
static Constant *getSub(Constant *C1, Constant *C2);
static Constant *getMul(Constant *C1, Constant *C2);
static Constant *getDiv(Constant *C1, Constant *C2);
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 *getAnd(Constant *C1, Constant *C2);
static Constant *getOr(Constant *C1, Constant *C2);

View File

@ -93,45 +93,43 @@ HANDLE_TERM_INST ( 6, Unreachable, UnreachableInst)
HANDLE_BINARY_INST( 7, Add , BinaryOperator)
HANDLE_BINARY_INST( 8, Sub , BinaryOperator)
HANDLE_BINARY_INST( 9, Mul , BinaryOperator)
HANDLE_BINARY_INST(10, Div , BinaryOperator)
HANDLE_BINARY_INST(11, Rem , 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)
// Logical operators...
HANDLE_BINARY_INST(12, And , BinaryOperator)
HANDLE_BINARY_INST(13, Or , BinaryOperator)
HANDLE_BINARY_INST(14, Xor , BinaryOperator)
HANDLE_BINARY_INST(14, And , BinaryOperator)
HANDLE_BINARY_INST(15, Or , BinaryOperator)
HANDLE_BINARY_INST(16, Xor , BinaryOperator)
// Binary comparison operators...
HANDLE_BINARY_INST(15, SetEQ , SetCondInst)
HANDLE_BINARY_INST(16, SetNE , SetCondInst)
HANDLE_BINARY_INST(17, SetLE , SetCondInst)
HANDLE_BINARY_INST(18, SetGE , SetCondInst)
HANDLE_BINARY_INST(19, SetLT , SetCondInst)
HANDLE_BINARY_INST(20, SetGT , SetCondInst)
LAST_BINARY_INST(20)
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)
// Memory operators...
FIRST_MEMORY_INST(21)
HANDLE_MEMORY_INST(21, Malloc, MallocInst) // Heap management instructions
HANDLE_MEMORY_INST(22, Free , FreeInst )
HANDLE_MEMORY_INST(23, Alloca, AllocaInst) // Stack management
HANDLE_MEMORY_INST(24, Load , LoadInst ) // Memory manipulation instrs
HANDLE_MEMORY_INST(25, Store , StoreInst )
HANDLE_MEMORY_INST(26, GetElementPtr, GetElementPtrInst)
LAST_MEMORY_INST(26)
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)
// Other operators...
FIRST_OTHER_INST(27)
HANDLE_OTHER_INST(27, PHI , PHINode ) // PHI node instruction
HANDLE_OTHER_INST(28, Cast , CastInst ) // Type cast
HANDLE_OTHER_INST(29, Call , CallInst ) // Call a function
HANDLE_OTHER_INST(30, Shl , ShiftInst ) // Shift operations
HANDLE_OTHER_INST(31, Shr , ShiftInst )
// 32 -> Empty slot used to be used for vanext in llvm 1.5 and before.
// 33 -> Empty slot used to be used for vaarg in llvm 1.5 and before.
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

View File

@ -112,9 +112,21 @@ inline BinaryOp_match<LHS, RHS, Instruction::Mul> m_Mul(const LHS &L,
}
template<typename LHS, typename RHS>
inline BinaryOp_match<LHS, RHS, Instruction::Div> m_Div(const LHS &L,
inline BinaryOp_match<LHS, RHS, Instruction::UDiv> m_UDiv(const LHS &L,
const RHS &R) {
return BinaryOp_match<LHS, RHS, Instruction::Div>(L, R);
return BinaryOp_match<LHS, RHS, Instruction::UDiv>(L, R);
}
template<typename LHS, typename RHS>
inline BinaryOp_match<LHS, RHS, Instruction::SDiv> m_SDiv(const LHS &L,
const RHS &R) {
return BinaryOp_match<LHS, RHS, Instruction::SDiv>(L, R);
}
template<typename LHS, typename RHS>
inline BinaryOp_match<LHS, RHS, Instruction::FDiv> m_FDiv(const LHS &L,
const RHS &R) {
return BinaryOp_match<LHS, RHS, Instruction::FDiv>(L, R);
}
template<typename LHS, typename RHS>

View File

@ -989,9 +989,9 @@ SCEVHandle SCEVMulExpr::get(std::vector<SCEVHandle> &Ops) {
SCEVHandle SCEVSDivExpr::get(const SCEVHandle &LHS, const SCEVHandle &RHS) {
if (SCEVConstant *RHSC = dyn_cast<SCEVConstant>(RHS)) {
if (RHSC->getValue()->equalsInt(1))
return LHS; // X /s 1 --> x
return LHS; // X sdiv 1 --> x
if (RHSC->getValue()->isAllOnesValue())
return SCEV::getNegativeSCEV(LHS); // X /s -1 --> -x
return SCEV::getNegativeSCEV(LHS); // X sdiv -1 --> -x
if (SCEVConstant *LHSC = dyn_cast<SCEVConstant>(LHS)) {
Constant *LHSCV = LHSC->getValue();
@ -1001,7 +1001,7 @@ SCEVHandle SCEVSDivExpr::get(const SCEVHandle &LHS, const SCEVHandle &RHS) {
LHSCV->getType()->getSignedVersion());
if (RHSCV->getType()->isUnsigned())
RHSCV = ConstantExpr::getCast(RHSCV, LHSCV->getType());
return SCEVUnknown::get(ConstantExpr::getDiv(LHSCV, RHSCV));
return SCEVUnknown::get(ConstantExpr::getSDiv(LHSCV, RHSCV));
}
}
@ -1384,10 +1384,9 @@ SCEVHandle ScalarEvolutionsImpl::createSCEV(Value *V) {
case Instruction::Mul:
return SCEVMulExpr::get(getSCEV(I->getOperand(0)),
getSCEV(I->getOperand(1)));
case Instruction::Div:
if (V->getType()->isInteger() && V->getType()->isSigned())
return SCEVSDivExpr::get(getSCEV(I->getOperand(0)),
getSCEV(I->getOperand(1)));
case Instruction::SDiv:
return SCEVSDivExpr::get(getSCEV(I->getOperand(0)),
getSCEV(I->getOperand(1)));
break;
case Instruction::Sub:
@ -2058,16 +2057,16 @@ SolveQuadraticEquation(const SCEVAddRecExpr *AddRec) {
return std::make_pair(CNC, CNC);
}
Constant *Two = ConstantInt::get(L->getValue()->getType(), 2);
Constant *C = L->getValue();
Constant *Two = ConstantInt::get(C->getType(), 2);
// Convert from chrec coefficients to polynomial coefficients AX^2+BX+C
Constant *C = L->getValue();
// The B coefficient is M-N/2
Constant *B = ConstantExpr::getSub(M->getValue(),
ConstantExpr::getDiv(N->getValue(),
ConstantExpr::getSDiv(N->getValue(),
Two));
// The A coefficient is N/2
Constant *A = ConstantExpr::getDiv(N->getValue(), Two);
Constant *A = ConstantExpr::getSDiv(N->getValue(), Two);
// Compute the B^2-4ac term.
Constant *SqrtTerm =
@ -2102,9 +2101,9 @@ SolveQuadraticEquation(const SCEVAddRecExpr *AddRec) {
SqrtTerm = ConstantExpr::getCast(SqrtTerm, SignedTy);
Constant *Solution1 =
ConstantExpr::getDiv(ConstantExpr::getAdd(NegB, SqrtTerm), TwoA);
ConstantExpr::getSDiv(ConstantExpr::getAdd(NegB, SqrtTerm), TwoA);
Constant *Solution2 =
ConstantExpr::getDiv(ConstantExpr::getSub(NegB, SqrtTerm), TwoA);
ConstantExpr::getSDiv(ConstantExpr::getSub(NegB, SqrtTerm), TwoA);
return std::make_pair(SCEVUnknown::get(Solution1),
SCEVUnknown::get(Solution2));
}
@ -2150,7 +2149,7 @@ SCEVHandle ScalarEvolutionsImpl::HowFarToZero(SCEV *V, const Loop *L) {
Constant *StartNegC = ConstantExpr::getNeg(StartCC);
Constant *Rem = ConstantExpr::getRem(StartNegC, StepC->getValue());
if (Rem->isNullValue()) {
Constant *Result =ConstantExpr::getDiv(StartNegC,StepC->getValue());
Constant *Result =ConstantExpr::getSDiv(StartNegC,StepC->getValue());
return SCEVUnknown::get(Result);
}
}
@ -2352,7 +2351,7 @@ SCEVHandle SCEVAddRecExpr::getNumIterationsInRange(ConstantRange Range) const {
Constant *ExitValue = Upper;
if (A != One) {
ExitValue = ConstantExpr::getSub(ConstantExpr::getAdd(Upper, A), One);
ExitValue = ConstantExpr::getDiv(ExitValue, A);
ExitValue = ConstantExpr::getSDiv(ExitValue, A);
}
assert(isa<ConstantInt>(ExitValue) &&
"Constant folding of integers not implemented?");

View File

@ -39,8 +39,18 @@ void set_scan_string (const char * str) {
yy_scan_string (str);
}
// Construct a token value for a non-obsolete token
#define RET_TOK(type, Enum, sym) \
llvmAsmlval.type = Instruction::Enum; return sym
llvmAsmlval.type.opcode = Instruction::Enum; \
llvmAsmlval.type.obsolete = false; \
return sym
// Construct a token value for an obsolete token
#define RET_TOK_OBSOLETE(type, Enum, sym) \
llvmAsmlval.type.opcode = Instruction::Enum; \
llvmAsmlval.type.obsolete = true; \
return sym
namespace llvm {
@ -247,7 +257,10 @@ opaque { return OPAQUE; }
add { RET_TOK(BinaryOpVal, Add, ADD); }
sub { RET_TOK(BinaryOpVal, Sub, SUB); }
mul { RET_TOK(BinaryOpVal, Mul, MUL); }
div { RET_TOK(BinaryOpVal, Div, DIV); }
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); }
and { RET_TOK(BinaryOpVal, And, AND); }
or { RET_TOK(BinaryOpVal, Or , OR ); }

View File

@ -201,4 +201,20 @@ struct ValID {
} // End llvm namespace
// This structure is used to keep track of obsolete opcodes. The lexer will
// retain the ability to parse obsolete opcode mnemonics. In this case it will
// set "obsolete" to true and the opcode will be the replacement opcode. For
// example if "rem" is encountered then opcode will be set to "urem" and the
// "obsolete" flag will be true. If the opcode is not obsolete then "obsolete"
// will be false.
template <class Enum>
struct OpcodeInfo {
Enum opcode;
bool obsolete;
};
typedef OpcodeInfo<llvm::Instruction::BinaryOps> BinaryOpInfo;
typedef OpcodeInfo<llvm::Instruction::TermOps> TermOpInfo;
typedef OpcodeInfo<llvm::Instruction::MemoryOps> MemOpInfo;
typedef OpcodeInfo<llvm::Instruction::OtherOps> OtherOpInfo;
#endif

File diff suppressed because it is too large Load Diff

View File

@ -107,34 +107,36 @@
ADD = 333,
SUB = 334,
MUL = 335,
DIV = 336,
REM = 337,
AND = 338,
OR = 339,
XOR = 340,
SETLE = 341,
SETGE = 342,
SETLT = 343,
SETGT = 344,
SETEQ = 345,
SETNE = 346,
MALLOC = 347,
ALLOCA = 348,
FREE = 349,
LOAD = 350,
STORE = 351,
GETELEMENTPTR = 352,
PHI_TOK = 353,
CAST = 354,
SELECT = 355,
SHL = 356,
SHR = 357,
VAARG = 358,
EXTRACTELEMENT = 359,
INSERTELEMENT = 360,
SHUFFLEVECTOR = 361,
VAARG_old = 362,
VANEXT_old = 363
UDIV = 336,
SDIV = 337,
FDIV = 338,
REM = 339,
AND = 340,
OR = 341,
XOR = 342,
SETLE = 343,
SETGE = 344,
SETLT = 345,
SETGT = 346,
SETEQ = 347,
SETNE = 348,
MALLOC = 349,
ALLOCA = 350,
FREE = 351,
LOAD = 352,
STORE = 353,
GETELEMENTPTR = 354,
PHI_TOK = 355,
CAST = 356,
SELECT = 357,
SHL = 358,
SHR = 359,
VAARG = 360,
EXTRACTELEMENT = 361,
INSERTELEMENT = 362,
SHUFFLEVECTOR = 363,
VAARG_old = 364,
VANEXT_old = 365
};
#endif
/* Tokens. */
@ -216,40 +218,42 @@
#define ADD 333
#define SUB 334
#define MUL 335
#define DIV 336
#define REM 337
#define AND 338
#define OR 339
#define XOR 340
#define SETLE 341
#define SETGE 342
#define SETLT 343
#define SETGT 344
#define SETEQ 345
#define SETNE 346
#define MALLOC 347
#define ALLOCA 348
#define FREE 349
#define LOAD 350
#define STORE 351
#define GETELEMENTPTR 352
#define PHI_TOK 353
#define CAST 354
#define SELECT 355
#define SHL 356
#define SHR 357
#define VAARG 358
#define EXTRACTELEMENT 359
#define INSERTELEMENT 360
#define SHUFFLEVECTOR 361
#define VAARG_old 362
#define VANEXT_old 363
#define UDIV 336
#define SDIV 337
#define FDIV 338
#define REM 339
#define AND 340
#define OR 341
#define XOR 342
#define SETLE 343
#define SETGE 344
#define SETLT 345
#define SETGT 346
#define SETEQ 347
#define SETNE 348
#define MALLOC 349
#define ALLOCA 350
#define FREE 351
#define LOAD 352
#define STORE 353
#define GETELEMENTPTR 354
#define PHI_TOK 355
#define CAST 356
#define SELECT 357
#define SHL 358
#define SHR 359
#define VAARG 360
#define EXTRACTELEMENT 361
#define INSERTELEMENT 362
#define SHUFFLEVECTOR 363
#define VAARG_old 364
#define VANEXT_old 365
#if ! defined (YYSTYPE) && ! defined (YYSTYPE_IS_DECLARED)
#line 974 "/proj/llvm/llvm_nc/lib/AsmParser/llvmAsmParser.y"
#line 1011 "/proj/llvm/llvm/lib/AsmParser/llvmAsmParser.y"
typedef union YYSTYPE {
llvm::Module *ModuleVal;
llvm::Function *FunctionVal;
@ -281,16 +285,16 @@ typedef union YYSTYPE {
bool BoolVal;
char *StrVal; // This memory is strdup'd!
llvm::ValID ValIDVal; // strdup'd memory maybe!
llvm::ValID ValIDVal; // strdup'd memory maybe!
llvm::Instruction::BinaryOps BinaryOpVal;
llvm::Instruction::TermOps TermOpVal;
llvm::Instruction::MemoryOps MemOpVal;
llvm::Instruction::OtherOps OtherOpVal;
llvm::Module::Endianness Endianness;
BinaryOpInfo BinaryOpVal;
TermOpInfo TermOpVal;
MemOpInfo MemOpVal;
OtherOpInfo OtherOpVal;
llvm::Module::Endianness Endianness;
} YYSTYPE;
/* Line 1447 of yacc.c. */
#line 294 "llvmAsmParser.tab.h"
#line 298 "llvmAsmParser.tab.h"
# define yystype YYSTYPE /* obsolescent; will be withdrawn */
# define YYSTYPE_IS_DECLARED 1
# define YYSTYPE_IS_TRIVIAL 1

View File

@ -813,6 +813,43 @@ static PATypeHolder HandleUpRefs(const Type *ty) {
return Ty;
}
/// This function is used to obtain the correct opcode for an instruction when
/// an obsolete opcode is encountered. The OI parameter (OpcodeInfo) has both
/// an opcode and an "obsolete" flag. These are generated by the lexer and
/// the "obsolete" member will be true when the lexer encounters the token for
/// an obsolete opcode. For example, "div" was replaced by [usf]div but we need
/// to maintain backwards compatibility for asm files that still have the "div"
/// instruction. This function handles converting div -> [usf]div appropriately.
/// @brief Convert obsolete opcodes to new values
static void
sanitizeOpCode(OpcodeInfo<Instruction::BinaryOps> &OI, const PATypeHolder& PATy)
{
// If its not obsolete, don't do anything
if (!OI.obsolete)
return;
// If its a packed type we want to use the element type
const Type* Ty = PATy;
if (const PackedType* PTy = dyn_cast<PackedType>(Ty))
Ty = PTy->getElementType();
// Depending on the opcode ..
switch (OI.opcode) {
default:
GenerateError("Invalid Obsolete OpCode");
break;
case Instruction::UDiv:
// Handle cases where the opcode needs to change
if (Ty->isFloatingPoint())
OI.opcode = Instruction::FDiv;
else if (Ty->isSigned())
OI.opcode = Instruction::SDiv;
break;
}
// Its not obsolete any more, we fixed it.
OI.obsolete = false;
}
// common code from the two 'RunVMAsmParser' functions
static Module* RunParser(Module * M) {
@ -1002,13 +1039,13 @@ Module *llvm::RunVMAsmParser(const char * AsmString, Module * M) {
bool BoolVal;
char *StrVal; // This memory is strdup'd!
llvm::ValID ValIDVal; // strdup'd memory maybe!
llvm::ValID ValIDVal; // strdup'd memory maybe!
llvm::Instruction::BinaryOps BinaryOpVal;
llvm::Instruction::TermOps TermOpVal;
llvm::Instruction::MemoryOps MemOpVal;
llvm::Instruction::OtherOps OtherOpVal;
llvm::Module::Endianness Endianness;
BinaryOpInfo BinaryOpVal;
TermOpInfo TermOpVal;
MemOpInfo MemOpVal;
OtherOpInfo OtherOpVal;
llvm::Module::Endianness Endianness;
}
%type <ModuleVal> Module FunctionList
@ -1076,8 +1113,8 @@ Module *llvm::RunVMAsmParser(const char * AsmString, Module * M) {
// Binary Operators
%type <BinaryOpVal> ArithmeticOps LogicalOps SetCondOps // Binops Subcatagories
%token <BinaryOpVal> ADD SUB MUL DIV REM AND OR XOR
%token <BinaryOpVal> SETLE SETGE SETLT SETGT SETEQ SETNE // Binary Comarators
%token <BinaryOpVal> ADD SUB MUL UDIV SDIV FDIV REM AND OR XOR
%token <BinaryOpVal> SETLE SETGE SETLT SETGT SETEQ SETNE // Binary Comparators
// Memory Instructions
%token <MemOpVal> MALLOC ALLOCA FREE LOAD STORE GETELEMENTPTR
@ -1114,7 +1151,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 | DIV | REM;
ArithmeticOps: ADD | SUB | MUL | UDIV | SDIV | FDIV | REM ;
LogicalOps : AND | OR | XOR;
SetCondOps : SETLE | SETGE | SETLT | SETGT | SETEQ | SETNE;
@ -1642,12 +1679,17 @@ ConstExpr: CAST '(' ConstVal TO Types ')' {
| ArithmeticOps '(' ConstVal ',' ConstVal ')' {
if ($3->getType() != $5->getType())
GEN_ERROR("Binary operator types must match!");
// First, make sure we're dealing with the right opcode by upgrading from
// obsolete versions.
sanitizeOpCode($1,$3->getType());
CHECK_FOR_ERROR;
// HACK: llvm 1.3 and earlier used to emit invalid pointer constant exprs.
// To retain backward compatibility with these early compilers, we emit a
// cast to the appropriate integer type automatically if we are in the
// broken case. See PR424 for more information.
if (!isa<PointerType>($3->getType())) {
$$ = ConstantExpr::get($1, $3, $5);
$$ = ConstantExpr::get($1.opcode, $3, $5);
} else {
const Type *IntPtrTy = 0;
switch (CurModule.CurrentModule->getPointerSize()) {
@ -1655,7 +1697,7 @@ ConstExpr: CAST '(' ConstVal TO Types ')' {
case Module::Pointer64: IntPtrTy = Type::LongTy; break;
default: GEN_ERROR("invalid pointer binary constant expr!");
}
$$ = ConstantExpr::get($1, ConstantExpr::getCast($3, IntPtrTy),
$$ = ConstantExpr::get($1.opcode, ConstantExpr::getCast($3, IntPtrTy),
ConstantExpr::getCast($5, IntPtrTy));
$$ = ConstantExpr::getCast($$, $3->getType());
}
@ -1669,13 +1711,13 @@ ConstExpr: CAST '(' ConstVal TO Types ')' {
!cast<PackedType>($3->getType())->getElementType()->isIntegral())
GEN_ERROR("Logical operator requires integral operands!");
}
$$ = ConstantExpr::get($1, $3, $5);
$$ = ConstantExpr::get($1.opcode, $3, $5);
CHECK_FOR_ERROR
}
| SetCondOps '(' ConstVal ',' ConstVal ')' {
if ($3->getType() != $5->getType())
GEN_ERROR("setcc operand types must match!");
$$ = ConstantExpr::get($1, $3, $5);
$$ = ConstantExpr::get($1.opcode, $3, $5);
CHECK_FOR_ERROR
}
| ShiftOps '(' ConstVal ',' ConstVal ')' {
@ -1683,7 +1725,7 @@ ConstExpr: CAST '(' ConstVal TO Types ')' {
GEN_ERROR("Shift count for shift constant must be unsigned byte!");
if (!$3->getType()->isInteger())
GEN_ERROR("Shift constant expression requires integer operand!");
$$ = ConstantExpr::get($1, $3, $5);
$$ = ConstantExpr::get($1.opcode, $3, $5);
CHECK_FOR_ERROR
}
| EXTRACTELEMENT '(' ConstVal ',' ConstVal ')' {
@ -2423,13 +2465,16 @@ 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 == Instruction::Rem)
if (isa<PackedType>((*$2).get()) && $1.opcode == Instruction::Rem)
GEN_ERROR("Rem not supported on packed types!");
// Upgrade the opcode from obsolete versions before we do anything with it.
sanitizeOpCode($1,*$2);
CHECK_FOR_ERROR;
Value* val1 = getVal(*$2, $3);
CHECK_FOR_ERROR
Value* val2 = getVal(*$2, $5);
CHECK_FOR_ERROR
$$ = BinaryOperator::create($1, val1, val2);
$$ = BinaryOperator::create($1.opcode, val1, val2);
if ($$ == 0)
GEN_ERROR("binary operator returned null!");
delete $2;
@ -2444,7 +2489,7 @@ InstVal : ArithmeticOps Types ValueRef ',' ValueRef {
CHECK_FOR_ERROR
Value* tmpVal2 = getVal(*$2, $5);
CHECK_FOR_ERROR
$$ = BinaryOperator::create($1, tmpVal1, tmpVal2);
$$ = BinaryOperator::create($1.opcode, tmpVal1, tmpVal2);
if ($$ == 0)
GEN_ERROR("binary operator returned null!");
delete $2;
@ -2458,7 +2503,7 @@ InstVal : ArithmeticOps Types ValueRef ',' ValueRef {
CHECK_FOR_ERROR
Value* tmpVal2 = getVal(*$2, $5);
CHECK_FOR_ERROR
$$ = new SetCondInst($1, tmpVal1, tmpVal2);
$$ = new SetCondInst($1.opcode, tmpVal1, tmpVal2);
if ($$ == 0)
GEN_ERROR("binary operator returned null!");
delete $2;
@ -2481,7 +2526,7 @@ InstVal : ArithmeticOps Types ValueRef ',' ValueRef {
GEN_ERROR("Shift amount must be ubyte!");
if (!$2->getType()->isInteger())
GEN_ERROR("Shift constant expression requires integer operand!");
$$ = new ShiftInst($1, $2, $4);
$$ = new ShiftInst($1.opcode, $2, $4);
CHECK_FOR_ERROR
}
| CAST ResolvedVal TO Types {

View File

@ -813,6 +813,43 @@ static PATypeHolder HandleUpRefs(const Type *ty) {
return Ty;
}
/// This function is used to obtain the correct opcode for an instruction when
/// an obsolete opcode is encountered. The OI parameter (OpcodeInfo) has both
/// an opcode and an "obsolete" flag. These are generated by the lexer and
/// the "obsolete" member will be true when the lexer encounters the token for
/// an obsolete opcode. For example, "div" was replaced by [usf]div but we need
/// to maintain backwards compatibility for asm files that still have the "div"
/// instruction. This function handles converting div -> [usf]div appropriately.
/// @brief Convert obsolete opcodes to new values
static void
sanitizeOpCode(OpcodeInfo<Instruction::BinaryOps> &OI, const PATypeHolder& PATy)
{
// If its not obsolete, don't do anything
if (!OI.obsolete)
return;
// If its a packed type we want to use the element type
const Type* Ty = PATy;
if (const PackedType* PTy = dyn_cast<PackedType>(Ty))
Ty = PTy->getElementType();
// Depending on the opcode ..
switch (OI.opcode) {
default:
GenerateError("Invalid Obsolete OpCode");
break;
case Instruction::UDiv:
// Handle cases where the opcode needs to change
if (Ty->isFloatingPoint())
OI.opcode = Instruction::FDiv;
else if (Ty->isSigned())
OI.opcode = Instruction::SDiv;
break;
}
// Its not obsolete any more, we fixed it.
OI.obsolete = false;
}
// common code from the two 'RunVMAsmParser' functions
static Module* RunParser(Module * M) {
@ -1002,13 +1039,13 @@ Module *llvm::RunVMAsmParser(const char * AsmString, Module * M) {
bool BoolVal;
char *StrVal; // This memory is strdup'd!
llvm::ValID ValIDVal; // strdup'd memory maybe!
llvm::ValID ValIDVal; // strdup'd memory maybe!
llvm::Instruction::BinaryOps BinaryOpVal;
llvm::Instruction::TermOps TermOpVal;
llvm::Instruction::MemoryOps MemOpVal;
llvm::Instruction::OtherOps OtherOpVal;
llvm::Module::Endianness Endianness;
BinaryOpInfo BinaryOpVal;
TermOpInfo TermOpVal;
MemOpInfo MemOpVal;
OtherOpInfo OtherOpVal;
llvm::Module::Endianness Endianness;
}
%type <ModuleVal> Module FunctionList
@ -1076,8 +1113,8 @@ Module *llvm::RunVMAsmParser(const char * AsmString, Module * M) {
// Binary Operators
%type <BinaryOpVal> ArithmeticOps LogicalOps SetCondOps // Binops Subcatagories
%token <BinaryOpVal> ADD SUB MUL DIV REM AND OR XOR
%token <BinaryOpVal> SETLE SETGE SETLT SETGT SETEQ SETNE // Binary Comarators
%token <BinaryOpVal> ADD SUB MUL UDIV SDIV FDIV REM AND OR XOR
%token <BinaryOpVal> SETLE SETGE SETLT SETGT SETEQ SETNE // Binary Comparators
// Memory Instructions
%token <MemOpVal> MALLOC ALLOCA FREE LOAD STORE GETELEMENTPTR
@ -1114,7 +1151,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 | DIV | REM;
ArithmeticOps: ADD | SUB | MUL | UDIV | SDIV | FDIV | REM ;
LogicalOps : AND | OR | XOR;
SetCondOps : SETLE | SETGE | SETLT | SETGT | SETEQ | SETNE;
@ -1642,12 +1679,17 @@ ConstExpr: CAST '(' ConstVal TO Types ')' {
| ArithmeticOps '(' ConstVal ',' ConstVal ')' {
if ($3->getType() != $5->getType())
GEN_ERROR("Binary operator types must match!");
// First, make sure we're dealing with the right opcode by upgrading from
// obsolete versions.
sanitizeOpCode($1,$3->getType());
CHECK_FOR_ERROR;
// HACK: llvm 1.3 and earlier used to emit invalid pointer constant exprs.
// To retain backward compatibility with these early compilers, we emit a
// cast to the appropriate integer type automatically if we are in the
// broken case. See PR424 for more information.
if (!isa<PointerType>($3->getType())) {
$$ = ConstantExpr::get($1, $3, $5);
$$ = ConstantExpr::get($1.opcode, $3, $5);
} else {
const Type *IntPtrTy = 0;
switch (CurModule.CurrentModule->getPointerSize()) {
@ -1655,7 +1697,7 @@ ConstExpr: CAST '(' ConstVal TO Types ')' {
case Module::Pointer64: IntPtrTy = Type::LongTy; break;
default: GEN_ERROR("invalid pointer binary constant expr!");
}
$$ = ConstantExpr::get($1, ConstantExpr::getCast($3, IntPtrTy),
$$ = ConstantExpr::get($1.opcode, ConstantExpr::getCast($3, IntPtrTy),
ConstantExpr::getCast($5, IntPtrTy));
$$ = ConstantExpr::getCast($$, $3->getType());
}
@ -1669,13 +1711,13 @@ ConstExpr: CAST '(' ConstVal TO Types ')' {
!cast<PackedType>($3->getType())->getElementType()->isIntegral())
GEN_ERROR("Logical operator requires integral operands!");
}
$$ = ConstantExpr::get($1, $3, $5);
$$ = ConstantExpr::get($1.opcode, $3, $5);
CHECK_FOR_ERROR
}
| SetCondOps '(' ConstVal ',' ConstVal ')' {
if ($3->getType() != $5->getType())
GEN_ERROR("setcc operand types must match!");
$$ = ConstantExpr::get($1, $3, $5);
$$ = ConstantExpr::get($1.opcode, $3, $5);
CHECK_FOR_ERROR
}
| ShiftOps '(' ConstVal ',' ConstVal ')' {
@ -1683,7 +1725,7 @@ ConstExpr: CAST '(' ConstVal TO Types ')' {
GEN_ERROR("Shift count for shift constant must be unsigned byte!");
if (!$3->getType()->isInteger())
GEN_ERROR("Shift constant expression requires integer operand!");
$$ = ConstantExpr::get($1, $3, $5);
$$ = ConstantExpr::get($1.opcode, $3, $5);
CHECK_FOR_ERROR
}
| EXTRACTELEMENT '(' ConstVal ',' ConstVal ')' {
@ -2423,13 +2465,16 @@ 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 == Instruction::Rem)
if (isa<PackedType>((*$2).get()) && $1.opcode == Instruction::Rem)
GEN_ERROR("Rem not supported on packed types!");
// Upgrade the opcode from obsolete versions before we do anything with it.
sanitizeOpCode($1,*$2);
CHECK_FOR_ERROR;
Value* val1 = getVal(*$2, $3);
CHECK_FOR_ERROR
Value* val2 = getVal(*$2, $5);
CHECK_FOR_ERROR
$$ = BinaryOperator::create($1, val1, val2);
$$ = BinaryOperator::create($1.opcode, val1, val2);
if ($$ == 0)
GEN_ERROR("binary operator returned null!");
delete $2;
@ -2444,7 +2489,7 @@ InstVal : ArithmeticOps Types ValueRef ',' ValueRef {
CHECK_FOR_ERROR
Value* tmpVal2 = getVal(*$2, $5);
CHECK_FOR_ERROR
$$ = BinaryOperator::create($1, tmpVal1, tmpVal2);
$$ = BinaryOperator::create($1.opcode, tmpVal1, tmpVal2);
if ($$ == 0)
GEN_ERROR("binary operator returned null!");
delete $2;
@ -2458,7 +2503,7 @@ InstVal : ArithmeticOps Types ValueRef ',' ValueRef {
CHECK_FOR_ERROR
Value* tmpVal2 = getVal(*$2, $5);
CHECK_FOR_ERROR
$$ = new SetCondInst($1, tmpVal1, tmpVal2);
$$ = new SetCondInst($1.opcode, tmpVal1, tmpVal2);
if ($$ == 0)
GEN_ERROR("binary operator returned null!");
delete $2;
@ -2481,7 +2526,7 @@ InstVal : ArithmeticOps Types ValueRef ',' ValueRef {
GEN_ERROR("Shift amount must be ubyte!");
if (!$2->getType()->isInteger())
GEN_ERROR("Shift constant expression requires integer operand!");
$$ = new ShiftInst($1, $2, $4);
$$ = new ShiftInst($1.opcode, $2, $4);
CHECK_FOR_ERROR
}
| CAST ResolvedVal TO Types {

File diff suppressed because it is too large Load Diff

View File

@ -226,6 +226,18 @@ protected:
Function* F ///< The function into which BBs will be inserted
);
/// Convert previous opcode values into the current value and/or construct
/// the instruction. This function handles all *abnormal* cases for
/// instruction generation based on obsolete opcode values. The normal cases
/// are handled by the ParseInstruction function.
Instruction* handleObsoleteOpcodes(
unsigned &opcode, ///< The old opcode, possibly updated by this function
std::vector<unsigned> &Oprnds, ///< The operands to the instruction
unsigned &iType, ///< The type code from the bytecode file
const Type* InstTy, ///< The type of the instruction
BasicBlock* BB ///< The basic block to insert into, if we need to
);
/// @brief Parse a single instruction.
void ParseInstruction(
std::vector<unsigned>& Args, ///< The arguments to be filled in
@ -336,6 +348,13 @@ private:
// unreachable instruction.
bool hasNoUnreachableInst;
// In version 5 and prior, instructions were signless. In version 6,
// instructions became signed. For example in version 5 we have the DIV
// instruction but in version 6 we have FDIV, SDIV and UDIV to replace it.
// This causes a renumbering of the instruction codes in version 6 that must
// be dealt with when reading old bytecode files.
bool hasSignlessInstructions;
/// In release 1.7 we changed intrinsic functions to not be overloaded. There
/// is no bytecode change for this, but to optimize the auto-upgrade of calls
/// to intrinsic functions, we save a mapping of old function definitions to

View File

@ -40,7 +40,7 @@ using namespace llvm;
/// so that the reader can distinguish which format of the bytecode file has
/// been written.
/// @brief The bytecode version number
const unsigned BCVersionNum = 5;
const unsigned BCVersionNum = 6;
static RegisterPass<WriteBytecodePass> X("emitbytecode", "Bytecode Writer");

View File

@ -499,28 +499,35 @@ public:
void visitInvoke(InvokeInst &I) { assert(0 && "TODO"); }
void visitUnwind(UnwindInst &I) { assert(0 && "TODO"); }
void visitBinary(User &I, unsigned IntOp, unsigned FPOp, unsigned VecOp);
void visitIntBinary(User &I, unsigned IntOp, unsigned VecOp);
void visitFPBinary(User &I, unsigned FPOp, unsigned VecOp);
void visitShift(User &I, unsigned Opcode);
void visitAdd(User &I) {
visitBinary(I, ISD::ADD, ISD::FADD, ISD::VADD);
if (I.getType()->isFloatingPoint())
visitFPBinary(I, ISD::FADD, ISD::VADD);
else
visitIntBinary(I, ISD::ADD, ISD::VADD);
}
void visitSub(User &I);
void visitMul(User &I) {
visitBinary(I, ISD::MUL, ISD::FMUL, ISD::VMUL);
}
void visitDiv(User &I) {
const Type *Ty = I.getType();
visitBinary(I,
Ty->isSigned() ? ISD::SDIV : ISD::UDIV, ISD::FDIV,
Ty->isSigned() ? ISD::VSDIV : ISD::VUDIV);
void visitMul(User &I) {
if (I.getType()->isFloatingPoint())
visitFPBinary(I, ISD::FMUL, ISD::VMUL);
else
visitIntBinary(I, ISD::MUL, ISD::VMUL);
}
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();
visitBinary(I, Ty->isSigned() ? ISD::SREM : ISD::UREM, ISD::FREM, 0);
if (Ty->isFloatingPoint())
visitFPBinary(I, ISD::FREM, 0);
else
visitIntBinary(I, Ty->isSigned() ? ISD::SREM : ISD::UREM, 0);
}
void visitAnd(User &I) { visitBinary(I, ISD::AND, 0, ISD::VAND); }
void visitOr (User &I) { visitBinary(I, ISD::OR, 0, ISD::VOR); }
void visitXor(User &I) { visitBinary(I, ISD::XOR, 0, ISD::VXOR); }
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); }
void visitShl(User &I) { visitShift(I, ISD::SHL); }
void visitShr(User &I) {
visitShift(I, I.getType()->isUnsigned() ? ISD::SRL : ISD::SRA);
@ -1142,25 +1149,38 @@ void SelectionDAGLowering::visitSub(User &I) {
setValue(&I, DAG.getNode(ISD::FNEG, Op2.getValueType(), Op2));
return;
}
}
visitBinary(I, ISD::SUB, ISD::FSUB, ISD::VSUB);
visitFPBinary(I, ISD::FSUB, ISD::VSUB);
} else
visitIntBinary(I, ISD::SUB, ISD::VSUB);
}
void SelectionDAGLowering::visitBinary(User &I, unsigned IntOp, unsigned FPOp,
unsigned VecOp) {
void
SelectionDAGLowering::visitIntBinary(User &I, unsigned IntOp, unsigned VecOp) {
const Type *Ty = I.getType();
SDOperand Op1 = getValue(I.getOperand(0));
SDOperand Op2 = getValue(I.getOperand(1));
if (Ty->isIntegral()) {
setValue(&I, DAG.getNode(IntOp, Op1.getValueType(), Op1, Op2));
} else if (Ty->isFloatingPoint()) {
setValue(&I, DAG.getNode(FPOp, Op1.getValueType(), Op1, Op2));
} else {
const PackedType *PTy = cast<PackedType>(Ty);
if (const PackedType *PTy = dyn_cast<PackedType>(Ty)) {
SDOperand Num = DAG.getConstant(PTy->getNumElements(), MVT::i32);
SDOperand Typ = DAG.getValueType(TLI.getValueType(PTy->getElementType()));
setValue(&I, DAG.getNode(VecOp, MVT::Vector, Op1, Op2, Num, Typ));
} else {
setValue(&I, DAG.getNode(IntOp, Op1.getValueType(), Op1, Op2));
}
}
void
SelectionDAGLowering::visitFPBinary(User &I, unsigned FPOp, unsigned VecOp) {
const Type *Ty = I.getType();
SDOperand Op1 = getValue(I.getOperand(0));
SDOperand Op2 = getValue(I.getOperand(1));
if (const PackedType *PTy = dyn_cast<PackedType>(Ty)) {
SDOperand Num = DAG.getConstant(PTy->getNumElements(), MVT::i32);
SDOperand Typ = DAG.getValueType(TLI.getValueType(PTy->getElementType()));
setValue(&I, DAG.getNode(VecOp, MVT::Vector, Op1, Op2, Num, Typ));
} else {
setValue(&I, DAG.getNode(FPOp, Op1.getValueType(), Op1, Op2));
}
}

View File

@ -42,8 +42,12 @@ static GenericValue executeMulInst(GenericValue Src1, GenericValue Src2,
const Type *Ty);
static GenericValue executeRemInst(GenericValue Src1, GenericValue Src2,
const Type *Ty);
static GenericValue executeDivInst(GenericValue Src1, GenericValue Src2,
const Type *Ty);
static GenericValue executeUDivInst(GenericValue Src1, GenericValue Src2,
const Type *Ty);
static GenericValue executeSDivInst(GenericValue Src1, GenericValue Src2,
const Type *Ty);
static GenericValue executeFDivInst(GenericValue Src1, GenericValue Src2,
const Type *Ty);
static GenericValue executeAndInst(GenericValue Src1, GenericValue Src2,
const Type *Ty);
static GenericValue executeOrInst(GenericValue Src1, GenericValue Src2,
@ -89,10 +93,18 @@ GenericValue Interpreter::getConstantExprValue (ConstantExpr *CE,
return executeMulInst(getOperandValue(CE->getOperand(0), SF),
getOperandValue(CE->getOperand(1), SF),
CE->getOperand(0)->getType());
case Instruction::Div:
return executeDivInst(getOperandValue(CE->getOperand(0), SF),
getOperandValue(CE->getOperand(1), SF),
CE->getOperand(0)->getType());
case Instruction::SDiv:
return executeSDivInst(getOperandValue(CE->getOperand(0), SF),
getOperandValue(CE->getOperand(1), SF),
CE->getOperand(0)->getType());
case Instruction::UDiv:
return executeUDivInst(getOperandValue(CE->getOperand(0), SF),
getOperandValue(CE->getOperand(1), SF),
CE->getOperand(0)->getType());
case Instruction::FDiv:
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),
getOperandValue(CE->getOperand(1), SF),
@ -242,18 +254,44 @@ static GenericValue executeMulInst(GenericValue Src1, GenericValue Src2,
return Dest;
}
static GenericValue executeDivInst(GenericValue Src1, GenericValue Src2,
static GenericValue executeUDivInst(GenericValue Src1, GenericValue Src2,
const Type *Ty) {
GenericValue Dest;
if (Ty->isSigned())
Ty = Ty->getUnsignedVersion();
switch (Ty->getTypeID()) {
IMPLEMENT_BINARY_OPERATOR(/, UByte);
IMPLEMENT_BINARY_OPERATOR(/, UShort);
IMPLEMENT_BINARY_OPERATOR(/, UInt);
IMPLEMENT_BINARY_OPERATOR(/, ULong);
default:
std::cout << "Unhandled type for UDiv instruction: " << *Ty << "\n";
abort();
}
return Dest;
}
static GenericValue executeSDivInst(GenericValue Src1, GenericValue Src2,
const Type *Ty) {
GenericValue Dest;
if (Ty->isUnsigned())
Ty = Ty->getSignedVersion();
switch (Ty->getTypeID()) {
IMPLEMENT_BINARY_OPERATOR(/, SByte);
IMPLEMENT_BINARY_OPERATOR(/, Short);
IMPLEMENT_BINARY_OPERATOR(/, Int);
IMPLEMENT_BINARY_OPERATOR(/, Long);
default:
std::cout << "Unhandled type for SDiv instruction: " << *Ty << "\n";
abort();
}
return Dest;
}
static GenericValue executeFDivInst(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);
IMPLEMENT_BINARY_OPERATOR(/, Float);
IMPLEMENT_BINARY_OPERATOR(/, Double);
default:
@ -504,7 +542,9 @@ void Interpreter::visitBinaryOperator(BinaryOperator &I) {
case Instruction::Add: R = executeAddInst (Src1, Src2, Ty); break;
case Instruction::Sub: R = executeSubInst (Src1, Src2, Ty); break;
case Instruction::Mul: R = executeMulInst (Src1, Src2, Ty); break;
case Instruction::Div: R = executeDivInst (Src1, Src2, Ty); break;
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::And: R = executeAndInst (Src1, Src2, Ty); break;
case Instruction::Or: R = executeOrInst (Src1, Src2, Ty); break;

View File

@ -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) {

View File

@ -319,3 +319,16 @@ entry:
}
//===---------------------------------------------------------------------===//
-instcombine should handle this transform:
setcc (sdiv X / C1 ), C2
when X, C1, and C2 are unsigned. Similarly for udiv and signed operands.
Currently InstCombine avoids this transform but will do it when the signs of
the operands and the sign of the divide match. See the FIXME in
InstructionCombining.cpp in the visitSetCondInst method after the switch case
for Instruction::UDiv (around line 4447) for more details.
The SingleSource/Benchmarks/Shootout-C++/hash and hash2 tests have examples of
this construct.
//===---------------------------------------------------------------------===//

View File

@ -1275,7 +1275,7 @@ public:
return true;
} else if (Op2V == -1.0) {
// pow(x,-1.0) -> 1.0/x
BinaryOperator* div_inst= BinaryOperator::createDiv(
BinaryOperator* div_inst= BinaryOperator::createFDiv(
ConstantFP::get(Ty,1.0), base, ci->getName()+".pow", ci);
ci->replaceAllUsesWith(div_inst);
ci->eraseFromParent();

View File

@ -131,7 +131,11 @@ namespace {
Instruction *visitAdd(BinaryOperator &I);
Instruction *visitSub(BinaryOperator &I);
Instruction *visitMul(BinaryOperator &I);
Instruction *visitDiv(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);
@ -1822,7 +1826,9 @@ FoundSExt:
return R;
}
// add (cast *A to intptrtype) B -> cast (GEP (cast *A to sbyte*) B) -> intptrtype
// add (cast *A to intptrtype) B ->
// cast (GEP (cast *A to sbyte*) B) ->
// intptrtype
{
CastInst* CI = dyn_cast<CastInst>(LHS);
Value* Other = RHS;
@ -1975,11 +1981,11 @@ Instruction *InstCombiner::visitSub(BinaryOperator &I) {
}
// 0 - (X sdiv C) -> (X sdiv -C)
if (Op1I->getOpcode() == Instruction::Div)
if (Op1I->getOpcode() == Instruction::SDiv)
if (ConstantInt *CSI = dyn_cast<ConstantInt>(Op0))
if (CSI->getType()->isSigned() && CSI->isNullValue())
if (CSI->isNullValue())
if (Constant *DivRHS = dyn_cast<Constant>(Op1I->getOperand(1)))
return BinaryOperator::createDiv(Op1I->getOperand(0),
return BinaryOperator::createSDiv(Op1I->getOperand(0),
ConstantExpr::getNeg(DivRHS));
// X - X*C --> X * (1-C)
@ -2156,64 +2162,28 @@ Instruction *InstCombiner::visitMul(BinaryOperator &I) {
return Changed ? &I : 0;
}
Instruction *InstCombiner::visitDiv(BinaryOperator &I) {
/// This function implements the transforms on div instructions that work
/// regardless of the kind of div instruction it is (udiv, sdiv, or fdiv). It is
/// used by the visitors to those instructions.
/// @brief Transforms common to all three div instructions
Instruction* InstCombiner::commonDivTransforms(BinaryOperator &I) {
Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1);
if (isa<UndefValue>(Op0)) // undef / X -> 0
// undef / X -> 0
if (isa<UndefValue>(Op0))
return ReplaceInstUsesWith(I, Constant::getNullValue(I.getType()));
// X / undef -> undef
if (isa<UndefValue>(Op1))
return ReplaceInstUsesWith(I, Op1); // X / undef -> undef
return ReplaceInstUsesWith(I, Op1);
if (ConstantInt *RHS = dyn_cast<ConstantInt>(Op1)) {
// div X, 1 == X
if (RHS->equalsInt(1))
return ReplaceInstUsesWith(I, Op0);
// div X, -1 == -X
if (RHS->isAllOnesValue())
return BinaryOperator::createNeg(Op0);
if (Instruction *LHS = dyn_cast<Instruction>(Op0))
if (LHS->getOpcode() == Instruction::Div)
if (ConstantInt *LHSRHS = dyn_cast<ConstantInt>(LHS->getOperand(1))) {
// (X / C1) / C2 -> X / (C1*C2)
return BinaryOperator::createDiv(LHS->getOperand(0),
ConstantExpr::getMul(RHS, LHSRHS));
}
// Check to see if this is an unsigned division with an exact power of 2,
// if so, convert to a right shift.
if (ConstantInt *C = dyn_cast<ConstantInt>(RHS))
if (C->getType()->isUnsigned())
if (uint64_t Val = C->getZExtValue()) // Don't break X / 0
if (isPowerOf2_64(Val)) {
uint64_t C = Log2_64(Val);
return new ShiftInst(Instruction::Shr, Op0,
ConstantInt::get(Type::UByteTy, C));
}
// -X/C -> X/-C
if (RHS->getType()->isSigned())
if (Value *LHSNeg = dyn_castNegVal(Op0))
return BinaryOperator::createDiv(LHSNeg, ConstantExpr::getNeg(RHS));
if (!RHS->isNullValue()) {
if (SelectInst *SI = dyn_cast<SelectInst>(Op0))
if (Instruction *R = FoldOpIntoSelect(I, SI, this))
return R;
if (isa<PHINode>(Op0))
if (Instruction *NV = FoldOpIntoPhi(I))
return NV;
}
}
// Handle div X, Cond?Y:Z
// Handle cases involving: div X, (select Cond, Y, Z)
if (SelectInst *SI = dyn_cast<SelectInst>(Op1)) {
// div X, (Cond ? 0 : Y) -> div X, Y. If the div 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
// 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.
// also. Note that div X, Y is just as good as div X, 0 (undef)
if (Constant *ST = dyn_cast<Constant>(SI->getOperand(1)))
if (ST->isNullValue()) {
Instruction *CondI = dyn_cast<Instruction>(SI->getOperand(0));
@ -2225,6 +2195,7 @@ Instruction *InstCombiner::visitDiv(BinaryOperator &I) {
UpdateValueUsesWith(SI, SI->getOperand(2));
return &I;
}
// Likewise for: div X, (Cond ? Y : 0) -> div X, Y
if (Constant *ST = dyn_cast<Constant>(SI->getOperand(2)))
if (ST->isNullValue()) {
@ -2237,28 +2208,42 @@ Instruction *InstCombiner::visitDiv(BinaryOperator &I) {
UpdateValueUsesWith(SI, SI->getOperand(1));
return &I;
}
}
// If this is 'udiv X, (Cond ? C1, C2)' where C1&C2 are powers of two,
// transform this into: '(Cond ? (udiv X, C1) : (udiv X, C2))'.
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.
uint64_t TVA = STO->getZExtValue(), FVA = SFO->getZExtValue();
if (isPowerOf2_64(TVA) && isPowerOf2_64(FVA)) {
unsigned TSA = Log2_64(TVA), FSA = Log2_64(FVA);
Constant *TC = ConstantInt::get(Type::UByteTy, TSA);
Instruction *TSI = new ShiftInst(Instruction::Shr, Op0,
TC, SI->getName()+".t");
TSI = InsertNewInstBefore(TSI, I);
return 0;
}
Constant *FC = ConstantInt::get(Type::UByteTy, FSA);
Instruction *FSI = new ShiftInst(Instruction::Shr, Op0,
FC, SI->getName()+".f");
FSI = InsertNewInstBefore(FSI, I);
return new SelectInst(SI->getOperand(0), TSI, FSI);
}
/// This function implements the transforms common to both integer division
/// instructions (udiv and sdiv). It is called by the visitors to those integer
/// division instructions.
/// @brief Common integer divide transforms
Instruction* InstCombiner::commonIDivTransforms(BinaryOperator &I) {
Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1);
if (Instruction *Common = commonDivTransforms(I))
return Common;
if (ConstantInt *RHS = dyn_cast<ConstantInt>(Op1)) {
// div X, 1 == X
if (RHS->equalsInt(1))
return ReplaceInstUsesWith(I, Op0);
// (X / C1) / C2 -> X / (C1*C2)
if (Instruction *LHS = dyn_cast<Instruction>(Op0))
if (Instruction::BinaryOps(LHS->getOpcode()) == I.getOpcode())
if (ConstantInt *LHSRHS = dyn_cast<ConstantInt>(LHS->getOperand(1))) {
return BinaryOperator::create(I.getOpcode(), LHS->getOperand(0),
ConstantExpr::getMul(RHS, LHSRHS));
}
if (!RHS->isNullValue()) { // avoid X udiv 0
if (SelectInst *SI = dyn_cast<SelectInst>(Op0))
if (Instruction *R = FoldOpIntoSelect(I, SI, this))
return R;
if (isa<PHINode>(Op0))
if (Instruction *NV = FoldOpIntoPhi(I))
return NV;
}
}
// 0 / X == 0, we don't need to preserve faults!
@ -2266,48 +2251,137 @@ Instruction *InstCombiner::visitDiv(BinaryOperator &I) {
if (LHS->equalsInt(0))
return ReplaceInstUsesWith(I, Constant::getNullValue(I.getType()));
if (I.getType()->isSigned()) {
// If the sign bits of both operands are zero (i.e. we can prove they are
// unsigned inputs), turn this into a udiv.
uint64_t Mask = 1ULL << (I.getType()->getPrimitiveSizeInBits()-1);
if (MaskedValueIsZero(Op1, Mask) && MaskedValueIsZero(Op0, Mask)) {
const Type *NTy = Op0->getType()->getUnsignedVersion();
Instruction *LHS = new CastInst(Op0, NTy, Op0->getName());
InsertNewInstBefore(LHS, I);
Value *RHS;
if (Constant *R = dyn_cast<Constant>(Op1))
RHS = ConstantExpr::getCast(R, NTy);
else
RHS = InsertNewInstBefore(new CastInst(Op1, NTy, Op1->getName()), I);
Instruction *Div = BinaryOperator::createDiv(LHS, RHS, I.getName());
InsertNewInstBefore(Div, I);
return new CastInst(Div, I.getType());
}
} else {
// Known to be an unsigned division.
if (Instruction *RHSI = dyn_cast<Instruction>(I.getOperand(1))) {
// Turn A / (C1 << N), where C1 is "1<<C2" into A >> (N+C2) [udiv only].
if (RHSI->getOpcode() == Instruction::Shl &&
isa<ConstantInt>(RHSI->getOperand(0)) &&
RHSI->getOperand(0)->getType()->isUnsigned()) {
uint64_t C1 = cast<ConstantInt>(RHSI->getOperand(0))->getZExtValue();
if (isPowerOf2_64(C1)) {
uint64_t C2 = Log2_64(C1);
Value *Add = RHSI->getOperand(1);
if (C2) {
Constant *C2V = ConstantInt::get(Add->getType(), C2);
Add = InsertNewInstBefore(BinaryOperator::createAdd(Add, C2V,
"tmp"), I);
return 0;
}
Instruction *InstCombiner::visitUDiv(BinaryOperator &I) {
Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1);
// Handle the integer div common cases
if (Instruction *Common = commonIDivTransforms(I))
return Common;
// X udiv C^2 -> X >> C
// Check to see if this is an unsigned division with an exact power of 2,
// if so, convert to a right shift.
if (ConstantInt *C = dyn_cast<ConstantInt>(Op1)) {
if (uint64_t Val = C->getZExtValue()) // Don't break X / 0
if (isPowerOf2_64(Val)) {
uint64_t ShiftAmt = Log2_64(Val);
Value* X = Op0;
const Type* XTy = X->getType();
bool isSigned = XTy->isSigned();
if (isSigned)
X = InsertCastBefore(X, XTy->getUnsignedVersion(), I);
Instruction* Result =
new ShiftInst(Instruction::Shr, X,
ConstantInt::get(Type::UByteTy, ShiftAmt));
if (!isSigned)
return Result;
InsertNewInstBefore(Result, I);
return new CastInst(Result, XTy->getSignedVersion(), I.getName());
}
}
// X udiv (C1 << N), where C1 is "1<<C2" --> X >> (N+C2)
if (ShiftInst *RHSI = dyn_cast<ShiftInst>(I.getOperand(1))) {
if (RHSI->getOpcode() == Instruction::Shl &&
isa<ConstantInt>(RHSI->getOperand(0))) {
uint64_t C1 = cast<ConstantInt>(RHSI->getOperand(0))->getZExtValue();
if (isPowerOf2_64(C1)) {
Value *N = RHSI->getOperand(1);
const Type* NTy = N->getType();
bool isSigned = NTy->isSigned();
if (uint64_t C2 = Log2_64(C1)) {
if (isSigned) {
NTy = NTy->getUnsignedVersion();
N = InsertCastBefore(N, NTy, I);
}
return new ShiftInst(Instruction::Shr, Op0, Add);
Constant *C2V = ConstantInt::get(NTy, C2);
N = InsertNewInstBefore(BinaryOperator::createAdd(N, C2V, "tmp"), I);
}
Instruction* Result = new ShiftInst(Instruction::Shr, Op0, N);
if (!isSigned)
return Result;
InsertNewInstBefore(Result, I);
return new CastInst(Result, NTy->getSignedVersion(), I.getName());
}
}
}
// udiv X, (Select Cond, C1, C2) --> Select Cond, (shr X, C1), (shr 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)))
if (!STO->isNullValue() && !STO->isNullValue()) {
uint64_t TVA = STO->getZExtValue(), FVA = SFO->getZExtValue();
if (isPowerOf2_64(TVA) && isPowerOf2_64(FVA)) {
// Compute the shift amounts
unsigned TSA = Log2_64(TVA), FSA = Log2_64(FVA);
// Make sure we get the unsigned version of X
Value* X = Op0;
const Type* origXTy = X->getType();
bool isSigned = origXTy->isSigned();
if (isSigned)
X = InsertCastBefore(X, X->getType()->getUnsignedVersion(), I);
// Construct the "on true" case of the select
Constant *TC = ConstantInt::get(Type::UByteTy, TSA);
Instruction *TSI =
new ShiftInst(Instruction::Shr, X, TC, SI->getName()+".t");
TSI = InsertNewInstBefore(TSI, I);
// Construct the "on false" case of the select
Constant *FC = ConstantInt::get(Type::UByteTy, FSA);
Instruction *FSI =
new ShiftInst(Instruction::Shr, X, FC, SI->getName()+".f");
FSI = InsertNewInstBefore(FSI, I);
// construct the select instruction and return it.
SelectInst* NewSI =
new SelectInst(SI->getOperand(0), TSI, FSI, SI->getName());
if (!isSigned)
return NewSI;
InsertNewInstBefore(NewSI, I);
return new CastInst(NewSI, origXTy, NewSI->getName());
}
}
}
return 0;
}
Instruction *InstCombiner::visitSDiv(BinaryOperator &I) {
Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1);
// Handle the integer div common cases
if (Instruction *Common = commonIDivTransforms(I))
return Common;
if (ConstantInt *RHS = dyn_cast<ConstantInt>(Op1)) {
// sdiv X, -1 == -X
if (RHS->isAllOnesValue())
return BinaryOperator::createNeg(Op0);
// -X/C -> X/-C
if (Value *LHSNeg = dyn_castNegVal(Op0))
return BinaryOperator::createSDiv(LHSNeg, ConstantExpr::getNeg(RHS));
}
// If the sign bits of both operands are zero (i.e. we can prove they are
// unsigned inputs), turn this into a udiv.
if (I.getType()->isInteger()) {
uint64_t Mask = 1ULL << (I.getType()->getPrimitiveSizeInBits()-1);
if (MaskedValueIsZero(Op1, Mask) && MaskedValueIsZero(Op0, Mask)) {
return BinaryOperator::createUDiv(Op0, Op1, I.getName());
}
}
return 0;
}
Instruction *InstCombiner::visitFDiv(BinaryOperator &I) {
return commonDivTransforms(I);
}
/// GetFactor - If we can prove that the specified value is at least a multiple
/// of some factor, return that factor.
@ -2376,13 +2450,12 @@ Instruction *InstCombiner::visitRem(BinaryOperator &I) {
uint64_t Mask = 1ULL << (I.getType()->getPrimitiveSizeInBits()-1);
if (MaskedValueIsZero(Op1, Mask) && MaskedValueIsZero(Op0, Mask)) {
const Type *NTy = Op0->getType()->getUnsignedVersion();
Instruction *LHS = new CastInst(Op0, NTy, Op0->getName());
InsertNewInstBefore(LHS, I);
Value *LHS = InsertCastBefore(Op0, NTy, I);
Value *RHS;
if (Constant *R = dyn_cast<Constant>(Op1))
RHS = ConstantExpr::getCast(R, NTy);
else
RHS = InsertNewInstBefore(new CastInst(Op1, NTy, Op1->getName()), I);
RHS = InsertCastBefore(Op1, NTy, I);
Instruction *Rem = BinaryOperator::createRem(LHS, RHS, I.getName());
InsertNewInstBefore(Rem, I);
return new CastInst(Rem, I.getType());
@ -3717,14 +3790,6 @@ Instruction *InstCombiner::visitXor(BinaryOperator &I) {
return Changed ? &I : 0;
}
/// MulWithOverflow - Compute Result = In1*In2, returning true if the result
/// overflowed for this type.
static bool MulWithOverflow(ConstantInt *&Result, ConstantInt *In1,
ConstantInt *In2) {
Result = cast<ConstantInt>(ConstantExpr::getMul(In1, In2));
return !In2->isNullValue() && ConstantExpr::getDiv(Result, In2) != In1;
}
static bool isPositive(ConstantInt *C) {
return C->getSExtValue() >= 0;
}
@ -4126,7 +4191,9 @@ Instruction *InstCombiner::visitSetCondInst(SetCondInst &I) {
}
}
// Since the RHS is a constantInt (CI), if the left hand side is an
// instruction, see if that instruction also has constants so that the
// instruction can be folded into the setcc
if (Instruction *LHSI = dyn_cast<Instruction>(Op0))
switch (LHSI->getOpcode()) {
case Instruction::And:
@ -4379,27 +4446,60 @@ Instruction *InstCombiner::visitSetCondInst(SetCondInst &I) {
}
break;
case Instruction::Div:
// Fold: (div X, C1) op C2 -> range check
case Instruction::SDiv:
case Instruction::UDiv:
// Fold: setcc ([us]div X, C1), C2 -> range test
// Fold this div into the comparison, producing a range check.
// Determine, based on the divide type, what the range is being
// checked. If there is an overflow on the low or high side, remember
// it, otherwise compute the range [low, hi) bounding the new value.
// See: InsertRangeTest above for the kinds of replacements possible.
if (ConstantInt *DivRHS = dyn_cast<ConstantInt>(LHSI->getOperand(1))) {
// Fold this div into the comparison, producing a range check.
// Determine, based on the divide type, what the range is being
// checked. If there is an overflow on the low or high side, remember
// it, otherwise compute the range [low, hi) bounding the new value.
bool LoOverflow = false, HiOverflow = 0;
// FIXME: If the operand types don't match the type of the divide
// then don't attempt this transform. The code below doesn't have the
// logic to deal with a signed divide and an unsigned compare (and
// vice versa). This is because (x /s C1) <s C2 produces different
// results than (x /s C1) <u C2 or (x /u C1) <s C2 or even
// (x /u C1) <u C2. Simply casting the operands and result won't
// work. :( The if statement below tests that condition and bails
// if it finds it.
const Type* DivRHSTy = DivRHS->getType();
unsigned DivOpCode = LHSI->getOpcode();
if (I.isEquality() &&
((DivOpCode == Instruction::SDiv && DivRHSTy->isUnsigned()) ||
(DivOpCode == Instruction::UDiv && DivRHSTy->isSigned())))
break;
// Initialize the variables that will indicate the nature of the
// range check.
bool LoOverflow = false, HiOverflow = false;
ConstantInt *LoBound = 0, *HiBound = 0;
ConstantInt *Prod;
bool ProdOV = MulWithOverflow(Prod, CI, DivRHS);
// Compute Prod = CI * DivRHS. We are essentially solving an equation
// of form X/C1=C2. We solve for X by multiplying C1 (DivRHS) and
// C2 (CI). By solving for X we can turn this into a range check
// instead of computing a divide.
ConstantInt *Prod =
cast<ConstantInt>(ConstantExpr::getMul(CI, DivRHS));
// Determine if the product overflows by seeing if the product is
// not equal to the divide. Make sure we do the same kind of divide
// as in the LHS instruction that we're folding.
bool ProdOV = !DivRHS->isNullValue() &&
(DivOpCode == Instruction::SDiv ?
ConstantExpr::getSDiv(Prod, DivRHS) :
ConstantExpr::getUDiv(Prod, DivRHS)) != CI;
// Get the SetCC opcode
Instruction::BinaryOps Opcode = I.getOpcode();
if (DivRHS->isNullValue()) { // Don't hack on divide by zeros.
} else if (LHSI->getType()->isUnsigned()) { // udiv
if (DivRHS->isNullValue()) {
// Don't hack on divide by zeros!
} else if (DivOpCode == Instruction::UDiv) { // udiv
LoBound = Prod;
LoOverflow = ProdOV;
HiOverflow = ProdOV || AddWithOverflow(HiBound, LoBound, DivRHS);
} else if (isPositive(DivRHS)) { // Divisor is > 0.
} else if (isPositive(DivRHS)) { // Divisor is > 0.
if (CI->isNullValue()) { // (X / pos) op 0
// Can't overflow.
LoBound = cast<ConstantInt>(ConstantExpr::getNeg(SubOne(DivRHS)));
@ -4415,12 +4515,12 @@ Instruction *InstCombiner::visitSetCondInst(SetCondInst &I) {
HiBound = Prod;
HiOverflow = ProdOV;
}
} else { // Divisor is < 0.
} else { // Divisor is < 0.
if (CI->isNullValue()) { // (X / neg) op 0
LoBound = AddOne(DivRHS);
HiBound = cast<ConstantInt>(ConstantExpr::getNeg(DivRHS));
if (HiBound == DivRHS)
LoBound = 0; // - INTMIN = INTMIN
LoBound = 0; // - INTMIN = INTMIN
} else if (isPositive(CI)) { // (X / neg) op pos
HiOverflow = LoOverflow = ProdOV;
if (!LoOverflow)
@ -5679,6 +5779,23 @@ Instruction *InstCombiner::visitCastInst(CastInst &CI) {
ConstantInt::get(CI.getType(), 1));
}
break;
case Instruction::SDiv:
case Instruction::UDiv:
// If we are just changing the sign, rewrite.
if (DestBitSize == SrcBitSize) {
// Don't insert two casts if they cannot be eliminated. We allow two
// casts to be inserted if the sizes are the same. This could only be
// converting signedness, which is a noop.
if (!ValueRequiresCast(Op1, DestTy,TD) ||
!ValueRequiresCast(Op0, DestTy, TD)) {
Value *Op0c = InsertOperandCastBefore(Op0, DestTy, SrcI);
Value *Op1c = InsertOperandCastBefore(Op1, DestTy, SrcI);
return BinaryOperator::create(
cast<BinaryOperator>(SrcI)->getOpcode(), Op0c, Op1c);
}
}
break;
case Instruction::Shl:
// Allow changing the sign of the source operand. Do not allow changing
// the size of the shift, UNLESS the shift amount is a constant. We

View File

@ -788,7 +788,9 @@ void PredicateSimplifier::Forwards::visitBinaryOperator(BinaryOperator &BO) {
Instruction::BinaryOps ops = BO.getOpcode();
switch (ops) {
case Instruction::Div:
case Instruction::UDiv:
case Instruction::SDiv:
case Instruction::FDiv:
case Instruction::Rem: {
Value *Divisor = BO.getOperand(1);
KP.addNotEqual(Constant::getNullValue(Divisor->getType()), Divisor);

View File

@ -113,7 +113,9 @@ static bool isUnmovableInstruction(Instruction *I) {
I->getOpcode() == Instruction::Malloc ||
I->getOpcode() == Instruction::Invoke ||
I->getOpcode() == Instruction::Call ||
I->getOpcode() == Instruction::Div ||
I->getOpcode() == Instruction::UDiv ||
I->getOpcode() == Instruction::SDiv ||
I->getOpcode() == Instruction::FDiv ||
I->getOpcode() == Instruction::Rem)
return true;
return false;

View File

@ -40,7 +40,9 @@ 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 *div(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;
@ -106,8 +108,14 @@ class VISIBILITY_HIDDEN TemplateRules : public ConstRules {
virtual Constant *mul(const Constant *V1, const Constant *V2) const {
return SubClassName::Mul((const ArgType *)V1, (const ArgType *)V2);
}
virtual Constant *div(const Constant *V1, const Constant *V2) const {
return SubClassName::Div((const ArgType *)V1, (const ArgType *)V2);
virtual Constant *udiv(const Constant *V1, const Constant *V2) const {
return SubClassName::UDiv((const ArgType *)V1, (const ArgType *)V2);
}
virtual Constant *sdiv(const Constant *V1, const Constant *V2) const {
return SubClassName::SDiv((const ArgType *)V1, (const ArgType *)V2);
}
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);
@ -178,16 +186,18 @@ class VISIBILITY_HIDDEN TemplateRules : public ConstRules {
// Default "noop" implementations
//===--------------------------------------------------------------------===//
static Constant *Add(const ArgType *V1, const ArgType *V2) { return 0; }
static Constant *Sub(const ArgType *V1, const ArgType *V2) { return 0; }
static Constant *Mul(const ArgType *V1, const ArgType *V2) { return 0; }
static Constant *Div(const ArgType *V1, const ArgType *V2) { return 0; }
static Constant *Rem(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; }
static Constant *Shl(const ArgType *V1, const ArgType *V2) { return 0; }
static Constant *Shr(const ArgType *V1, const ArgType *V2) { return 0; }
static Constant *Add (const ArgType *V1, const ArgType *V2) { return 0; }
static Constant *Sub (const ArgType *V1, const ArgType *V2) { return 0; }
static Constant *Mul (const ArgType *V1, const ArgType *V2) { return 0; }
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 *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; }
static Constant *Shl (const ArgType *V1, const ArgType *V2) { return 0; }
static Constant *Shr (const ArgType *V1, const ArgType *V2) { return 0; }
static Constant *LessThan(const ArgType *V1, const ArgType *V2) {
return 0;
}
@ -373,8 +383,14 @@ struct VISIBILITY_HIDDEN ConstantPackedRules
static Constant *Mul(const ConstantPacked *V1, const ConstantPacked *V2) {
return EvalVectorOp(V1, V2, ConstantExpr::getMul);
}
static Constant *Div(const ConstantPacked *V1, const ConstantPacked *V2) {
return EvalVectorOp(V1, V2, ConstantExpr::getDiv);
static Constant *UDiv(const ConstantPacked *V1, const ConstantPacked *V2) {
return EvalVectorOp(V1, V2, ConstantExpr::getUDiv);
}
static Constant *SDiv(const ConstantPacked *V1, const ConstantPacked *V2) {
return EvalVectorOp(V1, V2, ConstantExpr::getSDiv);
}
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);
@ -493,18 +509,25 @@ struct VISIBILITY_HIDDEN DirectIntRules
DEF_CAST(Double, ConstantFP , double)
#undef DEF_CAST
static Constant *Div(const ConstantInt *V1, const ConstantInt *V2) {
if (V2->isNullValue()) return 0;
if (V2->isAllOnesValue() && // MIN_INT / -1
(BuiltinType)V1->getZExtValue() == -(BuiltinType)V1->getZExtValue())
static Constant *UDiv(const ConstantInt *V1, const ConstantInt *V2) {
if (V2->isNullValue())
return 0;
BuiltinType R =
(BuiltinType)V1->getZExtValue() / (BuiltinType)V2->getZExtValue();
BuiltinType R = (BuiltinType)(V1->getZExtValue() / V2->getZExtValue());
return ConstantInt::get(*Ty, R);
}
static Constant *Rem(const ConstantInt *V1,
const ConstantInt *V2) {
static Constant *SDiv(const ConstantInt *V1, const ConstantInt *V2) {
if (V2->isNullValue())
return 0;
if (V2->isAllOnesValue() && // MIN_INT / -1
(BuiltinType)V1->getSExtValue() == -(BuiltinType)V1->getSExtValue())
return 0;
BuiltinType R =
(BuiltinType)(V1->getSExtValue() / V2->getSExtValue());
return ConstantInt::get(*Ty, R);
}
static Constant *Rem(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())
@ -615,7 +638,7 @@ struct VISIBILITY_HIDDEN DirectFPRules
(BuiltinType)V2->getValue());
return ConstantFP::get(*Ty, Result);
}
static Constant *Div(const ConstantFP *V1, const ConstantFP *V2) {
static Constant *FDiv(const ConstantFP *V1, const ConstantFP *V2) {
BuiltinType inf = std::numeric_limits<BuiltinType>::infinity();
if (V2->isExactlyValue(0.0)) return ConstantFP::get(*Ty, inf);
if (V2->isExactlyValue(-0.0)) return ConstantFP::get(*Ty, -inf);
@ -1224,7 +1247,9 @@ Constant *llvm::ConstantFoldBinaryInstruction(unsigned Opcode,
case Instruction::Add: C = ConstRules::get(V1, V2).add(V1, V2); break;
case Instruction::Sub: C = ConstRules::get(V1, V2).sub(V1, V2); break;
case Instruction::Mul: C = ConstRules::get(V1, V2).mul(V1, V2); break;
case Instruction::Div: C = ConstRules::get(V1, V2).div(V1, V2); break;
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::And: C = ConstRules::get(V1, V2).op_and(V1, V2); break;
case Instruction::Or: C = ConstRules::get(V1, V2).op_or (V1, V2); break;
@ -1307,7 +1332,9 @@ Constant *llvm::ConstantFoldBinaryInstruction(unsigned Opcode,
case Instruction::Mul:
case Instruction::And:
return Constant::getNullValue(V1->getType());
case Instruction::Div:
case Instruction::UDiv:
case Instruction::SDiv:
case Instruction::FDiv:
case Instruction::Rem:
if (!isa<UndefValue>(V2)) // undef/X -> 0
return Constant::getNullValue(V1->getType());
@ -1358,7 +1385,8 @@ Constant *llvm::ConstantFoldBinaryInstruction(unsigned Opcode,
if (CI->getZExtValue() == 1)
return const_cast<Constant*>(V1); // X * 1 == X
break;
case Instruction::Div:
case Instruction::UDiv:
case Instruction::SDiv:
if (const ConstantInt *CI = dyn_cast<ConstantInt>(V2))
if (CI->getZExtValue() == 1)
return const_cast<Constant*>(V1); // X / 1 == X
@ -1419,7 +1447,9 @@ Constant *llvm::ConstantFoldBinaryInstruction(unsigned Opcode,
case Instruction::Shl:
case Instruction::Shr:
case Instruction::Sub:
case Instruction::Div:
case Instruction::SDiv:
case Instruction::UDiv:
case Instruction::FDiv:
case Instruction::Rem:
default: // These instructions cannot be flopped around.
break;

View File

@ -75,7 +75,9 @@ bool Constant::canTrap() const {
switch (CE->getOpcode()) {
default:
return false;
case Instruction::Div:
case Instruction::UDiv:
case Instruction::SDiv:
case Instruction::FDiv:
case Instruction::Rem:
// Div and rem can trap if the RHS is not known to be non-zero.
if (!isa<ConstantInt>(getOperand(1)) || getOperand(1)->isNullValue())
@ -446,8 +448,14 @@ Constant *ConstantExpr::getSub(Constant *C1, Constant *C2) {
Constant *ConstantExpr::getMul(Constant *C1, Constant *C2) {
return get(Instruction::Mul, C1, C2);
}
Constant *ConstantExpr::getDiv(Constant *C1, Constant *C2) {
return get(Instruction::Div, C1, C2);
Constant *ConstantExpr::getUDiv(Constant *C1, Constant *C2) {
return get(Instruction::UDiv, C1, C2);
}
Constant *ConstantExpr::getSDiv(Constant *C1, Constant *C2) {
return get(Instruction::SDiv, C1, 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);
@ -1437,13 +1445,27 @@ Constant *ConstantExpr::get(unsigned Opcode, Constant *C1, Constant *C2) {
#ifndef NDEBUG
switch (Opcode) {
case Instruction::Add: case Instruction::Sub:
case Instruction::Mul: case Instruction::Div:
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!");
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::FDiv:
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:

View File

@ -94,7 +94,9 @@ const char *Instruction::getOpcodeName(unsigned OpCode) {
case Add: return "add";
case Sub: return "sub";
case Mul: return "mul";
case Div: return "div";
case UDiv: return "udiv";
case SDiv: return "sdiv";
case FDiv: return "fdiv";
case Rem: return "rem";
// Logical operators...
@ -221,7 +223,9 @@ bool Instruction::isComparison(unsigned op) {
///
bool Instruction::isTrapping(unsigned op) {
switch(op) {
case Div:
case UDiv:
case SDiv:
case FDiv:
case Rem:
case Load:
case Store:

View File

@ -1022,7 +1022,7 @@ void BinaryOperator::init(BinaryOps iType)
#ifndef NDEBUG
switch (iType) {
case Add: case Sub:
case Mul: case Div:
case Mul:
case Rem:
assert(getType() == LHS->getType() &&
"Arithmetic operation should return same type as operands!");
@ -1030,6 +1030,22 @@ void BinaryOperator::init(BinaryOps iType)
isa<PackedType>(getType())) &&
"Tried to create an arithmetic operation on a non-arithmetic type!");
break;
case UDiv:
case SDiv:
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/UDIV");
break;
case FDiv:
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 FDIV");
break;
case And: case Or:
case Xor:
assert(getType() == LHS->getType() &&

View File

@ -1041,7 +1041,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::Div, op1, op2);
BinaryOperator::create( Instruction::SDiv, op1, op2);
bb->getInstList().push_back( divop );
push_value( bb, divop );
break;
@ -1072,7 +1072,7 @@ StackerCompiler::handle_word( int tkn )
// Divide by the third operand
BinaryOperator* divop =
BinaryOperator::create( Instruction::Div, multop, op3);
BinaryOperator::create( Instruction::SDiv, multop, op3);
bb->getInstList().push_back( divop );
// Push the result

View File

@ -57,13 +57,12 @@ bool %test9(ubyte %A) {
uint %test10(uint %X, bool %C) {
%V = select bool %C, uint 64, uint 8
%R = div uint %X, %V
%R = udiv uint %X, %V
ret uint %R
}
uint %test10(uint %X, ubyte %B) {
%Amt = shl uint 32, ubyte %B
%V = div uint %X, %Amt
ret uint %V
int %test11(int %X, bool %C) {
%A = select bool %C, int 1024, int 32
%B = udiv int %X, %A
ret int %B
}

View File

@ -773,7 +773,9 @@ void CppWriter::printConstant(const Constant *CV) {
case Instruction::Add: Out << "getAdd"; break;
case Instruction::Sub: Out << "getSub"; break;
case Instruction::Mul: Out << "getMul"; break;
case Instruction::Div: Out << "getDiv"; break;
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::And: Out << "getAnd"; break;
case Instruction::Or: Out << "getOr"; break;
@ -1021,7 +1023,9 @@ CppWriter::printInstruction(const Instruction *I, const std::string& bbname) {
case Instruction::Add:
case Instruction::Sub:
case Instruction::Mul:
case Instruction::Div:
case Instruction::UDiv:
case Instruction::SDiv:
case Instruction::FDiv:
case Instruction::Rem:
case Instruction::And:
case Instruction::Or:
@ -1033,7 +1037,9 @@ CppWriter::printInstruction(const Instruction *I, const std::string& bbname) {
case Instruction::Add: Out << "Instruction::Add"; break;
case Instruction::Sub: Out << "Instruction::Sub"; break;
case Instruction::Mul: Out << "Instruction::Mul"; break;
case Instruction::Div: Out << "Instruction::Div"; break;
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::And: Out << "Instruction::And"; break;
case Instruction::Or: Out << "Instruction::Or"; break;