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/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));
}
}