From 014222e87977183f3e2e49a52d3a1ece4011c0a0 Mon Sep 17 00:00:00 2001 From: Jash Date: Sun, 23 Aug 2026 12:58:11 +0530 Subject: [PATCH 1/3] accept any shader model in .target The lexer enumerated sm_10 through sm_35, so every newer .target was a lexical error and ocelot aborted. That pinned callers to Kepler, which CUDA 12 no longer supports at all. Nothing reads the target string back: targetElement pushes it into statement.targets and ir/Module.cpp hardcodes "sm_21" for internally built modules. So one text-carrying token replaces the eight hardcoded ones and never needs updating for a new architecture. --- ocelot/include/ocelot/parser/PTXParser.h | 3 ++- ocelot/src/parser/PTXLexer.cpp | 9 +-------- ocelot/src/parser/PTXParser.cpp | 18 ++++++++---------- ocelot/src/parser/ptx.ll | 17 +---------------- ocelot/src/parser/ptxgrammar.yy | 17 +++++++++-------- 5 files changed, 21 insertions(+), 43 deletions(-) diff --git a/ocelot/include/ocelot/parser/PTXParser.h b/ocelot/include/ocelot/parser/PTXParser.h index 1527b55c..a017de5d 100644 --- a/ocelot/include/ocelot/parser/PTXParser.h +++ b/ocelot/include/ocelot/parser/PTXParser.h @@ -150,7 +150,7 @@ namespace parser void maxnreg( unsigned int regs ); void maxntid( unsigned int tidx, unsigned int tidy = 1024, unsigned int tidz = 1024 ); - void ctapersm( int target, unsigned int ctas ); + void ctapersm( const char* target, unsigned int ctas ); void maxnctapersm( unsigned int ctas ); void maxnctapersm(); void minnctapersm( unsigned int ctas ); @@ -171,6 +171,7 @@ namespace parser void singleList( float value ); void singleList1( float value ); void targetElement( int token ); + void targetElement( const char* target ); void target(); void noAddressSpace(); void addressSpace( int token ); diff --git a/ocelot/src/parser/PTXLexer.cpp b/ocelot/src/parser/PTXLexer.cpp index 8d9c3c01..f1871cae 100644 --- a/ocelot/src/parser/PTXLexer.cpp +++ b/ocelot/src/parser/PTXLexer.cpp @@ -134,15 +134,8 @@ namespace parser CASE(TOKEN_MAXNREG) CASE(TOKEN_MAXNTID) CASE(TOKEN_MAXNCTAPERSM) - CASE(TOKEN_SM10) + CASE(TOKEN_SHADER_MODEL) CASE(TOKEN_MINNCTAPERSM) - CASE(TOKEN_SM11) - CASE(TOKEN_SM12) - CASE(TOKEN_SM13) - CASE(TOKEN_SM20) - CASE(TOKEN_SM21) - CASE(TOKEN_SM30) - CASE(TOKEN_SM35) CASE(TOKEN_MAP_F64_TO_F32) CASE(TOKEN_CONST) CASE(TOKEN_GLOBAL) diff --git a/ocelot/src/parser/PTXParser.cpp b/ocelot/src/parser/PTXParser.cpp index 636237be..0b369b70 100644 --- a/ocelot/src/parser/PTXParser.cpp +++ b/ocelot/src/parser/PTXParser.cpp @@ -376,7 +376,7 @@ namespace parser } - void PTXParser::State::ctapersm( int target, unsigned int ctas ) + void PTXParser::State::ctapersm( const char* target, unsigned int ctas ) { report( " Rule: shareModel ':' TOKEN_DECIMAL_CONSTANT" ); } @@ -598,15 +598,7 @@ namespace parser void PTXParser::State::targetElement( int token ) { report( " Rule: targetOption" ); - if( token == TOKEN_SM10 ) statement.targets.push_back( "sm_10" ); - else if( token == TOKEN_SM11 ) statement.targets.push_back( "sm_11" ); - else if( token == TOKEN_SM12 ) statement.targets.push_back( "sm_12" ); - else if( token == TOKEN_SM13 ) statement.targets.push_back( "sm_13" ); - else if( token == TOKEN_SM20 ) statement.targets.push_back( "sm_20" ); - else if( token == TOKEN_SM21 ) statement.targets.push_back( "sm_21" ); - else if( token == TOKEN_SM30 ) statement.targets.push_back( "sm_30" ); - else if( token == TOKEN_SM35 ) statement.targets.push_back( "sm_35" ); - else if( token == TOKEN_MAP_F64_TO_F32 ) + if( token == TOKEN_MAP_F64_TO_F32 ) { statement.targets.push_back( "map_f64_to_f32" ); } @@ -622,6 +614,12 @@ namespace parser } } + void PTXParser::State::targetElement( const char* target ) + { + report( " Rule: targetOption" ); + statement.targets.push_back( target ); + } + void PTXParser::State::target() { report( " Rule: TARGET targetElementList" ); diff --git a/ocelot/src/parser/ptx.ll b/ocelot/src/parser/ptx.ll index e3d747ef..927f1ccb 100644 --- a/ocelot/src/parser/ptx.ll +++ b/ocelot/src/parser/ptx.ll @@ -317,22 +317,7 @@ LABEL ({IDENTIFIER}{WHITESPACE}":") ".gl" { yylval->value = TOKEN_GL; return TOKEN_GL; } ".sys" { yylval->value = TOKEN_SYS; return TOKEN_SYS; } -"sm_10" { yylval->value = TOKEN_SM10; - return TOKEN_SM10; } -"sm_11" { yylval->value = TOKEN_SM11; - return TOKEN_SM11; } -"sm_12" { yylval->value = TOKEN_SM12; - return TOKEN_SM12; } -"sm_13" { yylval->value = TOKEN_SM13; - return TOKEN_SM13; } -"sm_20" { yylval->value = TOKEN_SM20; - return TOKEN_SM20; } -"sm_21" { yylval->value = TOKEN_SM21; - return TOKEN_SM21; } -"sm_30" { yylval->value = TOKEN_SM30; - return TOKEN_SM30; } -"sm_35" { yylval->value = TOKEN_SM35; - return TOKEN_SM35; } +"sm_"[0-9]+[a-zA-Z]* { sstrcpy( yylval->text, yytext, 1024 ); return TOKEN_SHADER_MODEL; } "map_f64_to_f32" { yylval->value = TOKEN_MAP_F64_TO_F32; return TOKEN_MAP_F64_TO_F32; } "texmode_independent" { yylval->value = TOKEN_TEXMODE_INDEPENDENT; diff --git a/ocelot/src/parser/ptxgrammar.yy b/ocelot/src/parser/ptxgrammar.yy index 32ab8e38..a5d04981 100644 --- a/ocelot/src/parser/ptxgrammar.yy +++ b/ocelot/src/parser/ptxgrammar.yy @@ -76,8 +76,8 @@ %token TOKEN_SECTION TOKEN_ADDRESS_SIZE TOKEN_WEAK %token TOKEN_MAXNREG TOKEN_MAXNTID TOKEN_MAXNCTAPERSM TOKEN_MINNCTAPERSM -%token TOKEN_SM11 TOKEN_SM12 TOKEN_SM13 TOKEN_SM20 TOKEN_MAP_F64_TO_F32 -%token TOKEN_SM21 TOKEN_SM10 TOKEN_SM30 TOKEN_SM35 +%token TOKEN_MAP_F64_TO_F32 +%token TOKEN_SHADER_MODEL %token TOKEN_TEXMODE_INDEPENDENT TOKEN_TEXMODE_UNIFIED %token TOKEN_CONST TOKEN_GLOBAL TOKEN_LOCAL TOKEN_PARAM TOKEN_PRAGMA TOKEN_PTR @@ -259,16 +259,17 @@ singleList : '{' singleListSingle '}' ',' '{' singleListSingle '}'; singleInitializer : singleList | '{' singleList '}' | '{' singleListSingle '}' | singleListSingle; -shaderModel : TOKEN_SM10 | TOKEN_SM11 | TOKEN_SM12 | TOKEN_SM13 | TOKEN_SM20 - | TOKEN_SM21 | TOKEN_SM30 | TOKEN_SM35; - floatingPointOption : TOKEN_MAP_F64_TO_F32; textureOption: TOKEN_TEXMODE_INDEPENDENT | TOKEN_TEXMODE_UNIFIED; -targetOption : shaderModel | floatingPointOption | textureOption; +targetOption : floatingPointOption | textureOption; targetElement : targetOption { state.targetElement( $1 ); +} + | TOKEN_SHADER_MODEL +{ + state.targetElement( $1 ); }; targetElementList : /* empty string */ | targetElement @@ -603,9 +604,9 @@ maxntid : TOKEN_MAXNTID TOKEN_DECIMAL_CONSTANT ',' TOKEN_DECIMAL_CONSTANT ',' state.maxntid( $2, $4, $6 ); }; -ctapersm : shaderModel ':' TOKEN_DECIMAL_CONSTANT +ctapersm : TOKEN_SHADER_MODEL ':' TOKEN_DECIMAL_CONSTANT { - state.ctapersm( $1, $3 ); + state.ctapersm( $1, $3 ); }; ctapersmList : ctapersm | ctapersmList ',' ctapersm; From 7af6a5a7a1cd9229ec6044a58ad67f0f493daa0b Mon Sep 17 00:00:00 2001 From: Jash Date: Sun, 23 Aug 2026 12:58:11 +0530 Subject: [PATCH 2/3] bfi: pos and len are always u32 PTX types bfi's pos and len operands .u32 regardless of whether the instruction is .b32 or .b64, but the parser types immediates from the instruction type, so `bfi.b64 d, a, b, 32, 32` yielded b64 immediates and was rejected. Operand 1 already exempts immediates; operands 3 and 4 did not. Operand 4 also tested b.type instead of c.type. eval_Bfi already reads both as operandAsU32 for .b32 and .b64, so only the validator disagreed. nvcc emits bfi.b64 from sm_50 on. --- ocelot/src/ir/PTXInstruction.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/ocelot/src/ir/PTXInstruction.cpp b/ocelot/src/ir/PTXInstruction.cpp index 099a0493..c42c7506 100644 --- a/ocelot/src/ir/PTXInstruction.cpp +++ b/ocelot/src/ir/PTXInstruction.cpp @@ -667,12 +667,14 @@ std::string ir::PTXInstruction::valid() const { return "operand 2 type " + PTXOperand::toString( a.type ) + " cannot be assigned to " + PTXOperand::toString( type ); } - if( !PTXOperand::valid( PTXOperand::u32, b.type ) ) { + if( !PTXOperand::valid( PTXOperand::u32, b.type ) + && b.addressMode != PTXOperand::Immediate ) { return "operand 3 type " + PTXOperand::toString( b.type ) + " cannot be assigned to " + PTXOperand::toString( PTXOperand::u32 ); } - if( !PTXOperand::valid( PTXOperand::u32, b.type ) ) { + if( !PTXOperand::valid( PTXOperand::u32, c.type ) + && c.addressMode != PTXOperand::Immediate ) { return "operand 4 type " + PTXOperand::toString( c.type ) + " cannot be assigned to " + PTXOperand::toString( PTXOperand::u32 ); From 5eae8a24a2afa4f3d1129e5ccd8ede0bd0bee5a8 Mon Sep 17 00:00:00 2001 From: Jash Date: Sun, 23 Aug 2026 13:54:05 +0530 Subject: [PATCH 3/3] implement f16 cvt to and from f16 threw "conversion not implemented", and add, mul, max, setp, mov and ex2 rejected f16 as an instruction type, so nothing targeting sm_53 or newer could use half at all. f32 represents every f16 exactly, so operandAsF32 widens an f16 operand and the existing f32 paths are reused unchanged: cvt gets f16 as a source by falling through to the f32 case, and setp likewise. Destinations narrow with floatToHalf. The exact result of an f16 add or mul also fits in f32 (11 bit significands, so a product needs 22 of the 24 available), so computing in f32 and rounding once to f16 is correctly rounded, not double rounded. ex2 is .approx in PTX, so the f32 approximation is in spec. halfToFloat and floatToHalf were checked against numpy: all 65536 half bit patterns widen exactly, and 531082 narrowing cases including every exact tie midpoint round identically, ties to even. mad and min still reject f16 since they are not implemented for it. Measured on tinygrad's emulated CI, test/backend with DEV=MOCK+CUDA:PTX: sm_35 stays 1738 pass 0 fail 453 skip, identical to master. sm_53 goes from 109 errors to 1738 pass 0 fail 443 skip, the 10 freed skips being the fp16 tests that could never run before. --- .../src/executive/CooperativeThreadArray.cpp | 172 +++++++++++++++++- ocelot/src/ir/PTXInstruction.cpp | 26 +-- 2 files changed, 176 insertions(+), 22 deletions(-) diff --git a/ocelot/src/executive/CooperativeThreadArray.cpp b/ocelot/src/executive/CooperativeThreadArray.cpp index 81acd6dd..fd264bbb 100644 --- a/ocelot/src/executive/CooperativeThreadArray.cpp +++ b/ocelot/src/executive/CooperativeThreadArray.cpp @@ -859,6 +859,52 @@ ir::PTXS64 executive::CooperativeThreadArray::getRegAsS64(int threadID, \param threadID ID of the active thread \reg register index */ +/*! + PTX keeps .f16 values as an IEEE754 binary16 bit pattern in the low half of the + register slot. f32 represents every f16 exactly, so widening is lossless and a + cvt from f16 is exactly the cvt from the widened f32. +*/ +static ir::PTXF32 halfToFloat(ir::PTXU16 h) { + ir::PTXU32 sign = (ir::PTXU32)(h & 0x8000) << 16; + ir::PTXU32 exp = (h >> 10) & 0x1f, mant = h & 0x3ff, bits; + if (exp == 0) { + if (mant == 0) bits = sign; + else { + exp = 127 - 15 + 1; + while ((mant & 0x400) == 0) { mant <<= 1; --exp; } + bits = sign | (exp << 23) | ((mant & 0x3ff) << 13); + } + } + else if (exp == 0x1f) bits = sign | 0x7f800000 | (mant << 13); + else bits = sign | ((exp - 15 + 127) << 23) | (mant << 13); + return hydrazine::bit_cast(bits); +} + +/*! binary32 to binary16, round to nearest even, which is the PTX cvt.rn default. */ +static ir::PTXU16 floatToHalf(ir::PTXF32 f) { + ir::PTXU32 bits = hydrazine::bit_cast(f); + ir::PTXU16 sign = (ir::PTXU16)((bits >> 16) & 0x8000); + ir::PTXU32 rawexp = (bits >> 23) & 0xff, mant = bits & 0x7fffff; + if (rawexp == 0xff) { + return sign | 0x7c00 | (mant ? (ir::PTXU16)((mant >> 13) | 0x200) : 0); + } + int exp = (int)rawexp - 127 + 15; + if (exp >= 0x1f) return sign | 0x7c00; + if (exp <= 0) { + if (exp < -10) return sign; + mant |= 0x800000; + int shift = 14 - exp; + ir::PTXU32 h = mant >> shift; + ir::PTXU32 rem = mant & ((1u << shift) - 1), half = 1u << (shift - 1); + if (rem > half || (rem == half && (h & 1))) ++h; + return sign | (ir::PTXU16)h; + } + ir::PTXU16 h = (ir::PTXU16)((exp << 10) | (mant >> 13)); + ir::PTXU32 rem = mant & 0x1fff; + if (rem > 0x1000 || (rem == 0x1000 && (h & 1))) ++h; + return sign | h; +} + ir::PTXF32 executive::CooperativeThreadArray::getRegAsF32(int threadID, ir::PTXOperand::RegisterType reg) { ir::PTXF32 r = *( (ir::PTXF32*)( @@ -1500,6 +1546,9 @@ ir::PTXF32 executive::CooperativeThreadArray::operandAsF32(int threadID, const ir::PTXOperand &op) { switch (op.addressMode) { case ir::PTXOperand::Register: + if (op.type == ir::PTXOperand::f16) { + return halfToFloat(getRegAsB16(threadID, op.reg)); + } return getRegAsF32(threadID, op.reg); case ir::PTXOperand::Immediate: return (ir::PTXF32)(op.imm_single); @@ -1717,7 +1766,16 @@ void executive::CooperativeThreadArray::eval_Abs(CTAContext &context, void executive::CooperativeThreadArray::eval_Add(CTAContext &context, const ir::PTXInstruction &instr) { trace(); - if (instr.type == ir::PTXOperand::f32) { + if (instr.type == ir::PTXOperand::f16) { + for (int threadID = 0; threadID < threadCount; threadID++) { + if (!context.predicated(threadID, instr)) continue; + ir::PTXF32 a = operandAsF32(threadID, instr.a), + b = operandAsF32(threadID, instr.b); + setRegAsB16(threadID, instr.d.reg, + floatToHalf(sat(instr.modifier, a + b))); + } + } + else if (instr.type == ir::PTXOperand::f32) { for (int threadID = 0; threadID < threadCount; threadID++) { if (!context.predicated(threadID, instr)) continue; ir::PTXF32 d, a = ftz(instr.modifier, operandAsF32(threadID, instr.a)), @@ -3009,6 +3067,13 @@ void executive::CooperativeThreadArray::eval_Cvt(CTAContext &context, setRegAsS64(threadID, instr.d.reg, d); } break; + case ir::PTXOperand::f16: + { + setRegAsB16(threadID, instr.d.reg, + floatToHalf(toF32(operandAsB8(threadID, instr.a), + instr.modifier))); + } + break; case ir::PTXOperand::f32: { setRegAsF32(threadID, instr.d.reg, @@ -3059,6 +3124,13 @@ void executive::CooperativeThreadArray::eval_Cvt(CTAContext &context, setRegAsU64(threadID, instr.d.reg, a); } break; + case ir::PTXOperand::f16: + { + setRegAsB16(threadID, instr.d.reg, + floatToHalf(toF32(operandAsS8(threadID, instr.a), + instr.modifier))); + } + break; case ir::PTXOperand::f32: { setRegAsF32(threadID, instr.d.reg, @@ -3126,6 +3198,13 @@ void executive::CooperativeThreadArray::eval_Cvt(CTAContext &context, setRegAsS64(threadID, instr.d.reg, d); } break; + case ir::PTXOperand::f16: + { + setRegAsB16(threadID, instr.d.reg, + floatToHalf(toF32(operandAsB16(threadID, instr.a), + instr.modifier))); + } + break; case ir::PTXOperand::f32: { setRegAsF32(threadID, instr.d.reg, @@ -3192,6 +3271,13 @@ void executive::CooperativeThreadArray::eval_Cvt(CTAContext &context, setRegAsU64(threadID, instr.d.reg, a); } break; + case ir::PTXOperand::f16: + { + setRegAsB16(threadID, instr.d.reg, + floatToHalf(toF32(operandAsS16(threadID, instr.a), + instr.modifier))); + } + break; case ir::PTXOperand::f32: { setRegAsF32(threadID, instr.d.reg, @@ -3274,6 +3360,13 @@ void executive::CooperativeThreadArray::eval_Cvt(CTAContext &context, setRegAsS64(threadID, instr.d.reg, d); } break; + case ir::PTXOperand::f16: + { + setRegAsB16(threadID, instr.d.reg, + floatToHalf(toF32(operandAsU32(threadID, instr.a), + instr.modifier))); + } + break; case ir::PTXOperand::f32: { setRegAsF32(threadID, instr.d.reg, @@ -3354,6 +3447,13 @@ void executive::CooperativeThreadArray::eval_Cvt(CTAContext &context, setRegAsS64(threadID, instr.d.reg, a); } break; + case ir::PTXOperand::f16: + { + setRegAsB16(threadID, instr.d.reg, + floatToHalf(toF32(operandAsS32(threadID, instr.a), + instr.modifier))); + } + break; case ir::PTXOperand::f32: { setRegAsF32(threadID, instr.d.reg, @@ -3449,6 +3549,13 @@ void executive::CooperativeThreadArray::eval_Cvt(CTAContext &context, setRegAsS64(threadID, instr.d.reg, a); } break; + case ir::PTXOperand::f16: + { + setRegAsB16(threadID, instr.d.reg, + floatToHalf(toF32(operandAsS64(threadID, instr.a), + instr.modifier))); + } + break; case ir::PTXOperand::f32: { setRegAsF32(threadID, instr.d.reg, @@ -3546,6 +3653,13 @@ void executive::CooperativeThreadArray::eval_Cvt(CTAContext &context, setRegAsS64(threadID, instr.d.reg, d); } break; + case ir::PTXOperand::f16: + { + setRegAsB16(threadID, instr.d.reg, + floatToHalf(toF32(operandAsU64(threadID, instr.a), + instr.modifier))); + } + break; case ir::PTXOperand::f32: { setRegAsF32(threadID, instr.d.reg, @@ -3567,6 +3681,7 @@ void executive::CooperativeThreadArray::eval_Cvt(CTAContext &context, } } break; + case ir::PTXOperand::f16: // fall through, widened by operandAsF32 case ir::PTXOperand::f32: { switch (instr.type) { @@ -3727,6 +3842,17 @@ void executive::CooperativeThreadArray::eval_Cvt(CTAContext &context, setRegAsS64(threadID, instr.d.reg, d); } break; + case ir::PTXOperand::f16: + { + ir::PTXF32 a = operandAsF32(threadID, instr.a); + + a = roundToInt(a, instr.modifier, context, + instr); + + setRegAsB16(threadID, instr.d.reg, + floatToHalf(sat(instr.modifier, a))); + } + break; case ir::PTXOperand::f32: { ir::PTXF32 a = operandAsF32(threadID, instr.a); @@ -3914,6 +4040,13 @@ void executive::CooperativeThreadArray::eval_Cvt(CTAContext &context, setRegAsS64(threadID, instr.d.reg, d); } break; + case ir::PTXOperand::f16: + { + ir::PTXF64 a = operandAsF64(threadID, instr.a); + setRegAsB16(threadID, instr.d.reg, + floatToHalf(toF32(a, instr.modifier))); + } + break; case ir::PTXOperand::f32: { ir::PTXF64 a = operandAsF64(threadID, instr.a); @@ -4373,7 +4506,15 @@ void executive::CooperativeThreadArray::eval_Div(CTAContext &context, void executive::CooperativeThreadArray::eval_Ex2(CTAContext &context, const ir::PTXInstruction &instr) { trace(); - if (instr.type == ir::PTXOperand::f32) { + if (instr.type == ir::PTXOperand::f16) { + for (int threadID = 0; threadID < threadCount; threadID++) { + if (!context.predicated(threadID, instr)) continue; + ir::PTXF32 a = operandAsF32(threadID, instr.a); + setRegAsB16(threadID, instr.d.reg, + floatToHalf(hydrazine::exp2f(a))); + } + } + else if (instr.type == ir::PTXOperand::f32) { for (int threadID = 0; threadID < threadCount; threadID++) { if (!context.predicated(threadID, instr)) continue; @@ -5316,7 +5457,19 @@ void executive::CooperativeThreadArray::eval_Mad(CTAContext &context, void executive::CooperativeThreadArray::eval_Max(CTAContext &context, const ir::PTXInstruction &instr) { trace(); - if (instr.type == ir::PTXOperand::f32) { + if (instr.type == ir::PTXOperand::f16) { + for (int threadID = 0; threadID < threadCount; threadID++) { + if (!context.predicated(threadID, instr)) continue; + ir::PTXF32 a = operandAsF32(threadID, instr.a), + b = operandAsF32(threadID, instr.b); + ir::PTXF32 d; + if (hydrazine::isnan(a)) d = b; + else if (hydrazine::isnan(b)) d = a; + else d = (a > b) ? a : b; + setRegAsB16(threadID, instr.d.reg, floatToHalf(d)); + } + } + else if (instr.type == ir::PTXOperand::f32) { for (int threadID = 0; threadID < threadCount; threadID++) { if (!context.predicated(threadID, instr)) continue; @@ -5808,6 +5961,7 @@ void executive::CooperativeThreadArray::eval_Mov_imm(CTAContext &context, case ir::PTXOperand::u16: case ir::PTXOperand::s16: case ir::PTXOperand::b16: + case ir::PTXOperand::f16: // PTX materializes a half constant as mov.b16 into an .f16 reg { ir::PTXU16 a = operandAsU16(threadID, instr.a); setRegAsU16(threadID, instr.d.reg, a); @@ -5950,7 +6104,16 @@ void executive::CooperativeThreadArray::eval_Mul24(CTAContext &context, const ir */ void executive::CooperativeThreadArray::eval_Mul(CTAContext &context, const ir::PTXInstruction &instr) { trace(); - if (instr.type == ir::PTXOperand::f32) { + if (instr.type == ir::PTXOperand::f16) { + for (int threadID = 0; threadID < threadCount; threadID++) { + if (!context.predicated(threadID, instr)) continue; + ir::PTXF32 a = operandAsF32(threadID, instr.a), + b = operandAsF32(threadID, instr.b); + setRegAsB16(threadID, instr.d.reg, + floatToHalf(sat(instr.modifier, a * b))); + } + } + else if (instr.type == ir::PTXOperand::f32) { for (int threadID = 0; threadID < threadCount; threadID++) { if (!context.predicated(threadID, instr)) continue; @@ -7132,6 +7295,7 @@ void executive::CooperativeThreadArray::eval_SetP(CTAContext &context, } break; + case ir::PTXOperand::f16: // fall through, widened by operandAsF32 // single-precision float case ir::PTXOperand::f32: { diff --git a/ocelot/src/ir/PTXInstruction.cpp b/ocelot/src/ir/PTXInstruction.cpp index c42c7506..018f3fcc 100644 --- a/ocelot/src/ir/PTXInstruction.cpp +++ b/ocelot/src/ir/PTXInstruction.cpp @@ -504,8 +504,7 @@ std::string ir::PTXInstruction::valid() const { } case Add: { if ( !( type != PTXOperand::s8 && type != PTXOperand::u8 && - type != PTXOperand::b8 && type != PTXOperand::f16 - && type != PTXOperand::pred ) ) { + type != PTXOperand::b8 && type != PTXOperand::pred ) ) { return "invalid instruction type " + PTXOperand::toString( type ); } @@ -923,7 +922,7 @@ std::string ir::PTXInstruction::valid() const { break; } case Ex2: { - if( !( type == PTXOperand::f32 ) ) { + if( !( type == PTXOperand::f32 || type == PTXOperand::f16 ) ) { return "invalid instruction type " + PTXOperand::toString( type ); } @@ -1124,8 +1123,7 @@ std::string ir::PTXInstruction::valid() const { } case Max: { if( !( type != PTXOperand::s8 && type != PTXOperand::u8 && - type != PTXOperand::b8 && type != PTXOperand::f16 - && type != PTXOperand::pred ) ) { + type != PTXOperand::b8 && type != PTXOperand::pred ) ) { return "invalid instruction type " + PTXOperand::toString( type ); } @@ -1180,14 +1178,8 @@ std::string ir::PTXInstruction::valid() const { break; } case Mov: { - if ( ( a.type == PTXOperand::f16 ) && - a.addressMode != PTXOperand::Address && - a.addressMode != PTXOperand::Immediate ) { - return "invalid type for operand A " - + PTXOperand::toString( a.type ); - } if ( !( d.type != PTXOperand::s8 && d.type != PTXOperand::u8 - && d.type != PTXOperand::b8 && d.type != PTXOperand::f16 ) ) { + && d.type != PTXOperand::b8 ) ) { return "invalid type for operand D " + PTXOperand::toString( d.type ); } @@ -1224,8 +1216,7 @@ std::string ir::PTXInstruction::valid() const { } case Mul: { if( type == PTXOperand::s8 || type == PTXOperand::u8 - || type == PTXOperand::b8 || type == PTXOperand::f16 - || type == PTXOperand::pred ) { + || type == PTXOperand::b8 || type == PTXOperand::pred ) { return "invalid instruction type " + PTXOperand::toString( type ); } @@ -1616,8 +1607,8 @@ std::string ir::PTXInstruction::valid() const { && type != PTXOperand::s64 && type != PTXOperand::u16 && type != PTXOperand::u32 && type != PTXOperand::u64 && type != PTXOperand::b16 && type != PTXOperand::b32 - && type != PTXOperand::b64 && type != PTXOperand::f32 - && type != PTXOperand::f64 ) { + && type != PTXOperand::b64 && type != PTXOperand::f16 + && type != PTXOperand::f32 && type != PTXOperand::f64 ) { return "invalid instruction type " + PTXOperand::toString( type ); } @@ -1864,8 +1855,7 @@ std::string ir::PTXInstruction::valid() const { } case Sub: { if ( !( type != PTXOperand::s8 && type != PTXOperand::u8 && - type != PTXOperand::b8 && type != PTXOperand::f16 - && type != PTXOperand::pred ) ) { + type != PTXOperand::b8 && type != PTXOperand::pred ) ) { return "invalid instruction type " + PTXOperand::toString( type ); }