| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247 |
- // Copyright 2021 yuzu Emulator Project
- // Licensed under GPLv2 or any later version
- // Refer to the license.txt file included.
- #include <string_view>
- #include "shader_recompiler/backend/glsl/emit_context.h"
- #include "shader_recompiler/backend/glsl/emit_glsl_instructions.h"
- #include "shader_recompiler/frontend/ir/value.h"
- namespace Shader::Backend::GLSL {
- namespace {
- void SetZeroFlag(EmitContext& ctx, IR::Inst& inst, std::string_view result) {
- IR::Inst* const zero{inst.GetAssociatedPseudoOperation(IR::Opcode::GetZeroFromOp)};
- if (!zero) {
- return;
- }
- ctx.AddU1("{}={}==0;", *zero, result);
- zero->Invalidate();
- }
- void SetSignFlag(EmitContext& ctx, IR::Inst& inst, std::string_view result) {
- IR::Inst* const sign{inst.GetAssociatedPseudoOperation(IR::Opcode::GetSignFromOp)};
- if (!sign) {
- return;
- }
- ctx.AddU1("{}=int({})<0;", *sign, result);
- sign->Invalidate();
- }
- } // Anonymous namespace
- void EmitIAdd32(EmitContext& ctx, IR::Inst& inst, std::string_view a, std::string_view b) {
- const auto result{ctx.var_alloc.Define(inst, GlslVarType::U32)};
- if (IR::Inst* const carry{inst.GetAssociatedPseudoOperation(IR::Opcode::GetCarryFromOp)}) {
- ctx.uses_cc_carry = true;
- ctx.Add("iadd_op_b={};{}=uaddCarry({},{},carry);", b, result, a, b);
- ctx.AddU1("{}=carry!=0;", *carry);
- carry->Invalidate();
- } else {
- ctx.Add("{}={}+{};", result, a, b);
- }
- SetZeroFlag(ctx, inst, result);
- SetSignFlag(ctx, inst, result);
- if (IR::Inst * overflow{inst.GetAssociatedPseudoOperation(IR::Opcode::GetOverflowFromOp)}) {
- // https://stackoverflow.com/questions/55468823/how-to-detect-integer-overflow-in-c
- constexpr u32 s32_max{static_cast<u32>(std::numeric_limits<s32>::max())};
- const auto sub_a{fmt::format("{}u-{}", s32_max, a)};
- const auto op_b{ctx.uses_cc_carry ? "iadd_op_b" : b};
- ctx.AddU1("{}=int({})>=0?int({})>int({}):int({})<int({});", *overflow, a, op_b, sub_a, op_b,
- sub_a);
- overflow->Invalidate();
- }
- }
- void EmitIAdd64(EmitContext& ctx, IR::Inst& inst, std::string_view a, std::string_view b) {
- ctx.AddU64("{}={}+{};", inst, a, b);
- }
- void EmitISub32(EmitContext& ctx, IR::Inst& inst, std::string_view a, std::string_view b) {
- ctx.AddU32("{}={}-{};", inst, a, b);
- }
- void EmitISub64(EmitContext& ctx, IR::Inst& inst, std::string_view a, std::string_view b) {
- ctx.AddU64("{}={}-{};", inst, a, b);
- }
- void EmitIMul32(EmitContext& ctx, IR::Inst& inst, std::string_view a, std::string_view b) {
- ctx.AddU32("{}=uint({}*{});", inst, a, b);
- }
- void EmitINeg32(EmitContext& ctx, IR::Inst& inst, std::string_view value) {
- ctx.AddU32("{}=uint(-({}));", inst, value);
- }
- void EmitINeg64(EmitContext& ctx, IR::Inst& inst, std::string_view value) {
- ctx.AddU64("{}=-({});", inst, value);
- }
- void EmitIAbs32(EmitContext& ctx, IR::Inst& inst, std::string_view value) {
- ctx.AddU32("{}=abs(int({}));", inst, value);
- }
- void EmitIAbs64(EmitContext& ctx, IR::Inst& inst, std::string_view value) {
- ctx.AddU64("{}=abs(int64_t({}));", inst, value);
- }
- void EmitShiftLeftLogical32(EmitContext& ctx, IR::Inst& inst, std::string_view base,
- std::string_view shift) {
- ctx.AddU32("{}={}<<{};", inst, base, shift);
- }
- void EmitShiftLeftLogical64(EmitContext& ctx, IR::Inst& inst, std::string_view base,
- std::string_view shift) {
- ctx.AddU64("{}={}<<{};", inst, base, shift);
- }
- void EmitShiftRightLogical32(EmitContext& ctx, IR::Inst& inst, std::string_view base,
- std::string_view shift) {
- ctx.AddU32("{}={}>>{};", inst, base, shift);
- }
- void EmitShiftRightLogical64(EmitContext& ctx, IR::Inst& inst, std::string_view base,
- std::string_view shift) {
- ctx.AddU64("{}={}>>{};", inst, base, shift);
- }
- void EmitShiftRightArithmetic32(EmitContext& ctx, IR::Inst& inst, std::string_view base,
- std::string_view shift) {
- ctx.AddU32("{}=int({})>>{};", inst, base, shift);
- }
- void EmitShiftRightArithmetic64(EmitContext& ctx, IR::Inst& inst, std::string_view base,
- std::string_view shift) {
- ctx.AddU64("{}=int64_t({})>>{};", inst, base, shift);
- }
- void EmitBitwiseAnd32(EmitContext& ctx, IR::Inst& inst, std::string_view a, std::string_view b) {
- ctx.AddU32("{}={}&{};", inst, a, b);
- }
- void EmitBitwiseOr32(EmitContext& ctx, IR::Inst& inst, std::string_view a, std::string_view b) {
- ctx.AddU32("{}={}|{};", inst, a, b);
- }
- void EmitBitwiseXor32(EmitContext& ctx, IR::Inst& inst, std::string_view a, std::string_view b) {
- ctx.AddU32("{}={}^{};", inst, a, b);
- }
- void EmitBitFieldInsert(EmitContext& ctx, IR::Inst& inst, std::string_view base,
- std::string_view insert, std::string_view offset, std::string_view count) {
- ctx.AddU32("{}=bitfieldInsert({},{},int({}),int({}));", inst, base, insert, offset, count);
- }
- void EmitBitFieldSExtract(EmitContext& ctx, IR::Inst& inst, std::string_view base,
- std::string_view offset, std::string_view count) {
- const auto result{ctx.var_alloc.Define(inst, GlslVarType::U32)};
- ctx.Add("{}=uint(bitfieldExtract(int({}),int({}),int({})));", result, base, offset, count);
- SetZeroFlag(ctx, inst, result);
- SetSignFlag(ctx, inst, result);
- }
- void EmitBitFieldUExtract(EmitContext& ctx, IR::Inst& inst, std::string_view base,
- std::string_view offset, std::string_view count) {
- const auto result{ctx.var_alloc.Define(inst, GlslVarType::U32)};
- ctx.Add("{}=uint(bitfieldExtract(uint({}),int({}),int({})));", result, base, offset, count);
- SetZeroFlag(ctx, inst, result);
- SetSignFlag(ctx, inst, result);
- }
- void EmitBitReverse32(EmitContext& ctx, IR::Inst& inst, std::string_view value) {
- ctx.AddU32("{}=bitfieldReverse({});", inst, value);
- }
- void EmitBitCount32(EmitContext& ctx, IR::Inst& inst, std::string_view value) {
- ctx.AddU32("{}=bitCount({});", inst, value);
- }
- void EmitBitwiseNot32(EmitContext& ctx, IR::Inst& inst, std::string_view value) {
- ctx.AddU32("{}=~{};", inst, value);
- }
- void EmitFindSMsb32(EmitContext& ctx, IR::Inst& inst, std::string_view value) {
- ctx.AddU32("{}=findMSB(int({}));", inst, value);
- }
- void EmitFindUMsb32(EmitContext& ctx, IR::Inst& inst, std::string_view value) {
- ctx.AddU32("{}=findMSB(uint({}));", inst, value);
- }
- void EmitSMin32(EmitContext& ctx, IR::Inst& inst, std::string_view a, std::string_view b) {
- ctx.AddU32("{}=min(int({}),int({}));", inst, a, b);
- }
- void EmitUMin32(EmitContext& ctx, IR::Inst& inst, std::string_view a, std::string_view b) {
- ctx.AddU32("{}=min(uint({}),uint({}));", inst, a, b);
- }
- void EmitSMax32(EmitContext& ctx, IR::Inst& inst, std::string_view a, std::string_view b) {
- ctx.AddU32("{}=max(int({}),int({}));", inst, a, b);
- }
- void EmitUMax32(EmitContext& ctx, IR::Inst& inst, std::string_view a, std::string_view b) {
- ctx.AddU32("{}=max(uint({}),uint({}));", inst, a, b);
- }
- void EmitSClamp32(EmitContext& ctx, IR::Inst& inst, std::string_view value, std::string_view min,
- std::string_view max) {
- const auto result{ctx.var_alloc.Define(inst, GlslVarType::U32)};
- ctx.Add("{}=clamp(int({}),int({}),int({}));", result, value, min, max);
- SetZeroFlag(ctx, inst, result);
- SetSignFlag(ctx, inst, result);
- }
- void EmitUClamp32(EmitContext& ctx, IR::Inst& inst, std::string_view value, std::string_view min,
- std::string_view max) {
- const auto result{ctx.var_alloc.Define(inst, GlslVarType::U32)};
- ctx.Add("{}=clamp(uint({}),uint({}),uint({}));", result, value, min, max);
- SetZeroFlag(ctx, inst, result);
- SetSignFlag(ctx, inst, result);
- }
- void EmitSLessThan(EmitContext& ctx, IR::Inst& inst, std::string_view lhs, std::string_view rhs) {
- ctx.AddU1("{}=int({})<int({});", inst, lhs, rhs);
- }
- void EmitULessThan(EmitContext& ctx, IR::Inst& inst, std::string_view lhs, std::string_view rhs) {
- ctx.AddU1("{}=uint({})<uint({});", inst, lhs, rhs);
- }
- void EmitIEqual(EmitContext& ctx, IR::Inst& inst, std::string_view lhs, std::string_view rhs) {
- ctx.AddU1("{}={}=={};", inst, lhs, rhs);
- }
- void EmitSLessThanEqual(EmitContext& ctx, IR::Inst& inst, std::string_view lhs,
- std::string_view rhs) {
- ctx.AddU1("{}=int({})<=int({});", inst, lhs, rhs);
- }
- void EmitULessThanEqual(EmitContext& ctx, IR::Inst& inst, std::string_view lhs,
- std::string_view rhs) {
- ctx.AddU1("{}=uint({})<=uint({});", inst, lhs, rhs);
- }
- void EmitSGreaterThan(EmitContext& ctx, IR::Inst& inst, std::string_view lhs,
- std::string_view rhs) {
- ctx.AddU1("{}=int({})>int({});", inst, lhs, rhs);
- }
- void EmitUGreaterThan(EmitContext& ctx, IR::Inst& inst, std::string_view lhs,
- std::string_view rhs) {
- ctx.AddU1("{}=uint({})>uint({});", inst, lhs, rhs);
- }
- void EmitINotEqual(EmitContext& ctx, IR::Inst& inst, std::string_view lhs, std::string_view rhs) {
- ctx.AddU1("{}={}!={};", inst, lhs, rhs);
- }
- void EmitSGreaterThanEqual(EmitContext& ctx, IR::Inst& inst, std::string_view lhs,
- std::string_view rhs) {
- ctx.AddU1("{}=int({})>=int({});", inst, lhs, rhs);
- }
- void EmitUGreaterThanEqual(EmitContext& ctx, IR::Inst& inst, std::string_view lhs,
- std::string_view rhs) {
- ctx.AddU1("{}=uint({})>=uint({});", inst, lhs, rhs);
- }
- } // namespace Shader::Backend::GLSL
|