[LLVMdev] Passing return values on the stack & storing arbitrary sized integers

Fabian Scheler fabian.scheler at gmail.com
Tue Aug 21 01:25:00 PDT 2012


2012/8/20 Eli Friedman <eli.friedman at gmail.com>:
> On Mon, Aug 20, 2012 at 12:01 AM, Fabian Scheler
> <fabian.scheler at gmail.com> wrote:
>> Hi Eli,
>>
>>>>>> 2. Storing arbitrary sized integers
>>>>>>
>>>>>> The testcase "test/CodeGen/Generic/APIntLoadStore.ll" checks for
>>>>>> loading/storing e.g. i33 integers from/into global variable. The
>>>>>> questions are the same as regarding feature 1: How important is this
>>>>>> feature? Is it save to ignore it? Is there some guide how to implement
>>>>>> this?
>>>>>
>>>>> If you're using the LLVM CodeGen infrastructure and have everything
>>>>> else implemented correctly, this should be taken care of for you.  We
>>>>> have infrastructure generally referred to as "legalization" that will
>>>>> transform this into something sane for your target automatically.  I
>>>>> would suggest not ignoring this because the optimizers will
>>>>> occasionally generate unusual loads and stores.
>>>>
>>>> Hm, my problem is that the TriCore does not really support i64 only
>>>> paired 32.bit registers, but I need such a register class as some
>>>> instructions require them. So, the Legalizer thinks i64-instructions
>>>> are legal and integer types above i32 are not legalized automatically.
>>>> For the most operations I used setOperationAction, setLoadExtAction,
>>>> ... and now I have to handle loads/stores for i33. Maybe you can guide
>>>> me, where I shall look at inside LLVM how to do that.
>>>
>>> I'm not entirely sure why, but this seems to be a very frequent
>>> mistake: don't mark i64 legal unless you actually have i64 registers.
>>> Lying to the legalizer creates extra work for your target, and you're
>>> using codepaths which aren't well tested.  There are better ways to
>>> model a pair of i32 registers; if you have some case you're having
>>> trouble modeling, please ask.
>>
>> well, I did not implement the back-end at first, I am currently only
>> adapting it to LLVM 3.1, so I don't know if it was possible to model
>> the TriCore ISA in a better way. The TriCore supports register pairs
>> of two adjacent (even,odd) registers forming one 64-bit registers. A
>> few operation of the TriCore exploit these register pairs:
>> multiplication, for instance, places its result in on of those
>> register pairs, it it possible to load/store such register pairs
>> directly from/to memory and the calling conventions take them into
>> account, too. Everything else has to be done using 32-bit registers
>> and instructions.
>>
>> In the first place, these registers pairs were only present in the
>> tablegen descriptions and were only used to define the
>> multiplication-instruction. Furthermore, the calling conventions were
>> tweaked to be compatible to those specified by the TriCore EABI
>> (64-bit arguments have to passed in an appropriate register pair).
>> Everything worked quite fine. When moving to LLVM 3.1, however, the
>> generic code generation framework complained that it knew nothing
>> about those registers pairs that were only described in tablegen when
>> selecting the multiplication-instruction. So, I found no other
>> solution than to add these register pairs as i64-registers.
>>
>> If there is a more convenient solution for this setup, I would be
>> really glad to learn about it :-)
>
> Not sure exactly what's going wrong, but if the Tablegen selection
> code doesn't work correctly for a few unusual instructions, you can
> write out the code by hand in your target's implementation of
> SelectionDAGISel::Select.

OK, I rechecked my problem and I hope I can now describe it more precisely:

1. The TriCore supports register pairs forming 64.bit registers. These
64-bit registers are defined like this and form the "ER" register
class:

def E0  : TriCoreRegWithSubregs<0,  "e0",  [D0,  D1]>,  DwarfRegNum<[32]>;
...
def E14 : TriCoreRegWithSubregs<14, "e14", [D14, D15]>, DwarfRegNum<[39]>;

2. The TriCore has some instructions that make use of an arbitrary
register pair, for example integer division (consisting of a single
DVINIT and several DVSTEPs):

def DVINIT_Urr  : RrInstr<0x4b, 0x0a, (outs ER:$c), (ins DR:$a,
DR:$b), "dvinit.u\t$c, $a, $b",  []>;
def DVSTEP_Urrr : RrrInstr<0x6b, 0x0e, (outs ER:$c), (ins ER:$d,
DR:$b), "dvstep.u\t$c, $d, $b", []>;

def : Pat<(sdiv DR:$a, DR:$b),
              (EXTRACT_SUBREG
                (DVSTEPrrr
                  (DVSTEPrrr
                    (DVSTEPrrr
                      (DVSTEPrrr (DVINITrr DR:$a, DR:$b), DR:$b),
                      DR:$b),
                    DR:$b),
                  DR:$b),
                sub_even)>;

3. These are selected in a simple testcase:

define i32 @div(i32 %a, i32 %b) nounwind readnone {
entry:
  %div = sdiv i32 %a, %b                          ; <i32> [#uses=1]
  ret i32 %div
}

4. Instruction Scheduling calls GetCostForDef (in
ScheduleDAGRRList.cpp) when hitting the EXTRACT_SUBREG-Node introduced
by the Pattern above.

5. GetCostForDef crashes here, as getRepRegClassFor(VT /* == MVT::i64
*/) returns NULL:

RegClass = TLI->getRepRegClassFor(VT)->getID();

For LLVM versions before 3.1 this did not happen (I don't know why).
Solving this problem at the tablegen level means (I guess) not to use
an explicitly modelled "ER" register class at all, right? But how can
I describe that for example DVSTEP could use any of those registers
pairs as input and output? I have no clue how I can express this
constraint in tablegen without that ER register class or when manually
lowering ISD::SDIV during ISelLowering.

Ciao, Fabian



More information about the llvm-dev mailing list