| 228 | } |
| 229 | |
| 230 | uint32_t GcnCompiler::emitControlFlowDivergence() |
| 231 | { |
| 232 | uint32_t result = 0; |
| 233 | |
| 234 | const uint32_t utypeId = getScalarTypeId(GcnScalarType::Uint32); |
| 235 | const uint32_t btypeId = m_module.defBoolType(); |
| 236 | // We cheat the shader as if the CU only provide one single thread, |
| 237 | // so we only set EXEC bit against invocation id. |
| 238 | if (m_moduleInfo.options.separateSubgroup) |
| 239 | { |
| 240 | auto mask = emitCommonSystemValueLoad( |
| 241 | GcnSystemValue::SubgroupEqMask, GcnRegMask::select(0)); |
| 242 | // For non-compute shader, we only use low 32 bits of exec. |
| 243 | auto exec = m_state.exec.emitLoad(GcnRegMask::select(0)); |
| 244 | auto value = m_module.opBitwiseAnd(utypeId, exec.low.id, mask.id); |
| 245 | result = m_module.opINotEqual(btypeId, value, m_module.constu32(0)); |
| 246 | } |
| 247 | else |
| 248 | { |
| 249 | auto mask = emitCommonSystemValueLoad( |
| 250 | GcnSystemValue::SubgroupEqMask, GcnRegMask::firstN(2)); |
| 251 | |
| 252 | auto exec = m_state.exec.emitLoad(GcnRegMask::firstN(2)); |
| 253 | |
| 254 | auto maskX = emitRegisterExtract(mask, GcnRegMask::select(0)); |
| 255 | auto maskY = emitRegisterExtract(mask, GcnRegMask::select(1)); |
| 256 | auto valueX = m_module.opBitwiseAnd(utypeId, exec.low.id, maskX.id); |
| 257 | auto valueY = m_module.opBitwiseAnd(utypeId, exec.high.id, maskY.id); |
| 258 | auto resultX = m_module.opINotEqual(btypeId, valueX, m_module.constu32(0)); |
| 259 | auto resultY = m_module.opINotEqual(btypeId, valueY, m_module.constu32(0)); |
| 260 | result = m_module.opLogicalOr(btypeId, resultX, resultY); |
| 261 | } |
| 262 | return result; |
| 263 | } |
| 264 | |
| 265 | uint32_t GcnCompiler::emitControlFlowCondition(const GcnTokenCondition& condition) |
| 266 | { |
nothing calls this directly
no test coverage detected