Files
openairinterface5g/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_llr_computation.c
T

514 lines
20 KiB
C

/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
/*! \file PHY/NR_UE_TRANSPORT/nr_dlsch_llr_computation.c
* \brief Top-level routines for LLR computation of the PDSCH physical channel
* \author H. WANG
* \date 2018
* \version 0.1
* \company Eurecom
* \email:
* \note
* \warning
*/
#include "PHY/defs_nr_UE.h"
#include "PHY/phy_extern_nr_ue.h"
#include "nr_transport_proto_ue.h"
#include "PHY/TOOLS/tools_defs.h"
#include "PHY/sse_intrin.h"
//#define DEBUG_LLR_SIC
//==============================================================================================
// SINGLE-STREAM
//==============================================================================================
//----------------------------------------------------------------------------------------------
// QPSK
//----------------------------------------------------------------------------------------------
int nr_dlsch_qpsk_llr(NR_DL_FRAME_PARMS *frame_parms,
int32_t *rxdataF_comp,
int16_t *dlsch_llr,
uint8_t symbol,
uint32_t len,
uint8_t first_symbol_flag,
uint16_t nb_rb)
{
c16_t *rxF = (c16_t *)&rxdataF_comp[((int32_t)symbol*nb_rb*12)];
c16_t *llr32 = (c16_t *)dlsch_llr;
int i;
if (!llr32) {
LOG_E(PHY,"nr_dlsch_qpsk_llr: llr is null, symbol %d, llr32=%p\n",symbol, llr32);
return(-1);
}
/*
LOG_I(PHY,"dlsch_qpsk_llr: [symb %d / Length %d]: @LLR Buff %x, @LLR Buff(symb) %x \n",
symbol,
len,
dlsch_llr,
llr32);
*/
for (i=0; i<len; i++) {
//*llr32 = *rxF;
llr32->r = rxF->r >> 3;
llr32->i = rxF->i >> 3;
LOG_D(PHY,"dlsch_qpsk_llr %d : (%d,%d)\n", i, llr32->r, llr32->i);
rxF++;
llr32++;
}
return(0);
}
//----------------------------------------------------------------------------------------------
// 16-QAM
//----------------------------------------------------------------------------------------------
void nr_dlsch_16qam_llr(NR_DL_FRAME_PARMS *frame_parms,
int32_t *rxdataF_comp,
int16_t *dlsch_llr,
int32_t *dl_ch_mag,
uint8_t symbol,
uint32_t len,
uint8_t first_symbol_flag,
uint16_t nb_rb)
{
simde__m128i *rxF = (simde__m128i*)&rxdataF_comp[(symbol*nb_rb*12)];
simde__m128i *ch_mag;
simde__m128i llr128[2];
uint32_t *llr32;
int i;
unsigned char len_mod4=0;
llr32 = (uint32_t*)dlsch_llr;
ch_mag = (simde__m128i *)dl_ch_mag;
// printf("len=%d\n", len);
len_mod4 = len&3;
// printf("len_mod4=%d\n", len_mod4);
len>>=2; // length in quad words (4 REs)
// printf("len>>=2=%d\n", len);
len+=(len_mod4==0 ? 0 : 1);
// printf("len+=%d\n", len);
for (i=0; i<len; i++) {
simde__m128i xmm0 =simde_mm_abs_epi16(rxF[i]);
xmm0 =simde_mm_subs_epi16(ch_mag[i],xmm0);
// lambda_1=y_R, lambda_2=|y_R|-|h|^2, lamda_3=y_I, lambda_4=|y_I|-|h|^2
llr128[0] =simde_mm_unpacklo_epi32(rxF[i],xmm0);
llr128[1] =simde_mm_unpackhi_epi32(rxF[i],xmm0);
llr32[0] =simde_mm_extract_epi32(llr128[0],0); //((uint32_t *)&llr128[0])[0];
llr32[1] =simde_mm_extract_epi32(llr128[0],1); //((uint32_t *)&llr128[0])[1];
llr32[2] =simde_mm_extract_epi32(llr128[0],2); //((uint32_t *)&llr128[0])[2];
llr32[3] =simde_mm_extract_epi32(llr128[0],3); //((uint32_t *)&llr128[0])[3];
llr32[4] =simde_mm_extract_epi32(llr128[1],0); //((uint32_t *)&llr128[1])[0];
llr32[5] =simde_mm_extract_epi32(llr128[1],1); //((uint32_t *)&llr128[1])[1];
llr32[6] =simde_mm_extract_epi32(llr128[1],2); //((uint32_t *)&llr128[1])[2];
llr32[7] =simde_mm_extract_epi32(llr128[1],3); //((uint32_t *)&llr128[1])[3];
llr32+=8;
}
simde_mm_empty();
simde_m_empty();
}
//----------------------------------------------------------------------------------------------
// 64-QAM
//----------------------------------------------------------------------------------------------
void nr_dlsch_64qam_llr(NR_DL_FRAME_PARMS *frame_parms,
int32_t *rxdataF_comp,
int16_t *dlsch_llr,
int32_t *dl_ch_mag,
int32_t *dl_ch_magb,
uint8_t symbol,
uint32_t len,
uint8_t first_symbol_flag,
uint16_t nb_rb)
{
simde__m128i *rxF = (simde__m128i*)&rxdataF_comp[(symbol*nb_rb*12)];
simde__m128i *ch_mag,*ch_magb;
int i,len2;
unsigned char len_mod4;
int16_t *llr2;
llr2 = dlsch_llr;
ch_mag = (simde__m128i *)dl_ch_mag;
ch_magb = (simde__m128i *)dl_ch_magb;
// printf("nr_dlsch_64qam_llr: symbol %d,nb_rb %d, len %d,pbch_pss_sss_adjust %d\n",symbol,nb_rb,len,pbch_pss_sss_adjust);
/* LOG_I(PHY,"nr_dlsch_64qam_llr [symb %d / FirstSym %d / Length %d]: @LLR Buff %x \n",
symbol,
first_symbol_flag,
len,
dlsch_llr,
pllr_symbol);*/
len_mod4 =len&3;
len2=len>>2; // length in quad words (4 REs)
len2+=((len_mod4==0)?0:1);
for (i=0; i<len2; i++) {
simde__m128i xmm1, xmm2;
xmm1 =simde_mm_abs_epi16(rxF[i]);
xmm1 =simde_mm_subs_epi16(ch_mag[i],xmm1);
xmm2 =simde_mm_abs_epi16(xmm1);
xmm2 =simde_mm_subs_epi16(ch_magb[i],xmm2);
// loop over all LLRs in quad word (24 coded bits)
/*
for (j=0;j<8;j+=2) {
llr2[0] = ((short *)&rxF[i])[j];
llr2[1] = ((short *)&rxF[i])[j+1];
llr2[2] = ((short *)&xmm1)[j];
llr2[3] = ((short *)&xmm1)[j+1];
llr2[4] = ((short *)&xmm2)[j];
llr2[5] = ((short *)&xmm2)[j+1];
llr2+=6;
}
*/
llr2[0] = ((short *)&rxF[i])[0];
llr2[1] = ((short *)&rxF[i])[1];
llr2[2] =simde_mm_extract_epi16(xmm1,0);
llr2[3] =simde_mm_extract_epi16(xmm1,1);//((short *)&xmm1)[j+1];
llr2[4] =simde_mm_extract_epi16(xmm2,0);//((short *)&xmm2)[j];
llr2[5] =simde_mm_extract_epi16(xmm2,1);//((short *)&xmm2)[j+1];
llr2+=6;
llr2[0] = ((short *)&rxF[i])[2];
llr2[1] = ((short *)&rxF[i])[3];
llr2[2] =simde_mm_extract_epi16(xmm1,2);
llr2[3] =simde_mm_extract_epi16(xmm1,3);//((short *)&xmm1)[j+1];
llr2[4] =simde_mm_extract_epi16(xmm2,2);//((short *)&xmm2)[j];
llr2[5] =simde_mm_extract_epi16(xmm2,3);//((short *)&xmm2)[j+1];
llr2+=6;
llr2[0] = ((short *)&rxF[i])[4];
llr2[1] = ((short *)&rxF[i])[5];
llr2[2] =simde_mm_extract_epi16(xmm1,4);
llr2[3] =simde_mm_extract_epi16(xmm1,5);//((short *)&xmm1)[j+1];
llr2[4] =simde_mm_extract_epi16(xmm2,4);//((short *)&xmm2)[j];
llr2[5] =simde_mm_extract_epi16(xmm2,5);//((short *)&xmm2)[j+1];
llr2+=6;
llr2[0] = ((short *)&rxF[i])[6];
llr2[1] = ((short *)&rxF[i])[7];
llr2[2] =simde_mm_extract_epi16(xmm1,6);
llr2[3] =simde_mm_extract_epi16(xmm1,7);//((short *)&xmm1)[j+1];
llr2[4] =simde_mm_extract_epi16(xmm2,6);//((short *)&xmm2)[j];
llr2[5] =simde_mm_extract_epi16(xmm2,7);//((short *)&xmm2)[j+1];
llr2+=6;
}
simde_mm_empty();
simde_m_empty();
}
//----------------------------------------------------------------------------------------------
// 256-QAM
//----------------------------------------------------------------------------------------------
void nr_dlsch_256qam_llr(NR_DL_FRAME_PARMS *frame_parms,
int32_t *rxdataF_comp,
int16_t *dlsch_llr,
int32_t *dl_ch_mag,
int32_t *dl_ch_magb,
int32_t *dl_ch_magr,
uint8_t symbol,
uint32_t len,
uint8_t first_symbol_flag,
uint16_t nb_rb)
{
simde__m128i *rxF = (simde__m128i*)&rxdataF_comp[(symbol*nb_rb*12)];
simde__m128i *ch_mag,*ch_magb,*ch_magr;
int i,len2;
unsigned char len_mod4;
int16_t *llr2;
llr2 = dlsch_llr;
ch_mag = (simde__m128i *)dl_ch_mag;
ch_magb = (simde__m128i *)dl_ch_magb;
ch_magr = (simde__m128i *)dl_ch_magr;
len_mod4 =len&3;
len2=len>>2; // length in quad words (4 REs)
len2+=((len_mod4==0)?0:1);
for (i=0; i<len2; i++) {
simde__m128i xmm1 = simde_mm_abs_epi16(rxF[i]);
xmm1 = simde_mm_subs_epi16(ch_mag[i],xmm1);
simde__m128i xmm2 = simde_mm_abs_epi16(xmm1);
xmm2 = simde_mm_subs_epi16(ch_magb[i],xmm2);
simde__m128i xmm3 = simde_mm_abs_epi16(xmm2);
xmm3 = simde_mm_subs_epi16(ch_magr[i], xmm3);
llr2[0] = ((short *)&rxF[i])[0];
llr2[1] = ((short *)&rxF[i])[1];
llr2[2] = simde_mm_extract_epi16(xmm1,0);
llr2[3] = simde_mm_extract_epi16(xmm1,1);//((short *)&xmm1)[j+1];
llr2[4] = simde_mm_extract_epi16(xmm2,0);//((short *)&xmm2)[j];
llr2[5] = simde_mm_extract_epi16(xmm2,1);//((short *)&xmm2)[j+1];
llr2[6] = simde_mm_extract_epi16(xmm3,0);
llr2[7] = simde_mm_extract_epi16(xmm3,1);
llr2+=8;
llr2[0] = ((short *)&rxF[i])[2];
llr2[1] = ((short *)&rxF[i])[3];
llr2[2] = simde_mm_extract_epi16(xmm1,2);
llr2[3] = simde_mm_extract_epi16(xmm1,3);//((short *)&xmm1)[j+1];
llr2[4] = simde_mm_extract_epi16(xmm2,2);//((short *)&xmm2)[j];
llr2[5] = simde_mm_extract_epi16(xmm2,3);//((short *)&xmm2)[j+1];
llr2[6] = simde_mm_extract_epi16(xmm3,2);
llr2[7] = simde_mm_extract_epi16(xmm3,3);
llr2+=8;
llr2[0] = ((short *)&rxF[i])[4];
llr2[1] = ((short *)&rxF[i])[5];
llr2[2] = simde_mm_extract_epi16(xmm1,4);
llr2[3] = simde_mm_extract_epi16(xmm1,5);//((short *)&xmm1)[j+1];
llr2[4] = simde_mm_extract_epi16(xmm2,4);//((short *)&xmm2)[j];
llr2[5] = simde_mm_extract_epi16(xmm2,5);//((short *)&xmm2)[j+1];
llr2[6] = simde_mm_extract_epi16(xmm3,4);
llr2[7] = simde_mm_extract_epi16(xmm3,5);
llr2+=8;
llr2[0] = ((short *)&rxF[i])[6];
llr2[1] = ((short *)&rxF[i])[7];
llr2[2] = simde_mm_extract_epi16(xmm1,6);
llr2[3] = simde_mm_extract_epi16(xmm1,7);//((short *)&xmm1)[j+1];
llr2[4] = simde_mm_extract_epi16(xmm2,6);//((short *)&xmm2)[j];
llr2[5] = simde_mm_extract_epi16(xmm2,7);//((short *)&xmm2)[j+1];
llr2[6] = simde_mm_extract_epi16(xmm3,6);
llr2[7] = simde_mm_extract_epi16(xmm3,7);
llr2+=8;
}
simde_mm_empty();
simde_m_empty();
}
//==============================================================================================
// DUAL-STREAM
//==============================================================================================
//----------------------------------------------------------------------------------------------
// QPSK
//----------------------------------------------------------------------------------------------
simde__m128i y0r_over2 __attribute__ ((aligned(16)));
simde__m128i y0i_over2 __attribute__ ((aligned(16)));
simde__m128i y1r_over2 __attribute__ ((aligned(16)));
simde__m128i y1i_over2 __attribute__ ((aligned(16)));
simde__m128i A __attribute__ ((aligned(16)));
simde__m128i B __attribute__ ((aligned(16)));
simde__m128i C __attribute__ ((aligned(16)));
simde__m128i D __attribute__ ((aligned(16)));
simde__m128i E __attribute__ ((aligned(16)));
simde__m128i F __attribute__ ((aligned(16)));
simde__m128i G __attribute__ ((aligned(16)));
simde__m128i H __attribute__ ((aligned(16)));
void nr_qpsk_qpsk(short *stream0_in,
short *stream1_in,
short *stream0_out,
short *rho01,
int length
)
{
/*
This function computes the LLRs of stream 0 (s_0) in presence of the interfering stream 1 (s_1) assuming that both symbols are QPSK. It can be used for both MU-MIMO interference-aware receiver or for SU-MIMO receivers.
Parameters:
stream0_in = Matched filter output y0' = (h0*g0)*y0
stream1_in = Matched filter output y1' = (h0*g1)*y0
stream0_out = LLRs
rho01 = Correlation between the two effective channels \rho_{10} = (h1*g1)*(h0*g0)
length = number of resource elements
*/
simde__m128i *rho01_128i = (simde__m128i *)rho01;
simde__m128i *stream0_128i_in = (simde__m128i *)stream0_in;
simde__m128i *stream1_128i_in = (simde__m128i *)stream1_in;
simde__m128i *stream0_128i_out = (simde__m128i *)stream0_out;
simde__m128i ONE_OVER_SQRT_8 =simde_mm_set1_epi16(23170); //round(2^16/sqrt(8))
int i;
for (i=0; i<length>>2; i+=2) {
// in each iteration, we take 8 complex samples
simde__m128i xmm0 = rho01_128i[i]; // 4 symbols
simde__m128i xmm1 = rho01_128i[i+1];
// put (rho_r + rho_i)/2sqrt2 in rho_rpi
// put (rho_r - rho_i)/2sqrt2 in rho_rmi
xmm0 =simde_mm_shufflelo_epi16(xmm0,0xd8); // SIMDE_MM_SHUFFLE(0,2,1,3));
xmm0 =simde_mm_shufflehi_epi16(xmm0,0xd8); // SIMDE_MM_SHUFFLE(0,2,1,3));
xmm0 =simde_mm_shuffle_epi32(xmm0,0xd8); // SIMDE_MM_SHUFFLE(0,2,1,3));
xmm1 =simde_mm_shufflelo_epi16(xmm1,0xd8); // SIMDE_MM_SHUFFLE(0,2,1,3));
xmm1 =simde_mm_shufflehi_epi16(xmm1,0xd8); // SIMDE_MM_SHUFFLE(0,2,1,3));
xmm1 =simde_mm_shuffle_epi32(xmm1,0xd8); // SIMDE_MM_SHUFFLE(0,2,1,3));
//xmm0 = [Re(0,1) Re(2,3) Im(0,1) Im(2,3)]
//xmm1 = [Re(4,5) Re(6,7) Im(4,5) Im(6,7)]
simde__m128i xmm2 = simde_mm_unpacklo_epi64(xmm0, xmm1); // Re(rho)
simde__m128i xmm3 = simde_mm_unpackhi_epi64(xmm0, xmm1); // Im(rho)
simde__m128i rho_rpi = simde_mm_adds_epi16(xmm2, xmm3); // rho = Re(rho) + Im(rho)
simde__m128i rho_rmi = simde_mm_subs_epi16(xmm2, xmm3); // rho* = Re(rho) - Im(rho)
// divide by sqrt(8), no shift needed ONE_OVER_SQRT_8 = Q1.16
rho_rpi =simde_mm_mulhi_epi16(rho_rpi,ONE_OVER_SQRT_8);
rho_rmi =simde_mm_mulhi_epi16(rho_rmi,ONE_OVER_SQRT_8);
// Compute LLR for first bit of stream 0
// Compute real and imaginary parts of MF output for stream 0
xmm0 = stream0_128i_in[i];
xmm1 = stream0_128i_in[i+1];
xmm0 =simde_mm_shufflelo_epi16(xmm0,0xd8); // SIMDE_MM_SHUFFLE(0,2,1,3));
xmm0 =simde_mm_shufflehi_epi16(xmm0,0xd8); // SIMDE_MM_SHUFFLE(0,2,1,3));
xmm0 =simde_mm_shuffle_epi32(xmm0,0xd8); // SIMDE_MM_SHUFFLE(0,2,1,3));
xmm1 =simde_mm_shufflelo_epi16(xmm1,0xd8); // SIMDE_MM_SHUFFLE(0,2,1,3));
xmm1 =simde_mm_shufflehi_epi16(xmm1,0xd8); // SIMDE_MM_SHUFFLE(0,2,1,3));
xmm1 =simde_mm_shuffle_epi32(xmm1,0xd8); // SIMDE_MM_SHUFFLE(0,2,1,3));
//xmm0 = [Re(0,1) Re(2,3) Im(0,1) Im(2,3)]
//xmm1 = [Re(4,5) Re(6,7) Im(4,5) Im(6,7)]
simde__m128i y0r = simde_mm_unpacklo_epi64(xmm0, xmm1); // = [y0r(1),y0r(2),y0r(3),y0r(4)]
simde__m128i y0i = simde_mm_unpackhi_epi64(xmm0, xmm1);
simde__m128i y0r_over2 = simde_mm_srai_epi16(y0r, 1); // divide by 2
simde__m128i y0i_over2 = simde_mm_srai_epi16(y0i, 1); // divide by 2
// Compute real and imaginary parts of MF output for stream 1
xmm0 = stream1_128i_in[i];
xmm1 = stream1_128i_in[i+1];
xmm0 =simde_mm_shufflelo_epi16(xmm0,0xd8); // SIMDE_MM_SHUFFLE(0,2,1,3));
xmm0 =simde_mm_shufflehi_epi16(xmm0,0xd8); // SIMDE_MM_SHUFFLE(0,2,1,3));
xmm0 =simde_mm_shuffle_epi32(xmm0,0xd8); // SIMDE_MM_SHUFFLE(0,2,1,3));
xmm1 =simde_mm_shufflelo_epi16(xmm1,0xd8); // SIMDE_MM_SHUFFLE(0,2,1,3));
xmm1 =simde_mm_shufflehi_epi16(xmm1,0xd8); // SIMDE_MM_SHUFFLE(0,2,1,3));
xmm1 =simde_mm_shuffle_epi32(xmm1,0xd8); // SIMDE_MM_SHUFFLE(0,2,1,3));
//xmm0 = [Re(0,1) Re(2,3) Im(0,1) Im(2,3)]
//xmm1 = [Re(4,5) Re(6,7) Im(4,5) Im(6,7)]
simde__m128i y1r = simde_mm_unpacklo_epi64(xmm0, xmm1); //[y1r(1),y1r(2),y1r(3),y1r(4)]
simde__m128i y1i = simde_mm_unpackhi_epi64(xmm0, xmm1); //[y1i(1),y1i(2),y1i(3),y1i(4)]
simde__m128i y1r_over2 = simde_mm_srai_epi16(y1r, 1); // divide by 2
simde__m128i y1i_over2 = simde_mm_srai_epi16(y1i, 1); // divide by 2
// Compute the terms for the LLR of first bit
xmm0 =simde_mm_setzero_si128(); // ZERO
// 1 term for numerator of LLR
xmm3 =simde_mm_subs_epi16(y1r_over2,rho_rpi);
A =simde_mm_abs_epi16(xmm3); // A = |y1r/2 - rho/sqrt(8)|
xmm2 =simde_mm_adds_epi16(A,y0i_over2); // = |y1r/2 - rho/sqrt(8)| + y0i/2
xmm3 =simde_mm_subs_epi16(y1i_over2,rho_rmi);
B =simde_mm_abs_epi16(xmm3); // B = |y1i/2 - rho*/sqrt(8)|
simde__m128i logmax_num_re0 =simde_mm_adds_epi16(B,xmm2); // = |y1r/2 - rho/sqrt(8)|+|y1i/2 - rho*/sqrt(8)| + y0i/2
// 2 term for numerator of LLR
xmm3 =simde_mm_subs_epi16(y1r_over2,rho_rmi);
C =simde_mm_abs_epi16(xmm3); // C = |y1r/2 - rho*/4|
xmm2 =simde_mm_subs_epi16(C,y0i_over2); // = |y1r/2 - rho*/4| - y0i/2
xmm3 =simde_mm_adds_epi16(y1i_over2,rho_rpi);
D =simde_mm_abs_epi16(xmm3); // D = |y1i/2 + rho/4|
xmm2 =simde_mm_adds_epi16(xmm2,D); // |y1r/2 - rho*/4| + |y1i/2 + rho/4| - y0i/2
logmax_num_re0 =simde_mm_max_epi16(logmax_num_re0,xmm2); // max, numerator done
// 1 term for denominator of LLR
xmm3 =simde_mm_adds_epi16(y1r_over2,rho_rmi);
E =simde_mm_abs_epi16(xmm3); // E = |y1r/2 + rho*/4|
xmm2 =simde_mm_adds_epi16(E,y0i_over2); // = |y1r/2 + rho*/4| + y0i/2
xmm3 =simde_mm_subs_epi16(y1i_over2,rho_rpi);
F =simde_mm_abs_epi16(xmm3); // F = |y1i/2 - rho/4|
simde__m128i logmax_den_re0 =simde_mm_adds_epi16(F,xmm2); // = |y1r/2 + rho*/4| + |y1i/2 - rho/4| + y0i/2
// 2 term for denominator of LLR
xmm3 =simde_mm_adds_epi16(y1r_over2,rho_rpi);
G =simde_mm_abs_epi16(xmm3); // G = |y1r/2 + rho/4|
xmm2 =simde_mm_subs_epi16(G,y0i_over2); // = |y1r/2 + rho/4| - y0i/2
xmm3 =simde_mm_adds_epi16(y1i_over2,rho_rmi);
H =simde_mm_abs_epi16(xmm3); // H = |y1i/2 + rho*/4|
xmm2 =simde_mm_adds_epi16(xmm2,H); // = |y1r/2 + rho/4| + |y1i/2 + rho*/4| - y0i/2
logmax_den_re0 =simde_mm_max_epi16(logmax_den_re0,xmm2); // max, denominator done
// Compute the terms for the LLR of first bit
// 1 term for nominator of LLR
xmm2 = simde_mm_adds_epi16(A,y0r_over2);
simde__m128i logmax_num_im0 = simde_mm_adds_epi16(B, xmm2); // = |y1r/2 - rho/4| + |y1i/2 - rho*/4| + y0r/2
// 2 term for nominator of LLR
xmm2 =simde_mm_subs_epi16(E,y0r_over2);
xmm2 =simde_mm_adds_epi16(xmm2,F); // = |y1r/2 + rho*/4| + |y1i/2 - rho/4| - y0r/2
logmax_num_im0 =simde_mm_max_epi16(logmax_num_im0,xmm2); // max, nominator done
// 1 term for denominator of LLR
xmm2 =simde_mm_adds_epi16(C,y0r_over2);
simde__m128i logmax_den_im0 =simde_mm_adds_epi16(D,xmm2); // = |y1r/2 - rho*/4| + |y1i/2 + rho/4| - y0r/2
xmm2 =simde_mm_subs_epi16(G,y0r_over2);
xmm2 =simde_mm_adds_epi16(xmm2,H); // = |y1r/2 + rho/4| + |y1i/2 + rho*/4| - y0r/2
logmax_den_im0 =simde_mm_max_epi16(logmax_den_im0,xmm2); // max, denominator done
// LLR of first bit [L1(1), L1(2), L1(3), L1(4)]
y0r =simde_mm_adds_epi16(y0r,logmax_num_re0);
y0r =simde_mm_subs_epi16(y0r,logmax_den_re0);
// LLR of second bit [L2(1), L2(2), L2(3), L2(4)]
y0i =simde_mm_adds_epi16(y0i,logmax_num_im0);
y0i =simde_mm_subs_epi16(y0i,logmax_den_im0);
simde_mm_storeu_si128(&stream0_128i_out[i],simde_mm_unpacklo_epi16(y0r,y0i)); // = [L1(1), L2(1), L1(2), L2(2)]
if (i<((length>>1) - 1)) // false if only 2 REs remain
simde_mm_storeu_si128(&stream0_128i_out[i+1],simde_mm_unpackhi_epi16(y0r,y0i));
}
}