mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-12 13:30:51 +00:00
Fun x86 encoding tricks: when adding an immediate value of 128,
use a SUB instruction instead of an ADD, because -128 can be encoded in an 8-bit signed immediate field, while +128 can't be. This avoids the need for a 32-bit immediate field in this case. A similar optimization applies to 64-bit adds with 0x80000000, with the 32-bit signed immediate field. To support this, teach tablegen how to handle 64-bit constants. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@57663 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
74feef261a
commit
63f97201dc
@ -80,6 +80,7 @@ set( CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${LLVM_BINARY_DIR}/lib )
|
||||
# set(CMAKE_VERBOSE_MAKEFILE true)
|
||||
|
||||
add_definitions( -D__STDC_LIMIT_MACROS )
|
||||
add_definitions( -D__STDC_CONSTANT_MACROS )
|
||||
|
||||
if( LLVM_ON_UNIX )
|
||||
add_definitions( -DLLVM_ON_UNIX )
|
||||
|
@ -483,7 +483,7 @@ CPP.BaseFlags += -include llvm/System/Solaris.h
|
||||
endif
|
||||
|
||||
LD.Flags += -L$(LibDir) -L$(LLVMLibDir)
|
||||
CPP.BaseFlags += -D_GNU_SOURCE -D__STDC_LIMIT_MACROS
|
||||
CPP.BaseFlags += -D_GNU_SOURCE -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS
|
||||
# All -I flags should go here, so that they don't confuse llvm-config.
|
||||
CPP.Flags += $(sort -I$(PROJ_OBJ_DIR) -I$(PROJ_SRC_DIR) \
|
||||
$(patsubst %,-I%/include,\
|
||||
|
@ -61,13 +61,6 @@ def i64immSExt8 : PatLeaf<(i64 imm), [{
|
||||
return (int64_t)N->getZExtValue() == (int8_t)N->getZExtValue();
|
||||
}]>;
|
||||
|
||||
def i64immFFFFFFFF : PatLeaf<(i64 imm), [{
|
||||
// i64immFFFFFFFF - True if this is a specific constant we can't write in
|
||||
// tblgen files.
|
||||
return N->getZExtValue() == 0x00000000FFFFFFFFULL;
|
||||
}]>;
|
||||
|
||||
|
||||
def sextloadi64i8 : PatFrag<(ops node:$ptr), (i64 (sextloadi8 node:$ptr))>;
|
||||
def sextloadi64i16 : PatFrag<(ops node:$ptr), (i64 (sextloadi16 node:$ptr))>;
|
||||
def sextloadi64i32 : PatFrag<(ops node:$ptr), (i64 (sextloadi32 node:$ptr))>;
|
||||
@ -1323,8 +1316,22 @@ def : Pat<(i32 (anyext GR8:$src)),
|
||||
// Some peepholes
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// Odd encoding trick: -128 fits into an 8-bit immediate field while
|
||||
// +128 doesn't, so in this special case use a sub instead of an add.
|
||||
def : Pat<(add GR64:$src1, 128),
|
||||
(SUB64ri8 GR64:$src1, -128)>;
|
||||
def : Pat<(store (add (loadi64 addr:$dst), 128), addr:$dst),
|
||||
(SUB64mi8 addr:$dst, -128)>;
|
||||
|
||||
// The same trick applies for 32-bit immediate fields in 64-bit
|
||||
// instructions.
|
||||
def : Pat<(add GR64:$src1, 0x0000000080000000),
|
||||
(SUB64ri32 GR64:$src1, 0xffffffff80000000)>;
|
||||
def : Pat<(store (add (loadi64 addr:$dst), 0x00000000800000000), addr:$dst),
|
||||
(SUB64mi32 addr:$dst, 0xffffffff80000000)>;
|
||||
|
||||
// r & (2^32-1) ==> movz
|
||||
def : Pat<(and GR64:$src, i64immFFFFFFFF),
|
||||
def : Pat<(and GR64:$src, 0x00000000FFFFFFFF),
|
||||
(MOVZX64rr32 (i32 (EXTRACT_SUBREG GR64:$src, x86_subreg_32bit)))>;
|
||||
// r & (2^16-1) ==> movz
|
||||
def : Pat<(and GR64:$src, 0xffff),
|
||||
|
@ -2911,6 +2911,17 @@ def : Pat<(i32 (and (nvloadi32 addr:$src), (i32 65535))),
|
||||
// Some peepholes
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// Odd encoding trick: -128 fits into an 8-bit immediate field while
|
||||
// +128 doesn't, so in this special case use a sub instead of an add.
|
||||
def : Pat<(add GR16:$src1, 128),
|
||||
(SUB16ri8 GR16:$src1, -128)>;
|
||||
def : Pat<(store (add (loadi16 addr:$dst), 128), addr:$dst),
|
||||
(SUB16mi8 addr:$dst, -128)>;
|
||||
def : Pat<(add GR32:$src1, 128),
|
||||
(SUB32ri8 GR32:$src1, -128)>;
|
||||
def : Pat<(store (add (loadi32 addr:$dst), 128), addr:$dst),
|
||||
(SUB32mi8 addr:$dst, -128)>;
|
||||
|
||||
// r & (2^16-1) ==> movz
|
||||
def : Pat<(and GR32:$src1, 0xffff),
|
||||
(MOVZX32rr16 (i16 (EXTRACT_SUBREG GR32:$src1, x86_subreg_16bit)))>;
|
||||
|
11
test/CodeGen/X86/add-trick32.ll
Normal file
11
test/CodeGen/X86/add-trick32.ll
Normal file
@ -0,0 +1,11 @@
|
||||
; RUN: llvm-as < %s | llc -march=x86 > %t
|
||||
; RUN: not grep add %t
|
||||
; RUN: grep subl %t | count 1
|
||||
|
||||
; The immediate can be encoded in a smaller way if the
|
||||
; instruction is a sub instead of an add.
|
||||
|
||||
define i32 @foo(i32 inreg %a) nounwind {
|
||||
%b = add i32 %a, 128
|
||||
ret i32 %b
|
||||
}
|
15
test/CodeGen/X86/add-trick64.ll
Normal file
15
test/CodeGen/X86/add-trick64.ll
Normal file
@ -0,0 +1,15 @@
|
||||
; RUN: llvm-as < %s | llc -march=x86-64 > %t
|
||||
; RUN: not grep add %t
|
||||
; RUN: grep subq %t | count 2
|
||||
|
||||
; The immediate can be encoded in a smaller way if the
|
||||
; instruction is a sub instead of an add.
|
||||
|
||||
define i64 @foo(i64 inreg %a) nounwind {
|
||||
%b = add i64 %a, 2147483648
|
||||
ret i64 %b
|
||||
}
|
||||
define i64 @bar(i64 inreg %a) nounwind {
|
||||
%b = add i64 %a, 128
|
||||
ret i64 %b
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
// RUN: tblgen %s | grep -- -65536
|
||||
// RUN: tblgen %s | grep -- 4294901760
|
||||
|
||||
def X {
|
||||
int Y = 0xFFFF0000;
|
||||
|
@ -734,7 +734,8 @@ public:
|
||||
emitCode("int64_t CN"+utostr(CTmp)+" = cast<ConstantSDNode>("+
|
||||
RootName + ")->getSExtValue();");
|
||||
|
||||
emitCheck("CN" + utostr(CTmp) + " == " +itostr(II->getValue()));
|
||||
emitCheck("CN" + utostr(CTmp) + " == "
|
||||
"INT64_C(" +itostr(II->getValue()) + ")");
|
||||
} else {
|
||||
#ifndef NDEBUG
|
||||
Child->dump();
|
||||
|
@ -35,7 +35,7 @@ bool BitRecTy::baseClassOf(const BitsRecTy *RHS) const {
|
||||
}
|
||||
|
||||
Init *BitRecTy::convertValue(IntInit *II) {
|
||||
int Val = II->getValue();
|
||||
int64_t Val = II->getValue();
|
||||
if (Val != 0 && Val != 1) return 0; // Only accept 0 or 1 for a bit!
|
||||
|
||||
return new BitInit(Val != 0);
|
||||
@ -116,7 +116,7 @@ Init *IntRecTy::convertValue(BitInit *BI) {
|
||||
}
|
||||
|
||||
Init *IntRecTy::convertValue(BitsInit *BI) {
|
||||
int Result = 0;
|
||||
int64_t Result = 0;
|
||||
for (unsigned i = 0, e = BI->getNumBits(); i != e; ++i)
|
||||
if (BitInit *Bit = dynamic_cast<BitInit*>(BI->getBit(i))) {
|
||||
Result |= Bit->getValue() << i;
|
||||
@ -262,7 +262,7 @@ std::string BitsInit::getAsString() const {
|
||||
|
||||
bool BitsInit::printInHex(std::ostream &OS) const {
|
||||
// First, attempt to convert the value into an integer value...
|
||||
int Result = 0;
|
||||
int64_t Result = 0;
|
||||
for (unsigned i = 0, e = getNumBits(); i != e; ++i)
|
||||
if (BitInit *Bit = dynamic_cast<BitInit*>(getBit(i))) {
|
||||
Result |= Bit->getValue() << i;
|
||||
@ -338,11 +338,11 @@ Init *IntInit::convertInitializerBitRange(const std::vector<unsigned> &Bits) {
|
||||
BitsInit *BI = new BitsInit(Bits.size());
|
||||
|
||||
for (unsigned i = 0, e = Bits.size(); i != e; ++i) {
|
||||
if (Bits[i] >= 32) {
|
||||
if (Bits[i] >= 64) {
|
||||
delete BI;
|
||||
return 0;
|
||||
}
|
||||
BI->setBit(i, new BitInit(Value & (1 << Bits[i])));
|
||||
BI->setBit(i, new BitInit(Value & (INT64_C(1) << Bits[i])));
|
||||
}
|
||||
return BI;
|
||||
}
|
||||
@ -443,13 +443,13 @@ Init *BinOpInit::Fold() {
|
||||
IntInit *LHSi = dynamic_cast<IntInit*>(LHS);
|
||||
IntInit *RHSi = dynamic_cast<IntInit*>(RHS);
|
||||
if (LHSi && RHSi) {
|
||||
int LHSv = LHSi->getValue(), RHSv = RHSi->getValue();
|
||||
int Result;
|
||||
int64_t LHSv = LHSi->getValue(), RHSv = RHSi->getValue();
|
||||
int64_t Result;
|
||||
switch (getOpcode()) {
|
||||
default: assert(0 && "Bad opcode!");
|
||||
case SHL: Result = LHSv << RHSv; break;
|
||||
case SRA: Result = LHSv >> RHSv; break;
|
||||
case SRL: Result = (unsigned)LHSv >> (unsigned)RHSv; break;
|
||||
case SRL: Result = (uint64_t)LHSv >> (uint64_t)RHSv; break;
|
||||
}
|
||||
return new IntInit(Result);
|
||||
}
|
||||
@ -861,10 +861,10 @@ Record::getValueAsListOfDefs(const std::string &FieldName) const {
|
||||
}
|
||||
|
||||
/// getValueAsInt - This method looks up the specified field and returns its
|
||||
/// value as an int, throwing an exception if the field does not exist or if
|
||||
/// value as an int64_t, throwing an exception if the field does not exist or if
|
||||
/// the value is not the right type.
|
||||
///
|
||||
int Record::getValueAsInt(const std::string &FieldName) const {
|
||||
int64_t Record::getValueAsInt(const std::string &FieldName) const {
|
||||
const RecordVal *R = getValue(FieldName);
|
||||
if (R == 0 || R->getValue() == 0)
|
||||
throw "Record `" + getName() + "' does not have a field named `" +
|
||||
@ -880,10 +880,10 @@ int Record::getValueAsInt(const std::string &FieldName) const {
|
||||
/// its value as a vector of integers, throwing an exception if the field does
|
||||
/// not exist or if the value is not the right type.
|
||||
///
|
||||
std::vector<int>
|
||||
std::vector<int64_t>
|
||||
Record::getValueAsListOfInts(const std::string &FieldName) const {
|
||||
ListInit *List = getValueAsListInit(FieldName);
|
||||
std::vector<int> Ints;
|
||||
std::vector<int64_t> Ints;
|
||||
for (unsigned i = 0; i < List->getSize(); i++) {
|
||||
if (IntInit *II = dynamic_cast<IntInit*>(List->getElement(i))) {
|
||||
Ints.push_back(II->getValue());
|
||||
|
@ -565,11 +565,11 @@ public:
|
||||
/// IntInit - 7 - Represent an initalization by a literal integer value.
|
||||
///
|
||||
class IntInit : public Init {
|
||||
int Value;
|
||||
int64_t Value;
|
||||
public:
|
||||
explicit IntInit(int V) : Value(V) {}
|
||||
explicit IntInit(int64_t V) : Value(V) {}
|
||||
|
||||
int getValue() const { return Value; }
|
||||
int64_t getValue() const { return Value; }
|
||||
|
||||
virtual Init *convertInitializerTo(RecTy *Ty) {
|
||||
return Ty->convertValue(this);
|
||||
@ -1082,7 +1082,7 @@ public:
|
||||
/// its value as a vector of integers, throwing an exception if the field does
|
||||
/// not exist or if the value is not the right type.
|
||||
///
|
||||
std::vector<int> getValueAsListOfInts(const std::string &FieldName) const;
|
||||
std::vector<int64_t> getValueAsListOfInts(const std::string &FieldName) const;
|
||||
|
||||
/// getValueAsDef - This method looks up the specified field and returns its
|
||||
/// value as a Record, throwing an exception if the field does not exist or if
|
||||
@ -1097,10 +1097,10 @@ public:
|
||||
bool getValueAsBit(const std::string &FieldName) const;
|
||||
|
||||
/// getValueAsInt - This method looks up the specified field and returns its
|
||||
/// value as an int, throwing an exception if the field does not exist or if
|
||||
/// the value is not the right type.
|
||||
/// value as an int64_t, throwing an exception if the field does not exist or
|
||||
/// if the value is not the right type.
|
||||
///
|
||||
int getValueAsInt(const std::string &FieldName) const;
|
||||
int64_t getValueAsInt(const std::string &FieldName) const;
|
||||
|
||||
/// getValueAsDag - This method looks up the specified field and returns its
|
||||
/// value as an Dag, throwing an exception if the field does not exist or if
|
||||
|
@ -422,7 +422,7 @@ void RegisterInfoEmitter::run(std::ostream &OS) {
|
||||
std::map<Record*, std::set<Record*>, LessRecord> RegisterSuperRegs;
|
||||
std::map<Record*, std::set<Record*>, LessRecord> RegisterAliases;
|
||||
std::map<Record*, std::vector<std::pair<int, Record*> > > SubRegVectors;
|
||||
typedef std::map<Record*, std::vector<int>, LessRecord> DwarfRegNumsMapTy;
|
||||
typedef std::map<Record*, std::vector<int64_t>, LessRecord> DwarfRegNumsMapTy;
|
||||
DwarfRegNumsMapTy DwarfRegNums;
|
||||
|
||||
const std::vector<CodeGenRegister> &Regs = Target.getRegisters();
|
||||
@ -685,7 +685,7 @@ void RegisterInfoEmitter::run(std::ostream &OS) {
|
||||
unsigned maxLength = 0;
|
||||
for (unsigned i = 0, e = Registers.size(); i != e; ++i) {
|
||||
Record *Reg = Registers[i].TheDef;
|
||||
std::vector<int> RegNums = Reg->getValueAsListOfInts("DwarfNumbers");
|
||||
std::vector<int64_t> RegNums = Reg->getValueAsListOfInts("DwarfNumbers");
|
||||
maxLength = std::max((size_t)maxLength, RegNums.size());
|
||||
if (DwarfRegNums.count(Reg))
|
||||
cerr << "Warning: DWARF numbers for register " << getQualifiedName(Reg)
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <cerrno>
|
||||
using namespace llvm;
|
||||
|
||||
TGLexer::TGLexer(MemoryBuffer *StartBuf) : CurLineNo(1), CurBuf(StartBuf) {
|
||||
@ -343,7 +344,18 @@ tgtok::TokKind TGLexer::LexNumber() {
|
||||
if (CurPtr == NumStart)
|
||||
return ReturnError(CurPtr-2, "Invalid hexadecimal number");
|
||||
|
||||
errno = 0;
|
||||
CurIntVal = strtoll(NumStart, 0, 16);
|
||||
if (errno == EINVAL)
|
||||
return ReturnError(CurPtr-2, "Invalid hexadecimal number");
|
||||
if (errno == ERANGE) {
|
||||
errno = 0;
|
||||
CurIntVal = (int64_t)strtoull(NumStart, 0, 16);
|
||||
if (errno == EINVAL)
|
||||
return ReturnError(CurPtr-2, "Invalid hexadecimal number");
|
||||
if (errno == ERANGE)
|
||||
return ReturnError(CurPtr-2, "Hexadecimal number out of range");
|
||||
}
|
||||
return tgtok::IntVal;
|
||||
} else if (CurPtr[0] == 'b') {
|
||||
++CurPtr;
|
||||
|
@ -62,7 +62,7 @@ class TGLexer {
|
||||
const char *TokStart;
|
||||
tgtok::TokKind CurCode;
|
||||
std::string CurStrVal; // This is valid for ID, STRVAL, VARNAME, CODEFRAGMENT
|
||||
int CurIntVal; // This is valid for INTVAL.
|
||||
int64_t CurIntVal; // This is valid for INTVAL.
|
||||
|
||||
/// IncludeRec / IncludeStack - This captures the current set of include
|
||||
/// directives we are nested within.
|
||||
@ -98,7 +98,7 @@ public:
|
||||
"This token doesn't have a string value");
|
||||
return CurStrVal;
|
||||
}
|
||||
int getCurIntVal() const {
|
||||
int64_t getCurIntVal() const {
|
||||
assert(CurCode == tgtok::IntVal && "This token isn't an integer");
|
||||
return CurIntVal;
|
||||
}
|
||||
|
@ -294,8 +294,8 @@ bool TGParser::ParseRangePiece(std::vector<unsigned> &Ranges) {
|
||||
TokError("expected integer or bitrange");
|
||||
return true;
|
||||
}
|
||||
int Start = Lex.getCurIntVal();
|
||||
int End;
|
||||
int64_t Start = Lex.getCurIntVal();
|
||||
int64_t End;
|
||||
|
||||
if (Start < 0)
|
||||
return TokError("invalid range, cannot be negative");
|
||||
@ -426,7 +426,7 @@ RecTy *TGParser::ParseType() {
|
||||
TokError("expected integer in bits<n> type");
|
||||
return 0;
|
||||
}
|
||||
unsigned Val = Lex.getCurIntVal();
|
||||
uint64_t Val = Lex.getCurIntVal();
|
||||
if (Lex.Lex() != tgtok::greater) { // Eat count.
|
||||
TokError("expected '>' at end of bits<n> type");
|
||||
return 0;
|
||||
|
Loading…
Reference in New Issue
Block a user