Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(191)

Side by Side Diff: src/ia32/lithium-ia32.h

Issue 90643003: Experimental implementation: Exposing SIMD instructions into JavaScript Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Created 7 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/ia32/lithium-gap-resolver-ia32.cc ('k') | src/ia32/lithium-ia32.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2012 the V8 project authors. All rights reserved. 1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after
137 V(MathExp) \ 137 V(MathExp) \
138 V(MathFloor) \ 138 V(MathFloor) \
139 V(MathFloorOfDiv) \ 139 V(MathFloorOfDiv) \
140 V(MathLog) \ 140 V(MathLog) \
141 V(MathMinMax) \ 141 V(MathMinMax) \
142 V(MathPowHalf) \ 142 V(MathPowHalf) \
143 V(MathRound) \ 143 V(MathRound) \
144 V(MathSin) \ 144 V(MathSin) \
145 V(MathSqrt) \ 145 V(MathSqrt) \
146 V(MathTan) \ 146 V(MathTan) \
147 V(NullarySIMDOperation) \
148 V(UnarySIMDOperation) \
149 V(BinarySIMDOperation) \
150 V(TernarySIMDOperation) \
151 V(QuarternarySIMDOperation) \
147 V(ModI) \ 152 V(ModI) \
148 V(MulI) \ 153 V(MulI) \
149 V(NumberTagD) \ 154 V(NumberTagD) \
150 V(NumberTagI) \ 155 V(NumberTagI) \
151 V(NumberTagU) \ 156 V(NumberTagU) \
152 V(NumberUntagD) \ 157 V(NumberUntagD) \
158 V(Float32x4ToTagged) \
159 V(Int32x4ToTagged) \
160 V(TaggedToFloat32x4) \
161 V(TaggedToInt32x4) \
153 V(OsrEntry) \ 162 V(OsrEntry) \
154 V(OuterContext) \ 163 V(OuterContext) \
155 V(Parameter) \ 164 V(Parameter) \
156 V(Power) \ 165 V(Power) \
157 V(PushArgument) \ 166 V(PushArgument) \
158 V(RegExpLiteral) \ 167 V(RegExpLiteral) \
159 V(Return) \ 168 V(Return) \
160 V(SeqStringGetChar) \ 169 V(SeqStringGetChar) \
161 V(SeqStringSetChar) \ 170 V(SeqStringSetChar) \
162 V(ShiftI) \ 171 V(ShiftI) \
(...skipping 703 matching lines...) Expand 10 before | Expand all | Expand 10 after
866 temps_[0] = temp; 875 temps_[0] = temp;
867 } 876 }
868 877
869 LOperand* value() { return inputs_[0]; } 878 LOperand* value() { return inputs_[0]; }
870 LOperand* temp() { return temps_[0]; } 879 LOperand* temp() { return temps_[0]; }
871 880
872 DECLARE_CONCRETE_INSTRUCTION(MathPowHalf, "math-pow-half") 881 DECLARE_CONCRETE_INSTRUCTION(MathPowHalf, "math-pow-half")
873 }; 882 };
874 883
875 884
885 class LNullarySIMDOperation V8_FINAL : public LTemplateInstruction<1, 0, 0> {
886 public:
887 explicit LNullarySIMDOperation(BuiltinFunctionId op)
888 : op_(op) {
889 }
890
891 BuiltinFunctionId op() const { return op_; }
892
893 virtual Opcode opcode() const V8_OVERRIDE {
894 return LInstruction::kNullarySIMDOperation;
895 }
896 virtual void CompileToNative(LCodeGen* generator) V8_OVERRIDE;
897 virtual const char* Mnemonic() const V8_OVERRIDE;
898 static LNullarySIMDOperation* cast(LInstruction* instr) {
899 ASSERT(instr->IsNullarySIMDOperation());
900 return reinterpret_cast<LNullarySIMDOperation*>(instr);
901 }
902
903 DECLARE_HYDROGEN_ACCESSOR(NullarySIMDOperation)
904
905 private:
906 BuiltinFunctionId op_;
907 };
908
909
910 class LUnarySIMDOperation V8_FINAL : public LTemplateInstruction<1, 1, 0> {
911 public:
912 LUnarySIMDOperation(LOperand* value, BuiltinFunctionId op)
913 : op_(op) {
914 inputs_[0] = value;
915 }
916
917 LOperand* value() { return inputs_[0]; }
918 BuiltinFunctionId op() const { return op_; }
919
920 virtual Opcode opcode() const V8_OVERRIDE {
921 return LInstruction::kUnarySIMDOperation;
922 }
923 virtual void CompileToNative(LCodeGen* generator) V8_OVERRIDE;
924 virtual const char* Mnemonic() const V8_OVERRIDE;
925 static LUnarySIMDOperation* cast(LInstruction* instr) {
926 ASSERT(instr->IsUnarySIMDOperation());
927 return reinterpret_cast<LUnarySIMDOperation*>(instr);
928 }
929
930 DECLARE_HYDROGEN_ACCESSOR(UnarySIMDOperation)
931
932 private:
933 BuiltinFunctionId op_;
934 };
935
936
937 class LBinarySIMDOperation V8_FINAL : public LTemplateInstruction<1, 2, 0> {
938 public:
939 LBinarySIMDOperation(LOperand* left, LOperand* right, BuiltinFunctionId op)
940 : op_(op) {
941 inputs_[0] = left;
942 inputs_[1] = right;
943 }
944
945 LOperand* left() { return inputs_[0]; }
946 LOperand* right() { return inputs_[1]; }
947 BuiltinFunctionId op() const { return op_; }
948
949 virtual Opcode opcode() const V8_OVERRIDE {
950 return LInstruction::kBinarySIMDOperation;
951 }
952 virtual void CompileToNative(LCodeGen* generator) V8_OVERRIDE;
953 virtual const char* Mnemonic() const V8_OVERRIDE;
954 static LBinarySIMDOperation* cast(LInstruction* instr) {
955 ASSERT(instr->IsBinarySIMDOperation());
956 return reinterpret_cast<LBinarySIMDOperation*>(instr);
957 }
958
959 DECLARE_HYDROGEN_ACCESSOR(BinarySIMDOperation)
960
961 private:
962 BuiltinFunctionId op_;
963 };
964
965
966 class LTernarySIMDOperation V8_FINAL : public LTemplateInstruction<1, 3, 0> {
967 public:
968 LTernarySIMDOperation(LOperand* first, LOperand* second, LOperand* third,
969 BuiltinFunctionId op)
970 : op_(op) {
971 inputs_[0] = first;
972 inputs_[1] = second;
973 inputs_[2] = third;
974 }
975
976 LOperand* first() { return inputs_[0]; }
977 LOperand* second() { return inputs_[1]; }
978 LOperand* third() { return inputs_[2]; }
979 BuiltinFunctionId op() const { return op_; }
980
981 virtual Opcode opcode() const V8_OVERRIDE {
982 return LInstruction::kTernarySIMDOperation;
983 }
984 virtual void CompileToNative(LCodeGen* generator) V8_OVERRIDE;
985 virtual const char* Mnemonic() const V8_OVERRIDE;
986 static LTernarySIMDOperation* cast(LInstruction* instr) {
987 ASSERT(instr->IsTernarySIMDOperation());
988 return reinterpret_cast<LTernarySIMDOperation*>(instr);
989 }
990
991 DECLARE_HYDROGEN_ACCESSOR(TernarySIMDOperation)
992
993 private:
994 BuiltinFunctionId op_;
995 };
996
997
998 class LQuarternarySIMDOperation V8_FINAL
999 : public LTemplateInstruction<1, 4, 0> {
1000 public:
1001 LQuarternarySIMDOperation(LOperand* x, LOperand* y, LOperand* z,
1002 LOperand* w, BuiltinFunctionId op)
1003 : op_(op) {
1004 inputs_[0] = x;
1005 inputs_[1] = y;
1006 inputs_[2] = z;
1007 inputs_[3] = w;
1008 }
1009
1010 LOperand* x() { return inputs_[0]; }
1011 LOperand* y() { return inputs_[1]; }
1012 LOperand* z() { return inputs_[2]; }
1013 LOperand* w() { return inputs_[3]; }
1014 BuiltinFunctionId op() const { return op_; }
1015
1016 virtual Opcode opcode() const V8_OVERRIDE {
1017 return LInstruction::kQuarternarySIMDOperation;
1018 }
1019 virtual void CompileToNative(LCodeGen* generator) V8_OVERRIDE;
1020 virtual const char* Mnemonic() const V8_OVERRIDE;
1021 static LQuarternarySIMDOperation* cast(LInstruction* instr) {
1022 ASSERT(instr->IsQuarternarySIMDOperation());
1023 return reinterpret_cast<LQuarternarySIMDOperation*>(instr);
1024 }
1025
1026 DECLARE_HYDROGEN_ACCESSOR(QuarternarySIMDOperation)
1027
1028 private:
1029 BuiltinFunctionId op_;
1030 };
1031
1032
876 class LCmpObjectEqAndBranch V8_FINAL : public LControlInstruction<2, 0> { 1033 class LCmpObjectEqAndBranch V8_FINAL : public LControlInstruction<2, 0> {
877 public: 1034 public:
878 LCmpObjectEqAndBranch(LOperand* left, LOperand* right) { 1035 LCmpObjectEqAndBranch(LOperand* left, LOperand* right) {
879 inputs_[0] = left; 1036 inputs_[0] = left;
880 inputs_[1] = right; 1037 inputs_[1] = right;
881 } 1038 }
882 1039
883 LOperand* left() { return inputs_[0]; } 1040 LOperand* left() { return inputs_[0]; }
884 LOperand* right() { return inputs_[1]; } 1041 LOperand* right() { return inputs_[1]; }
885 1042
(...skipping 713 matching lines...) Expand 10 before | Expand all | Expand 10 after
1599 inputs_[0] = object; 1756 inputs_[0] = object;
1600 } 1757 }
1601 1758
1602 LOperand* object() { return inputs_[0]; } 1759 LOperand* object() { return inputs_[0]; }
1603 1760
1604 DECLARE_CONCRETE_INSTRUCTION(LoadExternalArrayPointer, 1761 DECLARE_CONCRETE_INSTRUCTION(LoadExternalArrayPointer,
1605 "load-external-array-pointer") 1762 "load-external-array-pointer")
1606 }; 1763 };
1607 1764
1608 1765
1609 class LLoadKeyed V8_FINAL : public LTemplateInstruction<1, 2, 0> { 1766 class LLoadKeyed V8_FINAL : public LTemplateInstruction<1, 2, 1> {
1610 public: 1767 public:
1611 LLoadKeyed(LOperand* elements, LOperand* key) { 1768 LLoadKeyed(LOperand* elements, LOperand* key, LOperand* temp) {
1612 inputs_[0] = elements; 1769 inputs_[0] = elements;
1613 inputs_[1] = key; 1770 inputs_[1] = key;
1771 temps_[0] = temp;
1614 } 1772 }
1615 LOperand* elements() { return inputs_[0]; } 1773 LOperand* elements() { return inputs_[0]; }
1616 LOperand* key() { return inputs_[1]; } 1774 LOperand* key() { return inputs_[1]; }
1775 LOperand* temp() { return temps_[0]; }
1617 ElementsKind elements_kind() const { 1776 ElementsKind elements_kind() const {
1618 return hydrogen()->elements_kind(); 1777 return hydrogen()->elements_kind();
1619 } 1778 }
1620 bool is_external() const { 1779 bool is_external() const {
1621 return hydrogen()->is_external(); 1780 return hydrogen()->is_external();
1622 } 1781 }
1623 1782
1624 DECLARE_CONCRETE_INSTRUCTION(LoadKeyed, "load-keyed") 1783 DECLARE_CONCRETE_INSTRUCTION(LoadKeyed, "load-keyed")
1625 DECLARE_HYDROGEN_ACCESSOR(LoadKeyed) 1784 DECLARE_HYDROGEN_ACCESSOR(LoadKeyed)
1626 1785
1627 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; 1786 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE;
1628 uint32_t additional_index() const { return hydrogen()->index_offset(); } 1787 uint32_t additional_index() const { return hydrogen()->index_offset(); }
1629 bool key_is_smi() { 1788 bool key_is_smi() {
1630 return hydrogen()->key()->representation().IsTagged(); 1789 return hydrogen()->key()->representation().IsTagged();
1631 } 1790 }
1632 }; 1791 };
1633 1792
1634 1793
1794 inline static bool ExternalArrayOpRequiresSpecialHandling(
1795 ElementsKind elements_kind) {
1796 return !CpuFeatures::IsSupported(SSE2) &&
1797 (elements_kind == EXTERNAL_FLOAT32x4_ELEMENTS ||
1798 elements_kind == EXTERNAL_INT32x4_ELEMENTS);
1799 }
1800
1801
1635 inline static bool ExternalArrayOpRequiresTemp( 1802 inline static bool ExternalArrayOpRequiresTemp(
1636 Representation key_representation, 1803 Representation key_representation,
1637 ElementsKind elements_kind) { 1804 ElementsKind elements_kind) {
1638 // Operations that require the key to be divided by two to be converted into 1805 // Operations that require the key to be divided by two to be converted into
1639 // an index cannot fold the scale operation into a load and need an extra 1806 // an index cannot fold the scale operation into a load and need an extra
1640 // temp register to do the work. 1807 // temp register to do the work.
1641 return key_representation.IsSmi() && 1808 return (key_representation.IsSmi() &&
1642 (elements_kind == EXTERNAL_BYTE_ELEMENTS || 1809 (elements_kind == EXTERNAL_BYTE_ELEMENTS ||
1643 elements_kind == EXTERNAL_UNSIGNED_BYTE_ELEMENTS || 1810 elements_kind == EXTERNAL_UNSIGNED_BYTE_ELEMENTS ||
1644 elements_kind == EXTERNAL_PIXEL_ELEMENTS); 1811 elements_kind == EXTERNAL_PIXEL_ELEMENTS)) ||
1812 (elements_kind == EXTERNAL_FLOAT32x4_ELEMENTS ||
1813 elements_kind == EXTERNAL_INT32x4_ELEMENTS);
1645 } 1814 }
1646 1815
1647 1816
1648 class LLoadKeyedGeneric V8_FINAL : public LTemplateInstruction<1, 3, 0> { 1817 class LLoadKeyedGeneric V8_FINAL : public LTemplateInstruction<1, 3, 0> {
1649 public: 1818 public:
1650 LLoadKeyedGeneric(LOperand* context, LOperand* obj, LOperand* key) { 1819 LLoadKeyedGeneric(LOperand* context, LOperand* obj, LOperand* key) {
1651 inputs_[0] = context; 1820 inputs_[0] = context;
1652 inputs_[1] = obj; 1821 inputs_[1] = obj;
1653 inputs_[2] = key; 1822 inputs_[2] = key;
1654 } 1823 }
(...skipping 628 matching lines...) Expand 10 before | Expand all | Expand 10 after
2283 2452
2284 DECLARE_CONCRETE_INSTRUCTION(StoreNamedGeneric, "store-named-generic") 2453 DECLARE_CONCRETE_INSTRUCTION(StoreNamedGeneric, "store-named-generic")
2285 DECLARE_HYDROGEN_ACCESSOR(StoreNamedGeneric) 2454 DECLARE_HYDROGEN_ACCESSOR(StoreNamedGeneric)
2286 2455
2287 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; 2456 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE;
2288 Handle<Object> name() const { return hydrogen()->name(); } 2457 Handle<Object> name() const { return hydrogen()->name(); }
2289 StrictModeFlag strict_mode_flag() { return hydrogen()->strict_mode_flag(); } 2458 StrictModeFlag strict_mode_flag() { return hydrogen()->strict_mode_flag(); }
2290 }; 2459 };
2291 2460
2292 2461
2293 class LStoreKeyed V8_FINAL : public LTemplateInstruction<0, 3, 0> { 2462 class LStoreKeyed V8_FINAL : public LTemplateInstruction<0, 3, 1> {
2294 public: 2463 public:
2295 LStoreKeyed(LOperand* obj, LOperand* key, LOperand* val) { 2464 LStoreKeyed(LOperand* obj, LOperand* key, LOperand* val, LOperand* temp) {
2296 inputs_[0] = obj; 2465 inputs_[0] = obj;
2297 inputs_[1] = key; 2466 inputs_[1] = key;
2298 inputs_[2] = val; 2467 inputs_[2] = val;
2468 temps_[0] = temp;
2299 } 2469 }
2300 2470
2301 bool is_external() const { return hydrogen()->is_external(); } 2471 bool is_external() const { return hydrogen()->is_external(); }
2302 LOperand* elements() { return inputs_[0]; } 2472 LOperand* elements() { return inputs_[0]; }
2303 LOperand* key() { return inputs_[1]; } 2473 LOperand* key() { return inputs_[1]; }
2304 LOperand* value() { return inputs_[2]; } 2474 LOperand* value() { return inputs_[2]; }
2475 LOperand* temp() { return temps_[0]; }
2305 ElementsKind elements_kind() const { 2476 ElementsKind elements_kind() const {
2306 return hydrogen()->elements_kind(); 2477 return hydrogen()->elements_kind();
2307 } 2478 }
2308 2479
2309 DECLARE_CONCRETE_INSTRUCTION(StoreKeyed, "store-keyed") 2480 DECLARE_CONCRETE_INSTRUCTION(StoreKeyed, "store-keyed")
2310 DECLARE_HYDROGEN_ACCESSOR(StoreKeyed) 2481 DECLARE_HYDROGEN_ACCESSOR(StoreKeyed)
2311 2482
2312 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; 2483 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE;
2313 uint32_t additional_index() const { return hydrogen()->index_offset(); } 2484 uint32_t additional_index() const { return hydrogen()->index_offset(); }
2314 bool NeedsCanonicalization() { return hydrogen()->NeedsCanonicalization(); } 2485 bool NeedsCanonicalization() { return hydrogen()->NeedsCanonicalization(); }
(...skipping 433 matching lines...) Expand 10 before | Expand all | Expand 10 after
2748 int GetNextSpillIndex(RegisterKind kind); 2919 int GetNextSpillIndex(RegisterKind kind);
2749 LOperand* GetNextSpillSlot(RegisterKind kind); 2920 LOperand* GetNextSpillSlot(RegisterKind kind);
2750 2921
2751 int num_double_slots() const { return num_double_slots_; } 2922 int num_double_slots() const { return num_double_slots_; }
2752 2923
2753 private: 2924 private:
2754 int num_double_slots_; 2925 int num_double_slots_;
2755 }; 2926 };
2756 2927
2757 2928
2929
2930 class LFloat32x4ToTagged V8_FINAL : public LTemplateInstruction<1, 1, 1> {
2931 public:
2932 explicit LFloat32x4ToTagged(LOperand* value,
2933 LOperand* temp) {
2934 inputs_[0] = value;
2935 temps_[0] = temp;
2936 }
2937
2938 LOperand* value() { return inputs_[0]; }
2939 LOperand* temp() { return temps_[0]; }
2940
2941 DECLARE_CONCRETE_INSTRUCTION(Float32x4ToTagged, "float32x4-tag")
2942 DECLARE_HYDROGEN_ACCESSOR(Change)
2943 };
2944
2945
2946 class LTaggedToFloat32x4 V8_FINAL : public LTemplateInstruction<1, 1, 1> {
2947 public:
2948 explicit LTaggedToFloat32x4(LOperand* value,
2949 LOperand* temp) {
2950 inputs_[0] = value;
2951 temps_[0] = temp;
2952 }
2953
2954 LOperand* value() { return inputs_[0]; }
2955 LOperand* temp() { return temps_[0]; }
2956
2957 DECLARE_CONCRETE_INSTRUCTION(TaggedToFloat32x4, "float32x4-untag")
2958 DECLARE_HYDROGEN_ACCESSOR(Change);
2959 };
2960
2961
2962
2963 class LInt32x4ToTagged V8_FINAL : public LTemplateInstruction<1, 1, 1> {
2964 public:
2965 explicit LInt32x4ToTagged(LOperand* value, LOperand* temp) {
2966 inputs_[0] = value;
2967 temps_[0] = temp;
2968 }
2969
2970 LOperand* value() { return inputs_[0]; }
2971 LOperand* temp() { return temps_[0]; }
2972
2973 DECLARE_CONCRETE_INSTRUCTION(Int32x4ToTagged, "int32x4-tag")
2974 DECLARE_HYDROGEN_ACCESSOR(Change)
2975 };
2976
2977
2978 class LTaggedToInt32x4 V8_FINAL : public LTemplateInstruction<1, 1, 1> {
2979 public:
2980 explicit LTaggedToInt32x4(LOperand* value, LOperand* temp) {
2981 inputs_[0] = value;
2982 temps_[0] = temp;
2983 }
2984
2985 LOperand* value() { return inputs_[0]; }
2986 LOperand* temp() { return temps_[0]; }
2987
2988 DECLARE_CONCRETE_INSTRUCTION(TaggedToInt32x4, "int32x4-untag")
2989 DECLARE_HYDROGEN_ACCESSOR(Change);
2990 };
2991
2992
2758 class LChunkBuilder V8_FINAL BASE_EMBEDDED { 2993 class LChunkBuilder V8_FINAL BASE_EMBEDDED {
2759 public: 2994 public:
2760 LChunkBuilder(CompilationInfo* info, HGraph* graph, LAllocator* allocator) 2995 LChunkBuilder(CompilationInfo* info, HGraph* graph, LAllocator* allocator)
2761 : chunk_(NULL), 2996 : chunk_(NULL),
2762 info_(info), 2997 info_(info),
2763 graph_(graph), 2998 graph_(graph),
2764 zone_(graph->zone()), 2999 zone_(graph->zone()),
2765 status_(UNUSED), 3000 status_(UNUSED),
2766 current_instruction_(NULL), 3001 current_instruction_(NULL),
2767 current_block_(NULL), 3002 current_block_(NULL),
(...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after
2936 3171
2937 DISALLOW_COPY_AND_ASSIGN(LChunkBuilder); 3172 DISALLOW_COPY_AND_ASSIGN(LChunkBuilder);
2938 }; 3173 };
2939 3174
2940 #undef DECLARE_HYDROGEN_ACCESSOR 3175 #undef DECLARE_HYDROGEN_ACCESSOR
2941 #undef DECLARE_CONCRETE_INSTRUCTION 3176 #undef DECLARE_CONCRETE_INSTRUCTION
2942 3177
2943 } } // namespace v8::internal 3178 } } // namespace v8::internal
2944 3179
2945 #endif // V8_IA32_LITHIUM_IA32_H_ 3180 #endif // V8_IA32_LITHIUM_IA32_H_
OLDNEW
« no previous file with comments | « src/ia32/lithium-gap-resolver-ia32.cc ('k') | src/ia32/lithium-ia32.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698