mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-15 17:39:25 +02:00
* correctly handle loads/stores of aggregate types if the source and
destination types are different: the pointer types of the load/store must be converted in that case, rather than the loaded/to be stored value (you can't bitcast aggregates in LLVM) git-svn-id: branches/hlcgllvm@26987 -
This commit is contained in:
parent
43e0eb3cfd
commit
98be5b0825
@ -70,6 +70,8 @@ interface
|
||||
constructor op_reg_size_ref_size(op:tllvmop;dst:tregister;fromsize:tdef;const src:treference;tosize:tdef);
|
||||
{ e.g. store fromsize src, ptrsize toref}
|
||||
constructor op_size_reg_size_ref(op:tllvmop;fromsize:tdef;src:tregister;ptrsize:tdef;const toref:treference);
|
||||
{ e.g. store fromsize srcref, ptrsize toref (with srcref.refaddr=full) }
|
||||
constructor op_size_ref_size_ref(op:tllvmop;fromsize:tdef;const src:treference;ptrsize:tdef;const toref:treference);
|
||||
{ e.g. store fromsize const, ptrsize toref}
|
||||
constructor op_size_const_size_ref(op:tllvmop;fromsize:tdef;src:int64;ptrsize:tdef;const toref:treference);
|
||||
{ e.g. dst = load fromsize fromref }
|
||||
@ -552,6 +554,17 @@ uses
|
||||
end;
|
||||
|
||||
|
||||
constructor taillvm.op_size_ref_size_ref(op: tllvmop; fromsize: tdef; const src: treference; ptrsize: tdef; const toref: treference);
|
||||
begin
|
||||
create_llvm(op);
|
||||
ops:=4;
|
||||
loaddef(0,fromsize);
|
||||
loadref(1,src);
|
||||
loaddef(2,ptrsize);
|
||||
loadref(3,toref);
|
||||
end;
|
||||
|
||||
|
||||
constructor taillvm.op_size_const_size_ref(op: tllvmop; fromsize: tdef; src: int64; ptrsize: tdef; const toref: treference);
|
||||
begin
|
||||
create_llvm(op);
|
||||
|
@ -167,19 +167,83 @@ implementation
|
||||
end;
|
||||
|
||||
|
||||
function def2intdef(fromsize, tosize: tdef): tdef;
|
||||
begin
|
||||
{ we cannot zero-extend from/to anything but ordinal/enum
|
||||
types }
|
||||
if not(tosize.typ in [orddef,enumdef]) then
|
||||
internalerror(2014012305);
|
||||
{ will give an internalerror if def_cgsize() returns OS_NO, which is
|
||||
what we want }
|
||||
result:=cgsize_orddef(def_cgsize(fromsize));
|
||||
end;
|
||||
|
||||
|
||||
procedure thlcgllvm.a_load_reg_ref(list: TAsmList; fromsize, tosize: tdef; register: tregister; const ref: treference);
|
||||
var
|
||||
tmpref,
|
||||
sref: treference;
|
||||
hreg: tregister;
|
||||
hreg,
|
||||
hreg2: tregister;
|
||||
tmpsize: tdef;
|
||||
begin
|
||||
sref:=make_simple_ref(list,ref,tosize);
|
||||
hreg:=register;
|
||||
if fromsize.size<>tosize.size then
|
||||
(* typecast the pointer to the value instead of the value itself if
|
||||
they have the same size but are of different kinds, because we can't
|
||||
e.g. typecast a loaded <{i32, i32}> to an i64 *)
|
||||
if (llvmaggregatetype(fromsize) or
|
||||
llvmaggregatetype(tosize)) and
|
||||
(fromsize<>tosize) then
|
||||
begin
|
||||
if fromsize.size>tosize.size then
|
||||
begin
|
||||
{ if source size is larger than the target size, we have to
|
||||
truncate it before storing. Unfortunately, we cannot truncate
|
||||
records (nor bitcast them to integers), so we first have to
|
||||
store them to memory and then bitcast the pointer to them
|
||||
}
|
||||
if fromsize.typ in [arraydef,recorddef] then
|
||||
begin
|
||||
{ store struct/array-in-register to memory }
|
||||
tmpsize:=def2intdef(fromsize,tosize);
|
||||
tg.gethltemp(list,fromsize,fromsize.size,tt_normal,tmpref);
|
||||
a_load_reg_ref(list,fromsize,fromsize,register,tmpref);
|
||||
{ typecast pointer to memory into pointer to integer type }
|
||||
hreg:=getaddressregister(list,getpointerdef(tmpsize));
|
||||
a_loadaddr_ref_reg(list,fromsize,getpointerdef(tmpsize),tmpref,hreg);
|
||||
reference_reset_base(sref,hreg,0,tmpref.alignment);
|
||||
{ load the integer from the temp into the destination }
|
||||
a_load_ref_ref(list,tmpsize,tosize,tmpref,sref);
|
||||
tg.ungettemp(list,tmpref);
|
||||
end
|
||||
else
|
||||
begin
|
||||
tmpsize:=def2intdef(tosize,fromsize);
|
||||
hreg:=getintregister(list,tmpsize);
|
||||
{ truncate the integer }
|
||||
a_load_reg_reg(list,fromsize,tmpsize,register,hreg);
|
||||
{ store it to memory (it will now be of the same size as the
|
||||
struct, and hence another path will be followed in this
|
||||
method) }
|
||||
a_load_reg_ref(list,tmpsize,tosize,hreg,sref);
|
||||
end;
|
||||
exit;
|
||||
end
|
||||
else
|
||||
begin
|
||||
hreg2:=getaddressregister(list,getpointerdef(fromsize));
|
||||
a_loadaddr_ref_reg(list,tosize,getpointerdef(fromsize),sref,hreg2);
|
||||
reference_reset_base(sref,hreg2,0,sref.alignment);
|
||||
tosize:=fromsize;
|
||||
end;
|
||||
end
|
||||
else if fromsize<>tosize then
|
||||
begin
|
||||
hreg:=getregisterfordef(list,tosize);
|
||||
a_load_reg_reg(list,fromsize,tosize,register,hreg);
|
||||
end;
|
||||
list.concat(taillvm.op_size_reg_size_ref(la_store,tosize,hreg,getpointerdef(tosize),sref))
|
||||
list.concat(taillvm.op_size_reg_size_ref(la_store,tosize,hreg,getpointerdef(tosize),sref));
|
||||
end;
|
||||
|
||||
|
||||
@ -218,15 +282,80 @@ implementation
|
||||
|
||||
procedure thlcgllvm.a_load_ref_reg(list: TAsmList; fromsize, tosize: tdef; const ref: treference; register: tregister);
|
||||
var
|
||||
tmpref,
|
||||
sref: treference;
|
||||
hreg: tregister;
|
||||
tmpsize: tdef;
|
||||
begin
|
||||
sref:=make_simple_ref(list,ref,fromsize);
|
||||
{ "named register"? }
|
||||
if sref.refaddr=addr_full then
|
||||
list.concat(taillvm.op_reg_size_ref_size(la_bitcast,register,fromsize,sref,tosize))
|
||||
begin
|
||||
{ can't bitcast records/arrays }
|
||||
if (llvmaggregatetype(fromsize) or
|
||||
llvmaggregatetype(tosize)) and
|
||||
(fromsize<>tosize) then
|
||||
begin
|
||||
tg.gethltemp(list,fromsize,fromsize.size,tt_normal,tmpref);
|
||||
list.concat(taillvm.op_size_ref_size_ref(la_store,fromsize,sref,getpointerdef(fromsize),tmpref));
|
||||
a_load_ref_reg(list,fromsize,tosize,tmpref,register);
|
||||
tg.ungettemp(list,tmpref);
|
||||
end
|
||||
else
|
||||
list.concat(taillvm.op_reg_size_ref_size(la_bitcast,register,fromsize,sref,tosize))
|
||||
end
|
||||
else
|
||||
begin
|
||||
if ((fromsize.typ in [arraydef,recorddef]) or
|
||||
(tosize.typ in [arraydef,recorddef])) and
|
||||
(fromsize<>tosize) then
|
||||
begin
|
||||
if fromsize.size<tosize.size then
|
||||
begin
|
||||
{ if the target size is larger than the source size, we
|
||||
have to perform the zero-extension using an integer type
|
||||
(can't zero-extend a record/array) }
|
||||
if fromsize.typ in [arraydef,recorddef] then
|
||||
begin
|
||||
{ typecast the pointer to the struct into a pointer to an
|
||||
integer of equal size }
|
||||
tmpsize:=def2intdef(fromsize,tosize);
|
||||
hreg:=getaddressregister(list,getpointerdef(tmpsize));
|
||||
a_loadaddr_ref_reg(list,fromsize,getpointerdef(tmpsize),sref,hreg);
|
||||
reference_reset_base(sref,hreg,0,sref.alignment);
|
||||
{ load that integer }
|
||||
a_load_ref_reg(list,tmpsize,tosize,sref,register);
|
||||
end
|
||||
else
|
||||
begin
|
||||
{ load the integer into an integer memory location with
|
||||
the same size as the struct (the integer should be
|
||||
unsigned, we don't want sign extensions here) }
|
||||
if is_signed(fromsize) then
|
||||
internalerror(2014012309);
|
||||
tmpsize:=def2intdef(tosize,fromsize);
|
||||
tg.gethltemp(list,tmpsize,tmpsize.size,tt_normal,tmpref);
|
||||
{ typecast the struct-sized integer location into the
|
||||
struct type }
|
||||
a_load_ref_ref(list,fromsize,tmpsize,sref,tmpref);
|
||||
{ load the struct in the register }
|
||||
a_load_ref_reg(list,tmpsize,tosize,tmpref,register);
|
||||
tg.ungettemp(list,tmpref);
|
||||
end;
|
||||
exit;
|
||||
end
|
||||
else
|
||||
begin
|
||||
(* typecast the pointer to the value instead of the value
|
||||
itself if they have the same size but are of different
|
||||
kinds, because we can't e.g. typecast a loaded <{i32, i32}>
|
||||
to an i64 *)
|
||||
hreg:=getaddressregister(list,getpointerdef(tosize));
|
||||
a_loadaddr_ref_reg(list,fromsize,getpointerdef(tosize),sref,hreg);
|
||||
reference_reset_base(sref,hreg,0,sref.alignment);
|
||||
fromsize:=tosize;
|
||||
end;
|
||||
end;
|
||||
hreg:=register;
|
||||
if fromsize<>tosize then
|
||||
hreg:=getregisterfordef(list,fromsize);
|
||||
|
Loading…
Reference in New Issue
Block a user