From 7a8951e2f0d35cbe76d12c5a9d74287a2258cd3b Mon Sep 17 00:00:00 2001 From: David Salinas Date: Wed, 10 Aug 2022 19:07:04 +0000 Subject: [PATCH 1/3] Respect --rocm-path option over ROCM_PATH environment variable --- amd/hipcc/src/hipBin_amd.h | 106 +++++++++++++++++++----------------- amd/hipcc/src/hipBin_base.h | 30 ++++++---- 2 files changed, 76 insertions(+), 60 deletions(-) diff --git a/amd/hipcc/src/hipBin_amd.h b/amd/hipcc/src/hipBin_amd.h index 4821bb203133ed..3dfa78b677b9c2 100644 --- a/amd/hipcc/src/hipBin_amd.h +++ b/amd/hipcc/src/hipBin_amd.h @@ -84,9 +84,6 @@ HipBinAmd::HipBinAmd() { platformInfo.runtime = rocclr; platformInfo.compiler = clang; platformInfoAMD_ = platformInfo; - constructRocclrHomePath(); // constructs RocclrHomePath - constructHsaPath(); // constructs hsa path - constructCompilerPath(); } // returns the Rocclr Home path @@ -240,9 +237,6 @@ void HipBinAmd::constructCompilerPath() { hipClangPath_ = complierPath; } - - - // returns clang path. const string& HipBinAmd::getCompilerPath() const { return hipClangPath_; @@ -387,8 +381,6 @@ bool HipBinAmd::detectPlatform() { return detected; } - - string HipBinAmd::getHipLibPath() const { string hipLibPath; const EnvVariables& env = getEnvVariables(); @@ -536,47 +528,10 @@ void HipBinAmd::executeHipCCCmd(vector argv) { } string HIPLDARCHFLAGS; - - initializeHipCXXFlags(); - initializeHipCFlags(); - initializeHipLdFlags(); string HIPCXXFLAGS, HIPCFLAGS, HIPLDFLAGS; - HIPCFLAGS = getHipCFlags(); - HIPCXXFLAGS = getHipCXXFlags(); - HIPLDFLAGS = getHipLdFlags(); - string hipLibPath; - string hipIncludePath, deviceLibPath; - hipLibPath = getHipLibPath(); - const string& roccmPath = getRoccmPath(); - const string& hipPath = getHipPath(); - const PlatformInfo& platformInfo = getPlatformInfo(); - const string& rocclrHomePath = getRocclrHomePath(); - const string& hipClangPath = getCompilerPath(); - hipIncludePath = getHipInclude(); - deviceLibPath = getDeviceLibPath(); - const string& hipVersion = getHipVersion(); - if (verbose & 0x2) { - cout << "HIP_PATH=" << hipPath << endl; - cout << "HIP_PLATFORM=" << PlatformTypeStr(platformInfo.platform) < argv) { setStdLib = 1; } + // Process --rocm-path option + const string& rocmPathOption = "--rocm-path="; + if (arg.compare(0,rocmPathOption.length(),rocmPathOption) == 0) + rocm_pathOption_ = arg.substr(rocmPathOption.length()); + // Check target selection option: --offload-arch= and --amdgpu-target=... for (unsigned int i = 0; i argv) { if (!swallowArg) toolArgs += " " + arg; prevArg = arg; - } // end of for loop - // No AMDGPU target specified at commandline. So look for HCC_AMDGPU_TARGET + } // end of ARGV Processing Loop + + // now construct Paths ... + constructRoccmPath(); // constructs Roccm Path + constructHipPath(); // constructs HIP Path + readHipVersion(); // stores the hip version + constructCompilerPath(); + constructRocclrHomePath(); + constructHsaPath(); + + initializeHipCXXFlags(); + initializeHipCFlags(); + initializeHipLdFlags(); + HIPCFLAGS = getHipCFlags(); + HIPCXXFLAGS = getHipCXXFlags(); + HIPLDFLAGS = getHipLdFlags(); + + string hipLibPath; + string hipIncludePath, deviceLibPath; + hipLibPath = getHipLibPath(); + const string& roccmPath = getRoccmPath(); + const string& hipPath = getHipPath(); + const PlatformInfo& platformInfo = getPlatformInfo(); + const string& rocclrHomePath = getRocclrHomePath(); + const string& hipClangPath = getCompilerPath(); + hipIncludePath = getHipInclude(); + deviceLibPath = getDeviceLibPath(); + const string& hipVersion = getHipVersion(); + if (verbose & 0x2) { + cout << "HIP_PATH=" << hipPath << endl; + cout << "HIP_PLATFORM=" << PlatformTypeStr(platformInfo.platform) <getInstance(); readOSInfo(); // detects if windows or linux - readEnvVariables(); // reads the envirnoment variables - constructHipPath(); // constructs HIP Path - constructRoccmPath(); // constructs Roccm Path - readHipVersion(); // stores the hip version + readEnvVariables(); // reads the environment variables } // detects the OS information @@ -330,7 +330,13 @@ void HipBinBase::constructHipPath() { // constructs the ROCM path void HipBinBase::constructRoccmPath() { - if (envVariables_.roccmPathEnv_.empty()) { + // we need to use --rocm-path option + string rocm_path_name = getrocm_pathOption(); + + // chose the --rocm-path option first, if specified. + if (!rocm_path_name.empty()) + variables_.roccmPathEnv_ = rocm_path_name; + else if (envVariables_.roccmPathEnv_.empty()) { const string& hipPath = getHipPath(); fs::path roccm_path(hipPath); roccm_path = roccm_path.parent_path(); @@ -339,7 +345,6 @@ void HipBinBase::constructRoccmPath() { if (!fs::exists(rocm_agent_enumerator_file)) { roccm_path = "/opt/rocm"; } - variables_.roccmPathEnv_ = roccm_path.string(); } else { variables_.roccmPathEnv_ = envVariables_.roccmPathEnv_;} } @@ -520,5 +525,8 @@ HipBinCommand HipBinBase::gethipconfigCmd(string argument) { return full; // default is full. return full if no commands are matched } +const string& HipBinBase::getrocm_pathOption() const { + return rocm_pathOption_; +} #endif // SRC_HIPBIN_BASE_H_ From ed44d8b991a37833afff3f358e37e21186fa3158 Mon Sep 17 00:00:00 2001 From: Siu Chi Chan Date: Mon, 7 Nov 2022 16:16:42 -0500 Subject: [PATCH 2/3] Write errors/warnings to std::err --- amd/hipcc/src/hipBin.cpp | 5 +++-- amd/hipcc/src/hipBin_amd.h | 33 +++++++++++++++++---------------- amd/hipcc/src/hipBin_base.h | 1 + amd/hipcc/src/hipBin_nvidia.h | 5 +++-- amd/hipcc/src/hipBin_util.h | 8 ++++---- 5 files changed, 28 insertions(+), 24 deletions(-) diff --git a/amd/hipcc/src/hipBin.cpp b/amd/hipcc/src/hipBin.cpp index dfbc35068fa276..3136fd3bf8be73 100644 --- a/amd/hipcc/src/hipBin.cpp +++ b/amd/hipcc/src/hipBin.cpp @@ -23,6 +23,7 @@ THE SOFTWARE. #include "hipBin_util.h" #include "hipBin_amd.h" #include "hipBin_nvidia.h" +#include #include #include @@ -75,7 +76,7 @@ HipBin::HipBin() { } // if no device is detected, then it is defaulted to AMD if (!platformDetected) { - cout << "Device not supported - Defaulting to AMD" << endl; + std::cerr << "Device not supported - Defaulting to AMD" << endl; // populates the struct with AMD info const PlatformInfo& platformInfo = hipBinAMDPtr_->getPlatformInfo(); platformVec_.push_back(platformInfo); @@ -109,7 +110,7 @@ void HipBin::executeHipBin(string filename, int argc, char* argv[]) { } else if (hipBinUtilPtr_->substringPresent(filename, "hipcc")) { executeHipCC(argc, argv); } else { - cout << "Command " << filename + std::cerr << "Command " << filename << " not supported. Name the exe as hipconfig" << " or hipcc and then try again ..." << endl; exit(-1); diff --git a/amd/hipcc/src/hipBin_amd.h b/amd/hipcc/src/hipBin_amd.h index 4821bb203133ed..833ebd454de795 100644 --- a/amd/hipcc/src/hipBin_amd.h +++ b/amd/hipcc/src/hipBin_amd.h @@ -25,6 +25,7 @@ THE SOFTWARE. #include "hipBin_base.h" #include "hipBin_util.h" +#include #include #include #include @@ -296,7 +297,7 @@ string HipBinAmd::getCompilerVersion() { } } } else { - cout << "Hip Clang Compiler not found" << endl; + std::cerr << "Hip Clang Compiler not found" << endl; } return complierVersion; } @@ -379,7 +380,7 @@ bool HipBinAmd::detectPlatform() { var.hipPlatformEnv_ == "hcc") { detected = true; if (var.hipPlatformEnv_ == "hcc") - cout << + std::cerr << "Warning: HIP_PLATFORM=hcc is deprecated."<< "Please use HIP_PLATFORM=amd." << endl; } @@ -425,7 +426,7 @@ void HipBinAmd::checkHipconfig() { cout << endl << "Check system installation: " << endl; cout << "check hipconfig in PATH..." << endl; if (system("which hipconfig > /dev/null 2>&1") != 0) { - cout << "FAIL " << endl; + std::cerr << "FAIL " << endl; } else { cout << "good" << endl; } @@ -436,7 +437,7 @@ void HipBinAmd::checkHipconfig() { cout << "check LD_LIBRARY_PATH (" << ldLibraryPath << ") contains HSA_PATH (" << hsaPath << ")..." << endl; if (ldLibraryPath.find(hsaPath) == string::npos) { - cout << "FAIL" << endl; + std::cerr << "FAIL" << endl; } else { cout << "good" << endl; } @@ -619,8 +620,8 @@ void HipBinAmd::executeHipCCCmd(vector argv) { string pattern = "^" + targetOpt + ".*"; if (hipBinUtilPtr_->stringRegexMatch(arg, pattern)) { if (targetOpt == "--amdgpu-target=") { - cout << "Warning: The --amdgpu-target option has been deprecated and will be removed in the future." - << " Use --offload-arch instead.\n"; + std::cerr << "Warning: The --amdgpu-target option has been deprecated and will be removed in the future." + << " Use --offload-arch instead.\n"; } // If targets string is not empty, // add a comma before adding new target option value. @@ -669,8 +670,8 @@ void HipBinAmd::executeHipCCCmd(vector argv) { } if (hipBinUtilPtr_->substringPresent( arg, "--amdhsa-code-object-version=")) { - cout << "Warning: The --amdhsa-code-object-version option has been deprecated and will be removed in the future." - << " Use -mllvm -mcode-object-version instead.\n"; + std::cerr << "Warning: The --amdhsa-code-object-version option has been deprecated and will be removed in the future." + << " Use -mllvm -mcode-object-version instead.\n"; arg = hipBinUtilPtr_->replaceStr( arg, "--amdhsa-code-object-version=", ""); hsacoVersion = arg; @@ -689,7 +690,7 @@ void HipBinAmd::executeHipCCCmd(vector argv) { string file = split_arg.at(1); ifstream in(file); if (!in.is_open()) { - cout << "unable to open file for reading: " << file << endl; + std::cerr << "unable to open file for reading: " << file << endl; exit(-1); } string new_arg; @@ -698,7 +699,7 @@ void HipBinAmd::executeHipCCCmd(vector argv) { new_file /= "response_file"; ofstream out(new_file); if (!out.is_open()) { - cout << "unable to open file for writing: " << + std::cerr << "unable to open file for writing: " << new_file.string() << endl; exit(-1); } @@ -884,10 +885,10 @@ void HipBinAmd::executeHipCCCmd(vector argv) { if (hipBinUtilPtr_->stringRegexMatch(arg, "^--hipcc.*")) { swallowArg = 1; if (arg == "--hipcc-func-supp") { - cout << "Warning: The --hipcc-func-supp option has been deprecated and will be removed in the future.\n"; + std::cerr << "Warning: The --hipcc-func-supp option has been deprecated and will be removed in the future.\n"; funcSupp = 1; } else if (arg == "--hipcc-no-func-supp") { - cout << "Warning: The --hipcc-no-func-supp option has been deprecated and will be removed in the future.\n"; + std::cerr << "Warning: The --hipcc-no-func-supp option has been deprecated and will be removed in the future.\n"; funcSupp = 0; } } else { @@ -981,7 +982,7 @@ void HipBinAmd::executeHipCCCmd(vector argv) { // does not check if the device supports the feature or not // e.g. vega10 does not support sramecc if (knownFeatures.find(procAndFeatures.at(i)) == knownFeatures.end()) { - cout << "Warning: The Feature: "<< procAndFeatures.at(i) << + std::cerr << "Warning: The Feature: "<< procAndFeatures.at(i) << " is unknown. Correct compilation is not guaranteed.\n"; } } @@ -1006,8 +1007,8 @@ void HipBinAmd::executeHipCCCmd(vector argv) { // rocm_agent_enumerator failed! Throw an error and die if linking is required if (default_amdgpu_target == 1 && compileOnly == 0) { // TODO(agunashe) exit from function - cout << "No valid AMD GPU target was either specified or found." - << "Please specify a valid target using --offload-arch=.\n"; + std::cerr << "No valid AMD GPU target was either specified or found." + << "Please specify a valid target using --offload-arch=.\n"; } HCC_EXTRA_LIBRARIES ="\n"; // TODO(agunashe) write to env @@ -1119,7 +1120,7 @@ void HipBinAmd::executeHipCCCmd(vector argv) { string cmdOut = sysOut.out; int CMD_EXIT_CODE = sysOut.exitCode; if (CMD_EXIT_CODE !=0) { - cout << "failed to execute:" << CMD << std::endl; + std::cerr << "failed to execute:" << CMD << std::endl; } exit(CMD_EXIT_CODE); } // end of runCmd section diff --git a/amd/hipcc/src/hipBin_base.h b/amd/hipcc/src/hipBin_base.h index 0d2d4433bc712e..0e180290245863 100644 --- a/amd/hipcc/src/hipBin_base.h +++ b/amd/hipcc/src/hipBin_base.h @@ -24,6 +24,7 @@ THE SOFTWARE. #include "hipBin_util.h" +#include #include #include diff --git a/amd/hipcc/src/hipBin_nvidia.h b/amd/hipcc/src/hipBin_nvidia.h index 6feb3150287019..d9a7b38a1aaf73 100644 --- a/amd/hipcc/src/hipBin_nvidia.h +++ b/amd/hipcc/src/hipBin_nvidia.h @@ -25,6 +25,7 @@ THE SOFTWARE. #include "hipBin_base.h" #include "hipBin_util.h" +#include #include #include @@ -88,7 +89,7 @@ bool HipBinNvidia::detectPlatform() { if (var.hipPlatformEnv_ == "nvidia" || var.hipPlatformEnv_ == "nvcc") { detected = true; if (var.hipPlatformEnv_ == "nvcc") - cout << "Warning: HIP_PLATFORM=nvcc is deprecated." + std::cerr << "Warning: HIP_PLATFORM=nvcc is deprecated." << "Please use HIP_PLATFORM=nvidia." << endl; } } @@ -126,7 +127,7 @@ void HipBinNvidia::checkHipconfig() { cout << endl << "Check system installation: " << endl; cout << "check hipconfig in PATH..." << endl; if (system("which hipconfig > /dev/null 2>&1") != 0) { - cout << "FAIL " << endl; + std::cerr << "FAIL " << endl; } else { cout << "good" << endl; } diff --git a/amd/hipcc/src/hipBin_util.h b/amd/hipcc/src/hipBin_util.h index cef25717d80ced..e7d607989aa0f1 100644 --- a/amd/hipcc/src/hipBin_util.h +++ b/amd/hipcc/src/hipBin_util.h @@ -213,7 +213,7 @@ string HipBinUtil::getSelfPath() const { fs::path exePath(path); path = exePath.parent_path().string(); } else { - cout << "readlink: Error reading the exe path" << endl; + std::cerr << "readlink: Error reading the exe path" << endl; perror("readlink"); exit(-1); } @@ -297,10 +297,10 @@ void HipBinUtil::deleteTempFiles() { for (unsigned int i = 0; i < tmpFiles_.size(); i++) { try { if (!fs::remove(tmpFiles_.at(i))) - cout << "Error deleting temp name: "<< tmpFiles_.at(i) < Date: Tue, 29 Nov 2022 18:04:16 +0000 Subject: [PATCH 3/3] SWDEV-362823 - remove code to extract hip-clang bundles from .a files --- amd/hipcc/src/hipBin_amd.h | 179 +------------------------------------ 1 file changed, 1 insertion(+), 178 deletions(-) diff --git a/amd/hipcc/src/hipBin_amd.h b/amd/hipcc/src/hipBin_amd.h index 236a1528c56145..6c906aa041c816 100644 --- a/amd/hipcc/src/hipBin_amd.h +++ b/amd/hipcc/src/hipBin_amd.h @@ -638,184 +638,7 @@ void HipBinAmd::executeHipCCCmd(vector argv) { swallowArg = 1; } - // process linker response file for hip-clang - // extract object files from static library and pass them directly to - // hip-clang in command line. - // TODO(hipcc): Remove this after hip-clang switch to lto and lld is able to - // handle clang-offload-bundler bundles. - if ((hipBinUtilPtr_->stringRegexMatch(arg, "^-Wl,@.*")) || - (hipBinUtilPtr_->stringRegexMatch(arg, "^@.*"))) { - // arg will have options type(-Wl,@ or @) and filename - vector split_arg = hipBinUtilPtr_->splitStr(targetsStr, '@'); - string file = split_arg.at(1); - ifstream in(file); - if (!in.is_open()) { - std::cerr << "unable to open file for reading: " << file << endl; - exit(-1); - } - string new_arg; - string tmpdir = hipBinUtilPtr_->getTempDir(); - fs::path new_file = tmpdir; - new_file /= "response_file"; - ofstream out(new_file); - if (!out.is_open()) { - std::cerr << "unable to open file for writing: " << - new_file.string() << endl; - exit(-1); - } - string line; - while (getline(in, line)) { - line = hipBinUtilPtr_->trim(line); - if ((hipBinUtilPtr_->stringRegexMatch(line, ".*\\.a$")) || - (hipBinUtilPtr_->stringRegexMatch(line, ".*\\.lo$"))) { - //## process static library for hip-clang - //## extract object files from static library and - //## pass them directly to hip-clang. - //## ToDo: Remove this after hip-clang switch to lto and - //## lld is able to handle clang-offload-bundler bundles. - string libFile = line; - string path = fs::absolute(line).string(); - // Check if all files in .a are object files. - string cmd = "cd "+ tmpdir + "; ar xv " + path; - SystemCmdOut sysOut; - sysOut = hipBinUtilPtr_->exec(cmd.c_str()); - string cmdOut = sysOut.out; - vector objs = hipBinUtilPtr_->splitStr(cmdOut, '\n'); - bool allIsObj = 1; - string realObjs = ""; - for (unsigned int i=0; i < objs.size(); i++) { - string obj = objs.at(i); - obj = hipBinUtilPtr_->trim(obj); - regex toReplace("x - "); - obj = hipBinUtilPtr_->replaceRegex(obj, toReplace, ""); - obj = "\"" + tmpdir + "/" + obj; - cmd = "file " + obj; - SystemCmdOut sysOut; - sysOut = hipBinUtilPtr_->exec(cmd.c_str()); - string fileType = sysOut.out; - bool isObj; - (hipBinUtilPtr_->substringPresent(fileType, "ELF") || - hipBinUtilPtr_->substringPresent(fileType, "COFF")) ? - isObj = true : isObj = false; - allIsObj = allIsObj && isObj; - if (isObj) { - realObjs = realObjs + " " + obj; - } else { - inputs.push_back(obj); - new_arg = "\"" + new_arg + obj + "\""; - } - } // end of objs for loop - realObjs = hipBinUtilPtr_->trim(realObjs); - if (allIsObj) { - out << line << "\n"; - } else if (!realObjs.empty()) { - fs::path libFilefs = libFile; - string libBaseName = libFilefs.stem().string(); - string libDir = libFilefs.parent_path().string(); - string libExt = libFilefs.extension().string(); - string libBaseNameTemp = libBaseName + "XXXXXX"; - libBaseName = hipBinUtilPtr_->mktempFile(libBaseNameTemp) + libExt; - cmd = "cd " + tmpdir + "; ar rc " + libBaseName + " " +realObjs; - SystemCmdOut sysOut; - sysOut = hipBinUtilPtr_->exec(cmd.c_str()); - string cmdOut = sysOut.out; - out << tmpdir + "/"+ libBaseName + "\n"; - } - } else if (hipBinUtilPtr_->stringRegexMatch(line, ".*\\.o$")) { - string cmd = "file " + line; - SystemCmdOut sysOut; - sysOut = hipBinUtilPtr_->exec(cmd.c_str()); - string fileType = sysOut.out; - bool isObj; - (hipBinUtilPtr_->substringPresent(fileType, "ELF") || - hipBinUtilPtr_->substringPresent(fileType, "COFF")) ? - isObj = true : isObj = false; - if (isObj) { - out << line << "\n"; - } else { - inputs.push_back(line); - new_arg = "\"" + new_arg + " " + line + "\""; - } - } else { - out << line << "\n"; - } - } // end of while loop - in.close(); - out.close(); - arg = "\"" + new_arg +" " +split_arg.at(0) + "\\" + new_file.string(); - escapeArg = 0; - } else if ((hipBinUtilPtr_->stringRegexMatch(arg, ".*\\.a$")) || - (hipBinUtilPtr_->stringRegexMatch(arg, ".*\\.lo$"))) { - string new_arg = ""; - string tmpdir = hipBinUtilPtr_->getTempDir(); - string libFile = arg; - string path = fs::absolute(arg).string(); - string cmd = "cd "+ tmpdir + "; ar xv " + path; - SystemCmdOut sysOut; - sysOut = hipBinUtilPtr_->exec(cmd.c_str()); - string cmdOut = sysOut.out; - vector objs = hipBinUtilPtr_->splitStr(cmdOut, '\n'); - bool allIsObj = 1; - string realObjs = ""; - for (unsigned int i =0; i< objs.size(); i++) { - string obj = objs.at(i); - obj = hipBinUtilPtr_->trim(obj); - regex toReplace("x - "); - string replaceWith = ""; - obj = hipBinUtilPtr_->replaceRegex(obj, toReplace , replaceWith); - obj = "\"" + tmpdir + "/" + obj + "\""; - string cmd = "file " + obj; - SystemCmdOut sysOut; - sysOut = hipBinUtilPtr_->exec(cmd.c_str()); - string fileType = sysOut.out; - bool isObj; - isObj = (hipBinUtilPtr_->substringPresent(fileType, "ELF") || - hipBinUtilPtr_->substringPresent(fileType, "COFF")); - if (hipBinUtilPtr_->substringPresent(fileType, "ELF")) { - cmd = "llvm-readelf -e -W " + obj; - SystemCmdOut sysOut; - sysOut = hipBinUtilPtr_->exec(cmd.c_str()); - string sections = sysOut.out; - isObj = !(hipBinUtilPtr_->substringPresent( - sections, "__CLANG_OFFLOAD_BUNDLE__")); - } - allIsObj = (allIsObj && isObj); - if (isObj) { - realObjs = realObjs + " " + obj; - } else { - inputs.push_back(obj); - if (new_arg != "") { - new_arg += " "; - } - new_arg += "\"" + obj + "\""; - } - } // end of objs for loop - - realObjs = hipBinUtilPtr_->trim(realObjs); - if (allIsObj) { - new_arg = arg; - } else if (!realObjs.empty()) { - fs::path libFilefs = libFile; - string libBaseName = libFilefs.stem().string(); - string libDir = libFilefs.parent_path().string(); - string libExt = libFilefs.extension().string(); - string libBaseNameTemp = libBaseName + "XXXXXX"; - libBaseName = hipBinUtilPtr_->mktempFile( - libBaseNameTemp) + libExt; - string cmd = "cd " + tmpdir +"; ar rc " + - libBaseName + " " + realObjs; - SystemCmdOut sysOut; - sysOut = hipBinUtilPtr_->exec(cmd.c_str()); - string cmdOut = sysOut.out; - new_arg += "\"" + tmpdir +"/" + libBaseName + "\""; - } - arg = "\"" + new_arg + "\""; - escapeArg = 0; - if (hipBinUtilPtr_->stringRegexMatch(toolArgs, ".*-Xlinker$")) { - toolArgs = toolArgs.substr(0, -8); - toolArgs = hipBinUtilPtr_->trim(toolArgs); - } - } else if (arg == "-x") { // end of substring \.a || .lo section + if (arg == "-x") { fileTypeFlag = 1; } else if ((arg == "c" && prevArg == "-x") || (arg == "-xc")) { fileTypeFlag = 1;