From 62e4c671b6b0f13c04a20bb43c05bfe84984ef34 Mon Sep 17 00:00:00 2001 From: Daniel Dunbar Date: Sat, 22 May 2010 21:02:33 +0000 Subject: [PATCH] MC/X86: Subdivide immediates a bit more, so that we properly recognize immediates based on the width of the target instruction. For example: addw $0xFFFF, %ax should match the same as addw $-1, %ax but we used to match it to the longer encoding. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@104453 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Target/X86/AsmParser/X86AsmParser.cpp | 85 ++++++++++++------ lib/Target/X86/X86Instr64bit.td | 4 +- lib/Target/X86/X86InstrInfo.td | 39 ++++++-- test/MC/AsmParser/X86/x86_64-imm-widths.s | 105 ++++++++++++++++++++++ 4 files changed, 195 insertions(+), 38 deletions(-) create mode 100644 test/MC/AsmParser/X86/x86_64-imm-widths.s diff --git a/lib/Target/X86/AsmParser/X86AsmParser.cpp b/lib/Target/X86/AsmParser/X86AsmParser.cpp index b291ef63b70..25ec6ce150c 100644 --- a/lib/Target/X86/AsmParser/X86AsmParser.cpp +++ b/lib/Target/X86/AsmParser/X86AsmParser.cpp @@ -186,32 +186,71 @@ struct X86Operand : public MCParsedAsmOperand { bool isImm() const { return Kind == Immediate; } - bool isImmSExt8() const { - // Accept immediates which fit in 8 bits when sign extended, and - // non-absolute immediates. + bool isImmSExti16i8() const { if (!isImm()) return false; - if (const MCConstantExpr *CE = dyn_cast(getImm())) { - int64_t Value = CE->getValue(); - return Value == (int64_t) (int8_t) Value; - } + // If this isn't a constant expr, just assume it fits and let relaxation + // handle it. + const MCConstantExpr *CE = dyn_cast(getImm()); + if (!CE) + return true; - return true; + // Otherwise, check the value is in a range that makes sense for this + // extension. + uint64_t Value = CE->getValue(); + return (( Value <= 0x000000000000007FULL)|| + (0x000000000000FF80ULL <= Value && Value <= 0x000000000000FFFFULL)|| + (0xFFFFFFFFFFFFFF80ULL <= Value && Value <= 0xFFFFFFFFFFFFFFFFULL)); } - - bool isImmSExt32() const { - // Accept immediates which fit in 32 bits when sign extended, and - // non-absolute immediates. + bool isImmSExti32i8() const { if (!isImm()) return false; - if (const MCConstantExpr *CE = dyn_cast(getImm())) { - int64_t Value = CE->getValue(); - return Value == (int64_t) (int32_t) Value; - } + // If this isn't a constant expr, just assume it fits and let relaxation + // handle it. + const MCConstantExpr *CE = dyn_cast(getImm()); + if (!CE) + return true; - return true; + // Otherwise, check the value is in a range that makes sense for this + // extension. + uint64_t Value = CE->getValue(); + return (( Value <= 0x000000000000007FULL)|| + (0x00000000FFFFFF80ULL <= Value && Value <= 0x00000000FFFFFFFFULL)|| + (0xFFFFFFFFFFFFFF80ULL <= Value && Value <= 0xFFFFFFFFFFFFFFFFULL)); + } + bool isImmSExti64i8() const { + if (!isImm()) + return false; + + // If this isn't a constant expr, just assume it fits and let relaxation + // handle it. + const MCConstantExpr *CE = dyn_cast(getImm()); + if (!CE) + return true; + + // Otherwise, check the value is in a range that makes sense for this + // extension. + uint64_t Value = CE->getValue(); + return (( Value <= 0x000000000000007FULL)|| + (0xFFFFFFFFFFFFFF80ULL <= Value && Value <= 0xFFFFFFFFFFFFFFFFULL)); + } + bool isImmSExti64i32() const { + if (!isImm()) + return false; + + // If this isn't a constant expr, just assume it fits and let relaxation + // handle it. + const MCConstantExpr *CE = dyn_cast(getImm()); + if (!CE) + return true; + + // Otherwise, check the value is in a range that makes sense for this + // extension. + uint64_t Value = CE->getValue(); + return (( Value <= 0x000000007FFFFFFFULL)|| + (0xFFFFFFFF80000000ULL <= Value && Value <= 0xFFFFFFFFFFFFFFFFULL)); } bool isMem() const { return Kind == Memory; } @@ -245,18 +284,6 @@ struct X86Operand : public MCParsedAsmOperand { addExpr(Inst, getImm()); } - void addImmSExt8Operands(MCInst &Inst, unsigned N) const { - // FIXME: Support user customization of the render method. - assert(N == 1 && "Invalid number of operands!"); - addExpr(Inst, getImm()); - } - - void addImmSExt32Operands(MCInst &Inst, unsigned N) const { - // FIXME: Support user customization of the render method. - assert(N == 1 && "Invalid number of operands!"); - addExpr(Inst, getImm()); - } - void addMemOperands(MCInst &Inst, unsigned N) const { assert((N == 5) && "Invalid number of operands!"); Inst.addOperand(MCOperand::CreateReg(getMemBaseReg())); diff --git a/lib/Target/X86/X86Instr64bit.td b/lib/Target/X86/X86Instr64bit.td index 24a1296c163..f2919f54f1b 100644 --- a/lib/Target/X86/X86Instr64bit.td +++ b/lib/Target/X86/X86Instr64bit.td @@ -19,7 +19,7 @@ // 64-bits but only 32 bits are significant. def i64i32imm : Operand { - let ParserMatchClass = ImmSExt32AsmOperand; + let ParserMatchClass = ImmSExti64i32AsmOperand; } // 64-bits but only 32 bits are significant, and those bits are treated as being @@ -32,7 +32,7 @@ def i64i32imm_pcrel : Operand { // 64-bits but only 8 bits are significant. def i64i8imm : Operand { - let ParserMatchClass = ImmSExt8AsmOperand; + let ParserMatchClass = ImmSExti64i8AsmOperand; } // Special i64mem for addresses of load folding tail calls. These are not diff --git a/lib/Target/X86/X86InstrInfo.td b/lib/Target/X86/X86InstrInfo.td index 5a5535a2db3..6e73766c8cc 100644 --- a/lib/Target/X86/X86InstrInfo.td +++ b/lib/Target/X86/X86InstrInfo.td @@ -270,24 +270,49 @@ def SSECC : Operand { let PrintMethod = "printSSECC"; } -def ImmSExt32AsmOperand : AsmOperandClass { - let Name = "ImmSExt32"; +class ImmSExtAsmOperandClass : AsmOperandClass { let SuperClasses = [ImmAsmOperand]; + let RenderMethod = "addImmOperands"; } -def ImmSExt8AsmOperand : AsmOperandClass { - let Name = "ImmSExt8"; - let SuperClasses = [ImmSExt32AsmOperand]; +// Sign-extended immediate classes. We don't need to define the full lattice +// here because there is no instruction with an ambiguity between ImmSExti64i32 +// and ImmSExti32i8. +// +// The strange ranges come from the fact that the assembler always works with +// 64-bit immediates, but for a 16-bit target value we want to accept both "-1" +// (which will be a -1ULL), and "0xFF" (-1 in 16-bits). + +// [0, 0x7FFFFFFF] | [0xFFFFFFFF80000000, 0xFFFFFFFFFFFFFFFF] +def ImmSExti64i32AsmOperand : ImmSExtAsmOperandClass { + let Name = "ImmSExti64i32"; +} + +// [0, 0x0000007F] | [0x000000000000FF80, 0x000000000000FFFF] | [0xFFFFFFFFFFFFFF80, 0xFFFFFFFFFFFFFFFF] +def ImmSExti16i8AsmOperand : ImmSExtAsmOperandClass { + let Name = "ImmSExti16i8"; + let SuperClasses = [ImmSExti64i32AsmOperand]; +} + +// [0, 0x0000007F] | [0x00000000FFFFFF80, 0x00000000FFFFFFFF] | [0xFFFFFFFFFFFFFF80, 0xFFFFFFFFFFFFFFFF] +def ImmSExti32i8AsmOperand : ImmSExtAsmOperandClass { + let Name = "ImmSExti32i8"; +} + +// [0, 0x0000007F] | [0xFFFFFFFFFFFFFF80, 0xFFFFFFFFFFFFFFFF] +def ImmSExti64i8AsmOperand : ImmSExtAsmOperandClass { + let Name = "ImmSExti64i8"; + let SuperClasses = [ImmSExti16i8AsmOperand, ImmSExti32i8AsmOperand, ImmSExti64i32AsmOperand]; } // A couple of more descriptive operand definitions. // 16-bits but only 8 bits are significant. def i16i8imm : Operand { - let ParserMatchClass = ImmSExt8AsmOperand; + let ParserMatchClass = ImmSExti16i8AsmOperand; } // 32-bits but only 8 bits are significant. def i32i8imm : Operand { - let ParserMatchClass = ImmSExt8AsmOperand; + let ParserMatchClass = ImmSExti32i8AsmOperand; } //===----------------------------------------------------------------------===// diff --git a/test/MC/AsmParser/X86/x86_64-imm-widths.s b/test/MC/AsmParser/X86/x86_64-imm-widths.s new file mode 100644 index 00000000000..6243717ba82 --- /dev/null +++ b/test/MC/AsmParser/X86/x86_64-imm-widths.s @@ -0,0 +1,105 @@ +// RUN: llvm-mc -triple x86_64- --show-encoding %s | FileCheck %s + +// CHECK: addb $0, %al +// CHECK: encoding: [0x04,0x00] + addb $0x00, %al + +// CHECK: addb $127, %al +// CHECK: encoding: [0x04,0x7f] + addb $0x7F, %al + +// CHECK: addb $128, %al +// CHECK: encoding: [0x04,0x80] + addb $0x80, %al + +// CHECK: addb $255, %al +// CHECK: encoding: [0x04,0xff] + addb $0xFF, %al + +// CHECK: addw $0, %ax +// CHECK: encoding: [0x66,0x83,0xc0,0x00] + addw $0x0000, %ax + +// CHECK: addw $127, %ax +// CHECK: encoding: [0x66,0x83,0xc0,0x7f] + addw $0x007F, %ax + +// CHECK: addw $65408, %ax +// CHECK: encoding: [0x66,0x83,0xc0,0x80] + addw $0xFF80, %ax + +// CHECK: addw $65535, %ax +// CHECK: encoding: [0x66,0x83,0xc0,0xff] + addw $0xFFFF, %ax + +// CHECK: addl $0, %eax +// CHECK: encoding: [0x83,0xc0,0x00] + addl $0x00000000, %eax + +// CHECK: addl $127, %eax +// CHECK: encoding: [0x83,0xc0,0x7f] + addl $0x0000007F, %eax + +// CHECK: addl $65408, %eax +// CHECK: encoding: [0x05,0x80,0xff,0x00,0x00] + addl $0xFF80, %eax + +// CHECK: addl $65535, %eax +// CHECK: encoding: [0x05,0xff,0xff,0x00,0x00] + addl $0xFFFF, %eax + +// CHECK: addl $4294967168, %eax +// CHECK: encoding: [0x83,0xc0,0x80] + addl $0xFFFFFF80, %eax + +// CHECK: addl $4294967295, %eax +// CHECK: encoding: [0x83,0xc0,0xff] + addl $0xFFFFFFFF, %eax + +// CHECK: addq $0, %rax +// CHECK: encoding: [0x48,0x83,0xc0,0x00] + addq $0x0000000000000000, %rax + +// CHECK: addq $127, %rax +// CHECK: encoding: [0x48,0x83,0xc0,0x7f] + addq $0x000000000000007F, %rax + +// CHECK: addq $-128, %rax +// CHECK: encoding: [0x48,0x83,0xc0,0x80] + addq $0xFFFFFFFFFFFFFF80, %rax + +// CHECK: addq $-1, %rax +// CHECK: encoding: [0x48,0x83,0xc0,0xff] + addq $0xFFFFFFFFFFFFFFFF, %rax + +// CHECK: addq $0, %rax +// CHECK: encoding: [0x48,0x83,0xc0,0x00] + addq $0x0000000000000000, %rax + +// CHECK: addq $65408, %rax +// CHECK: encoding: [0x48,0x05,0x80,0xff,0x00,0x00] + addq $0xFF80, %rax + +// CHECK: addq $65535, %rax +// CHECK: encoding: [0x48,0x05,0xff,0xff,0x00,0x00] + addq $0xFFFF, %rax + +// CHECK: movq $4294967168, %rax +// CHECK: encoding: [0x48,0xb8,0x80,0xff,0xff,0xff,0x00,0x00,0x00,0x00] + movq $0xFFFFFF80, %rax + +// CHECK: movq $4294967295, %rax +// CHECK: encoding: [0x48,0xb8,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00] + movq $0xFFFFFFFF, %rax + +// CHECK: addq $2147483647, %rax +// CHECK: encoding: [0x48,0x05,0xff,0xff,0xff,0x7f] + addq $0x000000007FFFFFFF, %rax + +// CHECK: addq $-2147483648, %rax +// CHECK: encoding: [0x48,0x05,0x00,0x00,0x00,0x80] + addq $0xFFFFFFFF80000000, %rax + +// CHECK: addq $-256, %rax +// CHECK: encoding: [0x48,0x05,0x00,0xff,0xff,0xff] + addq $0xFFFFFFFFFFFFFF00, %rax