mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-01-31 20:51:52 +01:00
[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
This commit is contained in:
parent
66a94dc7aa
commit
c2c8aeb508
@ -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); }
|
||||
|
@ -25,6 +25,14 @@ def u16imm64 : Operand<i64> {
|
||||
let EncoderMethod = "getImm16Encoding";
|
||||
let ParserMatchClass = PPCU16ImmAsmOperand;
|
||||
}
|
||||
def s17imm64 : Operand<i64> {
|
||||
// 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<iPTR> {
|
||||
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))]>;
|
||||
|
||||
|
@ -446,6 +446,18 @@ def u16imm : Operand<i32> {
|
||||
let EncoderMethod = "getImm16Encoding";
|
||||
let ParserMatchClass = PPCU16ImmAsmOperand;
|
||||
}
|
||||
def PPCS17ImmAsmOperand : AsmOperandClass {
|
||||
let Name = "S17Imm"; let PredicateMethod = "isS17Imm";
|
||||
let RenderMethod = "addImmOperands";
|
||||
}
|
||||
def s17imm : Operand<i32> {
|
||||
// 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)]>;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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]
|
||||
|
Loading…
x
Reference in New Issue
Block a user