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