diff --git a/source/Lib/CommonLib/CommonDef.h b/source/Lib/CommonLib/CommonDef.h
index ccad654c5f62b56c53eb64c8a2a011d280f64e35..cc5c60954674e081e54e24bd7eac46d5532020a9 100644
--- a/source/Lib/CommonLib/CommonDef.h
+++ b/source/Lib/CommonLib/CommonDef.h
@@ -614,7 +614,7 @@ static const int    BDMVR_INTME_AREA   = BDMVR_INTME_STRIDE * BDMVR_INTME_STRIDE
 static const int    BDMVR_INTME_CENTER = BDMVR_INTME_STRIDE * BDMVR_INTME_RANGE + BDMVR_INTME_RANGE; ///< Bilateral matching search area center
 static const int    BDMVR_SIMD_IF_FACTOR =                          8; ///< Specify the pixel alignment factor for SIMD IF. (Usually this factor is 8)
 static const int    BDMVR_INTME_MAX_NUM_SEARCH_ITERATION =         26; ///< for entire CU in bilateral mode, maximum number of refinement loops
-#if JVET_X0049_ADAPT_DMVR
+#if JVET_X0049_BDMVR_SW_OPT
 static const int    BDMVR_BUF_STRIDE = MAX_CU_SIZE + (BDMVR_INTME_RANGE << 1) + (BDMVR_SIMD_IF_FACTOR - 2);
 static const int    BDMVR_CENTER_POSITION = BDMVR_INTME_RANGE * BDMVR_BUF_STRIDE + BDMVR_INTME_RANGE;
 static const int    BM_MRG_MAX_NUM_CANDS = 6; ///< maximum number of BM merge candidates (note: should be at most equal to MRG_MAX_NUM_CANDS)
diff --git a/source/Lib/CommonLib/InterPrediction.cpp b/source/Lib/CommonLib/InterPrediction.cpp
index 45055e26840a4ac346c86625cfce16de12025b8f..4c5c08e72d17e462fd4a641efe27e9552c2f89d7 100644
--- a/source/Lib/CommonLib/InterPrediction.cpp
+++ b/source/Lib/CommonLib/InterPrediction.cpp
@@ -141,7 +141,7 @@ InterPrediction::InterPrediction()
 
 #if MULTI_PASS_DMVR
   int mvSearchIdx_bilMrg = 0;
-#if JVET_X0049_ADAPT_DMVR
+#if JVET_X0049_BDMVR_SW_OPT
   uint16_t currtPrio = 0, currIdx = 0;
   ::memset(m_pSearchEnlargeOffsetNum, 0, sizeof(m_pSearchEnlargeOffsetNum));
 #endif
@@ -149,13 +149,13 @@ InterPrediction::InterPrediction()
   {
     for (int x = -BDMVR_INTME_RANGE; x <= BDMVR_INTME_RANGE; x++)
     {
-#if JVET_X0049_ADAPT_DMVR
+#if JVET_X0049_BDMVR_SW_OPT
 #else
       m_pSearchEnlargeOffset_bilMrg[mvSearchIdx_bilMrg] = Mv(x, y);
 #endif
       if ( (abs(x) + abs(y)) == 0 )
       {
-#if JVET_X0049_ADAPT_DMVR
+#if JVET_X0049_BDMVR_SW_OPT
         currtPrio = 0;
         currIdx = m_pSearchEnlargeOffsetNum[currtPrio];
         m_pSearchEnlargeOffsetToIdx[currtPrio][currIdx] = mvSearchIdx_bilMrg;
@@ -167,7 +167,7 @@ InterPrediction::InterPrediction()
       }
       else if ( (abs(x) + abs(y)) < 4 )
       {
-#if JVET_X0049_ADAPT_DMVR
+#if JVET_X0049_BDMVR_SW_OPT
         currtPrio = 1;
         currIdx = m_pSearchEnlargeOffsetNum[currtPrio];
         m_pSearchEnlargeOffsetToIdx[currtPrio][currIdx] = mvSearchIdx_bilMrg;
@@ -179,7 +179,7 @@ InterPrediction::InterPrediction()
       }
       else if ((abs(x) + abs(y)) < 7)
       {
-#if JVET_X0049_ADAPT_DMVR
+#if JVET_X0049_BDMVR_SW_OPT
         currtPrio = 2;
         currIdx = m_pSearchEnlargeOffsetNum[currtPrio];
         m_pSearchEnlargeOffsetToIdx[currtPrio][currIdx] = mvSearchIdx_bilMrg;
@@ -191,7 +191,7 @@ InterPrediction::InterPrediction()
       }
       else if ((abs(x) + abs(y)) < 11)
       {
-#if JVET_X0049_ADAPT_DMVR
+#if JVET_X0049_BDMVR_SW_OPT
         currtPrio = 3;
         currIdx = m_pSearchEnlargeOffsetNum[currtPrio];
         m_pSearchEnlargeOffsetToIdx[currtPrio][currIdx] = mvSearchIdx_bilMrg;
@@ -203,7 +203,7 @@ InterPrediction::InterPrediction()
       }
       else
       {
-#if JVET_X0049_ADAPT_DMVR
+#if JVET_X0049_BDMVR_SW_OPT
         currtPrio = 4;
         currIdx = m_pSearchEnlargeOffsetNum[currtPrio];
         m_pSearchEnlargeOffsetToIdx[currtPrio][currIdx] = mvSearchIdx_bilMrg;
@@ -213,7 +213,7 @@ InterPrediction::InterPrediction()
         costShift_1_bilMrg[mvSearchIdx_bilMrg] = 1;
         costShift_2_bilMrg[mvSearchIdx_bilMrg++] = 2;
       }
-#if JVET_X0049_ADAPT_DMVR
+#if JVET_X0049_BDMVR_SW_OPT
       m_pSearchEnlargeOffset_bilMrg[currtPrio][currIdx] = Mv(x, y);
       m_pSearchEnlargeOffsetNum[currtPrio]++;
 #endif
@@ -6866,6 +6866,7 @@ bool InterPrediction::processBDMVR(PredictionUnit& pu)
     Mv         mvFinal_PU[2] = { pu.mv[0], pu.mv[1] };
     Mv         mvInitial_PU[2] = { pu.mv[0], pu.mv[1] };
 
+#if JVET_X0049_BDMVR_SW_OPT
 #if JVET_X0049_ADAPT_DMVR
     if (pu.bmDir == 1)
     {
@@ -6884,6 +6885,7 @@ bool InterPrediction::processBDMVR(PredictionUnit& pu)
       }
     }
     else
+#endif
     {
       minCost = xBDMVRMvSquareSearch<false>( mvFinal_PU, minCost, pu, mvInitial_PU, BDMVR_INTME_MAX_NUM_SEARCH_ITERATION, MV_FRACTIONAL_BITS_INTERNAL,     bUseMR, false );
       if (minCost > 0)
@@ -6943,7 +6945,7 @@ bool InterPrediction::processBDMVR(PredictionUnit& pu)
 
   int subPuIdx = 0;
   const int dmvrSubPuStrideIncr = DMVR_SUBPU_STRIDE - std::max(1, (int)(pu.lumaSize().width >> DMVR_SUBCU_WIDTH_LOG2));
-#if JVET_X0049_ADAPT_DMVR
+#if JVET_X0049_BDMVR_SW_OPT
   Distortion minCost = std::numeric_limits<Distortion>::max();
   const Mv   mvInitial[2] = { pu.mv[0], pu.mv[1] };
   Mv         mvFinal[2] = { pu.mv[0], pu.mv[1] };
@@ -6953,7 +6955,11 @@ bool InterPrediction::processBDMVR(PredictionUnit& pu)
   const int adaptiveSearchRangeHor = (dx >> 1) < BDMVR_INTME_RANGE ? (dx >> 1) : BDMVR_INTME_RANGE;
   const int adaptiveSearchRangeVer = (dy >> 1) < BDMVR_INTME_RANGE ? (dy >> 1) : BDMVR_INTME_RANGE;
   const bool adaptRange = (adaptiveSearchRangeHor != BDMVR_INTME_RANGE || adaptiveSearchRangeVer != BDMVR_INTME_RANGE);
+#if JVET_X0049_ADAPT_DMVR
   const int maxSearchRound = std::min(pu.bmMergeFlag ? BM_MRG_SUB_PU_INT_MAX_SRCH_ROUND : BDMVR_INTME_MAX_NUM_SEARCH_ITERATION, 5);
+#else
+  const int maxSearchRound = std::min(BDMVR_INTME_MAX_NUM_SEARCH_ITERATION, 5);
+#endif
 
   // prepare cDistParam for cost calculation
   DistParam cDistParam;
@@ -6990,7 +6996,7 @@ bool InterPrediction::processBDMVR(PredictionUnit& pu)
   {
     for (int x = puPos.x, xStart = 0; x < (puPos.x + pu.lumaSize().width); x = x + dx, xStart = xStart + dx)
     {
-#if JVET_X0049_ADAPT_DMVR
+#if JVET_X0049_BDMVR_SW_OPT
       subPu.UnitArea::operator=(UnitArea(pu.chromaFormat, Area(x, y, dx, dy)));
 
       minCost = std::numeric_limits<Distortion>::max();
@@ -7006,8 +7012,10 @@ bool InterPrediction::processBDMVR(PredictionUnit& pu)
           adaptiveSearchRangeHor, adaptiveSearchRangeVer,
 #if JVET_X0056_DMVD_EARLY_TERMINATION
           true,
-#else
+#elif JVET_X0049_ADAPT_DMVR
           pu.bmMergeFlag,
+#else
+          false,
 #endif
           earlyTerminateTh, cDistParam,
           pelBuffer, BDMVR_BUF_STRIDE);
@@ -7019,8 +7027,10 @@ bool InterPrediction::processBDMVR(PredictionUnit& pu)
           adaptiveSearchRangeHor, adaptiveSearchRangeVer,
 #if JVET_X0056_DMVD_EARLY_TERMINATION
           true,
-#else
+#elif JVET_X0049_ADAPT_DMVR
           pu.bmMergeFlag,
+#else
+          false,
 #endif
           earlyTerminateTh, cDistParam,
           pelBuffer, BDMVR_BUF_STRIDE);
@@ -7193,7 +7203,7 @@ void InterPrediction::xBDMVRPreInterpolation(const PredictionUnit& pu, const Mv
   }
 }
 
-#if JVET_X0049_ADAPT_DMVR
+#if JVET_X0049_BDMVR_SW_OPT
 template <bool adaptRange, bool useHadamard>
 Distortion InterPrediction::xBDMVRMvIntPelFullSearch(Mv&mvOffset, Distortion curBestCost, const Mv(&initialMv)[2], const int32_t maxSearchRounds, const int maxHorOffset, const int maxVerOffset, const bool earlySkip, const Distortion earlyTerminateTh, DistParam &cDistParam, Pel* pelBuffer[2], const int stride)
 {
@@ -7365,12 +7375,12 @@ Distortion InterPrediction::xBDMVRMvIntPelFullSearch(Mv(&curBestMv)[2], Distorti
 }
 #endif
 
-#if JVET_X0049_ADAPT_DMVR
+#if JVET_X0049_BDMVR_SW_OPT
 template<bool hPel>
 #endif
 Distortion InterPrediction::xBDMVRMvSquareSearch(Mv (&curBestMv)[2], Distortion curBestCost, PredictionUnit& pu, const Mv (&initialMv)[2], int32_t maxSearchRounds, int32_t searchStepShift, bool useMR, bool useHadmard)
 {
-#if !JVET_X0049_ADAPT_DMVR
+#if !JVET_X0049_BDMVR_SW_OPT
   if (curBestCost == 0)
   {
     return 0;
@@ -7387,7 +7397,7 @@ Distortion InterPrediction::xBDMVRMvSquareSearch(Mv (&curBestMv)[2], Distortion
   if (curBestCost == std::numeric_limits<Distortion>::max())
   {
     CHECK(searchStepShift < MV_FRACTIONAL_BITS_INTERNAL - 1, "this is not possible");
-#if JVET_X0049_ADAPT_DMVR
+#if JVET_X0049_BDMVR_SW_OPT
     if (hPel)
     {
       doPreInterpolation = true;
@@ -7437,7 +7447,7 @@ Distortion InterPrediction::xBDMVRMvSquareSearch(Mv (&curBestMv)[2], Distortion
 
       Mv mvOffset(cSearchOffset[nDirect].getHor() << searchStepShift, cSearchOffset[nDirect].getVer() << searchStepShift);
 
-#if JVET_X0049_ADAPT_DMVR
+#if JVET_X0049_BDMVR_SW_OPT
       if(hPel && uiRound > 0)
 #else
       if (searchStepShift == MV_FRACTIONAL_BITS_INTERNAL - 1 && uiRound > 0)
@@ -7449,7 +7459,7 @@ Distortion InterPrediction::xBDMVRMvSquareSearch(Mv (&curBestMv)[2], Distortion
         }
       }
       Mv mvCand[2] = {mvCurCenter[0] + mvOffset, mvCurCenter[1] - mvOffset};
-#if JVET_X0049_ADAPT_DMVR
+#if JVET_X0049_BDMVR_SW_OPT
       if(!hPel)
 #else
       if (searchStepShift == MV_FRACTIONAL_BITS_INTERNAL)
@@ -7479,7 +7489,7 @@ Distortion InterPrediction::xBDMVRMvSquareSearch(Mv (&curBestMv)[2], Distortion
                                         doPreInterpolation, searchStepShift, mvCurCenter, initialMv, nDirect );
 #endif
       localCostArray[nDirect] = tmCost;
-#if JVET_X0049_ADAPT_DMVR
+#if JVET_X0049_BDMVR_SW_OPT
       if(hPel && uiRound > 0)
 #else
       if (searchStepShift == MV_FRACTIONAL_BITS_INTERNAL - 1 && uiRound > 0)
@@ -7512,7 +7522,7 @@ Distortion InterPrediction::xBDMVRMvSquareSearch(Mv (&curBestMv)[2], Distortion
     }
   }
 
-#if JVET_X0049_ADAPT_DMVR
+#if JVET_X0049_BDMVR_SW_OPT
   if(!hPel)
 #else
   if (searchStepShift == MV_FRACTIONAL_BITS_INTERNAL)
@@ -7666,14 +7676,14 @@ Distortion InterPrediction::xBDMVRMvOneTemplateHPelSquareSearch(Mv(&curBestMv)[2
 }
 #endif
 
-#if JVET_X0049_ADAPT_DMVR
+#if JVET_X0049_BDMVR_SW_OPT
 Distortion InterPrediction::xBDMVRGetMatchingError(const PredictionUnit& pu, const Mv(&mv)[2], bool useMR, bool useHadmard)
 #else
 Distortion InterPrediction::xBDMVRGetMatchingError(const PredictionUnit& pu, const Mv(&mv)[2], bool useMR)
 #endif
 {
   // Fill L0'a and L1's prediction blocks
-#if JVET_X0049_ADAPT_DMVR
+#if JVET_X0049_BDMVR_SW_OPT
         Pel*     pelBuffer[2] = { m_filteredBlock[3][REF_PIC_LIST_0][0] + BDMVR_CENTER_POSITION, m_filteredBlock[3][REF_PIC_LIST_1][0] + BDMVR_CENTER_POSITION };
         const SizeType stride = BDMVR_BUF_STRIDE;
 #else
@@ -7694,7 +7704,7 @@ Distortion InterPrediction::xBDMVRGetMatchingError(const PredictionUnit& pu, con
   cDistParam.applyWeight = false;
   cDistParam.useMR       = useMR;
 
-#if JVET_X0049_ADAPT_DMVR
+#if JVET_X0049_BDMVR_SW_OPT
   m_pcRdCost->setDistParam(cDistParam, predBuf[0].Y(), predBuf[1].Y(), pu.cu->slice->clpRng(COMPONENT_Y).bd, COMPONENT_Y, useHadmard);
 #if FULL_NBIT
   if (useHadmard)
@@ -7742,7 +7752,7 @@ Distortion InterPrediction::xBDMVRGetMatchingError(const PredictionUnit& pu, con
   }
 
   // Locate L0'a and L1's prediction blocks in pre-interpolation buffer
-#if JVET_X0049_ADAPT_DMVR
+#if JVET_X0049_BDMVR_SW_OPT
   const int32_t stride = BDMVR_BUF_STRIDE;
 #else
   const int32_t stride = MAX_CU_SIZE + ( BDMVR_INTME_RANGE << 1 ) + ( BDMVR_SIMD_IF_FACTOR - 2 );
diff --git a/source/Lib/CommonLib/InterPrediction.h b/source/Lib/CommonLib/InterPrediction.h
index 3038ca48214e8fdb855b3ac8d04d47442798a393..7a69486c5d735208a6e4740d20c54b8a151ac84c 100644
--- a/source/Lib/CommonLib/InterPrediction.h
+++ b/source/Lib/CommonLib/InterPrediction.h
@@ -139,7 +139,7 @@ protected:
                              Mv(-2, 2), Mv(-1, 2), Mv(0, 2), Mv(1, 2), Mv(2, 2) };
   uint64_t m_SADsArray[((2 * DMVR_NUM_ITERATION) + 1) * ((2 * DMVR_NUM_ITERATION) + 1)];
 #if MULTI_PASS_DMVR
-#if JVET_X0049_ADAPT_DMVR
+#if JVET_X0049_BDMVR_SW_OPT
   Mv m_pSearchEnlargeOffset_bilMrg[5][BDMVR_INTME_AREA];
   uint16_t m_pSearchEnlargeOffsetToIdx[5][BDMVR_INTME_AREA];
   uint16_t m_pSearchEnlargeOffsetNum[5];
@@ -378,9 +378,11 @@ private:
 #endif
   void       xBDMVRPreInterpolation    (const PredictionUnit& pu, const Mv (&mvCenter)[2], bool doPreInterpolationFP, bool doPreInterpolationHP);
 
-#if JVET_X0049_ADAPT_DMVR
+#if JVET_X0049_BDMVR_SW_OPT
   Distortion xBDMVRGetMatchingError    (const PredictionUnit& pu, const Mv (&mv)[2], bool useMR, bool useHadmard = false );
+#if JVET_X0049_ADAPT_DMVR
   template <uint8_t dir>
+#endif
 #else
   Distortion xBDMVRGetMatchingError    (const PredictionUnit& pu, const Mv (&mv)[2], bool useMR );
 #endif
@@ -389,7 +391,7 @@ private:
                                       , const Mv(&mvInitial)[2]  // only used for full-pel MVD
                                       , int nDirect              // only used for half-pel MVD
                                         );
-#if JVET_X0049_ADAPT_DMVR
+#if JVET_X0049_BDMVR_SW_OPT
   template <bool adaptRange, bool useHadamard>
   Distortion xBDMVRMvIntPelFullSearch  (Mv&mvOffset, Distortion curBestCost, 
     const Mv(&initialMv)[2], 
@@ -399,10 +401,12 @@ private:
     const Distortion earlyTerminateTh, DistParam &cDistParam, Pel* pelBuffer[2], const int stride);
   template<bool hPel>
   Distortion xBDMVRMvSquareSearch(Mv(&curBestMv)[2], Distortion curBestCost, PredictionUnit& pu, const Mv(&initialMv)[2], int32_t maxSearchRounds, int32_t searchStepShift, bool useMR, bool useHadmard);
+#if JVET_X0049_ADAPT_DMVR
   template <uint8_t dir>
   Distortion xBDMVRMvOneTemplateHPelSquareSearch(Mv(&curBestMv)[2], Distortion curBestCost, PredictionUnit& pu,
     const Mv(&initialMv)[2], int32_t maxSearchRounds, int32_t searchStepShift,
     bool useMR, bool useHadmard);
+#endif
 #else
   Distortion xBDMVRMvIntPelFullSearch  (Mv (&curBestMv)[2], Distortion curBestCost, PredictionUnit& pu, const Mv (&initialMv)[2], int32_t maxSearchRounds, int32_t searchStepShift, bool useMR, const int subPuBufOffset );
   Distortion xBDMVRMvSquareSearch      (Mv(&curBestMv)[2], Distortion curBestCost, PredictionUnit& pu, const Mv(&initialMv)[2], int32_t maxSearchRounds, int32_t searchStepShift, bool useMR, bool useHadmard);
diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h
index 55207ac08d039e21d2c05645b188c3bc6a0c1c9c..b906ca705056f801606b49aa84f9f71e9c9e6397 100644
--- a/source/Lib/CommonLib/TypeDef.h
+++ b/source/Lib/CommonLib/TypeDef.h
@@ -125,7 +125,10 @@
 #define IF_12TAP                                          1 // 12-tap IF
 #define ENABLE_OBMC                                       1 // Enable Overlapped Block Motion Compensation
 
+#define JVET_X0049_BDMVR_SW_OPT                           1 // JVET-X0049: software optimization for BDMVR (lossless)
+#if JVET_X0049_BDMVR_SW_OPT
 #define JVET_X0049_ADAPT_DMVR                             1 // JVET-X0049: Adaptive DMVR
+#endif
 #define JVET_X0056_DMVD_EARLY_TERMINATION                 1 // JVET-X0056: Early termination for DMVR and TM
 
 // Inter template matching tools