From 5a02a02b411de878c031be9262ceee80fd582eb6 Mon Sep 17 00:00:00 2001 From: Ulrich Weigand Date: Wed, 26 Jun 2013 13:49:53 +0000 Subject: [PATCH] [PowerPC] Accept 17-bit signed immediates for addis The assembler currently strictly verifies that immediates for s16imm operands are in range (-32768 ... 32767). This matches the behaviour of the GNU assembler, with one exception: gas allows, as a special case, operands in an extended range (-65536 .. 65535) for the addis instruction only (and its extended mnemonic lis). The main reason for this seems to be to allow using unsigned 16-bit operands for lis, e.g. like lis %r1, 0xfedc. Since this has been supported by gas for a long time, and assembler source code seen "in the wild" actually exploits this feature, this patch adds equivalent support to LLVM for compatibility reasons. llvm-svn: 184946 --- llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp | 2 ++ llvm/lib/Target/PowerPC/PPCInstr64Bit.td | 12 ++++++++++-- llvm/lib/Target/PowerPC/PPCInstrInfo.td | 16 ++++++++++++++-- llvm/test/MC/PowerPC/ppc64-errors.s | 8 ++++++++ llvm/test/MC/PowerPC/ppc64-operands.s | 8 ++++++++ 5 files changed, 42 insertions(+), 4 deletions(-) diff --git a/llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp b/llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp index 2310bb3..cbe1321 100644 --- a/llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp +++ b/llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp @@ -267,6 +267,8 @@ public: bool isS16ImmX4() const { return Kind == Expression || (Kind == Immediate && isInt<16>(getImm()) && (getImm() & 3) == 0); } + bool isS17Imm() const { return Kind == Expression || + (Kind == Immediate && isInt<17>(getImm())); } bool isDirectBr() const { return Kind == Expression || (Kind == Immediate && isInt<26>(getImm()) && (getImm() & 3) == 0); } diff --git a/llvm/lib/Target/PowerPC/PPCInstr64Bit.td b/llvm/lib/Target/PowerPC/PPCInstr64Bit.td index f63ca24..b0386c3 100644 --- a/llvm/lib/Target/PowerPC/PPCInstr64Bit.td +++ b/llvm/lib/Target/PowerPC/PPCInstr64Bit.td @@ -25,6 +25,14 @@ def u16imm64 : Operand { let EncoderMethod = "getImm16Encoding"; let ParserMatchClass = PPCU16ImmAsmOperand; } +def s17imm64 : Operand { + // This operand type is used for addis/lis to allow the assembler parser + // to accept immediates in the range -65536..65535 for compatibility with + // the GNU assembler. The operand is treated as 16-bit otherwise. + let PrintMethod = "printS16ImmOperand"; + let EncoderMethod = "getImm16Encoding"; + let ParserMatchClass = PPCS17ImmAsmOperand; +} def tocentry : Operand { let MIOperandInfo = (ops i64imm:$imm); } @@ -330,7 +338,7 @@ let isReMaterializable = 1, isAsCheapAsAMove = 1, isMoveImm = 1 in { def LI8 : DForm_2_r0<14, (outs g8rc:$rD), (ins s16imm64:$imm), "li $rD, $imm", IntSimple, [(set i64:$rD, imm64SExt16:$imm)]>; -def LIS8 : DForm_2_r0<15, (outs g8rc:$rD), (ins s16imm64:$imm), +def LIS8 : DForm_2_r0<15, (outs g8rc:$rD), (ins s17imm64:$imm), "lis $rD, $imm", IntSimple, [(set i64:$rD, imm16ShiftedSExt:$imm)]>; } @@ -406,7 +414,7 @@ def ADDIC8 : DForm_2<12, (outs g8rc:$rD), (ins g8rc:$rA, s16imm64:$imm), def ADDI8 : DForm_2<14, (outs g8rc:$rD), (ins g8rc_nox0:$rA, s16imm64:$imm), "addi $rD, $rA, $imm", IntSimple, [(set i64:$rD, (add i64:$rA, imm64SExt16:$imm))]>; -def ADDIS8 : DForm_2<15, (outs g8rc:$rD), (ins g8rc_nox0:$rA, s16imm64:$imm), +def ADDIS8 : DForm_2<15, (outs g8rc:$rD), (ins g8rc_nox0:$rA, s17imm64:$imm), "addis $rD, $rA, $imm", IntSimple, [(set i64:$rD, (add i64:$rA, imm16ShiftedSExt:$imm))]>; diff --git a/llvm/lib/Target/PowerPC/PPCInstrInfo.td b/llvm/lib/Target/PowerPC/PPCInstrInfo.td index a970696..28396fd 100644 --- a/llvm/lib/Target/PowerPC/PPCInstrInfo.td +++ b/llvm/lib/Target/PowerPC/PPCInstrInfo.td @@ -446,6 +446,18 @@ def u16imm : Operand { let EncoderMethod = "getImm16Encoding"; let ParserMatchClass = PPCU16ImmAsmOperand; } +def PPCS17ImmAsmOperand : AsmOperandClass { + let Name = "S17Imm"; let PredicateMethod = "isS17Imm"; + let RenderMethod = "addImmOperands"; +} +def s17imm : Operand { + // This operand type is used for addis/lis to allow the assembler parser + // to accept immediates in the range -65536..65535 for compatibility with + // the GNU assembler. The operand is treated as 16-bit otherwise. + let PrintMethod = "printS16ImmOperand"; + let EncoderMethod = "getImm16Encoding"; + let ParserMatchClass = PPCS17ImmAsmOperand; +} def PPCDirectBrAsmOperand : AsmOperandClass { let Name = "DirectBr"; let PredicateMethod = "isDirectBr"; let RenderMethod = "addBranchTargetOperands"; @@ -1519,7 +1531,7 @@ def ADDICo : DForm_2<13, (outs gprc:$rD), (ins gprc:$rA, s16imm:$imm), "addic. $rD, $rA, $imm", IntGeneral, []>, isDOT, RecFormRel; } -def ADDIS : DForm_2<15, (outs gprc:$rD), (ins gprc_nor0:$rA, s16imm:$imm), +def ADDIS : DForm_2<15, (outs gprc:$rD), (ins gprc_nor0:$rA, s17imm:$imm), "addis $rD, $rA, $imm", IntSimple, [(set i32:$rD, (add i32:$rA, imm16ShiftedSExt:$imm))]>; let isCodeGenOnly = 1 in @@ -1539,7 +1551,7 @@ let isReMaterializable = 1, isAsCheapAsAMove = 1, isMoveImm = 1 in { def LI : DForm_2_r0<14, (outs gprc:$rD), (ins s16imm:$imm), "li $rD, $imm", IntSimple, [(set i32:$rD, imm32SExt16:$imm)]>; - def LIS : DForm_2_r0<15, (outs gprc:$rD), (ins s16imm:$imm), + def LIS : DForm_2_r0<15, (outs gprc:$rD), (ins s17imm:$imm), "lis $rD, $imm", IntSimple, [(set i32:$rD, imm16ShiftedSExt:$imm)]>; } diff --git a/llvm/test/MC/PowerPC/ppc64-errors.s b/llvm/test/MC/PowerPC/ppc64-errors.s index 1da5753..8b6dd53 100644 --- a/llvm/test/MC/PowerPC/ppc64-errors.s +++ b/llvm/test/MC/PowerPC/ppc64-errors.s @@ -32,6 +32,14 @@ # CHECK-NEXT: ori 1, 2, 65536 ori 1, 2, 65536 +# Signed 16-bit immediate operands (extended range for addis) + +# CHECK: error: invalid operand for instruction + addis 1, 0, -65537 + +# CHECK: error: invalid operand for instruction + addis 1, 0, 65536 + # D-Form memory operands # CHECK: error: invalid register number diff --git a/llvm/test/MC/PowerPC/ppc64-operands.s b/llvm/test/MC/PowerPC/ppc64-operands.s index 5cc6a3c..cb96fd4 100644 --- a/llvm/test/MC/PowerPC/ppc64-operands.s +++ b/llvm/test/MC/PowerPC/ppc64-operands.s @@ -40,6 +40,14 @@ # CHECK: ori 1, 2, 65535 # encoding: [0x60,0x41,0xff,0xff] ori 1, 2, 65535 +# Signed 16-bit immediate operands (extended range for addis) + +# CHECK: addis 1, 0, 0 # encoding: [0x3c,0x20,0x00,0x00] + addis 1, 0, -65536 + +# CHECK: addis 1, 0, -1 # encoding: [0x3c,0x20,0xff,0xff] + addis 1, 0, 65535 + # D-Form memory operands # CHECK: lwz 1, 0(0) # encoding: [0x80,0x20,0x00,0x00] -- 2.7.4