From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from [87.239.111.99] (localhost [127.0.0.1]) by dev.tarantool.org (Postfix) with ESMTP id 0605D8927F5; Tue, 28 Nov 2023 15:25:47 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 dev.tarantool.org 0605D8927F5 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=tarantool.org; s=dev; t=1701174347; bh=B4aUucevdcqlfcPBoUCG5W3tWFUofsfpSS1brIHzs7c=; h=To:Date:Subject:List-Id:List-Unsubscribe:List-Archive:List-Post: List-Help:List-Subscribe:From:Reply-To:Cc:From; b=u/2dDz8ZJH3XzDyTcGaY2xAIIgb9P0oopRVkapdLUOHK2ifHjldaDWOcppw3hG3lR AIHRQVKfKfV97LiyJ3K4IS0Z9ITQ44Snl1ErP/rQku6RX2RrvFwc6mpHCPOrAb0rmj ASuT0mX0gCtsF5vqNVWBxoJBpuDHZ00sbXRjnIDY= Received: from smtp16.i.mail.ru (smtp16.i.mail.ru [95.163.41.69]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by dev.tarantool.org (Postfix) with ESMTPS id C4FA7FDE41 for ; Tue, 28 Nov 2023 15:25:44 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 dev.tarantool.org C4FA7FDE41 Received: by smtp16.i.mail.ru with esmtpa (envelope-from ) id 1r7x9s-00GTrF-01; Tue, 28 Nov 2023 15:25:44 +0300 To: Maxim Kokryashkin , Sergey Bronnikov Date: Tue, 28 Nov 2023 15:21:12 +0300 Message-ID: <20231128122112.16229-1-skaplun@tarantool.org> X-Mailer: git-send-email 2.42.1 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Mailru-Src: smtp X-7564579A: EEAE043A70213CC8 X-77F55803: 4F1203BC0FB41BD9D2A6479154BC7F41A126550EFD29F2664D8B4428834D7431182A05F538085040A887B4917D543B881813BC007436C2F7CC4A70FB4FFA8F5FBCD1920647F9FD49 X-7FA49CB5: FF5795518A3D127A4AD6D5ED66289B5278DA827A17800CE701173C01F417A2A6EA1F7E6F0F101C67BD4B6F7A4D31EC0BCC500DACC3FED6E28638F802B75D45FF8AA50765F7900637C21C2889FA5309238638F802B75D45FF36EB9D2243A4F8B5A6FCA7DBDB1FC311F39EFFDF887939037866D6147AF826D8CD6CFCD849DFA72571FFD27D52BF52C3117882F4460429724CE54428C33FAD305F5C1EE8F4F765FC1BE95B8C87527B4BA471835C12D1D9774AD6D5ED66289B52BA9C0B312567BB23117882F44604297287769387670735201E561CDFBCA1751F618001F51B5FD3F9D2E47CDBA5A96583BA9C0B312567BB2376E601842F6C81A19E625A9149C048EE26055571C92BF10FEA93887B71B66F2BD8FC6C240DEA76429C9F4D5AE37F343AA9539A8B242431040A6AB1C7CE11FEE397AD43380FEE24CA302FCEF25BFAB345C4224003CC836476E2F48590F00D11D6E2021AF6380DFAD1A18204E546F3947CC2B5EEE3591E0D352E808ACE2090B5E1725E5C173C3A84C317B107DEF921CE79089D37D7C0E48F6C8AA50765F7900637BF1C901A33650803EFF80C71ABB335746BA297DBC24807EABDAD6C7F3747799A X-C1DE0DAB: 0D63561A33F958A52B245E58DAEDC03BC4B7CF48B3481556F6AAE36F1AF2432BF87CCE6106E1FC07E67D4AC08A07B9B0632EDEA9CD5989A39C5DF10A05D560A950611B66E3DA6D700B0A020F03D25A0997E3FB2386030E77 X-C8649E89: 1C3962B70DF3F0ADBF74143AD284FC7177DD89D51EBB7742DC8270968E61249B1004E42C50DC4CA955A7F0CF078B5EC49A30900B95165D340297C696F996E3844EF76F9D490E581F21E6CEC80C476566663FB2B2E92C51B0A1A1E5F87724E2351D7E09C32AA3244C64B2ECBEB8CE216C18C23EA5C408190033C9DC155518937FBAD658CF5C8AB4025DA084F8E80FEBD3202CD0F03380D9577A83BD0C44CE203720ABEDE4BBDD9CDD X-D57D3AED: 3ZO7eAau8CL7WIMRKs4sN3D3tLDjz0dLbV79QFUyzQ2Ujvy7cMT6pYYqY16iZVKkSc3dCLJ7zSJH7+u4VD18S7Vl4ZUrpaVfd2+vE6kuoey4m4VkSEu530nj6fImhcD4MUrOEAnl0W826KZ9Q+tr5ycPtXkTV4k65bRjmOUUP8cvGozZ33TWg5HZplvhhXbhDGzqmQDTd6OAevLeAnq3Ra9uf7zvY2zzsIhlcp/Y7m53TZgf2aB4JOg4gkr2biojcqZ8kcsJfPE7aOgQcpkeMw== X-Mailru-Sender: 11C2EC085EDE56FAC07928AF2646A769CBD897468541C9D11813BC007436C2F7BC4EE72AB2E748C5DEDBA653FF35249392D99EB8CC7091A70E183A470755BFD208F19895AA18418972D6B4FCE48DF648AE208404248635DF X-Mras: Ok Subject: [Tarantool-patches] [PATCH luajit] Prevent CSE of a REF_BASE operand across IR_RETF. X-BeenThere: tarantool-patches@dev.tarantool.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: Tarantool development patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , From: Sergey Kaplun via Tarantool-patches Reply-To: Sergey Kaplun Cc: tarantool-patches@dev.tarantool.org Errors-To: tarantool-patches-bounces@dev.tarantool.org Sender: "Tarantool-patches" From: Mike Pall Reported by XmiliaH. (cherry-picked from commit e73916d811710ab02a4dfe447d621c99f4e7186c) The RETF IR has a side effect: it shifts base when returning to a lower frame, i.e., it affects `REF_BASE` IR (0000) (thus, we can say that this IR is violating SSA form). So any optimization of IRs with `REF_BASE` as an operand across RETF IR may lead to incorrect optimizations (see details in the test file). This patch adds rules to the folding engine to prevent CSE across `IR_RETF` for all possible IRs containing REF_BASE. Sergey Kaplun: * added the description and the test for the problem Part of tarantool/tarantool#9145 --- Branch: https://github.com/tarantool/luajit/tree/skaplun/lj-784-cse-ref-base-over-retf Tarantool PR: https://github.com/tarantool/tarantool/pull/9421 Related issues: * https://github.com/LuaJIT/LuaJIT/issues/784 * https://github.com/tarantool/tarantool/issues/9145 Interested reviewers can mention that only the `SUB any BASE` case is tested. The reason is that other cases are impossible to record in LuaJIT: * EQ any BASE: EQ pgc REF_BASE IR for upvalues is emitted when the open upvalue aliases a SSA slot, i.e., it belongs to the frame of the currently executed function. In that case, if we want to emit RETF IR, we need to leave this function. So we need to record the UCLO bytecode, which is NIY in JIT. So, such a type of trace is impossible. * SUB BASE any: SUB BASE fr is emitted for the recording of VARG bytecode, in case varargs are undefined on trace. We need a vararg function to call to create an additional frame. But returning to lower frames from a vararg function isn't implemented in LuaJIT -- either the trace recording is stopped or the error is rased and the trace isn't compiled. Also, IINM, fr operands will always be different for different frames, so there is no possible CSE here. So, these cases are needed to prevent any regressions in the future. Please correct me if I've missed something. src/lj_opt_fold.c | 11 +++ .../lj-784-cse-ref-base-over-retf.test.lua | 86 +++++++++++++++++++ 2 files changed, 97 insertions(+) create mode 100644 test/tarantool-tests/lj-784-cse-ref-base-over-retf.test.lua diff --git a/src/lj_opt_fold.c b/src/lj_opt_fold.c index c5f2232e..750f1c7e 100644 --- a/src/lj_opt_fold.c +++ b/src/lj_opt_fold.c @@ -2313,6 +2313,17 @@ LJFOLDF(xload_kptr) LJFOLD(XLOAD any any) LJFOLDX(lj_opt_fwd_xload) +/* -- Frame handling ------------------------------------------------------ */ + +/* Prevent CSE of a REF_BASE operand across IR_RETF. */ +LJFOLD(SUB any BASE) +LJFOLD(SUB BASE any) +LJFOLD(EQ any BASE) +LJFOLDF(fold_base) +{ + return lj_opt_cselim(J, J->chain[IR_RETF]); +} + /* -- Write barriers ------------------------------------------------------ */ /* Write barriers are amenable to CSE, but not across any incremental diff --git a/test/tarantool-tests/lj-784-cse-ref-base-over-retf.test.lua b/test/tarantool-tests/lj-784-cse-ref-base-over-retf.test.lua new file mode 100644 index 00000000..095376fc --- /dev/null +++ b/test/tarantool-tests/lj-784-cse-ref-base-over-retf.test.lua @@ -0,0 +1,86 @@ +local tap = require('tap') + +-- Test file to demonstrate incorrect FOLD optimization for IR +-- with REF_BASE operand across IR RETF. +-- See also, https://github.com/LuaJIT/LuaJIT/issues/784. + +local test = tap.test('lj-784-cse-ref-base-over-retf'):skipcond({ + ['Test requires JIT enabled'] = not jit.status(), +}) + +test:plan(1) + +-- The RETF IR has a side effect: it shifts base when returning to +-- a lower frame, i.e., it affects `REF_BASE` IR (0000) (thus, we +-- can say that this IR is violating SSA form). +-- So any optimization of IRs with `REF_BASE` as an operand across +-- RETF IR may lead to incorrect optimizations. +-- In this test, SUB uref REF_BASE IR was eliminated, so instead +-- the following trace: +-- +-- 0004 p32 SUB 0003 0000 +-- 0005 > p32 UGT 0004 +32 +-- ... +-- 0009 > p32 RETF proto: 0x407dc118 [0x407dc194] +-- ... +-- 0012 p32 SUB 0003 0000 +-- 0013 > p32 UGT 0012 +72 +-- +-- We got the following: +-- +-- 0004 p32 SUB 0003 0000 +-- 0005 > p32 UGT 0004 +32 +-- ... +-- 0009 > p32 RETF proto: 0x41ffe0c0 [0x41ffe13c] +-- ... +-- 0012 > p32 UGT 0004 +72 +-- +-- As you can see, the 0012 SUB IR is eliminated because it is the +-- same as the 0004 IR. This leads to incorrect assertion guards +-- in the IR below. + +local MAGIC = 42 +-- XXX: simplify `jit.dump()` output. +local fmod = math.fmod + +local function exit_with_retf(closure) + -- Forcify stitch. Any NYI is OK here. + fmod(1, 1) + -- Call the closure so that we have emitted `uref - REF_BASE`. + closure(0) + -- Exit with `IR_RETF`. This will change `REF_BASE`. +end + +local function sub_uref_base(closure) + local open_upvalue + if closure == nil then + closure = function(val) + local old = open_upvalue + open_upvalue = val + return old + end + -- First, create an additional frame, so we got the trace, + -- where the open upvalue reference is always < `REF_BASE`. + sub_uref_base(closure) + end + for _ = 1, 4 do + -- `closure` function is inherited from the previous frame. + exit_with_retf(closure) + open_upvalue = MAGIC + -- The open upvalue guard will use CSE over `IR_RETF` for + -- `uref - REF_BASE`. `IR_RETF` changed the value of + -- `REF_BASE`. + -- Thus, the guards afterwards take the wrong IR as the first + -- operand, so they are not failed, and the wrong value is + -- returned from the trace. + open_upvalue = closure(0) + end + return open_upvalue +end + +jit.opt.start('hotloop=1') + +local res = sub_uref_base() +test:is(res, MAGIC, 'no SUB uref REF_BASE CSE across RETF') + +test:done(true) -- 2.42.1