LLVM学习笔记(50)
Posted wuhui_gdnt
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LLVM学习笔记(50)相关的知识,希望对你有一定的参考价值。
3.9. X86 EVEX2VEX映射表的生成(v7.0)
VEX编码方案支持现有指令编码的扩展或修改,以及新指令定义。(维基)
EVEX方案是VEX方案的一个4字节扩展,它支持AVX-512指令集,并允许访问新的512位ZMM寄存器以及新的掩码寄存器。(维基)
这个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域、不禁止EVEX到EVX的转换,把这些指令保存在容器EVEXInsts(类型std::vector<const CodeGenInstruction *>)中。接着在216遍历这些EVEX编码指令,如果指令的EVEX2VEXOverride域给出了等价的VEX编码指令,尝试获取对应的CodeGenInstruction对象(不少AVX-512指令把自己设为等价VEX编码指令)。
如果没有设置EVEX2VEXOverride域,则尝试通过IsMatch的operator()方法来获取:它遍历所有具有指定操作码的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使用的武器。
以上是关于LLVM学习笔记(50)的主要内容,如果未能解决你的问题,请参考以下文章