LLVM ISA指令选择与实现
LLVM ISA指令选择与实现
LLVM指令的选择
对指令选择过程中一些代码的解释:
1、这里的指令选择发生在SelectionDAG阶段的后段,即DAG图已经转成了目标机器的DAG并完成了Schedule(指令调度);但在寄存分配之前。此阶段其实就是发射机器指令了。
这个阶段中是采用BuildMI方法(定义在: llvm\include\llvm\Codgen\MachineBuilder.h)进行由前者到后者的转换的。
2、def : Pat<(i32 immSExt8:$in), (ADDiu R4, imm:$in)>;
这条指令的意思是进行一种匹配。至于用处可以看该文档,现在只用个例子进行解释。大意就是在selectDAG中会匹配到类似第一个参数的指令,匹配到后便会利用后一个参数的指令进行替换。而这句代码中的 i32 immSEx8:$in 代指的就是一个32位的立即数。immSExt8之前定义为:
def immSExt8 : PatLeaf<(imm), [{return isInt<8>(N->getSExtValue()); }]>;
这条指令是判定一个立即数是否是8位的,是的话才能匹配成功。第一个参数imm代表的就是立即数;第二个参数则是判定语句。具体的信息还得再领悟。。。
ADDiu R4, imm:$in 则是用来替代前一参数所代表的指令。
整条指令是由LLVM IR转成机器指令,发生在selectDAG阶段。而且可以看到这条指令并没有定义一个具体的名字,说明是可以匹配任何的指令,只要匹配成功就会执行。
Llvm ISA指令实现
LLVM确实大量使用了手工形式的RTTI,使用了isa<>、cast<>和dyn_cast<>等模板。这种形式的RTTI是可选的,可以添加到任何类中。也比dynamic_cast<>有效得多。
LLVM实现了某种自定义RTTI并使用了classof。
首先,LLVM系统非常具体,根本不是RTTI系统的替代品。对于大多数类,不需要生成RTTI信息当需要时,信息只在给定的层次结构中有意义排除了这个系统的多重继承识别对象类,以简单的层次结构为例:
struct Base {}; /* abstract */
struct DerivedLeft: Base {}; /* abstract */
struct DerivedRight:Base {};
struct MostDerivedL1: DerivedLeft {};
struct MostDerivedL2: DerivedLeft {};
struct MostDerivedR: DerivedRight {};
创建一个特定于此层次结构的枚举,其中每个可以实例化的层次结构成员都有一个枚举成员(其他成员将毫无用处)
enum BaseId {
DerivedRightId,
MostDerivedL1Id,
MostDerivedL2Id,
MostDerivedRId
};
然后,基类将使用返回此枚举的方法进行扩充。
struct Base {
static inline bool classof(Base const*) { return true; }
Base(BaseId id): Id(id) {}
BaseId getValueID() const { return Id; }
BaseId Id;
};
每一个具体的类也以这种方式被扩充:
struct DerivedRight: Base {
static inline bool classof(DerivedRight const*) { return true; }
static inline bool classof(Base const* B) {
switch(B->getValueID()) {
case DerivedRightId: case MostDerivedRId: return true;
default: return false;
}
}
DerivedRight(BaseId id = DerivedRightId): Base(id) {}
};
现在,可以简单地查询精确的类型以进行强制转换。
隐藏实施详细信息
但是,让用户对getValueID进行窃听会很麻烦,所以在LLVM中,这是通过使用classof方法隐藏的。
给定的类应该实现两类方法:一类用于其最深的基(测试BaseId的适当值),另一类用于自身(纯优化)。例如:
struct MostDerivedL1: DerivedLeft {
static inline bool classof(MostDerivedL1 const*) { return true; }
static inline bool classof(Base const* B) {
return B->getValueID() == MostDerivedL1Id;
}
MostDerivedL1(): DerivedLeft(MostDerivedL1Id) {}
};
这样,可以通过模板检查是否可以进行强制转换:
template <typename To, typename From>
bool isa(From const& f) {
return To::classof(&f);
}
想象一下,To是MostDerivedL1:
如果From是MostDerivedL1,那么调用classof的第一个重载,就会工作
如果From是其他类型,那么调用classof的第二个重载,检查使用枚举来确定具体类型是否匹配。
当关闭RTTI时,像是一种推荐的实现自己数据的方式。至少这非常非常有效+1,正在研究Clang和LLVM,而主要研究Clang。这根本不是自动的,事实上这就是重点,因为只要不使用,就不会为此付费。LLVM和Clang是非常具体的项目,有非常具体的需求,对于大多数项目来说,简单的RTTI就足够了。–
除了getValueID不是虚拟的,但基类具有getValueID返回的BaseId类型的成员。
不知道在想什么,因为其中一个目标是完全摆脱虚拟指针。–
MostDerivedL1应该继承自DerivedLeft,更正了定义。也应该适用于基类,例如,派生到基的转换将负责将DerivedLeft*转换为base*,然后将使用base::classof(base const*)(并返回true)。将在Base中添加实现类,目前缺失。
参考文献了解
https://stackoverflow.com/questions/6038330/how-is-llvm-isa-implemented/