f39f7063ef
[COMPILER] * NEW: Start working on the new jit system. [GB.JIT] * NEW: Rename the component as 'gb.jit.llvm'.
787 lines
23 KiB
C
787 lines
23 KiB
C
/***************************************************************************
|
|
|
|
jit_codegen_conv.h
|
|
|
|
gb.jit component
|
|
|
|
(c) 2012 Emil Lenngren <emil.lenngren [at] gmail.com>
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 1, or (at your option)
|
|
any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
|
MA 02110-1301, USA.
|
|
|
|
***************************************************************************/
|
|
|
|
#ifndef __JIT_CODEGEN_CONV_H
|
|
#define __JIT_CODEGEN_CONV_H
|
|
|
|
extern "C" {
|
|
#include "gbx_number.h"
|
|
#include "gb_common_buffer.h"
|
|
}
|
|
|
|
#ifdef __CYGWIN__
|
|
#define __finite finite
|
|
#endif
|
|
|
|
llvm::Value* JIT_conv_to_variant(Expression* value, llvm::Value* val, bool on_stack, bool* no_ref_variant){
|
|
llvm::Value* ret;
|
|
if (TYPE_is_string(value->type)){
|
|
ret = string_for_array_or_variant(val, value->type);
|
|
ret = get_new_struct(variant_type, getInteger(TARGET_BITS, T_STRING), builder->CreatePtrToInt(ret, llvmType(getInt64Ty)));
|
|
} else {
|
|
if (value->type < T_OBJECT && no_ref_variant)
|
|
*no_ref_variant = true;
|
|
|
|
llvm::Value* data;
|
|
llvm::Type* t64 = llvmType(getInt64Ty);
|
|
|
|
if (value->type < T_OBJECT)
|
|
ret = get_new_struct(variant_type, getInteger(TARGET_BITS, value->type));
|
|
else
|
|
ret = get_new_struct(variant_type, builder->CreatePtrToInt(extract_value(val, 0), LONG_TYPE));
|
|
|
|
switch(value->type){
|
|
case T_BYTE:
|
|
data = builder->CreateZExt(val, t64);
|
|
break;
|
|
case T_BOOLEAN:
|
|
case T_SHORT:
|
|
case T_INTEGER:
|
|
data = builder->CreateSExt(val, t64);
|
|
break;
|
|
case T_LONG:
|
|
data = val;
|
|
break;
|
|
case T_SINGLE:
|
|
data = builder->CreateBitCast(val, llvmType(getInt32Ty));
|
|
data = builder->CreateZExt(data, t64);
|
|
break;
|
|
case T_FLOAT:
|
|
data = builder->CreateBitCast(val, t64);
|
|
break;
|
|
case T_DATE:
|
|
data = builder->CreateShl(builder->CreateZExt(extract_value(val, 1), t64), getInteger(64, 32));
|
|
data = builder->CreateOr(data, builder->CreateZExt(extract_value(val, 0), t64));
|
|
break;
|
|
case T_POINTER:
|
|
data = builder->CreatePtrToInt(val, t64);
|
|
break;
|
|
case T_CLASS:
|
|
assert(dynamic_cast<PushClassExpression*>(value));
|
|
data = getInteger(64, (uint64_t)(void*)((PushClassExpression*)value)->klass);
|
|
val = builder->CreateIntToPtr(data, llvmType(getInt8PtrTy));
|
|
break;
|
|
case T_NULL:
|
|
break;
|
|
default:
|
|
data = builder->CreatePtrToInt(extract_value(val, 1), t64);
|
|
break;
|
|
}
|
|
if (value->type != T_NULL)
|
|
ret = insert_value(ret, data, 1);
|
|
|
|
if (on_stack){ //FIXME is this code really good/correct? stack seems strange
|
|
c_SP(-value->on_stack+1);
|
|
llvm::Value* addr = builder->CreateBitCast(get_value_on_top_addr(), pointer_t(LONG_TYPE));
|
|
|
|
builder->CreateStore(getInteger(TARGET_BITS, T_VARIANT), addr);
|
|
|
|
addr = builder->CreateGEP(addr, getInteger(TARGET_BITS, 1));
|
|
if (value->type < T_OBJECT)
|
|
builder->CreateStore(getInteger(TARGET_BITS, value->type), addr);
|
|
else
|
|
builder->CreateStore(builder->CreatePtrToInt(extract_value(val, 0), LONG_TYPE), addr);
|
|
|
|
if (value->type != T_NULL){
|
|
addr = builder->CreateGEP(addr, getInteger(TARGET_BITS, 1));
|
|
if (value->type == T_BYTE)
|
|
builder->CreateStore(builder->CreateZExt(val, llvmType(getInt32Ty)), builder->CreateBitCast(addr, llvmType(getInt32PtrTy)));
|
|
else if (value->type < T_INTEGER)
|
|
builder->CreateStore(builder->CreateSExt(val, llvmType(getInt32Ty)), builder->CreateBitCast(addr, llvmType(getInt32PtrTy)));
|
|
else if (value->type < T_OBJECT)
|
|
builder->CreateStore(val, builder->CreateBitCast(addr, pointer_t(TYPE_llvm(value->type))));
|
|
else
|
|
builder->CreateStore(extract_value(val, 1), builder->CreateBitCast(addr, charPP));
|
|
}
|
|
return ret;
|
|
}
|
|
}
|
|
c_SP(-value->on_stack+on_stack);
|
|
if (on_stack)
|
|
set_top_value(ret, T_VARIANT);
|
|
return ret;
|
|
}
|
|
|
|
llvm::Value* ConvExpression::codegen_get_value()
|
|
{
|
|
Expression* value = expr;
|
|
static const void *jump[16][16] =
|
|
{
|
|
/* ,-------> void b c h i l g f d cs s p v func class n */
|
|
// |
|
|
/* void */ { &&__OK, &&__NR, &&__NR, &&__NR, &&__NR, &&__NR, &&__NR, &&__NR, &&__NR, &&__NR, &&__NR, &&__NR, &&__NR, &&__NR, &&__NR, &&__NR, },
|
|
/* b */ { &&__N, &&__OK, &&__b2c, &&__b2h, &&__b2i, &&__b2l, &&__b2g, &&__b2f, &&__N, &&__b2s, &&__b2s, &&__N, &&__2v, &&__N, &&__N, &&__N, },
|
|
/* c */ { &&__N, NULL, &&__OK, &&__c2h, &&__c2i, &&__c2l, &&__c2g, &&__c2f, &&__c2d, &&__c2s, &&__c2s, &&__N, &&__2v, &&__N, &&__N, &&__N, },
|
|
/* h */ { &&__N, NULL, &&__h2c, &&__OK, &&__h2i, &&__h2l, &&__h2g, &&__h2f, &&__h2d, &&__h2s, &&__h2s, &&__N, &&__2v, &&__N, &&__N, &&__N, },
|
|
/* i */ { &&__N, NULL, &&__i2c, &&__i2h, &&__OK, &&__i2l, &&__i2g, &&__i2f, &&__i2d, &&__i2s, &&__i2s, &&__i2p, &&__2v, &&__N, &&__N, &&__N, },
|
|
/* l */ { &&__N, NULL, &&__l2c, &&__l2h, &&__l2i, &&__OK, &&__l2g, &&__l2f, &&__l2d, &&__l2s, &&__l2s, &&__l2p, &&__2v, &&__N, &&__N, &&__N, },
|
|
/* g */ { &&__N, NULL, &&__g2c, &&__g2h, &&__g2i, &&__g2l, &&__OK, &&__g2f, &&__g2d, &&__g2s, &&__g2s, &&__N, &&__2v, &&__N, &&__N, &&__N, },
|
|
/* f */ { &&__N, NULL, &&__f2c, &&__f2h, &&__f2i, &&__f2l, &&__f2g, &&__OK, &&__f2d, &&__f2s, &&__f2s, &&__N, &&__2v, &&__N, &&__N, &&__N, },
|
|
/* d */ { &&__N, &&__d2b, &&__d2c, &&__d2h, &&__d2i, &&__d2l, &&__d2g, &&__d2f, &&__OK, &&__d2s, &&__d2s, &&__N, &&__2v, &&__N, &&__N, &&__N, },
|
|
/* cs */ { &&__N, &&__s2b, &&__s2c, &&__s2h, &&__s2i, &&__s2l, &&__s2g, &&__s2f, &&__s2d, &&__OK, &&__OK, &&__N, &&__s2v, &&__N, &&__N, &&__N, },
|
|
/* s */ { &&__N, &&__s2b, &&__s2c, &&__s2h, &&__s2i, &&__s2l, &&__s2g, &&__s2f, &&__s2d, &&__OK, &&__OK, &&__N, &&__s2v, &&__N, &&__N, &&__N, },
|
|
/* p */ { &&__N, &&__N, &&__N, &&__N, &&__p2i, &&__p2l, &&__N, &&__N, &&__N, &&__N, &&__N, &&__OK, &&__2v, &&__N, &&__N, &&__N, },
|
|
/* v */ { &&__N, &&__v2, &&__v2, &&__v2, &&__v2, &&__v2, &&__v2, &&__v2, &&__v2, &&__v2, &&__v2, &&__v2, &&__OK, &&__N, &&__v2, &&__v2, },
|
|
/* func */ { &&__N, &&__func, &&__func, &&__func, &&__func, &&__func, &&__func, &&__func, &&__func, &&__func, &&__func, &&__F2p, &&__func, &&__OK, &&__N, &&__func, },
|
|
/* class */ { &&__N, &&__N, &&__N, &&__N, &&__N, &&__N, &&__N, &&__N, &&__N, &&__N, &&__N, &&__N, &&__2v, &&__N, &&__OK, &&__N, },
|
|
/* null */ { &&__N, NULL, &&__N, &&__N, &&__N, &&__N, &&__N, &&__N, NULL, NULL, NULL, &&__N, &&__2v, &&__N, &&__N, &&__OK, },
|
|
};
|
|
|
|
llvm::Value* val = NULL;
|
|
llvm::Value* ret;
|
|
|
|
if (value->type == (TYPE)-1)
|
|
goto __UNKNOWN;
|
|
else if ((type | value->type) >> 4)
|
|
goto __OBJECT;
|
|
else {
|
|
if (value->type != T_FUNCTION && value->type != T_CLASS)
|
|
val = value->codegen_get_value();
|
|
goto *jump[value->type][type];
|
|
}
|
|
|
|
|
|
__d2b:
|
|
ret = builder->CreateICmpNE(builder->CreateOr(extract_value(val, 0), extract_value(val, 1)), getInteger(32, 0));
|
|
goto __DONE;
|
|
|
|
__b2c:
|
|
__b2h:
|
|
__b2i:
|
|
__h2i:
|
|
__b2l:
|
|
__h2l:
|
|
__i2l:
|
|
|
|
ret = builder->CreateSExt(val, TYPE_llvm(type));
|
|
goto __DONE;
|
|
|
|
__h2c:
|
|
__i2c:
|
|
__l2c:
|
|
__i2h:
|
|
__l2h:
|
|
__l2i:
|
|
|
|
ret = builder->CreateTrunc(val, TYPE_llvm(type));
|
|
goto __DONE;
|
|
|
|
__g2c:
|
|
__f2c:
|
|
|
|
ret = builder->CreateFPToUI(val, llvmType(getInt8Ty));
|
|
goto __DONE;
|
|
|
|
__c2h:
|
|
__c2i:
|
|
__c2l:
|
|
|
|
ret = builder->CreateZExt(val, TYPE_llvm(type));
|
|
goto __DONE;
|
|
|
|
__g2h:
|
|
__f2h:
|
|
__g2i:
|
|
__f2i:
|
|
__g2l:
|
|
__f2l:
|
|
|
|
ret = builder->CreateFPToSI(val, TYPE_llvm(type));
|
|
goto __DONE;
|
|
|
|
__p2i:
|
|
__p2l:
|
|
|
|
ret = builder->CreatePtrToInt(val, TYPE_llvm(type));
|
|
goto __DONE;
|
|
|
|
__c2g:
|
|
__c2f:
|
|
|
|
ret = builder->CreateUIToFP(val, TYPE_llvm(type));
|
|
goto __DONE;
|
|
|
|
__b2g:
|
|
__h2g:
|
|
__i2g:
|
|
__b2f:
|
|
__h2f:
|
|
__i2f:
|
|
__l2f:
|
|
|
|
ret = builder->CreateSIToFP(val, TYPE_llvm(type));
|
|
goto __DONE;
|
|
|
|
__l2g:
|
|
|
|
ret = builder->CreateSIToFP(val, TYPE_llvm(type));
|
|
goto __test_overflow;
|
|
|
|
|
|
__f2g:
|
|
|
|
ret = builder->CreateFPTrunc(val, llvmType(getFloatTy));
|
|
goto __test_overflow;
|
|
|
|
__test_overflow:
|
|
{
|
|
llvm::Value* ret64 = type == T_SINGLE ? builder->CreateFPExt(ret, llvmType(getDoubleTy)) : ret;
|
|
llvm::Value* res = builder->CreateCall(get_global_function(__finite, 'i', "d"), ret64);
|
|
|
|
gen_if_noreturn(builder->CreateICmpEQ(res, getInteger(32, 0)), [&](){
|
|
create_throw(E_OVERFLOW);
|
|
}, "test_overflow");
|
|
|
|
goto __DONE;
|
|
}
|
|
|
|
__g2f:
|
|
|
|
ret = builder->CreateFPExt(val, llvmType(getDoubleTy));
|
|
goto __DONE;
|
|
|
|
__c2d:
|
|
__h2d:
|
|
__i2d:
|
|
|
|
ret = val;
|
|
if (value->type != T_INTEGER){
|
|
if (value->type == T_BYTE)
|
|
ret = builder->CreateZExt(ret, llvmType(getInt32Ty));
|
|
else
|
|
ret = builder->CreateSExt(ret, llvmType(getInt32Ty));
|
|
}
|
|
ret = gen_max(getInteger(32, 0), ret);
|
|
ret = get_new_struct(date_type, ret, getInteger(32, 0));
|
|
goto __DONE;
|
|
|
|
__l2d:
|
|
|
|
ret = builder->CreateSelect(
|
|
builder->CreateICmpSLT(val, getInteger(64, 0)),
|
|
getInteger(32, 0),
|
|
builder->CreateSelect(
|
|
builder->CreateICmpSGT(val, getInteger(64, INT_MAX)),
|
|
getInteger(32, INT_MAX),
|
|
builder->CreateTrunc(val, llvmType(getInt32Ty))
|
|
)
|
|
);
|
|
ret = get_new_struct(date_type, ret, getInteger(32, 0));
|
|
goto __DONE;
|
|
|
|
__g2d:
|
|
{
|
|
llvm::Value* ival = builder->CreateCall(get_global_function(floorf, 'f', "f"), val);
|
|
llvm::Value* timepart = builder->CreateFPToSI(builder->CreateFAdd(builder->CreateFMul(builder->CreateFSub(val, ival), getFloat(86400000.0f)), getFloat(0.5f)), llvmType(getInt32Ty));
|
|
ret = get_new_struct(date_type, builder->CreateFPToSI(ival, llvmType(getInt32Ty)), timepart);
|
|
goto __DONE;
|
|
}
|
|
|
|
__f2d:
|
|
{
|
|
llvm::Value* ival = builder->CreateCall(get_global_function(floor, 'd', "d"), val);
|
|
llvm::Value* timepart = builder->CreateFPToSI(builder->CreateFAdd(builder->CreateFMul(builder->CreateFSub(val, ival), getFloat(86400000.0)), getFloat(0.5)), llvmType(getInt32Ty));
|
|
ret = get_new_struct(date_type, builder->CreateFPToSI(ival, llvmType(getInt32Ty)), timepart);
|
|
goto __DONE;
|
|
}
|
|
|
|
__d2c:
|
|
__d2h:
|
|
__d2i:
|
|
__d2l:
|
|
|
|
ret = extract_value(val, 0);
|
|
if (type < T_INTEGER)
|
|
ret = builder->CreateTrunc(ret, TYPE_llvm(type));
|
|
else if (type == T_LONG)
|
|
ret = builder->CreateSExt(ret, llvmType(getInt64Ty));
|
|
goto __DONE;
|
|
|
|
__d2g:
|
|
{
|
|
llvm::Value* datepart = builder->CreateSIToFP(extract_value(val, 0), llvmType(getFloatTy));
|
|
llvm::Value* timepart = builder->CreateSIToFP(extract_value(val, 1), llvmType(getFloatTy));
|
|
|
|
ret = builder->CreateFAdd(datepart, builder->CreateFDiv(timepart, getFloat(86400000.0f)));
|
|
goto __DONE;
|
|
}
|
|
|
|
__d2f:
|
|
{
|
|
llvm::Value* datepart = builder->CreateSIToFP(extract_value(val, 0), llvmType(getDoubleTy));
|
|
llvm::Value* timepart = builder->CreateSIToFP(extract_value(val, 1), llvmType(getDoubleTy));
|
|
|
|
ret = builder->CreateFAdd(datepart, builder->CreateFDiv(timepart, getFloat(86400000.0)));
|
|
goto __DONE;
|
|
}
|
|
|
|
__b2s:
|
|
|
|
ret = builder->CreateSelect(val,
|
|
get_new_struct(string_type, getInteger(TARGET_BITS, T_CSTRING), get_global((void*)"T", llvmType(getInt8Ty)), getInteger(32, 0), getInteger(32, 1)),
|
|
get_new_struct(string_type, getInteger(TARGET_BITS, T_CSTRING), get_nullptr(), getInteger(32, 0), getInteger(32, 0))
|
|
);
|
|
goto __DONE;
|
|
|
|
__c2s:
|
|
__h2s:
|
|
__i2s:
|
|
__l2s:
|
|
{
|
|
llvm::Value* num;
|
|
if (value->type == T_BYTE)
|
|
num = builder->CreateZExt(val, llvmType(getInt64Ty));
|
|
else if (value->type == T_LONG)
|
|
num = val;
|
|
else
|
|
num = builder->CreateSExt(val, llvmType(getInt64Ty));
|
|
|
|
c_SP(-value->on_stack+on_stack);
|
|
|
|
llvm::Value* addr = on_stack ? get_value_on_top_addr() : temp_value;
|
|
|
|
builder->CreateCall4(get_global_function_jif(NUMBER_int_to_string, 'v', "liip"),
|
|
num, getInteger(32, 0), getInteger(32, 10), builder->CreateBitCast(addr, llvmType(getInt8PtrTy)));
|
|
|
|
ret = read_value(addr, T_STRING);
|
|
borrow(ret, T_STRING);
|
|
return ret;
|
|
}
|
|
|
|
__g2s:
|
|
__f2s:
|
|
{
|
|
c_SP(-value->on_stack+on_stack);
|
|
|
|
if (value->type == T_SINGLE)
|
|
val = builder->CreateFPExt(val, llvmType(getDoubleTy));
|
|
|
|
llvm::Value* args[] = {
|
|
val, getInteger(32, LF_GENERAL_NUMBER), get_nullptr(), getInteger(32, 0),
|
|
builder->CreateBitCast(temp_voidptr, llvmType(getInt8PtrTy)),
|
|
builder->CreateBitCast(temp_int, llvmType(getInt8PtrTy)), getInteger(8, 0)
|
|
};
|
|
/*llvm::Value* got_error =*/ builder->CreateCall(get_global_function_jif(LOCAL_format_number, 'c', "dipippc"), args);
|
|
|
|
llvm::Value* addr = on_stack ? get_value_on_top_addr() : temp_value;
|
|
|
|
builder->CreateCall3(get_global_function_jif(STRING_new_temp_value, 'v', "ppi"),
|
|
builder->CreateBitCast(addr, llvmType(getInt8PtrTy)),
|
|
builder->CreateLoad(temp_voidptr),
|
|
builder->CreateLoad(temp_int)
|
|
);
|
|
|
|
ret = read_value(addr, T_STRING);
|
|
borrow(ret, T_STRING);
|
|
return ret;
|
|
}
|
|
|
|
__d2s:
|
|
{
|
|
llvm::Value* src_addr = value->on_stack ? get_value_on_top_addr() : temp_value;
|
|
if (!value->on_stack)
|
|
store_value(src_addr, val, T_DATE, false);
|
|
|
|
c_SP(-value->on_stack+on_stack);
|
|
llvm::Value* addr = on_stack ? get_value_on_top_addr() : temp_value;
|
|
|
|
static char buffer[128];
|
|
|
|
llvm::Value* len = builder->CreateCall2(get_global_function_jif(DATE_to_string, 'i', "pp"),
|
|
get_global((void*)buffer, llvmType(getInt8Ty)),
|
|
builder->CreateBitCast(src_addr, llvmType(getInt8PtrTy))
|
|
);
|
|
builder->CreateCall3(get_global_function_jif(STRING_new_temp_value, 'v', "ppi"),
|
|
builder->CreateBitCast(addr, llvmType(getInt8PtrTy)),
|
|
get_global((void*)buffer, llvmType(getInt8Ty)),
|
|
len
|
|
);
|
|
|
|
ret = read_value(addr, T_STRING);
|
|
borrow(ret, T_STRING);
|
|
return ret;
|
|
}
|
|
|
|
__s2b:
|
|
|
|
ret = builder->CreateICmpNE(extract_value(val, 3), getInteger(32, 0));
|
|
release(val, value->type);
|
|
goto __DONE;
|
|
|
|
__s2c:
|
|
__s2h:
|
|
__s2i:
|
|
__s2l:
|
|
{
|
|
auto str = get_string_len(val);
|
|
|
|
c_SP(-value->on_stack+on_stack);
|
|
llvm::Value* addr = (on_stack && (type == T_INTEGER || type == T_LONG)) ? get_value_on_top_addr() : temp_value;
|
|
|
|
llvm::Value* got_error = builder->CreateCall4(get_global_function_jif(NUMBER_from_string, 'c', "ipip"),
|
|
getInteger(32, type == T_LONG ? NB_READ_LONG : NB_READ_INTEGER), str.first, str.second,
|
|
builder->CreateBitCast(addr, llvmType(getInt8PtrTy))
|
|
);
|
|
|
|
release(val, value->type);
|
|
|
|
gen_if_noreturn(builder->CreateICmpNE(got_error, getInteger(8, 0)), [&](){
|
|
create_throw(E_TYPE, JIF.F_TYPE_get_name(type), JIF.F_TYPE_get_name(value->type));
|
|
});
|
|
|
|
llvm::Value* intval = read_value(addr, type == T_LONG ? T_LONG : T_INTEGER);
|
|
|
|
if (type < T_INTEGER)
|
|
intval = builder->CreateTrunc(intval, TYPE_llvm(type));
|
|
|
|
if (on_stack && addr == temp_value)
|
|
set_top_value(intval, type);
|
|
|
|
return intval;
|
|
}
|
|
|
|
__s2g:
|
|
__s2f:
|
|
{
|
|
auto str = get_string_len(val);
|
|
|
|
c_SP(-value->on_stack+on_stack);
|
|
llvm::Value* addr = (on_stack && type == T_FLOAT) ? get_value_on_top_addr() : temp_value;
|
|
|
|
llvm::Value* got_error = builder->CreateCall4(get_global_function_jif(NUMBER_from_string, 'c', "ipip"),
|
|
getInteger(32, NB_READ_FLOAT), str.first, str.second,
|
|
builder->CreateBitCast(addr, llvmType(getInt8PtrTy))
|
|
);
|
|
|
|
release(val, value->type);
|
|
|
|
gen_if_noreturn(builder->CreateICmpNE(got_error, getInteger(8, 0)), [&](){
|
|
create_throw(E_TYPE, JIF.F_TYPE_get_name(type), JIF.F_TYPE_get_name(value->type));
|
|
});
|
|
|
|
llvm::Value* ret = read_value(addr, T_FLOAT);
|
|
|
|
if (type == T_SINGLE)
|
|
ret = builder->CreateFPTrunc(ret, llvmType(getFloatTy));
|
|
|
|
if (on_stack && addr == temp_value)
|
|
set_top_value(ret, type);
|
|
|
|
return ret;
|
|
}
|
|
|
|
__s2d:
|
|
{
|
|
auto str = get_string_len(val);
|
|
|
|
c_SP(-value->on_stack+on_stack);
|
|
llvm::Value* addr = on_stack ? get_value_on_top_addr() : temp_value;
|
|
|
|
llvm::Value* got_error = builder->CreateCall4(get_global_function_jif(DATE_from_string, 'c', "pipc"),
|
|
str.first, str.second,
|
|
builder->CreateBitCast(addr, llvmType(getInt8PtrTy)),
|
|
getInteger(8, false)
|
|
);
|
|
|
|
release(val, value->type);
|
|
|
|
gen_if_noreturn(builder->CreateICmpNE(got_error, getInteger(8, 0)), [&](){
|
|
create_throw(E_TYPE, JIF.F_TYPE_get_name(type), JIF.F_TYPE_get_name(value->type));
|
|
});
|
|
|
|
return read_value(addr, T_DATE);
|
|
}
|
|
|
|
/*addr = value->type == T_STRING ? value->_string.addr : NULL;
|
|
|
|
if (DATE_from_string(value->_string.addr + value->_string.start, value->_string.len, value, FALSE))
|
|
goto __N;
|
|
|
|
STRING_unref(&addr);
|
|
return;*/
|
|
|
|
__UNKNOWN:
|
|
value->on_stack = true;
|
|
value->codegen_on_stack();
|
|
__v2:
|
|
|
|
builder->CreateCall2(get_global_function_jif(VALUE_convert, 'v', "pj"),
|
|
builder->CreateBitCast(get_value_on_top_addr(), llvmType(getInt8PtrTy)),
|
|
getInteger(TARGET_BITS, type));
|
|
return ret_top_stack(type, on_stack);
|
|
|
|
/*VALUE_undo_variant(value);
|
|
goto __CONV;*/
|
|
|
|
__s2v:
|
|
__2v:
|
|
return JIT_conv_to_variant(value, val, on_stack, &no_ref_variant);
|
|
|
|
/* VALUE_put ne fonctionne pas avec T_STRING ! */
|
|
/*if (value->type != T_NULL)
|
|
VALUE_put(value, &value->_variant.value, value->type);
|
|
|
|
value->_variant.vtype = value->type;
|
|
value->type = T_VARIANT;
|
|
return;*/
|
|
|
|
__func:
|
|
|
|
//if (unknown_function(value))
|
|
// goto __CONV;
|
|
//else
|
|
goto __N;
|
|
|
|
__i2p:
|
|
__l2p:
|
|
|
|
ret = builder->CreateIntToPtr(val, llvmType(getInt8PtrTy));
|
|
goto __DONE;
|
|
|
|
__F2p:
|
|
|
|
//FIXME
|
|
abort();
|
|
/*value->_pointer.value = EXTERN_make_callback(&value->_function);
|
|
value->type = T_POINTER;
|
|
return;*/
|
|
|
|
__OBJECT:
|
|
{
|
|
if (!TYPE_is_object(type)){
|
|
val = value->codegen_get_value();
|
|
if (type == T_BOOLEAN){
|
|
llvm::Value* obj = extract_value(val, 1);
|
|
ret = builder->CreateICmpNE(obj, get_nullptr());
|
|
unref_object(obj);
|
|
goto __DONE;
|
|
}
|
|
//type == T_VARIANT
|
|
goto __2v;
|
|
}
|
|
|
|
if (!TYPE_is_object(value->type)){
|
|
if (value->type == T_NULL){
|
|
value->on_stack = false;
|
|
ret = get_new_struct(object_type, get_global((void*)type, llvmType(getInt8Ty)), get_nullptr());
|
|
goto __DONE;
|
|
}
|
|
|
|
if (value->type == T_VARIANT){
|
|
//Variant to Object
|
|
val = value->codegen_get_value();
|
|
goto __v2;
|
|
}
|
|
|
|
if (value->type == T_CLASS){
|
|
llvm::Value* object = get_global((void*)((PushClassExpression*)value)->klass, llvmType(getInt8Ty));
|
|
|
|
val = get_new_struct(object_type,
|
|
get_global((void*)GB.FindClass("Class"), llvmType(getInt8Ty)),
|
|
object);
|
|
|
|
borrow_object_no_nullcheck(object);
|
|
|
|
//To simplify code below
|
|
value->on_stack = false;
|
|
value->type = (TYPE)(void*)GB.FindClass("Class");
|
|
}
|
|
}
|
|
|
|
if (val == NULL)
|
|
val = value->codegen_get_value();
|
|
|
|
/*llvm::Value* klass = extract_value(val, 0);*/
|
|
llvm::Value* object = extract_value(val, 1);
|
|
llvm::Value* to_class = get_global((void*)type, llvmType(getInt8Ty));
|
|
|
|
if (type == T_OBJECT){
|
|
ret = get_new_struct(object_type, builder->CreateIntToPtr(getInteger(TARGET_BITS, T_OBJECT), llvmType(getInt8PtrTy)), object);
|
|
goto __DONE;
|
|
}
|
|
|
|
c_SP(-value->on_stack);
|
|
|
|
ret = gen_if_else_phi(builder->CreateICmpEQ(object, get_nullptr()), [&](){
|
|
//OK
|
|
return get_new_struct(object_type, to_class, object);
|
|
}, [&](){
|
|
if (value->type == T_OBJECT){
|
|
//klass = load_element(builder->CreateBitCast(klass, pointer_t(OBJECT_TYPE)), 0);
|
|
|
|
//return get_new_struct(object_type, to_class, builder->CreateCall3(get_global_function(JR_conv_from_T_OBJECT, 'p', "pp"), object, to_class));
|
|
}
|
|
|
|
/*//Check if klass is virtual
|
|
llvm::Value* class_flags = builder->CreateBitCast(builder->CreateGEP(klass, getInteger(TARGET_BITS, TARGET_BITS == 64 ? 32 : 20)), llvmType(getInt32Ty));
|
|
llvm::Value* is_virtual = builder->CreateTrunc(builder->CreateLShr(class_flags, getInteger(32, 10)), llvmType(getInt1Ty));
|
|
|
|
gen_if_noreturn(is_virtual, [&](){
|
|
create_throw(E_VIRTUAL);
|
|
}, "virtual_class");*/
|
|
|
|
if (value->type != T_OBJECT){
|
|
if (JIF.F_CLASS_inherits((CLASS*)(void*)value->type, (CLASS*)(void*)type)){
|
|
//This cast is always possible
|
|
return get_new_struct(object_type, to_class, object);
|
|
}
|
|
|
|
/*llvm::Value* first_invalid_test = builder->CreateICmpEQ(builder->CreateCall2(get_global_function(CLASS_inherits, 'c', "pp"), klass, to_class), getInteger(8, false));
|
|
|
|
llvm::Value* invalid_cast = gen_and_if(builder->CreateICmpNE(klass, to_class), [&](){
|
|
return builder->CreateICmpEQ(builder->CreateCall2(get_global_function(CLASS_inherits, 'c', "pp"), klass, to_class), getInteger(8, false));
|
|
});*/
|
|
}
|
|
return get_new_struct(object_type, to_class, builder->CreateCall2(get_global_function(JR_object_cast, 'p', "pp"), object, to_class));
|
|
|
|
});
|
|
|
|
if (on_stack)
|
|
push_value(ret, type);
|
|
return ret;
|
|
}
|
|
#if 0
|
|
if (!TYPE_is_object(type))
|
|
{
|
|
if (type == T_BOOLEAN)
|
|
{
|
|
test = (value->_object.object != NULL);
|
|
OBJECT_UNREF(value->_object.object, "VALUE_convert");
|
|
value->_boolean.value = -test;
|
|
value->type = T_BOOLEAN;
|
|
return;
|
|
}
|
|
|
|
if (type == T_VARIANT)
|
|
goto __2v;
|
|
|
|
goto __N;
|
|
}
|
|
|
|
if (!TYPE_is_object(value->type))
|
|
{
|
|
if (value->type == T_NULL)
|
|
{
|
|
OBJECT_null(value, (CLASS *)type); /* marche aussi pour type = T_OBJECT */
|
|
goto __TYPE;
|
|
}
|
|
|
|
if (value->type == T_VARIANT)
|
|
goto __v2;
|
|
|
|
if (value->type == T_FUNCTION)
|
|
goto __func;
|
|
|
|
if (value->type == T_CLASS)
|
|
{
|
|
klass = value->_class.klass;
|
|
|
|
if (CLASS_is_virtual(klass))
|
|
THROW(E_VIRTUAL);
|
|
|
|
CLASS_load(klass);
|
|
|
|
if (klass->auto_create)
|
|
value->_object.object = CLASS_auto_create(klass, 0);
|
|
else
|
|
value->_object.object = klass;
|
|
|
|
OBJECT_REF(value->_object.object, "VALUE_convert");
|
|
value->type = T_OBJECT;
|
|
/* on continue... */
|
|
}
|
|
else
|
|
goto __N;
|
|
}
|
|
|
|
if (value->_object.object == NULL)
|
|
goto __TYPE;
|
|
|
|
if (value->type == T_OBJECT)
|
|
{
|
|
/*if (value->_object.object == NULL)
|
|
goto __TYPE;*/
|
|
|
|
klass = OBJECT_class(value->_object.object);
|
|
/* on continue */
|
|
}
|
|
else
|
|
klass = value->_object.klass;
|
|
|
|
if (CLASS_is_virtual(klass))
|
|
THROW(E_VIRTUAL);
|
|
|
|
if (type == T_OBJECT)
|
|
goto __TYPE;
|
|
#endif
|
|
|
|
/*
|
|
if ((klass == (CLASS *)type) || CLASS_inherits(klass, (CLASS *)type))
|
|
goto __TYPE;
|
|
|
|
if (value->type != T_OBJECT && value->_object.object)
|
|
{
|
|
klass = OBJECT_class(value->_object.object);
|
|
value->type = T_OBJECT;
|
|
goto __RETRY;
|
|
}
|
|
|
|
if (klass->special[SPEC_CONVERT] != NO_SYMBOL)
|
|
{
|
|
void *conv = ((void *(*)())(CLASS_get_desc(klass, klass->special[SPEC_CONVERT])->constant.value._pointer))(value->_object.object, type);
|
|
if (conv)
|
|
{
|
|
OBJECT_REF(conv, "VALUE_conv");
|
|
OBJECT_UNREF(value->_object.object, "VALUE_conv");
|
|
value->_object.object = conv;
|
|
goto __TYPE;
|
|
}
|
|
}
|
|
|
|
THROW(E_TYPE, TYPE_get_name(type), TYPE_get_name((TYPE)klass));*/
|
|
|
|
__DONE:
|
|
|
|
c_SP(-value->on_stack+on_stack);
|
|
if (on_stack)
|
|
set_top_value(ret, type);
|
|
return ret;
|
|
|
|
__OK:
|
|
|
|
abort();
|
|
return val;
|
|
|
|
__N:
|
|
|
|
THROW(E_TYPE, JIF.F_TYPE_get_name(type), JIF.F_TYPE_get_name(value->type));
|
|
|
|
__NR:
|
|
|
|
THROW(E_NRETURN);
|
|
}
|
|
|
|
#endif /* __JIT_CODEGEN_CONV_H */
|