Showing posts with label C. Show all posts
Showing posts with label C. Show all posts

7/25/2025

Understanding C++ Templates, (class, member function and this)

 

template<int INT>
void AAA() {
std::cout << "INT = " << INT << std::endl;
}

How to Call It:

Normal Context (Outside Class):

AAA<2>(); // ✅ Just call directly
AAA<5>(); // ✅ Works fine
AAA<10>(); // ✅ No problem

Inside Template Class Context:

template<typename T>
class MyClass {
template<int INT>
void AAA() {
std::cout << "INT = " << INT << std::endl;
}

void some_function() {
// WRONG:
template AAA<2>(); // ❌ ERROR! Invalid syntax

// CORRECT:
this->template AAA<2>(); // ✅ Works!
AAA<2>(); // ✅ Usually works too
}
};

Key Point:

- template AAA<2>(); is INVALID C++ syntax
- this->template AAA<2>(); is VALID C++ syntax

The Rule:

- template keyword only goes after -> or . in template contexts
- You cannot start a statement with just template

Correct Examples:

this->template AAA<2>(); // ✅ In class context
obj.template AAA<2>(); // ✅ With object
ptr->template AAA<2>(); // ✅ With pointer
AAA<2>(); // ✅ Direct call (no template keyword needed)

C++ tuple vs vector, Tutorial

 

// ============================================================================
// SIMPLE COMPARISON: TUPLE vs VECTOR
// When to use which one and why they're different
// ============================================================================

#include <tuple>
#include <vector>
#include <iostream>
#include <string>

// ============================================================================
// VECTOR: Dynamic Array of SAME TYPE
// ============================================================================

void vector_example() {
std::cout << "=== VECTOR EXAMPLE ===" << std::endl;
// Vector holds multiple values of THE SAME TYPE
std::vector<int> numbers = {10, 20, 30, 40, 50};
std::cout << "Vector contents: ";
for (size_t i = 0; i < numbers.size(); i++) {
std::cout << numbers[i] << " ";
}
std::cout << std::endl;
// Add more elements
numbers.push_back(60);
numbers.push_back(70);
std::cout << "After adding elements: ";
for (int num : numbers) {
std::cout << num << " ";
}
std::cout << std::endl;
std::cout << "Vector size: " << numbers.size() << std::endl;
std::cout << "Can grow/shrink at runtime: YES" << std::endl;
std::cout << "All elements same type: YES (int)" << std::endl;
}

// ============================================================================
// TUPLE: Fixed Collection of DIFFERENT TYPES
// ============================================================================

void tuple_example() {
std::cout << "\n=== TUPLE EXAMPLE ===" << std::endl;
// Tuple holds DIFFERENT TYPES in fixed positions
std::tuple<int, float, std::string, bool> data = {42, 3.14f, "hello", true};
std::cout << "Tuple contents:" << std::endl;
std::cout << "Position 0 (int): " << std::get<0>(data) << std::endl;
std::cout << "Position 1 (float): " << std::get<1>(data) << std::endl;
std::cout << "Position 2 (string): " << std::get<2>(data) << std::endl;
std::cout << "Position 3 (bool): " << std::get<3>(data) << std::endl;
// Cannot add elements - size is fixed at compile time
// data.push_back(something); // ERROR! No such method
std::cout << "Tuple size: " << std::tuple_size_v<decltype(data)> << std::endl;
std::cout << "Can grow/shrink at runtime: NO" << std::endl;
std::cout << "All elements same type: NO (int, float, string, bool)" << std::endl;
}

// ============================================================================
// SIDE-BY-SIDE COMPARISON
// ============================================================================

void comparison() {
std::cout << "\n=== SIDE-BY-SIDE COMPARISON (marearts.com)===" << std::endl;
// VECTOR: All same type, dynamic size
std::vector<double> grades = {85.5, 92.0, 78.5, 95.0};
// TUPLE: Different types, fixed size
std::tuple<std::string, int, double, char> student = {"Alice", 20, 89.5, 'A'};
std::cout << "VECTOR (grades):" << std::endl;
std::cout << " Type: vector<double>" << std::endl;
std::cout << " Values: ";
for (double grade : grades) {
std::cout << grade << " ";
}
std::cout << std::endl;
std::cout << " Access: grades[0], grades[1], grades[2]..." << std::endl;
std::cout << " Can add more: YES (grades.push_back(88.0))" << std::endl;
std::cout << "\nTUPLE (student info):" << std::endl;
std::cout << " Type: tuple<string, int, double, char>" << std::endl;
std::cout << " Values: " << std::get<0>(student) << ", "
<< std::get<1>(student) << ", "
<< std::get<2>(student) << ", "
<< std::get<3>(student) << std::endl;
std::cout << " Access: std::get<0>(student), std::get<1>(student)..." << std::endl;
std::cout << " Can add more: NO (fixed at compile time)" << std::endl;
}

// ============================================================================
// WHEN TO USE WHICH?
// ============================================================================

void when_to_use() {
std::cout << "\n=== WHEN TO USE WHICH? ===" << std::endl;
std::cout << "USE VECTOR WHEN:" << std::endl;
std::cout << " ✓ All elements are the same type" << std::endl;
std::cout << " ✓ You don't know size at compile time" << std::endl;
std::cout << " ✓ Size can change during runtime" << std::endl;
std::cout << " ✓ You want to loop through elements" << std::endl;
std::cout << " ✓ Examples: list of numbers, array of names, dynamic data" << std::endl;
std::cout << "\nUSE TUPLE WHEN:" << std::endl;
std::cout << " ✓ Elements have different types" << std::endl;
std::cout << " ✓ Size is fixed and known at compile time" << std::endl;
std::cout << " ✓ Each position has specific meaning" << std::endl;
std::cout << " ✓ You want type safety for each element" << std::endl;
std::cout << " ✓ Examples: coordinates (x,y), person data (name,age,score), config settings" << std::endl;
}

// ============================================================================
// PRACTICAL EXAMPLES
// ============================================================================

void practical_examples() {
std::cout << "\n=== PRACTICAL EXAMPLES ===" << std::endl;
// VECTOR EXAMPLES (same type, dynamic)
std::cout << "VECTOR use cases:" << std::endl;
std::vector<int> test_scores; // Dynamic list of test scores
test_scores.push_back(85);
test_scores.push_back(92);
test_scores.push_back(78); // Can keep adding
std::vector<std::string> names = {"Alice", "Bob", "Charlie"}; // List of names
std::cout << " Test scores: ";
for (int score : test_scores) std::cout << score << " ";
std::cout << std::endl;
// TUPLE EXAMPLES (different types, fixed)
std::cout << "\nTUPLE use cases:" << std::endl;
std::tuple<int, int> coordinates = {10, 20}; // 2D point (x, y)
std::tuple<std::string, int, char> student = {"Bob", 19, 'B'}; // Name, age, grade
std::tuple<float, float, float> rgb_color = {0.8f, 0.2f, 0.5f}; // Red, green, blue
auto [x, y] = coordinates; // C++17 structured binding
std::cout << " Coordinates: (" << x << ", " << y << ")" << std::endl;
std::cout << " Student: " << std::get<0>(student) << ", age " << std::get<1>(student)
<< ", grade " << std::get<2>(student) << std::endl;
}

// ============================================================================
// MEMORY AND PERFORMANCE
// ============================================================================

void memory_and_performance() {
std::cout << "\n=== MEMORY & PERFORMANCE ===" << std::endl;
// Vector - dynamic allocation
std::vector<int> vec = {1, 2, 3, 4, 5};
// Tuple - compile-time known, usually stack allocated
std::tuple<int, int, int, int, int> tup = {1, 2, 3, 4, 5};
std::cout << "VECTOR:" << std::endl;
std::cout << " Memory: Heap allocated (dynamic)" << std::endl;
std::cout << " Access: Runtime indexing vec[i]" << std::endl;
std::cout << " Size overhead: Stores capacity + size info" << std::endl;
std::cout << " Performance: Slight overhead for bounds checking" << std::endl;
std::cout << "\nTUPLE:" << std::endl;
std::cout << " Memory: Usually stack allocated (compile-time size)" << std::endl;
std::cout << " Access: Compile-time indexing std::get<N>()" << std::endl;
std::cout << " Size overhead: None (just the data)" << std::endl;
std::cout << " Performance: Maximum efficiency (compile-time optimized)" << std::endl;
}

// ============================================================================
// CANNOT MIX - ERROR EXAMPLES
// ============================================================================

void error_examples() {
std::cout << "\n=== WHAT YOU CANNOT DO ===" << std::endl;
std::cout << "VECTOR limitations:" << std::endl;
std::cout << " ✗ Cannot mix types: vector<int, string> // COMPILER ERROR" << std::endl;
std::cout << " ✗ All elements must be same type" << std::endl;
std::cout << "\nTUPLE limitations:" << std::endl;
std::cout << " ✗ Cannot resize: tuple.push_back() // NO SUCH METHOD" << std::endl;
std::cout << " ✗ Cannot loop easily (no iterators)" << std::endl;
std::cout << " ✗ Must know position at compile time: tuple[i] // ERROR" << std::endl;
// Demonstrate what works
std::vector<int> good_vector = {1, 2, 3}; // ✓ Same type
// std::vector<int, string> bad_vector; // ✗ COMPILER ERROR
std::tuple<int, std::string> good_tuple = {42, "hello"}; // ✓ Different types
// good_tuple.push_back(123); // ✗ NO SUCH METHOD
std::cout << "\nWorking examples:" << std::endl;
std::cout << " Vector: " << good_vector[0] << ", " << good_vector[1] << std::endl;
std::cout << " Tuple: " << std::get<0>(good_tuple) << ", " << std::get<1>(good_tuple) << std::endl;
}

// ============================================================================
// MAIN FUNCTION
// ============================================================================

int main() {
std::cout << "TUPLE vs VECTOR - Simple Comparison" << std::endl;
std::cout << "====================================" << std::endl;
vector_example();
tuple_example();
comparison();
when_to_use();
practical_examples();
memory_and_performance();
error_examples();
std::cout << "\n=== QUICK SUMMARY ===" << std::endl;
std::cout << "VECTOR = Same type + Dynamic size + Runtime flexibility" << std::endl;
std::cout << "TUPLE = Different types + Fixed size + Compile-time safety" << std::endl;
std::cout << "\nThey solve different problems!" << std::endl;
return 0;
}

// ============================================================================
// KEY DIFFERENCES SUMMARY:
// ============================================================================
//
// VECTOR<T>:
// - All elements type T (same type)
// - Dynamic size (can grow/shrink)
// - Runtime access: vec[i]
// - Memory: heap allocated
// - Use for: lists, arrays, collections
//
// TUPLE<T1, T2, T3>:
// - Each element different type
// - Fixed size (compile-time)
// - Compile-time access: std::get<N>()
// - Memory: usually stack
// - Use for: structured data, coordinates, configs
//
// CHOOSE BASED ON:
// - Same vs different types?
// - Dynamic vs fixed size?
// - Runtime vs compile-time access?

C++ Tuple Tutorial,


// ============================================================================
// COMPLETE C++ TUPLE TUTORIAL
// ============================================================================

#include <tuple>
#include <iostream>
#include <string>
#include <typeinfo>

// ============================================================================
// PART 1: BASIC TUPLE CONCEPTS
// ============================================================================

void basic_tuple_usage() {
std::cout << "=== PART 1: Basic Tuple Usage ===" << std::endl;
// Creating tuples with values
std::tuple<int, float, std::string> data1 = {42, 3.14f, "hello"};
std::tuple<int, float, std::string> data2(100, 2.5f, "world");
auto data3 = std::make_tuple(200, 1.5f, "auto");
// Accessing elements
int first = std::get<0>(data1); // Gets 42
float second = std::get<1>(data1); // Gets 3.14f
std::string third = std::get<2>(data1); // Gets "hello"
std::cout << "data1: " << first << ", " << second << ", " << third << std::endl;
// Modifying elements
std::get<0>(data1) = 999;
std::cout << "Modified data1[0]: " << std::get<0>(data1) << std::endl;
// Tuple size
constexpr size_t size = std::tuple_size_v<decltype(data1)>;
std::cout << "Tuple size: " << size << std::endl;
}

// ============================================================================
// PART 2: TUPLES WITH DIFFERENT SIZES
// ============================================================================

void different_tuple_sizes() {
std::cout << "\n=== PART 2: Different Tuple Sizes ===" << std::endl;
std::tuple<int> single = {10}; // 1 element
std::tuple<int, int> pair = {20, 30}; // 2 elements
std::tuple<int, int, int> triple = {40, 50, 60}; // 3 elements
std::tuple<int, int, int, int, int> quintuple = {1, 2, 3, 4, 5}; // 5 elements
std::cout << "Single: " << std::get<0>(single) << std::endl;
std::cout << "Pair: " << std::get<0>(pair) << ", " << std::get<1>(pair) << std::endl;
std::cout << "Triple: " << std::get<0>(triple) << ", " << std::get<1>(triple) << ", " << std::get<2>(triple) << std::endl;
std::cout << "Quintuple[4]: " << std::get<4>(quintuple) << std::endl;
// Tuple sizes
std::cout << "Sizes: " << std::tuple_size_v<decltype(single)> << ", "
<< std::tuple_size_v<decltype(pair)> << ", "
<< std::tuple_size_v<decltype(triple)> << ", "
<< std::tuple_size_v<decltype(quintuple)> << std::endl;
}

// ============================================================================
// PART 3: MIXED TYPE TUPLES
// ============================================================================

void mixed_type_tuples() {
std::cout << "\n=== PART 3: Mixed Type Tuples ===" << std::endl;
// Different types in same tuple
std::tuple<int, float, double, char, bool, std::string> mixed = {
42, 3.14f, 2.718, 'A', true, "mixed"
};
std::cout << "Mixed tuple contents:" << std::endl;
std::cout << "int: " << std::get<0>(mixed) << std::endl;
std::cout << "float: " << std::get<1>(mixed) << std::endl;
std::cout << "double: " << std::get<2>(mixed) << std::endl;
std::cout << "char: " << std::get<3>(mixed) << std::endl;
std::cout << "bool: " << std::get<4>(mixed) << std::endl;
std::cout << "string: " << std::get<5>(mixed) << std::endl;
}

// ============================================================================
// PART 4: TUPLE_ELEMENT_T - EXTRACTING TYPES (NOT VALUES)
// ============================================================================

void tuple_element_type_extraction() {
std::cout << "\n=== PART 4: Type Extraction with std::tuple_element_t ===" << std::endl;
// Define a tuple TYPE (no actual values stored)
using MyTupleType = std::tuple<int, float, double, std::string>;
// Extract individual types from the tuple
using FirstType = std::tuple_element_t<0, MyTupleType>; // int
using SecondType = std::tuple_element_t<1, MyTupleType>; // float
using ThirdType = std::tuple_element_t<2, MyTupleType>; // double
using FourthType = std::tuple_element_t<3, MyTupleType>; // std::string
// Use the extracted types to create variables
FirstType var1 = 100; // int var1 = 100;
SecondType var2 = 2.5f; // float var2 = 2.5f;
ThirdType var3 = 3.14159; // double var3 = 3.14159;
FourthType var4 = "extracted"; // std::string var4 = "extracted";
std::cout << "Variables created from extracted types:" << std::endl;
std::cout << "var1 (int): " << var1 << std::endl;
std::cout << "var2 (float): " << var2 << std::endl;
std::cout << "var3 (double): " << var3 << std::endl;
std::cout << "var4 (string): " << var4 << std::endl;
// Show type information
std::cout << "Type information:" << std::endl;
std::cout << "FirstType: " << typeid(FirstType).name() << std::endl;
std::cout << "SecondType: " << typeid(SecondType).name() << std::endl;
std::cout << "ThirdType: " << typeid(ThirdType).name() << std::endl;
std::cout << "FourthType: " << typeid(FourthType).name() << std::endl;
}

// ============================================================================
// PART 5: TUPLES IN TEMPLATES
// ============================================================================

template <typename TupleType>
class TupleProcessor {
public:
// Extract types from the tuple
using FirstType = std::tuple_element_t<0, TupleType>;
using SecondType = std::tuple_element_t<1, TupleType>;
static constexpr size_t tuple_size = std::tuple_size_v<TupleType>;
void process() {
std::cout << "Processing tuple with " << tuple_size << " elements" << std::endl;
// Create variables using extracted types
FirstType first_var{}; // Default initialize
SecondType second_var{};
std::cout << "FirstType size: " << sizeof(FirstType) << " bytes" << std::endl;
std::cout << "SecondType size: " << sizeof(SecondType) << " bytes" << std::endl;
}
};

void tuples_in_templates() {
std::cout << "\n=== PART 5: Tuples in Templates ===" << std::endl;
// Different tuple types
using IntFloatTuple = std::tuple<int, float>;
using DoubleCharTuple = std::tuple<double, char>;
using StringBoolTuple = std::tuple<std::string, bool>;
// Create template instances with different tuple types
TupleProcessor<IntFloatTuple> processor1;
TupleProcessor<DoubleCharTuple> processor2;
TupleProcessor<StringBoolTuple> processor3;
processor1.process();
processor2.process();
processor3.process();
}

// ============================================================================
// PART 6: ADVANCED TUPLE TECHNIQUES
// ============================================================================

// Template that can handle tuples of any size
template <typename TupleType>
class FlexibleTupleHandler {
public:
static constexpr size_t size = std::tuple_size_v<TupleType>;
// Always safe - every tuple has at least element 0
using FirstType = std::tuple_element_t<0, TupleType>;
// Conditional type extraction (C++17 feature)
using SecondType = std::conditional_t<
(size >= 2),
std::tuple_element_t<1, TupleType>,
void // If tuple has less than 2 elements, use void
>;
void analyze_tuple() {
std::cout << "Tuple analysis:" << std::endl;
std::cout << " Size: " << size << std::endl;
std::cout << " FirstType size: " << sizeof(FirstType) << " bytes" << std::endl;
if constexpr (size >= 2) {
std::cout << " SecondType size: " << sizeof(SecondType) << " bytes" << std::endl;
} else {
std::cout << " No second element" << std::endl;
}
}
};

void advanced_tuple_techniques() {
std::cout << "\n=== PART 6: Advanced Tuple Techniques ===" << std::endl;
// Test with different sized tuples
FlexibleTupleHandler<std::tuple<int>> handler1; // 1 element
FlexibleTupleHandler<std::tuple<int, float>> handler2; // 2 elements
FlexibleTupleHandler<std::tuple<int, float, double>> handler3; // 3 elements
handler1.analyze_tuple();
handler2.analyze_tuple();
handler3.analyze_tuple();
}

// ============================================================================
// PART 7: PRACTICAL EXAMPLE - TYPE-BASED CONFIGURATION
// ============================================================================

// Define some configuration "types" (like layouts in GPU programming)
struct FastConfig { static constexpr const char* name = "Fast"; };
struct SmallConfig { static constexpr const char* name = "Small"; };
struct PreciseConfig { static constexpr const char* name = "Precise"; };

template <typename ConfigTuple>
class ConfigurableProcessor {
public:
using DataType = std::tuple_element_t<0, ConfigTuple>; // First: data type
using SpeedConfig = std::tuple_element_t<1, ConfigTuple>; // Second: speed config
using MemoryConfig = std::tuple_element_t<2, ConfigTuple>; // Third: memory config
void run() {
std::cout << "Running processor with:" << std::endl;
std::cout << " DataType size: " << sizeof(DataType) << " bytes" << std::endl;
std::cout << " Speed: " << SpeedConfig::name << std::endl;
std::cout << " Memory: " << MemoryConfig::name << std::endl;
}
};

void practical_example() {
std::cout << "\n=== PART 7: Practical Example ===" << std::endl;
// Different configurations using tuples
using Config1 = std::tuple<float, FastConfig, SmallConfig>;
using Config2 = std::tuple<double, PreciseConfig, FastConfig>;
using Config3 = std::tuple<int, SmallConfig, PreciseConfig>;
ConfigurableProcessor<Config1> processor1;
ConfigurableProcessor<Config2> processor2;
ConfigurableProcessor<Config3> processor3;
std::cout << "Configuration 1:" << std::endl;
processor1.run();
std::cout << "Configuration 2:" << std::endl;
processor2.run();
std::cout << "Configuration 3:" << std::endl;
processor3.run();
}

// ============================================================================
// PART 8: TUPLE UNPACKING AND STRUCTURED BINDINGS (C++17)
// ============================================================================

void tuple_unpacking() {
std::cout << "\n=== PART 8: Tuple Unpacking ===" << std::endl;
std::tuple<int, float, std::string> data = {42, 3.14f, "hello"};
// C++17 structured binding - unpack tuple into separate variables
auto [number, decimal, text] = data;
std::cout << "Unpacked values:" << std::endl;
std::cout << "number: " << number << std::endl;
std::cout << "decimal: " << decimal << std::endl;
std::cout << "text: " << text << std::endl;
// Modify unpacked variables (they're copies)
number = 999;
std::cout << "Modified number: " << number << std::endl;
std::cout << "Original tuple[0]: " << std::get<0>(data) << std::endl;
}

// ============================================================================
// MAIN FUNCTION - RUN ALL EXAMPLES
// ============================================================================

int main() {
std::cout << "C++ TUPLE COMPREHENSIVE TUTORIAL (MareArts)" << std::endl;
std::cout << "=================================" << std::endl;
basic_tuple_usage();
different_tuple_sizes();
mixed_type_tuples();
tuple_element_type_extraction();
tuples_in_templates();
advanced_tuple_techniques();
practical_example();
tuple_unpacking();
std::cout << "\n=== SUMMARY ===" << std::endl;
std::cout << "1. Tuples can hold any number of elements (1, 2, 3, 5, 10...)" << std::endl;
std::cout << "2. Tuples can store VALUES or define TYPES" << std::endl;
std::cout << "3. std::get<N>(tuple) accesses values" << std::endl;
std::cout << "4. std::tuple_element_t<N, TupleType> extracts types" << std::endl;
std::cout << "5. Templates + tuples = powerful type-based programming" << std::endl;
std::cout << "6. Perfect for configuration systems and generic programming" << std::endl;
return 0;
}

// ============================================================================
// KEY TAKEAWAYS:
// ============================================================================
//
// 1. TUPLE BASICS:
// - std::tuple<T1, T2, T3> can hold any types
// - Access with std::get<0>(tuple), std::get<1>(tuple), etc.
// - Size with std::tuple_size_v<TupleType>
//
// 2. TYPE EXTRACTION:
// - std::tuple_element_t<N, TupleType> gets the Nth type
// - Used at compile-time, not runtime
// - Perfect for template programming
//
// 3. TEMPLATE USAGE:
// - Tuples as template parameters enable type-based configuration
// - One template + multiple tuple types = multiple specialized classes
// - Compiler generates different code for each tuple type
//
// 4. FLEXIBILITY:
// - Any tuple size works
// - Mix any types in same tuple
// - Conditional type extraction for varying sizes
//
// 5. PRACTICAL APPLICATIONS:
// - Configuration systems (data type + algorithm choice)
// - Generic programming (same code, different types)
// - Type-safe parameter passing
// - Template specialization without code duplication

9/20/2024

mlir build and test

To build and run your toy1.cpp code with MLIR, you need to follow these steps. This assumes you are using the Toy language tutorial from MLIR as a base.

1. Setup MLIR Development Environment

If you haven’t done this already, you’ll need to clone and build the LLVM project with MLIR enabled. Here are the steps:

a. Clone LLVM with MLIR

git clone https://github.com/llvm/llvm-project.git
cd llvm-project

b. Build MLIR

mkdir build
cd build
cmake -G Ninja ../llvm \
  -DLLVM_ENABLE_PROJECTS=mlir \
  -DLLVM_BUILD_EXAMPLES=ON \
  -DCMAKE_BUILD_TYPE=Release \
  -DLLVM_ENABLE_ASSERTIONS=ON
cmake --build . --target check-mlir

You can also follow the full guide for building MLIR from the official MLIR Getting Started guide【19†source】.

2. Implementing the Toy Language (toy1.cpp)

You are using a simplified example of the Toy Language from the MLIR tutorial. For this code to work, you need to create a proper Toy dialect and Toy compiler.

a. Writing the toy1.cpp

Save your example code as toy1.cpp inside your MLIR directory.

#include "toy/Dialect.h"
#include "toy/Parser.h"
#include "toy/Passes.h"
#include "toy/Lowering.h"
#include <mlir/IR/MLIRContext.h>
#include <mlir/Pass/PassManager.h>
#include <mlir/ExecutionEngine/ExecutionEngine.h>
#include <mlir/IR/Verifier.h>
#include <mlir/Parser/Parser.h>
#include <mlir/Support/FileUtilities.h>
#include <mlir/Support/LogicalResult.h>
#include <mlir/Support/ToolUtilities.h>
#include <mlir/Support/LLVM.h>
#include <mlir/Target/LLVMIR/ModuleTranslation.h>

int main(int argc, char **argv) {
  mlir::MLIRContext context;
  mlir::PassManager pm(&context);
  
  // Define your toy program in MLIR (using Toy dialect)
  // "var a = [[1, 2, 3], [4, 5, 6]]; var b<2, 3> = ..."

  // Parse it, verify, and run it
  // Example: Create a pass that optimizes or lowers the Toy language IR into MLIR
  
  return 0;
}

You will need to modify this template to use the Toy language's parser and lower the Toy code into MLIR.

3. Integrating with the MLIR Pass Pipeline

You’ll need to define and register your passes. This step lowers Toy language constructs (like variable assignments, matrix multiplication, and transposing) into the MLIR representation.

b. Register Toy Passes and Dialect

You can define passes to lower your Toy language to MLIR:

// In your main, define the following steps:
pm.addPass(toy::createShapeInferencePass());
pm.addPass(mlir::createCSEPass());
pm.addPass(mlir::createCanonicalizerPass());
pm.addPass(toy::createLowerToAffinePass());
pm.addPass(toy::createLowerToLLVMPass());

4. Running Your Toy Code in MLIR

Once you've written the Toy language logic and set up the passes, you can now run and test it using the MLIR tools.

a. Compile toy1.cpp

After you set up your CMakeLists.txt file (using the MLIR Toy Tutorial) and ensure that the Toy dialect is registered, you can compile the Toy language.

cd build
cmake --build . --target toy-compiler

b. Run Toy Compiler

To run your Toy code and compile it into MLIR:

./toy-compiler toy1.cpp -o output.mlir

This will generate MLIR code for your Toy program.

5. Testing and Debugging

Once you've compiled your Toy language code to MLIR, you can use MLIR’s optimization and debugging tools:

mlir-opt output.mlir --canonicalize --cse
mlir-translate --mlir-to-llvmir output.mlir | llc -filetype=obj -o output.o

This will optimize and translate your Toy program into LLVM IR and finally to machine code that can be executed.

References:

This setup will help you compile and run Toy language code through MLIR!

8/22/2024

Install HIP (ROCm) compiler on CUDA system.


Try this process.


1. First, add the ROCm repository to your system. For Ubuntu, you can use these commands:

wget -q -O - https://repo.radeon.com/rocm/rocm.gpg.key | sudo apt-key add -
echo 'deb [arch=amd64] https://repo.radeon.com/rocm/apt/debian/ ubuntu main' | sudo tee /etc/apt/sources.list.d/rocm.list


2. Update your package list:

sudo apt update


3. Install the HIP runtime and compiler for CUDA:

sudo apt install hip-runtime-nvidia hip-dev


4. Set up environment variables. Add these lines to your `~/.bashrc` file:

export HIP_PLATFORM=nvidia
export PATH=$PATH:/opt/rocm/bin
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/opt/rocm/lib

Then run `source ~/.bashrc` to apply the changes.


5. Verify the installation:

hipconfig --full


6. Now try compiling your code again:

hipcc vector_add.cpp -o vector_add