mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-01-31 12:41:49 +01:00
[IR] Add a dedicated FNeg IR Instruction
The IEEE-754 Standard makes it clear that fneg(x) and fsub(-0.0, x) are two different operations. The former is a bitwise operation, while the latter is an arithmetic operation. This patch creates a dedicated FNeg IR Instruction to model that behavior. Differential Revision: https://reviews.llvm.org/D53877 llvm-svn: 346774
This commit is contained in:
parent
71947d8d0a
commit
3a2064d3a0
@ -54,6 +54,8 @@ extern "C" {
|
||||
* @{
|
||||
*/
|
||||
|
||||
/// External users depend on the following values being stable. It is not safe
|
||||
/// to reorder them.
|
||||
typedef enum {
|
||||
/* Terminator Instructions */
|
||||
LLVMRet = 1,
|
||||
@ -64,6 +66,9 @@ typedef enum {
|
||||
/* removed 6 due to API changes */
|
||||
LLVMUnreachable = 7,
|
||||
|
||||
/* Standard Unary Operators */
|
||||
LLVMFNeg = 66,
|
||||
|
||||
/* Standard Binary Operators */
|
||||
LLVMAdd = 8,
|
||||
LLVMFAdd = 9,
|
||||
|
@ -342,6 +342,7 @@ enum ConstantsCodes {
|
||||
CST_CODE_INLINEASM = 23, // INLINEASM: [sideeffect|alignstack|
|
||||
// asmdialect,asmstr,conststr]
|
||||
CST_CODE_CE_GEP_WITH_INRANGE_INDEX = 24, // [opty, flags, n x operands]
|
||||
CST_CODE_CE_UNOP = 25, // CE_UNOP: [opcode, opval]
|
||||
};
|
||||
|
||||
/// CastOpcodes - These are values used in the bitcode files to encode which
|
||||
@ -364,6 +365,14 @@ enum CastOpcodes {
|
||||
CAST_ADDRSPACECAST = 12
|
||||
};
|
||||
|
||||
/// UnaryOpcodes - These are values used in the bitcode files to encode which
|
||||
/// unop a CST_CODE_CE_UNOP or a XXX refers to. The values of these enums
|
||||
/// have no fixed relation to the LLVM IR enum values. Changing these will
|
||||
/// break compatibility with old files.
|
||||
enum UnaryOpcodes {
|
||||
UNOP_NEG = 0
|
||||
};
|
||||
|
||||
/// BinaryOpcodes - These are values used in the bitcode files to encode which
|
||||
/// binop a CST_CODE_CE_BINOP or a XXX refers to. The values of these enums
|
||||
/// have no fixed relation to the LLVM IR enum values. Changing these will
|
||||
@ -524,6 +533,7 @@ enum FunctionCodes {
|
||||
// 53 is unused.
|
||||
// 54 is unused.
|
||||
FUNC_CODE_OPERAND_BUNDLE = 55, // OPERAND_BUNDLE: [tag#, value...]
|
||||
FUNC_CODE_INST_UNOP = 56, // UNOP: [opcode, ty, opval]
|
||||
};
|
||||
|
||||
enum UseListCodes {
|
||||
|
@ -300,6 +300,8 @@ private:
|
||||
|
||||
bool translateFSub(const User &U, MachineIRBuilder &MIRBuilder);
|
||||
|
||||
bool translateFNeg(const User &U, MachineIRBuilder &MIRBuilder);
|
||||
|
||||
bool translateAdd(const User &U, MachineIRBuilder &MIRBuilder) {
|
||||
return translateBinaryOp(TargetOpcode::G_ADD, U, MIRBuilder);
|
||||
}
|
||||
|
@ -1114,6 +1114,13 @@ public:
|
||||
static Constant *getSelect(Constant *C, Constant *V1, Constant *V2,
|
||||
Type *OnlyIfReducedTy = nullptr);
|
||||
|
||||
/// get - Return a unary operator constant expression,
|
||||
/// folding if possible.
|
||||
///
|
||||
/// \param OnlyIfReducedTy see \a getWithOperands() docs.
|
||||
static Constant *get(unsigned Opcode, Constant *C1, unsigned Flags = 0,
|
||||
Type *OnlyIfReducedTy = nullptr);
|
||||
|
||||
/// get - Return a binary or shift operator constant expression,
|
||||
/// folding if possible.
|
||||
///
|
||||
|
@ -263,6 +263,7 @@ public:
|
||||
// of instructions...
|
||||
//
|
||||
RetTy visitCastInst(CastInst &I) { DELEGATE(UnaryInstruction);}
|
||||
RetTy visitUnaryOperator(UnaryOperator &I) { DELEGATE(UnaryInstruction);}
|
||||
RetTy visitBinaryOperator(BinaryOperator &I) { DELEGATE(Instruction);}
|
||||
RetTy visitCmpInst(CmpInst &I) { DELEGATE(Instruction);}
|
||||
RetTy visitUnaryInstruction(UnaryInstruction &I){ DELEGATE(Instruction);}
|
||||
|
@ -32,6 +32,20 @@
|
||||
#define LAST_TERM_INST(num)
|
||||
#endif
|
||||
|
||||
#ifndef FIRST_UNARY_INST
|
||||
#define FIRST_UNARY_INST(num)
|
||||
#endif
|
||||
#ifndef HANDLE_UNARY_INST
|
||||
#ifndef HANDLE_INST
|
||||
#define HANDLE_UNARY_INST(num, opcode, instclass)
|
||||
#else
|
||||
#define HANDLE_UNARY_INST(num, opcode, Class) HANDLE_INST(num, opcode, Class)
|
||||
#endif
|
||||
#endif
|
||||
#ifndef LAST_UNARY_INST
|
||||
#define LAST_UNARY_INST(num)
|
||||
#endif
|
||||
|
||||
#ifndef FIRST_BINARY_INST
|
||||
#define FIRST_BINARY_INST(num)
|
||||
#endif
|
||||
@ -123,87 +137,96 @@ HANDLE_TERM_INST ( 9, CatchRet , CatchReturnInst)
|
||||
HANDLE_TERM_INST (10, CatchSwitch , CatchSwitchInst)
|
||||
LAST_TERM_INST (10)
|
||||
|
||||
// Standard unary operators...
|
||||
FIRST_UNARY_INST(11)
|
||||
HANDLE_UNARY_INST(11, FNeg , UnaryOperator)
|
||||
LAST_UNARY_INST(11)
|
||||
|
||||
// Standard binary operators...
|
||||
FIRST_BINARY_INST(11)
|
||||
HANDLE_BINARY_INST(11, Add , BinaryOperator)
|
||||
HANDLE_BINARY_INST(12, FAdd , BinaryOperator)
|
||||
HANDLE_BINARY_INST(13, Sub , BinaryOperator)
|
||||
HANDLE_BINARY_INST(14, FSub , BinaryOperator)
|
||||
HANDLE_BINARY_INST(15, Mul , BinaryOperator)
|
||||
HANDLE_BINARY_INST(16, FMul , BinaryOperator)
|
||||
HANDLE_BINARY_INST(17, UDiv , BinaryOperator)
|
||||
HANDLE_BINARY_INST(18, SDiv , BinaryOperator)
|
||||
HANDLE_BINARY_INST(19, FDiv , BinaryOperator)
|
||||
HANDLE_BINARY_INST(20, URem , BinaryOperator)
|
||||
HANDLE_BINARY_INST(21, SRem , BinaryOperator)
|
||||
HANDLE_BINARY_INST(22, FRem , BinaryOperator)
|
||||
FIRST_BINARY_INST(12)
|
||||
HANDLE_BINARY_INST(12, Add , BinaryOperator)
|
||||
HANDLE_BINARY_INST(13, FAdd , BinaryOperator)
|
||||
HANDLE_BINARY_INST(14, Sub , BinaryOperator)
|
||||
HANDLE_BINARY_INST(15, FSub , BinaryOperator)
|
||||
HANDLE_BINARY_INST(16, Mul , BinaryOperator)
|
||||
HANDLE_BINARY_INST(17, FMul , BinaryOperator)
|
||||
HANDLE_BINARY_INST(18, UDiv , BinaryOperator)
|
||||
HANDLE_BINARY_INST(19, SDiv , BinaryOperator)
|
||||
HANDLE_BINARY_INST(20, FDiv , BinaryOperator)
|
||||
HANDLE_BINARY_INST(21, URem , BinaryOperator)
|
||||
HANDLE_BINARY_INST(22, SRem , BinaryOperator)
|
||||
HANDLE_BINARY_INST(23, FRem , BinaryOperator)
|
||||
|
||||
// Logical operators (integer operands)
|
||||
HANDLE_BINARY_INST(23, Shl , BinaryOperator) // Shift left (logical)
|
||||
HANDLE_BINARY_INST(24, LShr , BinaryOperator) // Shift right (logical)
|
||||
HANDLE_BINARY_INST(25, AShr , BinaryOperator) // Shift right (arithmetic)
|
||||
HANDLE_BINARY_INST(26, And , BinaryOperator)
|
||||
HANDLE_BINARY_INST(27, Or , BinaryOperator)
|
||||
HANDLE_BINARY_INST(28, Xor , BinaryOperator)
|
||||
LAST_BINARY_INST(28)
|
||||
HANDLE_BINARY_INST(24, Shl , BinaryOperator) // Shift left (logical)
|
||||
HANDLE_BINARY_INST(25, LShr , BinaryOperator) // Shift right (logical)
|
||||
HANDLE_BINARY_INST(26, AShr , BinaryOperator) // Shift right (arithmetic)
|
||||
HANDLE_BINARY_INST(27, And , BinaryOperator)
|
||||
HANDLE_BINARY_INST(28, Or , BinaryOperator)
|
||||
HANDLE_BINARY_INST(29, Xor , BinaryOperator)
|
||||
LAST_BINARY_INST(29)
|
||||
|
||||
// Memory operators...
|
||||
FIRST_MEMORY_INST(29)
|
||||
HANDLE_MEMORY_INST(29, Alloca, AllocaInst) // Stack management
|
||||
HANDLE_MEMORY_INST(30, Load , LoadInst ) // Memory manipulation instrs
|
||||
HANDLE_MEMORY_INST(31, Store , StoreInst )
|
||||
HANDLE_MEMORY_INST(32, GetElementPtr, GetElementPtrInst)
|
||||
HANDLE_MEMORY_INST(33, Fence , FenceInst )
|
||||
HANDLE_MEMORY_INST(34, AtomicCmpXchg , AtomicCmpXchgInst )
|
||||
HANDLE_MEMORY_INST(35, AtomicRMW , AtomicRMWInst )
|
||||
LAST_MEMORY_INST(35)
|
||||
FIRST_MEMORY_INST(30)
|
||||
HANDLE_MEMORY_INST(30, Alloca, AllocaInst) // Stack management
|
||||
HANDLE_MEMORY_INST(31, Load , LoadInst ) // Memory manipulation instrs
|
||||
HANDLE_MEMORY_INST(32, Store , StoreInst )
|
||||
HANDLE_MEMORY_INST(33, GetElementPtr, GetElementPtrInst)
|
||||
HANDLE_MEMORY_INST(34, Fence , FenceInst )
|
||||
HANDLE_MEMORY_INST(35, AtomicCmpXchg , AtomicCmpXchgInst )
|
||||
HANDLE_MEMORY_INST(36, AtomicRMW , AtomicRMWInst )
|
||||
LAST_MEMORY_INST(36)
|
||||
|
||||
// Cast operators ...
|
||||
// NOTE: The order matters here because CastInst::isEliminableCastPair
|
||||
// NOTE: (see Instructions.cpp) encodes a table based on this ordering.
|
||||
FIRST_CAST_INST(36)
|
||||
HANDLE_CAST_INST(36, Trunc , TruncInst ) // Truncate integers
|
||||
HANDLE_CAST_INST(37, ZExt , ZExtInst ) // Zero extend integers
|
||||
HANDLE_CAST_INST(38, SExt , SExtInst ) // Sign extend integers
|
||||
HANDLE_CAST_INST(39, FPToUI , FPToUIInst ) // floating point -> UInt
|
||||
HANDLE_CAST_INST(40, FPToSI , FPToSIInst ) // floating point -> SInt
|
||||
HANDLE_CAST_INST(41, UIToFP , UIToFPInst ) // UInt -> floating point
|
||||
HANDLE_CAST_INST(42, SIToFP , SIToFPInst ) // SInt -> floating point
|
||||
HANDLE_CAST_INST(43, FPTrunc , FPTruncInst ) // Truncate floating point
|
||||
HANDLE_CAST_INST(44, FPExt , FPExtInst ) // Extend floating point
|
||||
HANDLE_CAST_INST(45, PtrToInt, PtrToIntInst) // Pointer -> Integer
|
||||
HANDLE_CAST_INST(46, IntToPtr, IntToPtrInst) // Integer -> Pointer
|
||||
HANDLE_CAST_INST(47, BitCast , BitCastInst ) // Type cast
|
||||
HANDLE_CAST_INST(48, AddrSpaceCast, AddrSpaceCastInst) // addrspace cast
|
||||
LAST_CAST_INST(48)
|
||||
FIRST_CAST_INST(37)
|
||||
HANDLE_CAST_INST(37, Trunc , TruncInst ) // Truncate integers
|
||||
HANDLE_CAST_INST(38, ZExt , ZExtInst ) // Zero extend integers
|
||||
HANDLE_CAST_INST(39, SExt , SExtInst ) // Sign extend integers
|
||||
HANDLE_CAST_INST(40, FPToUI , FPToUIInst ) // floating point -> UInt
|
||||
HANDLE_CAST_INST(41, FPToSI , FPToSIInst ) // floating point -> SInt
|
||||
HANDLE_CAST_INST(42, UIToFP , UIToFPInst ) // UInt -> floating point
|
||||
HANDLE_CAST_INST(43, SIToFP , SIToFPInst ) // SInt -> floating point
|
||||
HANDLE_CAST_INST(44, FPTrunc , FPTruncInst ) // Truncate floating point
|
||||
HANDLE_CAST_INST(45, FPExt , FPExtInst ) // Extend floating point
|
||||
HANDLE_CAST_INST(46, PtrToInt, PtrToIntInst) // Pointer -> Integer
|
||||
HANDLE_CAST_INST(47, IntToPtr, IntToPtrInst) // Integer -> Pointer
|
||||
HANDLE_CAST_INST(48, BitCast , BitCastInst ) // Type cast
|
||||
HANDLE_CAST_INST(49, AddrSpaceCast, AddrSpaceCastInst) // addrspace cast
|
||||
LAST_CAST_INST(49)
|
||||
|
||||
FIRST_FUNCLETPAD_INST(49)
|
||||
HANDLE_FUNCLETPAD_INST(49, CleanupPad, CleanupPadInst)
|
||||
HANDLE_FUNCLETPAD_INST(50, CatchPad , CatchPadInst)
|
||||
LAST_FUNCLETPAD_INST(50)
|
||||
FIRST_FUNCLETPAD_INST(50)
|
||||
HANDLE_FUNCLETPAD_INST(50, CleanupPad, CleanupPadInst)
|
||||
HANDLE_FUNCLETPAD_INST(51, CatchPad , CatchPadInst)
|
||||
LAST_FUNCLETPAD_INST(51)
|
||||
|
||||
// Other operators...
|
||||
FIRST_OTHER_INST(51)
|
||||
HANDLE_OTHER_INST(51, ICmp , ICmpInst ) // Integer comparison instruction
|
||||
HANDLE_OTHER_INST(52, FCmp , FCmpInst ) // Floating point comparison instr.
|
||||
HANDLE_OTHER_INST(53, PHI , PHINode ) // PHI node instruction
|
||||
HANDLE_OTHER_INST(54, Call , CallInst ) // Call a function
|
||||
HANDLE_OTHER_INST(55, Select , SelectInst ) // select instruction
|
||||
HANDLE_USER_INST (56, UserOp1, Instruction) // May be used internally in a pass
|
||||
HANDLE_USER_INST (57, UserOp2, Instruction) // Internal to passes only
|
||||
HANDLE_OTHER_INST(58, VAArg , VAArgInst ) // vaarg instruction
|
||||
HANDLE_OTHER_INST(59, ExtractElement, ExtractElementInst)// extract from vector
|
||||
HANDLE_OTHER_INST(60, InsertElement, InsertElementInst) // insert into vector
|
||||
HANDLE_OTHER_INST(61, ShuffleVector, ShuffleVectorInst) // shuffle two vectors.
|
||||
HANDLE_OTHER_INST(62, ExtractValue, ExtractValueInst)// extract from aggregate
|
||||
HANDLE_OTHER_INST(63, InsertValue, InsertValueInst) // insert into aggregate
|
||||
HANDLE_OTHER_INST(64, LandingPad, LandingPadInst) // Landing pad instruction.
|
||||
LAST_OTHER_INST(64)
|
||||
FIRST_OTHER_INST(52)
|
||||
HANDLE_OTHER_INST(52, ICmp , ICmpInst ) // Integer comparison instruction
|
||||
HANDLE_OTHER_INST(53, FCmp , FCmpInst ) // Floating point comparison instr.
|
||||
HANDLE_OTHER_INST(54, PHI , PHINode ) // PHI node instruction
|
||||
HANDLE_OTHER_INST(55, Call , CallInst ) // Call a function
|
||||
HANDLE_OTHER_INST(56, Select , SelectInst ) // select instruction
|
||||
HANDLE_USER_INST (57, UserOp1, Instruction) // May be used internally in a pass
|
||||
HANDLE_USER_INST (58, UserOp2, Instruction) // Internal to passes only
|
||||
HANDLE_OTHER_INST(59, VAArg , VAArgInst ) // vaarg instruction
|
||||
HANDLE_OTHER_INST(60, ExtractElement, ExtractElementInst)// extract from vector
|
||||
HANDLE_OTHER_INST(61, InsertElement, InsertElementInst) // insert into vector
|
||||
HANDLE_OTHER_INST(62, ShuffleVector, ShuffleVectorInst) // shuffle two vectors.
|
||||
HANDLE_OTHER_INST(63, ExtractValue, ExtractValueInst)// extract from aggregate
|
||||
HANDLE_OTHER_INST(64, InsertValue, InsertValueInst) // insert into aggregate
|
||||
HANDLE_OTHER_INST(65, LandingPad, LandingPadInst) // Landing pad instruction.
|
||||
LAST_OTHER_INST(65)
|
||||
|
||||
#undef FIRST_TERM_INST
|
||||
#undef HANDLE_TERM_INST
|
||||
#undef LAST_TERM_INST
|
||||
|
||||
#undef FIRST_UNARY_INST
|
||||
#undef HANDLE_UNARY_INST
|
||||
#undef LAST_UNARY_INST
|
||||
|
||||
#undef FIRST_BINARY_INST
|
||||
#undef HANDLE_BINARY_INST
|
||||
#undef LAST_BINARY_INST
|
||||
|
@ -127,6 +127,7 @@ public:
|
||||
|
||||
const char *getOpcodeName() const { return getOpcodeName(getOpcode()); }
|
||||
bool isTerminator() const { return isTerminator(getOpcode()); }
|
||||
bool isUnaryOp() const { return isUnaryOp(getOpcode()); }
|
||||
bool isBinaryOp() const { return isBinaryOp(getOpcode()); }
|
||||
bool isIntDivRem() const { return isIntDivRem(getOpcode()); }
|
||||
bool isShift() { return isShift(getOpcode()); }
|
||||
@ -142,6 +143,9 @@ public:
|
||||
return OpCode >= TermOpsBegin && OpCode < TermOpsEnd;
|
||||
}
|
||||
|
||||
static inline bool isUnaryOp(unsigned Opcode) {
|
||||
return Opcode >= UnaryOpsBegin && Opcode < UnaryOpsEnd;
|
||||
}
|
||||
static inline bool isBinaryOp(unsigned Opcode) {
|
||||
return Opcode >= BinaryOpsBegin && Opcode < BinaryOpsEnd;
|
||||
}
|
||||
@ -662,6 +666,13 @@ public:
|
||||
#include "llvm/IR/Instruction.def"
|
||||
};
|
||||
|
||||
enum UnaryOps {
|
||||
#define FIRST_UNARY_INST(N) UnaryOpsBegin = N,
|
||||
#define HANDLE_UNARY_INST(N, OPC, CLASS) OPC = N,
|
||||
#define LAST_UNARY_INST(N) UnaryOpsEnd = N+1
|
||||
#include "llvm/IR/Instruction.def"
|
||||
};
|
||||
|
||||
enum BinaryOps {
|
||||
#define FIRST_BINARY_INST(N) BinaryOpsBegin = N,
|
||||
#define HANDLE_BINARY_INST(N, OPC, CLASS) OPC = N,
|
||||
|
@ -1103,6 +1103,71 @@ GetElementPtrInst::GetElementPtrInst(Type *PointeeType, Value *Ptr,
|
||||
|
||||
DEFINE_TRANSPARENT_OPERAND_ACCESSORS(GetElementPtrInst, Value)
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// UnaryOperator Class
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// a unary instruction
|
||||
class UnaryOperator : public UnaryInstruction {
|
||||
void AssertOK();
|
||||
|
||||
protected:
|
||||
UnaryOperator(UnaryOps iType, Value *S, Type *Ty,
|
||||
const Twine &Name, Instruction *InsertBefore);
|
||||
UnaryOperator(UnaryOps iType, Value *S, Type *Ty,
|
||||
const Twine &Name, BasicBlock *InsertAtEnd);
|
||||
|
||||
// Note: Instruction needs to be a friend here to call cloneImpl.
|
||||
friend class Instruction;
|
||||
|
||||
UnaryOperator *cloneImpl() const;
|
||||
|
||||
public:
|
||||
|
||||
/// Construct a unary instruction, given the opcode and an operand.
|
||||
/// Optionally (if InstBefore is specified) insert the instruction
|
||||
/// into a BasicBlock right before the specified instruction. The specified
|
||||
/// Instruction is allowed to be a dereferenced end iterator.
|
||||
///
|
||||
static UnaryOperator *Create(UnaryOps Op, Value *S,
|
||||
const Twine &Name = Twine(),
|
||||
Instruction *InsertBefore = nullptr);
|
||||
|
||||
/// Construct a unary instruction, given the opcode and an operand.
|
||||
/// Also automatically insert this instruction to the end of the
|
||||
/// BasicBlock specified.
|
||||
///
|
||||
static UnaryOperator *Create(UnaryOps Op, Value *S,
|
||||
const Twine &Name,
|
||||
BasicBlock *InsertAtEnd);
|
||||
|
||||
/// These methods just forward to Create, and are useful when you
|
||||
/// statically know what type of instruction you're going to create. These
|
||||
/// helpers just save some typing.
|
||||
#define HANDLE_UNARY_INST(N, OPC, CLASS) \
|
||||
static UnaryInstruction *Create##OPC(Value *V, \
|
||||
const Twine &Name = "") {\
|
||||
return Create(Instruction::OPC, V, Name);\
|
||||
}
|
||||
#include "llvm/IR/Instruction.def"
|
||||
#define HANDLE_UNARY_INST(N, OPC, CLASS) \
|
||||
static UnaryInstruction *Create##OPC(Value *V, \
|
||||
const Twine &Name, BasicBlock *BB) {\
|
||||
return Create(Instruction::OPC, V, Name, BB);\
|
||||
}
|
||||
#include "llvm/IR/Instruction.def"
|
||||
#define HANDLE_UNARY_INST(N, OPC, CLASS) \
|
||||
static UnaryInstruction *Create##OPC(Value *V, \
|
||||
const Twine &Name, Instruction *I) {\
|
||||
return Create(Instruction::OPC, V, Name, I);\
|
||||
}
|
||||
#include "llvm/IR/Instruction.def"
|
||||
|
||||
UnaryOps getOpcode() const {
|
||||
return static_cast<UnaryOps>(Instruction::getOpcode());
|
||||
}
|
||||
};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// ICmpInst Class
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -823,6 +823,8 @@ lltok::Kind LLLexer::LexIdentifier() {
|
||||
} \
|
||||
} while (false)
|
||||
|
||||
INSTKEYWORD(fneg, FNeg);
|
||||
|
||||
INSTKEYWORD(add, Add); INSTKEYWORD(fadd, FAdd);
|
||||
INSTKEYWORD(sub, Sub); INSTKEYWORD(fsub, FSub);
|
||||
INSTKEYWORD(mul, Mul); INSTKEYWORD(fmul, FMul);
|
||||
|
@ -3295,7 +3295,31 @@ bool LLParser::ParseValID(ValID &ID, PerFunctionState *PFS) {
|
||||
ID.Kind = ValID::t_Constant;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// Unary Operators.
|
||||
case lltok::kw_fneg: {
|
||||
unsigned Opc = Lex.getUIntVal();
|
||||
Constant *Val;
|
||||
Lex.Lex();
|
||||
if (ParseToken(lltok::lparen, "expected '(' in unary constantexpr") ||
|
||||
ParseGlobalTypeAndValue(Val) ||
|
||||
ParseToken(lltok::rparen, "expected ')' in unary constantexpr"))
|
||||
return true;
|
||||
|
||||
// Check that the type is valid for the operator.
|
||||
switch (Opc) {
|
||||
case Instruction::FNeg:
|
||||
if (!Val->getType()->isFPOrFPVectorTy())
|
||||
return Error(ID.Loc, "constexpr requires fp operands");
|
||||
break;
|
||||
default: llvm_unreachable("Unknown unary operator!");
|
||||
}
|
||||
unsigned Flags = 0;
|
||||
Constant *C = ConstantExpr::get(Opc, Val, Flags);
|
||||
ID.ConstantVal = C;
|
||||
ID.Kind = ValID::t_Constant;
|
||||
return false;
|
||||
}
|
||||
// Binary Operators.
|
||||
case lltok::kw_add:
|
||||
case lltok::kw_fadd:
|
||||
@ -5492,6 +5516,16 @@ int LLParser::ParseInstruction(Instruction *&Inst, BasicBlock *BB,
|
||||
case lltok::kw_catchswitch: return ParseCatchSwitch(Inst, PFS);
|
||||
case lltok::kw_catchpad: return ParseCatchPad(Inst, PFS);
|
||||
case lltok::kw_cleanuppad: return ParseCleanupPad(Inst, PFS);
|
||||
// Unary Operators.
|
||||
case lltok::kw_fneg: {
|
||||
FastMathFlags FMF = EatFastMathFlagsIfPresent();
|
||||
int Res = ParseUnaryOp(Inst, PFS, KeywordVal, 2);
|
||||
if (Res != 0)
|
||||
return Res;
|
||||
if (FMF.any())
|
||||
Inst->setFastMathFlags(FMF);
|
||||
return false;
|
||||
}
|
||||
// Binary Operators.
|
||||
case lltok::kw_add:
|
||||
case lltok::kw_sub:
|
||||
@ -6063,6 +6097,43 @@ bool LLParser::ParseCleanupPad(Instruction *&Inst, PerFunctionState &PFS) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Unary Operators.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// ParseUnaryOp
|
||||
/// ::= UnaryOp TypeAndValue ',' Value
|
||||
///
|
||||
/// If OperandType is 0, then any FP or integer operand is allowed. If it is 1,
|
||||
/// then any integer operand is allowed, if it is 2, any fp operand is allowed.
|
||||
bool LLParser::ParseUnaryOp(Instruction *&Inst, PerFunctionState &PFS,
|
||||
unsigned Opc, unsigned OperandType) {
|
||||
LocTy Loc; Value *LHS;
|
||||
if (ParseTypeAndValue(LHS, Loc, PFS))
|
||||
return true;
|
||||
|
||||
bool Valid;
|
||||
switch (OperandType) {
|
||||
default: llvm_unreachable("Unknown operand type!");
|
||||
case 0: // int or FP.
|
||||
Valid = LHS->getType()->isIntOrIntVectorTy() ||
|
||||
LHS->getType()->isFPOrFPVectorTy();
|
||||
break;
|
||||
case 1:
|
||||
Valid = LHS->getType()->isIntOrIntVectorTy();
|
||||
break;
|
||||
case 2:
|
||||
Valid = LHS->getType()->isFPOrFPVectorTy();
|
||||
break;
|
||||
}
|
||||
|
||||
if (!Valid)
|
||||
return Error(Loc, "invalid operand type for instruction");
|
||||
|
||||
Inst = UnaryOperator::Create((Instruction::UnaryOps)Opc, LHS);
|
||||
return false;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Binary Operators.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -571,6 +571,8 @@ namespace llvm {
|
||||
bool ParseCatchPad(Instruction *&Inst, PerFunctionState &PFS);
|
||||
bool ParseCleanupPad(Instruction *&Inst, PerFunctionState &PFS);
|
||||
|
||||
bool ParseUnaryOp(Instruction *&Inst, PerFunctionState &PFS, unsigned Opc,
|
||||
unsigned OperandType);
|
||||
bool ParseArithmetic(Instruction *&Inst, PerFunctionState &PFS, unsigned Opc,
|
||||
unsigned OperandType);
|
||||
bool ParseLogical(Instruction *&Inst, PerFunctionState &PFS, unsigned Opc);
|
||||
|
@ -270,6 +270,7 @@ enum Kind {
|
||||
kw_umin,
|
||||
|
||||
// Instruction Opcodes (Opcode in UIntVal).
|
||||
kw_fneg,
|
||||
kw_add,
|
||||
kw_fadd,
|
||||
kw_sub,
|
||||
|
@ -964,6 +964,20 @@ static int getDecodedCastOpcode(unsigned Val) {
|
||||
}
|
||||
}
|
||||
|
||||
static int getDecodedUnaryOpcode(unsigned Val, Type *Ty) {
|
||||
bool IsFP = Ty->isFPOrFPVectorTy();
|
||||
// UnOps are only valid for int/fp or vector of int/fp types
|
||||
if (!IsFP && !Ty->isIntOrIntVectorTy())
|
||||
return -1;
|
||||
|
||||
switch (Val) {
|
||||
default:
|
||||
return -1;
|
||||
case bitc::UNOP_NEG:
|
||||
return IsFP ? Instruction::FNeg : -1;
|
||||
}
|
||||
}
|
||||
|
||||
static int getDecodedBinaryOpcode(unsigned Val, Type *Ty) {
|
||||
bool IsFP = Ty->isFPOrFPVectorTy();
|
||||
// BinOps are only valid for int/fp or vector of int/fp types
|
||||
@ -2317,6 +2331,19 @@ Error BitcodeReader::parseConstants() {
|
||||
}
|
||||
break;
|
||||
}
|
||||
case bitc::CST_CODE_CE_UNOP: { // CE_UNOP: [opcode, opval]
|
||||
if (Record.size() < 2)
|
||||
return error("Invalid record");
|
||||
int Opc = getDecodedUnaryOpcode(Record[0], CurTy);
|
||||
if (Opc < 0) {
|
||||
V = UndefValue::get(CurTy); // Unknown unop.
|
||||
} else {
|
||||
Constant *LHS = ValueList.getConstantFwdRef(Record[1], CurTy);
|
||||
unsigned Flags = 0;
|
||||
V = ConstantExpr::get(Opc, LHS, Flags);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case bitc::CST_CODE_CE_BINOP: { // CE_BINOP: [opcode, opval, opval]
|
||||
if (Record.size() < 3)
|
||||
return error("Invalid record");
|
||||
@ -3535,7 +3562,27 @@ Error BitcodeReader::parseFunctionBody(Function *F) {
|
||||
I = nullptr;
|
||||
continue;
|
||||
}
|
||||
case bitc::FUNC_CODE_INST_UNOP: { // UNOP: [opval, ty, opcode]
|
||||
unsigned OpNum = 0;
|
||||
Value *LHS;
|
||||
if (getValueTypePair(Record, OpNum, NextValueNo, LHS) ||
|
||||
OpNum+1 > Record.size())
|
||||
return error("Invalid record");
|
||||
|
||||
int Opc = getDecodedUnaryOpcode(Record[OpNum++], LHS->getType());
|
||||
if (Opc == -1)
|
||||
return error("Invalid record");
|
||||
I = UnaryOperator::Create((Instruction::UnaryOps)Opc, LHS);
|
||||
InstructionList.push_back(I);
|
||||
if (OpNum < Record.size()) {
|
||||
if (isa<FPMathOperator>(I)) {
|
||||
FastMathFlags FMF = getDecodedFastMathFlags(Record[OpNum]);
|
||||
if (FMF.any())
|
||||
I->setFastMathFlags(FMF);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case bitc::FUNC_CODE_INST_BINOP: { // BINOP: [opval, ty, opval, opcode]
|
||||
unsigned OpNum = 0;
|
||||
Value *LHS, *RHS;
|
||||
|
@ -112,6 +112,8 @@ enum {
|
||||
|
||||
// FUNCTION_BLOCK abbrev id's.
|
||||
FUNCTION_INST_LOAD_ABBREV = bitc::FIRST_APPLICATION_ABBREV,
|
||||
FUNCTION_INST_UNOP_ABBREV,
|
||||
FUNCTION_INST_UNOP_FLAGS_ABBREV,
|
||||
FUNCTION_INST_BINOP_ABBREV,
|
||||
FUNCTION_INST_BINOP_FLAGS_ABBREV,
|
||||
FUNCTION_INST_CAST_ABBREV,
|
||||
@ -513,6 +515,13 @@ static unsigned getEncodedCastOpcode(unsigned Opcode) {
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned getEncodedUnaryOpcode(unsigned Opcode) {
|
||||
switch (Opcode) {
|
||||
default: llvm_unreachable("Unknown binary instruction!");
|
||||
case Instruction::FNeg: return bitc::UNOP_NEG;
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned getEncodedBinaryOpcode(unsigned Opcode) {
|
||||
switch (Opcode) {
|
||||
default: llvm_unreachable("Unknown binary instruction!");
|
||||
@ -2384,6 +2393,16 @@ void ModuleBitcodeWriter::writeConstants(unsigned FirstVal, unsigned LastVal,
|
||||
Record.push_back(Flags);
|
||||
}
|
||||
break;
|
||||
case Instruction::FNeg: {
|
||||
assert(CE->getNumOperands() == 1 && "Unknown constant expr!");
|
||||
Code = bitc::CST_CODE_CE_UNOP;
|
||||
Record.push_back(getEncodedUnaryOpcode(CE->getOpcode()));
|
||||
Record.push_back(VE.getValueID(C->getOperand(0)));
|
||||
uint64_t Flags = getOptimizationFlags(CE);
|
||||
if (Flags != 0)
|
||||
Record.push_back(Flags);
|
||||
break;
|
||||
}
|
||||
case Instruction::GetElementPtr: {
|
||||
Code = bitc::CST_CODE_CE_GEP;
|
||||
const auto *GO = cast<GEPOperator>(C);
|
||||
@ -2556,7 +2575,19 @@ void ModuleBitcodeWriter::writeInstruction(const Instruction &I,
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case Instruction::FNeg: {
|
||||
Code = bitc::FUNC_CODE_INST_UNOP;
|
||||
if (!pushValueAndType(I.getOperand(0), InstID, Vals))
|
||||
AbbrevToUse = FUNCTION_INST_UNOP_ABBREV;
|
||||
Vals.push_back(getEncodedUnaryOpcode(I.getOpcode()));
|
||||
uint64_t Flags = getOptimizationFlags(&I);
|
||||
if (Flags != 0) {
|
||||
if (AbbrevToUse == FUNCTION_INST_UNOP_ABBREV)
|
||||
AbbrevToUse = FUNCTION_INST_UNOP_FLAGS_ABBREV;
|
||||
Vals.push_back(Flags);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Instruction::GetElementPtr: {
|
||||
Code = bitc::FUNC_CODE_INST_GEP;
|
||||
AbbrevToUse = FUNCTION_INST_GEP_ABBREV;
|
||||
@ -3217,6 +3248,25 @@ void ModuleBitcodeWriter::writeBlockInfo() {
|
||||
FUNCTION_INST_LOAD_ABBREV)
|
||||
llvm_unreachable("Unexpected abbrev ordering!");
|
||||
}
|
||||
{ // INST_UNOP abbrev for FUNCTION_BLOCK.
|
||||
auto Abbv = std::make_shared<BitCodeAbbrev>();
|
||||
Abbv->Add(BitCodeAbbrevOp(bitc::FUNC_CODE_INST_UNOP));
|
||||
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LHS
|
||||
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 4)); // opc
|
||||
if (Stream.EmitBlockInfoAbbrev(bitc::FUNCTION_BLOCK_ID, Abbv) !=
|
||||
FUNCTION_INST_UNOP_ABBREV)
|
||||
llvm_unreachable("Unexpected abbrev ordering!");
|
||||
}
|
||||
{ // INST_UNOP_FLAGS abbrev for FUNCTION_BLOCK.
|
||||
auto Abbv = std::make_shared<BitCodeAbbrev>();
|
||||
Abbv->Add(BitCodeAbbrevOp(bitc::FUNC_CODE_INST_UNOP));
|
||||
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LHS
|
||||
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 4)); // opc
|
||||
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 8)); // flags
|
||||
if (Stream.EmitBlockInfoAbbrev(bitc::FUNCTION_BLOCK_ID, Abbv) !=
|
||||
FUNCTION_INST_UNOP_FLAGS_ABBREV)
|
||||
llvm_unreachable("Unexpected abbrev ordering!");
|
||||
}
|
||||
{ // INST_BINOP abbrev for FUNCTION_BLOCK.
|
||||
auto Abbv = std::make_shared<BitCodeAbbrev>();
|
||||
Abbv->Add(BitCodeAbbrevOp(bitc::FUNC_CODE_INST_BINOP));
|
||||
|
@ -330,6 +330,13 @@ bool IRTranslator::translateFSub(const User &U, MachineIRBuilder &MIRBuilder) {
|
||||
return translateBinaryOp(TargetOpcode::G_FSUB, U, MIRBuilder);
|
||||
}
|
||||
|
||||
bool IRTranslator::translateFNeg(const User &U, MachineIRBuilder &MIRBuilder) {
|
||||
MIRBuilder.buildInstr(TargetOpcode::G_FNEG)
|
||||
.addDef(getOrCreateVReg(U))
|
||||
.addUse(getOrCreateVReg(*U.getOperand(1)));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IRTranslator::translateCompare(const User &U,
|
||||
MachineIRBuilder &MIRBuilder) {
|
||||
const CmpInst *CI = dyn_cast<CmpInst>(&U);
|
||||
|
@ -2801,6 +2801,15 @@ static bool isVectorReductionOp(const User *I) {
|
||||
return ReduxExtracted;
|
||||
}
|
||||
|
||||
void SelectionDAGBuilder::visitUnary(const User &I, unsigned Opcode) {
|
||||
SDNodeFlags Flags;
|
||||
|
||||
SDValue Op = getValue(I.getOperand(0));
|
||||
SDValue UnNodeValue = DAG.getNode(Opcode, getCurSDLoc(), Op.getValueType(),
|
||||
Op, Flags);
|
||||
setValue(&I, UnNodeValue);
|
||||
}
|
||||
|
||||
void SelectionDAGBuilder::visitBinary(const User &I, unsigned Opcode) {
|
||||
SDNodeFlags Flags;
|
||||
if (auto *OFBinOp = dyn_cast<OverflowingBinaryOperator>(&I)) {
|
||||
|
@ -854,6 +854,9 @@ private:
|
||||
void visitInvoke(const InvokeInst &I);
|
||||
void visitResume(const ResumeInst &I);
|
||||
|
||||
void visitUnary(const User &I, unsigned Opcode);
|
||||
void visitFNeg(const User &I) { visitUnary(I, ISD::FNEG); }
|
||||
|
||||
void visitBinary(const User &I, unsigned Opcode);
|
||||
void visitShift(const User &I, unsigned Opcode);
|
||||
void visitAdd(const User &I) { visitBinary(I, ISD::ADD); }
|
||||
|
@ -1451,6 +1451,7 @@ int TargetLoweringBase::InstructionOpcodeToISD(unsigned Opcode) const {
|
||||
case CatchPad: return 0;
|
||||
case CatchSwitch: return 0;
|
||||
case CleanupPad: return 0;
|
||||
case FNeg: return ISD::FNEG;
|
||||
case Add: return ISD::ADD;
|
||||
case FAdd: return ISD::FADD;
|
||||
case Sub: return ISD::SUB;
|
||||
|
@ -1780,6 +1780,36 @@ Constant *ConstantExpr::getAddrSpaceCast(Constant *C, Type *DstTy,
|
||||
return getFoldedCast(Instruction::AddrSpaceCast, C, DstTy, OnlyIfReduced);
|
||||
}
|
||||
|
||||
Constant *ConstantExpr::get(unsigned Opcode, Constant *C, unsigned Flags,
|
||||
Type *OnlyIfReducedTy) {
|
||||
// Check the operands for consistency first.
|
||||
assert(Instruction::isUnaryOp(Opcode) &&
|
||||
"Invalid opcode in unary constant expression");
|
||||
|
||||
#ifndef NDEBUG
|
||||
switch (Opcode) {
|
||||
case Instruction::FNeg:
|
||||
assert(C->getType()->isFPOrFPVectorTy() &&
|
||||
"Tried to create a floating-point operation on a "
|
||||
"non-floating-point type!");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
// TODO: Try to constant fold operation.
|
||||
|
||||
if (OnlyIfReducedTy == C->getType())
|
||||
return nullptr;
|
||||
|
||||
Constant *ArgVec[] = { C };
|
||||
ConstantExprKeyType Key(Opcode, ArgVec, 0, Flags);
|
||||
|
||||
LLVMContextImpl *pImpl = C->getContext().pImpl;
|
||||
return pImpl->ExprConstants.getOrCreate(C->getType(), Key);
|
||||
}
|
||||
|
||||
Constant *ConstantExpr::get(unsigned Opcode, Constant *C1, Constant *C2,
|
||||
unsigned Flags, Type *OnlyIfReducedTy) {
|
||||
// Check the operands for consistency first.
|
||||
|
@ -529,7 +529,9 @@ struct ConstantExprKeyType {
|
||||
ConstantExpr *create(TypeClass *Ty) const {
|
||||
switch (Opcode) {
|
||||
default:
|
||||
if (Instruction::isCast(Opcode))
|
||||
if (Instruction::isCast(Opcode) ||
|
||||
(Opcode >= Instruction::UnaryOpsBegin &&
|
||||
Opcode < Instruction::UnaryOpsEnd))
|
||||
return new UnaryConstantExpr(Opcode, Ops[0], Ty);
|
||||
if ((Opcode >= Instruction::BinaryOpsBegin &&
|
||||
Opcode < Instruction::BinaryOpsEnd))
|
||||
|
@ -303,6 +303,9 @@ const char *Instruction::getOpcodeName(unsigned OpCode) {
|
||||
case CatchPad: return "catchpad";
|
||||
case CatchSwitch: return "catchswitch";
|
||||
|
||||
// Standard unary operators...
|
||||
case FNeg: return "fneg";
|
||||
|
||||
// Standard binary operators...
|
||||
case Add: return "add";
|
||||
case FAdd: return "fadd";
|
||||
|
@ -1956,6 +1956,59 @@ Type *ExtractValueInst::getIndexedType(Type *Agg,
|
||||
return const_cast<Type*>(Agg);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// UnaryOperator Class
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
UnaryOperator::UnaryOperator(UnaryOps iType, Value *S,
|
||||
Type *Ty, const Twine &Name,
|
||||
Instruction *InsertBefore)
|
||||
: UnaryInstruction(Ty, iType, S, InsertBefore) {
|
||||
Op<0>() = S;
|
||||
setName(Name);
|
||||
AssertOK();
|
||||
}
|
||||
|
||||
UnaryOperator::UnaryOperator(UnaryOps iType, Value *S,
|
||||
Type *Ty, const Twine &Name,
|
||||
BasicBlock *InsertAtEnd)
|
||||
: UnaryInstruction(Ty, iType, S, InsertAtEnd) {
|
||||
Op<0>() = S;
|
||||
setName(Name);
|
||||
AssertOK();
|
||||
}
|
||||
|
||||
UnaryOperator *UnaryOperator::Create(UnaryOps Op, Value *S,
|
||||
const Twine &Name,
|
||||
Instruction *InsertBefore) {
|
||||
return new UnaryOperator(Op, S, S->getType(), Name, InsertBefore);
|
||||
}
|
||||
|
||||
UnaryOperator *UnaryOperator::Create(UnaryOps Op, Value *S,
|
||||
const Twine &Name,
|
||||
BasicBlock *InsertAtEnd) {
|
||||
UnaryOperator *Res = Create(Op, S, Name);
|
||||
InsertAtEnd->getInstList().push_back(Res);
|
||||
return Res;
|
||||
}
|
||||
|
||||
void UnaryOperator::AssertOK() {
|
||||
Value *LHS = getOperand(0);
|
||||
(void)LHS; // Silence warnings.
|
||||
#ifndef NDEBUG
|
||||
switch (getOpcode()) {
|
||||
case FNeg:
|
||||
assert(getType() == LHS->getType() &&
|
||||
"Unary operation should return same type as operand!");
|
||||
assert(getType()->isFPOrFPVectorTy() &&
|
||||
"Tried to create a floating-point operation on a "
|
||||
"non-floating-point type!");
|
||||
break;
|
||||
default: llvm_unreachable("Invalid opcode provided");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// BinaryOperator Class
|
||||
//===----------------------------------------------------------------------===//
|
||||
@ -3697,6 +3750,10 @@ GetElementPtrInst *GetElementPtrInst::cloneImpl() const {
|
||||
return new (getNumOperands()) GetElementPtrInst(*this);
|
||||
}
|
||||
|
||||
UnaryOperator *UnaryOperator::cloneImpl() const {
|
||||
return Create(getOpcode(), Op<0>());
|
||||
}
|
||||
|
||||
BinaryOperator *BinaryOperator::cloneImpl() const {
|
||||
return Create(getOpcode(), Op<0>(), Op<1>());
|
||||
}
|
||||
|
@ -443,6 +443,7 @@ private:
|
||||
void visitBitCastInst(BitCastInst &I);
|
||||
void visitAddrSpaceCastInst(AddrSpaceCastInst &I);
|
||||
void visitPHINode(PHINode &PN);
|
||||
void visitUnaryOperator(UnaryOperator &U);
|
||||
void visitBinaryOperator(BinaryOperator &B);
|
||||
void visitICmpInst(ICmpInst &IC);
|
||||
void visitFCmpInst(FCmpInst &FC);
|
||||
@ -2990,6 +2991,28 @@ void Verifier::visitInvokeInst(InvokeInst &II) {
|
||||
visitTerminator(II);
|
||||
}
|
||||
|
||||
/// visitUnaryOperator - Check the argument to the unary operator.
|
||||
///
|
||||
void Verifier::visitUnaryOperator(UnaryOperator &U) {
|
||||
Assert(U.getType() == U.getOperand(0)->getType(),
|
||||
"Unary operators must have same type for"
|
||||
"operands and result!",
|
||||
&U);
|
||||
|
||||
switch (U.getOpcode()) {
|
||||
// Check that floating-point arithmetic operators are only used with
|
||||
// floating-point operands.
|
||||
case Instruction::FNeg:
|
||||
Assert(U.getType()->isFPOrFPVectorTy(),
|
||||
"FNeg operator only works with float types!", &U);
|
||||
break;
|
||||
default:
|
||||
llvm_unreachable("Unknown UnaryOperator opcode!");
|
||||
}
|
||||
|
||||
visitInstruction(U);
|
||||
}
|
||||
|
||||
/// visitBinaryOperator - Check that both arguments to the binary operator are
|
||||
/// of the same type!
|
||||
///
|
||||
|
@ -38,8 +38,12 @@ entry:
|
||||
%e = frem float %x, %y
|
||||
; CHECK: %e_vec = frem <3 x float> %vec, %vec
|
||||
%e_vec = frem <3 x float> %vec, %vec
|
||||
; CHECK: ret float %e
|
||||
ret float %e
|
||||
; CHECK: %f = fneg float %x
|
||||
%f = fneg float %x
|
||||
; CHECK: %f_vec = fneg <3 x float> %vec
|
||||
%f_vec = fneg <3 x float> %vec
|
||||
; CHECK: ret float %f
|
||||
ret float %f
|
||||
}
|
||||
|
||||
; CHECK: no_nan
|
||||
@ -72,8 +76,12 @@ entry:
|
||||
%e = frem nnan float %x, %y
|
||||
; CHECK: %e_vec = frem nnan <3 x float> %vec, %vec
|
||||
%e_vec = frem nnan <3 x float> %vec, %vec
|
||||
; CHECK: ret float %e
|
||||
ret float %e
|
||||
; CHECK: %f = fneg nnan float %x
|
||||
%f = fneg nnan float %x
|
||||
; CHECK: %f_vec = fneg nnan <3 x float> %vec
|
||||
%f_vec = fneg nnan <3 x float> %vec
|
||||
; CHECK: ret float %f
|
||||
ret float %f
|
||||
}
|
||||
|
||||
; CHECK: @contract(
|
||||
@ -174,6 +182,10 @@ entry:
|
||||
%e = frem nnan nsz float %x, %y
|
||||
; CHECK: %e_vec = frem nnan <3 x float> %vec, %vec
|
||||
%e_vec = frem nnan <3 x float> %vec, %vec
|
||||
; CHECK: ret float %e
|
||||
ret float %e
|
||||
; CHECK: %f = fneg nnan nsz float %x
|
||||
%f = fneg nnan nsz float %x
|
||||
; CHECK: %f_vec = fneg fast <3 x float> %vec
|
||||
%f_vec = fneg fast <3 x float> %vec
|
||||
; CHECK: ret float %f
|
||||
ret float %f
|
||||
}
|
||||
|
@ -762,7 +762,27 @@ define void @atomics(i32* %word) {
|
||||
}
|
||||
|
||||
;; Fast Math Flags
|
||||
define void @fastmathflags(float %op1, float %op2) {
|
||||
define void @fastmathflags_unop(float %op1) {
|
||||
%f.nnan = fneg nnan float %op1
|
||||
; CHECK: %f.nnan = fneg nnan float %op1
|
||||
%f.ninf = fneg ninf float %op1
|
||||
; CHECK: %f.ninf = fneg ninf float %op1
|
||||
%f.nsz = fneg nsz float %op1
|
||||
; CHECK: %f.nsz = fneg nsz float %op1
|
||||
%f.arcp = fneg arcp float %op1
|
||||
; CHECK: %f.arcp = fneg arcp float %op1
|
||||
%f.contract = fneg contract float %op1
|
||||
; CHECK: %f.contract = fneg contract float %op1
|
||||
%f.afn = fneg afn float %op1
|
||||
; CHECK: %f.afn = fneg afn float %op1
|
||||
%f.reassoc = fneg reassoc float %op1
|
||||
; CHECK: %f.reassoc = fneg reassoc float %op1
|
||||
%f.fast = fneg fast float %op1
|
||||
; CHECK: %f.fast = fneg fast float %op1
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @fastmathflags_binops(float %op1, float %op2) {
|
||||
%f.nnan = fadd nnan float %op1, %op2
|
||||
; CHECK: %f.nnan = fadd nnan float %op1, %op2
|
||||
%f.ninf = fadd ninf float %op1, %op2
|
||||
@ -997,6 +1017,13 @@ continue:
|
||||
ret i32 0
|
||||
}
|
||||
|
||||
; Instructions -- Unary Operations
|
||||
define void @instructions.unops(double %op1) {
|
||||
fneg double %op1
|
||||
; CHECK: fneg double %op1
|
||||
ret void
|
||||
}
|
||||
|
||||
; Instructions -- Binary Operations
|
||||
define void @instructions.binops(i8 %op1, i8 %op2) {
|
||||
; nuw x nsw
|
||||
|
@ -3,6 +3,15 @@
|
||||
; RUN: llvm-as < %s | llvm-bcanalyzer -dump | FileCheck %s
|
||||
; RUN: verify-uselistorder < %s
|
||||
|
||||
; CHECK: FUNCTION_BLOCK
|
||||
; CHECK: INST_UNOP {{.*}}op0=1
|
||||
; CHECK: INST_RET {{.*}}op0=1
|
||||
define double @test_float_unops(double %a) nounwind {
|
||||
%1 = fneg double %a
|
||||
ret double %1
|
||||
}
|
||||
|
||||
|
||||
; CHECK: FUNCTION_BLOCK
|
||||
; CHECK: INST_BINOP {{.*}}op0=1 op1=1
|
||||
; CHECK: INST_BINOP {{.*}}op0=1 op1=1
|
||||
|
@ -10,6 +10,21 @@ define float @fnegf(float %X) {
|
||||
ret float %Y
|
||||
}
|
||||
|
||||
define double @real_fneg(double %X) {
|
||||
%Y = fneg double %X ; <double> [#uses=1]
|
||||
ret double %Y
|
||||
}
|
||||
|
||||
define double @real_fneg_constant() {
|
||||
%Y = fneg double -2.0 ; <double> [#uses=1]
|
||||
ret double %Y
|
||||
}
|
||||
|
||||
define float @real_fnegf(float %X) {
|
||||
%Y = fneg float %X ; <float> [#uses=1]
|
||||
ret float %Y
|
||||
}
|
||||
|
||||
declare double @fabs(double)
|
||||
|
||||
declare float @fabsf(float)
|
||||
|
@ -127,3 +127,18 @@ define <4 x float> @fsub0_undef_elts_v4f32(<4 x float> %x) {
|
||||
ret <4 x float> %r
|
||||
}
|
||||
|
||||
define <4 x float> @fneg(<4 x float> %Q) nounwind {
|
||||
; X32-SSE-LABEL: fneg:
|
||||
; X32-SSE: # %bb.0:
|
||||
; X32-SSE-NEXT: xorps {{\.LCPI.*}}, %xmm0
|
||||
; X32-SSE-NEXT: retl
|
||||
;
|
||||
; X64-SSE-LABEL: fneg:
|
||||
; X64-SSE: # %bb.0:
|
||||
; X64-SSE-NEXT: xorps {{.*}}(%rip), %xmm0
|
||||
; X64-SSE-NEXT: retq
|
||||
%tmp = fneg <4 x float> %Q
|
||||
ret <4 x float> %tmp
|
||||
}
|
||||
|
||||
|
||||
|
@ -63,6 +63,14 @@ lpad:
|
||||
resume { i8*, i32 } zeroinitializer
|
||||
}
|
||||
|
||||
define i8 @call_with_same_range() {
|
||||
; CHECK-LABEL: @call_with_same_range
|
||||
; CHECK: tail call i8 @call_with_range
|
||||
bitcast i8 0 to i8
|
||||
%out = call i8 @dummy(), !range !0
|
||||
ret i8 %out
|
||||
}
|
||||
|
||||
define i8 @invoke_with_same_range() personality i8* undef {
|
||||
; CHECK-LABEL: @invoke_with_same_range()
|
||||
; CHECK: tail call i8 @invoke_with_range()
|
||||
@ -76,14 +84,6 @@ lpad:
|
||||
resume { i8*, i32 } zeroinitializer
|
||||
}
|
||||
|
||||
define i8 @call_with_same_range() {
|
||||
; CHECK-LABEL: @call_with_same_range
|
||||
; CHECK: tail call i8 @call_with_range
|
||||
bitcast i8 0 to i8
|
||||
%out = call i8 @dummy(), !range !0
|
||||
ret i8 %out
|
||||
}
|
||||
|
||||
|
||||
|
||||
declare i8 @dummy();
|
||||
|
@ -247,6 +247,7 @@ static const char *GetCodeName(unsigned CodeID, unsigned BlockID,
|
||||
STRINGIFY_CODE(CST_CODE, CE_CMP)
|
||||
STRINGIFY_CODE(CST_CODE, INLINEASM)
|
||||
STRINGIFY_CODE(CST_CODE, CE_SHUFVEC_EX)
|
||||
STRINGIFY_CODE(CST_CODE, CE_UNOP)
|
||||
case bitc::CST_CODE_BLOCKADDRESS: return "CST_CODE_BLOCKADDRESS";
|
||||
STRINGIFY_CODE(CST_CODE, DATA)
|
||||
}
|
||||
@ -267,6 +268,7 @@ static const char *GetCodeName(unsigned CodeID, unsigned BlockID,
|
||||
STRINGIFY_CODE(FUNC_CODE, INST_BR)
|
||||
STRINGIFY_CODE(FUNC_CODE, INST_SWITCH)
|
||||
STRINGIFY_CODE(FUNC_CODE, INST_INVOKE)
|
||||
STRINGIFY_CODE(FUNC_CODE, INST_UNOP)
|
||||
STRINGIFY_CODE(FUNC_CODE, INST_UNREACHABLE)
|
||||
STRINGIFY_CODE(FUNC_CODE, INST_CLEANUPRET)
|
||||
STRINGIFY_CODE(FUNC_CODE, INST_CATCHRET)
|
||||
|
Loading…
x
Reference in New Issue
Block a user