diff options
Diffstat (limited to 'src/shader_recompiler/frontend')
7 files changed, 706 insertions, 13 deletions
diff --git a/src/shader_recompiler/frontend/ir/ir_emitter.cpp b/src/shader_recompiler/frontend/ir/ir_emitter.cpp index 17be0c639..a3339f624 100644 --- a/src/shader_recompiler/frontend/ir/ir_emitter.cpp +++ b/src/shader_recompiler/frontend/ir/ir_emitter.cpp | |||
| @@ -1284,6 +1284,204 @@ U1 IREmitter::IGreaterThanEqual(const U32& lhs, const U32& rhs, bool is_signed) | |||
| 1284 | return Inst<U1>(is_signed ? Opcode::SGreaterThanEqual : Opcode::UGreaterThanEqual, lhs, rhs); | 1284 | return Inst<U1>(is_signed ? Opcode::SGreaterThanEqual : Opcode::UGreaterThanEqual, lhs, rhs); |
| 1285 | } | 1285 | } |
| 1286 | 1286 | ||
| 1287 | U32 IREmitter::SharedAtomicIAdd(const U32& pointer_offset, const U32& value) { | ||
| 1288 | return Inst<U32>(Opcode::SharedAtomicIAdd32, pointer_offset, value); | ||
| 1289 | } | ||
| 1290 | |||
| 1291 | U32 IREmitter::SharedAtomicSMin(const U32& pointer_offset, const U32& value) { | ||
| 1292 | return Inst<U32>(Opcode::SharedAtomicSMin32, pointer_offset, value); | ||
| 1293 | } | ||
| 1294 | |||
| 1295 | U32 IREmitter::SharedAtomicUMin(const U32& pointer_offset, const U32& value) { | ||
| 1296 | return Inst<U32>(Opcode::SharedAtomicUMin32, pointer_offset, value); | ||
| 1297 | } | ||
| 1298 | |||
| 1299 | U32 IREmitter::SharedAtomicIMin(const U32& pointer_offset, const U32& value, bool is_signed) { | ||
| 1300 | return is_signed ? SharedAtomicSMin(pointer_offset, value) | ||
| 1301 | : SharedAtomicUMin(pointer_offset, value); | ||
| 1302 | } | ||
| 1303 | |||
| 1304 | U32 IREmitter::SharedAtomicSMax(const U32& pointer_offset, const U32& value) { | ||
| 1305 | return Inst<U32>(Opcode::SharedAtomicSMax32, pointer_offset, value); | ||
| 1306 | } | ||
| 1307 | |||
| 1308 | U32 IREmitter::SharedAtomicUMax(const U32& pointer_offset, const U32& value) { | ||
| 1309 | return Inst<U32>(Opcode::SharedAtomicUMax32, pointer_offset, value); | ||
| 1310 | } | ||
| 1311 | |||
| 1312 | U32 IREmitter::SharedAtomicIMax(const U32& pointer_offset, const U32& value, bool is_signed) { | ||
| 1313 | return is_signed ? SharedAtomicSMax(pointer_offset, value) | ||
| 1314 | : SharedAtomicUMax(pointer_offset, value); | ||
| 1315 | } | ||
| 1316 | |||
| 1317 | U32 IREmitter::SharedAtomicInc(const U32& pointer_offset, const U32& value) { | ||
| 1318 | return Inst<U32>(Opcode::SharedAtomicInc32, pointer_offset, value); | ||
| 1319 | } | ||
| 1320 | |||
| 1321 | U32 IREmitter::SharedAtomicDec(const U32& pointer_offset, const U32& value) { | ||
| 1322 | return Inst<U32>(Opcode::SharedAtomicDec32, pointer_offset, value); | ||
| 1323 | } | ||
| 1324 | |||
| 1325 | U32 IREmitter::SharedAtomicAnd(const U32& pointer_offset, const U32& value) { | ||
| 1326 | return Inst<U32>(Opcode::SharedAtomicAnd32, pointer_offset, value); | ||
| 1327 | } | ||
| 1328 | |||
| 1329 | U32 IREmitter::SharedAtomicOr(const U32& pointer_offset, const U32& value) { | ||
| 1330 | return Inst<U32>(Opcode::SharedAtomicOr32, pointer_offset, value); | ||
| 1331 | } | ||
| 1332 | |||
| 1333 | U32 IREmitter::SharedAtomicXor(const U32& pointer_offset, const U32& value) { | ||
| 1334 | return Inst<U32>(Opcode::SharedAtomicXor32, pointer_offset, value); | ||
| 1335 | } | ||
| 1336 | |||
| 1337 | U32U64 IREmitter::SharedAtomicExchange(const U32& pointer_offset, const U32U64& value) { | ||
| 1338 | switch (value.Type()) { | ||
| 1339 | case Type::U32: | ||
| 1340 | return Inst<U32>(Opcode::SharedAtomicExchange32, pointer_offset, value); | ||
| 1341 | case Type::U64: | ||
| 1342 | return Inst<U64>(Opcode::SharedAtomicExchange64, pointer_offset, value); | ||
| 1343 | default: | ||
| 1344 | ThrowInvalidType(pointer_offset.Type()); | ||
| 1345 | } | ||
| 1346 | } | ||
| 1347 | |||
| 1348 | U32U64 IREmitter::GlobalAtomicIAdd(const U64& pointer_offset, const U32U64& value) { | ||
| 1349 | switch (value.Type()) { | ||
| 1350 | case Type::U32: | ||
| 1351 | return Inst<U32>(Opcode::GlobalAtomicIAdd32, pointer_offset, value); | ||
| 1352 | case Type::U64: | ||
| 1353 | return Inst<U64>(Opcode::GlobalAtomicIAdd64, pointer_offset, value); | ||
| 1354 | default: | ||
| 1355 | ThrowInvalidType(value.Type()); | ||
| 1356 | } | ||
| 1357 | } | ||
| 1358 | |||
| 1359 | U32U64 IREmitter::GlobalAtomicSMin(const U64& pointer_offset, const U32U64& value) { | ||
| 1360 | switch (value.Type()) { | ||
| 1361 | case Type::U32: | ||
| 1362 | return Inst<U32>(Opcode::GlobalAtomicSMin32, pointer_offset, value); | ||
| 1363 | case Type::U64: | ||
| 1364 | return Inst<U64>(Opcode::GlobalAtomicSMin64, pointer_offset, value); | ||
| 1365 | default: | ||
| 1366 | ThrowInvalidType(value.Type()); | ||
| 1367 | } | ||
| 1368 | } | ||
| 1369 | |||
| 1370 | U32U64 IREmitter::GlobalAtomicUMin(const U64& pointer_offset, const U32U64& value) { | ||
| 1371 | switch (value.Type()) { | ||
| 1372 | case Type::U32: | ||
| 1373 | return Inst<U32>(Opcode::GlobalAtomicUMin32, pointer_offset, value); | ||
| 1374 | case Type::U64: | ||
| 1375 | return Inst<U64>(Opcode::GlobalAtomicUMin64, pointer_offset, value); | ||
| 1376 | default: | ||
| 1377 | ThrowInvalidType(value.Type()); | ||
| 1378 | } | ||
| 1379 | } | ||
| 1380 | |||
| 1381 | U32U64 IREmitter::GlobalAtomicIMin(const U64& pointer_offset, const U32U64& value, bool is_signed) { | ||
| 1382 | return is_signed ? GlobalAtomicSMin(pointer_offset, value) | ||
| 1383 | : GlobalAtomicUMin(pointer_offset, value); | ||
| 1384 | } | ||
| 1385 | |||
| 1386 | U32U64 IREmitter::GlobalAtomicSMax(const U64& pointer_offset, const U32U64& value) { | ||
| 1387 | switch (value.Type()) { | ||
| 1388 | case Type::U32: | ||
| 1389 | return Inst<U32>(Opcode::GlobalAtomicSMax32, pointer_offset, value); | ||
| 1390 | case Type::U64: | ||
| 1391 | return Inst<U64>(Opcode::GlobalAtomicSMax64, pointer_offset, value); | ||
| 1392 | default: | ||
| 1393 | ThrowInvalidType(value.Type()); | ||
| 1394 | } | ||
| 1395 | } | ||
| 1396 | |||
| 1397 | U32U64 IREmitter::GlobalAtomicUMax(const U64& pointer_offset, const U32U64& value) { | ||
| 1398 | switch (value.Type()) { | ||
| 1399 | case Type::U32: | ||
| 1400 | return Inst<U32>(Opcode::GlobalAtomicUMax32, pointer_offset, value); | ||
| 1401 | case Type::U64: | ||
| 1402 | return Inst<U64>(Opcode::GlobalAtomicUMax64, pointer_offset, value); | ||
| 1403 | default: | ||
| 1404 | ThrowInvalidType(value.Type()); | ||
| 1405 | } | ||
| 1406 | } | ||
| 1407 | |||
| 1408 | U32U64 IREmitter::GlobalAtomicIMax(const U64& pointer_offset, const U32U64& value, bool is_signed) { | ||
| 1409 | return is_signed ? GlobalAtomicSMax(pointer_offset, value) | ||
| 1410 | : GlobalAtomicUMax(pointer_offset, value); | ||
| 1411 | } | ||
| 1412 | |||
| 1413 | U32 IREmitter::GlobalAtomicInc(const U64& pointer_offset, const U32& value) { | ||
| 1414 | return Inst<U32>(Opcode::GlobalAtomicInc32, pointer_offset, value); | ||
| 1415 | } | ||
| 1416 | |||
| 1417 | U32 IREmitter::GlobalAtomicDec(const U64& pointer_offset, const U32& value) { | ||
| 1418 | return Inst<U32>(Opcode::GlobalAtomicDec32, pointer_offset, value); | ||
| 1419 | } | ||
| 1420 | |||
| 1421 | U32U64 IREmitter::GlobalAtomicAnd(const U64& pointer_offset, const U32U64& value) { | ||
| 1422 | switch (value.Type()) { | ||
| 1423 | case Type::U32: | ||
| 1424 | return Inst<U32>(Opcode::GlobalAtomicAnd32, pointer_offset, value); | ||
| 1425 | case Type::U64: | ||
| 1426 | return Inst<U64>(Opcode::GlobalAtomicAnd64, pointer_offset, value); | ||
| 1427 | default: | ||
| 1428 | ThrowInvalidType(value.Type()); | ||
| 1429 | } | ||
| 1430 | } | ||
| 1431 | |||
| 1432 | U32U64 IREmitter::GlobalAtomicOr(const U64& pointer_offset, const U32U64& value) { | ||
| 1433 | switch (value.Type()) { | ||
| 1434 | case Type::U32: | ||
| 1435 | return Inst<U32>(Opcode::GlobalAtomicOr32, pointer_offset, value); | ||
| 1436 | case Type::U64: | ||
| 1437 | return Inst<U64>(Opcode::GlobalAtomicOr64, pointer_offset, value); | ||
| 1438 | default: | ||
| 1439 | ThrowInvalidType(value.Type()); | ||
| 1440 | } | ||
| 1441 | } | ||
| 1442 | |||
| 1443 | U32U64 IREmitter::GlobalAtomicXor(const U64& pointer_offset, const U32U64& value) { | ||
| 1444 | switch (value.Type()) { | ||
| 1445 | case Type::U32: | ||
| 1446 | return Inst<U32>(Opcode::GlobalAtomicXor32, pointer_offset, value); | ||
| 1447 | case Type::U64: | ||
| 1448 | return Inst<U64>(Opcode::GlobalAtomicXor64, pointer_offset, value); | ||
| 1449 | default: | ||
| 1450 | ThrowInvalidType(value.Type()); | ||
| 1451 | } | ||
| 1452 | } | ||
| 1453 | |||
| 1454 | U32U64 IREmitter::GlobalAtomicExchange(const U64& pointer_offset, const U32U64& value) { | ||
| 1455 | switch (value.Type()) { | ||
| 1456 | case Type::U32: | ||
| 1457 | return Inst<U32>(Opcode::GlobalAtomicExchange32, pointer_offset, value); | ||
| 1458 | case Type::U64: | ||
| 1459 | return Inst<U64>(Opcode::GlobalAtomicExchange64, pointer_offset, value); | ||
| 1460 | default: | ||
| 1461 | ThrowInvalidType(pointer_offset.Type()); | ||
| 1462 | } | ||
| 1463 | } | ||
| 1464 | |||
| 1465 | F32 IREmitter::GlobalAtomicF32Add(const U64& pointer_offset, const Value& value, | ||
| 1466 | const FpControl control) { | ||
| 1467 | return Inst<F32>(Opcode::GlobalAtomicAddF32, Flags{control}, pointer_offset, value); | ||
| 1468 | } | ||
| 1469 | |||
| 1470 | Value IREmitter::GlobalAtomicF16x2Add(const U64& pointer_offset, const Value& value, | ||
| 1471 | const FpControl control) { | ||
| 1472 | return Inst(Opcode::GlobalAtomicAddF16x2, Flags{control}, pointer_offset, value); | ||
| 1473 | } | ||
| 1474 | |||
| 1475 | Value IREmitter::GlobalAtomicF16x2Min(const U64& pointer_offset, const Value& value, | ||
| 1476 | const FpControl control) { | ||
| 1477 | return Inst(Opcode::GlobalAtomicMinF16x2, Flags{control}, pointer_offset, value); | ||
| 1478 | } | ||
| 1479 | |||
| 1480 | Value IREmitter::GlobalAtomicF16x2Max(const U64& pointer_offset, const Value& value, | ||
| 1481 | const FpControl control) { | ||
| 1482 | return Inst(Opcode::GlobalAtomicMaxF16x2, Flags{control}, pointer_offset, value); | ||
| 1483 | } | ||
| 1484 | |||
| 1287 | U1 IREmitter::LogicalOr(const U1& a, const U1& b) { | 1485 | U1 IREmitter::LogicalOr(const U1& a, const U1& b) { |
| 1288 | return Inst<U1>(Opcode::LogicalOr, a, b); | 1486 | return Inst<U1>(Opcode::LogicalOr, a, b); |
| 1289 | } | 1487 | } |
| @@ -1626,7 +1824,7 @@ Value IREmitter::ImageRead(const Value& handle, const Value& coords, TextureInst | |||
| 1626 | } | 1824 | } |
| 1627 | 1825 | ||
| 1628 | void IREmitter::ImageWrite(const Value& handle, const Value& coords, const Value& color, | 1826 | void IREmitter::ImageWrite(const Value& handle, const Value& coords, const Value& color, |
| 1629 | TextureInstInfo info) { | 1827 | TextureInstInfo info) { |
| 1630 | const Opcode op{handle.IsImmediate() ? Opcode::BoundImageWrite : Opcode::BindlessImageWrite}; | 1828 | const Opcode op{handle.IsImmediate() ? Opcode::BoundImageWrite : Opcode::BindlessImageWrite}; |
| 1631 | Inst(op, Flags{info}, handle, coords, color); | 1829 | Inst(op, Flags{info}, handle, coords, color); |
| 1632 | } | 1830 | } |
diff --git a/src/shader_recompiler/frontend/ir/ir_emitter.h b/src/shader_recompiler/frontend/ir/ir_emitter.h index ec60070ef..f9cbf1304 100644 --- a/src/shader_recompiler/frontend/ir/ir_emitter.h +++ b/src/shader_recompiler/frontend/ir/ir_emitter.h | |||
| @@ -228,6 +228,45 @@ public: | |||
| 228 | [[nodiscard]] U1 INotEqual(const U32& lhs, const U32& rhs); | 228 | [[nodiscard]] U1 INotEqual(const U32& lhs, const U32& rhs); |
| 229 | [[nodiscard]] U1 IGreaterThanEqual(const U32& lhs, const U32& rhs, bool is_signed); | 229 | [[nodiscard]] U1 IGreaterThanEqual(const U32& lhs, const U32& rhs, bool is_signed); |
| 230 | 230 | ||
| 231 | [[nodiscard]] U32 SharedAtomicIAdd(const U32& pointer_offset, const U32& value); | ||
| 232 | [[nodiscard]] U32 SharedAtomicSMin(const U32& pointer_offset, const U32& value); | ||
| 233 | [[nodiscard]] U32 SharedAtomicUMin(const U32& pointer_offset, const U32& value); | ||
| 234 | [[nodiscard]] U32 SharedAtomicIMin(const U32& pointer_offset, const U32& value, bool is_signed); | ||
| 235 | [[nodiscard]] U32 SharedAtomicSMax(const U32& pointer_offset, const U32& value); | ||
| 236 | [[nodiscard]] U32 SharedAtomicUMax(const U32& pointer_offset, const U32& value); | ||
| 237 | [[nodiscard]] U32 SharedAtomicIMax(const U32& pointer_offset, const U32& value, bool is_signed); | ||
| 238 | [[nodiscard]] U32 SharedAtomicInc(const U32& pointer_offset, const U32& value); | ||
| 239 | [[nodiscard]] U32 SharedAtomicDec(const U32& pointer_offset, const U32& value); | ||
| 240 | [[nodiscard]] U32 SharedAtomicAnd(const U32& pointer_offset, const U32& value); | ||
| 241 | [[nodiscard]] U32 SharedAtomicOr(const U32& pointer_offset, const U32& value); | ||
| 242 | [[nodiscard]] U32 SharedAtomicXor(const U32& pointer_offset, const U32& value); | ||
| 243 | [[nodiscard]] U32U64 SharedAtomicExchange(const U32& pointer_offset, const U32U64& value); | ||
| 244 | |||
| 245 | [[nodiscard]] U32U64 GlobalAtomicIAdd(const U64& pointer_offset, const U32U64& value); | ||
| 246 | [[nodiscard]] U32U64 GlobalAtomicSMin(const U64& pointer_offset, const U32U64& value); | ||
| 247 | [[nodiscard]] U32U64 GlobalAtomicUMin(const U64& pointer_offset, const U32U64& value); | ||
| 248 | [[nodiscard]] U32U64 GlobalAtomicIMin(const U64& pointer_offset, const U32U64& value, | ||
| 249 | bool is_signed); | ||
| 250 | [[nodiscard]] U32U64 GlobalAtomicSMax(const U64& pointer_offset, const U32U64& value); | ||
| 251 | [[nodiscard]] U32U64 GlobalAtomicUMax(const U64& pointer_offset, const U32U64& value); | ||
| 252 | [[nodiscard]] U32U64 GlobalAtomicIMax(const U64& pointer_offset, const U32U64& value, | ||
| 253 | bool is_signed); | ||
| 254 | [[nodiscard]] U32 GlobalAtomicInc(const U64& pointer_offset, const U32& value); | ||
| 255 | [[nodiscard]] U32 GlobalAtomicDec(const U64& pointer_offset, const U32& value); | ||
| 256 | [[nodiscard]] U32U64 GlobalAtomicAnd(const U64& pointer_offset, const U32U64& value); | ||
| 257 | [[nodiscard]] U32U64 GlobalAtomicOr(const U64& pointer_offset, const U32U64& value); | ||
| 258 | [[nodiscard]] U32U64 GlobalAtomicXor(const U64& pointer_offset, const U32U64& value); | ||
| 259 | [[nodiscard]] U32U64 GlobalAtomicExchange(const U64& pointer_offset, const U32U64& value); | ||
| 260 | |||
| 261 | [[nodiscard]] F32 GlobalAtomicF32Add(const U64& pointer_offset, const Value& value, | ||
| 262 | const FpControl control = {}); | ||
| 263 | [[nodiscard]] Value GlobalAtomicF16x2Add(const U64& pointer_offset, const Value& value, | ||
| 264 | const FpControl control = {}); | ||
| 265 | [[nodiscard]] Value GlobalAtomicF16x2Min(const U64& pointer_offset, const Value& value, | ||
| 266 | const FpControl control = {}); | ||
| 267 | [[nodiscard]] Value GlobalAtomicF16x2Max(const U64& pointer_offset, const Value& value, | ||
| 268 | const FpControl control = {}); | ||
| 269 | |||
| 231 | [[nodiscard]] U1 LogicalOr(const U1& a, const U1& b); | 270 | [[nodiscard]] U1 LogicalOr(const U1& a, const U1& b); |
| 232 | [[nodiscard]] U1 LogicalAnd(const U1& a, const U1& b); | 271 | [[nodiscard]] U1 LogicalAnd(const U1& a, const U1& b); |
| 233 | [[nodiscard]] U1 LogicalXor(const U1& a, const U1& b); | 272 | [[nodiscard]] U1 LogicalXor(const U1& a, const U1& b); |
diff --git a/src/shader_recompiler/frontend/ir/microinstruction.cpp b/src/shader_recompiler/frontend/ir/microinstruction.cpp index 2df631791..0f66c5627 100644 --- a/src/shader_recompiler/frontend/ir/microinstruction.cpp +++ b/src/shader_recompiler/frontend/ir/microinstruction.cpp | |||
| @@ -93,6 +93,72 @@ bool Inst::MayHaveSideEffects() const noexcept { | |||
| 93 | case Opcode::WriteSharedU32: | 93 | case Opcode::WriteSharedU32: |
| 94 | case Opcode::WriteSharedU64: | 94 | case Opcode::WriteSharedU64: |
| 95 | case Opcode::WriteSharedU128: | 95 | case Opcode::WriteSharedU128: |
| 96 | case Opcode::SharedAtomicIAdd32: | ||
| 97 | case Opcode::SharedAtomicSMin32: | ||
| 98 | case Opcode::SharedAtomicUMin32: | ||
| 99 | case Opcode::SharedAtomicSMax32: | ||
| 100 | case Opcode::SharedAtomicUMax32: | ||
| 101 | case Opcode::SharedAtomicInc32: | ||
| 102 | case Opcode::SharedAtomicDec32: | ||
| 103 | case Opcode::SharedAtomicAnd32: | ||
| 104 | case Opcode::SharedAtomicOr32: | ||
| 105 | case Opcode::SharedAtomicXor32: | ||
| 106 | case Opcode::SharedAtomicExchange32: | ||
| 107 | case Opcode::SharedAtomicExchange64: | ||
| 108 | case Opcode::GlobalAtomicIAdd32: | ||
| 109 | case Opcode::GlobalAtomicSMin32: | ||
| 110 | case Opcode::GlobalAtomicUMin32: | ||
| 111 | case Opcode::GlobalAtomicSMax32: | ||
| 112 | case Opcode::GlobalAtomicUMax32: | ||
| 113 | case Opcode::GlobalAtomicInc32: | ||
| 114 | case Opcode::GlobalAtomicDec32: | ||
| 115 | case Opcode::GlobalAtomicAnd32: | ||
| 116 | case Opcode::GlobalAtomicOr32: | ||
| 117 | case Opcode::GlobalAtomicXor32: | ||
| 118 | case Opcode::GlobalAtomicExchange32: | ||
| 119 | case Opcode::GlobalAtomicIAdd64: | ||
| 120 | case Opcode::GlobalAtomicSMin64: | ||
| 121 | case Opcode::GlobalAtomicUMin64: | ||
| 122 | case Opcode::GlobalAtomicSMax64: | ||
| 123 | case Opcode::GlobalAtomicUMax64: | ||
| 124 | case Opcode::GlobalAtomicAnd64: | ||
| 125 | case Opcode::GlobalAtomicOr64: | ||
| 126 | case Opcode::GlobalAtomicXor64: | ||
| 127 | case Opcode::GlobalAtomicExchange64: | ||
| 128 | case Opcode::GlobalAtomicAddF32: | ||
| 129 | case Opcode::GlobalAtomicAddF16x2: | ||
| 130 | case Opcode::GlobalAtomicAddF32x2: | ||
| 131 | case Opcode::GlobalAtomicMinF16x2: | ||
| 132 | case Opcode::GlobalAtomicMinF32x2: | ||
| 133 | case Opcode::GlobalAtomicMaxF16x2: | ||
| 134 | case Opcode::GlobalAtomicMaxF32x2: | ||
| 135 | case Opcode::StorageAtomicIAdd32: | ||
| 136 | case Opcode::StorageAtomicSMin32: | ||
| 137 | case Opcode::StorageAtomicUMin32: | ||
| 138 | case Opcode::StorageAtomicSMax32: | ||
| 139 | case Opcode::StorageAtomicUMax32: | ||
| 140 | case Opcode::StorageAtomicInc32: | ||
| 141 | case Opcode::StorageAtomicDec32: | ||
| 142 | case Opcode::StorageAtomicAnd32: | ||
| 143 | case Opcode::StorageAtomicOr32: | ||
| 144 | case Opcode::StorageAtomicXor32: | ||
| 145 | case Opcode::StorageAtomicExchange32: | ||
| 146 | case Opcode::StorageAtomicIAdd64: | ||
| 147 | case Opcode::StorageAtomicSMin64: | ||
| 148 | case Opcode::StorageAtomicUMin64: | ||
| 149 | case Opcode::StorageAtomicSMax64: | ||
| 150 | case Opcode::StorageAtomicUMax64: | ||
| 151 | case Opcode::StorageAtomicAnd64: | ||
| 152 | case Opcode::StorageAtomicOr64: | ||
| 153 | case Opcode::StorageAtomicXor64: | ||
| 154 | case Opcode::StorageAtomicExchange64: | ||
| 155 | case Opcode::StorageAtomicAddF32: | ||
| 156 | case Opcode::StorageAtomicAddF16x2: | ||
| 157 | case Opcode::StorageAtomicAddF32x2: | ||
| 158 | case Opcode::StorageAtomicMinF16x2: | ||
| 159 | case Opcode::StorageAtomicMinF32x2: | ||
| 160 | case Opcode::StorageAtomicMaxF16x2: | ||
| 161 | case Opcode::StorageAtomicMaxF32x2: | ||
| 96 | case Opcode::BindlessImageWrite: | 162 | case Opcode::BindlessImageWrite: |
| 97 | case Opcode::BoundImageWrite: | 163 | case Opcode::BoundImageWrite: |
| 98 | case Opcode::ImageWrite: | 164 | case Opcode::ImageWrite: |
diff --git a/src/shader_recompiler/frontend/ir/opcodes.inc b/src/shader_recompiler/frontend/ir/opcodes.inc index 86ea02560..dc776a73e 100644 --- a/src/shader_recompiler/frontend/ir/opcodes.inc +++ b/src/shader_recompiler/frontend/ir/opcodes.inc | |||
| @@ -321,6 +321,76 @@ OPCODE(INotEqual, U1, U32, | |||
| 321 | OPCODE(SGreaterThanEqual, U1, U32, U32, ) | 321 | OPCODE(SGreaterThanEqual, U1, U32, U32, ) |
| 322 | OPCODE(UGreaterThanEqual, U1, U32, U32, ) | 322 | OPCODE(UGreaterThanEqual, U1, U32, U32, ) |
| 323 | 323 | ||
| 324 | // Atomic operations | ||
| 325 | OPCODE(SharedAtomicIAdd32, U32, U32, U32, ) | ||
| 326 | OPCODE(SharedAtomicSMin32, U32, U32, U32, ) | ||
| 327 | OPCODE(SharedAtomicUMin32, U32, U32, U32, ) | ||
| 328 | OPCODE(SharedAtomicSMax32, U32, U32, U32, ) | ||
| 329 | OPCODE(SharedAtomicUMax32, U32, U32, U32, ) | ||
| 330 | OPCODE(SharedAtomicInc32, U32, U32, U32, ) | ||
| 331 | OPCODE(SharedAtomicDec32, U32, U32, U32, ) | ||
| 332 | OPCODE(SharedAtomicAnd32, U32, U32, U32, ) | ||
| 333 | OPCODE(SharedAtomicOr32, U32, U32, U32, ) | ||
| 334 | OPCODE(SharedAtomicXor32, U32, U32, U32, ) | ||
| 335 | OPCODE(SharedAtomicExchange32, U32, U32, U32, ) | ||
| 336 | OPCODE(SharedAtomicExchange64, U64, U32, U64, ) | ||
| 337 | |||
| 338 | OPCODE(GlobalAtomicIAdd32, U32, U64, U32, ) | ||
| 339 | OPCODE(GlobalAtomicSMin32, U32, U64, U32, ) | ||
| 340 | OPCODE(GlobalAtomicUMin32, U32, U64, U32, ) | ||
| 341 | OPCODE(GlobalAtomicSMax32, U32, U64, U32, ) | ||
| 342 | OPCODE(GlobalAtomicUMax32, U32, U64, U32, ) | ||
| 343 | OPCODE(GlobalAtomicInc32, U32, U64, U32, ) | ||
| 344 | OPCODE(GlobalAtomicDec32, U32, U64, U32, ) | ||
| 345 | OPCODE(GlobalAtomicAnd32, U32, U64, U32, ) | ||
| 346 | OPCODE(GlobalAtomicOr32, U32, U64, U32, ) | ||
| 347 | OPCODE(GlobalAtomicXor32, U32, U64, U32, ) | ||
| 348 | OPCODE(GlobalAtomicExchange32, U32, U64, U32, ) | ||
| 349 | OPCODE(GlobalAtomicIAdd64, U64, U64, U64, ) | ||
| 350 | OPCODE(GlobalAtomicSMin64, U64, U64, U64, ) | ||
| 351 | OPCODE(GlobalAtomicUMin64, U64, U64, U64, ) | ||
| 352 | OPCODE(GlobalAtomicSMax64, U64, U64, U64, ) | ||
| 353 | OPCODE(GlobalAtomicUMax64, U64, U64, U64, ) | ||
| 354 | OPCODE(GlobalAtomicAnd64, U64, U64, U64, ) | ||
| 355 | OPCODE(GlobalAtomicOr64, U64, U64, U64, ) | ||
| 356 | OPCODE(GlobalAtomicXor64, U64, U64, U64, ) | ||
| 357 | OPCODE(GlobalAtomicExchange64, U64, U64, U64, ) | ||
| 358 | OPCODE(GlobalAtomicAddF32, F32, U64, F32, ) | ||
| 359 | OPCODE(GlobalAtomicAddF16x2, U32, U64, F16x2, ) | ||
| 360 | OPCODE(GlobalAtomicAddF32x2, U32, U64, F32x2, ) | ||
| 361 | OPCODE(GlobalAtomicMinF16x2, U32, U64, F16x2, ) | ||
| 362 | OPCODE(GlobalAtomicMinF32x2, U32, U64, F32x2, ) | ||
| 363 | OPCODE(GlobalAtomicMaxF16x2, U32, U64, F16x2, ) | ||
| 364 | OPCODE(GlobalAtomicMaxF32x2, U32, U64, F32x2, ) | ||
| 365 | |||
| 366 | OPCODE(StorageAtomicIAdd32, U32, U32, U32, U32, ) | ||
| 367 | OPCODE(StorageAtomicSMin32, U32, U32, U32, U32, ) | ||
| 368 | OPCODE(StorageAtomicUMin32, U32, U32, U32, U32, ) | ||
| 369 | OPCODE(StorageAtomicSMax32, U32, U32, U32, U32, ) | ||
| 370 | OPCODE(StorageAtomicUMax32, U32, U32, U32, U32, ) | ||
| 371 | OPCODE(StorageAtomicInc32, U32, U32, U32, U32, ) | ||
| 372 | OPCODE(StorageAtomicDec32, U32, U32, U32, U32, ) | ||
| 373 | OPCODE(StorageAtomicAnd32, U32, U32, U32, U32, ) | ||
| 374 | OPCODE(StorageAtomicOr32, U32, U32, U32, U32, ) | ||
| 375 | OPCODE(StorageAtomicXor32, U32, U32, U32, U32, ) | ||
| 376 | OPCODE(StorageAtomicExchange32, U32, U32, U32, U32, ) | ||
| 377 | OPCODE(StorageAtomicIAdd64, U64, U32, U32, U64, ) | ||
| 378 | OPCODE(StorageAtomicSMin64, U64, U32, U32, U64, ) | ||
| 379 | OPCODE(StorageAtomicUMin64, U64, U32, U32, U64, ) | ||
| 380 | OPCODE(StorageAtomicSMax64, U64, U32, U32, U64, ) | ||
| 381 | OPCODE(StorageAtomicUMax64, U64, U32, U32, U64, ) | ||
| 382 | OPCODE(StorageAtomicAnd64, U64, U32, U32, U64, ) | ||
| 383 | OPCODE(StorageAtomicOr64, U64, U32, U32, U64, ) | ||
| 384 | OPCODE(StorageAtomicXor64, U64, U32, U32, U64, ) | ||
| 385 | OPCODE(StorageAtomicExchange64, U64, U32, U32, U64, ) | ||
| 386 | OPCODE(StorageAtomicAddF32, F32, U32, U32, F32, ) | ||
| 387 | OPCODE(StorageAtomicAddF16x2, U32, U32, U32, F16x2, ) | ||
| 388 | OPCODE(StorageAtomicAddF32x2, U32, U32, U32, F32x2, ) | ||
| 389 | OPCODE(StorageAtomicMinF16x2, U32, U32, U32, F16x2, ) | ||
| 390 | OPCODE(StorageAtomicMinF32x2, U32, U32, U32, F32x2, ) | ||
| 391 | OPCODE(StorageAtomicMaxF16x2, U32, U32, U32, F16x2, ) | ||
| 392 | OPCODE(StorageAtomicMaxF32x2, U32, U32, U32, F32x2, ) | ||
| 393 | |||
| 324 | // Logical operations | 394 | // Logical operations |
| 325 | OPCODE(LogicalOr, U1, U1, U1, ) | 395 | OPCODE(LogicalOr, U1, U1, U1, ) |
| 326 | OPCODE(LogicalAnd, U1, U1, U1, ) | 396 | OPCODE(LogicalAnd, U1, U1, U1, ) |
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/atomic_operations_global_memory.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/atomic_operations_global_memory.cpp new file mode 100644 index 000000000..7a32c5eb3 --- /dev/null +++ b/src/shader_recompiler/frontend/maxwell/translate/impl/atomic_operations_global_memory.cpp | |||
| @@ -0,0 +1,222 @@ | |||
| 1 | // Copyright 2021 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "common/bit_field.h" | ||
| 6 | #include "common/common_types.h" | ||
| 7 | #include "shader_recompiler/frontend/maxwell/translate/impl/impl.h" | ||
| 8 | |||
| 9 | namespace Shader::Maxwell { | ||
| 10 | namespace { | ||
| 11 | enum class AtomOp : u64 { | ||
| 12 | ADD, | ||
| 13 | MIN, | ||
| 14 | MAX, | ||
| 15 | INC, | ||
| 16 | DEC, | ||
| 17 | AND, | ||
| 18 | OR, | ||
| 19 | XOR, | ||
| 20 | EXCH, | ||
| 21 | SAFEADD, | ||
| 22 | }; | ||
| 23 | |||
| 24 | enum class AtomSize : u64 { | ||
| 25 | U32, | ||
| 26 | S32, | ||
| 27 | U64, | ||
| 28 | F32, | ||
| 29 | F16x2, | ||
| 30 | S64, | ||
| 31 | }; | ||
| 32 | |||
| 33 | IR::U32U64 ApplyIntegerAtomOp(IR::IREmitter& ir, const IR::U32U64& offset, const IR::U32U64& op_b, | ||
| 34 | AtomOp op, bool is_signed) { | ||
| 35 | switch (op) { | ||
| 36 | case AtomOp::ADD: | ||
| 37 | return ir.GlobalAtomicIAdd(offset, op_b); | ||
| 38 | case AtomOp::MIN: | ||
| 39 | return ir.GlobalAtomicIMin(offset, op_b, is_signed); | ||
| 40 | case AtomOp::MAX: | ||
| 41 | return ir.GlobalAtomicIMax(offset, op_b, is_signed); | ||
| 42 | case AtomOp::INC: | ||
| 43 | return ir.GlobalAtomicInc(offset, op_b); | ||
| 44 | case AtomOp::DEC: | ||
| 45 | return ir.GlobalAtomicDec(offset, op_b); | ||
| 46 | case AtomOp::AND: | ||
| 47 | return ir.GlobalAtomicAnd(offset, op_b); | ||
| 48 | case AtomOp::OR: | ||
| 49 | return ir.GlobalAtomicOr(offset, op_b); | ||
| 50 | case AtomOp::XOR: | ||
| 51 | return ir.GlobalAtomicXor(offset, op_b); | ||
| 52 | case AtomOp::EXCH: | ||
| 53 | return ir.GlobalAtomicExchange(offset, op_b); | ||
| 54 | default: | ||
| 55 | throw NotImplementedException("Integer Atom Operation {}", op); | ||
| 56 | } | ||
| 57 | } | ||
| 58 | |||
| 59 | IR::Value ApplyFpAtomOp(IR::IREmitter& ir, const IR::U64& offset, const IR::Value& op_b, AtomOp op, | ||
| 60 | AtomSize size) { | ||
| 61 | static constexpr IR::FpControl f16_control{ | ||
| 62 | .no_contraction{false}, | ||
| 63 | .rounding{IR::FpRounding::RN}, | ||
| 64 | .fmz_mode{IR::FmzMode::DontCare}, | ||
| 65 | }; | ||
| 66 | static constexpr IR::FpControl f32_control{ | ||
| 67 | .no_contraction{false}, | ||
| 68 | .rounding{IR::FpRounding::RN}, | ||
| 69 | .fmz_mode{IR::FmzMode::FTZ}, | ||
| 70 | }; | ||
| 71 | switch (op) { | ||
| 72 | case AtomOp::ADD: | ||
| 73 | return size == AtomSize::F32 ? ir.GlobalAtomicF32Add(offset, op_b, f32_control) | ||
| 74 | : ir.GlobalAtomicF16x2Add(offset, op_b, f16_control); | ||
| 75 | case AtomOp::MIN: | ||
| 76 | return ir.GlobalAtomicF16x2Min(offset, op_b, f16_control); | ||
| 77 | case AtomOp::MAX: | ||
| 78 | return ir.GlobalAtomicF16x2Max(offset, op_b, f16_control); | ||
| 79 | default: | ||
| 80 | throw NotImplementedException("FP Atom Operation {}", op); | ||
| 81 | } | ||
| 82 | } | ||
| 83 | |||
| 84 | IR::U64 AtomOffset(TranslatorVisitor& v, u64 insn) { | ||
| 85 | union { | ||
| 86 | u64 raw; | ||
| 87 | BitField<8, 8, IR::Reg> addr_reg; | ||
| 88 | BitField<28, 20, s64> addr_offset; | ||
| 89 | BitField<28, 20, u64> rz_addr_offset; | ||
| 90 | BitField<48, 1, u64> e; | ||
| 91 | } const mem{insn}; | ||
| 92 | |||
| 93 | const IR::U64 address{[&]() -> IR::U64 { | ||
| 94 | if (mem.e == 0) { | ||
| 95 | return v.ir.UConvert(64, v.X(mem.addr_reg)); | ||
| 96 | } | ||
| 97 | return v.L(mem.addr_reg); | ||
| 98 | }()}; | ||
| 99 | const u64 addr_offset{[&]() -> u64 { | ||
| 100 | if (mem.addr_reg == IR::Reg::RZ) { | ||
| 101 | // When RZ is used, the address is an absolute address | ||
| 102 | return static_cast<u64>(mem.rz_addr_offset.Value()); | ||
| 103 | } else { | ||
| 104 | return static_cast<u64>(mem.addr_offset.Value()); | ||
| 105 | } | ||
| 106 | }()}; | ||
| 107 | return v.ir.IAdd(address, v.ir.Imm64(addr_offset)); | ||
| 108 | } | ||
| 109 | |||
| 110 | bool AtomOpNotApplicable(AtomSize size, AtomOp op) { | ||
| 111 | // TODO: SAFEADD | ||
| 112 | switch (size) { | ||
| 113 | case AtomSize::S32: | ||
| 114 | case AtomSize::U64: | ||
| 115 | return (op == AtomOp::INC || op == AtomOp::DEC); | ||
| 116 | case AtomSize::S64: | ||
| 117 | return !(op == AtomOp::MIN || op == AtomOp::MAX); | ||
| 118 | case AtomSize::F32: | ||
| 119 | return op != AtomOp::ADD; | ||
| 120 | case AtomSize::F16x2: | ||
| 121 | return !(op == AtomOp::ADD || op == AtomOp::MIN || op == AtomOp::MAX); | ||
| 122 | default: | ||
| 123 | return false; | ||
| 124 | } | ||
| 125 | } | ||
| 126 | |||
| 127 | IR::U32U64 LoadGlobal(IR::IREmitter& ir, const IR::U64& offset, AtomSize size) { | ||
| 128 | switch (size) { | ||
| 129 | case AtomSize::U32: | ||
| 130 | case AtomSize::S32: | ||
| 131 | case AtomSize::F32: | ||
| 132 | case AtomSize::F16x2: | ||
| 133 | return ir.LoadGlobal32(offset); | ||
| 134 | case AtomSize::U64: | ||
| 135 | case AtomSize::S64: | ||
| 136 | return ir.PackUint2x32(ir.LoadGlobal64(offset)); | ||
| 137 | default: | ||
| 138 | throw NotImplementedException("Atom Size {}", size); | ||
| 139 | } | ||
| 140 | } | ||
| 141 | |||
| 142 | void StoreResult(TranslatorVisitor& v, IR::Reg dest_reg, const IR::Value& result, AtomSize size) { | ||
| 143 | switch (size) { | ||
| 144 | case AtomSize::U32: | ||
| 145 | case AtomSize::S32: | ||
| 146 | case AtomSize::F16x2: | ||
| 147 | return v.X(dest_reg, IR::U32{result}); | ||
| 148 | case AtomSize::U64: | ||
| 149 | case AtomSize::S64: | ||
| 150 | return v.L(dest_reg, IR::U64{result}); | ||
| 151 | case AtomSize::F32: | ||
| 152 | return v.F(dest_reg, IR::F32{result}); | ||
| 153 | default: | ||
| 154 | break; | ||
| 155 | } | ||
| 156 | } | ||
| 157 | } // Anonymous namespace | ||
| 158 | |||
| 159 | void TranslatorVisitor::ATOM(u64 insn) { | ||
| 160 | union { | ||
| 161 | u64 raw; | ||
| 162 | BitField<0, 8, IR::Reg> dest_reg; | ||
| 163 | BitField<8, 8, IR::Reg> addr_reg; | ||
| 164 | BitField<20, 8, IR::Reg> src_reg_b; | ||
| 165 | BitField<49, 3, AtomSize> size; | ||
| 166 | BitField<52, 4, AtomOp> op; | ||
| 167 | } const atom{insn}; | ||
| 168 | |||
| 169 | const bool size_64{atom.size == AtomSize::U64 || atom.size == AtomSize::S64}; | ||
| 170 | const bool is_signed{atom.size == AtomSize::S32 || atom.size == AtomSize::S64}; | ||
| 171 | const bool is_integer{atom.size != AtomSize::F32 && atom.size != AtomSize::F16x2}; | ||
| 172 | const IR::U64 offset{AtomOffset(*this, insn)}; | ||
| 173 | IR::Value result; | ||
| 174 | |||
| 175 | if (AtomOpNotApplicable(atom.size, atom.op)) { | ||
| 176 | result = LoadGlobal(ir, offset, atom.size); | ||
| 177 | } else if (!is_integer) { | ||
| 178 | if (atom.size == AtomSize::F32) { | ||
| 179 | result = ApplyFpAtomOp(ir, offset, F(atom.src_reg_b), atom.op, atom.size); | ||
| 180 | } else { | ||
| 181 | const IR::Value src_b{ir.UnpackFloat2x16(X(atom.src_reg_b))}; | ||
| 182 | result = ApplyFpAtomOp(ir, offset, src_b, atom.op, atom.size); | ||
| 183 | } | ||
| 184 | } else if (size_64) { | ||
| 185 | result = ApplyIntegerAtomOp(ir, offset, L(atom.src_reg_b), atom.op, is_signed); | ||
| 186 | } else { | ||
| 187 | result = ApplyIntegerAtomOp(ir, offset, X(atom.src_reg_b), atom.op, is_signed); | ||
| 188 | } | ||
| 189 | StoreResult(*this, atom.dest_reg, result, atom.size); | ||
| 190 | } | ||
| 191 | |||
| 192 | void TranslatorVisitor::RED(u64 insn) { | ||
| 193 | union { | ||
| 194 | u64 raw; | ||
| 195 | BitField<0, 8, IR::Reg> src_reg_b; | ||
| 196 | BitField<8, 8, IR::Reg> addr_reg; | ||
| 197 | BitField<20, 3, AtomSize> size; | ||
| 198 | BitField<23, 3, AtomOp> op; | ||
| 199 | } const red{insn}; | ||
| 200 | |||
| 201 | if (AtomOpNotApplicable(red.size, red.op)) { | ||
| 202 | return; | ||
| 203 | } | ||
| 204 | const bool size_64{red.size == AtomSize::U64 || red.size == AtomSize::S64}; | ||
| 205 | const bool is_signed{red.size == AtomSize::S32 || red.size == AtomSize::S64}; | ||
| 206 | const bool is_integer{red.size != AtomSize::F32 && red.size != AtomSize::F16x2}; | ||
| 207 | const IR::U64 offset{AtomOffset(*this, insn)}; | ||
| 208 | if (!is_integer) { | ||
| 209 | if (red.size == AtomSize::F32) { | ||
| 210 | ApplyFpAtomOp(ir, offset, F(red.src_reg_b), red.op, red.size); | ||
| 211 | } else { | ||
| 212 | const IR::Value src_b{ir.UnpackFloat2x16(X(red.src_reg_b))}; | ||
| 213 | ApplyFpAtomOp(ir, offset, src_b, red.op, red.size); | ||
| 214 | } | ||
| 215 | } else if (size_64) { | ||
| 216 | ApplyIntegerAtomOp(ir, offset, L(red.src_reg_b), red.op, is_signed); | ||
| 217 | } else { | ||
| 218 | ApplyIntegerAtomOp(ir, offset, X(red.src_reg_b), red.op, is_signed); | ||
| 219 | } | ||
| 220 | } | ||
| 221 | |||
| 222 | } // namespace Shader::Maxwell | ||
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/atomic_operations_shared_memory.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/atomic_operations_shared_memory.cpp new file mode 100644 index 000000000..8b974621e --- /dev/null +++ b/src/shader_recompiler/frontend/maxwell/translate/impl/atomic_operations_shared_memory.cpp | |||
| @@ -0,0 +1,110 @@ | |||
| 1 | // Copyright 2021 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "common/bit_field.h" | ||
| 6 | #include "common/common_types.h" | ||
| 7 | #include "shader_recompiler/frontend/maxwell/translate/impl/impl.h" | ||
| 8 | |||
| 9 | namespace Shader::Maxwell { | ||
| 10 | namespace { | ||
| 11 | enum class AtomOp : u64 { | ||
| 12 | ADD, | ||
| 13 | MIN, | ||
| 14 | MAX, | ||
| 15 | INC, | ||
| 16 | DEC, | ||
| 17 | AND, | ||
| 18 | OR, | ||
| 19 | XOR, | ||
| 20 | EXCH, | ||
| 21 | }; | ||
| 22 | |||
| 23 | enum class AtomsSize : u64 { | ||
| 24 | U32, | ||
| 25 | S32, | ||
| 26 | U64, | ||
| 27 | }; | ||
| 28 | |||
| 29 | IR::U32U64 ApplyAtomsOp(IR::IREmitter& ir, const IR::U32& offset, const IR::U32U64& op_b, AtomOp op, | ||
| 30 | bool is_signed) { | ||
| 31 | switch (op) { | ||
| 32 | case AtomOp::ADD: | ||
| 33 | return ir.SharedAtomicIAdd(offset, op_b); | ||
| 34 | case AtomOp::MIN: | ||
| 35 | return ir.SharedAtomicIMin(offset, op_b, is_signed); | ||
| 36 | case AtomOp::MAX: | ||
| 37 | return ir.SharedAtomicIMax(offset, op_b, is_signed); | ||
| 38 | case AtomOp::INC: | ||
| 39 | return ir.SharedAtomicInc(offset, op_b); | ||
| 40 | case AtomOp::DEC: | ||
| 41 | return ir.SharedAtomicDec(offset, op_b); | ||
| 42 | case AtomOp::AND: | ||
| 43 | return ir.SharedAtomicAnd(offset, op_b); | ||
| 44 | case AtomOp::OR: | ||
| 45 | return ir.SharedAtomicOr(offset, op_b); | ||
| 46 | case AtomOp::XOR: | ||
| 47 | return ir.SharedAtomicXor(offset, op_b); | ||
| 48 | case AtomOp::EXCH: | ||
| 49 | return ir.SharedAtomicExchange(offset, op_b); | ||
| 50 | default: | ||
| 51 | throw NotImplementedException("Integer Atoms Operation {}", op); | ||
| 52 | } | ||
| 53 | } | ||
| 54 | |||
| 55 | IR::U32 AtomsOffset(TranslatorVisitor& v, u64 insn) { | ||
| 56 | union { | ||
| 57 | u64 raw; | ||
| 58 | BitField<8, 8, IR::Reg> offset_reg; | ||
| 59 | BitField<30, 22, u64> absolute_offset; | ||
| 60 | BitField<30, 22, s64> relative_offset; | ||
| 61 | } const encoding{insn}; | ||
| 62 | |||
| 63 | if (encoding.offset_reg == IR::Reg::RZ) { | ||
| 64 | return v.ir.Imm32(static_cast<u32>(encoding.absolute_offset << 2)); | ||
| 65 | } else { | ||
| 66 | const s32 relative{static_cast<s32>(encoding.relative_offset << 2)}; | ||
| 67 | return v.ir.IAdd(v.X(encoding.offset_reg), v.ir.Imm32(relative)); | ||
| 68 | } | ||
| 69 | } | ||
| 70 | |||
| 71 | void StoreResult(TranslatorVisitor& v, IR::Reg dest_reg, const IR::Value& result, AtomsSize size) { | ||
| 72 | switch (size) { | ||
| 73 | case AtomsSize::U32: | ||
| 74 | case AtomsSize::S32: | ||
| 75 | return v.X(dest_reg, IR::U32{result}); | ||
| 76 | case AtomsSize::U64: | ||
| 77 | return v.L(dest_reg, IR::U64{result}); | ||
| 78 | default: | ||
| 79 | break; | ||
| 80 | } | ||
| 81 | } | ||
| 82 | } // Anonymous namespace | ||
| 83 | |||
| 84 | void TranslatorVisitor::ATOMS(u64 insn) { | ||
| 85 | union { | ||
| 86 | u64 raw; | ||
| 87 | BitField<0, 8, IR::Reg> dest_reg; | ||
| 88 | BitField<8, 8, IR::Reg> addr_reg; | ||
| 89 | BitField<20, 8, IR::Reg> src_reg_b; | ||
| 90 | BitField<28, 2, AtomsSize> size; | ||
| 91 | BitField<52, 4, AtomOp> op; | ||
| 92 | } const atoms{insn}; | ||
| 93 | |||
| 94 | const bool size_64{atoms.size == AtomsSize::U64}; | ||
| 95 | if (size_64 && atoms.op != AtomOp::EXCH) { | ||
| 96 | throw NotImplementedException("64-bit Atoms Operation {}", atoms.op.Value()); | ||
| 97 | } | ||
| 98 | const bool is_signed{atoms.size == AtomsSize::S32}; | ||
| 99 | const IR::U32 offset{AtomsOffset(*this, insn)}; | ||
| 100 | |||
| 101 | IR::Value result; | ||
| 102 | if (size_64) { | ||
| 103 | result = ApplyAtomsOp(ir, offset, L(atoms.src_reg_b), atoms.op, is_signed); | ||
| 104 | } else { | ||
| 105 | result = ApplyAtomsOp(ir, offset, X(atoms.src_reg_b), atoms.op, is_signed); | ||
| 106 | } | ||
| 107 | StoreResult(*this, atoms.dest_reg, result, atoms.size); | ||
| 108 | } | ||
| 109 | |||
| 110 | } // namespace Shader::Maxwell | ||
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/not_implemented.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/not_implemented.cpp index 327941223..aebe3072a 100644 --- a/src/shader_recompiler/frontend/maxwell/translate/impl/not_implemented.cpp +++ b/src/shader_recompiler/frontend/maxwell/translate/impl/not_implemented.cpp | |||
| @@ -17,18 +17,10 @@ void TranslatorVisitor::ATOM_cas(u64) { | |||
| 17 | ThrowNotImplemented(Opcode::ATOM_cas); | 17 | ThrowNotImplemented(Opcode::ATOM_cas); |
| 18 | } | 18 | } |
| 19 | 19 | ||
| 20 | void TranslatorVisitor::ATOM(u64) { | ||
| 21 | ThrowNotImplemented(Opcode::ATOM); | ||
| 22 | } | ||
| 23 | |||
| 24 | void TranslatorVisitor::ATOMS_cas(u64) { | 20 | void TranslatorVisitor::ATOMS_cas(u64) { |
| 25 | ThrowNotImplemented(Opcode::ATOMS_cas); | 21 | ThrowNotImplemented(Opcode::ATOMS_cas); |
| 26 | } | 22 | } |
| 27 | 23 | ||
| 28 | void TranslatorVisitor::ATOMS(u64) { | ||
| 29 | ThrowNotImplemented(Opcode::ATOMS); | ||
| 30 | } | ||
| 31 | |||
| 32 | void TranslatorVisitor::B2R(u64) { | 24 | void TranslatorVisitor::B2R(u64) { |
| 33 | ThrowNotImplemented(Opcode::B2R); | 25 | ThrowNotImplemented(Opcode::B2R); |
| 34 | } | 26 | } |
| @@ -241,10 +233,6 @@ void TranslatorVisitor::RAM(u64) { | |||
| 241 | ThrowNotImplemented(Opcode::RAM); | 233 | ThrowNotImplemented(Opcode::RAM); |
| 242 | } | 234 | } |
| 243 | 235 | ||
| 244 | void TranslatorVisitor::RED(u64) { | ||
| 245 | ThrowNotImplemented(Opcode::RED); | ||
| 246 | } | ||
| 247 | |||
| 248 | void TranslatorVisitor::RET(u64) { | 236 | void TranslatorVisitor::RET(u64) { |
| 249 | ThrowNotImplemented(Opcode::RET); | 237 | ThrowNotImplemented(Opcode::RET); |
| 250 | } | 238 | } |