github.com/rohankumardubey/syslog-redirector-golang@v0.0.0-20140320174030-4859f03d829a/src/pkg/runtime/softfloat_arm.c (about)

     1  // Copyright 2009 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // Software floating point interpretaton of ARM 7500 FP instructions.
     6  // The interpretation is not bit compatible with the 7500.
     7  // It uses true little-endian doubles, while the 7500 used mixed-endian.
     8  
     9  #include "runtime.h"
    10  #include "../../cmd/ld/textflag.h"
    11  
    12  #define CPSR 14
    13  #define FLAGS_N (1U << 31)
    14  #define FLAGS_Z (1U << 30)
    15  #define FLAGS_C (1U << 29)
    16  #define FLAGS_V (1U << 28)
    17  
    18  void	runtime·abort(void);
    19  void	math·sqrtC(uint64, uint64*);
    20  
    21  static	uint32	trace = 0;
    22  
    23  static void
    24  fabort(void)
    25  {
    26  	if (1) {
    27  		runtime·printf("Unsupported floating point instruction\n");
    28  		runtime·abort();
    29  	}
    30  }
    31  
    32  static void
    33  putf(uint32 reg, uint32 val)
    34  {
    35  	m->freglo[reg] = val;
    36  }
    37  
    38  static void
    39  putd(uint32 reg, uint64 val)
    40  {
    41  	m->freglo[reg] = (uint32)val;
    42  	m->freghi[reg] = (uint32)(val>>32);
    43  }
    44  
    45  static uint64
    46  getd(uint32 reg)
    47  {
    48  	return (uint64)m->freglo[reg] | ((uint64)m->freghi[reg]<<32);
    49  }
    50  
    51  static void
    52  fprint(void)
    53  {
    54  	uint32 i;
    55  	for (i = 0; i < 16; i++) {
    56  		runtime·printf("\tf%d:\t%X %X\n", i, m->freghi[i], m->freglo[i]);
    57  	}
    58  }
    59  
    60  static uint32
    61  d2f(uint64 d)
    62  {
    63  	uint32 x;
    64  
    65  	runtime·f64to32c(d, &x);
    66  	return x;
    67  }
    68  
    69  static uint64
    70  f2d(uint32 f)
    71  {
    72  	uint64 x;
    73  
    74  	runtime·f32to64c(f, &x);
    75  	return x;
    76  }
    77  
    78  static uint32
    79  fstatus(bool nan, int32 cmp)
    80  {
    81  	if(nan)
    82  		return FLAGS_C | FLAGS_V;
    83  	if(cmp == 0)
    84  		return FLAGS_Z | FLAGS_C;
    85  	if(cmp < 0)
    86  		return FLAGS_N;
    87  	return FLAGS_C;
    88  }
    89  
    90  // conditions array record the required CPSR cond field for the
    91  // first 5 pairs of conditional execution opcodes
    92  // higher 4 bits are must set, lower 4 bits are must clear
    93  static const uint8 conditions[10/2] = {
    94  	[0/2] = (FLAGS_Z >> 24) | 0, // 0: EQ (Z set), 1: NE (Z clear)
    95  	[2/2] = (FLAGS_C >> 24) | 0, // 2: CS/HS (C set), 3: CC/LO (C clear)
    96  	[4/2] = (FLAGS_N >> 24) | 0, // 4: MI (N set), 5: PL (N clear)
    97  	[6/2] = (FLAGS_V >> 24) | 0, // 6: VS (V set), 7: VC (V clear)
    98  	[8/2] = (FLAGS_C >> 24) | 
    99  	        (FLAGS_Z >> 28),     // 8: HI (C set and Z clear), 9: LS (C clear and Z set)
   100  };
   101  
   102  // returns number of words that the fp instruction
   103  // is occupying, 0 if next instruction isn't float.
   104  static uint32
   105  stepflt(uint32 *pc, uint32 *regs)
   106  {
   107  	uint32 i, opc, regd, regm, regn, cpsr;
   108  	int32 delta;
   109  	uint32 *addr;
   110  	uint64 uval;
   111  	int64 sval;
   112  	bool nan, ok;
   113  	int32 cmp;
   114  
   115  	i = *pc;
   116  
   117  	if(trace)
   118  		runtime·printf("stepflt %p %x (cpsr %x)\n", pc, i, regs[CPSR] >> 28);
   119  
   120  	opc = i >> 28;
   121  	if(opc == 14) // common case first
   122  		goto execute;
   123  	cpsr = regs[CPSR] >> 28;
   124  	switch(opc) {
   125  	case 0: case 1: case 2: case 3: case 4: 
   126  	case 5: case 6: case 7: case 8: case 9:
   127  		if(((cpsr & (conditions[opc/2] >> 4)) == (conditions[opc/2] >> 4)) &&
   128  		   ((cpsr & (conditions[opc/2] & 0xf)) == 0)) {
   129  			if(opc & 1) return 1;
   130  		} else {
   131  			if(!(opc & 1)) return 1;
   132  		}
   133  		break;
   134  	case 10: // GE (N == V)
   135  	case 11: // LT (N != V)
   136  		if((cpsr & (FLAGS_N >> 28)) == (cpsr & (FLAGS_V >> 28))) {
   137  			if(opc & 1) return 1;
   138  		} else {
   139  			if(!(opc & 1)) return 1;
   140  		}
   141  		break;
   142  	case 12: // GT (N == V and Z == 0)
   143  	case 13: // LE (N != V or Z == 1)
   144  		if((cpsr & (FLAGS_N >> 28)) == (cpsr & (FLAGS_V >> 28)) &&
   145  		   (cpsr & (FLAGS_Z >> 28)) == 0) {
   146  			if(opc & 1) return 1;
   147  		} else {
   148  			if(!(opc & 1)) return 1;
   149  		}
   150  		break;
   151  	case 14: // AL
   152  		break;
   153  	case 15: // shouldn't happen
   154  		return 0;
   155  	}
   156  	if(trace)
   157  		runtime·printf("conditional %x (cpsr %x) pass\n", opc, cpsr);
   158  	i = (0xeU << 28) | (i & 0xfffffff);
   159  
   160  execute:
   161  	// special cases
   162  	if((i&0xfffff000) == 0xe59fb000) {
   163  		// load r11 from pc-relative address.
   164  		// might be part of a floating point move
   165  		// (or might not, but no harm in simulating
   166  		// one instruction too many).
   167  		addr = (uint32*)((uint8*)pc + (i&0xfff) + 8);
   168  		regs[11] = addr[0];
   169  
   170  		if(trace)
   171  			runtime·printf("*** cpu R[%d] = *(%p) %x\n",
   172  				11, addr, regs[11]);
   173  		return 1;
   174  	}
   175  	if(i == 0xe08bb00d) {
   176  		// add sp to r11.
   177  		// might be part of a large stack offset address
   178  		// (or might not, but again no harm done).
   179  		regs[11] += regs[13];
   180  
   181  		if(trace)
   182  			runtime·printf("*** cpu R[%d] += R[%d] %x\n",
   183  				11, 13, regs[11]);
   184  		return 1;
   185  	}
   186  	if(i == 0xeef1fa10) {
   187  		regs[CPSR] = (regs[CPSR]&0x0fffffff) | m->fflag;
   188  
   189  		if(trace)
   190  			runtime·printf("*** fpsr R[CPSR] = F[CPSR] %x\n", regs[CPSR]);
   191  		return 1;
   192  	}
   193  	if((i&0xff000000) == 0xea000000) {
   194  		// unconditional branch
   195  		// can happen in the middle of floating point
   196  		// if the linker decides it is time to lay down
   197  		// a sequence of instruction stream constants.
   198  		delta = i&0xffffff;
   199  		delta = (delta<<8) >> 8;	// sign extend
   200  
   201  		if(trace)
   202  			runtime·printf("*** cpu PC += %x\n", (delta+2)*4);
   203  		return delta+2;
   204  	}
   205  
   206  	goto stage1;
   207  
   208  stage1:	// load/store regn is cpureg, regm is 8bit offset
   209  	regd = i>>12 & 0xf;
   210  	regn = i>>16 & 0xf;
   211  	regm = (i & 0xff) << 2;	// PLUS or MINUS ??
   212  
   213  	switch(i & 0xfff00f00) {
   214  	default:
   215  		goto stage2;
   216  
   217  	case 0xed900a00:	// single load
   218  		addr = (uint32*)(regs[regn] + regm);
   219  		m->freglo[regd] = addr[0];
   220  
   221  		if(trace)
   222  			runtime·printf("*** load F[%d] = %x\n",
   223  				regd, m->freglo[regd]);
   224  		break;
   225  
   226  	case 0xed900b00:	// double load
   227  		addr = (uint32*)(regs[regn] + regm);
   228  		m->freglo[regd] = addr[0];
   229  		m->freghi[regd] = addr[1];
   230  
   231  		if(trace)
   232  			runtime·printf("*** load D[%d] = %x-%x\n",
   233  				regd, m->freghi[regd], m->freglo[regd]);
   234  		break;
   235  
   236  	case 0xed800a00:	// single store
   237  		addr = (uint32*)(regs[regn] + regm);
   238  		addr[0] = m->freglo[regd];
   239  
   240  		if(trace)
   241  			runtime·printf("*** *(%p) = %x\n",
   242  				addr, addr[0]);
   243  		break;
   244  
   245  	case 0xed800b00:	// double store
   246  		addr = (uint32*)(regs[regn] + regm);
   247  		addr[0] = m->freglo[regd];
   248  		addr[1] = m->freghi[regd];
   249  
   250  		if(trace)
   251  			runtime·printf("*** *(%p) = %x-%x\n",
   252  				addr, addr[1], addr[0]);
   253  		break;
   254  	}
   255  	return 1;
   256  
   257  stage2:	// regd, regm, regn are 4bit variables
   258  	regm = i>>0 & 0xf;
   259  	switch(i & 0xfff00ff0) {
   260  	default:
   261  		goto stage3;
   262  
   263  	case 0xf3000110:	// veor
   264  		m->freglo[regd] = m->freglo[regm]^m->freglo[regn];
   265  		m->freghi[regd] = m->freghi[regm]^m->freghi[regn];
   266  
   267  		if(trace)
   268  			runtime·printf("*** veor D[%d] = %x-%x\n",
   269  				regd, m->freghi[regd], m->freglo[regd]);
   270  		break;
   271  
   272  	case 0xeeb00b00:	// D[regd] = const(regn,regm)
   273  		regn = (regn<<4) | regm;
   274  		regm = 0x40000000UL;
   275  		if(regn & 0x80)
   276  			regm |= 0x80000000UL;
   277  		if(regn & 0x40)
   278  			regm ^= 0x7fc00000UL;
   279  		regm |= (regn & 0x3f) << 16;
   280  		m->freglo[regd] = 0;
   281  		m->freghi[regd] = regm;
   282  
   283  		if(trace)
   284  			runtime·printf("*** immed D[%d] = %x-%x\n",
   285  				regd, m->freghi[regd], m->freglo[regd]);
   286  		break;
   287  
   288  	case 0xeeb00a00:	// F[regd] = const(regn,regm)
   289  		regn = (regn<<4) | regm;
   290  		regm = 0x40000000UL;
   291  		if(regn & 0x80)
   292  			regm |= 0x80000000UL;
   293  		if(regn & 0x40)
   294  			regm ^= 0x7e000000UL;
   295  		regm |= (regn & 0x3f) << 19;
   296  		m->freglo[regd] = regm;
   297  
   298  		if(trace)
   299  			runtime·printf("*** immed D[%d] = %x\n",
   300  				regd, m->freglo[regd]);
   301  		break;
   302  
   303  	case 0xee300b00:	// D[regd] = D[regn]+D[regm]
   304  		runtime·fadd64c(getd(regn), getd(regm), &uval);
   305  		putd(regd, uval);
   306  
   307  		if(trace)
   308  			runtime·printf("*** add D[%d] = D[%d]+D[%d] %x-%x\n",
   309  				regd, regn, regm, m->freghi[regd], m->freglo[regd]);
   310  		break;
   311  
   312  	case 0xee300a00:	// F[regd] = F[regn]+F[regm]
   313  		runtime·fadd64c(f2d(m->freglo[regn]), f2d(m->freglo[regm]), &uval);
   314  		m->freglo[regd] = d2f(uval);
   315  
   316  		if(trace)
   317  			runtime·printf("*** add F[%d] = F[%d]+F[%d] %x\n",
   318  				regd, regn, regm, m->freglo[regd]);
   319  		break;
   320  
   321  	case 0xee300b40:	// D[regd] = D[regn]-D[regm]
   322  		runtime·fsub64c(getd(regn), getd(regm), &uval);
   323  		putd(regd, uval);
   324  
   325  		if(trace)
   326  			runtime·printf("*** sub D[%d] = D[%d]-D[%d] %x-%x\n",
   327  				regd, regn, regm, m->freghi[regd], m->freglo[regd]);
   328  		break;
   329  
   330  	case 0xee300a40:	// F[regd] = F[regn]-F[regm]
   331  		runtime·fsub64c(f2d(m->freglo[regn]), f2d(m->freglo[regm]), &uval);
   332  		m->freglo[regd] = d2f(uval);
   333  
   334  		if(trace)
   335  			runtime·printf("*** sub F[%d] = F[%d]-F[%d] %x\n",
   336  				regd, regn, regm, m->freglo[regd]);
   337  		break;
   338  
   339  	case 0xee200b00:	// D[regd] = D[regn]*D[regm]
   340  		runtime·fmul64c(getd(regn), getd(regm), &uval);
   341  		putd(regd, uval);
   342  
   343  		if(trace)
   344  			runtime·printf("*** mul D[%d] = D[%d]*D[%d] %x-%x\n",
   345  				regd, regn, regm, m->freghi[regd], m->freglo[regd]);
   346  		break;
   347  
   348  	case 0xee200a00:	// F[regd] = F[regn]*F[regm]
   349  		runtime·fmul64c(f2d(m->freglo[regn]), f2d(m->freglo[regm]), &uval);
   350  		m->freglo[regd] = d2f(uval);
   351  
   352  		if(trace)
   353  			runtime·printf("*** mul F[%d] = F[%d]*F[%d] %x\n",
   354  				regd, regn, regm, m->freglo[regd]);
   355  		break;
   356  
   357  	case 0xee800b00:	// D[regd] = D[regn]/D[regm]
   358  		runtime·fdiv64c(getd(regn), getd(regm), &uval);
   359  		putd(regd, uval);
   360  
   361  		if(trace)
   362  			runtime·printf("*** div D[%d] = D[%d]/D[%d] %x-%x\n",
   363  				regd, regn, regm, m->freghi[regd], m->freglo[regd]);
   364  		break;
   365  
   366  	case 0xee800a00:	// F[regd] = F[regn]/F[regm]
   367  		runtime·fdiv64c(f2d(m->freglo[regn]), f2d(m->freglo[regm]), &uval);
   368  		m->freglo[regd] = d2f(uval);
   369  
   370  		if(trace)
   371  			runtime·printf("*** div F[%d] = F[%d]/F[%d] %x\n",
   372  				regd, regn, regm, m->freglo[regd]);
   373  		break;
   374  
   375  	case 0xee000b10:	// S[regn] = R[regd] (MOVW) (regm ignored)
   376  		m->freglo[regn] = regs[regd];
   377  
   378  		if(trace)
   379  			runtime·printf("*** cpy S[%d] = R[%d] %x\n",
   380  				regn, regd, m->freglo[regn]);
   381  		break;
   382  
   383  	case 0xee100b10:	// R[regd] = S[regn] (MOVW) (regm ignored)
   384  		regs[regd] = m->freglo[regn];
   385  
   386  		if(trace)
   387  			runtime·printf("*** cpy R[%d] = S[%d] %x\n",
   388  				regd, regn, regs[regd]);
   389  		break;
   390  	}
   391  	return 1;
   392  
   393  stage3:	// regd, regm are 4bit variables
   394  	switch(i & 0xffff0ff0) {
   395  	default:
   396  		goto done;
   397  
   398  	case 0xeeb00a40:	// F[regd] = F[regm] (MOVF)
   399  		m->freglo[regd] = m->freglo[regm];
   400  
   401  		if(trace)
   402  			runtime·printf("*** F[%d] = F[%d] %x\n",
   403  				regd, regm, m->freglo[regd]);
   404  		break;
   405  
   406  	case 0xeeb00b40:	// D[regd] = D[regm] (MOVD)
   407  		m->freglo[regd] = m->freglo[regm];
   408  		m->freghi[regd] = m->freghi[regm];
   409  
   410  		if(trace)
   411  			runtime·printf("*** D[%d] = D[%d] %x-%x\n",
   412  				regd, regm, m->freghi[regd], m->freglo[regd]);
   413  		break;
   414  
   415  	case 0xeeb10bc0:	// D[regd] = sqrt D[regm]
   416  		math·sqrtC(getd(regm), &uval);
   417  		putd(regd, uval);
   418  
   419  		if(trace)
   420  			runtime·printf("*** D[%d] = sqrt D[%d] %x-%x\n",
   421  				regd, regm, m->freghi[regd], m->freglo[regd]);
   422  		break;
   423  
   424  	case 0xeeb00bc0:	// D[regd] = abs D[regm]
   425  		m->freglo[regd] = m->freglo[regm];
   426  		m->freghi[regd] = m->freghi[regm] & ((1<<31)-1);
   427  
   428  		if(trace)
   429  			runtime·printf("*** D[%d] = abs D[%d] %x-%x\n",
   430  					regd, regm, m->freghi[regd], m->freglo[regd]);
   431  		break;
   432  
   433  	case 0xeeb00ac0:	// F[regd] = abs F[regm]
   434  		m->freglo[regd] = m->freglo[regm] & ((1<<31)-1);
   435  
   436  		if(trace)
   437  			runtime·printf("*** F[%d] = abs F[%d] %x\n",
   438  					regd, regm, m->freglo[regd]);
   439  		break;
   440  
   441  	case 0xeeb40bc0:	// D[regd] :: D[regm] (CMPD)
   442  		runtime·fcmp64c(getd(regd), getd(regm), &cmp, &nan);
   443  		m->fflag = fstatus(nan, cmp);
   444  
   445  		if(trace)
   446  			runtime·printf("*** cmp D[%d]::D[%d] %x\n",
   447  				regd, regm, m->fflag);
   448  		break;
   449  
   450  	case 0xeeb40ac0:	// F[regd] :: F[regm] (CMPF)
   451  		runtime·fcmp64c(f2d(m->freglo[regd]), f2d(m->freglo[regm]), &cmp, &nan);
   452  		m->fflag = fstatus(nan, cmp);
   453  
   454  		if(trace)
   455  			runtime·printf("*** cmp F[%d]::F[%d] %x\n",
   456  				regd, regm, m->fflag);
   457  		break;
   458  
   459  	case 0xeeb70ac0:	// D[regd] = F[regm] (MOVFD)
   460  		putd(regd, f2d(m->freglo[regm]));
   461  
   462  		if(trace)
   463  			runtime·printf("*** f2d D[%d]=F[%d] %x-%x\n",
   464  				regd, regm, m->freghi[regd], m->freglo[regd]);
   465  		break;
   466  
   467  	case 0xeeb70bc0:	// F[regd] = D[regm] (MOVDF)
   468  		m->freglo[regd] = d2f(getd(regm));
   469  
   470  		if(trace)
   471  			runtime·printf("*** d2f F[%d]=D[%d] %x-%x\n",
   472  				regd, regm, m->freghi[regd], m->freglo[regd]);
   473  		break;
   474  
   475  	case 0xeebd0ac0:	// S[regd] = F[regm] (MOVFW)
   476  		runtime·f64tointc(f2d(m->freglo[regm]), &sval, &ok);
   477  		if(!ok || (int32)sval != sval)
   478  			sval = 0;
   479  		m->freglo[regd] = sval;
   480  
   481  		if(trace)
   482  			runtime·printf("*** fix S[%d]=F[%d] %x\n",
   483  				regd, regm, m->freglo[regd]);
   484  		break;
   485  
   486  	case 0xeebc0ac0:	// S[regd] = F[regm] (MOVFW.U)
   487  		runtime·f64tointc(f2d(m->freglo[regm]), &sval, &ok);
   488  		if(!ok || (uint32)sval != sval)
   489  			sval = 0;
   490  		m->freglo[regd] = sval;
   491  
   492  		if(trace)
   493  			runtime·printf("*** fix unsigned S[%d]=F[%d] %x\n",
   494  				regd, regm, m->freglo[regd]);
   495  		break;
   496  
   497  	case 0xeebd0bc0:	// S[regd] = D[regm] (MOVDW)
   498  		runtime·f64tointc(getd(regm), &sval, &ok);
   499  		if(!ok || (int32)sval != sval)
   500  			sval = 0;
   501  		m->freglo[regd] = sval;
   502  
   503  		if(trace)
   504  			runtime·printf("*** fix S[%d]=D[%d] %x\n",
   505  				regd, regm, m->freglo[regd]);
   506  		break;
   507  
   508  	case 0xeebc0bc0:	// S[regd] = D[regm] (MOVDW.U)
   509  		runtime·f64tointc(getd(regm), &sval, &ok);
   510  		if(!ok || (uint32)sval != sval)
   511  			sval = 0;
   512  		m->freglo[regd] = sval;
   513  
   514  		if(trace)
   515  			runtime·printf("*** fix unsigned S[%d]=D[%d] %x\n",
   516  				regd, regm, m->freglo[regd]);
   517  		break;
   518  
   519  	case 0xeeb80ac0:	// D[regd] = S[regm] (MOVWF)
   520  		cmp = m->freglo[regm];
   521  		if(cmp < 0) {
   522  			runtime·fintto64c(-cmp, &uval);
   523  			putf(regd, d2f(uval));
   524  			m->freglo[regd] ^= 0x80000000;
   525  		} else {
   526  			runtime·fintto64c(cmp, &uval);
   527  			putf(regd, d2f(uval));
   528  		}
   529  
   530  		if(trace)
   531  			runtime·printf("*** float D[%d]=S[%d] %x-%x\n",
   532  				regd, regm, m->freghi[regd], m->freglo[regd]);
   533  		break;
   534  
   535  	case 0xeeb80a40:	// D[regd] = S[regm] (MOVWF.U)
   536  		runtime·fintto64c(m->freglo[regm], &uval);
   537  		putf(regd, d2f(uval));
   538  
   539  		if(trace)
   540  			runtime·printf("*** float unsigned D[%d]=S[%d] %x-%x\n",
   541  				regd, regm, m->freghi[regd], m->freglo[regd]);
   542  		break;
   543  
   544  	case 0xeeb80bc0:	// D[regd] = S[regm] (MOVWD)
   545  		cmp = m->freglo[regm];
   546  		if(cmp < 0) {
   547  			runtime·fintto64c(-cmp, &uval);
   548  			putd(regd, uval);
   549  			m->freghi[regd] ^= 0x80000000;
   550  		} else {
   551  			runtime·fintto64c(cmp, &uval);
   552  			putd(regd, uval);
   553  		}
   554  
   555  		if(trace)
   556  			runtime·printf("*** float D[%d]=S[%d] %x-%x\n",
   557  				regd, regm, m->freghi[regd], m->freglo[regd]);
   558  		break;
   559  
   560  	case 0xeeb80b40:	// D[regd] = S[regm] (MOVWD.U)
   561  		runtime·fintto64c(m->freglo[regm], &uval);
   562  		putd(regd, uval);
   563  
   564  		if(trace)
   565  			runtime·printf("*** float unsigned D[%d]=S[%d] %x-%x\n",
   566  				regd, regm, m->freghi[regd], m->freglo[regd]);
   567  		break;
   568  	}
   569  	return 1;
   570  
   571  done:
   572  	if((i&0xff000000) == 0xee000000 ||
   573  	   (i&0xff000000) == 0xed000000) {
   574  		runtime·printf("stepflt %p %x\n", pc, i);
   575  		fabort();
   576  	}
   577  	return 0;
   578  }
   579  
   580  typedef struct Sfregs Sfregs;
   581  
   582  // NOTE: These are all recorded as pointers because they are possibly live registers,
   583  // and we don't know what they contain. Recording them as pointers should be
   584  // safer than not.
   585  struct Sfregs
   586  {
   587  	uint32 *r0;
   588  	uint32 *r1;
   589  	uint32 *r2;
   590  	uint32 *r3;
   591  	uint32 *r4;
   592  	uint32 *r5;
   593  	uint32 *r6;
   594  	uint32 *r7;
   595  	uint32 *r8;
   596  	uint32 *r9;
   597  	uint32 *r10;
   598  	uint32 *r11;
   599  	uint32 *r12;
   600  	uint32 *r13;
   601  	uint32 cspr;
   602  };
   603  
   604  #pragma textflag NOSPLIT
   605  uint32*
   606  runtime·_sfloat2(uint32 *lr, Sfregs regs)
   607  {
   608  	uint32 skip;
   609  
   610  	skip = stepflt(lr, (uint32*)&regs.r0);
   611  	if(skip == 0) {
   612  		runtime·printf("sfloat2 %p %x\n", lr, *lr);
   613  		fabort(); // not ok to fail first instruction
   614  	}
   615  
   616  	lr += skip;
   617  	while(skip = stepflt(lr, (uint32*)&regs.r0))
   618  		lr += skip;
   619  	return lr;
   620  }