LLVM学习笔记(50)

3.9. X86 EVEX2VEX映射表的生成(v7.0)

VEX编码方案支持现有指令编码的扩展或修改,以及新指令定义。(维基

EVEX方案是VEX方案的一个4字节扩展,它支持AVX-512指令集,并允许访问新的512ZMM寄存器以及新的掩码寄存器。(维基

这个X86特定的TableGen处理生成一张表,将EVEX编码的指令映射到等价VEX编码指令。这样做通常可以将指令长度减少2字节。在V7.0中有一个EvexToVexInstPass遍将这张表用于这个目的。

188     void X86EVEX2VEXTablesEmitter::run(raw_ostream &OS) {

189       emitSourceFileHeader("X86 EVEX2VEX tables", OS);

190    

191       ArrayRef<const CodeGenInstruction *> NumberedInstructions =

192           Target.getInstructionsByEnumValue();

193    

194       for (const CodeGenInstruction *Inst : NumberedInstructions) {

195         // Filter non-X86 instructions.

196         if (!Inst->TheDef->isSubClassOf("X86Inst"))

197           continue;

198    

199         // Add VEX encoded instructions to one of VEXInsts vectors according to

200         // it's opcode.

201         if (Inst->TheDef->getValueAsDef("OpEnc")->getName() == "EncVEX") {

202           uint64_t Opcode = getValueFromBitsInit(Inst->TheDef->

203                                                  getValueAsBitsInit("Opcode"));

204           VEXInsts[Opcode].push_back(Inst);

205         }

206         // Add relevant EVEX encoded instructions to EVEXInsts

207         else if (Inst->TheDef->getValueAsDef("OpEnc")->getName() == "EncEVEX" &&

208                  !Inst->TheDef->getValueAsBit("hasEVEX_K") &&

209                  !Inst->TheDef->getValueAsBit("hasEVEX_B") &&

210                  getValueFromBitsInit(Inst->TheDef->

211                                             getValueAsBitsInit("EVEX_LL")) != 2 &&

212              !Inst->TheDef->getValueAsBit("notEVEX2VEXConvertible"))

213           EVEXInsts.push_back(Inst);

214       }

215    

216       for (const CodeGenInstruction *EVEXInst : EVEXInsts) {

217         uint64_t Opcode = getValueFromBitsInit(EVEXInst->TheDef->

218                                                getValueAsBitsInit("Opcode"));

219         // For each EVEX instruction look for a VEX match in the appropriate vector

220         // (instructions with the same opcode) using function object IsMatch.

221         // Allow EVEX2VEXOverride to explicitly specify a match.

222         const CodeGenInstruction *VEXInst = nullptr;

223         if (!EVEXInst->TheDef->isValueUnset("EVEX2VEXOverride")) {

224           StringRef AltInstStr =

225             EVEXInst->TheDef->getValueAsString("EVEX2VEXOverride");

226           Record *AltInstRec = Records.getDef(AltInstStr);

227           assert(AltInstRec && "EVEX2VEXOverride instruction not found!");

228           VEXInst = &Target.getInstruction(AltInstRec);

229         } else {

230           auto Match = llvm::find_if(VEXInsts[Opcode], IsMatch(EVEXInst));

231           if (Match != VEXInsts[Opcode].end())

232             VEXInst = *Match;

233         }

234    

235         if (!VEXInst)

236           continue;

237    

238         // In case a match is found add new entry to the appropriate table

239         switch (getValueFromBitsInit(

240             EVEXInst->TheDef->getValueAsBitsInit("EVEX_LL"))) {

241         case 0:

242           EVEX2VEX128.push_back(std::make_pair(EVEXInst, VEXInst)); // {0,0}

243           break;

244         case 1:

245           EVEX2VEX256.push_back(std::make_pair(EVEXInst, VEXInst)); // {0,1}

246           break;

247         default:

248           llvm_unreachable("Instruction's size not fit for the mapping!");

249         }

250       }

251    

252       // Print both tables

253       printTable(EVEX2VEX128, OS);

254       printTable(EVEX2VEX256, OS);

255     }

这个函数的处理并不复杂,其中涉及的指令域最开始都是来自X86Inst定义,由各个派生定义进行改写。上面201行条件如果成立,表示指令使用VEX编码,把该指令记录在VEXInsts容器中(类型std::map<uint64_t, std::vector<const CodeGenInstruction *>>),以操作码为键值。

207行条件筛选出EVEX编码的指令:该指令不使用掩码、不设置EVEX.B域及EVEX.L2域、不禁止EVEXEVX的转换,把这些指令保存在容器EVEXInsts(类型std::vector<const CodeGenInstruction *>)中。接着在216遍历这些EVEX编码指令,如果指令的EVEX2VEXOverride域给出了等价的VEX编码指令,尝试获取对应的CodeGenInstruction对象(不少AVX-512指令把自己设为等价VEX编码指令)。

如果没有设置EVEX2VEXOverride域,则尝试通过IsMatchoperator()方法来获取:它遍历所有具有指定操作码的VEX编码指令,找出其中匹配的那个。

103     class IsMatch {

104       const CodeGenInstruction *EVEXInst;

105    

106     public:

107       IsMatch(const CodeGenInstruction *EVEXInst) : EVEXInst(EVEXInst) {}

108    

109       bool operator()(const CodeGenInstruction *VEXInst) {

110         Record *RecE = EVEXInst->TheDef;

111         Record *RecV = VEXInst->TheDef;

112         uint64_t EVEX_W =

113             getValueFromBitsInit(RecE->getValueAsBitsInit("VEX_WPrefix"));

114         uint64_t VEX_W =

115             getValueFromBitsInit(RecV->getValueAsBitsInit("VEX_WPrefix"));

116    

117         if (RecV->getValueAsDef("OpEnc")->getName().str() != "EncVEX" ||

118             // VEX/EVEX fields

119             RecV->getValueAsDef("OpPrefix") != RecE->getValueAsDef("OpPrefix") ||

120             RecV->getValueAsDef("OpMap") != RecE->getValueAsDef("OpMap") ||

121             RecV->getValueAsBit("hasVEX_4V") != RecE->getValueAsBit("hasVEX_4V") ||

122                 !equalBitsInits(RecV->getValueAsBitsInit("EVEX_LL"),

123                             RecE->getValueAsBitsInit("EVEX_LL")) ||

124             // Match is allowed if either is VEX_WIG, or they match, or EVEX

125             // is VEX_W1X and VEX is VEX_W0.

126             (!(EVEX_W == 2 || VEX_W == 2 || EVEX_W == VEX_W ||

127                (EVEX_W == 3 && VEX_W == 0))) ||

128             // Instruction's format

129             RecV->getValueAsDef("Form") != RecE->getValueAsDef("Form") ||

130             RecV->getValueAsBit("isAsmParserOnly") !=

131                 RecE->getValueAsBit("isAsmParserOnly"))

132           return false;

133    

134         // This is needed for instructions with intrinsic version (_Int).

135         // Where the only difference is the size of the operands.

136         // For example: VUCOMISDZrm and Int_VUCOMISDrm

137         // Also for instructions that their EVEX version was upgraded to work with

138         // k-registers. For example VPCMPEQBrm (xmm output register) and

139         // VPCMPEQBZ128rm (k register output register).

140         for (unsigned i = 0, e = EVEXInst->Operands.size(); i < e; i++) {

141           Record *OpRec1 = EVEXInst->Operands[i].Rec;

142           Record *OpRec2 = VEXInst->Operands[i].Rec;

143    

144           if (OpRec1 == OpRec2)

145             continue;

146    

147           if (isRegisterOperand(OpRec1) && isRegisterOperand(OpRec2)) {

148             if (getRegOperandSize(OpRec1) != getRegOperandSize(OpRec2))

149               return false;

150           } else if (isMemoryOperand(OpRec1) && isMemoryOperand(OpRec2)) {

151             return false;

152           } else if (isImmediateOperand(OpRec1) && isImmediateOperand(OpRec2)) {

153             if (OpRec1->getValueAsDef("Type") != OpRec2->getValueAsDef("Type"))

154               return false;

155           } else

156             return false;

157         }

158    

159         return true;

160       }

161    

162     private:

163       static inline bool isRegisterOperand(const Record *Rec) {

164         return Rec->isSubClassOf("RegisterClass") ||

165                Rec->isSubClassOf("RegisterOperand");

166       }

167    

168       static inline bool isMemoryOperand(const Record *Rec) {

169         return Rec->isSubClassOf("Operand") &&

170                Rec->getValueAsString("OperandType") == "OPERAND_MEMORY";

171       }

172    

173       static inline bool isImmediateOperand(const Record *Rec) {

174         return Rec->isSubClassOf("Operand") &&

175                Rec->getValueAsString("OperandType") == "OPERAND_IMMEDIATE";

176       }

177    

178       static inline unsigned int getRegOperandSize(const Record *RegRec) {

179         if (RegRec->isSubClassOf("RegisterClass"))

180           return RegRec->getValueAsInt("Alignment");

181         if (RegRec->isSubClassOf("RegisterOperand"))

182           return RegRec->getValueAsDef("RegClass")->getValueAsInt("Alignment");

183    

184         llvm_unreachable("Register operand's size not known!");

185       }

186     };

匹配与指令的前缀、操作数类型、操作数保存的位置都有关。

最后,输出的表是这样的(表太长,只节选部分):

// X86 EVEX encoded instructions that have a VEX 128 encoding

// (table format: <EVEX opcode, VEX-128 opcode>).

static const X86EvexToVexCompressTableEntry X86EvexToVex128CompressTable[] = {

  // EVEX scalar with corresponding VEX.

  { X86::VADDPDZ128rm, X86::VADDPDrm },

  { X86::VADDPDZ128rr, X86::VADDPDrr },

  { X86::VADDPSZ128rm, X86::VADDPSrm },

  { X86::VADDPSZ128rr, X86::VADDPSrr },

  { X86::VADDSDZrm, X86::VADDSDrm },

  …

  { X86::VXORPDZ128rm, X86::VXORPDrm },

  { X86::VXORPDZ128rr, X86::VXORPDrr },

  { X86::VXORPSZ128rm, X86::VXORPSrm },

  { X86::VXORPSZ128rr, X86::VXORPSrr },

};

 

// X86 EVEX encoded instructions that have a VEX 256 encoding

// (table format: <EVEX opcode, VEX-256 opcode>).

static const X86EvexToVexCompressTableEntry X86EvexToVex256CompressTable[] = {

  // EVEX scalar with corresponding VEX.

  { X86::VADDPDZ256rm, X86::VADDPDYrm },

  { X86::VADDPDZ256rr, X86::VADDPDYrr },

  { X86::VADDPSZ256rm, X86::VADDPSYrm },

  { X86::VADDPSZ256rr, X86::VADDPSYrr },

  { X86::VAESDECLASTZ256rm, X86::VAESDECLASTYrm },

  …

  { X86::VXORPDZ256rm, X86::VXORPDYrm },

  { X86::VXORPDZ256rr, X86::VXORPDYrr },

  { X86::VXORPSZ256rm, X86::VXORPSYrm },

  { X86::VXORPSZ256rr, X86::VXORPSYrr },

};

其中X86EvexToVexCompressTableEntry是这样的结构:

41       struct X86EvexToVexCompressTableEntry {

42         uint16_t EvexOpcode;

43         uint16_t VexOpcode;

44      

45         bool operator<(const X86EvexToVexCompressTableEntry &RHS) const {

46           return EvexOpcode < RHS.EvexOpcode;

47         }

48      

49         friend bool operator<(const X86EvexToVexCompressTableEntry &TE,

50                               unsigned Opc) {

51           return TE.EvexOpcode < Opc;

52         }

53       };

这张映射表就是遍EvexToVexInstPass使用的武器。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值