// CHECK-SAME: mov [ebx + $$4], ecx
// CHECK-SAME: "*m,~{eax},~{ebx},~{dirflag},~{fpsr},~{flags}"(%struct.t3_type* %{{.*}})
}
+
+void bar() {}
+
+void t5() {
+ __asm {
+ call bar
+ jmp bar
+ }
+ // CHECK: t5
+ // CHECK: call void asm sideeffect inteldialect
+ // CHECK-SAME: call qword ptr ${0:P}
+ // CHECK-SAME: jmp qword ptr ${1:P}
+ // CHECK-SAME: "*m,*m,~{dirflag},~{fpsr},~{flags}"(void (...)* bitcast (void ()* @bar to void (...)*), void (...)* bitcast (void ()* @bar to void (...)*))
+}
/// These are flags set on operands, but should be considered
/// private, all access should go through the MCOperandInfo accessors.
/// See the accessors for a description of what these are.
-enum OperandFlags { LookupPtrRegClass = 0, Predicate, OptionalDef };
+enum OperandFlags {
+ LookupPtrRegClass = 0,
+ Predicate,
+ OptionalDef,
+ BranchTarget
+};
/// Operands are tagged with one of the values of this enum.
enum OperandType {
/// Set if this operand is a optional def.
bool isOptionalDef() const { return Flags & (1 << MCOI::OptionalDef); }
+ /// Set if this operand is a branch target.
+ bool isBranchTarget() const { return Flags & (1 << MCOI::BranchTarget); }
+
bool isGenericType() const {
return OperandType >= MCOI::OPERAND_FIRST_GENERIC &&
OperandType <= MCOI::OPERAND_LAST_GENERIC;
/// variable/label? Only valid when parsing MS-style inline assembly.
virtual bool needAddressOf() const { return false; }
- /// isCallOperand - Is this an operand of an inline-assembly call instruction?
- /// Only valid when parsing MS-style inline assembly.
- virtual bool isCallOperand() const { return false; }
-
/// isOffsetOfLocal - Do we need to emit code to get the offset of the local
/// variable, rather than its value? Only valid when parsing MS-style inline
/// assembly.
InputDecls.push_back(OpDecl);
InputDeclsAddressOf.push_back(Operand.needAddressOf());
InputConstraints.push_back(Constraint.str());
- if (Operand.isCallOperand())
+ if (Desc.OpInfo[i - 1].isBranchTarget())
AsmStrRewrites.emplace_back(AOK_CallInput, Start, SymName.size());
else
AsmStrRewrites.emplace_back(AOK_Input, Start, SymName.size());
}
}
- // Mark the operands of a call instruction. These need to be handled
- // differently when referenced in MS-style inline assembly.
- if (Name.startswith("call") || Name.startswith("lcall")) {
- for (size_t i = 1; i < Operands.size(); ++i) {
- X86Operand &Op = static_cast<X86Operand &>(*Operands[i]);
- Op.setCallOperand(true);
- }
- }
-
if (Flags)
Operands.push_back(X86Operand::CreatePrefix(Flags, NameLoc, NameLoc));
return false;
bool needAddressOf() const override { return AddressOf; }
- bool isCallOperand() const override { return CallOperand; }
- void setCallOperand(bool IsCallOperand) { CallOperand = IsCallOperand; }
-
bool isMem() const override { return Kind == Memory; }
bool isMemUnsized() const {
return Kind == Memory && Mem.Size == 0;
// registers are added manually.
let Uses = [ESP, SSP] in {
def CALLpcrel32 : Ii32PCRel<0xE8, RawFrm,
- (outs), (ins i32imm_pcrel:$dst),
+ (outs), (ins i32imm_brtarget:$dst),
"call{l}\t$dst", []>, OpSize32,
Requires<[Not64BitMode]>, Sched<[WriteJump]>;
let hasSideEffects = 0 in
def CALLpcrel16 : Ii16PCRel<0xE8, RawFrm,
- (outs), (ins i16imm_pcrel:$dst),
+ (outs), (ins i16imm_brtarget:$dst),
"call{w}\t$dst", []>, OpSize16,
Sched<[WriteJump]>;
def CALL16r : I<0xFF, MRM2r, (outs), (ins GR16:$dst),
// Tail call stuff.
let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1,
isCodeGenOnly = 1, Uses = [ESP, SSP] in {
- def TCRETURNdi : PseudoI<(outs), (ins i32imm_pcrel:$dst, i32imm:$offset),
+ def TCRETURNdi : PseudoI<(outs), (ins i32imm_brtarget:$dst, i32imm:$offset),
[]>, Sched<[WriteJump]>, NotMemoryFoldable;
def TCRETURNri : PseudoI<(outs), (ins ptr_rc_tailcall:$dst, i32imm:$offset),
[]>, Sched<[WriteJump]>, NotMemoryFoldable;
def TCRETURNmi : PseudoI<(outs), (ins i32mem_TC:$dst, i32imm:$offset),
[]>, Sched<[WriteJumpLd]>;
- def TAILJMPd : PseudoI<(outs), (ins i32imm_pcrel:$dst),
+ def TAILJMPd : PseudoI<(outs), (ins i32imm_brtarget:$dst),
[]>, Sched<[WriteJump]>;
def TAILJMPr : PseudoI<(outs), (ins ptr_rc_tailcall:$dst),
isCodeGenOnly = 1, SchedRW = [WriteJump] in
let Uses = [ESP, EFLAGS, SSP] in {
def TCRETURNdicc : PseudoI<(outs),
- (ins i32imm_pcrel:$dst, i32imm:$offset, i32imm:$cond), []>;
+ (ins i32imm_brtarget:$dst, i32imm:$offset, i32imm:$cond),
+ []>;
// This gets substituted to a conditional jump instruction in MC lowering.
- def TAILJMPd_CC : PseudoI<(outs), (ins i32imm_pcrel:$dst, i32imm:$cond), []>;
+ def TAILJMPd_CC : PseudoI<(outs), (ins i32imm_brtarget:$dst, i32imm:$cond), []>;
}
// that the offset between an arbitrary immediate and the call will fit in
// the 32-bit pcrel field that we have.
def CALL64pcrel32 : Ii32PCRel<0xE8, RawFrm,
- (outs), (ins i64i32imm_pcrel:$dst),
+ (outs), (ins i64i32imm_brtarget:$dst),
"call{q}\t$dst", []>, OpSize32,
Requires<[In64BitMode]>;
def CALL64r : I<0xFF, MRM2r, (outs), (ins GR64:$dst),
let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1,
isCodeGenOnly = 1, Uses = [RSP, SSP] in {
def TCRETURNdi64 : PseudoI<(outs),
- (ins i64i32imm_pcrel:$dst, i32imm:$offset),
+ (ins i64i32imm_brtarget:$dst, i32imm:$offset),
[]>, Sched<[WriteJump]>;
def TCRETURNri64 : PseudoI<(outs),
(ins ptr_rc_tailcall:$dst, i32imm:$offset),
(ins i64mem_TC:$dst, i32imm:$offset),
[]>, Sched<[WriteJumpLd]>, NotMemoryFoldable;
- def TAILJMPd64 : PseudoI<(outs), (ins i64i32imm_pcrel:$dst),
+ def TAILJMPd64 : PseudoI<(outs), (ins i64i32imm_brtarget:$dst),
[]>, Sched<[WriteJump]>;
def TAILJMPr64 : PseudoI<(outs), (ins ptr_rc_tailcall:$dst),
isCodeGenOnly = 1, SchedRW = [WriteJump] in
let Uses = [RSP, EFLAGS, SSP] in {
def TCRETURNdi64cc : PseudoI<(outs),
- (ins i64i32imm_pcrel:$dst, i32imm:$offset,
+ (ins i64i32imm_brtarget:$dst, i32imm:$offset,
i32imm:$cond), []>;
// This gets substituted to a conditional jump instruction in MC lowering.
def TAILJMPd64_CC : PseudoI<(outs),
- (ins i64i32imm_pcrel:$dst, i32imm:$cond), []>;
+ (ins i64i32imm_brtarget:$dst, i32imm:$cond), []>;
}
let OperandType = "OPERAND_MEMORY";
}
-let OperandType = "OPERAND_PCREL",
- ParserMatchClass = X86AbsMemAsmOperand,
- PrintMethod = "printPCRelImm" in {
-def i32imm_pcrel : Operand<i32>;
-def i16imm_pcrel : Operand<i16>;
-
-// Branch targets have OtherVT type and print as pc-relative values.
-def brtarget : Operand<OtherVT>;
-def brtarget8 : Operand<OtherVT>;
-
-}
-
// Special parser to detect 16-bit mode to select 16-bit displacement.
def X86AbsMem16AsmOperand : AsmOperandClass {
let Name = "AbsMem16";
let SuperClasses = [X86AbsMemAsmOperand];
}
-// Branch targets have OtherVT type and print as pc-relative values.
-let OperandType = "OPERAND_PCREL",
- PrintMethod = "printPCRelImm" in {
-let ParserMatchClass = X86AbsMem16AsmOperand in
- def brtarget16 : Operand<OtherVT>;
-let ParserMatchClass = X86AbsMemAsmOperand in
- def brtarget32 : Operand<OtherVT>;
+// Branch targets print as pc-relative values.
+class BranchTargetOperand<ValueType ty> : Operand<ty> {
+ let OperandType = "OPERAND_PCREL";
+ let PrintMethod = "printPCRelImm";
+ let ParserMatchClass = X86AbsMemAsmOperand;
+}
+
+def i32imm_brtarget : BranchTargetOperand<i32>;
+def i16imm_brtarget : BranchTargetOperand<i16>;
+
+// 64-bits but only 32 bits are significant, and those bits are treated as being
+// pc relative.
+def i64i32imm_brtarget : BranchTargetOperand<i64>;
+
+def brtarget : BranchTargetOperand<OtherVT>;
+def brtarget8 : BranchTargetOperand<OtherVT>;
+def brtarget16 : BranchTargetOperand<OtherVT> {
+ let ParserMatchClass = X86AbsMem16AsmOperand;
}
+def brtarget32 : BranchTargetOperand<OtherVT>;
let RenderMethod = "addSrcIdxOperands" in {
def X86SrcIdx8Operand : AsmOperandClass {
let OperandType = "OPERAND_IMMEDIATE";
}
-// 64-bits but only 32 bits are significant, and those bits are treated as being
-// pc relative.
-def i64i32imm_pcrel : Operand<i64> {
- let PrintMethod = "printPCRelImm";
- let ParserMatchClass = X86AbsMemAsmOperand;
- let OperandType = "OPERAND_PCREL";
-}
-
def lea64_32mem : Operand<i32> {
let PrintMethod = "printanymem";
let MIOperandInfo = (ops GR64, i8imm, GR64_NOSP, i32imm, SEGMENT_REG);
if (Op.Rec->isSubClassOf("OptionalDefOperand"))
Res += "|(1<<MCOI::OptionalDef)";
+ // Branch target operands. Check to see if the original unexpanded
+ // operand was of type BranchTargetOperand.
+ if (Op.Rec->isSubClassOf("BranchTargetOperand"))
+ Res += "|(1<<MCOI::BranchTarget)";
+
// Fill in operand type.
Res += ", ";
assert(!Op.OperandType.empty() && "Invalid operand type.");
TYPE("i128mem", TYPE_M)
TYPE("i256mem", TYPE_M)
TYPE("i512mem", TYPE_M)
- TYPE("i64i32imm_pcrel", TYPE_REL)
- TYPE("i16imm_pcrel", TYPE_REL)
- TYPE("i32imm_pcrel", TYPE_REL)
+ TYPE("i64i32imm_brtarget", TYPE_REL)
+ TYPE("i16imm_brtarget", TYPE_REL)
+ TYPE("i32imm_brtarget", TYPE_REL)
TYPE("ccode", TYPE_IMM)
TYPE("AVX512RC", TYPE_IMM)
TYPE("brtarget32", TYPE_REL)
if(OpSize != X86Local::OpSize16) {
// For instructions without an OpSize prefix, a declared 16-bit register or
// immediate encoding is special.
- ENCODING("i16imm", ENCODING_IW)
+ ENCODING("i16imm", ENCODING_IW)
}
- ENCODING("i16imm", ENCODING_Iv)
- ENCODING("i16i8imm", ENCODING_IB)
- ENCODING("i32imm", ENCODING_Iv)
- ENCODING("i32i8imm", ENCODING_IB)
- ENCODING("i64i32imm", ENCODING_ID)
- ENCODING("i64i8imm", ENCODING_IB)
- ENCODING("i8imm", ENCODING_IB)
- ENCODING("u8imm", ENCODING_IB)
- ENCODING("i16u8imm", ENCODING_IB)
- ENCODING("i32u8imm", ENCODING_IB)
- ENCODING("i64u8imm", ENCODING_IB)
- ENCODING("i64i32imm_pcrel", ENCODING_ID)
- ENCODING("i16imm_pcrel", ENCODING_IW)
- ENCODING("i32imm_pcrel", ENCODING_ID)
- ENCODING("brtarget32", ENCODING_ID)
- ENCODING("brtarget16", ENCODING_IW)
- ENCODING("brtarget8", ENCODING_IB)
- ENCODING("i64imm", ENCODING_IO)
- ENCODING("offset16_8", ENCODING_Ia)
- ENCODING("offset16_16", ENCODING_Ia)
- ENCODING("offset16_32", ENCODING_Ia)
- ENCODING("offset32_8", ENCODING_Ia)
- ENCODING("offset32_16", ENCODING_Ia)
- ENCODING("offset32_32", ENCODING_Ia)
- ENCODING("offset32_64", ENCODING_Ia)
- ENCODING("offset64_8", ENCODING_Ia)
- ENCODING("offset64_16", ENCODING_Ia)
- ENCODING("offset64_32", ENCODING_Ia)
- ENCODING("offset64_64", ENCODING_Ia)
- ENCODING("srcidx8", ENCODING_SI)
- ENCODING("srcidx16", ENCODING_SI)
- ENCODING("srcidx32", ENCODING_SI)
- ENCODING("srcidx64", ENCODING_SI)
- ENCODING("dstidx8", ENCODING_DI)
- ENCODING("dstidx16", ENCODING_DI)
- ENCODING("dstidx32", ENCODING_DI)
- ENCODING("dstidx64", ENCODING_DI)
+ ENCODING("i16imm", ENCODING_Iv)
+ ENCODING("i16i8imm", ENCODING_IB)
+ ENCODING("i32imm", ENCODING_Iv)
+ ENCODING("i32i8imm", ENCODING_IB)
+ ENCODING("i64i32imm", ENCODING_ID)
+ ENCODING("i64i8imm", ENCODING_IB)
+ ENCODING("i8imm", ENCODING_IB)
+ ENCODING("u8imm", ENCODING_IB)
+ ENCODING("i16u8imm", ENCODING_IB)
+ ENCODING("i32u8imm", ENCODING_IB)
+ ENCODING("i64u8imm", ENCODING_IB)
+ ENCODING("i64i32imm_brtarget", ENCODING_ID)
+ ENCODING("i16imm_brtarget", ENCODING_IW)
+ ENCODING("i32imm_brtarget", ENCODING_ID)
+ ENCODING("brtarget32", ENCODING_ID)
+ ENCODING("brtarget16", ENCODING_IW)
+ ENCODING("brtarget8", ENCODING_IB)
+ ENCODING("i64imm", ENCODING_IO)
+ ENCODING("offset16_8", ENCODING_Ia)
+ ENCODING("offset16_16", ENCODING_Ia)
+ ENCODING("offset16_32", ENCODING_Ia)
+ ENCODING("offset32_8", ENCODING_Ia)
+ ENCODING("offset32_16", ENCODING_Ia)
+ ENCODING("offset32_32", ENCODING_Ia)
+ ENCODING("offset32_64", ENCODING_Ia)
+ ENCODING("offset64_8", ENCODING_Ia)
+ ENCODING("offset64_16", ENCODING_Ia)
+ ENCODING("offset64_32", ENCODING_Ia)
+ ENCODING("offset64_64", ENCODING_Ia)
+ ENCODING("srcidx8", ENCODING_SI)
+ ENCODING("srcidx16", ENCODING_SI)
+ ENCODING("srcidx32", ENCODING_SI)
+ ENCODING("srcidx64", ENCODING_SI)
+ ENCODING("dstidx8", ENCODING_DI)
+ ENCODING("dstidx16", ENCODING_DI)
+ ENCODING("dstidx32", ENCODING_DI)
+ ENCODING("dstidx64", ENCODING_DI)
errs() << "Unhandled relocation encoding " << s << "\n";
llvm_unreachable("Unhandled relocation encoding");
}