ARMMCInstLower.cpp 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. //===-- ARMMCInstLower.cpp - Convert ARM MachineInstr to an MCInst --------===//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. //
  9. // This file contains code to lower ARM MachineInstrs to their corresponding
  10. // MCInst records.
  11. //
  12. //===----------------------------------------------------------------------===//
  13. #include "ARM.h"
  14. #include "ARMAsmPrinter.h"
  15. #include "ARMBaseInstrInfo.h"
  16. #include "ARMMachineFunctionInfo.h"
  17. #include "ARMSubtarget.h"
  18. #include "MCTargetDesc/ARMAddressingModes.h"
  19. #include "MCTargetDesc/ARMBaseInfo.h"
  20. #include "MCTargetDesc/ARMMCExpr.h"
  21. #include "llvm/ADT/APFloat.h"
  22. #include "llvm/CodeGen/MachineBasicBlock.h"
  23. #include "llvm/CodeGen/MachineInstr.h"
  24. #include "llvm/CodeGen/MachineOperand.h"
  25. #include "llvm/IR/Constants.h"
  26. #include "llvm/MC/MCContext.h"
  27. #include "llvm/MC/MCExpr.h"
  28. #include "llvm/MC/MCInst.h"
  29. #include "llvm/MC/MCInstBuilder.h"
  30. #include "llvm/MC/MCStreamer.h"
  31. #include "llvm/Support/ErrorHandling.h"
  32. #include <cassert>
  33. #include <cstdint>
  34. using namespace llvm;
  35. MCOperand ARMAsmPrinter::GetSymbolRef(const MachineOperand &MO,
  36. const MCSymbol *Symbol) {
  37. MCSymbolRefExpr::VariantKind SymbolVariant = MCSymbolRefExpr::VK_None;
  38. if (MO.getTargetFlags() & ARMII::MO_SBREL)
  39. SymbolVariant = MCSymbolRefExpr::VK_ARM_SBREL;
  40. const MCExpr *Expr =
  41. MCSymbolRefExpr::create(Symbol, SymbolVariant, OutContext);
  42. switch (MO.getTargetFlags() & ARMII::MO_OPTION_MASK) {
  43. default:
  44. llvm_unreachable("Unknown target flag on symbol operand");
  45. case ARMII::MO_NO_FLAG:
  46. break;
  47. case ARMII::MO_LO16:
  48. Expr =
  49. MCSymbolRefExpr::create(Symbol, SymbolVariant, OutContext);
  50. Expr = ARMMCExpr::createLower16(Expr, OutContext);
  51. break;
  52. case ARMII::MO_HI16:
  53. Expr =
  54. MCSymbolRefExpr::create(Symbol, SymbolVariant, OutContext);
  55. Expr = ARMMCExpr::createUpper16(Expr, OutContext);
  56. break;
  57. }
  58. if (!MO.isJTI() && MO.getOffset())
  59. Expr = MCBinaryExpr::createAdd(Expr,
  60. MCConstantExpr::create(MO.getOffset(),
  61. OutContext),
  62. OutContext);
  63. return MCOperand::createExpr(Expr);
  64. }
  65. bool ARMAsmPrinter::lowerOperand(const MachineOperand &MO,
  66. MCOperand &MCOp) {
  67. switch (MO.getType()) {
  68. default: llvm_unreachable("unknown operand type");
  69. case MachineOperand::MO_Register:
  70. // Ignore all implicit register operands.
  71. if (MO.isImplicit())
  72. return false;
  73. assert(!MO.getSubReg() && "Subregs should be eliminated!");
  74. MCOp = MCOperand::createReg(MO.getReg());
  75. break;
  76. case MachineOperand::MO_Immediate:
  77. MCOp = MCOperand::createImm(MO.getImm());
  78. break;
  79. case MachineOperand::MO_MachineBasicBlock:
  80. MCOp = MCOperand::createExpr(MCSymbolRefExpr::create(
  81. MO.getMBB()->getSymbol(), OutContext));
  82. break;
  83. case MachineOperand::MO_GlobalAddress:
  84. MCOp = GetSymbolRef(MO,
  85. GetARMGVSymbol(MO.getGlobal(), MO.getTargetFlags()));
  86. break;
  87. case MachineOperand::MO_ExternalSymbol:
  88. MCOp = GetSymbolRef(MO,
  89. GetExternalSymbolSymbol(MO.getSymbolName()));
  90. break;
  91. case MachineOperand::MO_JumpTableIndex:
  92. MCOp = GetSymbolRef(MO, GetJTISymbol(MO.getIndex()));
  93. break;
  94. case MachineOperand::MO_ConstantPoolIndex:
  95. if (Subtarget->genExecuteOnly())
  96. llvm_unreachable("execute-only should not generate constant pools");
  97. MCOp = GetSymbolRef(MO, GetCPISymbol(MO.getIndex()));
  98. break;
  99. case MachineOperand::MO_BlockAddress:
  100. MCOp = GetSymbolRef(MO, GetBlockAddressSymbol(MO.getBlockAddress()));
  101. break;
  102. case MachineOperand::MO_FPImmediate: {
  103. APFloat Val = MO.getFPImm()->getValueAPF();
  104. bool ignored;
  105. Val.convert(APFloat::IEEEdouble(), APFloat::rmTowardZero, &ignored);
  106. MCOp = MCOperand::createDFPImm(bit_cast<uint64_t>(Val.convertToDouble()));
  107. break;
  108. }
  109. case MachineOperand::MO_RegisterMask:
  110. // Ignore call clobbers.
  111. return false;
  112. }
  113. return true;
  114. }
  115. void llvm::LowerARMMachineInstrToMCInst(const MachineInstr *MI, MCInst &OutMI,
  116. ARMAsmPrinter &AP) {
  117. OutMI.setOpcode(MI->getOpcode());
  118. // In the MC layer, we keep modified immediates in their encoded form
  119. bool EncodeImms = false;
  120. switch (MI->getOpcode()) {
  121. default: break;
  122. case ARM::MOVi:
  123. case ARM::MVNi:
  124. case ARM::CMPri:
  125. case ARM::CMNri:
  126. case ARM::TSTri:
  127. case ARM::TEQri:
  128. case ARM::MSRi:
  129. case ARM::ADCri:
  130. case ARM::ADDri:
  131. case ARM::ADDSri:
  132. case ARM::SBCri:
  133. case ARM::SUBri:
  134. case ARM::SUBSri:
  135. case ARM::ANDri:
  136. case ARM::ORRri:
  137. case ARM::EORri:
  138. case ARM::BICri:
  139. case ARM::RSBri:
  140. case ARM::RSBSri:
  141. case ARM::RSCri:
  142. EncodeImms = true;
  143. break;
  144. }
  145. for (const MachineOperand &MO : MI->operands()) {
  146. MCOperand MCOp;
  147. if (AP.lowerOperand(MO, MCOp)) {
  148. if (MCOp.isImm() && EncodeImms) {
  149. int32_t Enc = ARM_AM::getSOImmVal(MCOp.getImm());
  150. if (Enc != -1)
  151. MCOp.setImm(Enc);
  152. }
  153. OutMI.addOperand(MCOp);
  154. }
  155. }
  156. }
  157. void ARMAsmPrinter::EmitSled(const MachineInstr &MI, SledKind Kind)
  158. {
  159. if (MI.getParent()->getParent()->getInfo<ARMFunctionInfo>()
  160. ->isThumbFunction())
  161. {
  162. MI.emitError("An attempt to perform XRay instrumentation for a"
  163. " Thumb function (not supported). Detected when emitting a sled.");
  164. return;
  165. }
  166. static const int8_t NoopsInSledCount = 6;
  167. // We want to emit the following pattern:
  168. //
  169. // .Lxray_sled_N:
  170. // ALIGN
  171. // B #20
  172. // ; 6 NOP instructions (24 bytes)
  173. // .tmpN
  174. //
  175. // We need the 24 bytes (6 instructions) because at runtime, we'd be patching
  176. // over the full 28 bytes (7 instructions) with the following pattern:
  177. //
  178. // PUSH{ r0, lr }
  179. // MOVW r0, #<lower 16 bits of function ID>
  180. // MOVT r0, #<higher 16 bits of function ID>
  181. // MOVW ip, #<lower 16 bits of address of __xray_FunctionEntry/Exit>
  182. // MOVT ip, #<higher 16 bits of address of __xray_FunctionEntry/Exit>
  183. // BLX ip
  184. // POP{ r0, lr }
  185. //
  186. OutStreamer->emitCodeAlignment(Align(4), &getSubtargetInfo());
  187. auto CurSled = OutContext.createTempSymbol("xray_sled_", true);
  188. OutStreamer->emitLabel(CurSled);
  189. auto Target = OutContext.createTempSymbol();
  190. // Emit "B #20" instruction, which jumps over the next 24 bytes (because
  191. // register pc is 8 bytes ahead of the jump instruction by the moment CPU
  192. // is executing it).
  193. // By analogy to ARMAsmPrinter::emitPseudoExpansionLowering() |case ARM::B|.
  194. // It is not clear why |addReg(0)| is needed (the last operand).
  195. EmitToStreamer(*OutStreamer, MCInstBuilder(ARM::Bcc).addImm(20)
  196. .addImm(ARMCC::AL).addReg(0));
  197. emitNops(NoopsInSledCount);
  198. OutStreamer->emitLabel(Target);
  199. recordSled(CurSled, MI, Kind, 2);
  200. }
  201. void ARMAsmPrinter::LowerPATCHABLE_FUNCTION_ENTER(const MachineInstr &MI)
  202. {
  203. EmitSled(MI, SledKind::FUNCTION_ENTER);
  204. }
  205. void ARMAsmPrinter::LowerPATCHABLE_FUNCTION_EXIT(const MachineInstr &MI)
  206. {
  207. EmitSled(MI, SledKind::FUNCTION_EXIT);
  208. }
  209. void ARMAsmPrinter::LowerPATCHABLE_TAIL_CALL(const MachineInstr &MI)
  210. {
  211. EmitSled(MI, SledKind::TAIL_CALL);
  212. }