mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-11-17 18:10:31 +00:00
4150d83abe
ADDC/ADDE use MVT::i1 (later, whatever it gets legalized to) instead of MVT::Flag. Remove CARRY_FALSE in favor of 0; adjust all target-independent code to use this format. Most targets will still produce a Flag-setting target-dependent version when selection is done. X86 is converted to use i32 instead, which means TableGen needs to produce different code in xxxGenDAGISel.inc. This keys off the new supportsHasI1 bit in xxxInstrInfo, currently set only for X86; in principle this is temporary and should go away when all other targets have been converted. All relevant X86 instruction patterns are modified to represent setting and using EFLAGS explicitly. The same can be done on other targets. The immediate behavior change is that an ADC/ADD pair are no longer tightly coupled in the X86 scheduler; they can be separated by instructions that don't clobber the flags (MOV). I will soon add some peephole optimizations based on using other instructions that set the flags to feed into ADC. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@72707 91177308-0d34-0410-b5e6-96231b3b80d8
584 lines
22 KiB
C++
584 lines
22 KiB
C++
//===- CodeGenTarget.cpp - CodeGen Target Class Wrapper -------------------===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This class wraps target description classes used by the various code
|
|
// generation TableGen backends. This makes it easier to access the data and
|
|
// provides a single place that needs to check it for validity. All of these
|
|
// classes throw exceptions on error conditions.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "CodeGenTarget.h"
|
|
#include "CodeGenIntrinsics.h"
|
|
#include "Record.h"
|
|
#include "llvm/ADT/StringExtras.h"
|
|
#include "llvm/Support/CommandLine.h"
|
|
#include "llvm/Support/Streams.h"
|
|
#include <algorithm>
|
|
using namespace llvm;
|
|
|
|
static cl::opt<unsigned>
|
|
AsmWriterNum("asmwriternum", cl::init(0),
|
|
cl::desc("Make -gen-asm-writer emit assembly writer #N"));
|
|
|
|
/// getValueType - Return the MVT::SimpleValueType that the specified TableGen
|
|
/// record corresponds to.
|
|
MVT::SimpleValueType llvm::getValueType(Record *Rec) {
|
|
return (MVT::SimpleValueType)Rec->getValueAsInt("Value");
|
|
}
|
|
|
|
std::string llvm::getName(MVT::SimpleValueType T) {
|
|
switch (T) {
|
|
case MVT::Other: return "UNKNOWN";
|
|
case MVT::i1: return "MVT::i1";
|
|
case MVT::i8: return "MVT::i8";
|
|
case MVT::i16: return "MVT::i16";
|
|
case MVT::i32: return "MVT::i32";
|
|
case MVT::i64: return "MVT::i64";
|
|
case MVT::i128: return "MVT::i128";
|
|
case MVT::iAny: return "MVT::iAny";
|
|
case MVT::fAny: return "MVT::fAny";
|
|
case MVT::f32: return "MVT::f32";
|
|
case MVT::f64: return "MVT::f64";
|
|
case MVT::f80: return "MVT::f80";
|
|
case MVT::f128: return "MVT::f128";
|
|
case MVT::ppcf128: return "MVT::ppcf128";
|
|
case MVT::Flag: return "MVT::Flag";
|
|
case MVT::isVoid:return "MVT::isVoid";
|
|
case MVT::v2i8: return "MVT::v2i8";
|
|
case MVT::v4i8: return "MVT::v4i8";
|
|
case MVT::v2i16: return "MVT::v2i16";
|
|
case MVT::v8i8: return "MVT::v8i8";
|
|
case MVT::v4i16: return "MVT::v4i16";
|
|
case MVT::v2i32: return "MVT::v2i32";
|
|
case MVT::v1i64: return "MVT::v1i64";
|
|
case MVT::v16i8: return "MVT::v16i8";
|
|
case MVT::v8i16: return "MVT::v8i16";
|
|
case MVT::v4i32: return "MVT::v4i32";
|
|
case MVT::v2i64: return "MVT::v2i64";
|
|
case MVT::v2f32: return "MVT::v2f32";
|
|
case MVT::v4f32: return "MVT::v4f32";
|
|
case MVT::v2f64: return "MVT::v2f64";
|
|
case MVT::v3i32: return "MVT::v3i32";
|
|
case MVT::v3f32: return "MVT::v3f32";
|
|
case MVT::iPTR: return "TLI.getPointerTy()";
|
|
case MVT::iPTRAny: return "TLI.getPointerTy()";
|
|
default: assert(0 && "ILLEGAL VALUE TYPE!"); return "";
|
|
}
|
|
}
|
|
|
|
std::string llvm::getEnumName(MVT::SimpleValueType T) {
|
|
switch (T) {
|
|
case MVT::Other: return "MVT::Other";
|
|
case MVT::i1: return "MVT::i1";
|
|
case MVT::i8: return "MVT::i8";
|
|
case MVT::i16: return "MVT::i16";
|
|
case MVT::i32: return "MVT::i32";
|
|
case MVT::i64: return "MVT::i64";
|
|
case MVT::i128: return "MVT::i128";
|
|
case MVT::iAny: return "MVT::iAny";
|
|
case MVT::fAny: return "MVT::fAny";
|
|
case MVT::f32: return "MVT::f32";
|
|
case MVT::f64: return "MVT::f64";
|
|
case MVT::f80: return "MVT::f80";
|
|
case MVT::f128: return "MVT::f128";
|
|
case MVT::ppcf128: return "MVT::ppcf128";
|
|
case MVT::Flag: return "MVT::Flag";
|
|
case MVT::isVoid:return "MVT::isVoid";
|
|
case MVT::v2i8: return "MVT::v2i8";
|
|
case MVT::v4i8: return "MVT::v4i8";
|
|
case MVT::v2i16: return "MVT::v2i16";
|
|
case MVT::v8i8: return "MVT::v8i8";
|
|
case MVT::v4i16: return "MVT::v4i16";
|
|
case MVT::v2i32: return "MVT::v2i32";
|
|
case MVT::v1i64: return "MVT::v1i64";
|
|
case MVT::v16i8: return "MVT::v16i8";
|
|
case MVT::v8i16: return "MVT::v8i16";
|
|
case MVT::v4i32: return "MVT::v4i32";
|
|
case MVT::v2i64: return "MVT::v2i64";
|
|
case MVT::v2f32: return "MVT::v2f32";
|
|
case MVT::v4f32: return "MVT::v4f32";
|
|
case MVT::v2f64: return "MVT::v2f64";
|
|
case MVT::v3i32: return "MVT::v3i32";
|
|
case MVT::v3f32: return "MVT::v3f32";
|
|
case MVT::iPTR: return "MVT::iPTR";
|
|
case MVT::iPTRAny: return "MVT::iPTRAny";
|
|
default: assert(0 && "ILLEGAL VALUE TYPE!"); return "";
|
|
}
|
|
}
|
|
|
|
/// getQualifiedName - Return the name of the specified record, with a
|
|
/// namespace qualifier if the record contains one.
|
|
///
|
|
std::string llvm::getQualifiedName(const Record *R) {
|
|
std::string Namespace = R->getValueAsString("Namespace");
|
|
if (Namespace.empty()) return R->getName();
|
|
return Namespace + "::" + R->getName();
|
|
}
|
|
|
|
|
|
|
|
|
|
/// getTarget - Return the current instance of the Target class.
|
|
///
|
|
CodeGenTarget::CodeGenTarget() {
|
|
std::vector<Record*> Targets = Records.getAllDerivedDefinitions("Target");
|
|
if (Targets.size() == 0)
|
|
throw std::string("ERROR: No 'Target' subclasses defined!");
|
|
if (Targets.size() != 1)
|
|
throw std::string("ERROR: Multiple subclasses of Target defined!");
|
|
TargetRec = Targets[0];
|
|
}
|
|
|
|
|
|
const std::string &CodeGenTarget::getName() const {
|
|
return TargetRec->getName();
|
|
}
|
|
|
|
std::string CodeGenTarget::getInstNamespace() const {
|
|
std::string InstNS;
|
|
|
|
for (inst_iterator i = inst_begin(), e = inst_end(); i != e; ++i) {
|
|
InstNS = i->second.Namespace;
|
|
|
|
// Make sure not to pick up "TargetInstrInfo" by accidentally getting
|
|
// the namespace off the PHI instruction or something.
|
|
if (InstNS != "TargetInstrInfo")
|
|
break;
|
|
}
|
|
|
|
return InstNS;
|
|
}
|
|
|
|
Record *CodeGenTarget::getInstructionSet() const {
|
|
return TargetRec->getValueAsDef("InstructionSet");
|
|
}
|
|
|
|
/// getAsmWriter - Return the AssemblyWriter definition for this target.
|
|
///
|
|
Record *CodeGenTarget::getAsmWriter() const {
|
|
std::vector<Record*> LI = TargetRec->getValueAsListOfDefs("AssemblyWriters");
|
|
if (AsmWriterNum >= LI.size())
|
|
throw "Target does not have an AsmWriter #" + utostr(AsmWriterNum) + "!";
|
|
return LI[AsmWriterNum];
|
|
}
|
|
|
|
void CodeGenTarget::ReadRegisters() const {
|
|
std::vector<Record*> Regs = Records.getAllDerivedDefinitions("Register");
|
|
if (Regs.empty())
|
|
throw std::string("No 'Register' subclasses defined!");
|
|
|
|
Registers.reserve(Regs.size());
|
|
Registers.assign(Regs.begin(), Regs.end());
|
|
}
|
|
|
|
CodeGenRegister::CodeGenRegister(Record *R) : TheDef(R) {
|
|
DeclaredSpillSize = R->getValueAsInt("SpillSize");
|
|
DeclaredSpillAlignment = R->getValueAsInt("SpillAlignment");
|
|
}
|
|
|
|
const std::string &CodeGenRegister::getName() const {
|
|
return TheDef->getName();
|
|
}
|
|
|
|
void CodeGenTarget::ReadRegisterClasses() const {
|
|
std::vector<Record*> RegClasses =
|
|
Records.getAllDerivedDefinitions("RegisterClass");
|
|
if (RegClasses.empty())
|
|
throw std::string("No 'RegisterClass' subclasses defined!");
|
|
|
|
RegisterClasses.reserve(RegClasses.size());
|
|
RegisterClasses.assign(RegClasses.begin(), RegClasses.end());
|
|
}
|
|
|
|
std::vector<unsigned char> CodeGenTarget::getRegisterVTs(Record *R) const {
|
|
std::vector<unsigned char> Result;
|
|
const std::vector<CodeGenRegisterClass> &RCs = getRegisterClasses();
|
|
for (unsigned i = 0, e = RCs.size(); i != e; ++i) {
|
|
const CodeGenRegisterClass &RC = RegisterClasses[i];
|
|
for (unsigned ei = 0, ee = RC.Elements.size(); ei != ee; ++ei) {
|
|
if (R == RC.Elements[ei]) {
|
|
const std::vector<MVT::SimpleValueType> &InVTs = RC.getValueTypes();
|
|
for (unsigned i = 0, e = InVTs.size(); i != e; ++i)
|
|
Result.push_back(InVTs[i]);
|
|
}
|
|
}
|
|
}
|
|
return Result;
|
|
}
|
|
|
|
|
|
CodeGenRegisterClass::CodeGenRegisterClass(Record *R) : TheDef(R) {
|
|
// Rename anonymous register classes.
|
|
if (R->getName().size() > 9 && R->getName()[9] == '.') {
|
|
static unsigned AnonCounter = 0;
|
|
R->setName("AnonRegClass_"+utostr(AnonCounter++));
|
|
}
|
|
|
|
std::vector<Record*> TypeList = R->getValueAsListOfDefs("RegTypes");
|
|
for (unsigned i = 0, e = TypeList.size(); i != e; ++i) {
|
|
Record *Type = TypeList[i];
|
|
if (!Type->isSubClassOf("ValueType"))
|
|
throw "RegTypes list member '" + Type->getName() +
|
|
"' does not derive from the ValueType class!";
|
|
VTs.push_back(getValueType(Type));
|
|
}
|
|
assert(!VTs.empty() && "RegisterClass must contain at least one ValueType!");
|
|
|
|
std::vector<Record*> RegList = R->getValueAsListOfDefs("MemberList");
|
|
for (unsigned i = 0, e = RegList.size(); i != e; ++i) {
|
|
Record *Reg = RegList[i];
|
|
if (!Reg->isSubClassOf("Register"))
|
|
throw "Register Class member '" + Reg->getName() +
|
|
"' does not derive from the Register class!";
|
|
Elements.push_back(Reg);
|
|
}
|
|
|
|
std::vector<Record*> SubRegClassList =
|
|
R->getValueAsListOfDefs("SubRegClassList");
|
|
for (unsigned i = 0, e = SubRegClassList.size(); i != e; ++i) {
|
|
Record *SubRegClass = SubRegClassList[i];
|
|
if (!SubRegClass->isSubClassOf("RegisterClass"))
|
|
throw "Register Class member '" + SubRegClass->getName() +
|
|
"' does not derive from the RegisterClass class!";
|
|
SubRegClasses.push_back(SubRegClass);
|
|
}
|
|
|
|
// Allow targets to override the size in bits of the RegisterClass.
|
|
unsigned Size = R->getValueAsInt("Size");
|
|
|
|
Namespace = R->getValueAsString("Namespace");
|
|
SpillSize = Size ? Size : MVT(VTs[0]).getSizeInBits();
|
|
SpillAlignment = R->getValueAsInt("Alignment");
|
|
CopyCost = R->getValueAsInt("CopyCost");
|
|
MethodBodies = R->getValueAsCode("MethodBodies");
|
|
MethodProtos = R->getValueAsCode("MethodProtos");
|
|
}
|
|
|
|
const std::string &CodeGenRegisterClass::getName() const {
|
|
return TheDef->getName();
|
|
}
|
|
|
|
void CodeGenTarget::ReadLegalValueTypes() const {
|
|
const std::vector<CodeGenRegisterClass> &RCs = getRegisterClasses();
|
|
for (unsigned i = 0, e = RCs.size(); i != e; ++i)
|
|
for (unsigned ri = 0, re = RCs[i].VTs.size(); ri != re; ++ri)
|
|
LegalValueTypes.push_back(RCs[i].VTs[ri]);
|
|
|
|
// Remove duplicates.
|
|
std::sort(LegalValueTypes.begin(), LegalValueTypes.end());
|
|
LegalValueTypes.erase(std::unique(LegalValueTypes.begin(),
|
|
LegalValueTypes.end()),
|
|
LegalValueTypes.end());
|
|
}
|
|
|
|
|
|
void CodeGenTarget::ReadInstructions() const {
|
|
std::vector<Record*> Insts = Records.getAllDerivedDefinitions("Instruction");
|
|
if (Insts.size() <= 2)
|
|
throw std::string("No 'Instruction' subclasses defined!");
|
|
|
|
// Parse the instructions defined in the .td file.
|
|
std::string InstFormatName =
|
|
getAsmWriter()->getValueAsString("InstFormatName");
|
|
|
|
for (unsigned i = 0, e = Insts.size(); i != e; ++i) {
|
|
std::string AsmStr = Insts[i]->getValueAsString(InstFormatName);
|
|
Instructions.insert(std::make_pair(Insts[i]->getName(),
|
|
CodeGenInstruction(Insts[i], AsmStr)));
|
|
}
|
|
}
|
|
|
|
/// getInstructionsByEnumValue - Return all of the instructions defined by the
|
|
/// target, ordered by their enum value.
|
|
void CodeGenTarget::
|
|
getInstructionsByEnumValue(std::vector<const CodeGenInstruction*>
|
|
&NumberedInstructions) {
|
|
std::map<std::string, CodeGenInstruction>::const_iterator I;
|
|
I = getInstructions().find("PHI");
|
|
if (I == Instructions.end()) throw "Could not find 'PHI' instruction!";
|
|
const CodeGenInstruction *PHI = &I->second;
|
|
|
|
I = getInstructions().find("INLINEASM");
|
|
if (I == Instructions.end()) throw "Could not find 'INLINEASM' instruction!";
|
|
const CodeGenInstruction *INLINEASM = &I->second;
|
|
|
|
I = getInstructions().find("DBG_LABEL");
|
|
if (I == Instructions.end()) throw "Could not find 'DBG_LABEL' instruction!";
|
|
const CodeGenInstruction *DBG_LABEL = &I->second;
|
|
|
|
I = getInstructions().find("EH_LABEL");
|
|
if (I == Instructions.end()) throw "Could not find 'EH_LABEL' instruction!";
|
|
const CodeGenInstruction *EH_LABEL = &I->second;
|
|
|
|
I = getInstructions().find("GC_LABEL");
|
|
if (I == Instructions.end()) throw "Could not find 'GC_LABEL' instruction!";
|
|
const CodeGenInstruction *GC_LABEL = &I->second;
|
|
|
|
I = getInstructions().find("DECLARE");
|
|
if (I == Instructions.end()) throw "Could not find 'DECLARE' instruction!";
|
|
const CodeGenInstruction *DECLARE = &I->second;
|
|
|
|
I = getInstructions().find("EXTRACT_SUBREG");
|
|
if (I == Instructions.end())
|
|
throw "Could not find 'EXTRACT_SUBREG' instruction!";
|
|
const CodeGenInstruction *EXTRACT_SUBREG = &I->second;
|
|
|
|
I = getInstructions().find("INSERT_SUBREG");
|
|
if (I == Instructions.end())
|
|
throw "Could not find 'INSERT_SUBREG' instruction!";
|
|
const CodeGenInstruction *INSERT_SUBREG = &I->second;
|
|
|
|
I = getInstructions().find("IMPLICIT_DEF");
|
|
if (I == Instructions.end())
|
|
throw "Could not find 'IMPLICIT_DEF' instruction!";
|
|
const CodeGenInstruction *IMPLICIT_DEF = &I->second;
|
|
|
|
I = getInstructions().find("SUBREG_TO_REG");
|
|
if (I == Instructions.end())
|
|
throw "Could not find 'SUBREG_TO_REG' instruction!";
|
|
const CodeGenInstruction *SUBREG_TO_REG = &I->second;
|
|
|
|
I = getInstructions().find("COPY_TO_REGCLASS");
|
|
if (I == Instructions.end())
|
|
throw "Could not find 'COPY_TO_REGCLASS' instruction!";
|
|
const CodeGenInstruction *COPY_TO_REGCLASS = &I->second;
|
|
|
|
// Print out the rest of the instructions now.
|
|
NumberedInstructions.push_back(PHI);
|
|
NumberedInstructions.push_back(INLINEASM);
|
|
NumberedInstructions.push_back(DBG_LABEL);
|
|
NumberedInstructions.push_back(EH_LABEL);
|
|
NumberedInstructions.push_back(GC_LABEL);
|
|
NumberedInstructions.push_back(DECLARE);
|
|
NumberedInstructions.push_back(EXTRACT_SUBREG);
|
|
NumberedInstructions.push_back(INSERT_SUBREG);
|
|
NumberedInstructions.push_back(IMPLICIT_DEF);
|
|
NumberedInstructions.push_back(SUBREG_TO_REG);
|
|
NumberedInstructions.push_back(COPY_TO_REGCLASS);
|
|
for (inst_iterator II = inst_begin(), E = inst_end(); II != E; ++II)
|
|
if (&II->second != PHI &&
|
|
&II->second != INLINEASM &&
|
|
&II->second != DBG_LABEL &&
|
|
&II->second != EH_LABEL &&
|
|
&II->second != GC_LABEL &&
|
|
&II->second != DECLARE &&
|
|
&II->second != EXTRACT_SUBREG &&
|
|
&II->second != INSERT_SUBREG &&
|
|
&II->second != IMPLICIT_DEF &&
|
|
&II->second != SUBREG_TO_REG &&
|
|
&II->second != COPY_TO_REGCLASS)
|
|
NumberedInstructions.push_back(&II->second);
|
|
}
|
|
|
|
|
|
/// isLittleEndianEncoding - Return whether this target encodes its instruction
|
|
/// in little-endian format, i.e. bits laid out in the order [0..n]
|
|
///
|
|
bool CodeGenTarget::isLittleEndianEncoding() const {
|
|
return getInstructionSet()->getValueAsBit("isLittleEndianEncoding");
|
|
}
|
|
|
|
/// supportsHasI1 - Return whether this target supports the implicit I1,
|
|
/// rather than Flags, for ADDC/ADDE
|
|
///
|
|
bool CodeGenTarget::supportsHasI1() const {
|
|
return getInstructionSet()->getValueAsBit("supportsHasI1");
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// ComplexPattern implementation
|
|
//
|
|
ComplexPattern::ComplexPattern(Record *R) {
|
|
Ty = ::getValueType(R->getValueAsDef("Ty"));
|
|
NumOperands = R->getValueAsInt("NumOperands");
|
|
SelectFunc = R->getValueAsString("SelectFunc");
|
|
RootNodes = R->getValueAsListOfDefs("RootNodes");
|
|
|
|
// Parse the properties.
|
|
Properties = 0;
|
|
std::vector<Record*> PropList = R->getValueAsListOfDefs("Properties");
|
|
for (unsigned i = 0, e = PropList.size(); i != e; ++i)
|
|
if (PropList[i]->getName() == "SDNPHasChain") {
|
|
Properties |= 1 << SDNPHasChain;
|
|
} else if (PropList[i]->getName() == "SDNPOptInFlag") {
|
|
Properties |= 1 << SDNPOptInFlag;
|
|
} else if (PropList[i]->getName() == "SDNPMayStore") {
|
|
Properties |= 1 << SDNPMayStore;
|
|
} else if (PropList[i]->getName() == "SDNPMayLoad") {
|
|
Properties |= 1 << SDNPMayLoad;
|
|
} else if (PropList[i]->getName() == "SDNPSideEffect") {
|
|
Properties |= 1 << SDNPSideEffect;
|
|
} else if (PropList[i]->getName() == "SDNPMemOperand") {
|
|
Properties |= 1 << SDNPMemOperand;
|
|
} else {
|
|
cerr << "Unsupported SD Node property '" << PropList[i]->getName()
|
|
<< "' on ComplexPattern '" << R->getName() << "'!\n";
|
|
exit(1);
|
|
}
|
|
|
|
// Parse the attributes.
|
|
Attributes = 0;
|
|
PropList = R->getValueAsListOfDefs("Attributes");
|
|
for (unsigned i = 0, e = PropList.size(); i != e; ++i)
|
|
if (PropList[i]->getName() == "CPAttrParentAsRoot") {
|
|
Attributes |= 1 << CPAttrParentAsRoot;
|
|
} else {
|
|
cerr << "Unsupported pattern attribute '" << PropList[i]->getName()
|
|
<< "' on ComplexPattern '" << R->getName() << "'!\n";
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// CodeGenIntrinsic Implementation
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
std::vector<CodeGenIntrinsic> llvm::LoadIntrinsics(const RecordKeeper &RC,
|
|
bool TargetOnly) {
|
|
std::vector<Record*> I = RC.getAllDerivedDefinitions("Intrinsic");
|
|
|
|
std::vector<CodeGenIntrinsic> Result;
|
|
|
|
for (unsigned i = 0, e = I.size(); i != e; ++i) {
|
|
bool isTarget = I[i]->getValueAsBit("isTarget");
|
|
if (isTarget == TargetOnly)
|
|
Result.push_back(CodeGenIntrinsic(I[i]));
|
|
}
|
|
return Result;
|
|
}
|
|
|
|
CodeGenIntrinsic::CodeGenIntrinsic(Record *R) {
|
|
TheDef = R;
|
|
std::string DefName = R->getName();
|
|
ModRef = WriteMem;
|
|
isOverloaded = false;
|
|
isCommutative = false;
|
|
|
|
if (DefName.size() <= 4 ||
|
|
std::string(DefName.begin(), DefName.begin() + 4) != "int_")
|
|
throw "Intrinsic '" + DefName + "' does not start with 'int_'!";
|
|
|
|
EnumName = std::string(DefName.begin()+4, DefName.end());
|
|
|
|
if (R->getValue("GCCBuiltinName")) // Ignore a missing GCCBuiltinName field.
|
|
GCCBuiltinName = R->getValueAsString("GCCBuiltinName");
|
|
|
|
TargetPrefix = R->getValueAsString("TargetPrefix");
|
|
Name = R->getValueAsString("LLVMName");
|
|
|
|
if (Name == "") {
|
|
// If an explicit name isn't specified, derive one from the DefName.
|
|
Name = "llvm.";
|
|
|
|
for (unsigned i = 0, e = EnumName.size(); i != e; ++i)
|
|
Name += (EnumName[i] == '_') ? '.' : EnumName[i];
|
|
} else {
|
|
// Verify it starts with "llvm.".
|
|
if (Name.size() <= 5 ||
|
|
std::string(Name.begin(), Name.begin() + 5) != "llvm.")
|
|
throw "Intrinsic '" + DefName + "'s name does not start with 'llvm.'!";
|
|
}
|
|
|
|
// If TargetPrefix is specified, make sure that Name starts with
|
|
// "llvm.<targetprefix>.".
|
|
if (!TargetPrefix.empty()) {
|
|
if (Name.size() < 6+TargetPrefix.size() ||
|
|
std::string(Name.begin() + 5, Name.begin() + 6 + TargetPrefix.size())
|
|
!= (TargetPrefix + "."))
|
|
throw "Intrinsic '" + DefName + "' does not start with 'llvm." +
|
|
TargetPrefix + ".'!";
|
|
}
|
|
|
|
// Parse the list of return types.
|
|
std::vector<MVT::SimpleValueType> OverloadedVTs;
|
|
ListInit *TypeList = R->getValueAsListInit("RetTypes");
|
|
for (unsigned i = 0, e = TypeList->getSize(); i != e; ++i) {
|
|
Record *TyEl = TypeList->getElementAsRecord(i);
|
|
assert(TyEl->isSubClassOf("LLVMType") && "Expected a type!");
|
|
MVT::SimpleValueType VT;
|
|
if (TyEl->isSubClassOf("LLVMMatchType")) {
|
|
unsigned MatchTy = TyEl->getValueAsInt("Number");
|
|
assert(MatchTy < OverloadedVTs.size() &&
|
|
"Invalid matching number!");
|
|
VT = OverloadedVTs[MatchTy];
|
|
// It only makes sense to use the extended and truncated vector element
|
|
// variants with iAny types; otherwise, if the intrinsic is not
|
|
// overloaded, all the types can be specified directly.
|
|
assert(((!TyEl->isSubClassOf("LLVMExtendedElementVectorType") &&
|
|
!TyEl->isSubClassOf("LLVMTruncatedElementVectorType")) ||
|
|
VT == MVT::iAny) && "Expected iAny type");
|
|
} else {
|
|
VT = getValueType(TyEl->getValueAsDef("VT"));
|
|
}
|
|
if (VT == MVT::iAny || VT == MVT::fAny || VT == MVT::iPTRAny) {
|
|
OverloadedVTs.push_back(VT);
|
|
isOverloaded |= true;
|
|
}
|
|
IS.RetVTs.push_back(VT);
|
|
IS.RetTypeDefs.push_back(TyEl);
|
|
}
|
|
|
|
if (IS.RetVTs.size() == 0)
|
|
throw "Intrinsic '"+DefName+"' needs at least a type for the ret value!";
|
|
|
|
// Parse the list of parameter types.
|
|
TypeList = R->getValueAsListInit("ParamTypes");
|
|
for (unsigned i = 0, e = TypeList->getSize(); i != e; ++i) {
|
|
Record *TyEl = TypeList->getElementAsRecord(i);
|
|
assert(TyEl->isSubClassOf("LLVMType") && "Expected a type!");
|
|
MVT::SimpleValueType VT;
|
|
if (TyEl->isSubClassOf("LLVMMatchType")) {
|
|
unsigned MatchTy = TyEl->getValueAsInt("Number");
|
|
assert(MatchTy < OverloadedVTs.size() &&
|
|
"Invalid matching number!");
|
|
VT = OverloadedVTs[MatchTy];
|
|
// It only makes sense to use the extended and truncated vector element
|
|
// variants with iAny types; otherwise, if the intrinsic is not
|
|
// overloaded, all the types can be specified directly.
|
|
assert(((!TyEl->isSubClassOf("LLVMExtendedElementVectorType") &&
|
|
!TyEl->isSubClassOf("LLVMTruncatedElementVectorType")) ||
|
|
VT == MVT::iAny) && "Expected iAny type");
|
|
} else
|
|
VT = getValueType(TyEl->getValueAsDef("VT"));
|
|
if (VT == MVT::iAny || VT == MVT::fAny || VT == MVT::iPTRAny) {
|
|
OverloadedVTs.push_back(VT);
|
|
isOverloaded |= true;
|
|
}
|
|
IS.ParamVTs.push_back(VT);
|
|
IS.ParamTypeDefs.push_back(TyEl);
|
|
}
|
|
|
|
// Parse the intrinsic properties.
|
|
ListInit *PropList = R->getValueAsListInit("Properties");
|
|
for (unsigned i = 0, e = PropList->getSize(); i != e; ++i) {
|
|
Record *Property = PropList->getElementAsRecord(i);
|
|
assert(Property->isSubClassOf("IntrinsicProperty") &&
|
|
"Expected a property!");
|
|
|
|
if (Property->getName() == "IntrNoMem")
|
|
ModRef = NoMem;
|
|
else if (Property->getName() == "IntrReadArgMem")
|
|
ModRef = ReadArgMem;
|
|
else if (Property->getName() == "IntrReadMem")
|
|
ModRef = ReadMem;
|
|
else if (Property->getName() == "IntrWriteArgMem")
|
|
ModRef = WriteArgMem;
|
|
else if (Property->getName() == "IntrWriteMem")
|
|
ModRef = WriteMem;
|
|
else if (Property->getName() == "Commutative")
|
|
isCommutative = true;
|
|
else if (Property->isSubClassOf("NoCapture")) {
|
|
unsigned ArgNo = Property->getValueAsInt("ArgNo");
|
|
ArgumentAttributes.push_back(std::make_pair(ArgNo, NoCapture));
|
|
} else
|
|
assert(0 && "Unknown property!");
|
|
}
|
|
}
|