Index: include/llvm-c/Core.h =================================================================== --- include/llvm-c/Core.h +++ include/llvm-c/Core.h @@ -54,6 +54,8 @@ * @{ */ +/// 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 @@ /* removed 6 due to API changes */ LLVMUnreachable = 7, + /* Standard Unary Operators */ + LLVMFNeg = 66, + /* Standard Binary Operators */ LLVMAdd = 8, LLVMFAdd = 9, Index: include/llvm/Bitcode/LLVMBitCodes.h =================================================================== --- include/llvm/Bitcode/LLVMBitCodes.h +++ include/llvm/Bitcode/LLVMBitCodes.h @@ -342,6 +342,7 @@ 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 @@ 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 @@ -465,7 +474,7 @@ FUNC_CODE_INST_BR = 11, // BR: [bb#, bb#, cond] or [bb#] FUNC_CODE_INST_SWITCH = 12, // SWITCH: [opty, op0, op1, ...] FUNC_CODE_INST_INVOKE = 13, // INVOKE: [attr, fnty, op0,op1, ...] - // 14 is unused. + FUNC_CODE_INST_UNOP = 14, // UNOP: [opcode, ty, opval] FUNC_CODE_INST_UNREACHABLE = 15, // UNREACHABLE FUNC_CODE_INST_PHI = 16, // PHI: [ty, val0,bb0, ...] Index: include/llvm/CodeGen/GlobalISel/IRTranslator.h =================================================================== --- include/llvm/CodeGen/GlobalISel/IRTranslator.h +++ include/llvm/CodeGen/GlobalISel/IRTranslator.h @@ -300,6 +300,8 @@ 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); } Index: include/llvm/IR/Constants.h =================================================================== --- include/llvm/IR/Constants.h +++ include/llvm/IR/Constants.h @@ -1114,6 +1114,13 @@ 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. /// Index: include/llvm/IR/InstVisitor.h =================================================================== --- include/llvm/IR/InstVisitor.h +++ include/llvm/IR/InstVisitor.h @@ -263,6 +263,7 @@ // 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);} Index: include/llvm/IR/Instruction.h =================================================================== --- include/llvm/IR/Instruction.h +++ include/llvm/IR/Instruction.h @@ -127,6 +127,7 @@ 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 @@ 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; } @@ -654,6 +658,13 @@ #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, Index: include/llvm/IR/Instruction.def =================================================================== --- include/llvm/IR/Instruction.def +++ 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 (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 Index: include/llvm/IR/Instructions.h =================================================================== --- include/llvm/IR/Instructions.h +++ include/llvm/IR/Instructions.h @@ -1104,6 +1104,71 @@ 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 //===----------------------------------------------------------------------===// Index: lib/AsmParser/LLLexer.cpp =================================================================== --- lib/AsmParser/LLLexer.cpp +++ lib/AsmParser/LLLexer.cpp @@ -822,6 +822,8 @@ } \ } while (false) + INSTKEYWORD(fneg, FNeg); + INSTKEYWORD(add, Add); INSTKEYWORD(fadd, FAdd); INSTKEYWORD(sub, Sub); INSTKEYWORD(fsub, FSub); INSTKEYWORD(mul, Mul); INSTKEYWORD(fmul, FMul); Index: lib/AsmParser/LLParser.h =================================================================== --- lib/AsmParser/LLParser.h +++ lib/AsmParser/LLParser.h @@ -571,6 +571,8 @@ 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); Index: lib/AsmParser/LLParser.cpp =================================================================== --- lib/AsmParser/LLParser.cpp +++ lib/AsmParser/LLParser.cpp @@ -3295,7 +3295,31 @@ 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 @@ 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: @@ -6064,6 +6098,39 @@ } //===----------------------------------------------------------------------===// +// 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. //===----------------------------------------------------------------------===// Index: lib/AsmParser/LLToken.h =================================================================== --- lib/AsmParser/LLToken.h +++ lib/AsmParser/LLToken.h @@ -270,6 +270,7 @@ kw_umin, // Instruction Opcodes (Opcode in UIntVal). + kw_fneg, kw_add, kw_fadd, kw_sub, Index: lib/Bitcode/Reader/BitcodeReader.cpp =================================================================== --- lib/Bitcode/Reader/BitcodeReader.cpp +++ lib/Bitcode/Reader/BitcodeReader.cpp @@ -963,6 +963,20 @@ } } +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 @@ -2316,6 +2330,19 @@ } 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"); @@ -3534,7 +3561,27 @@ 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; Index: lib/Bitcode/Writer/BitcodeWriter.cpp =================================================================== --- lib/Bitcode/Writer/BitcodeWriter.cpp +++ lib/Bitcode/Writer/BitcodeWriter.cpp @@ -112,6 +112,8 @@ // 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 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!"); @@ -2383,6 +2392,16 @@ 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); @@ -2555,7 +2574,19 @@ } } 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; @@ -3216,6 +3247,25 @@ 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)); Index: lib/CodeGen/GlobalISel/IRTranslator.cpp =================================================================== --- lib/CodeGen/GlobalISel/IRTranslator.cpp +++ lib/CodeGen/GlobalISel/IRTranslator.cpp @@ -330,6 +330,13 @@ 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); Index: lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h =================================================================== --- lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h +++ lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h @@ -854,6 +854,9 @@ 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); } Index: lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp =================================================================== --- lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -2801,6 +2801,15 @@ 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)) { Index: lib/CodeGen/TargetLoweringBase.cpp =================================================================== --- lib/CodeGen/TargetLoweringBase.cpp +++ lib/CodeGen/TargetLoweringBase.cpp @@ -1451,6 +1451,7 @@ 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; Index: lib/IR/Constants.cpp =================================================================== --- lib/IR/Constants.cpp +++ lib/IR/Constants.cpp @@ -1780,6 +1780,36 @@ 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. Index: lib/IR/ConstantsContext.h =================================================================== --- lib/IR/ConstantsContext.h +++ lib/IR/ConstantsContext.h @@ -529,7 +529,9 @@ 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)) Index: lib/IR/Instruction.cpp =================================================================== --- lib/IR/Instruction.cpp +++ lib/IR/Instruction.cpp @@ -303,6 +303,9 @@ 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"; Index: lib/IR/Instructions.cpp =================================================================== --- lib/IR/Instructions.cpp +++ lib/IR/Instructions.cpp @@ -1928,6 +1928,59 @@ } //===----------------------------------------------------------------------===// +// 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 //===----------------------------------------------------------------------===// @@ -3684,6 +3737,10 @@ 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>()); } Index: lib/IR/Verifier.cpp =================================================================== --- lib/IR/Verifier.cpp +++ lib/IR/Verifier.cpp @@ -443,6 +443,7 @@ 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 @@ 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! /// Index: test/Assembler/fast-math-flags.ll =================================================================== --- test/Assembler/fast-math-flags.ll +++ test/Assembler/fast-math-flags.ll @@ -38,8 +38,12 @@ %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 @@ %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 @@ %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 } Index: test/CodeGen/Generic/fneg-fabs.ll =================================================================== --- test/CodeGen/Generic/fneg-fabs.ll +++ test/CodeGen/Generic/fneg-fabs.ll @@ -10,6 +10,21 @@ 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) Index: test/CodeGen/X86/vec_fneg.ll =================================================================== --- test/CodeGen/X86/vec_fneg.ll +++ test/CodeGen/X86/vec_fneg.ll @@ -127,3 +127,18 @@ 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 +} + + Index: tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp =================================================================== --- tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp +++ tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp @@ -247,6 +247,7 @@ 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) }