1 //===- subzero/src/IceInstX8632.cpp - X86-32 instruction implementation ---===// 2 // 3 // The Subzero Code Generator 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 /// 10 /// \file 11 /// \brief Defines X8632 specific data related to X8632 Instructions and 12 /// Instruction traits. 13 /// 14 /// These are declared in the IceTargetLoweringX8632Traits.h header file. This 15 /// file also defines X8632 operand specific methods (dump and emit.) 16 /// 17 //===----------------------------------------------------------------------===// 18 #include "IceInstX8632.h" 19 20 #include "IceAssemblerX8632.h" 21 #include "IceCfg.h" 22 #include "IceCfgNode.h" 23 #include "IceConditionCodesX8632.h" 24 #include "IceInst.h" 25 #include "IceRegistersX8632.h" 26 #include "IceTargetLoweringX8632.h" 27 #include "IceOperand.h" 28 29 namespace Ice { 30 31 namespace X8632 { 32 33 const TargetX8632Traits::InstBrAttributesType 34 TargetX8632Traits::InstBrAttributes[] = { 35 #define X(val, encode, opp, dump, emit) \ 36 { X8632::Traits::Cond::opp, dump, emit } \ 37 , 38 ICEINSTX8632BR_TABLE 39 #undef X 40 }; 41 42 const TargetX8632Traits::InstCmppsAttributesType 43 TargetX8632Traits::InstCmppsAttributes[] = { 44 #define X(val, emit) \ 45 { emit } \ 46 , 47 ICEINSTX8632CMPPS_TABLE 48 #undef X 49 }; 50 51 const TargetX8632Traits::TypeAttributesType 52 TargetX8632Traits::TypeAttributes[] = { 53 #define X(tag, elty, cvt, sdss, pdps, spsd, int_, unpack, pack, width, fld) \ 54 { cvt, sdss, pdps, spsd, int_, unpack, pack, width, fld } \ 55 , 56 ICETYPEX8632_TABLE 57 #undef X 58 }; 59 60 const char *TargetX8632Traits::InstSegmentRegNames[] = { 61 #define X(val, name, prefix) name, 62 SEG_REGX8632_TABLE 63 #undef X 64 }; 65 66 uint8_t TargetX8632Traits::InstSegmentPrefixes[] = { 67 #define X(val, name, prefix) prefix, 68 SEG_REGX8632_TABLE 69 #undef X 70 }; 71 72 void TargetX8632Traits::X86Operand::dump(const Cfg *, Ostream &Str) const { 73 if (BuildDefs::dump()) 74 Str << "<OperandX8632>"; 75 } 76 77 TargetX8632Traits::X86OperandMem::X86OperandMem( 78 Cfg *Func, Type Ty, Variable *Base, Constant *Offset, Variable *Index, 79 uint16_t Shift, SegmentRegisters SegmentReg, bool IsRebased) 80 : X86Operand(kMem, Ty), Base(Base), Offset(Offset), Index(Index), 81 Shift(Shift), SegmentReg(SegmentReg), IsRebased(IsRebased) { 82 assert(Shift <= 3); 83 Vars = nullptr; 84 NumVars = 0; 85 if (Base) 86 ++NumVars; 87 if (Index) 88 ++NumVars; 89 if (NumVars) { 90 Vars = Func->allocateArrayOf<Variable *>(NumVars); 91 SizeT I = 0; 92 if (Base) 93 Vars[I++] = Base; 94 if (Index) 95 Vars[I++] = Index; 96 assert(I == NumVars); 97 } 98 } 99 100 namespace { 101 102 int32_t getRematerializableOffset(Variable *Var, 103 const Ice::X8632::TargetX8632 *Target) { 104 int32_t Disp = Var->getStackOffset(); 105 const auto RegNum = Var->getRegNum(); 106 if (RegNum == Target->getFrameReg()) { 107 Disp += Target->getFrameFixedAllocaOffset(); 108 } else if (RegNum != Target->getStackReg()) { 109 llvm::report_fatal_error("Unexpected rematerializable register type"); 110 } 111 return Disp; 112 } 113 114 void validateMemOperandPIC(const TargetX8632Traits::X86OperandMem *Mem, 115 bool UseNonsfi) { 116 if (!BuildDefs::asserts()) 117 return; 118 const bool HasCR = 119 Mem->getOffset() && llvm::isa<ConstantRelocatable>(Mem->getOffset()); 120 (void)HasCR; 121 const bool IsRebased = Mem->getIsRebased(); 122 (void)IsRebased; 123 if (UseNonsfi) 124 assert(HasCR == IsRebased); 125 else 126 assert(!IsRebased); 127 } 128 129 } // end of anonymous namespace 130 131 void TargetX8632Traits::X86OperandMem::emit(const Cfg *Func) const { 132 if (!BuildDefs::dump()) 133 return; 134 const bool UseNonsfi = getFlags().getUseNonsfi(); 135 validateMemOperandPIC(this, UseNonsfi); 136 const auto *Target = 137 static_cast<const ::Ice::X8632::TargetX8632 *>(Func->getTarget()); 138 // If the base is rematerializable, we need to replace it with the correct 139 // physical register (esp or ebp), and update the Offset. 140 int32_t Disp = 0; 141 if (getBase() && getBase()->isRematerializable()) { 142 Disp += getRematerializableOffset(getBase(), Target); 143 } 144 // The index should never be rematerializable. But if we ever allow it, then 145 // we should make sure the rematerialization offset is shifted by the Shift 146 // value. 147 if (getIndex()) 148 assert(!getIndex()->isRematerializable()); 149 Ostream &Str = Func->getContext()->getStrEmit(); 150 if (SegmentReg != DefaultSegment) { 151 assert(SegmentReg >= 0 && SegmentReg < SegReg_NUM); 152 Str << "%" << X8632::Traits::InstSegmentRegNames[SegmentReg] << ":"; 153 } 154 // Emit as Offset(Base,Index,1<<Shift). Offset is emitted without the leading 155 // '$'. Omit the (Base,Index,1<<Shift) part if Base==nullptr. 156 if (getOffset() == nullptr && Disp == 0) { 157 // No offset, emit nothing. 158 } else if (getOffset() == nullptr && Disp != 0) { 159 Str << Disp; 160 } else if (const auto *CI = llvm::dyn_cast<ConstantInteger32>(getOffset())) { 161 if (getBase() == nullptr || CI->getValue() || Disp != 0) 162 // Emit a non-zero offset without a leading '$'. 163 Str << CI->getValue() + Disp; 164 } else if (const auto *CR = 165 llvm::dyn_cast<ConstantRelocatable>(getOffset())) { 166 // TODO(sehr): ConstantRelocatable still needs updating for 167 // rematerializable base/index and Disp. 168 assert(Disp == 0); 169 CR->emitWithoutPrefix(Target, UseNonsfi ? "@GOTOFF" : ""); 170 } else { 171 llvm_unreachable("Invalid offset type for x86 mem operand"); 172 } 173 174 if (getBase() || getIndex()) { 175 Str << "("; 176 if (getBase()) 177 getBase()->emit(Func); 178 if (getIndex()) { 179 Str << ","; 180 getIndex()->emit(Func); 181 if (getShift()) 182 Str << "," << (1u << getShift()); 183 } 184 Str << ")"; 185 } 186 } 187 188 void TargetX8632Traits::X86OperandMem::dump(const Cfg *Func, 189 Ostream &Str) const { 190 if (!BuildDefs::dump()) 191 return; 192 if (SegmentReg != DefaultSegment) { 193 assert(SegmentReg >= 0 && SegmentReg < SegReg_NUM); 194 Str << X8632::Traits::InstSegmentRegNames[SegmentReg] << ":"; 195 } 196 bool Dumped = false; 197 Str << "["; 198 int32_t Disp = 0; 199 const auto *Target = 200 static_cast<const ::Ice::X8632::TargetX8632 *>(Func->getTarget()); 201 if (getBase() && getBase()->isRematerializable()) { 202 Disp += getRematerializableOffset(getBase(), Target); 203 } 204 if (getBase()) { 205 if (Func) 206 getBase()->dump(Func); 207 else 208 getBase()->dump(Str); 209 Dumped = true; 210 } 211 if (getIndex()) { 212 assert(!getIndex()->isRematerializable()); 213 if (getBase()) 214 Str << "+"; 215 if (getShift() > 0) 216 Str << (1u << getShift()) << "*"; 217 if (Func) 218 getIndex()->dump(Func); 219 else 220 getIndex()->dump(Str); 221 Dumped = true; 222 } 223 if (Disp) { 224 if (Disp > 0) 225 Str << "+"; 226 Str << Disp; 227 Dumped = true; 228 } 229 // Pretty-print the Offset. 230 bool OffsetIsZero = false; 231 bool OffsetIsNegative = false; 232 if (getOffset() == nullptr) { 233 OffsetIsZero = true; 234 } else if (const auto *CI = llvm::dyn_cast<ConstantInteger32>(getOffset())) { 235 OffsetIsZero = (CI->getValue() == 0); 236 OffsetIsNegative = (static_cast<int32_t>(CI->getValue()) < 0); 237 } else { 238 assert(llvm::isa<ConstantRelocatable>(getOffset())); 239 } 240 if (Dumped) { 241 if (!OffsetIsZero) { // Suppress if Offset is known to be 0 242 if (!OffsetIsNegative) // Suppress if Offset is known to be negative 243 Str << "+"; 244 getOffset()->dump(Func, Str); 245 } 246 } else { 247 // There is only the offset. 248 getOffset()->dump(Func, Str); 249 } 250 Str << "]"; 251 } 252 253 void TargetX8632Traits::X86OperandMem::emitSegmentOverride( 254 TargetX8632Traits::Assembler *Asm) const { 255 if (SegmentReg != DefaultSegment) { 256 assert(SegmentReg >= 0 && SegmentReg < SegReg_NUM); 257 Asm->emitSegmentOverride(X8632::Traits::InstSegmentPrefixes[SegmentReg]); 258 } 259 } 260 261 TargetX8632Traits::Address TargetX8632Traits::X86OperandMem::toAsmAddress( 262 TargetX8632Traits::Assembler *Asm, 263 const Ice::TargetLowering *TargetLowering, bool /*IsLeaAddr*/) const { 264 const auto *Target = 265 static_cast<const ::Ice::X8632::TargetX8632 *>(TargetLowering); 266 const bool UseNonsfi = getFlags().getUseNonsfi(); 267 validateMemOperandPIC(this, UseNonsfi); 268 int32_t Disp = 0; 269 if (getBase() && getBase()->isRematerializable()) { 270 Disp += getRematerializableOffset(getBase(), Target); 271 } 272 // The index should never be rematerializable. But if we ever allow it, then 273 // we should make sure the rematerialization offset is shifted by the Shift 274 // value. 275 if (getIndex()) 276 assert(!getIndex()->isRematerializable()); 277 AssemblerFixup *Fixup = nullptr; 278 // Determine the offset (is it relocatable?) 279 if (getOffset()) { 280 if (const auto *CI = llvm::dyn_cast<ConstantInteger32>(getOffset())) { 281 Disp += static_cast<int32_t>(CI->getValue()); 282 } else if (const auto CR = 283 llvm::dyn_cast<ConstantRelocatable>(getOffset())) { 284 Disp += CR->getOffset(); 285 Fixup = Asm->createFixup(Target->getAbsFixup(), CR); 286 } else { 287 llvm_unreachable("Unexpected offset type"); 288 } 289 } 290 291 // Now convert to the various possible forms. 292 if (getBase() && getIndex()) { 293 return X8632::Traits::Address(getEncodedGPR(getBase()->getRegNum()), 294 getEncodedGPR(getIndex()->getRegNum()), 295 X8632::Traits::ScaleFactor(getShift()), Disp, 296 Fixup); 297 } else if (getBase()) { 298 return X8632::Traits::Address(getEncodedGPR(getBase()->getRegNum()), Disp, 299 Fixup); 300 } else if (getIndex()) { 301 return X8632::Traits::Address(getEncodedGPR(getIndex()->getRegNum()), 302 X8632::Traits::ScaleFactor(getShift()), Disp, 303 Fixup); 304 } else { 305 return X8632::Traits::Address(Disp, Fixup); 306 } 307 } 308 309 TargetX8632Traits::Address 310 TargetX8632Traits::VariableSplit::toAsmAddress(const Cfg *Func) const { 311 assert(!Var->hasReg()); 312 const ::Ice::TargetLowering *Target = Func->getTarget(); 313 int32_t Offset = Var->getStackOffset() + getOffset(); 314 return X8632::Traits::Address(getEncodedGPR(Target->getFrameOrStackReg()), 315 Offset, AssemblerFixup::NoFixup); 316 } 317 318 void TargetX8632Traits::VariableSplit::emit(const Cfg *Func) const { 319 if (!BuildDefs::dump()) 320 return; 321 Ostream &Str = Func->getContext()->getStrEmit(); 322 assert(!Var->hasReg()); 323 // The following is copied/adapted from TargetX8632::emitVariable(). 324 const ::Ice::TargetLowering *Target = Func->getTarget(); 325 constexpr Type Ty = IceType_i32; 326 int32_t Offset = Var->getStackOffset() + getOffset(); 327 if (Offset) 328 Str << Offset; 329 Str << "(%" << Target->getRegName(Target->getFrameOrStackReg(), Ty) << ")"; 330 } 331 332 void TargetX8632Traits::VariableSplit::dump(const Cfg *Func, 333 Ostream &Str) const { 334 if (!BuildDefs::dump()) 335 return; 336 switch (Part) { 337 case Low: 338 Str << "low"; 339 break; 340 case High: 341 Str << "high"; 342 break; 343 } 344 Str << "("; 345 if (Func) 346 Var->dump(Func); 347 else 348 Var->dump(Str); 349 Str << ")"; 350 } 351 352 } // namespace X8632 353 } // end of namespace Ice 354 355 X86INSTS_DEFINE_STATIC_DATA(X8632, X8632::Traits) 356