Add semantic::Intrinsic
semantic::Intrinsic derives from semantic::CallTarget, which can be obtained from the Target() accessor on the CallExpression.
Flesh out semantic::Parameter to contain a `Usage` - extra metadata for the parameter.
The information in `Intrinsic` is enough to remove the `semantic::IntrinsicCall` and `semantic::TextureIntrinsicCall` types.
Change-Id: Ida9c193674ad8605d8f12f6a1d27f38c7d008434
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/40503
Reviewed-by: dan sinclair <dsinclair@chromium.org>
Commit-Queue: Ben Clayton <bclayton@google.com>
diff --git a/src/semantic/call.h b/src/semantic/call.h
index 6351421..0ef874f 100644
--- a/src/semantic/call.h
+++ b/src/semantic/call.h
@@ -26,96 +26,17 @@
class Call : public Castable<Call, Expression> {
public:
/// Constructor
- /// @param return_type the return type of the call
- explicit Call(type::Type* return_type);
+ /// @param target the call target
+ explicit Call(const CallTarget* target);
/// Destructor
~Call() override;
-};
-/// IntrinsicCall holds semantic information for ast::CallExpression nodes that
-/// call intrinsic functions.
-class IntrinsicCall : public Castable<IntrinsicCall, Call> {
- public:
- /// Constructor
- /// @param return_type the return type of the call
- /// @param intrinsic the call target intrinsic
- IntrinsicCall(type::Type* return_type, IntrinsicType intrinsic);
-
- /// Destructor
- ~IntrinsicCall() override;
-
- /// @returns the target intrinsic for the call
- IntrinsicType intrinsic() const { return intrinsic_; }
+ /// @return the target of the call
+ const CallTarget* Target() const { return target_; }
private:
- IntrinsicType const intrinsic_;
-};
-
-/// TextureIntrinsicCall holds semantic information for ast::CallExpression
-/// nodes that call intrinsic texture functions.
-class TextureIntrinsicCall
- : public Castable<TextureIntrinsicCall, IntrinsicCall> {
- public:
- /// Parameters describes the parameters for the texture function.
- struct Parameters {
- /// kNotUsed is the constant that indicates the given parameter is not part
- /// of the texture function signature.
- static constexpr const size_t kNotUsed = ~static_cast<size_t>(0u);
- /// Index holds each of the possible parameter indices. If a parameter index
- /// is equal to `kNotUsed` then this parameter is not used by the function.
- struct Index {
- /// Constructor
- Index();
- /// Copy constructor
- Index(const Index&);
- /// `array_index` parameter index.
- size_t array_index = kNotUsed;
- /// `bias` parameter index.
- size_t bias = kNotUsed;
- /// `coords` parameter index.
- size_t coords = kNotUsed;
- /// `depth_ref` parameter index.
- size_t depth_ref = kNotUsed;
- /// `ddx` parameter index.
- size_t ddx = kNotUsed;
- /// `ddy` parameter index.
- size_t ddy = kNotUsed;
- /// `level` parameter index.
- size_t level = kNotUsed;
- /// `offset` parameter index.
- size_t offset = kNotUsed;
- /// `sampler` parameter index.
- size_t sampler = kNotUsed;
- /// `sample_index` parameter index.
- size_t sample_index = kNotUsed;
- /// `texture` parameter index.
- size_t texture = kNotUsed;
- /// `value` parameter index.
- size_t value = kNotUsed;
- };
- /// The indices of all possible parameters.
- Index idx;
- /// Total number of parameters.
- size_t count = 0;
- };
-
- /// Constructor
- /// @param return_type the return type of the call
- /// @param intrinsic the call target intrinsic
- /// @param params the overload parameter info
- TextureIntrinsicCall(type::Type* return_type,
- IntrinsicType intrinsic,
- const Parameters& params);
-
- /// Destructor
- ~TextureIntrinsicCall() override;
-
- /// @return the texture call's parameters
- const Parameters& Params() const { return params_; }
-
- private:
- const Parameters params_;
+ CallTarget const* const target_;
};
} // namespace semantic
diff --git a/src/semantic/call_target.h b/src/semantic/call_target.h
index ddb6aac..43cbc0e 100644
--- a/src/semantic/call_target.h
+++ b/src/semantic/call_target.h
@@ -32,18 +32,52 @@
/// Parameter describes a single parameter of a call target
struct Parameter {
+ /// Usage is extra metadata for identifying a parameter based on its overload
+ /// position
+ enum class Usage {
+ kNone,
+ kArrayIndex,
+ kBias,
+ kCoords,
+ kDepthRef,
+ kDdx,
+ kDdy,
+ kLevel,
+ kOffset,
+ kSampler,
+ kSampleIndex,
+ kTexture,
+ kValue,
+ };
+
/// Parameter type
- type::Type* type;
+ type::Type* const type;
+ /// Parameter usage
+ Usage const usage = Usage::kNone;
};
+/// @returns a string representation of the given parameter usage.
+const char* str(Parameter::Usage usage);
+
+/// Parameters is a list of Parameter
using Parameters = std::vector<Parameter>;
+/// @param parameters the list of parameters
+/// @param usage the parameter usage to find
+/// @returns the index of the parameter with the given usage, or -1 if no
+/// parameter with the given usage exists.
+int IndexOf(const Parameters& parameters, Parameter::Usage usage);
+
/// CallTarget is the base for callable functions
class CallTarget : public Castable<CallTarget, Node> {
public:
/// Constructor
+ /// @param return_type the return type of the call target
/// @param parameters the parameters for the call target
- explicit CallTarget(const semantic::Parameters& parameters);
+ CallTarget(type::Type* return_type, const semantic::Parameters& parameters);
+
+ /// @return the return type of the call target
+ type::Type* ReturnType() const { return return_type_; }
/// Destructor
~CallTarget() override;
@@ -52,7 +86,8 @@
const Parameters& Parameters() const { return parameters_; }
private:
- semantic::Parameters parameters_;
+ type::Type* const return_type_;
+ semantic::Parameters const parameters_;
};
} // namespace semantic
diff --git a/src/semantic/intrinsic.h b/src/semantic/intrinsic.h
index f006f31..e2c1902 100644
--- a/src/semantic/intrinsic.h
+++ b/src/semantic/intrinsic.h
@@ -17,6 +17,8 @@
#include <ostream>
+#include "src/semantic/call_target.h"
+
namespace tint {
namespace semantic {
@@ -102,39 +104,37 @@
kTrunc
};
-/// Emits the name of the intrinsic function. The spelling,
-/// including case, matches the name in the WGSL spec.
-std::ostream& operator<<(std::ostream& out, IntrinsicType i);
-
-namespace intrinsic {
+/// @returns the name of the intrinsic function type. The spelling, including
+/// case, matches the name in the WGSL spec.
+const char* str(IntrinsicType i);
/// Determines if the given `i` is a coarse derivative
-/// @param i the intrinsic
+/// @param i the intrinsic type
/// @returns true if the given derivative is coarse.
-bool IsCoarseDerivative(IntrinsicType i);
+bool IsCoarseDerivativeIntrinsic(IntrinsicType i);
/// Determines if the given `i` is a fine derivative
-/// @param i the intrinsic
+/// @param i the intrinsic type
/// @returns true if the given derivative is fine.
-bool IsFineDerivative(IntrinsicType i);
+bool IsFineDerivativeIntrinsic(IntrinsicType i);
/// Determine if the given `i` is a derivative intrinsic
-/// @param i the intrinsic
+/// @param i the intrinsic type
/// @returns true if the given `i` is a derivative intrinsic
-bool IsDerivative(IntrinsicType i);
+bool IsDerivativeIntrinsic(IntrinsicType i);
/// Determines if the given `i` is a float classification intrinsic
-/// @param i the intrinsic
+/// @param i the intrinsic type
/// @returns true if the given `i` is a float intrinsic
bool IsFloatClassificationIntrinsic(IntrinsicType i);
/// Determines if the given `i` is a texture operation intrinsic
-/// @param i the intrinsic
+/// @param i the intrinsic type
/// @returns true if the given `i` is a texture operation intrinsic
bool IsTextureIntrinsic(IntrinsicType i);
/// Determines if the given `i` is a image query intrinsic
-/// @param i the intrinsic
+/// @param i the intrinsic type
/// @returns true if the given `i` is a image query intrinsic
bool IsImageQueryIntrinsic(IntrinsicType i);
@@ -143,11 +143,56 @@
/// @returns true if the given `i` is a data packing intrinsic
bool IsDataPackingIntrinsic(IntrinsicType i);
-/// @returns the name of the intrinsic function. The spelling, including case,
-/// matches the name in the WGSL spec.
-const char* str(IntrinsicType i);
+/// Intrinsic holds the semantic information for an intrinsic function.
+class Intrinsic : public Castable<Intrinsic, CallTarget> {
+ public:
+ /// Constructor
+ /// @param type the intrinsic type
+ /// @param return_type the return type for the intrinsic call
+ /// @param parameters the parameters for the intrinsic overload
+ Intrinsic(IntrinsicType type,
+ type::Type* return_type,
+ const semantic::Parameters& parameters);
-} // namespace intrinsic
+ /// Destructor
+ ~Intrinsic() override;
+
+ /// @return the type of the intrinsic
+ IntrinsicType Type() const { return type_; }
+
+ /// @returns the name of the intrinsic function type. The spelling, including
+ /// case, matches the name in the WGSL spec.
+ const char* str() const;
+
+ /// @returns true if intrinsic is a coarse derivative intrinsic
+ bool IsCoarseDerivative() const;
+
+ /// @returns true if intrinsic is a fine a derivative intrinsic
+ bool IsFineDerivative() const;
+
+ /// @returns true if intrinsic is a derivative intrinsic
+ bool IsDerivative() const;
+
+ /// @returns true if intrinsic is a float intrinsic
+ bool IsFloatClassification() const;
+
+ /// @returns true if intrinsic is a texture operation intrinsic
+ bool IsTexture() const;
+
+ /// @returns true if intrinsic is a image query intrinsic
+ bool IsImageQuery() const;
+
+ /// @returns true if intrinsic is a data packing intrinsic
+ bool IsDataPacking() const;
+
+ private:
+ IntrinsicType const type_;
+};
+
+/// Emits the name of the intrinsic function type. The spelling, including case,
+/// matches the name in the WGSL spec.
+std::ostream& operator<<(std::ostream& out, IntrinsicType i);
+
} // namespace semantic
} // namespace tint
diff --git a/src/semantic/sem_call.cc b/src/semantic/sem_call.cc
index 777ad51..632f3a0 100644
--- a/src/semantic/sem_call.cc
+++ b/src/semantic/sem_call.cc
@@ -15,30 +15,14 @@
#include "src/semantic/call.h"
TINT_INSTANTIATE_CLASS_ID(tint::semantic::Call);
-TINT_INSTANTIATE_CLASS_ID(tint::semantic::IntrinsicCall);
-TINT_INSTANTIATE_CLASS_ID(tint::semantic::TextureIntrinsicCall);
namespace tint {
namespace semantic {
-Call::Call(type::Type* return_type) : Base(return_type) {}
+Call::Call(const CallTarget* target)
+ : Base(target->ReturnType()), target_(target) {}
Call::~Call() = default;
-IntrinsicCall::IntrinsicCall(type::Type* return_type, IntrinsicType intrinsic)
- : Base(return_type), intrinsic_(intrinsic) {}
-
-IntrinsicCall::~IntrinsicCall() = default;
-
-TextureIntrinsicCall::TextureIntrinsicCall(type::Type* return_type,
- IntrinsicType intrinsic,
- const Parameters& params)
- : Base(return_type, intrinsic), params_(params) {}
-
-TextureIntrinsicCall::~TextureIntrinsicCall() = default;
-
-TextureIntrinsicCall::Parameters::Index::Index() = default;
-TextureIntrinsicCall::Parameters::Index::Index(const Index&) = default;
-
} // namespace semantic
} // namespace tint
diff --git a/src/semantic/sem_call_target.cc b/src/semantic/sem_call_target.cc
index 3b79a55..ad7f300 100644
--- a/src/semantic/sem_call_target.cc
+++ b/src/semantic/sem_call_target.cc
@@ -21,10 +21,50 @@
namespace tint {
namespace semantic {
-CallTarget::CallTarget(const semantic::Parameters& parameters)
- : parameters_(parameters) {}
+CallTarget::CallTarget(type::Type* return_type,
+ const semantic::Parameters& parameters)
+ : return_type_(return_type), parameters_(parameters) {}
CallTarget::~CallTarget() = default;
+int IndexOf(const Parameters& parameters, Parameter::Usage usage) {
+ for (size_t i = 0; i < parameters.size(); i++) {
+ if (parameters[i].usage == usage) {
+ return static_cast<int>(i);
+ }
+ }
+ return -1;
+}
+
+const char* str(Parameter::Usage usage) {
+ switch (usage) {
+ case Parameter::Usage::kArrayIndex:
+ return "array_index";
+ case Parameter::Usage::kBias:
+ return "bias";
+ case Parameter::Usage::kCoords:
+ return "coords";
+ case Parameter::Usage::kDepthRef:
+ return "depth_ref";
+ case Parameter::Usage::kDdx:
+ return "ddx";
+ case Parameter::Usage::kDdy:
+ return "ddy";
+ case Parameter::Usage::kLevel:
+ return "level";
+ case Parameter::Usage::kOffset:
+ return "offset";
+ case Parameter::Usage::kSampler:
+ return "sampler";
+ case Parameter::Usage::kSampleIndex:
+ return "sample_index";
+ case Parameter::Usage::kTexture:
+ return "texture";
+ case Parameter::Usage::kValue:
+ return "value";
+ default:
+ return "<unknown>";
+ }
+}
} // namespace semantic
} // namespace tint
diff --git a/src/semantic/sem_function.cc b/src/semantic/sem_function.cc
index 8c8d16c..db53339 100644
--- a/src/semantic/sem_function.cc
+++ b/src/semantic/sem_function.cc
@@ -37,7 +37,7 @@
semantic::Parameters parameters;
parameters.reserve(ast->params().size());
for (auto* param : ast->params()) {
- parameters.emplace_back(Parameter{param->type()});
+ parameters.emplace_back(Parameter{param->type(), Parameter::Usage::kNone});
}
return parameters;
}
@@ -48,7 +48,7 @@
std::vector<const Variable*> referenced_module_vars,
std::vector<const Variable*> local_referenced_module_vars,
std::vector<Symbol> ancestor_entry_points)
- : Base(GetParameters(ast)),
+ : Base(ast->return_type(), GetParameters(ast)),
referenced_module_vars_(std::move(referenced_module_vars)),
local_referenced_module_vars_(std::move(local_referenced_module_vars)),
ancestor_entry_points_(std::move(ancestor_entry_points)) {}
diff --git a/src/semantic/sem_intrinsic.cc b/src/semantic/sem_intrinsic.cc
index b2eea27..e12c1b4 100644
--- a/src/semantic/sem_intrinsic.cc
+++ b/src/semantic/sem_intrinsic.cc
@@ -14,15 +14,19 @@
#include "src/semantic/intrinsic.h"
+TINT_INSTANTIATE_CLASS_ID(tint::semantic::Intrinsic);
+
namespace tint {
namespace semantic {
std::ostream& operator<<(std::ostream& out, IntrinsicType i) {
- out << intrinsic::str(i);
+ out << str(i);
return out;
}
-namespace intrinsic {
+const char* Intrinsic::str() const {
+ return semantic::str(type_);
+}
const char* str(IntrinsicType i) {
/// The emitted name matches the spelling in the WGSL spec.
@@ -188,20 +192,20 @@
return "<unknown>";
}
-bool IsCoarseDerivative(IntrinsicType i) {
+bool IsCoarseDerivativeIntrinsic(IntrinsicType i) {
return i == IntrinsicType::kDpdxCoarse || i == IntrinsicType::kDpdyCoarse ||
i == IntrinsicType::kFwidthCoarse;
}
-bool IsFineDerivative(IntrinsicType i) {
+bool IsFineDerivativeIntrinsic(IntrinsicType i) {
return i == IntrinsicType::kDpdxFine || i == IntrinsicType::kDpdyFine ||
i == IntrinsicType::kFwidthFine;
}
-bool IsDerivative(IntrinsicType i) {
+bool IsDerivativeIntrinsic(IntrinsicType i) {
return i == IntrinsicType::kDpdx || i == IntrinsicType::kDpdy ||
- i == IntrinsicType::kFwidth || IsCoarseDerivative(i) ||
- IsFineDerivative(i);
+ i == IntrinsicType::kFwidth || IsCoarseDerivativeIntrinsic(i) ||
+ IsFineDerivativeIntrinsic(i);
}
bool IsFloatClassificationIntrinsic(IntrinsicType i) {
@@ -220,7 +224,7 @@
}
bool IsImageQueryIntrinsic(IntrinsicType i) {
- return i == semantic::IntrinsicType::kTextureDimensions ||
+ return i == IntrinsicType::kTextureDimensions ||
i == IntrinsicType::kTextureNumLayers ||
i == IntrinsicType::kTextureNumLevels ||
i == IntrinsicType::kTextureNumSamples;
@@ -234,6 +238,40 @@
i == IntrinsicType::kPack2x16Float;
}
-} // namespace intrinsic
+Intrinsic::Intrinsic(IntrinsicType type,
+ type::Type* return_type,
+ const semantic::Parameters& parameters)
+ : Base(return_type, parameters), type_(type) {}
+
+Intrinsic::~Intrinsic() = default;
+
+bool Intrinsic::IsCoarseDerivative() const {
+ return IsCoarseDerivativeIntrinsic(type_);
+}
+
+bool Intrinsic::IsFineDerivative() const {
+ return IsFineDerivativeIntrinsic(type_);
+}
+
+bool Intrinsic::IsDerivative() const {
+ return IsDerivativeIntrinsic(type_);
+}
+
+bool Intrinsic::IsFloatClassification() const {
+ return IsFloatClassificationIntrinsic(type_);
+}
+
+bool Intrinsic::IsTexture() const {
+ return IsTextureIntrinsic(type_);
+}
+
+bool Intrinsic::IsImageQuery() const {
+ return IsImageQueryIntrinsic(type_);
+}
+
+bool Intrinsic::IsDataPacking() const {
+ return IsDataPackingIntrinsic(type_);
+}
+
} // namespace semantic
} // namespace tint
diff --git a/src/type_determiner.cc b/src/type_determiner.cc
index 6b47ffa..7ea3c09 100644
--- a/src/type_determiner.cc
+++ b/src/type_determiner.cc
@@ -419,9 +419,9 @@
auto name = builder_->Symbols().NameFor(ident->symbol());
- auto intrinsic = MatchIntrinsic(name);
- if (intrinsic != IntrinsicType::kNone) {
- if (!DetermineIntrinsicCall(call, intrinsic)) {
+ auto intrinsic_type = MatchIntrinsicType(name);
+ if (intrinsic_type != IntrinsicType::kNone) {
+ if (!DetermineIntrinsicCall(call, intrinsic_type)) {
return false;
}
} else {
@@ -450,9 +450,7 @@
}
auto* function = iter->second;
- auto* return_ty = function->declaration->return_type();
- auto* sem = builder_->create<semantic::Call>(return_ty);
- builder_->Sem().Add(call, sem);
+ function_calls_.emplace(call, function);
}
return true;
@@ -548,14 +546,26 @@
} // namespace
bool TypeDeterminer::DetermineIntrinsicCall(ast::CallExpression* call,
- IntrinsicType intrinsic) {
- auto create_sem = [&](type::Type* result) {
- auto* sem = builder_->create<semantic::IntrinsicCall>(result, intrinsic);
- builder_->Sem().Add(call, sem);
+ IntrinsicType intrinsic_type) {
+ using Parameter = semantic::Parameter;
+ using Parameters = semantic::Parameters;
+ using Usage = Parameter::Usage;
+
+ std::vector<type::Type*> arg_tys;
+ arg_tys.reserve(call->params().size());
+ for (auto* expr : call->params()) {
+ arg_tys.emplace_back(TypeOf(expr));
+ }
+
+ auto create_sem = [&](type::Type* return_type) {
+ semantic::Parameters params; // TODO(bclayton): Populate this
+ auto* intrinsic = builder_->create<semantic::Intrinsic>(
+ intrinsic_type, return_type, params);
+ builder_->Sem().Add(call, builder_->create<semantic::Call>(intrinsic));
};
- std::string name = semantic::intrinsic::str(intrinsic);
- if (semantic::intrinsic::IsFloatClassificationIntrinsic(intrinsic)) {
+ std::string name = semantic::str(intrinsic_type);
+ if (semantic::IsFloatClassificationIntrinsic(intrinsic_type)) {
if (call->params().size() != 1) {
set_error(call->source(), "incorrect number of parameters for " + name);
return false;
@@ -571,131 +581,135 @@
}
return true;
}
- if (semantic::intrinsic::IsTextureIntrinsic(intrinsic)) {
- semantic::TextureIntrinsicCall::Parameters param;
+ if (semantic::IsTextureIntrinsic(intrinsic_type)) {
+ Parameters params;
- auto* texture_param = call->params()[0];
- if (!TypeOf(texture_param)->UnwrapAll()->Is<type::Texture>()) {
+ auto& ty = builder_->ty;
+
+ auto* texture = arg_tys[0]->UnwrapAll()->As<type::Texture>();
+ if (!texture) {
set_error(call->source(), "invalid first argument for " + name);
return false;
}
- type::Texture* texture =
- TypeOf(texture_param)->UnwrapAll()->As<type::Texture>();
bool is_array = type::IsTextureArray(texture->dim());
bool is_multisampled = texture->Is<type::MultisampledTexture>();
- switch (intrinsic) {
+ switch (intrinsic_type) {
case IntrinsicType::kTextureDimensions:
- param.idx.texture = param.count++;
- if (call->params().size() > param.count) {
- param.idx.level = param.count++;
+ params.emplace_back(Parameter{texture, Usage::kTexture});
+ if (arg_tys.size() > params.size()) {
+ params.emplace_back(Parameter{ty.i32(), Usage::kLevel});
}
break;
case IntrinsicType::kTextureNumLayers:
case IntrinsicType::kTextureNumLevels:
case IntrinsicType::kTextureNumSamples:
- param.idx.texture = param.count++;
+ params.emplace_back(Parameter{texture, Usage::kTexture});
break;
case IntrinsicType::kTextureLoad:
- param.idx.texture = param.count++;
- param.idx.coords = param.count++;
+ params.emplace_back(Parameter{texture, Usage::kTexture});
+ params.emplace_back(Parameter{arg_tys[1], Usage::kCoords});
if (is_array) {
- param.idx.array_index = param.count++;
+ params.emplace_back(Parameter{ty.i32(), Usage::kArrayIndex});
}
- if (call->params().size() > param.count) {
+ if (arg_tys.size() > params.size()) {
if (is_multisampled) {
- param.idx.sample_index = param.count++;
+ params.emplace_back(Parameter{ty.i32(), Usage::kSampleIndex});
} else {
- param.idx.level = param.count++;
+ params.emplace_back(Parameter{ty.i32(), Usage::kLevel});
}
}
break;
case IntrinsicType::kTextureSample:
- param.idx.texture = param.count++;
- param.idx.sampler = param.count++;
- param.idx.coords = param.count++;
+ params.emplace_back(Parameter{texture, Usage::kTexture});
+ params.emplace_back(Parameter{arg_tys[1], Usage::kSampler});
+ params.emplace_back(Parameter{arg_tys[2], Usage::kCoords});
if (is_array) {
- param.idx.array_index = param.count++;
+ params.emplace_back(Parameter{ty.i32(), Usage::kArrayIndex});
}
- if (call->params().size() > param.count) {
- param.idx.offset = param.count++;
+ if (arg_tys.size() > params.size()) {
+ params.emplace_back(
+ Parameter{arg_tys[params.size()], Usage::kOffset});
}
break;
case IntrinsicType::kTextureSampleBias:
- param.idx.texture = param.count++;
- param.idx.sampler = param.count++;
- param.idx.coords = param.count++;
+ params.emplace_back(Parameter{texture, Usage::kTexture});
+ params.emplace_back(Parameter{arg_tys[1], Usage::kSampler});
+ params.emplace_back(Parameter{arg_tys[2], Usage::kCoords});
if (is_array) {
- param.idx.array_index = param.count++;
+ params.emplace_back(Parameter{ty.i32(), Usage::kArrayIndex});
}
- param.idx.bias = param.count++;
- if (call->params().size() > param.count) {
- param.idx.offset = param.count++;
+ params.emplace_back(Parameter{ty.f32(), Usage::kBias});
+ if (arg_tys.size() > params.size()) {
+ params.emplace_back(
+ Parameter{arg_tys[params.size()], Usage::kOffset});
}
break;
case IntrinsicType::kTextureSampleLevel:
- param.idx.texture = param.count++;
- param.idx.sampler = param.count++;
- param.idx.coords = param.count++;
+ params.emplace_back(Parameter{texture, Usage::kTexture});
+ params.emplace_back(Parameter{arg_tys[1], Usage::kSampler});
+ params.emplace_back(Parameter{arg_tys[2], Usage::kCoords});
if (is_array) {
- param.idx.array_index = param.count++;
+ params.emplace_back(Parameter{ty.i32(), Usage::kArrayIndex});
}
- param.idx.level = param.count++;
- if (call->params().size() > param.count) {
- param.idx.offset = param.count++;
+ params.emplace_back(Parameter{ty.i32(), Usage::kLevel});
+ if (arg_tys.size() > params.size()) {
+ params.emplace_back(
+ Parameter{arg_tys[params.size()], Usage::kOffset});
}
break;
case IntrinsicType::kTextureSampleCompare:
- param.idx.texture = param.count++;
- param.idx.sampler = param.count++;
- param.idx.coords = param.count++;
+ params.emplace_back(Parameter{texture, Usage::kTexture});
+ params.emplace_back(Parameter{arg_tys[1], Usage::kSampler});
+ params.emplace_back(Parameter{arg_tys[2], Usage::kCoords});
if (is_array) {
- param.idx.array_index = param.count++;
+ params.emplace_back(Parameter{ty.i32(), Usage::kArrayIndex});
}
- param.idx.depth_ref = param.count++;
- if (call->params().size() > param.count) {
- param.idx.offset = param.count++;
+ params.emplace_back(Parameter{ty.f32(), Usage::kDepthRef});
+ if (arg_tys.size() > params.size()) {
+ params.emplace_back(
+ Parameter{arg_tys[params.size()], Usage::kOffset});
}
break;
case IntrinsicType::kTextureSampleGrad:
- param.idx.texture = param.count++;
- param.idx.sampler = param.count++;
- param.idx.coords = param.count++;
+ params.emplace_back(Parameter{texture, Usage::kTexture});
+ params.emplace_back(Parameter{arg_tys[1], Usage::kSampler});
+ params.emplace_back(Parameter{arg_tys[2], Usage::kCoords});
if (is_array) {
- param.idx.array_index = param.count++;
+ params.emplace_back(Parameter{ty.i32(), Usage::kArrayIndex});
}
- param.idx.ddx = param.count++;
- param.idx.ddy = param.count++;
- if (call->params().size() > param.count) {
- param.idx.offset = param.count++;
+ params.emplace_back(Parameter{arg_tys[params.size()], Usage::kDdx});
+ params.emplace_back(Parameter{arg_tys[params.size()], Usage::kDdy});
+ if (arg_tys.size() > params.size()) {
+ params.emplace_back(
+ Parameter{arg_tys[params.size()], Usage::kOffset});
}
break;
case IntrinsicType::kTextureStore:
- param.idx.texture = param.count++;
- param.idx.coords = param.count++;
+ params.emplace_back(Parameter{texture, Usage::kTexture});
+ params.emplace_back(Parameter{arg_tys[1], Usage::kCoords});
if (is_array) {
- param.idx.array_index = param.count++;
+ params.emplace_back(Parameter{ty.i32(), Usage::kArrayIndex});
}
- param.idx.value = param.count++;
+ params.emplace_back(Parameter{arg_tys[params.size()], Usage::kValue});
break;
default:
set_error(call->source(),
- "Internal compiler error: Unreachable intrinsic " +
- std::to_string(static_cast<int>(intrinsic)));
+ "Internal compiler error: Unreachable intrinsic " + name);
return false;
}
- if (call->params().size() != param.count) {
- set_error(call->source(),
- "incorrect number of parameters for " + name + ", got " +
- std::to_string(call->params().size()) + " and expected " +
- std::to_string(param.count));
+ if (arg_tys.size() != params.size()) {
+ set_error(call->source(), "incorrect number of arguments for " + name +
+ ", got " + std::to_string(arg_tys.size()) +
+ " and expected " +
+ std::to_string(params.size()));
return false;
}
// Set the function return type
type::Type* return_type = nullptr;
- switch (intrinsic) {
+ switch (intrinsic_type) {
case IntrinsicType::kTextureDimensions: {
auto* i32 = builder_->create<type::I32>();
switch (texture->dim()) {
@@ -748,16 +762,15 @@
}
}
- auto* sem = builder_->create<semantic::TextureIntrinsicCall>(
- return_type, intrinsic, param);
- builder_->Sem().Add(call, sem);
-
+ auto* intrinsic = builder_->create<semantic::Intrinsic>(
+ intrinsic_type, return_type, params);
+ builder_->Sem().Add(call, builder_->create<semantic::Call>(intrinsic));
return true;
}
const IntrinsicData* data = nullptr;
for (uint32_t i = 0; i < kIntrinsicDataCount; ++i) {
- if (intrinsic == kIntrinsicData[i].intrinsic) {
+ if (intrinsic_type == kIntrinsicData[i].intrinsic) {
data = &kIntrinsicData[i];
break;
}
@@ -847,7 +860,7 @@
}
std::string name = builder_->Symbols().NameFor(symbol);
- if (MatchIntrinsic(name) != IntrinsicType::kNone) {
+ if (MatchIntrinsicType(name) != IntrinsicType::kNone) {
// Identifier is to an intrinsic function, which has no type (currently).
return true;
}
@@ -857,7 +870,7 @@
return false;
}
-IntrinsicType TypeDeterminer::MatchIntrinsic(const std::string& name) {
+IntrinsicType TypeDeterminer::MatchIntrinsicType(const std::string& name) {
if (name == "abs") {
return IntrinsicType::kAbs;
} else if (name == "acos") {
@@ -1197,14 +1210,23 @@
return out;
};
+ std::unordered_map<FunctionInfo*, semantic::Function*> func_info_to_sem_func;
for (auto it : function_to_info_) {
auto* func = it.first;
auto* info = it.second;
- sem.Add(func,
- builder_->create<semantic::Function>(
- info->declaration, remap_vars(info->referenced_module_vars),
- remap_vars(info->local_referenced_module_vars),
- info->ancestor_entry_points));
+ auto* sem_func = builder_->create<semantic::Function>(
+ info->declaration, remap_vars(info->referenced_module_vars),
+ remap_vars(info->local_referenced_module_vars),
+ info->ancestor_entry_points);
+ func_info_to_sem_func.emplace(info, sem_func);
+ sem.Add(func, sem_func);
+ }
+
+ for (auto it : function_calls_) {
+ auto* call = it.first;
+ auto* func_info = it.second;
+ auto* sem_func = func_info_to_sem_func.at(func_info);
+ builder_->Sem().Add(call, builder_->create<semantic::Call>(sem_func));
}
}
diff --git a/src/type_determiner.h b/src/type_determiner.h
index c8dc34d..9928b90 100644
--- a/src/type_determiner.h
+++ b/src/type_determiner.h
@@ -24,6 +24,7 @@
#include "src/diagnostic/diagnostic.h"
#include "src/program_builder.h"
#include "src/scope_stack.h"
+#include "src/semantic/intrinsic.h"
#include "src/type/storage_texture_type.h"
namespace tint {
@@ -66,10 +67,10 @@
/// @returns true if the type determiner was successful
bool Determine();
- /// @param name the function name to try and match as an intrinsic.
+ /// @param name the function name to try and match as an intrinsic type.
/// @return the semantic::IntrinsicType for the given name. If `name` does not
- /// match an intrinsic, returns semantic::IntrinsicType::kNone
- static semantic::IntrinsicType MatchIntrinsic(const std::string& name);
+ /// match an intrinsic, returns semantic::Intrinsic::kNone
+ static semantic::IntrinsicType MatchIntrinsicType(const std::string& name);
private:
template <typename T>
@@ -177,7 +178,7 @@
bool DetermineConstructor(ast::ConstructorExpression* expr);
bool DetermineIdentifier(ast::IdentifierExpression* expr);
bool DetermineIntrinsicCall(ast::CallExpression* call,
- semantic::IntrinsicType intrinsic);
+ semantic::IntrinsicType intrinsic_type);
bool DetermineMemberAccessor(ast::MemberAccessorExpression* expr);
bool DetermineUnaryOp(ast::UnaryOpExpression* expr);
@@ -195,12 +196,13 @@
/// @param type the resolved type
void SetType(ast::Expression* expr, type::Type* type) const;
- ProgramBuilder* builder_;
+ ProgramBuilder* const builder_;
std::string error_;
ScopeStack<VariableInfo*> variable_stack_;
std::unordered_map<Symbol, FunctionInfo*> symbol_to_function_;
std::unordered_map<ast::Function*, FunctionInfo*> function_to_info_;
std::unordered_map<ast::Variable*, VariableInfo*> variable_to_info_;
+ std::unordered_map<ast::CallExpression*, FunctionInfo*> function_calls_;
FunctionInfo* current_function_ = nullptr;
BlockAllocator<VariableInfo> variable_infos_;
BlockAllocator<FunctionInfo> function_infos_;
diff --git a/src/type_determiner_test.cc b/src/type_determiner_test.cc
index 72f9e59..4b43554 100644
--- a/src/type_determiner_test.cc
+++ b/src/type_determiner_test.cc
@@ -1637,7 +1637,7 @@
TEST_P(IntrinsicDataTest, Lookup) {
auto param = GetParam();
- EXPECT_EQ(TypeDeterminer::MatchIntrinsic(param.name), param.intrinsic);
+ EXPECT_EQ(TypeDeterminer::MatchIntrinsicType(param.name), param.intrinsic);
}
INSTANTIATE_TEST_SUITE_P(
TypeDeterminerTest,
@@ -1717,7 +1717,7 @@
IntrinsicData{"trunc", IntrinsicType::kTrunc}));
TEST_F(TypeDeterminerTest, MatchIntrinsicNoMatch) {
- EXPECT_EQ(TypeDeterminer::MatchIntrinsic("not_intrinsic"),
+ EXPECT_EQ(TypeDeterminer::MatchIntrinsicType("not_intrinsic"),
IntrinsicType::kNone);
}
@@ -2466,42 +2466,15 @@
testing::ValuesIn(ast::intrinsic::test::TextureOverloadCase::ValidCases()));
std::string to_str(const std::string& function,
- const semantic::TextureIntrinsicCall::Parameters& params) {
- struct Parameter {
- size_t idx;
- std::string name;
- };
- std::vector<Parameter> list;
- auto maybe_add_param = [&list](size_t idx, const char* name) {
- if (idx !=
- semantic::TextureIntrinsicCall::Parameters::Parameters::kNotUsed) {
- list.emplace_back(Parameter{idx, name});
- }
- };
- maybe_add_param(params.idx.array_index, "array_index");
- maybe_add_param(params.idx.bias, "bias");
- maybe_add_param(params.idx.coords, "coords");
- maybe_add_param(params.idx.depth_ref, "depth_ref");
- maybe_add_param(params.idx.ddx, "ddx");
- maybe_add_param(params.idx.ddy, "ddy");
- maybe_add_param(params.idx.level, "level");
- maybe_add_param(params.idx.offset, "offset");
- maybe_add_param(params.idx.sampler, "sampler");
- maybe_add_param(params.idx.sample_index, "sample_index");
- maybe_add_param(params.idx.texture, "texture");
- maybe_add_param(params.idx.value, "value");
- std::sort(
- list.begin(), list.end(),
- [](const Parameter& a, const Parameter& b) { return a.idx < b.idx; });
-
+ const semantic::Parameters& params) {
std::stringstream out;
out << function << "(";
bool first = true;
- for (auto& param : list) {
+ for (auto& param : params) {
if (!first) {
out << ", ";
}
- out << param.name;
+ out << semantic::str(param.usage);
first = false;
}
out << ")";
@@ -2833,12 +2806,12 @@
}
}
- auto* sem = Sem().Get(call);
- ASSERT_NE(sem, nullptr);
- auto* intrinsic = sem->As<semantic::TextureIntrinsicCall>();
- ASSERT_NE(intrinsic, nullptr);
+ auto* call_sem = Sem().Get(call);
+ ASSERT_NE(call_sem, nullptr);
+ auto* target = call_sem->Target();
+ ASSERT_NE(target, nullptr);
- auto got = ::tint::to_str(param.function, intrinsic->Params());
+ auto got = ::tint::to_str(param.function, target->Parameters());
auto* expected = expected_texture_overload(param.overload);
EXPECT_EQ(got, expected);
}
diff --git a/src/validator/validator_impl.cc b/src/validator/validator_impl.cc
index ecad8ef..019423e 100644
--- a/src/validator/validator_impl.cc
+++ b/src/validator/validator_impl.cc
@@ -644,24 +644,23 @@
return false;
}
- auto* call_sem = program_->Sem().Get(expr);
- if (call_sem == nullptr) {
+ auto* call = program_->Sem().Get(expr);
+ if (call == nullptr) {
add_error(expr->source(), "CallExpression is missing semantic information");
return false;
}
- if (auto* intrinsic_sem = call_sem->As<semantic::IntrinsicCall>()) {
+ if (auto* intrinsic = call->Target()->As<semantic::Intrinsic>()) {
const IntrinsicData* data = nullptr;
for (uint32_t i = 0; i < kIntrinsicDataCount; ++i) {
- if (intrinsic_sem->intrinsic() == kIntrinsicData[i].intrinsic) {
+ if (intrinsic->Type() == kIntrinsicData[i].intrinsic) {
data = &kIntrinsicData[i];
break;
}
}
if (data != nullptr) {
- std::string builtin =
- semantic::intrinsic::str(intrinsic_sem->intrinsic());
+ std::string builtin = intrinsic->str();
if (expr->params().size() != data->param_count) {
add_error(expr->source(),
"incorrect number of parameters for " + builtin +
@@ -832,7 +831,7 @@
}
}
- if (semantic::intrinsic::IsDataPackingIntrinsic(data->intrinsic)) {
+ if (semantic::IsDataPackingIntrinsic(data->intrinsic)) {
if (!program_->TypeOf(expr)->Is<type::U32>()) {
add_error(expr->source(),
"incorrect type for " + builtin +
diff --git a/src/writer/hlsl/generator_impl.cc b/src/writer/hlsl/generator_impl.cc
index 2a4d304..9ac33c8 100644
--- a/src/writer/hlsl/generator_impl.cc
+++ b/src/writer/hlsl/generator_impl.cc
@@ -542,22 +542,22 @@
return 0;
}
- auto* call_sem = builder_.Sem().Get(expr);
- if (auto* sem = call_sem->As<semantic::TextureIntrinsicCall>()) {
- return EmitTextureCall(pre, out, expr, sem);
- }
- if (auto* sem = call_sem->As<semantic::IntrinsicCall>()) {
+ auto* call = builder_.Sem().Get(expr);
+ if (auto* intrinsic = call->Target()->As<semantic::Intrinsic>()) {
+ if (intrinsic->IsTexture()) {
+ return EmitTextureCall(pre, out, expr, intrinsic);
+ }
const auto& params = expr->params();
- if (sem->intrinsic() == semantic::IntrinsicType::kSelect) {
+ if (intrinsic->Type() == semantic::IntrinsicType::kSelect) {
error_ = "select not supported in HLSL backend yet";
return false;
- } else if (sem->intrinsic() == semantic::IntrinsicType::kIsNormal) {
+ } else if (intrinsic->Type() == semantic::IntrinsicType::kIsNormal) {
error_ = "is_normal not supported in HLSL backend yet";
return false;
- } else if (semantic::intrinsic::IsDataPackingIntrinsic(sem->intrinsic())) {
- return EmitDataPackingCall(pre, out, expr);
+ } else if (intrinsic->IsDataPacking()) {
+ return EmitDataPackingCall(pre, out, expr, intrinsic);
}
- auto name = generate_builtin_name(sem);
+ auto name = generate_builtin_name(intrinsic);
if (name.empty()) {
return false;
}
@@ -638,9 +638,8 @@
bool GeneratorImpl::EmitDataPackingCall(std::ostream& pre,
std::ostream& out,
- ast::CallExpression* expr) {
- auto* ident = builder_.Sem().Get(expr)->As<semantic::IntrinsicCall>();
-
+ ast::CallExpression* expr,
+ const semantic::Intrinsic* intrinsic) {
auto* param = expr->params()[0];
auto tmp_name = generate_name(kTempNamePrefix);
std::ostringstream expr_out;
@@ -650,17 +649,17 @@
uint32_t dims = 2;
bool is_signed = false;
uint32_t scale = 65535;
- if (ident->intrinsic() == semantic::IntrinsicType::kPack4x8Snorm ||
- ident->intrinsic() == semantic::IntrinsicType::kPack4x8Unorm) {
+ if (intrinsic->Type() == semantic::IntrinsicType::kPack4x8Snorm ||
+ intrinsic->Type() == semantic::IntrinsicType::kPack4x8Unorm) {
dims = 4;
scale = 255;
}
- if (ident->intrinsic() == semantic::IntrinsicType::kPack4x8Snorm ||
- ident->intrinsic() == semantic::IntrinsicType::kPack2x16Snorm) {
+ if (intrinsic->Type() == semantic::IntrinsicType::kPack4x8Snorm ||
+ intrinsic->Type() == semantic::IntrinsicType::kPack2x16Snorm) {
is_signed = true;
scale = (scale - 1) / 2;
}
- switch (ident->intrinsic()) {
+ switch (intrinsic->Type()) {
case semantic::IntrinsicType::kPack4x8Snorm:
case semantic::IntrinsicType::kPack4x8Unorm:
case semantic::IntrinsicType::kPack2x16Snorm:
@@ -698,17 +697,24 @@
bool GeneratorImpl::EmitTextureCall(std::ostream& pre,
std::ostream& out,
ast::CallExpression* expr,
- const semantic::TextureIntrinsicCall* sem) {
- auto* ident = expr->func()->As<ast::IdentifierExpression>();
+ const semantic::Intrinsic* intrinsic) {
+ using Usage = semantic::Parameter::Usage;
- auto params = expr->params();
- auto& pidx = sem->Params().idx;
- auto const kNotUsed = semantic::TextureIntrinsicCall::Parameters::kNotUsed;
+ auto parameters = intrinsic->Parameters();
+ auto arguments = expr->params();
- auto* texture = params[pidx.texture];
+ // Returns the argument with the given usage
+ auto arg = [&](Usage usage) {
+ int idx = semantic::IndexOf(parameters, usage);
+ return (idx >= 0) ? arguments[idx] : nullptr;
+ };
+
+ auto* texture = arg(Usage::kTexture);
+ assert(texture);
+
auto* texture_type = TypeOf(texture)->UnwrapAll()->As<type::Texture>();
- switch (sem->intrinsic()) {
+ switch (intrinsic->Type()) {
case semantic::IntrinsicType::kTextureDimensions:
case semantic::IntrinsicType::kTextureNumLayers:
case semantic::IntrinsicType::kTextureNumLevels:
@@ -718,7 +724,7 @@
const char* swizzle = "";
bool add_mip_level_in = false;
- switch (sem->intrinsic()) {
+ switch (intrinsic->Type()) {
case semantic::IntrinsicType::kTextureDimensions:
switch (texture_type->dim()) {
case type::TextureDimension::kNone:
@@ -823,8 +829,11 @@
return false;
}
pre << ".GetDimensions(";
- if (pidx.level != kNotUsed) {
- pre << pidx.level << ", ";
+ if (auto* level = arg(Usage::kLevel)) {
+ if (!EmitExpression(pre, pre, level)) {
+ return false;
+ }
+ pre << ", ";
} else if (add_mip_level_in) {
pre << "0, ";
}
@@ -859,7 +868,7 @@
bool pack_mip_in_coords = false;
- switch (sem->intrinsic()) {
+ switch (intrinsic->Type()) {
case semantic::IntrinsicType::kTextureSample:
out << ".Sample(";
break;
@@ -886,17 +895,18 @@
break;
default:
error_ = "Internal compiler error: Unhandled texture intrinsic '" +
- builder_.Symbols().NameFor(ident->symbol()) + "'";
+ std::string(intrinsic->str()) + "'";
return false;
}
- if (pidx.sampler != kNotUsed) {
- if (!EmitExpression(pre, out, params[pidx.sampler]))
+ if (auto* sampler = arg(Usage::kSampler)) {
+ if (!EmitExpression(pre, out, sampler))
return false;
out << ", ";
}
- auto* param_coords = params[pidx.coords];
+ auto* param_coords = arg(Usage::kCoords);
+ assert(param_coords);
auto emit_vector_appended_with_i32_zero = [&](tint::ast::Expression* vector) {
auto* i32 = builder_.create<type::I32>();
@@ -906,10 +916,9 @@
return EmitExpression(pre, out, packed);
};
- if (pidx.array_index != kNotUsed) {
+ if (auto* array_index = arg(Usage::kArrayIndex)) {
// Array index needs to be appended to the coordinates.
- auto* param_array_index = params[pidx.array_index];
- auto* packed = AppendVector(&builder_, param_coords, param_array_index);
+ auto* packed = AppendVector(&builder_, param_coords, array_index);
if (pack_mip_in_coords) {
if (!emit_vector_appended_with_i32_zero(packed)) {
return false;
@@ -928,18 +937,18 @@
return false;
}
- for (auto idx : {pidx.depth_ref, pidx.bias, pidx.level, pidx.ddx, pidx.ddy,
- pidx.sample_index, pidx.offset}) {
- if (idx != kNotUsed) {
+ for (auto usage : {Usage::kDepthRef, Usage::kBias, Usage::kLevel, Usage::kDdx,
+ Usage::kDdy, Usage::kSampleIndex, Usage::kOffset}) {
+ if (auto* e = arg(usage)) {
out << ", ";
- if (!EmitExpression(pre, out, params[idx]))
+ if (!EmitExpression(pre, out, e))
return false;
}
}
- if (sem->intrinsic() == semantic::IntrinsicType::kTextureStore) {
+ if (intrinsic->Type() == semantic::IntrinsicType::kTextureStore) {
out << "] = ";
- if (!EmitExpression(pre, out, params[pidx.value]))
+ if (!EmitExpression(pre, out, arg(Usage::kValue)))
return false;
} else {
out << ")";
@@ -949,9 +958,9 @@
} // namespace hlsl
std::string GeneratorImpl::generate_builtin_name(
- const semantic::IntrinsicCall* call) {
+ const semantic::Intrinsic* intrinsic) {
std::string out;
- switch (call->intrinsic()) {
+ switch (intrinsic->Type()) {
case semantic::IntrinsicType::kAcos:
case semantic::IntrinsicType::kAny:
case semantic::IntrinsicType::kAll:
@@ -990,7 +999,7 @@
case semantic::IntrinsicType::kMax:
case semantic::IntrinsicType::kMin:
case semantic::IntrinsicType::kClamp:
- out = semantic::intrinsic::str(call->intrinsic());
+ out = intrinsic->str();
break;
case semantic::IntrinsicType::kCountOneBits:
out = "countbits";
@@ -1043,8 +1052,7 @@
out = "smoothstep";
break;
default:
- error_ = "Unknown builtin method: " +
- std::string(semantic::intrinsic::str(call->intrinsic()));
+ error_ = "Unknown builtin method: " + std::string(intrinsic->str());
return "";
}
diff --git a/src/writer/hlsl/generator_impl.h b/src/writer/hlsl/generator_impl.h
index 22b8be0..805a0ce 100644
--- a/src/writer/hlsl/generator_impl.h
+++ b/src/writer/hlsl/generator_impl.h
@@ -48,8 +48,8 @@
// Forward declarations
namespace semantic {
-class TextureIntrinsicCall;
-class IntrinsicCall;
+class Call;
+class Intrinsic;
} // namespace semantic
namespace writer {
@@ -153,20 +153,22 @@
/// @param pre the preamble for the expression stream
/// @param out the output of the expression stream
/// @param expr the call expression
- /// @param sem the semantic information for the texture intrinsic call
+ /// @param intrinsic the semantic information for the texture intrinsic
/// @returns true if the call expression is emitted
bool EmitTextureCall(std::ostream& pre,
std::ostream& out,
ast::CallExpression* expr,
- const semantic::TextureIntrinsicCall* sem);
+ const semantic::Intrinsic* intrinsic);
/// Handles generating a call to data packing intrinsic
/// @param pre the preamble of the expression stream
/// @param out the output of the expression stream
/// @param expr the call expression
+ /// @param intrinsic the semantic information for the texture intrinsic
/// @returns true if the call expression is emitted
bool EmitDataPackingCall(std::ostream& pre,
std::ostream& out,
- ast::CallExpression* expr);
+ ast::CallExpression* expr,
+ const semantic::Intrinsic* intrinsic);
/// Handles a case statement
/// @param out the output stream
/// @param stmt the statement
@@ -363,9 +365,9 @@
std::string generate_storage_buffer_index_expression(std::ostream& pre,
ast::Expression* expr);
/// Handles generating a builtin method name
- /// @param call the semantic info for the intrinsic call
+ /// @param intrinsic the semantic info for the intrinsic
/// @returns the name or "" if not valid
- std::string generate_builtin_name(const semantic::IntrinsicCall* call);
+ std::string generate_builtin_name(const semantic::Intrinsic* intrinsic);
/// Converts a builtin to an attribute name
/// @param builtin the builtin to convert
/// @returns the string name of the builtin or blank on error
diff --git a/src/writer/hlsl/generator_impl_intrinsic_test.cc b/src/writer/hlsl/generator_impl_intrinsic_test.cc
index 2370d84..2b32853 100644
--- a/src/writer/hlsl/generator_impl_intrinsic_test.cc
+++ b/src/writer/hlsl/generator_impl_intrinsic_test.cc
@@ -175,7 +175,9 @@
auto* sem = program->Sem().Get(call);
ASSERT_NE(sem, nullptr);
- auto* intrinsic = sem->As<semantic::IntrinsicCall>();
+ auto* target = sem->Target();
+ ASSERT_NE(target, nullptr);
+ auto* intrinsic = target->As<semantic::Intrinsic>();
ASSERT_NE(intrinsic, nullptr);
EXPECT_EQ(gen.generate_builtin_name(intrinsic), param.hlsl_name);
diff --git a/src/writer/msl/generator_impl.cc b/src/writer/msl/generator_impl.cc
index 0020501..5c9c1de 100644
--- a/src/writer/msl/generator_impl.cc
+++ b/src/writer/msl/generator_impl.cc
@@ -444,12 +444,12 @@
return 0;
}
- auto* call_sem = program_->Sem().Get(expr);
- if (auto* sem = call_sem->As<semantic::TextureIntrinsicCall>()) {
- return EmitTextureCall(expr, sem);
- }
- if (auto* sem = call_sem->As<semantic::IntrinsicCall>()) {
- if (sem->intrinsic() == semantic::IntrinsicType::kPack2x16Float) {
+ auto* call = program_->Sem().Get(expr);
+ if (auto* intrinsic = call->Target()->As<semantic::Intrinsic>()) {
+ if (intrinsic->IsTexture()) {
+ return EmitTextureCall(expr, intrinsic);
+ }
+ if (intrinsic->Type() == semantic::IntrinsicType::kPack2x16Float) {
make_indent();
out_ << "as_type<uint>(half2(";
if (!EmitExpression(expr->params()[0])) {
@@ -458,7 +458,7 @@
out_ << "))";
return true;
}
- auto name = generate_builtin_name(sem);
+ auto name = generate_builtin_name(intrinsic);
if (name.empty()) {
return false;
}
@@ -568,18 +568,24 @@
}
bool GeneratorImpl::EmitTextureCall(ast::CallExpression* expr,
- const semantic::TextureIntrinsicCall* sem) {
- auto* ident = expr->func()->As<ast::IdentifierExpression>();
+ const semantic::Intrinsic* intrinsic) {
+ using Usage = semantic::Parameter::Usage;
- auto params = expr->params();
- auto& pidx = sem->Params().idx;
- auto const kNotUsed = semantic::TextureIntrinsicCall::Parameters::kNotUsed;
+ auto parameters = intrinsic->Parameters();
+ auto arguments = expr->params();
- assert(pidx.texture != kNotUsed);
- auto* texture_type =
- TypeOf(params[pidx.texture])->UnwrapAll()->As<type::Texture>();
+ // Returns the argument with the given usage
+ auto arg = [&](Usage usage) {
+ int idx = semantic::IndexOf(parameters, usage);
+ return (idx >= 0) ? arguments[idx] : nullptr;
+ };
- switch (sem->intrinsic()) {
+ auto* texture = arg(Usage::kTexture);
+ assert(texture);
+
+ auto* texture_type = TypeOf(texture)->UnwrapAll()->As<type::Texture>();
+
+ switch (intrinsic->Type()) {
case semantic::IntrinsicType::kTextureDimensions: {
std::vector<const char*> dims;
switch (texture_type->dim()) {
@@ -606,12 +612,14 @@
}
auto get_dim = [&](const char* name) {
- if (!EmitExpression(params[pidx.texture])) {
+ if (!EmitExpression(texture)) {
return false;
}
out_ << ".get_" << name << "(";
- if (pidx.level != kNotUsed) {
- out_ << pidx.level;
+ if (auto* level = arg(Usage::kLevel)) {
+ if (!EmitExpression(level)) {
+ return false;
+ }
}
out_ << ")";
return true;
@@ -636,7 +644,7 @@
}
case semantic::IntrinsicType::kTextureNumLayers: {
out_ << "int(";
- if (!EmitExpression(params[pidx.texture])) {
+ if (!EmitExpression(texture)) {
return false;
}
out_ << ".get_array_size())";
@@ -644,7 +652,7 @@
}
case semantic::IntrinsicType::kTextureNumLevels: {
out_ << "int(";
- if (!EmitExpression(params[pidx.texture])) {
+ if (!EmitExpression(texture)) {
return false;
}
out_ << ".get_num_mip_levels())";
@@ -652,7 +660,7 @@
}
case semantic::IntrinsicType::kTextureNumSamples: {
out_ << "int(";
- if (!EmitExpression(params[pidx.texture])) {
+ if (!EmitExpression(texture)) {
return false;
}
out_ << ".get_num_samples())";
@@ -662,12 +670,12 @@
break;
}
- if (!EmitExpression(params[pidx.texture]))
+ if (!EmitExpression(texture))
return false;
bool lod_param_is_named = true;
- switch (sem->intrinsic()) {
+ switch (intrinsic->Type()) {
case semantic::IntrinsicType::kTextureSample:
case semantic::IntrinsicType::kTextureSampleBias:
case semantic::IntrinsicType::kTextureSampleLevel:
@@ -686,7 +694,7 @@
break;
default:
error_ = "Internal compiler error: Unhandled texture intrinsic '" +
- program_->Symbols().NameFor(ident->symbol()) + "'";
+ std::string(intrinsic->str()) + "'";
return false;
}
@@ -698,40 +706,38 @@
first_arg = false;
};
- for (auto idx : {pidx.value, pidx.sampler, pidx.coords, pidx.array_index,
- pidx.depth_ref, pidx.sample_index}) {
- if (idx != kNotUsed) {
+ for (auto usage :
+ {Usage::kValue, Usage::kSampler, Usage::kCoords, Usage::kArrayIndex,
+ Usage::kDepthRef, Usage::kSampleIndex}) {
+ if (auto* e = arg(usage)) {
maybe_write_comma();
- if (!EmitExpression(params[idx]))
+ if (!EmitExpression(e))
return false;
}
}
- if (pidx.bias != kNotUsed) {
+ if (auto* bias = arg(Usage::kBias)) {
maybe_write_comma();
out_ << "bias(";
- if (!EmitExpression(params[pidx.bias])) {
+ if (!EmitExpression(bias)) {
return false;
}
out_ << ")";
}
- if (pidx.level != kNotUsed) {
+ if (auto* level = arg(Usage::kLevel)) {
maybe_write_comma();
if (lod_param_is_named) {
out_ << "level(";
}
- if (!EmitExpression(params[pidx.level])) {
+ if (!EmitExpression(level)) {
return false;
}
if (lod_param_is_named) {
out_ << ")";
}
}
- if (pidx.ddx != kNotUsed) {
- auto dim = TypeOf(params[pidx.texture])
- ->UnwrapPtrIfNeeded()
- ->As<type::Texture>()
- ->dim();
+ if (auto* ddx = arg(Usage::kDdx)) {
+ auto dim = texture_type->dim();
switch (dim) {
case type::TextureDimension::k2d:
case type::TextureDimension::k2dArray:
@@ -754,19 +760,19 @@
return false;
}
}
- if (!EmitExpression(params[pidx.ddx])) {
+ if (!EmitExpression(ddx)) {
return false;
}
out_ << ", ";
- if (!EmitExpression(params[pidx.ddy])) {
+ if (!EmitExpression(arg(Usage::kDdy))) {
return false;
}
out_ << ")";
}
- if (pidx.offset != kNotUsed) {
+ if (auto* offset = arg(Usage::kOffset)) {
maybe_write_comma();
- if (!EmitExpression(params[pidx.offset])) {
+ if (!EmitExpression(offset)) {
return false;
}
}
@@ -777,9 +783,9 @@
}
std::string GeneratorImpl::generate_builtin_name(
- const semantic::IntrinsicCall* call) {
+ const semantic::Intrinsic* intrinsic) {
std::string out = "metal::";
- switch (call->intrinsic()) {
+ switch (intrinsic->Type()) {
case semantic::IntrinsicType::kAcos:
case semantic::IntrinsicType::kAll:
case semantic::IntrinsicType::kAny:
@@ -817,10 +823,10 @@
case semantic::IntrinsicType::kTrunc:
case semantic::IntrinsicType::kSign:
case semantic::IntrinsicType::kClamp:
- out += semantic::intrinsic::str(call->intrinsic());
+ out += intrinsic->str();
break;
case semantic::IntrinsicType::kAbs:
- if (call->Type()->is_float_scalar_or_vector()) {
+ if (intrinsic->ReturnType()->is_float_scalar_or_vector()) {
out += "fabs";
} else {
out += "abs";
@@ -857,14 +863,14 @@
out += "isnormal";
break;
case semantic::IntrinsicType::kMax:
- if (call->Type()->is_float_scalar_or_vector()) {
+ if (intrinsic->ReturnType()->is_float_scalar_or_vector()) {
out += "fmax";
} else {
out += "max";
}
break;
case semantic::IntrinsicType::kMin:
- if (call->Type()->is_float_scalar_or_vector()) {
+ if (intrinsic->ReturnType()->is_float_scalar_or_vector()) {
out += "fmin";
} else {
out += "min";
@@ -895,8 +901,7 @@
out += "rsqrt";
break;
default:
- error_ = "Unknown import method: " +
- std::string(semantic::intrinsic::str(call->intrinsic()));
+ error_ = "Unknown import method: " + std::string(intrinsic->str());
return "";
}
return out;
diff --git a/src/writer/msl/generator_impl.h b/src/writer/msl/generator_impl.h
index 617061f..ccbb0d1 100644
--- a/src/writer/msl/generator_impl.h
+++ b/src/writer/msl/generator_impl.h
@@ -50,8 +50,8 @@
// Forward declarations
namespace semantic {
-class TextureIntrinsicCall;
-class IntrinsicCall;
+class Call;
+class Intrinsic;
} // namespace semantic
namespace writer {
@@ -121,10 +121,10 @@
/// Handles generating a call to a texture function (`textureSample`,
/// `textureSampleGrad`, etc)
/// @param expr the call expression
- /// @param sem the semantic information for the texture intrinsic call
+ /// @param intrinsic the semantic information for the texture intrinsic
/// @returns true if the call expression is emitted
bool EmitTextureCall(ast::CallExpression* expr,
- const semantic::TextureIntrinsicCall* sem);
+ const semantic::Intrinsic* intrinsic);
/// Handles a case statement
/// @param stmt the statement
/// @returns true if the statement was emitted successfully
@@ -258,9 +258,9 @@
/// @returns the name
std::string generate_name(const std::string& prefix);
/// Handles generating a builtin name
- /// @param call the semantic info for the intrinsic call
+ /// @param intrinsic the semantic info for the intrinsic
/// @returns the name or "" if not valid
- std::string generate_builtin_name(const semantic::IntrinsicCall* call);
+ std::string generate_builtin_name(const semantic::Intrinsic* intrinsic);
/// Checks if the global variable is in an input or output struct
/// @param var the variable to check
diff --git a/src/writer/msl/generator_impl_import_test.cc b/src/writer/msl/generator_impl_import_test.cc
index 76440d0..7b365f4 100644
--- a/src/writer/msl/generator_impl_import_test.cc
+++ b/src/writer/msl/generator_impl_import_test.cc
@@ -60,7 +60,9 @@
auto* sem = program->Sem().Get(call);
ASSERT_NE(sem, nullptr);
- auto* intrinsic = sem->As<semantic::IntrinsicCall>();
+ auto* target = sem->Target();
+ ASSERT_NE(target, nullptr);
+ auto* intrinsic = target->As<semantic::Intrinsic>();
ASSERT_NE(intrinsic, nullptr);
ASSERT_EQ(gen.generate_builtin_name(intrinsic),
diff --git a/src/writer/msl/generator_impl_intrinsic_test.cc b/src/writer/msl/generator_impl_intrinsic_test.cc
index 7829636..56b194a 100644
--- a/src/writer/msl/generator_impl_intrinsic_test.cc
+++ b/src/writer/msl/generator_impl_intrinsic_test.cc
@@ -182,7 +182,9 @@
auto* sem = program->Sem().Get(call);
ASSERT_NE(sem, nullptr);
- auto* intrinsic = sem->As<semantic::IntrinsicCall>();
+ auto* target = sem->Target();
+ ASSERT_NE(target, nullptr);
+ auto* intrinsic = target->As<semantic::Intrinsic>();
ASSERT_NE(intrinsic, nullptr);
EXPECT_EQ(gen.generate_builtin_name(intrinsic), param.msl_name);
diff --git a/src/writer/spirv/builder.cc b/src/writer/spirv/builder.cc
index ce32ebb..386f5a9 100644
--- a/src/writer/spirv/builder.cc
+++ b/src/writer/spirv/builder.cc
@@ -168,10 +168,10 @@
return type->As<type::Matrix>();
}
-uint32_t intrinsic_to_glsl_method(type::Type* type, IntrinsicType intrinsic) {
- switch (intrinsic) {
+uint32_t intrinsic_to_glsl_method(const semantic::Intrinsic* intrinsic) {
+ switch (intrinsic->Type()) {
case IntrinsicType::kAbs:
- if (type->is_float_scalar_or_vector()) {
+ if (intrinsic->ReturnType()->is_float_scalar_or_vector()) {
return GLSLstd450FAbs;
} else {
return GLSLstd450SAbs;
@@ -187,9 +187,9 @@
case IntrinsicType::kCeil:
return GLSLstd450Ceil;
case IntrinsicType::kClamp:
- if (type->is_float_scalar_or_vector()) {
+ if (intrinsic->ReturnType()->is_float_scalar_or_vector()) {
return GLSLstd450NClamp;
- } else if (type->is_unsigned_scalar_or_vector()) {
+ } else if (intrinsic->ReturnType()->is_unsigned_scalar_or_vector()) {
return GLSLstd450UClamp;
} else {
return GLSLstd450SClamp;
@@ -229,17 +229,17 @@
case IntrinsicType::kLog2:
return GLSLstd450Log2;
case IntrinsicType::kMax:
- if (type->is_float_scalar_or_vector()) {
+ if (intrinsic->ReturnType()->is_float_scalar_or_vector()) {
return GLSLstd450NMax;
- } else if (type->is_unsigned_scalar_or_vector()) {
+ } else if (intrinsic->ReturnType()->is_unsigned_scalar_or_vector()) {
return GLSLstd450UMax;
} else {
return GLSLstd450SMax;
}
case IntrinsicType::kMin:
- if (type->is_float_scalar_or_vector()) {
+ if (intrinsic->ReturnType()->is_float_scalar_or_vector()) {
return GLSLstd450NMin;
- } else if (type->is_unsigned_scalar_or_vector()) {
+ } else if (intrinsic->ReturnType()->is_unsigned_scalar_or_vector()) {
return GLSLstd450UMin;
} else {
return GLSLstd450SMin;
@@ -1826,12 +1826,13 @@
return 0;
}
- auto* sem = builder_.Sem().Get(expr);
- if (auto* intrinsic = sem->As<semantic::IntrinsicCall>()) {
- return GenerateIntrinsic(ident, expr, intrinsic);
+ auto* call = builder_.Sem().Get(expr);
+ auto* target = call->Target();
+ if (auto* intrinsic = target->As<semantic::Intrinsic>()) {
+ return GenerateIntrinsic(expr, intrinsic);
}
- auto type_id = GenerateTypeIfNeeded(sem->Type());
+ auto type_id = GenerateTypeIfNeeded(target->ReturnType());
if (type_id == 0) {
return 0;
}
@@ -1865,31 +1866,27 @@
return result_id;
}
-uint32_t Builder::GenerateIntrinsic(ast::IdentifierExpression* ident,
- ast::CallExpression* call,
- const semantic::IntrinsicCall* sem) {
+uint32_t Builder::GenerateIntrinsic(ast::CallExpression* call,
+ const semantic::Intrinsic* intrinsic) {
auto result = result_op();
auto result_id = result.to_i();
- auto result_type_id = GenerateTypeIfNeeded(TypeOf(call));
+ auto result_type_id = GenerateTypeIfNeeded(intrinsic->ReturnType());
if (result_type_id == 0) {
return 0;
}
- auto intrinsic = sem->intrinsic();
-
- if (semantic::intrinsic::IsFineDerivative(intrinsic) ||
- semantic::intrinsic::IsCoarseDerivative(intrinsic)) {
+ if (intrinsic->IsFineDerivative() || intrinsic->IsCoarseDerivative()) {
push_capability(SpvCapabilityDerivativeControl);
}
- if (semantic::intrinsic::IsImageQueryIntrinsic(intrinsic)) {
+ if (intrinsic->IsImageQuery()) {
push_capability(SpvCapabilityImageQuery);
}
- if (auto* tex_sem = sem->As<semantic::TextureIntrinsicCall>()) {
- if (!GenerateTextureIntrinsic(ident, call, tex_sem,
- Operand::Int(result_type_id), result)) {
+ if (intrinsic->IsTexture()) {
+ if (!GenerateTextureIntrinsic(call, intrinsic, Operand::Int(result_type_id),
+ result)) {
return 0;
}
return result_id;
@@ -1898,97 +1895,118 @@
OperandList params = {Operand::Int(result_type_id), result};
spv::Op op = spv::Op::OpNop;
- if (intrinsic == IntrinsicType::kAny) {
- op = spv::Op::OpAny;
- } else if (intrinsic == IntrinsicType::kAll) {
- op = spv::Op::OpAll;
- } else if (intrinsic == IntrinsicType::kArrayLength) {
- if (call->params().empty()) {
- error_ = "missing param for runtime array length";
- return 0;
- }
- auto* arg = call->params()[0];
+ switch (intrinsic->Type()) {
+ case IntrinsicType::kAny:
+ op = spv::Op::OpAny;
+ break;
+ case IntrinsicType::kAll:
+ op = spv::Op::OpAll;
+ break;
+ case IntrinsicType::kArrayLength: {
+ if (call->params().empty()) {
+ error_ = "missing param for runtime array length";
+ return 0;
+ }
+ auto* arg = call->params()[0];
- auto* accessor = arg->As<ast::MemberAccessorExpression>();
- if (accessor == nullptr) {
- error_ = "invalid expression for array length";
- return 0;
- }
+ auto* accessor = arg->As<ast::MemberAccessorExpression>();
+ if (accessor == nullptr) {
+ error_ = "invalid expression for array length";
+ return 0;
+ }
- auto struct_id = GenerateExpression(accessor->structure());
- if (struct_id == 0) {
- return 0;
- }
- params.push_back(Operand::Int(struct_id));
+ auto struct_id = GenerateExpression(accessor->structure());
+ if (struct_id == 0) {
+ return 0;
+ }
+ params.push_back(Operand::Int(struct_id));
- auto* type = TypeOf(accessor->structure())->UnwrapAll();
- if (!type->Is<type::Struct>()) {
- error_ =
- "invalid type (" + type->type_name() + ") for runtime array length";
- return 0;
- }
- // Runtime array must be the last member in the structure
- params.push_back(Operand::Int(
- uint32_t(type->As<type::Struct>()->impl()->members().size() - 1)));
+ auto* type = TypeOf(accessor->structure())->UnwrapAll();
+ if (!type->Is<type::Struct>()) {
+ error_ =
+ "invalid type (" + type->type_name() + ") for runtime array length";
+ return 0;
+ }
+ // Runtime array must be the last member in the structure
+ params.push_back(Operand::Int(
+ uint32_t(type->As<type::Struct>()->impl()->members().size() - 1)));
- if (!push_function_inst(spv::Op::OpArrayLength, params)) {
- return 0;
+ if (!push_function_inst(spv::Op::OpArrayLength, params)) {
+ return 0;
+ }
+ return result_id;
}
- return result_id;
- } else if (intrinsic == IntrinsicType::kCountOneBits) {
- op = spv::Op::OpBitCount;
- } else if (intrinsic == IntrinsicType::kDot) {
- op = spv::Op::OpDot;
- } else if (intrinsic == IntrinsicType::kDpdx) {
- op = spv::Op::OpDPdx;
- } else if (intrinsic == IntrinsicType::kDpdxCoarse) {
- op = spv::Op::OpDPdxCoarse;
- } else if (intrinsic == IntrinsicType::kDpdxFine) {
- op = spv::Op::OpDPdxFine;
- } else if (intrinsic == IntrinsicType::kDpdy) {
- op = spv::Op::OpDPdy;
- } else if (intrinsic == IntrinsicType::kDpdyCoarse) {
- op = spv::Op::OpDPdyCoarse;
- } else if (intrinsic == IntrinsicType::kDpdyFine) {
- op = spv::Op::OpDPdyFine;
- } else if (intrinsic == IntrinsicType::kFwidth) {
- op = spv::Op::OpFwidth;
- } else if (intrinsic == IntrinsicType::kFwidthCoarse) {
- op = spv::Op::OpFwidthCoarse;
- } else if (intrinsic == IntrinsicType::kFwidthFine) {
- op = spv::Op::OpFwidthFine;
- } else if (intrinsic == IntrinsicType::kIsInf) {
- op = spv::Op::OpIsInf;
- } else if (intrinsic == IntrinsicType::kIsNan) {
- op = spv::Op::OpIsNan;
- } else if (intrinsic == IntrinsicType::kReverseBits) {
- op = spv::Op::OpBitReverse;
- } else if (intrinsic == IntrinsicType::kSelect) {
- op = spv::Op::OpSelect;
- } else {
- GenerateGLSLstd450Import();
+ case IntrinsicType::kCountOneBits:
+ op = spv::Op::OpBitCount;
+ break;
+ case IntrinsicType::kDot:
+ op = spv::Op::OpDot;
+ break;
+ case IntrinsicType::kDpdx:
+ op = spv::Op::OpDPdx;
+ break;
+ case IntrinsicType::kDpdxCoarse:
+ op = spv::Op::OpDPdxCoarse;
+ break;
+ case IntrinsicType::kDpdxFine:
+ op = spv::Op::OpDPdxFine;
+ break;
+ case IntrinsicType::kDpdy:
+ op = spv::Op::OpDPdy;
+ break;
+ case IntrinsicType::kDpdyCoarse:
+ op = spv::Op::OpDPdyCoarse;
+ break;
+ case IntrinsicType::kDpdyFine:
+ op = spv::Op::OpDPdyFine;
+ break;
+ case IntrinsicType::kFwidth:
+ op = spv::Op::OpFwidth;
+ break;
+ case IntrinsicType::kFwidthCoarse:
+ op = spv::Op::OpFwidthCoarse;
+ break;
+ case IntrinsicType::kFwidthFine:
+ op = spv::Op::OpFwidthFine;
+ break;
+ case IntrinsicType::kIsInf:
+ op = spv::Op::OpIsInf;
+ break;
+ case IntrinsicType::kIsNan:
+ op = spv::Op::OpIsNan;
+ break;
+ case IntrinsicType::kReverseBits:
+ op = spv::Op::OpBitReverse;
+ break;
+ case IntrinsicType::kSelect:
+ op = spv::Op::OpSelect;
+ break;
+ default: {
+ GenerateGLSLstd450Import();
- auto set_iter = import_name_to_id_.find(kGLSLstd450);
- if (set_iter == import_name_to_id_.end()) {
- error_ = std::string("unknown import ") + kGLSLstd450;
- return 0;
+ auto set_iter = import_name_to_id_.find(kGLSLstd450);
+ if (set_iter == import_name_to_id_.end()) {
+ error_ = std::string("unknown import ") + kGLSLstd450;
+ return 0;
+ }
+ auto set_id = set_iter->second;
+ auto inst_id = intrinsic_to_glsl_method(intrinsic);
+ if (inst_id == 0) {
+ error_ = "unknown method " + std::string(intrinsic->str());
+ return 0;
+ }
+
+ params.push_back(Operand::Int(set_id));
+ params.push_back(Operand::Int(inst_id));
+
+ op = spv::Op::OpExtInst;
+ break;
}
- auto set_id = set_iter->second;
- auto inst_id = intrinsic_to_glsl_method(sem->Type(), sem->intrinsic());
- if (inst_id == 0) {
- error_ = "unknown method " + builder_.Symbols().NameFor(ident->symbol());
- return 0;
- }
-
- params.push_back(Operand::Int(set_id));
- params.push_back(Operand::Int(inst_id));
-
- op = spv::Op::OpExtInst;
}
if (op == spv::Op::OpNop) {
- error_ = "unable to determine operator for: " +
- builder_.Symbols().NameFor(ident->symbol());
+ error_ =
+ "unable to determine operator for: " + std::string(intrinsic->str());
return 0;
}
@@ -2009,32 +2027,46 @@
return result_id;
}
-bool Builder::GenerateTextureIntrinsic(
- ast::IdentifierExpression* ident,
- ast::CallExpression* call,
- const semantic::TextureIntrinsicCall* sem,
- Operand result_type,
- Operand result_id) {
- auto& pidx = sem->Params().idx;
- auto const kNotUsed = semantic::TextureIntrinsicCall::Parameters::kNotUsed;
+bool Builder::GenerateTextureIntrinsic(ast::CallExpression* call,
+ const semantic::Intrinsic* intrinsic,
+ Operand result_type,
+ Operand result_id) {
+ using Usage = semantic::Parameter::Usage;
- assert(pidx.texture != kNotUsed);
- auto* texture_type =
- TypeOf(call->params()[pidx.texture])->UnwrapAll()->As<type::Texture>();
+ auto parameters = intrinsic->Parameters();
+ auto arguments = call->params();
- auto op = spv::Op::OpNop;
-
- auto gen_param = [&](size_t idx) {
- auto* p = call->params()[idx];
- auto val_id = GenerateExpression(p);
+ // Generates the given expression, returning the operand ID
+ auto gen = [&](ast::Expression* expr) {
+ auto val_id = GenerateExpression(expr);
if (val_id == 0) {
return Operand::Int(0);
}
- val_id = GenerateLoadIfNeeded(TypeOf(p), val_id);
+ val_id = GenerateLoadIfNeeded(TypeOf(expr), val_id);
return Operand::Int(val_id);
};
+ // Returns the argument with the given usage
+ auto arg = [&](Usage usage) {
+ int idx = semantic::IndexOf(parameters, usage);
+ return (idx >= 0) ? arguments[idx] : nullptr;
+ };
+
+ // Generates the argument with the given usage, returning the operand ID
+ auto gen_arg = [&](Usage usage) {
+ auto* argument = arg(usage);
+ assert(argument);
+ return gen(argument);
+ };
+
+ auto* texture = arg(Usage::kTexture);
+ assert(texture);
+
+ auto* texture_type = TypeOf(texture)->UnwrapAll()->As<type::Texture>();
+
+ auto op = spv::Op::OpNop;
+
// Custom function to call after the texture-intrinsic op has been generated.
std::function<bool()> post_emission = [] { return true; };
@@ -2133,28 +2165,23 @@
};
auto append_coords_to_spirv_params = [&]() -> bool {
- if (pidx.array_index != kNotUsed) {
+ if (auto* array_index = arg(Usage::kArrayIndex)) {
// Array index needs to be appended to the coordinates.
- auto* param_coords = call->params()[pidx.coords];
- auto* param_array_index = call->params()[pidx.array_index];
-
- auto* packed = AppendVector(&builder_, param_coords, param_array_index);
+ auto* packed = AppendVector(&builder_, arg(Usage::kCoords), array_index);
auto param = GenerateTypeConstructorExpression(packed, false);
if (param == 0) {
return false;
}
spirv_params.emplace_back(Operand::Int(param));
} else {
- spirv_params.emplace_back(gen_param(pidx.coords)); // coordinates
+ spirv_params.emplace_back(gen_arg(Usage::kCoords)); // coordinates
}
return true;
};
auto append_image_and_coords_to_spirv_params = [&]() -> bool {
- assert(pidx.sampler != kNotUsed);
- assert(pidx.texture != kNotUsed);
- auto sampler_param = gen_param(pidx.sampler);
- auto texture_param = gen_param(pidx.texture);
+ auto sampler_param = gen_arg(Usage::kSampler);
+ auto texture_param = gen_arg(Usage::kTexture);
auto sampled_image =
GenerateSampledImage(texture_type, texture_param, sampler_param);
@@ -2163,7 +2190,7 @@
return append_coords_to_spirv_params();
};
- switch (sem->intrinsic()) {
+ switch (intrinsic->Type()) {
case IntrinsicType::kTextureDimensions: {
// Number of returned elements from OpImageQuerySize[Lod] may not match
// those of textureDimensions().
@@ -2205,13 +2232,13 @@
return false;
}
- spirv_params.emplace_back(gen_param(pidx.texture));
+ spirv_params.emplace_back(gen_arg(Usage::kTexture));
if (texture_type->Is<type::MultisampledTexture>() ||
texture_type->Is<type::StorageTexture>()) {
op = spv::Op::OpImageQuerySize;
- } else if (pidx.level != kNotUsed) {
+ } else if (auto* level = arg(Usage::kLevel)) {
op = spv::Op::OpImageQuerySizeLod;
- spirv_params.emplace_back(gen_param(pidx.level));
+ spirv_params.emplace_back(gen(level));
} else {
ast::SintLiteral i32_0(Source{}, builder_.create<type::I32>(), 0);
op = spv::Op::OpImageQuerySizeLod;
@@ -2242,7 +2269,7 @@
return false;
}
- spirv_params.emplace_back(gen_param(pidx.texture));
+ spirv_params.emplace_back(gen_arg(Usage::kTexture));
if (texture_type->Is<type::MultisampledTexture>() ||
texture_type->Is<type::StorageTexture>()) {
@@ -2258,43 +2285,43 @@
case IntrinsicType::kTextureNumLevels: {
op = spv::Op::OpImageQueryLevels;
append_result_type_and_id_to_spirv_params();
- spirv_params.emplace_back(gen_param(pidx.texture));
+ spirv_params.emplace_back(gen_arg(Usage::kTexture));
break;
}
case IntrinsicType::kTextureNumSamples: {
op = spv::Op::OpImageQuerySamples;
append_result_type_and_id_to_spirv_params();
- spirv_params.emplace_back(gen_param(pidx.texture));
+ spirv_params.emplace_back(gen_arg(Usage::kTexture));
break;
}
case IntrinsicType::kTextureLoad: {
op = texture_type->Is<type::StorageTexture>() ? spv::Op::OpImageRead
: spv::Op::OpImageFetch;
append_result_type_and_id_to_spirv_params_for_read();
- spirv_params.emplace_back(gen_param(pidx.texture));
+ spirv_params.emplace_back(gen_arg(Usage::kTexture));
if (!append_coords_to_spirv_params()) {
return false;
}
- if (pidx.level != kNotUsed) {
+ if (auto* level = arg(Usage::kLevel)) {
image_operands.emplace_back(
- ImageOperand{SpvImageOperandsLodMask, gen_param(pidx.level)});
+ ImageOperand{SpvImageOperandsLodMask, gen(level)});
}
- if (pidx.sample_index != kNotUsed) {
- image_operands.emplace_back(ImageOperand{SpvImageOperandsSampleMask,
- gen_param(pidx.sample_index)});
+ if (auto* sample_index = arg(Usage::kSampleIndex)) {
+ image_operands.emplace_back(
+ ImageOperand{SpvImageOperandsSampleMask, gen(sample_index)});
}
break;
}
case IntrinsicType::kTextureStore: {
op = spv::Op::OpImageWrite;
- spirv_params.emplace_back(gen_param(pidx.texture));
+ spirv_params.emplace_back(gen_arg(Usage::kTexture));
if (!append_coords_to_spirv_params()) {
return false;
}
- spirv_params.emplace_back(gen_param(pidx.value));
+ spirv_params.emplace_back(gen_arg(Usage::kValue));
break;
}
case IntrinsicType::kTextureSample: {
@@ -2311,9 +2338,8 @@
if (!append_image_and_coords_to_spirv_params()) {
return false;
}
- assert(pidx.bias != kNotUsed);
image_operands.emplace_back(
- ImageOperand{SpvImageOperandsBiasMask, gen_param(pidx.bias)});
+ ImageOperand{SpvImageOperandsBiasMask, gen_arg(Usage::kBias)});
break;
}
case IntrinsicType::kTextureSampleLevel: {
@@ -2322,20 +2348,19 @@
if (!append_image_and_coords_to_spirv_params()) {
return false;
}
- assert(pidx.level != kNotUsed);
auto level = Operand::Int(0);
- if (TypeOf(call->params()[pidx.level])->Is<type::I32>()) {
+ if (TypeOf(arg(Usage::kLevel))->Is<type::I32>()) {
// Depth textures have i32 parameters for the level, but SPIR-V expects
// F32. Cast.
auto* f32 = builder_.create<type::F32>();
ast::TypeConstructorExpression cast(Source{}, f32,
- {call->params()[pidx.level]});
+ {arg(Usage::kLevel)});
level = Operand::Int(GenerateExpression(&cast));
if (level.to_i() == 0) {
return false;
}
} else {
- level = gen_param(pidx.level);
+ level = gen_arg(Usage::kLevel);
}
image_operands.emplace_back(ImageOperand{SpvImageOperandsLodMask, level});
break;
@@ -2346,12 +2371,10 @@
if (!append_image_and_coords_to_spirv_params()) {
return false;
}
- assert(pidx.ddx != kNotUsed);
- assert(pidx.ddy != kNotUsed);
image_operands.emplace_back(
- ImageOperand{SpvImageOperandsGradMask, gen_param(pidx.ddx)});
+ ImageOperand{SpvImageOperandsGradMask, gen_arg(Usage::kDdx)});
image_operands.emplace_back(
- ImageOperand{SpvImageOperandsGradMask, gen_param(pidx.ddy)});
+ ImageOperand{SpvImageOperandsGradMask, gen_arg(Usage::kDdy)});
break;
}
case IntrinsicType::kTextureSampleCompare: {
@@ -2360,8 +2383,7 @@
if (!append_image_and_coords_to_spirv_params()) {
return false;
}
- assert(pidx.depth_ref != kNotUsed);
- spirv_params.emplace_back(gen_param(pidx.depth_ref));
+ spirv_params.emplace_back(gen_arg(Usage::kDepthRef));
type::F32 f32;
ast::FloatLiteral float_0(Source{}, &f32, 0.0);
@@ -2374,9 +2396,9 @@
break; // unreachable
}
- if (pidx.offset != kNotUsed) {
+ if (auto* offset = arg(Usage::kOffset)) {
image_operands.emplace_back(
- ImageOperand{SpvImageOperandsConstOffsetMask, gen_param(pidx.offset)});
+ ImageOperand{SpvImageOperandsConstOffsetMask, gen(offset)});
}
if (!image_operands.empty()) {
@@ -2393,8 +2415,8 @@
}
if (op == spv::Op::OpNop) {
- error_ = "unable to determine operator for: " +
- builder_.Symbols().NameFor(ident->symbol());
+ error_ =
+ "unable to determine operator for: " + std::string(intrinsic->str());
return false;
}
diff --git a/src/writer/spirv/builder.h b/src/writer/spirv/builder.h
index 3ab7479..b1d38b3 100644
--- a/src/writer/spirv/builder.h
+++ b/src/writer/spirv/builder.h
@@ -60,8 +60,7 @@
// Forward declarations
namespace semantic {
-class TextureIntrinsicCall;
-class IntrinsicCall;
+class Call;
} // namespace semantic
namespace writer {
@@ -359,25 +358,21 @@
/// @returns the expression ID on success or 0 otherwise
uint32_t GenerateCallExpression(ast::CallExpression* expr);
/// Generates an intrinsic call
- /// @param ident the intrinsic expression
/// @param call the call expression
- /// @param sem the semantic information for the intrinsic call
+ /// @param intrinsic the semantic information for the intrinsic
/// @returns the expression ID on success or 0 otherwise
- uint32_t GenerateIntrinsic(ast::IdentifierExpression* ident,
- ast::CallExpression* call,
- const semantic::IntrinsicCall* sem);
+ uint32_t GenerateIntrinsic(ast::CallExpression* call,
+ const semantic::Intrinsic* intrinsic);
/// Generates a texture intrinsic call. Emits an error and returns false if
/// we're currently outside a function.
- /// @param ident the texture intrinsic
/// @param call the call expression
- /// @param sem the semantic information for the texture intrinsic call
+ /// @param intrinsic the semantic information for the texture intrinsic
/// @param result_type result type operand of the texture instruction
/// @param result_id result identifier operand of the texture instruction
/// parameters
/// @returns true on success
- bool GenerateTextureIntrinsic(ast::IdentifierExpression* ident,
- ast::CallExpression* call,
- const semantic::TextureIntrinsicCall* sem,
+ bool GenerateTextureIntrinsic(ast::CallExpression* call,
+ const semantic::Intrinsic* intrinsic,
spirv::Operand result_type,
spirv::Operand result_id);
/// Generates a sampled image