summaryrefslogtreecommitdiffstats
path: root/js/src/jit/arm64/CodeGenerator-arm64.cpp
diff options
context:
space:
mode:
authorMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
committerMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
commit5f8de423f190bbb79a62f804151bc24824fa32d8 (patch)
tree10027f336435511475e392454359edea8e25895d /js/src/jit/arm64/CodeGenerator-arm64.cpp
parent49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff)
downloadUXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip
Add m-esr52 at 52.6.0
Diffstat (limited to 'js/src/jit/arm64/CodeGenerator-arm64.cpp')
-rw-r--r--js/src/jit/arm64/CodeGenerator-arm64.cpp783
1 files changed, 783 insertions, 0 deletions
diff --git a/js/src/jit/arm64/CodeGenerator-arm64.cpp b/js/src/jit/arm64/CodeGenerator-arm64.cpp
new file mode 100644
index 000000000..83330a262
--- /dev/null
+++ b/js/src/jit/arm64/CodeGenerator-arm64.cpp
@@ -0,0 +1,783 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "jit/arm64/CodeGenerator-arm64.h"
+
+#include "mozilla/MathAlgorithms.h"
+
+#include "jscntxt.h"
+#include "jscompartment.h"
+#include "jsnum.h"
+
+#include "jit/CodeGenerator.h"
+#include "jit/JitCompartment.h"
+#include "jit/JitFrames.h"
+#include "jit/MIR.h"
+#include "jit/MIRGraph.h"
+#include "vm/Shape.h"
+#include "vm/TraceLogging.h"
+
+#include "jsscriptinlines.h"
+
+#include "jit/shared/CodeGenerator-shared-inl.h"
+
+using namespace js;
+using namespace js::jit;
+
+using mozilla::FloorLog2;
+using mozilla::NegativeInfinity;
+using JS::GenericNaN;
+
+// shared
+CodeGeneratorARM64::CodeGeneratorARM64(MIRGenerator* gen, LIRGraph* graph, MacroAssembler* masm)
+ : CodeGeneratorShared(gen, graph, masm)
+{
+}
+
+bool
+CodeGeneratorARM64::generateOutOfLineCode()
+{
+ MOZ_CRASH("generateOutOfLineCode");
+}
+
+void
+CodeGeneratorARM64::emitBranch(Assembler::Condition cond, MBasicBlock* mirTrue, MBasicBlock* mirFalse)
+{
+ MOZ_CRASH("emitBranch");
+}
+
+void
+OutOfLineBailout::accept(CodeGeneratorARM64* codegen)
+{
+ MOZ_CRASH("accept");
+}
+
+void
+CodeGeneratorARM64::visitTestIAndBranch(LTestIAndBranch* test)
+{
+ MOZ_CRASH("visitTestIAndBranch");
+}
+
+void
+CodeGeneratorARM64::visitCompare(LCompare* comp)
+{
+ MOZ_CRASH("visitCompare");
+}
+
+void
+CodeGeneratorARM64::visitCompareAndBranch(LCompareAndBranch* comp)
+{
+ MOZ_CRASH("visitCompareAndBranch");
+}
+
+void
+CodeGeneratorARM64::bailoutIf(Assembler::Condition condition, LSnapshot* snapshot)
+{
+ MOZ_CRASH("bailoutIf");
+}
+
+void
+CodeGeneratorARM64::bailoutFrom(Label* label, LSnapshot* snapshot)
+{
+ MOZ_CRASH("bailoutFrom");
+}
+
+void
+CodeGeneratorARM64::bailout(LSnapshot* snapshot)
+{
+ MOZ_CRASH("bailout");
+}
+
+void
+CodeGeneratorARM64::visitOutOfLineBailout(OutOfLineBailout* ool)
+{
+ MOZ_CRASH("visitOutOfLineBailout");
+}
+
+void
+CodeGeneratorARM64::visitMinMaxD(LMinMaxD* ins)
+{
+ MOZ_CRASH("visitMinMaxD");
+}
+
+void
+CodeGeneratorARM64::visitMinMaxF(LMinMaxF* ins)
+{
+ MOZ_CRASH("visitMinMaxF");
+}
+
+void
+CodeGeneratorARM64::visitAbsD(LAbsD* ins)
+{
+ MOZ_CRASH("visitAbsD");
+}
+
+void
+CodeGeneratorARM64::visitAbsF(LAbsF* ins)
+{
+ MOZ_CRASH("visitAbsF");
+}
+
+void
+CodeGeneratorARM64::visitSqrtD(LSqrtD* ins)
+{
+ MOZ_CRASH("visitSqrtD");
+}
+
+void
+CodeGeneratorARM64::visitSqrtF(LSqrtF* ins)
+{
+ MOZ_CRASH("visitSqrtF");
+}
+
+// FIXME: Uh, is this a static function? It looks like it is...
+template <typename T>
+ARMRegister
+toWRegister(const T* a)
+{
+ return ARMRegister(ToRegister(a), 32);
+}
+
+// FIXME: Uh, is this a static function? It looks like it is...
+template <typename T>
+ARMRegister
+toXRegister(const T* a)
+{
+ return ARMRegister(ToRegister(a), 64);
+}
+
+js::jit::Operand
+toWOperand(const LAllocation* a)
+{
+ MOZ_CRASH("toWOperand");
+}
+
+vixl::CPURegister
+ToCPURegister(const LAllocation* a, Scalar::Type type)
+{
+ MOZ_CRASH("ToCPURegister");
+}
+
+vixl::CPURegister
+ToCPURegister(const LDefinition* d, Scalar::Type type)
+{
+ return ToCPURegister(d->output(), type);
+}
+
+void
+CodeGeneratorARM64::visitAddI(LAddI* ins)
+{
+ MOZ_CRASH("visitAddI");
+}
+
+void
+CodeGeneratorARM64::visitSubI(LSubI* ins)
+{
+ MOZ_CRASH("visitSubI");
+}
+
+void
+CodeGeneratorARM64::visitMulI(LMulI* ins)
+{
+ MOZ_CRASH("visitMulI");
+}
+
+
+void
+CodeGeneratorARM64::visitDivI(LDivI* ins)
+{
+ MOZ_CRASH("visitDivI");
+}
+
+void
+CodeGeneratorARM64::visitDivPowTwoI(LDivPowTwoI* ins)
+{
+ MOZ_CRASH("CodeGeneratorARM64::visitDivPowTwoI");
+}
+
+void
+CodeGeneratorARM64::modICommon(MMod* mir, Register lhs, Register rhs, Register output,
+ LSnapshot* snapshot, Label& done)
+{
+ MOZ_CRASH("CodeGeneratorARM64::modICommon");
+}
+
+void
+CodeGeneratorARM64::visitModI(LModI* ins)
+{
+ MOZ_CRASH("visitModI");
+}
+
+void
+CodeGeneratorARM64::visitModPowTwoI(LModPowTwoI* ins)
+{
+ MOZ_CRASH("visitModPowTwoI");
+}
+
+void
+CodeGeneratorARM64::visitModMaskI(LModMaskI* ins)
+{
+ MOZ_CRASH("CodeGeneratorARM64::visitModMaskI");
+}
+
+void
+CodeGeneratorARM64::visitBitNotI(LBitNotI* ins)
+{
+ MOZ_CRASH("visitBitNotI");
+}
+
+void
+CodeGeneratorARM64::visitBitOpI(LBitOpI* ins)
+{
+ MOZ_CRASH("visitBitOpI");
+}
+
+void
+CodeGeneratorARM64::visitShiftI(LShiftI* ins)
+{
+ MOZ_CRASH("visitShiftI");
+}
+
+void
+CodeGeneratorARM64::visitUrshD(LUrshD* ins)
+{
+ MOZ_CRASH("visitUrshD");
+}
+
+void
+CodeGeneratorARM64::visitPowHalfD(LPowHalfD* ins)
+{
+ MOZ_CRASH("visitPowHalfD");
+}
+
+MoveOperand
+CodeGeneratorARM64::toMoveOperand(const LAllocation a) const
+{
+ MOZ_CRASH("toMoveOperand");
+}
+
+class js::jit::OutOfLineTableSwitch : public OutOfLineCodeBase<CodeGeneratorARM64>
+{
+ MTableSwitch* mir_;
+ Vector<CodeLabel, 8, JitAllocPolicy> codeLabels_;
+
+ void accept(CodeGeneratorARM64* codegen) {
+ codegen->visitOutOfLineTableSwitch(this);
+ }
+
+ public:
+ OutOfLineTableSwitch(TempAllocator& alloc, MTableSwitch* mir)
+ : mir_(mir),
+ codeLabels_(alloc)
+ { }
+
+ MTableSwitch* mir() const {
+ return mir_;
+ }
+
+ bool addCodeLabel(CodeLabel label) {
+ return codeLabels_.append(label);
+ }
+ CodeLabel codeLabel(unsigned i) {
+ return codeLabels_[i];
+ }
+};
+
+void
+CodeGeneratorARM64::visitOutOfLineTableSwitch(OutOfLineTableSwitch* ool)
+{
+ MOZ_CRASH("visitOutOfLineTableSwitch");
+}
+
+void
+CodeGeneratorARM64::emitTableSwitchDispatch(MTableSwitch* mir, Register index_, Register base_)
+{
+ MOZ_CRASH("emitTableSwitchDispatch");
+}
+
+void
+CodeGeneratorARM64::visitMathD(LMathD* math)
+{
+ MOZ_CRASH("visitMathD");
+}
+
+void
+CodeGeneratorARM64::visitMathF(LMathF* math)
+{
+ MOZ_CRASH("visitMathF");
+}
+
+void
+CodeGeneratorARM64::visitFloor(LFloor* lir)
+{
+ MOZ_CRASH("visitFloor");
+}
+
+void
+CodeGeneratorARM64::visitFloorF(LFloorF* lir)
+{
+ MOZ_CRASH("visitFloorF");
+}
+
+void
+CodeGeneratorARM64::visitCeil(LCeil* lir)
+{
+ MOZ_CRASH("visitCeil");
+}
+
+void
+CodeGeneratorARM64::visitCeilF(LCeilF* lir)
+{
+ MOZ_CRASH("visitCeilF");
+}
+
+void
+CodeGeneratorARM64::visitRound(LRound* lir)
+{
+ MOZ_CRASH("visitRound");
+}
+
+void
+CodeGeneratorARM64::visitRoundF(LRoundF* lir)
+{
+ MOZ_CRASH("visitRoundF");
+}
+
+void
+CodeGeneratorARM64::visitClzI(LClzI* lir)
+{
+ MOZ_CRASH("visitClzI");
+}
+
+void
+CodeGeneratorARM64::visitCtzI(LCtzI* lir)
+{
+ MOZ_CRASH("visitCtzI");
+}
+
+void
+CodeGeneratorARM64::emitRoundDouble(FloatRegister src, Register dest, Label* fail)
+{
+ MOZ_CRASH("CodeGeneratorARM64::emitRoundDouble");
+}
+
+void
+CodeGeneratorARM64::visitTruncateDToInt32(LTruncateDToInt32* ins)
+{
+ MOZ_CRASH("visitTruncateDToInt32");
+}
+
+void
+CodeGeneratorARM64::visitTruncateFToInt32(LTruncateFToInt32* ins)
+{
+ MOZ_CRASH("visitTruncateFToInt32");
+}
+
+static const uint32_t FrameSizes[] = { 128, 256, 512, 1024 };
+
+FrameSizeClass
+FrameSizeClass::FromDepth(uint32_t frameDepth)
+{
+ return FrameSizeClass::None();
+}
+
+FrameSizeClass
+FrameSizeClass::ClassLimit()
+{
+ return FrameSizeClass(0);
+}
+
+uint32_t
+FrameSizeClass::frameSize() const
+{
+ MOZ_CRASH("arm64 does not use frame size classes");
+}
+
+ValueOperand
+CodeGeneratorARM64::ToValue(LInstruction* ins, size_t pos)
+{
+ return ValueOperand(ToRegister(ins->getOperand(pos)));
+}
+
+ValueOperand
+CodeGeneratorARM64::ToOutValue(LInstruction* ins)
+{
+ Register payloadReg = ToRegister(ins->getDef(0));
+ return ValueOperand(payloadReg);
+}
+
+ValueOperand
+CodeGeneratorARM64::ToTempValue(LInstruction* ins, size_t pos)
+{
+ MOZ_CRASH("CodeGeneratorARM64::ToTempValue");
+}
+
+void
+CodeGeneratorARM64::visitValue(LValue* value)
+{
+ MOZ_CRASH("visitValue");
+}
+
+void
+CodeGeneratorARM64::visitBox(LBox* box)
+{
+ MOZ_CRASH("visitBox");
+}
+
+void
+CodeGeneratorARM64::visitUnbox(LUnbox* unbox)
+{
+ MOZ_CRASH("visitUnbox");
+}
+
+void
+CodeGeneratorARM64::visitDouble(LDouble* ins)
+{
+ MOZ_CRASH("visitDouble");
+}
+
+void
+CodeGeneratorARM64::visitFloat32(LFloat32* ins)
+{
+ MOZ_CRASH("visitFloat32");
+}
+
+Register
+CodeGeneratorARM64::splitTagForTest(const ValueOperand& value)
+{
+ MOZ_CRASH("splitTagForTest");
+}
+
+void
+CodeGeneratorARM64::visitTestDAndBranch(LTestDAndBranch* test)
+{
+ MOZ_CRASH("visitTestDAndBranch");
+}
+
+void
+CodeGeneratorARM64::visitTestFAndBranch(LTestFAndBranch* test)
+{
+ MOZ_CRASH("visitTestFAndBranch");
+}
+
+void
+CodeGeneratorARM64::visitCompareD(LCompareD* comp)
+{
+ MOZ_CRASH("visitCompareD");
+}
+
+void
+CodeGeneratorARM64::visitCompareF(LCompareF* comp)
+{
+ MOZ_CRASH("visitCompareF");
+}
+
+void
+CodeGeneratorARM64::visitCompareDAndBranch(LCompareDAndBranch* comp)
+{
+ MOZ_CRASH("visitCompareDAndBranch");
+}
+
+void
+CodeGeneratorARM64::visitCompareFAndBranch(LCompareFAndBranch* comp)
+{
+ MOZ_CRASH("visitCompareFAndBranch");
+}
+
+void
+CodeGeneratorARM64::visitCompareB(LCompareB* lir)
+{
+ MOZ_CRASH("visitCompareB");
+}
+
+void
+CodeGeneratorARM64::visitCompareBAndBranch(LCompareBAndBranch* lir)
+{
+ MOZ_CRASH("visitCompareBAndBranch");
+}
+
+void
+CodeGeneratorARM64::visitCompareBitwise(LCompareBitwise* lir)
+{
+ MOZ_CRASH("visitCompareBitwise");
+}
+
+void
+CodeGeneratorARM64::visitCompareBitwiseAndBranch(LCompareBitwiseAndBranch* lir)
+{
+ MOZ_CRASH("visitCompareBitwiseAndBranch");
+}
+
+void
+CodeGeneratorARM64::visitBitAndAndBranch(LBitAndAndBranch* baab)
+{
+ MOZ_CRASH("visitBitAndAndBranch");
+}
+
+void
+CodeGeneratorARM64::visitWasmUint32ToDouble(LWasmUint32ToDouble* lir)
+{
+ MOZ_CRASH("visitWasmUint32ToDouble");
+}
+
+void
+CodeGeneratorARM64::visitWasmUint32ToFloat32(LWasmUint32ToFloat32* lir)
+{
+ MOZ_CRASH("visitWasmUint32ToFloat32");
+}
+
+void
+CodeGeneratorARM64::visitNotI(LNotI* ins)
+{
+ MOZ_CRASH("visitNotI");
+}
+
+// NZCV
+// NAN -> 0011
+// == -> 0110
+// < -> 1000
+// > -> 0010
+void
+CodeGeneratorARM64::visitNotD(LNotD* ins)
+{
+ MOZ_CRASH("visitNotD");
+}
+
+void
+CodeGeneratorARM64::visitNotF(LNotF* ins)
+{
+ MOZ_CRASH("visitNotF");
+}
+
+void
+CodeGeneratorARM64::visitLoadSlotV(LLoadSlotV* load)
+{
+ MOZ_CRASH("CodeGeneratorARM64::visitLoadSlotV");
+}
+
+void
+CodeGeneratorARM64::visitLoadSlotT(LLoadSlotT* load)
+{
+ MOZ_CRASH("CodeGeneratorARM64::visitLoadSlotT");
+}
+
+void
+CodeGeneratorARM64::visitStoreSlotT(LStoreSlotT* store)
+{
+ MOZ_CRASH("CodeGeneratorARM64::visitStoreSlotT");
+}
+
+void
+CodeGeneratorARM64::visitLoadElementT(LLoadElementT* load)
+{
+ MOZ_CRASH("CodeGeneratorARM64::visitLoadElementT");
+}
+
+void
+CodeGeneratorARM64::storeElementTyped(const LAllocation* value, MIRType valueType,
+ MIRType elementType, Register elements,
+ const LAllocation* index)
+{
+ MOZ_CRASH("CodeGeneratorARM64::storeElementTyped");
+}
+
+void
+CodeGeneratorARM64::visitGuardShape(LGuardShape* guard)
+{
+ MOZ_CRASH("visitGuardShape");
+}
+
+void
+CodeGeneratorARM64::visitGuardObjectGroup(LGuardObjectGroup* guard)
+{
+ MOZ_CRASH("visitGuardObjectGroup");
+}
+
+void
+CodeGeneratorARM64::visitGuardClass(LGuardClass* guard)
+{
+ MOZ_CRASH("CodeGeneratorARM64::visitGuardClass");
+}
+
+void
+CodeGeneratorARM64::visitInterruptCheck(LInterruptCheck* lir)
+{
+ MOZ_CRASH("CodeGeneratorARM64::visitInterruptCheck");
+}
+
+void
+CodeGeneratorARM64::generateInvalidateEpilogue()
+{
+ MOZ_CRASH("generateInvalidateEpilogue");
+}
+
+template <class U>
+Register
+getBase(U* mir)
+{
+ switch (mir->base()) {
+ case U::Heap: return HeapReg;
+ case U::Global: return GlobalReg;
+ }
+ return InvalidReg;
+}
+
+void
+CodeGeneratorARM64::visitLoadTypedArrayElementStatic(LLoadTypedArrayElementStatic* ins)
+{
+ MOZ_CRASH("CodeGeneratorARM64::visitLoadTypedArrayElementStatic");
+}
+
+void
+CodeGeneratorARM64::visitStoreTypedArrayElementStatic(LStoreTypedArrayElementStatic* ins)
+{
+ MOZ_CRASH("CodeGeneratorARM64::visitStoreTypedArrayElementStatic");
+}
+
+void
+CodeGeneratorARM64::visitWasmCall(LWasmCall* ins)
+{
+ MOZ_CRASH("vistWasmCall");
+}
+
+void
+CodeGeneratorARM64::visitWasmCallI64(LWasmCallI64* ins)
+{
+ MOZ_CRASH("vistWasmCallI64");
+}
+
+void
+CodeGeneratorARM64::visitAsmJSLoadHeap(LAsmJSLoadHeap* ins)
+{
+ MOZ_CRASH("visitAsmJSLoadHeap");
+}
+
+void
+CodeGeneratorARM64::visitAsmJSStoreHeap(LAsmJSStoreHeap* ins)
+{
+ MOZ_CRASH("visitAsmJSStoreHeap");
+}
+
+void
+CodeGeneratorARM64::visitAsmJSCompareExchangeHeap(LAsmJSCompareExchangeHeap* ins)
+{
+ MOZ_CRASH("visitAsmJSCompareExchangeHeap");
+}
+
+void
+CodeGeneratorARM64::visitAsmJSAtomicBinopHeap(LAsmJSAtomicBinopHeap* ins)
+{
+ MOZ_CRASH("visitAsmJSAtomicBinopHeap");
+}
+
+void
+CodeGeneratorARM64::visitWasmStackArg(LWasmStackArg* ins)
+{
+ MOZ_CRASH("visitWasmStackArg");
+}
+
+void
+CodeGeneratorARM64::visitUDiv(LUDiv* ins)
+{
+ MOZ_CRASH("visitUDiv");
+}
+
+void
+CodeGeneratorARM64::visitUMod(LUMod* ins)
+{
+ MOZ_CRASH("visitUMod");
+}
+
+void
+CodeGeneratorARM64::visitEffectiveAddress(LEffectiveAddress* ins)
+{
+ MOZ_CRASH("visitEffectiveAddress");
+}
+
+void
+CodeGeneratorARM64::visitWasmLoadGlobalVar(LWasmLoadGlobalVar* ins)
+{
+ MOZ_CRASH("visitWasmLoadGlobalVar");
+}
+
+void
+CodeGeneratorARM64::visitWasmStoreGlobalVar(LWasmStoreGlobalVar* ins)
+{
+ MOZ_CRASH("visitWasmStoreGlobalVar");
+}
+
+void
+CodeGeneratorARM64::visitNegI(LNegI* ins)
+{
+ MOZ_CRASH("visitNegI");
+}
+
+void
+CodeGeneratorARM64::visitNegD(LNegD* ins)
+{
+ MOZ_CRASH("visitNegD");
+}
+
+void
+CodeGeneratorARM64::visitNegF(LNegF* ins)
+{
+ MOZ_CRASH("visitNegF");
+}
+
+void
+CodeGeneratorARM64::setReturnDoubleRegs(LiveRegisterSet* regs)
+{
+ MOZ_ASSERT(ReturnFloat32Reg.code_ == FloatRegisters::s0);
+ MOZ_ASSERT(ReturnDoubleReg.code_ == FloatRegisters::d0);
+ FloatRegister s1 = {FloatRegisters::s1, FloatRegisters::Single};
+ regs->add(ReturnFloat32Reg);
+ regs->add(s1);
+ regs->add(ReturnDoubleReg);
+}
+
+void
+CodeGeneratorARM64::visitCompareExchangeTypedArrayElement(LCompareExchangeTypedArrayElement* lir)
+{
+ Register elements = ToRegister(lir->elements());
+ AnyRegister output = ToAnyRegister(lir->output());
+ Register temp = lir->temp()->isBogusTemp() ? InvalidReg : ToRegister(lir->temp());
+
+ Register oldval = ToRegister(lir->oldval());
+ Register newval = ToRegister(lir->newval());
+
+ Scalar::Type arrayType = lir->mir()->arrayType();
+ int width = Scalar::byteSize(arrayType);
+
+ if (lir->index()->isConstant()) {
+ Address dest(elements, ToInt32(lir->index()) * width);
+ masm.compareExchangeToTypedIntArray(arrayType, dest, oldval, newval, temp, output);
+ } else {
+ BaseIndex dest(elements, ToRegister(lir->index()), ScaleFromElemWidth(width));
+ masm.compareExchangeToTypedIntArray(arrayType, dest, oldval, newval, temp, output);
+ }
+}
+
+void
+CodeGeneratorARM64::visitAtomicExchangeTypedArrayElement(LAtomicExchangeTypedArrayElement* lir)
+{
+ Register elements = ToRegister(lir->elements());
+ AnyRegister output = ToAnyRegister(lir->output());
+ Register temp = lir->temp()->isBogusTemp() ? InvalidReg : ToRegister(lir->temp());
+
+ Register value = ToRegister(lir->value());
+
+ Scalar::Type arrayType = lir->mir()->arrayType();
+ int width = Scalar::byteSize(arrayType);
+
+ if (lir->index()->isConstant()) {
+ Address dest(elements, ToInt32(lir->index()) * width);
+ masm.atomicExchangeToTypedIntArray(arrayType, dest, value, temp, output);
+ } else {
+ BaseIndex dest(elements, ToRegister(lir->index()), ScaleFromElemWidth(width));
+ masm.atomicExchangeToTypedIntArray(arrayType, dest, value, temp, output);
+ }
+}
+