1
0
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:
Cameron McInally 2018-11-13 18:15:47 +00:00
parent 71947d8d0a
commit 3a2064d3a0
30 changed files with 594 additions and 82 deletions

View File

@ -54,6 +54,8 @@ extern "C" {
* @{ * @{
*/ */
/// External users depend on the following values being stable. It is not safe
/// to reorder them.
typedef enum { typedef enum {
/* Terminator Instructions */ /* Terminator Instructions */
LLVMRet = 1, LLVMRet = 1,
@ -64,6 +66,9 @@ typedef enum {
/* removed 6 due to API changes */ /* removed 6 due to API changes */
LLVMUnreachable = 7, LLVMUnreachable = 7,
/* Standard Unary Operators */
LLVMFNeg = 66,
/* Standard Binary Operators */ /* Standard Binary Operators */
LLVMAdd = 8, LLVMAdd = 8,
LLVMFAdd = 9, LLVMFAdd = 9,

View File

@ -342,6 +342,7 @@ enum ConstantsCodes {
CST_CODE_INLINEASM = 23, // INLINEASM: [sideeffect|alignstack| CST_CODE_INLINEASM = 23, // INLINEASM: [sideeffect|alignstack|
// asmdialect,asmstr,conststr] // asmdialect,asmstr,conststr]
CST_CODE_CE_GEP_WITH_INRANGE_INDEX = 24, // [opty, flags, n x operands] 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 /// CastOpcodes - These are values used in the bitcode files to encode which
@ -364,6 +365,14 @@ enum CastOpcodes {
CAST_ADDRSPACECAST = 12 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 /// 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 /// 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 /// have no fixed relation to the LLVM IR enum values. Changing these will
@ -524,6 +533,7 @@ enum FunctionCodes {
// 53 is unused. // 53 is unused.
// 54 is unused. // 54 is unused.
FUNC_CODE_OPERAND_BUNDLE = 55, // OPERAND_BUNDLE: [tag#, value...] FUNC_CODE_OPERAND_BUNDLE = 55, // OPERAND_BUNDLE: [tag#, value...]
FUNC_CODE_INST_UNOP = 56, // UNOP: [opcode, ty, opval]
}; };
enum UseListCodes { enum UseListCodes {

View File

@ -300,6 +300,8 @@ private:
bool translateFSub(const User &U, MachineIRBuilder &MIRBuilder); bool translateFSub(const User &U, MachineIRBuilder &MIRBuilder);
bool translateFNeg(const User &U, MachineIRBuilder &MIRBuilder);
bool translateAdd(const User &U, MachineIRBuilder &MIRBuilder) { bool translateAdd(const User &U, MachineIRBuilder &MIRBuilder) {
return translateBinaryOp(TargetOpcode::G_ADD, U, MIRBuilder); return translateBinaryOp(TargetOpcode::G_ADD, U, MIRBuilder);
} }

View File

@ -1114,6 +1114,13 @@ public:
static Constant *getSelect(Constant *C, Constant *V1, Constant *V2, static Constant *getSelect(Constant *C, Constant *V1, Constant *V2,
Type *OnlyIfReducedTy = nullptr); 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, /// get - Return a binary or shift operator constant expression,
/// folding if possible. /// folding if possible.
/// ///

View File

@ -263,6 +263,7 @@ public:
// of instructions... // of instructions...
// //
RetTy visitCastInst(CastInst &I) { DELEGATE(UnaryInstruction);} RetTy visitCastInst(CastInst &I) { DELEGATE(UnaryInstruction);}
RetTy visitUnaryOperator(UnaryOperator &I) { DELEGATE(UnaryInstruction);}
RetTy visitBinaryOperator(BinaryOperator &I) { DELEGATE(Instruction);} RetTy visitBinaryOperator(BinaryOperator &I) { DELEGATE(Instruction);}
RetTy visitCmpInst(CmpInst &I) { DELEGATE(Instruction);} RetTy visitCmpInst(CmpInst &I) { DELEGATE(Instruction);}
RetTy visitUnaryInstruction(UnaryInstruction &I){ DELEGATE(Instruction);} RetTy visitUnaryInstruction(UnaryInstruction &I){ DELEGATE(Instruction);}

View File

@ -32,6 +32,20 @@
#define LAST_TERM_INST(num) #define LAST_TERM_INST(num)
#endif #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 #ifndef FIRST_BINARY_INST
#define FIRST_BINARY_INST(num) #define FIRST_BINARY_INST(num)
#endif #endif
@ -123,87 +137,96 @@ HANDLE_TERM_INST ( 9, CatchRet , CatchReturnInst)
HANDLE_TERM_INST (10, CatchSwitch , CatchSwitchInst) HANDLE_TERM_INST (10, CatchSwitch , CatchSwitchInst)
LAST_TERM_INST (10) LAST_TERM_INST (10)
// Standard unary operators...
FIRST_UNARY_INST(11)
HANDLE_UNARY_INST(11, FNeg , UnaryOperator)
LAST_UNARY_INST(11)
// Standard binary operators... // Standard binary operators...
FIRST_BINARY_INST(11) FIRST_BINARY_INST(12)
HANDLE_BINARY_INST(11, Add , BinaryOperator) HANDLE_BINARY_INST(12, Add , BinaryOperator)
HANDLE_BINARY_INST(12, FAdd , BinaryOperator) HANDLE_BINARY_INST(13, FAdd , BinaryOperator)
HANDLE_BINARY_INST(13, Sub , BinaryOperator) HANDLE_BINARY_INST(14, Sub , BinaryOperator)
HANDLE_BINARY_INST(14, FSub , BinaryOperator) HANDLE_BINARY_INST(15, FSub , BinaryOperator)
HANDLE_BINARY_INST(15, Mul , BinaryOperator) HANDLE_BINARY_INST(16, Mul , BinaryOperator)
HANDLE_BINARY_INST(16, FMul , BinaryOperator) HANDLE_BINARY_INST(17, FMul , BinaryOperator)
HANDLE_BINARY_INST(17, UDiv , BinaryOperator) HANDLE_BINARY_INST(18, UDiv , BinaryOperator)
HANDLE_BINARY_INST(18, SDiv , BinaryOperator) HANDLE_BINARY_INST(19, SDiv , BinaryOperator)
HANDLE_BINARY_INST(19, FDiv , BinaryOperator) HANDLE_BINARY_INST(20, FDiv , BinaryOperator)
HANDLE_BINARY_INST(20, URem , BinaryOperator) HANDLE_BINARY_INST(21, URem , BinaryOperator)
HANDLE_BINARY_INST(21, SRem , BinaryOperator) HANDLE_BINARY_INST(22, SRem , BinaryOperator)
HANDLE_BINARY_INST(22, FRem , BinaryOperator) HANDLE_BINARY_INST(23, FRem , BinaryOperator)
// Logical operators (integer operands) // Logical operators (integer operands)
HANDLE_BINARY_INST(23, Shl , BinaryOperator) // Shift left (logical) HANDLE_BINARY_INST(24, Shl , BinaryOperator) // Shift left (logical)
HANDLE_BINARY_INST(24, LShr , BinaryOperator) // Shift right (logical) HANDLE_BINARY_INST(25, LShr , BinaryOperator) // Shift right (logical)
HANDLE_BINARY_INST(25, AShr , BinaryOperator) // Shift right (arithmetic) HANDLE_BINARY_INST(26, AShr , BinaryOperator) // Shift right (arithmetic)
HANDLE_BINARY_INST(26, And , BinaryOperator) HANDLE_BINARY_INST(27, And , BinaryOperator)
HANDLE_BINARY_INST(27, Or , BinaryOperator) HANDLE_BINARY_INST(28, Or , BinaryOperator)
HANDLE_BINARY_INST(28, Xor , BinaryOperator) HANDLE_BINARY_INST(29, Xor , BinaryOperator)
LAST_BINARY_INST(28) LAST_BINARY_INST(29)
// Memory operators... // Memory operators...
FIRST_MEMORY_INST(29) FIRST_MEMORY_INST(30)
HANDLE_MEMORY_INST(29, Alloca, AllocaInst) // Stack management HANDLE_MEMORY_INST(30, Alloca, AllocaInst) // Stack management
HANDLE_MEMORY_INST(30, Load , LoadInst ) // Memory manipulation instrs HANDLE_MEMORY_INST(31, Load , LoadInst ) // Memory manipulation instrs
HANDLE_MEMORY_INST(31, Store , StoreInst ) HANDLE_MEMORY_INST(32, Store , StoreInst )
HANDLE_MEMORY_INST(32, GetElementPtr, GetElementPtrInst) HANDLE_MEMORY_INST(33, GetElementPtr, GetElementPtrInst)
HANDLE_MEMORY_INST(33, Fence , FenceInst ) HANDLE_MEMORY_INST(34, Fence , FenceInst )
HANDLE_MEMORY_INST(34, AtomicCmpXchg , AtomicCmpXchgInst ) HANDLE_MEMORY_INST(35, AtomicCmpXchg , AtomicCmpXchgInst )
HANDLE_MEMORY_INST(35, AtomicRMW , AtomicRMWInst ) HANDLE_MEMORY_INST(36, AtomicRMW , AtomicRMWInst )
LAST_MEMORY_INST(35) LAST_MEMORY_INST(36)
// Cast operators ... // Cast operators ...
// NOTE: The order matters here because CastInst::isEliminableCastPair // NOTE: The order matters here because CastInst::isEliminableCastPair
// NOTE: (see Instructions.cpp) encodes a table based on this ordering. // NOTE: (see Instructions.cpp) encodes a table based on this ordering.
FIRST_CAST_INST(36) FIRST_CAST_INST(37)
HANDLE_CAST_INST(36, Trunc , TruncInst ) // Truncate integers HANDLE_CAST_INST(37, Trunc , TruncInst ) // Truncate integers
HANDLE_CAST_INST(37, ZExt , ZExtInst ) // Zero extend integers HANDLE_CAST_INST(38, ZExt , ZExtInst ) // Zero extend integers
HANDLE_CAST_INST(38, SExt , SExtInst ) // Sign extend integers HANDLE_CAST_INST(39, SExt , SExtInst ) // Sign extend integers
HANDLE_CAST_INST(39, FPToUI , FPToUIInst ) // floating point -> UInt HANDLE_CAST_INST(40, FPToUI , FPToUIInst ) // floating point -> UInt
HANDLE_CAST_INST(40, FPToSI , FPToSIInst ) // floating point -> SInt HANDLE_CAST_INST(41, FPToSI , FPToSIInst ) // floating point -> SInt
HANDLE_CAST_INST(41, UIToFP , UIToFPInst ) // UInt -> floating point HANDLE_CAST_INST(42, UIToFP , UIToFPInst ) // UInt -> floating point
HANDLE_CAST_INST(42, SIToFP , SIToFPInst ) // SInt -> floating point HANDLE_CAST_INST(43, SIToFP , SIToFPInst ) // SInt -> floating point
HANDLE_CAST_INST(43, FPTrunc , FPTruncInst ) // Truncate floating point HANDLE_CAST_INST(44, FPTrunc , FPTruncInst ) // Truncate floating point
HANDLE_CAST_INST(44, FPExt , FPExtInst ) // Extend floating point HANDLE_CAST_INST(45, FPExt , FPExtInst ) // Extend floating point
HANDLE_CAST_INST(45, PtrToInt, PtrToIntInst) // Pointer -> Integer HANDLE_CAST_INST(46, PtrToInt, PtrToIntInst) // Pointer -> Integer
HANDLE_CAST_INST(46, IntToPtr, IntToPtrInst) // Integer -> Pointer HANDLE_CAST_INST(47, IntToPtr, IntToPtrInst) // Integer -> Pointer
HANDLE_CAST_INST(47, BitCast , BitCastInst ) // Type cast HANDLE_CAST_INST(48, BitCast , BitCastInst ) // Type cast
HANDLE_CAST_INST(48, AddrSpaceCast, AddrSpaceCastInst) // addrspace cast HANDLE_CAST_INST(49, AddrSpaceCast, AddrSpaceCastInst) // addrspace cast
LAST_CAST_INST(48) LAST_CAST_INST(49)
FIRST_FUNCLETPAD_INST(49) FIRST_FUNCLETPAD_INST(50)
HANDLE_FUNCLETPAD_INST(49, CleanupPad, CleanupPadInst) HANDLE_FUNCLETPAD_INST(50, CleanupPad, CleanupPadInst)
HANDLE_FUNCLETPAD_INST(50, CatchPad , CatchPadInst) HANDLE_FUNCLETPAD_INST(51, CatchPad , CatchPadInst)
LAST_FUNCLETPAD_INST(50) LAST_FUNCLETPAD_INST(51)
// Other operators... // Other operators...
FIRST_OTHER_INST(51) FIRST_OTHER_INST(52)
HANDLE_OTHER_INST(51, ICmp , ICmpInst ) // Integer comparison instruction HANDLE_OTHER_INST(52, ICmp , ICmpInst ) // Integer comparison instruction
HANDLE_OTHER_INST(52, FCmp , FCmpInst ) // Floating point comparison instr. HANDLE_OTHER_INST(53, FCmp , FCmpInst ) // Floating point comparison instr.
HANDLE_OTHER_INST(53, PHI , PHINode ) // PHI node instruction HANDLE_OTHER_INST(54, PHI , PHINode ) // PHI node instruction
HANDLE_OTHER_INST(54, Call , CallInst ) // Call a function HANDLE_OTHER_INST(55, Call , CallInst ) // Call a function
HANDLE_OTHER_INST(55, Select , SelectInst ) // select instruction HANDLE_OTHER_INST(56, Select , SelectInst ) // select instruction
HANDLE_USER_INST (56, UserOp1, Instruction) // May be used internally in a pass HANDLE_USER_INST (57, UserOp1, Instruction) // May be used internally in a pass
HANDLE_USER_INST (57, UserOp2, Instruction) // Internal to passes only HANDLE_USER_INST (58, UserOp2, Instruction) // Internal to passes only
HANDLE_OTHER_INST(58, VAArg , VAArgInst ) // vaarg instruction HANDLE_OTHER_INST(59, VAArg , VAArgInst ) // vaarg instruction
HANDLE_OTHER_INST(59, ExtractElement, ExtractElementInst)// extract from vector HANDLE_OTHER_INST(60, ExtractElement, ExtractElementInst)// extract from vector
HANDLE_OTHER_INST(60, InsertElement, InsertElementInst) // insert into vector HANDLE_OTHER_INST(61, InsertElement, InsertElementInst) // insert into vector
HANDLE_OTHER_INST(61, ShuffleVector, ShuffleVectorInst) // shuffle two vectors. HANDLE_OTHER_INST(62, ShuffleVector, ShuffleVectorInst) // shuffle two vectors.
HANDLE_OTHER_INST(62, ExtractValue, ExtractValueInst)// extract from aggregate HANDLE_OTHER_INST(63, ExtractValue, ExtractValueInst)// extract from aggregate
HANDLE_OTHER_INST(63, InsertValue, InsertValueInst) // insert into aggregate HANDLE_OTHER_INST(64, InsertValue, InsertValueInst) // insert into aggregate
HANDLE_OTHER_INST(64, LandingPad, LandingPadInst) // Landing pad instruction. HANDLE_OTHER_INST(65, LandingPad, LandingPadInst) // Landing pad instruction.
LAST_OTHER_INST(64) LAST_OTHER_INST(65)
#undef FIRST_TERM_INST #undef FIRST_TERM_INST
#undef HANDLE_TERM_INST #undef HANDLE_TERM_INST
#undef LAST_TERM_INST #undef LAST_TERM_INST
#undef FIRST_UNARY_INST
#undef HANDLE_UNARY_INST
#undef LAST_UNARY_INST
#undef FIRST_BINARY_INST #undef FIRST_BINARY_INST
#undef HANDLE_BINARY_INST #undef HANDLE_BINARY_INST
#undef LAST_BINARY_INST #undef LAST_BINARY_INST

View File

@ -127,6 +127,7 @@ public:
const char *getOpcodeName() const { return getOpcodeName(getOpcode()); } const char *getOpcodeName() const { return getOpcodeName(getOpcode()); }
bool isTerminator() const { return isTerminator(getOpcode()); } bool isTerminator() const { return isTerminator(getOpcode()); }
bool isUnaryOp() const { return isUnaryOp(getOpcode()); }
bool isBinaryOp() const { return isBinaryOp(getOpcode()); } bool isBinaryOp() const { return isBinaryOp(getOpcode()); }
bool isIntDivRem() const { return isIntDivRem(getOpcode()); } bool isIntDivRem() const { return isIntDivRem(getOpcode()); }
bool isShift() { return isShift(getOpcode()); } bool isShift() { return isShift(getOpcode()); }
@ -142,6 +143,9 @@ public:
return OpCode >= TermOpsBegin && OpCode < TermOpsEnd; return OpCode >= TermOpsBegin && OpCode < TermOpsEnd;
} }
static inline bool isUnaryOp(unsigned Opcode) {
return Opcode >= UnaryOpsBegin && Opcode < UnaryOpsEnd;
}
static inline bool isBinaryOp(unsigned Opcode) { static inline bool isBinaryOp(unsigned Opcode) {
return Opcode >= BinaryOpsBegin && Opcode < BinaryOpsEnd; return Opcode >= BinaryOpsBegin && Opcode < BinaryOpsEnd;
} }
@ -662,6 +666,13 @@ public:
#include "llvm/IR/Instruction.def" #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 { enum BinaryOps {
#define FIRST_BINARY_INST(N) BinaryOpsBegin = N, #define FIRST_BINARY_INST(N) BinaryOpsBegin = N,
#define HANDLE_BINARY_INST(N, OPC, CLASS) OPC = N, #define HANDLE_BINARY_INST(N, OPC, CLASS) OPC = N,

View File

@ -1103,6 +1103,71 @@ GetElementPtrInst::GetElementPtrInst(Type *PointeeType, Value *Ptr,
DEFINE_TRANSPARENT_OPERAND_ACCESSORS(GetElementPtrInst, Value) 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 // ICmpInst Class
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//

View File

@ -823,6 +823,8 @@ lltok::Kind LLLexer::LexIdentifier() {
} \ } \
} while (false) } while (false)
INSTKEYWORD(fneg, FNeg);
INSTKEYWORD(add, Add); INSTKEYWORD(fadd, FAdd); INSTKEYWORD(add, Add); INSTKEYWORD(fadd, FAdd);
INSTKEYWORD(sub, Sub); INSTKEYWORD(fsub, FSub); INSTKEYWORD(sub, Sub); INSTKEYWORD(fsub, FSub);
INSTKEYWORD(mul, Mul); INSTKEYWORD(fmul, FMul); INSTKEYWORD(mul, Mul); INSTKEYWORD(fmul, FMul);

View File

@ -3295,7 +3295,31 @@ bool LLParser::ParseValID(ValID &ID, PerFunctionState *PFS) {
ID.Kind = ValID::t_Constant; ID.Kind = ValID::t_Constant;
return false; 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. // Binary Operators.
case lltok::kw_add: case lltok::kw_add:
case lltok::kw_fadd: 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_catchswitch: return ParseCatchSwitch(Inst, PFS);
case lltok::kw_catchpad: return ParseCatchPad(Inst, PFS); case lltok::kw_catchpad: return ParseCatchPad(Inst, PFS);
case lltok::kw_cleanuppad: return ParseCleanupPad(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. // Binary Operators.
case lltok::kw_add: case lltok::kw_add:
case lltok::kw_sub: case lltok::kw_sub:
@ -6063,6 +6097,43 @@ bool LLParser::ParseCleanupPad(Instruction *&Inst, PerFunctionState &PFS) {
return false; 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. // Binary Operators.
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//

View File

@ -571,6 +571,8 @@ namespace llvm {
bool ParseCatchPad(Instruction *&Inst, PerFunctionState &PFS); bool ParseCatchPad(Instruction *&Inst, PerFunctionState &PFS);
bool ParseCleanupPad(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, bool ParseArithmetic(Instruction *&Inst, PerFunctionState &PFS, unsigned Opc,
unsigned OperandType); unsigned OperandType);
bool ParseLogical(Instruction *&Inst, PerFunctionState &PFS, unsigned Opc); bool ParseLogical(Instruction *&Inst, PerFunctionState &PFS, unsigned Opc);

View File

@ -270,6 +270,7 @@ enum Kind {
kw_umin, kw_umin,
// Instruction Opcodes (Opcode in UIntVal). // Instruction Opcodes (Opcode in UIntVal).
kw_fneg,
kw_add, kw_add,
kw_fadd, kw_fadd,
kw_sub, kw_sub,

View File

@ -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) { static int getDecodedBinaryOpcode(unsigned Val, Type *Ty) {
bool IsFP = Ty->isFPOrFPVectorTy(); bool IsFP = Ty->isFPOrFPVectorTy();
// BinOps are only valid for int/fp or vector of int/fp types // BinOps are only valid for int/fp or vector of int/fp types
@ -2317,6 +2331,19 @@ Error BitcodeReader::parseConstants() {
} }
break; 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] case bitc::CST_CODE_CE_BINOP: { // CE_BINOP: [opcode, opval, opval]
if (Record.size() < 3) if (Record.size() < 3)
return error("Invalid record"); return error("Invalid record");
@ -3535,7 +3562,27 @@ Error BitcodeReader::parseFunctionBody(Function *F) {
I = nullptr; I = nullptr;
continue; 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] case bitc::FUNC_CODE_INST_BINOP: { // BINOP: [opval, ty, opval, opcode]
unsigned OpNum = 0; unsigned OpNum = 0;
Value *LHS, *RHS; Value *LHS, *RHS;

View File

@ -112,6 +112,8 @@ enum {
// FUNCTION_BLOCK abbrev id's. // FUNCTION_BLOCK abbrev id's.
FUNCTION_INST_LOAD_ABBREV = bitc::FIRST_APPLICATION_ABBREV, FUNCTION_INST_LOAD_ABBREV = bitc::FIRST_APPLICATION_ABBREV,
FUNCTION_INST_UNOP_ABBREV,
FUNCTION_INST_UNOP_FLAGS_ABBREV,
FUNCTION_INST_BINOP_ABBREV, FUNCTION_INST_BINOP_ABBREV,
FUNCTION_INST_BINOP_FLAGS_ABBREV, FUNCTION_INST_BINOP_FLAGS_ABBREV,
FUNCTION_INST_CAST_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) { static unsigned getEncodedBinaryOpcode(unsigned Opcode) {
switch (Opcode) { switch (Opcode) {
default: llvm_unreachable("Unknown binary instruction!"); default: llvm_unreachable("Unknown binary instruction!");
@ -2384,6 +2393,16 @@ void ModuleBitcodeWriter::writeConstants(unsigned FirstVal, unsigned LastVal,
Record.push_back(Flags); Record.push_back(Flags);
} }
break; 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: { case Instruction::GetElementPtr: {
Code = bitc::CST_CODE_CE_GEP; Code = bitc::CST_CODE_CE_GEP;
const auto *GO = cast<GEPOperator>(C); const auto *GO = cast<GEPOperator>(C);
@ -2556,7 +2575,19 @@ void ModuleBitcodeWriter::writeInstruction(const Instruction &I,
} }
} }
break; 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: { case Instruction::GetElementPtr: {
Code = bitc::FUNC_CODE_INST_GEP; Code = bitc::FUNC_CODE_INST_GEP;
AbbrevToUse = FUNCTION_INST_GEP_ABBREV; AbbrevToUse = FUNCTION_INST_GEP_ABBREV;
@ -3217,6 +3248,25 @@ void ModuleBitcodeWriter::writeBlockInfo() {
FUNCTION_INST_LOAD_ABBREV) FUNCTION_INST_LOAD_ABBREV)
llvm_unreachable("Unexpected abbrev ordering!"); 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. { // INST_BINOP abbrev for FUNCTION_BLOCK.
auto Abbv = std::make_shared<BitCodeAbbrev>(); auto Abbv = std::make_shared<BitCodeAbbrev>();
Abbv->Add(BitCodeAbbrevOp(bitc::FUNC_CODE_INST_BINOP)); Abbv->Add(BitCodeAbbrevOp(bitc::FUNC_CODE_INST_BINOP));

View File

@ -330,6 +330,13 @@ bool IRTranslator::translateFSub(const User &U, MachineIRBuilder &MIRBuilder) {
return translateBinaryOp(TargetOpcode::G_FSUB, U, 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, bool IRTranslator::translateCompare(const User &U,
MachineIRBuilder &MIRBuilder) { MachineIRBuilder &MIRBuilder) {
const CmpInst *CI = dyn_cast<CmpInst>(&U); const CmpInst *CI = dyn_cast<CmpInst>(&U);

View File

@ -2801,6 +2801,15 @@ static bool isVectorReductionOp(const User *I) {
return ReduxExtracted; 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) { void SelectionDAGBuilder::visitBinary(const User &I, unsigned Opcode) {
SDNodeFlags Flags; SDNodeFlags Flags;
if (auto *OFBinOp = dyn_cast<OverflowingBinaryOperator>(&I)) { if (auto *OFBinOp = dyn_cast<OverflowingBinaryOperator>(&I)) {

View File

@ -854,6 +854,9 @@ private:
void visitInvoke(const InvokeInst &I); void visitInvoke(const InvokeInst &I);
void visitResume(const ResumeInst &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 visitBinary(const User &I, unsigned Opcode);
void visitShift(const User &I, unsigned Opcode); void visitShift(const User &I, unsigned Opcode);
void visitAdd(const User &I) { visitBinary(I, ISD::ADD); } void visitAdd(const User &I) { visitBinary(I, ISD::ADD); }

View File

@ -1451,6 +1451,7 @@ int TargetLoweringBase::InstructionOpcodeToISD(unsigned Opcode) const {
case CatchPad: return 0; case CatchPad: return 0;
case CatchSwitch: return 0; case CatchSwitch: return 0;
case CleanupPad: return 0; case CleanupPad: return 0;
case FNeg: return ISD::FNEG;
case Add: return ISD::ADD; case Add: return ISD::ADD;
case FAdd: return ISD::FADD; case FAdd: return ISD::FADD;
case Sub: return ISD::SUB; case Sub: return ISD::SUB;

View File

@ -1780,6 +1780,36 @@ Constant *ConstantExpr::getAddrSpaceCast(Constant *C, Type *DstTy,
return getFoldedCast(Instruction::AddrSpaceCast, C, DstTy, OnlyIfReduced); 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, Constant *ConstantExpr::get(unsigned Opcode, Constant *C1, Constant *C2,
unsigned Flags, Type *OnlyIfReducedTy) { unsigned Flags, Type *OnlyIfReducedTy) {
// Check the operands for consistency first. // Check the operands for consistency first.

View File

@ -529,7 +529,9 @@ struct ConstantExprKeyType {
ConstantExpr *create(TypeClass *Ty) const { ConstantExpr *create(TypeClass *Ty) const {
switch (Opcode) { switch (Opcode) {
default: default:
if (Instruction::isCast(Opcode)) if (Instruction::isCast(Opcode) ||
(Opcode >= Instruction::UnaryOpsBegin &&
Opcode < Instruction::UnaryOpsEnd))
return new UnaryConstantExpr(Opcode, Ops[0], Ty); return new UnaryConstantExpr(Opcode, Ops[0], Ty);
if ((Opcode >= Instruction::BinaryOpsBegin && if ((Opcode >= Instruction::BinaryOpsBegin &&
Opcode < Instruction::BinaryOpsEnd)) Opcode < Instruction::BinaryOpsEnd))

View File

@ -303,6 +303,9 @@ const char *Instruction::getOpcodeName(unsigned OpCode) {
case CatchPad: return "catchpad"; case CatchPad: return "catchpad";
case CatchSwitch: return "catchswitch"; case CatchSwitch: return "catchswitch";
// Standard unary operators...
case FNeg: return "fneg";
// Standard binary operators... // Standard binary operators...
case Add: return "add"; case Add: return "add";
case FAdd: return "fadd"; case FAdd: return "fadd";

View File

@ -1956,6 +1956,59 @@ Type *ExtractValueInst::getIndexedType(Type *Agg,
return const_cast<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 // BinaryOperator Class
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
@ -3697,6 +3750,10 @@ GetElementPtrInst *GetElementPtrInst::cloneImpl() const {
return new (getNumOperands()) GetElementPtrInst(*this); return new (getNumOperands()) GetElementPtrInst(*this);
} }
UnaryOperator *UnaryOperator::cloneImpl() const {
return Create(getOpcode(), Op<0>());
}
BinaryOperator *BinaryOperator::cloneImpl() const { BinaryOperator *BinaryOperator::cloneImpl() const {
return Create(getOpcode(), Op<0>(), Op<1>()); return Create(getOpcode(), Op<0>(), Op<1>());
} }

View File

@ -443,6 +443,7 @@ private:
void visitBitCastInst(BitCastInst &I); void visitBitCastInst(BitCastInst &I);
void visitAddrSpaceCastInst(AddrSpaceCastInst &I); void visitAddrSpaceCastInst(AddrSpaceCastInst &I);
void visitPHINode(PHINode &PN); void visitPHINode(PHINode &PN);
void visitUnaryOperator(UnaryOperator &U);
void visitBinaryOperator(BinaryOperator &B); void visitBinaryOperator(BinaryOperator &B);
void visitICmpInst(ICmpInst &IC); void visitICmpInst(ICmpInst &IC);
void visitFCmpInst(FCmpInst &FC); void visitFCmpInst(FCmpInst &FC);
@ -2990,6 +2991,28 @@ void Verifier::visitInvokeInst(InvokeInst &II) {
visitTerminator(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 /// visitBinaryOperator - Check that both arguments to the binary operator are
/// of the same type! /// of the same type!
/// ///

View File

@ -38,8 +38,12 @@ entry:
%e = frem float %x, %y %e = frem float %x, %y
; CHECK: %e_vec = frem <3 x float> %vec, %vec ; CHECK: %e_vec = frem <3 x float> %vec, %vec
%e_vec = frem <3 x float> %vec, %vec %e_vec = frem <3 x float> %vec, %vec
; CHECK: ret float %e ; CHECK: %f = fneg float %x
ret float %e %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 ; CHECK: no_nan
@ -72,8 +76,12 @@ entry:
%e = frem nnan float %x, %y %e = frem nnan float %x, %y
; CHECK: %e_vec = frem nnan <3 x float> %vec, %vec ; CHECK: %e_vec = frem nnan <3 x float> %vec, %vec
%e_vec = frem nnan <3 x float> %vec, %vec %e_vec = frem nnan <3 x float> %vec, %vec
; CHECK: ret float %e ; CHECK: %f = fneg nnan float %x
ret float %e %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( ; CHECK: @contract(
@ -174,6 +182,10 @@ entry:
%e = frem nnan nsz float %x, %y %e = frem nnan nsz float %x, %y
; CHECK: %e_vec = frem nnan <3 x float> %vec, %vec ; CHECK: %e_vec = frem nnan <3 x float> %vec, %vec
%e_vec = frem nnan <3 x float> %vec, %vec %e_vec = frem nnan <3 x float> %vec, %vec
; CHECK: ret float %e ; CHECK: %f = fneg nnan nsz float %x
ret float %e %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
} }

View File

@ -762,7 +762,27 @@ define void @atomics(i32* %word) {
} }
;; Fast Math Flags ;; 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 %f.nnan = fadd nnan float %op1, %op2
; CHECK: %f.nnan = fadd nnan float %op1, %op2 ; CHECK: %f.nnan = fadd nnan float %op1, %op2
%f.ninf = fadd ninf float %op1, %op2 %f.ninf = fadd ninf float %op1, %op2
@ -997,6 +1017,13 @@ continue:
ret i32 0 ret i32 0
} }
; Instructions -- Unary Operations
define void @instructions.unops(double %op1) {
fneg double %op1
; CHECK: fneg double %op1
ret void
}
; Instructions -- Binary Operations ; Instructions -- Binary Operations
define void @instructions.binops(i8 %op1, i8 %op2) { define void @instructions.binops(i8 %op1, i8 %op2) {
; nuw x nsw ; nuw x nsw

View File

@ -3,6 +3,15 @@
; RUN: llvm-as < %s | llvm-bcanalyzer -dump | FileCheck %s ; RUN: llvm-as < %s | llvm-bcanalyzer -dump | FileCheck %s
; RUN: verify-uselistorder < %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: FUNCTION_BLOCK
; CHECK: INST_BINOP {{.*}}op0=1 op1=1 ; CHECK: INST_BINOP {{.*}}op0=1 op1=1
; CHECK: INST_BINOP {{.*}}op0=1 op1=1 ; CHECK: INST_BINOP {{.*}}op0=1 op1=1

View File

@ -10,6 +10,21 @@ define float @fnegf(float %X) {
ret float %Y 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 double @fabs(double)
declare float @fabsf(float) declare float @fabsf(float)

View File

@ -127,3 +127,18 @@ define <4 x float> @fsub0_undef_elts_v4f32(<4 x float> %x) {
ret <4 x float> %r 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
}

View File

@ -63,6 +63,14 @@ lpad:
resume { i8*, i32 } zeroinitializer 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 { define i8 @invoke_with_same_range() personality i8* undef {
; CHECK-LABEL: @invoke_with_same_range() ; CHECK-LABEL: @invoke_with_same_range()
; CHECK: tail call i8 @invoke_with_range() ; CHECK: tail call i8 @invoke_with_range()
@ -76,14 +84,6 @@ lpad:
resume { i8*, i32 } zeroinitializer 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(); declare i8 @dummy();

View File

@ -247,6 +247,7 @@ static const char *GetCodeName(unsigned CodeID, unsigned BlockID,
STRINGIFY_CODE(CST_CODE, CE_CMP) STRINGIFY_CODE(CST_CODE, CE_CMP)
STRINGIFY_CODE(CST_CODE, INLINEASM) STRINGIFY_CODE(CST_CODE, INLINEASM)
STRINGIFY_CODE(CST_CODE, CE_SHUFVEC_EX) STRINGIFY_CODE(CST_CODE, CE_SHUFVEC_EX)
STRINGIFY_CODE(CST_CODE, CE_UNOP)
case bitc::CST_CODE_BLOCKADDRESS: return "CST_CODE_BLOCKADDRESS"; case bitc::CST_CODE_BLOCKADDRESS: return "CST_CODE_BLOCKADDRESS";
STRINGIFY_CODE(CST_CODE, DATA) 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_BR)
STRINGIFY_CODE(FUNC_CODE, INST_SWITCH) STRINGIFY_CODE(FUNC_CODE, INST_SWITCH)
STRINGIFY_CODE(FUNC_CODE, INST_INVOKE) STRINGIFY_CODE(FUNC_CODE, INST_INVOKE)
STRINGIFY_CODE(FUNC_CODE, INST_UNOP)
STRINGIFY_CODE(FUNC_CODE, INST_UNREACHABLE) STRINGIFY_CODE(FUNC_CODE, INST_UNREACHABLE)
STRINGIFY_CODE(FUNC_CODE, INST_CLEANUPRET) STRINGIFY_CODE(FUNC_CODE, INST_CLEANUPRET)
STRINGIFY_CODE(FUNC_CODE, INST_CATCHRET) STRINGIFY_CODE(FUNC_CODE, INST_CATCHRET)