33 * Tiny Code Generator for QEMU
44 *
55 * Copyright (c) 2009, 2011 Stefan Weil
6+ * Copyright (c) 2018 SiFive, Inc
7+ * Copyright (c) 2008-2009 Arnaud Patard <arnaud.patard@rtp-net.org>
8+ * Copyright (c) 2009 Aurelien Jarno <aurelien@aurel32.net>
9+ * Copyright (c) 2008 Fabrice Bellard
610 *
7- * Based on tci/tcg-target.c.inc
11+ * Based on tci/tcg-target.c.inc and riscv/tcg-target.c.inc
812 *
913 * Permission is hereby granted, free of charge, to any person obtaining a copy
1014 * of this software and associated documentation files (the "Software"), to deal
@@ -154,6 +158,11 @@ static const uint8_t tcg_target_reg_index[TCG_TARGET_NB_REGS] = {
154158/* Local variable pointing to WasmContext */
155159#define CTX_IDX 0
156160
161+ /* Temporary local variables */
162+ #define TMP32_LOCAL_0_IDX 1
163+ #define TMP64_LOCAL_0_IDX 2
164+ #define TMP64_LOCAL_1_IDX 3
165+
157166/* Function index */
158167#define CHECK_UNWINDING_IDX 0 /* A function to check the Asyncify status */
159168#define HELPER_IDX_START 1 /* The first index of helper functions */
@@ -170,6 +179,8 @@ typedef enum {
170179 OPC_RETURN = 0x0f ,
171180 OPC_CALL = 0x10 ,
172181 OPC_LOCAL_GET = 0x20 ,
182+ OPC_LOCAL_SET = 0x21 ,
183+ OPC_LOCAL_TEE = 0x22 ,
173184 OPC_GLOBAL_GET = 0x23 ,
174185 OPC_GLOBAL_SET = 0x24 ,
175186
@@ -1217,11 +1228,156 @@ static void *qemu_ld_helper_ptr(uint32_t oi)
12171228 }
12181229}
12191230
1231+ #define MIN_TLB_MASK_TABLE_OFS INT_MIN
1232+
1233+ static uint8_t prepare_host_addr_wasm (TCGContext *s, uint8_t *hit_var,
1234+ TCGReg addr_reg, MemOpIdx oi,
1235+ bool is_ld)
1236+ {
1237+ MemOp opc = get_memop (oi);
1238+ TCGAtomAlign aa;
1239+ unsigned a_mask;
1240+ unsigned s_bits = opc & MO_SIZE;
1241+ unsigned s_mask = (1u << s_bits) - 1 ;
1242+ int mem_index = get_mmuidx (oi);
1243+ int fast_ofs = tlb_mask_table_ofs (s, mem_index);
1244+ int mask_ofs = fast_ofs + offsetof (CPUTLBDescFast, mask);
1245+ int table_ofs = fast_ofs + offsetof (CPUTLBDescFast, table);
1246+ int add_off = offsetof (CPUTLBEntry, addend);
1247+ tcg_target_long compare_mask;
1248+ int offset;
1249+
1250+ uint8_t tmp1 = TMP64_LOCAL_0_IDX;
1251+ uint8_t tmp2 = TMP64_LOCAL_1_IDX;
1252+
1253+ if (!tcg_use_softmmu) {
1254+ g_assert_not_reached ();
1255+ }
1256+
1257+ *hit_var = TMP32_LOCAL_0_IDX;
1258+ tcg_wasm_out_op_const (s, OPC_I32_CONST, 0 );
1259+ tcg_wasm_out_op_idx (s, OPC_LOCAL_SET, *hit_var);
1260+
1261+ aa = atom_and_align_for_opc (s, opc, MO_ATOM_IFALIGN, false );
1262+ a_mask = (1u << aa.align ) - 1 ;
1263+
1264+ /* Get the CPUTLBEntry offset */
1265+ tcg_wasm_out_op_idx (s, OPC_GLOBAL_GET, REG_IDX (addr_reg));
1266+ tcg_wasm_out_op_const (s, OPC_I64_CONST,
1267+ TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS);
1268+ tcg_wasm_out_op (s, OPC_I64_SHR_U);
1269+
1270+ tcg_wasm_out_op_idx (s, OPC_GLOBAL_GET, REG_IDX (TCG_AREG0));
1271+ offset = tcg_wasm_out_norm_ptr (s, mask_ofs);
1272+ tcg_wasm_out_op_ldst (s, OPC_I64_LOAD, 0 , offset);
1273+ tcg_wasm_out_op (s, OPC_I64_AND);
1274+
1275+ /* Get the pointer to the target CPUTLBEntry */
1276+ tcg_wasm_out_op_idx (s, OPC_GLOBAL_GET, REG_IDX (TCG_AREG0));
1277+ offset = tcg_wasm_out_norm_ptr (s, table_ofs);
1278+ tcg_wasm_out_op_ldst (s, OPC_I64_LOAD, 0 , offset);
1279+ tcg_wasm_out_op (s, OPC_I64_ADD);
1280+ tcg_wasm_out_op_idx (s, OPC_LOCAL_TEE, tmp1);
1281+
1282+ /* Load the tlb copmarator */
1283+ offset = tcg_wasm_out_norm_ptr (s, is_ld ? offsetof (CPUTLBEntry, addr_read)
1284+ : offsetof (CPUTLBEntry, addr_write));
1285+ tcg_wasm_out_op_ldst (s, OPC_I64_LOAD, 0 , offset);
1286+
1287+ /*
1288+ * For aligned accesses, we check the first byte and include the
1289+ * alignment bits within the address. For unaligned access, we
1290+ * check that we don't cross pages using the address of the last
1291+ * byte of the access.
1292+ */
1293+ tcg_wasm_out_op_idx (s, OPC_GLOBAL_GET, REG_IDX (addr_reg));
1294+ if (a_mask < s_mask) {
1295+ tcg_wasm_out_op_const (s, OPC_I64_CONST, s_mask - a_mask);
1296+ tcg_wasm_out_op (s, OPC_I64_ADD);
1297+ }
1298+ compare_mask = (uint64_t )TARGET_PAGE_MASK | a_mask;
1299+ tcg_wasm_out_op_const (s, OPC_I64_CONST, compare_mask);
1300+ tcg_wasm_out_op (s, OPC_I64_AND);
1301+
1302+ /* Compare masked address with the TLB entry. */
1303+ tcg_wasm_out_op (s, OPC_I64_EQ);
1304+
1305+ tcg_wasm_out_op_block (s, OPC_IF, BLOCK_NORET);
1306+
1307+ /* TLB Hit - translate address using addend. */
1308+ tcg_wasm_out_op_idx (s, OPC_LOCAL_GET, tmp1);
1309+ offset = tcg_wasm_out_norm_ptr (s, add_off);
1310+ tcg_wasm_out_op_ldst (s, OPC_I64_LOAD, 0 , offset);
1311+ tcg_wasm_out_op_idx (s, OPC_GLOBAL_GET, REG_IDX (addr_reg));
1312+ tcg_wasm_out_op (s, OPC_I64_ADD);
1313+ tcg_wasm_out_op_idx (s, OPC_LOCAL_SET, tmp2);
1314+ tcg_wasm_out_op_const (s, OPC_I32_CONST, 1 );
1315+ tcg_wasm_out_op_idx (s, OPC_LOCAL_SET, *hit_var);
1316+
1317+ tcg_wasm_out_op (s, OPC_END);
1318+
1319+ return tmp2;
1320+ }
1321+
1322+ static void tcg_wasm_out_qemu_ld_direct (
1323+ TCGContext *s, TCGReg r, uint8_t base, MemOp opc)
1324+ {
1325+ intptr_t ofs;
1326+ switch (opc & (MO_SSIZE)) {
1327+ case MO_UB:
1328+ tcg_wasm_out_op_idx (s, OPC_LOCAL_GET, base);
1329+ ofs = tcg_wasm_out_norm_ptr (s, 0 );
1330+ tcg_wasm_out_op_ldst (s, OPC_I64_LOAD8_U, 0 , ofs);
1331+ tcg_wasm_out_op_idx (s, OPC_GLOBAL_SET, REG_IDX (r));
1332+ break ;
1333+ case MO_SB:
1334+ tcg_wasm_out_op_idx (s, OPC_LOCAL_GET, base);
1335+ ofs = tcg_wasm_out_norm_ptr (s, 0 );
1336+ tcg_wasm_out_op_ldst (s, OPC_I64_LOAD8_S, 0 , ofs);
1337+ tcg_wasm_out_op_idx (s, OPC_GLOBAL_SET, REG_IDX (r));
1338+ break ;
1339+ case MO_UW:
1340+ tcg_wasm_out_op_idx (s, OPC_LOCAL_GET, base);
1341+ ofs = tcg_wasm_out_norm_ptr (s, 0 );
1342+ tcg_wasm_out_op_ldst (s, OPC_I64_LOAD16_U, 0 , ofs);
1343+ tcg_wasm_out_op_idx (s, OPC_GLOBAL_SET, REG_IDX (r));
1344+ break ;
1345+ case MO_SW:
1346+ tcg_wasm_out_op_idx (s, OPC_LOCAL_GET, base);
1347+ ofs = tcg_wasm_out_norm_ptr (s, 0 );
1348+ tcg_wasm_out_op_ldst (s, OPC_I64_LOAD16_S, 0 , ofs);
1349+ tcg_wasm_out_op_idx (s, OPC_GLOBAL_SET, REG_IDX (r));
1350+ break ;
1351+ case MO_UL:
1352+ tcg_wasm_out_op_idx (s, OPC_LOCAL_GET, base);
1353+ ofs = tcg_wasm_out_norm_ptr (s, 0 );
1354+ tcg_wasm_out_op_ldst (s, OPC_I64_LOAD32_U, 0 , ofs);
1355+ tcg_wasm_out_op_idx (s, OPC_GLOBAL_SET, REG_IDX (r));
1356+ break ;
1357+ case MO_SL:
1358+ tcg_wasm_out_op_idx (s, OPC_LOCAL_GET, base);
1359+ ofs = tcg_wasm_out_norm_ptr (s, 0 );
1360+ tcg_wasm_out_op_ldst (s, OPC_I64_LOAD32_S, 0 , ofs);
1361+ tcg_wasm_out_op_idx (s, OPC_GLOBAL_SET, REG_IDX (r));
1362+ break ;
1363+ case MO_UQ:
1364+ tcg_wasm_out_op_idx (s, OPC_LOCAL_GET, base);
1365+ ofs = tcg_wasm_out_norm_ptr (s, 0 );
1366+ tcg_wasm_out_op_ldst (s, OPC_I64_LOAD, 0 , ofs);
1367+ tcg_wasm_out_op_idx (s, OPC_GLOBAL_SET, REG_IDX (r));
1368+ break ;
1369+ default :
1370+ g_assert_not_reached ();
1371+ }
1372+ }
1373+
12201374static void tcg_wasm_out_qemu_ld (TCGContext *s, TCGReg data_reg,
12211375 TCGReg addr_reg, MemOpIdx oi)
12221376{
12231377 intptr_t helper_idx;
12241378 int64_t func_idx;
1379+ MemOp mop = get_memop (oi);
1380+ uint8_t base_var, hit_var;
12251381
12261382 helper_idx = (intptr_t )qemu_ld_helper_ptr (oi);
12271383 func_idx = get_helper_idx (s, helper_idx);
@@ -1230,6 +1386,14 @@ static void tcg_wasm_out_qemu_ld(TCGContext *s, TCGReg data_reg,
12301386 gen_func_type_qemu_ld (s, oi);
12311387 }
12321388
1389+ base_var = prepare_host_addr_wasm (s, &hit_var, addr_reg, oi, true );
1390+ tcg_wasm_out_op_idx (s, OPC_LOCAL_GET, hit_var);
1391+ tcg_wasm_out_op_const (s, OPC_I32_CONST, 1 );
1392+ tcg_wasm_out_op (s, OPC_I32_EQ);
1393+ tcg_wasm_out_op_block (s, OPC_IF, BLOCK_NORET);
1394+ tcg_wasm_out_qemu_ld_direct (s, data_reg, base_var, mop); /* fast path */
1395+ tcg_wasm_out_op (s, OPC_END);
1396+
12331397 /*
12341398 * update the block index so that the possible rewinding will
12351399 * skip this block
@@ -1238,6 +1402,10 @@ static void tcg_wasm_out_qemu_ld(TCGContext *s, TCGReg data_reg,
12381402 tcg_wasm_out_op_idx (s, OPC_GLOBAL_SET, BLOCK_IDX);
12391403 tcg_wasm_out_new_block (s);
12401404
1405+ tcg_wasm_out_op_idx (s, OPC_LOCAL_GET, hit_var);
1406+ tcg_wasm_out_op (s, OPC_I32_EQZ);
1407+ tcg_wasm_out_op_block (s, OPC_IF, BLOCK_NORET);
1408+
12411409 /* call the target helper */
12421410 tcg_wasm_out_op_idx (s, OPC_GLOBAL_GET, REG_IDX (TCG_AREG0));
12431411 tcg_wasm_out_op_idx (s, OPC_GLOBAL_GET, REG_IDX (addr_reg));
@@ -1247,6 +1415,8 @@ static void tcg_wasm_out_qemu_ld(TCGContext *s, TCGReg data_reg,
12471415 tcg_wasm_out_op_idx (s, OPC_CALL, func_idx);
12481416 tcg_wasm_out_op_idx (s, OPC_GLOBAL_SET, REG_IDX (data_reg));
12491417 tcg_wasm_out_handle_unwinding (s);
1418+
1419+ tcg_wasm_out_op (s, OPC_END);
12501420}
12511421
12521422static void *qemu_st_helper_ptr (uint32_t oi)
@@ -1266,12 +1436,47 @@ static void *qemu_st_helper_ptr(uint32_t oi)
12661436 }
12671437}
12681438
1439+ static void tcg_wasm_out_qemu_st_direct (
1440+ TCGContext *s, TCGReg lo, uint8_t base, MemOp opc)
1441+ {
1442+ intptr_t ofs;
1443+ switch (opc & (MO_SSIZE)) {
1444+ case MO_8:
1445+ tcg_wasm_out_op_idx (s, OPC_LOCAL_GET, base);
1446+ ofs = tcg_wasm_out_norm_ptr (s, 0 );
1447+ tcg_wasm_out_op_idx (s, OPC_GLOBAL_GET, REG_IDX (lo));
1448+ tcg_wasm_out_op_ldst (s, OPC_I64_STORE8, 0 , ofs);
1449+ break ;
1450+ case MO_16:
1451+ tcg_wasm_out_op_idx (s, OPC_LOCAL_GET, base);
1452+ ofs = tcg_wasm_out_norm_ptr (s, 0 );
1453+ tcg_wasm_out_op_idx (s, OPC_GLOBAL_GET, REG_IDX (lo));
1454+ tcg_wasm_out_op_ldst (s, OPC_I64_STORE16, 0 , ofs);
1455+ break ;
1456+ case MO_32:
1457+ tcg_wasm_out_op_idx (s, OPC_LOCAL_GET, base);
1458+ ofs = tcg_wasm_out_norm_ptr (s, 0 );
1459+ tcg_wasm_out_op_idx (s, OPC_GLOBAL_GET, REG_IDX (lo));
1460+ tcg_wasm_out_op_ldst (s, OPC_I64_STORE32, 0 , ofs);
1461+ break ;
1462+ case MO_64:
1463+ tcg_wasm_out_op_idx (s, OPC_LOCAL_GET, base);
1464+ ofs = tcg_wasm_out_norm_ptr (s, 0 );
1465+ tcg_wasm_out_op_idx (s, OPC_GLOBAL_GET, REG_IDX (lo));
1466+ tcg_wasm_out_op_ldst (s, OPC_I64_STORE, 0 , ofs);
1467+ break ;
1468+ default :
1469+ g_assert_not_reached ();
1470+ }
1471+ }
1472+
12691473static void tcg_wasm_out_qemu_st (TCGContext *s, TCGReg data_reg,
12701474 TCGReg addr_reg, MemOpIdx oi)
12711475{
12721476 intptr_t helper_idx;
12731477 int64_t func_idx;
12741478 MemOp mop = get_memop (oi);
1479+ uint8_t base_var, hit_var;
12751480
12761481 helper_idx = (intptr_t )qemu_st_helper_ptr (oi);
12771482 func_idx = get_helper_idx (s, helper_idx);
@@ -1280,6 +1485,14 @@ static void tcg_wasm_out_qemu_st(TCGContext *s, TCGReg data_reg,
12801485 gen_func_type_qemu_st (s, oi);
12811486 }
12821487
1488+ base_var = prepare_host_addr_wasm (s, &hit_var, addr_reg, oi, false );
1489+ tcg_wasm_out_op_idx (s, OPC_LOCAL_GET, hit_var);
1490+ tcg_wasm_out_op_const (s, OPC_I32_CONST, 1 );
1491+ tcg_wasm_out_op (s, OPC_I32_EQ);
1492+ tcg_wasm_out_op_block (s, OPC_IF, BLOCK_NORET);
1493+ tcg_wasm_out_qemu_st_direct (s, data_reg, base_var, mop); /* fast path */
1494+ tcg_wasm_out_op (s, OPC_END);
1495+
12831496 /*
12841497 * update the block index so that the possible rewinding will
12851498 * skip this block
@@ -1288,6 +1501,10 @@ static void tcg_wasm_out_qemu_st(TCGContext *s, TCGReg data_reg,
12881501 tcg_wasm_out_op_idx (s, OPC_GLOBAL_SET, BLOCK_IDX);
12891502 tcg_wasm_out_new_block (s);
12901503
1504+ tcg_wasm_out_op_idx (s, OPC_LOCAL_GET, hit_var);
1505+ tcg_wasm_out_op (s, OPC_I32_EQZ);
1506+ tcg_wasm_out_op_block (s, OPC_IF, BLOCK_NORET);
1507+
12911508 /* call the target helper */
12921509 tcg_wasm_out_op_idx (s, OPC_GLOBAL_GET, REG_IDX (TCG_AREG0));
12931510 tcg_wasm_out_op_idx (s, OPC_GLOBAL_GET, REG_IDX (addr_reg));
@@ -1305,6 +1522,8 @@ static void tcg_wasm_out_qemu_st(TCGContext *s, TCGReg data_reg,
13051522
13061523 tcg_wasm_out_op_idx (s, OPC_CALL, func_idx);
13071524 tcg_wasm_out_handle_unwinding (s);
1525+
1526+ tcg_wasm_out_op (s, OPC_END);
13081527}
13091528
13101529static void tcg_out_op_l (TCGContext *s, TCGOpcode op, TCGLabel *l0)
@@ -2152,7 +2371,7 @@ static const TCGOutOpQemuLdSt outop_qemu_st = {
21522371
21532372bool tcg_target_has_memory_bswap (MemOp memop)
21542373{
2155- return true ;
2374+ return false ;
21562375}
21572376
21582377static bool tcg_out_qemu_ld_slow_path (TCGContext *s, TCGLabelQemuLdst *l)
@@ -2384,7 +2603,7 @@ static const uint8_t mod_3[] = {
23842603 0x80 , 0x80 , 0x80 , 0x80 , 0x00 , /* placeholder for section size*/
23852604 1 , /* num of codes */
23862605 0x80 , 0x80 , 0x80 , 0x80 , 0x00 , /* placeholder for code size */
2387- 0x0 , /* local variables (none ) */
2606+ 0x2 , 0x1 , 0x7f , 0x2 , 0x7e , /* local variables (32bit*1, 64bit*2 ) */
23882607};
23892608
23902609#define MOD_3_PH_EXPORT_START_FUNC_IDX 102
0 commit comments