mirror of
https://github.com/RPCSX/rpcsx.git
synced 2026-01-20 07:30:24 +01:00
gpu: extend resource evaluation rules to handle relative resources
implement evaluation of x16 dword loads fixed evaluation of binary expressions
This commit is contained in:
parent
b85c6e6acc
commit
f4994f6717
|
|
@ -146,6 +146,13 @@ static ConverterFn *getPrimConverterFn(gnm::PrimitiveType primType,
|
|||
static_cast<unsigned>(primType));
|
||||
}
|
||||
}
|
||||
shader::eval::Value Cache::ShaderResources::eval(shader::ir::Value op) {
|
||||
if (op == ir::sop2::ADD_U32 || op == ir::sop2::ADDC_U32) {
|
||||
return eval(op.getOperand(1)) + eval(op.getOperand(2));
|
||||
}
|
||||
|
||||
return Evaluator::eval(op);
|
||||
}
|
||||
|
||||
void Cache::ShaderResources::loadResources(
|
||||
gcn::Resources &res, std::span<const std::uint32_t> userSgprs) {
|
||||
|
|
@ -454,8 +461,11 @@ Cache::ShaderResources::eval(ir::InstructionId instId,
|
|||
case 32:
|
||||
result = readPointer<std::array<std::uint32_t, 8>>(address);
|
||||
break;
|
||||
case 64:
|
||||
result = readPointer<std::array<std::uint32_t, 16>>(address);
|
||||
break;
|
||||
default:
|
||||
rx::die("unexpected pointer load size");
|
||||
rx::die("unexpected pointer load size %u", loadSize);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
|
@ -1275,9 +1285,9 @@ Cache::Shader Cache::Tag::getShader(const ShaderKey &key,
|
|||
|
||||
// deserialized.print(std::cerr, context.ns);
|
||||
|
||||
converted = gcn::convertToSpv(context, deserialized,
|
||||
mParent->mDevice->gcnSemanticModuleInfo,
|
||||
key.stage, env);
|
||||
converted = gcn::convertToSpv(
|
||||
context, deserialized, mParent->mDevice->gcnSemantic,
|
||||
mParent->mDevice->gcnSemanticModuleInfo, key.stage, env);
|
||||
if (!converted) {
|
||||
return {};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -211,7 +211,7 @@ struct ConvertedShader {
|
|||
|
||||
std::optional<ConvertedShader>
|
||||
convertToSpv(Context &context, ir::Region body,
|
||||
const SemanticInfo &semanticInfo,
|
||||
const SemanticModuleInfo &semanticModule, Stage stage,
|
||||
const Environment &state);
|
||||
|
||||
} // namespace shader::gcn
|
||||
|
|
|
|||
|
|
@ -191,7 +191,8 @@ CFG buildCFG(ir::Instruction firstInstruction,
|
|||
MemorySSA buildMemorySSA(CFG &cfg, ModuleInfo *moduleInfo = nullptr);
|
||||
|
||||
MemorySSA buildMemorySSA(CFG &cfg, const SemanticInfo &instructionSemantic,
|
||||
std::function<ir::Value(int)> getRegisterVarCb);
|
||||
std::function<ir::Value(int)> getRegisterVarCb,
|
||||
ModuleInfo *moduleInfo = nullptr);
|
||||
|
||||
bool dominates(ir::Instruction a, ir::Instruction b, bool isPostDom,
|
||||
graph::DomTree<ir::Value> &domTree);
|
||||
|
|
@ -385,10 +386,8 @@ struct Construct {
|
|||
CFG &getCfg() {
|
||||
return analysis.get<CFG>([this] {
|
||||
if (parent != nullptr) {
|
||||
return parent->getCfg().buildView(
|
||||
header,
|
||||
&parent->getPostDomTree(),
|
||||
{header, merge});
|
||||
return parent->getCfg().buildView(header, &parent->getPostDomTree(),
|
||||
{header, merge});
|
||||
}
|
||||
|
||||
return buildCFG(header);
|
||||
|
|
@ -402,10 +401,8 @@ struct Construct {
|
|||
|
||||
return analysis.get<Tag<CFG, kWithoutContinue>>([this] {
|
||||
if (parent != nullptr) {
|
||||
return parent->getCfg().buildView(
|
||||
header,
|
||||
&parent->getPostDomTree(),
|
||||
{header, merge}, loopContinue);
|
||||
return parent->getCfg().buildView(header, &parent->getPostDomTree(),
|
||||
{header, merge}, loopContinue);
|
||||
}
|
||||
|
||||
return buildCFG(header, {}, loopContinue);
|
||||
|
|
|
|||
|
|
@ -2,9 +2,9 @@
|
|||
|
||||
#include "Vector.hpp"
|
||||
#include "ir/Value.hpp"
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <variant>
|
||||
#include <array>
|
||||
|
||||
namespace shader::eval {
|
||||
struct Value {
|
||||
|
|
@ -15,7 +15,8 @@ struct Value {
|
|||
u16vec2, u16vec3, u16vec4, i16vec2, i16vec3, i16vec4, u32vec2, u32vec3,
|
||||
u32vec4, i32vec2, i32vec3, i32vec4, u64vec2, u64vec3, u64vec4, i64vec2,
|
||||
i64vec3, i64vec4, f32vec2, f32vec3, f32vec4, f64vec2, f64vec3, f64vec4,
|
||||
f16vec2, f16vec3, f16vec4, bool, bvec2, bvec3, bvec4, std::array<uint32_t, 8>>;
|
||||
f16vec2, f16vec3, f16vec4, bool, bvec2, bvec3, bvec4,
|
||||
std::array<uint32_t, 8>, std::array<std::uint32_t, 16>>;
|
||||
static constexpr auto StorageSize = std::variant_size_v<Storage>;
|
||||
Storage storage;
|
||||
|
||||
|
|
|
|||
|
|
@ -71,6 +71,10 @@ inline int stageToDescriptorSet(gcn::Stage stage) {
|
|||
|
||||
static void printFlat(std::ostream &os, ir::Instruction inst,
|
||||
ir::NameStorage &ns) {
|
||||
if (inst == nullptr) {
|
||||
os << "null";
|
||||
return;
|
||||
}
|
||||
os << ir::getInstructionName(inst.getKind(), inst.getOp());
|
||||
os << '(';
|
||||
|
||||
|
|
@ -91,29 +95,165 @@ static void printFlat(std::ostream &os, ir::Instruction inst,
|
|||
os << ')';
|
||||
}
|
||||
|
||||
static bool isEqual(ir::Value lhs, ir::Value rhs);
|
||||
|
||||
static bool isEqual(const ir::Operand &lhs, const ir::Operand &rhs) {
|
||||
return std::visit(
|
||||
[]<typename Lhs, typename Rhs>(const Lhs &lhs, const Rhs &rhs) {
|
||||
if constexpr (std::is_same_v<Lhs, Rhs>) {
|
||||
if constexpr (std::is_same_v<Lhs, ir::Value>) {
|
||||
return isEqual(lhs, rhs);
|
||||
} else {
|
||||
return lhs == rhs;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
lhs.value, rhs.value);
|
||||
}
|
||||
|
||||
static bool isEqual(ir::Value lhs, ir::Value rhs) {
|
||||
if (lhs == rhs) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((lhs == nullptr) != (rhs == nullptr)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (lhs.getInstId() != rhs.getInstId()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (lhs.getOperandCount() != rhs.getOperandCount()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (std::size_t i = 0, end = lhs.getOperandCount(); i < end; ++i) {
|
||||
if (!isEqual(lhs.getOperand(i), rhs.getOperand(i))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
struct ResourcesBuilder {
|
||||
gcn::Resources resources;
|
||||
ir::NameStorage *ns;
|
||||
|
||||
void addPointer(gcn::Resources::Pointer p) {
|
||||
int addPointer(gcn::Resources::Pointer p) {
|
||||
for (auto &pointer : resources.pointers) {
|
||||
if (pointer.size != p.size) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isEqual(pointer.base, p.base)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isEqual(pointer.offset, p.offset)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return pointer.resourceSlot;
|
||||
}
|
||||
|
||||
p.resourceSlot = resources.slots++;
|
||||
resources.pointers.push_back(p);
|
||||
return p.resourceSlot;
|
||||
}
|
||||
void addTexture(gcn::Resources::Texture p) {
|
||||
int addTexture(gcn::Resources::Texture p) {
|
||||
for (auto &texture : resources.textures) {
|
||||
bool equal = true;
|
||||
|
||||
for (std::size_t i = 0; i < std::size(texture.words); ++i) {
|
||||
if (!isEqual(texture.words[i], p.words[i])) {
|
||||
equal = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!equal) {
|
||||
continue;
|
||||
}
|
||||
|
||||
texture.access |= p.access;
|
||||
return texture.resourceSlot;
|
||||
}
|
||||
|
||||
p.resourceSlot = resources.slots++;
|
||||
resources.textures.push_back(p);
|
||||
return p.resourceSlot;
|
||||
}
|
||||
void addImageBuffer(gcn::Resources::ImageBuffer p) {
|
||||
int addImageBuffer(gcn::Resources::ImageBuffer p) {
|
||||
for (auto &buffer : resources.imageBuffers) {
|
||||
bool equal = true;
|
||||
|
||||
for (std::size_t i = 0; i < std::size(buffer.words); ++i) {
|
||||
if (!isEqual(buffer.words[i], p.words[i])) {
|
||||
equal = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!equal) {
|
||||
continue;
|
||||
}
|
||||
|
||||
buffer.access |= p.access;
|
||||
return buffer.resourceSlot;
|
||||
}
|
||||
|
||||
p.resourceSlot = resources.slots++;
|
||||
resources.imageBuffers.push_back(p);
|
||||
return p.resourceSlot;
|
||||
}
|
||||
void addBuffer(gcn::Resources::Buffer p) {
|
||||
int addBuffer(gcn::Resources::Buffer p) {
|
||||
for (auto &buffer : resources.buffers) {
|
||||
bool equal = true;
|
||||
|
||||
for (std::size_t i = 0; i < std::size(buffer.words); ++i) {
|
||||
if (!isEqual(buffer.words[i], p.words[i])) {
|
||||
equal = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!equal) {
|
||||
continue;
|
||||
}
|
||||
|
||||
buffer.access |= p.access;
|
||||
return buffer.resourceSlot;
|
||||
}
|
||||
|
||||
p.resourceSlot = resources.slots++;
|
||||
resources.buffers.push_back(p);
|
||||
return p.resourceSlot;
|
||||
}
|
||||
void addSampler(gcn::Resources::Sampler p) {
|
||||
int addSampler(gcn::Resources::Sampler p) {
|
||||
for (auto &sampler : resources.samplers) {
|
||||
bool equal = true;
|
||||
|
||||
for (std::size_t i = 0; i < std::size(sampler.words); ++i) {
|
||||
if (!isEqual(sampler.words[i], p.words[i])) {
|
||||
equal = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!equal) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return sampler.resourceSlot;
|
||||
}
|
||||
|
||||
p.resourceSlot = resources.slots++;
|
||||
resources.samplers.push_back(p);
|
||||
return p.resourceSlot;
|
||||
}
|
||||
|
||||
ir::Value unpackFunctionCall(MemorySSA &memorySSA, spv::Import &importer,
|
||||
|
|
@ -163,6 +303,30 @@ struct ResourcesBuilder {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
ir::Instruction unpackInstruction(MemorySSA &memorySSA, spv::Import &importer,
|
||||
ir::Instruction inst) {
|
||||
for (auto &op : inst.getOperands()) {
|
||||
auto value = op.getAsValue();
|
||||
if (!value) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (value == ir::spv::OpVariable || value == ir::spv::OpAccessChain) {
|
||||
auto varDef = memorySSA.getDefInst(inst, value);
|
||||
if (varDef == ir::spv::OpStore) {
|
||||
varDef = varDef.getOperand(1).getAsValue();
|
||||
}
|
||||
if (varDef == ir::amdgpu::POINTER) {
|
||||
return importIR(memorySSA, importer, varDef).staticCast<ir::Value>();
|
||||
}
|
||||
} else if (value == ir::amdgpu::POINTER) {
|
||||
return importIR(memorySSA, importer, value).staticCast<ir::Value>();
|
||||
}
|
||||
}
|
||||
|
||||
return inst;
|
||||
}
|
||||
|
||||
ir::Instruction unpackResourceDef(MemorySSA &memorySSA, spv::Import &importer,
|
||||
ir::memssa::Def def) {
|
||||
if (def == nullptr) {
|
||||
|
|
@ -180,6 +344,11 @@ struct ResourcesBuilder {
|
|||
defInst.staticCast<ir::Value>());
|
||||
}
|
||||
|
||||
if (defInst.getKind() != ir::Kind::Spv &&
|
||||
defInst.getKind() != ir::Kind::AmdGpu) {
|
||||
return unpackInstruction(memorySSA, importer, defInst);
|
||||
}
|
||||
|
||||
return importIR(memorySSA, importer, defInst);
|
||||
}
|
||||
|
||||
|
|
@ -194,6 +363,7 @@ struct ResourcesBuilder {
|
|||
phi.getOperand(i + 1).getAsValue().staticCast<ir::memssa::Def>();
|
||||
|
||||
auto inst = unpackResourceDef(memorySSA, importer, def);
|
||||
|
||||
if (inst == nullptr) {
|
||||
resources.hasUnknown = true;
|
||||
}
|
||||
|
|
@ -205,6 +375,7 @@ struct ResourcesBuilder {
|
|||
resourcePhi.addOperand(value);
|
||||
} else {
|
||||
auto block = resources.context.create<ir::Block>(inst.getLocation());
|
||||
inst.erase();
|
||||
block.addChild(inst);
|
||||
resourcePhi.addOperand(block);
|
||||
}
|
||||
|
|
@ -216,6 +387,20 @@ struct ResourcesBuilder {
|
|||
return importIR(memorySSA, importer, def.getLinkedInst());
|
||||
}
|
||||
|
||||
ir::Value toValue(ir::Instruction inst) {
|
||||
if (inst == nullptr) {
|
||||
return {};
|
||||
}
|
||||
|
||||
if (auto value = inst.cast<ir::Value>()) {
|
||||
return value;
|
||||
}
|
||||
|
||||
auto block = resources.context.create<ir::Block>(inst.getLocation());
|
||||
block.addChild(inst);
|
||||
return block;
|
||||
}
|
||||
|
||||
ir::Instruction importIR(MemorySSA &memorySSA, spv::Import &importer,
|
||||
ir::Instruction resource) {
|
||||
auto result = ir::clone(resource, resources.context, importer);
|
||||
|
|
@ -240,16 +425,15 @@ struct ResourcesBuilder {
|
|||
continue;
|
||||
}
|
||||
|
||||
if (auto value = resourceInst.cast<ir::Value>()) {
|
||||
cloned.staticCast<ir::Value>().replaceAllUsesWith(value);
|
||||
} else {
|
||||
auto block =
|
||||
resources.context.create<ir::Block>(resourceInst.getLocation());
|
||||
block.addChild(resourceInst);
|
||||
cloned.staticCast<ir::Value>().replaceAllUsesWith(block);
|
||||
}
|
||||
if (resourceInst != cloned) {
|
||||
if (resource == inst) {
|
||||
result = resourceInst;
|
||||
}
|
||||
|
||||
continue;
|
||||
cloned.staticCast<ir::Value>().replaceAllUsesWith(
|
||||
toValue(resourceInst));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (inst == ir::spv::OpFunctionCall) {
|
||||
|
|
@ -258,8 +442,55 @@ struct ResourcesBuilder {
|
|||
|
||||
if (unpacked) {
|
||||
cloned.staticCast<ir::Value>().replaceAllUsesWith(unpacked);
|
||||
if (resource == inst) {
|
||||
result = unpacked;
|
||||
}
|
||||
|
||||
if (visited.insert(unpacked).second) {
|
||||
workList.push_back(unpacked);
|
||||
workList.emplace_back(unpacked);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (inst.getKind() != ir::Kind::Spv &&
|
||||
inst.getKind() != ir::Kind::AmdGpu) {
|
||||
auto unpacked = unpackInstruction(memorySSA, importer, inst);
|
||||
|
||||
if (unpacked) {
|
||||
if (unpacked != inst) {
|
||||
cloned.staticCast<ir::Value>().replaceAllUsesWith(
|
||||
toValue(unpacked));
|
||||
|
||||
if (resource == inst) {
|
||||
result = unpacked;
|
||||
}
|
||||
|
||||
if (visited.insert(unpacked).second) {
|
||||
workList.emplace_back(unpacked);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// FIXME: pass read only parameters as value and remove this
|
||||
// workaround
|
||||
for (std::size_t i = 0, end = cloned.getOperandCount(); i < end;
|
||||
++i) {
|
||||
auto valueOp = cloned.getOperand(i).getAsValue();
|
||||
if (valueOp == nullptr) {
|
||||
continue;
|
||||
}
|
||||
if (valueOp != ir::spv::OpVariable) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto def = memorySSA.getDef(inst, inst.getOperand(i).getAsValue());
|
||||
if (auto resourceInst =
|
||||
unpackResourceDef(memorySSA, importer, def)) {
|
||||
cloned.replaceOperand(i, toValue(resourceInst));
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
|
|
@ -268,8 +499,13 @@ struct ResourcesBuilder {
|
|||
|
||||
for (auto &operand : inst.getOperands()) {
|
||||
if (auto value = operand.getAsValue()) {
|
||||
if (value.getKind() == ir::Kind::Spv &&
|
||||
ir::spv::isTypeOp(value.getOp())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (visited.insert(value).second) {
|
||||
workList.push_back(value);
|
||||
workList.emplace_back(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -286,9 +522,13 @@ struct ResourcesBuilder {
|
|||
|
||||
int slot = -1;
|
||||
|
||||
if (resourceSet.size() == 1 && resourceSet[0] != nullptr) {
|
||||
slot = resources.slots;
|
||||
}
|
||||
auto trackResource = [&](int resourceSlot) {
|
||||
if (slot == -1) {
|
||||
slot = resourceSlot;
|
||||
} else if (slot != resourceSlot) {
|
||||
slot = -2;
|
||||
}
|
||||
};
|
||||
|
||||
for (auto inst : resourceSet) {
|
||||
if (inst == ir::amdgpu::POINTER) {
|
||||
|
|
@ -296,11 +536,11 @@ struct ResourcesBuilder {
|
|||
auto base = inst.getOperand(2).getAsValue();
|
||||
auto offset = inst.getOperand(3).getAsValue();
|
||||
|
||||
addPointer({
|
||||
trackResource(addPointer({
|
||||
.size = loadSize,
|
||||
.base = base,
|
||||
.offset = offset,
|
||||
});
|
||||
}));
|
||||
|
||||
continue;
|
||||
}
|
||||
|
|
@ -309,11 +549,11 @@ struct ResourcesBuilder {
|
|||
auto access = static_cast<Access>(*inst.getOperand(1).getAsInt32());
|
||||
auto words = inst.getOperands().subspan(2);
|
||||
|
||||
addBuffer({
|
||||
trackResource(addBuffer({
|
||||
.access = access,
|
||||
.words = {words[0].getAsValue(), words[1].getAsValue(),
|
||||
words[2].getAsValue(), words[3].getAsValue()},
|
||||
});
|
||||
}));
|
||||
|
||||
continue;
|
||||
}
|
||||
|
|
@ -322,19 +562,19 @@ struct ResourcesBuilder {
|
|||
auto access = static_cast<Access>(*inst.getOperand(1).getAsInt32());
|
||||
auto words = inst.getOperands().subspan(2);
|
||||
if (words.size() > 4) {
|
||||
addTexture({
|
||||
trackResource(addTexture({
|
||||
.access = access,
|
||||
.words = {words[0].getAsValue(), words[1].getAsValue(),
|
||||
words[2].getAsValue(), words[3].getAsValue(),
|
||||
words[4].getAsValue(), words[5].getAsValue(),
|
||||
words[6].getAsValue(), words[7].getAsValue()},
|
||||
});
|
||||
}));
|
||||
} else {
|
||||
addTexture({
|
||||
trackResource(addTexture({
|
||||
.access = access,
|
||||
.words = {words[0].getAsValue(), words[1].getAsValue(),
|
||||
words[2].getAsValue(), words[3].getAsValue()},
|
||||
});
|
||||
}));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
|
@ -343,19 +583,19 @@ struct ResourcesBuilder {
|
|||
auto access = static_cast<Access>(*inst.getOperand(1).getAsInt32());
|
||||
auto words = inst.getOperands().subspan(2);
|
||||
if (words.size() > 4) {
|
||||
addImageBuffer({
|
||||
trackResource(addImageBuffer({
|
||||
.access = access,
|
||||
.words = {words[0].getAsValue(), words[1].getAsValue(),
|
||||
words[2].getAsValue(), words[3].getAsValue(),
|
||||
words[4].getAsValue(), words[5].getAsValue(),
|
||||
words[6].getAsValue(), words[7].getAsValue()},
|
||||
});
|
||||
}));
|
||||
} else {
|
||||
addImageBuffer({
|
||||
trackResource(addImageBuffer({
|
||||
.access = access,
|
||||
.words = {words[0].getAsValue(), words[1].getAsValue(),
|
||||
words[2].getAsValue(), words[3].getAsValue()},
|
||||
});
|
||||
}));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
|
@ -363,11 +603,11 @@ struct ResourcesBuilder {
|
|||
if (inst == ir::amdgpu::SAMPLER) {
|
||||
auto words = inst.getOperands().subspan(1);
|
||||
auto unorm = *inst.getOperand(5).getAsBool();
|
||||
addSampler({
|
||||
trackResource(addSampler({
|
||||
.unorm = unorm,
|
||||
.words = {words[0].getAsValue(), words[1].getAsValue(),
|
||||
words[2].getAsValue(), words[3].getAsValue()},
|
||||
});
|
||||
}));
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -877,6 +1117,7 @@ static void expToSpv(GcnConverter &converter, gcn::Stage stage,
|
|||
|
||||
static void instructionsToSpv(GcnConverter &converter, gcn::Import &importer,
|
||||
gcn::Stage stage, const gcn::Environment &env,
|
||||
const SemanticInfo &semanticInfo,
|
||||
const SemanticModuleInfo &semanticModuleInfo,
|
||||
gcn::ShaderInfo &info, ir::Region body) {
|
||||
auto &context = converter.gcnContext;
|
||||
|
|
@ -927,10 +1168,6 @@ static void instructionsToSpv(GcnConverter &converter, gcn::Import &importer,
|
|||
}
|
||||
|
||||
for (auto inst : body.children()) {
|
||||
if (inst.getKind() == ir::Kind::Spv) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (inst == ir::exp::EXP) {
|
||||
expToSpv(converter, stage, info, inst);
|
||||
inst.remove();
|
||||
|
|
@ -941,6 +1178,57 @@ static void instructionsToSpv(GcnConverter &converter, gcn::Import &importer,
|
|||
inst == ir::amdgpu::SAMPLER || inst == ir::amdgpu::TBUFFER ||
|
||||
inst == ir::amdgpu::IMAGE_BUFFER) {
|
||||
toAnalyze.push_back(inst.staticCast<ir::Value>());
|
||||
}
|
||||
}
|
||||
|
||||
if (!toAnalyze.empty()) {
|
||||
auto &cfg =
|
||||
context.analysis.get<CFG>([&] { return buildCFG(body.getFirst()); });
|
||||
|
||||
ModuleInfo moduleInfo;
|
||||
collectModuleInfo(moduleInfo, context.layout);
|
||||
auto memorySSA = buildMemorySSA(
|
||||
cfg, semanticInfo,
|
||||
[&](int regId) {
|
||||
return context.getOrCreateRegisterVariable(gcn::RegId(regId));
|
||||
},
|
||||
&moduleInfo);
|
||||
|
||||
spv::Import resourceImporter;
|
||||
// memorySSA.print(std::cerr, body, context.ns);
|
||||
|
||||
ResourcesBuilder resourcesBuilder;
|
||||
std::map<ir::Value, std::int32_t> resourceConfigSlots;
|
||||
resourcesBuilder.ns = &context.ns;
|
||||
for (auto inst : toAnalyze) {
|
||||
std::uint32_t configSlot = -1;
|
||||
int resourceSlot =
|
||||
resourcesBuilder.importResource(memorySSA, resourceImporter, inst);
|
||||
if (resourceSlot >= 0) {
|
||||
configSlot = info.create(gcn::ConfigType::ResourceSlot, resourceSlot);
|
||||
}
|
||||
|
||||
resourceConfigSlots[inst] = configSlot;
|
||||
}
|
||||
|
||||
for (auto [inst, slot] : resourceConfigSlots) {
|
||||
auto builder = gcn::Builder::createInsertBefore(context, inst);
|
||||
if (slot >= 0) {
|
||||
auto value = converter.createReadConfig(stage, builder, slot);
|
||||
value = builder.createSpvBitcast(inst.getLocation(),
|
||||
context.getTypeSInt32(), value);
|
||||
inst.replaceAllUsesWith(value);
|
||||
} else {
|
||||
inst.replaceAllUsesWith(context.simm32(-1));
|
||||
}
|
||||
inst.remove();
|
||||
}
|
||||
|
||||
info.resources = std::move(resourcesBuilder.resources);
|
||||
}
|
||||
|
||||
for (auto inst : body.children()) {
|
||||
if (inst.getKind() == ir::Kind::Spv) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -1290,47 +1578,6 @@ static void instructionsToSpv(GcnConverter &converter, gcn::Import &importer,
|
|||
inst.remove();
|
||||
}
|
||||
|
||||
if (!toAnalyze.empty()) {
|
||||
auto &cfg =
|
||||
context.analysis.get<CFG>([&] { return buildCFG(body.getFirst()); });
|
||||
|
||||
ModuleInfo moduleInfo;
|
||||
collectModuleInfo(moduleInfo, context.layout);
|
||||
auto memorySSA = buildMemorySSA(cfg, &moduleInfo);
|
||||
spv::Import resourceImporter;
|
||||
|
||||
// memorySSA.print(std::cerr, body, context.ns);
|
||||
|
||||
ResourcesBuilder resourcesBuilder;
|
||||
std::map<ir::Value, std::int32_t> resourceConfigSlots;
|
||||
resourcesBuilder.ns = &context.ns;
|
||||
for (auto inst : toAnalyze) {
|
||||
std::uint32_t configSlot = -1;
|
||||
int resourceSlot =
|
||||
resourcesBuilder.importResource(memorySSA, resourceImporter, inst);
|
||||
if (resourceSlot >= 0) {
|
||||
configSlot = info.create(gcn::ConfigType::ResourceSlot, resourceSlot);
|
||||
}
|
||||
|
||||
resourceConfigSlots[inst] = configSlot;
|
||||
}
|
||||
|
||||
for (auto [inst, slot] : resourceConfigSlots) {
|
||||
auto builder = gcn::Builder::createInsertBefore(context, inst);
|
||||
if (slot >= 0) {
|
||||
auto value = converter.createReadConfig(stage, builder, slot);
|
||||
value = builder.createSpvBitcast(inst.getLocation(),
|
||||
context.getTypeSInt32(), value);
|
||||
inst.replaceAllUsesWith(value);
|
||||
} else {
|
||||
inst.replaceAllUsesWith(context.simm32(-1));
|
||||
}
|
||||
inst.remove();
|
||||
}
|
||||
|
||||
info.resources = std::move(resourcesBuilder.resources);
|
||||
}
|
||||
|
||||
for (auto inst : body.children()) {
|
||||
if (inst.getKind() == ir::Kind::Spv) {
|
||||
continue;
|
||||
|
|
@ -1704,15 +1951,16 @@ static void createInitialValues(GcnConverter &converter,
|
|||
|
||||
std::optional<gcn::ConvertedShader>
|
||||
gcn::convertToSpv(Context &context, ir::Region body,
|
||||
const SemanticModuleInfo &semanticInfo, Stage stage,
|
||||
const SemanticInfo &semanticInfo,
|
||||
const SemanticModuleInfo &semanticModule, Stage stage,
|
||||
const Environment &env) {
|
||||
gcn::ConvertedShader result;
|
||||
GcnConverter converter{context};
|
||||
gcn::Import importer;
|
||||
|
||||
createInitialValues(converter, env, stage, result.info, body);
|
||||
instructionsToSpv(converter, importer, stage, env, semanticInfo, result.info,
|
||||
body);
|
||||
instructionsToSpv(converter, importer, stage, env, semanticInfo,
|
||||
semanticModule, result.info, body);
|
||||
if (stage != gcn::Stage::Cs) {
|
||||
replaceVariableWithConstant(
|
||||
context.getOrCreateRegisterVariable(gcn::RegId::ThreadId),
|
||||
|
|
|
|||
|
|
@ -964,13 +964,12 @@ MemorySSA MemorySSABuilder::build(CFG &cfg, auto &&handleInst) {
|
|||
return std::move(memSSA);
|
||||
}
|
||||
|
||||
MemorySSA
|
||||
shader::buildMemorySSA(CFG &cfg, const SemanticInfo &instructionSemantic,
|
||||
std::function<ir::Value(int)> getRegisterVarCb) {
|
||||
return MemorySSABuilder{}.build(cfg, [&](MemorySSABuilder &builder,
|
||||
ir::memssa::Scope scope,
|
||||
ir::Instruction inst) {
|
||||
using IRBuilder = MemorySSABuilder::IRBuilder;
|
||||
MemorySSA shader::buildMemorySSA(CFG &cfg,
|
||||
const SemanticInfo &instructionSemantic,
|
||||
std::function<ir::Value(int)> getRegisterVarCb,
|
||||
ModuleInfo *moduleInfo) {
|
||||
auto handleSemantic = [&](MemorySSABuilder &builder, ir::memssa::Scope scope,
|
||||
ir::Instruction inst) {
|
||||
auto semantic = instructionSemantic.findSemantic(inst.getInstId());
|
||||
if (semantic == nullptr) {
|
||||
return false;
|
||||
|
|
@ -1006,6 +1005,53 @@ shader::buildMemorySSA(CFG &cfg, const SemanticInfo &instructionSemantic,
|
|||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
auto handleModuleInfo = [&](MemorySSABuilder &builder,
|
||||
ir::memssa::Scope scope, ir::Instruction inst) {
|
||||
if (inst != ir::spv::OpFunctionCall) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto callee = inst.getOperand(1).getAsValue();
|
||||
auto it = moduleInfo->functions.find(callee);
|
||||
auto fnInfo = it == moduleInfo->functions.end() ? nullptr : &it->second;
|
||||
|
||||
if (fnInfo == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (auto [variable, access] : fnInfo->variables) {
|
||||
builder.createPointerAccess(inst, scope, variable, VarSearchType::Root,
|
||||
access);
|
||||
}
|
||||
|
||||
auto args = inst.getOperands();
|
||||
args = args.subspan(args.size() - fnInfo->parameters.size());
|
||||
|
||||
for (std::size_t i = 0; i < args.size(); ++i) {
|
||||
auto arg = args[i].getAsValue();
|
||||
auto param = fnInfo->parameters[i];
|
||||
|
||||
if (param.access == Access::None) {
|
||||
continue;
|
||||
}
|
||||
|
||||
builder.createPointerAccess(inst, scope, arg, VarSearchType::Root,
|
||||
param.access);
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
return MemorySSABuilder{}.build(cfg, [&](MemorySSABuilder &builder,
|
||||
ir::memssa::Scope scope,
|
||||
ir::Instruction inst) {
|
||||
if (handleSemantic(builder, scope, inst)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return moduleInfo != nullptr && handleModuleInfo(builder, scope, inst);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -1013,8 +1059,6 @@ MemorySSA shader::buildMemorySSA(CFG &cfg, ModuleInfo *moduleInfo) {
|
|||
return MemorySSABuilder{}.build(cfg, [&](MemorySSABuilder &builder,
|
||||
ir::memssa::Scope scope,
|
||||
ir::Instruction inst) {
|
||||
using IRBuilder = MemorySSABuilder::IRBuilder;
|
||||
|
||||
if (moduleInfo == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -364,7 +364,8 @@ eval::Value eval::Value::compositeExtract(const Value &index) const {
|
|||
|
||||
eval::Value eval::Value::isNan() const {
|
||||
using Cond = decltype([](auto type) {
|
||||
return std::is_floating_point_v<ComponentType<decltype(type)>> && !IsArray<decltype(type)>;
|
||||
return std::is_floating_point_v<ComponentType<decltype(type)>> &&
|
||||
!IsArray<decltype(type)>;
|
||||
});
|
||||
|
||||
return visit<Cond>(*this, [](auto &&value) -> Value {
|
||||
|
|
@ -384,7 +385,8 @@ eval::Value eval::Value::isNan() const {
|
|||
|
||||
eval::Value eval::Value::isInf() const {
|
||||
using Cond = decltype([](auto type) {
|
||||
return std::is_floating_point_v<ComponentType<decltype(type)>> && !IsArray<decltype(type)>;
|
||||
return std::is_floating_point_v<ComponentType<decltype(type)>> &&
|
||||
!IsArray<decltype(type)>;
|
||||
});
|
||||
|
||||
return visit<Cond>(*this, [](auto &&value) -> Value {
|
||||
|
|
@ -472,7 +474,7 @@ eval::Value eval::Value::makeSigned() const {
|
|||
eval::Value eval::Value::all() const {
|
||||
using Cond = decltype([](auto type) {
|
||||
return std::is_same_v<ComponentType<decltype(type)>, bool> &&
|
||||
(Components<decltype(type)> > 1) && !IsArray<decltype(type)>;
|
||||
(Components<decltype(type)> > 1) && !IsArray<decltype(type)>;
|
||||
});
|
||||
|
||||
return visit<Cond>(*this, [](auto &&value) {
|
||||
|
|
@ -506,7 +508,8 @@ eval::Value eval::Value::any() const {
|
|||
eval::Value eval::Value::select(const Value &trueValue,
|
||||
const Value &falseValue) const {
|
||||
using Cond = decltype([](auto type) consteval {
|
||||
return std::is_same_v<ComponentType<decltype(type)>, bool> && !IsArray<decltype(type)>;
|
||||
return std::is_same_v<ComponentType<decltype(type)>, bool> &&
|
||||
!IsArray<decltype(type)>;
|
||||
});
|
||||
|
||||
return visit<Cond>(*this, [&](auto &&cond) -> Value {
|
||||
|
|
@ -548,7 +551,8 @@ eval::Value eval::Value::iConvert(ir::Value type, bool isSigned) const {
|
|||
using Type = std::remove_cvref_t<decltype(type)>;
|
||||
|
||||
return std::is_integral_v<ComponentType<Type>> &&
|
||||
!std::is_same_v<bool, ComponentType<Type>> && !IsArray<decltype(type)>;
|
||||
!std::is_same_v<bool, ComponentType<Type>> &&
|
||||
!IsArray<decltype(type)>;
|
||||
});
|
||||
|
||||
using PairCond = decltype([](auto lhs, auto rhs) {
|
||||
|
|
@ -571,7 +575,8 @@ eval::Value eval::Value::iConvert(ir::Value type, bool isSigned) const {
|
|||
}
|
||||
eval::Value eval::Value::fConvert(ir::Value type) const {
|
||||
using Cond = decltype([](auto type) {
|
||||
return std::is_floating_point_v<ComponentType<decltype(type)>> && !IsArray<decltype(type)>;
|
||||
return std::is_floating_point_v<ComponentType<decltype(type)>> &&
|
||||
!IsArray<decltype(type)>;
|
||||
});
|
||||
|
||||
using PairCond = decltype([](auto lhs, auto rhs) {
|
||||
|
|
@ -640,10 +645,8 @@ std::optional<std::int64_t> eval::Value::sExtScalar() const {
|
|||
}
|
||||
|
||||
#define DEFINE_BINARY_OP(OP) \
|
||||
eval::Value eval::Value::operator OP(const Value & rhs) const { \
|
||||
using LhsCond = decltype([](auto &&lhs) { \
|
||||
return requires { static_cast<Value>(lhs OP rhs); }; \
|
||||
}); \
|
||||
eval::Value eval::Value::operator OP(const Value &rhs) const { \
|
||||
using LhsCond = decltype([](auto &&lhs) { return true; }); \
|
||||
return visit<LhsCond>(*this, [&]<typename Lhs>(Lhs &&lhs) -> Value { \
|
||||
using RhsCond = decltype([](auto &&rhs) { \
|
||||
return requires(Lhs lhs) { static_cast<Value>(lhs OP rhs); }; \
|
||||
|
|
|
|||
Loading…
Reference in a new issue