diff options
Diffstat (limited to 'lib/Target/X86/X86InstrNaCl.td')
-rw-r--r-- | lib/Target/X86/X86InstrNaCl.td | 437 |
1 files changed, 437 insertions, 0 deletions
diff --git a/lib/Target/X86/X86InstrNaCl.td b/lib/Target/X86/X86InstrNaCl.td new file mode 100644 index 0000000000..a729b88797 --- /dev/null +++ b/lib/Target/X86/X86InstrNaCl.td @@ -0,0 +1,437 @@ +//====- X86InstrNaCl.td - Describe NaCl Instructions ----*- tablegen -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file describes the modifications to the X86 instruction set needed for +// Native Client code generation. +// +//===----------------------------------------------------------------------===// + + +//===----------------------------------------------------------------------===// +// NaCl specific DAG Nodes. +// + +//===----------------------------------------------------------------------===// +// +// Native Client Pseudo-Instructions +// +// These instructions implement the Native Client pseudo-instructions, such +// as nacljmp and naclasp. +// +// TableGen and MC consider these to be "real" instructions. They can be +// parsed by the AsmParser and emitted by the AsmStreamer as if they +// were just regular instructions. They are not marked "Pseudo" because +// this would imply isCodeGenOnly=1, which would stop them from being +// parsed by the assembler. +// +// These instructions cannot be encoded (written into an object file) by the +// MCCodeEmitter. Instead, during direct object emission, they get lowered to +// a sequence of streamer emits. (see X86InstrNaCl.cpp) +// +// These instructions should not be used in CodeGen. They have no pattern +// and lack CodeGen metadata. Instead, the X86NaClRewritePass should +// generate these instructions after CodeGen is finished. +// +//===----------------------------------------------------------------------===// + + +//===----------------------------------------------------------------------===// +// 32-bit Native Client Pseudo Instructions +//===----------------------------------------------------------------------===// + +class NaClPI32<dag outs, dag ins, string asm> + : I<0, CustomFrm, outs, ins, asm, []>, Requires<[IsNaCl, In32BitMode]>; + +let isTerminator = 1, isBarrier = 1, hasCtrlDep = 1, isAsmParserOnly = 1 in { + def NACL_TRAP32 : NaClPI32<(outs), (ins), "nacltrap">; +} + +let isTerminator = 1, isReturn = 1, isBarrier = 1, + hasCtrlDep = 1, FPForm = SpecialFP, isAsmParserOnly = 1 in { + def NACL_RET32 : NaClPI32<(outs), (ins), "naclret">; + def NACL_RETI32 : NaClPI32<(outs), (ins i16imm:$amt), "naclreti\t$amt">; +} + +let isBranch = 1, isTerminator = 1, isBarrier = 1, isIndirectBranch = 1, + isAsmParserOnly = 1 in { + def NACL_JMP32r : NaClPI32<(outs), (ins GR32:$dst), "nacljmp\t$dst">; +} + +let isCall = 1, isAsmParserOnly = 1 in { + def NACL_CALL32d : NaClPI32<(outs), (ins i32imm_pcrel:$dst), + "naclcall\t$dst">; + def NACL_CALL32r : NaClPI32<(outs), (ins GR32:$dst), + "naclcall\t$dst">; +} + +// nacltlsaddr32 gets rewritten to: +// .bundle_align_end +// .bundle_lock +// leal\t$sym@TLSGD, %eax +// call\t___tls_get_addr@PLT +// .bundle_unlock +// (The linker expects the leal+call sequence to be directly adjacent) +let Defs = [EAX, ECX, EDX, FP0, FP1, FP2, FP3, FP4, FP5, FP6, ST0, + MM0, MM1, MM2, MM3, MM4, MM5, MM6, MM7, + XMM0, XMM1, XMM2, XMM3, XMM4, XMM5, XMM6, XMM7, + XMM8, XMM9, XMM10, XMM11, XMM12, XMM13, XMM14, XMM15, EFLAGS], + Uses = [ESP], + isAsmParserOnly = 1 in +def NACL_TLS_addr32 : NaClPI32<(outs), (ins i32mem:$sym), + "nacltlsaddr32\t$sym">; + +//===----------------------------------------------------------------------===// +// 64-bit Native Client Pseudo Instructions +//===----------------------------------------------------------------------===// + +class NaClPI64<dag outs, dag ins, string asm> + : I<0, CustomFrm, outs, ins, asm, []>, Requires<[IsNaCl, In64BitMode]>; + +let isTerminator = 1, isBarrier = 1, hasCtrlDep = 1, isAsmParserOnly = 1 in { + def NACL_TRAP64 : NaClPI64<(outs), (ins), "nacltrap">; +} + +let isTerminator = 1, isReturn = 1, isBarrier = 1, + hasCtrlDep = 1, FPForm = SpecialFP, isAsmParserOnly = 1 in { + def NACL_RET64 : NaClPI64<(outs), (ins), "naclret">; +} + +let isBranch = 1, isTerminator = 1, isBarrier = 1, isIndirectBranch = 1, + isAsmParserOnly = 1 in { + def NACL_JMP64r : NaClPI64<(outs), (ins GR32:$dst, GR64:$rZP), + "nacljmp\t{$dst, $rZP|$rZP, $dst}">; + def NACL_JMP64z : NaClPI64<(outs), (ins GR32:$dst), + "nacljmp\t$dst">; +} + + +let isCall = 1, isAsmParserOnly = 1 in { + def NACL_CALL64d : NaClPI64<(outs), (ins i32imm_pcrel:$dst), + "naclcall\t$dst">; + def NACL_CALL64r : NaClPI64<(outs), (ins GR32:$dst, GR64:$rZP), + "naclcall\t$dst,$rZP">; +} + +let Defs = [RSP, EFLAGS], Uses = [RSP], isAsmParserOnly = 1 in { + def NACL_ASPi8 : NaClPI64<(outs), (ins i64i8imm:$off, GR64:$rZP), + "naclasp{q}\t{$off, $rZP|$rZP, $off}">; + + def NACL_ASPi32: NaClPI64<(outs), (ins i64i32imm:$off, GR64:$rZP), + "naclasp{q}\t{$off, $rZP|$rZP, $off}">; + + def NACL_SSPi8 : NaClPI64<(outs), (ins i64i8imm:$off, GR64:$rZP), + "naclssp{q}\t{$off, $rZP|$rZP, $off}">; + + def NACL_SSPi32: NaClPI64<(outs), (ins i64i32imm:$off, GR64:$rZP), + "naclssp{q}\t{$off, $rZP|$rZP, $off}">; + + def NACL_ANDSPi32: NaClPI64<(outs), (ins i64i32imm:$off, GR64:$rZP), + "naclandsp{q}\t{$off, $rZP|$rZP, $off}">; +} + +let Defs = [RSP], Uses = [RBP], isAsmParserOnly = 1 in { + def NACL_SPADJi32 : NaClPI64<(outs), (ins i64i32imm:$off, GR64:$rZP), + "naclspadj\t{$off, $rZP|$rZP, $off}">; +} + +let Defs = [RSP], isAsmParserOnly = 1 in { + def NACL_RESTSPr : NaClPI64<(outs), (ins GR32:$src, GR64:$rZP), + "naclrestsp_noflags\t{$src, $rZP|$rZP, $src}">; + def NACL_RESTSPm : NaClPI64<(outs), (ins i32mem:$src, GR64:$rZP), + "naclrestsp_noflags\t{$src, $rZP|$rZP, $src}">; + def NACL_RESTSPrz : NaClPI64<(outs), (ins GR32:$src), + "naclrestsp_noflags\t$src">; +} + +def : MnemonicAlias<"naclrestsp", "naclrestsp_noflags">; + +let Defs = [RBP], isAsmParserOnly = 1 in { + def NACL_RESTBPr : NaClPI64<(outs), (ins GR32:$src, GR64:$rZP), + "naclrestbp\t{$src, $rZP|$rZP, $src}">; + def NACL_RESTBPm : NaClPI64<(outs), (ins i32mem:$src, GR64:$rZP), + "naclrestbp\t{$src, $rZP|$rZP, $src}">; + def NACL_RESTBPrz : NaClPI64<(outs), (ins GR32:$src), + "naclrestbp\t$src">; +} + +//===----------------------------------------------------------------------===// +// +// Code Generator Instructions (isCodeGenOnly == 1) +// +// These instructions exists to make CodeGen work with Native Client's +// modifications. +// +// Many of these instructions exist because of limitations in CodeGen +// or TableGen, and may become unnecessary in the future. +//===----------------------------------------------------------------------===// + + +//===----------------------------------------------------------------------===// +// +// CodeGen 32-bit +// +//===----------------------------------------------------------------------===// + + +// To avoid a naming conflict between call/naclcall, we have to +// disable the real CALLpcrel32 and CALL32r instructions when targeting +// for NaCl. Thus, they need to be produced here. + +let isCall = 1 in + // All calls clobber the non-callee saved registers. ESP is marked as + // a use to prevent stack-pointer assignments that appear immediately + // before calls from potentially appearing dead. Uses for argument + // registers are added manually. + let Defs = [EAX, ECX, EDX, FP0, FP1, FP2, FP3, FP4, FP5, FP6, ST0, + MM0, MM1, MM2, MM3, MM4, MM5, MM6, MM7, + XMM0, XMM1, XMM2, XMM3, XMM4, XMM5, XMM6, XMM7, + XMM8, XMM9, XMM10, XMM11, XMM12, XMM13, XMM14, XMM15, EFLAGS], + Uses = [ESP] in { + + def NACL_CG_CALLpcrel32 : I<0, Pseudo, + (outs), (ins i32imm_pcrel:$dst), + "naclcall\t$dst", []>, + Requires<[IsNaCl, In32BitMode]>; + def NACL_CG_CALL32r : I<0, Pseudo, + (outs), (ins GR32:$dst), + "naclcall\t$dst", [(X86call GR32:$dst)]>, + Requires<[IsNaCl, In32BitMode]>; +} + +// Normal calls, with various flavors of addresses. +def : Pat<(X86call (i32 tglobaladdr:$dst)), + (NACL_CG_CALLpcrel32 tglobaladdr:$dst)>, + Requires<[IsNaCl, In32BitMode]>; +def : Pat<(X86call (i32 texternalsym:$dst)), + (NACL_CG_CALLpcrel32 texternalsym:$dst)>, + Requires<[IsNaCl, In32BitMode]>; +def : Pat<(X86call (i32 imm:$dst)), + (NACL_CG_CALLpcrel32 imm:$dst)>, + Requires<[IsNaCl, In32BitMode, CallImmAddr]>; + +//===----------------------------------------------------------------------===// +// +// CodeGen 64-bit +// +//===----------------------------------------------------------------------===// + + +// Because pointers are 32-bit on X86-64 Native Client, we need to +// produce new versions of the JMP64/CALL64 instructions which can accept +// addresses which are i32 instead of i64. + +let isBranch = 1, isTerminator = 1, isBarrier = 1, isIndirectBranch = 1 in { + def NACL_CG_JMP64r : I<0, Pseudo, (outs), (ins GR32:$dst), + "nacljmp\t$dst", + [(brind GR32:$dst)]>, + Requires<[IsNaCl, In64BitMode]>; +} + +let isCall = 1 in + // All calls clobber the non-callee saved registers. RSP is marked as + // a use to prevent stack-pointer assignments that appear immediately + // before calls from potentially appearing dead. Uses for argument + // registers are added manually. + let Defs = [RAX, RCX, RDX, RSI, RDI, R8, R9, R10, R11, + FP0, FP1, FP2, FP3, FP4, FP5, FP6, ST0, ST1, + MM0, MM1, MM2, MM3, MM4, MM5, MM6, MM7, + XMM0, XMM1, XMM2, XMM3, XMM4, XMM5, XMM6, XMM7, + XMM8, XMM9, XMM10, XMM11, XMM12, XMM13, XMM14, XMM15, EFLAGS], + Uses = [RSP] in { + + def NACL_CG_CALL64pcrel32 : I<0, Pseudo, (outs), + (ins i32imm_pcrel:$dst), + "naclcall\t$dst", []>, + Requires<[IsNaCl, In64BitMode]>; + + def NACL_CG_CALL64r : I<0, Pseudo, (outs), (ins GR32:$dst), + "naclcall\t$dst,%r15", + [(X86call GR32:$dst)]>, + Requires<[IsNaCl, In64BitMode]>; +} + +def : Pat<(X86call (i32 tglobaladdr:$dst)), + (NACL_CG_CALL64pcrel32 tglobaladdr:$dst)>, + Requires<[IsNaCl, In64BitMode]>; +def : Pat<(X86call (i32 texternalsym:$dst)), + (NACL_CG_CALL64pcrel32 texternalsym:$dst)>, + Requires<[IsNaCl, In64BitMode]>; + +// Tail calls +// Also needed due to the i64 / i32 pointer problem. +let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1, + isCodeGenOnly = 1 in + let Defs = [RAX, RCX, RDX, RSI, RDI, R8, R9, R10, R11, + FP0, FP1, FP2, FP3, FP4, FP5, FP6, ST0, ST1, + MM0, MM1, MM2, MM3, MM4, MM5, MM6, MM7, + XMM0, XMM1, XMM2, XMM3, XMM4, XMM5, XMM6, XMM7, + XMM8, XMM9, XMM10, XMM11, XMM12, XMM13, XMM14, XMM15, EFLAGS], + Uses = [RSP] in { + + def NACL_CG_TCRETURNdi64 : I<0, Pseudo, (outs), + (ins i32imm_pcrel:$dst, i32imm:$offset), + "#TC_RETURN $dst $offset", []>, + Requires<[IsNaCl, In64BitMode]>; + def NACL_CG_TCRETURNri64 : I<0, Pseudo, (outs), + (ins GR32_TC_64:$dst, i32imm:$offset), + "#TC_RETURN $dst $offset", []>, + Requires<[IsNaCl, In64BitMode]>; + + def NACL_CG_TAILJMPd64 : I<0, Pseudo, (outs), + (ins i32imm_pcrel:$dst), + "jmp\t$dst # TAILCALL", []>, + Requires<[IsNaCl, In64BitMode]>; + def NACL_CG_TAILJMPr64 : I<0, Pseudo, (outs), + (ins GR32_TC_64:$dst), + "nacljmp\t$dst,%r15 # TAILCALL", []>, + Requires<[IsNaCl, In64BitMode]>; +} + +def : Pat<(X86tcret (i32 tglobaladdr:$dst), imm:$off), + (NACL_CG_TCRETURNdi64 tglobaladdr:$dst, imm:$off)>, + Requires<[IsNaCl, In64BitMode]>; + +def : Pat<(X86tcret (i32 texternalsym:$dst), imm:$off), + (NACL_CG_TCRETURNdi64 texternalsym:$dst, imm:$off)>, + Requires<[IsNaCl, In64BitMode]>; + +def : Pat<(X86tcret GR32_TC_64:$dst, imm:$off), + (NACL_CG_TCRETURNri64 GR32_TC_64:$dst, imm:$off)>, + Requires<[IsNaCl, In64BitMode]>; + +// ELF TLS Support + +let Defs = [EAX, ECX, EDX, FP0, FP1, FP2, FP3, FP4, FP5, FP6, ST0, + MM0, MM1, MM2, MM3, MM4, MM5, MM6, MM7, + XMM0, XMM1, XMM2, XMM3, XMM4, XMM5, XMM6, XMM7, + XMM8, XMM9, XMM10, XMM11, XMM12, XMM13, XMM14, XMM15, EFLAGS], + Uses = [ESP] in +def NACL_CG_TLS_addr32 : I<0, Pseudo, (outs), (ins i32mem:$sym), + ".bundle_align_end" + ".bundle_lock" + "leal\t$sym, %eax; " + "call\t___tls_get_addr@PLT" + ".bundle_unlock", + [(X86tlsaddr tls32addr:$sym)]>, + Requires<[In32BitMode, IsNaCl]>; + +// These are lowered in X86NaClRewritePass. +let Defs = [RAX, RCX, RDX, RSI, RDI, R8, R9, R10, R11, + FP0, FP1, FP2, FP3, FP4, FP5, FP6, ST0, ST1, + MM0, MM1, MM2, MM3, MM4, MM5, MM6, MM7, + XMM0, XMM1, XMM2, XMM3, XMM4, XMM5, XMM6, XMM7, + XMM8, XMM9, XMM10, XMM11, XMM12, XMM13, XMM14, XMM15, EFLAGS], + Uses = [RSP] in { +def NACL_CG_GD_TLS_addr64 : I<0, Pseudo, (outs), (ins i32mem:$sym), "", + [(X86tlsaddr tls32addr:$sym)]>, + Requires<[IsNaCl, In64BitMode]>; +def NACL_CG_LE_TLS_addr64 : I<0, Pseudo, (outs), (ins i32mem:$sym), "", + [(X86tlsaddr_le tls32addr:$sym)]>, + Requires<[IsNaCl, In64BitMode]>; +def NACL_CG_IE_TLS_addr64 : I<0, Pseudo, (outs), (ins i32mem:$sym), "", + [(X86tlsaddr_ie tls32addr:$sym)]>, + Requires<[IsNaCl, In64BitMode]>; +// For mtls-use-call. +def NACL_CG_LE_TLS_addr32 : I<0, Pseudo, (outs), (ins i32mem:$sym), "", + [(X86tlsaddr_le tls32addr:$sym)]>, + Requires<[IsNaCl, In32BitMode]>; +def NACL_CG_IE_TLS_addr32 : I<0, Pseudo, (outs), (ins i32mem:$sym), "", + [(X86tlsaddr_ie tls32addr:$sym)]>, + Requires<[IsNaCl, In32BitMode]>; +} + +let usesCustomInserter = 1, Defs = [EFLAGS] in +def NACL_CG_VAARG_64 : I<0, Pseudo, + (outs GR32:$dst), + (ins i8mem:$ap, i32imm:$size, i8imm:$mode, i32imm:$align), + "#NACL_VAARG_64 $dst, $ap, $size, $mode, $align", + [(set GR32:$dst, + (X86vaarg64 addr:$ap, imm:$size, imm:$mode, imm:$align)), + (implicit EFLAGS)]>, + Requires<[IsNaCl, In64BitMode]>; + +//===----------------------------------------------------------------------===// +// NativeClient intrinsics +// These provide the ability to implement several low-level features without +// having to link native ASM code on the client. +// These need to be kept in sync with in lib/Target/ARM/ARMInstrInfo.td and +// lib/Target/X86/X86InstrNaCl.cpp. +// TODO(sehr): Separate this code to allow NaCl and non-NaCl versions. + +// Saves all the callee-saves registers, [er]sp, and [er]ip to the JMP_BUF +// structure pointed to by 4(%esp) or rdi. The JMP_BUF structure is the +// maximum size over all supported architectures. The MC expansions happen +// in X86InstrNaCl.cpp. +let Uses = [ECX, RDX], Defs = [EAX, EFLAGS] in { + def NACL_SETJ32 : I<0, Pseudo, (outs), (ins), + "movl %ebx, 0(%ecx); " + "movl %ebp, 4(%ecx); " + "movl %esp, 8(%ecx); " + "movl %esi, 12(%ecx); " + "movl %edi, 16(%ecx); " + "movl %edx, 20(%ecx); " + "xorl %eax, %eax; ", + [(set EAX, (int_nacl_setjmp ECX, EDX))]>, + Requires<[IsNaCl, In32BitMode]>; +} +let Uses = [EDI, RDX], Defs = [EAX, EFLAGS] in { + def NACL_SETJ64 : I<0, Pseudo, (outs), (ins), + "movq %rbx, %nacl:0(%r15, %rdi); " + "movq %rbp, %nacl:8(%r15, %rdi); " + "movq %rsp, %nacl:16(%r15, %rdi); " + "movq %r12, %nacl:24(%r15, %rdi); " + "movq %r13, %nacl:32(%r15, %rdi); " + "movq %r14, %nacl:40(%r15, %rdi); " + "movq %rdx, %nacl:48(%r15, %rdi); " + "xorl %eax, %eax; ", + [(set EAX, (int_nacl_setjmp EDI, EDX))]>, + Requires<[IsNaCl, In64BitMode]>; +} + +// Restores all the callee-saves registers, [er]sp, and [er]ip from the JMP_BUF +// structure pointed to by 4(%esp) or %rdi. Returns the value in 8(%esp) or +// %rsi at entry. This implements the tail of longjmp, with the normalization +// of the return value (if the caller passes zero to longjmp, it should return +// 1) done in the caller. The MC expansions happen in X86InstrNaCl.cpp. +let isBranch = 1, isTerminator = 1, isBarrier = 1, isIndirectBranch = 1, + Uses = [EAX, ECX] in { + def NACL_LONGJ32 : I<0, Pseudo, (outs), (ins), + "movl $$1, %ebx; " + "andl %eax, %eax; " + "cmovzl %ebx, %eax; " + "movl 0(%ecx), %ebx; " + "movl 4(%ecx), %ebp; " + "movl 8(%ecx), %esp; " + "movl 12(%ecx), %esi; " + "movl 16(%ecx), %edi; " + "movl 20(%ecx), %ecx; " + "nacljmp %ecx; ", + [(int_nacl_longjmp ECX, EAX)]>, + Requires<[IsNaCl, In32BitMode]>, TB; +} + +let isBranch = 1, isTerminator = 1, isBarrier = 1, isIndirectBranch = 1, + Uses = [EAX, EDI, R15] in { + def NACL_LONGJ64 : I<0, Pseudo, (outs), (ins), + "movl $$1, %ebx; " + "andl %eax, %eax; " + "cmovzl %ebx, %eax; " + "movq %nacl:0(%r15, %edi), %rbx; " + "movq %nacl:8(%r15, %edi), %rdx; " + "naclrestbp %edx, %r15; " + "movq %nacl:16(%r15, %edi), %rdx; " + "naclrestsp %edx, %r15; " + "movq %nacl:24(%r15, %edi), %r12; " + "movq %nacl:32(%r15, %edi), %r13; " + "movq %nacl:40(%r15, %edi), %r14; " + "movq %nacl:48(%r15, %edi), %rcx; " + "nacljmp %ecx, %r15; ", + [(int_nacl_longjmp EDI, EAX)]>, + Requires<[IsNaCl, In64BitMode]>, TB; +} |