[llvm] 58acbce - [IR] Add Freeze instruction

via llvm-commits llvm-commits at lists.llvm.org
Mon Nov 4 22:55:04 PST 2019


Author: aqjune
Date: 2019-11-05T15:54:56+09:00
New Revision: 58acbce3def63a207b8f5a69318a99666a4aac53

URL: https://github.com/llvm/llvm-project/commit/58acbce3def63a207b8f5a69318a99666a4aac53
DIFF: https://github.com/llvm/llvm-project/commit/58acbce3def63a207b8f5a69318a99666a4aac53.diff

LOG: [IR] Add Freeze instruction

Summary:
- Define Instruction::Freeze, let it be UnaryOperator
- Add support for freeze to LLLexer/LLParser/BitcodeReader/BitcodeWriter
  The format is `%x = freeze <ty> %v`
- Add support for freeze instruction to llvm-c interface.
- Add m_Freeze in PatternMatch.
- Erase freeze when lowering IR to SelDag.

Reviewers: deadalnix, hfinkel, efriedma, lebedev.ri, nlopes, jdoerfert, regehr, filcab, delcypher, whitequark

Reviewed By: lebedev.ri, jdoerfert

Subscribers: jfb, kristof.beyls, hiraditya, lebedev.ri, steven_wu, dexonsmith, xbolva00, delcypher, spatel, regehr, trentxintong, vsk, filcab, nlopes, mehdi_amini, deadalnix, llvm-commits

Differential Revision: https://reviews.llvm.org/D29011

Added: 
    llvm/test/Bindings/llvm-c/freeze.ll

Modified: 
    llvm/include/llvm-c/Core.h
    llvm/include/llvm/Bitcode/LLVMBitCodes.h
    llvm/include/llvm/CodeGen/GlobalISel/IRTranslator.h
    llvm/include/llvm/IR/IRBuilder.h
    llvm/include/llvm/IR/Instruction.def
    llvm/include/llvm/IR/Operator.h
    llvm/include/llvm/IR/PatternMatch.h
    llvm/lib/AsmParser/LLLexer.cpp
    llvm/lib/AsmParser/LLParser.cpp
    llvm/lib/AsmParser/LLToken.h
    llvm/lib/Bitcode/Reader/BitcodeReader.cpp
    llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
    llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
    llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h
    llvm/lib/CodeGen/TargetLoweringBase.cpp
    llvm/lib/IR/ConstantFold.cpp
    llvm/lib/IR/Core.cpp
    llvm/lib/IR/Instruction.cpp
    llvm/lib/IR/Instructions.cpp
    llvm/lib/IR/Verifier.cpp
    llvm/test/Bindings/OCaml/core.ml
    llvm/test/Bitcode/compatibility.ll
    llvm/test/Transforms/MergeFunc/inline-asm.ll
    llvm/tools/llvm-c-test/echo.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm-c/Core.h b/llvm/include/llvm-c/Core.h
index b84970956666..23e855148bb5 100644
--- a/llvm/include/llvm-c/Core.h
+++ b/llvm/include/llvm-c/Core.h
@@ -69,6 +69,7 @@ typedef enum {
 
   /* Standard Unary Operators */
   LLVMFNeg           = 66,
+  LLVMFreeze         = 68,
 
   /* Standard Binary Operators */
   LLVMAdd            = 8,
@@ -3747,6 +3748,7 @@ LLVMValueRef LLVMBuildNUWNeg(LLVMBuilderRef B, LLVMValueRef V,
                              const char *Name);
 LLVMValueRef LLVMBuildFNeg(LLVMBuilderRef, LLVMValueRef V, const char *Name);
 LLVMValueRef LLVMBuildNot(LLVMBuilderRef, LLVMValueRef V, const char *Name);
+LLVMValueRef LLVMBuildFreeze(LLVMBuilderRef, LLVMValueRef V, const char *Name);
 
 /* Memory */
 LLVMValueRef LLVMBuildMalloc(LLVMBuilderRef, LLVMTypeRef Ty, const char *Name);

diff  --git a/llvm/include/llvm/Bitcode/LLVMBitCodes.h b/llvm/include/llvm/Bitcode/LLVMBitCodes.h
index 1a397068caf0..b97abc4f0612 100644
--- a/llvm/include/llvm/Bitcode/LLVMBitCodes.h
+++ b/llvm/include/llvm/Bitcode/LLVMBitCodes.h
@@ -391,7 +391,8 @@ enum CastOpcodes {
 /// have no fixed relation to the LLVM IR enum values.  Changing these will
 /// break compatibility with old files.
 enum UnaryOpcodes {
-  UNOP_FNEG = 0
+  UNOP_FNEG = 0,
+  UNOP_FREEZE = 1
 };
 
 /// BinaryOpcodes - These are values used in the bitcode files to encode which

diff  --git a/llvm/include/llvm/CodeGen/GlobalISel/IRTranslator.h b/llvm/include/llvm/CodeGen/GlobalISel/IRTranslator.h
index bdb92aa4689d..6a2ea05f1b08 100644
--- a/llvm/include/llvm/CodeGen/GlobalISel/IRTranslator.h
+++ b/llvm/include/llvm/CodeGen/GlobalISel/IRTranslator.h
@@ -483,6 +483,9 @@ class IRTranslator : public MachineFunctionPass {
   bool translateUserOp2(const User &U, MachineIRBuilder &MIRBuilder) {
     return false;
   }
+  bool translateFreeze(const User &U, MachineIRBuilder &MIRBuilder) {
+    return false;
+  }
 
   /// @}
 

diff  --git a/llvm/include/llvm/IR/IRBuilder.h b/llvm/include/llvm/IR/IRBuilder.h
index f556db7893c4..970fca6e1ebb 100644
--- a/llvm/include/llvm/IR/IRBuilder.h
+++ b/llvm/include/llvm/IR/IRBuilder.h
@@ -2392,6 +2392,10 @@ class IRBuilder : public IRBuilderBase, public Inserter {
     return Insert(LandingPadInst::Create(Ty, NumClauses), Name);
   }
 
+  Value *CreateFreeze(Value *V, const Twine &Name = "") {
+    return Insert(UnaryOperator::CreateFreeze(V, Name));
+  }
+
   //===--------------------------------------------------------------------===//
   // Utility creation methods
   //===--------------------------------------------------------------------===//

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

diff  --git a/llvm/include/llvm/IR/Operator.h b/llvm/include/llvm/IR/Operator.h
index c8ca7e9a00e8..7d0b739000c6 100644
--- a/llvm/include/llvm/IR/Operator.h
+++ b/llvm/include/llvm/IR/Operator.h
@@ -598,6 +598,9 @@ class BitCastOperator
   }
 };
 
+class FreezeOperator : public ConcreteOperator<Operator, Instruction::Freeze>
+{};
+
 } // end namespace llvm
 
 #endif // LLVM_IR_OPERATOR_H

diff  --git a/llvm/include/llvm/IR/PatternMatch.h b/llvm/include/llvm/IR/PatternMatch.h
index 37a2fe52ec11..173b664028f7 100644
--- a/llvm/include/llvm/IR/PatternMatch.h
+++ b/llvm/include/llvm/IR/PatternMatch.h
@@ -825,6 +825,28 @@ m_FNegNSZ(const RHS &X) {
   return m_FSub(m_AnyZeroFP(), X);
 }
 
+template <typename Op_t> struct Freeze_match {
+  Op_t X;
+
+  Freeze_match(const Op_t &Op) : X(Op) {}
+  template <typename OpTy> bool match(OpTy *V) {
+    auto *I = dyn_cast<UnaryOperator>(V);
+    if (!I) return false;
+
+    if (isa<FreezeOperator>(I))
+      return X.match(I->getOperand(0));
+
+    return false;
+  }
+};
+
+/// Matches freeze.
+template <typename OpTy>
+inline Freeze_match<OpTy>
+m_Freeze(const OpTy &X) {
+  return Freeze_match<OpTy>(X);
+}
+
 template <typename LHS, typename RHS>
 inline BinaryOp_match<LHS, RHS, Instruction::Mul> m_Mul(const LHS &L,
                                                         const RHS &R) {

diff  --git a/llvm/lib/AsmParser/LLLexer.cpp b/llvm/lib/AsmParser/LLLexer.cpp
index 819f8a0712db..c6df821a22cd 100644
--- a/llvm/lib/AsmParser/LLLexer.cpp
+++ b/llvm/lib/AsmParser/LLLexer.cpp
@@ -837,6 +837,7 @@ lltok::Kind LLLexer::LexIdentifier() {
   } while (false)
 
   INSTKEYWORD(fneg,  FNeg);
+  INSTKEYWORD(freeze, Freeze);
 
   INSTKEYWORD(add,   Add);  INSTKEYWORD(fadd,   FAdd);
   INSTKEYWORD(sub,   Sub);  INSTKEYWORD(fsub,   FSub);

diff  --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp
index 042f324249f6..c204a9448ce0 100644
--- a/llvm/lib/AsmParser/LLParser.cpp
+++ b/llvm/lib/AsmParser/LLParser.cpp
@@ -3414,7 +3414,8 @@ bool LLParser::ParseValID(ValID &ID, PerFunctionState *PFS) {
   }
  
   // Unary Operators.
-  case lltok::kw_fneg: {
+  case lltok::kw_fneg:
+  case lltok::kw_freeze: {
     unsigned Opc = Lex.getUIntVal();
     Constant *Val;
     Lex.Lex();
@@ -3429,6 +3430,8 @@ bool LLParser::ParseValID(ValID &ID, PerFunctionState *PFS) {
       if (!Val->getType()->isFPOrFPVectorTy())
         return Error(ID.Loc, "constexpr requires fp operands");
       break;
+    case Instruction::Freeze:
+      break;
     default: llvm_unreachable("Unknown unary operator!");
     }
     unsigned Flags = 0;
@@ -5722,6 +5725,7 @@ int LLParser::ParseInstruction(Instruction *&Inst, BasicBlock *BB,
       Inst->setFastMathFlags(FMF);
     return false;
   }
+  case lltok::kw_freeze: return ParseUnaryOp(Inst, PFS, KeywordVal, false);
   // Binary Operators.
   case lltok::kw_add:
   case lltok::kw_sub:
@@ -6325,16 +6329,14 @@ bool LLParser::ParseCleanupPad(Instruction *&Inst, PerFunctionState &PFS) {
 /// ParseUnaryOp
 ///  ::= UnaryOp TypeAndValue ',' Value
 ///
-/// If IsFP is false, then any integer operand is allowed, if it is true, any fp
-/// operand is allowed.
+/// If IsFP is true, then fp operand is only allowed.
 bool LLParser::ParseUnaryOp(Instruction *&Inst, PerFunctionState &PFS,
                             unsigned Opc, bool IsFP) {
   LocTy Loc; Value *LHS;
   if (ParseTypeAndValue(LHS, Loc, PFS))
     return true;
 
-  bool Valid = IsFP ? LHS->getType()->isFPOrFPVectorTy()
-                    : LHS->getType()->isIntOrIntVectorTy();
+  bool Valid = !IsFP || LHS->getType()->isFPOrFPVectorTy();
 
   if (!Valid)
     return Error(Loc, "invalid operand type for instruction");

diff  --git a/llvm/lib/AsmParser/LLToken.h b/llvm/lib/AsmParser/LLToken.h
index 2ebfb9da2579..e418f7cbfb49 100644
--- a/llvm/lib/AsmParser/LLToken.h
+++ b/llvm/lib/AsmParser/LLToken.h
@@ -279,6 +279,7 @@ enum Kind {
 
   // Instruction Opcodes (Opcode in UIntVal).
   kw_fneg,
+  kw_freeze,
   kw_add,
   kw_fadd,
   kw_sub,

diff  --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
index ed736298dfa0..71166ba337e6 100644
--- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
+++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
@@ -1055,16 +1055,13 @@ 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_FNEG:
-    return IsFP ? Instruction::FNeg : -1;
+    return Ty->isFPOrFPVectorTy() ? Instruction::FNeg : -1;
+  case bitc::UNOP_FREEZE:
+    return Instruction::Freeze;
   }
 }
 
@@ -3865,7 +3862,7 @@ Error BitcodeReader::parseFunctionBody(Function *F) {
     case bitc::FUNC_CODE_INST_UNOP: {    // UNOP: [opval, ty, opcode]
       unsigned OpNum = 0;
       Value *LHS;
-      if (getValueTypePair(Record, OpNum, NextValueNo, LHS) ||
+      if (getValueTypePair(Record, OpNum, NextValueNo, LHS, &FullTy) ||
           OpNum+1 > Record.size())
         return error("Invalid record");
 

diff  --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
index deb4019ea8ba..86d20e920fe2 100644
--- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
+++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
@@ -521,6 +521,7 @@ static unsigned getEncodedUnaryOpcode(unsigned Opcode) {
   switch (Opcode) {
   default: llvm_unreachable("Unknown binary instruction!");
   case Instruction::FNeg: return bitc::UNOP_FNEG;
+  case Instruction::Freeze: return bitc::UNOP_FREEZE;
   }
 }
 
@@ -2433,6 +2434,17 @@ void ModuleBitcodeWriter::writeConstants(unsigned FirstVal, unsigned LastVal,
           Record.push_back(VE.getTypeID(C->getOperand(0)->getType()));
           Record.push_back(VE.getValueID(C->getOperand(0)));
           AbbrevToUse = CONSTANTS_CE_CAST_Abbrev;
+        } else if (Instruction::isUnaryOp(CE->getOpcode())) {
+          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) {
+            assert(CE->getOpcode() == Instruction::FNeg);
+            Record.push_back(Flags);
+          }
+          break;
         } else {
           assert(CE->getNumOperands() == 2 && "Unknown constant expr!");
           Code = bitc::CST_CODE_CE_BINOP;
@@ -2444,16 +2456,6 @@ void ModuleBitcodeWriter::writeConstants(unsigned FirstVal, unsigned LastVal,
             Record.push_back(Flags);
         }
         break;
-      case Instruction::FNeg: {
-        assert(CE->getNumOperands() == 1 && "Unknown constant expr!");
-        Code = bitc::CST_CODE_CE_UNOP;
-        Record.push_back(getEncodedUnaryOpcode(CE->getOpcode()));
-        Record.push_back(VE.getValueID(C->getOperand(0)));
-        uint64_t Flags = getOptimizationFlags(CE);
-        if (Flags != 0)
-          Record.push_back(Flags);
-        break;
-      }
       case Instruction::GetElementPtr: {
         Code = bitc::CST_CODE_CE_GEP;
         const auto *GO = cast<GEPOperator>(C);
@@ -2611,6 +2613,17 @@ void ModuleBitcodeWriter::writeInstruction(const Instruction &I,
         AbbrevToUse = FUNCTION_INST_CAST_ABBREV;
       Vals.push_back(VE.getTypeID(I.getType()));
       Vals.push_back(getEncodedCastOpcode(I.getOpcode()));
+    } else if (isa<UnaryOperator>(I)) {
+      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);
+      }
     } else {
       assert(isa<BinaryOperator>(I) && "Unknown instruction!");
       Code = bitc::FUNC_CODE_INST_BINOP;
@@ -2626,19 +2639,6 @@ 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;

diff  --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
index 0e6e7027e0cd..914edad0b8b9 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -10592,3 +10592,8 @@ void SelectionDAGBuilder::visitSwitch(const SwitchInst &SI) {
     lowerWorkItem(W, SI.getCondition(), SwitchMBB, DefaultMBB);
   }
 }
+
+void SelectionDAGBuilder::visitFreeze(const User &I) {
+  SDValue N = getValue(I.getOperand(0));
+  setValue(&I, N);
+}

diff  --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h
index bfcf30b430b6..c288a4f69084 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h
@@ -668,6 +668,7 @@ class SelectionDAGBuilder {
 
   void visitUnary(const User &I, unsigned Opcode);
   void visitFNeg(const User &I) { visitUnary(I, ISD::FNEG); }
+  void visitFreeze(const User &I);
 
   void visitBinary(const User &I, unsigned Opcode);
   void visitShift(const User &I, unsigned Opcode);

diff  --git a/llvm/lib/CodeGen/TargetLoweringBase.cpp b/llvm/lib/CodeGen/TargetLoweringBase.cpp
index cb95d47e598f..c5b129029493 100644
--- a/llvm/lib/CodeGen/TargetLoweringBase.cpp
+++ b/llvm/lib/CodeGen/TargetLoweringBase.cpp
@@ -1663,6 +1663,7 @@ int TargetLoweringBase::InstructionOpcodeToISD(unsigned Opcode) const {
   case ExtractValue:   return ISD::MERGE_VALUES;
   case InsertValue:    return ISD::MERGE_VALUES;
   case LandingPad:     return 0;
+  case Freeze:         return 0;
   }
 
   llvm_unreachable("Unknown instruction type encountered!");

diff  --git a/llvm/lib/IR/ConstantFold.cpp b/llvm/lib/IR/ConstantFold.cpp
index a6cd83310088..218a25fdfff6 100644
--- a/llvm/lib/IR/ConstantFold.cpp
+++ b/llvm/lib/IR/ConstantFold.cpp
@@ -941,43 +941,52 @@ Constant *llvm::ConstantFoldInsertValueInstruction(Constant *Agg,
 Constant *llvm::ConstantFoldUnaryInstruction(unsigned Opcode, Constant *C) {
   assert(Instruction::isUnaryOp(Opcode) && "Non-unary instruction detected");
 
-  // Handle scalar UndefValue. Vectors are always evaluated per element.
-  bool HasScalarUndef = !C->getType()->isVectorTy() && isa<UndefValue>(C);
+  switch (static_cast<Instruction::UnaryOps>(Opcode)) {
+  default:
+    break;
+  case Instruction::FNeg: {
+    // Handle scalar UndefValue. Vectors are always evaluated per element.
+    bool HasScalarUndef = !C->getType()->isVectorTy() && isa<UndefValue>(C);
 
-  if (HasScalarUndef) {
-    switch (static_cast<Instruction::UnaryOps>(Opcode)) {
-    case Instruction::FNeg:
+    if (HasScalarUndef) {
       return C; // -undef -> undef
-    case Instruction::UnaryOpsEnd:
-      llvm_unreachable("Invalid UnaryOp");
     }
-  }
 
-  // Constant should not be UndefValue, unless these are vector constants.
-  assert(!HasScalarUndef && "Unexpected UndefValue");
-  // We only have FP UnaryOps right now.
-  assert(!isa<ConstantInt>(C) && "Unexpected Integer UnaryOp");
+    // Constant should not be UndefValue, unless these are vector constants.
+    assert(!HasScalarUndef && "Unexpected UndefValue");
+    assert(!isa<ConstantInt>(C) && "Unexpected Integer UnaryOp");
 
-  if (ConstantFP *CFP = dyn_cast<ConstantFP>(C)) {
-    const APFloat &CV = CFP->getValueAPF();
-    switch (Opcode) {
-    default:
-      break;
-    case Instruction::FNeg:
+    if (ConstantFP *CFP = dyn_cast<ConstantFP>(C)) {
+      const APFloat &CV = CFP->getValueAPF();
       return ConstantFP::get(C->getContext(), neg(CV));
-    }
-  } else if (VectorType *VTy = dyn_cast<VectorType>(C->getType())) {
-    // Fold each element and create a vector constant from those constants.
-    SmallVector<Constant*, 16> Result;
-    Type *Ty = IntegerType::get(VTy->getContext(), 32);
-    for (unsigned i = 0, e = VTy->getNumElements(); i != e; ++i) {
-      Constant *ExtractIdx = ConstantInt::get(Ty, i);
-      Constant *Elt = ConstantExpr::getExtractElement(C, ExtractIdx);
+    } else if (VectorType *VTy = dyn_cast<VectorType>(C->getType())) {
+      // Fold each element and create a vector constant from those constants.
+      SmallVector<Constant*, 16> Result;
+      Type *Ty = IntegerType::get(VTy->getContext(), 32);
+      for (unsigned i = 0, e = VTy->getNumElements(); i != e; ++i) {
+        Constant *ExtractIdx = ConstantInt::get(Ty, i);
+        Constant *Elt = ConstantExpr::getExtractElement(C, ExtractIdx);
+
+        Result.push_back(ConstantExpr::get(Opcode, Elt));
+      }
 
-      Result.push_back(ConstantExpr::get(Opcode, Elt));
+      return ConstantVector::get(Result);
     }
-
-    return ConstantVector::get(Result);
+    break;
+  }
+  case Instruction::Freeze: {
+    if (ConstantFP *CFP = dyn_cast<ConstantFP>(C)) {
+      return CFP;
+    } else if (ConstantInt *CINT = dyn_cast<ConstantInt>(C)) {
+      return CINT;
+    } else if (GlobalVariable *GV = dyn_cast<GlobalVariable>(C)) {
+      // A global variable is neither undef nor poison.
+      return GV;
+    }
+    break;
+  }
+  case Instruction::UnaryOpsEnd:
+    llvm_unreachable("Invalid UnaryOp");
   }
 
   // We don't know how to fold this.

diff  --git a/llvm/lib/IR/Core.cpp b/llvm/lib/IR/Core.cpp
index 03bff7e5fde0..78ae36c9018f 100644
--- a/llvm/lib/IR/Core.cpp
+++ b/llvm/lib/IR/Core.cpp
@@ -3410,6 +3410,11 @@ LLVMValueRef LLVMBuildFNeg(LLVMBuilderRef B, LLVMValueRef V, const char *Name) {
   return wrap(unwrap(B)->CreateFNeg(unwrap(V), Name));
 }
 
+LLVMValueRef LLVMBuildFreeze(LLVMBuilderRef B, LLVMValueRef V,
+                             const char *Name) {
+  return wrap(unwrap(B)->CreateFreeze(unwrap(V), Name));
+}
+
 LLVMValueRef LLVMBuildNot(LLVMBuilderRef B, LLVMValueRef V, const char *Name) {
   return wrap(unwrap(B)->CreateNot(unwrap(V), Name));
 }

diff  --git a/llvm/lib/IR/Instruction.cpp b/llvm/lib/IR/Instruction.cpp
index b157c7bb34bf..2e9310c11738 100644
--- a/llvm/lib/IR/Instruction.cpp
+++ b/llvm/lib/IR/Instruction.cpp
@@ -307,6 +307,7 @@ const char *Instruction::getOpcodeName(unsigned OpCode) {
 
   // Standard unary operators...
   case FNeg: return "fneg";
+  case Freeze: return "freeze";
 
   // Standard binary operators...
   case Add: return "add";

diff  --git a/llvm/lib/IR/Instructions.cpp b/llvm/lib/IR/Instructions.cpp
index f62ec8fbec17..95521ad91210 100644
--- a/llvm/lib/IR/Instructions.cpp
+++ b/llvm/lib/IR/Instructions.cpp
@@ -2232,6 +2232,9 @@ void UnaryOperator::AssertOK() {
            "Tried to create a floating-point operation on a "
            "non-floating-point type!");
     break;
+  case Freeze:
+    // Freeze can take any type as an argument.
+    break;
   default: llvm_unreachable("Invalid opcode provided");
   }
 #endif

diff  --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
index e89d8b0a9b58..91026c3b1b28 100644
--- a/llvm/lib/IR/Verifier.cpp
+++ b/llvm/lib/IR/Verifier.cpp
@@ -3145,6 +3145,9 @@ void Verifier::visitUnaryOperator(UnaryOperator &U) {
     Assert(U.getType()->isFPOrFPVectorTy(),
            "FNeg operator only works with float types!", &U);
     break;
+  case Instruction::Freeze:
+    // Freeze can take all kinds of types.
+    break;
   default:
     llvm_unreachable("Unknown UnaryOperator opcode!");
   }

diff  --git a/llvm/test/Bindings/OCaml/core.ml b/llvm/test/Bindings/OCaml/core.ml
index f649dbdb8fa2..185a286fcb27 100644
--- a/llvm/test/Bindings/OCaml/core.ml
+++ b/llvm/test/Bindings/OCaml/core.ml
@@ -267,6 +267,7 @@ let test_constants () =
    * CHECK: @const_nsw_neg = global i64 sub nsw
    * CHECK: @const_nuw_neg = global i64 sub nuw
    * CHECK: @const_fneg = global double fneg
+   * CHECK: @const_freeze = global i64 freeze
    * CHECK: @const_not = global i64 xor
    * CHECK: @const_add = global i64 add
    * CHECK: @const_nsw_add = global i64 add nsw
@@ -303,6 +304,7 @@ let test_constants () =
   ignore (define_global "const_nsw_neg" (const_nsw_neg foldbomb) m);
   ignore (define_global "const_nuw_neg" (const_nuw_neg foldbomb) m);
   ignore (define_global "const_fneg" (const_fneg ffoldbomb) m);
+  ignore (define_global "const_freeze" (const_freeze foldbomb) m);
   ignore (define_global "const_not" (const_not foldbomb) m);
   ignore (define_global "const_add" (const_add foldbomb five) m);
   ignore (define_global "const_nsw_add" (const_nsw_add foldbomb five) m);
@@ -1400,6 +1402,7 @@ let test_builder () =
     ignore (build_nsw_neg p1 "build_nsw_neg" b);
     ignore (build_nuw_neg p1 "build_nuw_neg" b);
     ignore (build_fneg f1 "build_fneg" b);
+    ignore (build_freeze f1 "build_freeze" b);
     ignore (build_not p1 "build_not" b);
     ignore (build_unreachable b)
   end;

diff  --git a/llvm/test/Bindings/llvm-c/freeze.ll b/llvm/test/Bindings/llvm-c/freeze.ll
new file mode 100644
index 000000000000..eb842c03b788
--- /dev/null
+++ b/llvm/test/Bindings/llvm-c/freeze.ll
@@ -0,0 +1,22 @@
+; RUN: llvm-as < %s | llvm-dis > %t.orig
+; RUN: llvm-as < %s | llvm-c-test --echo > %t.echo
+; RUN: 
diff  -w %t.orig %t.echo
+
+%struct.T = type { i32, i32 }
+
+define i32 @f(i32 %arg, <2 x i32> %arg2, float %arg3, <2 x float> %arg4,
+              i8* %arg5, %struct.T %arg6, [2 x i32] %arg7, { i32, i32 } %arg8) {
+  %1 = freeze i32 %arg
+  %2 = freeze i32 10
+  %3 = freeze i32 %1
+  %4 = freeze i32 undef
+  %5 = freeze i666 11
+  %6 = freeze <2 x i32> %arg2
+  %7 = freeze float %arg3
+  %8 = freeze <2 x float> %arg4
+  %9 = freeze i8* %arg5
+  %10 = freeze %struct.T %arg6
+  %11 = freeze [2 x i32] %arg7
+  %12 = freeze { i32, i32 } %arg8
+  ret i32 %1
+}

diff  --git a/llvm/test/Bitcode/compatibility.ll b/llvm/test/Bitcode/compatibility.ll
index 8269a90e1460..c7b22c7999dd 100644
--- a/llvm/test/Bitcode/compatibility.ll
+++ b/llvm/test/Bitcode/compatibility.ll
@@ -1172,9 +1172,17 @@ continue:
 }
 
 ; Instructions -- Unary Operations
-define void @instructions.unops(double %op1) {
+define void @instructions.unops(double %op1, i32 %op2, <2 x i32> %op3, i8* %op4) {
   fneg double %op1
   ; CHECK: fneg double %op1
+  freeze i32 %op2
+  ; CHECK: freeze i32 %op2
+  freeze double %op1
+  ; CHECK: freeze double %op1
+  freeze <2 x i32> %op3
+  ; CHECK: freeze <2 x i32> %op3
+  freeze i8* %op4
+  ; CHECK: freeze i8* %op4
   ret void
 }
 
@@ -1826,6 +1834,10 @@ define void @instructions.strictfp() strictfp {
   ret void
 }
 
+define i64 @constexpr_freeze() {
+  ret i64 freeze (i64 32)
+}
+
 ; immarg attribute
 declare void @llvm.test.immarg.intrinsic(i32 immarg)
 ; CHECK: declare void @llvm.test.immarg.intrinsic(i32 immarg)

diff  --git a/llvm/test/Transforms/MergeFunc/inline-asm.ll b/llvm/test/Transforms/MergeFunc/inline-asm.ll
index 15760242cf69..370d3c56f060 100644
--- a/llvm/test/Transforms/MergeFunc/inline-asm.ll
+++ b/llvm/test/Transforms/MergeFunc/inline-asm.ll
@@ -3,13 +3,13 @@
 ; CHECK-LABEL: @int_ptr_arg_
diff erent
 ; CHECK-NEXT: call void asm
 
-; CHECK-LABEL: @int_ptr_null
-; CHECK-NEXT: tail call void @float_ptr_null()
-
 ; CHECK-LABEL: @int_ptr_arg_same
 ; CHECK-NEXT: %2 = bitcast i32* %0 to float*
 ; CHECK-NEXT: tail call void @float_ptr_arg_same(float* %2)
 
+; CHECK-LABEL: @int_ptr_null
+; CHECK-NEXT: tail call void @float_ptr_null()
+
 ; Used to satisfy minimum size limit
 declare void @stuff()
 

diff  --git a/llvm/tools/llvm-c-test/echo.cpp b/llvm/tools/llvm-c-test/echo.cpp
index 8abbfb3fb0c0..7fca8ada5145 100644
--- a/llvm/tools/llvm-c-test/echo.cpp
+++ b/llvm/tools/llvm-c-test/echo.cpp
@@ -755,6 +755,11 @@ struct FunCloner {
         Dst = LLVMBuildInsertValue(Builder, Agg, V, I, Name);
         break;
       }
+      case LLVMFreeze: {
+        LLVMValueRef Arg = CloneValue(LLVMGetOperand(Src, 0));
+        Dst = LLVMBuildFreeze(Builder, Arg, Name);
+        break;
+      }
       default:
         break;
     }


        


More information about the llvm-commits mailing list