blob: 8da755ea5d84e534bb104d185fd7041d1162157e [file] [log] [blame]
/*
* Copyright (c) 2014 The Native Client Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "gtest/gtest.h"
#include <setjmp.h>
#include <stdio.h>
#include <stdlib.h>
// Macro to generate variable
#define VAR0(x) x = get_next()
#define VAR1(x) \
VAR0(x##0) \
, VAR0(x##1), VAR0(x##2), VAR0(x##3), VAR0(x##4), VAR0(x##5), VAR0(x##6), \
VAR0(x##7), VAR0(x##8), VAR0(x##9)
#define COMP(var, val) check_equals(var, val);
#define CHECK_VAL(x, i, s) \
COMP(x##i##0, s + i##0); \
COMP(x##i##1, s + i##1); \
COMP(x##i##2, s + i##2); \
COMP(x##i##3, s + i##3); \
COMP(x##i##4, s + i##4); \
COMP(x##i##5, s + i##5); \
COMP(x##i##6, s + i##6); \
COMP(x##i##7, s + i##7); \
COMP(x##i##8, s + i##8); \
COMP(x##i##9, s + i##9)
namespace {
class LongJmpStackSlotsTests : public ::testing::Test {
protected:
LongJmpStackSlotsTests() {
// You can do set-up work for each test here.
}
~LongJmpStackSlotsTests() override {}
void SetUp() override {}
void TearDown() override {}
};
} // namespace
static int g_counter = 9;
__attribute__((noinline)) int get_next(void) { return ++g_counter; }
__attribute__((noinline)) void check_equals(int actual, int expected) {
ASSERT_EQ(actual, expected);
}
/*
* This tests the reuse of stack slots in cases where use of
* setjmp() should disable that.
*
* this test must be compiled with optimisation, in order
* to run mem2reg and use spill slots. However, get_next() and
* check_equals() must not be inlined.
*/
TEST_F(LongJmpStackSlotsTests, TestLongJmpStackSlots) {
/*
* Keep enough variables live across the setjmp() call that they don't
* all fit in registers, so that the compiler spills some of them to
* spill slots on the stack.
*
* There need to be >31 variables here to test this on aarch64.
*/
int VAR1(a1);
int VAR1(a2);
int VAR1(a3);
int VAR1(a4);
jmp_buf buf;
if (setjmp(buf)) {
CHECK_VAL(a, 1, 0);
CHECK_VAL(a, 2, 0);
CHECK_VAL(a, 3, 0);
CHECK_VAL(a, 4, 0);
} else {
/*
* Again, keep enough variables live that some of them will need spill
* slots. A correct compiler will realise that a1...aN are still live
* (via setjmp()+longjmp()), and so not reuse the earlier spill slots.
* An incorrect compiler will think that a1..aN are dead here and wrongly
* reuse the earlier spill slots.
*/
int VAR1(b1);
int VAR1(b2);
int VAR1(b3);
int VAR1(b4);
int start = 40;
CHECK_VAL(b, 1, start);
CHECK_VAL(b, 2, start);
CHECK_VAL(b, 3, start);
CHECK_VAL(b, 4, start);
longjmp(buf, 1);
}
}