mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-21 00:32:23 +00:00
5d5c0624d0
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@141294 91177308-0d34-0410-b5e6-96231b3b80d8
149 lines
5.1 KiB
TableGen
149 lines
5.1 KiB
TableGen
// This test describes how we eventually want to describe instructions in
|
|
// the target independent code generators.
|
|
// RUN: llvm-tblgen %s
|
|
// XFAIL: vg_leak
|
|
|
|
// Target indep stuff.
|
|
class Instruction { // Would have other stuff eventually
|
|
bit isTwoAddress = 0;
|
|
string AssemblyString;
|
|
}
|
|
class RegisterClass;
|
|
|
|
class RTLNode;
|
|
|
|
def ops; // Marker for operand list.
|
|
|
|
// Various expressions used in RTL descriptions.
|
|
def imm8 : RTLNode;
|
|
def imm32 : RTLNode;
|
|
def addr : RTLNode;
|
|
|
|
def set : RTLNode;
|
|
def signext : RTLNode;
|
|
def zeroext : RTLNode;
|
|
def plus : RTLNode;
|
|
def and : RTLNode;
|
|
def xor : RTLNode;
|
|
def shl : RTLNode;
|
|
def load : RTLNode;
|
|
def store : RTLNode;
|
|
def unspec : RTLNode;
|
|
|
|
// Start of X86 specific stuff.
|
|
|
|
def R8 : RegisterClass;
|
|
def R16 : RegisterClass;
|
|
def R32 : RegisterClass;
|
|
|
|
def CL; // As are currently defined
|
|
def AL;
|
|
def AX;
|
|
def EDX;
|
|
|
|
class Format<bits<5> val> {
|
|
bits<5> Value = val;
|
|
}
|
|
|
|
def Pseudo : Format<0>; def RawFrm : Format<1>;
|
|
def AddRegFrm : Format<2>; def MRMDestReg : Format<3>;
|
|
def MRMDestMem : Format<4>; def MRMSrcReg : Format<5>;
|
|
def MRMSrcMem : Format<6>;
|
|
def MRM0r : Format<16>; def MRM1r : Format<17>; def MRM2r : Format<18>;
|
|
def MRM3r : Format<19>; def MRM4r : Format<20>; def MRM5r : Format<21>;
|
|
def MRM6r : Format<22>; def MRM7r : Format<23>;
|
|
def MRM0m : Format<24>; def MRM1m : Format<25>; def MRM2m : Format<26>;
|
|
def MRM3m : Format<27>; def MRM4m : Format<28>; def MRM5m : Format<29>;
|
|
def MRM6m : Format<30>; def MRM7m : Format<31>;
|
|
|
|
|
|
class Inst<dag opnds, string asmstr, bits<8> opcode,
|
|
Format f, list<dag> rtl> : Instruction {
|
|
dag Operands = opnds;
|
|
string AssemblyString = asmstr;
|
|
bits<8> Opcode = opcode;
|
|
Format Format = f;
|
|
list<dag> RTL = rtl;
|
|
}
|
|
|
|
|
|
// Start of instruction definitions, the real point of this file.
|
|
//
|
|
// Note that these patterns show a couple of important things:
|
|
// 1. The order and contents of the operands of the MachineInstr are
|
|
// described here. Eventually we can do away with this when everything
|
|
// is generated from the description.
|
|
// 2. The asm string is captured here, which makes it possible to get rid of
|
|
// a ton of hacks in the various printers and a bunch of flags.
|
|
// 3. Target specific properties (e.g. Format) can still be captured as
|
|
// needed.
|
|
// 4. We capture the behavior of the instruction with a simplified RTL-like
|
|
// expression.
|
|
// 5. The use/def properties for each operand are automatically inferred from
|
|
// the pattern.
|
|
// 6. Address expressions should become first-class entities.
|
|
|
|
// Simple copy instruction.
|
|
def MOV8rr : Inst<(ops R8:$dst, R8:$src),
|
|
"mov $dst, $src", 0x88, MRMDestReg,
|
|
[(set R8:$dst, R8:$src)]>;
|
|
|
|
// Simple immediate initialization.
|
|
def MOV8ri : Inst<(ops R8:$dst, imm8:$src),
|
|
"mov $dst, $src", 0xB0, AddRegFrm,
|
|
[(set R8:$dst, imm8:$src)]>;
|
|
|
|
// Two address instructions are described as three-addr instructions, with
|
|
// the special target-independent isTwoAddress flag set. The asm pattern
|
|
// should not refer to the $src1, this would be enforced by the
|
|
// TargetInstrInfo tablegen backend.
|
|
let isTwoAddress = 1 in
|
|
def AND8rr : Inst<(ops R8:$dst, R8:$src1, R8:$src2),
|
|
"and $dst, $src2", 0x20, MRMDestReg,
|
|
[(set R8:$dst, (and R8:$src1, R8:$src2))]>;
|
|
|
|
// Instructions that have explicit uses/defs make them explicit in the RTL.
|
|
// Instructions that need extra stuff emitted in the assembly can, trivially.
|
|
let isTwoAddress = 1 in
|
|
def SHL32rCL : Inst<(ops R32:$dst, R32:$src),
|
|
"shl $dst, CL", 0xD2, MRM4r,
|
|
[(set R32:$dst, (shl R32:$src, CL))]>;
|
|
|
|
// The RTL list is a list, allowing complex instructions to be defined easily.
|
|
// Temporary 'internal' registers can be used to break instructions apart.
|
|
let isTwoAddress = 1 in
|
|
def XOR32mi : Inst<(ops addr:$addr, imm32:$imm),
|
|
"xor $dst, $src2", 0x81, MRM6m,
|
|
[(set R32:$tmp1, (load addr:$addr)),
|
|
(set R32:$tmp2, (xor R32:$tmp1, imm32:$imm)),
|
|
(store addr:$addr, R32:$tmp2)]>;
|
|
|
|
// Alternatively, if each tmporary register is only used once, the instruction
|
|
// can just be described in nested form. This would be the canonical
|
|
// representation the target generator would convert the above into. Pick your
|
|
// favorite indentation scheme.
|
|
let isTwoAddress = 1 in
|
|
def AND32mr : Inst<(ops addr:$addr, R32:$src),
|
|
"xor $dst, $src2", 0x81, MRM6m,
|
|
[(store addr:$addr,
|
|
(and
|
|
(load addr:$addr),
|
|
R32:$src)
|
|
)
|
|
]>;
|
|
|
|
// Describing complex instructions is not too hard! Note how implicit uses/defs
|
|
// become explicit here.
|
|
def CBW : Inst<(ops),
|
|
"cbw", 0x98, RawFrm,
|
|
[(set AX, (signext AL))]>;
|
|
|
|
// Noop, does nothing.
|
|
def NOOP : Inst<(ops), "nop", 0x90, RawFrm, []>;
|
|
|
|
|
|
// Instructions that don't expect optimization can use unspec.
|
|
def IN8rr : Inst<(ops), "in AL, EDX", 0xEC, RawFrm,
|
|
[(set AL, (unspec EDX))]>;
|
|
|