uint64_t R600MCCodeEmitter::getMachineOpValue(const MCInst &MI, const MCOperand &MO, SmallVectorImpl<MCFixup> &Fixups, const MCSubtargetInfo &STI) const { if (MO.isReg()) { if (HAS_NATIVE_OPERANDS(MCII.get(MI.getOpcode()).TSFlags)) return MRI.getEncodingValue(MO.getReg()); return getHWReg(MO.getReg()); } if (MO.isExpr()) { const MCSymbolRefExpr *Expr = cast<MCSymbolRefExpr>(MO.getExpr()); // We put rodata at the end of code section, then map the entire // code secetion as vtx buf. Thus the section relative address is the // correct one. // Each R600 literal instruction has two operands // We can't easily get the order of the current one, so compare against // the first one and adjust offset. const unsigned offset = (&MO == &MI.getOperand(0)) ? 0 : 4; Fixups.push_back(MCFixup::create(offset, Expr, FK_SecRel_4, MI.getLoc())); return 0; } assert(MO.isImm()); return MO.getImm(); }
/// getAddSubImmOpValue - Return encoding for the 12-bit immediate value and /// the 2-bit shift field. The shift field is stored in bits 13-14 of the /// return value. uint32_t AArch64MCCodeEmitter::getAddSubImmOpValue(const MCInst &MI, unsigned OpIdx, SmallVectorImpl<MCFixup> &Fixups, const MCSubtargetInfo &STI) const { // Suboperands are [imm, shifter]. const MCOperand &MO = MI.getOperand(OpIdx); const MCOperand &MO1 = MI.getOperand(OpIdx + 1); assert(AArch64_AM::getShiftType(MO1.getImm()) == AArch64_AM::LSL && "unexpected shift type for add/sub immediate"); unsigned ShiftVal = AArch64_AM::getShiftValue(MO1.getImm()); assert((ShiftVal == 0 || ShiftVal == 12) && "unexpected shift value for add/sub immediate"); if (MO.isImm()) return MO.getImm() | (ShiftVal == 0 ? 0 : (1 << ShiftVal)); assert(MO.isExpr() && "Unable to encode MCOperand!"); const MCExpr *Expr = MO.getExpr(); // Encode the 12 bits of the fixup. MCFixupKind Kind = MCFixupKind(AArch64::fixup_aarch64_add_imm12); Fixups.push_back(MCFixup::create(0, Expr, Kind, MI.getLoc())); ++MCNumFixups; // Set the shift bit of the add instruction for relocation types // R_AARCH64_TLSLE_ADD_TPREL_HI12 and R_AARCH64_TLSLD_ADD_DTPREL_HI12. if (const AArch64MCExpr *A64E = dyn_cast<AArch64MCExpr>(Expr)) { AArch64MCExpr::VariantKind RefKind = A64E->getKind(); if (RefKind == AArch64MCExpr::VK_TPREL_HI12 || RefKind == AArch64MCExpr::VK_DTPREL_HI12) ShiftVal = 12; } return ShiftVal == 0 ? 0 : (1 << ShiftVal); }
/// getAddSubImmOpValue - Return encoding for the 12-bit immediate value and /// the 2-bit shift field. The shift field is stored in bits 13-14 of the /// return value. uint32_t AArch64MCCodeEmitter::getAddSubImmOpValue(const MCInst &MI, unsigned OpIdx, SmallVectorImpl<MCFixup> &Fixups, const MCSubtargetInfo &STI) const { // Suboperands are [imm, shifter]. const MCOperand &MO = MI.getOperand(OpIdx); const MCOperand &MO1 = MI.getOperand(OpIdx + 1); assert(AArch64_AM::getShiftType(MO1.getImm()) == AArch64_AM::LSL && "unexpected shift type for add/sub immediate"); unsigned ShiftVal = AArch64_AM::getShiftValue(MO1.getImm()); assert((ShiftVal == 0 || ShiftVal == 12) && "unexpected shift value for add/sub immediate"); if (MO.isImm()) return MO.getImm() | (ShiftVal == 0 ? 0 : (1 << ShiftVal)); assert(MO.isExpr() && "Unable to encode MCOperand!"); const MCExpr *Expr = MO.getExpr(); // Encode the 12 bits of the fixup. MCFixupKind Kind = MCFixupKind(AArch64::fixup_aarch64_add_imm12); Fixups.push_back(MCFixup::create(0, Expr, Kind, MI.getLoc())); ++MCNumFixups; return ShiftVal == 0 ? 0 : (1 << ShiftVal); }
void WebAssemblyMCCodeEmitter::encodeInstruction( const MCInst &MI, raw_ostream &OS, SmallVectorImpl<MCFixup> &Fixups, const MCSubtargetInfo &STI) const { // FIXME: This is not the real binary encoding. This is an extremely // over-simplified encoding where we just use uint64_t for everything. This // is a temporary measure. support::endian::Writer<support::little>(OS).write<uint64_t>(MI.getOpcode()); const MCInstrDesc &Desc = MCII.get(MI.getOpcode()); if (Desc.isVariadic()) support::endian::Writer<support::little>(OS).write<uint64_t>( MI.getNumOperands() - Desc.NumOperands); for (unsigned i = 0, e = MI.getNumOperands(); i < e; ++i) { const MCOperand &MO = MI.getOperand(i); if (MO.isReg()) { support::endian::Writer<support::little>(OS).write<uint64_t>(MO.getReg()); } else if (MO.isImm()) { support::endian::Writer<support::little>(OS).write<uint64_t>(MO.getImm()); } else if (MO.isFPImm()) { support::endian::Writer<support::little>(OS).write<double>(MO.getFPImm()); } else if (MO.isExpr()) { support::endian::Writer<support::little>(OS).write<uint64_t>(0); Fixups.push_back(MCFixup::create( (1 + MCII.get(MI.getOpcode()).isVariadic() + i) * sizeof(uint64_t), MO.getExpr(), STI.getTargetTriple().isArch64Bit() ? FK_Data_8 : FK_Data_4, MI.getLoc())); ++MCNumFixups; } else { llvm_unreachable("unexpected operand kind"); } } ++MCNumEmitted; // Keep track of the # of mi's emitted. }
// Expand PseudoAddTPRel to a simple ADD with the correct relocation. void RISCVMCCodeEmitter::expandAddTPRel(const MCInst &MI, raw_ostream &OS, SmallVectorImpl<MCFixup> &Fixups, const MCSubtargetInfo &STI) const { MCOperand DestReg = MI.getOperand(0); MCOperand SrcReg = MI.getOperand(1); MCOperand TPReg = MI.getOperand(2); assert(TPReg.isReg() && TPReg.getReg() == RISCV::X4 && "Expected thread pointer as second input to TP-relative add"); MCOperand SrcSymbol = MI.getOperand(3); assert(SrcSymbol.isExpr() && "Expected expression as third input to TP-relative add"); const RISCVMCExpr *Expr = dyn_cast<RISCVMCExpr>(SrcSymbol.getExpr()); assert(Expr && Expr->getKind() == RISCVMCExpr::VK_RISCV_TPREL_ADD && "Expected tprel_add relocation on TP-relative symbol"); // Emit the correct tprel_add relocation for the symbol. Fixups.push_back(MCFixup::create( 0, Expr, MCFixupKind(RISCV::fixup_riscv_tprel_add), MI.getLoc())); // Emit fixup_riscv_relax for tprel_add where the relax feature is enabled. if (STI.getFeatureBits()[RISCV::FeatureRelax]) { const MCConstantExpr *Dummy = MCConstantExpr::create(0, Ctx); Fixups.push_back(MCFixup::create( 0, Dummy, MCFixupKind(RISCV::fixup_riscv_relax), MI.getLoc())); } // Emit a normal ADD instruction with the given operands. MCInst TmpInst = MCInstBuilder(RISCV::ADD) .addOperand(DestReg) .addOperand(SrcReg) .addOperand(TPReg); uint32_t Binary = getBinaryCodeForInstr(TmpInst, Fixups, STI); support::endian::write(OS, Binary, support::little); }
uint32_t AArch64MCCodeEmitter::getMoveWideImmOpValue(const MCInst &MI, unsigned OpIdx, SmallVectorImpl<MCFixup> &Fixups, const MCSubtargetInfo &STI) const { const MCOperand &MO = MI.getOperand(OpIdx); if (MO.isImm()) return MO.getImm(); assert(MO.isExpr() && "Unexpected movz/movk immediate"); Fixups.push_back(MCFixup::create( 0, MO.getExpr(), MCFixupKind(AArch64::fixup_aarch64_movw), MI.getLoc())); ++MCNumFixups; return 0; }
/// getTestBranchTargetOpValue - Return the encoded value for a test-bit-and- /// branch target. uint32_t AArch64MCCodeEmitter::getTestBranchTargetOpValue( const MCInst &MI, unsigned OpIdx, SmallVectorImpl<MCFixup> &Fixups, const MCSubtargetInfo &STI) const { const MCOperand &MO = MI.getOperand(OpIdx); // If the destination is an immediate, we have nothing to do. if (MO.isImm()) return MO.getImm(); assert(MO.isExpr() && "Unexpected ADR target type!"); MCFixupKind Kind = MCFixupKind(AArch64::fixup_aarch64_pcrel_branch14); Fixups.push_back(MCFixup::create(0, MO.getExpr(), Kind, MI.getLoc())); ++MCNumFixups; // All of the information is in the fixup. return 0; }
template<unsigned FixupKind> uint32_t AArch64MCCodeEmitter::getLdStUImm12OpValue(const MCInst &MI, unsigned OpIdx, SmallVectorImpl<MCFixup> &Fixups, const MCSubtargetInfo &STI) const { const MCOperand &MO = MI.getOperand(OpIdx); uint32_t ImmVal = 0; if (MO.isImm()) ImmVal = static_cast<uint32_t>(MO.getImm()); else { assert(MO.isExpr() && "unable to encode load/store imm operand"); MCFixupKind Kind = MCFixupKind(FixupKind); Fixups.push_back(MCFixup::create(0, MO.getExpr(), Kind, MI.getLoc())); ++MCNumFixups; } return ImmVal; }
/// getAdrLabelOpValue - Return encoding info for 21-bit immediate ADR label /// target. uint32_t AArch64MCCodeEmitter::getAdrLabelOpValue(const MCInst &MI, unsigned OpIdx, SmallVectorImpl<MCFixup> &Fixups, const MCSubtargetInfo &STI) const { const MCOperand &MO = MI.getOperand(OpIdx); // If the destination is an immediate, we have nothing to do. if (MO.isImm()) return MO.getImm(); assert(MO.isExpr() && "Unexpected target type!"); const MCExpr *Expr = MO.getExpr(); MCFixupKind Kind = MI.getOpcode() == AArch64::ADR ? MCFixupKind(AArch64::fixup_aarch64_pcrel_adr_imm21) : MCFixupKind(AArch64::fixup_aarch64_pcrel_adrp_imm21); Fixups.push_back(MCFixup::create(0, Expr, Kind, MI.getLoc())); MCNumFixups += 1; // All of the information is in the fixup. return 0; }
void WebAssemblyMCCodeEmitter::encodeInstruction( const MCInst &MI, raw_ostream &OS, SmallVectorImpl<MCFixup> &Fixups, const MCSubtargetInfo &STI) const { uint64_t Start = OS.tell(); uint64_t Binary = getBinaryCodeForInstr(MI, Fixups, STI); assert(Binary < UINT8_MAX && "Multi-byte opcodes not supported yet"); OS << uint8_t(Binary); // For br_table instructions, encode the size of the table. In the MCInst, // there's an index operand, one operand for each table entry, and the // default operand. if (MI.getOpcode() == WebAssembly::BR_TABLE_I32 || MI.getOpcode() == WebAssembly::BR_TABLE_I64) encodeULEB128(MI.getNumOperands() - 2, OS); const MCInstrDesc &Desc = MCII.get(MI.getOpcode()); for (unsigned i = 0, e = MI.getNumOperands(); i < e; ++i) { const MCOperand &MO = MI.getOperand(i); if (MO.isReg()) { /* nothing to encode */ } else if (MO.isImm()) { if (i < Desc.getNumOperands()) { assert(Desc.TSFlags == 0 && "WebAssembly non-variable_ops don't use TSFlags"); const MCOperandInfo &Info = Desc.OpInfo[i]; if (Info.OperandType == WebAssembly::OPERAND_I32IMM) { encodeSLEB128(int32_t(MO.getImm()), OS); } else if (Info.OperandType == WebAssembly::OPERAND_I64IMM) { encodeSLEB128(int64_t(MO.getImm()), OS); } else if (Info.OperandType == WebAssembly::OPERAND_GLOBAL) { llvm_unreachable("wasm globals should only be accessed symbolicly"); } else if (Info.OperandType == WebAssembly::OPERAND_SIGNATURE) { encodeSLEB128(int64_t(MO.getImm()), OS); } else { encodeULEB128(uint64_t(MO.getImm()), OS); } } else { assert(Desc.TSFlags == (WebAssemblyII::VariableOpIsImmediate | WebAssemblyII::VariableOpImmediateIsLabel)); encodeULEB128(uint64_t(MO.getImm()), OS); } } else if (MO.isFPImm()) { assert(i < Desc.getNumOperands() && "Unexpected floating-point immediate as a non-fixed operand"); assert(Desc.TSFlags == 0 && "WebAssembly variable_ops floating point ops don't use TSFlags"); const MCOperandInfo &Info = Desc.OpInfo[i]; if (Info.OperandType == WebAssembly::OPERAND_F32IMM) { // TODO: MC converts all floating point immediate operands to double. // This is fine for numeric values, but may cause NaNs to change bits. float f = float(MO.getFPImm()); support::endian::Writer<support::little>(OS).write<float>(f); } else { assert(Info.OperandType == WebAssembly::OPERAND_F64IMM); double d = MO.getFPImm(); support::endian::Writer<support::little>(OS).write<double>(d); } } else if (MO.isExpr()) { const MCOperandInfo &Info = Desc.OpInfo[i]; llvm::MCFixupKind FixupKind; size_t PaddedSize; if (Info.OperandType == WebAssembly::OPERAND_I32IMM) { FixupKind = MCFixupKind(WebAssembly::fixup_code_sleb128_i32); PaddedSize = 5; } else if (Info.OperandType == WebAssembly::OPERAND_I64IMM) { FixupKind = MCFixupKind(WebAssembly::fixup_code_sleb128_i64); PaddedSize = 10; } else if (Info.OperandType == WebAssembly::OPERAND_FUNCTION32 || Info.OperandType == WebAssembly::OPERAND_OFFSET32 || Info.OperandType == WebAssembly::OPERAND_TYPEINDEX) { FixupKind = MCFixupKind(WebAssembly::fixup_code_uleb128_i32); PaddedSize = 5; } else if (Info.OperandType == WebAssembly::OPERAND_GLOBAL) { FixupKind = MCFixupKind(WebAssembly::fixup_code_global_index); PaddedSize = 5; } else { llvm_unreachable("unexpected symbolic operand kind"); } Fixups.push_back(MCFixup::create( OS.tell() - Start, MO.getExpr(), FixupKind, MI.getLoc())); ++MCNumFixups; encodeULEB128(0, OS, PaddedSize - 1); } else { llvm_unreachable("unexpected operand kind"); } } ++MCNumEmitted; // Keep track of the # of mi's emitted. }