diff options
Diffstat (limited to 'contrib/llvm-project/llvm/lib/CodeGen/MachineInstr.cpp')
-rw-r--r-- | contrib/llvm-project/llvm/lib/CodeGen/MachineInstr.cpp | 240 |
1 files changed, 147 insertions, 93 deletions
diff --git a/contrib/llvm-project/llvm/lib/CodeGen/MachineInstr.cpp b/contrib/llvm-project/llvm/lib/CodeGen/MachineInstr.cpp index e92dec5bea48..8e0777f8438a 100644 --- a/contrib/llvm-project/llvm/lib/CodeGen/MachineInstr.cpp +++ b/contrib/llvm-project/llvm/lib/CodeGen/MachineInstr.cpp @@ -13,7 +13,6 @@ #include "llvm/CodeGen/MachineInstr.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/Hashing.h" -#include "llvm/ADT/None.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallBitVector.h" #include "llvm/ADT/SmallVector.h" @@ -85,14 +84,10 @@ static void tryToGetTargetInfo(const MachineInstr &MI, } void MachineInstr::addImplicitDefUseOperands(MachineFunction &MF) { - if (MCID->ImplicitDefs) - for (const MCPhysReg *ImpDefs = MCID->getImplicitDefs(); *ImpDefs; - ++ImpDefs) - addOperand(MF, MachineOperand::CreateReg(*ImpDefs, true, true)); - if (MCID->ImplicitUses) - for (const MCPhysReg *ImpUses = MCID->getImplicitUses(); *ImpUses; - ++ImpUses) - addOperand(MF, MachineOperand::CreateReg(*ImpUses, false, true)); + for (MCPhysReg ImpDef : MCID->implicit_defs()) + addOperand(MF, MachineOperand::CreateReg(ImpDef, true, true)); + for (MCPhysReg ImpUse : MCID->implicit_uses()) + addOperand(MF, MachineOperand::CreateReg(ImpUse, false, true)); } /// MachineInstr ctor - This constructor creates a MachineInstr and adds the @@ -104,8 +99,8 @@ MachineInstr::MachineInstr(MachineFunction &MF, const MCInstrDesc &TID, assert(DbgLoc.hasTrivialDestructor() && "Expected trivial destructor"); // Reserve space for the expected number of operands. - if (unsigned NumOps = MCID->getNumOperands() + - MCID->getNumImplicitDefs() + MCID->getNumImplicitUses()) { + if (unsigned NumOps = MCID->getNumOperands() + MCID->implicit_defs().size() + + MCID->implicit_uses().size()) { CapOperands = OperandCapacity::get(NumOps); Operands = MF.allocateOperandArray(CapOperands); } @@ -129,6 +124,14 @@ MachineInstr::MachineInstr(MachineFunction &MF, const MachineInstr &MI) for (const MachineOperand &MO : MI.operands()) addOperand(MF, MO); + // Replicate ties between the operands, which addOperand was not + // able to do reliably. + for (unsigned i = 0, e = getNumOperands(); i < e; ++i) { + MachineOperand &NewMO = getOperand(i); + const MachineOperand &OrigMO = MI.getOperand(i); + NewMO.TiedTo = OrigMO.TiedTo; + } + // Copy all the sensible flags. setFlags(MI.Flags); } @@ -301,12 +304,15 @@ void MachineInstr::setExtraInfo(MachineFunction &MF, ArrayRef<MachineMemOperand *> MMOs, MCSymbol *PreInstrSymbol, MCSymbol *PostInstrSymbol, - MDNode *HeapAllocMarker) { + MDNode *HeapAllocMarker, MDNode *PCSections, + uint32_t CFIType) { bool HasPreInstrSymbol = PreInstrSymbol != nullptr; bool HasPostInstrSymbol = PostInstrSymbol != nullptr; bool HasHeapAllocMarker = HeapAllocMarker != nullptr; - int NumPointers = - MMOs.size() + HasPreInstrSymbol + HasPostInstrSymbol + HasHeapAllocMarker; + bool HasPCSections = PCSections != nullptr; + bool HasCFIType = CFIType != 0; + int NumPointers = MMOs.size() + HasPreInstrSymbol + HasPostInstrSymbol + + HasHeapAllocMarker + HasPCSections + HasCFIType; // Drop all extra info if there is none. if (NumPointers <= 0) { @@ -318,9 +324,11 @@ void MachineInstr::setExtraInfo(MachineFunction &MF, // out of line because PointerSumType cannot hold more than 4 tag types with // 32-bit pointers. // FIXME: Maybe we should make the symbols in the extra info mutable? - else if (NumPointers > 1 || HasHeapAllocMarker) { - Info.set<EIIK_OutOfLine>(MF.createMIExtraInfo( - MMOs, PreInstrSymbol, PostInstrSymbol, HeapAllocMarker)); + else if (NumPointers > 1 || HasHeapAllocMarker || HasPCSections || + HasCFIType) { + Info.set<EIIK_OutOfLine>( + MF.createMIExtraInfo(MMOs, PreInstrSymbol, PostInstrSymbol, + HeapAllocMarker, PCSections, CFIType)); return; } @@ -338,7 +346,7 @@ void MachineInstr::dropMemRefs(MachineFunction &MF) { return; setExtraInfo(MF, {}, getPreInstrSymbol(), getPostInstrSymbol(), - getHeapAllocMarker()); + getHeapAllocMarker(), getPCSections(), getCFIType()); } void MachineInstr::setMemRefs(MachineFunction &MF, @@ -349,7 +357,7 @@ void MachineInstr::setMemRefs(MachineFunction &MF, } setExtraInfo(MF, MMOs, getPreInstrSymbol(), getPostInstrSymbol(), - getHeapAllocMarker()); + getHeapAllocMarker(), getPCSections(), getCFIType()); } void MachineInstr::addMemOperand(MachineFunction &MF, @@ -372,7 +380,8 @@ void MachineInstr::cloneMemRefs(MachineFunction &MF, const MachineInstr &MI) { // are the same (including null). if (getPreInstrSymbol() == MI.getPreInstrSymbol() && getPostInstrSymbol() == MI.getPostInstrSymbol() && - getHeapAllocMarker() == MI.getHeapAllocMarker()) { + getHeapAllocMarker() == MI.getHeapAllocMarker() && + getPCSections() == MI.getPCSections()) { Info = MI.Info; return; } @@ -457,7 +466,7 @@ void MachineInstr::setPreInstrSymbol(MachineFunction &MF, MCSymbol *Symbol) { } setExtraInfo(MF, memoperands(), Symbol, getPostInstrSymbol(), - getHeapAllocMarker()); + getHeapAllocMarker(), getPCSections(), getCFIType()); } void MachineInstr::setPostInstrSymbol(MachineFunction &MF, MCSymbol *Symbol) { @@ -472,7 +481,7 @@ void MachineInstr::setPostInstrSymbol(MachineFunction &MF, MCSymbol *Symbol) { } setExtraInfo(MF, memoperands(), getPreInstrSymbol(), Symbol, - getHeapAllocMarker()); + getHeapAllocMarker(), getPCSections(), getCFIType()); } void MachineInstr::setHeapAllocMarker(MachineFunction &MF, MDNode *Marker) { @@ -481,7 +490,25 @@ void MachineInstr::setHeapAllocMarker(MachineFunction &MF, MDNode *Marker) { return; setExtraInfo(MF, memoperands(), getPreInstrSymbol(), getPostInstrSymbol(), - Marker); + Marker, getPCSections(), getCFIType()); +} + +void MachineInstr::setPCSections(MachineFunction &MF, MDNode *PCSections) { + // Do nothing if old and new symbols are the same. + if (PCSections == getPCSections()) + return; + + setExtraInfo(MF, memoperands(), getPreInstrSymbol(), getPostInstrSymbol(), + getHeapAllocMarker(), PCSections, getCFIType()); +} + +void MachineInstr::setCFIType(MachineFunction &MF, uint32_t Type) { + // Do nothing if old and new types are the same. + if (Type == getCFIType()) + return; + + setExtraInfo(MF, memoperands(), getPreInstrSymbol(), getPostInstrSymbol(), + getHeapAllocMarker(), getPCSections(), Type); } void MachineInstr::cloneInstrSymbols(MachineFunction &MF, @@ -496,6 +523,7 @@ void MachineInstr::cloneInstrSymbols(MachineFunction &MF, setPreInstrSymbol(MF, MI.getPreInstrSymbol()); setPostInstrSymbol(MF, MI.getPostInstrSymbol()); setHeapAllocMarker(MF, MI.getHeapAllocMarker()); + setPCSections(MF, MI.getPCSections()); } uint16_t MachineInstr::mergeFlagsWith(const MachineInstr &Other) const { @@ -608,8 +636,7 @@ bool MachineInstr::isIdenticalTo(const MachineInstr &Other, if (Check == IgnoreDefs) continue; else if (Check == IgnoreVRegDefs) { - if (!Register::isVirtualRegister(MO.getReg()) || - !Register::isVirtualRegister(OMO.getReg())) + if (!MO.getReg().isVirtual() || !OMO.getReg().isVirtual()) if (!MO.isIdenticalTo(OMO)) return false; } else { @@ -630,6 +657,34 @@ bool MachineInstr::isIdenticalTo(const MachineInstr &Other, if (getDebugLoc() && Other.getDebugLoc() && getDebugLoc() != Other.getDebugLoc()) return false; + // If pre- or post-instruction symbols do not match then the two instructions + // are not identical. + if (getPreInstrSymbol() != Other.getPreInstrSymbol() || + getPostInstrSymbol() != Other.getPostInstrSymbol()) + return false; + // Call instructions with different CFI types are not identical. + if (isCall() && getCFIType() != Other.getCFIType()) + return false; + + return true; +} + +bool MachineInstr::isEquivalentDbgInstr(const MachineInstr &Other) const { + if (!isDebugValueLike() || !Other.isDebugValueLike()) + return false; + if (getDebugLoc() != Other.getDebugLoc()) + return false; + if (getDebugVariable() != Other.getDebugVariable()) + return false; + if (getNumDebugOperands() != Other.getNumDebugOperands()) + return false; + for (unsigned OpIdx = 0; OpIdx < getNumDebugOperands(); ++OpIdx) + if (!getDebugOperand(OpIdx).isIdenticalTo(Other.getDebugOperand(OpIdx))) + return false; + if (!DIExpression::isEqualExpression( + getDebugExpression(), isIndirectDebugValue(), + Other.getDebugExpression(), Other.isIndirectDebugValue())) + return false; return true; } @@ -794,14 +849,14 @@ const DILabel *MachineInstr::getDebugLabel() const { } const MachineOperand &MachineInstr::getDebugVariableOp() const { - assert((isDebugValue() || isDebugRef()) && "not a DBG_VALUE*"); - unsigned VariableOp = isDebugValueList() ? 0 : 2; + assert((isDebugValueLike()) && "not a DBG_VALUE*"); + unsigned VariableOp = isNonListDebugValue() ? 2 : 0; return getOperand(VariableOp); } MachineOperand &MachineInstr::getDebugVariableOp() { - assert((isDebugValue() || isDebugRef()) && "not a DBG_VALUE*"); - unsigned VariableOp = isDebugValueList() ? 0 : 2; + assert((isDebugValueLike()) && "not a DBG_VALUE*"); + unsigned VariableOp = isNonListDebugValue() ? 2 : 0; return getOperand(VariableOp); } @@ -810,14 +865,14 @@ const DILocalVariable *MachineInstr::getDebugVariable() const { } const MachineOperand &MachineInstr::getDebugExpressionOp() const { - assert((isDebugValue() || isDebugRef()) && "not a DBG_VALUE*"); - unsigned ExpressionOp = isDebugValueList() ? 1 : 3; + assert((isDebugValueLike()) && "not a DBG_VALUE*"); + unsigned ExpressionOp = isNonListDebugValue() ? 3 : 1; return getOperand(ExpressionOp); } MachineOperand &MachineInstr::getDebugExpressionOp() { - assert((isDebugValue() || isDebugRef()) && "not a DBG_VALUE*"); - unsigned ExpressionOp = isDebugValueList() ? 1 : 3; + assert((isDebugValueLike()) && "not a DBG_VALUE*"); + unsigned ExpressionOp = isNonListDebugValue() ? 3 : 1; return getOperand(ExpressionOp); } @@ -993,7 +1048,7 @@ MachineInstr::readsWritesVirtualRegister(Register Reg, int MachineInstr::findRegisterDefOperandIdx(Register Reg, bool isDead, bool Overlap, const TargetRegisterInfo *TRI) const { - bool isPhys = Register::isPhysicalRegister(Reg); + bool isPhys = Reg.isPhysical(); for (unsigned i = 0, e = getNumOperands(); i != e; ++i) { const MachineOperand &MO = getOperand(i); // Accept regmask operands when Overlap is set. @@ -1004,7 +1059,7 @@ MachineInstr::findRegisterDefOperandIdx(Register Reg, bool isDead, bool Overlap, continue; Register MOReg = MO.getReg(); bool Found = (MOReg == Reg); - if (!Found && TRI && isPhys && Register::isPhysicalRegister(MOReg)) { + if (!Found && TRI && isPhys && MOReg.isPhysical()) { if (Overlap) Found = TRI->regsOverlap(MOReg, Reg); else @@ -1027,7 +1082,7 @@ int MachineInstr::findFirstPredOperandIdx() const { const MCInstrDesc &MCID = getDesc(); if (MCID.isPredicable()) { for (unsigned i = 0, e = getNumOperands(); i != e; ++i) - if (MCID.OpInfo[i].isPredicate()) + if (MCID.operands()[i].isPredicate()) return i; } @@ -1162,7 +1217,7 @@ void MachineInstr::clearKillInfo() { void MachineInstr::substituteRegister(Register FromReg, Register ToReg, unsigned SubIdx, const TargetRegisterInfo &RegInfo) { - if (Register::isPhysicalRegister(ToReg)) { + if (ToReg.isPhysical()) { if (SubIdx) ToReg = RegInfo.getSubReg(ToReg, SubIdx); for (MachineOperand &MO : operands()) { @@ -1465,7 +1520,7 @@ LLT MachineInstr::getTypeToPrint(unsigned OpIdx, SmallBitVector &PrintedTypes, if (isVariadic() || OpIdx >= getNumExplicitOperands()) return MRI.getType(Op.getReg()); - auto &OpInfo = getDesc().OpInfo[OpIdx]; + auto &OpInfo = getDesc().operands()[OpIdx]; if (!OpInfo.isGenericType()) return MRI.getType(Op.getReg()); @@ -1748,6 +1803,19 @@ void MachineInstr::print(raw_ostream &OS, ModuleSlotTracker &MST, OS << " heap-alloc-marker "; HeapAllocMarker->printAsOperand(OS, MST); } + if (MDNode *PCSections = getPCSections()) { + if (!FirstOp) { + FirstOp = false; + OS << ','; + } + OS << " pcsections "; + PCSections->printAsOperand(OS, MST); + } + if (uint32_t CFIType = getCFIType()) { + if (!FirstOp) + OS << ','; + OS << " cfi-type " << CFIType; + } if (DebugInstrNum) { if (!FirstOp) @@ -1822,7 +1890,7 @@ void MachineInstr::print(raw_ostream &OS, ModuleSlotTracker &MST, bool MachineInstr::addRegisterKilled(Register IncomingReg, const TargetRegisterInfo *RegInfo, bool AddIfNotFound) { - bool isPhysReg = Register::isPhysicalRegister(IncomingReg); + bool isPhysReg = IncomingReg.isPhysical(); bool hasAliases = isPhysReg && MCRegAliasIterator(IncomingReg, RegInfo, false).isValid(); bool Found = false; @@ -1853,7 +1921,7 @@ bool MachineInstr::addRegisterKilled(Register IncomingReg, MO.setIsKill(); Found = true; } - } else if (hasAliases && MO.isKill() && Register::isPhysicalRegister(Reg)) { + } else if (hasAliases && MO.isKill() && Reg.isPhysical()) { // A super-register kill already exists. if (RegInfo->isSuperRegister(IncomingReg, Reg)) return true; @@ -1887,7 +1955,7 @@ bool MachineInstr::addRegisterKilled(Register IncomingReg, void MachineInstr::clearRegisterKills(Register Reg, const TargetRegisterInfo *RegInfo) { - if (!Register::isPhysicalRegister(Reg)) + if (!Reg.isPhysical()) RegInfo = nullptr; for (MachineOperand &MO : operands()) { if (!MO.isReg() || !MO.isUse() || !MO.isKill()) @@ -1901,7 +1969,7 @@ void MachineInstr::clearRegisterKills(Register Reg, bool MachineInstr::addRegisterDead(Register Reg, const TargetRegisterInfo *RegInfo, bool AddIfNotFound) { - bool isPhysReg = Register::isPhysicalRegister(Reg); + bool isPhysReg = Reg.isPhysical(); bool hasAliases = isPhysReg && MCRegAliasIterator(Reg, RegInfo, false).isValid(); bool Found = false; @@ -1917,8 +1985,7 @@ bool MachineInstr::addRegisterDead(Register Reg, if (MOReg == Reg) { MO.setIsDead(); Found = true; - } else if (hasAliases && MO.isDead() && - Register::isPhysicalRegister(MOReg)) { + } else if (hasAliases && MO.isDead() && MOReg.isPhysical()) { // There exists a super-register that's marked dead. if (RegInfo->isSuperRegister(Reg, MOReg)) return true; @@ -1969,7 +2036,7 @@ void MachineInstr::setRegisterDefReadUndef(Register Reg, bool IsUndef) { void MachineInstr::addRegisterDefined(Register Reg, const TargetRegisterInfo *RegInfo) { - if (Register::isPhysicalRegister(Reg)) { + if (Reg.isPhysical()) { MachineOperand *MO = findRegisterDefOperand(Reg, false, false, RegInfo); if (MO) return; @@ -2017,7 +2084,7 @@ MachineInstrExpressionTrait::getHashValue(const MachineInstr* const &MI) { HashComponents.reserve(MI->getNumOperands() + 1); HashComponents.push_back(MI->getOpcode()); for (const MachineOperand &MO : MI->operands()) { - if (MO.isReg() && MO.isDef() && Register::isVirtualRegister(MO.getReg())) + if (MO.isReg() && MO.isDef() && MO.getReg().isVirtual()) continue; // Skip virtual register defs. HashComponents.push_back(hash_value(MO)); @@ -2065,41 +2132,35 @@ MachineInstrBuilder llvm::BuildMI(MachineFunction &MF, const DebugLoc &DL, MachineInstrBuilder llvm::BuildMI(MachineFunction &MF, const DebugLoc &DL, const MCInstrDesc &MCID, bool IsIndirect, - const MachineOperand &MO, - const MDNode *Variable, const MDNode *Expr) { - assert(isa<DILocalVariable>(Variable) && "not a variable"); - assert(cast<DIExpression>(Expr)->isValid() && "not an expression"); - assert(cast<DILocalVariable>(Variable)->isValidLocationForIntrinsic(DL) && - "Expected inlined-at fields to agree"); - if (MO.isReg()) - return BuildMI(MF, DL, MCID, IsIndirect, MO.getReg(), Variable, Expr); - - auto MIB = BuildMI(MF, DL, MCID).add(MO); - if (IsIndirect) - MIB.addImm(0U); - else - MIB.addReg(0U); - return MIB.addMetadata(Variable).addMetadata(Expr); -} - -MachineInstrBuilder llvm::BuildMI(MachineFunction &MF, const DebugLoc &DL, - const MCInstrDesc &MCID, bool IsIndirect, - ArrayRef<MachineOperand> MOs, + ArrayRef<MachineOperand> DebugOps, const MDNode *Variable, const MDNode *Expr) { assert(isa<DILocalVariable>(Variable) && "not a variable"); assert(cast<DIExpression>(Expr)->isValid() && "not an expression"); assert(cast<DILocalVariable>(Variable)->isValidLocationForIntrinsic(DL) && "Expected inlined-at fields to agree"); - if (MCID.Opcode == TargetOpcode::DBG_VALUE) - return BuildMI(MF, DL, MCID, IsIndirect, MOs[0], Variable, Expr); + if (MCID.Opcode == TargetOpcode::DBG_VALUE) { + assert(DebugOps.size() == 1 && + "DBG_VALUE must contain exactly one debug operand"); + MachineOperand DebugOp = DebugOps[0]; + if (DebugOp.isReg()) + return BuildMI(MF, DL, MCID, IsIndirect, DebugOp.getReg(), Variable, + Expr); + + auto MIB = BuildMI(MF, DL, MCID).add(DebugOp); + if (IsIndirect) + MIB.addImm(0U); + else + MIB.addReg(0U); + return MIB.addMetadata(Variable).addMetadata(Expr); + } auto MIB = BuildMI(MF, DL, MCID); MIB.addMetadata(Variable).addMetadata(Expr); - for (const MachineOperand &MO : MOs) - if (MO.isReg()) - MIB.addReg(MO.getReg()); + for (const MachineOperand &DebugOp : DebugOps) + if (DebugOp.isReg()) + MIB.addReg(DebugOp.getReg()); else - MIB.add(MO); + MIB.add(DebugOp); return MIB; } @@ -2117,21 +2178,12 @@ MachineInstrBuilder llvm::BuildMI(MachineBasicBlock &BB, MachineInstrBuilder llvm::BuildMI(MachineBasicBlock &BB, MachineBasicBlock::iterator I, const DebugLoc &DL, const MCInstrDesc &MCID, - bool IsIndirect, MachineOperand &MO, - const MDNode *Variable, const MDNode *Expr) { - MachineFunction &MF = *BB.getParent(); - MachineInstr *MI = BuildMI(MF, DL, MCID, IsIndirect, MO, Variable, Expr); - BB.insert(I, MI); - return MachineInstrBuilder(MF, *MI); -} - -MachineInstrBuilder llvm::BuildMI(MachineBasicBlock &BB, - MachineBasicBlock::iterator I, - const DebugLoc &DL, const MCInstrDesc &MCID, - bool IsIndirect, ArrayRef<MachineOperand> MOs, + bool IsIndirect, + ArrayRef<MachineOperand> DebugOps, const MDNode *Variable, const MDNode *Expr) { MachineFunction &MF = *BB.getParent(); - MachineInstr *MI = BuildMI(MF, DL, MCID, IsIndirect, MOs, Variable, Expr); + MachineInstr *MI = + BuildMI(MF, DL, MCID, IsIndirect, DebugOps, Variable, Expr); BB.insert(I, MI); return MachineInstrBuilder(MF, *MI); } @@ -2173,6 +2225,8 @@ MachineInstr *llvm::buildDbgValueForSpill(MachineBasicBlock &BB, MachineBasicBlock::iterator I, const MachineInstr &Orig, int FrameIndex, Register SpillReg) { + assert(!Orig.isDebugRef() && + "DBG_INSTR_REF should not reference a virtual register."); const DIExpression *Expr = computeExprForSpill(Orig, SpillReg); MachineInstrBuilder NewMI = BuildMI(BB, I, Orig.getDebugLoc(), Orig.getDesc()); @@ -2275,7 +2329,7 @@ static unsigned getSpillSlotSize(const MMOList &Accesses, return Size; } -Optional<unsigned> +std::optional<unsigned> MachineInstr::getSpillSize(const TargetInstrInfo *TII) const { int FI; if (TII->isStoreToStackSlotPostFE(*this, FI)) { @@ -2283,18 +2337,18 @@ MachineInstr::getSpillSize(const TargetInstrInfo *TII) const { if (MFI.isSpillSlotObjectIndex(FI)) return (*memoperands_begin())->getSize(); } - return None; + return std::nullopt; } -Optional<unsigned> +std::optional<unsigned> MachineInstr::getFoldedSpillSize(const TargetInstrInfo *TII) const { MMOList Accesses; if (TII->hasStoreToStackSlot(*this, Accesses)) return getSpillSlotSize(Accesses, getMF()->getFrameInfo()); - return None; + return std::nullopt; } -Optional<unsigned> +std::optional<unsigned> MachineInstr::getRestoreSize(const TargetInstrInfo *TII) const { int FI; if (TII->isLoadFromStackSlotPostFE(*this, FI)) { @@ -2302,15 +2356,15 @@ MachineInstr::getRestoreSize(const TargetInstrInfo *TII) const { if (MFI.isSpillSlotObjectIndex(FI)) return (*memoperands_begin())->getSize(); } - return None; + return std::nullopt; } -Optional<unsigned> +std::optional<unsigned> MachineInstr::getFoldedRestoreSize(const TargetInstrInfo *TII) const { MMOList Accesses; if (TII->hasLoadFromStackSlot(*this, Accesses)) return getSpillSlotSize(Accesses, getMF()->getFrameInfo()); - return None; + return std::nullopt; } unsigned MachineInstr::getDebugInstrNum() { |