Float clobbering on inline asm

On inline assembly, I spent some time trying to clobber float registers on inline assembly.

I was trying to clobber a float register, and I was getting:

unknown register name ‘f10’ in ‘asm’

After some debugging I found that the float registers should be clobbered as fr, so, here is an example where we are using and clobbering Counter Register, Conditional register, VSX and FP registers.

asm (
 // prepare to merge low and high
 "mtvsrd 33, %[high_vs0] ;"
 "mtvsrd 34, %[low_vs0] ;"

/*
 * ADJUST vs0 EXPECTED VALUE AFTER AN HTM FAILURE 
 */

// vs0 = 0x5555555555555555555FFFFFFFFFFFFFFFF
 "xxmrghd 0, 33, 34 ;"

/*
 * ADJUST vs32 EXPECTED VALUE AFTER AN HTM FAILURE
 */

// vs32 = 0x5555555555555555555FFFFFFFFFFFFFFFF
 "xxmrghd 32, 33, 34 ;"

/*
 * Wait an amount of context switches so load_fp and load_vec
 * overflow and MSR.FP, MSR.VEC, and MSR.VSX become zero (off).
 */
 "mtctr %[counter];"
 "1: bdnz 1b ;" /*Decrement CTR branch if CTR non zero */

/*
 * Do or don't touch FP prior to the test.
 * set MSR.FP = 1 before provoking a unavailable in TM
 * exception
 */
 "cmpldi %[test_fp],0;"
 "beq no_fp ;"
 "fadd 10,10,10 ;"
 "no_fp: ;"

/*
 * Do or don't touch VEC prior to the test
 * set MSR.VEC = 1 before provoking a unavailable in TM
 * exception
 */
 "cmpldi %[test_vec],0;"
 "beq no_vec ;"
 "vaddcuw 10, 10, 10 ;"
 "no_vec: ;"

/*
 * Perhaps it would be a better idea to do the
 * compares outside transactional context and simply
 * duplicate code
 */
 "tbegin. ;"
 "beq trans_fail;"

/* Do we do FP unavailable? */
 "cmpldi %[exception],%[ex_fp];"
 "bne 1f ;"
 "fadd 10,10,10 ;"
 "b done ;"

/* Do we do VEC unavailable? */
 "1: cmpldi %[exception],%[ex_vec];"
 "bne 2f ;"
 "vaddcuw 10,10,10 ;"
 "b done ;"

/*
 * Not FP or VEC, therefore VSX. Ensure this
 * instruction always generates a VSX Unavailiable.
 * ISA 3.0 is tricky here.
 * (xxmrghd will on 2.07 and 3.0)
 */
 "2: xxmrghd 10,10,10;"

"done: tend. ;"
 "trans_fail: ;"

/* Give values back to C */
 "mfvsrd %[high_vs0],0 ;"
 "xxsldwi 3,0,0,2 ;"
 "mfvsrd %[low_vs0],3 ;"
 "mfvsrd %[high_vs32],32 ;"
 "xxsldwi 3,32,32,2 ;"
 "mfvsrd %[low_vs32],3 ;"

/* Give CR back to C so that it can check what happend */
 "mfcr %[counter];"

: [high_vs0] "+r" (high_vs0),
 [low_vs0] "+r" (low_vs0),
 [high_vs32] "=r" (high_vs32),
 [low_vs32] "=r" (low_vs32),
 [counter] "+r" (counter)
 : [test_fp] "r" (flags.test_fp),
 [test_vec]"r" (flags.test_vec),
 [exception]"r" (flags.exception),
 [ex_fp] "i" (FP_UNA_EXCEPTION),
 [ex_vec] "i" (VEC_UNA_EXCEPTION),
 [ex_vsx] "i" (VSX_UNA_EXCEPTION)

/*
 * It is a mystery to me as to why "f10" doesn't work
 * in the clobbers
 */
 : "cr0", "ctr", "v10", "vs0", "vs10", "vs3", "vs32", "vs33", "vs34", "fr10"

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s