clang: lib/Basic/Targets/RISCV.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

9

10

11

12

17#include "llvm/ADT/StringSwitch.h"

18#include "llvm/Support/raw_ostream.h"

19#include "llvm/TargetParser/RISCVTargetParser.h"

20#include

21

22using namespace clang;

24

26

27 static const char *const GCCRegNames[] = {

28

29 "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7",

30 "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15",

31 "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23",

32 "x24", "x25", "x26", "x27", "x28", "x29", "x30", "x31",

33

34

35 "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",

36 "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15",

37 "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",

38 "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31",

39

40

41 "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7",

42 "v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15",

43 "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23",

44 "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31",

45

46

47 "fflags", "frm", "vtype", "vl", "vxsat", "vxrm", "sf.vcix_state"

48 };

49

51}

52

55 {{"zero"}, "x0"}, {{"ra"}, "x1"}, {{"sp"}, "x2"}, {{"gp"}, "x3"},

56 {{"tp"}, "x4"}, {{"t0"}, "x5"}, {{"t1"}, "x6"}, {{"t2"}, "x7"},

57 {{"s0"}, "x8"}, {{"s1"}, "x9"}, {{"a0"}, "x10"}, {{"a1"}, "x11"},

58 {{"a2"}, "x12"}, {{"a3"}, "x13"}, {{"a4"}, "x14"}, {{"a5"}, "x15"},

59 {{"a6"}, "x16"}, {{"a7"}, "x17"}, {{"s2"}, "x18"}, {{"s3"}, "x19"},

60 {{"s4"}, "x20"}, {{"s5"}, "x21"}, {{"s6"}, "x22"}, {{"s7"}, "x23"},

61 {{"s8"}, "x24"}, {{"s9"}, "x25"}, {{"s10"}, "x26"}, {{"s11"}, "x27"},

62 {{"t3"}, "x28"}, {{"t4"}, "x29"}, {{"t5"}, "x30"}, {{"t6"}, "x31"},

63 {{"ft0"}, "f0"}, {{"ft1"}, "f1"}, {{"ft2"}, "f2"}, {{"ft3"}, "f3"},

64 {{"ft4"}, "f4"}, {{"ft5"}, "f5"}, {{"ft6"}, "f6"}, {{"ft7"}, "f7"},

65 {{"fs0"}, "f8"}, {{"fs1"}, "f9"}, {{"fa0"}, "f10"}, {{"fa1"}, "f11"},

66 {{"fa2"}, "f12"}, {{"fa3"}, "f13"}, {{"fa4"}, "f14"}, {{"fa5"}, "f15"},

67 {{"fa6"}, "f16"}, {{"fa7"}, "f17"}, {{"fs2"}, "f18"}, {{"fs3"}, "f19"},

68 {{"fs4"}, "f20"}, {{"fs5"}, "f21"}, {{"fs6"}, "f22"}, {{"fs7"}, "f23"},

69 {{"fs8"}, "f24"}, {{"fs9"}, "f25"}, {{"fs10"}, "f26"}, {{"fs11"}, "f27"},

70 {{"ft8"}, "f28"}, {{"ft9"}, "f29"}, {{"ft10"}, "f30"}, {{"ft11"}, "f31"}};

72}

73

76 switch (*Name) {

77 default:

78 return false;

79 case 'I':

80

82 return true;

83 case 'J':

84

86 return true;

87 case 'K':

88

90 return true;

91 case 'f':

92

94 return true;

95 case 'A':

96

98 return true;

99 case 's':

100 case 'S':

102 return true;

103 case 'c':

104

105 if (Name[1] == 'r' || Name[1] == 'f') {

107 Name += 1;

108 return true;

109 }

110 return false;

111 case 'R':

112

114 return true;

115 case 'v':

116

117 if (Name[1] == 'r' || Name[1] == 'd' || Name[1] == 'm') {

119 Name += 1;

120 return true;

121 }

122 return false;

123 }

124}

125

127 std::string R;

128 switch (*Constraint) {

129

130 case 'c':

131 case 'v':

132 R = std::string("^") + std::string(Constraint, 2);

133 Constraint += 1;

134 break;

135 default:

137 break;

138 }

139 return R;

140}

141

142static unsigned getVersionValue(unsigned MajorVersion, unsigned MinorVersion) {

143 return MajorVersion * 1000000 + MinorVersion * 1000;

144}

145

148 Builder.defineMacro("__riscv");

149 bool Is64Bit = getTriple().isRISCV64();

150 Builder.defineMacro("__riscv_xlen", Is64Bit ? "64" : "32");

152 unsigned FLen = ISAInfo->getFLen();

153 unsigned MinVLen = ISAInfo->getMinVLen();

154 unsigned MaxELen = ISAInfo->getMaxELen();

155 unsigned MaxELenFp = ISAInfo->getMaxELenFp();

156 if (CodeModel == "default")

157 CodeModel = "small";

158

159 if (CodeModel == "small")

160 Builder.defineMacro("__riscv_cmodel_medlow");

161 else if (CodeModel == "medium")

162 Builder.defineMacro("__riscv_cmodel_medany");

163 else if (CodeModel == "large")

164 Builder.defineMacro("__riscv_cmodel_large");

165

166 StringRef ABIName = getABI();

167 if (ABIName == "ilp32f" || ABIName == "lp64f")

168 Builder.defineMacro("__riscv_float_abi_single");

169 else if (ABIName == "ilp32d" || ABIName == "lp64d")

170 Builder.defineMacro("__riscv_float_abi_double");

171 else

172 Builder.defineMacro("__riscv_float_abi_soft");

173

174 if (ABIName == "ilp32e" || ABIName == "lp64e")

175 Builder.defineMacro("__riscv_abi_rve");

176

177 Builder.defineMacro("__riscv_arch_test");

178

179 for (auto &Extension : ISAInfo->getExtensions()) {

180 auto ExtName = Extension.first;

181 auto ExtInfo = Extension.second;

182

183 Builder.defineMacro(Twine("__riscv_", ExtName),

185 }

186

187 if (ISAInfo->hasExtension("zmmul"))

188 Builder.defineMacro("__riscv_mul");

189

190 if (ISAInfo->hasExtension("m")) {

191 Builder.defineMacro("__riscv_div");

192 Builder.defineMacro("__riscv_muldiv");

193 }

194

195 if (ISAInfo->hasExtension("a")) {

196 Builder.defineMacro("__riscv_atomic");

197 Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1");

198 Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2");

199 Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4");

200 if (Is64Bit)

201 Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8");

202 }

203

204 if (FLen) {

205 Builder.defineMacro("__riscv_flen", Twine(FLen));

206 Builder.defineMacro("__riscv_fdiv");

207 Builder.defineMacro("__riscv_fsqrt");

208 }

209

210 if (MinVLen) {

211 Builder.defineMacro("__riscv_v_min_vlen", Twine(MinVLen));

212 Builder.defineMacro("__riscv_v_elen", Twine(MaxELen));

213 Builder.defineMacro("__riscv_v_elen_fp", Twine(MaxELenFp));

214 }

215

216 if (ISAInfo->hasExtension("c"))

217 Builder.defineMacro("__riscv_compressed");

218

219 if (ISAInfo->hasExtension("zve32x"))

220 Builder.defineMacro("__riscv_vector");

221

222

223 Builder.defineMacro("__riscv_v_intrinsic", Twine(getVersionValue(1, 0)));

224

226 if (VScale && VScale->first && VScale->first == VScale->second)

227 Builder.defineMacro("__riscv_v_fixed_vlen",

228 Twine(VScale->first * llvm::RISCV::RVVBitsPerBlock));

229

230 if (FastScalarUnalignedAccess)

231 Builder.defineMacro("__riscv_misaligned_fast");

232 else

233 Builder.defineMacro("__riscv_misaligned_avoid");

234

235 if (ISAInfo->hasExtension("e")) {

236 if (Is64Bit)

237 Builder.defineMacro("__riscv_64e");

238 else

239 Builder.defineMacro("__riscv_32e");

240 }

241}

242

244#define BUILTIN(ID, TYPE, ATTRS) \

245 {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES},

246#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \

247 {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES},

248#include "clang/Basic/BuiltinsRISCVVector.def"

249#define BUILTIN(ID, TYPE, ATTRS) \

250 {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES},

251#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \

252 {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES},

253#include "clang/Basic/BuiltinsRISCV.inc"

254};

255

259}

260

262 llvm::StringMap &Features, DiagnosticsEngine &Diags, StringRef CPU,

263 const std::vectorstd::string &FeaturesVec) const {

264

265 unsigned XLen = 32;

266

268 Features["64bit"] = true;

269 XLen = 64;

270 } else {

271 Features["32bit"] = true;

272 }

273

274 std::vectorstd::string AllFeatures = FeaturesVec;

275 auto ParseResult = llvm::RISCVISAInfo::parseFeatures(XLen, FeaturesVec);

276 if (!ParseResult) {

277 std::string Buffer;

278 llvm::raw_string_ostream OutputErrMsg(Buffer);

279 handleAllErrors(ParseResult.takeError(), [&](llvm::StringError &ErrMsg) {

280 OutputErrMsg << ErrMsg.getMessage();

281 });

282 Diags.Report(diag::err_invalid_feature_combination) << OutputErrMsg.str();

283 return false;

284 }

285

286

287 llvm::append_range(AllFeatures, (*ParseResult)->toFeatures());

289}

290

291std::optional<std::pair<unsigned, unsigned>>

293

294 unsigned VScaleMin = ISAInfo->getMinVLen() / llvm::RISCV::RVVBitsPerBlock;

295

296 if (LangOpts.VScaleMin || LangOpts.VScaleMax) {

297

298 VScaleMin = std::max(VScaleMin, LangOpts.VScaleMin);

299 unsigned VScaleMax = LangOpts.VScaleMax;

300 if (VScaleMax != 0 && VScaleMax < VScaleMin)

301 VScaleMax = VScaleMin;

302 return std::pair<unsigned, unsigned>(VScaleMin ? VScaleMin : 1, VScaleMax);

303 }

304

305 if (VScaleMin > 0) {

306 unsigned VScaleMax = ISAInfo->getMaxVLen() / llvm::RISCV::RVVBitsPerBlock;

307 return std::make_pair(VScaleMin, VScaleMax);

308 }

309

310 return std::nullopt;

311}

312

313

315 bool Is64Bit = getTriple().isRISCV64();

316 auto Result = llvm::StringSwitch<std::optional>(Feature)

317 .Case("riscv", true)

318 .Case("riscv32", !Is64Bit)

319 .Case("riscv64", Is64Bit)

320 .Case("32bit", !Is64Bit)

321 .Case("64bit", Is64Bit)

322 .Case("experimental", HasExperimental)

323 .Default(std::nullopt);

326

327 return ISAInfo->hasExtension(Feature);

328}

329

330

333 unsigned XLen = getTriple().isArch64Bit() ? 64 : 32;

334 auto ParseResult = llvm::RISCVISAInfo::parseFeatures(XLen, Features);

335 if (!ParseResult) {

336 std::string Buffer;

337 llvm::raw_string_ostream OutputErrMsg(Buffer);

338 handleAllErrors(ParseResult.takeError(), [&](llvm::StringError &ErrMsg) {

339 OutputErrMsg << ErrMsg.getMessage();

340 });

341 Diags.Report(diag::err_invalid_feature_combination) << OutputErrMsg.str();

342 return false;

343 } else {

344 ISAInfo = std::move(*ParseResult);

345 }

346

347 if (ABI.empty())

348 ABI = ISAInfo->computeDefaultABI().str();

349

350 if (ISAInfo->hasExtension("zfh") || ISAInfo->hasExtension("zhinx"))

352

353 FastScalarUnalignedAccess =

354 llvm::is_contained(Features, "+unaligned-scalar-mem");

355

356 if (llvm::is_contained(Features, "+experimental"))

357 HasExperimental = true;

358

359 if (ABI == "ilp32e" && ISAInfo->hasExtension("d")) {

360 Diags.Report(diag::err_invalid_feature_combination)

361 << "ILP32E cannot be used with the D ISA extension";

362 return false;

363 }

364 return true;

365}

366

368 bool Is64Bit = getTriple().isArch64Bit();

369 return llvm::RISCV::parseCPU(Name, Is64Bit);

370}

371

374 bool Is64Bit = getTriple().isArch64Bit();

375 llvm::RISCV::fillValidCPUArchList(Values, Is64Bit);

376}

377

379 bool Is64Bit = getTriple().isArch64Bit();

380 return llvm::RISCV::parseTuneCPU(Name, Is64Bit);

381}

382

385 bool Is64Bit = getTriple().isArch64Bit();

386 llvm::RISCV::fillValidTuneCPUArchList(Values, Is64Bit);

387}

388

390 auto RII = llvm::RISCVISAInfo::parseArchString(

391 "rv64i", true);

392

393 if (llvm::errorToBool(RII.takeError()))

394 llvm_unreachable("unsupport rv64i");

395

396 std::vectorstd::string FeatStrings =

397 (*RII)->toFeatures( true);

398 Features.insert(Features.end(), FeatStrings.begin(), FeatStrings.end());

399}

400

402 std::vectorstd::string &Features) {

403 auto RII = llvm::RISCVISAInfo::parseArchString(

404 FullArchStr, true);

405 if (llvm::errorToBool(RII.takeError())) {

406

407 Features.push_back(FullArchStr.str());

408 } else {

409

410

412 std::vectorstd::string FeatStrings =

413 (*RII)->toFeatures( true);

414 Features.insert(Features.end(), FeatStrings.begin(), FeatStrings.end());

415 }

416}

417

420 if (Features == "default")

421 return Ret;

423 Features.split(AttrFeatures, ";");

424 bool FoundArch = false;

425

426 auto handleArchExtension = [](StringRef AttrString,

427 std::vectorstd::string &Features) {

429 AttrString.split(Exts, ",");

430 for (auto Ext : Exts) {

431 if (Ext.empty())

432 continue;

433

434 StringRef ExtName = Ext.substr(1);

435 std::string TargetFeature =

436 llvm::RISCVISAInfo::getTargetFeatureForExtension(ExtName);

437 if (!TargetFeature.empty())

438 Features.push_back(Ext.front() + TargetFeature);

439 else

440 Features.push_back(Ext.str());

441 }

442 };

443

444 for (auto &Feature : AttrFeatures) {

445 Feature = Feature.trim();

446 StringRef AttrString = Feature.split("=").second.trim();

447

448 if (Feature.starts_with("arch=")) {

449

450 Ret.Features.clear();

451 if (FoundArch)

452 Ret.Duplicate = "arch=";

453 FoundArch = true;

454

455 if (AttrString.starts_with("+")) {

456

457 handleArchExtension(AttrString, Ret.Features);

458 } else {

459

461 }

462 } else if (Feature.starts_with("cpu=")) {

463 if (!Ret.CPU.empty())

464 Ret.Duplicate = "cpu=";

465

466 Ret.CPU = AttrString;

467

468 if (!FoundArch) {

469

470 StringRef MarchFromCPU = llvm::RISCV::getMArchFromMcpu(Ret.CPU);

471 if (MarchFromCPU != "") {

472 Ret.Features.clear();

474 }

475 }

476 } else if (Feature.starts_with("tune=")) {

477 if (!Ret.Tune.empty())

478 Ret.Duplicate = "tune=";

479

480 Ret.Tune = AttrString;

481 } else if (Feature.starts_with("priority")) {

482

483 } else if (Feature.starts_with("+")) {

484

485

486 handleArchExtension(Feature, Ret.Features);

487 }

488 }

489 return Ret;

490}

491

493

494

495

496 for (StringRef Feature : Features) {

497 auto [LHS, RHS] = Feature.rsplit(';');

498 if (LHS.consume_front("priority="))

499 Feature = LHS;

500 else if (RHS.consume_front("priority="))

501 Feature = RHS;

502 else

503 continue;

505 if (!Feature.getAsInteger(0, Priority))

507 }

508

509 return 0;

510}

511

514 switch (CC) {

515 default:

520 }

521}

522

524

525

526 return -1 != llvm::RISCVISAInfo::getRISCVFeaturesBitsInfo(Feature).second;

527}

528

530 return llvm::RISCVISAInfo::isSupportedExtensionFeature(Name);

531}

532

534 StringRef RegName, unsigned RegSize, bool &HasSizeMismatch) const {

535 if (RegName == "ra" || RegName == "sp" || RegName == "gp" ||

536 RegName == "tp" || RegName.starts_with("x") || RegName.starts_with("a") ||

537 RegName.starts_with("s") || RegName.starts_with("t")) {

538 unsigned XLen = getTriple().isArch64Bit() ? 64 : 32;

539 HasSizeMismatch = RegSize != XLen;

540 return true;

541 }

542 return false;

543}

544

546 assert(getTriple().isOSLinux() &&

547 "__builtin_cpu_is() is only supported for Linux.");

548

549 return llvm::RISCV::hasValidCPUModel(CPUName);

550}

Defines the Diagnostic-related interfaces.

static void populateNegativeRISCVFeatures(std::vector< std::string > &Features)

static unsigned getVersionValue(unsigned MajorVersion, unsigned MinorVersion)

static void handleFullArchString(StringRef FullArchStr, std::vector< std::string > &Features)

static constexpr Builtin::Info BuiltinInfo[]

Defines the clang::MacroBuilder utility class.

Enumerates target-specific builtins in their own namespaces within namespace clang.

Concrete class used by the front-end to report problems and issues.

DiagnosticBuilder Report(SourceLocation Loc, unsigned DiagID)

Issue the message to the client.

Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...

TargetOptions & getTargetOpts() const

Retrieve the target options.

const llvm::Triple & getTriple() const

Returns the target triple of the primary target.

virtual bool initFeatureMap(llvm::StringMap< bool > &Features, DiagnosticsEngine &Diags, StringRef CPU, const std::vector< std::string > &FeatureVec) const

Initialize the map with the default set of target features for the CPU this should include all legal ...

virtual std::string convertConstraint(const char *&Constraint) const

bool isValidFeatureName(StringRef Name) const override

Determine whether this TargetInfo supports the given feature.

std::string convertConstraint(const char *&Constraint) const override

void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override

===-— Other target property query methods -----------------------—===//

ArrayRef< Builtin::Info > getTargetBuiltins() const override

Return information about target-specific builtins for the current primary target, and info about whic...

bool validateAsmConstraint(const char *&Name, TargetInfo::ConstraintInfo &Info) const override

bool validateGlobalRegisterVariable(StringRef RegName, unsigned RegSize, bool &HasSizeMismatch) const override

Validate register name used for global register variables.

bool initFeatureMap(llvm::StringMap< bool > &Features, DiagnosticsEngine &Diags, StringRef CPU, const std::vector< std::string > &FeaturesVec) const override

Initialize the map with the default set of target features for the CPU this should include all legal ...

std::unique_ptr< llvm::RISCVISAInfo > ISAInfo

void fillValidTuneCPUList(SmallVectorImpl< StringRef > &Values) const override

Fill a SmallVectorImpl with the valid values for tuning CPU.

bool isValidTuneCPUName(StringRef Name) const override

Determine whether this TargetInfo supports the given CPU name for tuning.

std::optional< std::pair< unsigned, unsigned > > getVScaleRange(const LangOptions &LangOpts) const override

Returns target-specific min and max values VScale_Range.

CallingConvCheckResult checkCallingConvention(CallingConv CC) const override

Determines whether a given calling convention is valid for the target.

ArrayRef< const char * > getGCCRegNames() const override

ArrayRef< TargetInfo::GCCRegAlias > getGCCRegAliases() const override

void fillValidCPUList(SmallVectorImpl< StringRef > &Values) const override

Fill a SmallVectorImpl with the valid values to setCPU.

bool validateCpuSupports(StringRef Feature) const override

StringRef getABI() const override

Get the ABI currently in use.

uint64_t getFMVPriority(ArrayRef< StringRef > Features) const override

bool handleTargetFeatures(std::vector< std::string > &Features, DiagnosticsEngine &Diags) override

Perform initialization based on the user configured set of features.

ParsedTargetAttr parseTargetAttr(StringRef Str) const override

bool hasFeature(StringRef Feature) const override

Return true if has this feature, need to sync with handleTargetFeatures.

bool validateCpuIs(StringRef CPUName) const override

bool isValidCPUName(StringRef Name) const override

Determine whether this TargetInfo supports the given CPU name.

static const char *const GCCRegNames[]

The JSON file list parser is used to communicate input to InstallAPI.

@ Result

The result type of a method or function.

CallingConv

CallingConv - Specifies the calling convention that a function uses.

Contains information gathered from parsing the contents of TargetAttr.

void setRequiresImmediate(int Min, int Max)