已合并
feat(jit): support pointer and struct tiling constants #5719
feat(jit): support pointer and struct tiling constants #5719
已合并
XuebinYang创建于 12 天前
26 个文件变更+1146-605
@@ -458,6 +458,9 @@ class TestStaticCompileResourceGenerator(unittest.TestCase):
458 self.assertEqual(manifest["resource_id"], self.resource_id)458 self.assertEqual(manifest["resource_id"], self.resource_id)
459 self.assertEqual(manifest["kernels"][0]["kernel_name"], "add_custom_100000")459 self.assertEqual(manifest["kernels"][0]["kernel_name"], "add_custom_100000")
460 self.assertEqual(manifest["kernels"][0]["constant_infos"][0]["byte_size"], 24)460 self.assertEqual(manifest["kernels"][0]["constant_infos"][0]["byte_size"], 24)
461+ self.assertEqual(
462+ manifest["kernels"][0]["constant_infos"][0]["arg_type"], "pointer"
463+ )
461 self.assertTrue(os.path.isdir(os.path.join(self.output_dir, "resources")))464 self.assertTrue(os.path.isdir(os.path.join(self.output_dir, "resources")))
462 465 
463 def test_basic_mix_manifest_uses_static_wrapper_and_tiling_template(self):466 def test_basic_mix_manifest_uses_static_wrapper_and_tiling_template(self):
@@ -673,6 +676,7 @@ class TestStaticCompileResourceGenerator(unittest.TestCase):
673 {676 {
674 "name": "tiling_data",677 "name": "tiling_data",
675 "parameter_index": 4,678 "parameter_index": 4,
679+ "arg_type": "pointer",
676 "byte_size": 8,680 "byte_size": 8,
677 "file": "${resource}/resources/include/add_custom_tiling_data.h",681 "file": "${resource}/resources/include/add_custom_tiling_data.h",
678 "template": "@@STATIC_VALUE_tiling_data@@",682 "template": "@@STATIC_VALUE_tiling_data@@",
@@ -680,6 +684,7 @@ class TestStaticCompileResourceGenerator(unittest.TestCase):
680 {684 {
681 "name": "block_dim",685 "name": "block_dim",
682 "parameter_index": 5,686 "parameter_index": 5,
687+ "arg_type": "pointer",
683 "byte_size": 4,688 "byte_size": 4,
684 "file": "${resource}/resources/include/add_custom_tiling_data.h",689 "file": "${resource}/resources/include/add_custom_tiling_data.h",
685 "template": block_dim_template,690 "template": block_dim_template,
@@ -21,6 +21,7 @@ file(GLOB ACLRTC_SRC_FILES
21 21 
22set(ACLRTC_COMMON_DEPENDENCY_SRC_FILES22set(ACLRTC_COMMON_DEPENDENCY_SRC_FILES
23 ${ASCENDC_DIR}/tools/build/common/file_utils.cpp23 ${ASCENDC_DIR}/tools/build/common/file_utils.cpp
24+ ${ASCENDC_DIR}/tools/build/common/manifest_constant.cpp
24 ${ASCENDC_DIR}/tools/build/common/process_executor.cpp25 ${ASCENDC_DIR}/tools/build/common/process_executor.cpp
25 ${ASCENDC_DIR}/tools/build/common/directory_cleanup_guard.cpp26 ${ASCENDC_DIR}/tools/build/common/directory_cleanup_guard.cpp
26)27)
@@ -34,7 +34,6 @@ using ascendc::aclrtc::CompilationCommandExecutionLimits;
34using ascendc::aclrtc::CompilationCommandKind;34using ascendc::aclrtc::CompilationCommandKind;
35using ascendc::aclrtc::CompilationPlanExecutor;35using ascendc::aclrtc::CompilationPlanExecutor;
36using ascendc::aclrtc::KernelCompilationPlan;36using ascendc::aclrtc::KernelCompilationPlan;
37-using ascendc::aclrtc::KernelCompilationVariant;
38using ascendc::aclrtc::KernelSpecializationDiagnostics;37using ascendc::aclrtc::KernelSpecializationDiagnostics;
39using namespace mockcpp;38using namespace mockcpp;
40 39 
@@ -68,9 +67,6 @@ pid_t ReapCommandProcess(pid_t processId, int* waitStatus, int)
68 return waitResult;67 return waitResult;
69}68}
70 69 
71-static_assert(
72- std::is_same<std::underlying_type_t<KernelCompilationVariant>, uint32_t>::value,
73- "KernelCompilationVariant must have a stable width");
74static_assert(70static_assert(
75 std::is_same<std::underlying_type_t<CompilationCommandKind>, uint32_t>::value,71 std::is_same<std::underlying_type_t<CompilationCommandKind>, uint32_t>::value,
76 "CompilationCommandKind must have a stable width");72 "CompilationCommandKind must have a stable width");
@@ -9,6 +9,7 @@
9 */9 */
10 10 
11#include "specialization/kernel_compilation_plan_builder.h"11#include "specialization/kernel_compilation_plan_builder.h"
12+#include "specialization/compilation_manifest_parser.h"
12 13 
13#include <gtest/gtest.h>14#include <gtest/gtest.h>
14#include <nlohmann/json.hpp>15#include <nlohmann/json.hpp>
@@ -20,6 +21,7 @@
20#include <fstream>21#include <fstream>
21#include <string>22#include <string>
22#include <sys/stat.h>23#include <sys/stat.h>
24+#include <sys/mman.h>
23#include <unistd.h>25#include <unistd.h>
24 26 
25namespace {27namespace {
@@ -28,7 +30,6 @@ using Json = nlohmann::json;
28using ascendc::aclrtc::CompilationCommandKind;30using ascendc::aclrtc::CompilationCommandKind;
29using ascendc::aclrtc::KernelCompilationPlan;31using ascendc::aclrtc::KernelCompilationPlan;
30using ascendc::aclrtc::KernelCompilationPlanBuilder;32using ascendc::aclrtc::KernelCompilationPlanBuilder;
31-using ascendc::aclrtc::KernelCompilationVariant;
32using ascendc::aclrtc::NormalizedKernelSpecializationRequest;33using ascendc::aclrtc::NormalizedKernelSpecializationRequest;
33 34 
34class ScopedEnvironmentVariable final {35class ScopedEnvironmentVariable final {
@@ -122,7 +123,9 @@ Json CreateManifest()
122 {{{"kernel_name", "other_kernel"}, {"unsupported_future_field", Json::object()}},123 {{{"kernel_name", "other_kernel"}, {"unsupported_future_field", Json::object()}},
123 {{"kernel_name", "add_custom_100000"},124 {{"kernel_name", "add_custom_100000"},
124 {"constant_infos", Json::array(125 {"constant_infos", Json::array(
125- {{{"parameter_index", 0},126+ {{{"name", "tiling"},
127+ {"parameter_index", 0},
128+ {"arg_type", "pointer"},
126 {"byte_size", 2},129 {"byte_size", 2},
127 {"file", "${resource}/resources/include/constants.h"},130 {"file", "${resource}/resources/include/constants.h"},
128 {"template", "@@STATIC_TILING@@"}}})},131 {"template", "@@STATIC_TILING@@"}}})},
@@ -170,6 +173,79 @@ NormalizedKernelSpecializationRequest CreateRequest(
170 return request;173 return request;
171}174}
172 175 
176+aclError BuildPlanFromManifest(
177+ const NormalizedKernelSpecializationRequest& request, const Json& json, const fs::path& worktree,
178+ const fs::path& sourceDirectory, KernelCompilationPlan& plan)
179+{
180+ ascendc::aclrtc::CompilationManifest manifest;
181+ const aclError status = ascendc::aclrtc::CompilationManifestParser(json).ParseSelected(
182+ request.kernelName, request.enableSuperKernel, manifest);
183+ if (status != ascendc::aclrtc::ACLRTC_SUCCESS) {
184+ return status;
185+ }
186+ return KernelCompilationPlanBuilder(request, manifest, worktree, sourceDirectory).BuildCompilationPlan(plan);
187+}
188+ 
189+TEST(CompilationManifestParserTest, RepeatedSelectionsDoNotRetainPartialResults)
190+{
191+ const Json json = CreateManifest();
192+ ascendc::aclrtc::CompilationManifestParser parser(json);
193+ ascendc::aclrtc::CompilationManifest manifest;
194+ EXPECT_EQ(parser.ParseSelected("missing", false, manifest), ascendc::aclrtc::ACLRTC_ERROR_FAILURE);
195+ ASSERT_EQ(parser.ParseSelected("add_custom_100000", true, manifest), ascendc::aclrtc::ACLRTC_SUCCESS);
196+ ASSERT_EQ(manifest.commands.size(), 3U);
197+ EXPECT_EQ(parser.ParseSelected("missing", false, manifest), ascendc::aclrtc::ACLRTC_ERROR_FAILURE);
198+ EXPECT_EQ(manifest.commands.size(), 3U);
199+ ASSERT_EQ(parser.ParseSelected("add_custom_100000", false, manifest), ascendc::aclrtc::ACLRTC_SUCCESS);
200+ EXPECT_EQ(manifest.commands.size(), 1U);
201+ EXPECT_EQ(manifest.constants.size(), 1U);
202+}
203+ 
204+TEST(KernelCompilationPlanBuilderTest, BuildsRepeatedPlansWithoutMutatingParsedConstants)
205+{
206+ KernelPlanTestWorkspace workspace;
207+ ScopedEnvironmentVariable toolchain("ACLRTC_TEST_TOOLCHAIN", workspace.ToolchainPath().string());
208+ ScopedEnvironmentVariable ascendHome("ASCEND_HOME_PATH", workspace.ToolchainPath().string());
209+ const uint8_t bytes[] = {1, 2};
210+ const void* addresses[] = {bytes};
211+ auto request = CreateRequest(workspace, addresses, nullptr);
212+ ascendc::aclrtc::CompilationManifest manifest;
213+ const Json json = CreateManifest();
214+ ASSERT_EQ(
215+ ascendc::aclrtc::CompilationManifestParser(json).ParseSelected(
216+ request.kernelName, request.enableSuperKernel, manifest),
217+ ascendc::aclrtc::ACLRTC_SUCCESS);
218+ KernelCompilationPlanBuilder builder(request, manifest, workspace.ResourcePath(), workspace.SourceDirectoryPath());
219+ KernelCompilationPlan plan;
220+ ASSERT_EQ(builder.BuildCompilationPlan(plan), ascendc::aclrtc::ACLRTC_SUCCESS);
221+ ASSERT_EQ(builder.BuildCompilationPlan(plan), ascendc::aclrtc::ACLRTC_SUCCESS);
222+ ASSERT_EQ(plan.sourcePatches.size(), 1U);
223+ EXPECT_EQ(plan.sourcePatches[0].replacementText, "{0x01, 0x02}");
224+ EXPECT_EQ(manifest.constants[0].GetBoundData(), nullptr);
225+ EXPECT_EQ(manifest.constants[0].GetBoundByteSize(), 0U);
226+}
227+ 
228+TEST(CompilationManifestParserTest, OwnsSelectedFieldsWithoutResolvingRuntimeEnvironment)
229+{
230+ Json manifest = CreateManifest();
231+ manifest["kernels"][1]["objects"][1].erase("commands");
232+ manifest["options"]["unused"] = 7;
233+ ascendc::aclrtc::CompilationManifest spec;
234+ ASSERT_EQ(
235+ ascendc::aclrtc::CompilationManifestParser(manifest).ParseSelected("add_custom_100000", false, spec),
236+ ascendc::aclrtc::ACLRTC_SUCCESS);
237+ manifest.clear();
238+ ASSERT_EQ(spec.constants.size(), 1U);
239+ const uint8_t byte = 0;
240+ const void* addresses[] = {&byte};
241+ ASSERT_TRUE(spec.constants[0].BindArgument(1U, addresses, nullptr));
242+ EXPECT_EQ(spec.constants[0].GetBoundByteSize(), 2U);
243+ ASSERT_EQ(spec.commands.size(), 1U);
244+ EXPECT_EQ(spec.commands[0].executable, "${env:ACLRTC_TEST_TOOLCHAIN}/bin/bisheng");
245+ ASSERT_GE(spec.commands[0].arguments.size(), 3U);
246+ EXPECT_EQ(spec.commands[0].arguments[2], "-I${env:ACLRTC_TEST_TOOLCHAIN}/include");
247+}
248+ 
173TEST(KernelCompilationPlanBuilderTest, BuildsBasicPlanFromOnlySelectedManifestFields)249TEST(KernelCompilationPlanBuilderTest, BuildsBasicPlanFromOnlySelectedManifestFields)
174{250{
175 KernelPlanTestWorkspace workspace;251 KernelPlanTestWorkspace workspace;
@@ -184,9 +260,8 @@ TEST(KernelCompilationPlanBuilderTest, BuildsBasicPlanFromOnlySelectedManifestFi
184 260 
185 KernelCompilationPlan plan;261 KernelCompilationPlan plan;
186 EXPECT_EQ(262 EXPECT_EQ(
187- KernelCompilationPlanBuilder(263+ BuildPlanFromManifest(
188- request, CreateManifest(), workspace.ResourcePath(), workspace.SourceDirectoryPath())264+ request, CreateManifest(), workspace.ResourcePath(), workspace.SourceDirectoryPath(), plan),
189- .BuildCompilationPlan(plan),
190 0);265 0);
191 266 
192 ASSERT_EQ(plan.sourcePatches.size(), 1U);267 ASSERT_EQ(plan.sourcePatches.size(), 1U);
@@ -198,7 +273,7 @@ TEST(KernelCompilationPlanBuilderTest, BuildsBasicPlanFromOnlySelectedManifestFi
198 EXPECT_EQ(compileCommand.commandKind, CompilationCommandKind::Compile);273 EXPECT_EQ(compileCommand.commandKind, CompilationCommandKind::Compile);
199 EXPECT_EQ(compileCommand.executablePath, workspace.ToolchainPath() / "bin/bisheng");274 EXPECT_EQ(compileCommand.executablePath, workspace.ToolchainPath() / "bin/bisheng");
200 EXPECT_EQ(275 EXPECT_EQ(
201- compileCommand.commandArguments,276+ compileCommand.arguments,
202 (std::vector<std::string>{277 (std::vector<std::string>{
203 "-I", workspace.SourceDirectoryPath().string(), "-I" + (workspace.ToolchainPath() / "include").string(),278 "-I", workspace.SourceDirectoryPath().string(), "-I" + (workspace.ToolchainPath() / "include").string(),
204 (workspace.ResourcePath() / "resources/src/basic.cpp").string(), "-g", "-DVALUE=1", "-o",279 (workspace.ResourcePath() / "resources/src/basic.cpp").string(), "-g", "-DVALUE=1", "-o",
@@ -223,8 +298,7 @@ TEST(KernelCompilationPlanBuilderTest, BuildsPlanWithoutOptionalExternalSourceFi
223 298 
224 KernelCompilationPlan plan;299 KernelCompilationPlan plan;
225 EXPECT_EQ(300 EXPECT_EQ(
226- KernelCompilationPlanBuilder(request, manifest, workspace.ResourcePath(), fs::path())301+ BuildPlanFromManifest(request, manifest, workspace.ResourcePath(), fs::path(), plan),
227- .BuildCompilationPlan(plan),
228 ascendc::aclrtc::ACLRTC_SUCCESS);302 ascendc::aclrtc::ACLRTC_SUCCESS);
229}303}
230 304 
@@ -242,8 +316,7 @@ TEST(KernelCompilationPlanBuilderTest, RejectsCompileCommandWithoutOutputPath)
242 316 
243 KernelCompilationPlan plan;317 KernelCompilationPlan plan;
244 EXPECT_EQ(318 EXPECT_EQ(
245- KernelCompilationPlanBuilder(request, manifest, workspace.ResourcePath(), workspace.SourceDirectoryPath())319+ BuildPlanFromManifest(request, manifest, workspace.ResourcePath(), workspace.SourceDirectoryPath(), plan),
246- .BuildCompilationPlan(plan),
247 ascendc::aclrtc::ACLRTC_ERROR_FAILURE);320 ascendc::aclrtc::ACLRTC_ERROR_FAILURE);
248}321}
249 322 
@@ -261,8 +334,7 @@ TEST(KernelCompilationPlanBuilderTest, DoesNotTreatNonOutputOptionAsCompilerOutp
261 334 
262 KernelCompilationPlan plan;335 KernelCompilationPlan plan;
263 EXPECT_EQ(336 EXPECT_EQ(
264- KernelCompilationPlanBuilder(request, manifest, workspace.ResourcePath(), workspace.SourceDirectoryPath())337+ BuildPlanFromManifest(request, manifest, workspace.ResourcePath(), workspace.SourceDirectoryPath(), plan),
265- .BuildCompilationPlan(plan),
266 ascendc::aclrtc::ACLRTC_ERROR_FAILURE);338 ascendc::aclrtc::ACLRTC_ERROR_FAILURE);
267}339}
268 340 
@@ -280,9 +352,7 @@ TEST(KernelCompilationPlanBuilderTest, AcceptsCommandWithoutStageAndPreservesMan
280 352 
281 KernelCompilationPlan plan;353 KernelCompilationPlan plan;
282 ASSERT_EQ(354 ASSERT_EQ(
283- KernelCompilationPlanBuilder(request, manifest, workspace.ResourcePath(), workspace.SourceDirectoryPath())355+ BuildPlanFromManifest(request, manifest, workspace.ResourcePath(), workspace.SourceDirectoryPath(), plan), 0);
284- .BuildCompilationPlan(plan),
285- 0);
286 ASSERT_EQ(plan.compilationCommands.size(), 2U);356 ASSERT_EQ(plan.compilationCommands.size(), 2U);
287 EXPECT_EQ(plan.compilationCommands[0].diagnosticLabel, "basic/compile[0]");357 EXPECT_EQ(plan.compilationCommands[0].diagnosticLabel, "basic/compile[0]");
288 EXPECT_FALSE(plan.compilationCommands[0].parallelStage.has_value());358 EXPECT_FALSE(plan.compilationCommands[0].parallelStage.has_value());
@@ -300,14 +370,13 @@ TEST(KernelCompilationPlanBuilderTest, PreservesExplicitStagesAndManifestCommand
300 const void* argumentAddresses[] = {tilingBytes};370 const void* argumentAddresses[] = {tilingBytes};
301 const uint64_t argumentByteCounts[] = {sizeof(tilingBytes)};371 const uint64_t argumentByteCounts[] = {sizeof(tilingBytes)};
302 NormalizedKernelSpecializationRequest request = CreateRequest(workspace, argumentAddresses, argumentByteCounts);372 NormalizedKernelSpecializationRequest request = CreateRequest(workspace, argumentAddresses, argumentByteCounts);
303- request.compilationVariant = KernelCompilationVariant::BasicWithSuperKernel;373+ request.enableSuperKernel = true;
304 request.compilerOptions.superKernelOptions = {"-g"};374 request.compilerOptions.superKernelOptions = {"-g"};
305 375 
306 KernelCompilationPlan plan;376 KernelCompilationPlan plan;
307 ASSERT_EQ(377 ASSERT_EQ(
308- KernelCompilationPlanBuilder(378+ BuildPlanFromManifest(
309- request, CreateManifest(), workspace.ResourcePath(), workspace.SourceDirectoryPath())379+ request, CreateManifest(), workspace.ResourcePath(), workspace.SourceDirectoryPath(), plan),
310- .BuildCompilationPlan(plan),
311 0);380 0);
312 ASSERT_EQ(plan.compilationCommands.size(), 4U);381 ASSERT_EQ(plan.compilationCommands.size(), 4U);
313 EXPECT_EQ(plan.compilationCommands[0].diagnosticLabel, "basic/compile[0]");382 EXPECT_EQ(plan.compilationCommands[0].diagnosticLabel, "basic/compile[0]");
@@ -319,10 +388,8 @@ TEST(KernelCompilationPlanBuilderTest, PreservesExplicitStagesAndManifestCommand
319 EXPECT_EQ(plan.compilationCommands[2].parallelStage, 1U);388 EXPECT_EQ(plan.compilationCommands[2].parallelStage, 1U);
320 EXPECT_FALSE(plan.compilationCommands[3].parallelStage.has_value());389 EXPECT_FALSE(plan.compilationCommands[3].parallelStage.has_value());
321 EXPECT_NE(390 EXPECT_NE(
322- std::find(391+ std::find(plan.compilationCommands[1].arguments.begin(), plan.compilationCommands[1].arguments.end(), "-g"),
323- plan.compilationCommands[1].commandArguments.begin(), plan.compilationCommands[1].commandArguments.end(),392+ plan.compilationCommands[1].arguments.end());
324- "-g"),
325- plan.compilationCommands[1].commandArguments.end());
326}393}
327 394 
328TEST(KernelCompilationPlanBuilderTest, SelectsAllRequestedObjectsInManifestOrder)395TEST(KernelCompilationPlanBuilderTest, SelectsAllRequestedObjectsInManifestOrder)
@@ -335,7 +402,7 @@ TEST(KernelCompilationPlanBuilderTest, SelectsAllRequestedObjectsInManifestOrder
335 const void* argumentAddresses[] = {tilingBytes};402 const void* argumentAddresses[] = {tilingBytes};
336 const uint64_t argumentByteCounts[] = {sizeof(tilingBytes)};403 const uint64_t argumentByteCounts[] = {sizeof(tilingBytes)};
337 NormalizedKernelSpecializationRequest request = CreateRequest(workspace, argumentAddresses, argumentByteCounts);404 NormalizedKernelSpecializationRequest request = CreateRequest(workspace, argumentAddresses, argumentByteCounts);
338- request.compilationVariant = KernelCompilationVariant::BasicWithSuperKernel;405+ request.enableSuperKernel = true;
339 406 
340 Json manifest = CreateManifest();407 Json manifest = CreateManifest();
341 Json secondBasicObject = manifest["kernels"][1]["objects"][0];408 Json secondBasicObject = manifest["kernels"][1]["objects"][0];
@@ -354,9 +421,7 @@ TEST(KernelCompilationPlanBuilderTest, SelectsAllRequestedObjectsInManifestOrder
354 421 
355 KernelCompilationPlan plan;422 KernelCompilationPlan plan;
356 ASSERT_EQ(423 ASSERT_EQ(
357- KernelCompilationPlanBuilder(request, manifest, workspace.ResourcePath(), workspace.SourceDirectoryPath())424+ BuildPlanFromManifest(request, manifest, workspace.ResourcePath(), workspace.SourceDirectoryPath(), plan), 0);
358- .BuildCompilationPlan(plan),
359- 0);
360 425 
361 ASSERT_EQ(plan.compilationCommands.size(), 7U);426 ASSERT_EQ(plan.compilationCommands.size(), 7U);
362 EXPECT_EQ(plan.compilationCommands[0].diagnosticLabel, "basic/compile[0]");427 EXPECT_EQ(plan.compilationCommands[0].diagnosticLabel, "basic/compile[0]");
@@ -367,7 +432,7 @@ TEST(KernelCompilationPlanBuilderTest, SelectsAllRequestedObjectsInManifestOrder
367 EXPECT_EQ(plan.compilationCommands[5].diagnosticLabel, "sk_aux/objcopy[1]");432 EXPECT_EQ(plan.compilationCommands[5].diagnosticLabel, "sk_aux/objcopy[1]");
368 EXPECT_EQ(plan.compilationCommands[6].diagnosticLabel, "link");433 EXPECT_EQ(plan.compilationCommands[6].diagnosticLabel, "link");
369 434 
370- const std::vector<std::string>& linkArguments = plan.compilationCommands.back().commandArguments;435+ const std::vector<std::string>& linkArguments = plan.compilationCommands.back().arguments;
371 EXPECT_NE(436 EXPECT_NE(
372 std::find(437 std::find(
373 linkArguments.begin(), linkArguments.end(),438 linkArguments.begin(), linkArguments.end(),
@@ -393,16 +458,14 @@ TEST(KernelCompilationPlanBuilderTest, RequiresOnlyEnvironmentUsedBySelectedObje
393 458 
394 KernelCompilationPlan plan;459 KernelCompilationPlan plan;
395 EXPECT_EQ(460 EXPECT_EQ(
396- KernelCompilationPlanBuilder(461+ BuildPlanFromManifest(
397- request, CreateManifest(), workspace.ResourcePath(), workspace.SourceDirectoryPath())462+ request, CreateManifest(), workspace.ResourcePath(), workspace.SourceDirectoryPath(), plan),
398- .BuildCompilationPlan(plan),
399 0);463 0);
400 464 
401- request.compilationVariant = KernelCompilationVariant::BasicWithSuperKernel;465+ request.enableSuperKernel = true;
402 EXPECT_EQ(466 EXPECT_EQ(
403- KernelCompilationPlanBuilder(467+ BuildPlanFromManifest(
404- request, CreateManifest(), workspace.ResourcePath(), workspace.SourceDirectoryPath())468+ request, CreateManifest(), workspace.ResourcePath(), workspace.SourceDirectoryPath(), plan),
405- .BuildCompilationPlan(plan),
406 ascendc::aclrtc::ACLRTC_ERROR_FAILURE);469 ascendc::aclrtc::ACLRTC_ERROR_FAILURE);
407}470}
408 471 
@@ -421,17 +484,16 @@ TEST(KernelCompilationPlanBuilderTest, RejectsMalformedEnvironmentPlaceholders)
421 manifestWithUnterminatedPlaceholder["kernels"][1]["objects"][0]["commands"][0]["cmd"][2] =484 manifestWithUnterminatedPlaceholder["kernels"][1]["objects"][0]["commands"][0]["cmd"][2] =
422 "${env:ACLRTC_TEST_TOOLCHAIN";485 "${env:ACLRTC_TEST_TOOLCHAIN";
423 EXPECT_EQ(486 EXPECT_EQ(
424- KernelCompilationPlanBuilder(487+ BuildPlanFromManifest(
425- request, manifestWithUnterminatedPlaceholder, workspace.ResourcePath(), workspace.SourceDirectoryPath())488+ request, manifestWithUnterminatedPlaceholder, workspace.ResourcePath(), workspace.SourceDirectoryPath(),
426- .BuildCompilationPlan(plan),489+ plan),
427 ascendc::aclrtc::ACLRTC_ERROR_FAILURE);490 ascendc::aclrtc::ACLRTC_ERROR_FAILURE);
428 491 
429 Json manifestWithEmptyEnvironmentName = CreateManifest();492 Json manifestWithEmptyEnvironmentName = CreateManifest();
430 manifestWithEmptyEnvironmentName["kernels"][1]["objects"][0]["commands"][0]["cmd"][2] = "${env:}";493 manifestWithEmptyEnvironmentName["kernels"][1]["objects"][0]["commands"][0]["cmd"][2] = "${env:}";
431 EXPECT_EQ(494 EXPECT_EQ(
432- KernelCompilationPlanBuilder(495+ BuildPlanFromManifest(
433- request, manifestWithEmptyEnvironmentName, workspace.ResourcePath(), workspace.SourceDirectoryPath())496+ request, manifestWithEmptyEnvironmentName, workspace.ResourcePath(), workspace.SourceDirectoryPath(), plan),
434- .BuildCompilationPlan(plan),
435 ascendc::aclrtc::ACLRTC_ERROR_FAILURE);497 ascendc::aclrtc::ACLRTC_ERROR_FAILURE);
436}498}
437 499 
@@ -449,8 +511,7 @@ TEST(KernelCompilationPlanBuilderTest, RejectsUndefinedOptionReference)
449 511 
450 KernelCompilationPlan plan;512 KernelCompilationPlan plan;
451 EXPECT_EQ(513 EXPECT_EQ(
452- KernelCompilationPlanBuilder(request, manifest, workspace.ResourcePath(), workspace.SourceDirectoryPath())514+ BuildPlanFromManifest(request, manifest, workspace.ResourcePath(), workspace.SourceDirectoryPath(), plan),
453- .BuildCompilationPlan(plan),
454 ascendc::aclrtc::ACLRTC_ERROR_FAILURE);515 ascendc::aclrtc::ACLRTC_ERROR_FAILURE);
455}516}
456 517 
@@ -470,16 +531,10 @@ TEST(KernelCompilationPlanBuilderTest, DoesNotRecursivelyExpandEnvironmentOrUser
470 531 
471 KernelCompilationPlan plan;532 KernelCompilationPlan plan;
472 ASSERT_EQ(533 ASSERT_EQ(
473- KernelCompilationPlanBuilder(request, manifest, workspace.ResourcePath(), workspace.SourceDirectoryPath())534+ BuildPlanFromManifest(request, manifest, workspace.ResourcePath(), workspace.SourceDirectoryPath(), plan), 0);
474- .BuildCompilationPlan(plan),535+ const std::vector<std::string>& arguments = plan.compilationCommands.front().arguments;
475- 0);536+ EXPECT_NE(std::find(arguments.begin(), arguments.end(), "${options:not_reexpanded}"), arguments.end());
476- const std::vector<std::string>& commandArguments = plan.compilationCommands.front().commandArguments;537+ EXPECT_NE(std::find(arguments.begin(), arguments.end(), "${env:USER_OPTION_STAYS_LITERAL}"), arguments.end());
477- EXPECT_NE(
478- std::find(commandArguments.begin(), commandArguments.end(), "${options:not_reexpanded}"),
479- commandArguments.end());
480- EXPECT_NE(
481- std::find(commandArguments.begin(), commandArguments.end(), "${env:USER_OPTION_STAYS_LITERAL}"),
482- commandArguments.end());
483}538}
484 539 
485TEST(KernelCompilationPlanBuilderTest, AcceptsKernelWithoutLinkOptions)540TEST(KernelCompilationPlanBuilderTest, AcceptsKernelWithoutLinkOptions)
@@ -496,9 +551,7 @@ TEST(KernelCompilationPlanBuilderTest, AcceptsKernelWithoutLinkOptions)
496 551 
497 KernelCompilationPlan plan;552 KernelCompilationPlan plan;
498 EXPECT_EQ(553 EXPECT_EQ(
499- KernelCompilationPlanBuilder(request, manifest, workspace.ResourcePath(), workspace.SourceDirectoryPath())554+ BuildPlanFromManifest(request, manifest, workspace.ResourcePath(), workspace.SourceDirectoryPath(), plan), 0);
500- .BuildCompilationPlan(plan),
501- 0);
502 EXPECT_EQ(plan.sourcePatches.size(), 1U);555 EXPECT_EQ(plan.sourcePatches.size(), 1U);
503 ASSERT_EQ(plan.compilationCommands.size(), 2U);556 ASSERT_EQ(plan.compilationCommands.size(), 2U);
504 EXPECT_EQ(plan.compilationCommands.back().commandKind, CompilationCommandKind::Link);557 EXPECT_EQ(plan.compilationCommands.back().commandKind, CompilationCommandKind::Link);
@@ -515,17 +568,15 @@ TEST(KernelCompilationPlanBuilderTest, RejectsKernelWithoutStaticConstants)
515 Json manifestWithoutConstants = CreateManifest();568 Json manifestWithoutConstants = CreateManifest();
516 manifestWithoutConstants["kernels"][1].erase("constant_infos");569 manifestWithoutConstants["kernels"][1].erase("constant_infos");
517 EXPECT_EQ(570 EXPECT_EQ(
518- KernelCompilationPlanBuilder(571+ BuildPlanFromManifest(
519- request, manifestWithoutConstants, workspace.ResourcePath(), workspace.SourceDirectoryPath())572+ request, manifestWithoutConstants, workspace.ResourcePath(), workspace.SourceDirectoryPath(), plan),
520- .BuildCompilationPlan(plan),
521 ascendc::aclrtc::ACLRTC_ERROR_FAILURE);573 ascendc::aclrtc::ACLRTC_ERROR_FAILURE);
522 574 
523 Json manifestWithEmptyConstants = CreateManifest();575 Json manifestWithEmptyConstants = CreateManifest();
524 manifestWithEmptyConstants["kernels"][1]["constant_infos"] = Json::array();576 manifestWithEmptyConstants["kernels"][1]["constant_infos"] = Json::array();
525 EXPECT_EQ(577 EXPECT_EQ(
526- KernelCompilationPlanBuilder(578+ BuildPlanFromManifest(
527- request, manifestWithEmptyConstants, workspace.ResourcePath(), workspace.SourceDirectoryPath())579+ request, manifestWithEmptyConstants, workspace.ResourcePath(), workspace.SourceDirectoryPath(), plan),
528- .BuildCompilationPlan(plan),
529 ascendc::aclrtc::ACLRTC_ERROR_FAILURE);580 ascendc::aclrtc::ACLRTC_ERROR_FAILURE);
530}581}
531 582 
@@ -538,28 +589,144 @@ TEST(KernelCompilationPlanBuilderTest, RejectsMissingRuntimeConstantBuffer)
538 589 
539 KernelCompilationPlan plan;590 KernelCompilationPlan plan;
540 EXPECT_EQ(591 EXPECT_EQ(
541- KernelCompilationPlanBuilder(592+ BuildPlanFromManifest(
542- request, CreateManifest(), workspace.ResourcePath(), workspace.SourceDirectoryPath())593+ request, CreateManifest(), workspace.ResourcePath(), workspace.SourceDirectoryPath(), plan),
543- .BuildCompilationPlan(plan),
544 ascendc::aclrtc::ACLRTC_ERROR_INVALID_INPUT);594 ascendc::aclrtc::ACLRTC_ERROR_INVALID_INPUT);
545}595}
546 596 
547-TEST(KernelCompilationPlanBuilderTest, RejectsMismatchedRuntimeConstantByteCount)597+TEST(KernelCompilationPlanBuilderTest, PointerConstantUsesManifestByteSize)
548{598{
549 KernelPlanTestWorkspace workspace;599 KernelPlanTestWorkspace workspace;
550 ScopedEnvironmentVariable toolchainEnvironment("ACLRTC_TEST_TOOLCHAIN", workspace.ToolchainPath().string());600 ScopedEnvironmentVariable toolchainEnvironment("ACLRTC_TEST_TOOLCHAIN", workspace.ToolchainPath().string());
551 ScopedEnvironmentVariable ascendHomeEnvironment("ASCEND_HOME_PATH", workspace.ToolchainPath().string());601 ScopedEnvironmentVariable ascendHomeEnvironment("ASCEND_HOME_PATH", workspace.ToolchainPath().string());
552- const uint8_t oversizedTilingBytes[] = {0x01, 0x02, 0x03};602+ const uint8_t tilingBytes[] = {0x01, 0x02, 0x03};
553- const void* argumentDataPointers[] = {oversizedTilingBytes};603+ const void* argumentDataPointers[] = {tilingBytes};
554- const uint64_t argumentByteCounts[] = {sizeof(oversizedTilingBytes)};604+ NormalizedKernelSpecializationRequest request = CreateRequest(workspace, argumentDataPointers, nullptr);
555- NormalizedKernelSpecializationRequest request = CreateRequest(workspace, argumentDataPointers, argumentByteCounts);
556 605 
557 KernelCompilationPlan plan;606 KernelCompilationPlan plan;
558 EXPECT_EQ(607 EXPECT_EQ(
559- KernelCompilationPlanBuilder(608+ BuildPlanFromManifest(
560- request, CreateManifest(), workspace.ResourcePath(), workspace.SourceDirectoryPath())609+ request, CreateManifest(), workspace.ResourcePath(), workspace.SourceDirectoryPath(), plan),
561- .BuildCompilationPlan(plan),610+ ascendc::aclrtc::ACLRTC_SUCCESS);
562- ascendc::aclrtc::ACLRTC_ERROR_INVALID_INPUT);611+ ASSERT_EQ(plan.sourcePatches.size(), 1U);
612+ EXPECT_EQ(plan.sourcePatches[0].replacementText, "{0x01, 0x02}");
613+}
614+ 
615+TEST(KernelCompilationPlanBuilderTest, DefaultStructConstantUsesArgumentByteSize)
616+{
617+ KernelPlanTestWorkspace workspace;
618+ ScopedEnvironmentVariable toolchainEnvironment("ACLRTC_TEST_TOOLCHAIN", workspace.ToolchainPath().string());
619+ ScopedEnvironmentVariable ascendHomeEnvironment("ASCEND_HOME_PATH", workspace.ToolchainPath().string());
620+ const uint8_t tilingBytes[] = {0x01, 0x02, 0x03};
621+ const void* argumentDataPointers[] = {tilingBytes};
622+ const uint64_t argumentByteCounts[] = {sizeof(tilingBytes)};
623+ NormalizedKernelSpecializationRequest request = CreateRequest(workspace, argumentDataPointers, argumentByteCounts);
624+ Json manifest = CreateManifest();
625+ manifest["kernels"][1]["constant_infos"][0].erase("arg_type");
626+ manifest["kernels"][1]["constant_infos"][0].erase("byte_size");
627+ 
628+ KernelCompilationPlan plan;
629+ EXPECT_EQ(
630+ BuildPlanFromManifest(request, manifest, workspace.ResourcePath(), workspace.SourceDirectoryPath(), plan),
631+ ascendc::aclrtc::ACLRTC_SUCCESS);
632+ ASSERT_EQ(plan.sourcePatches.size(), 1U);
633+ EXPECT_EQ(plan.sourcePatches[0].replacementText, "{0x01, 0x02, 0x03}");
634+}
635+ 
636+TEST(KernelCompilationPlanBuilderTest, RejectsStructConstantWithManifestByteSize)
637+{
638+ KernelPlanTestWorkspace workspace;
639+ ScopedEnvironmentVariable toolchainEnvironment("ACLRTC_TEST_TOOLCHAIN", workspace.ToolchainPath().string());
640+ ScopedEnvironmentVariable ascendHomeEnvironment("ASCEND_HOME_PATH", workspace.ToolchainPath().string());
641+ const uint8_t tilingBytes[] = {0x01, 0x02, 0x03};
642+ const void* argumentDataPointers[] = {tilingBytes};
643+ const uint64_t argumentByteCounts[] = {sizeof(tilingBytes)};
644+ NormalizedKernelSpecializationRequest request = CreateRequest(workspace, argumentDataPointers, argumentByteCounts);
645+ Json manifest = CreateManifest();
646+ manifest["kernels"][1]["constant_infos"][0]["arg_type"] = "struct";
647+ 
648+ KernelCompilationPlan plan;
649+ EXPECT_EQ(
650+ BuildPlanFromManifest(request, manifest, workspace.ResourcePath(), workspace.SourceDirectoryPath(), plan),
651+ ascendc::aclrtc::ACLRTC_ERROR_FAILURE);
652+ manifest["kernels"][1]["constant_infos"][0].erase("arg_type");
653+ EXPECT_EQ(
654+ BuildPlanFromManifest(request, manifest, workspace.ResourcePath(), workspace.SourceDirectoryPath(), plan),
655+ ascendc::aclrtc::ACLRTC_ERROR_FAILURE);
656+ EXPECT_TRUE(plan.sourcePatches.empty());
657+}
658+ 
659+TEST(KernelCompilationPlanBuilderTest, RejectsInvalidInputsBeforeReadingAnyConstantBytes)
660+{
661+ KernelPlanTestWorkspace workspace;
662+ ScopedEnvironmentVariable toolchainEnvironment("ACLRTC_TEST_TOOLCHAIN", workspace.ToolchainPath().string());
663+ ScopedEnvironmentVariable ascendHomeEnvironment("ASCEND_HOME_PATH", workspace.ToolchainPath().string());
664+ for (int invalidInputKind : {0, 1, 2}) {
665+ // A protected buffer detects reads before the remaining inputs have been checked.
666+ ASSERT_EXIT(
667+ {
668+ const size_t pageSize = static_cast<size_t>(sysconf(_SC_PAGESIZE));
669+ void* unreadable = mmap(nullptr, pageSize, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
670+ if (unreadable == MAP_FAILED) {
671+ _exit(2);
672+ }
673+ const void* addresses[] = {unreadable};
674+ const uint64_t sizes[] = {2U};
675+ auto request = CreateRequest(workspace, addresses, sizes);
676+ Json manifest = CreateManifest();
677+ auto& kernel = manifest["kernels"][1];
678+ if (invalidInputKind == 0) {
679+ Json constant = kernel["constant_infos"][0];
680+ constant["parameter_index"] = 1U;
681+ kernel["constant_infos"].push_back(constant);
682+ } else if (invalidInputKind == 1) {
683+ kernel["objects"][0]["commands"][0]["cmd"][0] = "/aclrtc-test-missing-compiler";
684+ } else {
685+ unsetenv("ACLRTC_TEST_MISSING_LINK_OPTION");
686+ kernel["link_options"] = Json::array({"${env:ACLRTC_TEST_MISSING_LINK_OPTION}"});
687+ }
688+ KernelCompilationPlan plan;
689+ plan.linkedKernelElfPath = "unchanged.elf";
690+ const auto status = BuildPlanFromManifest(
691+ request, manifest, workspace.ResourcePath(), workspace.SourceDirectoryPath(), plan);
692+ const auto expected = invalidInputKind == 0 ? ascendc::aclrtc::ACLRTC_ERROR_INVALID_INPUT :
693+ ascendc::aclrtc::ACLRTC_ERROR_FAILURE;
694+ munmap(unreadable, pageSize);
695+ _exit(status == expected && plan.linkedKernelElfPath == "unchanged.elf" ? 0 : 1);
696+ },
697+ ::testing::ExitedWithCode(0), "");
698+ }
699+}
700+ 
701+TEST(KernelCompilationPlanBuilderTest, BuildsMixedConstantsUsingEachParameterIndexAndSizeSource)
702+{
703+ KernelPlanTestWorkspace workspace;
704+ ScopedEnvironmentVariable toolchainEnvironment("ACLRTC_TEST_TOOLCHAIN", workspace.ToolchainPath().string());
705+ ScopedEnvironmentVariable ascendHomeEnvironment("ASCEND_HOME_PATH", workspace.ToolchainPath().string());
706+ const uint8_t pointerBytes[] = {0x01, 0x02, 0x03};
707+ const uint8_t structBytes[] = {0xfe, 0xff, 0x04};
708+ const void* addresses[] = {nullptr, pointerBytes, structBytes};
709+ const uint64_t sizes[] = {0U, sizeof(void*), sizeof(structBytes)};
710+ auto request = CreateRequest(workspace, addresses, sizes);
711+ request.kernelArgumentCount = 3U;
712+ Json manifest = CreateManifest();
713+ auto& constants = manifest["kernels"][1]["constant_infos"];
714+ constants[0]["parameter_index"] = 1U;
715+ Json structConstant = constants[0];
716+ structConstant["parameter_index"] = 2U;
717+ structConstant["arg_type"] = "struct";
718+ structConstant.erase("byte_size");
719+ structConstant["template"] = "@@STRUCT@@";
720+ constants.push_back(structConstant);
721+ 
722+ KernelCompilationPlan plan;
723+ ASSERT_EQ(
724+ BuildPlanFromManifest(request, manifest, workspace.ResourcePath(), workspace.SourceDirectoryPath(), plan),
725+ ascendc::aclrtc::ACLRTC_SUCCESS);
726+ ASSERT_EQ(plan.sourcePatches.size(), 2U);
727+ EXPECT_EQ(plan.sourcePatches[0].replacementText, "{0x01, 0x02}");
728+ EXPECT_EQ(plan.sourcePatches[1].replacementText, "{0xfe, 0xff, 0x04}");
729+ EXPECT_EQ(plan.sourcePatches[1].templateText, "@@STRUCT@@");
563}730}
564 731 
565TEST(KernelCompilationPlanBuilderTest, RejectsMissingResourceWorktree)732TEST(KernelCompilationPlanBuilderTest, RejectsMissingResourceWorktree)
@@ -574,41 +741,11 @@ TEST(KernelCompilationPlanBuilderTest, RejectsMissingResourceWorktree)
574 741 
575 const fs::path missingWorktreePath = workspace.ResourcePath() / "missing";742 const fs::path missingWorktreePath = workspace.ResourcePath() / "missing";
576 EXPECT_EQ(743 EXPECT_EQ(
577- KernelCompilationPlanBuilder(request, CreateManifest(), missingWorktreePath, workspace.SourceDirectoryPath())744+ BuildPlanFromManifest(request, CreateManifest(), missingWorktreePath, workspace.SourceDirectoryPath(), plan),
578- .BuildCompilationPlan(plan),
579 ascendc::aclrtc::ACLRTC_ERROR_FAILURE);745 ascendc::aclrtc::ACLRTC_ERROR_FAILURE);
580}746}
581 747 
582-TEST(KernelCompilationPlanBuilderTest, RejectsInvalidRuntimeConstantLocations)748+TEST(KernelCompilationPlanBuilderTest, ExpandsCommandPrefixAndRejectsInvalidCommands)
583-{
584- KernelPlanTestWorkspace workspace;
585- ScopedEnvironmentVariable toolchainEnvironment("ACLRTC_TEST_TOOLCHAIN", workspace.ToolchainPath().string());
586- ScopedEnvironmentVariable ascendHomeEnvironment("ASCEND_HOME_PATH", workspace.ToolchainPath().string());
587- const uint8_t constantBytes[] = {0x01, 0x02};
588- const void* validArgumentDataPointers[] = {constantBytes};
589- const void* nullArgumentDataPointers[] = {nullptr};
590- const uint64_t argumentByteCounts[] = {sizeof(constantBytes)};
591- KernelCompilationPlan plan;
592- 
593- Json outOfRangeManifest = CreateManifest();
594- outOfRangeManifest["kernels"][1]["constant_infos"][0]["parameter_index"] = 1U;
595- NormalizedKernelSpecializationRequest request =
596- CreateRequest(workspace, validArgumentDataPointers, argumentByteCounts);
597- EXPECT_EQ(
598- KernelCompilationPlanBuilder(
599- request, outOfRangeManifest, workspace.ResourcePath(), workspace.SourceDirectoryPath())
600- .BuildCompilationPlan(plan),
601- ascendc::aclrtc::ACLRTC_ERROR_INVALID_INPUT);
602- 
603- request = CreateRequest(workspace, nullArgumentDataPointers, argumentByteCounts);
604- EXPECT_EQ(
605- KernelCompilationPlanBuilder(
606- request, CreateManifest(), workspace.ResourcePath(), workspace.SourceDirectoryPath())
607- .BuildCompilationPlan(plan),
608- ascendc::aclrtc::ACLRTC_ERROR_INVALID_INPUT);
609-}
610- 
611-TEST(KernelCompilationPlanBuilderTest, RejectsMalformedManifestCommands)
612{749{
613 KernelPlanTestWorkspace workspace;750 KernelPlanTestWorkspace workspace;
614 ScopedEnvironmentVariable toolchainEnvironment("ACLRTC_TEST_TOOLCHAIN", workspace.ToolchainPath().string());751 ScopedEnvironmentVariable toolchainEnvironment("ACLRTC_TEST_TOOLCHAIN", workspace.ToolchainPath().string());
@@ -623,37 +760,56 @@ TEST(KernelCompilationPlanBuilderTest, RejectsMalformedManifestCommands)
623 Json unsupportedCommandManifest = CreateManifest();760 Json unsupportedCommandManifest = CreateManifest();
624 unsupportedCommandManifest["kernels"][1]["objects"][0]["commands"][0]["type"] = "future-command";761 unsupportedCommandManifest["kernels"][1]["objects"][0]["commands"][0]["type"] = "future-command";
625 EXPECT_EQ(762 EXPECT_EQ(
626- KernelCompilationPlanBuilder(763+ BuildPlanFromManifest(
627- request, unsupportedCommandManifest, workspace.ResourcePath(), workspace.SourceDirectoryPath())764+ request, unsupportedCommandManifest, workspace.ResourcePath(), workspace.SourceDirectoryPath(), plan),
628- .BuildCompilationPlan(plan),
629 ascendc::aclrtc::ACLRTC_ERROR_FAILURE);765 ascendc::aclrtc::ACLRTC_ERROR_FAILURE);
630 766 
631 Json emptyCommandManifest = CreateManifest();767 Json emptyCommandManifest = CreateManifest();
632 emptyCommandManifest["kernels"][1]["objects"][0]["commands"][0]["cmd"] = Json::array();768 emptyCommandManifest["kernels"][1]["objects"][0]["commands"][0]["cmd"] = Json::array();
633 EXPECT_EQ(769 EXPECT_EQ(
634- KernelCompilationPlanBuilder(770+ BuildPlanFromManifest(
635- request, emptyCommandManifest, workspace.ResourcePath(), workspace.SourceDirectoryPath())771+ request, emptyCommandManifest, workspace.ResourcePath(), workspace.SourceDirectoryPath(), plan),
636- .BuildCompilationPlan(plan),
637 ascendc::aclrtc::ACLRTC_ERROR_FAILURE);772 ascendc::aclrtc::ACLRTC_ERROR_FAILURE);
638 773 
639 Json expandedExecutableManifest = CreateManifest();774 Json expandedExecutableManifest = CreateManifest();
640- expandedExecutableManifest["kernels"][1]["objects"][0]["commands"][0]["cmd"][0] = "${options:common_compile}";775+ expandedExecutableManifest["options"]["common_compile"] = Json::array();
776+ expandedExecutableManifest["kernels"][1]["objects"][0]["commands"][0]["cmd"] =
777+ Json::array({"${options:common_compile}"});
641 EXPECT_EQ(778 EXPECT_EQ(
642- KernelCompilationPlanBuilder(779+ BuildPlanFromManifest(
643- request, expandedExecutableManifest, workspace.ResourcePath(), workspace.SourceDirectoryPath())780+ request, expandedExecutableManifest, workspace.ResourcePath(), workspace.SourceDirectoryPath(), plan),
644- .BuildCompilationPlan(plan),
645 ascendc::aclrtc::ACLRTC_ERROR_FAILURE);781 ascendc::aclrtc::ACLRTC_ERROR_FAILURE);
646 782 
783+ KernelCompilationPlan expectedPlan;
784+ ASSERT_EQ(
785+ BuildPlanFromManifest(
786+ request, CreateManifest(), workspace.ResourcePath(), workspace.SourceDirectoryPath(), expectedPlan),
787+ ascendc::aclrtc::ACLRTC_SUCCESS);
788+ Json commandPrefixManifest = CreateManifest();
789+ auto& arguments = commandPrefixManifest["kernels"][1]["objects"][0]["commands"][0]["cmd"];
790+ Json commandPrefix = Json::array({arguments[0]});
791+ for (const auto& argument : commandPrefixManifest["options"]["common_compile"]) {
792+ commandPrefix.push_back(argument);
793+ }
794+ commandPrefixManifest["options"]["command_prefix"] = std::move(commandPrefix);
795+ arguments.erase(0);
796+ arguments[0] = "${options:command_prefix}";
797+ ASSERT_EQ(
798+ BuildPlanFromManifest(
799+ request, commandPrefixManifest, workspace.ResourcePath(), workspace.SourceDirectoryPath(), plan),
800+ ascendc::aclrtc::ACLRTC_SUCCESS);
801+ EXPECT_EQ(plan.compilationCommands[0].executablePath, expectedPlan.compilationCommands[0].executablePath);
802+ EXPECT_EQ(plan.compilationCommands[0].arguments, expectedPlan.compilationCommands[0].arguments);
803+ 
647 Json relativeExecutableManifest = CreateManifest();804 Json relativeExecutableManifest = CreateManifest();
648 relativeExecutableManifest["kernels"][1]["objects"][0]["commands"][0]["cmd"][0] = "bisheng";805 relativeExecutableManifest["kernels"][1]["objects"][0]["commands"][0]["cmd"][0] = "bisheng";
649 EXPECT_EQ(806 EXPECT_EQ(
650- KernelCompilationPlanBuilder(807+ BuildPlanFromManifest(
651- request, relativeExecutableManifest, workspace.ResourcePath(), workspace.SourceDirectoryPath())808+ request, relativeExecutableManifest, workspace.ResourcePath(), workspace.SourceDirectoryPath(), plan),
652- .BuildCompilationPlan(plan),
653 ascendc::aclrtc::ACLRTC_ERROR_FAILURE);809 ascendc::aclrtc::ACLRTC_ERROR_FAILURE);
654}810}
655 811 
656-TEST(KernelCompilationPlanBuilderTest, RequiresBasicAndRequestedSuperKernelObjects)812+TEST(KernelCompilationPlanBuilderTest, RequiresBasicAndFallsBackWhenSuperKernelIsAbsent)
657{813{
658 KernelPlanTestWorkspace workspace;814 KernelPlanTestWorkspace workspace;
659 ScopedEnvironmentVariable toolchainEnvironment("ACLRTC_TEST_TOOLCHAIN", workspace.ToolchainPath().string());815 ScopedEnvironmentVariable toolchainEnvironment("ACLRTC_TEST_TOOLCHAIN", workspace.ToolchainPath().string());
@@ -668,19 +824,29 @@ TEST(KernelCompilationPlanBuilderTest, RequiresBasicAndRequestedSuperKernelObjec
668 Json manifestWithoutBasic = CreateManifest();824 Json manifestWithoutBasic = CreateManifest();
669 manifestWithoutBasic["kernels"][1]["objects"].erase(0);825 manifestWithoutBasic["kernels"][1]["objects"].erase(0);
670 EXPECT_EQ(826 EXPECT_EQ(
671- KernelCompilationPlanBuilder(827+ BuildPlanFromManifest(
672- request, manifestWithoutBasic, workspace.ResourcePath(), workspace.SourceDirectoryPath())828+ request, manifestWithoutBasic, workspace.ResourcePath(), workspace.SourceDirectoryPath(), plan),
673- .BuildCompilationPlan(plan),
674 ascendc::aclrtc::ACLRTC_ERROR_FAILURE);829 ascendc::aclrtc::ACLRTC_ERROR_FAILURE);
675 830 
676- request.compilationVariant = KernelCompilationVariant::BasicWithSuperKernel;831+ request.enableSuperKernel = true;
832+ request.compilerOptions.superKernelOptions = {"--sk-only-test-option"};
677 Json manifestWithoutSuperKernel = CreateManifest();833 Json manifestWithoutSuperKernel = CreateManifest();
678 manifestWithoutSuperKernel["kernels"][1]["objects"].erase(1);834 manifestWithoutSuperKernel["kernels"][1]["objects"].erase(1);
679- EXPECT_EQ(835+ ASSERT_EQ(
680- KernelCompilationPlanBuilder(836+ BuildPlanFromManifest(
681- request, manifestWithoutSuperKernel, workspace.ResourcePath(), workspace.SourceDirectoryPath())837+ request, manifestWithoutSuperKernel, workspace.ResourcePath(), workspace.SourceDirectoryPath(), plan),
682- .BuildCompilationPlan(plan),838+ ascendc::aclrtc::ACLRTC_SUCCESS);
683- ascendc::aclrtc::ACLRTC_ERROR_FAILURE);839+ request.enableSuperKernel = false;
840+ KernelCompilationPlan basicPlan;
841+ ASSERT_EQ(
842+ BuildPlanFromManifest(
843+ request, manifestWithoutSuperKernel, workspace.ResourcePath(), workspace.SourceDirectoryPath(), basicPlan),
844+ ascendc::aclrtc::ACLRTC_SUCCESS);
845+ ASSERT_EQ(plan.compilationCommands.size(), basicPlan.compilationCommands.size());
846+ for (size_t index = 0; index < plan.compilationCommands.size(); ++index) {
847+ EXPECT_EQ(plan.compilationCommands[index].executablePath, basicPlan.compilationCommands[index].executablePath);
848+ EXPECT_EQ(plan.compilationCommands[index].arguments, basicPlan.compilationCommands[index].arguments);
849+ }
684}850}
685 851 
686TEST(KernelCompilationPlanBuilderTest, RejectsUnresolvableLinkInputs)852TEST(KernelCompilationPlanBuilderTest, RejectsUnresolvableLinkInputs)
@@ -699,25 +865,22 @@ TEST(KernelCompilationPlanBuilderTest, RejectsUnresolvableLinkInputs)
699 Json unresolvedLinkOptionManifest = CreateManifest();865 Json unresolvedLinkOptionManifest = CreateManifest();
700 unresolvedLinkOptionManifest["kernels"][1]["link_options"] = Json::array({"${env:ACLRTC_TEST_MISSING_LINK_INPUT}"});866 unresolvedLinkOptionManifest["kernels"][1]["link_options"] = Json::array({"${env:ACLRTC_TEST_MISSING_LINK_INPUT}"});
701 EXPECT_EQ(867 EXPECT_EQ(
702- KernelCompilationPlanBuilder(868+ BuildPlanFromManifest(
703- request, unresolvedLinkOptionManifest, workspace.ResourcePath(), workspace.SourceDirectoryPath())869+ request, unresolvedLinkOptionManifest, workspace.ResourcePath(), workspace.SourceDirectoryPath(), plan),
704- .BuildCompilationPlan(plan),
705 ascendc::aclrtc::ACLRTC_ERROR_FAILURE);870 ascendc::aclrtc::ACLRTC_ERROR_FAILURE);
706 871 
707 Json unresolvedObjectOutputManifest = CreateManifest();872 Json unresolvedObjectOutputManifest = CreateManifest();
708 unresolvedObjectOutputManifest["kernels"][1]["objects"][0]["outputs"][0] = "${env:ACLRTC_TEST_MISSING_LINK_INPUT}";873 unresolvedObjectOutputManifest["kernels"][1]["objects"][0]["outputs"][0] = "${env:ACLRTC_TEST_MISSING_LINK_INPUT}";
709 EXPECT_EQ(874 EXPECT_EQ(
710- KernelCompilationPlanBuilder(875+ BuildPlanFromManifest(
711- request, unresolvedObjectOutputManifest, workspace.ResourcePath(), workspace.SourceDirectoryPath())876+ request, unresolvedObjectOutputManifest, workspace.ResourcePath(), workspace.SourceDirectoryPath(), plan),
712- .BuildCompilationPlan(plan),
713 ascendc::aclrtc::ACLRTC_ERROR_FAILURE);877 ascendc::aclrtc::ACLRTC_ERROR_FAILURE);
714 878 
715 ScopedEnvironmentVariable missingLinkerEnvironment(879 ScopedEnvironmentVariable missingLinkerEnvironment(
716 "ASCEND_HOME_PATH", (workspace.ResourcePath() / "missing-toolchain").string());880 "ASCEND_HOME_PATH", (workspace.ResourcePath() / "missing-toolchain").string());
717 EXPECT_EQ(881 EXPECT_EQ(
718- KernelCompilationPlanBuilder(882+ BuildPlanFromManifest(
719- request, CreateManifest(), workspace.ResourcePath(), workspace.SourceDirectoryPath())883+ request, CreateManifest(), workspace.ResourcePath(), workspace.SourceDirectoryPath(), plan),
720- .BuildCompilationPlan(plan),
721 ascendc::aclrtc::ACLRTC_ERROR_FAILURE);884 ascendc::aclrtc::ACLRTC_ERROR_FAILURE);
722}885}
723 886 
@@ -733,32 +896,28 @@ TEST(KernelCompilationPlanBuilderTest, RejectsInvalidManifestSelectionInputs)
733 KernelCompilationPlan plan;896 KernelCompilationPlan plan;
734 897 
735 EXPECT_EQ(898 EXPECT_EQ(
736- KernelCompilationPlanBuilder(request, CreateManifest(), "relative-worktree", workspace.SourceDirectoryPath())899+ BuildPlanFromManifest(request, CreateManifest(), "relative-worktree", workspace.SourceDirectoryPath(), plan),
737- .BuildCompilationPlan(plan),
738 ascendc::aclrtc::ACLRTC_ERROR_FAILURE);900 ascendc::aclrtc::ACLRTC_ERROR_FAILURE);
739 901 
740 Json unsupportedSchemaManifest = CreateManifest();902 Json unsupportedSchemaManifest = CreateManifest();
741 unsupportedSchemaManifest["schema_version"] = "2.0";903 unsupportedSchemaManifest["schema_version"] = "2.0";
742 EXPECT_EQ(904 EXPECT_EQ(
743- KernelCompilationPlanBuilder(905+ BuildPlanFromManifest(
744- request, unsupportedSchemaManifest, workspace.ResourcePath(), workspace.SourceDirectoryPath())906+ request, unsupportedSchemaManifest, workspace.ResourcePath(), workspace.SourceDirectoryPath(), plan),
745- .BuildCompilationPlan(plan),
746 ascendc::aclrtc::ACLRTC_ERROR_FAILURE);907 ascendc::aclrtc::ACLRTC_ERROR_FAILURE);
747 908 
748 request.kernelName = "missing_kernel";909 request.kernelName = "missing_kernel";
749 EXPECT_EQ(910 EXPECT_EQ(
750- KernelCompilationPlanBuilder(911+ BuildPlanFromManifest(
751- request, CreateManifest(), workspace.ResourcePath(), workspace.SourceDirectoryPath())912+ request, CreateManifest(), workspace.ResourcePath(), workspace.SourceDirectoryPath(), plan),
752- .BuildCompilationPlan(plan),
753 ascendc::aclrtc::ACLRTC_ERROR_FAILURE);913 ascendc::aclrtc::ACLRTC_ERROR_FAILURE);
754 914 
755 request.kernelName = "add_custom_100000";915 request.kernelName = "add_custom_100000";
756 Json malformedSchemaManifest = CreateManifest();916 Json malformedSchemaManifest = CreateManifest();
757 malformedSchemaManifest["schema_version"] = Json::array();917 malformedSchemaManifest["schema_version"] = Json::array();
758 EXPECT_EQ(918 EXPECT_EQ(
759- KernelCompilationPlanBuilder(919+ BuildPlanFromManifest(
760- request, malformedSchemaManifest, workspace.ResourcePath(), workspace.SourceDirectoryPath())920+ request, malformedSchemaManifest, workspace.ResourcePath(), workspace.SourceDirectoryPath(), plan),
761- .BuildCompilationPlan(plan),
762 ascendc::aclrtc::ACLRTC_ERROR_FAILURE);921 ascendc::aclrtc::ACLRTC_ERROR_FAILURE);
763}922}
764 923 
@@ -779,22 +938,19 @@ TEST(KernelCompilationPlanBuilderTest, RejectsMissingEnvironmentVariablesAtEachE
779 manifest["options"]["common_compile"] = Json::array({"${env:ACLRTC_TEST_MISSING_ENV}/include"});938 manifest["options"]["common_compile"] = Json::array({"${env:ACLRTC_TEST_MISSING_ENV}/include"});
780 KernelCompilationPlan plan;939 KernelCompilationPlan plan;
781 EXPECT_NE(940 EXPECT_NE(
782- KernelCompilationPlanBuilder(request, manifest, workspace.ResourcePath(), workspace.SourceDirectoryPath())941+ BuildPlanFromManifest(request, manifest, workspace.ResourcePath(), workspace.SourceDirectoryPath(), plan),
783- .BuildCompilationPlan(plan),
784 ascendc::aclrtc::ACLRTC_SUCCESS);942 ascendc::aclrtc::ACLRTC_SUCCESS);
785 943 
786 manifest = CreateManifest();944 manifest = CreateManifest();
787 manifest["kernels"][1]["constant_infos"][0]["file"] = "${env:ACLRTC_TEST_MISSING_ENV}/constants.h";945 manifest["kernels"][1]["constant_infos"][0]["file"] = "${env:ACLRTC_TEST_MISSING_ENV}/constants.h";
788 EXPECT_NE(946 EXPECT_NE(
789- KernelCompilationPlanBuilder(request, manifest, workspace.ResourcePath(), workspace.SourceDirectoryPath())947+ BuildPlanFromManifest(request, manifest, workspace.ResourcePath(), workspace.SourceDirectoryPath(), plan),
790- .BuildCompilationPlan(plan),
791 ascendc::aclrtc::ACLRTC_SUCCESS);948 ascendc::aclrtc::ACLRTC_SUCCESS);
792 949 
793 ASSERT_EQ(unsetenv("ASCEND_HOME_PATH"), 0);950 ASSERT_EQ(unsetenv("ASCEND_HOME_PATH"), 0);
794 manifest = CreateManifest();951 manifest = CreateManifest();
795 EXPECT_NE(952 EXPECT_NE(
796- KernelCompilationPlanBuilder(request, manifest, workspace.ResourcePath(), workspace.SourceDirectoryPath())953+ BuildPlanFromManifest(request, manifest, workspace.ResourcePath(), workspace.SourceDirectoryPath(), plan),
797- .BuildCompilationPlan(plan),
798 ascendc::aclrtc::ACLRTC_SUCCESS);954 ascendc::aclrtc::ACLRTC_SUCCESS);
799}955}
800 956 
@@ -813,8 +969,7 @@ TEST(KernelCompilationPlanBuilderTest, ReportsResourceWorktreeInspectionErrors)
813 969 
814 KernelCompilationPlan plan;970 KernelCompilationPlan plan;
815 EXPECT_NE(971 EXPECT_NE(
816- KernelCompilationPlanBuilder(request, CreateManifest(), selfReferentialLink, workspace.SourceDirectoryPath())972+ BuildPlanFromManifest(request, CreateManifest(), selfReferentialLink, workspace.SourceDirectoryPath(), plan),
817- .BuildCompilationPlan(plan),
818 ascendc::aclrtc::ACLRTC_SUCCESS);973 ascendc::aclrtc::ACLRTC_SUCCESS);
819}974}
820} // namespace975} // namespace
@@ -70,7 +70,7 @@ TEST(KernelSpecializationRequestTest, NormalizesBasicRequestAndCopiesOptions)
70 EXPECT_EQ(normalizedRequest.resourceId, RESOURCE_ID);70 EXPECT_EQ(normalizedRequest.resourceId, RESOURCE_ID);
71 EXPECT_EQ(normalizedRequest.kernelName, "add_custom_100000");71 EXPECT_EQ(normalizedRequest.kernelName, "add_custom_100000");
72 EXPECT_EQ(normalizedRequest.outputElfPath, "/tmp/kernel.elf");72 EXPECT_EQ(normalizedRequest.outputElfPath, "/tmp/kernel.elf");
73- EXPECT_EQ(normalizedRequest.compilationVariant, ascendc::aclrtc::KernelCompilationVariant::Basic);73+ EXPECT_EQ(normalizedRequest.enableSuperKernel, false);
74 EXPECT_EQ(normalizedRequest.compilerOptions.basicOptions, (std::vector<std::string>{"-g", "-DVALUE=1"}));74 EXPECT_EQ(normalizedRequest.compilerOptions.basicOptions, (std::vector<std::string>{"-g", "-DVALUE=1"}));
75 EXPECT_TRUE(normalizedRequest.compilerOptions.superKernelOptions.empty());75 EXPECT_TRUE(normalizedRequest.compilerOptions.superKernelOptions.empty());
76}76}
@@ -96,7 +96,7 @@ TEST(KernelSpecializationRequestTest, EnablesSuperKernelAndRemovesControlOption)
96 96 
97 ascendc::aclrtc::NormalizedKernelSpecializationRequest normalizedRequest;97 ascendc::aclrtc::NormalizedKernelSpecializationRequest normalizedRequest;
98 EXPECT_EQ(ascendc::aclrtc::NormalizeKernelSpecializationRequest(request, "/tmp/kernel.elf", normalizedRequest), 0);98 EXPECT_EQ(ascendc::aclrtc::NormalizeKernelSpecializationRequest(request, "/tmp/kernel.elf", normalizedRequest), 0);
99- EXPECT_EQ(normalizedRequest.compilationVariant, ascendc::aclrtc::KernelCompilationVariant::BasicWithSuperKernel);99+ EXPECT_EQ(normalizedRequest.enableSuperKernel, true);
100 EXPECT_EQ(normalizedRequest.compilerOptions.superKernelOptions, (std::vector<std::string>{"-g", "-DDCCI_OFF"}));100 EXPECT_EQ(normalizedRequest.compilerOptions.superKernelOptions, (std::vector<std::string>{"-g", "-DDCCI_OFF"}));
101}101}
102 102 
@@ -109,7 +109,7 @@ TEST(KernelSpecializationRequestTest, IgnoresSuperKernelOptionsWithoutEnable)
109 109 
110 ascendc::aclrtc::NormalizedKernelSpecializationRequest normalizedRequest;110 ascendc::aclrtc::NormalizedKernelSpecializationRequest normalizedRequest;
111 EXPECT_EQ(ascendc::aclrtc::NormalizeKernelSpecializationRequest(request, "/tmp/kernel.elf", normalizedRequest), 0);111 EXPECT_EQ(ascendc::aclrtc::NormalizeKernelSpecializationRequest(request, "/tmp/kernel.elf", normalizedRequest), 0);
112- EXPECT_EQ(normalizedRequest.compilationVariant, ascendc::aclrtc::KernelCompilationVariant::Basic);112+ EXPECT_EQ(normalizedRequest.enableSuperKernel, false);
113 EXPECT_TRUE(normalizedRequest.compilerOptions.superKernelOptions.empty());113 EXPECT_TRUE(normalizedRequest.compilerOptions.superKernelOptions.empty());
114}114}
115 115 
@@ -161,7 +161,9 @@ private:
161 {"kernels", Json::array(161 {"kernels", Json::array(
162 {{{"kernel_name", "add_custom_100000"},162 {{{"kernel_name", "add_custom_100000"},
163 {"constant_infos", Json::array(163 {"constant_infos", Json::array(
164- {{{"parameter_index", 0},164+ {{{"name", "tiling"},
165+ {"parameter_index", 0},
166+ {"arg_type", "pointer"},
165 {"byte_size", 2},167 {"byte_size", 2},
166 {"file", "${resource}/resources/include/constants.h"},168 {"file", "${resource}/resources/include/constants.h"},
167 {"template", "@@STATIC_TILING@@"}}})},169 {"template", "@@STATIC_TILING@@"}}})},
@@ -207,6 +207,7 @@ add_executable(ascendc_ut_asc_compile_exporter
207 asc_compile_exporter/test_file_utils.cpp207 asc_compile_exporter/test_file_utils.cpp
208 asc_compile_exporter/test_manifest_bundle_types.cpp208 asc_compile_exporter/test_manifest_bundle_types.cpp
209 common/test_process_executor.cpp209 common/test_process_executor.cpp
210+ common/test_manifest_constant.cpp
210 asc_compile_exporter/test_resource_manifest_validator.cpp211 asc_compile_exporter/test_resource_manifest_validator.cpp
211 common/test_directory_cleanup_guard.cpp212 common/test_directory_cleanup_guard.cpp
212 asc_compile_exporter/test_ascendc_tool_log.cpp213 asc_compile_exporter/test_ascendc_tool_log.cpp
@@ -214,6 +215,7 @@ add_executable(ascendc_ut_asc_compile_exporter
214 ${ASCENDC_DIR}/tools/build/asc_compile_exporter/collected_manifest_repository.cpp215 ${ASCENDC_DIR}/tools/build/asc_compile_exporter/collected_manifest_repository.cpp
215 ${ASCENDC_DIR}/tools/build/asc_compile_exporter/manifest_bundle_compiler.cpp216 ${ASCENDC_DIR}/tools/build/asc_compile_exporter/manifest_bundle_compiler.cpp
216 ${ASCENDC_DIR}/tools/build/asc_compile_exporter/resource_manifest_validator.cpp217 ${ASCENDC_DIR}/tools/build/asc_compile_exporter/resource_manifest_validator.cpp
218+ ${ASCENDC_DIR}/tools/build/common/manifest_constant.cpp
217 ${ASCENDC_DIR}/tools/build/common/file_utils.cpp219 ${ASCENDC_DIR}/tools/build/common/file_utils.cpp
218 ${ASCENDC_DIR}/tools/build/common/process_executor.cpp220 ${ASCENDC_DIR}/tools/build/common/process_executor.cpp
219 ${ASCENDC_DIR}/tools/build/common/directory_cleanup_guard.cpp221 ${ASCENDC_DIR}/tools/build/common/directory_cleanup_guard.cpp
@@ -33,6 +33,7 @@ Json MakeValidManifest()
33{33{
34 Json constant = {34 Json constant = {
35 {"name", "weight"},35 {"name", "weight"},
36+ {"arg_type", "pointer"},
36 {"parameter_index", Json::number_unsigned_t(0U)},37 {"parameter_index", Json::number_unsigned_t(0U)},
37 {"byte_size", Json::number_unsigned_t(4U)},38 {"byte_size", Json::number_unsigned_t(4U)},
38 {"file", "${resource}/resources/weight.bin"},39 {"file", "${resource}/resources/weight.bin"},
@@ -133,6 +134,20 @@ TEST_F(ResourceManifestValidatorTest, AcceptsCompleteAndMinimalValidManifests)
133 Command(namedOptions)["cmd"][0U] = "${options:custom_compile}";134 Command(namedOptions)["cmd"][0U] = "${options:custom_compile}";
134 Command(namedOptions)["cmd"].insert(Command(namedOptions)["cmd"].begin() + 1U, "${options:custom_compile}");135 Command(namedOptions)["cmd"].insert(Command(namedOptions)["cmd"].begin() + 1U, "${options:custom_compile}");
135 EXPECT_TRUE(Validate(namedOptions));136 EXPECT_TRUE(Validate(namedOptions));
137+ 
138+ Json pointerConstant = MakeValidManifest();
139+ Constant(pointerConstant)["arg_type"] = "pointer";
140+ EXPECT_TRUE(Validate(pointerConstant));
141+ 
142+ Json explicitStructConstant = MakeValidManifest();
143+ Constant(explicitStructConstant)["arg_type"] = "struct";
144+ Constant(explicitStructConstant).erase("byte_size");
145+ EXPECT_TRUE(Validate(explicitStructConstant));
146+ 
147+ Json defaultStructConstant = MakeValidManifest();
148+ Constant(defaultStructConstant).erase("arg_type");
149+ Constant(defaultStructConstant).erase("byte_size");
150+ EXPECT_TRUE(Validate(defaultStructConstant));
136}151}
137 152 
138TEST_F(ResourceManifestValidatorTest, RejectsInvalidTopLevelFields)153TEST_F(ResourceManifestValidatorTest, RejectsInvalidTopLevelFields)
@@ -224,21 +239,7 @@ TEST_F(ResourceManifestValidatorTest, ValidatesMarkersAndReferencedPaths)
224TEST_F(ResourceManifestValidatorTest, ValidatesConstants)239TEST_F(ResourceManifestValidatorTest, ValidatesConstants)
225{240{
226 ExpectInvalid(241 ExpectInvalid(
227- "constant is not an object", [](Json& manifest) { Kernel(manifest)["constant_infos"][0U] = "weight"; });242+ "struct must not contain byte_size", [](Json& manifest) { Constant(manifest)["arg_type"] = "struct"; });
228- ExpectInvalid("constant has extra field", [](Json& manifest) { Constant(manifest)["extra"] = true; });
229- ExpectInvalid("constant name is missing", [](Json& manifest) {
230- Constant(manifest).erase("name");
231- Constant(manifest)["extra"] = true;
232- });
233- ExpectInvalid("constant name has wrong type", [](Json& manifest) { Constant(manifest)["name"] = 1U; });
234- ExpectInvalid("constant name is empty", [](Json& manifest) { Constant(manifest)["name"] = ""; });
235- ExpectInvalid("parameter_index has wrong type", [](Json& manifest) { Constant(manifest)["parameter_index"] = -1; });
236- ExpectInvalid("byte_size has wrong type", [](Json& manifest) { Constant(manifest)["byte_size"] = "4"; });
237- ExpectInvalid(
238- "byte_size is zero", [](Json& manifest) { Constant(manifest)["byte_size"] = Json::number_unsigned_t(0U); });
239- ExpectInvalid("constant file has wrong type", [](Json& manifest) { Constant(manifest)["file"] = 1U; });
240- ExpectInvalid("constant template has wrong type", [](Json& manifest) { Constant(manifest)["template"] = 1U; });
241- ExpectInvalid("constant template is empty", [](Json& manifest) { Constant(manifest)["template"] = ""; });
242 ExpectInvalid(243 ExpectInvalid(
243 "constant file lacks resource prefix", [](Json& manifest) { Constant(manifest)["file"] = "resources/x"; });244 "constant file lacks resource prefix", [](Json& manifest) { Constant(manifest)["file"] = "resources/x"; });
244 ExpectInvalid("constant file is outside resource_path", [](Json& manifest) {245 ExpectInvalid("constant file is outside resource_path", [](Json& manifest) {
@@ -0,0 +1,163 @@
1+/**
2+ * Copyright (c) 2026 Huawei Technologies Co., Ltd.
3+ * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
4+ * CANN Open Software License Agreement Version 2.0 (the "License").
5+ * Please refer to the License for details. You may not use this file except in compliance with the License.
6+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7+ * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
8+ * See LICENSE in the root of the software repository for the full text of the License.
9+ */
10+ 
11+#include "manifest_constant.h"
12+ 
13+#include <gtest/gtest.h>
14+#include <nlohmann/json.hpp>
15+#include <limits>
16+#include <vector>
17+ 
18+namespace {
19+using Json = nlohmann::json;
20+using ascendc::ManifestConstant;
21+ 
22+Json MakeConstant()
23+{
24+ return {{"name", "tiling"}, {"parameter_index", 2}, {"file", "${resource}/tiling.h"}, {"template", "@@TILING@@"}};
25+}
26+ 
27+TEST(ManifestConstantTest, ResolvesDefaultAndExplicitStructSizes)
28+{
29+ for (bool explicitType : {false, true}) {
30+ Json input = MakeConstant();
31+ if (explicitType) {
32+ input["arg_type"] = "struct";
33+ }
34+ ManifestConstant constant;
35+ ASSERT_TRUE(constant.ParseDefinition(input));
36+ input.clear();
37+ EXPECT_EQ(constant.GetName(), "tiling");
38+ EXPECT_EQ(constant.GetParameterIndex(), 2U);
39+ EXPECT_EQ(constant.GetTargetFile(), "${resource}/tiling.h");
40+ EXPECT_EQ(constant.GetTemplateText(), "@@TILING@@");
41+ uint8_t byte = 0;
42+ const void* addresses[] = {nullptr, nullptr, &byte};
43+ const uint64_t sizes[] = {0U, 0U, 17U};
44+ ASSERT_TRUE(constant.BindArgument(3U, addresses, sizes));
45+ EXPECT_EQ(constant.GetBoundData(), &byte);
46+ EXPECT_EQ(constant.GetBoundByteSize(), 17U);
47+ }
48+}
49+ 
50+TEST(ManifestConstantTest, PreservesSignedAndUnsignedPointerSizeBoundaries)
51+{
52+ for (const Json& size : std::vector<Json>{1, int64_t{4}, std::numeric_limits<uint64_t>::max()}) {
53+ Json input = MakeConstant();
54+ input["arg_type"] = "pointer";
55+ input["byte_size"] = size;
56+ input["parameter_index"] = std::numeric_limits<uint64_t>::max();
57+ ManifestConstant constant;
58+ ASSERT_TRUE(constant.ParseDefinition(input));
59+ EXPECT_EQ(constant.GetParameterIndex(), std::numeric_limits<uint64_t>::max());
60+ input["parameter_index"] = 0;
61+ ASSERT_TRUE(constant.ParseDefinition(input));
62+ uint8_t byte = 0;
63+ const void* addresses[] = {&byte};
64+ ASSERT_TRUE(constant.BindArgument(1U, addresses, nullptr));
65+ EXPECT_EQ(constant.GetBoundByteSize(), size.get<uint64_t>());
66+ }
67+}
68+ 
69+TEST(ManifestConstantTest, RejectsInvalidFieldsWithoutChangingParsedConstant)
70+{
71+ std::vector<Json> inputs{nullptr, Json::array(), 1};
72+ for (const char* field : {"name", "parameter_index", "file", "template"}) {
73+ Json input = MakeConstant();
74+ input.erase(field);
75+ inputs.push_back(input);
76+ }
77+ for (const Json& fields : std::vector<Json>{
78+ {{"name", ""}},
79+ {{"name", 1}},
80+ {{"file", ""}},
81+ {{"file", nullptr}},
82+ {{"template", ""}},
83+ {{"template", true}},
84+ {{"parameter_index", -1}},
85+ {{"parameter_index", 1.5}},
86+ {{"parameter_index", "2"}},
87+ {{"parameter_index", true}},
88+ {{"arg_type", nullptr}},
89+ {{"arg_type", "other"}},
90+ {{"extra", 1}},
91+ {{"byte_size", 4}},
92+ {{"arg_type", "struct"}, {"byte_size", 4}},
93+ {{"arg_type", "pointer"}},
94+ {{"arg_type", "pointer"}, {"byte_size", 0}},
95+ {{"arg_type", "pointer"}, {"byte_size", -1}},
96+ {{"arg_type", "pointer"}, {"byte_size", 1.5}},
97+ {{"arg_type", "pointer"}, {"byte_size", "4"}},
98+ {{"arg_type", "pointer"}, {"byte_size", true}}}) {
99+ Json input = MakeConstant();
100+ input.update(fields);
101+ inputs.push_back(input);
102+ }
103+ ManifestConstant constant;
104+ Json valid = MakeConstant();
105+ valid.update({{"arg_type", "pointer"}, {"byte_size", 7}});
106+ ASSERT_TRUE(constant.ParseDefinition(valid));
107+ uint8_t byte = 0;
108+ const void* addresses[] = {nullptr, nullptr, &byte};
109+ ASSERT_TRUE(constant.BindArgument(3U, addresses, nullptr));
110+ for (const Json& input : inputs) {
111+ SCOPED_TRACE(input.dump());
112+ EXPECT_FALSE(constant.ParseDefinition(input));
113+ EXPECT_EQ(constant.GetName(), "tiling");
114+ EXPECT_EQ(constant.GetParameterIndex(), 2U);
115+ EXPECT_EQ(constant.GetTargetFile(), "${resource}/tiling.h");
116+ EXPECT_EQ(constant.GetTemplateText(), "@@TILING@@");
117+ EXPECT_EQ(constant.GetBoundData(), &byte);
118+ EXPECT_EQ(constant.GetBoundByteSize(), 7U);
119+ }
120+}
121+TEST(ManifestConstantTest, RejectsBindingBeforeParsingAndResetsBindingAfterSuccessfulParse)
122+{
123+ ManifestConstant constant;
124+ uint8_t first = 1;
125+ uint8_t second = 2;
126+ const void* addresses[] = {nullptr, nullptr, &first};
127+ uint64_t sizes[] = {0U, 0U, 1U};
128+ EXPECT_FALSE(constant.BindArgument(3U, addresses, sizes));
129+ EXPECT_EQ(constant.GetBoundData(), nullptr);
130+ EXPECT_EQ(constant.GetBoundByteSize(), 0U);
131+ EXPECT_FALSE(constant.ParseDefinition(Json::object()));
132+ ASSERT_TRUE(constant.ParseDefinition(MakeConstant()));
133+ ASSERT_TRUE(constant.BindArgument(3U, addresses, sizes));
134+ addresses[2] = &second;
135+ sizes[2] = 2U;
136+ ASSERT_TRUE(constant.BindArgument(3U, addresses, sizes));
137+ EXPECT_EQ(constant.GetBoundData(), &second);
138+ EXPECT_EQ(constant.GetBoundByteSize(), 2U);
139+ ASSERT_TRUE(constant.ParseDefinition(MakeConstant()));
140+ EXPECT_EQ(constant.GetBoundData(), nullptr);
141+ EXPECT_EQ(constant.GetBoundByteSize(), 0U);
142+ ASSERT_TRUE(constant.BindArgument(3U, addresses, sizes));
143+}
144+ 
145+TEST(ManifestConstantTest, RejectsInvalidArgumentsWithoutChangingBinding)
146+{
147+ ManifestConstant constant;
148+ ASSERT_TRUE(constant.ParseDefinition(MakeConstant()));
149+ uint8_t byte = 0;
150+ const void* addresses[] = {nullptr, nullptr, &byte};
151+ const void* nullAddresses[] = {nullptr, nullptr, nullptr};
152+ const uint64_t sizes[] = {0U, 0U, 1U};
153+ const uint64_t zeroSizes[] = {0U, 0U, 0U};
154+ ASSERT_TRUE(constant.BindArgument(3U, addresses, sizes));
155+ EXPECT_FALSE(constant.BindArgument(3U, nullptr, sizes));
156+ EXPECT_FALSE(constant.BindArgument(2U, addresses, sizes));
157+ EXPECT_FALSE(constant.BindArgument(3U, nullAddresses, sizes));
158+ EXPECT_FALSE(constant.BindArgument(3U, addresses, nullptr));
159+ EXPECT_FALSE(constant.BindArgument(3U, addresses, zeroSizes));
160+ EXPECT_EQ(constant.GetBoundData(), &byte);
161+ EXPECT_EQ(constant.GetBoundByteSize(), 1U);
162+}
163+} // namespace
@@ -14,6 +14,7 @@ add_library(acl_rtc SHARED
14 ${SRC}14 ${SRC}
15 ${SPECIALIZATION_SRC}15 ${SPECIALIZATION_SRC}
16 ${CMAKE_CURRENT_SOURCE_DIR}/../build/common/file_utils.cpp16 ${CMAKE_CURRENT_SOURCE_DIR}/../build/common/file_utils.cpp
17+ ${CMAKE_CURRENT_SOURCE_DIR}/../build/common/manifest_constant.cpp
17 ${CMAKE_CURRENT_SOURCE_DIR}/../build/common/process_executor.cpp18 ${CMAKE_CURRENT_SOURCE_DIR}/../build/common/process_executor.cpp
18 ${CMAKE_CURRENT_SOURCE_DIR}/../build/common/directory_cleanup_guard.cpp19 ${CMAKE_CURRENT_SOURCE_DIR}/../build/common/directory_cleanup_guard.cpp
19)20)
@@ -0,0 +1,42 @@
1+/**
2+ * Copyright (c) 2026 Huawei Technologies Co., Ltd.
3+ * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
4+ * CANN Open Software License Agreement Version 2.0 (the "License").
5+ * Please refer to the License for details. You may not use this file except in compliance with the License.
6+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7+ * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
8+ * See LICENSE in the root of the software repository for the full text of the License.
9+ */
10+ 
11+#ifndef ASCENDC_ACLRTC_COMPILATION_MANIFEST_H
12+#define ASCENDC_ACLRTC_COMPILATION_MANIFEST_H
13+ 
14+#include "kernel_specialization_types.h"
15+#include "manifest_constant.h"
16+ 
17+namespace ascendc {
18+namespace aclrtc {
19+ 
20+enum class ManifestObjectKind { Basic, SuperKernel };
21+ 
22+struct ManifestCommand {
23+ CompilationCommandKind commandKind{CompilationCommandKind::Compile};
24+ ManifestObjectKind objectKind{ManifestObjectKind::Basic};
25+ std::optional<uint32_t> parallelStage;
26+ std::string diagnosticLabel;
27+ std::string executable;
28+ std::vector<std::string> arguments;
29+};
30+ 
31+// Owns the selected fields independently of the source JSON.
32+struct CompilationManifest {
33+ std::vector<ManifestConstant> constants;
34+ std::vector<ManifestCommand> commands;
35+ std::vector<std::string> linkOptions;
36+ std::vector<std::string> linkInputs;
37+};
38+ 
39+} // namespace aclrtc
40+} // namespace ascendc
41+ 
42+#endif // ASCENDC_ACLRTC_COMPILATION_MANIFEST_H
@@ -0,0 +1,217 @@
1+/**
2+ * Copyright (c) 2026 Huawei Technologies Co., Ltd.
3+ * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
4+ * CANN Open Software License Agreement Version 2.0 (the "License").
5+ * Please refer to the License for details. You may not use this file except in compliance with the License.
6+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7+ * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
8+ * See LICENSE in the root of the software repository for the full text of the License.
9+ */
10+ 
11+#include "compilation_manifest_parser.h"
12+ 
13+#include "ascendc_tool_log.h"
14+#include <nlohmann/json.hpp>
15+#include <limits>
16+ 
17+namespace ascendc {
18+namespace aclrtc {
19+namespace {
20+using Json = nlohmann::json;
21+constexpr char SCHEMA_VERSION[] = "1.0";
22+constexpr char OPTIONS_PREFIX[] = "${options:";
23+ 
24+bool ReadBoundedNonnegativeInteger(const Json& value, uint64_t maximum, uint64_t& result)
25+{
26+ if (!value.is_number_integer() || (!value.is_number_unsigned() && value.get<int64_t>() < 0)) {
27+ return false;
28+ }
29+ result = value.get<uint64_t>();
30+ return result <= maximum;
31+}
32+ 
33+} // namespace
34+ 
35+aclError CompilationManifestParser::ParseConstants(const Json& kernel, std::vector<ManifestConstant>& constants) const
36+{
37+ const auto infos = kernel.find("constant_infos");
38+ if (infos == kernel.end() || !infos->is_array() || infos->empty()) {
39+ ASCENDLOGE("Selected kernel requires a nonempty constant_infos array");
40+ return ACLRTC_ERROR_FAILURE;
41+ }
42+ for (size_t index = 0; index < infos->size(); ++index) {
43+ const Json& info = infos->at(index);
44+ ManifestConstant spec;
45+ if (!spec.ParseDefinition(info)) {
46+ return ACLRTC_ERROR_FAILURE;
47+ }
48+ constants.emplace_back(std::move(spec));
49+ }
50+ return ACLRTC_SUCCESS;
51+}
52+ 
53+aclError CompilationManifestParser::ExpandOptionsReference(
54+ const std::string& argument, const std::string& location, std::vector<std::string>& arguments) const
55+{
56+ if (argument.compare(0, sizeof(OPTIONS_PREFIX) - 1U, OPTIONS_PREFIX) != 0 ||
57+ argument.size() <= sizeof(OPTIONS_PREFIX) || argument.back() != '}') {
58+ arguments.push_back(argument);
59+ return ACLRTC_SUCCESS;
60+ }
61+ const std::string name = argument.substr(sizeof(OPTIONS_PREFIX) - 1U, argument.size() - sizeof(OPTIONS_PREFIX));
62+ const auto options = borrowedManifest_.find("options");
63+ if (options == borrowedManifest_.end() || !options->is_object() || !options->contains(name)) {
64+ ASCENDLOGE("Manifest value %s references undefined options key '%s'", location.c_str(), name.c_str());
65+ return ACLRTC_ERROR_FAILURE;
66+ }
67+ const auto values = options->at(name).get<std::vector<std::string>>();
68+ arguments.insert(arguments.end(), values.begin(), values.end());
69+ return ACLRTC_SUCCESS;
70+}
71+ 
72+aclError CompilationManifestParser::ParseCommand(
73+ const Json& command, const std::string& objectName, ManifestObjectKind objectKind, size_t index,
74+ ManifestCommand& spec) const
75+{
76+ const std::string type = command.at("type").get<std::string>();
77+ if (type == "compile") {
78+ spec.commandKind = CompilationCommandKind::Compile;
79+ } else if (type == "objcopy") {
80+ spec.commandKind = CompilationCommandKind::ObjectCopy;
81+ } else {
82+ ASCENDLOGE(
83+ "Manifest object %s command[%zu] has unsupported type '%s'", objectName.c_str(), index, type.c_str());
84+ return ACLRTC_ERROR_FAILURE;
85+ }
86+ spec.objectKind = objectKind;
87+ spec.diagnosticLabel = objectName + "/" + type + "[" + std::to_string(index) + "]";
88+ if (command.contains("stage")) {
89+ uint64_t stage = 0U;
90+ if (!ReadBoundedNonnegativeInteger(command.at("stage"), std::numeric_limits<uint32_t>::max(), stage)) {
91+ ASCENDLOGE("Manifest command %s has invalid stage", spec.diagnosticLabel.c_str());
92+ return ACLRTC_ERROR_FAILURE;
93+ }
94+ spec.parallelStage = static_cast<uint32_t>(stage);
95+ }
96+ const auto argv = command.at("cmd").get<std::vector<std::string>>();
97+ if (argv.empty()) {
98+ ASCENDLOGE("Manifest command %s has an empty cmd array", spec.diagnosticLabel.c_str());
99+ return ACLRTC_ERROR_FAILURE;
100+ }
101+ std::vector<std::string> expandedArguments;
102+ for (size_t argumentIndex = 0U; argumentIndex < argv.size(); ++argumentIndex) {
103+ const aclError result = ExpandOptionsReference(
104+ argv[argumentIndex], spec.diagnosticLabel + ".cmd[" + std::to_string(argumentIndex) + "]",
105+ expandedArguments);
106+ if (result != ACLRTC_SUCCESS) {
107+ return result;
108+ }
109+ }
110+ if (expandedArguments.empty()) {
111+ ASCENDLOGE("Manifest command %s expands to an empty cmd array", spec.diagnosticLabel.c_str());
112+ return ACLRTC_ERROR_FAILURE;
113+ }
114+ spec.executable = std::move(expandedArguments.front());
115+ expandedArguments.erase(expandedArguments.begin());
116+ spec.arguments = std::move(expandedArguments);
117+ return ACLRTC_SUCCESS;
118+}
119+ 
120+aclError CompilationManifestParser::ParseSelectedObjects(
121+ const Json& kernel, bool enableSuperKernel, CompilationManifest& spec) const
122+{
123+ bool foundBasic = false;
124+ bool foundSuperKernel = false;
125+ const auto& objects = kernel.at("objects");
126+ if (!objects.is_array()) {
127+ ASCENDLOGE("Selected kernel objects must be an array");
128+ return ACLRTC_ERROR_FAILURE;
129+ }
130+ for (const auto& object : objects) {
131+ const std::string type = object.at("object_type").get<std::string>();
132+ ManifestObjectKind kind;
133+ if (type == "basic") {
134+ foundBasic = true;
135+ kind = ManifestObjectKind::Basic;
136+ } else if (type == "sk") {
137+ foundSuperKernel = true;
138+ if (!enableSuperKernel) {
139+ continue;
140+ }
141+ kind = ManifestObjectKind::SuperKernel;
142+ } else {
143+ continue;
144+ }
145+ const std::string name = object.at("object_name").get<std::string>();
146+ const auto& commands = object.at("commands");
147+ if (!commands.is_array() || commands.empty()) {
148+ ASCENDLOGE("Selected object %s requires a nonempty commands array", name.c_str());
149+ return ACLRTC_ERROR_FAILURE;
150+ }
151+ for (size_t index = 0; index < commands.size(); ++index) {
152+ ManifestCommand command;
153+ const aclError result = ParseCommand(commands.at(index), name, kind, index, command);
154+ if (result != ACLRTC_SUCCESS) {
155+ return result;
156+ }
157+ spec.commands.emplace_back(std::move(command));
158+ }
159+ const auto outputs = object.at("outputs").get<std::vector<std::string>>();
160+ spec.linkInputs.insert(spec.linkInputs.end(), outputs.begin(), outputs.end());
161+ }
162+ if (!foundBasic) {
163+ ASCENDLOGE("Selected kernel is missing a required basic object");
164+ return ACLRTC_ERROR_FAILURE;
165+ }
166+ if (enableSuperKernel && !foundSuperKernel) {
167+ ASCENDLOGI("Selected kernel has no sk object; compiling basic only despite --enable-super-kernel");
168+ }
169+ return ACLRTC_SUCCESS;
170+}
171+ 
172+aclError CompilationManifestParser::ParseSelected(
173+ const std::string& kernelName, bool enableSuperKernel, CompilationManifest& parsedManifest) const
174+{
175+ try {
176+ if (borrowedManifest_.at("schema_version").get<std::string>() != SCHEMA_VERSION) {
177+ ASCENDLOGE("Unsupported manifest schema_version; expected %s", SCHEMA_VERSION);
178+ return ACLRTC_ERROR_FAILURE;
179+ }
180+ const auto& kernels = borrowedManifest_.at("kernels");
181+ if (!kernels.is_array()) {
182+ ASCENDLOGE("Manifest kernels must be an array");
183+ return ACLRTC_ERROR_FAILURE;
184+ }
185+ const Json* selectedKernel = nullptr;
186+ for (const auto& kernel : kernels) {
187+ if (kernel.at("kernel_name").get<std::string>() == kernelName) {
188+ selectedKernel = &kernel;
189+ break;
190+ }
191+ }
192+ if (selectedKernel == nullptr) {
193+ ASCENDLOGE("Kernel entry '%s' is not present in the manifest", kernelName.c_str());
194+ return ACLRTC_ERROR_FAILURE;
195+ }
196+ CompilationManifest spec;
197+ aclError result = ParseConstants(*selectedKernel, spec.constants);
198+ if (result != ACLRTC_SUCCESS) {
199+ return result;
200+ }
201+ result = ParseSelectedObjects(*selectedKernel, enableSuperKernel, spec);
202+ if (result != ACLRTC_SUCCESS) {
203+ return result;
204+ }
205+ if (selectedKernel->contains("link_options")) {
206+ spec.linkOptions = selectedKernel->at("link_options").get<std::vector<std::string>>();
207+ }
208+ parsedManifest = std::move(spec);
209+ return ACLRTC_SUCCESS;
210+ } catch (const nlohmann::json::exception& error) {
211+ ASCENDLOGE("Invalid manifest fields for kernel '%s': %s", kernelName.c_str(), error.what());
212+ return ACLRTC_ERROR_FAILURE;
213+ }
214+}
215+ 
216+} // namespace aclrtc
217+} // namespace ascendc
@@ -0,0 +1,41 @@
1+/**
2+ * Copyright (c) 2026 Huawei Technologies Co., Ltd.
3+ * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
4+ * CANN Open Software License Agreement Version 2.0 (the "License").
5+ * Please refer to the License for details. You may not use this file except in compliance with the License.
6+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7+ * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
8+ * See LICENSE in the root of the software repository for the full text of the License.
9+ */
10+ 
11+#ifndef ASCENDC_ACLRTC_COMPILATION_MANIFEST_PARSER_H
12+#define ASCENDC_ACLRTC_COMPILATION_MANIFEST_PARSER_H
13+ 
14+#include "compilation_manifest.h"
15+#include <nlohmann/json_fwd.hpp>
16+ 
17+namespace ascendc {
18+namespace aclrtc {
19+ 
20+class CompilationManifestParser final {
21+public:
22+ explicit CompilationManifestParser(const nlohmann::json& manifest) : borrowedManifest_(manifest) {}
23+ aclError ParseSelected(const std::string& kernelName, bool enableSuperKernel, CompilationManifest& result) const;
24+ 
25+private:
26+ aclError ParseConstants(const nlohmann::json& kernel, std::vector<ManifestConstant>& constants) const;
27+ aclError ExpandOptionsReference(
28+ const std::string& argument, const std::string& location, std::vector<std::string>& arguments) const;
29+ aclError ParseCommand(
30+ const nlohmann::json& command, const std::string& objectName, ManifestObjectKind objectKind, size_t index,
31+ ManifestCommand& result) const;
32+ aclError ParseSelectedObjects(
33+ const nlohmann::json& kernel, bool enableSuperKernel, CompilationManifest& result) const;
34+ 
35+ const nlohmann::json& borrowedManifest_;
36+};
37+ 
38+} // namespace aclrtc
39+} // namespace ascendc
40+ 
41+#endif // ASCENDC_ACLRTC_COMPILATION_MANIFEST_PARSER_H
@@ -68,11 +68,10 @@ aclError CompilationPlanExecutor::ExecuteCompilationCommand(
68 const CompilationCommand& compilationCommand, ProcessExecutorResult& executorResult) const68 const CompilationCommand& compilationCommand, ProcessExecutorResult& executorResult) const
69{69{
70 ProcessExecutorRequest executorRequest;70 ProcessExecutorRequest executorRequest;
71- executorRequest.arguments.reserve(compilationCommand.commandArguments.size() + 1U);71+ executorRequest.arguments.reserve(compilationCommand.arguments.size() + 1U);
72 executorRequest.arguments.emplace_back(compilationCommand.executablePath.string());72 executorRequest.arguments.emplace_back(compilationCommand.executablePath.string());
73 executorRequest.arguments.insert(73 executorRequest.arguments.insert(
74- executorRequest.arguments.end(), compilationCommand.commandArguments.begin(),74+ executorRequest.arguments.end(), compilationCommand.arguments.begin(), compilationCommand.arguments.end());
75- compilationCommand.commandArguments.end());
76 executorRequest.mirroredOutputLogFilePath = specializationDiagnostics_.GetCompilationLogFilePath();75 executorRequest.mirroredOutputLogFilePath = specializationDiagnostics_.GetCompilationLogFilePath();
77 executorRequest.executionTimeout = compilationCommand.commandKind == CompilationCommandKind::Compile ?76 executorRequest.executionTimeout = compilationCommand.commandKind == CompilationCommandKind::Compile ?
78 commandExecutionLimits_.compileCommandTimeout :77 commandExecutionLimits_.compileCommandTimeout :
@@ -24,29 +24,8 @@ namespace ascendc {
24namespace aclrtc {24namespace aclrtc {
25namespace {25namespace {
26namespace fs = boost::filesystem;26namespace fs = boost::filesystem;
27-using Json = nlohmann::json;
28- 
29-constexpr char SUPPORTED_MANIFEST_SCHEMA_VERSION[] = "1.0";
30-constexpr char OPTIONS_REFERENCE_PREFIX[] = "${options:";
31constexpr char ENVIRONMENT_REFERENCE_PREFIX[] = "${env:";27constexpr char ENVIRONMENT_REFERENCE_PREFIX[] = "${env:";
32 28 
33-enum class ManifestObjectKind : uint32_t {
34- Basic,
35- SuperKernel,
36-};
37- 
38-struct SelectedManifestObject {
39- const Json* manifestObject{nullptr};
40- ManifestObjectKind objectKind{ManifestObjectKind::Basic};
41-};
42- 
43-struct ManifestExpansionContext {
44- const Json& resourceManifest;
45- const fs::path& resourceWorktreePath;
46- const fs::path& outputDirectoryPath;
47- const fs::path& externalSourceDirectoryPath;
48-};
49- 
50void ReplaceAllLiteralOccurrences(std::string& text, const std::string& literalText, const std::string& replacementText)29void ReplaceAllLiteralOccurrences(std::string& text, const std::string& literalText, const std::string& replacementText)
51{30{
52 size_t occurrencePosition = 0U;31 size_t occurrencePosition = 0U;
@@ -99,66 +78,6 @@ bool ExpandEnvironmentVariablePlaceholders(
99 return true;78 return true;
100}79}
101 80 
102-bool ExpandPathAndEnvironmentPlaceholders(
103- const std::string& manifestText, const std::string& manifestValueLocation,
104- const ManifestExpansionContext& expansionContext, std::string& resolvedText)
105-{
106- std::string pathResolvedText = manifestText;
107- ReplaceAllLiteralOccurrences(pathResolvedText, "${resource}", expansionContext.resourceWorktreePath.string());
108- ReplaceAllLiteralOccurrences(pathResolvedText, "${output}", expansionContext.outputDirectoryPath.string());
109- ReplaceAllLiteralOccurrences(
110- pathResolvedText, "${source_file_path}", expansionContext.externalSourceDirectoryPath.string());
111- return ExpandEnvironmentVariablePlaceholders(pathResolvedText, manifestValueLocation, resolvedText);
112-}
113- 
114-bool ParseWholeArgumentOptionsPlaceholder(const std::string& manifestArgument, std::string& optionName)
115-{
116- if (manifestArgument.compare(0, sizeof(OPTIONS_REFERENCE_PREFIX) - 1U, OPTIONS_REFERENCE_PREFIX) != 0 ||
117- manifestArgument.size() <= sizeof(OPTIONS_REFERENCE_PREFIX) || manifestArgument.back() != '}') {
118- return false;
119- }
120- optionName = manifestArgument.substr(
121- sizeof(OPTIONS_REFERENCE_PREFIX) - 1U, manifestArgument.size() - sizeof(OPTIONS_REFERENCE_PREFIX));
122- return !optionName.empty();
123-}
124- 
125-aclError ExpandManifestArgument(
126- const std::string& manifestArgument, const std::string& argumentLocation,
127- const ManifestExpansionContext& expansionContext, std::vector<std::string>& expandedArguments)
128-{
129- std::string optionName;
130- if (!ParseWholeArgumentOptionsPlaceholder(manifestArgument, optionName)) {
131- std::string resolvedArgument;
132- if (!ExpandPathAndEnvironmentPlaceholders(
133- manifestArgument, argumentLocation, expansionContext, resolvedArgument)) {
134- return ACLRTC_ERROR_FAILURE;
135- }
136- expandedArguments.emplace_back(std::move(resolvedArgument));
137- return ACLRTC_SUCCESS;
138- }
139- 
140- const auto optionTable = expansionContext.resourceManifest.find("options");
141- if (optionTable == expansionContext.resourceManifest.end() || !optionTable->is_object() ||
142- optionTable->find(optionName) == optionTable->end()) {
143- ASCENDLOGE(
144- "Manifest value %s references undefined options key '%s'; define this key in the top-level options "
145- "object and regenerate the JIT resource",
146- argumentLocation.c_str(), optionName.c_str());
147- return ACLRTC_ERROR_FAILURE;
148- }
149- const std::vector<std::string> optionArguments = optionTable->at(optionName).get<std::vector<std::string>>();
150- for (size_t optionIndex = 0U; optionIndex < optionArguments.size(); ++optionIndex) {
151- std::string resolvedArgument;
152- const std::string optionLocation = "options['" + optionName + "'][" + std::to_string(optionIndex) + "]";
153- if (!ExpandPathAndEnvironmentPlaceholders(
154- optionArguments[optionIndex], optionLocation, expansionContext, resolvedArgument)) {
155- return ACLRTC_ERROR_FAILURE;
156- }
157- expandedArguments.emplace_back(std::move(resolvedArgument));
158- }
159- return ACLRTC_SUCCESS;
160-}
161- 
162bool IsAbsoluteExecutableRegularFile(const fs::path& executablePath)81bool IsAbsoluteExecutableRegularFile(const fs::path& executablePath)
163{82{
164 boost::system::error_code fileError;83 boost::system::error_code fileError;
@@ -171,15 +90,14 @@ bool IsMissingPathError(const boost::system::error_code& pathError) noexcept
171 return pathError.value() == ENOENT || pathError.value() == ENOTDIR;90 return pathError.value() == ENOENT || pathError.value() == ENOTDIR;
172}91}
173 92 
174-bool FindSeparatedCompilerOutputOptionPosition(93+bool FindSeparatedCompilerOutputOptionPosition(const std::vector<std::string>& arguments, size_t& outputOptionPosition)
175- const std::vector<std::string>& commandArguments, size_t& outputOptionPosition)
176{94{
177- for (size_t argumentIndex = 0; argumentIndex < commandArguments.size(); ++argumentIndex) {95+ for (size_t argumentIndex = 0; argumentIndex < arguments.size(); ++argumentIndex) {
178- const std::string& argument = commandArguments[argumentIndex];96+ const std::string& argument = arguments[argumentIndex];
179 if (argument != "-o") {97 if (argument != "-o") {
180 continue;98 continue;
181 }99 }
182- if (argumentIndex + 1U < commandArguments.size() && !commandArguments[argumentIndex + 1U].empty()) {100+ if (argumentIndex + 1U < arguments.size() && !arguments[argumentIndex + 1U].empty()) {
183 outputOptionPosition = argumentIndex;101 outputOptionPosition = argumentIndex;
184 return true;102 return true;
185 }103 }
@@ -204,119 +122,54 @@ std::string FormatBytesAsCppInitializerList(const void* constantAddress, uint64_
204 return encodedBytes.str();122 return encodedBytes.str();
205}123}
206 124 
207-aclError BuildConstantSourcePatches(125+} // namespace
208- const Json& selectedKernel, const NormalizedKernelSpecializationRequest& specializationRequest,
209- const ManifestExpansionContext& expansionContext, std::vector<KernelSourcePatch>& sourcePatches)
210-{
211- const auto constantInfos = selectedKernel.find("constant_infos");
212- if (constantInfos == selectedKernel.end() || constantInfos->empty()) {
213- ASCENDLOGE("Selected kernel must contain at least one constant_info for static compilation; regenerate the JIT "
214- "resource with its static constant metadata");
215- return ACLRTC_ERROR_FAILURE;
216- }
217- for (size_t constantIndex = 0U; constantIndex < constantInfos->size(); ++constantIndex) {
218- const Json& constantInfo = constantInfos->at(constantIndex);
219- const uint64_t constantArgumentIndex = constantInfo.at("parameter_index").get<uint64_t>();
220- const uint64_t requiredConstantByteCount = constantInfo.at("byte_size").get<uint64_t>();
221- if (specializationRequest.borrowedKernelArgumentDataPointers == nullptr ||
222- specializationRequest.borrowedKernelArgumentByteCounts == nullptr) {
223- ASCENDLOGE(
224- "constant parameter_index %llu requires argsAddr and argsBytes; set both request arrays with at "
225- "least argsCount entries",
226- static_cast<unsigned long long>(constantArgumentIndex));
227- return ACLRTC_ERROR_INVALID_INPUT;
228- }
229- if (constantArgumentIndex >= specializationRequest.kernelArgumentCount) {
230- ASCENDLOGE(
231- "constant parameter_index %llu is outside argsCount %llu; set argsCount greater than %llu and "
232- "provide matching argsAddr and argsBytes entries",
233- static_cast<unsigned long long>(constantArgumentIndex),
234- static_cast<unsigned long long>(specializationRequest.kernelArgumentCount),
235- static_cast<unsigned long long>(constantArgumentIndex));
236- return ACLRTC_ERROR_INVALID_INPUT;
237- }
238- if (specializationRequest.borrowedKernelArgumentDataPointers[constantArgumentIndex] == nullptr) {
239- ASCENDLOGE(
240- "argsAddr[%llu] must not be null for a static constant; set it to the constant data buffer",
241- static_cast<unsigned long long>(constantArgumentIndex));
242- return ACLRTC_ERROR_INVALID_INPUT;
243- }
244- const uint64_t suppliedConstantByteCount =
245- specializationRequest.borrowedKernelArgumentByteCounts[constantArgumentIndex];
246- if (suppliedConstantByteCount != requiredConstantByteCount) {
247- ASCENDLOGE(
248- "argsBytes[%llu]=%llu does not match required byte_size %llu; set argsBytes[%llu] to %llu",
249- static_cast<unsigned long long>(constantArgumentIndex),
250- static_cast<unsigned long long>(suppliedConstantByteCount),
251- static_cast<unsigned long long>(requiredConstantByteCount),
252- static_cast<unsigned long long>(constantArgumentIndex),
253- static_cast<unsigned long long>(requiredConstantByteCount));
254- return ACLRTC_ERROR_INVALID_INPUT;
255- }
256 126 
257- std::string resolvedTargetFilePath;127+bool KernelCompilationPlanBuilder::ExpandPathAndEnvironmentReferences(
258- const std::string constantFileLocation = "constant_infos[" + std::to_string(constantIndex) + "].file";128+ const std::string& text, const std::string& location, std::string& resolvedText) const
259- if (!ExpandPathAndEnvironmentPlaceholders(129+{
260- constantInfo.at("file").get<std::string>(), constantFileLocation, expansionContext,130+ std::string pathResolvedText = text;
261- resolvedTargetFilePath)) {131+ ReplaceAllLiteralOccurrences(pathResolvedText, "${resource}", resourceWorktreePath_.string());
132+ ReplaceAllLiteralOccurrences(pathResolvedText, "${output}", outputDirectoryPath_.string());
133+ ReplaceAllLiteralOccurrences(pathResolvedText, "${source_file_path}", externalSourceDirectoryPath_.string());
134+ return ExpandEnvironmentVariablePlaceholders(pathResolvedText, location, resolvedText);
135+}
136+ 
137+aclError KernelCompilationPlanBuilder::BuildConstantSourcePatches(KernelCompilationPlan& plan) const
138+{
139+ auto constants = borrowedManifest_.constants;
140+ std::vector<KernelSourcePatch> patches;
141+ for (ManifestConstant& constant : constants) {
142+ if (!constant.BindArgument(
143+ specializationRequest_.kernelArgumentCount, specializationRequest_.borrowedKernelArgumentDataPointers,
144+ specializationRequest_.borrowedKernelArgumentByteCounts)) {
145+ return ACLRTC_ERROR_INVALID_INPUT;
146+ }
147+ std::string targetFile;
148+ if (!ExpandPathAndEnvironmentReferences(constant.GetTargetFile(), constant.GetName(), targetFile)) {
262 return ACLRTC_ERROR_FAILURE;149 return ACLRTC_ERROR_FAILURE;
263 }150 }
264- sourcePatches.push_back(151+ patches.push_back({targetFile, constant.GetTemplateText(), {}});
265- {resolvedTargetFilePath, constantInfo.at("template").get<std::string>(),
266- FormatBytesAsCppInitializerList(
267- specializationRequest.borrowedKernelArgumentDataPointers[constantArgumentIndex],
268- requiredConstantByteCount)});
269 }152 }
153+ // Avoid reading caller-owned buffers if any constant binding or target expansion fails.
154+ for (size_t index = 0; index < constants.size(); ++index) {
155+ patches[index].replacementText =
156+ FormatBytesAsCppInitializerList(constants[index].GetBoundData(), constants[index].GetBoundByteSize());
157+ }
158+ plan.sourcePatches = std::move(patches);
270 return ACLRTC_SUCCESS;159 return ACLRTC_SUCCESS;
271}160}
272 161 
273-aclError BuildManifestCommand(162+aclError KernelCompilationPlanBuilder::BindManifestCommand(
274- const Json& manifestCommand, const SelectedManifestObject& selectedObject, size_t commandIndex,163+ const ManifestCommand& spec, CompilationCommand& compilationCommand) const
275- const NormalizedKernelSpecializationRequest& specializationRequest,
276- const ManifestExpansionContext& expansionContext, CompilationCommand& compilationCommand)
277{164{
278- const std::string manifestObjectName = selectedObject.manifestObject->at("object_name").get<std::string>();165+ compilationCommand.commandKind = spec.commandKind;
279- const std::string commandType = manifestCommand.at("type").get<std::string>();166+ compilationCommand.parallelStage = spec.parallelStage;
280- if (commandType == "compile") {167+ compilationCommand.diagnosticLabel = spec.diagnosticLabel;
281- compilationCommand.commandKind = CompilationCommandKind::Compile;168+ std::string executable;
282- } else if (commandType == "objcopy") {169+ if (!ExpandPathAndEnvironmentReferences(spec.executable, spec.diagnosticLabel, executable)) {
283- compilationCommand.commandKind = CompilationCommandKind::ObjectCopy;
284- } else {
285- ASCENDLOGE(
286- "Manifest object %s command[%zu] has unsupported type '%s'; regenerate the JIT resource using a "
287- "command type supported by ACLRTC",
288- manifestObjectName.c_str(), commandIndex, commandType.c_str());
289 return ACLRTC_ERROR_FAILURE;170 return ACLRTC_ERROR_FAILURE;
290 }171 }
291- const auto parallelStage = manifestCommand.find("stage");172+ compilationCommand.executablePath = std::move(executable);
292- if (parallelStage != manifestCommand.end()) {
293- compilationCommand.parallelStage = parallelStage->get<uint32_t>();
294- }
295- compilationCommand.diagnosticLabel =
296- manifestObjectName + "/" + commandType + "[" + std::to_string(commandIndex) + "]";
297- 
298- const std::vector<std::string> manifestArguments = manifestCommand.at("cmd").get<std::vector<std::string>>();
299- if (manifestArguments.empty()) {
300- ASCENDLOGE(
301- "Manifest command %s has an empty cmd array; regenerate the JIT resource",
302- compilationCommand.diagnosticLabel.c_str());
303- return ACLRTC_ERROR_FAILURE;
304- }
305- std::vector<std::string> expandedExecutable;
306- aclError result = ExpandManifestArgument(
307- manifestArguments.front(), compilationCommand.diagnosticLabel + ".cmd[0]", expansionContext,
308- expandedExecutable);
309- if (result != ACLRTC_SUCCESS) {
310- return result;
311- }
312- if (expandedExecutable.size() != 1U) {
313- ASCENDLOGE(
314- "Manifest command %s executable expanded to %zu argv items; regenerate the JIT resource so cmd[0] "
315- "resolves to exactly one executable path",
316- compilationCommand.diagnosticLabel.c_str(), expandedExecutable.size());
317- return ACLRTC_ERROR_FAILURE;
318- }
319- compilationCommand.executablePath = std::move(expandedExecutable.front());
320 if (!IsAbsoluteExecutableRegularFile(compilationCommand.executablePath)) {173 if (!IsAbsoluteExecutableRegularFile(compilationCommand.executablePath)) {
321 ASCENDLOGE(174 ASCENDLOGE(
322 "Manifest command %s requires an absolute path to an existing executable regular file: path=%s; "175 "Manifest command %s requires an absolute path to an existing executable regular file: path=%s; "
@@ -325,111 +178,65 @@ aclError BuildManifestCommand(
325 return ACLRTC_ERROR_FAILURE;178 return ACLRTC_ERROR_FAILURE;
326 }179 }
327 180 
328- for (size_t argumentIndex = 1U; argumentIndex < manifestArguments.size(); ++argumentIndex) {181+ for (const std::string& argument : spec.arguments) {
329- const std::string argumentLocation =182+ std::string resolvedArgument;
330- compilationCommand.diagnosticLabel + ".cmd[" + std::to_string(argumentIndex) + "]";183+ if (!ExpandPathAndEnvironmentReferences(argument, spec.diagnosticLabel, resolvedArgument)) {
331- result = ExpandManifestArgument(184+ return ACLRTC_ERROR_FAILURE;
332- manifestArguments[argumentIndex], argumentLocation, expansionContext, compilationCommand.commandArguments);
333- if (result != ACLRTC_SUCCESS) {
334- return result;
335 }185 }
186+ compilationCommand.arguments.emplace_back(std::move(resolvedArgument));
336 }187 }
337 188 
338 if (compilationCommand.commandKind == CompilationCommandKind::Compile) {189 if (compilationCommand.commandKind == CompilationCommandKind::Compile) {
339 size_t outputOptionPosition = 0U;190 size_t outputOptionPosition = 0U;
340- if (!FindSeparatedCompilerOutputOptionPosition(compilationCommand.commandArguments, outputOptionPosition)) {191+ if (!FindSeparatedCompilerOutputOptionPosition(compilationCommand.arguments, outputOptionPosition)) {
341 ASCENDLOGE(192 ASCENDLOGE(
342 "Manifest compile command %s must contain a valid separated '-o' output option and a non-empty "193 "Manifest compile command %s must contain a valid separated '-o' output option and a non-empty "
343 "output path; regenerate the JIT resource with '-o' followed by its output path",194 "output path; regenerate the JIT resource with '-o' followed by its output path",
344 compilationCommand.diagnosticLabel.c_str());195 compilationCommand.diagnosticLabel.c_str());
345 return ACLRTC_ERROR_FAILURE;196 return ACLRTC_ERROR_FAILURE;
346 }197 }
347- const std::vector<std::string>& userOptions = selectedObject.objectKind == ManifestObjectKind::Basic ?198+ const auto& options = spec.objectKind == ManifestObjectKind::Basic ?
348- specializationRequest.compilerOptions.basicOptions :199+ specializationRequest_.compilerOptions.basicOptions :
349- specializationRequest.compilerOptions.superKernelOptions;200+ specializationRequest_.compilerOptions.superKernelOptions;
350- compilationCommand.commandArguments.insert(201+ compilationCommand.arguments.insert(
351- compilationCommand.commandArguments.begin() + static_cast<std::ptrdiff_t>(outputOptionPosition),202+ compilationCommand.arguments.begin() + static_cast<std::ptrdiff_t>(outputOptionPosition), options.begin(),
352- userOptions.begin(), userOptions.end());203+ options.end());
353 }204 }
354 return ACLRTC_SUCCESS;205 return ACLRTC_SUCCESS;
355}206}
356 207 
357-aclError SelectManifestObjectsForCompilation(208+aclError KernelCompilationPlanBuilder::BindLinkCommand(
358- const Json& selectedKernel, KernelCompilationVariant compilationVariant,209+ const CompilationManifest& spec, KernelCompilationPlan& plan) const
359- std::vector<SelectedManifestObject>& selectedObjects)
360-{
361- bool foundBasicObject = false;
362- bool foundSuperKernelObject = false;
363- for (const Json& manifestObject : selectedKernel.at("objects")) {
364- const std::string objectType = manifestObject.at("object_type").get<std::string>();
365- if (objectType == "basic") {
366- foundBasicObject = true;
367- selectedObjects.push_back({&manifestObject, ManifestObjectKind::Basic});
368- } else if (objectType == "sk") {
369- foundSuperKernelObject = true;
370- if (compilationVariant == KernelCompilationVariant::BasicWithSuperKernel) {
371- selectedObjects.push_back({&manifestObject, ManifestObjectKind::SuperKernel});
372- }
373- }
374- }
375- if (!foundBasicObject) {
376- ASCENDLOGE("Selected kernel does not contain a basic object; regenerate the JIT resource");
377- return ACLRTC_ERROR_FAILURE;
378- }
379- if (compilationVariant == KernelCompilationVariant::BasicWithSuperKernel && !foundSuperKernelObject) {
380- ASCENDLOGE("Super-kernel compilation was requested but the selected kernel has no sk object; remove "
381- "--enable-super-kernel or use a JIT resource that contains an sk object");
382- return ACLRTC_ERROR_FAILURE;
383- }
384- return ACLRTC_SUCCESS;
385-}
386- 
387-aclError BuildLinkCommand(
388- const Json& selectedKernel, const std::vector<SelectedManifestObject>& selectedObjects,
389- const ManifestExpansionContext& expansionContext, CompilationCommand& linkCommand,
390- std::set<fs::path>& requiredOutputDirectories, fs::path& linkedKernelElfPath)
391{210{
211+ CompilationCommand linkCommand;
212+ std::set<fs::path> requiredOutputDirectories{outputDirectoryPath_};
392 linkCommand.commandKind = CompilationCommandKind::Link;213 linkCommand.commandKind = CompilationCommandKind::Link;
393 linkCommand.diagnosticLabel = "link";214 linkCommand.diagnosticLabel = "link";
394 std::string linkerPath;215 std::string linkerPath;
395- if (!ExpandPathAndEnvironmentPlaceholders(216+ if (!ExpandPathAndEnvironmentReferences(
396- "${env:ASCEND_HOME_PATH}/bin/ld.lld", "internal linker executable", expansionContext, linkerPath)) {217+ "${env:ASCEND_HOME_PATH}/bin/ld.lld", "internal linker executable", linkerPath)) {
397 return ACLRTC_ERROR_FAILURE;218 return ACLRTC_ERROR_FAILURE;
398 }219 }
399 linkCommand.executablePath = linkerPath;220 linkCommand.executablePath = linkerPath;
400 221 
401- const auto linkOptions = selectedKernel.find("link_options");222+ for (const std::string& option : spec.linkOptions) {
402- if (linkOptions != selectedKernel.end()) {223+ std::string resolvedOption;
403- const std::vector<std::string> configuredLinkOptions = linkOptions->get<std::vector<std::string>>();224+ if (!ExpandPathAndEnvironmentReferences(option, "link_options", resolvedOption)) {
404- for (size_t linkOptionIndex = 0U; linkOptionIndex < configuredLinkOptions.size(); ++linkOptionIndex) {225+ return ACLRTC_ERROR_FAILURE;
405- std::string resolvedLinkOption;
406- const std::string linkOptionLocation = "link_options[" + std::to_string(linkOptionIndex) + "]";
407- if (!ExpandPathAndEnvironmentPlaceholders(
408- configuredLinkOptions[linkOptionIndex], linkOptionLocation, expansionContext, resolvedLinkOption)) {
409- return ACLRTC_ERROR_FAILURE;
410- }
411- linkCommand.commandArguments.emplace_back(std::move(resolvedLinkOption));
412 }226 }
227+ linkCommand.arguments.emplace_back(std::move(resolvedOption));
413 }228 }
414- for (const SelectedManifestObject& selectedObject : selectedObjects) {229+ for (const std::string& input : spec.linkInputs) {
415- const std::string manifestObjectName = selectedObject.manifestObject->at("object_name").get<std::string>();230+ std::string resolvedInput;
416- const std::vector<std::string> outputs =231+ if (!ExpandPathAndEnvironmentReferences(input, "link_inputs", resolvedInput)) {
417- selectedObject.manifestObject->at("outputs").get<std::vector<std::string>>();232+ return ACLRTC_ERROR_FAILURE;
418- for (size_t outputIndex = 0U; outputIndex < outputs.size(); ++outputIndex) {
419- std::string resolvedOutput;
420- const std::string outputLocation = manifestObjectName + ".outputs[" + std::to_string(outputIndex) + "]";
421- if (!ExpandPathAndEnvironmentPlaceholders(
422- outputs[outputIndex], outputLocation, expansionContext, resolvedOutput)) {
423- return ACLRTC_ERROR_FAILURE;
424- }
425- linkCommand.commandArguments.emplace_back(resolvedOutput);
426- requiredOutputDirectories.emplace(fs::path(resolvedOutput).parent_path());
427 }233 }
234+ requiredOutputDirectories.emplace(fs::path(resolvedInput).parent_path());
235+ linkCommand.arguments.emplace_back(std::move(resolvedInput));
428 }236 }
429- linkedKernelElfPath = expansionContext.outputDirectoryPath / "linked_kernel.elf";237+ plan.linkedKernelElfPath = outputDirectoryPath_ / "linked_kernel.elf";
430- requiredOutputDirectories.emplace(linkedKernelElfPath.parent_path());238+ linkCommand.arguments.emplace_back("-o");
431- linkCommand.commandArguments.emplace_back("-o");239+ linkCommand.arguments.emplace_back(plan.linkedKernelElfPath.string());
432- linkCommand.commandArguments.emplace_back(linkedKernelElfPath.string());
433 if (!IsAbsoluteExecutableRegularFile(linkCommand.executablePath)) {240 if (!IsAbsoluteExecutableRegularFile(linkCommand.executablePath)) {
434 ASCENDLOGE(241 ASCENDLOGE(
435 "Linker requires an absolute path to an existing executable regular file: path=%s; verify "242 "Linker requires an absolute path to an existing executable regular file: path=%s; verify "
@@ -437,118 +244,73 @@ aclError BuildLinkCommand(
437 linkCommand.executablePath.c_str());244 linkCommand.executablePath.c_str());
438 return ACLRTC_ERROR_FAILURE;245 return ACLRTC_ERROR_FAILURE;
439 }246 }
247+ plan.compilationCommands.emplace_back(std::move(linkCommand));
248+ plan.requiredOutputDirectoryPaths.assign(requiredOutputDirectories.begin(), requiredOutputDirectories.end());
249+ return ACLRTC_SUCCESS;
250+}
251+ 
252+aclError KernelCompilationPlanBuilder::CheckResourceWorktreeDirectory() const
253+{
254+ if (!resourceWorktreePath_.is_absolute()) {
255+ ASCENDLOGE(
256+ "ResourceRegistry returned a non-absolute worktree path: %s; fix the registry integration",
257+ resourceWorktreePath_.c_str());
258+ return ACLRTC_ERROR_FAILURE;
259+ }
260+ boost::system::error_code worktreeError;
261+ const bool worktreeIsDirectory = fs::is_directory(resourceWorktreePath_, worktreeError);
262+ if (worktreeError && !IsMissingPathError(worktreeError)) {
263+ ASCENDLOGE(
264+ "Failed to inspect resource worktree: path=%s error=%d message=%s; fix the registry "
265+ "integration",
266+ resourceWorktreePath_.c_str(), worktreeError.value(), worktreeError.message().c_str());
267+ return ACLRTC_ERROR_FAILURE;
268+ }
269+ if (!worktreeIsDirectory) {
270+ ASCENDLOGE(
271+ "Resource worktree must be an existing directory: path=%s; fix the registry integration",
272+ resourceWorktreePath_.c_str());
273+ return ACLRTC_ERROR_FAILURE;
274+ }
440 return ACLRTC_SUCCESS;275 return ACLRTC_SUCCESS;
441}276}
442-} // namespace
443 277 
444KernelCompilationPlanBuilder::KernelCompilationPlanBuilder(278KernelCompilationPlanBuilder::KernelCompilationPlanBuilder(
445- const NormalizedKernelSpecializationRequest& specializationRequest, const nlohmann::json& resourceManifest,279+ const NormalizedKernelSpecializationRequest& specializationRequest, const CompilationManifest& manifest,
446 fs::path resourceWorktreePath, fs::path externalSourceDirectoryPath)280 fs::path resourceWorktreePath, fs::path externalSourceDirectoryPath)
447 : specializationRequest_(specializationRequest),281 : specializationRequest_(specializationRequest),
448- resourceManifest_(resourceManifest),282+ borrowedManifest_(manifest),
449 resourceWorktreePath_(std::move(resourceWorktreePath)),283 resourceWorktreePath_(std::move(resourceWorktreePath)),
450- externalSourceDirectoryPath_(std::move(externalSourceDirectoryPath))284+ externalSourceDirectoryPath_(std::move(externalSourceDirectoryPath)),
285+ outputDirectoryPath_(
286+ resourceWorktreePath_ / (".aclrtc_" + specializationRequest_.specializationSessionId) / "outputs")
451{}287{}
452 288 
453aclError KernelCompilationPlanBuilder::BuildCompilationPlan(KernelCompilationPlan& compilationPlan) const289aclError KernelCompilationPlanBuilder::BuildCompilationPlan(KernelCompilationPlan& compilationPlan) const
454{290{
455- try {291+ aclError result = CheckResourceWorktreeDirectory();
456- if (!resourceWorktreePath_.is_absolute()) {292+ if (result != ACLRTC_SUCCESS) {
457- ASCENDLOGE(293+ return result;
458- "ResourceRegistry returned a non-absolute worktree path: %s; fix the registry integration",
459- resourceWorktreePath_.c_str());
460- return ACLRTC_ERROR_FAILURE;
461- }
462- boost::system::error_code worktreeError;
463- const bool worktreeIsDirectory = fs::is_directory(resourceWorktreePath_, worktreeError);
464- if (worktreeError && !IsMissingPathError(worktreeError)) {
465- ASCENDLOGE(
466- "Failed to inspect resource worktree: path=%s error=%d message=%s; fix the registry "
467- "integration",
468- resourceWorktreePath_.c_str(), worktreeError.value(), worktreeError.message().c_str());
469- return ACLRTC_ERROR_FAILURE;
470- }
471- if (!worktreeIsDirectory) {
472- ASCENDLOGE(
473- "Resource worktree must be an existing directory: path=%s; fix the registry integration",
474- resourceWorktreePath_.c_str());
475- return ACLRTC_ERROR_FAILURE;
476- }
477- const std::string schemaVersion = resourceManifest_.at("schema_version").get<std::string>();
478- if (schemaVersion != SUPPORTED_MANIFEST_SCHEMA_VERSION) {
479- ASCENDLOGE(
480- "Unsupported Manifest schema_version '%s'; expected '%s'. Regenerate the JIT resource with a "
481- "compatible pack tool",
482- schemaVersion.c_str(), SUPPORTED_MANIFEST_SCHEMA_VERSION);
483- return ACLRTC_ERROR_FAILURE;
484- }
485- 
486- const Json* selectedKernel = nullptr;
487- for (const Json& kernel : resourceManifest_.at("kernels")) {
488- if (kernel.at("kernel_name").get<std::string>() == specializationRequest_.kernelName) {
489- selectedKernel = &kernel;
490- break;
491- }
492- }
493- if (selectedKernel == nullptr) {
494- ASCENDLOGE(
495- "Kernel entry '%s' is not present in JIT resource '%s'; correct kernelEntry or resourceId",
496- specializationRequest_.kernelName.c_str(), specializationRequest_.resourceId.c_str());
497- return ACLRTC_ERROR_FAILURE;
498- }
499- 
500- KernelCompilationPlan builtPlan;
501- const fs::path outputDirectoryPath =
502- resourceWorktreePath_ / (".aclrtc_" + specializationRequest_.specializationSessionId) / "outputs";
503- const ManifestExpansionContext expansionContext{
504- resourceManifest_, resourceWorktreePath_, outputDirectoryPath, externalSourceDirectoryPath_};
505- aclError result = BuildConstantSourcePatches(
506- *selectedKernel, specializationRequest_, expansionContext, builtPlan.sourcePatches);
507- if (result != ACLRTC_SUCCESS) {
508- return result;
509- }
510- 
511- std::vector<SelectedManifestObject> selectedObjects;
512- result = SelectManifestObjectsForCompilation(
513- *selectedKernel, specializationRequest_.compilationVariant, selectedObjects);
514- if (result != ACLRTC_SUCCESS) {
515- return result;
516- }
517- 
518- for (const SelectedManifestObject& selectedObject : selectedObjects) {
519- const Json& commands = selectedObject.manifestObject->at("commands");
520- for (size_t commandIndex = 0U; commandIndex < commands.size(); ++commandIndex) {
521- CompilationCommand command;
522- result = BuildManifestCommand(
523- commands.at(commandIndex), selectedObject, commandIndex, specializationRequest_, expansionContext,
524- command);
525- if (result != ACLRTC_SUCCESS) {
526- return result;
527- }
528- builtPlan.compilationCommands.emplace_back(std::move(command));
529- }
530- }
531- 
532- std::set<fs::path> requiredOutputDirectories{outputDirectoryPath};
533- CompilationCommand linkCommand;
534- result = BuildLinkCommand(
535- *selectedKernel, selectedObjects, expansionContext, linkCommand, requiredOutputDirectories,
536- builtPlan.linkedKernelElfPath);
537- if (result != ACLRTC_SUCCESS) {
538- return result;
539- }
540- builtPlan.compilationCommands.emplace_back(std::move(linkCommand));
541- builtPlan.requiredOutputDirectoryPaths.assign(
542- requiredOutputDirectories.begin(), requiredOutputDirectories.end());
543- compilationPlan = std::move(builtPlan);
544- return ACLRTC_SUCCESS;
545- } catch (const nlohmann::json::exception& exception) {
546- ASCENDLOGE(
547- "Manifest data consumed for kernel entry '%s' is incompatible with schema %s: %s; regenerate the JIT "
548- "resource with a compatible pack tool",
549- specializationRequest_.kernelName.c_str(), SUPPORTED_MANIFEST_SCHEMA_VERSION, exception.what());
550- return ACLRTC_ERROR_FAILURE;
551 }294 }
295+ KernelCompilationPlan plan;
296+ for (const ManifestCommand& spec : borrowedManifest_.commands) {
297+ CompilationCommand command;
298+ result = BindManifestCommand(spec, command);
299+ if (result != ACLRTC_SUCCESS) {
300+ return result;
301+ }
302+ plan.compilationCommands.emplace_back(std::move(command));
303+ }
304+ result = BindLinkCommand(borrowedManifest_, plan);
305+ if (result != ACLRTC_SUCCESS) {
306+ return result;
307+ }
308+ result = BuildConstantSourcePatches(plan);
309+ if (result != ACLRTC_SUCCESS) {
310+ return result;
311+ }
312+ compilationPlan = std::move(plan);
313+ return ACLRTC_SUCCESS;
552}314}
553 315 
554} // namespace aclrtc316} // namespace aclrtc
@@ -11,10 +11,9 @@
11#ifndef ASCENDC_ACLRTC_KERNEL_COMPILATION_PLAN_BUILDER_H11#ifndef ASCENDC_ACLRTC_KERNEL_COMPILATION_PLAN_BUILDER_H
12#define ASCENDC_ACLRTC_KERNEL_COMPILATION_PLAN_BUILDER_H12#define ASCENDC_ACLRTC_KERNEL_COMPILATION_PLAN_BUILDER_H
13 13 
14-#include "kernel_specialization_types.h"14+#include "compilation_manifest.h"
15 15 
16#include <boost/filesystem/path.hpp>16#include <boost/filesystem/path.hpp>
17-#include <nlohmann/json.hpp>
18 17 
19namespace ascendc {18namespace ascendc {
20namespace aclrtc {19namespace aclrtc {
@@ -22,16 +21,24 @@ namespace aclrtc {
22class KernelCompilationPlanBuilder final {21class KernelCompilationPlanBuilder final {
23public:22public:
24 KernelCompilationPlanBuilder(23 KernelCompilationPlanBuilder(
25- const NormalizedKernelSpecializationRequest& specializationRequest, const nlohmann::json& resourceManifest,24+ const NormalizedKernelSpecializationRequest& specializationRequest, const CompilationManifest& manifest,
26 boost::filesystem::path resourceWorktreePath, boost::filesystem::path externalSourceDirectoryPath);25 boost::filesystem::path resourceWorktreePath, boost::filesystem::path externalSourceDirectoryPath);
27 26 
28 aclError BuildCompilationPlan(KernelCompilationPlan& compilationPlan) const;27 aclError BuildCompilationPlan(KernelCompilationPlan& compilationPlan) const;
29 28 
30private:29private:
30+ aclError CheckResourceWorktreeDirectory() const;
31+ bool ExpandPathAndEnvironmentReferences(
32+ const std::string& text, const std::string& location, std::string& resolvedText) const;
33+ aclError BuildConstantSourcePatches(KernelCompilationPlan& plan) const;
34+ aclError BindManifestCommand(const ManifestCommand& spec, CompilationCommand& command) const;
35+ aclError BindLinkCommand(const CompilationManifest& manifest, KernelCompilationPlan& plan) const;
36+ 
31 const NormalizedKernelSpecializationRequest& specializationRequest_;37 const NormalizedKernelSpecializationRequest& specializationRequest_;
32- const nlohmann::json& resourceManifest_;38+ const CompilationManifest& borrowedManifest_;
33 boost::filesystem::path resourceWorktreePath_;39 boost::filesystem::path resourceWorktreePath_;
34 boost::filesystem::path externalSourceDirectoryPath_;40 boost::filesystem::path externalSourceDirectoryPath_;
41+ boost::filesystem::path outputDirectoryPath_;
35};42};
36 43 
37} // namespace aclrtc44} // namespace aclrtc
@@ -12,6 +12,7 @@
12 12 
13#include "compilation_plan_executor.h"13#include "compilation_plan_executor.h"
14#include "kernel_compilation_plan_builder.h"14#include "kernel_compilation_plan_builder.h"
15+#include "compilation_manifest_parser.h"
15#include "kernel_compilation_workspace.h"16#include "kernel_compilation_workspace.h"
16#include "kernel_specialization_diagnostics.h"17#include "kernel_specialization_diagnostics.h"
17#include "ascendc_tool_log.h"18#include "ascendc_tool_log.h"
@@ -203,12 +204,18 @@ aclError KernelSpecializationSession::RunSpecializationWithMaterializedResource(
203 specializationRequest.specializationSessionId);204 specializationRequest.specializationSessionId);
204 diagnostics.WriteManifestSnapshot(compilationResource.manifest);205 diagnostics.WriteManifestSnapshot(compilationResource.manifest);
205 206 
206- KernelCompilationPlan compilationPlan;207+ CompilationManifest manifest;
207 aclError specializationStatus =208 aclError specializationStatus =
208- KernelCompilationPlanBuilder(209+ CompilationManifestParser(compilationResource.manifest)
209- specializationRequest, compilationResource.manifest, compilationWorkspace.GetWorktreePath(),210+ .ParseSelected(specializationRequest.kernelName, specializationRequest.enableSuperKernel, manifest);
210- compilationResource.externalSourceDirectoryPath)211+ if (specializationStatus != ACLRTC_SUCCESS) {
211- .BuildCompilationPlan(compilationPlan);212+ return ReportSpecializationStatus(specializationRequest, diagnostics, specializationStatus);
213+ }
214+ KernelCompilationPlan compilationPlan;
215+ specializationStatus = KernelCompilationPlanBuilder(
216+ specializationRequest, manifest, compilationWorkspace.GetWorktreePath(),
217+ compilationResource.externalSourceDirectoryPath)
218+ .BuildCompilationPlan(compilationPlan);
212 if (specializationStatus != ACLRTC_SUCCESS) {219 if (specializationStatus != ACLRTC_SUCCESS) {
213 return ReportSpecializationStatus(specializationRequest, diagnostics, specializationStatus);220 return ReportSpecializationStatus(specializationRequest, diagnostics, specializationStatus);
214 }221 }
@@ -148,7 +148,7 @@ void KernelSpecializationDiagnostics::AppendCommandToReplayScript(const Compilat
148 }148 }
149 try {149 try {
150 std::string replayLine = QuoteArgumentForReplayScript(compilationCommand.executablePath.string());150 std::string replayLine = QuoteArgumentForReplayScript(compilationCommand.executablePath.string());
151- for (const std::string& argument : compilationCommand.commandArguments) {151+ for (const std::string& argument : compilationCommand.arguments) {
152 replayLine += " " + QuoteArgumentForReplayScript(argument);152 replayLine += " " + QuoteArgumentForReplayScript(argument);
153 }153 }
154 replayLine += '\n';154 replayLine += '\n';
@@ -198,7 +198,7 @@ aclError NormalizeSuperKernelCompilerOptions(
198 return ACLRTC_SUCCESS;198 return ACLRTC_SUCCESS;
199 }199 }
200 200 
201- normalizedRequest.compilationVariant = KernelCompilationVariant::BasicWithSuperKernel;201+ normalizedRequest.enableSuperKernel = true;
202 for (size_t optionIndex = 0U; optionIndex < copiedSuperKernelOptions.size(); ++optionIndex) {202 for (size_t optionIndex = 0U; optionIndex < copiedSuperKernelOptions.size(); ++optionIndex) {
203 std::string& superKernelOption = copiedSuperKernelOptions[optionIndex];203 std::string& superKernelOption = copiedSuperKernelOptions[optionIndex];
204 if (superKernelOption == SUPER_KERNEL_ENABLE_OPTION) {204 if (superKernelOption == SUPER_KERNEL_ENABLE_OPTION) {
@@ -30,11 +30,6 @@ constexpr aclError ACLRTC_ERROR_LINKING = 176004;
30constexpr aclError ACLRTC_ERROR_OUT_OF_MEMORY = 276001;30constexpr aclError ACLRTC_ERROR_OUT_OF_MEMORY = 276001;
31constexpr aclError ACLRTC_ERROR_FAILURE = 576000;31constexpr aclError ACLRTC_ERROR_FAILURE = 576000;
32 32 
33-enum class KernelCompilationVariant : uint32_t {
34- Basic,
35- BasicWithSuperKernel,
36-};
37- 
38enum class CompilationCommandKind : uint32_t {33enum class CompilationCommandKind : uint32_t {
39 Compile,34 Compile,
40 ObjectCopy,35 ObjectCopy,
@@ -51,7 +46,7 @@ struct NormalizedKernelSpecializationRequest {
51 std::string resourceId;46 std::string resourceId;
52 std::string kernelName;47 std::string kernelName;
53 boost::filesystem::path outputElfPath;48 boost::filesystem::path outputElfPath;
54- KernelCompilationVariant compilationVariant{KernelCompilationVariant::Basic};49+ bool enableSuperKernel{false};
55 KernelCompilerOptions compilerOptions;50 KernelCompilerOptions compilerOptions;
56 uint64_t kernelArgumentCount{0};51 uint64_t kernelArgumentCount{0};
57 const void* const* borrowedKernelArgumentDataPointers{nullptr};52 const void* const* borrowedKernelArgumentDataPointers{nullptr};
@@ -69,7 +64,7 @@ struct CompilationCommand {
69 std::optional<uint32_t> parallelStage;64 std::optional<uint32_t> parallelStage;
70 std::string diagnosticLabel;65 std::string diagnosticLabel;
71 boost::filesystem::path executablePath;66 boost::filesystem::path executablePath;
72- std::vector<std::string> commandArguments;67+ std::vector<std::string> arguments;
73};68};
74 69 
75struct KernelCompilationPlan {70struct KernelCompilationPlan {
@@ -39,6 +39,7 @@ add_executable(asc_compile_exporter
39 manifest_bundle_compiler.cpp39 manifest_bundle_compiler.cpp
40 resource_manifest_validator.cpp40 resource_manifest_validator.cpp
41 ../common/file_utils.cpp41 ../common/file_utils.cpp
42+ ../common/manifest_constant.cpp
42 ../common/process_executor.cpp43 ../common/process_executor.cpp
43 ../common/directory_cleanup_guard.cpp44 ../common/directory_cleanup_guard.cpp
44)45)
@@ -18,6 +18,7 @@
18 18 
19#include "ascendc_tool_log.h"19#include "ascendc_tool_log.h"
20#include "file_utils.h"20#include "file_utils.h"
21+#include "manifest_constant.h"
21#include "nlohmann/json.hpp"22#include "nlohmann/json.hpp"
22 23 
23namespace ascendc {24namespace ascendc {
@@ -313,49 +314,19 @@ bool ResourceManifestValidator::ValidateOptionArray(const std::string& name)
313 314 
314bool ResourceManifestValidator::ValidateConstant(const Json& constant, std::set<std::string>& constantNames)315bool ResourceManifestValidator::ValidateConstant(const Json& constant, std::set<std::string>& constantNames)
315{316{
316- if (!CheckAndLog(constant.is_object(), __LINE__, "invalid constant: expected an object") ||317+ ManifestConstant parsed;
317- !CheckAndLog(constant.contains("name"), __LINE__, "missing required constant field: name") ||318+ if (!parsed.ParseDefinition(constant)) {
318- !CheckAndLog(
319- constant.contains("parameter_index"), __LINE__, "missing required constant field: parameter_index") ||
320- !CheckAndLog(constant.contains("byte_size"), __LINE__, "missing required constant field: byte_size") ||
321- !CheckAndLog(constant.contains("file"), __LINE__, "missing required constant field: file") ||
322- !CheckAndLog(constant.contains("template"), __LINE__, "missing required constant field: template") ||
323- !CheckAndLog(constant.size() == 5U, __LINE__, "invalid constant: expected exactly five fields") ||
324- !CheckAndLog(constant.at("name").is_string(), __LINE__, "invalid constant name: expected a string") ||
325- !CheckAndLog(
326- !constant.at("name").get_ref<const std::string&>().empty(), __LINE__,
327- "invalid constant name: expected a nonempty string") ||
328- !CheckAndLog(
329- constant.at("parameter_index").is_number_unsigned(), __LINE__,
330- "invalid parameter_index: expected an unsigned integer") ||
331- !CheckAndLog(
332- constant.at("byte_size").is_number_unsigned(), __LINE__,
333- "invalid byte_size: expected an unsigned integer") ||
334- !CheckAndLog(
335- constant.at("byte_size").get<Json::number_unsigned_t>() != 0U, __LINE__,
336- "invalid byte_size: expected a nonzero value") ||
337- !CheckAndLog(constant.at("file").is_string(), __LINE__, "invalid constant file: expected a string") ||
338- !CheckAndLog(constant.at("template").is_string(), __LINE__, "invalid constant template: expected a string") ||
339- !CheckAndLog(
340- !constant.at("template").get_ref<const std::string&>().empty(), __LINE__,
341- "invalid constant template: expected a nonempty string")) {
342 return false;319 return false;
343 }320 }
344- 
345- const std::string name = constant.at("name").get_ref<const std::string&>();
346- const std::string file = constant.at("file").get_ref<const std::string&>();
347 if (!CheckAndLog(321 if (!CheckAndLog(
348- file.rfind(std::string(RESOURCE_ROOT_MARKER) + "/", 0U) == 0U, __LINE__,322+ parsed.GetTargetFile().rfind(std::string(RESOURCE_ROOT_MARKER) + "/", 0U) == 0U, __LINE__,
349 "invalid constant file: expected ${resource}/<relative-path>") ||323 "invalid constant file: expected ${resource}/<relative-path>") ||
350- !ValidateResourceReference(file) ||324+ !ValidateResourceReference(parsed.GetTargetFile()) ||
351- !CheckAndLog(constantNames.insert(name).second, __LINE__, "duplicate constant name: name=" + name)) {325+ !CheckAndLog(
326+ constantNames.insert(parsed.GetName()).second, __LINE__,
327+ "duplicate constant name: name=" + parsed.GetName())) {
352 return false;328 return false;
353 }329 }
354- 
355- ASCENDLOGD(
356- "Validated constant: name=%s parameter_index=%llu byte_size=%llu", name.c_str(),
357- static_cast<unsigned long long>(constant.at("parameter_index").get<Json::number_unsigned_t>()),
358- static_cast<unsigned long long>(constant.at("byte_size").get<Json::number_unsigned_t>()));
359 return true;330 return true;
360}331}
361 332 
@@ -736,6 +736,7 @@ class ManifestPackageWriter:
736 {736 {
737 "name": constant_info.name,737 "name": constant_info.name,
738 "parameter_index": constant_info.parameter_index,738 "parameter_index": constant_info.parameter_index,
739+ "arg_type": "pointer",
739 "byte_size": constant_info.byte_size,740 "byte_size": constant_info.byte_size,
740 "file": _resource_placeholder(741 "file": _resource_placeholder(
741 self._resource_path,742 self._resource_path,
@@ -731,6 +731,7 @@ class ManifestPackageWriter:
731 {731 {
732 "name": constant_info.name,732 "name": constant_info.name,
733 "parameter_index": constant_info.parameter_index,733 "parameter_index": constant_info.parameter_index,
734+ "arg_type": "pointer",
734 "byte_size": constant_info.byte_size,735 "byte_size": constant_info.byte_size,
735 "file": _resource_placeholder(736 "file": _resource_placeholder(
736 self._resource_path,737 self._resource_path,
@@ -0,0 +1,125 @@
1+/**
2+ * Copyright (c) 2026 Huawei Technologies Co., Ltd.
3+ * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
4+ * CANN Open Software License Agreement Version 2.0 (the "License").
5+ * Please refer to the License for details. You may not use this file except in compliance with the License.
6+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7+ * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
8+ * See LICENSE in the root of the software repository for the full text of the License.
9+ */
10+ 
11+#include "manifest_constant.h"
12+ 
13+#include "ascendc_tool_log.h"
14+ 
15+#include <nlohmann/json.hpp>
16+#include <utility>
17+ 
18+namespace ascendc {
19+namespace {
20+using Json = nlohmann::json;
21+ 
22+bool ReadNonnegativeInteger(const Json& value, uint64_t& result)
23+{
24+ if (!value.is_number_integer() || (!value.is_number_unsigned() && value.get<int64_t>() < 0)) {
25+ return false;
26+ }
27+ result = value.get<uint64_t>();
28+ return true;
29+}
30+} // namespace
31+ 
32+bool ManifestConstant::ParseDefinition(const Json& constant)
33+{
34+ if (!constant.is_object()) {
35+ ASCENDLOGE("constant must be an object");
36+ return false;
37+ }
38+ for (const char* field : {"name", "parameter_index", "file", "template"}) {
39+ if (!constant.contains(field)) {
40+ ASCENDLOGE("Missing required constant field: %s", field);
41+ return false;
42+ }
43+ }
44+ for (const char* field : {"name", "file", "template"}) {
45+ if (!constant.at(field).is_string() || constant.at(field).get_ref<const std::string&>().empty()) {
46+ ASCENDLOGE("Constant field must be a nonempty string: %s", field);
47+ return false;
48+ }
49+ }
50+ ManifestConstant result;
51+ if (!ReadNonnegativeInteger(constant.at("parameter_index"), result.parameterIndex_)) {
52+ ASCENDLOGE("parameter_index must be a nonnegative integer");
53+ return false;
54+ }
55+ const bool hasArgumentType = constant.contains("arg_type");
56+ if (hasArgumentType && !constant.at("arg_type").is_string()) {
57+ ASCENDLOGE("arg_type must be a string");
58+ return false;
59+ }
60+ const std::string argumentType = hasArgumentType ? constant.at("arg_type").get<std::string>() : "struct";
61+ const bool hasByteSize = constant.contains("byte_size");
62+ if (argumentType == "pointer") {
63+ uint64_t byteCount = 0U;
64+ if (!hasByteSize || !ReadNonnegativeInteger(constant.at("byte_size"), byteCount) || byteCount == 0U) {
65+ ASCENDLOGE("pointer constant requires a positive integer byte_size");
66+ return false;
67+ }
68+ result.manifestByteSize_ = byteCount;
69+ } else if (argumentType == "struct") {
70+ if (hasByteSize) {
71+ ASCENDLOGE("struct constant must omit byte_size; size comes from argsBytes");
72+ return false;
73+ }
74+ } else {
75+ ASCENDLOGE("arg_type must be pointer or struct");
76+ return false;
77+ }
78+ constexpr size_t requiredFieldCount = 4U;
79+ const size_t expectedFieldCount = requiredFieldCount + (hasArgumentType ? 1U : 0U) + (hasByteSize ? 1U : 0U);
80+ if (constant.size() != expectedFieldCount) {
81+ ASCENDLOGE("constant contains unexpected fields");
82+ return false;
83+ }
84+ result.name_ = constant.at("name").get<std::string>();
85+ result.targetFile_ = constant.at("file").get<std::string>();
86+ result.templateText_ = constant.at("template").get<std::string>();
87+ result.definitionParsed_ = true;
88+ *this = std::move(result);
89+ return true;
90+}
91+ 
92+bool ManifestConstant::BindArgument(uint64_t argsCount, const void* const* argsAddr, const uint64_t* argsBytes)
93+{
94+ if (!definitionParsed_) {
95+ ASCENDLOGE("Constant definition must be parsed before binding an argument");
96+ return false;
97+ }
98+ if (parameterIndex_ >= argsCount) {
99+ ASCENDLOGE(
100+ "Constant %s parameter_index %llu is outside argsCount %llu", name_.c_str(),
101+ static_cast<unsigned long long>(parameterIndex_), static_cast<unsigned long long>(argsCount));
102+ return false;
103+ }
104+ if (argsAddr == nullptr || argsAddr[parameterIndex_] == nullptr) {
105+ ASCENDLOGE(
106+ "Constant %s requires a nonnull argsAddr[%llu]", name_.c_str(),
107+ static_cast<unsigned long long>(parameterIndex_));
108+ return false;
109+ }
110+ uint64_t byteSize = manifestByteSize_;
111+ if (byteSize == 0U) {
112+ if (argsBytes == nullptr || argsBytes[parameterIndex_] == 0U) {
113+ ASCENDLOGE(
114+ "Constant %s requires nonzero argsBytes[%llu]", name_.c_str(),
115+ static_cast<unsigned long long>(parameterIndex_));
116+ return false;
117+ }
118+ byteSize = argsBytes[parameterIndex_];
119+ }
120+ borrowedData_ = argsAddr[parameterIndex_];
121+ boundByteSize_ = byteSize;
122+ return true;
123+}
124+ 
125+} // namespace ascendc
@@ -0,0 +1,46 @@
1+/**
2+ * Copyright (c) 2026 Huawei Technologies Co., Ltd.
3+ * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
4+ * CANN Open Software License Agreement Version 2.0 (the "License").
5+ * Please refer to the License for details. You may not use this file except in compliance with the License.
6+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7+ * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
8+ * See LICENSE in the root of the software repository for the full text of the License.
9+ */
10+ 
11+#ifndef ASCENDC_COMMON_MANIFEST_CONSTANT_H
12+#define ASCENDC_COMMON_MANIFEST_CONSTANT_H
13+ 
14+#include <cstdint>
15+#include <string>
16+#include <nlohmann/json_fwd.hpp>
17+ 
18+namespace ascendc {
19+ 
20+class ManifestConstant final {
21+public:
22+ bool ParseDefinition(const nlohmann::json& constantJson);
23+ bool BindArgument(uint64_t argsCount, const void* const* argsAddr, const uint64_t* argsBytes);
24+ 
25+ const std::string& GetName() const { return name_; }
26+ uint64_t GetParameterIndex() const { return parameterIndex_; }
27+ const std::string& GetTargetFile() const { return targetFile_; }
28+ const std::string& GetTemplateText() const { return templateText_; }
29+ const void* GetBoundData() const { return borrowedData_; }
30+ uint64_t GetBoundByteSize() const { return boundByteSize_; }
31+ 
32+private:
33+ bool definitionParsed_{false};
34+ std::string name_;
35+ uint64_t parameterIndex_{0U};
36+ // Zero means the byte size must be obtained from the bound argument.
37+ uint64_t manifestByteSize_{0U};
38+ std::string targetFile_;
39+ std::string templateText_;
40+ const void* borrowedData_{nullptr};
41+ uint64_t boundByteSize_{0U};
42+};
43+ 
44+} // namespace ascendc
45+ 
46+#endif // ASCENDC_COMMON_MANIFEST_CONSTANT_H