+static bool try_create_integer(literal_expression_t *literal,
+ type_t *type, unsigned char base)
+{
+ const char *string = literal->value.begin;
+ size_t size = literal->value.size;
+
+ assert(type->kind == TYPE_ATOMIC);
+ atomic_type_kind_t akind = type->atomic.akind;
+
+ ir_mode *mode = atomic_modes[akind];
+ ir_tarval *tv = new_integer_tarval_from_str(string, size, 1, base, mode);
+ if (tv == tarval_bad)
+ return false;
+
+ literal->base.type = type;
+ literal->target_value = tv;
+ return true;
+}
+
+static void create_integer_tarval(literal_expression_t *literal)
+{
+ unsigned us = 0;
+ unsigned ls = 0;
+ const string_t *suffix = &literal->suffix;
+ /* parse suffix */
+ if (suffix->size > 0) {
+ for (const char *c = suffix->begin; *c != '\0'; ++c) {
+ if (*c == 'u' || *c == 'U') { ++us; }
+ if (*c == 'l' || *c == 'L') { ++ls; }
+ }
+ }
+
+ unsigned base;
+ switch (literal->base.kind) {
+ case EXPR_LITERAL_INTEGER_OCTAL: base = 8; break;
+ case EXPR_LITERAL_INTEGER: base = 10; break;
+ case EXPR_LITERAL_INTEGER_HEXADECIMAL: base = 16; break;
+ default: panic("invalid literal kind");
+ }
+
+ tarval_int_overflow_mode_t old_mode = tarval_get_integer_overflow_mode();
+
+ /* now try if the constant is small enough for some types */
+ tarval_set_integer_overflow_mode(TV_OVERFLOW_BAD);
+ if (ls < 1) {
+ if (us == 0 && try_create_integer(literal, type_int, base))
+ goto finished;
+ if ((us == 1 || base != 10)
+ && try_create_integer(literal, type_unsigned_int, base))
+ goto finished;
+ }
+ if (ls < 2) {
+ if (us == 0 && try_create_integer(literal, type_long, base))
+ goto finished;
+ if ((us == 1 || base != 10)
+ && try_create_integer(literal, type_unsigned_long, base))
+ goto finished;
+ }
+ /* last try? then we should not report tarval_bad */
+ if (us != 1 && base == 10)
+ tarval_set_integer_overflow_mode(TV_OVERFLOW_WRAP);
+ if (us == 0 && try_create_integer(literal, type_long_long, base))
+ goto finished;
+
+ /* last try */
+ assert(us == 1 || base != 10);
+ tarval_set_integer_overflow_mode(TV_OVERFLOW_WRAP);
+ bool res = try_create_integer(literal, type_unsigned_long_long, base);
+ if (!res)
+ panic("internal error when parsing number literal");
+
+finished:
+ tarval_set_integer_overflow_mode(old_mode);
+}
+
+void determine_literal_type(literal_expression_t *literal)
+{
+ switch (literal->base.kind) {
+ case EXPR_LITERAL_INTEGER:
+ case EXPR_LITERAL_INTEGER_OCTAL:
+ case EXPR_LITERAL_INTEGER_HEXADECIMAL:
+ create_integer_tarval(literal);
+ return;
+ default:
+ break;
+ }