[llvm] [OFFLOAD] Add plugin with support for Intel oneAPI Level Zero (PR #158900)
Alexey Sachkov via llvm-commits
llvm-commits at lists.llvm.org
Tue Sep 16 06:23:40 PDT 2025
================
@@ -0,0 +1,371 @@
+//===--- Level Zero Target RTL Implementation -----------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Level Zero RTL Options support
+//
+//===----------------------------------------------------------------------===//
+
+#include "omptarget.h"
+
+#include "L0Defs.h"
+#include "L0Options.h"
+#include "L0Trace.h"
+
+namespace llvm::omp::target::plugin {
+
+/// Is the given RootID, SubID, CcsID specified in ONEAPI_DEVICE_SELECTOR
+bool L0OptionsTy::shouldAddDevice(int32_t RootID, int32_t SubID,
+ int32_t CCSID) const {
+ if (ExplicitRootDevices.empty())
+ return false;
+ for (const auto &RootDev : ExplicitRootDevices) {
+ const auto ErootID = std::get<1>(RootDev);
+ if (ErootID != -2 && RootID != ErootID)
+ continue;
+ const auto EsubID = std::get<2>(RootDev);
+ if (((EsubID != -2) || (SubID == -1)) && (EsubID != SubID))
+ continue;
+ const auto ECCSID = std::get<3>(RootDev);
+ if (((ECCSID != -2) || (CCSID == -1)) && (ECCSID != CCSID))
+ continue;
+ // Check if isDiscard
+ if (!std::get<0>(RootDev))
+ return false;
+ return true;
+ }
+ return false;
+}
+
+/// Read environment variables
+void L0OptionsTy::processEnvironmentVars() {
+ // Compilation options for IGC
+ UserCompilationOptions +=
+ std::string(" ") +
+ StringEnvar("LIBOMPTARGET_LEVEL_ZERO_COMPILATION_OPTIONS", "").get();
+
+ // Explicit Device mode if ONEAPI_DEVICE_SELECTOR is set
+ const StringEnvar DeviceSelectorVar("ONEAPI_DEVICE_SELECTOR", "");
+ if (DeviceSelectorVar.isPresent()) {
+ std::string EnvStr(std::move(DeviceSelectorVar.get()));
+ uint32_t numDiscard = 0;
+ std::transform(EnvStr.begin(), EnvStr.end(), EnvStr.begin(),
+ [](unsigned char C) { return std::tolower(C); });
+
+ std::vector<std::string_view> Entries = tokenize(EnvStr, ";", true);
+ for (const auto &Term : Entries) {
+ bool isDiscard = false;
+ std::vector<std::string_view> Pair = tokenize(Term, ":", true);
+ if (Pair.empty()) {
+ FAILURE_MESSAGE(
+ "Incomplete selector! Pair and device must be specified.\n");
+ } else if (Pair.size() == 1) {
+ FAILURE_MESSAGE("Incomplete selector! Try '%s:*'if all devices "
+ "under the Pair was original intention.\n",
+ Pair[0].data());
+ } else if (Pair.size() > 2) {
+ FAILURE_MESSAGE(
+ "Error parsing selector string \"%s\" Too many colons (:)\n",
+ Term.data());
+ }
+ if (!((Pair[0][0] == '*') ||
+ (!strncmp(Pair[0].data(), "level_zero", Pair[0].length())) ||
+ (!strncmp(Pair[0].data(), "!level_zero", Pair[0].length()))))
+ break;
+ isDiscard = Pair[0][0] == '!';
+ if (isDiscard)
+ numDiscard++;
+ else if (numDiscard > 0)
+ FAILURE_MESSAGE("All negative(discarding) filters must appear after "
+ "all positive(accepting) filters!");
+
+ std::vector<std::string_view> Targets = tokenize(Pair[1], ",", true);
+ for (const auto &TargetStr : Targets) {
+ bool HasDeviceWildCard = false;
+ bool HasSubDeviceWildCard = false;
+ bool DeviceNum = false;
+ std::vector<std::string_view> DeviceSubTuple =
+ tokenize(TargetStr, ".", true);
+ int32_t RootD[3] = {-1, -1, -1};
+ if (DeviceSubTuple.empty()) {
+ FAILURE_MESSAGE(
+ "ONEAPI_DEVICE_SELECTOR parsing error. Device must be "
+ "specified.");
+ }
+
+ std::string_view TopDeviceStr = DeviceSubTuple[0];
+ static const std::array<std::string, 7> DeviceStr = {
+ "host", "cpu", "gpu", "acc", "fpga", "*"};
+ auto It =
+ find_if(DeviceStr.begin(), DeviceStr.end(),
+ [&](auto DeviceStr) { return TopDeviceStr == DeviceStr; });
+ if (It != DeviceStr.end()) {
+ if (TopDeviceStr[0] == '*') {
+ HasDeviceWildCard = true;
+ RootD[0] = -2;
+ } else if (!strncmp(DeviceSubTuple[0].data(), "gpu", 3))
+ continue;
+ } else {
+ std::string TDS(TopDeviceStr);
+ if (!isDigits(TDS)) {
+ FAILURE_MESSAGE("error parsing device number: %s",
+ DeviceSubTuple[0].data());
+ } else {
+ RootD[0] = std::stoi(TDS);
+ DeviceNum = true;
+ }
----------------
AlexeySachkov wrote:
Why do we convert a `string_view` back to `string` in order to check that it only contains digits?
`StringRef` is constructible from `string_view` and has method `getAsInteger` - I suggest we use it instead of custom error checking.
https://github.com/llvm/llvm-project/pull/158900
More information about the llvm-commits
mailing list