Index: include/llvm/CodeGen/ISDOpcodes.h =================================================================== --- include/llvm/CodeGen/ISDOpcodes.h +++ include/llvm/CodeGen/ISDOpcodes.h @@ -177,6 +177,9 @@ /// UNDEF - An undefined node. UNDEF, + // FREEZE - A freeze node + FREEZE, + /// EXTRACT_ELEMENT - This is used to get the lower or upper (determined by /// a Constant, which is required to be operand #1) half of the integer or /// float value specified as operand #0. This is only for use before Index: include/llvm/CodeGen/SelectionDAGISel.h =================================================================== --- include/llvm/CodeGen/SelectionDAGISel.h +++ include/llvm/CodeGen/SelectionDAGISel.h @@ -265,6 +265,8 @@ void Select_UNDEF(SDNode *N); void CannotYetSelect(SDNode *N); + void Select_FREEZE(SDNode *N); + private: void DoInstructionSelection(); SDNode *MorphNode(SDNode *Node, unsigned TargetOpc, SDVTList VTs, Index: lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp =================================================================== --- lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp +++ lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp @@ -154,6 +154,9 @@ case ISD::ATOMIC_CMP_SWAP_WITH_SUCCESS: Res = PromoteIntRes_AtomicCmpSwap(cast(N), ResNo); break; + case ISD::FREEZE: + Res = PromoteIntRes_FREEZE(N); + break; } // If the result is null then the sub-method took care of registering it. @@ -303,6 +306,12 @@ CreateStackStoreLoad(InOp, OutVT)); } +SDValue DAGTypeLegalizer::PromoteIntRes_FREEZE(SDNode *N) { + SDValue V = GetPromotedInteger(N->getOperand(0)); + return DAG.getNode(N->getOpcode(), SDLoc(N), + V.getValueType(), V); +} + SDValue DAGTypeLegalizer::PromoteIntRes_BSWAP(SDNode *N) { SDValue Op = GetPromotedInteger(N->getOperand(0)); EVT OVT = N->getValueType(0); @@ -904,6 +913,7 @@ case ISD::SRL: case ISD::ROTL: case ISD::ROTR: Res = PromoteIntOp_Shift(N); break; + case ISD::FREEZE: Res = PromoteIntOp_FREEZE(N); break; } // If the result is null, the sub-method took care of registering results etc. @@ -1252,6 +1262,10 @@ N->getOperand(0).getValueType().getScalarType()); } +SDValue DAGTypeLegalizer::PromoteIntOp_FREEZE(SDNode *N) { + SDValue Op = GetPromotedInteger(N->getOperand(0)); + return DAG.getNode(ISD::FREEZE, SDLoc(N), Op.getValueType(), Op); +} //===----------------------------------------------------------------------===// // Integer Result Expansion @@ -1282,6 +1296,7 @@ case ISD::SELECT: SplitRes_SELECT(N, Lo, Hi); break; case ISD::SELECT_CC: SplitRes_SELECT_CC(N, Lo, Hi); break; case ISD::UNDEF: SplitRes_UNDEF(N, Lo, Hi); break; + case ISD::FREEZE: SplitRes_FREEZE(N, Lo, Hi); break; case ISD::BITCAST: ExpandRes_BITCAST(N, Lo, Hi); break; case ISD::BUILD_PAIR: ExpandRes_BUILD_PAIR(N, Lo, Hi); break; @@ -2747,6 +2762,7 @@ case ISD::STORE: Res = ExpandIntOp_STORE(cast(N), OpNo); break; case ISD::TRUNCATE: Res = ExpandIntOp_TRUNCATE(N); break; case ISD::UINT_TO_FP: Res = ExpandIntOp_UINT_TO_FP(N); break; + case ISD::FREEZE: Res = ExpandIntOp_FREEZE(N); break; case ISD::SHL: case ISD::SRA: @@ -3197,6 +3213,11 @@ return Swap.getValue(1); } +SDValue DAGTypeLegalizer::ExpandIntOp_FREEZE(SDNode *N) { + SDValue InL, InH; + GetExpandedInteger(N->getOperand(0), InL, InH); + return DAG.getNode(ISD::FREEZE, SDLoc(N), N->getValueType(0), InL); +} SDValue DAGTypeLegalizer::PromoteIntRes_EXTRACT_SUBVECTOR(SDNode *N) { SDValue InOp0 = N->getOperand(0); Index: lib/CodeGen/SelectionDAG/LegalizeTypes.h =================================================================== --- lib/CodeGen/SelectionDAG/LegalizeTypes.h +++ lib/CodeGen/SelectionDAG/LegalizeTypes.h @@ -255,6 +255,7 @@ SDValue PromoteIntRes_EXTRACT_VECTOR_ELT(SDNode *N); SDValue PromoteIntRes_FP_TO_XINT(SDNode *N); SDValue PromoteIntRes_FP_TO_FP16(SDNode *N); + SDValue PromoteIntRes_FREEZE(SDNode *N); SDValue PromoteIntRes_INT_EXTEND(SDNode *N); SDValue PromoteIntRes_LOAD(LoadSDNode *N); SDValue PromoteIntRes_MLOAD(MaskedLoadSDNode *N); @@ -290,6 +291,7 @@ SDValue PromoteIntOp_INSERT_VECTOR_ELT(SDNode *N, unsigned OpNo); SDValue PromoteIntOp_EXTRACT_VECTOR_ELT(SDNode *N); SDValue PromoteIntOp_EXTRACT_SUBVECTOR(SDNode *N); + SDValue PromoteIntOp_FREEZE(SDNode *N); SDValue PromoteIntOp_CONCAT_VECTORS(SDNode *N); SDValue PromoteIntOp_SCALAR_TO_VECTOR(SDNode *N); SDValue PromoteIntOp_SELECT(SDNode *N, unsigned OpNo); @@ -380,6 +382,7 @@ SDValue ExpandIntOp_UINT_TO_FP(SDNode *N); SDValue ExpandIntOp_RETURNADDR(SDNode *N); SDValue ExpandIntOp_ATOMIC_STORE(SDNode *N); + SDValue ExpandIntOp_FREEZE(SDNode *N); void IntegerExpandSetCCOperands(SDValue &NewLHS, SDValue &NewRHS, ISD::CondCode &CCCode, const SDLoc &dl); @@ -809,6 +812,7 @@ void SplitRes_SELECT (SDNode *N, SDValue &Lo, SDValue &Hi); void SplitRes_SELECT_CC (SDNode *N, SDValue &Lo, SDValue &Hi); void SplitRes_UNDEF (SDNode *N, SDValue &Lo, SDValue &Hi); + void SplitRes_FREEZE (SDNode *N, SDValue &Lo, SDValue &Hi); //===--------------------------------------------------------------------===// // Generic Expansion: LegalizeTypesGeneric.cpp Index: lib/CodeGen/SelectionDAG/LegalizeTypesGeneric.cpp =================================================================== --- lib/CodeGen/SelectionDAG/LegalizeTypesGeneric.cpp +++ lib/CodeGen/SelectionDAG/LegalizeTypesGeneric.cpp @@ -553,3 +553,12 @@ Lo = DAG.getUNDEF(LoVT); Hi = DAG.getUNDEF(HiVT); } + +void DAGTypeLegalizer::SplitRes_FREEZE(SDNode *N, SDValue &Lo, SDValue &Hi) { + SDValue L, H; + SDLoc dl(N); + GetSplitOp(N->getOperand(0), L, H); + + Lo = DAG.getNode(ISD::FREEZE, dl, L.getValueType(), L); + Hi = DAG.getNode(ISD::FREEZE, dl, H.getValueType(), H); +} Index: lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp =================================================================== --- lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -9350,5 +9350,9 @@ void SelectionDAGBuilder::visitFreeze(const FreezeInst &I) { SDValue N = getValue(I.getOperand(0)); - setValue(&I, N); + SDLoc dl = getCurSDLoc(); + EVT DestVT = DAG.getTargetLoweringInfo().getValueType(DAG.getDataLayout(), + I.getType()); + + setValue(&I, DAG.getNode(ISD::FREEZE, dl, DestVT, N)); } Index: lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp =================================================================== --- lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp +++ lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp @@ -298,6 +298,7 @@ case ISD::GC_TRANSITION_START: return "gc_transition.start"; case ISD::GC_TRANSITION_END: return "gc_transition.end"; case ISD::GET_DYNAMIC_AREA_OFFSET: return "get.dynamic.area.offset"; + case ISD::FREEZE: return "freeze"; // Bit manipulation case ISD::BITREVERSE: return "bitreverse"; Index: lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp =================================================================== --- lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp +++ lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp @@ -2227,6 +2227,57 @@ CurDAG->SelectNodeTo(N, TargetOpcode::IMPLICIT_DEF, N->getValueType(0)); } +void SelectionDAGISel::Select_FREEZE(SDNode *N) { + SDValue Op = N->getOperand(0); + EVT Ty = N->getValueType(0); + SDLoc dl(N); + + // Select FREEZE to CopyToReg + CopyFromReg. + // This blocks propagation of UNDEF while translating SelDag into + // MachineInstr. + // LLVM translates an UNDEF node into multiple IMPLICIT_DEF + // instructions (in MachineInstr) if the UNDEF has multiple uses. + // For example, + // + // %y1 = UNDEF + // %t1 = mul i64 %y1, %y1 + // + // It is translated into MachineInstr code + // + // %vreg2 = IMPLICIT_DEF + // %vreg3 = IMPLICIT_DEF + // %vreg1 = IMUL32rr %vreg2, %vreg3 + // + // However, with freeze, + // + // %y1 = freeze i64 UNDEF + // %t1 = mul i64 %y1, %y1 + // + // each read of %y1 must yield same value, so it must be translated into : + // + // %vreg2 = IMPLICIT_DEF + // %vreg1 = IMUL32rr %vreg2, %vreg2 + // + // Selecting FREEZE into CopyToReg + CopyFromReg helps this. + // + // We don't have FREEZE pseudo-instruction in MachineInstr-level now. + // If FREEZE instruction is added later, the code below must be + // changed as well. + + const TargetRegisterClass *RC = TLI->getRegClassFor(Ty.getSimpleVT()); + // Create a new virtual register. + unsigned NewVirtReg = RegInfo->createVirtualRegister(RC); + // Create CopyToReg node ('copy val into NewVirtReg') + SDValue CTRVal = CurDAG->getCopyToReg(CurDAG->getEntryNode(), dl, + NewVirtReg, Op); + // Create CopyFromReg node ('get value from NewVirtReg') + SDValue CFRVal = CurDAG->getCopyFromReg(CTRVal, dl, NewVirtReg, Ty); + // Mark selected. + CTRVal->setNodeId(-1); + ReplaceUses(SDValue(N, 0), CFRVal); + CurDAG->RemoveDeadNode(N); +} + /// GetVBR - decode a vbr encoding whose top bit is set. LLVM_ATTRIBUTE_ALWAYS_INLINE static inline uint64_t GetVBR(uint64_t Val, const unsigned char *MatcherTable, unsigned &Idx) { @@ -2853,6 +2904,9 @@ case ISD::UNDEF: Select_UNDEF(NodeToMatch); return; + case ISD::FREEZE: + Select_FREEZE(NodeToMatch); + return; } assert(!NodeToMatch->isMachineOpcode() && "Node already selected!"); Index: lib/CodeGen/TargetLoweringBase.cpp =================================================================== --- lib/CodeGen/TargetLoweringBase.cpp +++ lib/CodeGen/TargetLoweringBase.cpp @@ -1744,7 +1744,7 @@ case ExtractValue: return ISD::MERGE_VALUES; case InsertValue: return ISD::MERGE_VALUES; case LandingPad: return 0; - case Freeze: return 0; + case Freeze: return ISD::FREEZE; } llvm_unreachable("Unknown instruction type encountered!"); Index: test/CodeGen/X86/freeze-legalize.ll =================================================================== --- /dev/null +++ test/CodeGen/X86/freeze-legalize.ll @@ -0,0 +1,29 @@ +; Make sure that seldag legalization works correctly for freeze instruction. +; RUN: llc -march=x86 < %s 2>&1 | FileCheck %s + +; CHECK: movl $303174162, %ecx +; CHECK: movl $875836468, %esi +; CHECK: movl $1448498774, %edx +; CHECK: movl $2021161080, %eax +; CHECK: xorl %esi, %eax +; CHECK: xorl %ecx, %edx +; CHECK: popl %esi +; CHECK: retl + +define i64 @expand(i32 %x) { + %y1 = freeze i64 1302123111658042420 ; 0x1212121234343434 + %y2 = freeze i64 6221254864647256184 ; 0x5656565678787878 + %t2 = xor i64 %y1, %y2 + ret i64 %t2 +} + +; CHECK: movw $682, %cx +; CHECK: movw $992, %ax +; CHECK: addl %ecx, %eax +; CHECK: retl +define i10 @promote() { + %a = freeze i10 682 ; 0x2AA + %b = freeze i10 992 ; 0x3E0 + %res = add i10 %a, %b + ret i10 %res +} Index: test/CodeGen/X86/freeze.ll =================================================================== --- /dev/null +++ test/CodeGen/X86/freeze.ll @@ -0,0 +1,19 @@ +; RUN: llc -mtriple=x86_64-unknown-linux-gnu -print-machineinstrs=expand-isel-pseudos %s -o /dev/null 2>&1 | FileCheck %s --check-prefix=MCINSTR +; RUN: llc -mtriple=x86_64-unknown-linux-gnu < %s 2>&1 | FileCheck %s --check-prefix=X86ASM + +; X86ASM: imull %eax, %eax +; X86ASM: xorl %eax, %eax +; X86ASM: retq + +; MCINSTR: %vreg1[[attr1:.*]] = IMPLICIT_DEF; +; MCINSTR: %vreg2[[attr2:.*]] = IMUL32rr %vreg1[[attr3:.*]], %vreg1, +; MCINSTR: %vreg3[[attr4:.*]] = XOR32rr %vreg2[[attr5:.*]], %vreg1, +; MCINSTR: %EAX[[attr6:.*]] = COPY %vreg3; +; MCINSTR: RET 0, %EAX + +define i32 @foo(i32 %x) { + %y1 = freeze i32 undef + %t1 = mul i32 %y1, %y1 + %t2 = xor i32 %t1, %y1 + ret i32 %t2 +}