diff --git a/include/llvm-c/Core.h b/include/llvm-c/Core.h index c093c0906ce..0784275ace8 100644 --- a/include/llvm-c/Core.h +++ b/include/llvm-c/Core.h @@ -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, diff --git a/include/llvm/Bitcode/LLVMBitCodes.h b/include/llvm/Bitcode/LLVMBitCodes.h index 5467ecc2626..f0d11e9c168 100644 --- a/include/llvm/Bitcode/LLVMBitCodes.h +++ b/include/llvm/Bitcode/LLVMBitCodes.h @@ -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 { diff --git a/include/llvm/CodeGen/GlobalISel/IRTranslator.h b/include/llvm/CodeGen/GlobalISel/IRTranslator.h index 2498ee93321..04629f6b320 100644 --- a/include/llvm/CodeGen/GlobalISel/IRTranslator.h +++ b/include/llvm/CodeGen/GlobalISel/IRTranslator.h @@ -300,6 +300,8 @@ class IRTranslator : public MachineFunctionPass { 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); } diff --git a/include/llvm/IR/Constants.h b/include/llvm/IR/Constants.h index f9d5ebc560c..52fc4da62b6 100644 --- a/include/llvm/IR/Constants.h +++ b/include/llvm/IR/Constants.h @@ -1114,6 +1114,13 @@ class ConstantExpr : public Constant { 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. /// diff --git a/include/llvm/IR/InstVisitor.h b/include/llvm/IR/InstVisitor.h index 554417f984a..5e9b18d90a0 100644 --- a/include/llvm/IR/InstVisitor.h +++ b/include/llvm/IR/InstVisitor.h @@ -263,6 +263,7 @@ class InstVisitor { // 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);} diff --git a/include/llvm/IR/Instruction.def b/include/llvm/IR/Instruction.def index 86617299c44..58e4e2e1d6c 100644 --- a/include/llvm/IR/Instruction.def +++ b/include/llvm/IR/Instruction.def @@ -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_FUNCLETPAD_INST(49) -HANDLE_FUNCLETPAD_INST(49, CleanupPad, CleanupPadInst) -HANDLE_FUNCLETPAD_INST(50, CatchPad , CatchPadInst) - LAST_FUNCLETPAD_INST(50) + 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(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 diff --git a/include/llvm/IR/Instruction.h b/include/llvm/IR/Instruction.h index e1a1faedf11..7a81f700ee4 100644 --- a/include/llvm/IR/Instruction.h +++ b/include/llvm/IR/Instruction.h @@ -127,6 +127,7 @@ class Instruction : public User, 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 @@ class Instruction : public User, 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 @@ class Instruction : public User, #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, diff --git a/include/llvm/IR/Instructions.h b/include/llvm/IR/Instructions.h index 01d83df90ae..bd8cec54156 100644 --- a/include/llvm/IR/Instructions.h +++ b/include/llvm/IR/Instructions.h @@ -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(Instruction::getOpcode()); + } +}; + //===----------------------------------------------------------------------===// // ICmpInst Class //===----------------------------------------------------------------------===// diff --git a/lib/AsmParser/LLLexer.cpp b/lib/AsmParser/LLLexer.cpp index af4f43986ef..4f8ce3ddc7b 100644 --- a/lib/AsmParser/LLLexer.cpp +++ b/lib/AsmParser/LLLexer.cpp @@ -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); diff --git a/lib/AsmParser/LLParser.cpp b/lib/AsmParser/LLParser.cpp index 5fe1e125d48..856be2fb64a 100644 --- a/lib/AsmParser/LLParser.cpp +++ b/lib/AsmParser/LLParser.cpp @@ -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. //===----------------------------------------------------------------------===// diff --git a/lib/AsmParser/LLParser.h b/lib/AsmParser/LLParser.h index cec1a8e8f7e..6f8962b6d4e 100644 --- a/lib/AsmParser/LLParser.h +++ b/lib/AsmParser/LLParser.h @@ -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); diff --git a/lib/AsmParser/LLToken.h b/lib/AsmParser/LLToken.h index f8f5955a16c..dae1d41fd8c 100644 --- a/lib/AsmParser/LLToken.h +++ b/lib/AsmParser/LLToken.h @@ -270,6 +270,7 @@ enum Kind { kw_umin, // Instruction Opcodes (Opcode in UIntVal). + kw_fneg, kw_add, kw_fadd, kw_sub, diff --git a/lib/Bitcode/Reader/BitcodeReader.cpp b/lib/Bitcode/Reader/BitcodeReader.cpp index 56e05f8f085..3b1d54f82cb 100644 --- a/lib/Bitcode/Reader/BitcodeReader.cpp +++ b/lib/Bitcode/Reader/BitcodeReader.cpp @@ -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(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; diff --git a/lib/Bitcode/Writer/BitcodeWriter.cpp b/lib/Bitcode/Writer/BitcodeWriter.cpp index f4634c9d3f4..06eb0f76254 100644 --- a/lib/Bitcode/Writer/BitcodeWriter.cpp +++ b/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -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(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(); + 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(); + 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(); Abbv->Add(BitCodeAbbrevOp(bitc::FUNC_CODE_INST_BINOP)); diff --git a/lib/CodeGen/GlobalISel/IRTranslator.cpp b/lib/CodeGen/GlobalISel/IRTranslator.cpp index ef090777726..0a41877839a 100644 --- a/lib/CodeGen/GlobalISel/IRTranslator.cpp +++ b/lib/CodeGen/GlobalISel/IRTranslator.cpp @@ -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(&U); diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp index bf24d7f7562..ebe172548e3 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ b/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -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(&I)) { diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h b/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h index 4b5dda982f1..5f9cdb69daf 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h +++ b/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h @@ -854,6 +854,9 @@ class SelectionDAGBuilder { 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); } diff --git a/lib/CodeGen/TargetLoweringBase.cpp b/lib/CodeGen/TargetLoweringBase.cpp index 166ff18e775..44afbef946f 100644 --- a/lib/CodeGen/TargetLoweringBase.cpp +++ b/lib/CodeGen/TargetLoweringBase.cpp @@ -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; diff --git a/lib/IR/Constants.cpp b/lib/IR/Constants.cpp index 2351e7e4a38..7368a4c8571 100644 --- a/lib/IR/Constants.cpp +++ b/lib/IR/Constants.cpp @@ -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. diff --git a/lib/IR/ConstantsContext.h b/lib/IR/ConstantsContext.h index e9f31e4ded6..eac17139708 100644 --- a/lib/IR/ConstantsContext.h +++ b/lib/IR/ConstantsContext.h @@ -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)) diff --git a/lib/IR/Instruction.cpp b/lib/IR/Instruction.cpp index 1e326370318..f077957969f 100644 --- a/lib/IR/Instruction.cpp +++ b/lib/IR/Instruction.cpp @@ -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"; diff --git a/lib/IR/Instructions.cpp b/lib/IR/Instructions.cpp index 0295da95a3a..7d159039c27 100644 --- a/lib/IR/Instructions.cpp +++ b/lib/IR/Instructions.cpp @@ -1956,6 +1956,59 @@ Type *ExtractValueInst::getIndexedType(Type *Agg, return const_cast(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>()); } diff --git a/lib/IR/Verifier.cpp b/lib/IR/Verifier.cpp index 4d0135d8338..899534dd10f 100644 --- a/lib/IR/Verifier.cpp +++ b/lib/IR/Verifier.cpp @@ -443,6 +443,7 @@ class Verifier : public InstVisitor, VerifierSupport { 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! /// diff --git a/test/Assembler/fast-math-flags.ll b/test/Assembler/fast-math-flags.ll index edff26e6d68..1af2320f0a1 100644 --- a/test/Assembler/fast-math-flags.ll +++ b/test/Assembler/fast-math-flags.ll @@ -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 } diff --git a/test/Bitcode/compatibility.ll b/test/Bitcode/compatibility.ll index 8c0471a1134..1d57f759391 100644 --- a/test/Bitcode/compatibility.ll +++ b/test/Bitcode/compatibility.ll @@ -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 diff --git a/test/Bitcode/function-encoding-rel-operands.ll b/test/Bitcode/function-encoding-rel-operands.ll index 1307dd48337..9486e04a0d5 100644 --- a/test/Bitcode/function-encoding-rel-operands.ll +++ b/test/Bitcode/function-encoding-rel-operands.ll @@ -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 diff --git a/test/CodeGen/Generic/fneg-fabs.ll b/test/CodeGen/Generic/fneg-fabs.ll index 2f2f59762cb..cafc1f132b5 100644 --- a/test/CodeGen/Generic/fneg-fabs.ll +++ b/test/CodeGen/Generic/fneg-fabs.ll @@ -10,6 +10,21 @@ define float @fnegf(float %X) { ret float %Y } +define double @real_fneg(double %X) { + %Y = fneg double %X ; [#uses=1] + ret double %Y +} + +define double @real_fneg_constant() { + %Y = fneg double -2.0 ; [#uses=1] + ret double %Y +} + +define float @real_fnegf(float %X) { + %Y = fneg float %X ; [#uses=1] + ret float %Y +} + declare double @fabs(double) declare float @fabsf(float) diff --git a/test/CodeGen/X86/vec_fneg.ll b/test/CodeGen/X86/vec_fneg.ll index e84f7163bbe..f0c98990683 100644 --- a/test/CodeGen/X86/vec_fneg.ll +++ b/test/CodeGen/X86/vec_fneg.ll @@ -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 +} + + diff --git a/test/Transforms/MergeFunc/call-and-invoke-with-ranges.ll b/test/Transforms/MergeFunc/call-and-invoke-with-ranges.ll index 806ca3c17a6..f138ac42914 100644 --- a/test/Transforms/MergeFunc/call-and-invoke-with-ranges.ll +++ b/test/Transforms/MergeFunc/call-and-invoke-with-ranges.ll @@ -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(); diff --git a/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp b/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp index 5b82e4634c1..789a666cb41 100644 --- a/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp +++ b/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp @@ -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)